Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-13 09:44:40

0001 // ============================================================================
0002 //! \file   RunAlgorithmsOutsideOfReco.cxx
0003 //! \author Derek Anderson
0004 //! \date   10.01.2025
0005 // ----------------------------------------------------------------------------
0006 //! \brief
0007 //!   Example ROOT macro illustrating how to run an
0008 //!   EICrecon algorithm outside of EICrecon, and how to
0009 //!   write out your own PODIO collections. The code is
0010 //!   completely unoptimized! So don't expect great
0011 //!   performance...
0012 //!
0013 //! \usage
0014 //!   Has to be run inside eic-shell! run the `setup.sh`
0015 //!   script beforehand to make sure relevant include
0016 //!   locations are in your paths.
0017 //!
0018 //!       $ source setup.sh
0019 //!       $ root -b -q RunAlgorithmsOutsideOfReco.cxx
0020 // ============================================================================
0021 
0022 #ifndef RunAlgorithmsOutsideOfReco_cxx
0023 #define RunAlgorithmsOutsideOfReco_cxx
0024 
0025 #include <algorithms/logger.h>
0026 #include <algorithms/service.h>
0027 #include <edm4hep/EventHeaderCollection.h>
0028 #include <edm4hep/MCParticleCollection.h>
0029 #include <edm4hep/utils/vector_utils.h>
0030 #include <edm4eic/InclusiveKinematicsCollection.h>
0031 #include <edm4eic/ReconstructedParticleCollection.h>
0032 #include <EICrecon/algorithms/reco/ElectronReconstruction.h>
0033 #include <EICrecon/algorithms/reco/InclusiveKinematicsElectron.h>
0034 #include <EICrecon/algorithms/reco/JetReconstruction.h>
0035 #include <EICrecon/algorithms/reco/ScatteredElectronsEMinusPz.h>
0036 #include <EICrecon/services/particle/ParticleSvc.h>
0037 #include <podio/CollectionBase.h>
0038 #include <podio/Frame.h>
0039 #include <podio/ROOTReader.h>
0040 #include <podio/ROOTWriter.h>
0041 #include <TFile.h>
0042 #include <TH1.h>
0043 #include <TH2.h>
0044 #include <iostream>
0045 #include <memory>
0046 #include <string>
0047 #include <utility>
0048 #include <vector>
0049 
0050 R__LOAD_LIBRARY(EICrecon/plugins/reco.so)
0051 
0052 
0053 
0054 // user options ---------------------------------------------------------------
0055 
0056 struct Options {
0057   std::string in_file;   // input eicrecon file
0058   std::string out_hist;  // output file for histograms
0059   std::string out_tree;  // output file for podio tree
0060 } DefaultOptions = {
0061   "root://dtn-eic.jlab.org//volatile/eic/EPIC/RECO/25.06.1/epic_craterlake/DIS/NC/10x100/minQ2=10/pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_5.1287.eicrecon.edm4eic.root",
0062   "test_algo.hists.root",
0063   "test_algo.tree.root"
0064 };
0065 
0066 
0067 
0068 // macro body -----------------------------------------------------------------
0069 
0070 void RunAlgorithmsOutsideOfReco(const Options& opt = DefaultOptions) {
0071 
0072   // announce start
0073   std::cout << "\n  Starting algorithm example!" << std::endl;
0074 
0075   // open inputs/output files -------------------------------------------------
0076 
0077   // open input/output with podio reader/writer
0078   podio::ROOTWriter writer = podio::ROOTWriter(opt.out_tree);
0079   podio::ROOTReader reader = podio::ROOTReader();
0080   reader.openFile(opt.in_file);
0081   std::cout << "    Opened PODIO frame reader/writer." << std::endl;
0082 
0083   // open output histogram file
0084   TFile* outHist = new TFile(opt.out_hist.data(), "recreate");
0085   if (!outHist) {
0086     std::cerr << "PANIC: couldn't open output histogram file!" << std::endl;
0087     return;
0088   }
0089   std::cout << "    Opened output file." << std::endl;
0090 
0091   // define output histograms -------------------------------------------------
0092 
0093   // make sure hist errors on on
0094   TH1::SetDefaultSumw2(true);
0095   TH2::SetDefaultSumw2(true);
0096 
0097   // helper struct for histogram binning
0098   struct Bin {
0099     uint32_t num;
0100     float    start;
0101     float    stop;
0102   };
0103 
0104   // define histogram binning
0105   std::vector<Bin> bins = {
0106     {101, -10., 1e3},  // Q^2
0107     {102, -1., 50.},   // energy
0108     {200 , -5., 5.}    // eta
0109   };
0110 
0111   // define histograms
0112   TH1D* hReconQ2  = new TH1D("hReconQ2", "EICrecon Q^{2} (e-method)", bins[0].num, bins[0].start, bins[0].stop);
0113   TH1D* hRerunQ2  = new TH1D("hRerunQ2", "Recalculated Q2 (e-method)", bins[0].num, bins[0].start, bins[0].stop);
0114   TH2D* hReconExH = new TH2D("hReconExH", "EICrecon jet E vs. #eta (anti-k_{T})", bins[2].num, bins[2].start, bins[2].stop, bins[1].num, bins[1].start, bins[1].stop);
0115   TH2D* hRerunExH = new TH2D("hRerunExH", "EICrecon jet E vs. #eta (ee-k_{T})", bins[2].num, bins[2].start, bins[2].stop, bins[1].num, bins[1].start, bins[1].stop);
0116   std::cout << "    Defined histograms." << std::endl;
0117 
0118   // initialize necessary services for algorithms -----------------------------
0119 
0120   // the particle service is needed for
0121   //   - ScatteredElectronsEMinusPz
0122   //   - InclusiveKinematicsElectron
0123   auto& svcParticle = algorithms::ParticleSvc::instance();
0124   svcParticle.init();
0125 
0126   // initialize algorithms to rerun -------------------------------------------
0127 
0128   // modify configurations for algorithms we want to rerun
0129   eicrecon::JetReconstructionConfig cfgJetReco {
0130     .jetAlgo = "ee_kt_algorithm"
0131   };
0132 
0133   eicrecon::ElectronReconstructionConfig cfgElecReco {
0134     .min_energy_over_momentum = 0.5,
0135     .max_energy_over_momentum = 1.5
0136   };
0137 
0138   eicrecon::ScatteredElectronsEMinusPzConfig cfgDISElecSelect {
0139     .minEMinusPz = 1.0,
0140     .maxEMinusPz = 100.0
0141   };
0142 
0143   // set up new jet reconstruction algorithm
0144   eicrecon::JetReconstruction<edm4eic::ReconstructedParticle> algoJetReco("ReconstructedChargedEEKtJets");
0145   algoJetReco.level(algorithms::LogLevel::kInfo);
0146   algoJetReco.applyConfig(cfgJetReco);
0147   algoJetReco.init();
0148 
0149   // set up new DIS/kinematic algorithms
0150   eicrecon::ElectronReconstruction algoElecReco("LooselyReconstructedElectronsForDIS");
0151   algoElecReco.level(algorithms::LogLevel::kInfo);
0152   algoElecReco.applyConfig(cfgElecReco);
0153   algoElecReco.init();
0154 
0155   eicrecon::ScatteredElectronsEMinusPz algoDISElecSelect("TightlyScatteredElectronsEMinusPz");
0156   algoDISElecSelect.level(algorithms::LogLevel::kInfo);
0157   algoDISElecSelect.applyConfig(cfgDISElecSelect);
0158   algoDISElecSelect.init();
0159 
0160   eicrecon::InclusiveKinematicsElectron algoKinemElec("ReconstructedInclusiveKinematicsElectron");
0161   algoKinemElec.level(algorithms::LogLevel::kInfo);
0162   algoKinemElec.init();
0163 
0164   // event loop ---------------------------------------------------------------
0165 
0166   // get no. of frames and announce start of event loop
0167   const uint64_t nEvts = reader.getEntries(podio::Category::Event);
0168   std::cout << "    Starting event loop: " << nEvts << " events to process." << std::endl;
0169 
0170   // iterate through frames (i.e. events in this case)
0171   for (uint64_t iEvt = 0; iEvt < nEvts; ++iEvt) {
0172 
0173     // announce progress
0174     uint64_t iProg = iEvt + 1;
0175     if (iProg % 100 == 0) {
0176       std::cout << "      Processing event " << iProg << "/" << nEvts << "..." << std::endl;
0177     }
0178 
0179     // open input frame
0180     auto iFrame = podio::Frame(reader.readNextEntry(podio::Category::Event));
0181 
0182     // grab & analyze default collections -------------------------------------
0183 
0184     // grab necessary collections from EICrecon output
0185     auto& mcPars       = iFrame.get<edm4hep::MCParticleCollection>("MCParticles");
0186     auto& recoPars     = iFrame.get<edm4eic::ReconstructedParticleCollection>("ReconstructedParticles");
0187     auto& recoChrgs    = iFrame.get<edm4eic::ReconstructedParticleCollection>("ReconstructedChargedParticles");
0188     auto& recoChrgJets = iFrame.get<edm4eic::ReconstructedParticleCollection>("ReconstructedChargedJets");
0189     auto& kineElecs    = iFrame.get<edm4eic::InclusiveKinematicsCollection>("InclusiveKinematicsElectron");
0190     auto& hadronFS     = iFrame.get<edm4eic::HadronicFinalStateCollection>("HadronicFinalState");
0191 
0192     // fill histograms from default collections
0193     for (const auto& kine : kineElecs) {
0194       hReconQ2 -> Fill( kine.getQ2() );
0195     }
0196     for (const auto& jet : recoChrgJets) {
0197       hReconExH -> Fill(
0198         edm4hep::utils::eta( jet.getMomentum() ),
0199         jet.getEnergy()
0200       );
0201     }
0202 
0203     // run modified algorithms & analyze/save output --------------------------
0204 
0205     // create output collections
0206     auto oHeaders      = std::make_unique<edm4hep::EventHeaderCollection>();
0207     auto oJets         = std::make_unique<edm4eic::ReconstructedParticleCollection>();
0208     auto oElectrons    = std::make_unique<edm4eic::ReconstructedParticleCollection>();
0209     auto oDISElectrons = std::make_unique<edm4eic::ReconstructedParticleCollection>();
0210     auto oKineElecs    = std::make_unique<edm4eic::InclusiveKinematicsCollection>();
0211 
0212     // set header info
0213     auto header = oHeaders -> create();
0214     header.setEventNumber(iEvt);
0215     header.setRunNumber(0);
0216     header.setWeight(1.0);
0217 
0218     // rerun jet reconstruction
0219     auto inJetReco  = std::make_tuple(&recoChrgs);
0220     auto outJetReco = std::make_tuple(oJets.get());
0221     algoJetReco.process(inJetReco, outJetReco);
0222 
0223     // rerun electron reconstruction
0224     //   -- NOTE this algorithm returns a subset
0225     //      collection!
0226     //   -- So output indicates indices in input
0227     //      collection corresponding to identified
0228     //      electrons!
0229     auto inElecReco  = std::make_tuple(&recoPars);
0230     auto outElecReco = std::make_tuple(oElectrons.get());
0231     algoElecReco.process(inElecReco, outElecReco);
0232 
0233     // select new DIS electron candidates
0234     //   -- this also returns a subset collection
0235     auto inDISSelect  = std::make_tuple(&recoPars, oElectrons.get());
0236     auto outDISSelect = std::make_tuple(oDISElectrons.get());
0237     algoDISElecSelect.process(inDISSelect, outDISSelect);
0238 
0239     auto inKinemElec  = std::make_tuple(&mcPars, oDISElectrons.get(), &hadronFS);
0240     auto outKinemElec = std::make_tuple(oKineElecs.get());
0241     algoKinemElec.process(inKinemElec, outKinemElec);
0242 
0243     // fill histograms from modified collections
0244     for (const auto& kine : *oKineElecs) {
0245       hRerunQ2 -> Fill( kine.getQ2() );
0246     }
0247     for (const auto& jet : *oJets) {
0248       hRerunExH -> Fill(
0249         edm4hep::utils::eta( jet.getMomentum() ),
0250         jet.getEnergy()
0251       );
0252     }
0253 
0254     // collect output collections into a frame
0255     // and write to TTree
0256     auto oFrame = podio::Frame();
0257     oFrame.put(std::move(oHeaders), "EventHeader");
0258     oFrame.put(std::move(oElectrons), "LooselyReconstructedElectrons");
0259     oFrame.put(std::move(oDISElectrons), "TightlyScatteredElectronsEMinusPz");
0260     oFrame.put(std::move(oJets), "ReconstructedChargedEEKtJets");
0261     oFrame.put(std::move(oKineElecs), "ReconstructedInclusiveKinematicsElectron");
0262     writer.writeFrame(oFrame, "events");
0263 
0264   }  // end event loop
0265   std::cout << "    Event loop finished." << std::endl;
0266 
0267   // save output & close ------------------------------------------------------
0268 
0269   // save histograms output
0270   outHist   -> cd();
0271   hReconQ2  -> Write();
0272   hRerunQ2  -> Write();
0273   hReconExH -> Write();
0274   hRerunExH -> Write();
0275   outHist   -> Close();
0276   std::cout << "    Saved and closed histogram output." << std::endl;
0277 
0278   // save output collections
0279   writer.finish();
0280 
0281   // announce end & exit
0282   std::cout << "  Finished algorithm example!\n" << std::endl;
0283   return;
0284 
0285 }
0286 
0287 #endif
0288 
0289 // end ========================================================================