#include "DSelector_ksigma0.h" void DSelector_ksigma0::Init(TTree *locTree) { // The Init() function is called when the selector needs to initialize a new tree or chain. // Typically here the branch addresses and branch pointers of the tree will be set. // Init() will be called many times when running on PROOF (once per file to be processed). //SET OUTPUT FILE NAME //can be overriden by user in PROOF dOutputFileName = "ksigma0.root"; //"" for none dOutputTreeFileName = ""; //"" for none //DO THIS NEXT //Because this function gets called for each TTree in the TChain, we must be careful: //We need to re-initialize the tree interface & branch wrappers, but don't want to recreate histograms bool locInitializedPriorFlag = dInitializedFlag; //save whether have been initialized previously DSelector::Init(locTree); //This must be called to initialize wrappers for each new TTree //gDirectory now points to the output file with name dOutputFileName (if any) dBeamBunchPeriod = dAnalysisUtilities.Get_BeamBunchPeriod(Get_RunNumber()); if(locInitializedPriorFlag) return; //have already created histograms, etc. below: exit //THEN THIS Get_ComboWrappers(); dPreviousRunNumber = 0; /*********************************** EXAMPLE USER INITIALIZATION: ANALYSIS ACTIONS **********************************/ //ANALYSIS ACTIONS: //Executed in order if added to dAnalysisActions //false/true below: use measured/kinfit data //PID dAnalysisActions.push_back(new DHistogramAction_ParticleID(dComboWrapper, false)); dAnalysisActions.push_back(new DCutAction_dEdx(dComboWrapper, false, KPlus, SYS_CDC)); dAnalysisActions.push_back(new DCutAction_dEdx(dComboWrapper, false, Proton, SYS_CDC)); dAnalysisActions.push_back(new DCutAction_dEdx(dComboWrapper, false, PiMinus, SYS_CDC)); //below: value: +/- N ns, Unknown: All PIDs, SYS_NULL: all timing systems dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 0.4, KPlus, SYS_BCAL)); dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 0.25, KPlus, SYS_TOF)); dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 0.5, KPlus, SYS_FCAL)); dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 1.0, Proton, SYS_FCAL)); dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 0.8, Proton, SYS_BCAL)); dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 0.5, Proton, SYS_TOF)); dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 0.4, Gamma, SYS_BCAL)); dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, 1.0, Gamma, SYS_FCAL)); dAnalysisActions.push_back(new DHistogramAction_ParticleID(dComboWrapper, false, "PostPID")); //MASSES dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Lambda, 1000, 1.0, 1.2, "Lambda")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Sigma0, 1000, 1.1, 1.3, "Sigma0")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, true, Sigma0, 1000, 1.1, 1.3, "Sigma0_KinFit")); dAnalysisActions.push_back(new DHistogramAction_MissingMassSquared(dComboWrapper, false, 1000, -0.1, 0.1)); //FCAL PHOTON CUT dAnalysisActions.push_back(new DCutAction_PIDDeltaT(dComboWrapper, false, -1.0, Gamma, SYS_FCAL)); //cut if hits FCAL //MASSES dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Lambda, 1000, 1.0, 1.2, "Lambda_PostFCALCut")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Sigma0, 1000, 1.1, 1.3, "Sigma0_PostFCALCut")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, true, Sigma0, 1000, 1.1, 1.3, "Sigma0_KinFit_PostFCALCut")); dAnalysisActions.push_back(new DHistogramAction_MissingMassSquared(dComboWrapper, false, 1000, -0.1, 0.1, "PostFCALCut")); //KINFIT RESULTS dAnalysisActions.push_back(new DHistogramAction_KinFitResults(dComboWrapper)); dAnalysisActions.push_back(new DCutAction_MissingMassSquared(dComboWrapper, false, -0.02, 0.005)); dAnalysisActions.push_back(new DCutAction_InvariantMass(dComboWrapper, false, Lambda, 1.1, 1.13)); //dAnalysisActions.push_back(new DCutAction_KinFitFOM(dComboWrapper, 1.0E-25)); //CAN'T CUT IF WANT TO DO BEAM ASYMMETRY!!!! //MASSES dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Lambda, 1000, 1.0, 1.2, "Lambda_PostKinFitCut")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Sigma0, 1000, 1.1, 1.3, "Sigma0_PostKinFitCut")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, true, Sigma0, 1000, 1.1, 1.3, "Sigma0_KinFit_PostKinFitCut")); dAnalysisActions.push_back(new DHistogramAction_MissingMassSquared(dComboWrapper, false, 1000, -0.1, 0.1, "PostKinFitCut")); //BEAM ENERGY dAnalysisActions.push_back(new DHistogramAction_BeamEnergy(dComboWrapper, false)); dAnalysisActions.push_back(new DCutAction_BeamEnergy(dComboWrapper, false, 8.4, 9.0)); //MASSES dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Lambda, 1000, 1.0, 1.2, "Lambda_PostBeamECut")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, false, Sigma0, 1000, 1.1, 1.3, "Sigma0_PostBeamECut")); dAnalysisActions.push_back(new DHistogramAction_InvariantMass(dComboWrapper, true, Sigma0, 1000, 1.1, 1.3, "Sigma0_KinFit_PostBeamECut")); dAnalysisActions.push_back(new DHistogramAction_MissingMassSquared(dComboWrapper, false, 1000, -0.1, 0.1, "PostBeamECut")); //KINEMATICS dAnalysisActions.push_back(new DHistogramAction_ParticleComboKinematics(dComboWrapper, false)); dAnalysisActions.push_back(new DHistogramAction_ParticleComboKinematics(dComboWrapper, true, "KinFit")); //INITIALIZE ACTIONS //If you create any actions that you want to run manually (i.e. don't add to dAnalysisActions), be sure to initialize them here as well Initialize_Actions(); /******************************** EXAMPLE USER INITIALIZATION: STAND-ALONE HISTOGRAMS *******************************/ //BEAM ASYMMETRY HISTOGRAMS gDirectory->mkdir("BeamAsymmetry", "BeamAsymmetry")->cd(); { //t dHistMap_MandelstamT[true] = new TH1D("MandelstamT_RFSignal", ";t (GeV^{2})", 500, -5.0, 0.0); dHistMap_MandelstamT[false] = new TH1D("MandelstamT_RFSideband", ";t (GeV^{2})", 500, -5.0, 0.0); vector locBeamPolarizations(3, ""); locBeamPolarizations[0] = "PARA"; locBeamPolarizations[1] = "PERP"; locBeamPolarizations[2] = "AMO"; for(auto& locPolType : locBeamPolarizations) { //sigma0 mass vs t string locHistName = string("Sigma0MassVsT_RFSignal_") + locPolType; string locHistTitle = ";t (GeV^{2});#gammap#rightarrowK^{#plus} Missing Mass (GeV/c^{2})"; dHistMap_Sigma0MassVsT[locPolType][true] = new TH2D(locHistName.c_str(), locHistTitle.c_str(), 200, -5.0, 0.0, 400, 1.1, 1.3); locHistName = string("Sigma0MassVsT_RFSideband_") + locPolType; dHistMap_Sigma0MassVsT[locPolType][false] = new TH2D(locHistName.c_str(), locHistTitle.c_str(), 200, -5.0, 0.0, 400, 1.1, 1.3); //prod plane phi vs t locHistTitle = ";t (GeV^{2});Production Plane #phi#circ"; locHistName = string("ProdPlanePhiVsT_RFSignal_Sigma0Signal_") + locPolType; dHistMap_ProdPlanePhiVsT[locPolType][true][true] = new TH2D(locHistName.c_str(), locHistTitle.c_str(), 200, -5.0, 0.0, 360, -180.0, 180.0); locHistName = string("ProdPlanePhiVsT_RFSignal_Sigma0Sideband_") + locPolType; dHistMap_ProdPlanePhiVsT[locPolType][true][false] = new TH2D(locHistName.c_str(), locHistTitle.c_str(), 200, -5.0, 0.0, 360, -180.0, 180.0); locHistName = string("ProdPlanePhiVsT_RFSideband_Sigma0Signal_") + locPolType; dHistMap_ProdPlanePhiVsT[locPolType][false][true] = new TH2D(locHistName.c_str(), locHistTitle.c_str(), 200, -5.0, 0.0, 360, -180.0, 180.0); locHistName = string("ProdPlanePhiVsT_RFSideband_Sigma0Sideband_") + locPolType; dHistMap_ProdPlanePhiVsT[locPolType][false][false] = new TH2D(locHistName.c_str(), locHistTitle.c_str(), 200, -5.0, 0.0, 360, -180.0, 180.0); } } gDirectory->cd(".."); /***************************************** ADVANCED: CHOOSE BRANCHES TO READ ****************************************/ //TO SAVE PROCESSING TIME //If you know you don't need all of the branches/data, but just a subset of it, you can speed things up //By default, for each event, the data is retrieved for all branches //If you know you only need data for some branches, you can skip grabbing data from the branches you don't need //Do this by doing something similar to the commented code below //dTreeInterface->Clear_GetEntryBranches(); //now get none //dTreeInterface->Register_GetEntryBranch("Proton__P4"); //manually set the branches you want } Bool_t DSelector_ksigma0::Process(Long64_t locEntry) { // The Process() function is called for each entry in the tree. The entry argument // specifies which entry in the currently loaded tree is to be processed. // // This function should contain the "body" of the analysis. It can contain // simple or elaborate selection criteria, run algorithms on the data // of the event and typically fill histograms. // // The processing can be stopped by calling Abort(). // Use fStatus to set the return value of TTree::Process(). // The return value is currently not used. //CALL THIS FIRST DSelector::Process(locEntry); //Gets the data from the tree for the entry //cout << "RUN " << Get_RunNumber() << ", EVENT " << Get_EventNumber() << endl; /******************************************** GET POLARIZATION ORIENTATION ******************************************/ //Only if the run number changes //RCDB environment must be setup in order for this to work! (Will return false otherwise) UInt_t locRunNumber = Get_RunNumber(); if(locRunNumber != dPreviousRunNumber) { dIsPolarizedFlag = dAnalysisUtilities.Get_IsPolarizedBeam(locRunNumber, dIsPARAFlag); dPreviousRunNumber = locRunNumber; } /********************************************* SETUP UNIQUENESS TRACKING ********************************************/ //ANALYSIS ACTIONS: Reset uniqueness tracking for each action //For any actions that you are executing manually, be sure to call Reset_NewEvent() on them here Reset_Actions_NewEvent(); //PREVENT-DOUBLE COUNTING WHEN HISTOGRAMMING //Sometimes, some content is the exact same between one combo and the next //e.g. maybe two combos have different beam particles, but the same data for the final-state //When histogramming, you don't want to double-count when this happens: artificially inflates your signal (or background) //So, for each quantity you histogram, keep track of what particles you used (for a given combo) //Then for each combo, just compare to what you used before, and make sure it's unique //EXAMPLE 1: Particle-specific info: set locUsedSoFar_BeamEnergy; //Int_t: Unique ID for beam particles. set: easy to use, fast to search //EXAMPLE 2: Combo-specific info: //In general: Could have multiple particles with the same PID: Use a set of Int_t's //In general: Multiple PIDs, so multiple sets: Contain within a map //Multiple combos: Contain maps within a set (easier, faster to search) set > > locUsedSoFar_Sigma0Mass; //INSERT USER ANALYSIS UNIQUENESS TRACKING HERE /************************************************* LOOP OVER COMBOS *************************************************/ //"Best:" For the given combo of composite particles, the value from the combo with the best kinfit confidence level //internal map: beam/meson combo map >, double> dBestSigma0MassMap, dBestProdPlanePhiMap, dBestTMap, dBestKinFitConLevMap; bool locBestIsRFSignalFlag = false, locBestIsSigma0SignalFlag = false; //Loop over combos UInt_t locNumSurvivingCombos = 0; for(UInt_t loc_i = 0; loc_i < Get_NumCombos(); ++loc_i) { //Set branch array indices for combo and all combo particles dComboWrapper->Set_ComboIndex(loc_i); // Is used to indicate when combos have been cut if(dComboWrapper->Get_IsComboCut()) // Is false when tree originally created continue; // Combo has been cut previously /********************************************** GET PARTICLE INDICES *********************************************/ //Used for tracking uniqueness when filling histograms, and for determining unused particles //Step 0 Int_t locBeamID = dComboBeamWrapper->Get_BeamID(); Int_t locKPlusTrackID = dKPlusWrapper->Get_TrackID(); //Step 1 Int_t locPhotonNeutralID = dPhotonWrapper->Get_NeutralID(); //Step 2 Int_t locProtonTrackID = dProtonWrapper->Get_TrackID(); Int_t locPiMinusTrackID = dPiMinusWrapper->Get_TrackID(); /*********************************************** GET FOUR-MOMENTUM **********************************************/ // Get P4's: //is kinfit if kinfit performed, else is measured //dTargetP4 is target p4 //Step 0 TLorentzVector locBeamP4 = dComboBeamWrapper->Get_P4(); TLorentzVector locKPlusP4 = dKPlusWrapper->Get_P4(); //Step 1 TLorentzVector locDecayingSigma0P4 = dDecayingSigma0Wrapper->Get_P4(); TLorentzVector locPhotonP4 = dPhotonWrapper->Get_P4(); //Step 2 TLorentzVector locDecayingLambdaP4 = dDecayingLambdaWrapper->Get_P4(); TLorentzVector locProtonP4 = dProtonWrapper->Get_P4(); TLorentzVector locPiMinusP4 = dPiMinusWrapper->Get_P4(); // Get Measured P4's: //Step 0 TLorentzVector locBeamP4_Measured = dComboBeamWrapper->Get_P4_Measured(); TLorentzVector locKPlusP4_Measured = dKPlusWrapper->Get_P4_Measured(); //Step 1 TLorentzVector locPhotonP4_Measured = dPhotonWrapper->Get_P4_Measured(); //Step 2 TLorentzVector locProtonP4_Measured = dProtonWrapper->Get_P4_Measured(); TLorentzVector locPiMinusP4_Measured = dPiMinusWrapper->Get_P4_Measured(); /********************************************* COMBINE FOUR-MOMENTUM ********************************************/ // DO YOUR STUFF HERE // Combine 4-vectors TLorentzVector locMissingP4_Measured = locBeamP4_Measured + dTargetP4; locMissingP4_Measured -= locKPlusP4_Measured + locPhotonP4_Measured + locProtonP4_Measured + locPiMinusP4_Measured; TLorentzVector locLambdaP4_Measured = locProtonP4_Measured + locPiMinusP4_Measured; TLorentzVector locSigma0P4_Measured = locLambdaP4_Measured + locPhotonP4_Measured; TLorentzVector locSigma0P4_KinFit = locDecayingLambdaP4 + locPhotonP4; /******************************************** EXECUTE ANALYSIS ACTIONS *******************************************/ // Loop through the analysis actions, executing them in order for the active particle combo if(!Execute_Actions()) //if the active combo fails a cut, IsComboCutFlag automatically set continue; //if you manually execute any actions, and it fails a cut, be sure to call: //dComboWrapper->Set_IsComboCut(true); /************************************************* MISCELLANEOUS *************************************************/ ++locNumSurvivingCombos; /****************************************** BEAM ASYMMETRY, BEST COMBO *******************************************/ //NEED: //A) "production-plane-phi" (K+_phi for given beam E) vs t for the signal & sideband regions of the sigma0 //calc both t & "production-plane-phi" from gamma/K+ combo //both quantities (t, phi) require the same source particles, so no extra complications //There can be multiple combos with the same gamma/k+ combo that will result in different values for t & phi (due to kinfit involving sigma0 as well) //Therefore, for each gamma/K+ combo, choose the overall combo with the highest kinfit confidence level //Also, do RF sideband subtraction to remove background from multiple beamE's //not strictly necessary, but helps reduce background (is this really a good idea?) (background is just a constant offset anyway?) //B) sigma0 mass vs t to get the sigma0 sideband subtraction scale //calc sigma0 mass & t from beam/meson (consistent with above) //There can be multiple combos with the same beam/gamma combo that will result in different values for t & sigma0 mass (due to kinfit involving p/pi-/g as well) //Therefore, for each beam/meson combo, choose the overall combo with the highest kinfit confidence level //sigma0 mass: can calculate from gamma & K+, or from decay products //the calculated value from the gamma/K+ and the decay products is the same //but ONLY if using kinfit info (constrained) //measured is NOT constrained //however, the double-counting check is VERY different //that's OK: either way: one combo is signal, and the rest are background. //It's just that the SIZE of "the rest" is different, depending on whether you choose gamma/K+ or decay products //AND: There are multiple combos with the same beam/K+ combo, but they have different kinfit sigma0 mass (due to kinfit involving decay products as well) //So, when this happens, choose the combo with the highest kinfit confidence level //beam/meson combo map > locUsedThisCombo_BeamMeson; locUsedThisCombo_BeamMeson[Unknown].insert(locBeamID); locUsedThisCombo_BeamMeson[KPlus].insert(locKPlusTrackID); //kinfit conlev double locKinFitConfidenceLevel = dComboWrapper->Get_ConfidenceLevel_KinFit(); auto locConLevIterator = dBestKinFitConLevMap.find(locUsedThisCombo_BeamMeson); if(locConLevIterator == dBestKinFitConLevMap.end()) dBestKinFitConLevMap[locUsedThisCombo_BeamMeson] = locKinFitConfidenceLevel; else if(locKinFitConfidenceLevel > locConLevIterator->second) locConLevIterator->second = locKinFitConfidenceLevel; else continue; //get values double locSigma0Mass_KinFit = locSigma0P4_KinFit.M(); //same whether using decay products or beam/meson (kinfit: p4 conserved) //provided fit converged double locProdPlanePhi = dAnalysisUtilities.Calc_ProdPlanePhi_Pseudoscalar(locBeamP4_Measured.E(), dTargetPID, locKPlusP4_Measured); double locT = (locBeamP4 - locKPlusP4).Mag2(); //fill values dBestSigma0MassMap[locUsedThisCombo_BeamMeson] = locSigma0Mass_KinFit; dBestTMap[locUsedThisCombo_BeamMeson] = locT; dBestProdPlanePhiMap[locUsedThisCombo_BeamMeson] = locProdPlanePhi; //get beam/rf delta-t TLorentzVector locBeamX4 = dComboBeamWrapper->Get_X4(); double locRFTime = dComboWrapper->Get_RFTime_Measured(); double locBeamRFDeltaT = locBeamX4.T() - (locRFTime + (locBeamX4.Z() - dTargetCenter.Z())/29.9792458); //set flags locBestIsRFSignalFlag = fabs(locBeamRFDeltaT) <= (0.5*dBeamBunchPeriod); locBestIsSigma0SignalFlag = ((locSigma0Mass_KinFit > 1.16) && (locSigma0Mass_KinFit <= 1.23)); } // end of combo loop //FILL HISTOGRAMS: Num combos / events surviving actions Fill_NumCombosSurvivedHists(); //FILL ASYMMETRY INFO FOR BEST COMBOS //loop over beam/meson combos string locPolType = "AMO"; if(dIsPolarizedFlag) locPolType = dIsPARAFlag ? "PARA" : "PERP"; for(auto& locTPair : dBestTMap) { auto& locComboMap = locTPair.first; double locT = locTPair.second; double locSigma0Mass = dBestSigma0MassMap[locComboMap]; double locProdPlanePhi = dBestProdPlanePhiMap[locComboMap]; dHistMap_MandelstamT[locBestIsRFSignalFlag]->Fill(locT); //should really be sideband subtracted dHistMap_Sigma0MassVsT[locPolType][locBestIsRFSignalFlag]->Fill(locT, locSigma0Mass); //should really be sideband subtracted //string: PARA, PERP, or AMO //first bool: rf signal/sideband //2nd bool: sigma0 signal/sideband dHistMap_ProdPlanePhiVsT[locPolType][locBestIsRFSignalFlag][locBestIsSigma0SignalFlag]->Fill(locT, locProdPlanePhi); } /************************************ EXAMPLE: FILL CLONE OF TTREE HERE WITH CUTS APPLIED ************************************/ /* Bool_t locIsEventCut = true; for(UInt_t loc_i = 0; loc_i < Get_NumCombos(); ++loc_i) { //Set branch array indices for combo and all combo particles dComboWrapper->Set_ComboIndex(loc_i); // Is used to indicate when combos have been cut if(dComboWrapper->Get_IsComboCut()) continue; locIsEventCut = false; // At least one combo succeeded break; } if(!locIsEventCut && dOutputTreeFileName != "") FillOutputTree(); */ return kTRUE; } void DSelector_ksigma0::Finalize(void) { //Save anything to output here that you do not want to be in the default DSelector output ROOT file. //Otherwise, don't do anything else (especially if you are using PROOF). //If you are using PROOF, this function is called on each thread, //so anything you do will not have the combined information from the various threads. //Besides, it is best-practice to do post-processing (e.g. fitting) separately, in case there is a problem. //DO YOUR STUFF HERE //CALL THIS LAST DSelector::Finalize(); //Saves results to the output file }