From ad38fb54997706924cce9410ddaab242dd100cd3 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:31:59 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`mas?= =?UTF-8?q?ter`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @blackcathj. * https://github.com/sPHENIX-Test/coresoftware/pull/13#issuecomment-3769405550 The following files were modified: * `generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc` * `generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc` * `generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h` * `generators/PHPythia8/PHPythia8.cc` * `generators/phhepmc/PHHepMCGenEventv1.cc` * `offline/QA/Calorimeters/CaloValid.cc` * `offline/QA/Tracking/MicromegasClusterQA.cc` * `offline/QA/Tracking/MicromegasClusterQA.h` * `offline/QA/Tracking/StateClusterResidualsQA.cc` * `offline/QA/Tracking/StateClusterResidualsQA.h` * `offline/framework/ffamodules/CDBInterface.cc` * `offline/framework/ffamodules/FlagHandler.h` * `offline/framework/ffamodules/HeadReco.cc` * `offline/framework/ffamodules/HeadReco.h` * `offline/framework/ffamodules/SyncReco.h` * `offline/framework/ffamodules/Timing.cc` * `offline/framework/ffamodules/Timing.h` * `offline/framework/fun4all/Fun4AllServer.cc` * `offline/framework/fun4all/Fun4AllServer.h` * `offline/framework/fun4all/InputFileHandler.cc` * `offline/framework/fun4all/InputFileHandler.h` * `offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc` * `offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc` * `offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h` * `offline/framework/fun4allraw/SingleMvtxPoolInput.cc` * `offline/framework/fun4allraw/SingleTriggeredInput.cc` * `offline/framework/fun4allraw/SingleTriggeredInput.h` * `offline/packages/CaloEmbedding/CombineTowerInfo.cc` * `offline/packages/CaloEmbedding/CombineTowerInfo.h` * `offline/packages/CaloEmbedding/CopyIODataNodes.cc` * `offline/packages/CaloEmbedding/CopyIODataNodes.h` * `offline/packages/CaloReco/PhotonClusterBuilder.cc` * `offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc` * `offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc` * `offline/packages/PHGenFitPkg/PHGenFit/Track.cc` * `offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc` * `offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h` * `offline/packages/jetbackground/DetermineTowerBackground.cc` * `offline/packages/jetbackground/DetermineTowerBackground.h` * `offline/packages/mbd/MbdCalib.cc` * `offline/packages/mbd/MbdEvent.cc` * `offline/packages/mbd/MbdReco.cc` * `offline/packages/mbd/MbdSig.h` * `offline/packages/micromegas/MicromegasClusterizer.cc` * `offline/packages/micromegas/MicromegasCombinedDataDecoder.cc` * `offline/packages/micromegas/MicromegasCombinedDataDecoder.h` * `offline/packages/micromegas/MicromegasDefs.cc` * `offline/packages/micromegas/MicromegasDefs.h` * `offline/packages/mvtx/CylinderGeom_Mvtx.cc` * `offline/packages/mvtx/CylinderGeom_Mvtx.h` * `offline/packages/mvtx/MvtxClusterPruner.cc` * `offline/packages/mvtx/MvtxClusterizer.cc` * `offline/packages/mvtx/MvtxHitPruner.cc` * `offline/packages/mvtx/SegmentationAlpide.cc` * `offline/packages/tpc/LaserClusterizer.cc` * `offline/packages/tpc/LaserEventIdentifier.cc` * `offline/packages/tpc/Tpc3DClusterizer.cc` * `offline/packages/tpc/TpcClusterMover.cc` * `offline/packages/tpc/TpcClusterMover.h` * `offline/packages/tpc/TpcClusterizer.cc` * `offline/packages/tpc/TpcCombinedRawDataUnpacker.cc` * `offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc` * `offline/packages/tpc/TpcDistortionCorrection.cc` * `offline/packages/tpc/TpcLoadDistortionCorrection.cc` * `offline/packages/tpc/TpcRawDataTree.cc` * `offline/packages/tpc/TpcRawWriter.cc` * `offline/packages/tpc/TpcSimpleClusterizer.cc` * `offline/packages/tpc/TrainingHits.cc` * `offline/packages/trackbase/AlignmentTransformation.cc` * `offline/packages/trackbase/AlignmentTransformation.h` * `offline/packages/trackreco/DSTClusterPruning.cc` * `offline/packages/trackreco/DSTClusterPruning.h` * `offline/packages/trackreco/PHActsTrkFitter.cc` * `offline/packages/trackreco/PHActsTrkFitter.h` * `offline/packages/trackreco/PHSiliconTpcTrackMatching.cc` * `offline/packages/trackreco/PHSiliconTpcTrackMatching.h` * `offline/packages/trackreco/PHSimpleVertexFinder.h` * `offline/packages/trackreco/PHTpcDeltaZCorrection.h` --- .../Herwig/HepMCTrigger/HepMCJetTrigger.cc | 31 +- .../HepMCTrigger/HepMCParticleTrigger.cc | 552 ++++++++++++ .../HepMCTrigger/HepMCParticleTrigger.h | 137 +++ generators/PHPythia8/PHPythia8.cc | 58 +- generators/phhepmc/PHHepMCGenEventv1.cc | 16 +- offline/QA/Calorimeters/CaloValid.cc | 38 +- offline/QA/Tracking/MicromegasClusterQA.cc | 30 +- offline/QA/Tracking/MicromegasClusterQA.h | 48 +- .../QA/Tracking/StateClusterResidualsQA.cc | 318 +++++++ offline/QA/Tracking/StateClusterResidualsQA.h | 130 +++ offline/framework/ffamodules/CDBInterface.cc | 26 +- offline/framework/ffamodules/FlagHandler.h | 32 +- offline/framework/ffamodules/HeadReco.cc | 26 +- offline/framework/ffamodules/HeadReco.h | 30 +- offline/framework/ffamodules/SyncReco.h | 49 +- offline/framework/ffamodules/Timing.cc | 9 +- offline/framework/ffamodules/Timing.h | 16 +- offline/framework/fun4all/Fun4AllServer.cc | 71 +- offline/framework/fun4all/Fun4AllServer.h | 28 +- offline/framework/fun4all/InputFileHandler.cc | 91 ++ offline/framework/fun4all/InputFileHandler.h | 132 ++- .../Fun4AllStreamingInputManager.cc | 168 ++-- .../SingleMicromegasPoolInput_v2.cc | 77 +- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 32 +- .../fun4allraw/SingleMvtxPoolInput.cc | 44 +- .../fun4allraw/SingleTriggeredInput.cc | 127 ++- .../fun4allraw/SingleTriggeredInput.h | 111 ++- .../CaloEmbedding/CombineTowerInfo.cc | 131 +++ .../packages/CaloEmbedding/CombineTowerInfo.h | 59 ++ .../packages/CaloEmbedding/CopyIODataNodes.cc | 140 ++- .../packages/CaloEmbedding/CopyIODataNodes.h | 20 +- .../packages/CaloReco/PhotonClusterBuilder.cc | 18 +- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 23 +- .../packages/PHGenFitPkg/PHGenFit/Fitter.cc | 64 +- .../packages/PHGenFitPkg/PHGenFit/Track.cc | 174 +++- .../Skimmers/Trigger/TriggerDSTSkimmer.cc | 33 +- .../Skimmers/Trigger/TriggerDSTSkimmer.h | 49 +- .../jetbackground/DetermineTowerBackground.cc | 277 ++++-- .../jetbackground/DetermineTowerBackground.h | 79 +- offline/packages/mbd/MbdCalib.cc | 17 +- offline/packages/mbd/MbdEvent.cc | 105 ++- offline/packages/mbd/MbdReco.cc | 22 +- offline/packages/mbd/MbdSig.h | 16 +- .../micromegas/MicromegasClusterizer.cc | 71 +- .../MicromegasCombinedDataDecoder.cc | 38 +- .../MicromegasCombinedDataDecoder.h | 84 +- offline/packages/micromegas/MicromegasDefs.cc | 81 +- offline/packages/micromegas/MicromegasDefs.h | 14 +- offline/packages/mvtx/CylinderGeom_Mvtx.cc | 129 ++- offline/packages/mvtx/CylinderGeom_Mvtx.h | 80 +- offline/packages/mvtx/MvtxClusterPruner.cc | 243 ++++-- offline/packages/mvtx/MvtxClusterizer.cc | 218 +++-- offline/packages/mvtx/MvtxHitPruner.cc | 122 ++- offline/packages/mvtx/SegmentationAlpide.cc | 19 +- offline/packages/tpc/LaserClusterizer.cc | 805 ++++++++++-------- offline/packages/tpc/LaserEventIdentifier.cc | 14 +- offline/packages/tpc/Tpc3DClusterizer.cc | 466 ++++++---- offline/packages/tpc/TpcClusterMover.cc | 85 +- offline/packages/tpc/TpcClusterMover.h | 17 +- offline/packages/tpc/TpcClusterizer.cc | 206 +++-- .../tpc/TpcCombinedRawDataUnpacker.cc | 18 +- .../tpc/TpcCombinedRawDataUnpackerDebug.cc | 33 +- .../packages/tpc/TpcDistortionCorrection.cc | 11 +- .../tpc/TpcLoadDistortionCorrection.cc | 22 +- offline/packages/tpc/TpcRawDataTree.cc | 14 +- offline/packages/tpc/TpcRawWriter.cc | 21 +- offline/packages/tpc/TpcSimpleClusterizer.cc | 95 ++- offline/packages/tpc/TrainingHits.cc | 32 +- .../trackbase/AlignmentTransformation.cc | 153 ++-- .../trackbase/AlignmentTransformation.h | 62 +- .../packages/trackreco/DSTClusterPruning.cc | 59 +- .../packages/trackreco/DSTClusterPruning.h | 14 + offline/packages/trackreco/PHActsTrkFitter.cc | 410 +++++---- offline/packages/trackreco/PHActsTrkFitter.h | 111 ++- .../trackreco/PHSiliconTpcTrackMatching.cc | 17 +- .../trackreco/PHSiliconTpcTrackMatching.h | 43 +- .../packages/trackreco/PHSimpleVertexFinder.h | 34 +- .../trackreco/PHTpcDeltaZCorrection.h | 15 +- 78 files changed, 5895 insertions(+), 1615 deletions(-) create mode 100644 generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc create mode 100644 generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h create mode 100644 offline/QA/Tracking/StateClusterResidualsQA.cc create mode 100644 offline/QA/Tracking/StateClusterResidualsQA.h create mode 100644 offline/packages/CaloEmbedding/CombineTowerInfo.cc create mode 100644 offline/packages/CaloEmbedding/CombineTowerInfo.h diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc index 02ca208f25..2d6216f8a9 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc @@ -85,6 +85,17 @@ bool HepMCJetTrigger::isGoodEvent(HepMC::GenEvent* e1) return false; } +/** + * @brief Cluster final-state particles from a HepMC event into anti-kt (R=0.4) jets. + * + * Particles used for clustering are final-state (status == 1) with no end vertex; neutrinos + * (PDG IDs with absolute value in [12, 18]) are excluded. Each resulting PseudoJet has its + * user_index set to the originating particle's barcode. + * + * @param e1 Pointer to the HepMC::GenEvent to cluster. + * @return std::vector Inclusive jets produced by the anti-kt (R=0.4) clustering, + * in FastJet's PseudoJet format. + */ std::vector HepMCJetTrigger::findAllJets(HepMC::GenEvent* e1) { // do the fast jet clustering, antikt r=-0.4 @@ -96,6 +107,11 @@ std::vector HepMCJetTrigger::findAllJets(HepMC::GenEvent* e1 if (!(*iter)->end_vertex() && (*iter)->status() == 1) { auto p = (*iter)->momentum(); + auto pd = std::abs((*iter)->pdg_id()); + if (pd >= 12 && pd <= 18) + { + continue; // keep jet in the expected behavioro + } fastjet::PseudoJet pj(p.px(), p.py(), p.pz(), p.e()); pj.set_user_index((*iter)->barcode()); input.push_back(pj); @@ -115,6 +131,15 @@ std::vector HepMCJetTrigger::findAllJets(HepMC::GenEvent* e1 return output; } +/** + * @brief Counts jets that pass the eta and transverse momentum selection. + * + * Scans the provided jets, ignores those with absolute pseudorapidity greater than 1.1, + * and counts jets with transverse momentum greater than the configured threshold. + * + * @param jets Vector of candidate jets to evaluate. + * @return int Number of jets with |eta| ≤ 1.1 and pt greater than the trigger threshold. + */ int HepMCJetTrigger::jetsAboveThreshold(const std::vector& jets) const { // search through for the number of identified jets above the threshold @@ -122,10 +147,14 @@ int HepMCJetTrigger::jetsAboveThreshold(const std::vector& j for (const auto& j : jets) { float const pt = j.pt(); + if (std::abs(j.eta()) > 1.1) + { + continue; + } if (pt > this->threshold) { n_good_jets++; } } return n_good_jets; -} +} \ No newline at end of file diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc new file mode 100644 index 0000000000..512ff7fb01 --- /dev/null +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -0,0 +1,552 @@ +#include "HepMCParticleTrigger.h" + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +//____________________________________________________________________________.. +/** + * @brief Construct a HepMCParticleTrigger with configurable trigger and cut defaults. + * + * Initializes the trigger threshold, optional event-count limit, and default kinematic + * cut values and flags used to select particles (eta, absolute eta, pT, momentum, pz). + * + * @param trigger_thresh pT threshold used to enable and set the lower pT cut when nonzero. + * @param n_incom Goal number of good events to collect when event limiting is enabled. + * @param up_lim If true, stop processing after reaching the goal number of good events. + * @param name Module name passed to the SubsysReco base class. + */ +HepMCParticleTrigger::HepMCParticleTrigger(float trigger_thresh, int n_incom, bool up_lim, const std::string& name) + : SubsysReco(name) + , threshold(trigger_thresh) + , goal_event_number(n_incom) + , set_event_limit(up_lim) + , _theEtaHigh(1.1) + , _theEtaLow(-1.1) + , _thePtHigh(999.9) + , _thePtLow(0) + , _thePHigh(999.9) + , _thePLow(-999.9) + , _thePzHigh(999.9) + , _thePzLow(-999.9) + , + + _doEtaHighCut(true) + , _doEtaLowCut(true) + , _doBothEtaCut(true) + , + + _doAbsEtaHighCut(false) + , _doAbsEtaLowCut(false) + , _doBothAbsEtaCut(false) + , + + _doPtHighCut(false) + , _doPtLowCut(false) + , _doBothPtCut(false) + , + _doPHighCut(false) + , _doPLowCut(false) + , _doBothPCut(false) + , + + _doPzHighCut(false) + , _doPzLowCut(false) + , _doBothPzCut(false) +{ + if (threshold != 0) + { + _doPtLowCut = true; + _thePtLow = threshold; + } +} + +/** + * @brief Filter an input event using the configured HepMC particle trigger and update internal counters. + * + * Checks the PHHepMCGenEventMap on the provided node tree and verifies every contained HepMC::GenEvent + * against the configured trigger criteria. Increments the total event counter and, for events that pass, + * increments the accepted-event counter. Respects an optional configured limit on the number of accepted events. + * + * @param topNode Top-level node of the Fun4All/PHENIX node tree from which HepMC event data are retrieved. + * @return int `Fun4AllReturnCodes::EVENT_OK` if the event passed the trigger and was processed; `Fun4AllReturnCodes::ABORTEVENT` if processing should be aborted + * (no PHHepMCGenEventMap found, missing event data, the event failed the trigger, or the configured accepted-event limit has been reached). + */ +int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) +{ + // std::cout << "HepMCParticleTrigger::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; + n_evts++; + if (this->set_event_limit == true) + { // needed to keep all HepMC output at the same number of events + if (n_good >= this->goal_event_number) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + } + bool good_event{false}; + PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); + if (!phg) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + for (PHHepMCGenEventMap::ConstIter eventIter = phg->begin(); eventIter != phg->end(); ++eventIter) + { + PHHepMCGenEvent* hepev = eventIter->second; + if (!hepev) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + HepMC::GenEvent* ev = hepev->getEvent(); + if (!ev) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + good_event = isGoodEvent(ev); + if (!good_event) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + } + if (good_event) + { + n_good++; + } + return Fun4AllReturnCodes::EVENT_OK; +} +/** + * @brief Add a particle PDG identifier to the trigger list. + * + * @param particlePid PDG code of the particle to include when counting trigger particles. + */ +void HepMCParticleTrigger::AddParticle(int particlePid) +{ + _theParticles.push_back(particlePid); + return; +} +/** + * @brief Adds multiple particle PDG IDs to the trigger list. + * + * Appends each PDG identifier from the provided vector to the module's internal list of trigger particles. + * + * @param particles Vector of particle PDG IDs to add. + */ +void HepMCParticleTrigger::AddParticles(const std::vector& particles) +{ + for (auto p : particles) + { + _theParticles.push_back(p); + } + return; +} + +/** + * @brief Configure the upper transverse momentum (pT) cut. + * + * Sets the pT upper bound used when filtering particles and enables the high-pT cut. + * + * @param pt Upper pT threshold (same units as particle momentum, typically GeV/c). + * + * If a pT lower cut is already enabled, this call also enables the combined pT range check. + */ +void HepMCParticleTrigger::SetPtHigh(double pt) +{ + _thePtHigh = pt; + _doPtHighCut = true; + if (_doPtLowCut) + { + _doBothPtCut = true; + } + return; +} +/** + * @brief Set the lower transverse momentum (pT) threshold for the trigger and enable the pT low cut. + * + * Sets the lower pT bound used when selecting trigger particles and enables the pT-low filter. If a pT-high bound + * has already been enabled, also enable the combined pT-high-and-low mode. + * + * @param pt Lower pT threshold (same units used throughout the module, e.g., GeV/c). + */ +void HepMCParticleTrigger::SetPtLow(double pt) +{ + _thePtLow = pt; + _doPtLowCut = true; + if (_doPtHighCut) + { + _doBothPtCut = true; + } + return; +} +/** + * @brief Configure both upper and lower transverse momentum (pt) cuts. + * + * Enables the pt high and pt low selection and sets their thresholds. + * + * @param ptHigh Upper bound on transverse momentum (inclusive). + * @param ptLow Lower bound on transverse momentum (inclusive). + */ +void HepMCParticleTrigger::SetPtHighLow(double ptHigh, double ptLow) +{ + _thePtHigh = ptHigh; + _doPtHighCut = true; + _thePtLow = ptLow; + _doPtLowCut = true; + _doBothPtCut = true; + return; +} +/** + * @brief Set the upper bound for total momentum and enable the corresponding cut. + * + * Enables the momentum-high cut using the provided threshold. If a momentum-low cut + * is already enabled, marks that both high and low momentum cuts should be applied. + * + * @param pt Upper momentum threshold (total momentum) to apply as the high cut. + */ +void HepMCParticleTrigger::SetPHigh(double pt) +{ + _thePHigh = pt; + _doPHighCut = true; + if (_doPLowCut) + { + _doBothPCut = true; + } + return; +} +/** + * @brief Set the lower bound for the particle total momentum cut. + * + * Sets the low momentum threshold and enables the P-low cut. If a P-high cut + * is already enabled, also enable the combined P-high/P-low cut. + * + * @param pt Lower bound for the particle total momentum (P) to accept. + */ +void HepMCParticleTrigger::SetPLow(double pt) +{ + _thePLow = pt; + _doPLowCut = true; + if (_doPHighCut) + { + _doBothPCut = true; + } + return; +} +/** + * @brief Sets high and low thresholds for total momentum and enables momentum cuts. + * + * @param ptHigh Upper bound for the total momentum (p). + * @param ptLow Lower bound for the total momentum (p). + */ +void HepMCParticleTrigger::SetPHighLow(double ptHigh, double ptLow) +{ + _thePHigh = ptHigh; + _doPHighCut = true; + _thePLow = ptLow; + _doPLowCut = true; + _doBothPCut = true; + return; +} +/** + * @brief Set the upper bound for the longitudinal momentum (pz) cut. + * + * Sets the Pz high threshold to the given value and enables the Pz-high cut. + * If a Pz-low cut is already enabled, also enables the combined Pz high+low cut. + * + * @param pt Upper bound for particle pz to pass the Pz cut (same units as input momenta). + */ +void HepMCParticleTrigger::SetPzHigh(double pt) +{ + _thePzHigh = pt; + _doPzHighCut = true; + if (_doPzLowCut) + { + _doBothPzCut = true; + } + return; +} +/** + * @brief Set the lower bound for the longitudinal momentum (pz) cut and enable it. + * + * When a high-pz cut is already enabled, this also enables the combined pz-range cut. + * + * @param pt Lower pz threshold (inclusive). + */ +void HepMCParticleTrigger::SetPzLow(double pt) +{ + _thePzLow = pt; + _doPzLowCut = true; + if (_doPzHighCut) + { + _doBothPzCut = true; + } + return; +} +/** + * @brief Set upper and lower bounds for the longitudinal momentum (pz) cut. + * + * Enables the pz high and low cuts and configures the module to apply both bounds. + * + * @param ptHigh Upper bound for |pz| (high threshold). + * @param ptLow Lower bound for |pz| (low threshold). + */ +void HepMCParticleTrigger::SetPzHighLow(double ptHigh, double ptLow) +{ + _thePzHigh = ptHigh; + _doPzHighCut = true; + _thePzLow = ptLow; + _doPzLowCut = true; + _doBothPzCut = true; + return; +} +/** + * @brief Set the upper pseudorapidity (eta) cut and enable the corresponding cut flag. + * + * Enables the eta-high cut using the supplied upper bound and, if a eta-low cut is already active, + * marks that both eta high and low cuts are in effect. + * + * @param pt Upper bound for pseudorapidity (eta). + */ +void HepMCParticleTrigger::SetEtaHigh(double pt) +{ + _theEtaHigh = pt; + _doEtaHighCut = true; + if (_doEtaLowCut) + { + _doBothEtaCut = true; + } + return; +} +/** + * @brief Set the lower bound for eta and enable the corresponding cut. + * + * Enables the eta low cut and, if an eta high cut is already enabled, also enables the combined eta-range cut. + * + * @param pt Lower eta bound to apply (inclusive). + */ +void HepMCParticleTrigger::SetEtaLow(double pt) +{ + _theEtaLow = pt; + _doEtaLowCut = true; + if (_doEtaHighCut) + { + _doBothEtaCut = true; + } + return; +} +/** + * @brief Configure both upper and lower pseudorapidity (eta) bounds and enable their checks. + * + * Sets the eta upper bound to @p ptHigh and the eta lower bound to @p ptLow, and enables + * the corresponding high, low, and combined eta cut flags so particles will be tested + * against both limits. + * + * @param ptHigh Upper pseudorapidity bound (eta). + * @param ptLow Lower pseudorapidity bound (eta). + */ +void HepMCParticleTrigger::SetEtaHighLow(double ptHigh, double ptLow) +{ + _theEtaHigh = ptHigh; + _doEtaHighCut = true; + _theEtaLow = ptLow; + _doEtaLowCut = true; + _doBothEtaCut = true; + return; +} +/** + * @brief Set the upper bound for absolute pseudorapidity and enable the corresponding cut. + * + * Configures the absolute-eta high threshold to `pt` and activates the absolute-eta high cut. + * If an absolute-eta low cut is already active, also enables the combined absolute-eta range cut. + * + * @param pt Upper bound on |eta|. + */ +void HepMCParticleTrigger::SetAbsEtaHigh(double pt) +{ + _theEtaHigh = pt; + _doAbsEtaHighCut = true; + if (_doAbsEtaLowCut) + { + _doBothAbsEtaCut = true; + } + return; +} +/** + * @brief Configure the lower bound for absolute pseudorapidity and enable the corresponding cut. + * + * Sets the absolute-eta lower threshold and enables the absolute-eta-low cut; if an absolute-eta-high + * cut is already enabled, enables the combined absolute-eta high/low cut. + * + * @param pt Lower bound on absolute pseudorapidity (|eta|). + */ +void HepMCParticleTrigger::SetAbsEtaLow(double pt) +{ + _theEtaLow = pt; + _doAbsEtaLowCut = true; + if (_doAbsEtaHighCut) + { + _doBothAbsEtaCut = true; + } + return; +} +/** + * @brief Set absolute pseudorapidity bounds and enable the corresponding cuts. + * + * Sets the upper and lower limits for |eta| and activates both the absolute-eta + * high and low cuts. + * + * @param ptHigh Upper bound for absolute pseudorapidity (|eta|). + * @param ptLow Lower bound for absolute pseudorapidity (|eta|). + */ +void HepMCParticleTrigger::SetAbsEtaHighLow(double ptHigh, double ptLow) +{ + _theEtaHigh = ptHigh; + _doAbsEtaHighCut = true; + _theEtaLow = ptLow; + _doAbsEtaLowCut = true; + _doBothAbsEtaCut = true; + return; +} +/** + * @brief Determines whether the given HepMC event satisfies the configured trigger. + * + * Evaluates the event using the active kinematic and stability cuts and verifies that each + * configured trigger particle type is present at least once after those cuts. + * + * @param e1 HepMC event to evaluate. + * @return `true` if every configured trigger particle has a count greater than zero, `false` otherwise. + */ +bool HepMCParticleTrigger::isGoodEvent(HepMC::GenEvent* e1) +{ + // this is really just the call to actually evaluate and return the filter + /*if (this->threshold == 0) + { + return true; + }*/ + std::vector n_trigger_particles = getParticles(e1); + for (auto ntp : n_trigger_particles) + { + if (ntp <= 0) + { + return false; // make sure all particles have at least 1 + } + } + return true; +} + +/** + * @brief Count trigger particle occurrences in a HepMC event after applying configured cuts. + * + * Scans the provided GenEvent and counts particles that satisfy the module's configured + * stability and kinematic selection criteria (eta/|eta|, pt, momentum magnitude, pz). + * The returned vector contains the observed counts for each PDG id in the module's + * configured trigger list, preserving that order. + * + * @param e1 Pointer to the HepMC::GenEvent to inspect. + * @return std::vector Counts of matching particles for each configured trigger PDG id; + * `0` for a requested PDG id if no matching particles are found. + */ +std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) +{ + std::vector n_trigger{}; + std::map particle_types; + for (HepMC::GenEvent::particle_const_iterator iter = e1->particles_begin(); iter != e1->particles_end(); ++iter) + { + if (m_doStableParticleOnly && ((*iter)->end_vertex() || (*iter)->status() != 1)) + { + continue; + } + auto p = (*iter)->momentum(); + float px = p.px(); + float py = p.py(); + float pz = p.pz(); + float p_M = std::sqrt(std::pow(px, 2) + std::pow(py, 2) + std::pow(pz, 2)); + float pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); + int pid = std::abs((*iter)->pdg_id()); + double eta = p.eta(); + if ((_doEtaHighCut || _doBothEtaCut) && eta > _theEtaHigh) + { + continue; + } + if ((_doEtaLowCut || _doBothEtaCut) && eta < _theEtaLow) + { + continue; + } + if ((_doAbsEtaHighCut || _doBothAbsEtaCut) && std::abs(eta) > _theEtaHigh) + { + continue; + } + if ((_doAbsEtaLowCut || _doBothAbsEtaCut) && std::abs(eta) < _theEtaLow) + { + continue; + } + if ((_doPtHighCut || _doBothPtCut) && pt > _thePtHigh) + { + continue; + } + if ((_doPtLowCut || _doBothPtCut) && pt < _thePtLow) + { + continue; + } + if ((_doPHighCut || _doBothPCut) && p_M > _thePHigh) + { + continue; + } + if ((_doPLowCut || _doBothPCut) && p_M < _thePLow) + { + continue; + } + if ((_doPzHighCut || _doBothPzCut) && pz > _thePzHigh) + { + continue; + } + if ((_doPzLowCut || _doBothPzCut) && pz < _thePzLow) + { + continue; + } + if (particle_types.contains(pid)) + { + particle_types[pid]++; + } + else + { + particle_types[pid] = 1; + } + } + n_trigger.reserve(_theParticles.size()); + for (auto p : _theParticles) + { + n_trigger.push_back(particleAboveThreshold(particle_types, p)); // make sure we have at least one of each required particle + } + return n_trigger; +} +/** + * @brief Retrieve the observed count for a requested trigger particle PDG id. + * + * Looks up the absolute value of the provided `trigger_particle` in `n_particles` + * and returns the associated count of particles that passed the configured cuts. + * + * @param n_particles Map from absolute PDG id to observed count after cuts. + * @param trigger_particle PDG id to query; the sign is ignored (absolute value used). + * @return int Count for the requested particle PDG id if present, `0` otherwise. + */ +int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_particles, int trigger_particle) +{ + // search through for the number of identified trigger particles passing cuts + auto it = n_particles.find(std::abs(trigger_particle)); + if (it != n_particles.end()) + { + return it->second; + } + return 0; +} \ No newline at end of file diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h new file mode 100644 index 0000000000..64c086870a --- /dev/null +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -0,0 +1,137 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef HEPMCPARTICLETRIGGER_H +#define HEPMCPARTICLETRIGGER_H + +#include + +#include + +#include +#include +#include +#include + +class PHCompositeNode; +/** + * Representation of a generated event in the HepMC event record. + * + * Forward declaration of HepMC::GenEvent; include the HepMC event headers for the full definition and functionality. + */ +namespace HepMC +{ + class GenEvent; +} + +class HepMCParticleTrigger : public SubsysReco +{ + public: + HepMCParticleTrigger(float trigger_thresh = 10., int n_incom = 1000, bool up_lim = false, const std::string& name = "HepMCParticleTrigger"); + + ~HepMCParticleTrigger() override = default; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode* topNode) override; + + /// Clean up internals after each event. + + /// Called at the end of each run. + + /// Called at the end of all processing. + + /// Reset + void AddParticles(const std::vector&); //exclusively take input in the form of a pdg_ids (22 for photon, primary use case) + void AddParticle(int); + + /* void AddParents(const std::string &parents); + void AddParents(int parent); + void AddParents(std::vector parents); + void AddParentspID(std::vector parents); + */ + void SetPtHigh(double); + void SetPtLow(double); + void SetPtHighLow(double, double); + + void SetPHigh(double); + void SetPLow(double); + void SetPHighLow(double, double); + + void SetEtaHigh(double); + void SetEtaLow(double); + void SetEtaHighLow(double, double); + + void SetAbsEtaHigh(double); + void SetAbsEtaLow(double); + void SetAbsEtaHighLow(double, double); + + void SetPzHigh(double); + void SetPzLow(double); + void SetPzHighLow(double, double); + + /** + * Restrict selection to stable particles only when enabled. + * @param b `true` to enable filtering to stable particles only, `false` to include unstable particles. + */ +void SetStableParticleOnly(bool b) { m_doStableParticleOnly = b; } + + private: + bool isGoodEvent(HepMC::GenEvent* e1); + std::vector getParticles(HepMC::GenEvent* e1); + int particleAboveThreshold(const std::map& n_particles, int particle); + // std::vector _theParentsi {}; + std::vector _theParticles{}; + bool m_doStableParticleOnly{true}; + float threshold{0.}; + int goal_event_number{1000}; + /** + * @brief Number of events processed by this module. + * + * Incremented for each call to process_event to track how many events have been examined. + */ +int n_evts{0}; + /** + * Number of events classified as "good" by the trigger. + * + * Incremented for each event that passes the configured particle-type and kinematic cuts. + */ +int n_good{0}; + bool set_event_limit{false}; + + float _theEtaHigh{1.1}; + float _theEtaLow{-1.1}; + float _thePtHigh{999.9}; + float _thePtLow{-999.9}; + float _thePHigh{999.9}; + float _thePLow{-999.9}; + float _thePzHigh{999.9}; + float _thePzLow{-999.9}; + + bool _doEtaHighCut{true}; + bool _doEtaLowCut{true}; + bool _doBothEtaCut{true}; + + bool _doAbsEtaHighCut{false}; + bool _doAbsEtaLowCut{false}; + bool _doBothAbsEtaCut{false}; + + bool _doPtHighCut{false}; + bool _doPtLowCut{false}; + bool _doBothPtCut{false}; + + bool _doPHighCut{false}; + bool _doPLowCut{false}; + bool _doBothPCut{false}; + + bool _doPzHighCut{false}; + bool _doPzLowCut{false}; + /** + * Enable applying both Pz high and low cuts. + * + * When true, particles are required to satisfy both the configured Pz high and Pz low thresholds. + */ +bool _doBothPzCut{false}; +}; + +#endif // HEPMCPARTICLETRIGGER_H \ No newline at end of file diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 9aa14d4684..a502b16fc2 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -33,6 +33,20 @@ #include #include // for operator<<, endl +/** + * @brief Construct a PHPythia8 generator instance and configure HepMC conversion. + * + * Initializes the Pythia8 engine using the path from the environment variable + * `PYTHIA8`, configures a HepMC::Pythia8ToHepMC converter to store process, + * PDF, and cross-section information, and sets the default embedding ID to 1. + * The constructor preserves and restores std::cout formatting around Pythia8 + * construction to avoid altering global stream state. + * + * If `PYTHIA8` is not set, an error message is printed and the Pythia8 instance + * remains uninitialized. + * + * @param name Name forwarded to the SubsysReco base class (module instance name). + */ PHPythia8::PHPythia8(const std::string &name) : SubsysReco(name) { @@ -45,8 +59,12 @@ PHPythia8::PHPythia8(const std::string &name) std::string thePath(charPath); thePath += "/xmldoc/"; + // the pythia8 ctor messes with the formatting, so we save the cout state here + // and restore it later + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); m_Pythia8.reset(new Pythia8::Pythia(thePath)); - + std::cout.copyfmt(old_state); m_Pythia8ToHepMC.reset(new HepMC::Pythia8ToHepMC()); m_Pythia8ToHepMC->set_store_proc(true); m_Pythia8ToHepMC->set_store_pdf(true); @@ -55,6 +73,18 @@ PHPythia8::PHPythia8(const std::string &name) PHHepMCGenHelper::set_embedding_id(1); // default embedding ID to 1 } +/** + * @brief Initialize the Pythia8 generator, configure nodes, and seed the RNG. + * + * Performs module initialization: reads an optional configuration file and any + * queued Pythia command strings, creates the required node tree under the + * provided top-level node, sets Pythia's random seed (mapped from PHRandomSeed + * into Pythia's valid range) and prints it for reproducibility, then calls + * Pythia8::init(). + * + * @param topNode Top-level PHCompositeNode under which generator nodes are created. + * @return int Fun4All return code; returns Fun4AllReturnCodes::EVENT_OK on success. + */ int PHPythia8::Init(PHCompositeNode *topNode) { if (!m_ConfigFileName.empty()) @@ -92,8 +122,15 @@ int PHPythia8::Init(PHCompositeNode *topNode) // print out seed so we can make this is reproducible std::cout << "PHPythia8 random seed: " << seed << std::endl; + +// pythia again messes with the cout formatting + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); // save current state + m_Pythia8->init(); + std::cout.copyfmt(old_state); // restore state to saved state + return Fun4AllReturnCodes::EVENT_OK; } @@ -160,6 +197,17 @@ void PHPythia8::print_config() const m_Pythia8->info.list(); } +/** + * @brief Generate a Pythia8 event that satisfies the configured triggers, convert it to HepMC, insert it into the PH node tree, and update run statistics. + * + * This function repeatedly generates Pythia8 events until the registered trigger logic (OR/AND semantics) is satisfied, + * then converts the accepted Pythia8 event into a HepMC::GenEvent, optionally appends the generator event weight, + * inserts the HepMC event into the PH node tree via PHHepMCGenHelper, increments the internal event counter, + * and updates the PHGenIntegral statistics (accepted event count, processed event count, sum of weights, and integrated luminosity) + * when the integral node is present. + * + * @return Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTRUN if insertion of the HepMC event into the PH node tree fails. + */ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) { if (Verbosity() >= VERBOSITY_MORE) @@ -170,6 +218,9 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) bool passedGen = false; bool passedTrigger = false; // int genCounter = 0; +// pythia again messes with the cout formatting in its event loop + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); // save current state while (!passedTrigger) { @@ -245,6 +296,7 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) if (!success) { std::cout << "PHPythia8::process_event - Failed to add event to HepMC record!" << std::endl; + std::cout.copyfmt(old_state); // restore state to saved state return Fun4AllReturnCodes::ABORTRUN; } @@ -265,6 +317,8 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) ++m_EventCount; + std::cout.copyfmt(old_state); // restore state to saved state + // save statistics if (m_IntegralNode) { @@ -321,4 +375,4 @@ void PHPythia8::register_trigger(PHPy8GenTrigger *theTrigger) std::cout << "PHPythia8::registerTrigger - trigger " << theTrigger->GetName() << " registered" << std::endl; } m_RegisteredTriggers.push_back(theTrigger); -} +} \ No newline at end of file diff --git a/generators/phhepmc/PHHepMCGenEventv1.cc b/generators/phhepmc/PHHepMCGenEventv1.cc index bc8eef6f41..9a239c7a2d 100644 --- a/generators/phhepmc/PHHepMCGenEventv1.cc +++ b/generators/phhepmc/PHHepMCGenEventv1.cc @@ -9,6 +9,7 @@ #include #include // for cout +#include #include // for map #include #include // for swap @@ -101,6 +102,15 @@ CLHEP::HepLorentzRotation PHHepMCGenEventv1::get_LorentzRotation_Lab2EvtGen() co return get_LorentzRotation_EvtGen2Lab().inverse(); } +/** + * @brief Retrieve the reaction-plane angle for a given harmonic. + * + * @param n Harmonic number for which to obtain the reaction-plane angle psi_n. + * @return float The psi_n angle in radians if found, `NaN` otherwise. + * + * If the requested harmonic is not present in the stored map, the function + * writes a warning to stdout and returns quiet `NaN`. + */ float PHHepMCGenEventv1::get_flow_psi(unsigned int n) const { auto it = m_psi_n.find(n); @@ -109,6 +119,6 @@ float PHHepMCGenEventv1::get_flow_psi(unsigned int n) const return it->second; } - std::cout << "PHHepMCGenEventv1::get_flow_psi - Warning - requested reaction plane angle psi_n for n=" << n << " does not exist. Returning 0.0" << std::endl; - return 0.0F; -} + std::cout << "PHHepMCGenEventv1::get_flow_psi - Warning - requested reaction plane angle psi_n for n=" << n << " does not exist. Returning NAN" << std::endl; + return std::numeric_limits::quiet_NaN(); +} \ No newline at end of file diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 2451672807..af9842a5b4 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -142,6 +142,21 @@ int CaloValid::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Process calorimeter towers and related detector data for a single event. + * + * Decodes trigger information, accumulates per-detector energies, processes calibrated + * and raw tower data for CEMC, HCALIN, and HCALOUT, fills QA and correlation histograms, + * analyzes MBD PMTs, and performs cluster-based pi0 reconstruction and trigger-alignment + * bookkeeping (leading-cluster, per-trigger profiles). Uses nodes from the supplied + * PHCompositeNode tree to read event header, vertex, GL1 packet, tower containers, + * MBD PMTs, and cluster/geometry containers. + * + * @param topNode Root node of the Fun4All/PHENIX node tree from which required + * detector and event data are retrieved. + * @return int Fun4AllReturnCodes::EVENT_OK on successful processing; returns 0 if the + * CEMC cluster container is missing (fatal condition encountered in this routine). + */ int CaloValid::process_towers(PHCompositeNode* topNode) { //---------------------------Event header--------------------------------// @@ -335,13 +350,16 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - totalcemc += offlineenergy; + if (isGood) + { + totalcemc += offlineenergy; + } h_emcaltime->Fill(_timef); if (offlineenergy > emcal_hit_threshold) { h_cemc_etaphi_time->Fill(ieta, iphi, _timef); h_cemc_etaphi->Fill(ieta, iphi); - if (isGood && (scaledBits[10] || scaledBits[11])) + if (isGood && (scaledBits[10] || scaledBits[12])) { h_cemc_etaphi_wQA->Fill(ieta, iphi, offlineenergy); } @@ -407,14 +425,17 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - totalihcal += offlineenergy; + if (isGood) + { + totalihcal += offlineenergy; + } h_ihcaltime->Fill(_timef); if (offlineenergy > ihcal_hit_threshold) { h_ihcal_etaphi->Fill(ieta, iphi); h_ihcal_etaphi_time->Fill(ieta, iphi, _timef); - if (isGood && (scaledBits[10] || scaledBits[11])) + if (isGood && (scaledBits[10] || scaledBits[12])) { h_ihcal_etaphi_wQA->Fill(ieta, iphi, offlineenergy); } @@ -472,14 +493,17 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - totalohcal += offlineenergy; + if (isGood) + { + totalohcal += offlineenergy; + } h_ohcaltime->Fill(_timef); if (offlineenergy > ohcal_hit_threshold) { h_ohcal_etaphi_time->Fill(ieta, iphi, _timef); h_ohcal_etaphi->Fill(ieta, iphi); - if (isGood && (scaledBits[10] || scaledBits[11])) + if (isGood && (scaledBits[10] || scaledBits[12])) { h_ohcal_etaphi_wQA->Fill(ieta, iphi, offlineenergy); } @@ -1292,4 +1316,4 @@ void CaloValid::createHistos() } hm->registerHisto(h_triggerVec); hm->registerHisto(pr_ldClus_trig); -} +} \ No newline at end of file diff --git a/offline/QA/Tracking/MicromegasClusterQA.cc b/offline/QA/Tracking/MicromegasClusterQA.cc index 41efeffaa7..db61aac9e0 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.cc +++ b/offline/QA/Tracking/MicromegasClusterQA.cc @@ -61,7 +61,12 @@ MicromegasClusterQA::MicromegasClusterQA(const std::string& name) { } -//____________________________________________________________________________.. +/** + * @brief Initialize Micromegas cluster QA: load calibrations, read geometry to determine detectors, and create QA histograms. + * + * @param topNode Framework top-level node providing access to geometry and calibration data. + * @return int Fun4AllReturnCodes::EVENT_OK on successful initialization. + */ int MicromegasClusterQA::InitRun(PHCompositeNode* topNode) { // print configuration @@ -73,6 +78,9 @@ int MicromegasClusterQA::InitRun(PHCompositeNode* topNode) << (m_calibration_filename.empty() ? "unspecified" : m_calibration_filename) << std::endl; + std::cout << "MicromegasClusterQA::InitRun - m_sample_min: " << m_sample_min << std::endl; + std::cout << "MicromegasClusterQA::InitRun - m_sample_max: " << m_sample_max << std::endl; + // read calibrations if (!m_calibration_filename.empty()) { @@ -115,7 +123,16 @@ int MicromegasClusterQA::InitRun(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. +/** + * Process a single event: analyze Micromegas clusters and fill QA histograms for cluster size, charge, + * per-detector multiplicity, and reference/found cluster counts. + * + * Clusters are skipped if none of their associated hits have a sample within [m_sample_min, m_sample_max). + * Cluster charge is computed as the sum of (ADC - pedestal) over associated hits; clusters with charge > 200 + * are counted as "good" for reference/found statistics. + * + * @return Fun4AllReturnCodes::EVENT_OK on success. + */ int MicromegasClusterQA::process_event(PHCompositeNode* topNode) { // acts geometry @@ -162,6 +179,13 @@ int MicromegasClusterQA::process_event(PHCompositeNode* topNode) // find associated hits const auto hit_range = m_cluster_hit_map->getHits(ckey); + // check hit samples + // if none of the associated hits' sample is within acceptable range, skip the cluster + if( std::none_of( hit_range.first, hit_range.second, + [this]( const TrkrClusterHitAssoc::Map::value_type& pair ) + { return MicromegasDefs::getSample( pair.second ) >= m_sample_min && MicromegasDefs::getSample( pair.second ) < m_sample_max; } ) ) + { continue; } + // store cluster size and fill cluster size histogram const int cluster_size = std::distance(hit_range.first, hit_range.second); m_h_cluster_size->Fill(detid, cluster_size); @@ -269,4 +293,4 @@ void MicromegasClusterQA::create_histograms() } return; -} +} \ No newline at end of file diff --git a/offline/QA/Tracking/MicromegasClusterQA.h b/offline/QA/Tracking/MicromegasClusterQA.h index 338e5302de..7df05a5820 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.h +++ b/offline/QA/Tracking/MicromegasClusterQA.h @@ -23,6 +23,39 @@ class TH2; class PHCompositeNode; +/** + * Set the default pedestal value used for hit charge calculation when calibration data is not used. + * @param value Default pedestal value in ADC units. + */ + +/** + * Enable or disable use of the default pedestal instead of per-channel calibration data. + * @param value `true` to use the default pedestal, `false` to use calibration data when available. + */ + +/** + * Set the path to the Micromegas calibration file to be loaded for per-channel pedestal and gain. + * @param value Filesystem path or identifier of the calibration file. + */ + +/** + * Set the minimum sample index (inclusive) to consider when integrating signal for a hit. + * @param value Minimum sample index for signal integration. + */ + +/** + * Set the maximum sample index (inclusive) to consider when integrating signal for a hit. + * @param value Maximum sample index for signal integration. + */ + +/** + * Create and initialize all QA histograms used by this module. + */ + +/** + * Get the prefix used for histogram names produced by this module. + * @returns Prefix string for histogram naming. + */ class MicromegasClusterQA : public SubsysReco { public: @@ -51,6 +84,13 @@ class MicromegasClusterQA : public SubsysReco m_calibration_filename = value; } + /// set min sample for signal hits + void set_sample_min(uint16_t value) { m_sample_min = value; } + + /// set max sample for signal hits + void set_sample_max(uint16_t value) { m_sample_max = value; } + + private: void create_histograms(); @@ -98,6 +138,12 @@ class MicromegasClusterQA : public SubsysReco /// keep track of detector names std::vector m_detector_names; + /// min sample for signal + uint16_t m_sample_min = 0; + + /// max sample for signal + uint16_t m_sample_max = 1024; + ///@name calibration filename //@{ @@ -116,4 +162,4 @@ class MicromegasClusterQA : public SubsysReco //@} }; -#endif // MicromegasClusterQA_H +#endif // MicromegasClusterQA_H \ No newline at end of file diff --git a/offline/QA/Tracking/StateClusterResidualsQA.cc b/offline/QA/Tracking/StateClusterResidualsQA.cc new file mode 100644 index 0000000000..1dd4423369 --- /dev/null +++ b/offline/QA/Tracking/StateClusterResidualsQA.cc @@ -0,0 +1,318 @@ +#include "StateClusterResidualsQA.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace +{ + template + /** + * @brief Compute the square of a value. + * + * @tparam T Type that supports multiplication. + * @param t Value to be squared. + * @return T The value multiplied by itself. + */ +inline T square (T const& t) { return t * t; } + + template + class range_adaptor + { + public: + /** + * @brief Construct a range adaptor from a pair of iterators. + * + * Stores the provided begin and end iterators so the adaptor can expose a + * range-compatible interface via begin() and end(). + * + * @param begin Iterator pointing to the start of the range. + * @param end Iterator pointing one past the end of the range. + */ + explicit range_adaptor( + T const& begin, + T const& end) + : m_begin(begin) + , m_end(end) + { + } + /** + * @brief Access the range's beginning iterator. + * + * @return const reference to the stored begin iterator. + */ +T const& begin() { return m_begin; } + /** + * @brief Returns the stored end iterator of the range adaptor. + * + * @return T const& Const reference to the stored end iterator. + */ +T const& end() { return m_end; } + + private: + T m_begin; + T m_end; + }; +} /** + * @brief Construct a StateClusterResidualsQA module with the given instance name. + * + * @param name Identifier used to register the SubsysReco module and label produced QA objects. + */ + +StateClusterResidualsQA::StateClusterResidualsQA(const std::string& name) + : SubsysReco(name) +{ +} + +/** + * @brief Initialize run: create histograms and retrieve required nodes and histograms. + * + * Retrieves SvtxTrackMap, TrkrClusterContainer, ActsGeometry, and the QA histogram + * manager from the provided top-level node. If any of these cannot be found the + * run is aborted. On success, internal vectors of histogram pointers are populated + * for each pending configuration. + * + * @param top_node Top-level node of the event/data tree. + * @return int Fun4All return code: `EVENT_OK` on success; `ABORTRUN` if a required + * node (track map, cluster container, ActsGeometry) or the QA histogram + * manager cannot be found. + */ +int StateClusterResidualsQA::InitRun( + PHCompositeNode* top_node) +{ + createHistos(); + + // F4A will not actually ABORTRUN unless that return code is issued here + auto* track_map = findNode::getClass(top_node, m_track_map_node_name); + if (!track_map) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get track map:\n" + << "\t\"" << m_track_map_node_name << "\"\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + auto* cluster_map = findNode::getClass(top_node, m_clusterContainerName); + if (!cluster_map) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get cluster map:\n" + << "\t\"" << m_clusterContainerName << "\"\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + auto *geometry = findNode::getClass(top_node, "ActsGeometry"); + if (!geometry) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get ActsGeometry:\n" + << "\t\"" << "ActsGeometry" << "\"\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + auto* hm = QAHistManagerDef::getHistoManager(); + if (!hm) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get QAHistManager\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + for (const auto& cfg : m_pending) + { + m_histograms_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_x")))); + m_histograms_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_y")))); + m_histograms_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_z")))); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +/** + * @brief Processes a single event and fills per-configuration residual histograms between track states and clusters. + * + * For each track, counts clusters per detector subsystem, applies each pending configuration's selection + * (charge sign, per-subsystem cluster-count ranges, phi/eta/pt ranges), and for configurations that pass + * fills the X, Y, and Z histograms with the difference (state position - cluster global position) for every + * state associated with a cluster. + * + * @param top_node Top-level event node used to retrieve the SvtxTrackMap, TrkrClusterContainer, and ActsGeometry. + * @return int EVENT_OK on success. + */ +int StateClusterResidualsQA::process_event(PHCompositeNode* top_node) +{ + auto* track_map = findNode::getClass(top_node, m_track_map_node_name); + auto *cluster_map = findNode::getClass(top_node, m_clusterContainerName); + auto *geometry = findNode::getClass(top_node, "ActsGeometry"); + + for (auto const& [idkey, track] : *track_map) + { + if (!track) + { + continue; + } + + // count states + std::map counters = { + {TrkrDefs::mvtxId, 0}, + {TrkrDefs::inttId, 0}, + {TrkrDefs::tpcId, 0}, + {TrkrDefs::micromegasId, 0}, + }; + + for (auto const& [path_length, state] : range_adaptor(track->begin_states(), track->end_states())) + { + // There is an additional state representing the vertex at the beginning of the map, + // but getTrkrId will return 0 for its corresponding cluster + // Identify it as having path_length identically equal to 0 + if (path_length == 0) { continue; } + + auto trkr_id = static_cast(TrkrDefs::getTrkrId(state->get_cluskey())); + auto itr = counters.find(trkr_id); + if (itr == counters.end()) { continue; } + ++itr->second; + } + + float track_eta = track->get_eta(); + float track_phi = track->get_phi(); + float track_pt = track->get_pt(); + int h = 0; + for (const auto& cfg : m_pending) + { + if (cfg.charge != 0) + { + if ((cfg.charge < 0) && track->get_positive_charge()) + { + continue; + } + if ((cfg.charge > 0) && !(track->get_positive_charge())) + { + continue; + } + } + if (cfg.min_mvtx_clusters <= counters[TrkrDefs::mvtxId] && cfg.max_mvtx_clusters >= counters[TrkrDefs::mvtxId] + && cfg.min_intt_clusters <= counters[TrkrDefs::inttId] && cfg.max_intt_clusters >= counters[TrkrDefs::inttId] + && cfg.min_tpc_clusters <= counters[TrkrDefs::tpcId] && cfg.max_tpc_clusters >= counters[TrkrDefs::tpcId] + && cfg.phi_min <= track_phi && cfg.phi_max >= track_phi + && cfg.eta_min <= track_eta && cfg.eta_max >= track_eta + && cfg.pt_min <= track_pt && cfg.pt_max >= track_pt) + { + for (auto const& [path_length, state] : range_adaptor(track->begin_states(), track->end_states())) + { + if (path_length == 0) { continue; } + + auto *cluster = cluster_map->findCluster(state->get_cluskey()); + float state_x = state->get_x(); + float state_y = state->get_y(); + float state_z = state->get_z(); + Acts::Vector3 glob = geometry->getGlobalPosition(state->get_cluskey(), cluster); + float cluster_x = glob.x(); + float cluster_y = glob.y(); + float cluster_z = glob.z(); + if (cluster) + { + m_histograms_x[h]->Fill(state_x - cluster_x); + m_histograms_y[h]->Fill(state_y - cluster_y); + m_histograms_z[h]->Fill(state_z - cluster_z); + } + } + } + ++h; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +/** + * @brief Create and register per-configuration histograms for state–cluster residuals. + * + * For each configuration in m_pending, creates three TH1F histograms named + * "_x", "_y", and "_z" for the X, Y, and Z + * residuals respectively. Each histogram uses m_nBins and the corresponding + * axis range (m_xrange, m_yrange, m_zrange), is labeled with "State-Cluster + * Residual [cm]" on the x-axis and "Entries" on the y-axis, is styled + * with blue marker and line colors, and is registered with the QA histogram + * manager. + */ +void StateClusterResidualsQA::createHistos() +{ + auto *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + for (const auto& cfg : m_pending) + { + TH1F* h_new_x = new TH1F( + (cfg.name + "_x").c_str(), + ";State-Cluster X Residual [cm];Entries", + m_nBins, m_xrange.first, m_xrange.second); + h_new_x->SetMarkerColor(kBlue); + h_new_x->SetLineColor(kBlue); + hm->registerHisto(h_new_x); + TH1F* h_new_y = new TH1F( + (cfg.name + "_y").c_str(), + ";State-Cluster Y Residual [cm];Entries", + m_nBins, m_yrange.first, m_yrange.second); + h_new_y->SetMarkerColor(kBlue); + h_new_y->SetLineColor(kBlue); + hm->registerHisto(h_new_y); + TH1F* h_new_z = new TH1F( + (cfg.name + "_z").c_str(), + ";State-Cluster Z Residual [cm];Entries", + m_nBins, m_zrange.first, m_zrange.second); + h_new_z->SetMarkerColor(kBlue); + h_new_z->SetLineColor(kBlue); + hm->registerHisto(h_new_z); + } +} + +/** + * @brief Finalize the module at the end of a run. + * + * Ensures the QA histogram manager is available and performs any finalization + * steps required by this QA module. + * + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ +int StateClusterResidualsQA::EndRun(const int /*unused*/) +{ + auto *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + return Fun4AllReturnCodes::EVENT_OK; +} \ No newline at end of file diff --git a/offline/QA/Tracking/StateClusterResidualsQA.h b/offline/QA/Tracking/StateClusterResidualsQA.h new file mode 100644 index 0000000000..bfbbd9c53d --- /dev/null +++ b/offline/QA/Tracking/StateClusterResidualsQA.h @@ -0,0 +1,130 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef STATECLUSTERRESIDUALSQA_H +#define STATECLUSTERRESIDUALSQA_H + +#include + +#include +#include +#include +#include +#include + +class PHCompositeNode; +class TH1; + +struct ResidualHistConfig +{ + std::string name = "h_StateClusterResidualsQA_"; + std::string title = ";Residual [cm];Entries"; + + int min_mvtx_clusters = 0; + int max_mvtx_clusters = 3; + int min_intt_clusters = 0; + int max_intt_clusters = 4; + int min_tpc_clusters = 0; + int max_tpc_clusters = 48; + + float phi_min = -M_PI; + float phi_max = M_PI; + float eta_min = -1.1; + float eta_max = 1.1; + + float pt_min = 0.0; + float pt_max = FLT_MAX; + + int charge = 0; +}; + +class StateClusterResidualsQA : public SubsysReco +{ + public: + StateClusterResidualsQA(const std::string& name = "StateClusterResidualsQA"); + ~StateClusterResidualsQA() override = default; + + /** + * Set the node name used to retrieve the track map. + * @param track_map_node_name Name of the node containing the track map (default: "SvtxTrackMap"). + */ + void set_track_map_name(std::string const& track_map_node_name) { m_track_map_node_name = track_map_node_name; } + + StateClusterResidualsQA& addHistogram(const std::string& name) + { + ResidualHistConfig cfg; + cfg.name += name; + m_pending.push_back(cfg); + return *this; + } + StateClusterResidualsQA& setNMvtx(int min, int max) + { + m_pending.back().min_mvtx_clusters = min; + m_pending.back().max_mvtx_clusters = max; + return *this; + } + StateClusterResidualsQA& setNIntt(int min, int max) + { + m_pending.back().min_intt_clusters = min; + m_pending.back().max_intt_clusters = max; + return *this; + } + StateClusterResidualsQA& setNTpc(int min, int max) + { + m_pending.back().min_tpc_clusters = min; + m_pending.back().max_tpc_clusters = max; + return *this; + } + StateClusterResidualsQA& setPhiRange(float min, float max) + { + m_pending.back().phi_min = min; + m_pending.back().phi_max = max; + return *this; + } + StateClusterResidualsQA& setEtaRange(float min, float max) + { + m_pending.back().eta_min = min; + m_pending.back().eta_max = max; + return *this; + } + StateClusterResidualsQA& setPtRange(float min, float max) + { + m_pending.back().pt_min = min; + m_pending.back().pt_max = max; + return *this; + } + StateClusterResidualsQA& setPositiveTracks() + { + m_pending.back().charge = 1; + return *this; + } + StateClusterResidualsQA& setNegativeTracks() + { + m_pending.back().charge = -1; + return *this; + } + + void createHistos(); + + int InitRun(PHCompositeNode*) override; + + int process_event(PHCompositeNode*) override; + + int EndRun(const int runnumber) override; + + private: + std::vector m_pending; + + std::string m_track_map_node_name = "SvtxTrackMap"; + std::string m_clusterContainerName = "TRKR_CLUSTER"; + + int m_nBins = 50; + std::pair m_xrange {-0.5,0.5}; + std::pair m_yrange {-0.5,0.5}; + std::pair m_zrange {-0.5,0.5}; + + std::vector m_histograms_x{}; + std::vector m_histograms_y{}; + std::vector m_histograms_z{}; +}; + +#endif // TRACKFITTINGQA_H \ No newline at end of file diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index 2b4feef203..fe3a67f345 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -120,6 +120,19 @@ void CDBInterface::Print(const std::string & /* what */) const } } +/** + * @brief Retrieve a calibration or data URL for a given domain, using configured global tag and timestamp. + * + * Queries the CDB for the URL associated with the specified domain and the TIMESTAMP/CDB_GLOBALTAG flags from recoConsts. + * If the interface is disabled, returns an empty string immediately. If no URL is found and disabling of defaults is not enabled, + * the function will retry using the domain suffixed with "_default" and, if still not found, fall back to the provided filename. + * When a non-empty URL is obtained, the (domain, url, timestamp) tuple is recorded in the instance URL cache. + * If required flags are missing, the process terminates via gSystem->Exit(1). + * + * @param domain Domain name to query in the CDB. + * @param filename Local filename to use as a fallback when no CDB URL is found and defaults are allowed. + * @return std::string The resolved URL if found, the provided filename when used as fallback, or an empty string if disabled or no URL and defaults are disabled. + */ std::string CDBInterface::getUrl(const std::string &domain, const std::string &filename) { if (disable) @@ -185,11 +198,14 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f std::cout << "... reply: " << return_url << std::endl; } } - auto pret = m_UrlVector.insert(make_tuple(domain_noconst, return_url, timestamp)); - if (!pret.second && Verbosity() > 1) + if (! return_url.empty()) { - std::cout << PHWHERE << "not adding again " << domain_noconst << ", url: " << return_url - << ", time stamp: " << timestamp << std::endl; + auto pret = m_UrlVector.insert(make_tuple(domain_noconst, return_url, timestamp)); + if (!pret.second && Verbosity() > 1) + { + std::cout << PHWHERE << "not adding again " << domain_noconst << ", url: " << return_url + << ", time stamp: " << timestamp << std::endl; + } } return return_url; -} +} \ No newline at end of file diff --git a/offline/framework/ffamodules/FlagHandler.h b/offline/framework/ffamodules/FlagHandler.h index f5cc06bcdb..90002848d2 100644 --- a/offline/framework/ffamodules/FlagHandler.h +++ b/offline/framework/ffamodules/FlagHandler.h @@ -7,14 +7,38 @@ #include -class PHCompositeNode; - +/** + * Construct a FlagHandler module with an optional name. + * @param name Human-readable name for the module instance. + */ +/** + * Destroy the FlagHandler module. + */ +/** + * Ensure the Flag node exists; if it does, read flags and copy them into reconstruction constants. + * @param topNode Root node of the framework node tree to create or read the Flag node from. + * @returns 0 on success, non-zero on error. + */ +/** + * Perform end-of-processing cleanup for the module. + * @param topNode Root node of the framework node tree. + * @returns 0 on success, non-zero on error. + */ +/** + * Print information about the module. + * @param what Selector for which information to print (defaults to "ALL"). + */ +/** + * Update or create run-level nodes related to flags during processing. + * @param topNode Root node of the framework node tree to update. + * @returns 0 on success, non-zero on error. + */ class FlagHandler : public SubsysReco { public: FlagHandler(const std::string &name = "FlagHandler"); - ~FlagHandler() override {} + ~FlagHandler() override = default; /** Create the Flag Node if it does not exist, if it exists, read back flags and copy them into recoConsts @@ -31,4 +55,4 @@ class FlagHandler : public SubsysReco private: }; -#endif // FFAMODULES_FLAGHANDLER_H +#endif // FFAMODULES_FLAGHANDLER_H \ No newline at end of file diff --git a/offline/framework/ffamodules/HeadReco.cc b/offline/framework/ffamodules/HeadReco.cc index 75e879fdff..378792f9a4 100644 --- a/offline/framework/ffamodules/HeadReco.cc +++ b/offline/framework/ffamodules/HeadReco.cc @@ -61,6 +61,19 @@ int HeadReco::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Populates EventHeader with event-level metadata from the node tree. + * + * Populates the EventHeader node using heavy-ion information from the foreground + * PHHepMCGenEvent (if present) — including impact parameter, event plane angle, + * flow psi values (when available), eccentricity, Ncoll, and Npart — or falls + * back to the PRDF Event's event type when no generator map is present. Also + * sets the run number and event sequence from the Fun4AllServer and invokes + * identify() when verbosity is enabled. + * + * @param topNode Top-level node of the current event's node tree. + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ int HeadReco::process_event(PHCompositeNode *topNode) { Fun4AllServer *se = Fun4AllServer::instance(); @@ -84,10 +97,13 @@ int HeadReco::process_event(PHCompositeNode *topNode) { evtheader->set_ImpactParameter(hi->impact_parameter()); evtheader->set_EventPlaneAngle(hi->event_plane_angle()); - for (unsigned int n = 1; n <= 6; ++n) - { - evtheader->set_FlowPsiN(n, genevt->get_flow_psi(n)); - } + if (! genevt->get_flow_psi_map().empty()) + { + for (unsigned int n = 1; n <= 6; ++n) + { + evtheader->set_FlowPsiN(n, genevt->get_flow_psi(n)); + } + } evtheader->set_eccentricity(hi->eccentricity()); evtheader->set_ncoll(hi->Ncoll()); evtheader->set_npart(hi->Npart_targ() + hi->Npart_proj()); @@ -112,4 +128,4 @@ int HeadReco::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/framework/ffamodules/HeadReco.h b/offline/framework/ffamodules/HeadReco.h index ca2f6cf34e..9920b9d531 100644 --- a/offline/framework/ffamodules/HeadReco.h +++ b/offline/framework/ffamodules/HeadReco.h @@ -7,13 +7,37 @@ #include // for string -class PHCompositeNode; +/** + * Reconstruction module for the Head detector that integrates with the SubsysReco framework. + */ +/** + * Create a HeadReco module with an optional instance name. + * @param name Instance name for this module (defaults to "HeadReco"). + */ + +/** + * Initialize module resources before event processing. + * @param topNode Root node of the framework's node tree. + * @returns 0 on success, non-zero on error. + */ + +/** + * Perform per-run initialization at the start of a run. + * @param topNode Root node of the framework's node tree. + * @returns 0 on success, non-zero on error. + */ + +/** + * Process a single event. + * @param topNode Root node of the framework's node tree. + * @returns 0 on success, non-zero on error. + */ class HeadReco : public SubsysReco { public: HeadReco(const std::string &name = "HeadReco"); - ~HeadReco() override {} + ~HeadReco() override = default; int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -21,4 +45,4 @@ class HeadReco : public SubsysReco protected: }; -#endif +#endif \ No newline at end of file diff --git a/offline/framework/ffamodules/SyncReco.h b/offline/framework/ffamodules/SyncReco.h index 0a490302a0..0ef8df706e 100644 --- a/offline/framework/ffamodules/SyncReco.h +++ b/offline/framework/ffamodules/SyncReco.h @@ -5,13 +5,54 @@ #include -class PHCompositeNode; +/** + * SyncReco subsystem reconstruction component responsible for synchronizing + * event segmentation and providing lifecycle hooks for initialization and event processing. + */ +/** + * Construct a SyncReco instance. + * @param name Human-readable name for the instance (defaults to "SYNC"). + */ + +/** + * Initialize module-level resources and create required nodes under @p topNode. + * @param topNode Top-level node of the framework node tree. + * @returns Status code: 0 on success, non-zero on error. + */ + +/** + * Prepare run-dependent resources before event processing begins. + * @param topNode Top-level node of the framework node tree. + * @returns Status code: 0 on success, non-zero on error. + */ + +/** + * Process a single event, performing synchronization-related actions using data under @p topNode. + * @param topNode Top-level node of the framework node tree. + * @returns Status code: 0 on success, non-zero on error. + */ + +/** + * Set a forced segment number to override the segment determined from input files. + * @param i Segment number to force; use -1 to disable the override. + */ + +/** + * Create the required node tree structure under @p topNode for this module. + * @param topNode Top-level node of the framework node tree. + * @returns Status code: 0 on success, non-zero on error. + */ + +/** + * Optional forced segment override used to replace the segment number coming from input files; + * a value of -1 indicates no override is applied. + */ class SyncReco : public SubsysReco { public: SyncReco(const std::string &name = "SYNC"); - ~SyncReco() override {} + ~SyncReco() override = default; int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; @@ -24,7 +65,7 @@ class SyncReco : public SubsysReco // just if we need to override the segment for e.g. embedding // where we want to reuse hijing files which normally set // the segment number - int forced_segment = -1; + int forced_segment {-1}; }; -#endif /* FFAMODULES_SYNCRECO_H */ +#endif /* FFAMODULES_SYNCRECO_H */ \ No newline at end of file diff --git a/offline/framework/ffamodules/Timing.cc b/offline/framework/ffamodules/Timing.cc index f662ba1b33..3a0da54110 100644 --- a/offline/framework/ffamodules/Timing.cc +++ b/offline/framework/ffamodules/Timing.cc @@ -3,10 +3,13 @@ #include #include // for SubsysReco -#include - #include +/** + * @brief Construct a Timing subsystem with the specified name. + * + * @param name Name used to identify this SubsysReco instance. + */ Timing::Timing(const std::string &name) : SubsysReco(name) { @@ -30,4 +33,4 @@ int Timing::process_event(PHCompositeNode * /*topNode*/) call_counter = 0; } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/framework/ffamodules/Timing.h b/offline/framework/ffamodules/Timing.h index 01b95638e0..e73b824ae4 100644 --- a/offline/framework/ffamodules/Timing.h +++ b/offline/framework/ffamodules/Timing.h @@ -8,16 +8,18 @@ #include // for string #include -class PHCompositeNode; - class Timing : public SubsysReco { public: Timing(const std::string &name = "Timing"); - ~Timing() override {} - int InitRun(PHCompositeNode *topNode) override; - int process_event(PHCompositeNode *topNode) override; - void SetCallCounter(unsigned int i) { calls = i; } + ~Timing() override = default; + int InitRun(PHCompositeNode * /*topNode*/) override; + int process_event(PHCompositeNode * /*topNode*/) override; + /** + * Set the target maximum number of calls used by the Timing module. + * @param i Target number of calls. + */ +void SetCallCounter(unsigned int i) { calls = i; } private: unsigned int call_counter{0}; @@ -26,4 +28,4 @@ class Timing : public SubsysReco time_t starttime{0}; }; -#endif +#endif \ No newline at end of file diff --git a/offline/framework/fun4all/Fun4AllServer.cc b/offline/framework/fun4all/Fun4AllServer.cc index 9d8779204e..f18b84b2d1 100644 --- a/offline/framework/fun4all/Fun4AllServer.cc +++ b/offline/framework/fun4all/Fun4AllServer.cc @@ -120,6 +120,13 @@ Fun4AllServer::~Fun4AllServer() return; } +/** + * @brief Initialize the server runtime environment and register default managers and nodes. + * + * Disables ROOT's default signal handlers, saves std::cout formatting state, creates and + * registers the server-wide histogram manager and the FrameWorkVars histogram, instantiates + * the default synchronization manager, and creates the TOP node and its node tree. + */ void Fun4AllServer::InitAll() { // first remove stupid root signal handler to get @@ -128,9 +135,9 @@ void Fun4AllServer::InitAll() { gSystem->IgnoreSignal((ESignals) i); } + m_saved_cout_state.copyfmt(std::cout); // save current state Fun4AllMonitoring::instance()->Snapshot("StartUp"); - std::string histomanagername; - histomanagername = Name() + "HISTOS"; + std::string histomanagername = Name() + "HISTOS"; ServerHistoManager = new Fun4AllHistoManager(histomanagername); registerHistoManager(ServerHistoManager); double uplim = NFRAMEWORKBINS - 0.5; @@ -176,6 +183,21 @@ int Fun4AllServer::isHistoRegistered(const std::string &name) const return iret; } +/** + * @brief Register a SubsysReco instance under a named top node and initialize it. + * + * Creates (if needed) ROOT TDirectory entries for the top node and subsystem, calls the + * subsystem's Init() with the subsystem's top PHCompositeNode, records the subsystem and + * a timer for later use, and stores the Init() return code. + * + * @param subsystem SubsysReco pointer to register and initialize. + * @param topnodename Name of the top node under which the subsystem's node and ROOT directories will be created. + * @return int `0` on successful registration; otherwise returns the nonzero code returned by the subsystem's Init(). + * If the subsystem's Init() returns Fun4AllReturnCodes::DONOTREGISTERSUBSYSTEM, registration is skipped and `0` is returned. + * + * Notes: + * - On failure to create required ROOT directories or if an exception is thrown during Init(), the function prints an error and terminates the process. + */ int Fun4AllServer::registerSubsystem(SubsysReco *subsystem, const std::string &topnodename) { Fun4AllServer *se = Fun4AllServer::instance(); @@ -245,6 +267,7 @@ int Fun4AllServer::registerSubsystem(SubsysReco *subsystem, const std::string &t << subsystem->Name() << std::endl; exit(1); } + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting gROOT->cd(currdir.c_str()); if (iret) { @@ -503,6 +526,14 @@ TNamed *Fun4AllServer::getHisto(const std::string &hname) const return (ServerHistoManager->getHisto(hname)); } +/** + * @brief Process a single event through all registered subsystems, I/O managers, and histogram managers. + * + * Processes one event: advances internal event counters, invokes each subsystem's process_event + * and records their return codes, handles discard/abort semantics, writes output and histogram files + * as required, resets per-event state for subsystems and sync managers, and takes monitoring snapshots. + * + * @return int `0` on normal completion of the event processing; `Fun4AllReturnCodes::ABORTRUN` if a subsystem requested run abortion; `Fun4AllReturnCodes::ABORTPROCESSING` if a subsystem requested processing abortion. int Fun4AllServer::process_event() { eventcounter++; @@ -576,6 +607,7 @@ int Fun4AllServer::process_event() ffamemtracker->Snapshot("Fun4AllServerProcessEvent"); #endif int retcode = Subsystem.first->process_event(Subsystem.second); + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting #ifdef FFAMEMTRACKER ffamemtracker->Snapshot("Fun4AllServerProcessEvent"); #endif @@ -854,6 +886,15 @@ int Fun4AllServer::BeginRunTimeStamp(PHTimeStamp &TimeStp) return 0; } +/** + * @brief Begin a new run and initialize subsystems for the specified run number. + * + * Resets per-run state, establishes the run start timestamp (unless overridden), + * invokes each registered subsystem's BeginRun, registers and begins any newly + * queued subsystems, and prints the node tree. + * + * @param runno Run number to begin. + * @return int Accumulated return code from subsystem BeginRun calls; `0` indicates success. int Fun4AllServer::BeginRun(const int runno) { eventcounter = 0; // reset event counter for every new run @@ -899,6 +940,7 @@ int Fun4AllServer::BeginRun(const int runno) for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) { iret = BeginRunSubsystem(*iter); + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting } for (; !NewSubsystems.empty(); NewSubsystems.pop_front()) { @@ -1048,6 +1090,19 @@ int Fun4AllServer::MakeNodesPersistent(PHCompositeNode *startNode) // NOLINT(mi return 0; } +/** + * @brief Invoke EndRun on every registered subsystem using the server's ROOT directory layout. + * + * Calls each subsystem's EndRun(runno) while changing into the subsystem-specific TDirectory + * so subsystem outputs are placed in the correct ROOT directory. Restores the original ROOT + * directory and the saved std::cout formatting state after visiting all subsystems. + * + * If a subsystem throws any exception during EndRun, this function logs the error and + * terminates the program. + * + * @param runno Run number to pass to each subsystem's EndRun method. + * @return int `0` on success. + */ int Fun4AllServer::EndRun(const int runno) { std::vector>::iterator iter; @@ -1092,12 +1147,21 @@ int Fun4AllServer::EndRun(const int runno) << (*iter).first->Name() << std::endl; exit(1); } + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting } gROOT->cd(currdir.c_str()); return 0; } +/** + * @brief Finalizes the server: ends the current run, finalizes subsystems, writes run information, and closes outputs. + * + * Calls End() on every registered subsystem, writes the RUN node via registered output managers if present, + * closes all output files, and conditionally dumps histograms and prints any recorded complaints. + * + * @return int Accumulated integer result from all SubsysReco::End calls (sum of return codes). + */ int Fun4AllServer::End() { recoConsts *rc = recoConsts::instance(); @@ -1144,6 +1208,7 @@ int Fun4AllServer::End() << (*iter).first->Name() << std::endl; exit(1); } + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting } gROOT->cd(currdir.c_str()); PHNodeIterator nodeiter(TopNode); @@ -1820,4 +1885,4 @@ int Fun4AllServer::UpdateRunNode() iret += Subsystem.first->UpdateRunNode(Subsystem.second); } return iret; -} +} \ No newline at end of file diff --git a/offline/framework/fun4all/Fun4AllServer.h b/offline/framework/fun4all/Fun4AllServer.h index 0c7ea72c14..512f3e5d5c 100644 --- a/offline/framework/fun4all/Fun4AllServer.h +++ b/offline/framework/fun4all/Fun4AllServer.h @@ -140,10 +140,28 @@ class Fun4AllServer : public Fun4AllBase int ScreamEveryEvent{0}; int unregistersubsystem{0}; int runnumber{0}; - int eventnumber{0}; - int eventcounter{0}; - int keep_db_connected{0}; - + /** + * Current event number tracked by the server. + * + * This counter is incremented for each processed event and is initialized to 0. + */ +int eventnumber{0}; + /** + * @brief Counts processed events. + * + * Total number of events processed by the server since initialization. + * This counter is incremented for each event that the framework processes. + */ +int eventcounter{0}; + /** + * Control persistence of the database connection across runs. + * + * When set to 1 the server keeps the database connection open between operations; + * when set to 0 the connection is closed when not in use. + */ +int keep_db_connected{0}; + + std::ios m_saved_cout_state{nullptr}; std::vector ComplaintList; std::vector ResetNodeList {"DST"}; std::vector> Subsystems; @@ -160,4 +178,4 @@ class Fun4AllServer : public Fun4AllBase std::map timer_map; }; -#endif +#endif \ No newline at end of file diff --git a/offline/framework/fun4all/InputFileHandler.cc b/offline/framework/fun4all/InputFileHandler.cc index 8939b67568..a3f06049b0 100644 --- a/offline/framework/fun4all/InputFileHandler.cc +++ b/offline/framework/fun4all/InputFileHandler.cc @@ -3,11 +3,23 @@ #include +#include + #include #include #include #include +#include +/** + * @brief Add a filename to the handler's input list. + * + * Appends the given filename to the active file queue and to the preserved copy + * used for resetting the file list. + * + * @param filename Path or identifier of the input file to add. + * @return int `0` on success. + */ int InputFileHandler::AddFile(const std::string &filename) { if (GetVerbosity() > 0) @@ -80,6 +92,17 @@ int InputFileHandler::AddListFile(const std::string &filename) return 0; } +/** + * Advance to and open the next file in the internal file list. + * + * If a pre-opening script is configured, it is invoked with the candidate filename + * (and the configured file name, if present) before attempting to open the file. + * If opening the candidate file fails, the file is removed from the list and the + * handler proceeds to the next entry. + * + * @return InputFileHandlerReturnCodes::SUCCESS if a file was successfully opened and is ready for processing, + * InputFileHandlerReturnCodes::FAILURE if no files remain to open. + */ int InputFileHandler::OpenNextFile() { while (!m_FileList.empty()) @@ -89,6 +112,19 @@ int InputFileHandler::OpenNextFile() { std::cout << PHWHERE << " opening next file: " << *iter << std::endl; } + if (!GetOpeningScript().empty()) + { + std::vector stringvec; + stringvec.push_back(*iter); + if (!m_FileName.empty()) + { + stringvec.push_back(m_FileName); + } + if (RunBeforeOpening(stringvec)) + { + std::cout << PHWHERE << " RunBeforeOpening() failed" << std::endl; + } + } if (fileopen(*iter)) { std::cout << PHWHERE << " could not open file: " << *iter << std::endl; @@ -140,8 +176,63 @@ int InputFileHandler::ResetFileList() return 0; } +/** + * @brief Attempt to open the input file identified by fname. + * + * Performs whatever setup is required to make the file ready for processing by + * the InputFileHandler (e.g., open file handle, validate format). + * + * @param fname Path to the input file to open. + * @return int `0` on success, non-zero error code on failure. + */ int InputFileHandler::fileopen(const std::string &fname) { std::cout << "InputFileHandler::fileopen opening " << fname << std::endl; return 0; } + +/** + * @brief Execute a configured pre-open script with provided arguments. + * + * If a pre-opening script is configured, validates the script exists and has owner-execute permission, + * then executes it with the handler's configured opening arguments followed by the entries in @p stringvec. + * + * @param stringvec Additional arguments appended to the script command (typically filenames to be opened). + * @return int Exit status of the script: `0` on success; `-1` if the script is not configured, not found, or not owner-executable; otherwise the script's exit code (normalized to the conventional low-order byte). + */ +int InputFileHandler::RunBeforeOpening(const std::vector &stringvec) +{ + if (m_RunBeforeOpeningScript.empty()) + { + return 0; + } + if (!std::filesystem::exists(m_RunBeforeOpeningScript)) + { + std::cout << PHWHERE << " script " << m_RunBeforeOpeningScript << " not found" + << std::endl; + return -1; + } + if (!((std::filesystem::status(m_RunBeforeOpeningScript).permissions() & std::filesystem::perms::owner_exec) == std::filesystem::perms::owner_exec)) + { + std::cout << PHWHERE << "RunBeforeOpeningScript script " + << m_RunBeforeOpeningScript << " is not owner executable" << std::endl; + return -1; + } + std::string fullcmd = m_RunBeforeOpeningScript + " " + m_OpeningArgs; + for (const auto& iter : stringvec) + { + fullcmd += " " + iter; + } + + if (m_Verbosity > 1) + { + std::cout << PHWHERE << " running " << fullcmd << std::endl; + } + unsigned int iret = gSystem->Exec(fullcmd.c_str()); + + if (iret) + { + iret = iret >> 8U; + } + return static_cast (iret); +} \ No newline at end of file diff --git a/offline/framework/fun4all/InputFileHandler.h b/offline/framework/fun4all/InputFileHandler.h index 823ae33b38..054c182986 100644 --- a/offline/framework/fun4all/InputFileHandler.h +++ b/offline/framework/fun4all/InputFileHandler.h @@ -4,13 +4,108 @@ #include #include #include +#include -class InputFileHandler +/** + * Construct an InputFileHandler with default state. + */ + + /** + * Destroy the InputFileHandler. + */ + + /** + * Open the specified input file. + * @param filename Path to the file to open. + * @returns An integer status code (implementation-defined). + */ + + /** + * Close the currently opened file. + * @returns `-1` by default to indicate failure or unimplemented behavior; derived classes may return other status codes. + */ + + /** + * Reset the internal file list to its initial state. + * @returns An integer status code (implementation-defined). + */ + + /** + * Advance to and open the next file from the internal file list. + * @returns An integer status code indicating success or failure. + */ + + /** + * Add a filename parsed from a list (e.g., batch list) to the internal file list. + * @param filename Filename to add. + * @returns An integer status code indicating success or failure. + */ + + /** + * Add a single filename to the internal file list. + * @param filename Filename to add. + * @returns An integer status code indicating success or failure. + */ + + /** + * Record that the given filename has been opened by appending it to the opened-files list. + * @param filename Filename that was opened. + */ + + /** + * Print status or diagnostics about the handler. + * @param what Selector for what to print (defaults to "ALL"). + */ + + /** + * Query whether a file is currently open. + * @returns `1` if open, `0` if not (or other implementation-specific integer flags). + */ + + /** + * Set the open state flag for the handler. + * @param i Integer value to set the open state to. + */ + + /** + * Set the verbosity level used by the handler. + * @param i Verbosity level. + */ + + /** + * Get the current verbosity level. + * @returns The verbosity level. + */ + + /** + * Update or synchronize the internal file list (e.g., copy or refresh working list). + */ + + /** + * Set the current filename tracked by the handler. + * @param fn Filename to set as current. + */ + + /** + * Get the current filename tracked by the handler. + * @returns Reference to the current filename string. + */ + + /** + * Check whether the internal candidate file list is empty. + * @returns `true` if the file list contains no entries, `false` otherwise. + */ + + /** + * Set the repeat count or flag controlling how files are reprocessed. + * @param i Repeat count or flag (defaults to -1). + */ + class InputFileHandler { public: InputFileHandler() = default; virtual ~InputFileHandler() = default; - virtual int fileopen(const std::string & /*filename*/);// { return 0; } + virtual int fileopen(const std::string & /*filename*/); // { return 0; } virtual int fileclose() { return -1; } virtual int ResetFileList(); @@ -32,15 +127,42 @@ class InputFileHandler std::pair::const_iterator, std::list::const_iterator> FileOpenListBeginEnd() { return std::make_pair(m_FileListOpened.begin(), m_FileListOpened.end()); } const std::list &GetFileList() const { return m_FileListCopy; } const std::list &GetFileOpenedList() const { return m_FileListOpened; } + /** + * Set the script to run before opening files. + * @param script Path or command string of the script to execute prior to opening a file. + */ +void SetOpeningScript(const std::string &script) { m_RunBeforeOpeningScript = script; } + const std::string &GetOpeningScript() const { return m_RunBeforeOpeningScript; } + /** + * Set the argument string to pass to the script run before opening files. + * @param args Space-separated or otherwise-formatted argument string to supply to the pre-opening script previously set via SetOpeningScript. + */ +void SetOpeningScriptArgs(const std::string &args) { m_OpeningArgs = args; } + const std::string &GetOpeningScriptArgs() const { return m_OpeningArgs; } + int RunBeforeOpening(const std::vector &stringvec); private: int m_IsOpen{0}; - int m_Repeat{0}; - uint64_t m_Verbosity{0}; + /** + * Controls how many times file processing should be repeated. + * + * A value of 0 means files are processed once (no repetition). Higher values + * request that files be reopened/processed that many additional times. + */ +int m_Repeat{0}; + /** + * Verbosity level for logging and diagnostic output. + * + * Higher values increase the amount of diagnostic information produced. + * Defaults to 0. + */ +uint64_t m_Verbosity{0}; std::string m_FileName; + std::string m_RunBeforeOpeningScript; + std::string m_OpeningArgs; std::list m_FileList; std::list m_FileListCopy; std::list m_FileListOpened; // all files which were opened during running }; -#endif +#endif \ No newline at end of file diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 78b3e3a365..472e61199b 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -642,6 +642,18 @@ int Fun4AllStreamingInputManager::FillGl1() return 0; } +/** + * @brief Populate the INTT raw-hit container from cached INTT input pools and update INTT QA state. + * + * Ensures INTT input pools are filled (via FillInttPool), locates or creates the InttRawHitContainer node, + * establishes or updates the reference BCO window, discards cached INTT entries that are earlier than the + * allowed negative offset (invoking CleanupUsedPackets / clearPacketBClkStackMap / clearFeeGTML1BCOMap on each + * registered INTT input for any discarded BCO), fills QA histograms that tag packets/fees relative to the current + * reference BCO, and appends all INTT hits with BCO <= (m_RefBCO + m_intt_bco_range) into the InttRawHitContainer. + * The function may call gSystem->Exit(1) and abort if the InttRawHitContainer node cannot be found or created. + * + * @return int `0` on success, or the non-zero error code returned by FillInttPool(). + */ int Fun4AllStreamingInputManager::FillIntt() { int iret = FillInttPool(); @@ -776,9 +788,15 @@ int Fun4AllStreamingInputManager::FillIntt() { h_taggedAllFee_intt->Fill(refbcobitshift); } - while (m_InttRawHitMap.begin()->first <= select_crossings - m_intt_negative_bco) + + for (auto& [bco, hitinfo] : m_InttRawHitMap) { - for (auto *intthititer : m_InttRawHitMap.begin()->second.InttRawHitVector) + if (bco > select_crossings) + { + break; + } + + for (auto *intthititer : hitinfo.InttRawHitVector) { if (Verbosity() > 1) { @@ -788,25 +806,23 @@ int Fun4AllStreamingInputManager::FillIntt() } inttcont->AddHit(intthititer); } - for (auto *iter : m_InttInputVector) - { - iter->CleanupUsedPackets(m_InttRawHitMap.begin()->first); - if (m_intt_negative_bco < 2) // triggered mode - { - iter->clearPacketBClkStackMap(m_InttRawHitMap.begin()->first); - iter->clearFeeGTML1BCOMap(m_InttRawHitMap.begin()->first); - } - } - m_InttRawHitMap.begin()->second.InttRawHitVector.clear(); - m_InttRawHitMap.erase(m_InttRawHitMap.begin()); - if (m_InttRawHitMap.empty()) - { - break; - } - } + } return 0; } - +/** + * @brief Populate MVTX raw event header and hit container from buffered MVTX packets. + * + * Computes a BCO selection window based on the current reference BCO and configured MVTX ranges, + * performs tagging and QA histogram updates, and transfers matching FeeIdInfo, L1 trigger BCOs, + * and raw hits from the internal MVTX buffers into the MVTX raw event header and MVTX raw hit + * container nodes in the top node tree. + * + * The function initializes the reference BCO if it is unset, advances past buffered entries that + * are earlier than the allowed negative offset, and only moves entries whose BCO falls within the + * computed lower and upper limits. Missing required MVTX nodes cause an immediate abort. + * + * @return int 0 on success, non-zero error code returned by FillMvtxPool on failure. + */ int Fun4AllStreamingInputManager::FillMvtx() { int iret = FillMvtxPool(); @@ -846,7 +862,7 @@ int Fun4AllStreamingInputManager::FillMvtx() } select_crossings += m_RefBCO; - uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_bco_range ? 0 : m_RefBCO - m_mvtx_bco_range; + uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_negative_bco ? 0 : m_RefBCO - m_mvtx_negative_bco; if (Verbosity() > 2) { std::cout << "select MVTX crossings" @@ -981,90 +997,42 @@ int Fun4AllStreamingInputManager::FillMvtx() } taggedPacketsFEEs.clear(); - if (m_mvtx_is_triggered) + uint64_t lower_limit = m_mvtx_is_triggered ? select_crossings : select_crossings - m_mvtx_bco_range - m_mvtx_negative_bco; + uint64_t upper_limit = m_mvtx_is_triggered ? select_crossings + m_mvtx_bco_range : select_crossings; + + for (auto& [bco, hitinfo] : m_MvtxRawHitMap) { - while (select_crossings <= m_MvtxRawHitMap.begin()->first && m_MvtxRawHitMap.begin()->first <= select_crossings + m_mvtx_bco_range) // triggered + if (bco < lower_limit) { - if (Verbosity() > 2) - { - std::cout << "Adding 0x" << std::hex << m_MvtxRawHitMap.begin()->first - << " ref: 0x" << select_crossings << std::dec << std::endl; - } - for (auto *mvtxFeeIdInfo : m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector) - { - if (Verbosity() > 1) - { - mvtxFeeIdInfo->identify(); - } - mvtxEvtHeader->AddFeeIdInfo(mvtxFeeIdInfo); - delete mvtxFeeIdInfo; - } - m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector.clear(); - mvtxEvtHeader->AddL1Trg(m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco); + continue; + } + if (bco > upper_limit) + { + break; + } - for (auto *mvtxhititer : m_MvtxRawHitMap.begin()->second.MvtxRawHitVector) - { - if (Verbosity() > 1) - { - mvtxhititer->identify(); - } - mvtxcont->AddHit(mvtxhititer); - } - for (auto *iter : m_MvtxInputVector) - { - iter->CleanupUsedPackets(m_MvtxRawHitMap.begin()->first); - } - m_MvtxRawHitMap.begin()->second.MvtxRawHitVector.clear(); - m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco.clear(); - m_MvtxRawHitMap.erase(m_MvtxRawHitMap.begin()); - // m_MvtxRawHitMap.empty() need to be checked here since we do not call FillPoolMvtx() - if (m_MvtxRawHitMap.empty()) - { - break; - } + if (Verbosity() > 2) + { + std::cout << "Adding 0x" << std::hex << bco + << " ref: 0x" << select_crossings << std::dec << std::endl; } - } - else - { - while (select_crossings - m_mvtx_bco_range - m_mvtx_negative_bco <= m_MvtxRawHitMap.begin()->first && m_MvtxRawHitMap.begin()->first <= select_crossings) // streamed + for (auto *mvtxFeeIdInfo : hitinfo.MvtxFeeIdInfoVector) { - if (Verbosity() > 2) - { - std::cout << "Adding 0x" << std::hex << m_MvtxRawHitMap.begin()->first - << " ref: 0x" << select_crossings << std::dec << std::endl; - } - for (auto *mvtxFeeIdInfo : m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector) + if (Verbosity() > 1) { - if (Verbosity() > 1) - { - mvtxFeeIdInfo->identify(); - } - mvtxEvtHeader->AddFeeIdInfo(mvtxFeeIdInfo); - delete mvtxFeeIdInfo; + mvtxFeeIdInfo->identify(); } - m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector.clear(); - mvtxEvtHeader->AddL1Trg(m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco); + mvtxEvtHeader->AddFeeIdInfo(mvtxFeeIdInfo); + } + mvtxEvtHeader->AddL1Trg(hitinfo.MvtxL1TrgBco); - for (auto *mvtxhititer : m_MvtxRawHitMap.begin()->second.MvtxRawHitVector) - { - if (Verbosity() > 1) - { - mvtxhititer->identify(); - } - mvtxcont->AddHit(mvtxhititer); - } - for (auto *iter : m_MvtxInputVector) - { - iter->CleanupUsedPackets(m_MvtxRawHitMap.begin()->first); - } - m_MvtxRawHitMap.begin()->second.MvtxRawHitVector.clear(); - m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco.clear(); - m_MvtxRawHitMap.erase(m_MvtxRawHitMap.begin()); - // m_MvtxRawHitMap.empty() need to be checked here since we do not call FillPoolMvtx() - if (m_MvtxRawHitMap.empty()) + for (auto *mvtxhititer : hitinfo.MvtxRawHitVector) + { + if (Verbosity() > 1) { - break; + mvtxhititer->identify(); } + mvtxcont->AddHit(mvtxhititer); } } @@ -1420,9 +1388,17 @@ int Fun4AllStreamingInputManager::FillMicromegasPool() return 0; } +/** + * @brief Ensures MVTX input pools are filled and validates run number consistency. + * + * Calls FillPool(ref_bco_minus_range) on each registered MVTX input, sets the manager run + * number from the first input, and aborts the process if a run-number mismatch is detected. + * + * @return int `0` on success, `-1` if the MVTX raw-hit map is empty (no data available). + */ int Fun4AllStreamingInputManager::FillMvtxPool() { - uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_bco_range ? m_mvtx_bco_range : m_RefBCO - m_mvtx_bco_range; + uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_negative_bco ? m_mvtx_negative_bco : m_RefBCO - m_mvtx_negative_bco; for (auto *iter : m_MvtxInputVector) { if (Verbosity() > 3) @@ -1569,4 +1545,4 @@ void Fun4AllStreamingInputManager::createQAHistos() h_tagBcoFelix_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCO_felix%i") % i).str())); h_tagBcoFelixAllFees_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCOAllFees_Felix%i") % i).str())); } -} +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 7500e3badf..ac65955fb1 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -524,7 +524,14 @@ void SingleMicromegasPoolInput_v2::FillBcoQA(uint64_t gtm_bco) // how many waveforms found for this BCO h_waveform->Fill(n_waveforms); } -//_______________________________________________________ +/** + * @brief Create and register QA histograms and (optionally) an evaluation TTree for Micromegas BCO and waveform monitoring. + * + * Sets up histograms that track per-GTM-BCO packet and waveform counts, per-packet and per-FEE waveform totals and drop counts, + * and heartbeat statistics. When evaluation mode is enabled, opens an output TFile and creates a TTree with branches that record + * per-waveform metadata and matching information (is_heartbeat, matched, packet_id, fee_id, channel, GTM and FEE BCO fields, + * and predicted-matching fields). + */ void SingleMicromegasPoolInput_v2::createQAHistos() { auto* hm = QAHistManagerDef::getHistoManager(); @@ -607,6 +614,7 @@ void SingleMicromegasPoolInput_v2::createQAHistos() m_evaluation_file.reset(new TFile(m_evaluation_filename.c_str(), "RECREATE")); m_evaluation_tree = new TTree("T", "T"); m_evaluation_tree->Branch("is_heartbeat", &m_waveform.is_heartbeat); + m_evaluation_tree->Branch("matched", &m_waveform.matched); m_evaluation_tree->Branch("packet_id", &m_waveform.packet_id); m_evaluation_tree->Branch("fee_id", &m_waveform.fee_id); m_evaluation_tree->Branch("channel", &m_waveform.channel); @@ -788,7 +796,20 @@ void SingleMicromegasPoolInput_v2::decode_gtm_data(int packet_id, const SingleMi } } -//____________________________________________________________________ +/** + * @brief Process and decode a complete FEE data buffer for a given packet and FEE, producing Micromegas raw hits. + * + * Parses one or more FEE sub-packets from the per-FEE buffer, validates headers and CRC, updates QA counters/histograms + * and heartbeat statistics, attempts to match FEE BX timestamps to a GTM BCO, and on successful match constructs and + * stores MicromegasRawHitv3 objects (and forwards them to the StreamingInputManager if available). + * + * When BCO matching fails for a waveform the function increments drop counters and histograms and skips creating a hit. + * If evaluation mode is enabled, per-waveform evaluation fields (including match status and predicted/matched BCOs) + * are populated and the evaluation tree is filled for both matched and non-matched cases. + * + * @param packet_id Identifier of the packet (index in per-packet bookkeeping) whose matching context is used. + * @param fee_id Identifier of the FEE whose data buffer will be consumed. + */ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int fee_id) { // get bco information @@ -912,6 +933,13 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int // try get gtm bco matching fee const auto& fee_bco = payload.bx_timestamp; + if( m_do_evaluation ) + { + m_waveform.is_heartbeat = is_heartbeat; + m_waveform.fee_id = fee_id; + m_waveform.channel = payload.channel; + m_waveform.fee_bco = fee_bco; + } // find matching gtm bco uint64_t gtm_bco = 0; @@ -920,9 +948,20 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int { // assign gtm bco gtm_bco = result.value(); - } - else - { + if( m_do_evaluation ) + { + m_waveform.matched = true; + m_waveform.gtm_bco_matched = gtm_bco; + { + const auto predicted = bco_matching_information.get_predicted_fee_bco(gtm_bco);; + if( predicted ) + { + m_waveform.fee_bco_predicted_matched = predicted.value(); + } + } + m_evaluation_tree->Fill(); + } + } else { // increment counter and histogram ++m_waveform_counters[packet_id].dropped_bco; ++m_fee_waveform_counters[fee_id].dropped_bco; @@ -935,28 +974,16 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int ++m_fee_heartbeat_counters[fee_id].dropped_bco; } - // skip the waverform - continue; - } - - if (m_do_evaluation) - { - m_waveform.is_heartbeat = (payload.type == HEARTBEAT_T); - m_waveform.fee_id = fee_id; - m_waveform.channel = payload.channel; - m_waveform.fee_bco = fee_bco; - - m_waveform.gtm_bco_matched = gtm_bco; + if( m_do_evaluation ) { - const auto predicted = bco_matching_information.get_predicted_fee_bco(gtm_bco); - ; - if (predicted) - { - m_waveform.fee_bco_predicted_matched = predicted.value(); - } + m_waveform.matched = false; + m_waveform.gtm_bco_matched = 0; + m_waveform.fee_bco_predicted_matched = 0; + m_evaluation_tree->Fill(); } - m_evaluation_tree->Fill(); + // skip the waverform + continue; } // ignore heartbeat waveforms @@ -1024,4 +1051,4 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int m_MicromegasRawHitMap[gtm_bco].push_back(newhit.release()); } -} +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index d8c3c1da62..8bda085da0 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -212,8 +212,25 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput std::unique_ptr m_evaluation_file; /** - * waveform is similar to sample except that there is only one of which per waveform, - * and that it stores the max adc and corresponding sample_id + * Summary representation of a single waveform peak and its timing/matching metadata. + * + * Represents one waveform-level summary entry (one per waveform) containing identifiers + * (packet, FEE, channel), heartbeat flag, matching status, and BCO (beam-clock) values + * used for cross-subsystem alignment and matching between GTM and FEE clocks. + * + * Members: + * - packet_id: packet index containing the waveform. + * - fee_id: FEE identifier within the packet. + * - channel: channel identifier on the FEE. + * - is_heartbeat: true when the measurement is a heartbeat rather than a waveform. + * - matched: true when this waveform has been matched to a GTM/FEE BCO during matching. + * - gtm_bco_first: first GTM BCO seen for this waveform (reference start). + * - gtm_bco: GTM BCO associated with the waveform. + * - gtm_bco_matched: GTM BCO that was matched to an FEE BCO (if any). + * - fee_bco_first: first FEE BCO seen for this waveform (reference start). + * - fee_bco: FEE BCO associated with the waveform. + * - fee_bco_predicted: FEE BCO predicted from GTM timing. + * - fee_bco_predicted_matched: predicted FEE BCO that was matched. */ class Waveform { @@ -230,7 +247,14 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// true if measurement is hearbeat bool is_heartbeat = false; - /// ll1 bco + /// true if matched + bool matched = false; + + /** + * Beam clock (BCO) value from the first GTM LL1 marker associated with this waveform. + * + * Stored as a 64-bit unsigned integer; initialized to 0 when not set. + */ uint64_t gtm_bco_first {0}; /// ll1 bco @@ -260,4 +284,4 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput //*} }; -#endif +#endif \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc index de98a9936e..93c0c88a68 100644 --- a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc +++ b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc @@ -1,7 +1,7 @@ #include "SingleMvtxPoolInput.h" -#include "MvtxRawDefs.h" #include "Fun4AllStreamingInputManager.h" +#include "MvtxRawDefs.h" #include "mvtx_pool.h" #include @@ -28,8 +28,17 @@ #include #include +/** + * @brief Construct a SingleMvtxPoolInput and initialize internal state. + * + * Allocates the two-element packet pointer array and sets the default MVTX raw + * hit container name to "MVTXRAWHIT". + * + * @param name Identifier passed to the SingleStreamingInput base class. + */ SingleMvtxPoolInput::SingleMvtxPoolInput(const std::string &name) - : SingleStreamingInput(name), plist(new Packet *[2]) + : SingleStreamingInput(name) + , plist(new Packet *[2]) { m_rawHitContainerName = "MVTXRAWHIT"; @@ -48,6 +57,19 @@ SingleMvtxPoolInput::~SingleMvtxPoolInput() } } +/** + * @brief Consume available input events, extract MVTX strobes and hits, and populate internal pools and containers. + * + * Processes incoming DAQ events until collection conditions indicate temporary pause or end-of-data. + * For each packet it builds or updates a per-packet mvtx_pool, decodes per-FEE strobes and L1 triggers, + * constructs MvtxRawHitv1 objects for strobes with BCO >= minBCO, and assigns L1 trigger BCOs to the nearest + * preceding (or equal) strobe BCO. Populates and updates internal structures such as m_MvtxRawHitMap, + * m_BclkStack, m_FEEBclkMap, m_FeeStrobeMap, and m_FeeGTML1BCOMap, and forwards hits, fee info, and L1 + * associations to the StreamingInputManager when available. May advance file reading and mark the input as + * finished via AllDone() on unrecoverable file errors. + * + * @param minBCO Minimum strobe BCO threshold; strobes with BCO less than this value are ignored. + */ void SingleMvtxPoolInput::FillPool(const uint64_t minBCO) { if (AllDone()) // no more files and all events read @@ -161,7 +183,7 @@ void SingleMvtxPoolInput::FillPool(const uint64_t minBCO) m_BclkStack.insert(strb_bco); m_FEEBclkMap[feeId] = strb_bco; - if (strb_bco < minBCO - m_NegativeBco) + if (strb_bco < minBCO) { continue; } @@ -206,7 +228,7 @@ void SingleMvtxPoolInput::FillPool(const uint64_t minBCO) auto it = m_BclkStack.lower_bound(lv1Bco); // auto const strb_it = (it == m_BclkStack.begin()) ? (*it == lv1Bco ? it : m_BclkStack.cend()) : --it; // this is equivalent but human readable for the above: - auto strb_it = m_BclkStack.cend(); + auto strb_it = m_BclkStack.cend(); if (it == m_BclkStack.begin()) { @@ -435,6 +457,16 @@ void SingleMvtxPoolInput::CreateDSTNode(PHCompositeNode *topNode) } } +/** + * @brief Configure MVTX timing and BCO window parameters and propagate them to the StreamingInputManager. + * + * @details + * Reads the strobe width (optionally from the DB) and sets m_BcoRange and m_NegativeBco according to MVTX standalone/triggered and strobe-width rules. + * If MVTX is in triggered mode, enables MVTX-triggered mode in the StreamingInputManager. Finally, forwards the configured BCO range and negative BCO + * to the StreamingInputManager if available. + * + * @note If strobe width is requested from the database but not defined for the current run, the function prints a warning and calls exit(1), terminating the process. + */ void SingleMvtxPoolInput::ConfigureStreamingInputManager() { auto [runnumber, segment] = Fun4AllUtils::GetRunSegment(*(GetFileList().begin())); @@ -462,7 +494,7 @@ void SingleMvtxPoolInput::ConfigureStreamingInputManager() else if (m_strobeWidth > 9 && m_strobeWidth < 11) { m_BcoRange = 500; - m_NegativeBco = 500; + m_NegativeBco = 120; } else if (m_strobeWidth < 1) // triggered mode { @@ -492,4 +524,4 @@ void SingleMvtxPoolInput::ConfigureStreamingInputManager() StreamingInputManager()->SetMvtxNegativeBco(m_NegativeBco); } return; -} +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index 3bb6b30a2b..e92b00efd1 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -327,6 +327,17 @@ int SingleTriggeredInput::fileclose() return 0; } +/** + * @brief Populate per-packet event deques for the next pool window and compute per-packet clocks. + * + * Fills m_PacketEventDeque and associated per-packet clock/diff arrays for up to pooldepth entries by reading events + * from the current input iterator (opening subsequent files as needed). On the first processed event it will create + * DST packet nodes and initialize run-dependent state. The method updates internal shift/backup structures, advances + * the input iterator, and may mark end-of-input via AllDone/FilesDone on I/O failure. + * + * @return int The minimum number of events available across all packet deques after filling (values 0..pooldepth), + * or -1 on fatal input/iterator error. + */ int SingleTriggeredInput::FillEventVector() { while (GetEventIterator() == nullptr) // at startup this is a null pointer @@ -352,6 +363,12 @@ int SingleTriggeredInput::FillEventVector() m_bclkarray_map[pid][0] = tmp; m_bclkdiffarray_map[pid].fill(std::numeric_limits::max()); + static bool firstclockarray=true; + if(firstclockarray){ + std::cout << "first clock call pid " << pid << " m_bclkarray_map[pid][0] : " << m_bclkarray_map[pid][0] << std::endl; + firstclockarray=false; + } + if ( representative_pid == -1 ) { representative_pid = pid; @@ -368,12 +385,17 @@ int SingleTriggeredInput::FillEventVector() while (i < pooldepth) { Event* evt{nullptr}; + bool skiptrace = false; if (this != Gl1Input()) { auto* gl1 = dynamic_cast(Gl1Input()); if (gl1) { int nskip = gl1->GetGl1SkipArray()[i]; + if(nskip >0) + { + skiptrace = true; + } while (nskip > 0) { @@ -391,6 +413,7 @@ int SingleTriggeredInput::FillEventVector() if (skip_evt->getEvtType() != DATAEVENT) { + delete skip_evt; continue; } @@ -412,14 +435,91 @@ int SingleTriggeredInput::FillEventVector() { if (Verbosity() > 0) { - std::cout << Name() << ": Early stop of SEB skip after " << (gl1->GetGl1SkipArray()[i] - nskip) << " from intial " << gl1->GetGl1SkipArray()[i] << " events." << std::endl; + std::cout << Name() << ": Early stop in pool " << i << " of SEB skip after " << (gl1->GetGl1SkipArray()[i] - nskip) << " from intial " << gl1->GetGl1SkipArray()[i] << " events. gl1diff vs sebdiff : " << gl1_diff << " vs " << seb_diff << std::endl; } evt = skip_evt; + skiptrace = false; break; } delete skip_evt; nskip--; } + + if(skiptrace) + { + evt = GetEventIterator()->getNextEvent(); + while (!evt) + { + fileclose(); + if (OpenNextFile() == InputFileHandlerReturnCodes::FAILURE) + { + FilesDone(1); + return -1; + } + evt = GetEventIterator()->getNextEvent(); + } + if (evt->getEvtType() != DATAEVENT) + { + if (Verbosity() > 0) + { + std::cout << Name() << " dropping non data event: " << evt->getEvtSequence() << std::endl; + } + delete evt; + continue; + } + + Packet* pkt = evt->getPacket(representative_pid); + if (!pkt) + { + std::cout << "representative packet invalid inside skiptrace.. continuing.." << std::endl; + continue; + } + FillPacketClock(evt, pkt, i); + uint64_t seb_diff = m_bclkdiffarray_map[representative_pid][i]; + int gl1pid = Gl1Input()->m_bclkdiffarray_map.begin()->first; + uint64_t gl1_diff = gl1->m_bclkdiffarray_map[gl1pid][i]; + + bool clockconsistency=true; + if (seb_diff != gl1_diff) + { + clockconsistency=false; + int clockconstcount = 0; + while(!clockconsistency && clockconstcount<5) + { + std::cout << Name() << ": Still inconsistent clock diff after Gl1 drop. gl1diff vs sebdiff : " << gl1_diff << " vs " << seb_diff << std::endl; + delete pkt; + delete evt; + evt = GetEventIterator()->getNextEvent(); + while (!evt) + { + fileclose(); + if (OpenNextFile() == InputFileHandlerReturnCodes::FAILURE) + { + FilesDone(1); + return -1; + } + evt = GetEventIterator()->getNextEvent(); + } + pkt = evt->getPacket(representative_pid); + if (!pkt) + { + std::cout << "representative packet invalid inside skiptrace.. continuing.." << std::endl; + continue; + } + + FillPacketClock(evt, pkt, i); + uint64_t seb_diff_next = m_bclkdiffarray_map[representative_pid][i]; + uint64_t gl1_diff_next = gl1->m_bclkdiffarray_map[gl1pid][i]; + std::cout << "seb_diff_next : " << seb_diff_next << " , gl1_diff_next : " << gl1_diff_next << std::endl; + if(seb_diff_next == gl1_diff_next) + { + clockconsistency=true; + std::cout << Name() << " : recovered by additional skip in skiptrace" << std::endl; + } + clockconstcount++; + } + } + } } } @@ -485,14 +585,16 @@ int SingleTriggeredInput::FillEventVector() } FillPacketClock(thisevt, pkt, i); m_PacketEventDeque[pid].push_back(thisevt); + delete pkt; - + if (representative_pid == -1 && m_PacketShiftOffset[pid] == 0) { representative_pid = pid; } } i++; + eventcounter++; } size_t minSize = pooldepth; @@ -1079,6 +1181,21 @@ void SingleTriggeredInput::dumpdeque() return; } +/** + * Consume the next synchronized pool event by converting per-packet input events into + * output CaloPacket nodes and advancing internal event queues. + * + * Processes the front event from each packet's deque (unless that packet is marked as + * having an alignment problem), validates packet identifiers, fills and resets the + * destination CaloPacket structures, applies ditch/override/shift handling, runs FEM + * event-number/clock consistency checks, and deletes input events that are no longer + * needed. After processing, per-packet ditch indices are decremented and one element is + * popped from each non-empty packet deque. The method also updates the run number and + * internal FEM event-number set. + * + * @return `Fun4AllReturnCodes::EVENT_OK` on successful conversion and deque advancement; + * `-1` if there are no more events to read or if an alignment problem prevents processing. + */ int SingleTriggeredInput::ReadEvent() { for (const auto& [pid, dq] : m_PacketEventDeque) @@ -1116,16 +1233,15 @@ int SingleTriggeredInput::ReadEvent() [](const std::pair& p) { return p.second == 0; }); std::set events_to_delete; - for (auto& [pid, dq] : m_PacketEventDeque) { if(m_PacketAlignmentProblem[pid]) { continue; } + Event* evt = dq.front(); Packet* packet = evt->getPacket(pid); - int packet_id = packet->getIdentifier(); if (packet_id != pid) { @@ -1137,7 +1253,6 @@ int SingleTriggeredInput::ReadEvent() CaloPacket *newhit = findNode::getClass(m_topNode, packet_id); newhit->Reset(); - if (m_DitchPackets.contains(packet_id) && m_DitchPackets[packet_id].contains(0)) { newhit->setStatus(OfflinePacket::PACKET_DROPPED); @@ -1240,4 +1355,4 @@ int SingleTriggeredInput::ReadEvent() } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.h b/offline/framework/fun4allraw/SingleTriggeredInput.h index 088be73bef..561972fc4f 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.h +++ b/offline/framework/fun4allraw/SingleTriggeredInput.h @@ -32,19 +32,46 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler ~SingleTriggeredInput() override; virtual Eventiterator *GetEventIterator() { return m_EventIterator; } virtual void FillPool(); - virtual void RunNumber(const int runno) { m_RunNumber = runno; } + /** + * Set the current run number used for subsequent event processing. + * @param runno The run number to assign to this input handler. + */ +virtual void RunNumber(const int runno) { m_RunNumber = runno; } virtual int RunNumber() const { return m_RunNumber; } - virtual void EventNumber(const int i) { m_EventNumber = i; } - virtual int EventNumber() const { return m_EventNumber; } - virtual int EventsInThisFile() const { return m_EventsThisFile; } virtual int fileopen(const std::string &filename) override; + /** + * Close the currently opened input file and release associated resources. + * @returns `0` on success, non-zero on failure. + */ + /** + * Get the completion status flag for this input. + * @returns Non-zero if processing is complete, `0` if not complete. + */ + /** + * Set the completion status flag for this input. + * @param i Non-zero to mark processing as complete, `0` to mark as not complete. + */ virtual int fileclose() override; virtual int AllDone() const { return m_AllDone; } virtual void AllDone(const int i) { m_AllDone = i; } virtual int FilesDone() const { return m_FilesDone; } - virtual void FilesDone(const int i) { m_FilesDone = i; } - virtual void EventAlignmentProblem(const int i) { m_EventAlignmentProblem = i; } + /** + * Set the number of files that have been processed by this input handler. + * @param i The count of files processed to store internally. + */ +virtual void FilesDone(const int i) { m_FilesDone = i; } + /** + * Set the event alignment problem flag or counter. + * @param i New value for the event alignment problem flag or count. + */ +virtual void EventAlignmentProblem(const int i) { m_EventAlignmentProblem = i; } virtual int EventAlignmentProblem() const { return m_EventAlignmentProblem; } + /** + * Set the current event number used by the input handler. + * @param i Event number to store as the current event index. + */ +virtual void EventNumber(const int i) { m_EventNumber = i; } + virtual int EventNumber() const { return m_EventNumber; } virtual void CreateDSTNodes(Event *evt); // these ones are used directly by the derived classes, maybe later // move to cleaner accessors @@ -91,12 +118,37 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler private: Eventiterator *m_EventIterator{nullptr}; SingleTriggeredInput *m_Gl1Input{nullptr}; - int m_AllDone{0}; - uint64_t m_Event{0}; - int m_EventNumber{0}; - int m_EventsThisFile{0}; - int m_EventAlignmentProblem{0}; - int m_FilesDone{0}; + /** + * Overall completion status flag for the input handler. + * + * 0 indicates processing is ongoing; any non-zero value indicates processing is complete. + */ +int m_AllDone{0}; + /** + * @brief Running total of processed events. + * + * Incremented for each processed event and used as a global event counter/identifier for this input handler. + */ +uint64_t m_Event{0}; + /** + * Current event number within the input stream used for tracking processed events. + * + * This integer is incremented as events are read and represents the sequential + * index (event count) for the input source. + */ +int m_EventNumber{0}; + /** + * Count of event alignment problems encountered. + * + * Tracks how many alignment or clock-consistency issues have been detected for processed events; a value of 0 indicates no problems. + */ +int m_EventAlignmentProblem{0}; + /** + * Number of input files that have been processed. + * + * Maintains a running count of completed files for this input handler; initialized to 0. + */ +int m_FilesDone{0}; int m_LastEvent{std::numeric_limits::max()}; int m_ProblemEvent{-1}; int m_RepresPacket{-1}; @@ -105,7 +157,37 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler bool firstcall{true}; bool firstclockcheck{true}; bool m_KeepPacketsFlag{false}; - bool m_packetclk_copy_runs{false}; + /** + * If true, copy beam-clock information from representative packets into other packets during run processing. + */ +/** + * Set of packet IDs for which the copied clock has been verified as correct. + */ +/** + * Map of packet ID -> set of event indices that should be skipped ("ditched") for that packet. + */ +/** + * Set of FEM event numbers that have been observed or tracked. + */ +/** + * Set of packet IDs that should have their clocks overridden with the representative packet's clock. + */ +/** + * Map of packet ID -> number of consecutive alignment failures encountered for that packet. + */ +/** + * Map of packet ID -> flag indicating whether an alignment problem has been recorded for that packet. + */ +/** + * Map of packet ID -> flag indicating whether the last difference in the previous pool was considered bad for that packet. + */ +/** + * Map of packet ID -> previously known valid beam clock origin (BCO) value for that packet. + */ +/** + * Monotonic counter of processed events across the lifetime of this input instance. + */ +bool m_packetclk_copy_runs{false}; std::set m_CorrectCopiedClockPackets; std::map> m_DitchPackets; std::set m_FEMEventNrSet; @@ -114,6 +196,7 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler std::map m_PacketAlignmentProblem; std::map m_PrevPoolLastDiffBad; std::map m_PreviousValidBCOMap; + long long eventcounter{0}; }; -#endif +#endif \ No newline at end of file diff --git a/offline/packages/CaloEmbedding/CombineTowerInfo.cc b/offline/packages/CaloEmbedding/CombineTowerInfo.cc new file mode 100644 index 0000000000..34e85e96ed --- /dev/null +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.cc @@ -0,0 +1,131 @@ +#include "CombineTowerInfo.h" + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +/** + * @brief Construct a CombineTowerInfo module with the given module name. + * + * @param name Identifier used to name this SubsysReco module instance. + */ +CombineTowerInfo::CombineTowerInfo(const std::string& name) + : SubsysReco(name) +{ +} + +/** + * @brief Initialize run-time nodes and validate input/output node names. + * + * Ensures that the configured input and output node names are set and then + * creates or locates the required nodes under the provided top node. + * + * @param topNode Top-level node used to locate or create required DST nodes. + * @return int Fun4AllReturnCodes::EVENT_OK on success. + * @throws std::runtime_error If any of m_inputNodeA, m_inputNodeB, or m_outputNode is empty. + */ +int CombineTowerInfo::InitRun(PHCompositeNode* topNode) +{ + if (m_inputNodeA.empty() || m_inputNodeB.empty() || m_outputNode.empty()) + { + throw std::runtime_error("CombineTowerInfo: input/output node names not set"); + } + + CreateNodes(topNode); + return Fun4AllReturnCodes::EVENT_OK; +} + +/** + * @brief Locate input TowerInfoContainer nodes and initialize or create the output container. + * + * Retrieves the DST and detector nodes from the provided top-level node, obtains the two input + * TowerInfoContainer instances (m_towersA and m_towersB) from their configured node names, and + * sets up the output TowerInfoContainer (m_towersOut) under the detector node. If the output + * container does not exist, it is created by cloning the first input container and attaching it + * to the detector node. + * + * @param topNode Top-level PHCompositeNode used to search for DST, detector, input, and output nodes. + * + * @throws std::runtime_error If the DST node is not found, if either input container is missing, + * or if the two input containers have different sizes. + */ +void CombineTowerInfo::CreateNodes(PHCompositeNode* topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode* dstNode = + dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + + if (!dstNode) + { + throw std::runtime_error("CombineTowerInfo: DST node not found"); + } + + PHCompositeNode *DetNode = dynamic_cast(iter.findFirst("PHCompositeNode", m_detector)); + + m_towersA = findNode::getClass(topNode, m_inputNodeA); + m_towersB = findNode::getClass(topNode, m_inputNodeB); + + if (!m_towersB) + { + std::cout << "CombineTowerInfo: " <(dstNode, m_outputNode); + if (!m_towersOut) + { + m_towersOut = + dynamic_cast(m_towersA->CloneMe()); + + auto* node = new PHIODataNode( + m_towersOut, m_outputNode, "PHObject"); + + DetNode->addNode(node); + } + + if (m_towersA->size() != m_towersB->size()) + { + throw std::runtime_error("CombineTowerInfo: input containers have different sizes"); + } +} + +/** + * @brief Populate the output TowerInfoContainer by merging corresponding towers from the two inputs. + * + * For each tower index, copies the contents of the tower from input A into the output container + * and sets the output tower's energy to the sum of the energies from input A and input B. + * + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ +int CombineTowerInfo::process_event(PHCompositeNode* /*topNode*/) +{ + const unsigned int ntowers = m_towersA->size(); + + for (unsigned int ich = 0; ich < ntowers; ++ich) + { + TowerInfo* towerA = m_towersA->get_tower_at_channel(ich); + TowerInfo* towerB = m_towersB->get_tower_at_channel(ich); + TowerInfo* towerO = m_towersOut->get_tower_at_channel(ich); + + towerO->copy_tower(towerA); + + const float e_sum = towerA->get_energy() + towerB->get_energy(); + towerO->set_energy(e_sum); + } + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/CaloEmbedding/CombineTowerInfo.h b/offline/packages/CaloEmbedding/CombineTowerInfo.h new file mode 100644 index 0000000000..3b7e784188 --- /dev/null +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.h @@ -0,0 +1,59 @@ +#ifndef COMBINETOWERINFO_H +#define COMBINETOWERINFO_H + +#include + +#include + +class PHCompositeNode; +class TowerInfoContainer; + +class CombineTowerInfo : public SubsysReco +{ + public: + explicit CombineTowerInfo(const std::string& name = "CombineTowerInfo"); + ~CombineTowerInfo() override = default; + + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + + /** + * Set the input node name for tower container A. + * @param name Name of the node to read TowerInfoContainer A from. + */ +void set_inputNodeA(const std::string& name) { m_inputNodeA = name; } + /** + * Set the name of the input node for tower container B. + * @param name Name of the input node from which TowerInfoContainer B will be read. + */ +void set_inputNodeB(const std::string& name) { m_inputNodeB = name; } + /** + * Set the name of the output node where combined TowerInfo will be stored. + * @param name Name of the output node. + */ +void set_outputNode(const std::string& name) { m_outputNode = name; } + /** + * Set the detector identifier used when combining tower information. + * @param name Name of the detector. + */ +void set_detector(const std::string& name) { m_detector = name; } + + private: + void CreateNodes(PHCompositeNode* topNode); + + std::string m_inputNodeA; + std::string m_inputNodeB; + std::string m_outputNode; + std::string m_detector; + + TowerInfoContainer* m_towersA{nullptr}; + TowerInfoContainer* m_towersB{nullptr}; + /** + * @brief Pointer to the output TowerInfoContainer that stores combined tower information. + * + * Initialized to nullptr and set during initialization when the output node/container is created. + */ +TowerInfoContainer* m_towersOut{nullptr}; +}; + +#endif diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.cc b/offline/packages/CaloEmbedding/CopyIODataNodes.cc index 0d4d4536ff..f7eb87379d 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.cc +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.cc @@ -7,6 +7,9 @@ #include +#include +#include + #include #include @@ -25,7 +28,15 @@ CopyIODataNodes::CopyIODataNodes(const std::string &name) { } -//____________________________________________________________________________.. +/** + * @brief Initialize run-time IO data nodes in the output top node based on enabled copy flags. + * + * For each enabled m_Copy* flag, ensures the corresponding IO data node is created or copied + * from the provided source topNode into the Fun4AllServer's output top node. + * + * @param topNode Source top-level node from which IO data nodes are read. + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ int CopyIODataNodes::InitRun(PHCompositeNode *topNode) { Fun4AllServer *se = Fun4AllServer::instance(); @@ -57,11 +68,24 @@ int CopyIODataNodes::InitRun(PHCompositeNode *topNode) { CreateSyncObject(topNode, se->topNode()); } + if (m_CopyTowerInfoFlag) + { + CreateTowerInfo(topNode, se->topNode()); + } return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. +/** + * @brief Copies enabled event-level IO data nodes from a source node into the framework top node. + * + * For each enabled copy flag (event header, centrality info, global vertex map, minimum-bias info, + * MbdOut, sync object, and tower info), invokes the corresponding copy routine to transfer data + * from the provided source topNode into the Fun4AllServer top node. + * + * @param topNode Source PHCompositeNode containing event-level IO data to copy. + * @return int Fun4AllReturnCodes::EVENT_OK on completion. + */ int CopyIODataNodes::process_event(PHCompositeNode *topNode) { Fun4AllServer *se = Fun4AllServer::instance(); @@ -89,6 +113,10 @@ int CopyIODataNodes::process_event(PHCompositeNode *topNode) { CopySyncObject(topNode, se->topNode()); } + if (m_CopyTowerInfoFlag) + { + CopyTowerInfo(topNode, se->topNode()); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -277,6 +305,16 @@ void CopyIODataNodes::CreateMinimumBiasInfo(PHCompositeNode *from_topNode, PHCom return; } +/** + * @brief Copy MinimumBiasInfo data from a source node tree into a destination node tree. + * + * Copies the contents of the `MinimumBiasInfo` object found under `from_topNode` into the + * `MinimumBiasInfo` object found under `to_topNode` by invoking the source object's `CopyTo`. + * If the module verbosity is greater than zero, prints identify() information for both objects. + * + * @param from_topNode Top-level node containing the source `MinimumBiasInfo`. + * @param to_topNode Top-level node containing the destination `MinimumBiasInfo`. + */ void CopyIODataNodes::CopyMinimumBiasInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { MinimumBiasInfo *from_minimumbiasinfo = findNode::getClass(from_topNode, "MinimumBiasInfo"); @@ -293,6 +331,51 @@ void CopyIODataNodes::CopyMinimumBiasInfo(PHCompositeNode *from_topNode, PHCompo return; } +/** + * @brief Copy all tower entries from the source TowerInfoContainer to the destination. + * + * Iterates the source TowerInfoContainer identified by from_towerInfo_name and + * copies each TowerInfo into the corresponding channel in the destination + * TowerInfoContainer identified by to_towerInfo_name. When verbosity is enabled, + * prints identify() information for both containers. + * + * @param from_topNode Top-level node containing the source TowerInfoContainer. + * @param to_topNode Top-level node containing (or receiving) the destination TowerInfoContainer. + */ +void CopyIODataNodes::CopyTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + TowerInfoContainer *from_towerInfo = findNode::getClass(from_topNode, from_towerInfo_name); + TowerInfoContainer *to_towerInfo = findNode::getClass( to_topNode, to_towerInfo_name); + unsigned int ntowers = from_towerInfo->size(); + for (unsigned int ch = 0; ch < ntowers; ++ch) + { + TowerInfo *from_tow = from_towerInfo->get_tower_at_channel(ch); + to_towerInfo->get_tower_at_channel(ch)->copy_tower(from_tow); + } + + if (Verbosity() > 0) + { + std::cout << "From TowerInfoContainer identify()" << std::endl; + from_towerInfo->identify(); + std::cout << "To TowerInfoCOntainer identify()" << std::endl; + to_towerInfo->identify(); + } + + return; +} + + +/** + * @brief Ensure an MbdOut node exists in the destination and create it by cloning the source if absent. + * + * If an MbdOut exists under from_topNode, this function ensures a corresponding MbdOut + * is present under to_topNode; if the destination node is missing, it creates a DST/MBD + * subtree (if needed), clones the source MbdOut, and attaches it as "MbdOut". + * If the source MbdOut cannot be found, the function disables the m_CopyMbdOutFlag. + * + * @param from_topNode Source top-level node to read the MbdOut from. + * @param to_topNode Destination top-level node to create or attach the cloned MbdOut to. + */ void CopyIODataNodes::CreateMbdOut(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { @@ -330,6 +413,57 @@ void CopyIODataNodes::CreateMbdOut(PHCompositeNode *from_topNode, PHCompositeNod } +/** + * @brief Ensure a TowerInfoContainer exists under the destination top node by cloning it from the source if absent. + * + * If a TowerInfoContainer named by `from_towerInfo_name` exists under `from_topNode` but not under `to_topNode`, + * this function clones the source container and attaches it to a `DST` composite node under `to_topNode` using + * the name `to_towerInfo_name`. If the source container cannot be found, the copy flag `m_CopyTowerInfoFlag` + * is disabled and no destination container is created. + * + * @param from_topNode Top-level node to read the source TowerInfoContainer from. + * @param to_topNode Top-level node to attach the cloned TowerInfoContainer to (under a `DST` composite node if needed). + */ +void CopyIODataNodes::CreateTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + std::cout << "copying tower info" << std::endl; + TowerInfoContainer *from_towerInfo = findNode::getClass(from_topNode, from_towerInfo_name); + if (!from_towerInfo) + { + std::cout << "Could not locate TowerInfoContainer on " << from_topNode->getName() << std::endl; + m_CopyTowerInfoFlag = false; + return; + } + TowerInfoContainer *to_towerInfo = findNode::getClass(to_topNode, to_towerInfo_name); + if (!to_towerInfo) + { + PHNodeIterator iter(to_topNode); + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + dstNode = new PHCompositeNode("DST"); + to_topNode->addNode(dstNode); + } + to_towerInfo = dynamic_cast(from_towerInfo->CloneMe()); + PHIODataNode *newNode = new PHIODataNode(to_towerInfo, to_towerInfo_name, "PHObject"); + dstNode->addNode(newNode); + } + return; +} + + + + +/** + * @brief Copy MbdOut data from a source composite node into a destination composite node. + * + * Finds the MbdOut object under from_topNode and the MbdOut object under to_topNode, + * copies the contents from the source into the destination, and (when Verbosity() > 0) + * prints identify() information for both objects. + * + * @param from_topNode Composite node containing the source MbdOut. + * @param to_topNode Composite node containing the destination MbdOut. + */ void CopyIODataNodes::CopyMbdOut(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { MbdOut *from_mbdout = findNode::getClass(from_topNode, "MbdOut"); @@ -385,4 +519,4 @@ void CopyIODataNodes::CopySyncObject(PHCompositeNode *from_topNode, PHCompositeN to_syncobject->identify(); } return; -} +} \ No newline at end of file diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.h b/offline/packages/CaloEmbedding/CopyIODataNodes.h index 08626bdafb..e7eb4637f1 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.h +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.h @@ -35,6 +35,18 @@ class CopyIODataNodes : public SubsysReco void CopyMbdOut(bool flag = true) { m_CopyMbdOutFlag = flag; } void CopyRunHeader(bool flag = true) { m_CopyRunHeaderFlag = flag; } void CopySyncObject(bool flag = true) { m_CopySyncObjectFlag = flag; } + /** + * Enable copying of tower information and set the source and destination towerInfo node names. + * @param set_from_towerInfo_name Name of the source towerInfo node to copy from. + * @param set_to_towerInfo_name Name of the destination towerInfo node to copy to. + */ + void set_CopyTowerInfo(const std::string& set_from_towerInfo_name,const std::string& set_to_towerInfo_name) + { + from_towerInfo_name = set_from_towerInfo_name; + to_towerInfo_name = set_to_towerInfo_name; + m_CopyTowerInfoFlag = true; + return; + } private: void CreateCentralityInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); @@ -56,6 +68,8 @@ class CopyIODataNodes : public SubsysReco void CreateSyncObject(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); void CopySyncObject(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CopyTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CreateTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); bool m_CopyCentralityInfoFlag = true; bool m_CopyEventHeaderFlag = true; @@ -64,6 +78,10 @@ class CopyIODataNodes : public SubsysReco bool m_CopyMbdOutFlag = true; bool m_CopyRunHeaderFlag = true; bool m_CopySyncObjectFlag = true; + bool m_CopyTowerInfoFlag = false; + + std::string from_towerInfo_name = {}; + std::string to_towerInfo_name = {}; }; -#endif // COPYIODATANODES_H +#endif // COPYIODATANODES_H \ No newline at end of file diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.cc b/offline/packages/CaloReco/PhotonClusterBuilder.cc index 263ae04ef0..2525d7432c 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.cc +++ b/offline/packages/CaloReco/PhotonClusterBuilder.cc @@ -272,6 +272,21 @@ void PhotonClusterBuilder::calculate_bdt_score(PhotonClusterv1* photon) photon->set_shower_shape_parameter("bdt_score", bdt_score); } +/** + * @brief Compute and assign electromagnetic shower-shape, HCAL, timing, and isolation parameters for a photon cluster. + * + * Calculates a 7x7 EMCal energy grid centered on the cluster, derives standard shower-shape sums and moment-like variables + * (e11, e22, e33, e55, e77, e13, e15, e17, e31, e51, e71, e35, e37, e53, e73, e57, e75, weta, wphi, weta_cog, wphi_cog, etc.), + * cluster timing and saturation counts, nearest HCAL tower matching with 2x2/3x3 HCAL Et sums, and calorimeter-layer isolation + * values at multiple radii. All computed quantities are stored on the provided PhotonClusterv1 via set_shower_shape_parameter. + * + * If the input RawCluster contains no shower-shape data (empty), the function returns without modifying the photon. + * + * @param rc Pointer to the input RawCluster providing tower map and shower-shape inputs. + * @param photon PhotonClusterv1 object to receive computed shower-shape, HCAL and isolation parameters. + * @param cluster_eta Cluster pseudorapidity used for ET and isolation calculations. + * @param cluster_phi Cluster phi used for grid centering and isolation calculations. + */ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonClusterv1* photon, float cluster_eta, float cluster_phi) { std::vector showershape = rc->get_shower_shapes(m_shape_min_tower_E); @@ -566,6 +581,7 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster photon->set_shower_shape_parameter("et3", showershape[2]); photon->set_shower_shape_parameter("et4", showershape[3]); photon->set_shower_shape_parameter("e11", e11); + photon->set_shower_shape_parameter("e22", showershape[8] + showershape[9] + showershape[10] + showershape[11]); photon->set_shower_shape_parameter("e33", e33); photon->set_shower_shape_parameter("e55", e55); photon->set_shower_shape_parameter("e77", e77); @@ -909,4 +925,4 @@ double PhotonClusterBuilder::deltaR(double eta1, double phi1, double eta2, doubl dphi += 2 * M_PI; } return sqrt(pow(eta1 - eta2, 2) + pow(dphi, 2)); -} +} \ No newline at end of file diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 38b60d55ba..b80f461508 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -132,6 +132,20 @@ int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) return 0; } +/** + * @brief Process a single event: build decay candidates and handle output. + * + * Processes event data from the provided node tree to construct candidate mother, + * intermediate, and daughter KFParticle objects according to the configured decay + * descriptor and options. If no tracks or (when required) no vertices are present, + * the event is skipped. For each candidate, the method optionally opens the output + * file (on the first candidate), increments the candidate counter, fills output + * branches, and (when enabled) writes candidate information to the DST node and/or + * prints human-readable summaries. + * + * @param topNode Top-level node containing event data (tracks, vertices, etc.). + * @return int Fun4AllReturnCodes::EVENT_OK on success (event processed or skipped). + */ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) { @@ -148,7 +162,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) { std::cout << "KFParticle: Event skipped as there are no tracks" << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + return Fun4AllReturnCodes::EVENT_OK; } if (!m_use_fake_pv) @@ -162,7 +176,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) { std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + return Fun4AllReturnCodes::EVENT_OK; } } else @@ -174,10 +188,9 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) { std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + return Fun4AllReturnCodes::EVENT_OK; } } - } createDecay(topNode, mother, vertex_kfparticle, daughters, intermediates, nPVs); @@ -569,4 +582,4 @@ void KFParticle_sPHENIX::getField() fieldmap->Delete(); fin->Close(); -} +} \ No newline at end of file diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc index 8fe89b5019..18c6961c62 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc @@ -44,6 +44,18 @@ namespace genfit namespace PHGenFit { + /** + * @brief Constructs a Fitter using a geometry file and configures field, materials, fitter type, and optional event display. + * + * Initializes the geometry from the given TGeo file, installs the provided PHField into GenFit, configures material effects, + * optionally enables the GenFit event display, and selects the internal GenFit fitter implementation according to fitter_choice. + * + * @param tgeo_file_name Path to a ROOT TGeo geometry file to import. + * @param field Pointer to a PHField used to construct the GenFit field mapping; must not be null. + * @param fitter_choice Name of the fitter implementation to instantiate (e.g., "KalmanFitterRefTrack", "KalmanFitter", "DafSimple", "DafRef"). + * @param /*track_rep_choice*/ Placeholder for track representation choice (ignored by this constructor). + * @param doEventDisplay If true, enables and retains a GenFit EventDisplay instance for later use. + */ Fitter::Fitter( const std::string& tgeo_file_name, const PHField* field, @@ -51,9 +63,9 @@ namespace PHGenFit const std::string& /*track_rep_choice*/, const bool doEventDisplay) : verbosity(1000) + , _tgeo_manager(new TGeoManager("Default", "Geane geometry")) , _doEventDisplay(doEventDisplay) { - _tgeo_manager = new TGeoManager("Default", "Geane geometry"); TGeoManager::Import(tgeo_file_name.data()); assert(field); @@ -73,26 +85,24 @@ namespace PHGenFit } // init fitter - if (fitter_choice.compare("KalmanFitterRefTrack") == 0) + if (fitter_choice == "KalmanFitterRefTrack") { _fitter = new genfit::KalmanFitterRefTrack(); } - else if (fitter_choice.compare("KalmanFitter") == 0) -// NOLINTNEXTLINE(bugprone-branch-clone) - { + else if (fitter_choice == "KalmanFitter") + { // NOLINT(bugprone-branch-clone) _fitter = new genfit::KalmanFitter(); } - else if (fitter_choice.compare("DafSimple") == 0) + else if (fitter_choice == "DafSimple") { _fitter = new genfit::DAF(false); } - else if (fitter_choice.compare("DafRef") == 0) + else if (fitter_choice == "DafRef") { _fitter = new genfit::DAF(true); } else -// NOLINTNEXTLINE(bugprone-branch-clone) - { + { // NOLINT(bugprone-branch-clone) _fitter = new genfit::KalmanFitter(); } @@ -203,6 +213,17 @@ namespace PHGenFit return new Fitter(tgeo_manager, fieldMap, fitter_choice, track_rep_choice, doEventDisplay); } + /** + * @brief Constructs a Fitter using an existing geometry manager and field map, and configures the chosen GenFit fitter and optional event display. + * + * Initializes the GenFit FieldManager and MaterialEffects, creates the selected fitter implementation, and enables event display if requested. + * + * @param tgeo_manager Pointer to an existing TGeoManager that provides detector geometry for fitting. + * @param fieldMap Pointer to a GenFit magnetic field map used during propagation and fitting. + * @param fitter_choice Enum value selecting which GenFit fitter implementation to instantiate (e.g., KalmanFitter, KalmanFitterRefTrack, DafSimple, DafRef). + * @param /*track_rep_choice*/ Unused parameter retained for API compatibility; the constructor ignores track representation choice. + * @param doEventDisplay If true, initializes and retains a GenFit EventDisplay instance for visualizing fitted tracks. + */ Fitter::Fitter(TGeoManager* tgeo_manager, genfit::AbsBField* fieldMap, const PHGenFit::Fitter::FitterType& fitter_choice, const PHGenFit::Fitter::TrackRepType& /*track_rep_choice*/, @@ -235,7 +256,7 @@ namespace PHGenFit { _fitter = new genfit::KalmanFitterRefTrack(); } - if (fitter_choice == PHGenFit::Fitter::DafSimple) + else if (fitter_choice == PHGenFit::Fitter::DafSimple) { _fitter = new genfit::DAF(false); } @@ -266,6 +287,19 @@ namespace PHGenFit return new Fitter(tgeo_manager, fieldMap, fitter_choice, track_rep_choice, doEventDisplay); } + /** + * @brief Constructs a Fitter using an existing geometry manager and field map. + * + * Initializes the GenFit field manager and material effects, optionally enables + * the event display, and instantiates the requested fitter implementation. + * + * @param tgeo_manager Pointer to an existing TGeoManager that provides geometry. + * @param fieldMap GenFit magnetic field map used for propagation. + * @param fitter_choice Name of the fitter to create; supported values: + * "KalmanFitterRefTrack", "KalmanFitter", "DafSimple", "DafRef". + * If the value is unrecognized, no fitter is created and an error is logged. + * @param doEventDisplay If true, acquires the GenFit EventDisplay singleton for visualization. + */ Fitter::Fitter(TGeoManager* tgeo_manager, genfit::AbsBField* fieldMap, const std::string& fitter_choice, const std::string& /*track_rep_choice*/, const bool doEventDisplay) @@ -289,19 +323,19 @@ namespace PHGenFit } // init fitter - if (fitter_choice.compare("KalmanFitterRefTrack") == 0) + if (fitter_choice == "KalmanFitterRefTrack") { _fitter = new genfit::KalmanFitterRefTrack(); } - else if (fitter_choice.compare("KalmanFitter") == 0) + else if (fitter_choice == "KalmanFitter") { _fitter = new genfit::KalmanFitter(); } - else if (fitter_choice.compare("DafSimple") == 0) + else if (fitter_choice == "DafSimple") { _fitter = new genfit::DAF(false); } - else if (fitter_choice.compare("DafRef") == 0) + else if (fitter_choice == "DafRef") { _fitter = new genfit::DAF(true); } @@ -344,4 +378,4 @@ namespace PHGenFit return new Fitter(tgeo_manager, fieldMap, fitter_choice, track_rep_choice, doEventDisplay); } -} // namespace PHGenFit +} // namespace PHGenFit \ No newline at end of file diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Track.cc b/offline/packages/PHGenFitPkg/PHGenFit/Track.cc index b1643e8cd0..4ace2d78f7 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Track.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Track.cc @@ -48,8 +48,8 @@ #define WILD_DOUBLE (-999999) -//#define _DEBUG_ -//#define _PRINT_MATRIX_ +// #define _DEBUG_ +// #define _PRINT_MATRIX_ #ifdef _DEBUG_ #include @@ -59,12 +59,26 @@ ofstream fout_matrix("matrix.txt"); namespace PHGenFit { + /** + * @brief Constructs a PHGenFit::Track seeded with a six-dimensional initial state. + * + * Initializes an internal genfit::Track using the provided track representation and a seed + * state defined by position, momentum, and covariance, and sets the verbosity level. + * + * @param rep Pointer to the GenFit track representation used for propagation and fitting. + * @param seed_pos Seed position in global coordinates. + * @param seed_mom Seed momentum in global coordinates. + * @param seed_cov 6x6 covariance matrix for the seed state (position and momentum). + * @param v Verbosity level for logging and debug output. + * + * The constructor allocates a new genfit::Track stored in the member `_track`. Ownership of + * `rep` is not transferred by this constructor (caller is responsible for managing it). + */ Track::Track(genfit::AbsTrackRep* rep, const TVector3& seed_pos, const TVector3& seed_mom, const TMatrixDSym& seed_cov, const int v) + : verbosity(v) { // TODO Add input param check - verbosity = v; - genfit::MeasuredStateOnPlane seedMSoP(rep); seedMSoP.setPosMomCov(seed_pos, seed_mom, seed_cov); // const genfit::StateOnPlane seedSoP(seedMSoP); @@ -77,15 +91,35 @@ namespace PHGenFit //_track = NEW(genfit::Track)(rep, seedState, seedCov); } + /** + * @brief Create a new Track by copying another Track's GenFit track and associated metadata. + * + * Performs a deep copy of the underlying genfit::Track and duplicates cluster ID and cluster key + * vectors as well as the vertex identifier. + * + * @param t Source track to copy. + */ Track::Track(const PHGenFit::Track& t) + : verbosity(t.verbosity) + , _track(new genfit::Track(*(t.getGenFitTrack()))) + , _clusterIDs(t.get_cluster_IDs()) + , _clusterkeys(t.get_cluster_keys()) + , _vertex_id(t.get_vertex_id()) { - _track = new genfit::Track(*(t.getGenFitTrack())); - verbosity = t.verbosity; - _clusterIDs = t.get_cluster_IDs(); - _clusterkeys = t.get_cluster_keys(); - _vertex_id = t.get_vertex_id(); } + /** + * @brief Adds a measurement to the track and records its cluster metadata. + * + * Converts the provided PHGenFit::Measurement into a GenFit measurement, inserts a new TrackPoint + * holding that measurement into the internal GenFit track, and appends the measurement's cluster ID + * and cluster key to the track's metadata. The function takes ownership of the `measurement` and + * deletes it before returning. + * + * @param measurement Pointer to the measurement to add; ownership is transferred and the object + * will be deleted by this function. + * @return int `0` on success. + */ int Track::addMeasurement(PHGenFit::Measurement* measurement) { std::vector msmts; @@ -182,6 +216,14 @@ namespace PHGenFit return pathlenth; } + /** + * Create and return a `MeasuredStateOnPlane` representing the track state extrapolated to the plane defined by origin `O` and normal `n`. + * + * @param O Origin point of the destination plane. + * @param n Normal vector of the destination plane. + * @param tr_point_id Index of the track point used as the extrapolation base. + * @return genfit::MeasuredStateOnPlane* Pointer to a newly allocated `MeasuredStateOnPlane` containing the extrapolated state, or `nullptr` if the extrapolation failed. + */ genfit::MeasuredStateOnPlane* Track::extrapolateToPlane(const TVector3& O, const TVector3& n, const int tr_point_id) const { genfit::MeasuredStateOnPlane* state = new genfit::MeasuredStateOnPlane(); @@ -191,12 +233,21 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } + /** + * @brief Extrapolates the track state to the closest point on a 3D line and writes the resulting plane state. + * + * Uses the track's fitter backward-update state at the specified track point as the starting state, extrapolates that state to the line defined by a point and a direction, and stores the resulting MeasuredStateOnPlane in `state`. + * + * @param state Reference that will be overwritten with the extrapolated MeasuredStateOnPlane. + * @param line_point A point on the destination line (world coordinates). + * @param line_direction Direction vector of the destination line (world coordinates). + * @param tr_point_id Identifier of the TrackPoint whose fitter state is used as the starting state. + * @return double Path length along the track from the starting state to the line, or `WILD_DOUBLE` if the TrackPoint is missing or extrapolation fails. + */ double Track::extrapolateToLine(genfit::MeasuredStateOnPlane& state, const TVector3& line_point, const TVector3& line_direction, const int tr_point_id) const { double pathlenth = WILD_DOUBLE; @@ -231,6 +282,14 @@ namespace PHGenFit return pathlenth; } + /** + * @brief Extrapolates the track state to the given infinite line and produces the state at the point of closest approach. + * + * @param line_point A point on the target line. + * @param line_direction Direction vector of the target line. + * @param tr_point_id Index of the track point to use as the source state for extrapolation. + * @return genfit::MeasuredStateOnPlane* Pointer to a heap-allocated state at the extrapolation point, or `nullptr` if extrapolation failed. Caller takes ownership of the returned pointer. + */ genfit::MeasuredStateOnPlane* Track::extrapolateToLine(const TVector3& line_point, const TVector3& line_direction, const int tr_point_id) const { genfit::MeasuredStateOnPlane* state = new genfit::MeasuredStateOnPlane(); @@ -240,12 +299,24 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } + /** + * @brief Extrapolates the track state to an infinite cylinder and returns the path length. + * + * Uses the track's fitted (forward or backward) state at the specified track point when available; + * otherwise seeds a state from the track's seed position/momentum/covariance before extrapolation. + * + * @param state Output measured state on the plane at the extrapolation point (modified on success). + * @param radius Radius of the target cylinder. + * @param line_point A point on the cylinder's symmetry axis. + * @param line_direction Direction vector of the cylinder's symmetry axis. + * @param tr_point_id Index of the track point whose fitter state should be used as the starting state. + * @param direction Use `1` to prefer the forward update, `-1` to prefer the backward update. + * @return double Path length along the track from the starting state to the cylinder surface; `WILD_DOUBLE` on failure. + */ double Track::extrapolateToCylinder(genfit::MeasuredStateOnPlane& state, double radius, const TVector3& line_point, const TVector3& line_direction, const int tr_point_id, const int direction) const { #ifdef _DEBUG_ @@ -351,6 +422,20 @@ namespace PHGenFit return pathlenth; } + /** + * @brief Allocate and return the track state extrapolated to a cylindrical surface. + * + * Allocates a new genfit::MeasuredStateOnPlane, attempts to extrapolate the track to + * the cylinder defined by a central line and radius, and returns the resulting state. + * + * @param radius Radius of the cylinder to extrapolate to. + * @param line_point A point on the central axis of the cylinder. + * @param line_direction Direction vector of the cylinder's central axis. + * @param tr_point_id Track point index used as the starting reference for extrapolation. + * @param direction Extrapolation direction: must be +1 or -1. + * @return genfit::MeasuredStateOnPlane* Pointer to the allocated state on success; `nullptr` on failure. + * The caller takes ownership of the returned pointer and is responsible for deleting it. + */ genfit::MeasuredStateOnPlane* Track::extrapolateToCylinder(double radius, const TVector3& line_point, const TVector3& line_direction, const int tr_point_id, const int direction) const { assert(direction == 1 || direction == -1); @@ -361,12 +446,25 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } + /** + * @brief Performs a Kalman update using one or more measurements and produces candidate tracks with incremental chi2. + * + * For each measurement in `measurements` this creates a copy of the current track, applies a Kalman-predict/ update + * sequence at a plane constructed from the measurement, and if the update yields a positive chi2 increment inserts the + * candidate track into `incr_chi2s_new_tracks` keyed by that chi2 increment. + * + * @param measurements Vector of measurements to apply; each measurement is consumed (ownership transferred). + * @param incr_chi2s_new_tracks Map where keys are chi2 increments and values are shared pointers to the corresponding new tracks produced by the update. + * @param base_tp_idx Index of the base TrackPoint to obtain the reference fitter info/state for prediction. + * @param direction Direction for prediction/update (typically ±1) used to select forward/backward updates. + * @param blowup_factor Factor to multiply the state covariance before prediction when greater than 1. + * @param use_fitted_state If true, initialize from the fitter's fitted state; otherwise initialize from the fitter's update in the specified direction. + * @return int -1 if `measurements` is empty, 0 on success. + */ int Track::updateOneMeasurementKalman( const std::vector& measurements, std::map >& incr_chi2s_new_tracks, @@ -385,7 +483,7 @@ namespace PHGenFit << std::endl; #endif - if (measurements.size() == 0) + if (measurements.empty()) { return -1; } @@ -437,11 +535,11 @@ namespace PHGenFit #endif continue; } - //#ifdef _DEBUG_ + // #ifdef _DEBUG_ // std::cout << __LINE__ << "\n ###################################################################"<Print(); // std::cout << __LINE__ << "\n ###################################################################"<getFittedState(true)); @@ -579,7 +677,7 @@ namespace PHGenFit // std::cout << err_phi << "\t" << err_z << "\t"; } #endif - for (auto rawMeasurement : rawMeasurements) + for (auto* rawMeasurement : rawMeasurements) { fi->addMeasurementsOnPlane( rawMeasurement->constructMeasurementsOnPlane(*state)); @@ -598,7 +696,7 @@ namespace PHGenFit << ": size of fi's MeasurementsOnPlane: " << measurements_on_plane.size() << std::endl; #endif - for (auto it : measurements_on_plane) + for (auto* it : measurements_on_plane) { const genfit::MeasurementOnPlane& mOnPlane = *it; // const double weight = mOnPlane.getWeight(); @@ -760,6 +858,18 @@ namespace PHGenFit return pathlenth; } + /** + * @brief Extrapolates the track state to a given 3D point and returns the resulting plane state. + * + * Extrapolates from the track (using the specified track point as the reference) to the point P and returns + * a newly allocated genfit::MeasuredStateOnPlane representing the extrapolated state on the plane that + * GenFit uses to represent the point. Ownership of the returned pointer is transferred to the caller. + * + * @param P Target 3D point to extrapolate to. + * @param tr_point_id Index of the track point to use as the reference state for extrapolation. + * If invalid or if extrapolation fails, the function returns nullptr. + * @return genfit::MeasuredStateOnPlane* Pointer to the extrapolated state on success, `nullptr` on failure. + */ genfit::MeasuredStateOnPlane* Track::extrapolateToPoint(const TVector3& P, const int tr_point_id) const { genfit::MeasuredStateOnPlane* state = new genfit::MeasuredStateOnPlane(); @@ -769,12 +879,14 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + return state; } + /** + * @brief Retrieve the fit's chi-square value. + * + * @return The chi-square (chi2) of the track fit; `NaN` if the cardinal representation or fit status is unavailable. + */ double Track::get_chi2() const { double chi2 = std::numeric_limits::quiet_NaN(); @@ -903,4 +1015,4 @@ namespace PHGenFit return mom; } -} // namespace PHGenFit +} // namespace PHGenFit \ No newline at end of file diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc index b519fd472e..2a222fa6c0 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc @@ -1,4 +1,3 @@ - #include "TriggerDSTSkimmer.h" #include @@ -17,9 +16,31 @@ TriggerDSTSkimmer::TriggerDSTSkimmer(const std::string &name) { } -//____________________________________________________________________________.. +/** + * Process a single event applying trigger selection and optional acceptance limits. + * + * Validates configured trigger indices, optionally aborts when the maximum number + * of accepted events has been reached, and when trigger indices are provided + * checks the Gl1Packet ScaledVector bits to determine whether any requested + * trigger fired. If the event passes selection, increments the accepted-events + * counter. + * + * @param topNode Root node for event data access (PHCompositeNode). + * @return Fun4AllReturnCodes::EVENT_OK when the event is accepted. + * @return Fun4AllReturnCodes::ABORTEVENT when the event is rejected due to + * having reached the acceptance limit (when enabled), missing Gl1Packet, + * or none of the requested triggers fired. + * @return Fun4AllReturnCodes::ABORTRUN when a configured trigger index is out + * of the valid range [0..63]. + */ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) { + + if ((accepted_events >= max_accept) && use_max_accept) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + if (Verbosity() > 0) { if (ievent % 1000 == 0) @@ -45,7 +66,7 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) if (n_trigger_index != 0) { bool trigger_fired = false; - Gl1Packet *_gl1PacketInfo = findNode::getClass(topNode, "GL1Packet"); + Gl1Packet *_gl1PacketInfo = findNode::getClass(topNode, 14001); int gl1_trigger_vector_scaled[64] = {0}; if (_gl1PacketInfo) { @@ -61,6 +82,7 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) std::cout << "TriggerDSTSkimmer::process_event - Error - Can't find Trigger Node Gl1Packet therefore no selection can be made" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } + for (int it = 0; it < n_trigger_index; ++it) { if (gl1_trigger_vector_scaled[m_trigger_index[it]] == 1) @@ -74,5 +96,8 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } } + + accepted_events++; + return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h index dfb2c47a7c..492757ecb6 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h @@ -20,12 +20,55 @@ class TriggerDSTSkimmer : public SubsysReco int process_event(PHCompositeNode *topNode) override; - void SetTrigger(std::vector &trigger_vector) {m_trigger_index = trigger_vector;} + /** + * Set the list of trigger indices used to decide which events to accept. + * + * Copies the provided trigger indices into the internal trigger-index list, + * replacing any previously set indices. + * + * @param trigger_vector Vector of trigger indices to use for event selection. + */ +void SetTrigger(std::vector &trigger_vector) {m_trigger_index = trigger_vector;} + + /** + * Enable the maximum-accept mode and configure the maximum number of accepted events. + * @param max_events Maximum number of events to accept; when this limit is reached, the skimmer will stop accepting additional events. + */ + void set_accept_max(int max_events) + { + use_max_accept = true; + max_accept = max_events; + return; + } private: std::vector m_trigger_index{10}; - int ievent{0}; + /** + * Number of events processed by this skimmer instance. + * + * Incremented for each call to process_event to track the current event index. + */ +int ievent{0}; + + /** + * @brief Number of events accepted by the skimmer. + * + * Incremented each time an event passes selection; used to track progress and to enforce + * the configured maximum number of accepted events when that limit is enabled. + */ +int accepted_events{0}; + /** + * Maximum number of events to accept when maximum-accept mode is enabled. + * + * Initial value is 0. The limit is applied only if `use_max_accept` is set (via set_accept_max). + */ +int max_accept{0}; + /** + * When true, the skimmer enforces the maximum accepted-events limit defined by `max_accept`. + */ +bool use_max_accept{false}; + }; -#endif // JETDSTSKIMMER_H +#endif // JETDSTSKIMMER_H \ No newline at end of file diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 9823d337f6..8c589bb57c 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -14,6 +14,10 @@ #include #include +#include +#include +#include + #include #include @@ -50,11 +54,91 @@ DetermineTowerBackground::DetermineTowerBackground(const std::string &name) _UE.resize(3, std::vector(1, 0)); } +/** + * @brief Initialize the run and set up output nodes, optionally loading average calorimeter v2 calibrations. + * + * If flow mode equals 4, attempts to load average calorimeter v2 calibrations before node creation; + * if calibration loading fails, the run initialization is aborted. + * + * @param topNode Top-level node from which to create or attach output nodes. + * @return int Fun4All return code: `Fun4AllReturnCodes::ABORTRUN` if calibration loading failed when required, + * otherwise the result of creating the output node (e.g., `EVENT_OK` on success). + */ int DetermineTowerBackground::InitRun(PHCompositeNode *topNode) { + if (_do_flow == 4) + { + if (Verbosity()) + { + std::cout << "Loading the average calo v2" << std::endl; + } + if (LoadCalibrations()) + { + std::cout << "Load calibrations failed." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + } + return CreateNode(topNode); } +/** + * @brief Load calo average v2 calibration and populate centrality v2 values. + * + * Loads calibration data from the configured CDB URL (or the overwrite path when set) + * and fills the internal _CENTRALITY_V2 vector with 100 values taken from the + * "jet_calo_v2" field for centrality bins 0–99. + * + * If no calibration path is found, the function prints an error message and terminates + * the process via exit(-1). + * + * @return int EVENT_OK on success. + */ +int DetermineTowerBackground::LoadCalibrations() +{ + + CDBTTree *cdbtree_calo_v2 = nullptr; + + std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); + if (m_overwrite_average_calo_v2) + { + calibdir = m_overwrite_average_calo_v2_path; + } + + if (calibdir.empty()) + { + std::cout << "Could not find filename for calo average v2, exiting" << std::endl; + exit(-1); + } + + cdbtree_calo_v2 = new CDBTTree(calibdir); + + + cdbtree_calo_v2->LoadCalibrations(); + + _CENTRALITY_V2.assign(100,0); + + for (int icent = 0; icent < 100; icent++) + { + _CENTRALITY_V2[icent] = cdbtree_calo_v2->GetFloatValue(icent, "jet_calo_v2"); + } + + delete cdbtree_calo_v2; + + return Fun4AllReturnCodes::EVENT_OK; +} + +/** + * @brief Compute per-layer underlying-event (UE) tower densities and event flow (Psi2, v2) and store results in the node tree. + * + * Extracts tower and jet information from the provided node tree, selects seed regions, computes flow (from calo, sEPD, HIJING truth, or centrality depending on configuration), applies seed and bad-tower masking and flow modulation, calculates UE density per eta strip for EMCAL/IHCAL/OHCAL, and writes the results to the TowerBackground node. + * + * @param topNode Top-level PHCompositeNode containing detector, jet, eventplane, and centrality nodes required for the calculation. + * @return int Fun4AllReturnCodes::EVENT_OK on success; + * Fun4AllReturnCodes::ABORTRUN if required tower information is missing; + * -1 for fatal failures during flow extraction (e.g., missing truth or eventplane when required). + */ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) { @@ -481,7 +565,92 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) } } - if ( _do_flow >= 1 ) + + // Get psi + if (_do_flow == 2) + { // HIJING truth flow extraction + PHG4TruthInfoContainer *truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + + if (!truthinfo) + { + std::cout << "DetermineTowerBackground::process_event: FATAL , G4TruthInfo does not exist , cannot extract truth flow with do_flow = " << _do_flow << std::endl; + return -1; + } + + PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange(); + + float Hijing_Qx = 0; + float Hijing_Qy = 0; + + for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) + { + PHG4Particle *g4particle = iter->second; + + if (truthinfo->isEmbeded(g4particle->get_track_id()) != 0) + { + continue; + } + + TLorentzVector t; + t.SetPxPyPzE(g4particle->get_px(), g4particle->get_py(), g4particle->get_pz(), g4particle->get_e()); + + float truth_pt = t.Pt(); + if (truth_pt < 0.4) + { + continue; + } + float truth_eta = t.Eta(); + if (std::fabs(truth_eta) > 1.1) + { + continue; + } + float truth_phi = t.Phi(); + int truth_pid = g4particle->get_pid(); + + if (Verbosity() > 10) + { + std::cout << "DetermineTowerBackground::process_event: determining truth flow, using particle w/ pt / eta / phi " << truth_pt << " / " << truth_eta << " / " << truth_phi << " , embed / PID = " << truthinfo->isEmbeded(g4particle->get_track_id()) << " / " << truth_pid << std::endl; + } + + Hijing_Qx += truth_pt * std::cos(2 * truth_phi); + Hijing_Qy += truth_pt * std::sin(2 * truth_phi); + } + + _Psi2 = std::atan2(Hijing_Qy, Hijing_Qx) / 2.0; + + if (Verbosity() > 0) + { + std::cout << "DetermineTowerBackground::process_event: flow extracted from Hijing truth particles, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; + } + } + else if (_do_flow == 3 || _do_flow == 4) + { // sEPD event plane extraction + // get event plane map + EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); + if (!epmap) + { + std::cout << "DetermineTowerBackground::process_event: FATAL, EventplaneinfoMap does not exist, cannot extract sEPD flow with do_flow = " << _do_flow << std::endl; + exit(-1); + } + if (!(epmap->empty())) + { + auto *EPDNS = epmap->get(EventplaneinfoMap::sEPDNS); + _Psi2 = EPDNS->get_shifted_psi(2); + } + else + { + _is_flow_failure = true; + _Psi2 = 0; + } + + if (Verbosity() > 0) + { + std::cout << "DetermineTowerBackground::process_event: flow extracted from sEPD, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; + } + + } + + if ( _do_flow >= 1 && _do_flow < 4) { if (Verbosity() > 0) @@ -754,88 +923,6 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) { // Calo event plane _Psi2 = std::atan2(Q_y, Q_x) / 2.0; } - else if (_do_flow == 2) - { // HIJING truth flow extraction - PHG4TruthInfoContainer *truthinfo = findNode::getClass(topNode, "G4TruthInfo"); - - if (!truthinfo) - { - std::cout << "DetermineTowerBackground::process_event: FATAL , G4TruthInfo does not exist , cannot extract truth flow with do_flow = " << _do_flow << std::endl; - return -1; - } - - PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange(); - - float Hijing_Qx = 0; - float Hijing_Qy = 0; - - for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) - { - PHG4Particle *g4particle = iter->second; - - if (truthinfo->isEmbeded(g4particle->get_track_id()) != 0) - { - continue; - } - - TLorentzVector t; - t.SetPxPyPzE(g4particle->get_px(), g4particle->get_py(), g4particle->get_pz(), g4particle->get_e()); - - float truth_pt = t.Pt(); - if (truth_pt < 0.4) - { - continue; - } - float truth_eta = t.Eta(); - if (std::fabs(truth_eta) > 1.1) - { - continue; - } - float truth_phi = t.Phi(); - int truth_pid = g4particle->get_pid(); - - if (Verbosity() > 10) - { - std::cout << "DetermineTowerBackground::process_event: determining truth flow, using particle w/ pt / eta / phi " << truth_pt << " / " << truth_eta << " / " << truth_phi << " , embed / PID = " << truthinfo->isEmbeded(g4particle->get_track_id()) << " / " << truth_pid << std::endl; - } - - Hijing_Qx += truth_pt * std::cos(2 * truth_phi); - Hijing_Qy += truth_pt * std::sin(2 * truth_phi); - } - - _Psi2 = std::atan2(Hijing_Qy, Hijing_Qx) / 2.0; - - if (Verbosity() > 0) - { - std::cout << "DetermineTowerBackground::process_event: flow extracted from Hijing truth particles, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; - } - } - else if (_do_flow == 3) - { // sEPD event plane extraction - // get event plane map - EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); - if (!epmap) - { - std::cout << "DetermineTowerBackground::process_event: FATAL, EventplaneinfoMap does not exist, cannot extract sEPD flow with do_flow = " << _do_flow << std::endl; - exit(-1); - } - if (!(epmap->empty())) - { - auto *EPDNS = epmap->get(EventplaneinfoMap::sEPDNS); - _Psi2 = EPDNS->get_shifted_psi(2); - } - else - { - _is_flow_failure = true; - _Psi2 = 0; - } - - if (Verbosity() > 0) - { - std::cout << "DetermineTowerBackground::process_event: flow extracted from sEPD, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; - } - - } if (std::isnan(_Psi2) || std::isinf(_Psi2)) { @@ -890,7 +977,30 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) std::cout << "DetermineTowerBackground::process_event: flow extraction successful, Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) , v2 = " << _v2 << std::endl; } } // if do flow + else if (_do_flow == 4) + { + CentralityInfo *centinfo = findNode::getClass(topNode, "CentralityInfo"); + + if (!centinfo) + { + std::cout << "DetermineTowerBackground::process_event: FATAL, CentralityInfo does not exist, cannot extract centrality with do_flow = " << _do_flow << std::endl; + exit(-1); + } + + int centrality_bin = centinfo->get_centrality_bin(CentralityInfo::PROP::mbd_NS); + + if (centrality_bin > 0 && centrality_bin < 95) + { + _v2 = _CENTRALITY_V2[centrality_bin]; + } + else + { + _v2 = 0; + _is_flow_failure = true; + _Psi2 = 0; + } + } // now calculate energy densities... _nTowers = 0; // store how many towers were used to determine bkg @@ -1110,4 +1220,3 @@ void DetermineTowerBackground::FillNode(PHCompositeNode *topNode) - diff --git a/offline/packages/jetbackground/DetermineTowerBackground.h b/offline/packages/jetbackground/DetermineTowerBackground.h index a8a6d0209c..7f0c16c160 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.h +++ b/offline/packages/jetbackground/DetermineTowerBackground.h @@ -13,6 +13,7 @@ #include #include #include +#include // forward declarations class PHCompositeNode; @@ -34,13 +35,46 @@ class DetermineTowerBackground : public SubsysReco int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; - void SetBackgroundOutputName(const std::string &name) { _backgroundName = name; } - void SetSeedType(int seed_type) { _seed_type = seed_type; } - void SetFlow(int do_flow) { _do_flow = do_flow; }; - - void SetSeedJetD(float D) { _seed_jet_D = D; }; - void SetSeedJetPt(float pt) { _seed_jet_pt = pt; }; - void SetSeedMaxConst(float max_const) { _seed_max_const = max_const; }; + /** + * Set the background output node name used by the module. + * @param name Background output name (node key) to use when creating or locating the background data node. + */ +void SetBackgroundOutputName(const std::string &name) { _backgroundName = name; } + /** + * Set the seed type that selects the seed-finding strategy for exclusion seeds. + * @param seed_type Integer selector identifying which seed-finding strategy to use. + */ +void SetSeedType(int seed_type) { _seed_type = seed_type; } + /** + * Enable or disable flow processing. + * @param do_flow Non-zero to enable flow, zero to disable. + */ +void SetFlow(int do_flow) { _do_flow = do_flow; }; + /** + * Enable overwriting the average calorimeter v2 and set the source path. + * @param url Filesystem or resource path pointing to the replacement average calo v2 data. + */ + void SetOverwriteCaloV2(std::string &url) + { + m_overwrite_average_calo_v2 = true; + m_overwrite_average_calo_v2_path = url; + } + /** + * Set the seed-jet distance parameter used to select seed jets. + * @param D Distance parameter R for seed-jet clustering in eta-phi space. + */ +void SetSeedJetD(float D) { _seed_jet_D = D; }; + /** + * Set the seed-jet transverse-momentum threshold. + * + * @param pt Transverse momentum threshold for seed jets in GeV/c. + */ +void SetSeedJetPt(float pt) { _seed_jet_pt = pt; }; + /** + * Set the maximum constant used when evaluating seed jets. + * @param max_const Maximum constant applied to seed selection. + */ +void SetSeedMaxConst(float max_const) { _seed_max_const = max_const; }; void UseReweighting(bool do_reweight ) { _do_reweight = do_reweight; } @@ -55,9 +89,32 @@ class DetermineTowerBackground : public SubsysReco int CreateNode(PHCompositeNode *topNode); void FillNode(PHCompositeNode *topNode); - int _do_flow{0}; - float _v2{0}; - float _Psi2{0}; + int LoadCalibrations(); + + std::vector _CENTRALITY_V2; + std::string m_calibName = "JET_AVERAGE_CALO_V2_SEPD_PSI2"; + bool m_overwrite_average_calo_v2{false}; + std::string m_overwrite_average_calo_v2_path; + + /** + * Controls whether flow modulation is applied to background calculations. + * + * When non-zero, flow (v2/Psi2) corrections are applied to tower/background processing; + * when zero, flow corrections are not applied. + */ +int _do_flow{0}; + /** + * @brief Event or bin-level second-order azimuthal anisotropy coefficient (v2). + * + * Stores the estimated v2 value used for flow-modulated background calculations. + */ +float _v2{0}; + /** + * Event-plane angle used for v2 calculations. + * + * Stored in radians for the current event; populated when flow estimation is performed. + */ +float _Psi2{0}; std::vector > _UE; int _nStrips{0}; int _nTowers{0}; @@ -106,4 +163,4 @@ class DetermineTowerBackground : public SubsysReco std::string OHTowerName; }; -#endif +#endif \ No newline at end of file diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 22b1e9930d..d8a05c0ef0 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -1213,6 +1213,20 @@ int MbdCalib::Download_SlewCorr(const std::string& dbase_location) return 1; } +/** + * @brief Load per-channel time-RMS calibration data and build interpolated lookup curves. + * + * Reads time-RMS calibration vectors from either a CDB `.root` tree or a `.calib` text file, + * populates per-FEE channel containers (_trms_y, _trms_npts, _trms_minrange, _trms_maxrange), + * and produces interpolated per-ADC-index curves in _trms_y_interp for use by lookup routines. + * Q-channels (as defined by the geometry) are skipped. + * + * @param dbase_location Filesystem path or CDB file location to read calibration data from + * (expects either a `.root` CDB tree or a `.calib` text file). + * @return int `1` on success; `-1` if calibration data are missing or invalid after load; + * `-2` if the file contains an invalid FEE channel index; + * `-3` if the input file could not be opened. + */ int MbdCalib::Download_TimeRMS(const std::string& dbase_location) { //Verbosity(100); @@ -1331,7 +1345,7 @@ int MbdCalib::Download_TimeRMS(const std::string& dbase_location) if ( _trms_y[0].empty() ) { - std::cout << PHWHERE << ", ERROR, unknown file type, " << dbase_location << std::endl; + std::cout << PHWHERE << ", WARNING, trms calib missing " << dbase_location << std::endl; _status = -1; return _status; // file not found } @@ -2418,4 +2432,3 @@ TGraph *MbdCalib::get_lut_graph(const int pmtch, std::string_view type) return g; } - diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index d8c72b4395..5a889e778a 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -402,7 +402,26 @@ bool MbdEvent::isbadtch(const int ipmtch) #ifndef ONLINE -// Get raw data from event combined DSTs +/** + * Populate per-channel sample buffers from two combined DST CaloPacket objects and + * convert them into MBD-level raw and PMT containers. + * + * Extracts sample arrays, clocks, and FEM clocks from the two CaloPacket inputs (packets + * 1001 and 1002), fills internal sample buffers used by MbdEvent, runs packet-level + * processing to produce MbdRawContainer contents, and then produces MbdPmtContainer + * outputs. When provided, GL1 trigger information (gl1raw) is used to require MBD + * trigger bits during calibration passes. + * + * @param dstp Array of two CaloPacket pointers (packets 1001 and 1002) supplying samples and clocks. + * @param bbcraws Output MbdRawContainer to be filled from packet processing. + * @param bbcpmts Output MbdPmtContainer to be filled from raw-container processing. + * @param gl1raw Optional GL1 trigger packet used to filter events in calibration passes. + * @return Fun4AllReturnCodes::DISCARDEVENT if both input packets are null; + * Fun4AllReturnCodes::ABORTEVENT if a packet is missing or contains zero samples, + * or if calibration-mode trigger bits are not set in gl1raw; + * otherwise the processing status (typically the current event index or the + * value returned by ProcessPackets/ProcessRawContainer). + */ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbcraws, MbdPmtContainer *bbcpmts, Gl1Packet *gl1raw) { //std::cout << "MbdEvent::SetRawData()" << std::endl; @@ -451,6 +470,7 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc if (dstp[ipkt]) { _nsamples = dstp[ipkt]->iValue(0, "SAMPLES"); + { static bool printcount{true}; if ( printcount && Verbosity() > 0) @@ -460,6 +480,13 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc } } + // skip empty packets, corrupt event + if ( _nsamples == 0 ) + { + std::cout << PHWHERE << " ERROR, evt " << m_evt << " no samples in Packet " << pktid << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + m_xmitclocks[ipkt] = static_cast(dstp[ipkt]->iValue(0, "CLOCK")); m_femclocks[ipkt][0] = static_cast(dstp[ipkt]->iValue(0, "FEMCLOCK")); @@ -484,9 +511,17 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc } _mbdsig[feech].SetNSamples( _nsamples ); - _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]); - + + if ( _nsamples > 0 && _nsamples <= 30 ) + { + _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]); + } /* + else + { + std::cout << PHWHERE << " empty feech " << feech << std::endl; + } + std::cout << "feech " << feech << std::endl; _mbdsig[feech].Print(); */ @@ -516,7 +551,18 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc return status; } -#endif // ONLINE +#endif /** + * @brief Populate MBD raw and PMT containers from an Event's PRDF packets. + * + * Validates the Event and its sample data, extracts per-channel sample arrays + * from packets 1001 and 1002 into internal signal objects, and then fills the + * provided MbdRawContainer and MbdPmtContainer via the processing pipeline. + * + * @param event Input Event; must be a DATAEVENT and non-null. + * @param bbcraws Output container that will be filled with per-channel raw results. + * @param bbcpmts Output container that will be filled with per-PMT time/charge results. + * @return int `m_evt` (the processed event index) on success; `Fun4AllReturnCodes::ABORTEVENT`, `-1`, or other negative error codes on failure (e.g., missing packets or zero samples). + */ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer *bbcpmts) { @@ -565,6 +611,7 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer if (p[ipkt]) { _nsamples = p[ipkt]->iValue(0, "SAMPLES"); + { static int counter = 0; if ( counter<1 ) @@ -574,6 +621,15 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer counter++; } + // If packets are missing, stop processing event + if ( _nsamples == 0 ) + { + std::cout << PHWHERE << " ERROR, skipping evt " << m_evt << " nsamples = 0 " << pktid << std::endl; + delete p[ipkt]; + p[ipkt] = nullptr; + return Fun4AllReturnCodes::ABORTEVENT; + } + m_xmitclocks[ipkt] = static_cast(p[ipkt]->iValue(0, "CLOCK")); m_femclocks[ipkt][0] = static_cast(p[ipkt]->iValue(0, "FEMCLOCK")); @@ -631,13 +687,21 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer return status; } +/** + * @brief Process per-FEE packet signals and populate the raw PMT container. + * + * Processes all configured FEE channels for the current event, applies timing and charge extraction, updates internal event/clocks state, and fills bbcraws with per-PMT raw amplitude, time, and charge values. May advance the internal event counter and short-circuit processing when performing sample-maximum calibration. + * + * @param bbcraws Output container that will be filled with per-PMT raw results (amplitude, time, charge), number of PMTs, and clock metadata. + * @return int Current event index after processing, or a negative code to indicate special conditions (for example, -1001 when processing is stopped early to collect sample-maximum calibration data). + */ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) { //std::cout << "In ProcessPackets" << std::endl; // Do a quick sanity check that all fem counters agree if (m_xmitclocks[0] != m_xmitclocks[1]) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR, xmitclocks don't agree" << std::endl; + std::cout << __FILE__ << ":" << __LINE__ << " ERROR, xmitclocks don't agree, evt " << m_evt << std::endl; } /* // format changed in run2024, need to update check @@ -673,6 +737,11 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) int pmtch = _mbdgeom->get_pmt(ifeech); int type = _mbdgeom->get_type(ifeech); // 0 = T-channel, 1 = Q-channel + if ( _mbdsig[ifeech].GetNSamples()==0 ) + { + continue; + } + // time channel if (type == 0) { @@ -731,6 +800,15 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) return m_evt; } +/** + * @brief Convert per-channel raw signals into calibrated PMT-level time and charge and update event state. + * + * Processes each front-end channel that contains samples, computes per-PMT time and charge values (applying sample-maximum, T/Q conversions, t0/scorrection and gain corrections where applicable), writes results into the provided MbdPmtContainer, updates clock fields, runs post-processing on PMTs, and advances the internal event counter. + * + * @param bbcraws Raw per-channel container providing sampled waveforms and per-channel raw results. + * @param bbcpmts Output PMT-level container which will be populated with per-PMT charge and time (`set_pmt`) and whose `npmt` will be set. + * @return int The event index after processing (internal m_evt after it has been incremented). + */ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbcpmts) { //std::cout << "In ProcessRawContainer" << std::endl; @@ -739,6 +817,11 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc int pmtch = _mbdgeom->get_pmt(ifeech); int type = _mbdgeom->get_type(ifeech); // 0 = T-channel, 1 = Q-channel + if ( _mbdsig[ifeech].GetNSamples()==0 ) + { + continue; + } + // time channel if (type == 0) { @@ -854,8 +937,14 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc */ TGraphErrors *gsubpulse = _mbdsig[ifeech].GetGraph(); - Double_t *y = gsubpulse->GetY(); - h2_trange->Fill( y[samp_max], pmtch ); // fill ped-subtracted tdc + if ( gsubpulse ) + { + Double_t *y = gsubpulse->GetY(); + if ( y ) + { + h2_trange->Fill( y[samp_max], pmtch ); // fill ped-subtracted tdc + } + } } } @@ -1550,4 +1639,4 @@ PHG4VtxPoint *MbdEvent::GetPrimaryVtx(PHCompositeNode *topNode) return _vtxp; } -#endif +#endif \ No newline at end of file diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index c19ed37ba9..dc0153a21c 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -70,7 +70,18 @@ int MbdReco::InitRun(PHCompositeNode *topNode) return ret; } -//____________________________________________________________________________.. +/** + * @brief Perform per-event MBD reconstruction and populate MBD output nodes. + * + * Processes raw MBD data (from PRDF/Event or CaloPacket containers), applies calibration/recalibration + * as configured, runs hit/time calculation, and updates MbdOut and the global MBD vertex map when applicable. + * When an EventHeader is present, the event sequence is recorded and assigned to the MbdEvent before processing. + * + * @param topNode Top of the node tree used to locate input and output data nodes. + * @return int `Fun4AllReturnCodes::EVENT_OK` on normal completion or when an event is skipped; + * `Fun4AllReturnCodes::DISCARDEVENT` when the event should be discarded by the framework; + * `Fun4AllReturnCodes::ABORTEVENT` when processing must be aborted due to missing/invalid essential data. + */ int MbdReco::process_event(PHCompositeNode *topNode) { getNodes(topNode); @@ -103,7 +114,8 @@ int MbdReco::process_event(PHCompositeNode *topNode) int status = Fun4AllReturnCodes::EVENT_OK; if ( m_evtheader!=nullptr ) { - m_mbdevent->set_EventNumber( m_evtheader->get_EvtSequence() ); + _evtnum = m_evtheader->get_EvtSequence(); + m_mbdevent->set_EventNumber( _evtnum ); } if ( m_event!=nullptr ) @@ -125,7 +137,7 @@ int MbdReco::process_event(PHCompositeNode *topNode) static int counter = 0; if ( counter<3 ) { - std::cout << PHWHERE << " Warning, MBD discarding event " << std::endl; + std::cout << PHWHERE << " Warning, MBD discarding event " << _evtnum << std::endl; counter++; } return Fun4AllReturnCodes::DISCARDEVENT; @@ -135,7 +147,7 @@ int MbdReco::process_event(PHCompositeNode *topNode) static int counter = 0; if ( counter<3 ) { - std::cout << PHWHERE << " Warning, MBD aborting event " << std::endl; + std::cout << PHWHERE << " Warning, MBD aborting event " << _evtnum << std::endl; counter++; } return Fun4AllReturnCodes::ABORTEVENT; @@ -365,4 +377,4 @@ int MbdReco::getNodes(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index 0b8b420ffa..c82db5d3d4 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -32,9 +32,21 @@ class MbdSig void SetY(const Float_t *y, const int invert = 1); void SetXY(const Float_t *x, const Float_t *y, const int invert = 1); + /** + * Get the number of samples in this signal. + * + * @return The number of samples (_nsamples). + */ +int GetNSamples() { return _nsamples; } + void SetCalib(MbdCalib *mcal); - TH1 *GetHist() { return hpulse; } + /** + * Accesses the pulse histogram for this signal. + * + * @returns Pointer to the pulse histogram (hpulse), or `nullptr` if not available. + */ +TH1 *GetHist() { return hpulse; } TGraphErrors *GetGraph() { return gpulse; } Double_t GetAmpl() { return f_ampl; } Double_t GetTime() { return f_time; } @@ -197,4 +209,4 @@ class MbdSig int _verbose{0}; }; -#endif // __MBDSIG_H__ +#endif // __MBDSIG_H__ \ No newline at end of file diff --git a/offline/packages/micromegas/MicromegasClusterizer.cc b/offline/packages/micromegas/MicromegasClusterizer.cc index c57d6ed3f5..1e2e298719 100644 --- a/offline/packages/micromegas/MicromegasClusterizer.cc +++ b/offline/packages/micromegas/MicromegasClusterizer.cc @@ -150,15 +150,29 @@ int MicromegasClusterizer::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -//_______________________________________________________________________________ +/** + * @brief Cluster Micromegas hits into TrkrCluster objects and record cluster–hit associations. + * + * Processes all Micromegas hitsets found under the provided node tree, groups adjacent strips into clusters, + * computes per-cluster position, size, ADC sums, and errors, inserts clusters into the TRKR_CLUSTER container, + * and records associations into the TRKR_CLUSTERHITASSOC container. + * + * @param topNode Root node of the current event's node tree (used to access hit, geometry, calibration, and cluster nodes). + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) { // geometry PHG4CylinderGeomContainer* geonode = nullptr; for( std::string geonodename: {"CYLINDERGEOM_MICROMEGAS_FULL", "CYLINDERGEOM_MICROMEGAS" } ) - { if(( geonode = findNode::getClass(topNode, geonodename.c_str()) )) { break; -}} + { + // try load node and test + geonode = findNode::getClass(topNode, geonodename); + if( geonode ) { break;} + } + + //ma assert(geonode); // hitset container @@ -182,8 +196,8 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) for( auto hitset_it = hitset_range.first; hitset_it != hitset_range.second; ++hitset_it ) { // get hitset, key and layer - TrkrHitSet* hitset = hitset_it->second; - const TrkrDefs::hitsetkey hitsetkey = hitset_it->first; + const auto& [hitsetkey, hitset] = *hitset_it; + const auto layer = TrkrDefs::getLayer(hitsetkey); const auto tileid = MicromegasDefs::getTileId(hitsetkey); @@ -215,17 +229,39 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) using range_list_t = std::vector; range_list_t ranges; - // loop over hits - const auto hit_range = hitset->getHits(); + // Make a local copy of hitsets, sorted along strips + /* when there are multiple hits on the same strip, only the first one (in time) is kept */ + class StripSortFtor + { + public: + /** + * @brief Compares two hitkeys by their Micromegas strip index. + * + * @param first Hit key whose strip index is the left-hand operand of the comparison. + * @param second Hit key whose strip index is the right-hand operand of the comparison. + * @return `true` if the strip index of `first` is less than the strip index of `second`, `false` otherwise. + */ + bool operator() ( const TrkrDefs::hitkey& first, const TrkrDefs::hitkey& second ) const + { return MicromegasDefs::getStrip(first) < MicromegasDefs::getStrip(second); } + }; + + using LocalMap = std::map; + LocalMap local_hitmap; + + { + // loop over hits + const auto hit_range = hitset->getHits(); + std::copy( hit_range.first, hit_range.second, std::inserter(local_hitmap, local_hitmap.end()) ); + } // keep track of first iterator of runing cluster - auto begin = hit_range.first; + auto begin = local_hitmap.begin(); // keep track of previous strip uint16_t previous_strip = 0; bool first = true; - for( auto hit_it = hit_range.first; hit_it != hit_range.second; ++hit_it ) + for( auto hit_it = local_hitmap.begin(); hit_it != local_hitmap.end(); ++hit_it ) { // get hit key @@ -233,18 +269,11 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) // get strip number const auto strip = MicromegasDefs::getStrip( hitkey ); - - if( first ) + if( !first && (strip - previous_strip > 1 ) ) { - previous_strip = strip; - first = false; - continue; - - } else if( strip - previous_strip > 1 ) { - // store current cluster range - ranges.push_back( std::make_pair( begin, hit_it ) ); + ranges.emplace_back( begin, hit_it ); // reinitialize begin of next cluster range begin = hit_it; @@ -252,13 +281,13 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) } // update previous strip + first = false; previous_strip = strip; } // store last cluster - if( begin != hit_range.second ) { ranges.push_back( std::make_pair( begin, hit_range.second ) ); -} + if( begin != local_hitmap.end() ) { ranges.emplace_back( begin, local_hitmap.end() ); } // initialize cluster count int cluster_count = 0; @@ -419,4 +448,4 @@ int MicromegasClusterizer::End(PHCompositeNode* /*topNode*/) } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc index a5269617f7..62ba752c64 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc @@ -117,7 +117,17 @@ int MicromegasCombinedDataDecoder::InitRun(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } -//___________________________________________________________________________ +/** + * @brief Process Micromegas raw hits, decode signals, and populate TRKR hitsets. + * + * Iterates over all Micromegas raw hits on the supplied node tree, applies mapping, + * masking, hot-channel and calibration-based thresholds, selects the peak ADC sample, + * and creates TrkrHitv2 entries (organized by hitsetkey and hitkey) for qualifying signals. + * Per-hitset hit counts in m_hitcounts are incremented for each created hit. + * + * @param topNode Top-level node of the Fun4All/PHCompositeNode tree containing input and output containers. + * @return int Fun4AllReturnCodes::EVENT_OK on successful processing. + */ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) { // load relevant nodes @@ -203,13 +213,14 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) // loop over sample_range find maximum const auto sample_range = std::make_pair(rawhit->get_sample_begin(), rawhit->get_sample_end()); - std::vector adc_list; + using sample_pair_t = std::pair; + std::vector adc_list; for (auto is = std::max(m_sample_min, sample_range.first); is < std::min(m_sample_max, sample_range.second); ++is) { const uint16_t adc = rawhit->get_adc(is); if (adc != MicromegasDefs::m_adc_invalid) { - adc_list.push_back(adc); + adc_list.emplace_back(is, adc); } } @@ -220,16 +231,18 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) // get max adc value in range /* TODO: use more advanced signal processing */ - auto max_adc = *std::max_element(adc_list.begin(), adc_list.end()); + auto max_adc = *std::max_element(adc_list.begin(), adc_list.end(), + [](const sample_pair_t& first, const sample_pair_t& second) + { return first.second < second.second; } ); // compare to hard min_adc value - if (max_adc < m_min_adc) + if (max_adc.second < m_min_adc) { continue; } // compare to threshold - if (max_adc < pedestal + m_n_sigma * rms) + if (max_adc.second < pedestal + m_n_sigma * rms) { continue; } @@ -243,7 +256,8 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) << " tile: " << tile << " channel: " << channel << " strip: " << strip - << " adc: " << max_adc + << " sample: " << max_adc.first + << " adc: " << max_adc.second << std::endl; } @@ -251,19 +265,19 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) const auto hitset_it = trkrhitsetcontainer->findOrAddHitSet(hitsetkey); // generate hit key - const TrkrDefs::hitkey hitkey = MicromegasDefs::genHitKey(strip); + const TrkrDefs::hitkey hitkey = MicromegasDefs::genHitKey(strip, max_adc.first); // find existing hit, or create - auto hit = hitset_it->second->getHit(hitkey); + auto* hit = hitset_it->second->getHit(hitkey); if (hit) { - // std::cout << "MicromegasCombinedDataDecoder::process_event - duplicated hit, hitsetkey: " << hitsetkey << " strip: " << strip << std::endl; + std::cout << "MicromegasCombinedDataDecoder::process_event - duplicated hit, hitsetkey: " << hitsetkey << " strip: " << strip << std::endl; continue; } // create hit, assign adc and insert in hitset hit = new TrkrHitv2; - hit->setAdc(max_adc); + hit->setAdc(max_adc.second); hitset_it->second->addHitSpecificKey(hitkey, hit); // increment counter @@ -291,4 +305,4 @@ int MicromegasCombinedDataDecoder::End(PHCompositeNode* /*topNode*/) } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h index 32eebc56e0..f66167958d 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h @@ -17,7 +17,70 @@ class PHCompositeNode; -/// micromegas raw data decoder +/** + * Micromegas raw data decoder component. + * Acts as a SubsysReco module that decodes Micromegas raw hits into detector-level structures. + */ + +/** + * Construct a MicromegasCombinedDataDecoder. + * @param name Optional module name used to identify this instance. + */ + +/** + * Perform global initialization before any runs. + * @param topNode Pointer to the top-level PHCompositeNode. + * @returns Status code. + */ + +/** + * Perform run-specific initialization. + * @param topNode Pointer to the top-level PHCompositeNode. + * @returns Status code. + */ + +/** + * Process a single event. + * @param topNode Pointer to the top-level PHCompositeNode. + * @returns Status code. + */ + +/** + * Finalize processing and release resources. + * @param topNode Pointer to the top-level PHCompositeNode. + * @returns Status code. + */ + +/** + * Set the calibration file path. + * @param value Filesystem path to the calibration (pedestal) ROOT file. + */ + +/** + * Set the hot channel map file path. + * @param value Filesystem path to the hot-channel map file. + */ + +/** + * Set the number of RMS sigmas used to define the static threshold for each channel. + * @param value Threshold multiplier applied to channel RMS to determine per-channel threshold. + */ + +/** + * Set the minimum ADC value used to accept a channel regardless of pedestal/RMS. + * This is used to exclude channels that failed calibration by requiring their raw ADC to exceed this value. + * @param value Minimum ADC count. + */ + +/** + * Set the minimum sample index (inclusive) within a waveform to consider as part of a signal hit. + * @param value Minimum sample index. + */ + +/** + * Set the maximum sample index (inclusive) within a waveform to consider as part of a signal hit. + * @param value Maximum sample index. + */ class MicromegasCombinedDataDecoder : public SubsysReco { public: @@ -46,13 +109,22 @@ class MicromegasCombinedDataDecoder : public SubsysReco void set_n_sigma(double value) { m_n_sigma = value; } /// set minimum ADC value, disregarding pedestal and RMS. - /** This removes faulty channels for which calibration has failed */ + /** + * Set the minimum ADC threshold used to ignore channels when calibration has failed. + * @param value Minimum ADC value; channels with ADC below this are considered faulty and will be removed. + */ void set_min_adc(double value) { m_min_adc = value; } - /// set min sample for noise estimation + /** + * Set the minimum sample index considered part of a signal hit. + * @param value Minimum sample index (inclusive) to treat as signal when decoding raw data. + */ void set_sample_min(uint16_t value) { m_sample_min = value; } - /// set min sample for noise estimation + /** + * Set the maximum sample index considered part of a signal hit. + * @param value Maximum sample index for signal hits. + */ void set_sample_max(uint16_t value) { m_sample_max = value; } private: @@ -85,11 +157,11 @@ class MicromegasCombinedDataDecoder : public SubsysReco uint16_t m_sample_min = 0; /// max sample for signal - uint16_t m_sample_max = 100; + uint16_t m_sample_max = 1024; /// keep track of number of hits per hitsetid using hitcountmap_t = std::map; hitcountmap_t m_hitcounts; }; -#endif +#endif \ No newline at end of file diff --git a/offline/packages/micromegas/MicromegasDefs.cc b/offline/packages/micromegas/MicromegasDefs.cc index 0766d78b8e..682bec9fc6 100644 --- a/offline/packages/micromegas/MicromegasDefs.cc +++ b/offline/packages/micromegas/MicromegasDefs.cc @@ -25,57 +25,102 @@ namespace * 8 - 16 segmentation type * 0 - 8 tile id */ - static constexpr unsigned int kBitShiftSegmentation = 8; - static constexpr unsigned int kBitShiftTileId = 0; + constexpr unsigned int kBitShiftSegmentation = 8; + constexpr unsigned int kBitShiftTileId = 0; //! bit shift for hit key - static constexpr unsigned int kBitShiftStrip = 0; + constexpr unsigned int kBitShiftStrip = 0; + constexpr unsigned int kBitShiftSample = 8; } namespace MicromegasDefs { - //________________________________________________________________ + /** + * @brief Compose a Micromegas hitset key encoding layer, segmentation type, and tile id. + * + * The returned key encodes the Micromegas tracker identifier and the specified layer, + * and embeds the segmentation type and tile identifier into their respective bit fields. + * + * @param layer Detector layer index. + * @param type Segmentation type to encode. + * @param tile Tile identifier (0–255). + * @return TrkrDefs::hitsetkey A hitset key containing the Micromegas ID, layer, segmentation type, and tile id. + */ TrkrDefs::hitsetkey genHitSetKey(uint8_t layer, SegmentationType type, uint8_t tile ) { TrkrDefs::hitsetkey key = TrkrDefs::genHitSetKey(TrkrDefs::TrkrId::micromegasId, layer); - TrkrDefs::hitsetkey tmp = to_underlying_type(type); + TrkrDefs::hitsetkey tmp = to_underlying_type(type)&0x1U; key |= (tmp << kBitShiftSegmentation); - tmp = tile; + tmp = tile&0xFFU; key |= (tmp << kBitShiftTileId); return key; } - //________________________________________________________________ + /** + * @brief Extracts the segmentation type encoded in a hitset key. + * + * @param key Hitset key from which to retrieve the segmentation type. + * @return SegmentationType The segmentation type stored in the given hitset key. + */ SegmentationType getSegmentationType(TrkrDefs::hitsetkey key) { TrkrDefs::hitsetkey tmp = (key >> kBitShiftSegmentation); - return static_cast(tmp); + return static_cast(tmp&0x1U); } - //________________________________________________________________ + /** + * @brief Extracts the tile ID from a Micromegas hitset key. + * + * @param key Hitset key that encodes the tile ID. + * @return uint8_t Tile ID in the range 0–255. + */ uint8_t getTileId(TrkrDefs::hitsetkey key) { TrkrDefs::hitsetkey tmp = (key >> kBitShiftTileId); - return tmp; + return tmp&0xFFU; } - //________________________________________________________________ - TrkrDefs::hitkey genHitKey(uint16_t strip) + /** + * @brief Constructs a hit key that encodes a strip index and a sample value. + * + * @param strip 8-bit strip identifier; only the lowest 8 bits are used. + * @param sample 16-bit sample value; only the lowest 16 bits are used. + * @return TrkrDefs::hitkey Combined hit key with the strip in bits [7:0] and the sample in bits [23:8]. + */ + TrkrDefs::hitkey genHitKey(uint16_t strip, uint16_t sample) { - TrkrDefs::hitkey key = strip << kBitShiftStrip; - return key; + const TrkrDefs::hitkey key = (strip&0xFFU) << kBitShiftStrip; + const TrkrDefs::hitkey tmp = (sample&0xFFFFU) << kBitShiftSample; + return key|tmp; } - //________________________________________________________________ - uint16_t getStrip( TrkrDefs::hitkey key ) + /** + * @brief Extracts the strip index from a hit key. + * + * @param key Packed hit key containing the strip and sample fields. + * @return uint8_t Strip index extracted from the hit key (0–255). + */ + uint8_t getStrip( TrkrDefs::hitkey key ) { TrkrDefs::hitkey tmp = (key >> kBitShiftStrip); - return tmp; + return tmp & 0xFFU; + } + + /** + * @brief Extracts the sample field from a hit key. + * + * @param key Hit key containing encoded strip and sample fields. + * @return uint16_t The 16-bit sample value encoded in the key (sample bits starting at kBitShiftSample). + */ + uint16_t getSample( TrkrDefs::hitkey key ) + { + TrkrDefs::hitkey tmp = (key >> kBitShiftSample); + return tmp & 0xFFFFU; } //________________________________________________________________ @@ -92,4 +137,4 @@ namespace MicromegasDefs return getTileId( tmp ); } -} +} \ No newline at end of file diff --git a/offline/packages/micromegas/MicromegasDefs.h b/offline/packages/micromegas/MicromegasDefs.h index c95fdffd72..fec976973a 100644 --- a/offline/packages/micromegas/MicromegasDefs.h +++ b/offline/packages/micromegas/MicromegasDefs.h @@ -25,7 +25,9 @@ namespace MicromegasDefs }; //! tells the drift direction for a given micromegas layer - /*! this is needed for properly implementing transverse diffusion in the layer */ + /** + * Defines the direction of electron drift used for transverse diffusion calculations. + */ enum class DriftDirection: uint8_t { INWARD, @@ -60,11 +62,15 @@ namespace MicromegasDefs /*! * @brief Generate a hitkey from strip index inside tile * @param[in] strip strip index + * @param[in] sample sample index */ - TrkrDefs::hitkey genHitKey(uint16_t strip ); + TrkrDefs::hitkey genHitKey(uint16_t strip, uint16_t sample = 0 ); //! get strip from hit key - uint16_t getStrip(TrkrDefs::hitkey); + uint8_t getStrip(TrkrDefs::hitkey); + + //! get sample from hit key + uint16_t getSample(TrkrDefs::hitkey); /*! * @brief Get the segmentation type from cluster key @@ -128,4 +134,4 @@ namespace MicromegasDefs } -#endif +#endif \ No newline at end of file diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.cc b/offline/packages/mvtx/CylinderGeom_Mvtx.cc index e220d1474d..6bb9c1ddec 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.cc +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.cc @@ -8,9 +8,24 @@ #include #include // for operator<<, basic_ostream::operator<<, basic_... -using namespace std; using Segmentation = SegmentationAlpide; +/** + * @brief Constructs a CylinderGeom_Mvtx and initializes stave and sensor geometry constants. + * + * Initializes layer indexing, stave counts and angular parameters, sets pixel pitch and + * sensor thickness from Segmentation constants, and populates sensor/chip/module/half-stave + * localization offsets (values derived from mvtx_stave_v1.gdml). + * + * All spatial values are expressed in centimeters. + * + * @param in_layer Layer index for this geometry. + * @param in_N_staves Number of staves in the layer. + * @param in_layer_nominal_radius Nominal radius of the layer. + * @param in_phistep Angular step between staves (phi). + * @param in_phitilt Stave tilt angle about the phi direction. + * @param in_phi0 Reference phi offset for stave indexing. + */ CylinderGeom_Mvtx::CylinderGeom_Mvtx( int in_layer, int in_N_staves, @@ -72,6 +87,17 @@ CylinderGeom_Mvtx::CylinderGeom_Mvtx( return; } +/** + * @brief Compute stave and chip indices corresponding to a 3D point in world coordinates. + * + * Calculates the stave index from the point's azimuthal angle (phi) around the cylinder + * and the chip index from the point's axial (z) position, then stores them in the + * provided output parameters. + * + * @param world A 3-element vector [x, y, z] giving the point in world coordinates. + * @param stave_index Output parameter set to the computed stave index (azimuthal). + * @param chip_index Output parameter set to the computed chip index (axial/z). + */ void CylinderGeom_Mvtx::get_sensor_indices_from_world_coords(std::vector& world, unsigned int& stave_index, unsigned int& chip_index) { // stave number is fom phi @@ -89,12 +115,25 @@ void CylinderGeom_Mvtx::get_sensor_indices_from_world_coords(std::vector double chip_delta_z = (inner_loc_chip_in_module[8][2] - inner_loc_chip_in_module[0][2]) / 8.0; // int chip_tmp = (int) (world[2]/chip_delta_z) + 4; // 0-9 int chip_tmp = round(world[2] / chip_delta_z) + 4; // 0-9 - // std::cout << " z " << world[2] << " chip_delta_z " << chip_delta_z << " chip_tmp " << chip_tmp << endl; + // std::cout << " z " << world[2] << " chip_delta_z " << chip_delta_z << " chip_tmp " << chip_tmp << std::endl; stave_index = stave_tmp; chip_index = chip_tmp; } +/** + * @brief Map sensor-local coordinates to detector pixel indices. + * + * Converts a point given in sensor-local coordinates to chip-local coordinates, + * assigns the corresponding detector row and column, and returns whether the + * point maps to a valid pixel. Coordinates very close to the sensor edges are + * nudged slightly to avoid rounding issues. + * + * @param sensor_local Sensor-local position (X and Z components are used). + * @param iRow Output: detector row index corresponding to the X direction. + * @param iCol Output: detector column index corresponding to the Z direction. + * @return `true` if the coordinates map to a valid pixel and `iRow`/`iCol` are set, `false` otherwise. + */ bool CylinderGeom_Mvtx::get_pixel_from_local_coords(TVector3 sensor_local, int& iRow, int& iCol) { // YCM (2020-01-02): It seems that due some round issues, local coords of hits at the edge of the sensor volume @@ -102,15 +141,15 @@ bool CylinderGeom_Mvtx::get_pixel_from_local_coords(TVector3 sensor_local, int& double EPS = 5e-6; if (fabs(fabs(sensor_local.X()) - SegmentationAlpide::ActiveMatrixSizeRows / 2.F) < EPS) { - // cout << " Adjusting X, before X= " << sensor_local.X() << endl; + // std::cout << " Adjusting X, before X= " << sensor_local.X() << std::endl; sensor_local.SetX(((sensor_local.X() < 0) ? -1 : 1) * (SegmentationAlpide::ActiveMatrixSizeRows / 2.F - EPS)); - // cout << " Adjusting X, after X= " << sensor_local.X() << endl; + // std::cout << " Adjusting X, after X= " << sensor_local.X() << std::endl; } if (fabs(fabs(sensor_local.Z()) - SegmentationAlpide::ActiveMatrixSizeCols / 2.F) < EPS) { - // cout << " Adjusting Z, before Z= " << sensor_local.Z() << endl; + // std::cout << " Adjusting Z, before Z= " << sensor_local.Z() << std::endl; sensor_local.SetZ(((sensor_local.Z() < 0) ? -1 : 1) * (SegmentationAlpide::ActiveMatrixSizeCols / 2.F - EPS)); - // cout << " Adjusting Z, after Z= " << sensor_local.Z() << endl; + // std::cout << " Adjusting Z, after Z= " << sensor_local.Z() << std::endl; } // YCM (2020-01-02): go from sensor to chip local coords TVector3 in_chip = sensor_local; @@ -120,23 +159,33 @@ bool CylinderGeom_Mvtx::get_pixel_from_local_coords(TVector3 sensor_local, int& return SegmentationAlpide::localToDetector(in_chip.X(), in_chip.Z(), iRow, iCol); } +/** + * @brief Convert sensor-local coordinates to a linear pixel index. + * + * @param sensor_local Coordinates expressed in the sensor-local frame. + * @return int Linear pixel index computed as (column) + (row) * get_NX(); indexing starts at 0. + * + * If the coordinates lie outside the active sensor area, the function prints diagnostic messages + * and still returns the computed linear index, which may be outside the valid [0, get_NX()*get_NZ()) range. + */ int CylinderGeom_Mvtx::get_pixel_from_local_coords(const TVector3& sensor_local) { - int Ngridx, Ngridz; + int Ngridx; + int Ngridz; bool px_in = get_pixel_from_local_coords(sensor_local, Ngridx, Ngridz); if (!px_in) { - cout << PHWHERE + std::cout << PHWHERE << " Pixel is out sensor. (" << sensor_local.X() << ", " << sensor_local.Y() << ", " << sensor_local.Z() << ")." - << endl; + << std::endl; } if (Ngridx < 0 || Ngridx >= get_NX() || Ngridz < 0 || Ngridz >= get_NZ()) { - cout << PHWHERE << "Wrong pixel value X= " << Ngridx << " and Z= " << Ngridz << endl; + std::cout << PHWHERE << "Wrong pixel value X= " << Ngridx << " and Z= " << Ngridz << std::endl; } // numbering starts at zero @@ -151,14 +200,28 @@ TVector3 CylinderGeom_Mvtx::get_local_coords_from_pixel(int NXZ) return get_local_coords_from_pixel(Ngridx, Ngridz); } +/** + * @brief Convert detector pixel indices to sensor-local coordinates. + * + * Converts the given detector pixel indices (row, column) into a TVector3 + * representing the position in the sensor-local coordinate system. + * + * @param iRow Pixel row index within the detector. + * @param iCol Pixel column index within the detector. + * @return TVector3 Position in sensor-local coordinates corresponding to the pixel. + * + * Note: If the provided indices are out of range, a diagnostic message is + * printed to stdout and the returned vector is the computed value after the + * failed conversion attempt (offset from chip to sensor coordinates is still applied). + */ TVector3 CylinderGeom_Mvtx::get_local_coords_from_pixel(int iRow, int iCol) { TVector3 local; bool check = SegmentationAlpide::detectorToLocal((float) iRow, (float) iCol, local); if (!check) { - cout << PHWHERE << "Pixel coord ( " << iRow << ", " << iCol << " )" - << "out of range" << endl; + std::cout << PHWHERE << "Pixel coord ( " << iRow << ", " << iCol << " )" + << "out of range" << std::endl; } // Transform location in chip to location in sensors TVector3 trChipToSens(loc_sensor_in_chip[0], @@ -168,6 +231,14 @@ TVector3 CylinderGeom_Mvtx::get_local_coords_from_pixel(int iRow, int iCol) return local; } +/** + * @brief Prints a concise description of this cylinder geometry to the given stream. + * + * Outputs layer index, layer radius, number of full and half staves, pixel X and Z pitch, and pixel thickness + * in a single line to the provided output stream. + * + * @param os Output stream to receive the summary. + */ void CylinderGeom_Mvtx::identify(std::ostream& os) const { os << "CylinderGeom_Mvtx: layer: " << layer @@ -177,7 +248,7 @@ void CylinderGeom_Mvtx::identify(std::ostream& os) const << ", pixel_x: " << pixel_x << ", pixel_z: " << pixel_z << ", pixel_thickness: " << pixel_thickness - << endl; + << std::endl; return; } @@ -187,22 +258,46 @@ int CylinderGeom_Mvtx::get_NZ() const return SegmentationAlpide::NCols; } +/** + * @brief Number of pixel rows in the detector's X dimension. + * + * @return int Number of X (row) pixels per sensor/chip. + */ int CylinderGeom_Mvtx::get_NX() const { return SegmentationAlpide::NRows; } -int CylinderGeom_Mvtx::get_pixel_X_from_pixel_number(int NXZ) +/** + * @brief Compute the X (row) index corresponding to a linear pixel index. + * + * @param NXZ Linear pixel index encoded as x + z * get_NX(). + * @return int X index within the pixel grid in the range [0, get_NX() - 1]. + */ +int CylinderGeom_Mvtx::get_pixel_X_from_pixel_number(int NXZ) const { return NXZ % get_NX(); } -int CylinderGeom_Mvtx::get_pixel_Z_from_pixel_number(int NXZ) +/** + * @brief Compute the Z (column) index for a given linear pixel number. + * + * @param NXZ Linear pixel index in row-major order (x + z * get_NX()). + * @return int Z (column) index corresponding to NXZ. + */ +int CylinderGeom_Mvtx::get_pixel_Z_from_pixel_number(int NXZ) const { return NXZ / get_NX(); } -int CylinderGeom_Mvtx::get_pixel_number_from_xbin_zbin(int xbin, int zbin) // obsolete +/** + * @brief Compute the linear pixel index from x and z bin coordinates. + * + * @param xbin Zero-based x (row) index within the sensor grid. + * @param zbin Zero-based z (column) index within the sensor grid. + * @return int Linear pixel index equal to xbin + zbin * get_NX(). + */ +int CylinderGeom_Mvtx::get_pixel_number_from_xbin_zbin(int xbin, int zbin) const // obsolete { return xbin + zbin * get_NX(); -} +} \ No newline at end of file diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.h b/offline/packages/mvtx/CylinderGeom_Mvtx.h index e28da2c594..a925dd36cf 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.h +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.h @@ -8,12 +8,80 @@ #include +/** + * Construct a CylinderGeom_Mvtx with geometry parameters for a specific layer. + * @param layer Detector layer index. + * @param in_N_staves Number of staves in the layer. + * @param in_layer_nominal_radius Nominal radius of the layer. + * @param in_phistep Angular step between staves (radians). + * @param in_phitilt Stave tilt angle (radians). + * @param in_phi0 Azimuthal offset of the first stave (radians). + */ + +/** + * Output identifying information about this geometry to the provided stream. + * @param os Stream to write identification information to. + */ + +/** + * Determine stave and chip indices corresponding to world coordinates. + * @param world World coordinates as a vector of three doubles {x,y,z}. + * @param stave Output stave index. + * @param chip Output chip index within the stave. + */ + +/** + * Map local sensor coordinates to integer pixel row and column indices. + * @param sensor_local Local coordinates in the sensor frame. + * @param iRow Output pixel row index. + * @param iCol Output pixel column index. + * @returns `true` if the coordinates map to a valid pixel, `false` otherwise. + */ + +/** + * Map local sensor coordinates to a flattened pixel index. + * @param sensor_local Local coordinates in the sensor frame. + * @returns Flattened pixel index corresponding to the local coordinates, or a negative value if outside the sensor. + */ + +/** + * Return the local sensor coordinates for a given flattened pixel index. + * @param NXZ Flattened pixel index. + * @returns Local coordinates of the pixel center as a TVector3. + */ + +/** + * Return the local sensor coordinates for a given pixel row and column. + * @param iRow Pixel row index. + * @param iCol Pixel column index. + * @returns Local coordinates of the pixel center as a TVector3. + */ + +/** + * Return the X (column) index for a flattened pixel number. + * @param NXZ Flattened pixel index. + * @returns X (column) index of the pixel. + */ + +/** + * Return the Z (row) index for a flattened pixel number. + * @param NXZ Flattened pixel index. + * @returns Z (row) index of the pixel. + */ + +/** + * Compute a flattened pixel number from X (column) and Z (row) bin indices. + * @param xbin X (column) bin index. + * @param zbin Z (row) bin index. + * @returns Flattened pixel index corresponding to the provided bin indices. + * @deprecated This method is obsolete. + */ class CylinderGeom_Mvtx : public PHG4CylinderGeom { public: CylinderGeom_Mvtx( int layer, - int in_Nstaves, + int in_N_staves, double in_layer_nominal_radius, double in_phistep, double in_phitilt, @@ -31,7 +99,7 @@ class CylinderGeom_Mvtx : public PHG4CylinderGeom { } - ~CylinderGeom_Mvtx() override {} + ~CylinderGeom_Mvtx() override = default; // from PHObject void identify(std::ostream& os = std::cout) const override; @@ -53,11 +121,11 @@ class CylinderGeom_Mvtx : public PHG4CylinderGeom TVector3 get_local_coords_from_pixel(int NXZ); TVector3 get_local_coords_from_pixel(int iRow, int iCol); - int get_pixel_X_from_pixel_number(int NXZ); + int get_pixel_X_from_pixel_number(int NXZ) const; - int get_pixel_Z_from_pixel_number(int NXZ); + int get_pixel_Z_from_pixel_number(int NXZ) const; - int get_pixel_number_from_xbin_zbin(int xbin, int zbin); // obsolete + int get_pixel_number_from_xbin_zbin(int xbin, int zbin) const; // obsolete double get_stave_phi_tilt() const { return stave_phi_tilt; } double get_stave_phi_0() const { return stave_phi_0; } @@ -97,4 +165,4 @@ class CylinderGeom_Mvtx : public PHG4CylinderGeom ClassDefOverride(CylinderGeom_Mvtx, 2) }; -#endif +#endif \ No newline at end of file diff --git a/offline/packages/mvtx/MvtxClusterPruner.cc b/offline/packages/mvtx/MvtxClusterPruner.cc index 24d41db63d..dac7ffc387 100644 --- a/offline/packages/mvtx/MvtxClusterPruner.cc +++ b/offline/packages/mvtx/MvtxClusterPruner.cc @@ -12,108 +12,162 @@ #include #include -#include #include +#include -#include #include +#include namespace { //! range adaptor to be able to use range-based for loop - template class range_adaptor + template + class range_adaptor { - public: - range_adaptor( const T& range ):m_range(range){} - const typename T::first_type& begin() {return m_range.first;} - const typename T::second_type& end() {return m_range.second;} - private: + public: + /** + * @brief Construct an adaptor that exposes a pair-like range as an iterable for range-based for loops. + * + * @param range Pair-like range (e.g., a std::pair of iterators or any object providing begin/end) to be copied into the adaptor for iteration. + */ + explicit range_adaptor(const T& range) + : m_range(range) + { + } + /** + * @brief Accesses the beginning element of the wrapped pair-like range. + * + * @return Reference to the first element of the stored pair representing the range start. + */ +const typename T::first_type& begin() { return m_range.first; } + /** + * @brief Access the end of the underlying pair-like range. + * + * @return const typename T::second_type& Reference to the range's end element (the pair's second). + */ +const typename T::second_type& end() { return m_range.second; } + + private: T m_range; }; - // print cluster information - void print_cluster_information( TrkrDefs::cluskey ckey, TrkrCluster* cluster ) + /** + * @brief Prints MVTX cluster metadata to standard output. + * + * When `cluster` is non-null, prints the cluster key, local position (X,Y), + * size, layer, stave, chip, strobe, and index. When `cluster` is null, prints + * the cluster key, layer, stave, chip, strobe, and index. + * + * @param ckey Identifier for the MVTX cluster. + * @param cluster Pointer to the cluster; may be null to indicate absence of + * cluster object (in which case position and size are omitted). + */ + void print_cluster_information(TrkrDefs::cluskey ckey, TrkrCluster* cluster) { - if( cluster ) + if (cluster) { std::cout << " MVTX cluster: " << ckey - << " position: (" << cluster->getLocalX() << ", " << cluster->getLocalY() << ")" - << " size: " << (int)cluster->getSize() - << " layer: " << (int)TrkrDefs::getLayer(ckey) - << " stave: " << (int) MvtxDefs::getStaveId(ckey) - << " chip: " << (int)MvtxDefs::getChipId(ckey) - << " strobe: " << (int)MvtxDefs::getStrobeId(ckey) - << " index: " << (int)TrkrDefs::getClusIndex(ckey) - << std::endl; - } else { + << " position: (" << cluster->getLocalX() << ", " << cluster->getLocalY() << ")" + << " size: " << (int) cluster->getSize() + << " layer: " << (int) TrkrDefs::getLayer(ckey) + << " stave: " << (int) MvtxDefs::getStaveId(ckey) + << " chip: " << (int) MvtxDefs::getChipId(ckey) + << " strobe: " << MvtxDefs::getStrobeId(ckey) + << " index: " << (int) TrkrDefs::getClusIndex(ckey) + << std::endl; + } + else + { std::cout << " MVTX cluster: " << ckey - << " layer: " << (int)TrkrDefs::getLayer(ckey) - << " stave: " << (int) MvtxDefs::getStaveId(ckey) - << " chip: " << (int)MvtxDefs::getChipId(ckey) - << " strobe: " << (int)MvtxDefs::getStrobeId(ckey) - << " index: " << (int)TrkrDefs::getClusIndex(ckey) - << std::endl; + << " layer: " << (int) TrkrDefs::getLayer(ckey) + << " stave: " << (int) MvtxDefs::getStaveId(ckey) + << " chip: " << (int) MvtxDefs::getChipId(ckey) + << " strobe: " << MvtxDefs::getStrobeId(ckey) + << " index: " << (int) TrkrDefs::getClusIndex(ckey) + << std::endl; } } using hitkeyset_t = std::set; - using clustermap_t = std::map; + using clustermap_t = std::map; -} +} // namespace -//_____________________________________________________________________________ -MvtxClusterPruner::MvtxClusterPruner(const std::string &name) +/** + * @brief Constructs the MvtxClusterPruner module. + * + * Initializes the SubsysReco base with the given module name. + * + * @param name Name used to identify and register this SubsysReco instance. + */ +MvtxClusterPruner::MvtxClusterPruner(const std::string& name) : SubsysReco(name) { } -//_____________________________________________________________________________ -int MvtxClusterPruner::InitRun(PHCompositeNode * /*topNode*/) +/** + * @brief Log the current strict-matching setting and perform no additional initialization. + * + * Prints the value of m_use_strict_matching to standard output and completes initialization. + * + * @return int Fun4AllReturnCodes::EVENT_OK to indicate successful initialization. + */ +int MvtxClusterPruner::InitRun(PHCompositeNode* /*topNode*/) { std::cout << "MvtxClusterPruner::InitRun - m_use_strict_matching: " << m_use_strict_matching << std::endl; return Fun4AllReturnCodes::EVENT_OK; } -//_____________________________________________________________________________ -int MvtxClusterPruner::process_event(PHCompositeNode *topNode) +/** + * @brief Prune redundant MVTX clusters across consecutive strobe keys. + * + * Compares clusters from a given MVTX hitset to clusters in the next strobe and removes redundant clusters: + * - If strict matching is enabled, removes clusters whose associated hit sets are identical. + * - If strict matching is disabled, removes clusters whose associated hit set is a subset of another cluster's hit set. + * + * @param topNode The root node of the PHENIX/Acts node tree used to access TRKR_CLUSTER and TRKR_CLUSTERHITASSOC. + * @return Fun4All return code: `Fun4AllReturnCodes::EVENT_OK` on success (processing completed or skipped if required nodes are absent). + */ +int MvtxClusterPruner::process_event(PHCompositeNode* topNode) { // load relevant nodes - auto trkrclusters = findNode::getClass(topNode, "TRKR_CLUSTER"); - if( !trkrclusters ) + auto* trkrclusters = findNode::getClass(topNode, "TRKR_CLUSTER"); + if (!trkrclusters) { std::cout << "MvtxClusterPruner::process_event - TRKR_CLUSTER not found. Doing nothing" << std::endl; return Fun4AllReturnCodes::EVENT_OK; } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); - if( !clusterhitassoc ) + auto* clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + if (!clusterhitassoc) { std::cout << "MvtxClusterPruner::process_event - TRKR_CLUSTERHITASSOC not found. Doing nothing" << std::endl; return Fun4AllReturnCodes::EVENT_OK; } // lambda method to create map of cluster keys and associated hits - auto get_cluster_map = [trkrclusters,clusterhitassoc]( TrkrDefs::hitsetkey key ) + auto get_cluster_map = [trkrclusters, clusterhitassoc](TrkrDefs::hitsetkey key) { clustermap_t out; // get all clusters for this hitsetkey - const auto cluster_range= trkrclusters->getClusters(key); - for( const auto& [ckey,cluster]:range_adaptor(cluster_range) ) + const auto cluster_range = trkrclusters->getClusters(key); + for (const auto& [ckey, cluster] : range_adaptor(cluster_range)) { // get associated hits const auto& hit_range = clusterhitassoc->getHits(ckey); hitkeyset_t hitkeys; - std::transform(hit_range.first, hit_range.second, std::inserter(hitkeys,hitkeys.end()), - [](const TrkrClusterHitAssoc::Map::value_type& pair ){ return pair.second; }); - out.emplace(ckey,std::move(hitkeys)); + std::transform(hit_range.first, hit_range.second, std::inserter(hitkeys, hitkeys.end()), + [](const TrkrClusterHitAssoc::Map::value_type& pair) + { return pair.second; }); + out.emplace(ckey, std::move(hitkeys)); } return out; }; // loop over MVTX hitset keys const auto hitsetkeys = trkrclusters->getHitSetKeys(TrkrDefs::mvtxId); - for( const auto& hitsetkey:hitsetkeys ) + for (const auto& hitsetkey : hitsetkeys) { // get layer, stave, chip and current strobe const auto layer = TrkrDefs::getLayer(hitsetkey); @@ -125,111 +179,116 @@ int MvtxClusterPruner::process_event(PHCompositeNode *topNode) const auto cluster_map1 = get_cluster_map(hitsetkey); // get clusters for the next strobe - int next_strobe = current_strobe+1; + int next_strobe = current_strobe + 1; const auto hitsetkey_next_strobe = MvtxDefs::genHitSetKey(layer, stave, chip, next_strobe); const auto clusterk_map2 = get_cluster_map(hitsetkey_next_strobe); // loop over clusters from first range - for( auto [ckey1,hitkeys1]:cluster_map1) + for (auto [ckey1, hitkeys1] : cluster_map1) { // increment counter ++m_cluster_counter_total; // get correcponding cluser - auto cluster1 = Verbosity() ? trkrclusters->findCluster(ckey1):nullptr; + auto* cluster1 = Verbosity() ? trkrclusters->findCluster(ckey1) : nullptr; // loop over clusters from second range - for( auto [ckey2,hitkeys2]:clusterk_map2) + for (auto [ckey2, hitkeys2] : clusterk_map2) { - auto cluster2 = Verbosity() ? trkrclusters->findCluster(ckey2):nullptr; + auto* cluster2 = Verbosity() ? trkrclusters->findCluster(ckey2) : nullptr; - if( m_use_strict_matching ) + if (m_use_strict_matching) { // see if hitsets are identical - if(hitkeys1 == hitkeys2) + if (hitkeys1 == hitkeys2) { // increment counter ++m_cluster_counter_deleted; - if( Verbosity() ) + if (Verbosity()) { std::cout << "Removing cluster "; - print_cluster_information( ckey2, cluster2); + print_cluster_information(ckey2, cluster2); std::cout << "Keeping cluster "; - print_cluster_information( ckey1, cluster1); + print_cluster_information(ckey1, cluster1); } // always remove second cluster trkrclusters->removeCluster(ckey2); break; } - - } else { - + } + else + { // make sure first set is larger than second const bool swapped = hitkeys2.size() > hitkeys1.size(); - if( swapped ) { std::swap(hitkeys2,hitkeys1); } + if (swapped) + { + std::swap(hitkeys2, hitkeys1); + } // see if hitkeys2 is a subset of hitkeys1 - if( std::includes(hitkeys1.begin(), hitkeys1.end(), hitkeys2.begin(), hitkeys2.end()) ) + if (std::includes(hitkeys1.begin(), hitkeys1.end(), hitkeys2.begin(), hitkeys2.end())) { // increment counter ++m_cluster_counter_deleted; - if( swapped ) + if (swapped) { - - if( Verbosity() ) + if (Verbosity()) { std::cout << "Removing cluster "; - print_cluster_information( ckey1, cluster1); + print_cluster_information(ckey1, cluster1); std::cout << "Keeping cluster "; - print_cluster_information( ckey2, cluster2); + print_cluster_information(ckey2, cluster2); } // remove first cluster trkrclusters->removeCluster(ckey1); break; - } else { - - if( Verbosity() ) - { - std::cout << "Removing cluster "; - print_cluster_information( ckey2, cluster2); - - std::cout << "Keeping cluster "; - print_cluster_information( ckey1, cluster1); - } + } + if (Verbosity()) + { + std::cout << "Removing cluster "; + print_cluster_information(ckey2, cluster2); - // remove second cluster - trkrclusters->removeCluster(ckey2); + std::cout << "Keeping cluster "; + print_cluster_information(ckey1, cluster1); } + + // remove second cluster + trkrclusters->removeCluster(ckey2); } - } // strict matching + } // strict matching - } // second cluster loop - } // first cluster loop - } // hitsetkey loop + } // second cluster loop + } // first cluster loop + } // hitsetkey loop return Fun4AllReturnCodes::EVENT_OK; - } -//_____________________________________________________________________________ -int MvtxClusterPruner::End(PHCompositeNode * /*topNode*/) +/** + * @brief Logs final cluster pruning statistics. + * + * Prints the total number of cluster comparisons, the number of clusters removed, + * and the fraction removed, then completes module finalization. + * + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ +int MvtxClusterPruner::End(PHCompositeNode* /*topNode*/) { - std::cout << "MvtxClusterPruner::End -" - << " m_cluster_counter_total: " << m_cluster_counter_total - << std::endl; - std::cout << "MvtxClusterPruner::End -" - << " m_cluster_counter_deleted: " << m_cluster_counter_deleted - << " fraction: " << double( m_cluster_counter_deleted )/m_cluster_counter_total - << std::endl; + << " m_cluster_counter_total: " << m_cluster_counter_total + << std::endl; + std::cout << "MvtxClusterPruner::End -" + << " m_cluster_counter_deleted: " << m_cluster_counter_deleted + << " fraction: " << double(m_cluster_counter_deleted) / m_cluster_counter_total + << std::endl; return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/mvtx/MvtxClusterizer.cc b/offline/packages/mvtx/MvtxClusterizer.cc index 7970b369eb..db49609453 100644 --- a/offline/packages/mvtx/MvtxClusterizer.cc +++ b/offline/packages/mvtx/MvtxClusterizer.cc @@ -63,80 +63,104 @@ namespace /// convenience square method template - inline constexpr T square(const T &x) + /** + * @brief Compute the square of a value. + * + * @tparam T Type of the input value. + * @param x Value to be squared. + * @return T The result of x multiplied by itself. + */ + constexpr T square(const T &x) { return x * x; } -} // namespace +} /** + * Determine whether two MVTX hits are adjacent according to the current Z-clustering mode. + * + * When Z clustering is enabled, hits are adjacent if their column indices differ by at most 1 + * and their row indices differ by at most 1. When Z clustering is disabled, hits are adjacent + * only if they share the same column and their row indices differ by at most 1. + * + * @param lhs Pair of (hitkey, TrkrHit*) for the first hit. + * @param rhs Pair of (hitkey, TrkrHit*) for the second hit. + * @return `true` if the two hits are adjacent under the module's Z-clustering mode, `false` otherwise. + */ bool MvtxClusterizer::are_adjacent( const std::pair &lhs, - const std::pair &rhs) + const std::pair &rhs) const { if (GetZClustering()) { return - // column adjacent - ( (MvtxDefs::getCol(lhs.first) > MvtxDefs::getCol(rhs.first)) ? - MvtxDefs::getCol(lhs.first)<=MvtxDefs::getCol(rhs.first)+1: - MvtxDefs::getCol(rhs.first)<=MvtxDefs::getCol(lhs.first)+1) && - - // row adjacent - ( (MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? - MvtxDefs::getRow(lhs.first)<=MvtxDefs::getRow(rhs.first)+1: - MvtxDefs::getRow(rhs.first)<=MvtxDefs::getRow(lhs.first)+1); - - } else { + // column adjacent + ((MvtxDefs::getCol(lhs.first) > MvtxDefs::getCol(rhs.first)) ? MvtxDefs::getCol(lhs.first) <= MvtxDefs::getCol(rhs.first) + 1 : MvtxDefs::getCol(rhs.first) <= MvtxDefs::getCol(lhs.first) + 1) && - return + // row adjacent + ((MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? MvtxDefs::getRow(lhs.first) <= MvtxDefs::getRow(rhs.first) + 1 : MvtxDefs::getRow(rhs.first) <= MvtxDefs::getRow(lhs.first) + 1); + } + return // column identical - MvtxDefs::getCol(rhs.first)==MvtxDefs::getCol(lhs.first) && + MvtxDefs::getCol(rhs.first) == MvtxDefs::getCol(lhs.first) && // row adjacent - ( (MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? - MvtxDefs::getRow(lhs.first)<=MvtxDefs::getRow(rhs.first)+1: - MvtxDefs::getRow(rhs.first)<=MvtxDefs::getRow(lhs.first)+1); - - } + ((MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? MvtxDefs::getRow(lhs.first) <= MvtxDefs::getRow(rhs.first) + 1 : MvtxDefs::getRow(rhs.first) <= MvtxDefs::getRow(lhs.first) + 1); } -bool MvtxClusterizer::are_adjacent(RawHit *lhs, RawHit *rhs) +/** + * @brief Determine whether two RawHit objects are neighboring for clustering. + * + * When Z-dimension clustering is enabled, two hits are neighbors if their phi bins + * differ by at most 1 and their time (T) bins differ by at most 1. When Z-dimension + * clustering is disabled, two hits are neighbors only if they share the same phi bin + * and their T bins differ by at most 1. + * + * @param lhs Pointer to the first RawHit to compare. + * @param rhs Pointer to the second RawHit to compare. + * @return `true` if the hits are adjacent according to the current Z-clustering mode, `false` otherwise. + */ +bool MvtxClusterizer::are_adjacent(RawHit *lhs, RawHit *rhs) const { if (GetZClustering()) { return - // phi adjacent (== column) - ((lhs->getPhiBin() > rhs->getPhiBin()) ? - lhs->getPhiBin() <= rhs->getPhiBin()+1: - rhs->getPhiBin() <= lhs->getPhiBin()+1) && - - // time adjacent (== row) - ((lhs->getTBin() > rhs->getTBin()) ? - lhs->getTBin() <= rhs->getTBin()+1: - rhs->getTBin() <= lhs->getTBin()+1); + // phi adjacent (== column) + ((lhs->getPhiBin() > rhs->getPhiBin()) ? lhs->getPhiBin() <= rhs->getPhiBin() + 1 : rhs->getPhiBin() <= lhs->getPhiBin() + 1) && - } else { - - return + // time adjacent (== row) + ((lhs->getTBin() > rhs->getTBin()) ? lhs->getTBin() <= rhs->getTBin() + 1 : rhs->getTBin() <= lhs->getTBin() + 1); + } + return // phi identical (== column) lhs->getPhiBin() == rhs->getPhiBin() && // time adjacent (== row) - ((lhs->getTBin() > rhs->getTBin()) ? - lhs->getTBin() <= rhs->getTBin()+1: - rhs->getTBin() <= lhs->getTBin()+1); - - } + ((lhs->getTBin() > rhs->getTBin()) ? lhs->getTBin() <= rhs->getTBin() + 1 : rhs->getTBin() <= lhs->getTBin() + 1); } +/** + * @brief Construct a MvtxClusterizer module with the given SubsysReco name. + * + * @param name Framework-visible name for this SubsysReco module instance. + */ MvtxClusterizer::MvtxClusterizer(const std::string &name) : SubsysReco(name) { } +/** + * @brief Initialize run-level nodes required for MVTX clustering. + * + * Ensures the DST/TRKR node hierarchy contains container nodes for clusters and cluster-hit associations, + * creating TRKR, TRKR_CLUSTER, and TRKR_CLUSTERHITASSOC if missing; optionally creates Trkr_SvtxClusHitsVerbose + * when verbose cluster-hit recording is enabled. + * + * @param topNode Top-level PHCompositeNode (typically the DST node root) where TRKR-related nodes are attached. + * @return int Fun4All return code: `Fun4AllReturnCodes::ABORTRUN` if the DST node is missing, `Fun4AllReturnCodes::EVENT_OK` on success. + */ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) { //----------------- @@ -165,7 +189,7 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { @@ -183,7 +207,7 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { @@ -208,14 +232,14 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) if (!mClusHitsVerbose) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); if (!DetNode) { DetNode = new PHCompositeNode("TRKR"); dstNode->addNode(DetNode); } mClusHitsVerbose = new ClusHitsVerbosev1(); - auto newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); + auto *newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); DetNode->addNode(newNode); } } @@ -227,18 +251,28 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) if (Verbosity() > 0) { std::cout << "====================== MvtxClusterizer::InitRun() " - "=====================" - << std::endl; + "=====================" + << std::endl; std::cout << " Z-dimension Clustering = " << std::boolalpha << m_makeZClustering - << std::noboolalpha << std::endl; + << std::noboolalpha << std::endl; std::cout << "==================================================================" - "=========" - << std::endl; + "=========" + << std::endl; } return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Cluster MVTX hits for a single event and record resulting clusters. + * + * Resets existing MVTX clusters and cluster-hit associations, reads either + * regular or raw MVTX hit sets from the node tree depending on configuration, + * runs the appropriate clustering routine, and stores clusters and associations. + * + * @param topNode Root node of the event data tree. + * @return int Fun4AllReturnCodes::EVENT_OK on success; Fun4AllReturnCodes::ABORTRUN if required nodes are missing. + */ int MvtxClusterizer::process_event(PHCompositeNode *topNode) { // get node containing the digitized hits @@ -283,7 +317,7 @@ int MvtxClusterizer::process_event(PHCompositeNode *topNode) // reset MVTX clusters and cluster associations const auto hitsetkeys = m_clusterlist->getHitSetKeys(TrkrDefs::mvtxId); - for( const auto& hitsetkey:hitsetkeys) + for (const auto &hitsetkey : hitsetkeys) { m_clusterlist->removeClusters(hitsetkey); m_clusterhitassoc->removeAssocs(hitsetkey); @@ -304,6 +338,15 @@ int MvtxClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Cluster MVTX hits into TrkrCluster objects and record cluster–hit associations. + * + * For the current event node, collects MVTX hits per hitset, groups adjacent hits into clusters, + * creates TrkrClusterv5 objects with position, size, and error estimates, adds clusters to the + * module cluster container, and records associations between cluster keys and hit keys. + * + * @param topNode Top-level PHCompositeNode for the current event (used to retrieve geometry and hit containers). + */ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) { if (Verbosity() > 0) @@ -337,8 +380,8 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) unsigned int chip = MvtxDefs::getChipId(hitsetitr->first); unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first); std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first - << " layer " << layer << " stave " << stave << " chip " << chip - << " strobe " << strobe << std::endl; + << " layer " << layer << " stave " << stave << " chip " << chip + << " strobe " << strobe << std::endl; } if (Verbosity() > 2) @@ -394,7 +437,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) std::vector component(num_vertices(G)); // this is the actual clustering, performed by boost - boost::connected_components(G, &component[0]); + boost::connected_components(G, component.data()); // Loop over the components(hits) compiling a list of the // unique connected groups (ie. clusters). @@ -405,7 +448,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) cluster_ids.insert(component[i]); clusters.insert(make_pair(component[i], hitvec[i])); } - for (const auto& clusid:cluster_ids) + for (const auto &clusid : cluster_ids) { auto clusrange = clusters.equal_range(clusid); auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); @@ -413,7 +456,8 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) // determine the size of the cluster in phi and z std::set phibins; std::set zbins; - std::map m_phi, m_z; // Note, there are no "cut" bins for Svtx Clusters + std::map m_phi; + std::map m_z; // Note, there are no "cut" bins for Svtx Clusters // determine the cluster position... double locxsum = 0.; @@ -426,7 +470,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) // we need the geometry object for this layer to get the global positions int layer = TrkrDefs::getLayer(ckey); - auto layergeom = dynamic_cast(geom_container->GetLayerGeom(layer)); + auto *layergeom = dynamic_cast(geom_container->GetLayerGeom(layer)); if (!layergeom) { exit(1); @@ -574,11 +618,11 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) if (Verbosity() > 0) { std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer - << " rad " << layergeom->get_radius() << " phibins " - << phibins.size() << " pitch " << pitch << " phisize " << phisize - << " zbins " << zbins.size() << " length " << length << " zsize " - << zsize << " local x " << locclusx << " local y " << locclusz - << std::endl; + << " rad " << layergeom->get_radius() << " phibins " + << phibins.size() << " pitch " << pitch << " phisize " << phisize + << " zbins " << zbins.size() << " length " << length << " zsize " + << zsize << " local x " << locclusx << " local y " << locclusz + << std::endl; } auto clus = std::make_unique(); @@ -605,7 +649,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) } } // clusitr loop - } // loop over hitsets + } // loop over hitsets if (Verbosity() > 1) { @@ -616,6 +660,15 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) return; } +/** + * @brief Cluster MVTX raw hits and record resulting clusters. + * + * Groups adjacent RawHit objects (per the module's adjacency rules) into connected components, + * computes each cluster's local position, size, and error estimates, and inserts a TrkrClusterv5 + * for each cluster into the module's cluster container using a generated cluster key. + * + * @param topNode Event node tree root used to fetch MVTX geometry and raw-hit containers. + */ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) { if (Verbosity() > 0) @@ -650,8 +703,8 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) unsigned int chip = MvtxDefs::getChipId(hitsetitr->first); unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first); std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first - << " layer " << layer << " stave " << stave << " chip " << chip - << " strobe " << strobe << std::endl; + << " layer " << layer << " stave " << stave << " chip " << chip + << " strobe " << strobe << std::endl; } if (Verbosity() > 2) @@ -695,7 +748,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) std::vector component(num_vertices(G)); // this is the actual clustering, performed by boost - boost::connected_components(G, &component[0]); + boost::connected_components(G, component.data()); // Loop over the components(hits) compiling a list of the // unique connected groups (ie. clusters). @@ -709,7 +762,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) } // std::cout << "found cluster #: "<< clusters.size()<< std::endl; // loop over the componenets and make clusters - for( const auto& clusid:cluster_ids) + for (const auto &clusid : cluster_ids) { auto clusrange = clusters.equal_range(clusid); @@ -731,7 +784,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) // we need the geometry object for this layer to get the global positions int layer = TrkrDefs::getLayer(ckey); - auto layergeom = dynamic_cast( + auto *layergeom = dynamic_cast( geom_container->GetLayerGeom(layer)); if (!layergeom) { @@ -845,11 +898,11 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) if (Verbosity() > 0) { std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer - << " rad " << layergeom->get_radius() << " phibins " - << phibins.size() << " pitch " << pitch << " phisize " << phisize - << " zbins " << zbins.size() << " length " << length << " zsize " - << zsize << " local x " << locclusx << " local y " << locclusz - << std::endl; + << " rad " << layergeom->get_radius() << " phibins " + << phibins.size() << " pitch " << pitch << " phisize " << phisize + << " zbins " << zbins.size() << " length " << length << " zsize " + << zsize << " local x " << locclusx << " local y " << locclusz + << std::endl; } auto clus = std::make_unique(); @@ -875,7 +928,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); } } // clusitr loop - } // loop over hitsets + } // loop over hitsets if (Verbosity() > 1) { @@ -886,6 +939,15 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) return; } +/** + * @brief Print a verbosity-controlled summary of clusters found under the TRKR_CLUSTER node. + * + * If verbosity is enabled (>0) this retrieves the TRKR_CLUSTER container from the provided + * node tree and prints the total number of clusters; at higher verbosity (>3) it also + * calls the container's identify() method to print detailed information. + * + * @param topNode Root node of the PHENIX node tree from which TRKR_CLUSTER is retrieved. + */ void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode) { if (Verbosity() > 0) @@ -898,11 +960,11 @@ void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode) } std::cout << "================= After MvtxClusterizer::process_event() " - "====================" - << std::endl; + "====================" + << std::endl; std::cout << " There are " << clusterlist->size() - << " clusters recorded: " << std::endl; + << " clusters recorded: " << std::endl; if (Verbosity() > 3) { @@ -910,9 +972,9 @@ void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode) } std::cout << "==================================================================" - "=========" - << std::endl; + "=========" + << std::endl; } return; -} +} \ No newline at end of file diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index 4f141a4c3f..d35a11b275 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -51,26 +51,73 @@ namespace { //! range adaptor to be able to use range-based for loop - template class range_adaptor + template + class range_adaptor { - public: - range_adaptor( const T& range ):m_range(range){} - const typename T::first_type& begin() {return m_range.first;} - const typename T::second_type& end() {return m_range.second;} - private: + public: + /** + * @brief Construct a range_adaptor that captures the given pair-like range. + * + * Stores a copy of `range` so the adaptor can expose begin()/end() for range-based + * iteration over pair-like ranges (for example, the result of `equal_range`). + * + * @param range Pair-like range with `first` and `second` members to adapt. + */ + explicit range_adaptor(const T& range) + : m_range(range) + { + } + /** + * @brief Provides the beginning element of the wrapped pair-based range. + * + * @return const typename T::first_type& Reference to the first element of the underlying pair. + */ +const typename T::first_type& begin() { return m_range.first; } + /** + * @brief Access the end element of the underlying pair-based range. + * + * @return const typename T::second_type& Reference to the range's second element (the end iterator/value). + */ +const typename T::second_type& end() { return m_range.second; } + + private: T m_range; }; -} +} /** + * @brief Construct a MvtxHitPruner module with the given name. + * + * @param name Module name used to identify this SubsysReco instance. + */ -MvtxHitPruner::MvtxHitPruner(const std::string &name) +MvtxHitPruner::MvtxHitPruner(const std::string& name) : SubsysReco(name) { } -int MvtxHitPruner::InitRun(PHCompositeNode * /*topNode*/) -{ return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Perform per-run initialization for the MvtxHitPruner module. + * + * Currently no run-specific setup is required. + * + * @return Fun4AllReturnCodes::EVENT_OK on successful initialization. + */ +int MvtxHitPruner::InitRun(PHCompositeNode* /*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} -int MvtxHitPruner::process_event(PHCompositeNode *topNode) +/** + * @brief Consolidates MVTX hits into their strobe-0 hitsets and removes non-zero-strobe hitsets. + * + * Scans MVTX hitsets for variants with non-zero strobe IDs, copies any hits that are not + * already present into the corresponding strobe-0 (bare) hitset, and removes the original + * non-zero-strobe hitsets from the TRKR_HITSET container. + * + * @param topNode Top-level node for the current event node tree. + * @return Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTRUN if the + * required TRKR_HITSET node cannot be found. + */ +int MvtxHitPruner::process_event(PHCompositeNode* topNode) { // get node containing the digitized hits m_hits = findNode::getClass(topNode, "TRKR_HITSET"); @@ -93,12 +140,14 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) std::set bare_hitset_set; const auto hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); - for( const auto& [hitsetkey,hitset]:range_adaptor(hitsetrange) ) + for (const auto& [hitsetkey, hitset] : range_adaptor(hitsetrange)) { - // get strobe, skip if already zero const int strobe = MvtxDefs::getStrobeId(hitsetkey); - if( strobe == 0 ) continue; + if (strobe == 0) + { + continue; + } // get the hitsetkey value for strobe 0 const auto bare_hitsetkey = MvtxDefs::resetStrobe(hitsetkey); @@ -117,43 +166,46 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) for (const auto& bare_hitsetkey : bare_hitset_set) { // find matching hitset of creater - auto bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; + auto* bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; if (Verbosity()) { std::cout - << "MvtxHitPruner::process_event - bare_hitset " << bare_hitsetkey - << " initially has " << bare_hitset->size() << " hits " - << std::endl; + << "MvtxHitPruner::process_event - bare_hitset " << bare_hitsetkey + << " initially has " << bare_hitset->size() << " hits " + << std::endl; } // get all hitsets with non-zero strobe that match the bare hitset key auto bare_hitsetrange = hitset_multimap.equal_range(bare_hitsetkey); - for( const auto& [unused,hitsetkey]:range_adaptor(bare_hitsetrange) ) + for (const auto& [unused, hitsetkey] : range_adaptor(bare_hitsetrange)) { const int strobe = MvtxDefs::getStrobeId(hitsetkey); - if( strobe == 0 ) continue; + if (strobe == 0) + { + continue; + } if (Verbosity()) { std::cout << "MvtxHitPruner::process_event -" - << " process hitsetkey " << hitsetkey - << " from strobe " << strobe - << " for bare_hitsetkey " << bare_hitsetkey - << std::endl; + << " process hitsetkey " << hitsetkey + << " from strobe " << strobe + << " for bare_hitsetkey " << bare_hitsetkey + << std::endl; } // copy all hits to the hitset with strobe 0 - auto hitset = m_hits->findHitSet(hitsetkey); + auto* hitset = m_hits->findHitSet(hitsetkey); if (Verbosity()) { std::cout << "MvtxHitPruner::process_event - hitsetkey " << hitsetkey - << " has strobe " << strobe << " and has " << hitset->size() - << " hits, so copy it" << std::endl; + << " has strobe " << strobe << " and has " << hitset->size() + << " hits, so copy it" << std::endl; } TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for( const auto& [hitkey,old_hit]:range_adaptor(hitrangei) ) + for (const auto& [hitkey, old_hit] : range_adaptor(hitrangei)) { if (Verbosity()) { @@ -166,9 +218,9 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) if (Verbosity()) { std::cout - << "MvtxHitPruner::process_event - hitkey " << hitkey - << " is already in bare hitsest, do not copy" - << std::endl; + << "MvtxHitPruner::process_event - hitkey " << hitkey + << " is already in bare hitsest, do not copy" + << std::endl; } continue; } @@ -177,11 +229,11 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) if (Verbosity()) { std::cout - << "MvtxHitPruner::process_event - copying over hitkey " - << hitkey << std::endl; + << "MvtxHitPruner::process_event - copying over hitkey " + << hitkey << std::endl; } - auto new_hit = new TrkrHitv2; + auto* new_hit = new TrkrHitv2; new_hit->CopyFrom(old_hit); bare_hitset->addHitSpecificKey(hitkey, new_hit); } @@ -193,4 +245,4 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/mvtx/SegmentationAlpide.cc b/offline/packages/mvtx/SegmentationAlpide.cc index 6b9aecddd0..e50183c46d 100644 --- a/offline/packages/mvtx/SegmentationAlpide.cc +++ b/offline/packages/mvtx/SegmentationAlpide.cc @@ -5,16 +5,23 @@ */ #include "SegmentationAlpide.h" -#include - #include +#include +/** + * @brief Prints a formatted summary of ALPIDE segmentation parameters to standard output. + * + * Outputs three lines: + * - Pixel size along rows and columns in microns. + * - Passive edge sizes (bottom, top, left/right) in microns. + * - Active and total sensor sizes for rows and columns in centimeters. + */ void SegmentationAlpide::print() { - std::cout << (boost::format("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns") % (PitchRow * 1e4) % NRows % (PitchCol * 1e4) % NCols).str() + std::cout << std::format("Pixel size: {:.2f} (along {} rows) {:.2f} (along {} columns) microns", (PitchRow * 1e4), NRows, (PitchCol * 1e4), NCols) << std::endl; - std::cout << (boost::format("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns") % (PassiveEdgeReadOut * 1e4) % (PassiveEdgeTop * 1e4) % (PassiveEdgeSide * 1e4)).str() + std::cout << std::format("Passive edges: bottom: {:.2f}, top: {:.2f}, left/right: {:.2f} microns", (PassiveEdgeReadOut * 1e4), (PassiveEdgeTop * 1e4), (PassiveEdgeSide * 1e4)) << std::endl; - std::cout << (boost::format("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm") % ActiveMatrixSizeRows % SensorSizeRows % ActiveMatrixSizeCols % SensorSizeCols).str() + std::cout << std::format("Active/Total size: {:.6f}/{:.6f} (rows) {:.6f}/{:.6f} (cols) cm", ActiveMatrixSizeRows, SensorSizeRows, ActiveMatrixSizeCols, SensorSizeCols) << std::endl; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 170f95944d..9353de0f50 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -31,13 +31,10 @@ #include #include +#include #include #include #include -//#include -//#include -#include -//#include #include #include @@ -46,15 +43,16 @@ #include #include // for sqrt, cos, sin +#include #include #include #include // for _Rb_tree_cons... +#include +#include #include +#include #include // for pair #include -#include -#include -#include #include @@ -68,12 +66,9 @@ using adcKey = std::pair; using pointKeyLaser = std::pair; using hitData = std::pair; - -int layerMins[3] = {7,23,39}; +int layerMins[3] = {7, 23, 39}; int layerMaxes[3] = {22, 38, 54}; - - namespace { struct thread_data @@ -101,28 +96,34 @@ namespace pthread_mutex_t mythreadlock; const std::vector neighborOffsets = { - point(1, 0, 0), point(-1, 0, 0), - point(0, 1, 0), point(0, -1, 0), - point(0, 0, 1), point(0, 0, -1), - point(0, 0, 2), point(0, 0, -2) - }; - - - double layerFunction(double *x, double *par) + point(1, 0, 0), point(-1, 0, 0), + point(0, 1, 0), point(0, -1, 0), + point(0, 0, 1), point(0, 0, -1), + point(0, 0, 2), point(0, 0, -2)}; + + /** + * @brief Computes the expected layer response as the overlap fraction between a unit-width bin centered at x[0] and a peak centered at `mu`, scaled by amplitude `A`. + * + * The function treats the peak as occupying a unit interval centered at `mu` and the measurement as a unit interval centered at round(x[0]); it returns the length of their overlap multiplied by `A`. + * + * @param x Pointer to an array whose first element x[0] is the layer coordinate (continuous). + * @param par Parameter array where par[0] = A (amplitude scale) and par[1] = mu (peak center). + * @return double Overlap length between the two unit intervals multiplied by `A`; returns 0.0 when there is no overlap. + */ + double layerFunction(double *x, const double *par) { double A = par[0]; double mu = par[1]; - double binCenter = round(x[0]); double overlapLow = std::max(binCenter - 0.5, mu - 0.5); double overlapHigh = std::min(binCenter + 0.5, mu + 0.5); double overlap = overlapHigh - overlapLow; - if(overlap <= 0.0) + if (overlap <= 0.0) { return 0.0; } - return A*overlap; + return A * overlap; /* if(fabs(x[0] - mu) < 1) { @@ -131,50 +132,90 @@ namespace } return 0.0; */ - - } + /** + * @brief Evaluates a scaled Gaussian in the phi dimension. + * + * Computes par[0] multiplied by a Gaussian evaluated at x[0] with mean par[1] + * and standard deviation par[2]. If par[2] is less than 0, returns 0.0. + * + * @param x Pointer to an array where x[0] is the phi coordinate to evaluate. + * @param par Parameter array where: + * - par[0]: amplitude (scale factor), + * - par[1]: mean, + * - par[2]: standard deviation (sigma). + * @return double The value par[0] * Gaussian(x[0]; par[1], par[2]) or `0.0` if par[2] < 0. + */ double phiFunction(double *x, double *par) { - if(par[2] < 0.0) + if (par[2] < 0.0) { return 0.0; } - return par[0] * TMath::Gaus(x[0],par[1],par[2],false); + return par[0] * TMath::Gaus(x[0], par[1], par[2], false); } + /** + * @brief Computes a modified Gaussian multiplied by an asymmetric complementary error-term factor for a time coordinate. + * + * Evaluates par[0] * Gaussian(x[0]; mean=par[1], sigma=par[2]) * (1 + erfc(par[3] * (x[0]-par[1])/(sqrt(2)*par[2]))). + * If par[2] is negative, the function returns 0.0. + * + * @param x Pointer to the independent-variable array; x[0] is the time coordinate to evaluate. + * @param par Parameter array where: + * - par[0]: overall amplitude scaling, + * - par[1]: Gaussian mean, + * - par[2]: Gaussian standard deviation (sigma); must be >= 0 or result is 0, + * - par[3]: factor controlling the complementary-error-term asymmetry. + * @return double The evaluated value of the modified Gaussian at x[0]. + */ double timeFunction(double *x, double *par) { - if(par[2] < 0.0) + if (par[2] < 0.0) { return 0.0; } - double g = TMath::Gaus(x[0],par[1],par[2],true); - double cdf = 1 + TMath::Erfc(par[3]*(x[0]-par[1])/(sqrt(2.0)*par[2])); - return par[0]*g*cdf; + double g = TMath::Gaus(x[0], par[1], par[2], true); + double cdf = 1 + TMath::Erfc(par[3] * (x[0] - par[1]) / (sqrt(2.0) * par[2])); + return par[0] * g * cdf; } + /** + * @brief Extracts the connected region of hits that contains a specified seed hit. + * + * Given a set of candidate hits, replaces clusHits with the subset that forms the + * connected region (via 3D adjacency) containing the hit identified by maxKey. + * Connectivity is determined by matching neighbor offsets in integer 3D coordinates + * (coordinates compared within a tolerance of 0.01). + * + * @param clusHits On input, the list of candidate hits (each as (point, key)). On + * output, contains only the hits belonging to the connected region that includes + * the seed specified by maxKey. + * @param maxKey Pair of (hitkey, hitsetkey) identifying the seed hit whose region + * should be extracted; this parameter is not modified. + */ void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey) { std::vector> regions; std::vector unvisited; - for(auto &clusHit : clusHits) + unvisited.reserve(clusHits.size()); + for (auto &clusHit : clusHits) { unvisited.push_back(clusHit); } - while(!unvisited.empty()) + while (!unvisited.empty()) { std::vector region; std::queue q; unsigned int mIndex = 0; - int i=0; - for(auto hit : unvisited) + int i = 0; + for (auto hit : unvisited) { - if(hit.second.second.first == maxKey.first && hit.second.second.second == maxKey.second) + if (hit.second.second.first == maxKey.first && hit.second.second.second == maxKey.second) { mIndex = i; break; @@ -183,11 +224,11 @@ namespace } auto seed = unvisited[mIndex]; - unvisited.erase(unvisited.begin()+mIndex); + unvisited.erase(unvisited.begin() + mIndex); q.push(seed); region.push_back(seed); - while(!q.empty()) + while (!q.empty()) { float ix = q.front().first.get<0>(); float iy = q.front().first.get<1>(); @@ -200,13 +241,12 @@ namespace float ny = iy + neigh.get<1>(); float nz = iz + neigh.get<2>(); - for(unsigned int v=0; v() - nx) < 0.01 && fabs(unvisited[v].first.get<1>() - ny) < 0.01 && fabs(unvisited[v].first.get<2>() - nz) < 0.01) + if (fabs(unvisited[v].first.get<0>() - nx) < 0.01 && fabs(unvisited[v].first.get<1>() - ny) < 0.01 && fabs(unvisited[v].first.get<2>() - nz) < 0.01) { auto newSeed = unvisited[v]; - unvisited.erase(unvisited.begin()+v); + unvisited.erase(unvisited.begin() + v); q.push(newSeed); region.push_back(newSeed); break; @@ -215,18 +255,26 @@ namespace } } regions.push_back(region); - } clusHits.clear(); - for(auto hit : regions[0]) + for (auto hit : regions[0]) { clusHits.push_back(hit); } - } - + /** + * @brief Remove a set of clustered hits from the spatial index and ADC lookup. + * + * For each hit in clusHits, removes the hit from the provided R-tree and + * erases the first entry in adcMap whose spechitkey matches the hit's + * spechitkey. + * + * @param clusHits Vector of hit records to remove; each element's spechitkey is used to find ADC entries. + * @param rtree Spatial index (R-tree) containing the hits; matching entries will be removed. + * @param adcMap Multimap mapping ADC values to hit keys; the first matching entry per hit will be erased. + */ void remove_hits(std::vector &clusHits, bgi::rtree> &rtree, std::multimap &adcMap) { for (auto &clusHit : clusHits) @@ -237,51 +285,59 @@ namespace for (auto iterAdc = adcMap.begin(); iterAdc != adcMap.end();) { - if(iterAdc->second.second == spechitkey) - { - iterAdc = adcMap.erase(iterAdc); - break; - } - else - { - ++iterAdc; - } + if (iterAdc->second.second == spechitkey) + { + iterAdc = adcMap.erase(iterAdc); + break; + } + + ++iterAdc; } } - } + /** + * @brief Compute and record cluster properties from a set of hits. + * + * Builds a LaserClusterv2 describing the provided hits, computes its geometric + * and statistical properties (ADC sum, centroid in layer/iphi/time and in x/y/z, + * per-axis spreads, and counts of distinct layer/iphi/it bins), and appends + * the cluster and its generated cluster key to the thread_data vectors. + * When enabled, a constrained 3D fit refines the cluster position and shape; + * otherwise ADC-weighted centroids are used. Temporary histograms and fit + * objects are internally created and cleaned up. + * + * @param clusHits Vector of hit entries that belong to the cluster (coordinates + ADC + hit keys). + * @param my_data Per-thread context and storage; updated by appending the new cluster and its key. + * @param maxADCKey Hit identifier used as the seed/key basis for generating the cluster key. + */ void calc_cluster_parameter(std::vector &clusHits, thread_data &my_data, std::pair maxADCKey) { - - - findConnectedRegions3(clusHits, maxADCKey); - double rSum = 0.0; double phiSum = 0.0; double tSum = 0.0; - + double layerSum = 0.0; double iphiSum = 0.0; double itSum = 0.0; - + double adcSum = 0.0; - + double maxAdc = 0.0; TrkrDefs::hitsetkey maxKey = 0; - + unsigned int nHits = clusHits.size(); - + auto *clus = new LaserClusterv2; - + int meanSide = 0; - + std::vector usedLayer; std::vector usedIPhi; std::vector usedIT; - + double meanLayer = 0.0; double meanIPhi = 0.0; double meanIT = 0.0; @@ -293,113 +349,110 @@ namespace unsigned int adc = clusHit.second.first; int side = TpcDefs::getSide(spechitkey.second); - + if (side) { - meanSide++; + meanSide++; } else { - meanSide--; + meanSide--; } - + PHG4TpcGeom *layergeom = my_data.geom_container->GetLayerCellGeom((int) coords[0]); - + double r = layergeom->get_radius(); double phi = layergeom->get_phi(coords[1], side); double t = layergeom->get_zcenter(fabs(coords[2])); - + double hitzdriftlength = t * my_data.tGeometry->get_drift_velocity(); double hitZ = my_data.tdriftmax * my_data.tGeometry->get_drift_velocity() - hitzdriftlength; - - - bool foundLayer = false; - for (float i : usedLayer) - { - if (coords[0] == i) - { - foundLayer = true; - break; - } - } - - if (!foundLayer) - { - usedLayer.push_back(coords[0]); - } - - bool foundIPhi = false; - for (float i : usedIPhi) - { - if (coords[1] == i) - { - foundIPhi = true; - break; - } - } - - if (!foundIPhi) - { - usedIPhi.push_back(coords[1]); - } - - bool foundIT = false; - for (float i : usedIT) - { - if (coords[2] == i) - { - foundIT = true; - break; - } - } - - if (!foundIT) - { - usedIT.push_back(coords[2]); - } - - clus->addHit(); - clus->setHitLayer(clus->getNhits() - 1, coords[0]); - clus->setHitIPhi(clus->getNhits() - 1, coords[1]); - clus->setHitIT(clus->getNhits() - 1, coords[2]); - clus->setHitX(clus->getNhits() - 1, r * cos(phi)); - clus->setHitY(clus->getNhits() - 1, r * sin(phi)); - clus->setHitZ(clus->getNhits() - 1, hitZ); - clus->setHitAdc(clus->getNhits() - 1, (float) adc); - - rSum += r * adc; - phiSum += phi * adc; - tSum += t * adc; - - layerSum += coords[0] * adc; - iphiSum += coords[1] * adc; - itSum += coords[2] * adc; - - meanLayer += coords[0]; - meanIPhi += coords[1]; - meanIT += coords[2]; - - adcSum += adc; - - if (adc > maxAdc) - { - maxAdc = adc; - maxKey = spechitkey.second; - } - - } - + + bool foundLayer = false; + for (float i : usedLayer) + { + if (coords[0] == i) + { + foundLayer = true; + break; + } + } + + if (!foundLayer) + { + usedLayer.push_back(coords[0]); + } + + bool foundIPhi = false; + for (float i : usedIPhi) + { + if (coords[1] == i) + { + foundIPhi = true; + break; + } + } + + if (!foundIPhi) + { + usedIPhi.push_back(coords[1]); + } + + bool foundIT = false; + for (float i : usedIT) + { + if (coords[2] == i) + { + foundIT = true; + break; + } + } + + if (!foundIT) + { + usedIT.push_back(coords[2]); + } + + clus->addHit(); + clus->setHitLayer(clus->getNhits() - 1, coords[0]); + clus->setHitIPhi(clus->getNhits() - 1, coords[1]); + clus->setHitIT(clus->getNhits() - 1, coords[2]); + clus->setHitX(clus->getNhits() - 1, r * cos(phi)); + clus->setHitY(clus->getNhits() - 1, r * sin(phi)); + clus->setHitZ(clus->getNhits() - 1, hitZ); + clus->setHitAdc(clus->getNhits() - 1, (float) adc); + + rSum += r * adc; + phiSum += phi * adc; + tSum += t * adc; + + layerSum += coords[0] * adc; + iphiSum += coords[1] * adc; + itSum += coords[2] * adc; + + meanLayer += coords[0]; + meanIPhi += coords[1]; + meanIT += coords[2]; + + adcSum += adc; + + if (adc > maxAdc) + { + maxAdc = adc; + maxKey = spechitkey.second; + } + } + if (nHits == 0) { return; } - double clusR = rSum / adcSum; double clusPhi = phiSum / adcSum; double clusT = tSum / adcSum; double zdriftlength = clusT * my_data.tGeometry->get_drift_velocity(); - + double clusX = clusR * cos(clusPhi); double clusY = clusR * sin(clusPhi); double clusZ = my_data.tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; @@ -408,10 +461,10 @@ namespace clusZ = -clusZ; for (int i = 0; i < (int) clus->getNhits(); i++) { - clus->setHitZ(i, -1 * clus->getHitZ(i)); + clus->setHitZ(i, -1 * clus->getHitZ(i)); } } - + std::sort(usedLayer.begin(), usedLayer.end()); std::sort(usedIPhi.begin(), usedIPhi.end()); std::sort(usedIT.begin(), usedIT.end()); @@ -419,30 +472,28 @@ namespace meanLayer = meanLayer / nHits; meanIPhi = meanIPhi / nHits; meanIT = meanIT / nHits; - + double sigmaLayer = 0.0; double sigmaIPhi = 0.0; double sigmaIT = 0.0; - + double sigmaWeightedLayer = 0.0; double sigmaWeightedIPhi = 0.0; double sigmaWeightedIT = 0.0; - - pthread_mutex_lock(&mythreadlock); - my_data.hitHist = new TH3D(Form("hitHist_event%d_side%d_sector%d_module%d_cluster%d",my_data.eventNum,(int)my_data.side,(int)my_data.sector,(int)my_data.module,(int)my_data.cluster_vector.size()),";layer;iphi;it",usedLayer.size()+2,usedLayer[0]-1.5,*usedLayer.rbegin()+1.5,usedIPhi.size()+2,usedIPhi[0]-1.5,*usedIPhi.rbegin()+1.5,usedIT.size()+2,usedIT[0]-1.5,*usedIT.rbegin()+1.5); + pthread_mutex_lock(&mythreadlock); + my_data.hitHist = new TH3D(std::format("hitHist_event{}_side{}_sector{}_module{}_cluster{}", my_data.eventNum, (int) my_data.side, (int) my_data.sector, (int) my_data.module, (int) my_data.cluster_vector.size()).c_str(), ";layer;iphi;it", usedLayer.size() + 2, usedLayer[0] - 1.5, *usedLayer.rbegin() + 1.5, usedIPhi.size() + 2, usedIPhi[0] - 1.5, *usedIPhi.rbegin() + 1.5, usedIT.size() + 2, usedIT[0] - 1.5, *usedIT.rbegin() + 1.5); - //TH3D *hitHist = new TH3D(Form("hitHist_event%d_side%d_sector%d_module%d_cluster%d",my_data.eventNum,(int)my_data.side,(int)my_data.sector,(int)my_data.module,(int)my_data.cluster_vector.size()),";layer;iphi;it",usedLayer.size()+2,usedLayer[0]-1.5,*usedLayer.rbegin()+1.5,usedIPhi.size()+2,usedIPhi[0]-1.5,*usedIPhi.rbegin()+1.5,usedIT.size()+2,usedIT[0]-1.5,*usedIT.rbegin()+1.5); + // TH3D *hitHist = new TH3D(Form("hitHist_event%d_side%d_sector%d_module%d_cluster%d",my_data.eventNum,(int)my_data.side,(int)my_data.sector,(int)my_data.module,(int)my_data.cluster_vector.size()),";layer;iphi;it",usedLayer.size()+2,usedLayer[0]-1.5,*usedLayer.rbegin()+1.5,usedIPhi.size()+2,usedIPhi[0]-1.5,*usedIPhi.rbegin()+1.5,usedIT.size()+2,usedIT[0]-1.5,*usedIT.rbegin()+1.5); for (int i = 0; i < (int) clus->getNhits(); i++) { - my_data.hitHist->Fill(clus->getHitLayer(i), clus->getHitIPhi(i), clus->getHitIT(i), clus->getHitAdc(i)); sigmaLayer += pow(clus->getHitLayer(i) - meanLayer, 2); sigmaIPhi += pow(clus->getHitIPhi(i) - meanIPhi, 2); sigmaIT += pow(clus->getHitIT(i) - meanIT, 2); - + sigmaWeightedLayer += clus->getHitAdc(i) * pow(clus->getHitLayer(i) - (layerSum / adcSum), 2); sigmaWeightedIPhi += clus->getHitAdc(i) * pow(clus->getHitIPhi(i) - (iphiSum / adcSum), 2); sigmaWeightedIT += clus->getHitAdc(i) * pow(clus->getHitIT(i) - (itSum / adcSum), 2); @@ -451,20 +502,18 @@ namespace bool fitSuccess = false; ROOT::Fit::Fitter *fit3D = new ROOT::Fit::Fitter; - if(my_data.doFitting) + if (my_data.doFitting) { - double par_init[7] = { - maxAdc, - meanLayer, - meanIPhi, 0.75, - meanIT, 0.5, 1 - }; + maxAdc, + meanLayer, + meanIPhi, 0.75, + meanIT, 0.5, 1}; double satThreshold = 900.0; double sigma_ADC = 20.0; - auto nll = [&](const double* par) + auto nll = [&](const double *par) { double nll_val = 0.0; @@ -472,37 +521,37 @@ namespace int ny = my_data.hitHist->GetNbinsY(); int nz = my_data.hitHist->GetNbinsZ(); - double parLayer[2] = {1.0,par[1]}; - double parPhi[4] = {1.0,par[2],par[3]}; - double parTime[4] = {1.0,par[4],par[5],par[6]}; + double parLayer[2] = {1.0, par[1]}; + double parPhi[4] = {1.0, par[2], par[3]}; + double parTime[4] = {1.0, par[4], par[5], par[6]}; double xyz[3]; for (int i = 1; i <= nx; ++i) { - xyz[0] = my_data.hitHist->GetXaxis()->GetBinCenter(i); + xyz[0] = my_data.hitHist->GetXaxis()->GetBinCenter(i); for (int j = 1; j <= ny; ++j) { - xyz[1] = my_data.hitHist->GetYaxis()->GetBinCenter(j); + xyz[1] = my_data.hitHist->GetYaxis()->GetBinCenter(j); for (int k = 1; k <= nz; ++k) { xyz[2] = my_data.hitHist->GetZaxis()->GetBinCenter(k); double observed = my_data.hitHist->GetBinContent(i, j, k); - double expected = par[0]*layerFunction(&xyz[0], parLayer)*phiFunction(&xyz[1], parPhi)*timeFunction(&xyz[2], parTime); + double expected = par[0] * layerFunction(&xyz[0], parLayer) * phiFunction(&xyz[1], parPhi) * timeFunction(&xyz[2], parTime); - if(observed <= my_data.adc_threshold) + if (observed <= my_data.adc_threshold) { double arg = (expected - my_data.adc_threshold) / (sqrt(2.0) * sigma_ADC); double tail_prob = 0.5 * TMath::Erfc(arg); nll_val -= log(tail_prob + 1e-12); } - else if(observed < satThreshold) + else if (observed < satThreshold) { double resid = (observed - expected) / sigma_ADC; nll_val += 0.5 * (resid * resid + log(2 * TMath::Pi() * sigma_ADC * sigma_ADC)); } - else if(observed >= satThreshold) + else if (observed >= satThreshold) { double arg = (satThreshold - expected) / (sqrt(2.0) * sigma_ADC); double tail_prob = 0.5 * TMath::Erfc(arg); @@ -518,35 +567,33 @@ namespace fit3D->Config().ParSettings(0).SetName("amp"); fit3D->Config().ParSettings(0).SetStepSize(10); - fit3D->Config().ParSettings(0).SetLimits(0,5000); + fit3D->Config().ParSettings(0).SetLimits(0, 5000); fit3D->Config().ParSettings(1).SetName("mu_layer"); fit3D->Config().ParSettings(1).SetStepSize(0.1); - fit3D->Config().ParSettings(1).SetLimits(usedLayer[0],*usedLayer.rbegin()); + fit3D->Config().ParSettings(1).SetLimits(usedLayer[0], *usedLayer.rbegin()); fit3D->Config().ParSettings(2).SetName("mu_phi"); fit3D->Config().ParSettings(2).SetStepSize(0.1); - fit3D->Config().ParSettings(2).SetLimits(usedIPhi[0],*usedIPhi.rbegin()); + fit3D->Config().ParSettings(2).SetLimits(usedIPhi[0], *usedIPhi.rbegin()); fit3D->Config().ParSettings(3).SetName("sig_phi"); fit3D->Config().ParSettings(3).SetStepSize(0.1); - fit3D->Config().ParSettings(3).SetLimits(0.01,2); + fit3D->Config().ParSettings(3).SetLimits(0.01, 2); fit3D->Config().ParSettings(4).SetName("mu_t"); fit3D->Config().ParSettings(4).SetStepSize(0.1); - fit3D->Config().ParSettings(4).SetLimits(usedIT[0],*usedIT.rbegin()); + fit3D->Config().ParSettings(4).SetLimits(usedIT[0], *usedIT.rbegin()); fit3D->Config().ParSettings(5).SetName("sig_t"); fit3D->Config().ParSettings(5).SetStepSize(0.1); - fit3D->Config().ParSettings(5).SetLimits(0.01,10); + fit3D->Config().ParSettings(5).SetLimits(0.01, 10); fit3D->Config().ParSettings(6).SetName("lambda_t"); fit3D->Config().ParSettings(6).SetStepSize(0.01); - fit3D->Config().ParSettings(6).SetLimits(0,5); + fit3D->Config().ParSettings(6).SetLimits(0, 5); - - if(usedLayer.size() == 1) + if (usedLayer.size() == 1) { fit3D->Config().ParSettings(1).Fix(); } fitSuccess = fit3D->FitFCN(); - if (my_data.Verbosity > 2) { std::cout << "fit success: " << fitSuccess << std::endl; @@ -554,13 +601,9 @@ namespace } pthread_mutex_unlock(&mythreadlock); - - - if(my_data.doFitting && fitSuccess) + if (my_data.doFitting && fitSuccess) { - - const ROOT::Fit::FitResult& result = fit3D->Result(); - + const ROOT::Fit::FitResult &result = fit3D->Result(); PHG4TpcGeom *layergeomLow = my_data.geom_container->GetLayerCellGeom((int) floor(result.Parameter(1))); PHG4TpcGeom *layergeomHigh = my_data.geom_container->GetLayerCellGeom((int) ceil(result.Parameter(1))); @@ -569,12 +612,12 @@ namespace double RHigh = layergeomHigh->get_radius(); double phiHigh_RLow = -999.0; - if(ceil(result.Parameter(2)) < layergeomLow->get_phibins()) + if (ceil(result.Parameter(2)) < layergeomLow->get_phibins()) { phiHigh_RLow = layergeomLow->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); } double phiHigh_RHigh = -999.0; - if(ceil(result.Parameter(2)) < layergeomHigh->get_phibins()) + if (ceil(result.Parameter(2)) < layergeomHigh->get_phibins()) { phiHigh_RHigh = layergeomHigh->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); } @@ -587,18 +630,17 @@ namespace double meanPhi_RLow = ((result.Parameter(2) - floor(result.Parameter(2)))) * (phiHigh_RLow - phiLow_RLow) + phiLow_RLow; double meanPhi_RHigh = ((result.Parameter(2) - floor(result.Parameter(2)))) * (phiHigh_RHigh - phiLow_RHigh) + phiLow_RHigh; - double meanPhi = 0.5*(meanPhi_RLow + meanPhi_RHigh); - if(phiHigh_RLow == -999.0 && phiHigh_RHigh != -999.0) + double meanPhi = 0.5 * (meanPhi_RLow + meanPhi_RHigh); + if (phiHigh_RLow == -999.0 && phiHigh_RHigh != -999.0) { meanPhi = meanPhi_RHigh; } - else if(phiHigh_RLow != -999.0 && phiHigh_RHigh == -999.0) + else if (phiHigh_RLow != -999.0 && phiHigh_RHigh == -999.0) { meanPhi = meanPhi_RLow; } - - if(phiHigh_RLow == -999.0 && phiHigh_RHigh == -999.0) + if (phiHigh_RLow == -999.0 && phiHigh_RHigh == -999.0) { clus->setAdc(adcSum); clus->setX(clusX); @@ -619,10 +661,10 @@ namespace clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); } else - { + { clus->setAdc(adcSum); - clus->setX(meanR*cos(meanPhi)); - clus->setY(meanR*sin(meanPhi)); + clus->setX(meanR * cos(meanPhi)); + clus->setY(meanR * sin(meanPhi)); clus->setZ(clusZ); clus->setFitMode(true); clus->setLayer(result.Parameter(1)); @@ -663,25 +705,29 @@ namespace const auto ckey = TrkrDefs::genClusKey(maxKey, my_data.cluster_vector.size()); my_data.cluster_vector.push_back(clus); my_data.cluster_key_vector.push_back(ckey); - - if(fit3D) - { - delete fit3D; - } - if(my_data.hitHist) + delete fit3D; + + if (my_data.hitHist) { delete my_data.hitHist; my_data.hitHist = nullptr; } - - } - + /** + * @brief Build spatial index from the thread's hitsets and extract clusters for the assigned module region. + * + * Processes the hits listed in my_data->hitsets: filters hits by ADC threshold and proximity to the thread's peak time bin, + * inserts unique hits into a spatial index, then repeatedly finds connected hit regions, computes cluster parameters, + * and removes processed hits until no candidates remain. Discovered clusters and their keys are appended to the + * corresponding containers in the provided thread_data. + * + * @param my_data Per-thread processing state and configuration (geometry, thresholds, peak time, layer bounds, verbosity, + * and output cluster vectors). Must contain populated hitsets; returns immediately if hitsets is empty. + */ void ProcessModuleData(thread_data *my_data) { - if (my_data->Verbosity > 2) { pthread_mutex_lock(&mythreadlock); @@ -693,85 +739,84 @@ namespace std::multimap adcMap; - if (my_data->hitsets.size() == 0) + if (my_data->hitsets.empty()) { return; } - for(int i=0; i<(int)my_data->hitsets.size(); i++) + for (int i = 0; i < (int) my_data->hitsets.size(); i++) { auto *hitset = my_data->hitsets[i]; unsigned int layer = my_data->layers[i]; bool side = my_data->side; unsigned int sector = my_data->sector; - TrkrDefs::hitsetkey hitsetKey = TpcDefs::genHitSetKey(layer, sector, (int)side); + TrkrDefs::hitsetkey hitsetKey = TpcDefs::genHitSetKey(layer, sector, (int) side); TrkrHitSet::ConstRange hitrangei = hitset->getHits(); for (TrkrHitSet::ConstIterator hitr = hitrangei.first; hitr != hitrangei.second; ++hitr) { - float_t fadc = hitr->second->getAdc(); - unsigned short adc = 0; - if (fadc > my_data->adc_threshold) - { - adc = (unsigned short) fadc; - } - else - { - continue; - } - - int iphi = TpcDefs::getPad(hitr->first); - int it = TpcDefs::getTBin(hitr->first); - - if(fabs(it - my_data->peakTimeBin) > 5) - { - continue; - } - - point coords = point((int) layer, iphi, it); - - std::vector testduplicate; - rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), - point(layer + 0.001, iphi + 0.001, it + 0.001))), - std::back_inserter(testduplicate)); - if (!testduplicate.empty()) - { - testduplicate.clear(); - continue; - } - - TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); - - auto spechitkey = std::make_pair(hitKey, hitsetKey); - pointKeyLaser coordsKey = std::make_pair(coords, spechitkey); - adcMap.insert(std::make_pair(adc, coordsKey)); + float_t fadc = hitr->second->getAdc(); + unsigned short adc = 0; + if (fadc > my_data->adc_threshold) + { + adc = (unsigned short) fadc; + } + else + { + continue; + } + + int iphi = TpcDefs::getPad(hitr->first); + int it = TpcDefs::getTBin(hitr->first); + + if (fabs(it - my_data->peakTimeBin) > 5) + { + continue; + } + + point coords = point((int) layer, iphi, it); + + std::vector testduplicate; + rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), + point(layer + 0.001, iphi + 0.001, it + 0.001))), + std::back_inserter(testduplicate)); + if (!testduplicate.empty()) + { + testduplicate.clear(); + continue; + } + + TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); + + auto spechitkey = std::make_pair(hitKey, hitsetKey); + pointKeyLaser coordsKey = std::make_pair(coords, spechitkey); + adcMap.insert(std::make_pair(adc, coordsKey)); auto adckey = std::make_pair(adc, spechitkey); - rtree.insert(std::make_pair(point(1.0*layer, 1.0*iphi, 1.0*it), adckey)); + rtree.insert(std::make_pair(point(1.0 * layer, 1.0 * iphi, 1.0 * it), adckey)); } } - //finished filling rtree + // finished filling rtree - while (adcMap.size() > 0) + while (!adcMap.empty()) { auto iterKey = adcMap.rbegin(); - if(iterKey == adcMap.rend()) + if (iterKey == adcMap.rend()) { - break; + break; } - auto coords = iterKey->second.first; int layer = coords.get<0>(); int iphi = coords.get<1>(); int it = coords.get<2>(); - + if (my_data->Verbosity > 2) { pthread_mutex_lock(&mythreadlock); - std::cout << "working on cluster " << my_data->cluster_vector.size() << " side: " << my_data->side << " sector: " << my_data->sector << " module: " << (layer<23 ? 1 : (layer<39 ? 2 : 3) ) << std::endl; + // NOLINTNEXTLINE (readability-avoid-nested-conditional-operator) + std::cout << "working on cluster " << my_data->cluster_vector.size() << " side: " << my_data->side << " sector: " << my_data->sector << " module: " << (layer < 23 ? 1 : (layer < 39 ? 2 : 3)) << std::endl; pthread_mutex_unlock(&mythreadlock); - } std::vector clusHits; @@ -781,23 +826,43 @@ namespace calc_cluster_parameter(clusHits, *my_data, iterKey->second.second); remove_hits(clusHits, rtree, adcMap); - } } + /** + * @brief Thread entry point that processes a module's data. + * + * Processes the work described by the provided thread_data and then terminates the calling thread. + * + * @param threadarg Pointer to a thread_data struct containing per-thread processing state. + * @return Always `nullptr`; the thread terminates by calling `pthread_exit`. + */ void *ProcessModule(void *threadarg) { - auto my_data = static_cast(threadarg); + auto *my_data = static_cast(threadarg); ProcessModuleData(my_data); pthread_exit(nullptr); } -} //namespace +} /** + * @brief Construct a LaserClusterizer subsystem instance. + * + * @param name Subsystem name passed to the SubsysReco base class; used to identify this module in the run framework. + */ LaserClusterizer::LaserClusterizer(const std::string &name) : SubsysReco(name) { } +/** + * @brief Initialize runtime resources, ensure cluster and geometry nodes exist, and configure drift timing. + * + * Ensures the DST/TRKR node structure contains a LaserClusterContainer (creates one under TRKR if missing), + * locates the TPC geometry container, and derives the ADC clock period and maximum drift time used by the clusterizer. + * + * @param topNode Root node of the event/node tree to search for DST and geometry nodes. + * @return int Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTRUN if required nodes (DST or TPC geometry) are missing. + */ int LaserClusterizer::InitRun(PHCompositeNode *topNode) { TH1::AddDirectory(kFALSE); @@ -818,7 +883,7 @@ int LaserClusterizer::InitRun(PHCompositeNode *topNode) { laserClusterNodeName = "LAMINATION_CLUSTER"; } - auto laserclusters = findNode::getClass(dstNode, laserClusterNodeName); + auto *laserclusters = findNode::getClass(dstNode, laserClusterNodeName); if (!laserclusters) { PHNodeIterator dstiter(dstNode); @@ -835,7 +900,7 @@ int LaserClusterizer::InitRun(PHCompositeNode *topNode) new PHIODataNode(laserclusters, laserClusterNodeName, "PHObject"); DetNode->addNode(LaserClusterContainerNode); } - + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!m_geom_container) @@ -850,6 +915,20 @@ int LaserClusterizer::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Process a single event: identify laser events, cluster TPC laser hits per sector/side/module, and add resulting clusters to the configured LaserClusterContainer. + * + * This routine: + * - Verifies required nodes (EventHeader, LaserEventInfo, DST, TRKR_HITSET, ActsGeometry, and the laser cluster container). + * - Skips events that are not identified as laser events according to LaserEventInfo and run-number rules. + * - Partitions TPC hitsets by sector, side, and module, then launches worker threads (or runs sequentially) to build clusters for each partition. + * - Collects per-thread clusters and adds them to the laser cluster container. + * + * @param topNode Root of the PHENIX/Fun4All node tree containing event and detector data. + * @return int Fun4AllReturnCodes::EVENT_OK on success; + * Fun4AllReturnCodes::ABORTRUN if required nodes or geometry are missing or LaserEventInfo cannot be found; + * non-zero error code on thread or mutex initialization failures. + */ int LaserClusterizer::process_event(PHCompositeNode *topNode) { eventHeader = findNode::getClass(topNode, "EventHeader"); @@ -873,7 +952,7 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - if((eventHeader->get_RunNumber() > 66153 && !m_laserEventInfo->isGl1LaserEvent()) || (eventHeader->get_RunNumber() <= 66153 && !m_laserEventInfo->isLaserEvent())) + if ((eventHeader->get_RunNumber() > 66153 && !m_laserEventInfo->isGl1LaserEvent()) || (eventHeader->get_RunNumber() <= 66153 && !m_laserEventInfo->isLaserEvent())) { return Fun4AllReturnCodes::EVENT_OK; } @@ -897,7 +976,7 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + // get node for clusters std::string laserClusterNodeName = "LASER_CLUSTER"; if (m_lamination) @@ -921,8 +1000,8 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - TrkrHitSetContainer::ConstRange hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId);; - + TrkrHitSetContainer::ConstRange hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId); + struct thread_pair_t { pthread_t thread{}; @@ -938,123 +1017,122 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) if (pthread_mutex_init(&mythreadlock, nullptr) != 0) { - std::cout << std::endl << " mutex init failed" << std::endl; + std::cout << std::endl + << " mutex init failed" << std::endl; return 1; } - - for (unsigned int sec=0; sec<12; sec++) + + for (unsigned int sec = 0; sec < 12; sec++) { - for (int s=0; s<2; s++) + for (int s = 0; s < 2; s++) { - for (unsigned int mod=0; mod<3; mod++) + for (unsigned int mod = 0; mod < 3; mod++) { - - if(Verbosity() > 2) + if (Verbosity() > 2) { std::cout << "making thread for side: " << s << " sector: " << sec << " module: " << mod << std::endl; } - thread_pair_t &thread_pair = threads.emplace_back(); - - std::vector hitsets; - std::vector layers; - - std::vector cluster_vector; - std::vector cluster_key_vector; - - for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; - hitsetitr != hitsetrange.second; - ++hitsetitr) - { - unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); - int side = TpcDefs::getSide(hitsetitr->first); - unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); - if (sector != sec || side != s) - { - continue; - } - if ((mod==0 && (layer<7 || layer>22)) || (mod==1 && (layer<=22 || layer>38) ) || (mod==2 && (layer<=38 || layer>54))) - { - continue; - } - - TrkrHitSet *hitset = hitsetitr->second; - - hitsets.push_back(hitset); - layers.push_back(layer); - - } - - thread_pair.data.geom_container = m_geom_container; - thread_pair.data.tGeometry = m_tGeometry; - thread_pair.data.hitsets = hitsets; - thread_pair.data.layers = layers; - thread_pair.data.side = (bool)s; - thread_pair.data.sector = sec; + thread_pair_t &thread_pair = threads.emplace_back(); + + std::vector hitsets; + std::vector layers; + + std::vector cluster_vector; + std::vector cluster_key_vector; + + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); + int side = TpcDefs::getSide(hitsetitr->first); + unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); + if (sector != sec || side != s) + { + continue; + } + if ((mod == 0 && (layer < 7 || layer > 22)) || (mod == 1 && (layer <= 22 || layer > 38)) || (mod == 2 && (layer <= 38 || layer > 54))) + { + continue; + } + + TrkrHitSet *hitset = hitsetitr->second; + + hitsets.push_back(hitset); + layers.push_back(layer); + } + + thread_pair.data.geom_container = m_geom_container; + thread_pair.data.tGeometry = m_tGeometry; + thread_pair.data.hitsets = hitsets; + thread_pair.data.layers = layers; + thread_pair.data.side = (bool) s; + thread_pair.data.sector = sec; thread_pair.data.module = mod; - thread_pair.data.cluster_vector = cluster_vector; - thread_pair.data.cluster_key_vector = cluster_key_vector; - thread_pair.data.adc_threshold = m_adc_threshold; - thread_pair.data.peakTimeBin = m_laserEventInfo->getPeakSample(s); - thread_pair.data.layerMin = 3; - thread_pair.data.layerMax = 3; - thread_pair.data.tdriftmax = m_tdriftmax; + thread_pair.data.cluster_vector = cluster_vector; + thread_pair.data.cluster_key_vector = cluster_key_vector; + thread_pair.data.adc_threshold = m_adc_threshold; + thread_pair.data.peakTimeBin = m_laserEventInfo->getPeakSample(s); + thread_pair.data.layerMin = 3; + thread_pair.data.layerMax = 3; + thread_pair.data.tdriftmax = m_tdriftmax; thread_pair.data.eventNum = m_event; thread_pair.data.Verbosity = Verbosity(); thread_pair.data.hitHist = nullptr; thread_pair.data.doFitting = m_do_fitting; - int rc; - rc = pthread_create(&thread_pair.thread, &attr, ProcessModule, (void *) &thread_pair.data); - - if (rc) - { - std::cout << "Error:unable to create thread," << rc << std::endl; - } - - if (m_do_sequential) - { - //wait for termination of thread - int rc2 = pthread_join(thread_pair.thread, nullptr); - if (rc2) - { - std::cout << "Error:unable to join," << rc2 << std::endl; - } - - //add clusters from thread to laserClusterContainer - const auto &data(thread_pair.data); - for(int index = 0; index < (int) data.cluster_vector.size(); ++index) - { - auto cluster = data.cluster_vector[index]; - const auto ckey = data.cluster_key_vector[index]; - - m_clusterlist->addClusterSpecifyKey(ckey, cluster); - } - } + int rc; + rc = pthread_create(&thread_pair.thread, &attr, ProcessModule, (void *) &thread_pair.data); + + if (rc) + { + std::cout << "Error:unable to create thread," << rc << std::endl; + } + + if (m_do_sequential) + { + // wait for termination of thread + int rc2 = pthread_join(thread_pair.thread, nullptr); + if (rc2) + { + std::cout << "Error:unable to join," << rc2 << std::endl; + } + + // add clusters from thread to laserClusterContainer + const auto &data(thread_pair.data); + for (int index = 0; index < (int) data.cluster_vector.size(); ++index) + { + auto *cluster = data.cluster_vector[index]; + const auto ckey = data.cluster_key_vector[index]; + + m_clusterlist->addClusterSpecifyKey(ckey, cluster); + } + } } } } - + pthread_attr_destroy(&attr); if (!m_do_sequential) { - for (const auto & thread_pair : threads) + for (const auto &thread_pair : threads) { int rc2 = pthread_join(thread_pair.thread, nullptr); if (rc2) { - std::cout << "Error:unable to join," << rc2 << std::endl; + std::cout << "Error:unable to join," << rc2 << std::endl; } - - //const auto &data(thread_pair.data); - - for(int index = 0; index < (int) thread_pair.data.cluster_vector.size(); ++index) + + // const auto &data(thread_pair.data); + + for (int index = 0; index < (int) thread_pair.data.cluster_vector.size(); ++index) { - auto cluster = thread_pair.data.cluster_vector[index]; - const auto ckey = thread_pair.data.cluster_key_vector[index]; - - m_clusterlist->addClusterSpecifyKey(ckey, cluster); + auto *cluster = thread_pair.data.cluster_vector[index]; + const auto ckey = thread_pair.data.cluster_key_vector[index]; + + m_clusterlist->addClusterSpecifyKey(ckey, cluster); } } } @@ -1067,5 +1145,4 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; - -} +} \ No newline at end of file diff --git a/offline/packages/tpc/LaserEventIdentifier.cc b/offline/packages/tpc/LaserEventIdentifier.cc index 8b6035db05..31533cf9ff 100644 --- a/offline/packages/tpc/LaserEventIdentifier.cc +++ b/offline/packages/tpc/LaserEventIdentifier.cc @@ -111,6 +111,16 @@ int LaserEventIdentifier::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Processes a single event to identify laser-induced TPC signals and update event metadata. + * + * Examines GL1 raw hit information and TPC hit time-bin distributions to detect laser events or GL1 laser/pileup conditions. + * Updates the LaserEventInfo node with GL1 flags, laser-event flag, per-side peak sample indices, and peak widths. + * Accumulates time-bin counts into per-side histograms, performs peak finding and Gaussian fits, and optionally fills a debug TTree. + * + * @param topNode Top-level node of the PHENIX/Fun4All node tree containing input and output nodes (e.g., "LaserEventInfo", "GL1RAWHIT", TRKR hit nodes). + * @return int Fun4All return code: `Fun4AllReturnCodes::ABORTRUN` if the LaserEventInfo node is missing; `Fun4AllReturnCodes::EVENT_OK` otherwise. + */ int LaserEventIdentifier::process_event(PHCompositeNode *topNode) { m_laserEventInfo = findNode::getClass(topNode, "LaserEventInfo"); @@ -130,7 +140,7 @@ int LaserEventIdentifier::process_event(PHCompositeNode *topNode) } else if(m_runnumber > 66153) { - if ((gl1pkt->getGTMAllBusyVector() & (1<<14)) == 0) + if ((gl1pkt->getGTMAllBusyVector() & (1U<<14U)) == 0) { m_laserEventInfo->setIsGl1LaserEvent(true); m_laserEventInfo->setIsGl1LaserPileupEvent(false); @@ -274,4 +284,4 @@ int LaserEventIdentifier::End(PHCompositeNode * /*topNode*/) } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/Tpc3DClusterizer.cc b/offline/packages/tpc/Tpc3DClusterizer.cc index e19cbf507f..ac12d48f24 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.cc +++ b/offline/packages/tpc/Tpc3DClusterizer.cc @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,17 @@ Tpc3DClusterizer::Tpc3DClusterizer(const std::string &name) { } +/** + * @brief Initialize run-time nodes, outputs, geometry, and timers required for 3D clustering. + * + * Ensures the DST/TRKR/LASER_CLUSTER node exists (creating it if necessary), opens debug and + * output ROOT files and creates histograms/trees/ntuple when configured, retrieves the TPC + * geometry container and computes ADC timing parameters, and initializes profiling timers. + * + * @param topNode Pointer to the top-level PHCompositeNode of the DST node tree. + * @return int `Fun4AllReturnCodes::EVENT_OK` on success, `Fun4AllReturnCodes::ABORTRUN` if the + * DST node or required TPC geometry container is missing. + */ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); @@ -72,7 +84,7 @@ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto laserclusters = findNode::getClass(dstNode, "LASER_CLUSTER"); + auto *laserclusters = findNode::getClass(dstNode, "LASER_CLUSTER"); if (!laserclusters) { PHNodeIterator dstiter(dstNode); @@ -111,13 +123,14 @@ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) m_clusterTree->Branch("time_erase", &time_erase); m_clusterTree->Branch("time_all", &time_all); } - - if (m_output){ + + if (m_output) + { m_outputFile = new TFile(m_outputFileName.c_str(), "RECREATE"); - m_clusterNT = new TNtuple("clus3D", "clus3D","event:seed:x:y:z:r:phi:phibin:tbin:adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize"); + m_clusterNT = new TNtuple("clus3D", "clus3D", "event:seed:x:y:z:r:phi:phibin:tbin:adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize"); } - + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!m_geom_container) @@ -142,13 +155,27 @@ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Perform 3D clustering of TPC hits for the current event and store resulting laser clusters. + * + * Identifies laser-like hits in the TPC, groups them into 3D clusters, and adds resulting LaserCluster + * objects to the LASER_CLUSTER container. Updates internal timing/profiling and optional debug/output + * structures as configured. May early-abort the run if required DST or geometry nodes are missing. + * + * @param topNode Top-level node of the current event containing DST, hit sets, geometry, and cluster nodes. + * @return int Fun4AllReturnCodes::EVENT_OK on success; Fun4AllReturnCodes::ABORTRUN if required nodes + * (DST, TRKR_HITSET, LASER_CLUSTER, or ActsGeometry) are missing and processing is aborted. + */ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) { ++m_event; - recoConsts* rc = recoConsts::instance(); - if (rc->FlagExist("RANDOMSEED")){ - m_seed = (int)rc->get_IntFlag("RANDOMSEED"); - } else { + recoConsts *rc = recoConsts::instance(); + if (rc->FlagExist("RANDOMSEED")) + { + m_seed = rc->get_IntFlag("RANDOMSEED"); + } + else + { m_seed = std::numeric_limits::quiet_NaN(); } @@ -163,11 +190,12 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) } // get node containing the digitized hits m_hits = findNode::getClass(topNode, "TRKR_HITSET"); - if (!m_hits){ + if (!m_hits) + { std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + // get node for clusters m_clusterlist = findNode::getClass(topNode, "LASER_CLUSTER"); if (!m_clusterlist) @@ -193,7 +221,8 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) bgi::rtree> rtree_reject; for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; - ++hitsetitr){ + ++hitsetitr) + { TrkrHitSet *hitset = hitsetitr->second; unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); int side = TpcDefs::getSide(hitsetitr->first); @@ -202,49 +231,54 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) TrkrHitSet::ConstRange hitrangei = hitset->getHits(); for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr){ + hitr != hitrangei.second; + ++hitr) + { int iphi = TpcDefs::getPad(hitr->first); int it = TpcDefs::getTBin(hitr->first); // std::cout << " iphi: " << iphi << " it: " << it << std::endl; - float_t fadc = (hitr->second->getAdc());// - m_pedestal; // proper int rounding +0.5 + float_t fadc = (hitr->second->getAdc()); // - m_pedestal; // proper int rounding +0.5 unsigned short adc = 0; - if (fadc > 0){ - adc = (unsigned short) fadc; + if (fadc > 0) + { + adc = (unsigned short) fadc; } - if (adc <= 0){ - continue; + if (adc <= 0) + { + continue; } - + std::vector testduplicate; rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), - point(layer + 0.001, iphi + 0.001, it + 0.001))), - std::back_inserter(testduplicate)); - if (!testduplicate.empty()){ - testduplicate.clear(); - continue; + point(layer + 0.001, iphi + 0.001, it + 0.001))), + std::back_inserter(testduplicate)); + if (!testduplicate.empty()) + { + testduplicate.clear(); + continue; } TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); - + auto spechitkey = std::make_pair(hitKey, hitsetKey); rtree_reject.insert(std::make_pair(point(1.0 * layer, 1.0 * iphi, 1.0 * it), spechitkey)); } } - + std::multimap, std::array>> adcMap; // std::cout << "n hitsets: " << std::distance(hitsetrange.first,hitsetrange.second) // << std::endl; for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; - ++hitsetitr){ + ++hitsetitr) + { TrkrHitSet *hitset = hitsetitr->second; unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); int side = TpcDefs::getSide(hitsetitr->first); unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); - //PHG4TpcGeom *layergeom = m_geom_container->GetLayerCellGeom(layer); - // double r = layergeom->get_radius(); - + // PHG4TpcGeom *layergeom = m_geom_container->GetLayerCellGeom(layer); + // double r = layergeom->get_radius(); + TrkrDefs::hitsetkey hitsetKey = TpcDefs::genHitSetKey(layer, sector, side); TrkrHitSet::ConstRange hitrangei = hitset->getHits(); @@ -252,74 +286,122 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) // << std::endl; // int nhits = 0; for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr){ + hitr != hitrangei.second; + ++hitr) + { int iphi = TpcDefs::getPad(hitr->first); int it = TpcDefs::getTBin(hitr->first); // std::cout << " iphi: " << iphi << " it: " << it << std::endl; - float_t fadc = (hitr->second->getAdc());// - m_pedestal; // proper int rounding +0.5 + float_t fadc = (hitr->second->getAdc()); // - m_pedestal; // proper int rounding +0.5 unsigned short adc = 0; // std::cout << " nhit: " << nhits++ << "adc: " << fadc << " phi: " << iphi << " it: " << it << std::endl; - if (fadc > 0){ - adc = (unsigned short) fadc; + if (fadc > 0) + { + adc = (unsigned short) fadc; } - if (adc <= 0){ - continue; + if (adc <= 0) + { + continue; } - if(layer>=7+32){ - //if(side==1)continue; - if(abs(iphi-0)<=2) continue; - if(abs(iphi-191)<=2) continue; - if(abs(iphi-206)<=1) continue; - if(abs(iphi-383)<=2) continue; - if(abs(iphi-576)<=2) continue; - if(abs(iphi-767)<=2) continue; - if(abs(iphi-960)<=2) continue; - if(abs(iphi-1522)<=2) continue; - if(abs(iphi-1344)<=2) continue; - if(abs(iphi-1536)<=2) continue; - if(abs(iphi-1728)<=2) continue; - if(abs(iphi-1920)<=2) continue; - if(abs(iphi-2111)<=2) continue; - if(abs(iphi-2303)<=2) continue; + if (layer >= 7 + 32) + { + // if(side==1)continue; + if (abs(iphi - 0) <= 2) + { + continue; + } + if (abs(iphi - 191) <= 2) + { + continue; + } + if (abs(iphi - 206) <= 1) + { + continue; + } + if (abs(iphi - 383) <= 2) + { + continue; + } + if (abs(iphi - 576) <= 2) + { + continue; + } + if (abs(iphi - 767) <= 2) + { + continue; + } + if (abs(iphi - 960) <= 2) + { + continue; + } + if (abs(iphi - 1522) <= 2) + { + continue; + } + if (abs(iphi - 1344) <= 2) + { + continue; + } + if (abs(iphi - 1536) <= 2) + { + continue; + } + if (abs(iphi - 1728) <= 2) + { + continue; + } + if (abs(iphi - 1920) <= 2) + { + continue; + } + if (abs(iphi - 2111) <= 2) + { + continue; + } + if (abs(iphi - 2303) <= 2) + { + continue; + } } /* double phi = layergeom->get_phi(iphi); double m_sampa_tbias = 39.6; double zdriftlength = (layergeom->get_zcenter(it)+ m_sampa_tbias) * m_tGeometry->get_drift_velocity(); - + float x = r * cos(phi); float y = r * sin(phi); float z = m_tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength; if (side == 0){ - z = -z; - it = -it; + z = -z; + it = -it; } */ std::array coords = {(int) layer, iphi, it}; - + std::vector testduplicate; rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), - point(layer + 0.001, iphi + 0.001, it + 0.001))), - std::back_inserter(testduplicate)); - if (!testduplicate.empty()){ - testduplicate.clear(); - continue; + point(layer + 0.001, iphi + 0.001, it + 0.001))), + std::back_inserter(testduplicate)); + if (!testduplicate.empty()) + { + testduplicate.clear(); + continue; } - - //test for isolated hit + + // test for isolated hit std::vector testisolated; rtree_reject.query(bgi::intersects(box(point(layer - 1.001, iphi - 1.001, it - 1.001), - point(layer + 1.001, iphi + 1.001, it + 1.001))), - std::back_inserter(testisolated)); - if(testisolated.size()==1){ - //testisolated.clear(); - continue; + point(layer + 1.001, iphi + 1.001, it + 1.001))), + std::back_inserter(testisolated)); + if (testisolated.size() == 1) + { + // testisolated.clear(); + continue; } - + TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); - + auto spechitkey = std::make_pair(hitKey, hitsetKey); auto keyCoords = std::make_pair(spechitkey, coords); adcMap.insert(std::make_pair(adc, keyCoords)); @@ -327,38 +409,43 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) rtree.insert(std::make_pair(point(1.0 * layer, 1.0 * iphi, 1.0 * it), spechitkey)); } } - - if (Verbosity() > 1){ + + if (Verbosity() > 1) + { std::cout << "finished looping over hits" << std::endl; std::cout << "map size: " << adcMap.size() << std::endl; std::cout << "rtree size: " << rtree.size() << std::endl; } - + // done filling rTree - + t_all->restart(); - - while (adcMap.size() > 0){ + + while (!adcMap.empty()) + { auto iterKey = adcMap.rbegin(); - if (iterKey == adcMap.rend()){ + if (iterKey == adcMap.rend()) + { break; } - + auto coords = iterKey->second.second; int layer = coords[0]; int iphi = coords[1]; int it = coords[2]; - + int layerMax = layer + 1; - if (layer == 22 || layer == 38 || layer == 54){ + if (layer == 22 || layer == 38 || layer == 54) + { layerMax = layer; } int layerMin = layer - 1; - if (layer == 7 || layer == 23 || layer == 39){ + if (layer == 7 || layer == 23 || layer == 39) + { layerMin = layer; } - + std::vector clusHits; t_search->restart(); @@ -376,21 +463,24 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) clusHits.clear(); } - if (m_debug){ + if (m_debug) + { m_nClus = (int) m_eventClusters.size(); } t_all->stop(); - if (m_debug){ + if (m_debug) + { time_search = t_search->get_accumulated_time() / 1000.; time_clus = t_clus->get_accumulated_time() / 1000.; time_erase = t_erase->get_accumulated_time() / 1000.; time_all = t_all->get_accumulated_time() / 1000.; - + m_clusterTree->Fill(); } - - if (Verbosity()){ + + if (Verbosity()) + { std::cout << "rtree search time: " << t_search->get_accumulated_time() / 1000. << " sec" << std::endl; std::cout << "clustering time: " << t_clus->get_accumulated_time() / 1000. << " sec" << std::endl; std::cout << "erasing time: " << t_erase->get_accumulated_time() / 1000. << " sec" << std::endl; @@ -401,30 +491,50 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -int Tpc3DClusterizer::ResetEvent(PHCompositeNode * /*topNode*/){ +/** + * @brief Reset per-event histograms and debug cluster state. + * + * Resets internal per-event histograms used for iteration and time diagnostics. + * If debug mode is enabled, also resets additional timing histograms and clears + * the per-event cluster debug container. + * + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ +int Tpc3DClusterizer::ResetEvent(PHCompositeNode * /*topNode*/) +{ m_itHist_0->Reset(); m_itHist_1->Reset(); - + if (m_debug) - { - m_tHist_0->Reset(); - m_tHist_1->Reset(); - - m_eventClusters.clear(); - } - + { + m_tHist_0->Reset(); + m_tHist_1->Reset(); + + m_eventClusters.clear(); + } + return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Finalize processing by writing and closing enabled debug and output ROOT files. + * + * If debug mode is enabled, writes the cluster debug tree to the debug file and closes it. + * If output is enabled, writes the cluster NTuple to the output file and closes it. + * + * @return Fun4AllReturnCodes::EVENT_OK indicating successful finalization. + */ int Tpc3DClusterizer::End(PHCompositeNode * /*topNode*/) { - if (m_debug){ + if (m_debug) + { m_debugFile->cd(); m_clusterTree->Write(); m_debugFile->Close(); } - if (m_output){ + if (m_output) + { m_outputFile->cd(); m_clusterNT->Write(); m_outputFile->Close(); @@ -432,9 +542,35 @@ int Tpc3DClusterizer::End(PHCompositeNode * /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Compute and register a 3D laser cluster from a set of seed hits. + * + * Calculates ADC-weighted cluster properties (position, sums, sizes, seed hit) + * from the provided hit coordinates and ADC lookup, constructs a LaserCluster, + * and adds it to the module's LaserClusterContainer. Also fills the cluster + * output NTuple and, when debugging is enabled, stores a cloned debug copy. + * + * @param clusHits Vector of hit descriptors where each element pairs a 3D + * coordinate tuple (layer, iphi, it) with the hit key + * (hitkey, hitsetkey) for that hit. Only hits present in + * @p adcMap are included in the composed cluster. + * @param adcMap Multimap keyed by ADC value mapping to a pair of + * (hitkey, hitsetkey) and integer coordinate array; used to + * retrieve per-hit ADC values and to correlate hits with the + * input @p clusHits. + * + * Side effects: + * - On success (at least one matched hit) a new LaserCluster is created and + * added to m_clusterlist with a generated cluster key. + * - The cluster summary is appended to m_clusterNT. + * - If m_debug is set, a cloned cluster is stored in m_eventClusters for + * per-event debugging. + * + * If no hits are provided or no ADC entries match, no cluster is added. + */ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHits, std::multimap, std::array>> &adcMap) { - //std::cout << "nu clus" << std::endl; + // std::cout << "nu clus" << std::endl; double rSum = 0.0; double phiSum = 0.0; double tSum = 0.0; @@ -449,9 +585,12 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi TrkrDefs::hitsetkey maxKey = 0; unsigned int nHits = clusHits.size(); - int iphimin = 6666, iphimax = -1; - int ilaymin = 6666, ilaymax = -1; - float itmin = 66666666.6, itmax = -6666666666.6; + int iphimin = 6666; + int iphimax = -1; + int ilaymin = 6666; + int ilaymax = -1; + float itmin = 66666666.6; + float itmax = -6666666666.6; auto *clus = new LaserClusterv1; for (auto &clusHit : clusHits) @@ -468,21 +607,21 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi double phi = layergeom->get_phi(coords[1], side); double t = layergeom->get_zcenter(fabs(coords[2])); int tbin = coords[2]; - int lay = coords[0];//TrkrDefs::getLayer(spechitkey.second); + int lay = coords[0]; // TrkrDefs::getLayer(spechitkey.second); double hitzdriftlength = t * m_tGeometry->get_drift_velocity(); double hitZ = m_tdriftmax * m_tGeometry->get_drift_velocity() - hitzdriftlength; /*std::cout << " lay: " << lay - << " phi: " << phi - << " t: " << t - << " side: " << side - << std::endl; + << " phi: " << phi + << " t: " << t + << " side: " << side + << std::endl; */ - if(phiiphimax){iphimax = phi;} - if(layilaymax){ilaymax = lay;} - if(tbinitmax){itmax = tbin;} + iphimin = std::min(phi, iphimin); + iphimax = std::max(phi, iphimax); + ilaymin = std::min(lay, ilaymin); + ilaymax = std::max(lay, ilaymax); + itmin = std::min(tbin, itmin); + itmax = std::max(tbin, itmax); for (auto &iterKey : adcMap) { @@ -522,7 +661,7 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi if (nHits == 0) { - std::cout << "no hits"<< std::endl; + std::cout << "no hits" << std::endl; return; } @@ -554,67 +693,84 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi clus->setLayer(layerSum / adcSum); clus->setIPhi(iphiSum / adcSum); clus->setIT(itSum / adcSum); - int phisize = iphimax - iphimin + 1; - int lsize = ilaymax - ilaymin + 1; - int tsize = itmax - itmin +1; + int phisize = iphimax - iphimin + 1; + int lsize = ilaymax - ilaymin + 1; + int tsize = itmax - itmin + 1; if (m_debug) { m_currentCluster = (LaserCluster *) clus->CloneMe(); m_eventClusters.push_back((LaserCluster *) m_currentCluster->CloneMe()); } // if(nHits>1&&tsize>5){ - if(nHits>=1){ + if (nHits >= 1) + { const auto ckey = TrkrDefs::genClusKey(maxKey, m_clusterlist->size()); m_clusterlist->addClusterSpecifyKey(ckey, clus); - } else { + } + else + { delete clus; } - - //event:seed:x:y:z:r:phi:phibin:tbin::adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize + // event:seed:x:y:z:r:phi:phibin:tbin::adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize //"event:seed:x:y:z:r:phi:phibin:tbin::adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize" /* std::cout << " l size: " << lsize - << " phisize : " << phisize - << " tsize: " << tsize - << " maxside: " << maxside - << std::endl; + << " phisize : " << phisize + << " tsize: " << tsize + << " maxside: " << maxside + << std::endl; */ // if (m_output){ - float fX[20] = {0}; - int n = 0; - fX[n++] = m_event; - fX[n++] = m_seed; - fX[n++] = clusX; - fX[n++] = clusY; - fX[n++] = clusZ; - fX[n++] = clusR; - fX[n++] = clusPhi; - fX[n++] = clusiPhi; - fX[n++] = clusT; - fX[n++] = adcSum; - fX[n++] = maxAdc; - fX[n++] = (layerSum/adcSum); - fX[n++] = maxsector; - fX[n++] = maxside; - fX[n++] = nHits; - fX[n++] = phisize; - fX[n++] = tsize; - fX[n++] = lsize; - m_clusterNT->Fill(fX); - // } + float fX[20] = {0}; + int n = 0; + fX[n++] = m_event; + fX[n++] = m_seed; + fX[n++] = clusX; + fX[n++] = clusY; + fX[n++] = clusZ; + fX[n++] = clusR; + fX[n++] = clusPhi; + fX[n++] = clusiPhi; + fX[n++] = clusT; + fX[n++] = adcSum; + fX[n++] = maxAdc; + fX[n++] = (layerSum / adcSum); + fX[n++] = maxsector; + fX[n++] = maxside; + fX[n++] = nHits; + fX[n++] = phisize; + fX[n++] = tsize; + fX[n++] = lsize; + m_clusterNT->Fill(fX); + // } } +/** + * @brief Remove entries for consumed hits from indexing structures used during clustering. + * + * Erases entries in the ADC multimap that correspond to the supplied cluster hits. The provided + * Boost R-tree is available for spatial removals as well (spatial removal calls are optional/ + * commented in the implementation). + * + * @param clusHits Vector of pairs where each element contains a spatial point and its associated hit key + * representing hits that have been consumed by a cluster. + * @param rtree Boost.Geometry R-tree indexing the spatial locations of hits; may be used to remove + * spatial entries corresponding to consumed hits. + * @param adcMap Multimap from ADC value to a pair of (hit key, hitset key) and coordinate indices; + * entries whose hit key matches an element of `clusHits` will be erased. + */ void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rtree> &rtree, std::multimap, std::array>> &adcMap) { for (auto &clusHit : clusHits) { auto spechitkey = clusHit.second; - if(rtree.size()==0){ + if (rtree.empty()) + { std::cout << "not good" << std::endl; } - //rtree.remove(clusHit); + // rtree.remove(clusHit); for (auto iterAdc = adcMap.begin(); iterAdc != adcMap.end();) { @@ -623,10 +779,8 @@ void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rt iterAdc = adcMap.erase(iterAdc); break; } - else - { - ++iterAdc; - } + + ++iterAdc; } } -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcClusterMover.cc b/offline/packages/tpc/TpcClusterMover.cc index 643fe5587f..4cf37e1cea 100644 --- a/offline/packages/tpc/TpcClusterMover.cc +++ b/offline/packages/tpc/TpcClusterMover.cc @@ -17,19 +17,39 @@ namespace { - [[maybe_unused]] std::ostream& operator << (std::ostream& out, const Acts::Vector3& v ) + /** + * @brief Formats an Acts::Vector3 as "(x, y, z)" and writes it to an output stream. + * + * @param out Stream to write the formatted vector to. + * @param v 3D vector whose components will be written in the order x, y, z. + * @return std::ostream& Reference to the same output stream after writing. + */ + [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector3& v) { out << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")"; return out; } -} +} /** + * @brief Construct a TpcClusterMover and initialize TPC layer geometry. + * + * Initializes radial spacing for the inner, middle, and outer TPC regions and + * computes the default radius for each of the 48 readout layers as the midpoint + * of its region bin. + * + * @details + * - inner/mid/outer spacings are computed from the configured region boundary radii. + * - layer_radius[0..15] are set for the inner region, + * layer_radius[16..31] are set for the middle region, + * layer_radius[32..47] are set for the outer region. + */ TpcClusterMover::TpcClusterMover() + : inner_tpc_spacing((mid_tpc_min_radius - inner_tpc_min_radius) / 16.0) + , mid_tpc_spacing((outer_tpc_min_radius - mid_tpc_min_radius) / 16.0) + , outer_tpc_spacing((outer_tpc_max_radius - outer_tpc_min_radius) / 16.0) { // initialize layer radii - inner_tpc_spacing = (mid_tpc_min_radius - inner_tpc_min_radius) / 16.0; - mid_tpc_spacing = (outer_tpc_min_radius - mid_tpc_min_radius) / 16.0; - outer_tpc_spacing = (outer_tpc_max_radius - outer_tpc_min_radius) / 16.0; + for (int i = 0; i < 16; ++i) { layer_radius[i] = inner_tpc_min_radius + (double) i * inner_tpc_spacing + 0.5 * inner_tpc_spacing; @@ -44,7 +64,16 @@ TpcClusterMover::TpcClusterMover() } } -void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer *cellgeo) +/** + * @brief Populate internal layer radii from the TPC cell geometry container. + * + * Reads layer radii from the provided PHG4TpcGeomContainer and stores them + * into the mover's internal layer_radius array so subsequent cluster projections + * use the geometry-derived surface radii. + * + * @param cellgeo TPC geometry container providing per-layer radius information. + */ +void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer* cellgeo) { if (_verbosity > 0) { @@ -62,10 +91,23 @@ void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer *cellgeo) } } -//____________________________________________________________________________.. +/** + * @brief Move TPC clusters on a track to their readout layer surfaces while leaving non‑TPC clusters unchanged. + * + * Fits a circle to the track's TPC cluster positions to determine the transverse trajectory and fits z as a function + * of radius to determine longitudinal position; each TPC cluster is then projected from its distorted position + * onto the target readout layer radius and replaced by the projected global position. Clusters for which a valid + * projection cannot be determined are omitted from the returned list. If the track contains fewer than three TPC + * clusters, the input list is returned unchanged. + * + * @param global_in Vector of (cluster key, global position) pairs for all clusters on the track. TPC clusters are + * identified by their cluster key and are the only ones moved; non‑TPC clusters are preserved as provided. + * @return std::vector> Vector of (cluster key, global position) pairs where + * TPC cluster positions have been replaced by their projections to the corresponding readout layer radii; + * non‑TPC clusters are included unchanged. Clusters that could not be projected are not included for the failed entries. + */ std::vector> TpcClusterMover::processTrack(const std::vector>& global_in) { - // Get the global positions of the TPC clusters for this track, already corrected for distortions, and move them to the surfaces // The input object contains all clusters for the track @@ -74,7 +116,7 @@ std::vector> TpcClusterMover::proces std::vector tpc_global_vec; std::vector tpc_cluskey_vec; - for (const auto& [ckey,global]:global_in) + for (const auto& [ckey, global] : global_in) { const auto trkrid = TrkrDefs::getTrkrId(ckey); if (trkrid == TrkrDefs::tpcId) @@ -85,7 +127,7 @@ std::vector> TpcClusterMover::proces else { // si clusters stay where they are - global_moved.emplace_back(ckey,global); + global_moved.emplace_back(ckey, global); } } @@ -158,7 +200,26 @@ std::vector> TpcClusterMover::proces return global_moved; } -int TpcClusterMover::get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y) +/** + * @brief Selects the intersection point between a fitted circle and a cylinder at a given radius. + * + * Computes the two intersection candidates between the circle (centered at (X0,Y0) with radius R) + * and the cylinder of radius target_radius, then assigns (x,y) to the candidate chosen based on + * proximity to the original cluster position (xclus,yclus). If the intersection computation fails, + * the function signals the failure without modifying (x,y). + * + * @param target_radius Cylinder radius (target surface) to intersect with. + * @param R Radius of the fitted circle. + * @param X0 X coordinate of the fitted circle center. + * @param Y0 Y coordinate of the fitted circle center. + * @param xclus X coordinate of the original cluster position, used to select the closer intersection. + * @param yclus Y coordinate of the original cluster position, used to select the closer intersection. + * @param[out] x Selected intersection X coordinate. + * @param[out] y Selected intersection Y coordinate. + * @return int `Fun4AllReturnCodes::EVENT_OK` if a valid intersection was selected and (x,y) set; + * `Fun4AllReturnCodes::ABORTEVENT` if the intersection calculation failed. + */ +int TpcClusterMover::get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double& x, double& y) const { // finds the intersection of the fitted circle with the cylinder having radius = target_radius const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(target_radius, R, X0, Y0); @@ -188,4 +249,4 @@ int TpcClusterMover::get_circle_circle_intersection(double target_radius, double y = yminus; } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcClusterMover.h b/offline/packages/tpc/TpcClusterMover.h index dc67312f7f..1ba4749a2b 100644 --- a/offline/packages/tpc/TpcClusterMover.h +++ b/offline/packages/tpc/TpcClusterMover.h @@ -12,6 +12,19 @@ class PHG4TpcGeomContainer; +/** + * Compute an intersection coordinate between two circles. + * + * @param target_radius Radius of the target circle centered at (xclus, yclus). + * @param R Radius of the circle centered at (X0, Y0). + * @param X0 X coordinate of the first circle center. + * @param Y0 Y coordinate of the first circle center. + * @param xclus X coordinate of the target circle center. + * @param yclus Y coordinate of the target circle center. + * @param x Output parameter set to the X coordinate of an intersection point when one exists. + * @param y Output parameter set to the Y coordinate of an intersection point when one exists. + * @returns Number of intersection points found: `0` (no intersection), `1` (tangent), or `2` (two intersections). + */ class TpcClusterMover { public: @@ -27,7 +40,7 @@ class TpcClusterMover void initialize_geometry(PHG4TpcGeomContainer *cellgeo); private: - int get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y); + int get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y) const; double _z_start = 0.0; double _y_start = 0.0; @@ -50,4 +63,4 @@ class TpcClusterMover int _verbosity = 0; }; -#endif +#endif \ No newline at end of file diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index bd5fc3c340..cf8146c82e 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -25,7 +25,6 @@ #include #include #include -#include #include #include // for SubsysReco @@ -50,6 +49,7 @@ #include +#include #include #include // for sqrt, cos, sin #include @@ -64,7 +64,14 @@ namespace { template - inline constexpr T square(const T &x) + /** + * @brief Compute the square of a value. + * + * @tparam T Type that supports multiplication (T operator*(const T&, const T&)). + * @param x Value to square. + * @return T The value multiplied by itself (x * x). + */ + constexpr T square(const T &x) { return x * x; } @@ -357,6 +364,19 @@ namespace return; } + /** + * @brief Determines whether a hit at the given phi/time bin has any non-zero neighbors. + * + * Checks the 3x3 neighborhood centered on (iphi, it) (excluding the center bin) and + * treats bins outside [0, NPhiBinsMax) or [0, NTBinsMax) as clipped to the valid range. + * + * @param iphi Phi-bin index of the hit. + * @param it Time-bin index of the hit. + * @param NPhiBinsMax Number of phi bins (upper exclusive bound). + * @param NTBinsMax Number of time bins (upper exclusive bound). + * @param adcval 2D array of ADC values indexed as adcval[phi][time]. + * @return int `1` if all neighboring bins in the 8-neighborhood have ADC value 0, `0` otherwise. + */ int is_hit_isolated(int iphi, int it, int NPhiBinsMax, int NTBinsMax, const std::vector> &adcval) { // check isolated hits @@ -365,20 +385,14 @@ namespace int isosum = 0; int isophimin = iphi - 1; - if (isophimin < 0) - { - isophimin = 0; - } + isophimin = std::max(isophimin, 0); int isophimax = iphi + 1; if (!(isophimax < NPhiBinsMax)) { isophimax = NPhiBinsMax - 1; } int isotmin = it - 1; - if (isotmin < 0) - { - isotmin = 0; - } + isotmin = std::max(isotmin, 0); int isotmax = it + 1; if (!(isotmax < NTBinsMax)) { @@ -465,6 +479,26 @@ namespace return; } + /** + * @brief Compute cluster properties from a list of hits and append resulting cluster data to thread state. + * + * Processes the provided hits to form a cluster: computes ADC-weighted centroid in phi and drift time, + * estimates spatial errors, determines the corresponding detector surface, and — if the cluster passes + * quality thresholds — constructs a TrkrClusterv5 and appends it to my_data.cluster_vector. + * When configured, this routine also: + * - runs a neural-network refinement to adjust cluster phi/z, + * - produces a TrainingHits object for supervised training and appends it to my_data.v_hits, + * - records per-bin ADC summaries for verbose output, + * - and records cluster–hit associations into my_data.association_vector. + * + * @param iphi_center Phi-bin index of the seed (center) hit within the local layer indexing. + * @param it_center Time-bin index of the seed (center) hit within the local layer indexing. + * @param ihit_list Vector of hits (iphi/it/adc/edge) that belong to the candidate cluster. + * @param my_data Per-thread processing context where produced clusters, associations, verbose records, + * and configuration (thresholds, geometry, NN flags, etc.) are stored and read. + * @param ntouch Number of overlapping hits touching other clusters; recorded on the created cluster. + * @param nedge Number of edge hits in the cluster; recorded on the created cluster. + */ void calc_cluster_parameter(const int iphi_center, const int it_center, const std::vector &ihit_list, thread_data &my_data, int ntouch, int nedge) { @@ -537,30 +571,11 @@ namespace continue; } - if (adc > max_adc) - { - max_adc = adc; - } - - if (iphi > phibinhi) - { - phibinhi = iphi; - } - - if (iphi < phibinlo) - { - phibinlo = iphi; - } - - if (it > tbinhi) - { - tbinhi = it; - } - - if (it < tbinlo) - { - tbinlo = it; - } + max_adc = std::max(max_adc, static_cast(std::round(adc))); // preserves rounding (0.5 -> 1) + phibinhi = std::max(iphi, phibinhi); + phibinlo = std::min(iphi, phibinlo); + tbinhi = std::max(it, tbinhi); + tbinlo = std::min(it, tbinlo); // if(it==it_center){ yg_sum += adc; } // update phi sums @@ -686,7 +701,7 @@ namespace // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; if (sqrt(phi_err_square) > my_data.min_err_squared) { - auto clus = new TrkrClusterv5; + auto *clus = new TrkrClusterv5; // auto clus = std::make_unique(); clus_base = clus; clus->setAdc(adc_sum); @@ -738,19 +753,19 @@ namespace if (my_data.fillClusHitsVerbose && b_made_cluster) { // push the data back to - my_data.phivec_ClusHitsVerbose.push_back(std::vector>{}); - my_data.zvec_ClusHitsVerbose.push_back(std::vector>{}); + my_data.phivec_ClusHitsVerbose.emplace_back(); + my_data.zvec_ClusHitsVerbose.emplace_back(); auto &vphi = my_data.phivec_ClusHitsVerbose.back(); auto &vz = my_data.zvec_ClusHitsVerbose.back(); for (auto &entry : m_phi) { - vphi.push_back({entry.first, entry.second}); + vphi.emplace_back(entry.first, entry.second); } for (auto &entry : m_z) { - vz.push_back({entry.first, entry.second}); + vz.emplace_back(entry.first, entry.second); } } @@ -777,6 +792,24 @@ namespace // std::cout << "done calc" << std::endl; } + /** + * @brief Process a single sector (layer/side/sector) to find and build TPC clusters. + * + * Reads hits from the thread-specific hitset or rawhitset, constructs a 2D ADC map, + * identifies local maxima and grows clusters around peaks, computes per-cluster + * parameters (including optional neural-network refinement), and records cluster + * objects and hit associations into the provided thread-local outputs. + * + * The function respects configured thresholds, wedge emulation, fixed-window logic, + * and single-hit suppression flags. When enabled, it also generates training hit + * records for each cluster. + * + * @param my_data Pointer to the thread_data structure containing input hitset/rawhitset, + * geometry and configuration parameters. This object is mutated: + * - cluster_vector is appended with created cluster objects, + * - association_vector is appended with cluster↔hit associations, + * - v_hits is appended with generated TrainingHits when training is enabled. + */ void ProcessSectorData(thread_data *my_data) { const auto &pedestal = my_data->pedestal; @@ -875,7 +908,7 @@ namespace } if (adc > my_data->edge_threshold) { - adcval[phibin][tbin] = (unsigned short) adc; + adcval[phibin][tbin] = adc; } } } @@ -967,7 +1000,7 @@ namespace } */ // std::cout << "done filling " << std::endl; - while (all_hit_map.size() > 0) + while (!all_hit_map.empty()) { // std::cout << "all hit map size: " << all_hit_map.size() << std::endl; auto iter = all_hit_map.rbegin(); @@ -1013,22 +1046,10 @@ namespace { continue; } - if (wiphi > wphibinhi) - { - wphibinhi = wiphi; - } - if (wiphi < wphibinlo) - { - wphibinlo = wiphi; - } - if (wit > wtbinhi) - { - wtbinhi = wit; - } - if (wit < wtbinlo) - { - wtbinlo = wit; - } + wphibinhi = std::max(wiphi, wphibinhi); + wphibinlo = std::min(wiphi, wphibinlo); + wtbinhi = std::max(wit, wtbinhi); + wtbinlo = std::min(wit, wtbinlo); } char wtsize = wtbinhi - wtbinlo + 1; char wphisize = wphibinhi - wphibinlo + 1; @@ -1075,9 +1096,15 @@ namespace */ // pthread_exit(nullptr); } + /** + * @brief Thread entry point that processes a sector's data. + * + * @param threadarg Pointer to a thread_data instance containing per-thread sector context. + * @return void* Never returns; the thread terminates via pthread_exit(nullptr). + */ void *ProcessSector(void *threadarg) { - auto my_data = static_cast(threadarg); + auto *my_data = static_cast(threadarg); ProcessSectorData(my_data); pthread_exit(nullptr); } @@ -1120,6 +1147,18 @@ bool TpcClusterizer::is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom * return reject_it; } +/** + * @brief Initialize runtime nodes, geometry, and optional neural-network model for the TPC clusterizer. + * + * Ensures required DST subnodes and containers (TRKR_CLUSTER, TRKR_CLUSTERHITASSOC, TRAINING_HITSET) + * exist under the "DST/TRKR" node, configures flags for training hit generation and NN usage, + * attempts to load the TorchScript NN model when enabled, optionally prepares a verbose output node, + * and reads TPC geometry to initialize ADC timing (AdcClockPeriod) and print sample layer geometry. + * + * @param topNode Top-level PHCompositeNode for the job; used to locate or create required child nodes. + * @return int Fun4AllReturnCodes::EVENT_OK on successful initialization, Fun4AllReturnCodes::ABORTRUN + * if required nodes (DST or TPC geometry) are missing or initialization cannot proceed. + */ int TpcClusterizer::InitRun(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); @@ -1133,7 +1172,7 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { PHNodeIterator dstiter(dstNode); @@ -1151,7 +1190,7 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { PHNodeIterator dstiter(dstNode); @@ -1168,7 +1207,7 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(newNode); } - auto training_container = findNode::getClass(dstNode, "TRAINING_HITSET"); + auto *training_container = findNode::getClass(dstNode, "TRAINING_HITSET"); if (!training_container) { PHNodeIterator dstiter(dstNode); @@ -1217,18 +1256,18 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) if (!mClusHitsVerbose) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); if (!DetNode) { DetNode = new PHCompositeNode("TRKR"); dstNode->addNode(DetNode); } mClusHitsVerbose = new ClusHitsVerbosev1(); - auto newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); + auto *newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); DetNode->addNode(newNode); } } - auto geom = + auto *geom = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!geom) { @@ -1239,18 +1278,33 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) AdcClockPeriod = geom->GetFirstLayerCellGeom()->get_zstep(); std::cout << "FirstLayerCellGeomv1 streamer: " << std::endl; - auto *g1 = (PHG4TpcGeomv1*) geom->GetFirstLayerCellGeom(); // cast because << not in the base class + auto *g1 = static_cast (geom->GetFirstLayerCellGeom()); // cast because << not in the base class std::cout << *g1 << std::endl; std::cout << "LayerCellGeomv1 streamer for layer 24: " << std::endl; - auto *g2 = (PHG4TpcGeomv1*) geom->GetLayerCellGeom(24); // cast because << not in the base class + auto *g2 = static_cast (geom->GetLayerCellGeom(24)); // cast because << not in the base class std::cout << *g2 << std::endl; std::cout << "LayerCellGeomv1 streamer for layer 40: " << std::endl; - auto *g3 = (PHG4TpcGeomv1*) geom->GetLayerCellGeom(40); // cast because << not in the base class + auto *g3 = static_cast (geom->GetLayerCellGeom(40)); // cast because << not in the base class std::cout << *g3 << std::endl; return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Perform TPC clustering for the current event and write clusters and associations to DST nodes. + * + * Clusters hits (either digitized or raw) per TPC hitset (layer/sector/side) using a sectorized, + * optionally multi-threaded algorithm, optionally produces training hit records and verbose hit output, + * and stores resulting TrkrCluster objects and cluster-hit associations into the DST node tree. + * Alignment transforms are temporarily disabled for the duration of this call to ensure consistent + * construction-space coordinates during clustering. + * + * @param topNode Top-level node of the event node tree (DST) from which input hit sets, geometry, + * and output containers are retrieved and to which resulting cluster containers are written. + * @return int Fun4AllReturnCodes::EVENT_OK on success; Fun4AllReturnCodes::ABORTRUN if required + * nodes (e.g. DST, hitset, geometry, or cluster containers) are missing; nonzero on + * internal errors (e.g. mutex or thread creation failures). + */ int TpcClusterizer::process_event(PHCompositeNode *topNode) { // The TPC is the only subsystem that clusters in global coordinates. For consistency, @@ -1489,18 +1543,18 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map m_clusterlist->addClusterSpecifyKey(ckey, cluster); if (mClusHitsVerbose) { - for (auto &hit : data.phivec_ClusHitsVerbose[index]) + for (const auto &hit : data.phivec_ClusHitsVerbose[index]) { mClusHitsVerbose->addPhiHit(hit.first, hit.second); } - for (auto &hit : data.zvec_ClusHitsVerbose[index]) + for (const auto &hit : data.zvec_ClusHitsVerbose[index]) { mClusHitsVerbose->addZHit(hit.first, hit.second); } @@ -1624,7 +1678,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map m_clusterlist->addClusterSpecifyKey(ckey, cluster); @@ -1668,7 +1722,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map // std::cout << "X: " << cluster->getLocalX() << "Y: " << cluster->getLocalY() << std::endl; @@ -1676,11 +1730,11 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) if (mClusHitsVerbose) { - for (auto &hit : data.phivec_ClusHitsVerbose[index]) + for (const auto &hit : data.phivec_ClusHitsVerbose[index]) { mClusHitsVerbose->addPhiHit(hit.first, (float) hit.second); } - for (auto &hit : data.zvec_ClusHitsVerbose[index]) + for (const auto &hit : data.zvec_ClusHitsVerbose[index]) { mClusHitsVerbose->addZHit(hit.first, (float) hit.second); } @@ -1698,7 +1752,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) m_clusterhitassoc->addAssoc(ckey, hkey); } - for (auto v_hit : thread_pair.data.v_hits) + for (auto *v_hit : thread_pair.data.v_hits) { if (_store_hits) { @@ -1738,4 +1792,4 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) int TpcClusterizer::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc index c194567d58..6c4abde3d5 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc @@ -53,11 +53,23 @@ TpcCombinedRawDataUnpacker::~TpcCombinedRawDataUnpacker() { delete m_cdbttree; } +/** + * @brief Enable zero-suppression emulation and load TPC zero-suppression thresholds. + * + * Sets internal flags to enable zero-suppression emulation and disable baseline correction, + * then attempts to load ADU thresholds for the three TPC regions from the CDB entry + * identified by "TPC_ZS_THRESHOLDS". If the CDB directory is empty, the method returns + * without changing the existing threshold values (default threshold of 20 is used). + * + * @details + * Loaded threshold values are stored in m_zs_threshold[0..2]. Verbose diagnostic output + * is printed when Verbosity() > 1. + */ void TpcCombinedRawDataUnpacker::ReadZeroSuppressedData() { m_do_zs_emulation = true; m_do_baseline_corr = false; - auto cdb = CDBInterface::instance(); + auto *cdb = CDBInterface::instance(); std::string dir = cdb->getUrl("TPC_ZS_THRESHOLDS"); auto cdbtree = std::make_unique(dir); @@ -75,7 +87,7 @@ void TpcCombinedRawDataUnpacker::ReadZeroSuppressedData() { name.str(""); name << "R"<GetSingleFloatValue(name.str().c_str()); + m_zs_threshold[i] = cdbtree->GetSingleFloatValue(name.str()); if(Verbosity() > 1) { std::cout << "Loading ADU threshold of " << m_zs_threshold[i] << " for region " << i << std::endl; @@ -700,4 +712,4 @@ int TpcCombinedRawDataUnpacker::End(PHCompositeNode* /*topNode*/) // if(m_Debug==1) hm->dumpHistos(m_filename, "RECREATE"); return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc index 0bb412197f..c785ba9acb 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc @@ -34,6 +34,7 @@ #include #include +#include #include #include // for exit #include // for exit @@ -169,6 +170,17 @@ int TpcCombinedRawDataUnpackerDebug::InitRun(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Process a single event: unpack TPC raw hits, build TrkrHits, and apply optional zero-suppression and baseline corrections. + * + * Processes TPC raw data from the provided node tree, converts raw samples into TrkrHit entries (with or without zero suppression), + * estimates per-channel pedestals and widths when enabled, computes per-FEE baseline corrections when configured, applies noise + * rejection, and optionally fills debugging ntuples and histograms. Updates the TRKR_HITSET node with produced hits. + * + * @param topNode Root of the PHENIX node tree used to find input containers and attach output hit sets. + * @return int Fun4All return code: `EVENT_OK` on successful processing, `DISCARDEVENT` when the event is outside the configured event range + * or when required nodes are missing in a recoverable manner, or `ABORTRUN` when a fatal geometry node is absent. + */ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) { if (_ievent < startevt || _ievent > endevt) @@ -234,14 +246,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) TpcRawHit* tpchit = tpccont->get_hit(i); uint64_t gtm_bco = tpchit->get_gtm_bco(); - if (gtm_bco < bco_min) - { - bco_min = gtm_bco; - } - if (gtm_bco > bco_max) - { - bco_max = gtm_bco; - } + bco_min = std::min(gtm_bco, bco_min); + bco_max = std::max(gtm_bco, bco_max); int fee = tpchit->get_fee(); int channel = tpchit->get_channel(); @@ -539,7 +545,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) for (int binx = 1; binx < hist2d->GetNbinsX(); binx++) { - double timebin = ((TAxis*) hist2d->GetXaxis())->GetBinCenter(binx); + double timebin = ( hist2d->GetXaxis())->GetBinCenter(binx); std::string histname1d = "h" + std::to_string(hiter.first) + "_" + std::to_string((int) timebin); TH1D* hist1d = hist2d->ProjectionY(histname1d.c_str(), binx, binx); float local_ped = 0; @@ -697,11 +703,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) if ((float(adc) - pedestal_offset - corr) > (hpedwidth2 * m_ped_sig_cut)) { float nuadc = (float(adc) - corr - pedestal_offset); - if (nuadc < 0) - { - nuadc = 0; - } - hitr->second->setAdc(float(nuadc)); + nuadc = std::max(nuadc, 0); + hitr->second->setAdc(nuadc); #ifdef DEBUG // hitr->second->setAdc(10); if (tbin == 383 && layer >= 7 + 32 && fee == 21) @@ -788,4 +791,4 @@ int TpcCombinedRawDataUnpackerDebug::End(PHCompositeNode* /*topNode*/) // if(m_Debug==1) hm->dumpHistos(m_filename, "RECREATE"); return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcDistortionCorrection.cc b/offline/packages/tpc/TpcDistortionCorrection.cc index b759331e77..e5e0289f4c 100644 --- a/offline/packages/tpc/TpcDistortionCorrection.cc +++ b/offline/packages/tpc/TpcDistortionCorrection.cc @@ -15,7 +15,14 @@ namespace { template - inline constexpr T square(const T& x) + /** + * @brief Compute the square of a value. + * + * @tparam T Type of the input value. + * @param x Value to be squared. + * @return T The input multiplied by itself (x * x). + */ + constexpr T square(const T x) { return x * x; } @@ -137,4 +144,4 @@ if(dcc->m_use_scalefactor) const auto y_new = r_new * std::sin(phi_new); return {x_new, y_new, z_new}; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.cc b/offline/packages/tpc/TpcLoadDistortionCorrection.cc index 0ce2ffa4e1..a60a45837c 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.cc +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.cc @@ -45,7 +45,17 @@ TpcLoadDistortionCorrection::TpcLoadDistortionCorrection(const std::string& name { } -//_____________________________________________________________________ +/** + * @brief Load distortion correction histograms from configured files into node tree containers. + * + * For each enabled correction slot, ensures a TpcDistortionCorrectionContainer exists under the + * RUN node, opens the configured ROOT file, reads the per-side distortion histograms + * (hIntDistortionP/R/Z for _negz and _posz), sets the container's dimension and configuration + * flags (phi units, z-interpolation, and scaling), and optionally prints histogram info. + * + * @param topNode Top-level node of the current run/event node tree; used to find or create the RUN/ nodes. + * @return `Fun4AllReturnCodes::ABORTRUN` if the RUN node is missing, `Fun4AllReturnCodes::EVENT_OK` on successful initialization. + */ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) { // look for distortion calibration object @@ -58,7 +68,7 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) } /// Get the RUN node and check - auto runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + auto *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); if (!runNode) { std::cout << "TpcLoadDistortionCorrection::InitRun - RUN Node missing, quitting" << std::endl; @@ -74,17 +84,17 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) } // get distortion correction object and create if not found - auto distortion_correction_object = findNode::getClass(topNode, m_node_name[i]); + auto *distortion_correction_object = findNode::getClass(topNode, m_node_name[i]); if (!distortion_correction_object) { std::cout << "TpcLoadDistortionCorrection::InitRun - creating TpcDistortionCorrectionContainer in node " << m_node_name[i] << std::endl; distortion_correction_object = new TpcDistortionCorrectionContainer; - auto node = new PHDataNode(distortion_correction_object, m_node_name[i]); + auto *node = new PHDataNode(distortion_correction_object, m_node_name[i]); runNode->addNode(node); } std::cout << "TpcLoadDistortionCorrection::InitRun - reading corrections from " << m_correction_filename[i] << std::endl; - auto distortion_tfile = TFile::Open(m_correction_filename[i].c_str()); + auto *distortion_tfile = TFile::Open(m_correction_filename[i].c_str()); if (!distortion_tfile) { std::cout << "TpcLoadDistortionCorrection::InitRun - cannot open " << m_correction_filename[i] << std::endl; @@ -137,4 +147,4 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) int TpcLoadDistortionCorrection::process_event(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcRawDataTree.cc b/offline/packages/tpc/TpcRawDataTree.cc index 6199fb7425..6d80dbda68 100644 --- a/offline/packages/tpc/TpcRawDataTree.cc +++ b/offline/packages/tpc/TpcRawDataTree.cc @@ -1,4 +1,3 @@ - #include "TpcRawDataTree.h" #include @@ -27,7 +26,14 @@ TpcRawDataTree::TpcRawDataTree(const std::string &name) M.setMapNames("AutoPad-R1-RevA.sch.ChannelMapping.csv", "AutoPad-R2-RevA-Pads.sch.ChannelMapping.csv", "AutoPad-R3-RevA.sch.ChannelMapping.csv"); } -//____________________________________________________________________________.. +/** + * @brief Initializes output ROOT file, trees, and histograms for raw TPC data. + * + * Creates and configures the output TFile, TTree branches for packets, samples, and taggers, + * and allocates histograms used for ADC values, timing, and checksum diagnostics. + * + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ int TpcRawDataTree::InitRun(PHCompositeNode * /*unused*/) { sectorNum = m_fname; @@ -61,7 +67,7 @@ int TpcRawDataTree::InitRun(PHCompositeNode * /*unused*/) m_SampleTree->Branch("nWaveormInFrame", &m_nWaveormInFrame, "nWaveormInFrame/I"); m_SampleTree->Branch("maxFEECount", &m_maxFEECount, "maxFEECount/I"); m_SampleTree->Branch("nSamples", &m_nSamples, "nSamples/I"); - m_SampleTree->Branch("adcSamples", &m_adcSamples[0], "adcSamples[nSamples]/s"); + m_SampleTree->Branch("adcSamples", m_adcSamples.data(), "adcSamples[nSamples]/s"); m_SampleTree->Branch("fee", &m_fee, "fee/I"); m_SampleTree->Branch("sampaAddress", &m_sampaAddress, "sampaAddress/I"); m_SampleTree->Branch("sampaChannel", &m_sampaChannel, "sampaChannel/I"); @@ -279,4 +285,4 @@ int TpcRawDataTree::End(PHCompositeNode * /*topNode*/) m_file->Close(); return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcRawWriter.cc b/offline/packages/tpc/TpcRawWriter.cc index 5d7711e2bb..f49f921b32 100644 --- a/offline/packages/tpc/TpcRawWriter.cc +++ b/offline/packages/tpc/TpcRawWriter.cc @@ -59,6 +59,17 @@ TpcRawWriter::TpcRawWriter(const std::string &name) std::cout << PHWHERE << "Construct TpcRawWriter" << std::endl; } +/** + * @brief Ensure TRKR-related DST nodes and containers exist, creating them if missing. + * + * Ensures the DST composite node contains a TRKR composite node and that the + * TRKR_CLUSTER, TRKR_CLUSTERHITASSOC, and TRKR_RAWHITSET containers are present; + * missing nodes/containers are created and attached under DST/TRKR. + * + * @param topNode Top-level node of the Fun4All node tree where DST is expected. + * @return Fun4AllReturnCodes::EVENT_OK on successful initialization, + * Fun4AllReturnCodes::ABORTRUN if the DST node is missing. + */ int TpcRawWriter::InitRun(PHCompositeNode *topNode) { if (topNode) @@ -76,7 +87,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { PHNodeIterator dstiter(dstNode); @@ -94,7 +105,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { PHNodeIterator dstiter(dstNode); @@ -116,7 +127,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) if (!m_rawhits) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); if (!DetNode) { DetNode = new PHCompositeNode("TRKR"); @@ -124,7 +135,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) } m_rawhits = new RawHitSetContainerv1; - auto newNode = new PHIODataNode(m_rawhits, "TRKR_RAWHITSET", "PHObject"); + auto *newNode = new PHIODataNode(m_rawhits, "TRKR_RAWHITSET", "PHObject"); DetNode->addNode(newNode); } @@ -676,4 +687,4 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) int TpcRawWriter::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TpcSimpleClusterizer.cc b/offline/packages/tpc/TpcSimpleClusterizer.cc index f439d1d682..7d0f46afee 100644 --- a/offline/packages/tpc/TpcSimpleClusterizer.cc +++ b/offline/packages/tpc/TpcSimpleClusterizer.cc @@ -33,6 +33,7 @@ #include +#include #include #include // for sqrt, cos, sin #include @@ -46,7 +47,14 @@ namespace { template - inline constexpr T square(const T &x) + /** + * @brief Computes the square of a value. + * + * @tparam T Type that supports multiplication. + * @param x Value to be squared. + * @return T The value of x multiplied by itself. + */ + constexpr T square(const T &x) { return x * x; } @@ -114,6 +122,21 @@ namespace ihit_list.push_back(thisHit); } + /** + * @brief Compute cluster parameters from a list of hits and append the resulting cluster. + * + * Computes ADC-weighted cluster position and uncertainties from the provided hit list, + * creates a TrkrClusterv3 with global and local coordinates (using Acts when available), + * estimates local errors, appends the cluster to my_data.cluster_vector, and (when enabled) + * records cluster→hit associations in my_data.association_vector. + * + * @param ihit_list Vector of hits forming the cluster; each entry is (adc, (phibin, zbin)). + * @param my_data Per-thread context providing layer geometry, geometry accessor, bin offsets, + * calibration parameters (par0_neg/par0_pos), and output vectors for clusters and associations. + * + * @note If the corresponding TPC surface cannot be found for the computed global position, + * the function returns without adding a cluster or associations. + */ void calc_cluster_parameter(std::vector &ihit_list, thread_data &my_data) { // loop over the hits in this cluster @@ -142,22 +165,10 @@ namespace int iphi = iter.second.first + my_data.phioffset; int iz = iter.second.second + my_data.zoffset; - if (iphi > phibinhi) - { - phibinhi = iphi; - } - if (iphi < phibinlo) - { - phibinlo = iphi; - } - if (iz > zbinhi) - { - zbinhi = iz; - } - if (iz < zbinlo) - { - zbinlo = iz; - } + phibinhi = std::max(iphi, phibinhi); + phibinlo = std::min(iphi, phibinlo); + zbinhi = std::max(iz, zbinhi); + zbinlo = std::min(iz, zbinlo); // update phi sums double phi_center = my_data.layergeom->get_phicenter(iphi, my_data.side); @@ -205,7 +216,7 @@ namespace clusz -= (clusz < 0) ? my_data.par0_neg : my_data.par0_pos; // create cluster and fill - auto clus = new TrkrClusterv3; + auto *clus = new TrkrClusterv3; clus->setAdc(adc_sum); /// Get the surface key to find the surface from the map @@ -278,9 +289,21 @@ namespace } } + /** + * @brief Processes a single TPC hitset (sector) in a worker thread to form clusters. + * + * Reads hits from the provided thread_data hitset, performs per-sector clustering + * (building clusters from ADC-weighted neighbouring hits), and appends resulting + * TrkrClusterv3 objects and cluster-hit associations into the thread_data output vectors. + * + * @param threadarg Pointer to a thread_data struct that supplies geometry, hitset, + * clustering parameters, and holds output vectors (`cluster_vector` + * and `association_vector`) to be filled by this function. + * @return nullptr on thread completion. + */ void *ProcessSector(void *threadarg) { - auto my_data = (struct thread_data *) threadarg; + auto *my_data = (struct thread_data *) threadarg; const auto &pedestal = my_data->pedestal; const auto &phibins = my_data->phibins; @@ -332,11 +355,11 @@ namespace all_hit_map.insert(std::make_pair(adc, thisHit)); } // adcval[phibin][zbin] = (unsigned short) adc; - adcval[phibin][zbin] = (unsigned short) adc; + adcval[phibin][zbin] = adc; } } - while (all_hit_map.size() > 0) + while (!all_hit_map.empty()) { auto iter = all_hit_map.rbegin(); if (iter == all_hit_map.rend()) @@ -400,6 +423,15 @@ bool TpcSimpleClusterizer::is_in_sector_boundary(int phibin, int sector, PHG4Tpc return reject_it; } +/** + * @brief Ensure DST node tree contains TRKR cluster and association containers. + * + * Creates TRKR_CLUSTER and TRKR_CLUSTERHITASSOC nodes under DST/TRKR when they are absent, + * leaving existing nodes intact. + * + * @param topNode Root node of the runtime PHENIX node tree (usually the top-level PHCompositeNode). + * @return int Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTRUN if the DST node is missing. + */ int TpcSimpleClusterizer::InitRun(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); @@ -413,7 +445,7 @@ int TpcSimpleClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { PHNodeIterator dstiter(dstNode); @@ -431,7 +463,7 @@ int TpcSimpleClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { PHNodeIterator dstiter(dstNode); @@ -451,6 +483,19 @@ int TpcSimpleClusterizer::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Perform TPC hitset clustering and store resulting clusters and associations in the DST node tree. + * + * Processes all TPC hitsets in the event using per-hitset threads, computes cluster parameters, inserts created + * TrkrClusterv3 objects into the TRKR_CLUSTER container, and records cluster–hit associations in TRKR_CLUSTERHITASSOC. + * + * @param topNode Top-level node of the event node tree (used to locate DST, hitset container, cluster container, + * association container, TPC geometry container, and Acts geometry). + * @return int Fun4AllReturnCodes::EVENT_OK on success; + * Fun4AllReturnCodes::ABORTRUN if required nodes (DST, TRKR_HITSET, TRKR_CLUSTER, TRKR_CLUSTERHITASSOC, + * TPCGEOMCONTAINER, or ActsGeometry) are missing; + * returns 1 if pthread mutex initialization fails. Other nonzero return values may indicate pthread + * creation or join errors logged to stdout. */ int TpcSimpleClusterizer::process_event(PHCompositeNode *topNode) { // int print_layer = 18; @@ -614,7 +659,7 @@ int TpcSimpleClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map m_clusterlist->addClusterSpecifyKey(ckey, cluster); @@ -641,4 +686,4 @@ int TpcSimpleClusterizer::process_event(PHCompositeNode *topNode) int TpcSimpleClusterizer::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/tpc/TrainingHits.cc b/offline/packages/tpc/TrainingHits.cc index 3a70db0854..75a6c6ac55 100644 --- a/offline/packages/tpc/TrainingHits.cc +++ b/offline/packages/tpc/TrainingHits.cc @@ -1,19 +1,31 @@ #include "TrainingHits.h" +/** + * @brief Constructs a TrainingHits object with all members zero-initialized. + * + * Initializes numeric members (radius, phi, z, phistep, zstep, layer, ntouch, nedge, cluskey) + * to zero and fills the ADC vector container with zeros. + */ TrainingHits::TrainingHits() + : radius(0.) + , phi(0.) + , z(0.) + , phistep(0.) + , zstep(0.) + , layer(0) + , ntouch(0) + , nedge(0) + , cluskey(0) { v_adc.fill(0); - radius = 0.; - phi = 0.; - z = 0.; - phistep = 0.; - zstep = 0.; - layer = 0; - ntouch = 0; - nedge = 0; - cluskey = 0; } +/** + * @brief Resets all members of TrainingHits to their default zero values. + * + * Sets floating-point members (radius, phi, z, phistep, zstep) to 0.0, integer members + * (layer, ntouch, nedge, cluskey) to 0, and fills the v_adc container with zeros. + */ void TrainingHits::Reset() { v_adc.fill(0); @@ -26,4 +38,4 @@ void TrainingHits::Reset() ntouch = 0; nedge = 0; cluskey = 0; -} +} \ No newline at end of file diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index b3eb79fcb0..028e0ac729 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -29,6 +29,19 @@ #include #include +/** + * @brief Builds and installs alignment transforms for detector surfaces from alignment parameters. + * + * Reads alignment parameters (from a disk file or database), parses per-surface perturbations + * (angles and translations), optionally applies randomized perturbations, constructs per-surface + * Acts transforms (including special handling for TPC module local-frame translations and module-tilt + * behavior), and inserts the resulting transforms into the persistent and transient alignment + * containers. After processing all entries the geometry context is updated with the created map + * and alignment usage is enabled. + * + * @param topNode Root of the PHENIX/Fun4All node tree used to locate geometry, create or attach + * alignment transform containers, and update the geometry context. + */ void AlignmentTransformation::createMap(PHCompositeNode* topNode) { localVerbosity = 0; @@ -277,6 +290,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) surf = surfMaps.getTpcSurface(this_hitsetkey, (unsigned int) sskey); Eigen::Vector3d localFrameTranslation(0, 0, 0); + use_module_tilt = false; if (test_layer < 4 || use_module_tilt_always) { // get the local frame translation that puts the local surface center at the tilted position after the local rotations are applied @@ -285,6 +299,9 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) double this_radius = std::sqrt(this_center[0] * this_center[0] + this_center[1] * this_center[1]); float moduleRadius = TpcModuleRadii[side][sector][this_region]; // radius of the center of the module in cm localFrameTranslation = getTpcLocalFrameTranslation(moduleRadius, this_radius, sensorAngles) * 10; // cm to mm + + // set this flag for later use + use_module_tilt = true; } Acts::Transform3 transform; @@ -355,7 +372,22 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) alignmentTransformationContainer::use_alignment = true; } -// currently used as the transform maker +/** + * @brief Compose an alignment transform for a surface from local/global rotations and translations. + * + * Builds and returns the composed Acts::Transform3 that applies the provided global translation, + * global rotation, surface (acts) pose, local frame translation, and local rotation according to + * the selected ordering (which depends on the tracker id and the survey flag). + * + * @param surf The surface whose nominal Acts transform (pose) is used as part of the composition. + * @param millepedeTranslation Global translation perturbation to apply (same units as the surface). + * @param sensorAngles Local rotation angles (alpha, beta, gamma) applied in the sensor/local frame (radians). + * @param localFrameTranslation Translation applied in the sensor/local frame (same units as the surface). + * @param sensorAnglesGlobal Global rotation angles (rx, ry, rz) applied in the global frame (radians). + * @param trkrid Tracker identifier used to select region-specific transform ordering (e.g., TPC). + * @param survey If true, treat the provided millepede/global parameters as survey values and use the survey composition. + * @return Acts::Transform3 The composed transform that maps the surface's local coordinates to the updated global frame. + */ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, Eigen::Vector3d& millepedeTranslation, Eigen::Vector3d& sensorAngles, Eigen::Vector3d& localFrameTranslation, Eigen::Vector3d& sensorAnglesGlobal, unsigned int trkrid, bool survey) { // define null matrices @@ -417,70 +449,83 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, Acts::Transform3 transform; //! If we read the survey parameters directly, that is the full transform if (survey) - { - //! The millepede affines will just be what was read in, which was the - //! survey information. This should (in principle) be equivalent to - //! the ideal position + any misalignment - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * mpLocalRotationAffine; - } - else - { - if (trkrid == TrkrDefs::tpcId) { - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + //! The millepede affines will just be what was read in, which was the + //! survey information. This should (in principle) be equivalent to + //! the ideal position + any misalignment + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * mpLocalRotationAffine; } - else + else { - if(use_new_silicon_rotation_order) + // not survey. this is the normal usage + + if (trkrid == TrkrDefs::tpcId) { - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + if(use_module_tilt) + { + // use module tilt transforms with local rotation followed by local translation + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + } + else + { + // backward compatibility for old alignment params sets + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * mpLocalRotationAffine * actsRotationAffine; + } } else { - // needed for backward compatibility to existing local rotations in MVTX - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * mpLocalRotationAffine * actsRotationAffine; + // silicon and TPOT + if(use_new_silicon_rotation_order) + { + // use new transform order for silicon as well as TPC + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + } + else + { + // needed for backward compatibility to existing local rotation parmeter sets in silicon + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * mpLocalRotationAffine * actsRotationAffine; + } } } - } - + if (localVerbosity) - { - Acts::Transform3 actstransform = actsTranslationAffine * actsRotationAffine; - - std::cout << "newMakeTransform" << std::endl; - std::cout << "Input sensorAngles: " << std::endl - << sensorAngles << std::endl; - std::cout << "Input sensorAnglesGlobal: " << std::endl - << sensorAnglesGlobal << std::endl; - std::cout << "Input translation: " << std::endl - << millepedeTranslation << std::endl; - std::cout << "mpLocalRotationAffine: " << std::endl - << mpLocalRotationAffine.matrix() << std::endl; - std::cout << "mpLocalTranslationAffine: " << std::endl - << mpLocalTranslationAffine.matrix() << std::endl; - std::cout << "actsRotationAffine: " << std::endl - << actsRotationAffine.matrix() << std::endl; - std::cout << "actsTranslationAffine: " << std::endl - << actsTranslationAffine.matrix() << std::endl; - std::cout << "mpRotationGlobalAffine: " << std::endl - << mpGlobalRotationAffine.matrix() << std::endl; - std::cout << "mpTranslationGlobalAffine: " << std::endl - << mpGlobalTranslationAffine.matrix() << std::endl; - std::cout << "Overall transform: " << std::endl - << transform.matrix() << std::endl; - std::cout << "overall * idealinv " << std::endl - << (transform * actstransform.inverse()).matrix() << std::endl; - std::cout << "overall - ideal " << std::endl; - for (int test = 0; test < transform.matrix().rows(); test++) { - for (int test2 = 0; test2 < transform.matrix().cols(); test2++) - { - std::cout << transform(test, test2) - actstransform(test, test2) << ", "; - } - std::cout << std::endl; + Acts::Transform3 actstransform = actsTranslationAffine * actsRotationAffine; + + std::cout << "newMakeTransform" << std::endl; + std::cout << "Input sensorAngles: " << std::endl + << sensorAngles << std::endl; + std::cout << "Input sensorAnglesGlobal: " << std::endl + << sensorAnglesGlobal << std::endl; + std::cout << "Input translation: " << std::endl + << millepedeTranslation << std::endl; + std::cout << "mpLocalRotationAffine: " << std::endl + << mpLocalRotationAffine.matrix() << std::endl; + std::cout << "mpLocalTranslationAffine: " << std::endl + << mpLocalTranslationAffine.matrix() << std::endl; + std::cout << "actsRotationAffine: " << std::endl + << actsRotationAffine.matrix() << std::endl; + std::cout << "actsTranslationAffine: " << std::endl + << actsTranslationAffine.matrix() << std::endl; + std::cout << "mpRotationGlobalAffine: " << std::endl + << mpGlobalRotationAffine.matrix() << std::endl; + std::cout << "mpTranslationGlobalAffine: " << std::endl + << mpGlobalTranslationAffine.matrix() << std::endl; + std::cout << "Overall transform: " << std::endl + << transform.matrix() << std::endl; + std::cout << "overall * idealinv " << std::endl + << (transform * actstransform.inverse()).matrix() << std::endl; + std::cout << "overall - ideal " << std::endl; + for (int test = 0; test < transform.matrix().rows(); test++) + { + for (int test2 = 0; test2 < transform.matrix().cols(); test2++) + { + std::cout << transform(test, test2) - actstransform(test, test2) << ", "; + } + std::cout << std::endl; + } } - } - + return transform; } @@ -674,4 +719,4 @@ double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetke double surf_radius = std::sqrt(surf_center[0] * surf_center[0] + surf_center[1] * surf_center[1]); return surf_radius; -} +} \ No newline at end of file diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index 7055d6c65a..bf36d6fab2 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -14,6 +14,63 @@ class PHCompositeNode; class ActsGeometry; +/** + * Populate the node tree with the alignment transformation map used by this object. + * @param topNode Top-level node under which the alignment map and any required nodes will be created. + */ + +/** + * Create and attach an alignmentTransformationContainer under the provided top-level node. + * @param topNode Top-level node under which the alignment transform container will be created. + */ + +/** + * Generate random alignment perturbations from per-axis angular and translational deviations. + * The generated perturbations are stored in the object's perturbationAngles, perturbationAnglesGlobal, + * and perturbationTranslation members and will be applied according to enabled subsystem flags. + * @param angleDev Per-axis standard deviations (radians) for rotation perturbations around X, Y, Z. + * @param transformDev Per-axis standard deviations (length units) for translation perturbations along X, Y, Z. + */ + +/** + * Set MVTX subsystem per-axis standard deviations for rotation and translation perturbations. + * The first three elements of mvtxDevs are rotation standard deviations (radians) about X, Y, Z; + * the last three are translation standard deviations along X, Y, Z. Enables MVTX perturbations. + * @param mvtxDevs Array of six values: [angleX, angleY, angleZ, transX, transY, transZ]. + */ + +/** + * Set INTT subsystem per-axis standard deviations for rotation and translation perturbations. + * The first three elements of inttDevs are rotation standard deviations (radians) about X, Y, Z; + * the last three are translation standard deviations along X, Y, Z. Enables INTT perturbations. + * @param inttDevs Array of six values: [angleX, angleY, angleZ, transX, transY, transZ]. + */ + +/** + * Set TPC subsystem per-axis standard deviations for rotation and translation perturbations. + * The first three elements of tpcDevs are rotation standard deviations (radians) about X, Y, Z; + * the last three are translation standard deviations along X, Y, Z. Enables TPC perturbations. + * @param tpcDevs Array of six values: [angleX, angleY, angleZ, transX, transY, transZ]. + */ + +/** + * Set Micromegas (MM) subsystem per-axis standard deviations for rotation and translation perturbations. + * The first three elements of mmDevs are rotation standard deviations (radians) about X, Y, Z; + * the last three are translation standard deviations along X, Y, Z. Enables MM perturbations. + * @param mmDevs Array of six values: [angleX, angleY, angleZ, transX, transY, transZ]. + */ + +/** + * Set the misalignment scale factor for a specific detector layer. + * @param layer Layer identifier for which the factor applies. + * @param factor Multiplicative factor applied to the layer's misalignment magnitudes. + */ + +/** + * Retrieve the misalignment scale factor for a specific detector layer. + * @param layer Layer identifier whose misalignment factor will be returned. + * @returns The multiplicative misalignment factor for the given layer. + */ class AlignmentTransformation { public: @@ -128,7 +185,8 @@ class AlignmentTransformation bool use_new_silicon_rotation_order = false; bool use_module_tilt_always = false; - + bool use_module_tilt = false; // starts at false in all cases + bool use_intt_survey_geometry = false; Acts::Transform3 newMakeTransform(const Surface& surf, Eigen::Vector3d& millepedeTranslation, Eigen::Vector3d& sensorAngles, Eigen::Vector3d& localFrameTranslation, Eigen::Vector3d& sensorAnglesGlobal, unsigned int trkrid, bool survey); @@ -149,4 +207,4 @@ class AlignmentTransformation double sectorPhi[2][12] = {}; }; -#endif +#endif \ No newline at end of file diff --git a/offline/packages/trackreco/DSTClusterPruning.cc b/offline/packages/trackreco/DSTClusterPruning.cc index 15bfe547ca..afa4c60bf9 100644 --- a/offline/packages/trackreco/DSTClusterPruning.cc +++ b/offline/packages/trackreco/DSTClusterPruning.cc @@ -145,7 +145,29 @@ int DSTClusterPruning::load_nodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } -//_____________________________________________________________________ +/** + * @brief Populate the reduced cluster container with clusters referenced by track seeds. + * + * This routine ensures that every cluster referenced by the configured track seed containers + * is present in the reduced cluster map by copying missing clusters from the full cluster map. + * + * @details + * - If required containers (full cluster map, reduced cluster map, track seed container, + * silicon seed container, and TPC seed container) are not all present, the function returns + * without modifying state. + * - When m_pruneAllSeeds is true, the function iterates over both the TPC and silicon seed + * containers and processes every TrackSeed found. + * - When m_pruneAllSeeds is false, the function iterates over the main track seed container, + * uses per-track indices to locate corresponding TPC and silicon seeds, and processes only + * those seeds. + * - For each referenced cluster key, if the cluster exists in the full cluster map but is + * missing from the reduced cluster map, a new TrkrClusterv5 is allocated, populated by + * copying the full cluster, and inserted into the reduced cluster map. + * + * Side effects: + * - Allocates TrkrClusterv5 objects for missing reduced clusters and adds them to m_reduced_cluster_map. + * - Emits diagnostic output to stdout depending on Verbosity(). + */ void DSTClusterPruning::prune_clusters() { // use this to create object that looks through both tracks and clusters and saves into new object @@ -177,6 +199,39 @@ void DSTClusterPruning::prune_clusters() } return; } + if(m_pruneAllSeeds) + { + for(const auto& container : {m_tpc_track_seed_container, m_silicon_track_seed_container}) + { + for (const auto& trackseed : *container) + { + if (!trackseed) + { + std::cout << "No TrackSeed" << std::endl; + continue; + } + + for (auto key_iter = trackseed->begin_cluster_keys(); key_iter != trackseed->end_cluster_keys(); ++key_iter) + { + const auto& cluster_key = *key_iter; + auto *cluster = m_cluster_map->findCluster(cluster_key); + if (!cluster) + { + std::cout << "DSTClusterPruning::evaluate_tracks - unable to find cluster for key " << cluster_key << std::endl; + continue; + } + if (!m_reduced_cluster_map->findCluster(cluster_key)) + { + m_cluster = new TrkrClusterv5(); + m_cluster->CopyFrom(cluster); + m_reduced_cluster_map->addClusterSpecifyKey(cluster_key, m_cluster); + } + } + } + } + return; + } + for (const auto& trackseed : *m_track_seed_container) { if (!trackseed) @@ -402,4 +457,4 @@ void DSTClusterPruning::print_clusters() std::cout << "end of loop" << "\n"; } -} +} \ No newline at end of file diff --git a/offline/packages/trackreco/DSTClusterPruning.h b/offline/packages/trackreco/DSTClusterPruning.h index c9ec35ea53..0f7bc65f9f 100644 --- a/offline/packages/trackreco/DSTClusterPruning.h +++ b/offline/packages/trackreco/DSTClusterPruning.h @@ -36,6 +36,11 @@ class TrkrHitSetContainer; class TrkrHitTruthAssoc; class TrackSeedContainer; +/** + * Enable dumping of clusters for every seed. + * + * When enabled, clusters from all silicon and TPC track seeds will be dumped individually by the pruning routine. + */ class DSTClusterPruning : public SubsysReco { public: @@ -52,6 +57,12 @@ class DSTClusterPruning : public SubsysReco //! end of processing //int End(PHCompositeNode*) override; + //! dump all clusters on all seeds out + void pruneAllSeeds() + { + m_pruneAllSeeds = true; + } + private: //! load nodes int load_nodes(PHCompositeNode*); @@ -68,6 +79,9 @@ class DSTClusterPruning : public SubsysReco TrackSeedContainer* m_tpc_track_seed_container = nullptr; TrackSeedContainer* m_silicon_track_seed_container = nullptr; +//! set to true if you want to dump out all clusters on all silicon +//! and all tpc seeds individually + bool m_pruneAllSeeds = false; //@} // debugging helpers diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index a26ee1fa0a..7c3db696f4 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -5,7 +5,6 @@ * \author Tony Frawley */ - #include "PHActsTrkFitter.h" #include "ActsPropagator.h" @@ -25,7 +24,7 @@ #include #include #include -//#include +// #include #include #include #include @@ -86,6 +85,17 @@ PHActsTrkFitter::PHActsTrkFitter(const std::string& name) { } +/** + * @brief Initialize runtime state and configure Acts-based track fitting. + * + * Loads and creates required nodes, configures alignment and magnetic-field handling, + * constructs Kalman and directed-Kalman fitter functions, optionally collects material + * surfaces, configures the outlier finder, initializes timing histograms and the + * Acts evaluator (if enabled), and validates required geometry containers. + * + * @param topNode Top-level node of the framework's node tree used to find/create required nodes. + * @return int Fun4All return code: `EVENT_OK` on success, `ABORTEVENT` if required nodes could not be created or retrieved, or `ABORTRUN` if required geometry containers are missing. + */ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) { if (Verbosity() > 1) @@ -134,8 +144,8 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) MaterialSurfaceSelector selector; if (m_fitSiliconMMs || m_directNavigation) { - m_tGeometry->geometry().tGeometry->visitSurfaces(selector,false); - //std::cout<<"selector.surfaces.size() "<geometry().tGeometry->visitSurfaces(selector, false); + // std::cout<<"selector.surfaces.size() "<(m_evalname); m_evaluator->Init(topNode); - if(m_actsEvaluator && !m_simActsEvaluator) + if (m_actsEvaluator && !m_simActsEvaluator) { m_evaluator->isData(); } @@ -182,10 +192,10 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) _tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!_tpccellgeo) - { - std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + { + std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } if (Verbosity() > 1) { @@ -269,6 +279,15 @@ int PHActsTrkFitter::ResetEvent(PHCompositeNode* /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Finalize the fitter and release runtime resources. + * + * If time analysis was enabled, writes timing histograms and closes the timing file. + * If an Acts evaluator is attached, calls its End routine. If the outlier finder is used, + * writes outlier data. Prints a completion message when verbosity is greater than zero. + * + * @return int Fun4AllReturnCodes::EVENT_OK on success. + */ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) { if (m_timeAnalysis) @@ -287,7 +306,7 @@ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) { m_evaluator->End(); } - if(m_useOutlierFinder) + if (m_useOutlierFinder) { m_outlierFinder.Write(); } @@ -298,6 +317,22 @@ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Iterate over seed tracks and perform Acts-based refits for each seed. + * + * For each seed in the input seed map, constructs source links and an Acts seed, + * runs the Acts track fitter (optionally scanning INTT crossing variations), + * converts successful fit results into SvtxTrack objects, and inserts them into + * the module's output track maps. Failed fits increment the module's bad-fit + * counter. + * + * @param logLevel Acts logging level to use for per-track fitting operations. + * + * Side effects: + * - Inserts fitted tracks into m_trackMap or m_directedTrackMap. + * - May increment m_nBadFits for failed fits. + * - Uses/mutates transient alignment/geocontext state for per-track corrections. + */ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { auto logger = Acts::getDefaultLogger("PHActsTrkFitter", logLevel); @@ -314,47 +349,46 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) // capture the input crossing value, and set crossing parameters //============================== - short silicon_crossing = SHRT_MAX; - auto siseed = m_siliconSeeds->get(siid); - if(siseed) - { - silicon_crossing = siseed->get_crossing(); - } + short silicon_crossing = SHRT_MAX; + auto *siseed = m_siliconSeeds->get(siid); + if (siseed) + { + silicon_crossing = siseed->get_crossing(); + } short crossing = silicon_crossing; short int crossing_estimate = crossing; - if(m_enable_crossing_estimate) - { - crossing_estimate = track->get_crossing_estimate(); // geometric crossing estimate from matcher - } + if (m_enable_crossing_estimate) + { + crossing_estimate = track->get_crossing_estimate(); // geometric crossing estimate from matcher + } //=============================== - // must have silicon seed with valid crossing if we are doing a SC calibration fit if (m_fitSiliconMMs) + { + if ((siid == std::numeric_limits::max()) || (silicon_crossing == SHRT_MAX)) { - if( (siid == std::numeric_limits::max()) || (silicon_crossing == SHRT_MAX)) - { - continue; - } + continue; } + } // do not skip TPC only tracks, just set crossing to the nominal zero - if(!siseed) - { - crossing = 0; - } + if (!siseed) + { + crossing = 0; + } if (Verbosity() > 1) { - if(siseed) - { - std::cout << "tpc and si id " << tpcid << ", " << siid << " silicon_crossing " << silicon_crossing - << " crossing " << crossing << " crossing estimate " << crossing_estimate << std::endl; - } + if (siseed) + { + std::cout << "tpc and si id " << tpcid << ", " << siid << " silicon_crossing " << silicon_crossing + << " crossing " << crossing << " crossing estimate " << crossing_estimate << std::endl; + } } - auto tpcseed = m_tpcSeeds->get(tpcid); + auto *tpcseed = m_tpcSeeds->get(tpcid); /// Need to also check that the tpc seed wasn't removed by the ghost finder if (!tpcseed) @@ -381,7 +415,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (Verbosity() > 1 && siseed) { std::cout << " m_pp_mode " << m_pp_mode << " m_enable_crossing_estimate " << m_enable_crossing_estimate - << " INTT crossing " << crossing << " crossing_estimate " << crossing_estimate << std::endl; + << " INTT crossing " << crossing << " crossing_estimate " << crossing_estimate << std::endl; } short int this_crossing = crossing; @@ -390,35 +424,35 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) std::vector chisq_ndf; std::vector svtx_vec; - if(m_pp_mode) + if (m_pp_mode) + { + if (m_enable_crossing_estimate && crossing == SHRT_MAX) + { + // this only happens if there is a silicon seed but no assigned INTT crossing, and only in pp_mode + // If there is no INTT crossing, start with the crossing_estimate value, vary up and down, fit, and choose the best chisq/ndf + use_estimate = true; + nvary = max_bunch_search; + if (Verbosity() > 1) + { + std::cout << " No INTT crossing: use crossing_estimate " << crossing_estimate << " with nvary " << nvary << std::endl; + } + } + else { - if (m_enable_crossing_estimate && crossing == SHRT_MAX) - { - // this only happens if there is a silicon seed but no assigned INTT crossing, and only in pp_mode - // If there is no INTT crossing, start with the crossing_estimate value, vary up and down, fit, and choose the best chisq/ndf - use_estimate = true; - nvary = max_bunch_search; - if (Verbosity() > 1) - { - std::cout << " No INTT crossing: use crossing_estimate " << crossing_estimate << " with nvary " << nvary << std::endl; - } - } - else - { - // use INTT crossing - crossing_estimate = crossing; - } + // use INTT crossing + crossing_estimate = crossing; } + } else + { + // non pp mode, we want only crossing zero, veto others + if (siseed && silicon_crossing != 0) { - // non pp mode, we want only crossing zero, veto others - if(siseed && silicon_crossing != 0) - { - crossing = 0; - //continue; - } - crossing_estimate = crossing; + crossing = 0; + // continue; } + crossing_estimate = crossing; + } // Fit this track assuming either: // crossing = INTT value, if it exists (uses nvary = 0) @@ -441,16 +475,16 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) makeSourceLinks.initialize(_tpccellgeo); makeSourceLinks.setVerbosity(Verbosity()); makeSourceLinks.set_pp_mode(m_pp_mode); - for(const auto& layer : m_ignoreLayer) + for (const auto& layer : m_ignoreLayer) { makeSourceLinks.ignoreLayer(layer); } // loop over modifiedTransformSet and replace transient elements modified for the previous track with the default transforms // does nothing if m_transient_id_set is empty makeSourceLinks.resetTransientTransformMap( - m_alignmentTransformationMapTransient, - m_transient_id_set, - m_tGeometry); + m_alignmentTransformationMapTransient, + m_transient_id_set, + m_tGeometry); if (m_use_clustermover) { @@ -459,37 +493,56 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { // silicon source links sourceLinks = makeSourceLinks.getSourceLinksClusterMover( - siseed, + siseed, + measurements, + m_clusterContainer, + m_tGeometry, + m_globalPositionWrapper, + this_crossing); + } + + // tpc source links + const auto tpcSourceLinks = makeSourceLinks.getSourceLinksClusterMover( + tpcseed, measurements, m_clusterContainer, m_tGeometry, m_globalPositionWrapper, this_crossing); - } - - // tpc source links - const auto tpcSourceLinks = makeSourceLinks.getSourceLinksClusterMover( - tpcseed, - measurements, - m_clusterContainer, - m_tGeometry, - m_globalPositionWrapper, - this_crossing); // add tpc sourcelinks to silicon source links sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end()); - - } else { - + } + else + { // make source links using transient transforms for distortion corrections - if(Verbosity() > 1) - { std::cout << "Calling getSourceLinks for si seed, siid " << siid << " and tpcid " << tpcid << std::endl; } + if (Verbosity() > 1) + { + std::cout << "Calling getSourceLinks for si seed, siid " << siid << " and tpcid " << tpcid << std::endl; + } if (siseed && !m_ignoreSilicon) { // silicon source links sourceLinks = makeSourceLinks.getSourceLinks( - siseed, + siseed, + measurements, + m_clusterContainer, + m_tGeometry, + m_globalPositionWrapper, + m_alignmentTransformationMapTransient, + m_transient_id_set, + this_crossing); + } + + if (Verbosity() > 1) + { + std::cout << "Calling getSourceLinks for tpc seed, siid " << siid << " and tpcid " << tpcid << std::endl; + } + + // tpc source links + const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( + tpcseed, measurements, m_clusterContainer, m_tGeometry, @@ -497,21 +550,6 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_alignmentTransformationMapTransient, m_transient_id_set, this_crossing); - } - - if(Verbosity() > 1) - { std::cout << "Calling getSourceLinks for tpc seed, siid " << siid << " and tpcid " << tpcid << std::endl; } - - // tpc source links - const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( - tpcseed, - measurements, - m_clusterContainer, - m_tGeometry, - m_globalPositionWrapper, - m_alignmentTransformationMapTransient, - m_transient_id_set, - this_crossing); // add tpc sourcelinks to silicon source links sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end()); @@ -524,15 +562,15 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) Acts::Vector3 position(0, 0, 0); if (siseed) { - position = TrackSeedHelper::get_xyz(siseed)*Acts::UnitConstants::cm; + position = TrackSeedHelper::get_xyz(siseed) * Acts::UnitConstants::cm; } - if(!siseed || !is_valid(position) || m_ignoreSilicon) + if (!siseed || !is_valid(position) || m_ignoreSilicon) { - position = TrackSeedHelper::get_xyz(tpcseed)*Acts::UnitConstants::cm; + position = TrackSeedHelper::get_xyz(tpcseed) * Acts::UnitConstants::cm; } if (!is_valid(position)) { - if(Verbosity() > 4) + if (Verbosity() > 4) { std::cout << "Invalid position of " << position.transpose() << std::endl; } @@ -559,26 +597,26 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) for (const auto& surface_apr : m_materialSurfaces) { - if(m_forceSiOnlyFit) + if (m_forceSiOnlyFit) { - if(surface_apr->geometryId().volume() >12) + if (surface_apr->geometryId().volume() > 12) { continue; } } bool pop_flag = false; - if(surface_apr->geometryId().approach() == 1) + if (surface_apr->geometryId().approach() == 1) { surfaces.push_back(surface_apr); } else { pop_flag = true; - for (const auto& surface_sns: surfaces_tmp) + for (const auto& surface_sns : surfaces_tmp) { if (surface_apr->geometryId().volume() == surface_sns->geometryId().volume()) { - if ( surface_apr->geometryId().layer()==surface_sns->geometryId().layer()) + if (surface_apr->geometryId().layer() == surface_sns->geometryId().layer()) { pop_flag = false; surfaces.push_back(surface_sns); @@ -594,9 +632,9 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) surfaces.pop_back(); pop_flag = false; } - if (surface_apr->geometryId().volume() == 12&& surface_apr->geometryId().layer()==8) + if (surface_apr->geometryId().volume() == 12 && surface_apr->geometryId().layer() == 8) { - for (const auto& surface_sns: surfaces_tmp) + for (const auto& surface_sns : surfaces_tmp) { if (14 == surface_sns->geometryId().volume()) { @@ -619,13 +657,13 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { // make sure micromegas are in the tracks, if required if (m_useMicromegas && - std::none_of(surfaces.begin(), surfaces.end(), [this](const auto& surface) - { return m_tGeometry->maps().isMicromegasSurface(surface); })) - { - continue; + std::none_of(surfaces.begin(), surfaces.end(), [this](const auto& surface) + { return m_tGeometry->maps().isMicromegasSurface(surface); })) + { + continue; + } } } - } float px = std::numeric_limits::quiet_NaN(); float py = std::numeric_limits::quiet_NaN(); @@ -635,7 +673,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) float seedphi = 0; float seedtheta = 0; float seedeta = 0; - if(siseed) + if (siseed) { seedphi = siseed->get_phi(); seedtheta = siseed->get_theta(); @@ -659,7 +697,9 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) px = pt * std::cos(phi); py = pt * std::sin(phi); pz = pt * std::cosh(eta) * std::cos(theta); - } else { + } + else + { px = seedpt * std::cos(seedphi); py = seedpt * std::sin(seedphi); pz = seedpt * std::cosh(seedeta) * std::cos(seedtheta); @@ -668,14 +708,14 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) Acts::Vector3 momentum(px, py, pz); if (!is_valid(momentum)) { - if(Verbosity() > 4) + if (Verbosity() > 4) { std::cout << "Invalid momentum of " << momentum.transpose() << std::endl; } continue; } - auto pSurface = Acts::Surface::makeShared( position); + auto pSurface = Acts::Surface::makeShared(position); Acts::Vector4 actsFourPos(position(0), position(1), position(2), 10 * Acts::UnitConstants::ns); Acts::BoundSquareMatrix cov = setDefaultCovariance(); @@ -723,8 +763,10 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) auto trackStateContainer = std::make_shared(); ActsTrackFittingAlgorithm::TrackContainer tracks(trackContainer, trackStateContainer); - if(Verbosity() > 1) - { std::cout << "Calling fitTrack for track with siid " << siid << " tpcid " << tpcid << " crossing " << crossing << std::endl; } + if (Verbosity() > 1) + { + std::cout << "Calling fitTrack for track with siid " << siid << " tpcid " << tpcid << " crossing " << crossing << std::endl; + } auto result = fitTrack(sourceLinks, seed, kfOptions, surfaces, calibrator, tracks); fitTimer.stop(); @@ -761,7 +803,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (ivary != nvary) { - if(Verbosity() > 3) + if (Verbosity() > 3) { std::cout << "Skipping track fit for trial variation" << std::endl; } @@ -806,7 +848,6 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (getTrackFitResult(result, track, &newTrack, tracks, measurements)) { - // insert in dedicated map m_directedTrackMap->insertWithKey(&newTrack, trid); } @@ -822,11 +863,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_trackMap->insertWithKey(&newTrack, trid); } } // end insert track for normal fit - } // end case where INTT crossing is known - - - - + } // end case where INTT crossing is known } else if (!m_fitSiliconMMs) { @@ -840,7 +877,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) << std::endl; } } // end fit failed case - } // end ivary loop + } // end ivary loop trackTimer.stop(); auto trackTime = trackTimer.get_accumulated_time(); @@ -854,11 +891,26 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) return; } +/** + * Populate an SvtxTrack from an Acts fit result when the fit provides a valid reference surface. + * + * If the fit result contains a reference surface, updates the provided SvtxTrack with fitted + * parameters and covariance, optionally records alignment state (when commissioning and both + * silicon and TPC seeds are present), invokes the Acts evaluator if enabled, and fills timing + * diagnostics when configured. + * + * @param fitOutput The Acts fitting result to extract the fitted trajectory and parameters from. + * @param seed The input TrackSeed associated with this fit (used for evaluation/metadata). + * @param track The SvtxTrack to update with the fit result. + * @param tracks Container holding Acts track state(s) produced by the fitter. + * @param measurements Container of measurements/source-links associated with the fit. + * @return `true` if the fit had a valid reference surface and the SvtxTrack was updated, `false` otherwise. + */ bool PHActsTrkFitter::getTrackFitResult( - const FitResult& fitOutput, - TrackSeed* seed, SvtxTrack* track, - const ActsTrackFittingAlgorithm::TrackContainer& tracks, - const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) + const FitResult& fitOutput, + TrackSeed* seed, SvtxTrack* track, + const ActsTrackFittingAlgorithm::TrackContainer& tracks, + const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { /// Make a trajectory state for storage, which conforms to Acts track fit /// analysis tool @@ -872,12 +924,12 @@ bool PHActsTrkFitter::getTrackFitResult( // retrieve track parameters from fit result Acts::BoundTrackParameters parameters = ActsExamples::TrackParameters(outtrack.referenceSurface().getSharedPtr(), - outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()); + outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()); indexedParams.emplace( - outtrack.tipIndex(), - ActsExamples::TrackParameters{outtrack.referenceSurface().getSharedPtr(), - outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()}); + outtrack.tipIndex(), + ActsExamples::TrackParameters{outtrack.referenceSurface().getSharedPtr(), + outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()}); if (Verbosity() > 2) { @@ -937,7 +989,22 @@ bool PHActsTrkFitter::getTrackFitResult( return false; } -//__________________________________________________________________________________ +/** + * Selects and runs the appropriate Acts track fitter for the given source links and seed. + * + * If silicon micromegas fitting or direct navigation is enabled, runs the configured + * direct fitter; otherwise runs the configured full fitter. The chosen fitter is + * executed with the provided seed, options, calibrator, and surface sequence (when used), + * and any produced track candidates are appended to `tracks`. + * + * @param sourceLinks Measurement source links to fit. + * @param seed Initial track parameters for the fit. + * @param kfOptions General fitter options and configuration. + * @param surfSequence Ordered surface sequence used by the direct fitter (ignored by the full fitter). + * @param calibrator Calibrator adapter applied during fitting. + * @param[out] tracks Container appended with fitted track candidates. + * @return ActsTrackFittingAlgorithm::TrackFitterResult Result of the fit, including status and fitted track information. + */ ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack( const std::vector& sourceLinks, const ActsTrackFittingAlgorithm::TrackParameters& seed, @@ -948,13 +1015,27 @@ ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack( { // use direct fit for silicon MM gits or direct navigation if (m_fitSiliconMMs || m_directNavigation) - { return (*m_fitCfg.dFit)(sourceLinks, seed, kfOptions, surfSequence, calibrator, tracks); } + { + return (*m_fitCfg.dFit)(sourceLinks, seed, kfOptions, surfSequence, calibrator, tracks); + } // use full fit in all other cases return (*m_fitCfg.fit)(sourceLinks, seed, kfOptions, calibrator, tracks); } -//__________________________________________________________________________________ +/** + * @brief Extracts and filters source links that correspond to silicon and micromegas detector surfaces. + * + * Iterates over the provided source links, finds each link's Acts surface via the tracking geometry, + * and appends that surface to the supplied surfaces vector when the link is accepted. + * Acceptance respects configuration flags: when silicon/MM fitting is enabled, TPC surfaces are excluded; + * when micromegas usage is disabled, micromegas surfaces are excluded; when a silicon-only fit is forced, + * both TPC and micromegas surfaces are excluded. + * + * @param sourceLinks Input collection of source links to filter. + * @param[out] surfaces Vector that will be appended with the corresponding surface pointers for each accepted source link. + * @return SourceLinkVec A vector containing the subset of input source links that correspond to the accepted surfaces. + */ SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks, SurfacePtrVec& surfaces) const { SourceLinkVec siliconMMSls; @@ -986,9 +1067,9 @@ SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks } } - if(m_forceSiOnlyFit) + if (m_forceSiOnlyFit) { - if(m_tGeometry->maps().isMicromegasSurface(surf)||m_tGeometry->maps().isTpcSurface(surf)) + if (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isTpcSurface(surf)) { continue; } @@ -1010,6 +1091,15 @@ SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks return siliconMMSls; } +/** + * @brief Ensure surfaces are ordered by geometry volume then layer, removing any out-of-order entries. + * + * Scans the provided surface vector in place and removes surfaces that violate ascending order + * first by geometryId().volume() and then by geometryId().layer(). Each removed surface is + * reported to standard output. + * + * @param surfaces Vector of surface pointers to validate and potentially modify (in-place). + */ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const { for (unsigned int i = 0; i < surfaces.size() - 1; i++) @@ -1058,11 +1148,25 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const } } +/** + * @brief Populate an SvtxTrack with results from an Acts fit. + * + * Transfers the fitted trajectory tip parameters into the provided SvtxTrack by setting + * position, momentum, charge, chi-squared, NDF, and covariance (when available). It also + * (optionally) fills SvtxTrackStates for the measurements belonging to the fitted Acts + * trajectory and, when silicon-MM fitting is enabled and the track has a TPC seed, + * extrapolates and appends track states for associated TPC clusters. + * + * @param tips Indices of trajectory tips from the Acts multi-trajectory (first entry is used). + * @param paramsMap Mapping from trajectory index to fitted indexed parameters. + * @param tracks Acts track container that holds trajectory states and measurements. + * @param track SvtxTrack object to update in-place with fit results and derived states. + */ void PHActsTrkFitter::updateSvtxTrack( - const std::vector& tips, - const Trajectory::IndexedParameters& paramsMap, - const ActsTrackFittingAlgorithm::TrackContainer& tracks, - SvtxTrack* track) + const std::vector& tips, + const Trajectory::IndexedParameters& paramsMap, + const ActsTrackFittingAlgorithm::TrackContainer& tracks, + SvtxTrack* track) { const auto& mj = tracks.trackStateContainer(); @@ -1133,31 +1237,37 @@ void PHActsTrkFitter::updateSvtxTrack( trackStateTimer.restart(); if (m_fillSvtxTrackStates) - { transformer.fillSvtxTrackStates(mj, trackTip, track, m_transient_geocontext); } + { + transformer.fillSvtxTrackStates(mj, trackTip, track, m_transient_geocontext); + } // in using silicon mm fit also extrapolate track parameters to all TPC surfaces with clusters // get all tpc clusters auto* seed = track->get_tpc_seed(); - if( m_fitSiliconMMs && seed ) + if (m_fitSiliconMMs && seed) { - // acts propagator ActsPropagator propagator(m_tGeometry); // loop over cluster keys associated to TPC seed - for( auto key_iter = seed->begin_cluster_keys(); key_iter != seed->end_cluster_keys(); ++key_iter ) + for (auto key_iter = seed->begin_cluster_keys(); key_iter != seed->end_cluster_keys(); ++key_iter) { const auto& cluskey = *key_iter; // make sure cluster is from TPC const auto detId = TrkrDefs::getTrkrId(cluskey); if (detId != TrkrDefs::tpcId) - { continue; } + { + continue; + } // get layer, propagate const auto layer = TrkrDefs::getLayer(cluskey); auto result = propagator.propagateTrack(params, layer); - if( !result.ok() ) { continue; } + if (!result.ok()) + { + continue; + } // get path length and extrapolated parameters auto& [pathLength, trackStateParams] = result.value(); @@ -1380,4 +1490,4 @@ int PHActsTrkFitter::getNodes(PHCompositeNode* topNode) m_globalPositionWrapper.set_suppressCrossing(true); return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index c6e0afec35..4e438a0da2 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include @@ -127,22 +127,62 @@ class PHActsTrkFitter : public SubsysReco } void SetIteration(int iter) { _n_iteration = iter; } - void set_track_map_name(const std::string& map_name) { _track_map_name = map_name; } - void set_svtx_seed_map_name(const std::string& map_name) { _svtx_seed_map_name = map_name; } + /** + * Set the SvtxTrackMap node name used for output tracks. + * + * @param map_name Name of the SvtxTrackMap node to assign. + */ +void set_track_map_name(const std::string& map_name) { _track_map_name = map_name; } + /** + * Set the name of the Svtx seed map used by the fitter. + * @param map_name Name of the Svtx seed map node to locate on the node tree. + */ +void set_svtx_seed_map_name(const std::string& map_name) { _svtx_seed_map_name = map_name; } - void set_svtx_alignment_state_map_name(const std::string& map_name) { - _svtx_alignment_state_map_name = map_name; - m_alignStates.alignmentStateMap(map_name); + /** + * Set the Svtx alignment state map name and configure Acts alignment states to use it. + * @param map_name Name of the Svtx alignment state map to assign and apply to Acts alignment states. + */ + void set_svtx_alignment_state_map_name(const std::string& map_name) + { + _svtx_alignment_state_map_name = map_name; + m_alignStates.alignmentStateMap(map_name); } - /// Set flag for pp running + /** + * Enable or disable proton–proton (pp) running mode. + * @param ispp `true` to enable pp mode, `false` to disable it. + */ void set_pp_mode(bool ispp) { m_pp_mode = ispp; } - void set_enable_geometric_crossing_estimate(bool flag) { m_enable_crossing_estimate = flag ; } - void set_use_clustermover(bool use) { m_use_clustermover = use; } - void ignoreLayer(int layer) { m_ignoreLayer.insert(layer); } - void setTrkrClusterContainerName(std::string &name){ m_clusterContainerName = name; } - void setDirectNavigation(bool flag) { m_directNavigation = flag; } + /** + * Enable or disable the geometric crossing estimate used during track fitting. + * @param flag If `true`, enable the geometric crossing estimate; if `false`, disable it. + */ +void set_enable_geometric_crossing_estimate(bool flag) { m_enable_crossing_estimate = flag; } + /** + * Enable or disable the cluster mover used during fitting. + * @param use `true` to enable the cluster mover, `false` to disable it. + */ +void set_use_clustermover(bool use) { m_use_clustermover = use; } + /** + * Mark a detector layer to be excluded from fitting. + * + * @param layer Index of the detector layer to ignore during track fitting. + */ +void ignoreLayer(int layer) { m_ignoreLayer.insert(layer); } + /** + * Set the name of the TRKR cluster container used for input clusters. + * @param name Name of the TRKR cluster container on the node tree. + */ +void setTrkrClusterContainerName(const std::string& name) { m_clusterContainerName = name; } + /** + * Enable or disable direct navigation through detector surfaces during fitting. + * + * @param flag If `true`, use direct navigation (fit follows a precomputed sequence of surfaces + * such as silicon and micromegas for the track). If `false`, use the default navigation. + */ +void setDirectNavigation(bool flag) { m_directNavigation = flag; } private: /// Get all the nodes @@ -155,10 +195,10 @@ class PHActsTrkFitter : public SubsysReco /// Convert the acts track fit result to an svtx track void updateSvtxTrack( - const std::vector& tips, - const Trajectory::IndexedParameters& paramsMap, - const ActsTrackFittingAlgorithm::TrackContainer& tracks, - SvtxTrack* track); + const std::vector& tips, + const Trajectory::IndexedParameters& paramsMap, + const ActsTrackFittingAlgorithm::TrackContainer& tracks, + SvtxTrack* track); /// Helper function to call either the regular navigation or direct /// navigation, depending on m_fitSiliconMMs @@ -233,14 +273,29 @@ class PHActsTrkFitter : public SubsysReco bool m_directNavigation = true; - // do we have a constant field + /** + * Collects surfaces that have associated material into the selector's list. + * + * If the provided surface has non-null material and is not already present + * in `surfaces`, it is appended to the vector. + * + * @param surface Pointer to the surface to test and potentially collect. + */ bool m_ConstField{false}; - double fieldstrength{std::numeric_limits::quiet_NaN()}; + /** + * Collect unique surfaces that contain non-null material into the selector. + * + * If the provided surface has associated material and is not already present + * in `surfaces`, it is appended to the `surfaces` vector. + * + * @param surface Surface to test and possibly add to the selector's list. + */ + double fieldstrength{std::numeric_limits::quiet_NaN()}; // max variation of bunch crossing away from crossing_estimate short int max_bunch_search = 2; - //name of TRKR_CLUSTER container + // name of TRKR_CLUSTER container std::string m_clusterContainerName = "TRKR_CLUSTER"; //!@name evaluator @@ -253,7 +308,7 @@ class PHActsTrkFitter : public SubsysReco //@} //! tracks -// SvtxTrackMap* m_seedTracks = nullptr; + // SvtxTrackMap* m_seedTracks = nullptr; //! tpc global position wrapper TpcGlobalPositionWrapper m_globalPositionWrapper; @@ -268,7 +323,7 @@ class PHActsTrkFitter : public SubsysReco int _n_iteration = 0; std::string _track_map_name = "SvtxTrackMap"; std::string _svtx_seed_map_name = "SvtxTrackSeedContainer"; - std::string _svtx_alignment_state_map_name = "SvtxAlignmentStateMap"; + std::string _svtx_alignment_state_map_name = "SvtxAlignmentStateMap"; /// Default particle assumption to pion unsigned int m_pHypothesis = 211; @@ -292,14 +347,18 @@ class PHActsTrkFitter : public SubsysReco std::vector m_materialSurfaces = {}; - struct MaterialSurfaceSelector { + struct MaterialSurfaceSelector + { std::vector surfaces = {}; /// @param surface is the test surface - void operator()(const Acts::Surface* surface) { - if (surface->surfaceMaterial() != nullptr) { + void operator()(const Acts::Surface* surface) + { + if (surface->surfaceMaterial() != nullptr) + { if (std::find(surfaces.begin(), surfaces.end(), surface) == - surfaces.end()) { + surfaces.end()) + { surfaces.push_back(surface); } } @@ -307,4 +366,4 @@ class PHActsTrkFitter : public SubsysReco }; }; -#endif +#endif \ No newline at end of file diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc index 2e66a6df28..30bd788392 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc @@ -387,6 +387,17 @@ int PHSiliconTpcTrackMatching::End(PHCompositeNode * /*unused*/) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Retrieve required nodes from the PHCompositeNode tree and create missing output container. + * + * Searches the provided top-level node tree for and assigns internal pointers to required containers and services + * (cluster crossing assoc, silicon track seeds, TPC track seeds, cluster container, and Acts geometry). + * If the SvtxTrackSeedContainer node is absent, it is created under the DST/SVTX subtree and registered on the node tree. + * + * @param topNode Top-level PHCompositeNode to search for required nodes. + * @return int Fun4All return code: `Fun4AllReturnCodes::EVENT_OK` on success; `Fun4AllReturnCodes::ABORTEVENT` if a required node + * (silicon track seed container, TPC track seed container, cluster container, or Acts geometry) is missing. + */ int PHSiliconTpcTrackMatching::GetNodes(PHCompositeNode *topNode) { //--------------------------------- @@ -445,10 +456,10 @@ int PHSiliconTpcTrackMatching::GetNodes(PHCompositeNode *topNode) svtxNode->addNode(node); } - _cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + _cluster_map = findNode::getClass(topNode, _cluster_map_name); if (!_cluster_map) { - std::cout << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl; + std::cout << PHWHERE << " ERROR: Can't find node " <<_cluster_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -841,4 +852,4 @@ std::vector PHSiliconTpcTrackMatching::getTrackletClusterList cluskey_vec.push_back(key); } // end loop over clusters for this track return cluskey_vec; -} +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h index acb157bd83..0fefae8706 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h @@ -136,10 +136,35 @@ class PHSiliconTpcTrackMatching : public SubsysReco, public PHParameterInterface // void set_use_old_matching(const bool flag) { _use_old_matching = flag; } void set_test_windows_printout(const bool test) { _test_windows = test; } - void set_file_name(const std::string &name) { _file_name = name; } - void set_pp_mode(const bool flag) { _pp_mode = flag; } - void set_use_intt_crossing(const bool flag) { _use_intt_crossing = flag; } - + /** + * Set the output ROOT file name used by the module. + * + * @param name New filename for the module's output TFile. + */ +void set_file_name(const std::string &name) { _file_name = name; } + /** + * Enable or disable pp (proton–proton) collision mode. + * @param flag `true` to enable pp mode, `false` to disable it. + */ +void set_pp_mode(const bool flag) { _pp_mode = flag; } + /** + * Enable or disable using INTT-derived cluster crossing corrections. + * + * When enabled, cluster z-crossing information from the INTT detector is used + * to correct cluster positions for matching; when disabled, INTT crossing data + * is ignored. + * + * @param flag `true` to use INTT crossings, `false` to ignore them. + */ +void set_use_intt_crossing(const bool flag) { _use_intt_crossing = flag; } + /** + * Set the node name used to locate the cluster container. + * @param name Node name of the cluster map (e.g., "TRKR_CLUSTER"). + */ + void set_cluster_map_name(const std::string &name) + { + _cluster_map_name = name; + } int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *) override; @@ -200,7 +225,12 @@ class PHSiliconTpcTrackMatching : public SubsysReco, public PHParameterInterface // double _collision_rate = 50e3; // input rate for phi correction // double _reference_collision_rate = 50e3; // reference rate for phi correction - // double _si_vertex_dzmax = 0.25; // mm + /** + * Retrieve the list of cluster keys associated with a given tracklet. + * + * @param tracklet Pointer to the TrackSeed whose constituent clusters are requested. + * @returns A vector of TrkrDefs::cluskey values corresponding to clusters used by the tracklet. + */ double fieldstrength{std::numeric_limits::quiet_NaN()}; bool _test_windows = false; @@ -210,8 +240,9 @@ class PHSiliconTpcTrackMatching : public SubsysReco, public PHParameterInterface int _n_iteration = 0; std::string _track_map_name = "TpcTrackSeedContainer"; std::string _silicon_track_map_name = "SiliconTrackSeedContainer"; + std::string _cluster_map_name = "TRKR_CLUSTER"; std::string m_fieldMap = "1.4"; std::vector getTrackletClusterList(TrackSeed* tracklet); }; -#endif // PHSILICONTPCTRACKMATCHING_H +#endif // PHSILICONTPCTRACKMATCHING_H \ No newline at end of file diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index da0e36fabf..f4b7a6fab7 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -51,11 +51,33 @@ class PHSimpleVertexFinder : public SubsysReco void setTrackPtCut(const double cut) { _track_pt_cut = cut; } // void setUseTrackCovariance(bool set) {_use_track_covariance = set;} void setOutlierPairCut(const double cut) { _outlier_cut = cut; } - void setTrackMapName(const std::string &name) { _track_map_name = name; } - void setVertexMapName(const std::string &name) { _vertex_map_name = name; } - void zeroField(const bool flag) { _zero_field = flag; } - void setTrkrClusterContainerName(std::string &name){ m_clusterContainerName = name; } - void set_pp_mode(bool mode) { _pp_mode = mode; } + /** + * Set the node name used to look up the track map in the node tree. + * @param name Node name for the SvtxTrackMap to retrieve (e.g., "SvtxTrackMap"). + */ +void setTrackMapName(const std::string &name) { _track_map_name = name; } + /** + * Set the node name used for the SvtxVertexMap container. + * @param name Name of the vertex map node in the node tree. + */ +void setVertexMapName(const std::string &name) { _vertex_map_name = name; } + /** + * Configure whether vertex finding should assume a zero magnetic field (use straight-line track propagation). + * @param flag `true` to treat the magnetic field as zero, `false` to use the nonzero field behavior. + */ +void zeroField(const bool flag) { _zero_field = flag; } + /** + * Set the name of the tracker cluster container used by the finder. + * + * @param name Name of the TrkrClusterContainer node (e.g., "TRKR_CLUSTER"). + */ +void setTrkrClusterContainerName(const std::string &name){ m_clusterContainerName = name; } + /** + * Set proton–proton collision mode. + * + * @param mode If `true`, enable proton–proton (pp) mode; if `false`, disable pp mode (use non-pp/heavy-ion mode). + */ +void set_pp_mode(bool mode) { _pp_mode = mode; } private: int GetNodes(PHCompositeNode *topNode); @@ -118,4 +140,4 @@ class PHSimpleVertexFinder : public SubsysReco bool _pp_mode = true; // default to pp mode }; -#endif // PHSIMPLEVERTEXFINDER_H +#endif // PHSIMPLEVERTEXFINDER_H \ No newline at end of file diff --git a/offline/packages/trackreco/PHTpcDeltaZCorrection.h b/offline/packages/trackreco/PHTpcDeltaZCorrection.h index 46d099f587..2dc061e623 100644 --- a/offline/packages/trackreco/PHTpcDeltaZCorrection.h +++ b/offline/packages/trackreco/PHTpcDeltaZCorrection.h @@ -31,8 +31,19 @@ class PHTpcDeltaZCorrection : public SubsysReco, public PHParameterInterface int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; + /** + * Reset configurable parameters to their default values. + * + * This restores all module configuration parameters to their defaults (for example the cluster + * container name and any other runtime-adjustable settings). + */ + + /** + * Override the TrkrClusterContainer node name used by the module. + * @param name Name of the cluster container node (e.g., "TRKR_CLUSTER"). + */ void SetDefaultParameters() override; - void setTrkrClusterContainerName(std::string &name) { m_clusterContainerName = name; } + void setTrkrClusterContainerName(const std::string &name) { m_clusterContainerName = name; } private: /// load nodes @@ -61,4 +72,4 @@ class PHTpcDeltaZCorrection : public SubsysReco, public PHParameterInterface std::set m_corrected_clusters; }; -#endif // PHTpcDeltaZCorrection_H +#endif // PHTpcDeltaZCorrection_H \ No newline at end of file From b14b7e77c846851bb96c81258550ed1322c2c767 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 Jan 2026 17:32:15 +0000 Subject: [PATCH 2/2] Fix missing final newline in docstring PR --- generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc | 2 +- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc | 2 +- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h | 2 +- generators/PHPythia8/PHPythia8.cc | 2 +- generators/phhepmc/PHHepMCGenEventv1.cc | 2 +- offline/QA/Calorimeters/CaloValid.cc | 2 +- offline/QA/Tracking/MicromegasClusterQA.cc | 2 +- offline/QA/Tracking/MicromegasClusterQA.h | 2 +- offline/QA/Tracking/StateClusterResidualsQA.cc | 2 +- offline/QA/Tracking/StateClusterResidualsQA.h | 2 +- offline/framework/ffamodules/CDBInterface.cc | 2 +- offline/framework/ffamodules/FlagHandler.h | 2 +- offline/framework/ffamodules/HeadReco.cc | 2 +- offline/framework/ffamodules/HeadReco.h | 2 +- offline/framework/ffamodules/SyncReco.h | 2 +- offline/framework/ffamodules/Timing.cc | 2 +- offline/framework/ffamodules/Timing.h | 2 +- offline/framework/fun4all/Fun4AllServer.cc | 2 +- offline/framework/fun4all/Fun4AllServer.h | 2 +- offline/framework/fun4all/InputFileHandler.cc | 2 +- offline/framework/fun4all/InputFileHandler.h | 2 +- offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc | 2 +- offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc | 2 +- offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h | 2 +- offline/framework/fun4allraw/SingleMvtxPoolInput.cc | 2 +- offline/framework/fun4allraw/SingleTriggeredInput.cc | 2 +- offline/framework/fun4allraw/SingleTriggeredInput.h | 2 +- offline/packages/CaloEmbedding/CombineTowerInfo.cc | 1 + offline/packages/CaloEmbedding/CombineTowerInfo.h | 1 + offline/packages/CaloEmbedding/CopyIODataNodes.cc | 2 +- offline/packages/CaloEmbedding/CopyIODataNodes.h | 2 +- offline/packages/CaloReco/PhotonClusterBuilder.cc | 2 +- offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 2 +- offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc | 2 +- offline/packages/PHGenFitPkg/PHGenFit/Track.cc | 2 +- offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc | 2 +- offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h | 2 +- offline/packages/jetbackground/DetermineTowerBackground.cc | 1 + offline/packages/jetbackground/DetermineTowerBackground.h | 2 +- offline/packages/mbd/MbdCalib.cc | 1 + offline/packages/mbd/MbdEvent.cc | 2 +- offline/packages/mbd/MbdReco.cc | 2 +- offline/packages/mbd/MbdSig.h | 2 +- offline/packages/micromegas/MicromegasClusterizer.cc | 2 +- offline/packages/micromegas/MicromegasCombinedDataDecoder.cc | 2 +- offline/packages/micromegas/MicromegasCombinedDataDecoder.h | 2 +- offline/packages/micromegas/MicromegasDefs.cc | 2 +- offline/packages/micromegas/MicromegasDefs.h | 2 +- offline/packages/mvtx/CylinderGeom_Mvtx.cc | 2 +- offline/packages/mvtx/CylinderGeom_Mvtx.h | 2 +- offline/packages/mvtx/MvtxClusterPruner.cc | 2 +- offline/packages/mvtx/MvtxClusterizer.cc | 2 +- offline/packages/mvtx/MvtxHitPruner.cc | 2 +- offline/packages/mvtx/SegmentationAlpide.cc | 2 +- offline/packages/tpc/LaserClusterizer.cc | 2 +- offline/packages/tpc/LaserEventIdentifier.cc | 2 +- offline/packages/tpc/Tpc3DClusterizer.cc | 2 +- offline/packages/tpc/TpcClusterMover.cc | 2 +- offline/packages/tpc/TpcClusterMover.h | 2 +- offline/packages/tpc/TpcClusterizer.cc | 2 +- offline/packages/tpc/TpcCombinedRawDataUnpacker.cc | 2 +- offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc | 2 +- offline/packages/tpc/TpcDistortionCorrection.cc | 2 +- offline/packages/tpc/TpcLoadDistortionCorrection.cc | 2 +- offline/packages/tpc/TpcRawDataTree.cc | 2 +- offline/packages/tpc/TpcRawWriter.cc | 2 +- offline/packages/tpc/TpcSimpleClusterizer.cc | 2 +- offline/packages/tpc/TrainingHits.cc | 2 +- offline/packages/trackbase/AlignmentTransformation.cc | 2 +- offline/packages/trackbase/AlignmentTransformation.h | 2 +- offline/packages/trackreco/DSTClusterPruning.cc | 2 +- offline/packages/trackreco/DSTClusterPruning.h | 2 +- offline/packages/trackreco/PHActsTrkFitter.cc | 2 +- offline/packages/trackreco/PHActsTrkFitter.h | 2 +- offline/packages/trackreco/PHSiliconTpcTrackMatching.cc | 2 +- offline/packages/trackreco/PHSiliconTpcTrackMatching.h | 2 +- offline/packages/trackreco/PHSimpleVertexFinder.h | 2 +- offline/packages/trackreco/PHTpcDeltaZCorrection.h | 2 +- 78 files changed, 78 insertions(+), 74 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc index 2d6216f8a9..fc60efa208 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc @@ -157,4 +157,4 @@ int HepMCJetTrigger::jetsAboveThreshold(const std::vector& j } } return n_good_jets; -} \ No newline at end of file +} diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 512ff7fb01..f36ba51d3a 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -549,4 +549,4 @@ int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_par return it->second; } return 0; -} \ No newline at end of file +} diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index 64c086870a..38154b6d8a 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -134,4 +134,4 @@ int n_good{0}; bool _doBothPzCut{false}; }; -#endif // HEPMCPARTICLETRIGGER_H \ No newline at end of file +#endif // HEPMCPARTICLETRIGGER_H diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index a502b16fc2..9640501a0d 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -375,4 +375,4 @@ void PHPythia8::register_trigger(PHPy8GenTrigger *theTrigger) std::cout << "PHPythia8::registerTrigger - trigger " << theTrigger->GetName() << " registered" << std::endl; } m_RegisteredTriggers.push_back(theTrigger); -} \ No newline at end of file +} diff --git a/generators/phhepmc/PHHepMCGenEventv1.cc b/generators/phhepmc/PHHepMCGenEventv1.cc index 9a239c7a2d..6c8976f329 100644 --- a/generators/phhepmc/PHHepMCGenEventv1.cc +++ b/generators/phhepmc/PHHepMCGenEventv1.cc @@ -121,4 +121,4 @@ float PHHepMCGenEventv1::get_flow_psi(unsigned int n) const std::cout << "PHHepMCGenEventv1::get_flow_psi - Warning - requested reaction plane angle psi_n for n=" << n << " does not exist. Returning NAN" << std::endl; return std::numeric_limits::quiet_NaN(); -} \ No newline at end of file +} diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index af9842a5b4..b71f0ad16d 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -1316,4 +1316,4 @@ void CaloValid::createHistos() } hm->registerHisto(h_triggerVec); hm->registerHisto(pr_ldClus_trig); -} \ No newline at end of file +} diff --git a/offline/QA/Tracking/MicromegasClusterQA.cc b/offline/QA/Tracking/MicromegasClusterQA.cc index db61aac9e0..0893474cae 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.cc +++ b/offline/QA/Tracking/MicromegasClusterQA.cc @@ -293,4 +293,4 @@ void MicromegasClusterQA::create_histograms() } return; -} \ No newline at end of file +} diff --git a/offline/QA/Tracking/MicromegasClusterQA.h b/offline/QA/Tracking/MicromegasClusterQA.h index 7df05a5820..f6c5fa8d96 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.h +++ b/offline/QA/Tracking/MicromegasClusterQA.h @@ -162,4 +162,4 @@ class MicromegasClusterQA : public SubsysReco //@} }; -#endif // MicromegasClusterQA_H \ No newline at end of file +#endif // MicromegasClusterQA_H diff --git a/offline/QA/Tracking/StateClusterResidualsQA.cc b/offline/QA/Tracking/StateClusterResidualsQA.cc index 1dd4423369..2f7e77a402 100644 --- a/offline/QA/Tracking/StateClusterResidualsQA.cc +++ b/offline/QA/Tracking/StateClusterResidualsQA.cc @@ -315,4 +315,4 @@ int StateClusterResidualsQA::EndRun(const int /*unused*/) assert(hm); return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/QA/Tracking/StateClusterResidualsQA.h b/offline/QA/Tracking/StateClusterResidualsQA.h index bfbbd9c53d..2a4bfed68f 100644 --- a/offline/QA/Tracking/StateClusterResidualsQA.h +++ b/offline/QA/Tracking/StateClusterResidualsQA.h @@ -127,4 +127,4 @@ class StateClusterResidualsQA : public SubsysReco std::vector m_histograms_z{}; }; -#endif // TRACKFITTINGQA_H \ No newline at end of file +#endif // TRACKFITTINGQA_H diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index fe3a67f345..ed3cea5398 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -208,4 +208,4 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f } } return return_url; -} \ No newline at end of file +} diff --git a/offline/framework/ffamodules/FlagHandler.h b/offline/framework/ffamodules/FlagHandler.h index 90002848d2..f968501114 100644 --- a/offline/framework/ffamodules/FlagHandler.h +++ b/offline/framework/ffamodules/FlagHandler.h @@ -55,4 +55,4 @@ class FlagHandler : public SubsysReco private: }; -#endif // FFAMODULES_FLAGHANDLER_H \ No newline at end of file +#endif // FFAMODULES_FLAGHANDLER_H diff --git a/offline/framework/ffamodules/HeadReco.cc b/offline/framework/ffamodules/HeadReco.cc index 378792f9a4..761fc51b37 100644 --- a/offline/framework/ffamodules/HeadReco.cc +++ b/offline/framework/ffamodules/HeadReco.cc @@ -128,4 +128,4 @@ int HeadReco::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/framework/ffamodules/HeadReco.h b/offline/framework/ffamodules/HeadReco.h index 9920b9d531..407069af84 100644 --- a/offline/framework/ffamodules/HeadReco.h +++ b/offline/framework/ffamodules/HeadReco.h @@ -45,4 +45,4 @@ class HeadReco : public SubsysReco protected: }; -#endif \ No newline at end of file +#endif diff --git a/offline/framework/ffamodules/SyncReco.h b/offline/framework/ffamodules/SyncReco.h index 0ef8df706e..5f08f433a8 100644 --- a/offline/framework/ffamodules/SyncReco.h +++ b/offline/framework/ffamodules/SyncReco.h @@ -68,4 +68,4 @@ class SyncReco : public SubsysReco int forced_segment {-1}; }; -#endif /* FFAMODULES_SYNCRECO_H */ \ No newline at end of file +#endif /* FFAMODULES_SYNCRECO_H */ diff --git a/offline/framework/ffamodules/Timing.cc b/offline/framework/ffamodules/Timing.cc index 3a0da54110..6e583e38bf 100644 --- a/offline/framework/ffamodules/Timing.cc +++ b/offline/framework/ffamodules/Timing.cc @@ -33,4 +33,4 @@ int Timing::process_event(PHCompositeNode * /*topNode*/) call_counter = 0; } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/framework/ffamodules/Timing.h b/offline/framework/ffamodules/Timing.h index e73b824ae4..00bb4646ef 100644 --- a/offline/framework/ffamodules/Timing.h +++ b/offline/framework/ffamodules/Timing.h @@ -28,4 +28,4 @@ void SetCallCounter(unsigned int i) { calls = i; } time_t starttime{0}; }; -#endif \ No newline at end of file +#endif diff --git a/offline/framework/fun4all/Fun4AllServer.cc b/offline/framework/fun4all/Fun4AllServer.cc index f18b84b2d1..f1eb9735d2 100644 --- a/offline/framework/fun4all/Fun4AllServer.cc +++ b/offline/framework/fun4all/Fun4AllServer.cc @@ -1885,4 +1885,4 @@ int Fun4AllServer::UpdateRunNode() iret += Subsystem.first->UpdateRunNode(Subsystem.second); } return iret; -} \ No newline at end of file +} diff --git a/offline/framework/fun4all/Fun4AllServer.h b/offline/framework/fun4all/Fun4AllServer.h index 512f3e5d5c..7bd3328fa8 100644 --- a/offline/framework/fun4all/Fun4AllServer.h +++ b/offline/framework/fun4all/Fun4AllServer.h @@ -178,4 +178,4 @@ int keep_db_connected{0}; std::map timer_map; }; -#endif \ No newline at end of file +#endif diff --git a/offline/framework/fun4all/InputFileHandler.cc b/offline/framework/fun4all/InputFileHandler.cc index a3f06049b0..4073b89fb2 100644 --- a/offline/framework/fun4all/InputFileHandler.cc +++ b/offline/framework/fun4all/InputFileHandler.cc @@ -235,4 +235,4 @@ int InputFileHandler::RunBeforeOpening(const std::vector &stringvec iret = iret >> 8U; } return static_cast (iret); -} \ No newline at end of file +} diff --git a/offline/framework/fun4all/InputFileHandler.h b/offline/framework/fun4all/InputFileHandler.h index 054c182986..b10693248b 100644 --- a/offline/framework/fun4all/InputFileHandler.h +++ b/offline/framework/fun4all/InputFileHandler.h @@ -165,4 +165,4 @@ uint64_t m_Verbosity{0}; std::list m_FileListOpened; // all files which were opened during running }; -#endif \ No newline at end of file +#endif diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 472e61199b..377c01fccb 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -1545,4 +1545,4 @@ void Fun4AllStreamingInputManager::createQAHistos() h_tagBcoFelix_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCO_felix%i") % i).str())); h_tagBcoFelixAllFees_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCOAllFees_Felix%i") % i).str())); } -} \ No newline at end of file +} diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index ac65955fb1..7f3ce1e910 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -1051,4 +1051,4 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int m_MicromegasRawHitMap[gtm_bco].push_back(newhit.release()); } -} \ No newline at end of file +} diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index 8bda085da0..5b6c3b67f1 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -284,4 +284,4 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput //*} }; -#endif \ No newline at end of file +#endif diff --git a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc index 93c0c88a68..6177f5e82b 100644 --- a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc +++ b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc @@ -524,4 +524,4 @@ void SingleMvtxPoolInput::ConfigureStreamingInputManager() StreamingInputManager()->SetMvtxNegativeBco(m_NegativeBco); } return; -} \ No newline at end of file +} diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index e92b00efd1..dd0ce10e61 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -1355,4 +1355,4 @@ int SingleTriggeredInput::ReadEvent() } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.h b/offline/framework/fun4allraw/SingleTriggeredInput.h index 561972fc4f..ccf742396e 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.h +++ b/offline/framework/fun4allraw/SingleTriggeredInput.h @@ -199,4 +199,4 @@ bool m_packetclk_copy_runs{false}; long long eventcounter{0}; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/CaloEmbedding/CombineTowerInfo.cc b/offline/packages/CaloEmbedding/CombineTowerInfo.cc index 34e85e96ed..d015a5e3aa 100644 --- a/offline/packages/CaloEmbedding/CombineTowerInfo.cc +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.cc @@ -129,3 +129,4 @@ int CombineTowerInfo::process_event(PHCompositeNode* /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } + diff --git a/offline/packages/CaloEmbedding/CombineTowerInfo.h b/offline/packages/CaloEmbedding/CombineTowerInfo.h index 3b7e784188..e4671a6a72 100644 --- a/offline/packages/CaloEmbedding/CombineTowerInfo.h +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.h @@ -57,3 +57,4 @@ TowerInfoContainer* m_towersOut{nullptr}; }; #endif + diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.cc b/offline/packages/CaloEmbedding/CopyIODataNodes.cc index f7eb87379d..ab8f3cfb2e 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.cc +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.cc @@ -519,4 +519,4 @@ void CopyIODataNodes::CopySyncObject(PHCompositeNode *from_topNode, PHCompositeN to_syncobject->identify(); } return; -} \ No newline at end of file +} diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.h b/offline/packages/CaloEmbedding/CopyIODataNodes.h index e7eb4637f1..f300fafb00 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.h +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.h @@ -84,4 +84,4 @@ class CopyIODataNodes : public SubsysReco std::string to_towerInfo_name = {}; }; -#endif // COPYIODATANODES_H \ No newline at end of file +#endif // COPYIODATANODES_H diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.cc b/offline/packages/CaloReco/PhotonClusterBuilder.cc index 2525d7432c..793090e6fe 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.cc +++ b/offline/packages/CaloReco/PhotonClusterBuilder.cc @@ -925,4 +925,4 @@ double PhotonClusterBuilder::deltaR(double eta1, double phi1, double eta2, doubl dphi += 2 * M_PI; } return sqrt(pow(eta1 - eta2, 2) + pow(dphi, 2)); -} \ No newline at end of file +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index b80f461508..bc0acb06ab 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -582,4 +582,4 @@ void KFParticle_sPHENIX::getField() fieldmap->Delete(); fin->Close(); -} \ No newline at end of file +} diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc index 18c6961c62..7c8cf34cb3 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc @@ -378,4 +378,4 @@ namespace PHGenFit return new Fitter(tgeo_manager, fieldMap, fitter_choice, track_rep_choice, doEventDisplay); } -} // namespace PHGenFit \ No newline at end of file +} // namespace PHGenFit diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Track.cc b/offline/packages/PHGenFitPkg/PHGenFit/Track.cc index 4ace2d78f7..726985cb0f 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Track.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Track.cc @@ -1015,4 +1015,4 @@ namespace PHGenFit return mom; } -} // namespace PHGenFit \ No newline at end of file +} // namespace PHGenFit diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc index 2a222fa6c0..b24009ea7a 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc @@ -100,4 +100,4 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) accepted_events++; return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h index 492757ecb6..4603ff148a 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h @@ -71,4 +71,4 @@ bool use_max_accept{false}; }; -#endif // JETDSTSKIMMER_H \ No newline at end of file +#endif // JETDSTSKIMMER_H diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 8c589bb57c..33a6316045 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -1220,3 +1220,4 @@ void DetermineTowerBackground::FillNode(PHCompositeNode *topNode) + diff --git a/offline/packages/jetbackground/DetermineTowerBackground.h b/offline/packages/jetbackground/DetermineTowerBackground.h index 7f0c16c160..0fc06a71f5 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.h +++ b/offline/packages/jetbackground/DetermineTowerBackground.h @@ -163,4 +163,4 @@ float _Psi2{0}; std::string OHTowerName; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index d8a05c0ef0..781d8a7004 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -2432,3 +2432,4 @@ TGraph *MbdCalib::get_lut_graph(const int pmtch, std::string_view type) return g; } + diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index 5a889e778a..f1bd036985 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -1639,4 +1639,4 @@ PHG4VtxPoint *MbdEvent::GetPrimaryVtx(PHCompositeNode *topNode) return _vtxp; } -#endif \ No newline at end of file +#endif diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index dc0153a21c..a241bf1ed8 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -377,4 +377,4 @@ int MbdReco::getNodes(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index c82db5d3d4..331c58d222 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -209,4 +209,4 @@ TH1 *GetHist() { return hpulse; } int _verbose{0}; }; -#endif // __MBDSIG_H__ \ No newline at end of file +#endif // __MBDSIG_H__ diff --git a/offline/packages/micromegas/MicromegasClusterizer.cc b/offline/packages/micromegas/MicromegasClusterizer.cc index 1e2e298719..501599e82f 100644 --- a/offline/packages/micromegas/MicromegasClusterizer.cc +++ b/offline/packages/micromegas/MicromegasClusterizer.cc @@ -448,4 +448,4 @@ int MicromegasClusterizer::End(PHCompositeNode* /*topNode*/) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc index 62ba752c64..5b61efad3b 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc @@ -305,4 +305,4 @@ int MicromegasCombinedDataDecoder::End(PHCompositeNode* /*topNode*/) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h index f66167958d..7c5fcafe27 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h @@ -164,4 +164,4 @@ class MicromegasCombinedDataDecoder : public SubsysReco hitcountmap_t m_hitcounts; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/micromegas/MicromegasDefs.cc b/offline/packages/micromegas/MicromegasDefs.cc index 682bec9fc6..d53180c61d 100644 --- a/offline/packages/micromegas/MicromegasDefs.cc +++ b/offline/packages/micromegas/MicromegasDefs.cc @@ -137,4 +137,4 @@ namespace MicromegasDefs return getTileId( tmp ); } -} \ No newline at end of file +} diff --git a/offline/packages/micromegas/MicromegasDefs.h b/offline/packages/micromegas/MicromegasDefs.h index fec976973a..e9b5a045f4 100644 --- a/offline/packages/micromegas/MicromegasDefs.h +++ b/offline/packages/micromegas/MicromegasDefs.h @@ -134,4 +134,4 @@ namespace MicromegasDefs } -#endif \ No newline at end of file +#endif diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.cc b/offline/packages/mvtx/CylinderGeom_Mvtx.cc index 6bb9c1ddec..092ae656f4 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.cc +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.cc @@ -300,4 +300,4 @@ int CylinderGeom_Mvtx::get_pixel_Z_from_pixel_number(int NXZ) const int CylinderGeom_Mvtx::get_pixel_number_from_xbin_zbin(int xbin, int zbin) const // obsolete { return xbin + zbin * get_NX(); -} \ No newline at end of file +} diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.h b/offline/packages/mvtx/CylinderGeom_Mvtx.h index a925dd36cf..1506b5cab4 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.h +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.h @@ -165,4 +165,4 @@ class CylinderGeom_Mvtx : public PHG4CylinderGeom ClassDefOverride(CylinderGeom_Mvtx, 2) }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/mvtx/MvtxClusterPruner.cc b/offline/packages/mvtx/MvtxClusterPruner.cc index dac7ffc387..09131f1bea 100644 --- a/offline/packages/mvtx/MvtxClusterPruner.cc +++ b/offline/packages/mvtx/MvtxClusterPruner.cc @@ -291,4 +291,4 @@ int MvtxClusterPruner::End(PHCompositeNode* /*topNode*/) << std::endl; return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/mvtx/MvtxClusterizer.cc b/offline/packages/mvtx/MvtxClusterizer.cc index db49609453..6095fc6178 100644 --- a/offline/packages/mvtx/MvtxClusterizer.cc +++ b/offline/packages/mvtx/MvtxClusterizer.cc @@ -977,4 +977,4 @@ void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode) } return; -} \ No newline at end of file +} diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index d35a11b275..0dffcd33ac 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -245,4 +245,4 @@ int MvtxHitPruner::process_event(PHCompositeNode* topNode) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/mvtx/SegmentationAlpide.cc b/offline/packages/mvtx/SegmentationAlpide.cc index e50183c46d..2575ac4e9d 100644 --- a/offline/packages/mvtx/SegmentationAlpide.cc +++ b/offline/packages/mvtx/SegmentationAlpide.cc @@ -24,4 +24,4 @@ void SegmentationAlpide::print() << std::endl; std::cout << std::format("Active/Total size: {:.6f}/{:.6f} (rows) {:.6f}/{:.6f} (cols) cm", ActiveMatrixSizeRows, SensorSizeRows, ActiveMatrixSizeCols, SensorSizeCols) << std::endl; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 9353de0f50..2368a0df1c 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -1145,4 +1145,4 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/LaserEventIdentifier.cc b/offline/packages/tpc/LaserEventIdentifier.cc index 31533cf9ff..64bcbb1dc2 100644 --- a/offline/packages/tpc/LaserEventIdentifier.cc +++ b/offline/packages/tpc/LaserEventIdentifier.cc @@ -284,4 +284,4 @@ int LaserEventIdentifier::End(PHCompositeNode * /*topNode*/) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/Tpc3DClusterizer.cc b/offline/packages/tpc/Tpc3DClusterizer.cc index ac12d48f24..5f385c82f9 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.cc +++ b/offline/packages/tpc/Tpc3DClusterizer.cc @@ -783,4 +783,4 @@ void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rt ++iterAdc; } } -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcClusterMover.cc b/offline/packages/tpc/TpcClusterMover.cc index 4cf37e1cea..d7a8f04eab 100644 --- a/offline/packages/tpc/TpcClusterMover.cc +++ b/offline/packages/tpc/TpcClusterMover.cc @@ -249,4 +249,4 @@ int TpcClusterMover::get_circle_circle_intersection(double target_radius, double y = yminus; } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcClusterMover.h b/offline/packages/tpc/TpcClusterMover.h index 1ba4749a2b..34a609dd4f 100644 --- a/offline/packages/tpc/TpcClusterMover.h +++ b/offline/packages/tpc/TpcClusterMover.h @@ -63,4 +63,4 @@ class TpcClusterMover int _verbosity = 0; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index cf8146c82e..7f00b989ff 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1792,4 +1792,4 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) int TpcClusterizer::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc index 6c4abde3d5..56d7fa8511 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc @@ -712,4 +712,4 @@ int TpcCombinedRawDataUnpacker::End(PHCompositeNode* /*topNode*/) // if(m_Debug==1) hm->dumpHistos(m_filename, "RECREATE"); return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc index c785ba9acb..9fd8e53872 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc @@ -791,4 +791,4 @@ int TpcCombinedRawDataUnpackerDebug::End(PHCompositeNode* /*topNode*/) // if(m_Debug==1) hm->dumpHistos(m_filename, "RECREATE"); return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcDistortionCorrection.cc b/offline/packages/tpc/TpcDistortionCorrection.cc index e5e0289f4c..743af55b7f 100644 --- a/offline/packages/tpc/TpcDistortionCorrection.cc +++ b/offline/packages/tpc/TpcDistortionCorrection.cc @@ -144,4 +144,4 @@ if(dcc->m_use_scalefactor) const auto y_new = r_new * std::sin(phi_new); return {x_new, y_new, z_new}; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.cc b/offline/packages/tpc/TpcLoadDistortionCorrection.cc index a60a45837c..713a89215f 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.cc +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.cc @@ -147,4 +147,4 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) int TpcLoadDistortionCorrection::process_event(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcRawDataTree.cc b/offline/packages/tpc/TpcRawDataTree.cc index 6d80dbda68..76d6a28363 100644 --- a/offline/packages/tpc/TpcRawDataTree.cc +++ b/offline/packages/tpc/TpcRawDataTree.cc @@ -285,4 +285,4 @@ int TpcRawDataTree::End(PHCompositeNode * /*topNode*/) m_file->Close(); return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcRawWriter.cc b/offline/packages/tpc/TpcRawWriter.cc index f49f921b32..529a6d9d26 100644 --- a/offline/packages/tpc/TpcRawWriter.cc +++ b/offline/packages/tpc/TpcRawWriter.cc @@ -687,4 +687,4 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) int TpcRawWriter::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TpcSimpleClusterizer.cc b/offline/packages/tpc/TpcSimpleClusterizer.cc index 7d0f46afee..6e3fb8febf 100644 --- a/offline/packages/tpc/TpcSimpleClusterizer.cc +++ b/offline/packages/tpc/TpcSimpleClusterizer.cc @@ -686,4 +686,4 @@ int TpcSimpleClusterizer::process_event(PHCompositeNode *topNode) int TpcSimpleClusterizer::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/tpc/TrainingHits.cc b/offline/packages/tpc/TrainingHits.cc index 75a6c6ac55..12d5f49ce2 100644 --- a/offline/packages/tpc/TrainingHits.cc +++ b/offline/packages/tpc/TrainingHits.cc @@ -38,4 +38,4 @@ void TrainingHits::Reset() ntouch = 0; nedge = 0; cluskey = 0; -} \ No newline at end of file +} diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 028e0ac729..c5e606569f 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -719,4 +719,4 @@ double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetke double surf_radius = std::sqrt(surf_center[0] * surf_center[0] + surf_center[1] * surf_center[1]); return surf_radius; -} \ No newline at end of file +} diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index bf36d6fab2..f17a25feff 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -207,4 +207,4 @@ class AlignmentTransformation double sectorPhi[2][12] = {}; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/trackreco/DSTClusterPruning.cc b/offline/packages/trackreco/DSTClusterPruning.cc index afa4c60bf9..5b8b8af17e 100644 --- a/offline/packages/trackreco/DSTClusterPruning.cc +++ b/offline/packages/trackreco/DSTClusterPruning.cc @@ -457,4 +457,4 @@ void DSTClusterPruning::print_clusters() std::cout << "end of loop" << "\n"; } -} \ No newline at end of file +} diff --git a/offline/packages/trackreco/DSTClusterPruning.h b/offline/packages/trackreco/DSTClusterPruning.h index 0f7bc65f9f..590fc28e86 100644 --- a/offline/packages/trackreco/DSTClusterPruning.h +++ b/offline/packages/trackreco/DSTClusterPruning.h @@ -89,4 +89,4 @@ class DSTClusterPruning : public SubsysReco // bool generateKey = false; }; -#endif // DSTCLUSTERPRUNING_H \ No newline at end of file +#endif // DSTCLUSTERPRUNING_H diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 7c3db696f4..4d72ead202 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1490,4 +1490,4 @@ int PHActsTrkFitter::getNodes(PHCompositeNode* topNode) m_globalPositionWrapper.set_suppressCrossing(true); return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 4e438a0da2..5c0dade9ae 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -366,4 +366,4 @@ void setDirectNavigation(bool flag) { m_directNavigation = flag; } }; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc index 30bd788392..15bdeff999 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc @@ -852,4 +852,4 @@ std::vector PHSiliconTpcTrackMatching::getTrackletClusterList cluskey_vec.push_back(key); } // end loop over clusters for this track return cluskey_vec; -} \ No newline at end of file +} diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h index 0fefae8706..13356df522 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h @@ -245,4 +245,4 @@ void set_use_intt_crossing(const bool flag) { _use_intt_crossing = flag; } std::vector getTrackletClusterList(TrackSeed* tracklet); }; -#endif // PHSILICONTPCTRACKMATCHING_H \ No newline at end of file +#endif // PHSILICONTPCTRACKMATCHING_H diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index f4b7a6fab7..cd58f11b6b 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -140,4 +140,4 @@ void set_pp_mode(bool mode) { _pp_mode = mode; } bool _pp_mode = true; // default to pp mode }; -#endif // PHSIMPLEVERTEXFINDER_H \ No newline at end of file +#endif // PHSIMPLEVERTEXFINDER_H diff --git a/offline/packages/trackreco/PHTpcDeltaZCorrection.h b/offline/packages/trackreco/PHTpcDeltaZCorrection.h index 2dc061e623..287297fd5d 100644 --- a/offline/packages/trackreco/PHTpcDeltaZCorrection.h +++ b/offline/packages/trackreco/PHTpcDeltaZCorrection.h @@ -72,4 +72,4 @@ class PHTpcDeltaZCorrection : public SubsysReco, public PHParameterInterface std::set m_corrected_clusters; }; -#endif // PHTpcDeltaZCorrection_H \ No newline at end of file +#endif // PHTpcDeltaZCorrection_H