Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:21:35

0001 #include "AnaTutorial.h"
0002 
0003 /// Cluster/Calorimeter includes
0004 #include <calobase/RawCluster.h>
0005 #include <calobase/RawClusterContainer.h>
0006 #include <calobase/RawClusterUtility.h>
0007 #include <calobase/RawTower.h>
0008 #include <calobase/RawTowerContainer.h>
0009 #include <calobase/RawTowerGeom.h>
0010 #include <calobase/RawTowerGeomContainer.h>
0011 #include <calotrigger/CaloTriggerInfo.h>
0012 
0013 /// Jet includes
0014 #include <jetbase/Jet.h>
0015 #include <jetbase/JetMap.h>
0016 
0017 /// Tracking includes
0018 #include <globalvertex/GlobalVertex.h>
0019 #include <globalvertex/GlobalVertexMap.h>
0020 #include <trackbase_historic/SvtxTrack.h>
0021 #include <trackbase_historic/SvtxTrackMap.h>
0022 #include <globalvertex/SvtxVertex.h>
0023 #include <globalvertex/SvtxVertexMap.h>
0024 
0025 /// Truth evaluation includes
0026 #include <g4eval/JetEvalStack.h>
0027 #include <g4eval/SvtxEvalStack.h>
0028 
0029 /// HEPMC truth includes
0030 #pragma GCC diagnostic push
0031 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
0032 #include <HepMC/GenEvent.h>
0033 #include <HepMC/GenVertex.h>
0034 #pragma GCC diagnostic pop
0035 
0036 #include <phhepmc/PHHepMCGenEvent.h>
0037 #include <phhepmc/PHHepMCGenEventMap.h>
0038 
0039 /// Fun4All includes
0040 #include <fun4all/Fun4AllHistoManager.h>
0041 #include <fun4all/Fun4AllReturnCodes.h>
0042 #include <g4main/PHG4Hit.h>
0043 #include <g4main/PHG4Particle.h>
0044 #include <g4main/PHG4TruthInfoContainer.h>
0045 #include <phool/PHCompositeNode.h>
0046 #include <phool/getClass.h>
0047 
0048 /// ROOT includes
0049 #include <TFile.h>
0050 #include <TH1.h>
0051 #include <TH2.h>
0052 #include <TNtuple.h>
0053 #include <TTree.h>
0054 
0055 /// C++ includes
0056 #include <cassert>
0057 #include <cmath>
0058 #include <sstream>
0059 #include <string>
0060 
0061 /**
0062  * This class demonstrates the construction and use of an analysis module
0063  * within the sPHENIX Fun4All framework. It is intended to show how to
0064  * obtain physics objects from the analysis tree, and then write them out
0065  * to a ROOT tree and file for further offline analysis.
0066  */
0067 
0068 /**
0069  * Constructor of module
0070  */
0071 AnaTutorial::AnaTutorial(const std::string &name, const std::string &filename)
0072   : SubsysReco(name)
0073   , m_outfilename(filename)
0074   , m_hm(nullptr)
0075   , m_minjetpt(5.0)
0076   , m_mincluspt(0.25)
0077   , m_analyzeTracks(true)
0078   , m_analyzeClusters(true)
0079   , m_analyzeJets(true)
0080   , m_analyzeTruth(false)
0081 {
0082   /// Initialize variables and trees so we don't accidentally access
0083   /// memory that was never allocated
0084   initializeVariables();
0085   initializeTrees();
0086 }
0087 
0088 /**
0089  * Destructor of module
0090  */
0091 AnaTutorial::~AnaTutorial()
0092 {
0093   delete m_hm;
0094   delete m_hepmctree;
0095   delete m_truthjettree;
0096   delete m_recojettree;
0097   delete m_tracktree;
0098 }
0099 
0100 /**
0101  * Initialize the module and prepare looping over events
0102  */
0103 int AnaTutorial::Init(PHCompositeNode * /*topNode*/)
0104 {
0105   if (Verbosity() > 5)
0106   {
0107     std::cout << "Beginning Init in AnaTutorial" << std::endl;
0108   }
0109 
0110   m_outfile = new TFile(m_outfilename.c_str(), "RECREATE");
0111 
0112   m_phi_h = new TH1D("phi_h", ";Counts;#phi [rad]", 50, -6, 6);
0113   m_eta_phi_h = new TH2F("phi_eta_h", ";#eta;#phi [rad]", 10, -1, 1, 50, -6, 6);
0114 
0115   return 0;
0116 }
0117 
0118 /**
0119  * Main workhorse function where each event is looped over and
0120  * data from each event is collected from the node tree for analysis
0121  */
0122 int AnaTutorial::process_event(PHCompositeNode *topNode)
0123 {
0124   if (Verbosity() > 5)
0125   {
0126     std::cout << "Beginning process_event in AnaTutorial" << std::endl;
0127   }
0128   /// Get the truth information
0129   if (m_analyzeTruth)
0130   {
0131     getHEPMCTruth(topNode);
0132     getPHG4Truth(topNode);
0133   }
0134 
0135   /// Get the tracks
0136   if (m_analyzeTracks)
0137   {
0138     getTracks(topNode);
0139   }
0140   /// Get the truth and reconstructed jets
0141   if (m_analyzeJets)
0142   {
0143     getTruthJets(topNode);
0144     getReconstructedJets(topNode);
0145   }
0146 
0147   /// Get calorimeter information
0148   if (m_analyzeClusters)
0149   {
0150     getEMCalClusters(topNode);
0151   }
0152 
0153   return Fun4AllReturnCodes::EVENT_OK;
0154 }
0155 
0156 /**
0157  * End the module and finish any data collection. Clean up any remaining
0158  * loose ends
0159  */
0160 int AnaTutorial::End(PHCompositeNode * /*topNode*/)
0161 {
0162   if (Verbosity() > 1)
0163   {
0164     std::cout << "Ending AnaTutorial analysis package" << std::endl;
0165   }
0166 
0167   /// Change to the outfile
0168   m_outfile->cd();
0169 
0170   /// If we analyzed the tracks, write the tree out
0171   if (m_analyzeTracks)
0172   {
0173     m_tracktree->Write();
0174   }
0175 
0176   /// If we analyzed the jets, write them out
0177   if (m_analyzeJets)
0178   {
0179     m_truthjettree->Write();
0180     m_recojettree->Write();
0181   }
0182 
0183   /// If we analyzed the truth particles, write them out
0184   if (m_analyzeTruth)
0185   {
0186     m_hepmctree->Write();
0187     m_truthtree->Write();
0188   }
0189 
0190   /// If we analyzed the clusters, write them out
0191   if (m_analyzeClusters)
0192   {
0193     m_clustertree->Write();
0194   }
0195 
0196   /// Write out any other histograms
0197   m_phi_h->Write();
0198   m_eta_phi_h->Write();
0199 
0200   /// Write and close the outfile
0201   m_outfile->Write();
0202   m_outfile->Close();
0203 
0204   /// Clean up pointers and associated histos/trees in TFile
0205   delete m_outfile;
0206 
0207   if (Verbosity() > 1)
0208   {
0209     std::cout << "Finished AnaTutorial analysis package" << std::endl;
0210   }
0211 
0212   return 0;
0213 }
0214 
0215 /**
0216  * This method gets all of the HEPMC truth particles from the node tree
0217  * and stores them in a ROOT TTree. The HEPMC truth particles are what,
0218  * for example, directly comes out of PYTHIA and thus gives you all of
0219  * the associated parton information
0220  */
0221 void AnaTutorial::getHEPMCTruth(PHCompositeNode *topNode)
0222 {
0223   /// Get the node from the node tree
0224   PHHepMCGenEventMap *hepmceventmap = findNode::getClass<PHHepMCGenEventMap>(topNode, "PHHepMCGenEventMap");
0225 
0226   /// If the node was not properly put on the tree, return
0227   if (!hepmceventmap)
0228   {
0229     std::cout << PHWHERE
0230               << "HEPMC event map node is missing, can't collected HEPMC truth particles"
0231               << std::endl;
0232     return;
0233   }
0234 
0235   /// Could have some print statements for debugging with verbosity
0236   if (Verbosity() > 1)
0237   {
0238     std::cout << "Getting HEPMC truth particles " << std::endl;
0239   }
0240 
0241   /// You can iterate over the number of events in a hepmc event
0242   /// for pile up events where you have multiple hard scatterings per bunch crossing
0243   for (PHHepMCGenEventMap::ConstIter eventIter = hepmceventmap->begin();
0244        eventIter != hepmceventmap->end();
0245        ++eventIter)
0246   {
0247     /// Get the event
0248     PHHepMCGenEvent *hepmcevent = eventIter->second;
0249 
0250     if (hepmcevent)
0251     {
0252       /// Get the event characteristics, inherited from HepMC classes
0253       HepMC::GenEvent *truthevent = hepmcevent->getEvent();
0254       if (!truthevent)
0255       {
0256         std::cout << PHWHERE
0257                   << "no evt pointer under phhepmvgeneventmap found "
0258                   << std::endl;
0259         return;
0260       }
0261 
0262       /// Get the parton info
0263       HepMC::PdfInfo *pdfinfo = truthevent->pdf_info();
0264 
0265       /// Get the parton info as determined from HEPMC
0266       m_partid1 = pdfinfo->id1();
0267       m_partid2 = pdfinfo->id2();
0268       m_x1 = pdfinfo->x1();
0269       m_x2 = pdfinfo->x2();
0270 
0271       /// Are there multiple partonic intercations in a p+p event
0272       m_mpi = truthevent->mpi();
0273 
0274       /// Get the PYTHIA signal process id identifying the 2-to-2 hard process
0275       m_process_id = truthevent->signal_process_id();
0276 
0277       if (Verbosity() > 2)
0278       {
0279         std::cout << " Iterating over an event" << std::endl;
0280       }
0281       /// Loop over all the truth particles and get their information
0282       for (HepMC::GenEvent::particle_const_iterator iter = truthevent->particles_begin();
0283            iter != truthevent->particles_end();
0284            ++iter)
0285       {
0286         /// Get each pythia particle characteristics
0287         m_truthenergy = (*iter)->momentum().e();
0288         m_truthpid = (*iter)->pdg_id();
0289 
0290         m_trutheta = (*iter)->momentum().pseudoRapidity();
0291         m_truthphi = (*iter)->momentum().phi();
0292         m_truthpx = (*iter)->momentum().px();
0293         m_truthpy = (*iter)->momentum().py();
0294         m_truthpz = (*iter)->momentum().pz();
0295         m_truthpt = sqrt(m_truthpx * m_truthpx + m_truthpy * m_truthpy);
0296 
0297         /// Fill the truth tree
0298         m_hepmctree->Fill();
0299         m_numparticlesinevent++;
0300       }
0301     }
0302   }
0303 }
0304 
0305 /**
0306  * This function collects the truth PHG4 stable particles that
0307  * are produced from PYTHIA, or some other event generator. These
0308  * are the stable particles, e.g. there are not any (for example)
0309  * partons here.
0310  */
0311 void AnaTutorial::getPHG4Truth(PHCompositeNode *topNode)
0312 {
0313   /// G4 truth particle node
0314   PHG4TruthInfoContainer *truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0315 
0316   if (!truthinfo)
0317   {
0318     std::cout << PHWHERE
0319               << "PHG4TruthInfoContainer node is missing, can't collect G4 truth particles"
0320               << std::endl;
0321     return;
0322   }
0323 
0324   /// Get the primary particle range
0325   PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange();
0326 
0327   /// Loop over the G4 truth (stable) particles
0328   for (PHG4TruthInfoContainer::ConstIterator iter = range.first;
0329        iter != range.second;
0330        ++iter)
0331   {
0332     /// Get this truth particle
0333     const PHG4Particle *truth = iter->second;
0334 
0335     /// Get this particles momentum, etc.
0336     m_truthpx = truth->get_px();
0337     m_truthpy = truth->get_py();
0338     m_truthpz = truth->get_pz();
0339     m_truthp = sqrt(m_truthpx * m_truthpx + m_truthpy * m_truthpy + m_truthpz * m_truthpz);
0340     m_truthenergy = truth->get_e();
0341 
0342     m_truthpt = sqrt(m_truthpx * m_truthpx + m_truthpy * m_truthpy);
0343 
0344     m_truthphi = atan(m_truthpy / m_truthpx);
0345 
0346     m_trutheta = atanh(m_truthpz / m_truthenergy);
0347     /// Check for nans
0348     if (!std::isfinite(m_trutheta))
0349     {
0350       m_trutheta = -99;
0351     }
0352     m_truthpid = truth->get_pid();
0353 
0354     /// Fill the g4 truth tree
0355     m_truthtree->Fill();
0356   }
0357 }
0358 
0359 /**
0360  * This method gets the tracks as reconstructed from the tracker. It also
0361  * compares the reconstructed track to its truth track counterpart as determined
0362  * by the
0363  */
0364 void AnaTutorial::getTracks(PHCompositeNode *topNode)
0365 {
0366   /// SVTX tracks node
0367   SvtxTrackMap *trackmap = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
0368 
0369   if (!trackmap)
0370   {
0371     std::cout << PHWHERE
0372               << "SvtxTrackMap node is missing, can't collect tracks"
0373               << std::endl;
0374     return;
0375   }
0376 
0377   /// EvalStack for truth track matching
0378   if (!m_svtxEvalStack)
0379   {
0380     m_svtxEvalStack = new SvtxEvalStack(topNode);
0381     m_svtxEvalStack->set_verbosity(Verbosity());
0382   }
0383 
0384   m_svtxEvalStack->next_event(topNode);
0385 
0386   /// Get the track evaluator
0387   SvtxTrackEval *trackeval = m_svtxEvalStack->get_track_eval();
0388 
0389   /// Get the range for primary tracks
0390   PHG4TruthInfoContainer *truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0391 
0392   if (Verbosity() > 1)
0393   {
0394     std::cout << "Get the SVTX tracks" << std::endl;
0395   }
0396   for (auto &iter : *trackmap)
0397   {
0398     SvtxTrack *track = iter.second;
0399 
0400     /// Get the reconstructed track info
0401     m_tr_px = track->get_px();
0402     m_tr_py = track->get_py();
0403     m_tr_pz = track->get_pz();
0404     m_tr_p = sqrt(m_tr_px * m_tr_px + m_tr_py * m_tr_py + m_tr_pz * m_tr_pz);
0405 
0406     m_tr_pt = sqrt(m_tr_px * m_tr_px + m_tr_py * m_tr_py);
0407 
0408     // Make some cuts on the track to clean up sample
0409     if (m_tr_pt < 0.5)
0410     {
0411       continue;
0412     }
0413     m_tr_phi = track->get_phi();
0414     m_tr_eta = track->get_eta();
0415 
0416     m_charge = track->get_charge();
0417     m_chisq = track->get_chisq();
0418     m_ndf = track->get_ndf();
0419     m_dca = track->get_dca();
0420     m_tr_x = track->get_x();
0421     m_tr_y = track->get_y();
0422     m_tr_z = track->get_z();
0423 
0424     /// Get truth track info that matches this reconstructed track
0425     PHG4Particle *truthtrack = trackeval->max_truth_particle_by_nclusters(track);
0426     m_truth_is_primary = truthinfo->is_primary(truthtrack);
0427 
0428     m_truthtrackpx = truthtrack->get_px();
0429     m_truthtrackpy = truthtrack->get_py();
0430     m_truthtrackpz = truthtrack->get_pz();
0431     m_truthtrackp = std::sqrt(m_truthtrackpx * m_truthtrackpx + m_truthtrackpy * m_truthtrackpy + m_truthtrackpz * m_truthtrackpz);
0432 
0433     m_truthtracke = truthtrack->get_e();
0434 
0435     m_truthtrackpt = sqrt(m_truthtrackpx * m_truthtrackpx + m_truthtrackpy * m_truthtrackpy);
0436     m_truthtrackphi = atan(m_truthtrackpy / m_truthtrackpx);
0437     m_truthtracketa = atanh(m_truthtrackpz / m_truthtrackp);
0438     m_truthtrackpid = truthtrack->get_pid();
0439 
0440     m_tracktree->Fill();
0441   }
0442 }
0443 
0444 /**
0445  * Method that gets the truth jets and stores them in a tree
0446  */
0447 void AnaTutorial::getTruthJets(PHCompositeNode *topNode)
0448 {
0449   if (Verbosity() > 1)
0450   {
0451     std::cout << "get the truth jets" << std::endl;
0452   }
0453 
0454   /// Get the truth jet node
0455   JetMap *truth_jets = findNode::getClass<JetMap>(topNode, "AntiKt_Truth_r04");
0456 
0457   /// Get reco jets associated to truth jets to study e.g. jet efficiencies
0458   JetMap *reco_jets = findNode::getClass<JetMap>(topNode, "AntiKt_Tower_r04");
0459   if (!m_jetEvalStack)
0460   {
0461     m_jetEvalStack = new JetEvalStack(topNode, "AntiKt_Tower_r04",
0462                                       "AntiKt_Truth_r04");
0463   }
0464   m_jetEvalStack->next_event(topNode);
0465   JetTruthEval *trutheval = m_jetEvalStack->get_truth_eval();
0466 
0467   if (!truth_jets)
0468   {
0469     std::cout << PHWHERE
0470               << "Truth jet node is missing, can't collect truth jets"
0471               << std::endl;
0472     return;
0473   }
0474 
0475   /// Iterate over the truth jets
0476   for (JetMap::Iter iter = truth_jets->begin();
0477        iter != truth_jets->end();
0478        ++iter)
0479   {
0480     Jet *truthJet = iter->second;
0481 
0482     m_truthjetpt = truthJet->get_pt();
0483 
0484     std::set<PHG4Particle *> truthjetcomp =
0485         trutheval->all_truth_particles(truthJet);
0486     int ntruthconstituents = 0;
0487     // loop over the constituents of the truth jet
0488     for (auto truthpart : truthjetcomp)
0489     {
0490       // get the particle of the truthjet
0491       if (!truthpart)
0492       {
0493         std::cout << "no truth particles in the jet??" << std::endl;
0494         break;
0495       }
0496 
0497       ntruthconstituents++;
0498     }
0499 
0500     if (ntruthconstituents < 3)
0501     {
0502       continue;
0503     }
0504     /// Only collect truthjets above the _minjetpt cut
0505     if (m_truthjetpt < m_minjetpt)
0506     {
0507       continue;
0508     }
0509 
0510     m_truthjeteta = truthJet->get_eta();
0511     m_truthjetpx = truthJet->get_px();
0512     m_truthjetpy = truthJet->get_py();
0513     m_truthjetpz = truthJet->get_pz();
0514     m_truthjetphi = truthJet->get_phi();
0515     m_truthjetp = truthJet->get_p();
0516     m_truthjetenergy = truthJet->get_e();
0517 
0518     m_recojetpt = 0;
0519     m_recojetid = 0;
0520     m_recojetpx = 0;
0521     m_recojetpy = 0;
0522     m_recojetpz = 0;
0523     m_recojetphi = 0;
0524     m_recojetp = 0;
0525     m_recojetenergy = 0;
0526     m_dR = -99;
0527     float closestjet = 9999;
0528     /// Iterate over the reconstructed jets
0529     for (auto &reco_jet : *reco_jets)
0530     {
0531       const Jet *recoJet = reco_jet.second;
0532       m_recojetpt = recoJet->get_pt();
0533       if (m_recojetpt < m_minjetpt - m_minjetpt * 0.4)
0534       {
0535         continue;
0536       }
0537 
0538       m_recojeteta = recoJet->get_eta();
0539       m_recojetphi = recoJet->get_phi();
0540 
0541       if (Verbosity() > 1)
0542       {
0543         std::cout << "matching by distance jet" << std::endl;
0544       }
0545 
0546       float dphi = m_recojetphi - m_truthjetphi;
0547       if (dphi > M_PI)
0548       {
0549         dphi -= M_PI * 2.;
0550       }
0551       if (dphi < -1 * M_PI)
0552       {
0553         dphi += M_PI * 2.;
0554       }
0555 
0556       float deta = m_recojeteta - m_truthjeteta;
0557       /// Determine the distance in eta phi space between the reconstructed
0558       /// and truth jets
0559       m_dR = std::sqrt(pow(dphi, 2.) + pow(deta, 2.));
0560 
0561       /// If this truth jet is closer than the previous truth jet, it is
0562       /// closer and thus should be considered the truth jet
0563       if (m_dR < truth_jets->get_par() && m_dR < closestjet)
0564       {
0565         // Get reco jet characteristics
0566         m_recojetid = recoJet->get_id();
0567         m_recojetpx = recoJet->get_px();
0568         m_recojetpy = recoJet->get_py();
0569         m_recojetpz = recoJet->get_pz();
0570         m_recojetphi = recoJet->get_phi();
0571         m_recojetp = recoJet->get_p();
0572         m_recojetenergy = recoJet->get_e();
0573       }
0574     }
0575 
0576     /// Fill the truthjet tree
0577     m_truthjettree->Fill();
0578   }
0579 }
0580 
0581 /**
0582  * Get the reconstructed jets and store them in a tree
0583  */
0584 void AnaTutorial::getReconstructedJets(PHCompositeNode *topNode)
0585 {
0586   /// Get the reconstructed tower jets
0587   JetMap *reco_jets = findNode::getClass<JetMap>(topNode, "AntiKt_Tower_r04");
0588   /// Get the truth jets
0589   JetMap *truth_jets = findNode::getClass<JetMap>(topNode, "AntiKt_Truth_r04");
0590 
0591   if (!m_jetEvalStack)
0592   {
0593     m_jetEvalStack = new JetEvalStack(topNode, "AntiKt_Tower_r04",
0594                                       "AntiKt_Truth_r04");
0595   }
0596   m_jetEvalStack->next_event(topNode);
0597   JetRecoEval *recoeval = m_jetEvalStack->get_reco_eval();
0598   if (!reco_jets)
0599   {
0600     std::cout << PHWHERE
0601               << "Reconstructed jet node is missing, can't collect reconstructed jets"
0602               << std::endl;
0603     return;
0604   }
0605 
0606   if (Verbosity() > 1)
0607   {
0608     std::cout << "Get all Reco Jets" << std::endl;
0609   }
0610 
0611   /// Iterate over the reconstructed jets
0612   for (JetMap::Iter recoIter = reco_jets->begin();
0613        recoIter != reco_jets->end();
0614        ++recoIter)
0615   {
0616     Jet *recoJet = recoIter->second;
0617     m_recojetpt = recoJet->get_pt();
0618     if (m_recojetpt < m_minjetpt)
0619     {
0620       continue;
0621     }
0622 
0623     m_recojeteta = recoJet->get_eta();
0624 
0625     // Get reco jet characteristics
0626     m_recojetid = recoJet->get_id();
0627     m_recojetpx = recoJet->get_px();
0628     m_recojetpy = recoJet->get_py();
0629     m_recojetpz = recoJet->get_pz();
0630     m_recojetphi = recoJet->get_phi();
0631     m_recojetp = recoJet->get_p();
0632     m_recojetenergy = recoJet->get_e();
0633 
0634     if (Verbosity() > 1)
0635     {
0636       std::cout << "matching by distance jet" << std::endl;
0637     }
0638 
0639     /// Set the matched truth jet characteristics to 0
0640     m_truthjetid = 0;
0641     m_truthjetp = 0;
0642     m_truthjetphi = 0;
0643     m_truthjeteta = 0;
0644     m_truthjetpt = 0;
0645     m_truthjetenergy = 0;
0646     m_truthjetpx = 0;
0647     m_truthjetpy = 0;
0648     m_truthjetpz = 0;
0649 
0650     Jet *truthjet = recoeval->max_truth_jet_by_energy(recoJet);
0651     if (truthjet)
0652     {
0653       m_truthjetid = truthjet->get_id();
0654       m_truthjetp = truthjet->get_p();
0655       m_truthjetpx = truthjet->get_px();
0656       m_truthjetpy = truthjet->get_py();
0657       m_truthjetpz = truthjet->get_pz();
0658       m_truthjeteta = truthjet->get_eta();
0659       m_truthjetphi = truthjet->get_phi();
0660       m_truthjetenergy = truthjet->get_e();
0661       m_truthjetpt = sqrt(m_truthjetpx * m_truthjetpx + m_truthjetpy * m_truthjetpy);
0662     }
0663 
0664     /// Check to make sure the truth jet node is available
0665     else if (truth_jets)
0666     {
0667       /// Match the reconstructed jet to the closest truth jet in delta R space
0668       /// Iterate over the truth jets
0669       float closestjet = 9999;
0670       for (auto &truth_jet : *truth_jets)
0671       {
0672         const Jet *truthJet = truth_jet.second;
0673 
0674         float thisjetpt = truthJet->get_pt();
0675         if (thisjetpt < m_minjetpt)
0676         {
0677           continue;
0678         }
0679 
0680         float thisjeteta = truthJet->get_eta();
0681         float thisjetphi = truthJet->get_phi();
0682 
0683         float dphi = m_recojetphi - thisjetphi;
0684         if (dphi > M_PI)
0685         {
0686           dphi -= M_PI * 2.;
0687         }
0688         if (dphi < -1. * M_PI)
0689         {
0690           dphi += M_PI * 2.;
0691         }
0692 
0693         float deta = m_recojeteta - thisjeteta;
0694         /// Determine the distance in eta phi space between the reconstructed
0695         /// and truth jets
0696         m_dR = sqrt(pow(dphi, 2.) + pow(deta, 2.));
0697 
0698         /// If this truth jet is closer than the previous truth jet, it is
0699         /// closer and thus should be considered the truth jet
0700         if (m_dR < reco_jets->get_par() && m_dR < closestjet)
0701         {
0702           m_truthjetid = -9999;
0703           m_truthjetp = truthJet->get_p();
0704           m_truthjetphi = truthJet->get_phi();
0705           m_truthjeteta = truthJet->get_eta();
0706           m_truthjetpt = truthJet->get_pt();
0707           m_truthjetenergy = truthJet->get_e();
0708           m_truthjetpx = truthJet->get_px();
0709           m_truthjetpy = truthJet->get_py();
0710           m_truthjetpz = truthJet->get_pz();
0711           closestjet = m_dR;
0712         }
0713       }
0714     }
0715     m_recojettree->Fill();
0716   }
0717 }
0718 
0719 /**
0720  * This method gets clusters from the EMCal and stores them in a tree. It
0721  * also demonstrates how to get trigger emulator information. Clusters from
0722  * other containers can be obtained in a similar way (e.g. clusters from
0723  * the IHCal, etc.)
0724  */
0725 void AnaTutorial::getEMCalClusters(PHCompositeNode *topNode)
0726 {
0727   /// Get the raw cluster container
0728   /// Note: other cluster containers exist as well. Check out the node tree when
0729   /// you run a simulation
0730   RawClusterContainer *clusters = findNode::getClass<RawClusterContainer>(topNode, "CLUSTER_CEMC");
0731 
0732   if (!clusters)
0733   {
0734     std::cout << PHWHERE
0735               << "EMCal cluster node is missing, can't collect EMCal clusters"
0736               << std::endl;
0737     return;
0738   }
0739 
0740   /// Get the global vertex to determine the appropriate pseudorapidity of the clusters
0741   GlobalVertexMap *vertexmap = findNode::getClass<GlobalVertexMap>(topNode, "GlobalVertexMap");
0742   if (!vertexmap)
0743   {
0744     std::cout << "AnaTutorial::getEmcalClusters - Fatal Error - GlobalVertexMap node is missing. Please turn on the do_global flag in the main macro in order to reconstruct the global vertex." << std::endl;
0745     assert(vertexmap);  // force quit
0746 
0747     return;
0748   }
0749 
0750   if (vertexmap->empty())
0751   {
0752     std::cout << "AnaTutorial::getEmcalClusters - Fatal Error - GlobalVertexMap node is empty. Please turn on the do_global flag in the main macro in order to reconstruct the global vertex." << std::endl;
0753     return;
0754   }
0755 
0756   /// just take a bbc vertex
0757   GlobalVertex *vtx = nullptr;
0758   for(auto iter = vertexmap->begin(); iter!= vertexmap->end(); ++iter)
0759     {
0760       GlobalVertex* vertex = iter->second;
0761       if(vertex->find_vtxids(GlobalVertex::MBD) != vertex->end_vtxids())
0762     {
0763       vtx = vertex;
0764     }
0765     }
0766   if (vtx == nullptr)
0767   {
0768     return;
0769   }
0770 
0771   /// Trigger emulator
0772   CaloTriggerInfo *trigger = findNode::getClass<CaloTriggerInfo>(topNode, "CaloTriggerInfo");
0773 
0774   /// Can obtain some trigger information if desired
0775   if (trigger)
0776   {
0777     m_E_4x4 = trigger->get_best_EMCal_4x4_E();
0778   }
0779   RawClusterContainer::ConstRange begin_end = clusters->getClusters();
0780   RawClusterContainer::ConstIterator clusIter;
0781 
0782   /// Loop over the EMCal clusters
0783   for (clusIter = begin_end.first;
0784        clusIter != begin_end.second;
0785        ++clusIter)
0786   {
0787     /// Get this cluster
0788     const RawCluster *cluster = clusIter->second;
0789 
0790     /// Get cluster characteristics
0791     /// This helper class determines the photon characteristics
0792     /// depending on the vertex position
0793     /// This is important for e.g. eta determination and E_T determination
0794     CLHEP::Hep3Vector vertex(vtx->get_x(), vtx->get_y(), vtx->get_z());
0795     CLHEP::Hep3Vector E_vec_cluster = RawClusterUtility::GetECoreVec(*cluster, vertex);
0796     m_clusenergy = E_vec_cluster.mag();
0797     m_cluseta = E_vec_cluster.pseudoRapidity();
0798     m_clustheta = E_vec_cluster.getTheta();
0799     m_cluspt = E_vec_cluster.perp();
0800     m_clusphi = E_vec_cluster.getPhi();
0801 
0802     if (m_cluspt < m_mincluspt)
0803     {
0804       continue;
0805     }
0806 
0807     m_cluspx = m_cluspt * cos(m_clusphi);
0808     m_cluspy = m_cluspt * sin(m_clusphi);
0809     m_cluspz = sqrt(m_clusenergy * m_clusenergy - m_cluspx * m_cluspx - m_cluspy * m_cluspy);
0810 
0811     // fill the cluster tree with all emcal clusters
0812     m_clustertree->Fill();
0813   }
0814 }
0815 
0816 /**
0817  * This function puts all of the tree branch assignments in one place so as to not
0818  * clutter up the AnaTutorial::Init function.
0819  */
0820 void AnaTutorial::initializeTrees()
0821 {
0822   m_recojettree = new TTree("jettree", "A tree with reconstructed jets");
0823   m_recojettree->Branch("m_recojetpt", &m_recojetpt, "m_recojetpt/D");
0824   m_recojettree->Branch("m_recojetid", &m_recojetid, "m_recojetid/I");
0825   m_recojettree->Branch("m_recojetpx", &m_recojetpx, "m_recojetpx/D");
0826   m_recojettree->Branch("m_recojetpy", &m_recojetpy, "m_recojetpy/D");
0827   m_recojettree->Branch("m_recojetpz", &m_recojetpz, "m_recojetpz/D");
0828   m_recojettree->Branch("m_recojetphi", &m_recojetphi, "m_recojetphi/D");
0829   m_recojettree->Branch("m_recojeteta", &m_recojeteta, "m_recojeteta/D");
0830   m_recojettree->Branch("m_recojetenergy", &m_recojetenergy, "m_recojetenergy/D");
0831   m_recojettree->Branch("m_truthjetid", &m_truthjetid, "m_truthjetid/I");
0832   m_recojettree->Branch("m_truthjetp", &m_truthjetp, "m_truthjetp/D");
0833   m_recojettree->Branch("m_truthjetphi", &m_truthjetphi, "m_truthjetphi/D");
0834   m_recojettree->Branch("m_truthjeteta", &m_truthjeteta, "m_truthjeteta/D");
0835   m_recojettree->Branch("m_truthjetpt", &m_truthjetpt, "m_truthjetpt/D");
0836   m_recojettree->Branch("m_truthjetenergy", &m_truthjetenergy, "m_truthjetenergy/D");
0837   m_recojettree->Branch("m_truthjetpx", &m_truthjetpx, "m_truthjetpx/D");
0838   m_recojettree->Branch("m_truthjetpy", &m_truthjetpy, "m_truthjyetpy/D");
0839   m_recojettree->Branch("m_truthjetpz", &m_truthjetpz, "m_truthjetpz/D");
0840   m_recojettree->Branch("m_dR", &m_dR, "m_dR/D");
0841 
0842   m_truthjettree = new TTree("truthjettree", "A tree with truth jets");
0843   m_truthjettree->Branch("m_truthjetid", &m_truthjetid, "m_truthjetid/I");
0844   m_truthjettree->Branch("m_truthjetp", &m_truthjetp, "m_truthjetp/D");
0845   m_truthjettree->Branch("m_truthjetphi", &m_truthjetphi, "m_truthjetphi/D");
0846   m_truthjettree->Branch("m_truthjeteta", &m_truthjeteta, "m_truthjeteta/D");
0847   m_truthjettree->Branch("m_truthjetpt", &m_truthjetpt, "m_truthjetpt/D");
0848   m_truthjettree->Branch("m_truthjetenergy", &m_truthjetenergy, "m_truthjetenergy/D");
0849   m_truthjettree->Branch("m_truthjetpx", &m_truthjetpx, "m_truthjetpx/D");
0850   m_truthjettree->Branch("m_truthjetpy", &m_truthjetpy, "m_truthjetpy/D");
0851   m_truthjettree->Branch("m_truthjetpz", &m_truthjetpz, "m_truthjetpz/D");
0852   m_truthjettree->Branch("m_dR", &m_dR, "m_dR/D");
0853   m_truthjettree->Branch("m_recojetpt", &m_recojetpt, "m_recojetpt/D");
0854   m_truthjettree->Branch("m_recojetid", &m_recojetid, "m_recojetid/I");
0855   m_truthjettree->Branch("m_recojetpx", &m_recojetpx, "m_recojetpx/D");
0856   m_truthjettree->Branch("m_recojetpy", &m_recojetpy, "m_recojetpy/D");
0857   m_truthjettree->Branch("m_recojetpz", &m_recojetpz, "m_recojetpz/D");
0858   m_truthjettree->Branch("m_recojetphi", &m_recojetphi, "m_recojetphi/D");
0859   m_truthjettree->Branch("m_recojeteta", &m_recojeteta, "m_recojeteta/D");
0860   m_truthjettree->Branch("m_recojetenergy", &m_recojetenergy, "m_recojetenergy/D");
0861   m_tracktree = new TTree("tracktree", "A tree with svtx tracks");
0862   m_tracktree->Branch("m_tr_px", &m_tr_px, "m_tr_px/D");
0863   m_tracktree->Branch("m_tr_py", &m_tr_py, "m_tr_py/D");
0864   m_tracktree->Branch("m_tr_pz", &m_tr_pz, "m_tr_pz/D");
0865   m_tracktree->Branch("m_tr_p", &m_tr_p, "m_tr_p/D");
0866   m_tracktree->Branch("m_tr_pt", &m_tr_pt, "m_tr_pt/D");
0867   m_tracktree->Branch("m_tr_phi", &m_tr_phi, "m_tr_phi/D");
0868   m_tracktree->Branch("m_tr_eta", &m_tr_eta, "m_tr_eta/D");
0869   m_tracktree->Branch("m_charge", &m_charge, "m_charge/I");
0870   m_tracktree->Branch("m_chisq", &m_chisq, "m_chisq/D");
0871   m_tracktree->Branch("m_ndf", &m_ndf, "m_ndf/I");
0872   m_tracktree->Branch("m_dca", &m_dca, "m_dca/D");
0873   m_tracktree->Branch("m_tr_x", &m_tr_x, "m_tr_x/D");
0874   m_tracktree->Branch("m_tr_y", &m_tr_y, "m_tr_y/D");
0875   m_tracktree->Branch("m_tr_z", &m_tr_z, "m_tr_z/D");
0876   m_tracktree->Branch("m_truth_is_primary", &m_truth_is_primary, "m_truth_is_primary/I");
0877   m_tracktree->Branch("m_truthtrackpx", &m_truthtrackpx, "m_truthtrackpx/D");
0878   m_tracktree->Branch("m_truthtrackpy", &m_truthtrackpy, "m_truthtrackpy/D");
0879   m_tracktree->Branch("m_truthtrackpz", &m_truthtrackpz, "m_truthtrackpz/D");
0880   m_tracktree->Branch("m_truthtrackp", &m_truthtrackp, "m_truthtrackp/D");
0881   m_tracktree->Branch("m_truthtracke", &m_truthtracke, "m_truthtracke/D");
0882   m_tracktree->Branch("m_truthtrackpt", &m_truthtrackpt, "m_truthtrackpt/D");
0883   m_tracktree->Branch("m_truthtrackphi", &m_truthtrackphi, "m_truthtrackphi/D");
0884   m_tracktree->Branch("m_truthtracketa", &m_truthtracketa, "m_truthtracketa/D");
0885   m_tracktree->Branch("m_truthtrackpid", &m_truthtrackpid, "m_truthtrackpid/I");
0886 
0887   m_hepmctree = new TTree("hepmctree", "A tree with hepmc truth particles");
0888   m_hepmctree->Branch("m_partid1", &m_partid1, "m_partid1/I");
0889   m_hepmctree->Branch("m_partid2", &m_partid2, "m_partid2/I");
0890   m_hepmctree->Branch("m_x1", &m_x1, "m_x1/D");
0891   m_hepmctree->Branch("m_x2", &m_x2, "m_x2/D");
0892   m_hepmctree->Branch("m_mpi", &m_mpi, "m_mpi/I");
0893   m_hepmctree->Branch("m_process_id", &m_process_id, "m_process_id/I");
0894   m_hepmctree->Branch("m_truthenergy", &m_truthenergy, "m_truthenergy/D");
0895   m_hepmctree->Branch("m_trutheta", &m_trutheta, "m_trutheta/D");
0896   m_hepmctree->Branch("m_truthphi", &m_truthphi, "m_truthphi/D");
0897   m_hepmctree->Branch("m_truthpx", &m_truthpx, "m_truthpx/D");
0898   m_hepmctree->Branch("m_truthpy", &m_truthpy, "m_truthpy/D");
0899   m_hepmctree->Branch("m_truthpz", &m_truthpz, "m_truthpz/D");
0900   m_hepmctree->Branch("m_truthpt", &m_truthpt, "m_truthpt/D");
0901   m_hepmctree->Branch("m_numparticlesinevent", &m_numparticlesinevent, "m_numparticlesinevent/I");
0902   m_hepmctree->Branch("m_truthpid", &m_truthpid, "m_truthpid/I");
0903 
0904   m_truthtree = new TTree("truthg4tree", "A tree with truth g4 particles");
0905   m_truthtree->Branch("m_truthenergy", &m_truthenergy, "m_truthenergy/D");
0906   m_truthtree->Branch("m_truthp", &m_truthp, "m_truthp/D");
0907   m_truthtree->Branch("m_truthpx", &m_truthpx, "m_truthpx/D");
0908   m_truthtree->Branch("m_truthpy", &m_truthpy, "m_truthpy/D");
0909   m_truthtree->Branch("m_truthpz", &m_truthpz, "m_truthpz/D");
0910   m_truthtree->Branch("m_truthpt", &m_truthpt, "m_truthpt/D");
0911   m_truthtree->Branch("m_truthphi", &m_truthphi, "m_truthphi/D");
0912   m_truthtree->Branch("m_trutheta", &m_trutheta, "m_trutheta/D");
0913   m_truthtree->Branch("m_truthpid", &m_truthpid, "m_truthpid/I");
0914 
0915   m_clustertree = new TTree("clustertree", "A tree with emcal clusters");
0916   m_clustertree->Branch("m_clusenergy", &m_clusenergy, "m_clusenergy/D");
0917   m_clustertree->Branch("m_cluseta", &m_cluseta, "m_cluseta/D");
0918   m_clustertree->Branch("m_clustheta", &m_clustheta, "m_clustheta/D");
0919   m_clustertree->Branch("m_cluspt", &m_cluspt, "m_cluspt/D");
0920   m_clustertree->Branch("m_clusphi", &m_clusphi, "m_clusphi/D");
0921   m_clustertree->Branch("m_cluspx", &m_cluspx, "m_cluspx/D");
0922   m_clustertree->Branch("m_cluspy", &m_cluspy, "m_cluspy/D");
0923   m_clustertree->Branch("m_cluspz", &m_cluspz, "m_cluspz/D");
0924   m_clustertree->Branch("m_E_4x4", &m_E_4x4, "m_E_4x4/D");
0925 }
0926 
0927 /**
0928  * This function initializes all of the member variables in this class so that there
0929  * are no variables that might not be set before e.g. writing them to the output
0930  * trees.
0931  */
0932 void AnaTutorial::initializeVariables()
0933 {
0934   m_outfile = new TFile();
0935   m_phi_h = new TH1F();
0936   m_eta_phi_h = new TH2F();
0937 
0938   m_partid1 = -99;
0939   m_partid2 = -99;
0940   m_x1 = -99;
0941   m_x2 = -99;
0942   m_mpi = -99;
0943   m_process_id = -99;
0944   m_truthenergy = -99;
0945   m_trutheta = -99;
0946   m_truthphi = -99;
0947   m_truthp = -99;
0948   m_truthpx = -99;
0949   m_truthpy = -99;
0950   m_truthpz = -99;
0951   m_truthpt = -99;
0952   m_numparticlesinevent = -99;
0953   m_truthpid = -99;
0954 
0955   m_tr_px = -99;
0956   m_tr_py = -99;
0957   m_tr_pz = -99;
0958   m_tr_p = -99;
0959   m_tr_pt = -99;
0960   m_tr_phi = -99;
0961   m_tr_eta = -99;
0962   m_charge = -99;
0963   m_chisq = -99;
0964   m_ndf = -99;
0965   m_dca = -99;
0966   m_tr_x = -99;
0967   m_tr_y = -99;
0968   m_tr_z = -99;
0969   m_truth_is_primary = -99;
0970   m_truthtrackpx = -99;
0971   m_truthtrackpy = -99;
0972   m_truthtrackpz = -99;
0973   m_truthtrackp = -99;
0974   m_truthtracke = -99;
0975   m_truthtrackpt = -99;
0976   m_truthtrackphi = -99;
0977   m_truthtracketa = -99;
0978   m_truthtrackpid = -99;
0979 
0980   m_recojetpt = -99;
0981   m_recojetid = -99;
0982   m_recojetpx = -99;
0983   m_recojetpy = -99;
0984   m_recojetpz = -99;
0985   m_recojetphi = -99;
0986   m_recojetp = -99;
0987   m_recojetenergy = -99;
0988   m_recojeteta = -99;
0989   m_truthjetid = -99;
0990   m_truthjetp = -99;
0991   m_truthjetphi = -99;
0992   m_truthjeteta = -99;
0993   m_truthjetpt = -99;
0994   m_truthjetenergy = -99;
0995   m_truthjetpx = -99;
0996   m_truthjetpy = -99;
0997   m_truthjetpz = -99;
0998   m_dR = -99;
0999 }