From 5adbf5c679c08aab43fd6d045345baecea0dd2b1 Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Wed, 17 Dec 2025 20:59:39 -0500 Subject: [PATCH 001/866] djl -- add average calo v2 as an option for flow --- .../jetbackground/DetermineTowerBackground.cc | 252 ++++++++++++------ .../jetbackground/DetermineTowerBackground.h | 13 +- offline/packages/jetbackground/Makefile.am | 3 + 3 files changed, 184 insertions(+), 84 deletions(-) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 9823d337f6..63100bcbea 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -14,6 +14,10 @@ #include #include +#include +#include +#include + #include #include @@ -52,9 +56,65 @@ DetermineTowerBackground::DetermineTowerBackground(const std::string &name) int DetermineTowerBackground::InitRun(PHCompositeNode *topNode) { + if (_do_flow == 4) + { + if (Verbosity()) + { + std::cout << "Loading the average calo v2" << std::endl; + } + LoadCalibrations(); + + } + return CreateNode(topNode); } +int DetermineTowerBackground::LoadCalibrations() +{ + + CDBTTree *cdbtree_calo_v2 = nullptr; + + std::string calibdir; + if (m_overwrite_average_calo_v2) + { + calibdir = m_overwrite_average_calo_v2_path; + } + else + { + calibdir = CDBInterface::instance()->getUrl(m_calibName); + } + + if (calibdir.empty()) + { + std::cout << "Could not find and load histograms for EMCAL LUTs! defaulting to the identity table!" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + else + { + cdbtree_calo_v2 = new CDBTTree(calibdir); + } + + if (!cdbtree_calo_v2) + { + std::cout << "Error in finding Average Calo v2." << std::endl; + + return Fun4AllReturnCodes::ABORTRUN; + } + + cdbtree_calo_v2->LoadCalibrations(); + + _CENTRALITY_V2.fill(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; +} + int DetermineTowerBackground::process_event(PHCompositeNode *topNode) { @@ -481,7 +541,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 +899,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 +953,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 diff --git a/offline/packages/jetbackground/DetermineTowerBackground.h b/offline/packages/jetbackground/DetermineTowerBackground.h index a8a6d0209c..a46d48e616 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; @@ -37,7 +38,11 @@ class DetermineTowerBackground : public SubsysReco 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 SetOverwriteCaloV2(std::string &url) + { + m_overwrite_average_calo_v2 = true; + m_overwrite_average_calo_v2_path = url; + } 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; }; @@ -55,6 +60,12 @@ class DetermineTowerBackground : public SubsysReco int CreateNode(PHCompositeNode *topNode); void FillNode(PHCompositeNode *topNode); + int LoadCalibrations(); + std::array _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; + int _do_flow{0}; float _v2{0}; float _Psi2{0}; diff --git a/offline/packages/jetbackground/Makefile.am b/offline/packages/jetbackground/Makefile.am index 6fe9740a4e..ad45676fbe 100644 --- a/offline/packages/jetbackground/Makefile.am +++ b/offline/packages/jetbackground/Makefile.am @@ -24,6 +24,8 @@ libjetbackground_la_LDFLAGS = \ libjetbackground_la_LIBADD = \ libjetbackground_io.la \ -lcalo_io \ + -lcentrality_io \ + -lcdbobjects \ -lConstituentSubtractor \ -leventplaneinfo_io \ -lglobalvertex \ @@ -33,6 +35,7 @@ libjetbackground_la_LIBADD = \ -lphg4hit \ -lphparameter \ -lqautils \ + -lffamodules \ -lSubsysReco pkginclude_HEADERS = \ From 35a6b31e4b87d1ce0fe8e10fb3450750dae4538a Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Wed, 17 Dec 2025 21:11:40 -0500 Subject: [PATCH 002/866] add return if LoadCalibrations failed --- offline/packages/jetbackground/DetermineTowerBackground.cc | 6 +++++- offline/packages/jetbackground/DetermineTowerBackground.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 63100bcbea..12bc78130d 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -62,7 +62,11 @@ int DetermineTowerBackground::InitRun(PHCompositeNode *topNode) { std::cout << "Loading the average calo v2" << std::endl; } - LoadCalibrations(); + if (!LoadCalibrations()) + { + std::cout << "Load calibrations failed." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } } diff --git a/offline/packages/jetbackground/DetermineTowerBackground.h b/offline/packages/jetbackground/DetermineTowerBackground.h index a46d48e616..8905c2c93d 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.h +++ b/offline/packages/jetbackground/DetermineTowerBackground.h @@ -61,6 +61,7 @@ class DetermineTowerBackground : public SubsysReco void FillNode(PHCompositeNode *topNode); int LoadCalibrations(); + std::array _CENTRALITY_V2; std::string m_calibName = "JET_AVERAGE_CALO_V2_SEPD_PSI2"; bool m_overwrite_average_calo_v2{false}; From 2e9ccc7bd05638acfab1959cc62d9e2bbca8515d Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Wed, 17 Dec 2025 22:46:03 -0500 Subject: [PATCH 003/866] djl -- array to vector --- offline/packages/jetbackground/DetermineTowerBackground.cc | 2 +- offline/packages/jetbackground/DetermineTowerBackground.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 12bc78130d..9a2e550e5d 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -107,7 +107,7 @@ int DetermineTowerBackground::LoadCalibrations() cdbtree_calo_v2->LoadCalibrations(); - _CENTRALITY_V2.fill(0); + _CENTRALITY_V2.assign(100,0); for (int icent = 0; icent < 100; icent++) { diff --git a/offline/packages/jetbackground/DetermineTowerBackground.h b/offline/packages/jetbackground/DetermineTowerBackground.h index 8905c2c93d..ed9e34bf9a 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.h +++ b/offline/packages/jetbackground/DetermineTowerBackground.h @@ -62,7 +62,7 @@ class DetermineTowerBackground : public SubsysReco int LoadCalibrations(); - std::array _CENTRALITY_V2; + 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; From ce0d3af05d26ad9aaf3275d50dce0afd8d54b2ec Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Fri, 19 Dec 2025 09:12:26 -0500 Subject: [PATCH 004/866] djl -- change error handling to exit and not check for nullptr --- .../jetbackground/DetermineTowerBackground.cc | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 9a2e550e5d..7f021f4f39 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -91,20 +91,13 @@ int DetermineTowerBackground::LoadCalibrations() if (calibdir.empty()) { std::cout << "Could not find and load histograms for EMCAL LUTs! defaulting to the identity table!" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; + exit(-1); } else { cdbtree_calo_v2 = new CDBTTree(calibdir); } - - if (!cdbtree_calo_v2) - { - std::cout << "Error in finding Average Calo v2." << std::endl; - - return Fun4AllReturnCodes::ABORTRUN; - } - + cdbtree_calo_v2->LoadCalibrations(); _CENTRALITY_V2.assign(100,0); From 6ddbed51e0941f64f3acb2cf6c90bdcf47b33b6d Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 14 Apr 2025 10:57:21 -0400 Subject: [PATCH 005/866] Add matching flag to evaluation. Fill ntuple for both matched and unmatched waveforms --- .../SingleMicromegasPoolInput_v2.cc | 51 +++++++++++-------- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 3 ++ 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 7500e3badf..89c0caa9f3 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -607,6 +607,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); @@ -912,6 +913,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 +928,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 +954,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 diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index d8c3c1da62..3746b9eb41 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -230,6 +230,9 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// true if measurement is hearbeat bool is_heartbeat = false; + /// true if matched + bool matched = false; + /// ll1 bco uint64_t gtm_bco_first {0}; From ba90ae834d4c8d8e283828482904d753c6104afb Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 6 Jan 2026 12:05:55 -0500 Subject: [PATCH 006/866] Changes to CM Distortions --- offline/packages/tpc/LaserClusterizer.cc | 146 ++++- .../tpccalib/TpcCentralMembraneMatching.cc | 95 ++- .../tpccalib/TpcCentralMembraneMatching.h | 10 +- .../packages/tpccalib/TpcLaminationFitting.cc | 558 ++++++++++++++---- .../packages/tpccalib/TpcLaminationFitting.h | 46 +- 5 files changed, 726 insertions(+), 129 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 170f95944d..6f143bb1c2 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -155,6 +155,106 @@ namespace return par[0]*g*cdf; } + void splitWeaklyConnectedRegion(const std::vector ®ion, std::vector> &outputRegions) + { + int N = region.size(); + std::vector> adj(N); + for(int i=0; i() + neigh.get<0>() - region[j].first.get<0>()) < 0.01 && + fabs(region[i].first.get<1>() + neigh.get<1>() - region[j].first.get<1>()) < 0.01 && + fabs(region[i].first.get<2>() + neigh.get<2>() - region[j].first.get<2>()) < 0.01) + { + adj[i].push_back(j); + adj[j].push_back(i); + break; + } + } + } + } + + std::cout << " constructed adjacency list, average degree = " << std::accumulate(adj.begin(), adj.end(), 0.0, [](double s, auto &v) { return s + v.size(); }) / N << ")" << std::endl; + + std::vector disc(N, -1), low(N, -1), parent(N, -1); + std::vector> bridges; + int time=0; + + std::function dfs = [&](int u) + { + disc[u] = low[u] = ++time; + for(auto v : adj[u]) + { + if(disc[v] == -1) + { + parent[v] = u; + dfs(v); + low[u] = std::min(low[u], low[v]); + if(low[v] > disc[u]) + { + bridges.emplace_back(u,v); + } + } + else if(v != parent[u]) + { + low[u] = std::min(low[u], disc[v]); + } + } + }; + + for(int i=0; i> adj2 = adj; + int removed = 0; + for(auto [u,v] : bridges) + { + if(adj[u].size() > 2 && adj[v].size() > 2) + { + adj2[u].erase(std::remove(adj2[u].begin(), adj2[u].end(), v), adj2[u].end()); + adj2[v].erase(std::remove(adj2[v].begin(), adj2[v].end(), u), adj2[v].end()); + removed++; + std::cout << " removed weak bridge between nodes " << u << " (deg = " << adj[u].size() << ") and " << v << " (deg = " << adj[v].size() << ")" << std::endl; + } + } + + std::cout << " Removed " << removed << " weak bridges, now finding connected components" << std::endl; + + std::vector visited(N, false); + for(int i=0; i sub; + std::queue q; + q.push(i); + visited[i] = true; + while(!q.empty()) + { + int u = q.front(); + q.pop(); + sub.push_back(region[u]); + for(auto v : adj2[u]) + { + if(!visited[v]) + { + visited[v] = true; + q.push(v); + } + } + } + outputRegions.push_back(sub); + std::cout << " found subregion of size " << sub.size() << std::endl; + } + std::cout << " finished splitting region into " << outputRegions.size() << " subregions" << std::endl; +} + void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey) { std::vector> regions; @@ -215,11 +315,55 @@ namespace } } regions.push_back(region); + } + std::cout << "finished with normal region finding, now splitting weakly connected regions" << std::endl; + + std::vector> refinedRegions; + int regionNum = 0; + for(auto ®ion : regions) + { + std::vector> tmpRefinedRegions; + std::cout << "starting to split region " << regionNum << " with " << region.size() << " hits" << std::endl; + regionNum++; + splitWeaklyConnectedRegion(region, tmpRefinedRegions); + std::cout << "finished splitting region into " << tmpRefinedRegions.size() << std::endl; + for(auto &subregion : tmpRefinedRegions) + { + refinedRegions.push_back(subregion); + } + std::cout << "total refined regions so far: " << refinedRegions.size() << std::endl; } + std::sort(refinedRegions.begin(), refinedRegions.end(), [&](const auto &a, const auto &b) + { + bool a_has = false; + bool b_has = false; + for(auto &h : a) + { + if(h.second.second.first == maxKey.first && h.second.second.second == maxKey.second) + { + a_has = true; + break; + } + } + for(auto &h : b) + { + if(h.second.second.first == maxKey.first && h.second.second.second == maxKey.second) + { + b_has = true; + break; + } + } + if(a_has != b_has) + { + return a_has; + } + return a.size() > b.size(); + }); + clusHits.clear(); - for(auto hit : regions[0]) + for(auto hit : refinedRegions[0]) { clusHits.push_back(hit); } diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index 6fa65dfbdf..60df27bbbb 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -16,6 +16,8 @@ #include +#include + #include #include @@ -160,11 +162,13 @@ namespace TpcCentralMembraneMatching::TpcCentralMembraneMatching(const std::string& name) : SubsysReco(name) { + /* // calculate stripes center positions CalculateCenters(nPads_R1, R1_e, nGoodStripes_R1_e, keepUntil_R1_e, nStripesIn_R1_e, nStripesBefore_R1_e, cx1_e, cy1_e); CalculateCenters(nPads_R1, R1, nGoodStripes_R1, keepUntil_R1, nStripesIn_R1, nStripesBefore_R1, cx1, cy1); CalculateCenters(nPads_R2, R2, nGoodStripes_R2, keepUntil_R2, nStripesIn_R2, nStripesBefore_R2, cx2, cy2); CalculateCenters(nPads_R3, R3, nGoodStripes_R3, keepUntil_R3, nStripesIn_R3, nStripesBefore_R3, cx3, cy3); + */ } //___________________________________________________________ @@ -1095,7 +1099,31 @@ int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) // Get truth cluster positions //===================== - const double phi_petal = M_PI / 9.0; // angle span of one petal + CDBTTree *cdbttree = new CDBTTree("/sphenix/u/bkimelman/CMStripePattern.root"); + cdbttree->LoadCalibrations(); + auto cdbMap = cdbttree->GetDoubleEntryMap(); + for (const auto &[index, values] : cdbMap) + { + m_truth_index.push_back(index); + double tmpR = cdbttree->GetDoubleValue(index, "truthR"); + double tmpPhi = cdbttree->GetDoubleValue(index, "truthPhi"); + TVector3 dummyPos(tmpR*cos(tmpPhi), tmpR*sin(tmpPhi), (index / 10000 < 18 ? 1.0 : -1.0)); + m_truth_pos.push_back(dummyPos); + truth_r_phi[(index / 10000 < 18 ? 1 : 0)]->Fill(tmpPhi, tmpR); + if(Verbosity() > 2) + { + std::cout << " index " << index << " x " << dummyPos.X() << " y " << dummyPos.Y() + << " phi " << std::atan2(dummyPos.Y(), dummyPos.X()) + << " radius " << get_r(dummyPos.X(), dummyPos.Y()) << std::endl; + } + if(m_savehistograms) + { + hxy_truth->Fill(dummyPos.X(), dummyPos.Y()); + } + + } + + //const double phi_petal = M_PI / 9.0; // angle span of one petal /* * utility function to @@ -1103,6 +1131,7 @@ int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) * - assign proper z, * - insert in container */ + /* auto save_truth_position = [&](TVector3 source) { source.SetZ(-1); @@ -1279,6 +1308,7 @@ for (int j = 0; j < nRadii; ++j) } } } +*/ /* int count[2] = {0, 0}; @@ -2150,7 +2180,14 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) cmdiff->setTruthR(m_truth_pos[i].Perp()); cmdiff->setTruthZ(m_truth_pos[i].Z()); - if (m_averageMode) + if (m_totalDistMode) + { + cmdiff->setRecoPhi(raw_pos[reco_index].Phi()); + cmdiff->setRecoR(raw_pos[reco_index].Perp()); + cmdiff->setRecoZ(raw_pos[reco_index].Z()); + cmdiff->setNclusters(reco_nhits[reco_index]); + } + else if (m_averageMode) { cmdiff->setRecoPhi(static_pos[reco_index].Phi()); cmdiff->setRecoR(static_pos[reco_index].Perp()); @@ -2186,6 +2223,14 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) dr = static_pos[reco_index].Perp() - m_truth_pos[i].Perp(); dphi = delta_phi(static_pos[reco_index].Phi() - m_truth_pos[i].Phi()); } + if(m_totalDistMode) + { + clus_r = raw_pos[reco_index].Perp(); + clus_phi = raw_pos[reco_index].Phi(); + + dr = raw_pos[reco_index].Perp() - m_truth_pos[i].Perp(); + dphi = delta_phi(raw_pos[reco_index].Phi() - m_truth_pos[i].Phi()); + } if (clus_phi < 0) { clus_phi += 2 * M_PI; @@ -2260,6 +2305,8 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) for(int s=0; s<2; s++) { + int N = gr_dR[s]->GetN(); + bool firstGoodR = false; for(int j=1; j<=m_dcc_out->m_hDRint[s]->GetNbinsY(); j++) { @@ -2283,8 +2330,46 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) for(int i=2; i<=m_dcc_out->m_hDRint[s]->GetNbinsX()-1; i++) { double phiVal = m_dcc_out->m_hDRint[s]->GetXaxis()->GetBinCenter(i); - m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal,RVal)); - m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); + + double num_dPhi = 0.0; + double num_dR = 0.0; + double den = 0.0; + double smoothing_parameter = 2.0; + + for(int k=0; kGetX()[k]); + double interp_RdPhi = RVal*interp_dPhi; + double interp_dR = RVal - gr_dR[s]->GetY()[k]; + + double distSq = (interp_RdPhi*interp_RdPhi) + (interp_dR*interp_dR); + + if(distSq > 100.0) continue; + + if(distSq < 1e-9) + { + num_dPhi = gr_dPhi[s]->GetZ()[k]; + num_dR = gr_dR[s]->GetZ()[k]; + + den = 1.0; + + break; + } + + double weight = 1.0 / pow(distSq, smoothing_parameter / 2.0); + num_dPhi += weight * gr_dPhi[s]->GetZ()[k]; + num_dR += weight * gr_dR[s]->GetZ()[k]; + den += weight; + + } + + if(den > 0.0) + { + m_dcc_out->m_hDRint[s]->SetBinContent(i, j, num_dR / den); + m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); + } + //m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal,RVal)); + //m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); } } } @@ -2693,6 +2778,7 @@ int TpcCentralMembraneMatching::GetNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +/* //_____________________________________________________________ void TpcCentralMembraneMatching::CalculateCenters( int nPads, @@ -2763,3 +2849,4 @@ void TpcCentralMembraneMatching::CalculateCenters( nGoodStripes[j] = i_out; } } +*/ diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.h b/offline/packages/tpccalib/TpcCentralMembraneMatching.h index bb09e8d8fe..b88bfbe6e5 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.h +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.h @@ -101,6 +101,11 @@ class TpcCentralMembraneMatching : public SubsysReco m_averageMode = averageMode; } + void set_totalDistMode(bool totalDistMode) + { + m_totalDistMode = totalDistMode; + } + void set_event_sequence(int seq) { m_event_sequence = seq; @@ -202,7 +207,8 @@ class TpcCentralMembraneMatching : public SubsysReco bool m_useHeader{true}; bool m_averageMode{false}; - + bool m_totalDistMode{false}; + std::vector e_matched; std::vector e_truthIndex; std::vector e_truthR; @@ -301,6 +307,7 @@ class TpcCentralMembraneMatching : public SubsysReco //@} + /* ///@name central membrane pads definitions //@{ static constexpr double mm{1.0}; @@ -367,6 +374,7 @@ class TpcCentralMembraneMatching : public SubsysReco std::array &nStripesIn, std::array &nStripesBefore, double cx[][nRadii], double cy[][nRadii]); + */ /// store centers of all central membrane pads std::vector m_truth_pos; diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 8c99fbb622..b69672fa8f 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -8,6 +8,8 @@ #include +#include + #include #include @@ -27,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -59,25 +62,47 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) { for (int s = 0; s < 2; s++) { + + m_hPetal[s] = new TH2D((boost::format("hPetal_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s;#phi;R [cm]") %(s == 1 ? "North" : "South")).str().c_str(), 500, m_phiModMin[s], m_phiModMax[s], 500, 30, 80); + m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;m;B") %(s == 1 ? "North" : "South")).str().c_str(), 41, -0.0205, 0.0205, 49, -3.0625, 3.0625); + for (int l = 0; l < 18; l++) { - double shift = l * M_PI / 9; + double shift = (l * M_PI / 9); if (s == 0) { shift += M_PI / 18; } + m_laminationIdeal[l][s] = shift; + //this function for the offset was determined from fitting the measured lamination offsets vs ideal lamination phi from field off data in run 75103 + //m_laminationOffset[l][s] = -0.00296837 + 0.0014604 * cos(shift - 1.2246); + if(s == 0) + { + m_laminationOffset[l][s] = -0.00236289 + 0.00143918 * cos(shift - 1.31782); + } + else + { + m_laminationOffset[l][s] = -0.00323259 + 0.00138333 * cos(shift - 1.25373); + } - m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{expected}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %shift).str().c_str(), 200, 30, 80, 200, shift - 0.2, shift + 0.2); - //m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[0]+[1]*exp(-[2]*x)", 30, 80); - //m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[0]*(1+exp(-[2]*(x-[1])))", 30, 80); - m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[3]+[0]*(1-exp(-[2]*(x-[1])))", 30, 80); - //m_fLamination[l][s]->SetParameters(-0.022 + shift, log(3.0/(-0.22 + shift)), 0.12); - m_fLamination[l][s]->SetParameters(-0.011, 30, 0.16, 0.0); - m_fLamination[l][s]->SetParLimits(0, -0.22, 0.0); - m_fLamination[l][s]->SetParLimits(1, 0, 80); - m_fLamination[l][s]->SetParLimits(2, 0.0, 3); - m_fLamination[l][s]->FixParameter(3, shift); - m_laminationCenter[l][s] = shift; + if(m_fieldOff) + { + m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{ideal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %m_laminationIdeal[l][s]).str().c_str(), 200, 30, 80, 200, m_laminationIdeal[l][s] - 0.2, m_laminationIdeal[l][s] + 0.2); + m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[0]+[1]", 30, 80); + m_fLamination[l][s]->SetParameters(-0.003, m_laminationIdeal[l][s]); + m_fLamination[l][s]->SetParLimits(0, -0.05, 0.05); + m_fLamination[l][s]->FixParameter(1, m_laminationIdeal[l][s]); + } + else + { + m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{nominal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %(m_laminationIdeal[l][s]+m_laminationOffset[l][s])).str().c_str(), 200, 30, 80, 200, m_laminationIdeal[l][s]+m_laminationOffset[l][s] - 0.2, m_laminationIdeal[l][s]+m_laminationOffset[l][s] + 0.2); + m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[3]+[0]*(1-exp(-[2]*(x-[1])))", 30, 80); + m_fLamination[l][s]->SetParameters(-0.08, 38, 0.16, 0.0); + m_fLamination[l][s]->SetParLimits(0, -0.02, 0.0); + m_fLamination[l][s]->SetParLimits(1, 0, 50); + m_fLamination[l][s]->SetParLimits(2, 0.0, 1.0); + m_fLamination[l][s]->FixParameter(3, m_laminationIdeal[l][s]+m_laminationOffset[l][s]); + } } } @@ -116,6 +141,90 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) m_run_ZDC_map_auau.insert(std::pair(54969, 9680.)); */ + /* + for(int module=0; module<4; module++) + { + double spacing[nRadii]; + for(int j=0; j m_phiModMax[s]) + { + phi[s] -= M_PI / 9; + } + m_truthR[s].push_back(RValues[module][j]); + m_truthPhi[s].push_back(phi[s]); + } + + } + } + } + */ + CDBTTree *cdbttree = new CDBTTree("/sphenix/u/bkimelman/CMStripePattern.root"); + cdbttree->LoadCalibrations(); + auto cdbMap = cdbttree->GetDoubleEntryMap(); + for (const auto &[index, values] : cdbMap) + { + if(index / 10000 == 18) + { + m_truthR[0].push_back(cdbttree->GetDoubleValue(index, "truthR")); + m_truthPhi[0].push_back(cdbttree->GetDoubleValue(index, "truthPhi")); + } + else if(index / 10000 == 0) + { + m_truthR[1].push_back(cdbttree->GetDoubleValue(index, "truthR")); + m_truthPhi[1].push_back(cdbttree->GetDoubleValue(index, "truthPhi")); + } + } + /* + for(int i=0; i<32; i++) + { + for(int j=0; j<11; j++) + { + int index0 = 18 + i*100 + j; + int index1 = i*100 + j; + + double R0 = cdbttree->GetDoubleValue(index0, "truthR"); + double Phi0 = cdbttree->GetDoubleValue(index0, "truthPhi"); + if(!std::isnan(R0) && !std::isnan(Phi0)) + { + m_truthR[0].push_back(R0); + m_truthPhi[0].push_back(Phi0); + } + + double R1 = cdbttree->GetDoubleValue(index1, "truthR"); + double Phi1 = cdbttree->GetDoubleValue(index1, "truthPhi"); + if(!std::isnan(R1) && !std::isnan(Phi1)) + { + m_truthR[1].push_back(R1); + m_truthPhi[1].push_back(Phi1); + } + } + } + */ + int ret = GetNodes(topNode); return ret; } @@ -205,12 +314,16 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) m_dcc_out->m_hDZint[i] = new TH2F((boost::format("hIntDistortionZ%s") % extension[i]).str().c_str(), (boost::format("hIntDistortionZ%s") % extension[i]).str().c_str(), m_phibins + 2, phiMin, phiMax, m_rbins + 2, rMin, rMax); delete m_dcc_out->m_hentries[i]; m_dcc_out->m_hentries[i] = new TH2I((boost::format("hEntries%s") % extension[i]).str().c_str(), (boost::format("hEntries%s") % extension[i]).str().c_str(), m_phibins + 2, phiMin, phiMax, m_rbins + 2, rMin, rMax); + + phiDistortionLamination[i] = new TH2F((boost::format("phiDistortionLamination%s") % extension[i]).str().c_str(), (boost::format("phiDistortionLamination%s") % extension[i]).str().c_str(), m_phibins + 2, phiMin, phiMax, m_rbins + 2, rMin, rMax); + } m_laminationTree = new TTree("laminationTree","laminationTree"); m_laminationTree->Branch("side",&m_side); m_laminationTree->Branch("lamIndex",&m_lamIndex); m_laminationTree->Branch("lamPhi",&m_lamPhi); + m_laminationTree->Branch("lamOffset",&m_lamShift); m_laminationTree->Branch("goodFit",&m_goodFit); m_laminationTree->Branch("A",&m_A); m_laminationTree->Branch("B",&m_B); @@ -266,11 +379,12 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) LaserCluster *cmclus = cmclus_orig; // const unsigned int adc = cmclus->getAdc(); bool side = (bool) TpcDefs::getSide(cmkey); - if (cmclus->getNLayers() <= m_nLayerCut) + if (cmclus->getNLayers() < m_nLayerCut) { continue; } + //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); if (m_dcc_in_module_edge) @@ -284,25 +398,49 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) TVector3 tmp_pos(pos[0], pos[1], pos[2]); - for (int l = 0; l < 18; l++) + if(cmclus->getNLayers() > m_nLayerCut && cmclus->getSDWeightedLayer() > 0.5) { - double shift = m_laminationCenter[l][side]; - - double phi2pi = tmp_pos.Phi(); - if (side && phi2pi < -0.2) - { - phi2pi += 2 * M_PI; - } - if (!side && phi2pi < M_PI / 18 - 0.2) + for (int l = 0; l < 18; l++) { - phi2pi += 2 * M_PI; + double shift = m_laminationIdeal[l][side]; + + double phi2pi = tmp_pos.Phi(); + if (side && phi2pi < -0.2) + { + phi2pi += 2 * M_PI; + } + if (!side && phi2pi < M_PI / 18 - 0.2) + { + phi2pi += 2 * M_PI; + } + + if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) + { + m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi); + } } + } - if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) - { - m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi); - } + if(cmclus->getSDWeightedLayer() > 0.5) + { + continue; + } + + double phi2pimod = tmp_pos.Phi(); + if (phi2pimod < 0.0) + { + phi2pimod += 2 * M_PI; + } + while(side && phi2pimod > M_PI / 9) + { + phi2pimod -= M_PI / 9; } + while(!side && phi2pimod > M_PI / 18) + { + phi2pimod -= M_PI / 9; + } + + m_hPetal[side]->Fill(phi2pimod, tmp_pos.Perp()); } return Fun4AllReturnCodes::EVENT_OK; @@ -332,6 +470,7 @@ int TpcLaminationFitting::fitLaminations() //float ZDC = 4500.0; TF1 *Af[2] = {new TF1("AN","pol1",0,100000), new TF1("AS","pol1",0,100000)}; TF1 *Bf[2] = {new TF1("BN","pol1",0,100000), new TF1("BS","pol1",0,100000)}; + //TF1 *Cf[2] = {new TF1("CN","pol1",0,100000), new TF1("CS","pol1",0,100000)}; double Cseed[2] = {0.16, 0.125}; if(ppMode) @@ -353,9 +492,12 @@ int TpcLaminationFitting::fitLaminations() Af[0]->SetParameters(-0.007999,-1.783e-6); Af[1]->SetParameters(-0.003288,-2.297e-6); - + Bf[0]->SetParameters(31.55,0.0006141); Bf[1]->SetParameters(34.7,0.0005226); + + //Cf[0]->SetParameters(5.33e-5,0.0); + //Cf[1]->SetParameters(4.166e-5,0.0); } else { @@ -383,6 +525,9 @@ int TpcLaminationFitting::fitLaminations() Bf[0]->SetParameters(32.96,0.0002997); Bf[1]->SetParameters(31.19,0.0005622); + //Cf[0]->SetParameters(1.316-5,0.0); + //Cf[1]->SetParameters(1.284e-5,0.0); + Cseed[0] = 0.125; Cseed[1] = 0.122; } @@ -404,12 +549,16 @@ int TpcLaminationFitting::fitLaminations() TGraph *gr = new TGraph(); TGraph *proj = new TGraph(); - //m_fLamination[l][s]->SetParameters(-0.022 + m_laminationCenter[l][s], 4.595 * seedScale, 0.138); - //m_fLamination[l][s]->SetParameters(-0.022 + m_laminationCenter[l][s], log(4.595 * seedScale/(-0.022 + m_laminationCenter[l][s])), 0.138); - //m_fLamination[l][s]->SetParameters(-0.011 + m_laminationCenter[l][s], 0.025, 0.16); - //m_fLamination[l][s]->SetParameters(-0.011, 30, 0.16, m_laminationCenter[l][s]); - m_fLamination[l][s]->SetParameters(Af[s]->Eval(m_ZDC_coincidence), Bf[s]->Eval(m_ZDC_coincidence), Cseed[s], m_laminationCenter[l][s]); - m_fLamination[l][s]->FixParameter(3, m_laminationCenter[l][s]); + if(m_fieldOff) + { + m_fLamination[l][s]->SetParameters(0.003, m_laminationIdeal[l][s]); + m_fLamination[l][s]->FixParameter(1, m_laminationIdeal[l][s]); + } + else + { + m_fLamination[l][s]->SetParameters(Af[s]->Eval(m_ZDC_coincidence), Bf[s]->Eval(m_ZDC_coincidence), Cseed[s], m_laminationIdeal[l][s] + m_laminationOffset[l][s]); + m_fLamination[l][s]->FixParameter(3, m_laminationIdeal[l][s] + m_laminationOffset[l][s]); + } TF1 *fitSeed = (TF1 *) m_fLamination[l][s]->Clone(); fitSeed->SetName((boost::format("fitSeed%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str()); @@ -448,7 +597,7 @@ int TpcLaminationFitting::fitLaminations() { double phi = m_hLamination[l][s]->GetYaxis()->GetBinCenter(j); - if (fabs(phi - m_laminationCenter[l][s]) > 0.05) + if (fabs(phi - m_laminationIdeal[l][s]) > 0.05) { continue; } @@ -485,6 +634,7 @@ int TpcLaminationFitting::fitLaminations() double distToFunc = 0.0; int nBinsUsed = 0; + int nBinsUsed_R_lt_45 = 0; for (int i = 1; i <= m_hLamination[l][s]->GetNbinsX(); i++) { @@ -510,6 +660,10 @@ int TpcLaminationFitting::fitLaminations() { distToFunc += j; nBinsUsed++; + if(R < 45.0) + { + nBinsUsed_R_lt_45++; + } break; } } @@ -517,7 +671,7 @@ int TpcLaminationFitting::fitLaminations() m_distanceToFit[l][s] = distToFunc / nBinsUsed; m_nBinsFit[l][s] = nBinsUsed; - if (nBinsUsed < 10 || distToFunc / nBinsUsed > 1.0) + if (nBinsUsed < 10 || distToFunc / nBinsUsed > 1.0 || nBinsUsed_R_lt_45 < 5) { m_laminationGoodFit[l][s] = false; } @@ -531,14 +685,8 @@ int TpcLaminationFitting::fitLaminations() return Fun4AllReturnCodes::EVENT_OK; } -int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) +int TpcLaminationFitting::InterpolatePhiDistortions() { - phiDistortionLamination[0] = (TH2 *) simPhiDistortion[0]->Clone(); - phiDistortionLamination[0]->Reset(); - phiDistortionLamination[0]->SetName("phiDistortionLamination0"); - phiDistortionLamination[1] = (TH2 *) simPhiDistortion[1]->Clone(); - phiDistortionLamination[1]->Reset(); - phiDistortionLamination[1]->SetName("phiDistortionLamination1"); for (int s = 0; s < 2; s++) { @@ -566,51 +714,31 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) phi -= 2 * M_PI; } int phiBin = phiDistortionLamination[s]->GetXaxis()->FindBin(phi); - //m_fLamination[l][s]->SetParameter(0, m_fLamination[l][s]->GetParameter(0) - m_laminationCenter[l][s]); - m_fLamination[l][s]->SetParameter(3, m_laminationOffset[l][s]); - /* - if(s==0) - { - m_fLamination[l][s]->SetParameter(3, 0.0); - } + if(m_fieldOff) + { + m_fLamination[l][s]->SetParameter(1, 0.0); + } else - { - m_fLamination[l][s]->SetParameter(3, 0.0); - } - */ - //m_fLamination[l][s]->SetParameter(3, 0.0); + { + //m_fLamination[l][s]->SetParameter(3, -1.0*m_laminationOffset[l][s]); + m_fLamination[l][s]->SetParameter(3, 0.0); + } double phiDistortion = R * m_fLamination[l][s]->Integral(phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i), phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1)) / (phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1) - phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i)); - //m_fLamination[l][s]->SetParameter(0, m_fLamination[l][s]->GetParameter(0) + m_laminationCenter[l][s]); - m_fLamination[l][s]->SetParameter(3, m_laminationCenter[l][s]); + if(m_fieldOff) + { + m_fLamination[l][s]->SetParameter(1, m_laminationIdeal[l][s]); + } + else + { + //m_fLamination[l][s]->SetParameter(3, m_laminationIdeal[l][s]); + m_fLamination[l][s]->SetParameter(3, m_laminationIdeal[l][s] + m_laminationOffset[l][s]); + } phiDistortionLamination[s]->SetBinContent(phiBin, i, phiDistortion); + m_dcc_out->m_hDPint[s]->SetBinContent(phiBin, i, phiDistortion); } } } - for (int s = 0; s < 2; s++) - { - m_dcc_out->m_hDPint[s] = (TH2 *) phiDistortionLamination[s]->Clone(); - m_dcc_out->m_hDPint[s]->SetName((boost::format("hIntDistortionP%s") %(s == 0 ? "_negz" : "_posz")).str().c_str()); - } - - /* - for(int s=0; s<2; s++) - { - for(int i=1; i<=m_dcc_out->m_hDPint[s]->GetNbinsX(); i++) - { - for(int j=1; j<=m_dcc_out->m_hDPint[s]->GetNbinsY(); j++) - { - if(phiDistortionLamination[s]->GetBinContent(i,j) != 0.0) - { - m_dcc_out->m_hDPint[s]->SetBinContent(i,j, phiDistortionLamination[s]->GetBinContent(i,j)); - } - } - } - } - */ - - // m_dcc_out->m_hDPint[0] = (TH2*)phiDistortionLamination[0]->Clone(); - // m_dcc_out->m_hDPint[1] = (TH2*)phiDistortionLamination[1]->Clone(); for (int s = 0; s < 2; s++) { @@ -629,17 +757,14 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) laminationPhiBins.push_back(j); } } - if (laminationPhiBins.size() > 1) { laminationPhiBins.push_back(laminationPhiBins[0]); } - for (int lamPair = 0; lamPair < (int) laminationPhiBins.size() - 1; lamPair++) { double dist0 = m_dcc_out->m_hDPint[s]->GetBinContent(laminationPhiBins[lamPair], i); double dist1 = m_dcc_out->m_hDPint[s]->GetBinContent(laminationPhiBins[lamPair + 1], i); - int nEmptyBins = laminationPhiBins[lamPair + 1] - laminationPhiBins[lamPair] - 1; if (laminationPhiBins[lamPair] > laminationPhiBins[lamPair + 1]) { @@ -650,7 +775,6 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) bool wrap = false; int wrapBin = -1; for (int j = 1; j <= nEmptyBins; j++) - // for(int j=+ 1; j m_dcc_out->m_hDPint[s]->GetNbinsX() - 1) { @@ -674,6 +798,141 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) return Fun4AllReturnCodes::EVENT_OK; } +int TpcLaminationFitting::doGlobalRMatching(int side) +{ + + std::vector distortedPhi; + TF1 *tmpLamFit = (TF1*)m_fLamination[0][side]->Clone(); + + if(m_fieldOff) + { + tmpLamFit->SetParameters(0.0, 0.0); + } + else + { + double meanA = 0.0; + double meanB = 0.0; + double meanC = 0.0; + double meanOffset = 0.0; + int nGoodFits = 0; + for(int l = 0; l < 18; l++) + { + if(!m_laminationGoodFit[l][side]) + { + continue; + } + meanA += m_fLamination[l][side]->GetParameter(0); + meanB += m_fLamination[l][side]->GetParameter(1); + meanC += m_fLamination[l][side]->GetParameter(2); + meanOffset += m_laminationOffset[l][side]; + nGoodFits++; + } + if(nGoodFits == 0) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + meanA /= nGoodFits; + meanB /= nGoodFits; + meanC /= nGoodFits; + meanOffset /= nGoodFits; + //tmpLamFit->SetParameters(meanA, meanB, meanC, meanOffset); + tmpLamFit->SetParameters(meanA, meanB, meanC, 0.0); + } + + + for(int i=0; i<(int)m_truthPhi[side].size(); i++) + { + double distortedPhiTmp = m_truthPhi[side][i] + tmpLamFit->Eval(m_truthR[side][i]); + while(distortedPhiTmp < m_phiModMin[side]) + { + distortedPhiTmp += M_PI / 9; + } + while(distortedPhiTmp > m_phiModMax[side]) + { + distortedPhiTmp -= M_PI / 9; + } + distortedPhi.push_back(distortedPhiTmp); + } + + double maxSum = 0.0; + double best_m = 0.0; + double best_b = 0.0; + int mStep = 0; + int bStep = 0; + for(double m = -0.02; m<=0.02; m+=0.001) + { + for(double b=-3.0; b<=3.0; b+=0.125) + { + double sum = 0.0; + for(int i=0; i<(int)m_truthR[side].size(); i++) + { + double distortedTruthR = (m_truthR[side][i] + b)/(1.0 - m); + int binR = m_hPetal[side]->GetYaxis()->FindBin(distortedTruthR); + int binPhi = m_hPetal[side]->GetXaxis()->FindBin(distortedPhi[i]); + for(int j=-2; j<=2; j++) + { + int neighborBinR = binR + j; + if(neighborBinR < 1 || neighborBinR > m_hPetal[side]->GetNbinsY()) continue; + for(int k=-5; k<=5; k++) + { + int neighborBinPhi = binPhi + k; + if(neighborBinPhi < 1) + { + neighborBinPhi += m_hPetal[side]->GetNbinsX(); + } + if(neighborBinPhi > m_hPetal[side]->GetNbinsX()) + { + neighborBinPhi -= m_hPetal[side]->GetNbinsX(); + } + sum += m_hPetal[side]->GetBinContent(neighborBinPhi, neighborBinR); + } + } + } + std::cout << "working on side " << side << " m step " << mStep << " b step " << bStep << " with m = " << m << " and b = " << b << " with sum = " << sum << std::endl; + + m_parameterScan[side]->Fill(m, b, sum); + + if(sum > maxSum) + { + maxSum = sum; + best_m = m; + best_b = b; + } + bStep++; + } + mStep++; + } + + std::cout << "Best R distortion for side " << side << " is m = " << best_m << " and b = " << best_b << " with sum of " << maxSum << std::endl; + + for(int j=2; j<=m_dcc_out->m_hDRint[side]->GetNbinsX()-1; j++) + { + for(int i=2; i<=m_dcc_out->m_hDRint[side]->GetNbinsY()-1; i++) + { + double R = m_dcc_out->m_hDRint[side]->GetYaxis()->GetBinCenter(i); + double distortionR = R * best_m + best_b; + m_dcc_out->m_hDRint[side]->SetBinContent(j, i, distortionR); + } + } + + std::vector bestDistortedR; + for(int i=0; i<(int)m_truthR[side].size(); i++) + { + double distortedR = (m_truthR[side][i] + best_b)/(1.0 - best_m); + bestDistortedR.push_back(distortedR); + } + + m_bestRMatch[side] = new TGraph(distortedPhi.size(), &distortedPhi[0], &bestDistortedR[0]); + m_bestRMatch[side]->SetTitle((boost::format("Best R matching TPC %s, m = %.3f b = %.3f") %(side == 0 ? "South" : "North") %best_m %best_b).str().c_str()); + m_bestRMatch[side]->SetName((boost::format("bestRMatch_side%d") %side).str().c_str()); + m_bestRMatch[side]->SetMarkerStyle(25); + m_bestRMatch[side]->SetMarkerSize(0.8); + m_bestRMatch[side]->SetMarkerColor(kRed); + + return Fun4AllReturnCodes::EVENT_OK; +} + int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) { @@ -735,19 +994,55 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } m_fLamination[l][s]->Draw("same"); - TLine *line = new TLine(30,m_laminationCenter[l][s],80,m_laminationCenter[l][s]); - line->SetLineColor(kBlue); - line->SetLineStyle(2); - line->Draw("same"); + TLegend *leg = new TLegend(0.15,0.15,0.45,0.4); + + TLine *lineIdeal; + TLine *lineOffset; + if(m_fieldOff) + { + lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); + lineIdeal->SetLineColor(kBlue); + leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); + } + else + { + lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); + lineIdeal->SetLineColor(kBlue); + leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); + + lineOffset = new TLine(30,m_laminationIdeal[l][s]+m_laminationOffset[l][s],80,m_laminationIdeal[l][s]+m_laminationOffset[l][s]); + lineOffset->SetLineColor(kGreen+2); + lineOffset->SetLineStyle(2); + leg->AddEntry(lineOffset,Form("#phi_{ideal}+#phi_{offset}=%.6f",m_laminationOffset[l][s]), "l"); + lineOffset->Draw("same"); + } + lineIdeal->Draw("same"); + + leg->Draw("same"); + + TPaveText *pars = new TPaveText(0.6, 0.55, 0.85, 0.85, "NDC"); - pars->AddText("#phi = #phi_{ideal} + A#times (1 - e^{-C#times (R - B)})"); - pars->AddText((boost::format("A=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); - pars->AddText((boost::format("#phi_{ideal}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(3) %m_fLamination[l][s]->GetParError(3)).str().c_str()); - pars->AddText((boost::format("B=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(1) %m_fLamination[l][s]->GetParError(1)).str().c_str()); - pars->AddText((boost::format("C=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(2) %m_fLamination[l][s]->GetParError(2)).str().c_str()); - pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); - pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); + if(m_fieldOff) + { + pars->AddText("#phi = #phi_{ideal} + #phi_{offset}"); + pars->AddText((boost::format("#phi_{ideal}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(1) %m_fLamination[l][s]->GetParError(1)).str().c_str()); + pars->AddText((boost::format("#phi_{offset}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); + pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); + pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); + } + else + { + pars->AddText("#phi = #phi_{ideal} + A#times (1 - e^{-C#times (R - B)})"); + pars->AddText((boost::format("A=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); + //pars->AddText((boost::format("#phi_{ideal}=%.3f#pm 0.000") %m_laminationIdeal[l][s]).str().c_str()); + pars->AddText((boost::format("#phi_{nominal}=%.3f#pm 0.000") %(m_laminationIdeal[l][s]+m_laminationOffset[l][s])).str().c_str()); + //pars->AddText((boost::format("#phi_{offset}=%.3f#pm 0.000") %m_laminationOffset[l][s]).str().c_str()); + pars->AddText((boost::format("B=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(1) %m_fLamination[l][s]->GetParError(1)).str().c_str()); + pars->AddText((boost::format("C=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(2) %m_fLamination[l][s]->GetParError(2)).str().c_str()); + pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); + pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); + } pars->Draw("same"); c1->SaveAs(m_QAFileName.c_str()); } @@ -755,22 +1050,23 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) c1->SaveAs((boost::format("%s]") %m_QAFileName).str().c_str()); } - TFile *simDistortion = new TFile("/cvmfs/sphenix.sdcc.bnl.gov/gcc-12.1.0/release/release_new/new.10/share/calibrations/distortion_maps/average_minus_static_distortion_inverted_10-new.root", "READ"); - TH3 *hIntDistortionP_posz = (TH3 *) simDistortion->Get("hIntDistortionP_posz"); - hIntDistortionP_posz->GetZaxis()->SetRange(2, 2); - TH2 *simPhiDistortion[2]; - simPhiDistortion[1] = (TH2 *) hIntDistortionP_posz->Project3D("yx"); - TH3 *hIntDistortionP_negz = (TH3 *) simDistortion->Get("hIntDistortionP_negz"); - hIntDistortionP_negz->GetZaxis()->SetRange(hIntDistortionP_negz->GetNbinsZ() - 1, hIntDistortionP_negz->GetNbinsZ() - 1); - simPhiDistortion[0] = (TH2 *) hIntDistortionP_negz->Project3D("yx"); - - int interpolateSuccess = InterpolatePhiDistortions(simPhiDistortion); + //TFile *simDistortion = new TFile("/cvmfs/sphenix.sdcc.bnl.gov/gcc-12.1.0/release/release_new/new.10/share/calibrations/distortion_maps/average_minus_static_distortion_inverted_10-new.root", "READ"); + //TH3 *hIntDistortionP_posz = (TH3 *) simDistortion->Get("hIntDistortionP_posz"); + //hIntDistortionP_posz->GetZaxis()->SetRange(2, 2); + //TH2 *simPhiDistortion[2]; + //simPhiDistortion[1] = (TH2 *) hIntDistortionP_posz->Project3D("yx"); + //TH3 *hIntDistortionP_negz = (TH3 *) simDistortion->Get("hIntDistortionP_negz"); + //hIntDistortionP_negz->GetZaxis()->SetRange(hIntDistortionP_negz->GetNbinsZ() - 1, hIntDistortionP_negz->GetNbinsZ() - 1); + //simPhiDistortion[0] = (TH2 *) hIntDistortionP_negz->Project3D("yx"); + + int interpolateSuccess = InterpolatePhiDistortions(); if (interpolateSuccess != Fun4AllReturnCodes::EVENT_OK) { std::cout << PHWHERE << " Return code for lamination interpolation was " << interpolateSuccess << " and not successful" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } + /* for (int s = 0; s < 2; s++) { scaleFactorMap[s] = (TH2 *) m_dcc_out->m_hDPint[s]->Clone(); @@ -785,9 +1081,18 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) TH3 *hIntDistortionR_negz = (TH3 *) simDistortion->Get("hIntDistortionR_negz"); hIntDistortionR_negz->GetZaxis()->SetRange(hIntDistortionR_negz->GetNbinsZ() - 1, hIntDistortionR_negz->GetNbinsZ() - 1); simRDistortion[0] = (TH2 *) hIntDistortionR_negz->Project3D("yx"); + */ + + for (int s = 0; s < 2; s++) { + int RMatchingSuccess = doGlobalRMatching(s); + if (RMatchingSuccess != Fun4AllReturnCodes::EVENT_OK) + { + std::cout << PHWHERE << " Return code for doGlobalRMatching was " << RMatchingSuccess << " and not successful" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } /* for(int i=1; i<=m_dcc_out->m_hDRint[s]->GetNbinsX(); i++) { @@ -800,10 +1105,11 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } } */ - m_dcc_out->m_hDRint[s] = (TH2 *) simRDistortion[s]->Clone(); - m_dcc_out->m_hDRint[s]->SetName((boost::format("hIntDistortionR%s") %(s == 0 ? "_negz" : "_posz")).str().c_str()); - m_dcc_out->m_hDRint[s]->Multiply(scaleFactorMap[s]); + //m_dcc_out->m_hDRint[s] = (TH2 *) simRDistortion[s]->Clone(); + //m_dcc_out->m_hDRint[s]->SetName((boost::format("hIntDistortionR%s") %(s == 0 ? "_negz" : "_posz")).str().c_str()); + //m_dcc_out->m_hDRint[s]->Multiply(scaleFactorMap[s]); } + fill_guarding_bins(m_dcc_out); @@ -815,14 +1121,27 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) { m_side = s; m_lamIndex = s*18 + l; - m_lamPhi = m_laminationCenter[l][s]; + m_lamPhi = m_laminationIdeal[l][s]; + m_lamShift = m_laminationOffset[l][s]; m_goodFit = m_laminationGoodFit[l][s]; - m_A = m_fLamination[l][s]->GetParameter(0); - m_B = m_fLamination[l][s]->GetParameter(1); - m_C = m_fLamination[l][s]->GetParameter(2); - m_A_err = m_fLamination[l][s]->GetParError(0); - m_B_err = m_fLamination[l][s]->GetParError(1); - m_C_err = m_fLamination[l][s]->GetParError(2); + if(m_fieldOff) + { + m_A = m_fLamination[l][s]->GetParameter(0); + m_A_err = m_fLamination[l][s]->GetParError(0); + m_B = -999; + m_B_err = -999; + m_C = -999; + m_C_err = -999; + } + else + { + m_A = m_fLamination[l][s]->GetParameter(0); + m_B = m_fLamination[l][s]->GetParameter(1); + m_C = m_fLamination[l][s]->GetParameter(2); + m_A_err = m_fLamination[l][s]->GetParError(0); + m_B_err = m_fLamination[l][s]->GetParError(1); + m_C_err = m_fLamination[l][s]->GetParError(2); + } m_dist = m_distanceToFit[l][s]; m_nBins = m_nBinsFit[l][s]; m_laminationTree->Fill(); @@ -841,7 +1160,10 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } } phiDistortionLamination[s]->Write(); - scaleFactorMap[s]->Write(); + //scaleFactorMap[s]->Write(); + m_hPetal[s]->Write(); + m_bestRMatch[s]->Write(); + m_parameterScan[s]->Write(); } m_laminationTree->Write(); @@ -860,7 +1182,7 @@ void TpcLaminationFitting::fill_guarding_bins(TpcDistortionCorrectionContainer * { for (int s = 0; s < 2; s++) { - for (const auto &h : {dcc->m_hDRint[s], dcc->m_hDPint[s]}) + for (const auto &h : {dcc->m_hDPint[s], dcc->m_hDRint[s]}) { const auto phibins = h->GetNbinsX(); const auto rbins = h->GetNbinsY(); diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 73d77533d3..a44160ca02 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -44,7 +44,9 @@ class TpcLaminationFitting : public SubsysReco } void set_ppMode(bool mode){ ppMode = mode; } - + + void set_fieldOff(bool fieldOff){ m_fieldOff = fieldOff; } + void set_grid_dimensions(int phibins, int rbins); void set_nLayerCut(unsigned int cut) { m_nLayerCut = cut; } @@ -61,7 +63,8 @@ class TpcLaminationFitting : public SubsysReco int GetNodes(PHCompositeNode *topNode); int fitLaminations(); - int InterpolatePhiDistortions(TH2 *simPhiDistortion[2]); + int InterpolatePhiDistortions(); + int doGlobalRMatching(int side); void fill_guarding_bins(TpcDistortionCorrectionContainer *dcc); TpcDistortionCorrection m_distortionCorrection; @@ -78,12 +81,20 @@ class TpcLaminationFitting : public SubsysReco TH2 *m_hLamination[18][2]{{nullptr}}; TF1 *m_fLamination[18][2]{{nullptr}}; - double m_laminationCenter[18][2]{{0.0}}; + double m_laminationIdeal[18][2]{{0.0}}; + //double m_laminationCenter[18][2]{{0.0}}; double m_laminationOffset[18][2]{{0.0}}; + //double m_laminationOffset{0.00337078}; + //double m_laminationOffset{0.002775}; bool m_laminationGoodFit[18][2]{{false}}; double m_distanceToFit[18][2]{{0.0}}; int m_nBinsFit[18][2]{{0}}; + TH2 *m_hPetal[2]{nullptr}; + TGraph *m_bestRMatch[2]{nullptr}; + TH2 *m_parameterScan[2]{nullptr}; + + TH2 *phiDistortionLamination[2]{nullptr}; TH2 *scaleFactorMap[2]{nullptr}; @@ -103,10 +114,13 @@ class TpcLaminationFitting : public SubsysReco //std::map m_run_ZDC_map_pp; //std::map m_run_ZDC_map_auau; + bool m_fieldOff{false}; + TTree *m_laminationTree{nullptr}; bool m_side{false}; int m_lamIndex{0}; double m_lamPhi{0}; + double m_lamShift{0}; bool m_goodFit{false}; double m_A{0}; double m_B{0}; @@ -117,13 +131,35 @@ class TpcLaminationFitting : public SubsysReco double m_dist{0}; int m_nBins{0}; - int m_phibins{24}; + int m_phibins{80}; static constexpr float m_phiMin{0}; static constexpr float m_phiMax{2. * M_PI}; - int m_rbins{12}; + int m_rbins{52}; static constexpr float m_rMin{20}; // cm static constexpr float m_rMax{80}; // cm + + /* + const int nRadii{8}; + const int nStripes[4]{6,6,8,12}; + const int nPads[4]{96,96,128,192}; + const double RValues[4][8] = {{22.70902789, 23.84100043, 24.97297296, 26.1049455, 27.23691804, 28.36889058, 29.50086312, 30.63283566},{31.7648082, 32.89678074, 34.02875328, 35.16072582, 36.29269836, 37.4246709, 38.55664344, 39.68861597},{42.1705532, 44.2119258, 46.2532984, 48.29467608, 50.336069, 52.3774416, 54.4188015, 56.4601868},{59.46048725, 61.6545823, 63.84867738, 66.04277246, 68.23686754, 70.43096262, 72.6250577, 74.81915277}}; + + const int keepThisAndAfter[8]{1,0,1,0,1,0,1,0}; + const int keepUntil[4][8]{{4,4,5,4,5,5,5,5},{5,5,6,5,6,5,6,5},{7,7,8,7,8,8,8,8},{11,10,11,11,11,11,12,11}}; + + const double phi_petal = M_PI/6.0; + const int pr_mult = 3; + const int dw_mult = 8; + const double diffwidth = 0.06; + const double adjust = 0.015; + */ + + std::vector m_truthR[2]; + std::vector m_truthPhi[2]; + + double m_phiModMin[2]{-M_PI/18, 0.0}; + double m_phiModMax[2]{M_PI/18, M_PI/9}; }; #endif From 67423a3fe8df962d45028aaf31bd5fb99066a974 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 6 Jan 2026 15:17:57 -0500 Subject: [PATCH 007/866] clang-format --- offline/packages/trackreco/PHActsTrkFitter.cc | 299 +++++++++--------- offline/packages/trackreco/PHActsTrkFitter.h | 39 ++- 2 files changed, 176 insertions(+), 162 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index a26ee1fa0a..f66767d305 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 @@ -134,8 +133,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 +181,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) { @@ -287,7 +286,7 @@ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) { m_evaluator->End(); } - if(m_useOutlierFinder) + if (m_useOutlierFinder) { m_outlierFinder.Write(); } @@ -314,44 +313,43 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) // capture the input crossing value, and set crossing parameters //============================== - short silicon_crossing = SHRT_MAX; + short silicon_crossing = SHRT_MAX; auto siseed = m_siliconSeeds->get(siid); - if(siseed) - { - silicon_crossing = siseed->get_crossing(); - } + 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); @@ -381,7 +379,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 +388,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 +439,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 +457,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 +514,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 +526,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 +561,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 +596,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 +621,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 +637,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 +661,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 +672,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 +727,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 +767,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 +812,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 +827,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 +841,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(); @@ -855,10 +856,10 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } 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 +873,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) { @@ -948,7 +949,9 @@ 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); @@ -986,9 +989,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; } @@ -1059,10 +1062,10 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const } 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 +1136,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(); diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index c6e0afec35..d0e221a40e 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include @@ -130,18 +130,19 @@ class PHActsTrkFitter : public SubsysReco 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; } - void set_svtx_alignment_state_map_name(const std::string& map_name) { - _svtx_alignment_state_map_name = map_name; - m_alignStates.alignmentStateMap(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 flag for pp running 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_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 setTrkrClusterContainerName(std::string& name) { m_clusterContainerName = name; } void setDirectNavigation(bool flag) { m_directNavigation = flag; } private: @@ -155,10 +156,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 @@ -240,7 +241,7 @@ class PHActsTrkFitter : public SubsysReco // 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 +254,7 @@ class PHActsTrkFitter : public SubsysReco //@} //! tracks -// SvtxTrackMap* m_seedTracks = nullptr; + // SvtxTrackMap* m_seedTracks = nullptr; //! tpc global position wrapper TpcGlobalPositionWrapper m_globalPositionWrapper; @@ -268,7 +269,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 +293,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); } } From 014600afcfdbfe9b29cefb45d37aaddde106f174 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Tue, 6 Jan 2026 16:06:00 -0500 Subject: [PATCH 008/866] adding quality flag to total energy calc and correlations --- offline/QA/Calorimeters/CaloValid.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index bef0cf3809..8575c565b9 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -330,7 +330,10 @@ 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) { @@ -402,7 +405,10 @@ 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) @@ -467,7 +473,10 @@ 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) From 2a654bd1530246ac915364ec030134ee9363cfa4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 6 Jan 2026 16:14:48 -0500 Subject: [PATCH 009/866] clang-tidy for PHGenFit --- .../packages/PHGenFitPkg/PHGenFit/Fitter.cc | 24 ++++----- .../packages/PHGenFitPkg/PHGenFit/Track.cc | 50 ++++++++----------- 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc index 8fe89b5019..127af3539e 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc @@ -51,9 +51,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 +73,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(); } @@ -289,19 +287,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); } diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Track.cc b/offline/packages/PHGenFitPkg/PHGenFit/Track.cc index b1643e8cd0..0e06f15984 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 @@ -60,11 +60,10 @@ ofstream fout_matrix("matrix.txt"); namespace PHGenFit { 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); @@ -78,12 +77,12 @@ namespace PHGenFit } 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(); } int Track::addMeasurement(PHGenFit::Measurement* measurement) @@ -191,10 +190,8 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } double Track::extrapolateToLine(genfit::MeasuredStateOnPlane& state, const TVector3& line_point, const TVector3& line_direction, const int tr_point_id) const @@ -240,10 +237,8 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } 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 @@ -361,10 +356,8 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } int Track::updateOneMeasurementKalman( @@ -385,7 +378,7 @@ namespace PHGenFit << std::endl; #endif - if (measurements.size() == 0) + if (measurements.empty()) { return -1; } @@ -437,11 +430,11 @@ namespace PHGenFit #endif continue; } - //#ifdef _DEBUG_ + // #ifdef _DEBUG_ // std::cout << __LINE__ << "\n ###################################################################"<Print(); // std::cout << __LINE__ << "\n ###################################################################"<getFittedState(true)); @@ -579,7 +572,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 +591,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(); @@ -769,10 +762,7 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + return state; } double Track::get_chi2() const From 3e9477772211f43dff6202bba49303d9ef0e7254 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Tue, 6 Jan 2026 16:29:08 -0500 Subject: [PATCH 010/866] appeasing the rabbit --- offline/QA/Calorimeters/CaloValid.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 8575c565b9..52707a05cc 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -405,7 +405,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - if(isGood) + if (isGood) { totalihcal += offlineenergy; } @@ -473,7 +473,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - if(isGood) + if (isGood) { totalohcal += offlineenergy; } From 667a5cc7bf9431851db82eea27e80063aafc0e64 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 6 Jan 2026 16:34:15 -0500 Subject: [PATCH 011/866] clang-tidy for mvtx --- offline/packages/mvtx/CylinderGeom_Mvtx.cc | 32 ++-- offline/packages/mvtx/CylinderGeom_Mvtx.h | 10 +- offline/packages/mvtx/MvtxClusterPruner.cc | 178 ++++++++++---------- offline/packages/mvtx/MvtxClusterizer.cc | 133 +++++++-------- offline/packages/mvtx/MvtxClusterizer.h | 4 +- offline/packages/mvtx/MvtxHitPruner.cc | 14 +- offline/packages/mvtx/SegmentationAlpide.cc | 9 +- 7 files changed, 184 insertions(+), 196 deletions(-) diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.cc b/offline/packages/mvtx/CylinderGeom_Mvtx.cc index e220d1474d..ab22c80bdc 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.cc +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.cc @@ -8,7 +8,6 @@ #include #include // for operator<<, basic_ostream::operator<<, basic_... -using namespace std; using Segmentation = SegmentationAlpide; CylinderGeom_Mvtx::CylinderGeom_Mvtx( @@ -89,7 +88,7 @@ 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; @@ -102,15 +101,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; @@ -122,21 +121,22 @@ bool CylinderGeom_Mvtx::get_pixel_from_local_coords(TVector3 sensor_local, int& 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 @@ -157,8 +157,8 @@ TVector3 CylinderGeom_Mvtx::get_local_coords_from_pixel(int iRow, int iCol) 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], @@ -177,7 +177,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; } @@ -192,17 +192,17 @@ int CylinderGeom_Mvtx::get_NX() const return SegmentationAlpide::NRows; } -int CylinderGeom_Mvtx::get_pixel_X_from_pixel_number(int NXZ) +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) +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 +int CylinderGeom_Mvtx::get_pixel_number_from_xbin_zbin(int xbin, int zbin) const // obsolete { return xbin + zbin * get_NX(); } diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.h b/offline/packages/mvtx/CylinderGeom_Mvtx.h index e28da2c594..047673a549 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.h +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.h @@ -13,7 +13,7 @@ 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 +31,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 +53,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; } diff --git a/offline/packages/mvtx/MvtxClusterPruner.cc b/offline/packages/mvtx/MvtxClusterPruner.cc index 24d41db63d..456b302dd9 100644 --- a/offline/packages/mvtx/MvtxClusterPruner.cc +++ b/offline/packages/mvtx/MvtxClusterPruner.cc @@ -12,108 +12,116 @@ #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: + explicit 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: T m_range; }; // print cluster information - void print_cluster_information( TrkrDefs::cluskey ckey, TrkrCluster* cluster ) + 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) +MvtxClusterPruner::MvtxClusterPruner(const std::string& name) : SubsysReco(name) { } //_____________________________________________________________________________ -int MvtxClusterPruner::InitRun(PHCompositeNode * /*topNode*/) +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) +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 +133,109 @@ 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*/) +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; } diff --git a/offline/packages/mvtx/MvtxClusterizer.cc b/offline/packages/mvtx/MvtxClusterizer.cc index 7970b369eb..eb54930acd 100644 --- a/offline/packages/mvtx/MvtxClusterizer.cc +++ b/offline/packages/mvtx/MvtxClusterizer.cc @@ -63,7 +63,7 @@ namespace /// convenience square method template - inline constexpr T square(const T &x) + constexpr T square(const T &x) { return x * x; } @@ -71,65 +71,45 @@ namespace 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) && + // 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 { - - 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) +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) && + // 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); - - } 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); } MvtxClusterizer::MvtxClusterizer(const std::string &name) @@ -165,7 +145,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 +163,7 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { @@ -208,14 +188,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,13 +207,13 @@ 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; @@ -283,7 +263,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); @@ -337,8 +317,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 +374,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 +385,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 +393,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 +407,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 +555,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 +586,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) } } // clusitr loop - } // loop over hitsets + } // loop over hitsets if (Verbosity() > 1) { @@ -650,8 +631,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 +676,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 +690,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 +712,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 +826,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 +856,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); } } // clusitr loop - } // loop over hitsets + } // loop over hitsets if (Verbosity() > 1) { @@ -898,11 +879,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,8 +891,8 @@ void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode) } std::cout << "==================================================================" - "=========" - << std::endl; + "=========" + << std::endl; } return; diff --git a/offline/packages/mvtx/MvtxClusterizer.h b/offline/packages/mvtx/MvtxClusterizer.h index ce4794b5d1..10c65914cd 100644 --- a/offline/packages/mvtx/MvtxClusterizer.h +++ b/offline/packages/mvtx/MvtxClusterizer.h @@ -65,8 +65,8 @@ class MvtxClusterizer : public SubsysReco private: // bool are_adjacent(const pixel lhs, const pixel rhs); bool record_ClusHitsVerbose{false}; - bool are_adjacent(const std::pair &lhs, const std::pair &rhs); - bool are_adjacent(RawHit *lhs, RawHit *rhs); + bool are_adjacent(const std::pair &lhs, const std::pair &rhs) const; + bool are_adjacent(RawHit *lhs, RawHit *rhs) const; void ClusterMvtx(PHCompositeNode *topNode); void ClusterMvtxRaw(PHCompositeNode *topNode); diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index 4f141a4c3f..d4395b6f4a 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -54,7 +54,7 @@ namespace template class range_adaptor { public: - range_adaptor( const T& range ):m_range(range){} + explicit 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: @@ -98,7 +98,8 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) // 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,7 +118,7 @@ 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 @@ -131,7 +132,8 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) 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()) { @@ -143,7 +145,7 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) } // copy all hits to the hitset with strobe 0 - auto hitset = m_hits->findHitSet(hitsetkey); + auto *hitset = m_hits->findHitSet(hitsetkey); if (Verbosity()) { @@ -181,7 +183,7 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) << hitkey << std::endl; } - auto new_hit = new TrkrHitv2; + auto *new_hit = new TrkrHitv2; new_hit->CopyFrom(old_hit); bare_hitset->addHitSpecificKey(hitkey, new_hit); } diff --git a/offline/packages/mvtx/SegmentationAlpide.cc b/offline/packages/mvtx/SegmentationAlpide.cc index 6b9aecddd0..0b1aae48cf 100644 --- a/offline/packages/mvtx/SegmentationAlpide.cc +++ b/offline/packages/mvtx/SegmentationAlpide.cc @@ -5,16 +5,15 @@ */ #include "SegmentationAlpide.h" -#include - #include +#include 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; } From 45a8c5b431b3774a7e229368f91d7e8f537d26bb Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 6 Jan 2026 18:15:18 -0500 Subject: [PATCH 012/866] clang-tidy for tpc --- offline/packages/tpc/LaserClusterizer.cc | 680 ++++++++---------- offline/packages/tpc/LaserEventIdentifier.cc | 2 +- offline/packages/tpc/Tpc3DClusterizer.cc | 385 ++++++---- offline/packages/tpc/TpcClusterMover.cc | 20 +- offline/packages/tpc/TpcClusterMover.h | 2 +- offline/packages/tpc/TpcClusterizer.cc | 103 +-- .../tpc/TpcCombinedRawDataUnpacker.cc | 4 +- .../tpc/TpcCombinedRawDataUnpackerDebug.cc | 20 +- .../packages/tpc/TpcDistortionCorrection.cc | 2 +- .../tpc/TpcLoadDistortionCorrection.cc | 8 +- offline/packages/tpc/TpcRawDataTree.cc | 2 +- offline/packages/tpc/TpcRawWriter.cc | 8 +- offline/packages/tpc/TpcSimpleClusterizer.cc | 37 +- offline/packages/tpc/TrainingHits.cc | 18 +- 14 files changed, 635 insertions(+), 656 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 170f95944d..84e0477caa 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,25 @@ 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) - }; - + 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) + 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,28 +123,26 @@ namespace } return 0.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); } 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; } void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey) @@ -160,21 +150,22 @@ namespace 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 +174,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 +191,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 +205,15 @@ namespace } } regions.push_back(region); - } clusHits.clear(); - for(auto hit : regions[0]) + for (auto hit : regions[0]) { clusHits.push_back(hit); } - } - void remove_hits(std::vector &clusHits, bgi::rtree> &rtree, std::multimap &adcMap) { for (auto &clusHit : clusHits) @@ -237,51 +224,44 @@ 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; } } - } 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 +273,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 +385,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 +396,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 +426,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 +445,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 +491,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 +525,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 +536,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 +554,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 +585,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 +629,18 @@ 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; } - - } - void ProcessModuleData(thread_data *my_data) { - if (my_data->Verbosity > 2) { pthread_mutex_lock(&mythreadlock); @@ -693,85 +652,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,17 +739,16 @@ namespace calc_cluster_parameter(clusHits, *my_data, iterKey->second.second); remove_hits(clusHits, rtree, adcMap); - } } void *ProcessModule(void *threadarg) { - auto my_data = static_cast(threadarg); + auto *my_data = static_cast(threadarg); ProcessModuleData(my_data); pthread_exit(nullptr); } -} //namespace +} // namespace LaserClusterizer::LaserClusterizer(const std::string &name) : SubsysReco(name) @@ -818,7 +775,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 +792,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) @@ -873,7 +830,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 +854,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 +878,9 @@ 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 +896,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 +1024,4 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; - } diff --git a/offline/packages/tpc/LaserEventIdentifier.cc b/offline/packages/tpc/LaserEventIdentifier.cc index 8b6035db05..5968d2f09f 100644 --- a/offline/packages/tpc/LaserEventIdentifier.cc +++ b/offline/packages/tpc/LaserEventIdentifier.cc @@ -130,7 +130,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); diff --git a/offline/packages/tpc/Tpc3DClusterizer.cc b/offline/packages/tpc/Tpc3DClusterizer.cc index e19cbf507f..562231b71b 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.cc +++ b/offline/packages/tpc/Tpc3DClusterizer.cc @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -72,7 +73,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 +112,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) @@ -145,10 +147,13 @@ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) 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 +168,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 +199,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 +209,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 +264,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 +387,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 +441,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 +469,33 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -int Tpc3DClusterizer::ResetEvent(PHCompositeNode * /*topNode*/){ +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; } 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(); @@ -434,7 +505,7 @@ int Tpc3DClusterizer::End(PHCompositeNode * /*topNode*/) 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 +520,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 +542,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 +596,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,55 +628,57 @@ 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); + // } } void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rtree> &rtree, std::multimap, std::array>> &adcMap) @@ -611,10 +687,11 @@ void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rt { 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 +700,8 @@ void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rt iterAdc = adcMap.erase(iterAdc); break; } - else - { - ++iterAdc; - } + + ++iterAdc; } } } diff --git a/offline/packages/tpc/TpcClusterMover.cc b/offline/packages/tpc/TpcClusterMover.cc index 643fe5587f..39c5e156d4 100644 --- a/offline/packages/tpc/TpcClusterMover.cc +++ b/offline/packages/tpc/TpcClusterMover.cc @@ -17,19 +17,20 @@ namespace { - [[maybe_unused]] std::ostream& operator << (std::ostream& out, const Acts::Vector3& v ) + [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector3& v) { out << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")"; return out; } -} +} // namespace 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 +45,7 @@ TpcClusterMover::TpcClusterMover() } } -void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer *cellgeo) +void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer* cellgeo) { if (_verbosity > 0) { @@ -65,7 +66,6 @@ void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer *cellgeo) //____________________________________________________________________________.. 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 +74,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 +85,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 +158,7 @@ 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) +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); diff --git a/offline/packages/tpc/TpcClusterMover.h b/offline/packages/tpc/TpcClusterMover.h index dc67312f7f..92a053e990 100644 --- a/offline/packages/tpc/TpcClusterMover.h +++ b/offline/packages/tpc/TpcClusterMover.h @@ -27,7 +27,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; diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index bd5fc3c340..05fb1fe121 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,7 @@ namespace { template - inline constexpr T square(const T &x) + constexpr T square(const T &x) { return x * x; } @@ -365,20 +365,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)) { @@ -537,30 +531,15 @@ namespace continue; } - if (adc > max_adc) - { - max_adc = adc; - } + max_adc = std::max(adc, max_adc); - if (iphi > phibinhi) - { - phibinhi = iphi; - } + phibinhi = std::max(iphi, phibinhi); - if (iphi < phibinlo) - { - phibinlo = iphi; - } + phibinlo = std::min(iphi, phibinlo); - if (it > tbinhi) - { - tbinhi = it; - } + tbinhi = std::max(it, tbinhi); - if (it < tbinlo) - { - tbinlo = it; - } + tbinlo = std::min(it, tbinlo); // if(it==it_center){ yg_sum += adc; } // update phi sums @@ -686,7 +665,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 +717,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); } } @@ -875,7 +854,7 @@ namespace } if (adc > my_data->edge_threshold) { - adcval[phibin][tbin] = (unsigned short) adc; + adcval[phibin][tbin] = adc; } } } @@ -967,7 +946,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 +992,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; @@ -1077,7 +1044,7 @@ namespace } void *ProcessSector(void *threadarg) { - auto my_data = static_cast(threadarg); + auto *my_data = static_cast(threadarg); ProcessSectorData(my_data); pthread_exit(nullptr); } @@ -1133,7 +1100,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 +1118,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 +1135,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 +1184,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) { @@ -1489,18 +1456,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 +1591,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 +1635,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 +1643,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 +1665,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) { diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc index c194567d58..5f276c3c3a 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc @@ -57,7 +57,7 @@ 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 +75,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; diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc index 0bb412197f..803a822aa9 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 @@ -234,14 +235,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 +534,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 +692,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) diff --git a/offline/packages/tpc/TpcDistortionCorrection.cc b/offline/packages/tpc/TpcDistortionCorrection.cc index b759331e77..8974053b48 100644 --- a/offline/packages/tpc/TpcDistortionCorrection.cc +++ b/offline/packages/tpc/TpcDistortionCorrection.cc @@ -15,7 +15,7 @@ namespace { template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.cc b/offline/packages/tpc/TpcLoadDistortionCorrection.cc index 0ce2ffa4e1..65bf156a7a 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.cc +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.cc @@ -58,7 +58,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 +74,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; diff --git a/offline/packages/tpc/TpcRawDataTree.cc b/offline/packages/tpc/TpcRawDataTree.cc index 6199fb7425..1141b5de55 100644 --- a/offline/packages/tpc/TpcRawDataTree.cc +++ b/offline/packages/tpc/TpcRawDataTree.cc @@ -61,7 +61,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"); diff --git a/offline/packages/tpc/TpcRawWriter.cc b/offline/packages/tpc/TpcRawWriter.cc index 5d7711e2bb..41c5f26df3 100644 --- a/offline/packages/tpc/TpcRawWriter.cc +++ b/offline/packages/tpc/TpcRawWriter.cc @@ -76,7 +76,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 +94,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 +116,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 +124,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); } diff --git a/offline/packages/tpc/TpcSimpleClusterizer.cc b/offline/packages/tpc/TpcSimpleClusterizer.cc index f439d1d682..f1fb0d5b76 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,7 @@ namespace { template - inline constexpr T square(const T &x) + constexpr T square(const T &x) { return x * x; } @@ -142,22 +143,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 +194,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 @@ -280,7 +269,7 @@ namespace 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 +321,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()) @@ -413,7 +402,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 +420,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); @@ -614,7 +603,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); diff --git a/offline/packages/tpc/TrainingHits.cc b/offline/packages/tpc/TrainingHits.cc index 3a70db0854..20a810b225 100644 --- a/offline/packages/tpc/TrainingHits.cc +++ b/offline/packages/tpc/TrainingHits.cc @@ -1,17 +1,17 @@ #include "TrainingHits.h" 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; } void TrainingHits::Reset() From 1ba5701e07a88eaa3ecde2bf040490e06e24effb Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Dec 2025 20:18:53 -0500 Subject: [PATCH 013/866] Added sample to hit key. This will allow to use timed hits. --- offline/packages/micromegas/MicromegasDefs.cc | 17 +++++++++++++---- offline/packages/micromegas/MicromegasDefs.h | 8 ++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/offline/packages/micromegas/MicromegasDefs.cc b/offline/packages/micromegas/MicromegasDefs.cc index 0766d78b8e..78732951f7 100644 --- a/offline/packages/micromegas/MicromegasDefs.cc +++ b/offline/packages/micromegas/MicromegasDefs.cc @@ -30,6 +30,7 @@ namespace //! bit shift for hit key static constexpr unsigned int kBitShiftStrip = 0; + static constexpr unsigned int kBitShiftSample = 8; } @@ -65,19 +66,27 @@ namespace MicromegasDefs } //________________________________________________________________ - TrkrDefs::hitkey genHitKey(uint16_t strip) + TrkrDefs::hitkey genHitKey(uint16_t strip, uint16_t sample) { - TrkrDefs::hitkey key = strip << kBitShiftStrip; - return key; + const TrkrDefs::hitkey key = strip << kBitShiftStrip; + const TrkrDefs::hitkey tmp = sample << kBitShiftSample; + return key|tmp; } //________________________________________________________________ - uint16_t getStrip( TrkrDefs::hitkey key ) + uint8_t getStrip( TrkrDefs::hitkey key ) { TrkrDefs::hitkey tmp = (key >> kBitShiftStrip); return tmp; } + //________________________________________________________________ + uint16_t getSample( TrkrDefs::hitkey key ) + { + TrkrDefs::hitkey tmp = (key >> kBitShiftSample); + return tmp; + } + //________________________________________________________________ SegmentationType getSegmentationType(TrkrDefs::cluskey key) { diff --git a/offline/packages/micromegas/MicromegasDefs.h b/offline/packages/micromegas/MicromegasDefs.h index c95fdffd72..b206b8f895 100644 --- a/offline/packages/micromegas/MicromegasDefs.h +++ b/offline/packages/micromegas/MicromegasDefs.h @@ -60,11 +60,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 From 815ceef6091af9d078e45087f67a4a5b4fdd3205 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Dec 2025 22:23:29 -0500 Subject: [PATCH 014/866] Add sample to hit key --- .../MicromegasCombinedDataDecoder.cc | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc index a5269617f7..50bcb97cd6 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc @@ -203,13 +203,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 +221,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 +246,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 +255,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); 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 From d0a251d8b689ab4392265b30107b165fd32021d9 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Dec 2025 22:56:37 -0500 Subject: [PATCH 015/866] fixed comments --- offline/packages/micromegas/MicromegasCombinedDataDecoder.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h index 32eebc56e0..3789284f26 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h @@ -49,10 +49,10 @@ class MicromegasCombinedDataDecoder : public SubsysReco /** This removes faulty channels for which calibration has failed */ void set_min_adc(double value) { m_min_adc = value; } - /// set min sample for noise estimation + /// set min sample for signal hits void set_sample_min(uint16_t value) { m_sample_min = value; } - /// set min sample for noise estimation + /// set max sample for signal hits void set_sample_max(uint16_t value) { m_sample_max = value; } private: From 0f8adaa30c2faff52d68041b095452bae425a906 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Dec 2025 22:56:44 -0500 Subject: [PATCH 016/866] Sort hits by strip number if multiple hits are found on the same strip only the first one, timewise, is kept. --- .../micromegas/MicromegasClusterizer.cc | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/offline/packages/micromegas/MicromegasClusterizer.cc b/offline/packages/micromegas/MicromegasClusterizer.cc index c57d6ed3f5..a28ed156b6 100644 --- a/offline/packages/micromegas/MicromegasClusterizer.cc +++ b/offline/packages/micromegas/MicromegasClusterizer.cc @@ -157,8 +157,10 @@ 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; -}} + { + if(( geonode = findNode::getClass(topNode, geonodename.c_str()) )) + { break;} + } assert(geonode); // hitset container @@ -182,8 +184,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 +217,32 @@ 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: + 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 @@ -257,8 +274,7 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) } // store last cluster - if( begin != hit_range.second ) { ranges.push_back( std::make_pair( begin, hit_range.second ) ); -} + if( begin != local_hitmap.end() ) { ranges.push_back( std::make_pair( begin, local_hitmap.end() ) ); } // initialize cluster count int cluster_count = 0; From 49ff81c07d86cc01fbabbd9174b4a7c922fa86e4 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Dec 2025 23:36:50 -0500 Subject: [PATCH 017/866] default max sample is 1024 (full range) --- offline/packages/micromegas/MicromegasCombinedDataDecoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h index 3789284f26..33033f1992 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h @@ -85,7 +85,7 @@ 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; From 0c648ef39945d565c448104949e8fa09e3134ce8 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Dec 2025 23:37:12 -0500 Subject: [PATCH 018/866] implemented min and max sample range for selecting clusters. --- offline/QA/Tracking/MicromegasClusterQA.cc | 10 ++++++++++ offline/QA/Tracking/MicromegasClusterQA.h | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/offline/QA/Tracking/MicromegasClusterQA.cc b/offline/QA/Tracking/MicromegasClusterQA.cc index 41efeffaa7..6feb510c54 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.cc +++ b/offline/QA/Tracking/MicromegasClusterQA.cc @@ -73,6 +73,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()) { @@ -162,6 +165,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); diff --git a/offline/QA/Tracking/MicromegasClusterQA.h b/offline/QA/Tracking/MicromegasClusterQA.h index 338e5302de..d6de8344c4 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.h +++ b/offline/QA/Tracking/MicromegasClusterQA.h @@ -51,6 +51,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 +105,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 //@{ From 9e7cf18f915644e5ddeaffa3788646752b84595d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 6 Jan 2026 19:12:01 -0500 Subject: [PATCH 019/866] fix bad bug found by coderabbit --- offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc index 127af3539e..aeb01dee62 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc @@ -233,7 +233,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); } From 514cbf6da040c597ebcf629d6abae888b307001f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 6 Jan 2026 19:14:02 -0500 Subject: [PATCH 020/866] better performace according to code rabbit --- offline/packages/tpc/TpcDistortionCorrection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpc/TpcDistortionCorrection.cc b/offline/packages/tpc/TpcDistortionCorrection.cc index 8974053b48..71b9ea8b2f 100644 --- a/offline/packages/tpc/TpcDistortionCorrection.cc +++ b/offline/packages/tpc/TpcDistortionCorrection.cc @@ -15,7 +15,7 @@ namespace { template - constexpr T square(const T& x) + constexpr T square(const T x) { return x * x; } From 5c1fb73ad663c9c906fe52346fdd680f761c9353 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 6 Jan 2026 19:18:30 -0500 Subject: [PATCH 021/866] make coderabbit happy --- offline/packages/tpc/LaserClusterizer.cc | 1 - offline/packages/tpc/TpcClusterizer.cc | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 84e0477caa..754ee8d248 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -879,7 +879,6 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) } TrkrHitSetContainer::ConstRange hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId); - ; struct thread_pair_t { diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 05fb1fe121..4548bde728 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1206,13 +1206,13 @@ 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; From 3f3052247cb9dd147110341d056b36471b009495 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 6 Jan 2026 19:21:03 -0500 Subject: [PATCH 022/866] fix botched formatting --- offline/packages/mvtx/MvtxHitPruner.cc | 82 +++++++++++++++----------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index d4395b6f4a..58cbb423c4 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -51,26 +51,33 @@ namespace { //! range adaptor to be able to use range-based for loop - template class range_adaptor + template + class range_adaptor { - public: - explicit 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: + explicit 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: T m_range; }; -} +} // namespace -MvtxHitPruner::MvtxHitPruner(const std::string &name) +MvtxHitPruner::MvtxHitPruner(const std::string& name) : SubsysReco(name) { } -int MvtxHitPruner::InitRun(PHCompositeNode * /*topNode*/) -{ return Fun4AllReturnCodes::EVENT_OK; } +int MvtxHitPruner::InitRun(PHCompositeNode* /*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} -int MvtxHitPruner::process_event(PHCompositeNode *topNode) +int MvtxHitPruner::process_event(PHCompositeNode* topNode) { // get node containing the digitized hits m_hits = findNode::getClass(topNode, "TRKR_HITSET"); @@ -93,13 +100,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); @@ -118,44 +126,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()) { @@ -168,9 +178,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; } @@ -179,11 +189,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); } From 078517886c6a4a094cb5e34a04be0ba2408496fa Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 6 Jan 2026 21:00:52 -0500 Subject: [PATCH 023/866] clang-tidy --- offline/packages/trackreco/PHActsTrkFitter.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index f66767d305..2ca1426301 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -314,7 +314,7 @@ 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); + auto *siseed = m_siliconSeeds->get(siid); if (siseed) { silicon_crossing = siseed->get_crossing(); @@ -352,7 +352,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } } - 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) From e06322f2d50ad00157f219c6871c0deed0c6d7d4 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 6 Jan 2026 23:01:50 -0500 Subject: [PATCH 024/866] Update offline/packages/micromegas/MicromegasDefs.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/micromegas/MicromegasDefs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/micromegas/MicromegasDefs.cc b/offline/packages/micromegas/MicromegasDefs.cc index 78732951f7..b26a02564a 100644 --- a/offline/packages/micromegas/MicromegasDefs.cc +++ b/offline/packages/micromegas/MicromegasDefs.cc @@ -77,7 +77,7 @@ namespace MicromegasDefs uint8_t getStrip( TrkrDefs::hitkey key ) { TrkrDefs::hitkey tmp = (key >> kBitShiftStrip); - return tmp; + return tmp & 0xFF; } //________________________________________________________________ From 89660ef82ddcb6517de607817a00f1afacb04b11 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 6 Jan 2026 23:05:57 -0500 Subject: [PATCH 025/866] Update offline/packages/micromegas/MicromegasDefs.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/micromegas/MicromegasDefs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/micromegas/MicromegasDefs.cc b/offline/packages/micromegas/MicromegasDefs.cc index b26a02564a..0e669b1d88 100644 --- a/offline/packages/micromegas/MicromegasDefs.cc +++ b/offline/packages/micromegas/MicromegasDefs.cc @@ -84,7 +84,7 @@ namespace MicromegasDefs uint16_t getSample( TrkrDefs::hitkey key ) { TrkrDefs::hitkey tmp = (key >> kBitShiftSample); - return tmp; + return tmp & 0xFFFF; } //________________________________________________________________ From 2f32421454bc8ff6608e9ca2fb4eab9ac5218384 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 7 Jan 2026 10:22:55 -0500 Subject: [PATCH 026/866] handle max between a double and an int correctly with rounding --- offline/packages/tpc/TpcClusterizer.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 4548bde728..c0137613f5 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -531,14 +531,10 @@ namespace continue; } - max_adc = std::max(adc, max_adc); - + 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; } From 3fe3cd3fd97d4994f46577d85609972ae240632b Mon Sep 17 00:00:00 2001 From: cdean-github Date: Wed, 7 Jan 2026 11:45:04 -0500 Subject: [PATCH 027/866] CD: New version of silicon pooling --- .../Fun4AllStreamingInputManager.cc | 132 +++++------------- .../fun4allraw/SingleMvtxPoolInput.cc | 11 +- 2 files changed, 43 insertions(+), 100 deletions(-) diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 78b3e3a365..0bea81197b 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -776,9 +776,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 +794,9 @@ 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; } - int Fun4AllStreamingInputManager::FillMvtx() { int iret = FillMvtxPool(); @@ -846,7 +836,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 +971,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); } } @@ -1422,7 +1364,7 @@ int Fun4AllStreamingInputManager::FillMicromegasPool() 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) diff --git a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc index de98a9936e..4ce498ee9e 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 @@ -29,7 +29,8 @@ #include SingleMvtxPoolInput::SingleMvtxPoolInput(const std::string &name) - : SingleStreamingInput(name), plist(new Packet *[2]) + : SingleStreamingInput(name) + , plist(new Packet *[2]) { m_rawHitContainerName = "MVTXRAWHIT"; @@ -161,7 +162,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 +207,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()) { @@ -462,7 +463,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 { From c6b077cd4329601bbc6bf975e1336f1bff6fc48d Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 7 Jan 2026 14:54:21 -0500 Subject: [PATCH 028/866] - removed static as per clang-tidy - consolidated all key setters/getters with masks --- offline/packages/micromegas/MicromegasDefs.cc | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/offline/packages/micromegas/MicromegasDefs.cc b/offline/packages/micromegas/MicromegasDefs.cc index 0e669b1d88..8a35461492 100644 --- a/offline/packages/micromegas/MicromegasDefs.cc +++ b/offline/packages/micromegas/MicromegasDefs.cc @@ -25,12 +25,12 @@ 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; - static constexpr unsigned int kBitShiftSample = 8; + constexpr unsigned int kBitShiftStrip = 0; + constexpr unsigned int kBitShiftSample = 8; } @@ -42,10 +42,10 @@ namespace MicromegasDefs { 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; @@ -55,21 +55,21 @@ namespace MicromegasDefs SegmentationType getSegmentationType(TrkrDefs::hitsetkey key) { TrkrDefs::hitsetkey tmp = (key >> kBitShiftSegmentation); - return static_cast(tmp); + return static_cast(tmp&0x1U); } //________________________________________________________________ uint8_t getTileId(TrkrDefs::hitsetkey key) { TrkrDefs::hitsetkey tmp = (key >> kBitShiftTileId); - return tmp; + return tmp&0xFFU; } //________________________________________________________________ TrkrDefs::hitkey genHitKey(uint16_t strip, uint16_t sample) { - const TrkrDefs::hitkey key = strip << kBitShiftStrip; - const TrkrDefs::hitkey tmp = sample << kBitShiftSample; + const TrkrDefs::hitkey key = (strip&0xFFU) << kBitShiftStrip; + const TrkrDefs::hitkey tmp = (sample&0xFFFFU) << kBitShiftSample; return key|tmp; } @@ -77,14 +77,14 @@ namespace MicromegasDefs uint8_t getStrip( TrkrDefs::hitkey key ) { TrkrDefs::hitkey tmp = (key >> kBitShiftStrip); - return tmp & 0xFF; + return tmp & 0xFFU; } //________________________________________________________________ uint16_t getSample( TrkrDefs::hitkey key ) { TrkrDefs::hitkey tmp = (key >> kBitShiftSample); - return tmp & 0xFFFF; + return tmp & 0xFFFFU; } //________________________________________________________________ From f5a6ec82f5784410804b0d115be034816b496ebe Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 7 Jan 2026 15:10:41 -0500 Subject: [PATCH 029/866] clang-tidy --- offline/packages/micromegas/MicromegasClusterizer.cc | 11 +++++++---- .../micromegas/MicromegasCombinedDataDecoder.cc | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/offline/packages/micromegas/MicromegasClusterizer.cc b/offline/packages/micromegas/MicromegasClusterizer.cc index a28ed156b6..9444d9ef26 100644 --- a/offline/packages/micromegas/MicromegasClusterizer.cc +++ b/offline/packages/micromegas/MicromegasClusterizer.cc @@ -158,9 +158,12 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) 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 @@ -261,7 +264,7 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) } 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; @@ -274,7 +277,7 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) } // store last cluster - if( begin != local_hitmap.end() ) { ranges.push_back( std::make_pair( begin, local_hitmap.end() ) ); } + if( begin != local_hitmap.end() ) { ranges.emplace_back( begin, local_hitmap.end() ); } // initialize cluster count int cluster_count = 0; diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc index 50bcb97cd6..1c34357280 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc @@ -258,7 +258,7 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) 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; From af55b25f25d7c859a488ed1e03aa779aa8969fe9 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Wed, 7 Jan 2026 19:57:56 -0500 Subject: [PATCH 030/866] add e22 showershape --- offline/packages/CaloReco/PhotonClusterBuilder.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.cc b/offline/packages/CaloReco/PhotonClusterBuilder.cc index 263ae04ef0..edcf5f4418 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.cc +++ b/offline/packages/CaloReco/PhotonClusterBuilder.cc @@ -566,6 +566,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); From 8d61916570e48698737f61814f3c6131093c64f4 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 7 Jan 2026 20:05:29 -0500 Subject: [PATCH 031/866] more clang-tidy --- offline/packages/micromegas/MicromegasClusterizer.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/offline/packages/micromegas/MicromegasClusterizer.cc b/offline/packages/micromegas/MicromegasClusterizer.cc index 9444d9ef26..5da9264c11 100644 --- a/offline/packages/micromegas/MicromegasClusterizer.cc +++ b/offline/packages/micromegas/MicromegasClusterizer.cc @@ -253,16 +253,9 @@ 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.emplace_back( begin, hit_it ); @@ -272,6 +265,7 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) } // update previous strip + first = false; previous_strip = strip; } From 3a535f03b5f98661ee09fcd6a9f5e8f0cc9eb828 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 01:20:38 +0000 Subject: [PATCH 032/866] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20?= =?UTF-8?q?`photonclass`?= 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-Collaboration/coresoftware/pull/4095#issuecomment-3721466089 The following files were modified: * `offline/packages/CaloReco/PhotonClusterBuilder.cc` --- offline/packages/CaloReco/PhotonClusterBuilder.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.cc b/offline/packages/CaloReco/PhotonClusterBuilder.cc index 263ae04ef0..59bb5be1ae 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.cc +++ b/offline/packages/CaloReco/PhotonClusterBuilder.cc @@ -272,6 +272,17 @@ void PhotonClusterBuilder::calculate_bdt_score(PhotonClusterv1* photon) photon->set_shower_shape_parameter("bdt_score", bdt_score); } +/// @brief Extracts and stores shower-shape and isolation observables for a cluster onto a PhotonClusterv1. +/// +— Computes a 7x7 local energy grid around the cluster lead tower, derives moments, summed energies +— (e.g., e11, e22, e33, e55, e77 and related e13..e75), centroid and width metrics (weta, wphi, cog variants), +— timing and saturation counters, closest HCAL tower ET summaries, and calorimeter-layer isolation values, +— and attaches these values to the provided photon via set_shower_shape_parameter. +/// +@param rc Pointer to the RawCluster providing tower membership and shower-shape inputs; if rc->get_shower_shapes(...) is empty the function returns without modifying the photon. +///@param photon PhotonClusterv1 instance to receive computed shower-shape and isolation parameters. +///@param cluster_eta Pseudorapidity of the cluster (used for ET calculations and stored as "cluster_eta"). +///@param cluster_phi Azimuthal angle of the cluster (used for storage as "cluster_phi"). 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 +577,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 +921,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 From 66f7822a0485031066f4a504adf35c8b037023b4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 8 Jan 2026 11:02:53 -0500 Subject: [PATCH 033/866] =?UTF-8?q?Revert=20"=F0=9F=93=9D=20Add=20docstrin?= =?UTF-8?q?gs=20to=20`photonclass`"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- offline/packages/CaloReco/PhotonClusterBuilder.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.cc b/offline/packages/CaloReco/PhotonClusterBuilder.cc index 59bb5be1ae..edcf5f4418 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.cc +++ b/offline/packages/CaloReco/PhotonClusterBuilder.cc @@ -272,17 +272,6 @@ void PhotonClusterBuilder::calculate_bdt_score(PhotonClusterv1* photon) photon->set_shower_shape_parameter("bdt_score", bdt_score); } -/// @brief Extracts and stores shower-shape and isolation observables for a cluster onto a PhotonClusterv1. -/// -— Computes a 7x7 local energy grid around the cluster lead tower, derives moments, summed energies -— (e.g., e11, e22, e33, e55, e77 and related e13..e75), centroid and width metrics (weta, wphi, cog variants), -— timing and saturation counters, closest HCAL tower ET summaries, and calorimeter-layer isolation values, -— and attaches these values to the provided photon via set_shower_shape_parameter. -/// -@param rc Pointer to the RawCluster providing tower membership and shower-shape inputs; if rc->get_shower_shapes(...) is empty the function returns without modifying the photon. -///@param photon PhotonClusterv1 instance to receive computed shower-shape and isolation parameters. -///@param cluster_eta Pseudorapidity of the cluster (used for ET calculations and stored as "cluster_eta"). -///@param cluster_phi Azimuthal angle of the cluster (used for storage as "cluster_phi"). 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); @@ -921,4 +910,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 +} From 7e92dc741cb391e4d3ab4a21b9d0df7b3c2d6262 Mon Sep 17 00:00:00 2001 From: emclaughlin2 Date: Thu, 8 Jan 2026 13:24:39 -0500 Subject: [PATCH 034/866] Fix bugs in CaloValid to select correct MB + 10 cm trigger --- offline/QA/Calorimeters/CaloValid.cc | 8 ++++---- offline/QA/Calorimeters/CaloValid.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 243395c2bb..756169c105 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -267,7 +267,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) uint64_t raw[64] = {0}; uint64_t live[64] = {0}; // long long int scaled[64] = { 0 }; - Gl1Packet* gl1PacketInfo = findNode::getClass(topNode, 14001); + Gl1Packet* gl1PacketInfo = findNode::getClass(topNode, "14001"); if (!gl1PacketInfo) { gl1PacketInfo = findNode::getClass(topNode, "GL1Packet"); @@ -344,7 +344,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) { 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); } @@ -420,7 +420,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) { 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); } @@ -488,7 +488,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) { 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); } diff --git a/offline/QA/Calorimeters/CaloValid.h b/offline/QA/Calorimeters/CaloValid.h index 2e2f9e278e..baaede0fe5 100644 --- a/offline/QA/Calorimeters/CaloValid.h +++ b/offline/QA/Calorimeters/CaloValid.h @@ -55,7 +55,7 @@ class CaloValid : public SubsysReco TriggerAnalyzer* trigAna{nullptr}; TH3* h_pi0_trigIB_mass{nullptr}; - std::vector triggerIndices{10, 28, 29, 30, 31}; // MBD NS>=1, Photon Triggers + std::vector triggerIndices{10, 12, 28, 29, 30, 31}; // MBD NS>=1, Photon Triggers TH1* h_cemc_channel_pedestal[128 * 192]{nullptr}; TH1* h_ihcal_channel_pedestal[32 * 48]{nullptr}; From a573ec3353165b9f96dee9bdd29a1b22439f5bc9 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 8 Jan 2026 16:42:46 -0500 Subject: [PATCH 035/866] make setters functional --- offline/packages/trackreco/PHActsTrkFitter.h | 2 +- offline/packages/trackreco/PHSiliconTpcTrackMatching.cc | 4 ++-- offline/packages/trackreco/PHSiliconTpcTrackMatching.h | 6 +++++- offline/packages/trackreco/PHSimpleVertexFinder.h | 2 +- offline/packages/trackreco/PHTpcDeltaZCorrection.h | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index d0e221a40e..cca5095c79 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -142,7 +142,7 @@ class PHActsTrkFitter : public SubsysReco 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 setTrkrClusterContainerName(const std::string& name) { m_clusterContainerName = name; } void setDirectNavigation(bool flag) { m_directNavigation = flag; } private: diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc index 2e66a6df28..6aaae4bf93 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc @@ -445,10 +445,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; } diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h index acb157bd83..6de4a1dd3a 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h @@ -139,7 +139,10 @@ class PHSiliconTpcTrackMatching : public SubsysReco, public PHParameterInterface 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; } - + void set_cluster_map_name(const std::string &name) + { + _cluster_map_name = name; + } int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *) override; @@ -210,6 +213,7 @@ 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); }; diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index da0e36fabf..6915693c4b 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -54,7 +54,7 @@ class PHSimpleVertexFinder : public SubsysReco 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 setTrkrClusterContainerName(const std::string &name){ m_clusterContainerName = name; } void set_pp_mode(bool mode) { _pp_mode = mode; } private: diff --git a/offline/packages/trackreco/PHTpcDeltaZCorrection.h b/offline/packages/trackreco/PHTpcDeltaZCorrection.h index 46d099f587..4d383cc854 100644 --- a/offline/packages/trackreco/PHTpcDeltaZCorrection.h +++ b/offline/packages/trackreco/PHTpcDeltaZCorrection.h @@ -32,7 +32,7 @@ class PHTpcDeltaZCorrection : public SubsysReco, public PHParameterInterface int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; void SetDefaultParameters() override; - void setTrkrClusterContainerName(std::string &name) { m_clusterContainerName = name; } + void setTrkrClusterContainerName(const std::string &name) { m_clusterContainerName = name; } private: /// load nodes From fcb63122023840acf3277b9267bb32e223d81238 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 8 Jan 2026 18:55:38 -0500 Subject: [PATCH 036/866] Fix Gl1Packet ID type from string to integer Tonight I am going to have fried rabbit... I added the integer interface so we can just use the packet id as nodename without having to convert to strings (that's done inside the code - that's the only thing this interface does). Sorry about that --- offline/QA/Calorimeters/CaloValid.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 756169c105..19c834bdab 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -267,7 +267,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) uint64_t raw[64] = {0}; uint64_t live[64] = {0}; // long long int scaled[64] = { 0 }; - Gl1Packet* gl1PacketInfo = findNode::getClass(topNode, "14001"); + Gl1Packet* gl1PacketInfo = findNode::getClass(topNode, 14001); if (!gl1PacketInfo) { gl1PacketInfo = findNode::getClass(topNode, "GL1Packet"); From 36cd47aa98888fa88e97872d9894c15eb288f70c Mon Sep 17 00:00:00 2001 From: silas-gross Date: Fri, 9 Jan 2026 08:46:01 -0500 Subject: [PATCH 037/866] adding more of the skeleton structure --- .../HepMCTrigger/HepMCParticleTrigger.cc | 165 ++++++++++++++++++ .../HepMCTrigger/HepMCParticleTrigger.h | 123 +++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc create mode 100644 generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc new file mode 100644 index 0000000000..71e35b3bb9 --- /dev/null +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -0,0 +1,165 @@ +#include "HepMCJetTrigger.h" + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +//____________________________________________________________________________.. +// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) +HepMCJetTrigger::HepMCJetTrigger(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(-999.9) + , _theEtaLow(-999.9) + , _thePtHigh(999.9) + , _thePtLow(-999.9) + , _thePHigh(999.9) + , _thePLow(-999.9) + , _thePzHigh(999.9) + , _thePzLow(-999.9) + , + + _doEtaHighCut(false) + , _doEtaLowCut(false) + , _doBothEtaCut(false) + , + + _doAbsEtaHighCut(false) + , _doAbsEtaLowCut(false) + , _doBothAbsEtaCut(false) + , + + _doPtHighCut(false) + , _doPtLowCut(false) + , _doBothPtCut(false) + , + + _doPHighCut(false) + , _doPLowCut(false) + , _doBothPCut(false) + , + + _doPzHighCut(false) + , _doPzLowCut(false) + , _doBothPzCut(false) +{ +} + +//____________________________________________________________________________.. +int HepMCJetTrigger::process_event(PHCompositeNode* topNode) +{ + // std::cout << "HepMCJetTrigger::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; + } + } + 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; + } + bool const good_event = isGoodEvent(ev); + if (good_event) + { + n_good++; + } + if (!good_event) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + } + return Fun4AllReturnCodes::EVENT_OK; +} +void HepMCParticleTrigger::AddParticles(const std::string &particles) +{ + std::vector addedParts = convertToInt() + _theParticles.insert( +} +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 = jetsAboveThreshold(jets); + for(auto ntp:n_trigger_particles) + { + if(ntp <=0 ) return false; + } + return true; +} + +std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) +{ + 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; + else{ + auto p = (*iter)->momentum(); + float px = p.px(); + float py = p.py(); + float pz = p.pz(); + float p = 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 = (*iter)->pid(); + double eta = p.eta(); + if((_doEtaHighCut || _doBothEtaCut ) && eta > _theEtaHigh) continue; + if((_doEtaLowCut || _doBothEtaCut ) && eta < _theEtaLow) continue; + if((_doAbsEtaHighCut || _doBothAbsEtaCut ) && std::abs(eta) > _theAbsEtaHigh) continue; + if((_doAbsEtaLowCut || _doBothAbsEtaCut ) && std::abs(eta) < _theAbsEtaLow) continue; + if((_doPtHighCut || _doBothPtCut ) && pt > _thePtHigh) continue; + if((_doPLowCut || _doBothPCut ) && pt < _thePtLow) continue; + if((_doPHighCut || _doBothPCut ) && p > _thePHigh) continue; + if((_doPLowCut || _doBothPCut ) && p < _thePLow) continue; + if((_doPzHighCut || _doBothPzCut ) && pz > _thePzHigh) continue; + if((_doPzLowCut || _doBothPzCut ) && pz < _thePzLow) continue; + + } + return output; +} +int HepMCParticle::particlesAboveThreshold(const std::vector& jets) +{ + // search through for the number of identified jets above the threshold + int n_good_jets = 0; + for (const auto& j : jets) + { + float const pt = j.pt(); + if (pt > this->threshold) + { + n_good_jets++; + } + } + return n_good_jets; +} diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h new file mode 100644 index 0000000000..33f2c82486 --- /dev/null +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -0,0 +1,123 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef HEPMCJETTRIGGER_H +#define HEPMCJETTRIGGER_H + +#include + +#include + +#include +#include + +class PHCompositeNode; +namespace HepMC +{ + class GenEvent; +} + +class HepMCJetTrigger : public SubsysReco +{ + public: + HepMCJetTrigger(float trigger_thresh = 10., int n_incom = 1000, bool up_lim = false, const std::string& name = "HepMCJetTrigger"); + + ~HepMCJetTrigger() override = default; + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + + /** Called for first event when run number is known. + Typically this is where you may want to fetch data from + database, because you know the run number. A place + to book histograms which have to know the run number. + */ + + /** 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::string &particles); + void AddParticles(int particle); + void AddParticles(std::vector particles); + void AddParticlespID(std::vector particles); + + void AddParents(const std::string &parents); + void AddParents(int parent); + void AddParents(std::vector parents); + void AddParentspID(std::vector parents); + + void SetPtHigh(double pt); + void SetPtLow(double pt); + void SetPtHighLow(double ptHigh, double ptLow); + + void SetPHigh(double p); + void SetPLow(double p); + void SetPHighLow(double pHigh, double pLow); + + void SetEtaHigh(double eta); + void SetEtaLow(double eta); + void SetEtaHighLow(double etaHigh, double etaLow); + + void SetAbsEtaHigh(double eta); + void SetAbsEtaLow(double eta); + void SetAbsEtaHighLow(double etaHigh, double etaLow); + + void SetPzHigh(double pz); + void SetPzLow(double pz); + void SetPzHighLow(double pzHigh, double pzLow); + + void SetStableParticleOnly(bool b) { m_doStableParticleOnly = b; } + private: + std::vector _theParents; + std::vector _theParticles; + + bool isGoodEvent(HepMC::GenEvent* e1); + std::vector findAllParticles(HepMC::GenEvent* e1); + int particleAboveThreshold(std::map n_particles, int particle); + float threshold{0.}; + int goal_event_number{1000}; + int n_evts{0}; + int n_good{0}; + bool set_event_limit{false}; + float _theEtaHigh{-999.9}; + float _theEtaLow{-999.9}; + 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{false}; + bool _doEtaLowCut{false}; + bool _doBothEtaCut{false}; + + 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}; + bool _doBothPzCut{false}; +}; + +#endif // HEPMCJETTRIGGER_H From c3615514e6b4be3508b379a356831e285fe4ce25 Mon Sep 17 00:00:00 2001 From: silas-gross Date: Fri, 9 Jan 2026 19:29:25 -0500 Subject: [PATCH 038/866] Nearly done, just need to dust around the edges --- .../HepMCTrigger/HepMCParticleTrigger.cc | 172 +++++++++++++++--- .../HepMCTrigger/HepMCParticleTrigger.h | 48 +++-- 2 files changed, 171 insertions(+), 49 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 71e35b3bb9..3bf04c5e65 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -101,29 +101,152 @@ int HepMCJetTrigger::process_event(PHCompositeNode* topNode) } return Fun4AllReturnCodes::EVENT_OK; } -void HepMCParticleTrigger::AddParticles(const std::string &particles) +void HepMCParticleTrigger::AddParticle(int particlePid) { - std::vector addedParts = convertToInt() - _theParticles.insert( + _theParticles.push_back(particlePid); + return; +} +void HepMCParticleTrigger::AddParticles(std::vector particles) +{ + for(auto p:particles) _theParticles.push_back(p); + return; +} + +void SetPtHigh(double pt) +{ + _thePtHigh=pt; + _doPtHighCut=true; + if(_doPtLowCut) _doBothPtCut=true; + return; +} +void SetPtLow(double pt) +{ + _thePtLow=pt; + _doPtLowCut=true; + if(_doPtHighCut) _doBothPtCut=true; + return; +} +void SetPtHighLow(double ptHigh, double ptLow) +{ + _thePtHigh=pt; + _doPtHighCut=true; + _thePtLow=pt; + _doPtLowCut=true; + _doBothPtCut=true; + return; +} +void SetPHigh(double pt) +{ + _thePHigh=pt; + _doPHighCut=true; + if(_doPLowCut) _doBothPCut=true; + return; +} +void SetPLow(double pt) +{ + _thePLow=pt; + _doPLowCut=true; + if(_doPHighCut) _doBothPCut=true; + return; +} +void SetPHighLow(double ptHigh, double ptLow) +{ + _thePHigh=pt; + _doPHighCut=true; + _thePLow=pt; + _doPLowCut=true; + _doBothPCut=true; + return; +} +void SetPzHigh(double pt) +{ + _thePzHigh=pt; + _doPzHighCut=true; + if(_doPzLowCut) _doBothPzCut=true; + return; +} +void SetPzLow(double pt) +{ + _thePzLow=pt; + _doPzLowCut=true; + if(_doPzHighCut) _doBothPzCut=true; + return; +} +void SetPzHighLow(double ptHigh, double ptLow) +{ + _thePzHigh=pt; + _doPzHighCut=true; + _thePzLow=pt; + _doPzLowCut=true; + _doBothPzCut=true; + return; +} +void SetEtaHigh(double pt) +{ + _theEtaHigh=pt; + _doEtaHighCut=true; + if(_doEtaLowCut) _doBothEtaCut=true; + return; +} +void SetEtaLow(double pt) +{ + _theEtaLow=pt; + _doEtaLowCut=true; + if(_doEtaHighCut) _doBothEtaCut=true; + return; +} +void SetEtaHighLow(double ptHigh, double ptLow) +{ + _theEtaHigh=pt; + _doEtaHighCut=true; + _theEtaLow=pt; + _doEtaLowCut=true; + _doBothEtaCut=true; + return; +} +void SetAbsEtaHigh(double pt) +{ + _theAbsEtaHigh=pt; + _doAbsEtaHighCut=true; + if(_doAbsEtaLowCut) _doBothAbsEtaCut=true; + return; +} +void SetAbsEtaLow(double pt) +{ + _theAbsEtaLow=pt; + _doAbsEtaLowCut=true; + if(_doAbsEtaHighCut) _doBothAbsEtaCut=true; + return; +} +void SetAbsEtaHighLow(double ptHigh, double ptLow) +{ + _theAbsEtaHigh=pt; + _doAbsEtaHighCut=true; + _theAbsEtaLow=pt; + _doAbsEtaLowCut=true; + _doBothAbsEtaCut=true; + return; } bool HepMCParticleTrigger::isGoodEvent(HepMC::GenEvent* e1) { // this is really just the call to actually evaluate and return the filter - if (this->threshold == 0) + /*if (this->threshold == 0) { return true; - } - std::vector n_trigger_particles = jetsAboveThreshold(jets); + }*/ + std::vector n_trigger_particles = getParticles(e1); for(auto ntp:n_trigger_particles) { - if(ntp <=0 ) return false; + if(ntp <=0 ) return false; //make sure all } return true; } std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) -{ - for (HepMC::GenEvent::particle_const_iterator iter = e1->particles_begin(); iter != e1->particles_end(); ++iter) +{ + 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; else{ @@ -137,29 +260,30 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) double eta = p.eta(); if((_doEtaHighCut || _doBothEtaCut ) && eta > _theEtaHigh) continue; if((_doEtaLowCut || _doBothEtaCut ) && eta < _theEtaLow) continue; - if((_doAbsEtaHighCut || _doBothAbsEtaCut ) && std::abs(eta) > _theAbsEtaHigh) continue; - if((_doAbsEtaLowCut || _doBothAbsEtaCut ) && std::abs(eta) < _theAbsEtaLow) continue; + if((_doAbsEtaHighCut || _doBothAbsEtaCut ) && std::abs(eta) > _theEtaHigh) continue; + if((_doAbsEtaLowCut || _doBothAbsEtaCut ) && std::abs(eta) < _theEtaLow) continue; if((_doPtHighCut || _doBothPtCut ) && pt > _thePtHigh) continue; if((_doPLowCut || _doBothPCut ) && pt < _thePtLow) continue; if((_doPHighCut || _doBothPCut ) && p > _thePHigh) continue; if((_doPLowCut || _doBothPCut ) && p < _thePLow) continue; if((_doPzHighCut || _doBothPzCut ) && pz > _thePzHigh) continue; if((_doPzLowCut || _doBothPzCut ) && pz < _thePzLow) continue; + if(particle_types.find(pid) != particle_types.end()) particle_types[pid]++; + else particle_types[pid]=1; + } + for(auto p:_theParticles) + { + n_trigger.push_back(particlesAboveThreshold(particle_types, p)); //make sure we have at least one of each required particle + } } - return output; + return n_trigger; } -int HepMCParticle::particlesAboveThreshold(const std::vector& jets) +int HepMCParticle::particlesAboveThreshold(std::map n_particles, int trigger_particle ) { - // search through for the number of identified jets above the threshold - int n_good_jets = 0; - for (const auto& j : jets) - { - float const pt = j.pt(); - if (pt > this->threshold) - { - n_good_jets++; - } - } - return n_good_jets; + // search through for the number of identified trigger particles passing cuts + for(auto p:n_particles){ + if(std::abs(p.first) == std::abs(trigger_particle)) return p.second; //accept both trigger particle and antiparticle + } + return 0; } diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index 33f2c82486..a20eab5c6a 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -47,44 +47,42 @@ class HepMCJetTrigger : public SubsysReco /// Called at the end of all processing. /// Reset - void AddParticles(const std::string &particles); - void AddParticles(int particle); - void AddParticles(std::vector particles); - void AddParticlespID(std::vector particles); + void AddParticles(std::vector); + void AddParticle(int); - void AddParents(const std::string &parents); +/* void AddParents(const std::string &parents); void AddParents(int parent); void AddParents(std::vector parents); void AddParentspID(std::vector parents); - - void SetPtHigh(double pt); - void SetPtLow(double pt); - void SetPtHighLow(double ptHigh, double ptLow); - - void SetPHigh(double p); - void SetPLow(double p); - void SetPHighLow(double pHigh, double pLow); +*/ + void SetPtHigh(double); + void SetPtLow(double); + void SetPtHighLow(double, double); + + void SetPHigh(double); + void SetPLow(double); + void SetPHighLow(double, double); - void SetEtaHigh(double eta); - void SetEtaLow(double eta); - void SetEtaHighLow(double etaHigh, double etaLow); + void SetEtaHigh(double); + void SetEtaLow(double); + void SetEtaHighLow(double, double); - void SetAbsEtaHigh(double eta); - void SetAbsEtaLow(double eta); - void SetAbsEtaHighLow(double etaHigh, double etaLow); + void SetAbsEtaHigh(double); + void SetAbsEtaLow(double); + void SetAbsEtaHighLow(double, double); - void SetPzHigh(double pz); - void SetPzLow(double pz); - void SetPzHighLow(double pzHigh, double pzLow); + void SetPzHigh(double); + void SetPzLow(double); + void SetPzHighLow(double, double); void SetStableParticleOnly(bool b) { m_doStableParticleOnly = b; } private: - std::vector _theParents; - std::vector _theParticles; - bool isGoodEvent(HepMC::GenEvent* e1); std::vector findAllParticles(HepMC::GenEvent* e1); int particleAboveThreshold(std::map n_particles, int particle); + std::vector _theParentsi {}; + std::vector _theParticles {}; + bool m_doStableParticleOnly {true}; float threshold{0.}; int goal_event_number{1000}; int n_evts{0}; From 23ef520ae205100966a33f7e55d89c06fd76cf95 Mon Sep 17 00:00:00 2001 From: silas-gross Date: Sat, 10 Jan 2026 00:37:51 -0500 Subject: [PATCH 039/866] Bare minimum working version of HepMC particle trigger. Requires input of trigger particle to be in the form of the PDG ID number, working on mimizing friction --- .../HepMCTrigger/HepMCParticleTrigger.cc | 83 ++++++++++--------- .../HepMCTrigger/HepMCParticleTrigger.h | 30 +++---- generators/Herwig/HepMCTrigger/Makefile.am | 15 +++- 3 files changed, 73 insertions(+), 55 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 3bf04c5e65..78df141289 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -1,4 +1,4 @@ -#include "HepMCJetTrigger.h" +#include "HepMCParticleTrigger.h" #include #include @@ -16,10 +16,10 @@ #include #include #include - +#include //____________________________________________________________________________.. // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -HepMCJetTrigger::HepMCJetTrigger(float trigger_thresh, int n_incom, bool up_lim, const std::string& name) +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) @@ -58,12 +58,17 @@ HepMCJetTrigger::HepMCJetTrigger(float trigger_thresh, int n_incom, bool up_lim, , _doPzLowCut(false) , _doBothPzCut(false) { + if(threshold != 0 ) + { + _doPtLowCut=true; + _thePtLow=threshold; + } } //____________________________________________________________________________.. -int HepMCJetTrigger::process_event(PHCompositeNode* topNode) +int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) { - // std::cout << "HepMCJetTrigger::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; + // 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 @@ -112,117 +117,117 @@ void HepMCParticleTrigger::AddParticles(std::vector particles) return; } -void SetPtHigh(double pt) +void HepMCParticleTrigger::SetPtHigh(double pt) { _thePtHigh=pt; _doPtHighCut=true; if(_doPtLowCut) _doBothPtCut=true; return; } -void SetPtLow(double pt) +void HepMCParticleTrigger::SetPtLow(double pt) { _thePtLow=pt; _doPtLowCut=true; if(_doPtHighCut) _doBothPtCut=true; return; } -void SetPtHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetPtHighLow(double ptHigh, double ptLow) { - _thePtHigh=pt; + _thePtHigh=ptHigh; _doPtHighCut=true; - _thePtLow=pt; + _thePtLow=ptLow; _doPtLowCut=true; _doBothPtCut=true; return; } -void SetPHigh(double pt) +void HepMCParticleTrigger::SetPHigh(double pt) { _thePHigh=pt; _doPHighCut=true; if(_doPLowCut) _doBothPCut=true; return; } -void SetPLow(double pt) +void HepMCParticleTrigger::SetPLow(double pt) { _thePLow=pt; _doPLowCut=true; if(_doPHighCut) _doBothPCut=true; return; } -void SetPHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetPHighLow(double ptHigh, double ptLow) { - _thePHigh=pt; + _thePHigh=ptHigh; _doPHighCut=true; - _thePLow=pt; + _thePLow=ptLow; _doPLowCut=true; _doBothPCut=true; return; } -void SetPzHigh(double pt) +void HepMCParticleTrigger::SetPzHigh(double pt) { _thePzHigh=pt; _doPzHighCut=true; if(_doPzLowCut) _doBothPzCut=true; return; } -void SetPzLow(double pt) +void HepMCParticleTrigger::SetPzLow(double pt) { _thePzLow=pt; _doPzLowCut=true; if(_doPzHighCut) _doBothPzCut=true; return; } -void SetPzHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetPzHighLow(double ptHigh, double ptLow) { - _thePzHigh=pt; + _thePzHigh=ptHigh; _doPzHighCut=true; - _thePzLow=pt; + _thePzLow=ptLow; _doPzLowCut=true; _doBothPzCut=true; return; } -void SetEtaHigh(double pt) +void HepMCParticleTrigger::SetEtaHigh(double pt) { _theEtaHigh=pt; _doEtaHighCut=true; if(_doEtaLowCut) _doBothEtaCut=true; return; } -void SetEtaLow(double pt) +void HepMCParticleTrigger::SetEtaLow(double pt) { _theEtaLow=pt; _doEtaLowCut=true; if(_doEtaHighCut) _doBothEtaCut=true; return; } -void SetEtaHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetEtaHighLow(double ptHigh, double ptLow) { - _theEtaHigh=pt; + _theEtaHigh=ptHigh; _doEtaHighCut=true; - _theEtaLow=pt; + _theEtaLow=ptLow; _doEtaLowCut=true; _doBothEtaCut=true; return; } -void SetAbsEtaHigh(double pt) +void HepMCParticleTrigger::SetAbsEtaHigh(double pt) { - _theAbsEtaHigh=pt; + _theEtaHigh=pt; _doAbsEtaHighCut=true; if(_doAbsEtaLowCut) _doBothAbsEtaCut=true; return; } -void SetAbsEtaLow(double pt) +void HepMCParticleTrigger::SetAbsEtaLow(double pt) { - _theAbsEtaLow=pt; + _theEtaLow=pt; _doAbsEtaLowCut=true; if(_doAbsEtaHighCut) _doBothAbsEtaCut=true; return; } -void SetAbsEtaHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetAbsEtaHighLow(double ptHigh, double ptLow) { - _theAbsEtaHigh=pt; + _theEtaHigh=ptHigh; _doAbsEtaHighCut=true; - _theAbsEtaLow=pt; + _theEtaLow=ptLow; _doAbsEtaLowCut=true; _doBothAbsEtaCut=true; return; @@ -237,7 +242,7 @@ bool HepMCParticleTrigger::isGoodEvent(HepMC::GenEvent* e1) std::vector n_trigger_particles = getParticles(e1); for(auto ntp:n_trigger_particles) { - if(ntp <=0 ) return false; //make sure all + if(ntp <=0 ) return false; //make sure all particles have at least 1 } return true; } @@ -254,9 +259,9 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) float px = p.px(); float py = p.py(); float pz = p.pz(); - float p = std::sqrt(std::pow(px, 2) + std::pow(py, 2) + std::pow(pz, 2)); + 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 = (*iter)->pid(); + int pid = (*iter)->pdg_id(); double eta = p.eta(); if((_doEtaHighCut || _doBothEtaCut ) && eta > _theEtaHigh) continue; if((_doEtaLowCut || _doBothEtaCut ) && eta < _theEtaLow) continue; @@ -264,8 +269,8 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) if((_doAbsEtaLowCut || _doBothAbsEtaCut ) && std::abs(eta) < _theEtaLow) continue; if((_doPtHighCut || _doBothPtCut ) && pt > _thePtHigh) continue; if((_doPLowCut || _doBothPCut ) && pt < _thePtLow) continue; - if((_doPHighCut || _doBothPCut ) && p > _thePHigh) continue; - if((_doPLowCut || _doBothPCut ) && p < _thePLow) 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.find(pid) != particle_types.end()) particle_types[pid]++; @@ -273,13 +278,13 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) } for(auto p:_theParticles) { - n_trigger.push_back(particlesAboveThreshold(particle_types, p)); //make sure we have at least one of each required particle + n_trigger.push_back(particleAboveThreshold(particle_types, p)); //make sure we have at least one of each required particle } } return n_trigger; } -int HepMCParticle::particlesAboveThreshold(std::map n_particles, int trigger_particle ) +int HepMCParticleTrigger::particleAboveThreshold(std::map n_particles, int trigger_particle ) { // search through for the number of identified trigger particles passing cuts for(auto p:n_particles){ diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index a20eab5c6a..904c8b381b 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -1,7 +1,7 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -#ifndef HEPMCJETTRIGGER_H -#define HEPMCJETTRIGGER_H +#ifndef HEPMCPARTICLETRIGGER_H +#define HEPMCPARTICLETRIGGER_H #include @@ -9,6 +9,7 @@ #include #include +#include class PHCompositeNode; namespace HepMC @@ -16,12 +17,12 @@ namespace HepMC class GenEvent; } -class HepMCJetTrigger : public SubsysReco +class HepMCParticleTrigger : public SubsysReco { public: - HepMCJetTrigger(float trigger_thresh = 10., int n_incom = 1000, bool up_lim = false, const std::string& name = "HepMCJetTrigger"); + HepMCParticleTrigger(float trigger_thresh = 10., int n_incom = 1000, bool up_lim = false, const std::string& name = "HepMCParticleTrigger"); - ~HepMCJetTrigger() override = default; + ~HepMCParticleTrigger() override = default; /** Called during initialization. Typically this is where you can book histograms, and e.g. @@ -78,9 +79,9 @@ class HepMCJetTrigger : public SubsysReco void SetStableParticleOnly(bool b) { m_doStableParticleOnly = b; } private: bool isGoodEvent(HepMC::GenEvent* e1); - std::vector findAllParticles(HepMC::GenEvent* e1); + std::vector getParticles(HepMC::GenEvent* e1); int particleAboveThreshold(std::map n_particles, int particle); - std::vector _theParentsi {}; +// std::vector _theParentsi {}; std::vector _theParticles {}; bool m_doStableParticleOnly {true}; float threshold{0.}; @@ -88,14 +89,15 @@ class HepMCJetTrigger : public SubsysReco int n_evts{0}; int n_good{0}; bool set_event_limit{false}; + float _theEtaHigh{-999.9}; float _theEtaLow{-999.9}; - float _thePtHigh(999.9}; - float _thePtLow(-999.9}; - float _thePHigh(999.9}; - float _thePLow(-999.9}; - float _thePzHigh(999.9}; - float _thePzLow(-999.9}; + 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{false}; bool _doEtaLowCut{false}; @@ -118,4 +120,4 @@ class HepMCJetTrigger : public SubsysReco bool _doBothPzCut{false}; }; -#endif // HEPMCJETTRIGGER_H +#endif // HEPMCPARTICLETRIGGER_H diff --git a/generators/Herwig/HepMCTrigger/Makefile.am b/generators/Herwig/HepMCTrigger/Makefile.am index 17ef6c4221..9807a9a78e 100644 --- a/generators/Herwig/HepMCTrigger/Makefile.am +++ b/generators/Herwig/HepMCTrigger/Makefile.am @@ -12,20 +12,31 @@ AM_LDFLAGS = \ `fastjet-config --libs` pkginclude_HEADERS = \ - HepMCJetTrigger.h + HepMCJetTrigger.h \ + HepMCParticleTrigger.h lib_LTLIBRARIES = \ - libHepMCJetTrigger.la + libHepMCJetTrigger.la \ + libHepMCParticleTrigger.la libHepMCJetTrigger_la_SOURCES = \ HepMCJetTrigger.cc +libHepMCParticleTrigger_la_SOURCES = \ + HepMCParticleTrigger.cc + libHepMCJetTrigger_la_LIBADD = \ -lphool \ -lSubsysReco \ -lfun4all \ -lphhepmc +libHepMCParticleTrigger_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lfun4all \ + -lphhepmc + BUILT_SOURCES = testexternals.cc noinst_PROGRAMS = \ From 498393ae4ce57bd504a198d8ec1eea5f3d3cc533 Mon Sep 17 00:00:00 2001 From: silas-gross Date: Sat, 10 Jan 2026 02:55:04 -0500 Subject: [PATCH 040/866] Fixed to adress issues found by CodeRabbit --- .../Herwig/HepMCTrigger/HepMCParticleTrigger.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 78df141289..95ec6fbe08 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -268,7 +268,7 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) if((_doAbsEtaHighCut || _doBothAbsEtaCut ) && std::abs(eta) > _theEtaHigh) continue; if((_doAbsEtaLowCut || _doBothAbsEtaCut ) && std::abs(eta) < _theEtaLow) continue; if((_doPtHighCut || _doBothPtCut ) && pt > _thePtHigh) continue; - if((_doPLowCut || _doBothPCut ) && pt < _thePtLow) 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; @@ -276,12 +276,11 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) if(particle_types.find(pid) != particle_types.end()) particle_types[pid]++; else particle_types[pid]=1; } - for(auto p:_theParticles) - { - n_trigger.push_back(particleAboveThreshold(particle_types, p)); //make sure we have at least one of each required particle - } - - } + } + 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; } int HepMCParticleTrigger::particleAboveThreshold(std::map n_particles, int trigger_particle ) From e18445b324ad8d1bf30b997e075cfeea18f64e0a Mon Sep 17 00:00:00 2001 From: silas-gross Date: Sat, 10 Jan 2026 04:03:37 -0500 Subject: [PATCH 041/866] a few more code rabbit fixes --- .../HepMCTrigger/HepMCParticleTrigger.cc | 22 +++++++++---------- .../HepMCTrigger/HepMCParticleTrigger.h | 3 ++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 95ec6fbe08..bd23087b24 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -77,6 +77,7 @@ int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } } + bool good_event; PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); if (!phg) { @@ -94,16 +95,16 @@ int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) { return Fun4AllReturnCodes::ABORTEVENT; } - bool const good_event = isGoodEvent(ev); - if (good_event) - { - n_good++; - } + good_event = isGoodEvent(ev); if (!good_event) { return Fun4AllReturnCodes::ABORTEVENT; } } + if (good_event) + { + n_good++; + } return Fun4AllReturnCodes::EVENT_OK; } void HepMCParticleTrigger::AddParticle(int particlePid) @@ -253,7 +254,7 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) 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; + if (m_doStableParticleOnly && ((*iter)->end_vertex() || (*iter)->status() != 1)) continue; else{ auto p = (*iter)->momentum(); float px = p.px(); @@ -283,11 +284,10 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) } return n_trigger; } -int HepMCParticleTrigger::particleAboveThreshold(std::map n_particles, int trigger_particle ) +int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_particles, int trigger_particle ) { // search through for the number of identified trigger particles passing cuts - for(auto p:n_particles){ - if(std::abs(p.first) == std::abs(trigger_particle)) return p.second; //accept both trigger particle and antiparticle - } - return 0; + auto it = n_particles.find(std::abs(trigger_particle)); + if( it!= n_particles.end()) return it->second; + else return 0; } diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index 904c8b381b..a0124f5292 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -10,6 +10,7 @@ #include #include #include +#include class PHCompositeNode; namespace HepMC @@ -80,7 +81,7 @@ class HepMCParticleTrigger : public SubsysReco private: bool isGoodEvent(HepMC::GenEvent* e1); std::vector getParticles(HepMC::GenEvent* e1); - int particleAboveThreshold(std::map n_particles, int particle); + int particleAboveThreshold(const std::map& n_particles, int particle); // std::vector _theParentsi {}; std::vector _theParticles {}; bool m_doStableParticleOnly {true}; From ebbee62e94b22bb02b900d2859f47a0ac4990aa1 Mon Sep 17 00:00:00 2001 From: silas-gross Date: Sat, 10 Jan 2026 04:57:16 -0500 Subject: [PATCH 042/866] Is this the last one CodeRabbit??? --- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index bd23087b24..242769aa07 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -77,7 +77,7 @@ int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } } - bool good_event; + bool good_event {false}; PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); if (!phg) { From 3d0a2e419b572423830dc759d8401b54a1e7e053 Mon Sep 17 00:00:00 2001 From: silas-gross Date: Sat, 10 Jan 2026 05:15:06 -0500 Subject: [PATCH 043/866] fixed pdgid lookup issue --- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 242769aa07..00620e8378 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -262,7 +262,7 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) 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 = (*iter)->pdg_id(); + int pid = std::abs((*iter)->pdg_id()); double eta = p.eta(); if((_doEtaHighCut || _doBothEtaCut ) && eta > _theEtaHigh) continue; if((_doEtaLowCut || _doBothEtaCut ) && eta < _theEtaLow) continue; From 5628bd2ead56b013c7747ed54bac89cabdbf7601 Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Sat, 10 Jan 2026 11:50:00 -0500 Subject: [PATCH 044/866] code rabbit found a bug in the return value --- .../jetbackground/DetermineTowerBackground.cc | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 7f021f4f39..c359b6914c 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -62,7 +62,7 @@ int DetermineTowerBackground::InitRun(PHCompositeNode *topNode) { std::cout << "Loading the average calo v2" << std::endl; } - if (!LoadCalibrations()) + if (LoadCalibrations()) { std::cout << "Load calibrations failed." << std::endl; return Fun4AllReturnCodes::ABORTRUN; @@ -78,25 +78,20 @@ int DetermineTowerBackground::LoadCalibrations() CDBTTree *cdbtree_calo_v2 = nullptr; - std::string calibdir; + std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); if (m_overwrite_average_calo_v2) { calibdir = m_overwrite_average_calo_v2_path; } - else - { - calibdir = CDBInterface::instance()->getUrl(m_calibName); - } if (calibdir.empty()) { - std::cout << "Could not find and load histograms for EMCAL LUTs! defaulting to the identity table!" << std::endl; + std::cout << "Could not find filename for calo average v2, exiting" << std::endl; exit(-1); } - else - { - cdbtree_calo_v2 = new CDBTTree(calibdir); - } + + cdbtree_calo_v2 = new CDBTTree(calibdir); + cdbtree_calo_v2->LoadCalibrations(); From 62c7a10ac75901e77b8f97c2186ddc74c8191233 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 10 Jan 2026 16:52:22 -0500 Subject: [PATCH 045/866] add hook to run shell script before opening an input file --- offline/framework/fun4all/InputFileHandler.cc | 11 +++++++++++ offline/framework/fun4all/InputFileHandler.h | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/offline/framework/fun4all/InputFileHandler.cc b/offline/framework/fun4all/InputFileHandler.cc index 8939b67568..0e0333f4a6 100644 --- a/offline/framework/fun4all/InputFileHandler.cc +++ b/offline/framework/fun4all/InputFileHandler.cc @@ -89,6 +89,17 @@ 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); + } + RunBeforeOpening(stringvec); + } + std::cout << "closing " << m_FileName << ", opening " << *iter << std::endl; if (fileopen(*iter)) { std::cout << PHWHERE << " could not open file: " << *iter << std::endl; diff --git a/offline/framework/fun4all/InputFileHandler.h b/offline/framework/fun4all/InputFileHandler.h index 823ae33b38..646c42b055 100644 --- a/offline/framework/fun4all/InputFileHandler.h +++ b/offline/framework/fun4all/InputFileHandler.h @@ -32,12 +32,19 @@ 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; } + void SetOpeningScript(const std::string &script) {m_RunBeforeOpeningScript = script;} + const std::string &GetOpeningScript() const {return m_RunBeforeOpeningScript;} + void SetOpeningScriptArgs(const std::string &args) {m_OpeningArgs = args;} + const std::string &GetOpeningScriptArgs() const {return m_OpeningArgs;} + void RunBeforeOpening(const std::vector &stringvec); private: int m_IsOpen{0}; int m_Repeat{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 From 5d5a980f6c6c53c795e3921a53450ac6eaed5189 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 10 Jan 2026 17:29:25 -0500 Subject: [PATCH 046/866] do not save cdb files if they are empty (do not exist) --- offline/framework/ffamodules/CDBInterface.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index 2b4feef203..2a0b3e1b3c 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -185,11 +185,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; } From fd444863e9a16fa6e644291f04fb53028990ee8d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 10 Jan 2026 17:29:38 -0500 Subject: [PATCH 047/866] cleanup, modernize --- offline/framework/ffamodules/CDBInterface.h | 1 - offline/framework/ffamodules/FlagHandler.h | 4 +--- offline/framework/ffamodules/HeadReco.h | 4 +--- offline/framework/ffamodules/SyncReco.h | 6 ++---- offline/framework/ffamodules/Timing.cc | 2 -- offline/framework/ffamodules/Timing.h | 8 +++----- 6 files changed, 7 insertions(+), 18 deletions(-) diff --git a/offline/framework/ffamodules/CDBInterface.h b/offline/framework/ffamodules/CDBInterface.h index c88fae9dee..4132b35a34 100644 --- a/offline/framework/ffamodules/CDBInterface.h +++ b/offline/framework/ffamodules/CDBInterface.h @@ -10,7 +10,6 @@ #include #include // for tuple -class PHCompositeNode; class SphenixClient; class CDBInterface : public SubsysReco diff --git a/offline/framework/ffamodules/FlagHandler.h b/offline/framework/ffamodules/FlagHandler.h index f5cc06bcdb..fd7e40cca3 100644 --- a/offline/framework/ffamodules/FlagHandler.h +++ b/offline/framework/ffamodules/FlagHandler.h @@ -7,14 +7,12 @@ #include -class PHCompositeNode; - 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 diff --git a/offline/framework/ffamodules/HeadReco.h b/offline/framework/ffamodules/HeadReco.h index ca2f6cf34e..53fbc3c6c3 100644 --- a/offline/framework/ffamodules/HeadReco.h +++ b/offline/framework/ffamodules/HeadReco.h @@ -7,13 +7,11 @@ #include // for string -class PHCompositeNode; - 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; diff --git a/offline/framework/ffamodules/SyncReco.h b/offline/framework/ffamodules/SyncReco.h index 0a490302a0..73d0954593 100644 --- a/offline/framework/ffamodules/SyncReco.h +++ b/offline/framework/ffamodules/SyncReco.h @@ -5,13 +5,11 @@ #include -class PHCompositeNode; - 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 +22,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 */ diff --git a/offline/framework/ffamodules/Timing.cc b/offline/framework/ffamodules/Timing.cc index f662ba1b33..16210e4f73 100644 --- a/offline/framework/ffamodules/Timing.cc +++ b/offline/framework/ffamodules/Timing.cc @@ -3,8 +3,6 @@ #include #include // for SubsysReco -#include - #include Timing::Timing(const std::string &name) diff --git a/offline/framework/ffamodules/Timing.h b/offline/framework/ffamodules/Timing.h index 01b95638e0..a9a5ccd39d 100644 --- a/offline/framework/ffamodules/Timing.h +++ b/offline/framework/ffamodules/Timing.h @@ -8,15 +8,13 @@ #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; + ~Timing() override = default; + int InitRun(PHCompositeNode * /*topNode*/) override; + int process_event(PHCompositeNode * /*topNode*/) override; void SetCallCounter(unsigned int i) { calls = i; } private: From 51336ae67e987750787913f562142fd6352f54b7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 10 Jan 2026 18:57:49 -0500 Subject: [PATCH 048/866] fix clang-tidy for HepMCTrigger --- .../HepMCTrigger/HepMCParticleTrigger.cc | 384 ++++++++++-------- .../HepMCTrigger/HepMCParticleTrigger.h | 48 +-- 2 files changed, 229 insertions(+), 203 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 00620e8378..e60473bdef 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -14,9 +14,9 @@ #include #include +#include #include #include -#include //____________________________________________________________________________.. // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) HepMCParticleTrigger::HepMCParticleTrigger(float trigger_thresh, int n_incom, bool up_lim, const std::string& name) @@ -24,45 +24,12 @@ HepMCParticleTrigger::HepMCParticleTrigger(float trigger_thresh, int n_incom, bo , threshold(trigger_thresh) , goal_event_number(n_incom) , set_event_limit(up_lim) - , _theEtaHigh(-999.9) - , _theEtaLow(-999.9) - , _thePtHigh(999.9) - , _thePtLow(-999.9) - , _thePHigh(999.9) - , _thePLow(-999.9) - , _thePzHigh(999.9) - , _thePzLow(-999.9) - , - - _doEtaHighCut(false) - , _doEtaLowCut(false) - , _doBothEtaCut(false) - , - - _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; - } + if (threshold != 0) + { + _doPtLowCut = true; + _thePtLow = threshold; + } } //____________________________________________________________________________.. @@ -77,7 +44,7 @@ int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } } - bool good_event {false}; + bool good_event{false}; PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); if (!phg) { @@ -101,137 +68,170 @@ int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } } - if (good_event) - { - n_good++; - } + if (good_event) + { + n_good++; + } return Fun4AllReturnCodes::EVENT_OK; } void HepMCParticleTrigger::AddParticle(int particlePid) { - _theParticles.push_back(particlePid); - return; + _theParticles.push_back(particlePid); + return; } -void HepMCParticleTrigger::AddParticles(std::vector particles) +void HepMCParticleTrigger::AddParticles(const std::vector& particles) { - for(auto p:particles) _theParticles.push_back(p); - return; + for (auto p : particles) + { + _theParticles.push_back(p); + } + return; } -void HepMCParticleTrigger::SetPtHigh(double pt) +void HepMCParticleTrigger::SetPtHigh(double pt) { - _thePtHigh=pt; - _doPtHighCut=true; - if(_doPtLowCut) _doBothPtCut=true; - return; + _thePtHigh = pt; + _doPtHighCut = true; + if (_doPtLowCut) + { + _doBothPtCut = true; + } + return; } -void HepMCParticleTrigger::SetPtLow(double pt) +void HepMCParticleTrigger::SetPtLow(double pt) { - _thePtLow=pt; - _doPtLowCut=true; - if(_doPtHighCut) _doBothPtCut=true; - return; + _thePtLow = pt; + _doPtLowCut = true; + if (_doPtHighCut) + { + _doBothPtCut = true; + } + return; } -void HepMCParticleTrigger::SetPtHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetPtHighLow(double ptHigh, double ptLow) { - _thePtHigh=ptHigh; - _doPtHighCut=true; - _thePtLow=ptLow; - _doPtLowCut=true; - _doBothPtCut=true; - return; + _thePtHigh = ptHigh; + _doPtHighCut = true; + _thePtLow = ptLow; + _doPtLowCut = true; + _doBothPtCut = true; + return; } -void HepMCParticleTrigger::SetPHigh(double pt) +void HepMCParticleTrigger::SetPHigh(double pt) { - _thePHigh=pt; - _doPHighCut=true; - if(_doPLowCut) _doBothPCut=true; - return; + _thePHigh = pt; + _doPHighCut = true; + if (_doPLowCut) + { + _doBothPCut = true; + } + return; } -void HepMCParticleTrigger::SetPLow(double pt) +void HepMCParticleTrigger::SetPLow(double pt) { - _thePLow=pt; - _doPLowCut=true; - if(_doPHighCut) _doBothPCut=true; - return; + _thePLow = pt; + _doPLowCut = true; + if (_doPHighCut) + { + _doBothPCut = true; + } + return; } -void HepMCParticleTrigger::SetPHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetPHighLow(double ptHigh, double ptLow) { - _thePHigh=ptHigh; - _doPHighCut=true; - _thePLow=ptLow; - _doPLowCut=true; - _doBothPCut=true; - return; + _thePHigh = ptHigh; + _doPHighCut = true; + _thePLow = ptLow; + _doPLowCut = true; + _doBothPCut = true; + return; } -void HepMCParticleTrigger::SetPzHigh(double pt) +void HepMCParticleTrigger::SetPzHigh(double pt) { - _thePzHigh=pt; - _doPzHighCut=true; - if(_doPzLowCut) _doBothPzCut=true; - return; + _thePzHigh = pt; + _doPzHighCut = true; + if (_doPzLowCut) + { + _doBothPzCut = true; + } + return; } -void HepMCParticleTrigger::SetPzLow(double pt) +void HepMCParticleTrigger::SetPzLow(double pt) { - _thePzLow=pt; - _doPzLowCut=true; - if(_doPzHighCut) _doBothPzCut=true; - return; + _thePzLow = pt; + _doPzLowCut = true; + if (_doPzHighCut) + { + _doBothPzCut = true; + } + return; } -void HepMCParticleTrigger::SetPzHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetPzHighLow(double ptHigh, double ptLow) { - _thePzHigh=ptHigh; - _doPzHighCut=true; - _thePzLow=ptLow; - _doPzLowCut=true; - _doBothPzCut=true; - return; + _thePzHigh = ptHigh; + _doPzHighCut = true; + _thePzLow = ptLow; + _doPzLowCut = true; + _doBothPzCut = true; + return; } -void HepMCParticleTrigger::SetEtaHigh(double pt) +void HepMCParticleTrigger::SetEtaHigh(double pt) { - _theEtaHigh=pt; - _doEtaHighCut=true; - if(_doEtaLowCut) _doBothEtaCut=true; - return; + _theEtaHigh = pt; + _doEtaHighCut = true; + if (_doEtaLowCut) + { + _doBothEtaCut = true; + } + return; } -void HepMCParticleTrigger::SetEtaLow(double pt) +void HepMCParticleTrigger::SetEtaLow(double pt) { - _theEtaLow=pt; - _doEtaLowCut=true; - if(_doEtaHighCut) _doBothEtaCut=true; - return; + _theEtaLow = pt; + _doEtaLowCut = true; + if (_doEtaHighCut) + { + _doBothEtaCut = true; + } + return; } -void HepMCParticleTrigger::SetEtaHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetEtaHighLow(double ptHigh, double ptLow) { - _theEtaHigh=ptHigh; - _doEtaHighCut=true; - _theEtaLow=ptLow; - _doEtaLowCut=true; - _doBothEtaCut=true; - return; + _theEtaHigh = ptHigh; + _doEtaHighCut = true; + _theEtaLow = ptLow; + _doEtaLowCut = true; + _doBothEtaCut = true; + return; } -void HepMCParticleTrigger::SetAbsEtaHigh(double pt) +void HepMCParticleTrigger::SetAbsEtaHigh(double pt) { - _theEtaHigh=pt; - _doAbsEtaHighCut=true; - if(_doAbsEtaLowCut) _doBothAbsEtaCut=true; - return; + _theEtaHigh = pt; + _doAbsEtaHighCut = true; + if (_doAbsEtaLowCut) + { + _doBothAbsEtaCut = true; + } + return; } -void HepMCParticleTrigger::SetAbsEtaLow(double pt) +void HepMCParticleTrigger::SetAbsEtaLow(double pt) { - _theEtaLow=pt; - _doAbsEtaLowCut=true; - if(_doAbsEtaHighCut) _doBothAbsEtaCut=true; - return; + _theEtaLow = pt; + _doAbsEtaLowCut = true; + if (_doAbsEtaHighCut) + { + _doBothAbsEtaCut = true; + } + return; } -void HepMCParticleTrigger::SetAbsEtaHighLow(double ptHigh, double ptLow) +void HepMCParticleTrigger::SetAbsEtaHighLow(double ptHigh, double ptLow) { - _theEtaHigh=ptHigh; - _doAbsEtaHighCut=true; - _theEtaLow=ptLow; - _doAbsEtaLowCut=true; - _doBothAbsEtaCut=true; - return; + _theEtaHigh = ptHigh; + _doAbsEtaHighCut = true; + _theEtaLow = ptLow; + _doAbsEtaLowCut = true; + _doBothAbsEtaCut = true; + return; } bool HepMCParticleTrigger::isGoodEvent(HepMC::GenEvent* e1) { @@ -241,53 +241,97 @@ bool HepMCParticleTrigger::isGoodEvent(HepMC::GenEvent* e1) return true; }*/ std::vector n_trigger_particles = getParticles(e1); - for(auto ntp:n_trigger_particles) + for (auto ntp : n_trigger_particles) { - if(ntp <=0 ) return false; //make sure all particles have at least 1 + if (ntp <= 0) + { + return false; // make sure all particles have at least 1 + } } return true; } 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) +{ + 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; - else{ - 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.find(pid) != particle_types.end()) particle_types[pid]++; - else particle_types[pid]=1; - } + 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; + } } - for(auto p:_theParticles) + 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 - } + n_trigger.push_back(particleAboveThreshold(particle_types, p)); // make sure we have at least one of each required particle + } return n_trigger; } -int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_particles, int trigger_particle ) +int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_particles, int trigger_particle) { - // search through for the number of identified trigger particles passing cuts + // 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; - else return 0; + if (it != n_particles.end()) + { + return it->second; + } + return 0; } diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index a0124f5292..33e9a1316f 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -7,10 +7,10 @@ #include +#include +#include #include #include -#include -#include class PHCompositeNode; namespace HepMC @@ -25,38 +25,19 @@ class HepMCParticleTrigger : public SubsysReco ~HepMCParticleTrigger() override = default; - /** Called during initialization. - Typically this is where you can book histograms, and e.g. - register them to Fun4AllServer (so they can be output to file - using Fun4AllServer::dumpHistos() method). - */ - - /** Called for first event when run number is known. - Typically this is where you may want to fetch data from - database, because you know the run number. A place - to book histograms which have to know the run number. - */ - /** 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(std::vector); + void AddParticles(const std::vector&); void AddParticle(int); -/* void AddParents(const std::string &parents); - void AddParents(int parent); - void AddParents(std::vector parents); - void AddParentspID(std::vector parents); -*/ + /* 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); @@ -64,11 +45,11 @@ class HepMCParticleTrigger : public SubsysReco 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); @@ -76,15 +57,16 @@ class HepMCParticleTrigger : public SubsysReco void SetPzHigh(double); void SetPzLow(double); void SetPzHighLow(double, double); - + 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}; + // std::vector _theParentsi {}; + std::vector _theParticles{}; + bool m_doStableParticleOnly{true}; float threshold{0.}; int goal_event_number{1000}; int n_evts{0}; From b0df38c7862f4cc32eb8299d3bbbc3021e54a4c9 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 10 Jan 2026 21:37:25 -0500 Subject: [PATCH 049/866] fix typo in initialiation --- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index 33e9a1316f..f0f9f78e3d 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -73,7 +73,7 @@ class HepMCParticleTrigger : public SubsysReco int n_good{0}; bool set_event_limit{false}; - float _theEtaHigh{-999.9}; + float _theEtaHigh{999.9}; float _theEtaLow{-999.9}; float _thePtHigh{999.9}; float _thePtLow{-999.9}; From 11cb711723dcd5aef7c01433ac1fccc3955e47bc Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Mon, 12 Jan 2026 15:10:44 -0500 Subject: [PATCH 050/866] fixed crash when calopackets are empty --- offline/packages/mbd/MbdEvent.cc | 42 ++++++++++++++++++++++++++++---- offline/packages/mbd/MbdReco.cc | 7 +++--- offline/packages/mbd/MbdReco.h | 2 ++ offline/packages/mbd/MbdSig.h | 2 ++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index d8c72b4395..9b68641cbd 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -484,9 +484,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(); */ @@ -548,6 +556,7 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer // int flag_err = 0; Packet *p[2]{nullptr}; + int tot_nsamples{0}; for (int ipkt = 0; ipkt < 2; ipkt++) { int pktid = 1001 + ipkt; // packet id @@ -565,6 +574,7 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer if (p[ipkt]) { _nsamples = p[ipkt]->iValue(0, "SAMPLES"); + tot_nsamples += _nsamples; { static int counter = 0; if ( counter<1 ) @@ -618,6 +628,12 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer } } + // If packets are missing, stop processing + if ( tot_nsamples == 0 ) + { + return -1002; + } + // Fill MbdRawContainer int status = ProcessPackets(bbcraws); if ( _fitsonly ) @@ -637,7 +653,7 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) // 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 +689,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) { @@ -739,6 +760,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 +880,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 + } + } } } diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index c19ed37ba9..004e191e78 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -103,7 +103,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 +126,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 +136,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; diff --git a/offline/packages/mbd/MbdReco.h b/offline/packages/mbd/MbdReco.h index 0dfc7d7cbc..6e00de68f3 100644 --- a/offline/packages/mbd/MbdReco.h +++ b/offline/packages/mbd/MbdReco.h @@ -52,6 +52,8 @@ class MbdReco : public SubsysReco float m_tres = 0.05; std::unique_ptr m_gaussian = nullptr; + int _evtnum{-1}; + std::unique_ptr m_mbdevent{nullptr}; Event *m_event{nullptr}; std::arraym_mbdpacket{nullptr}; diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index 0b8b420ffa..e933f33392 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -32,6 +32,8 @@ 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); + int GetNSamples() { return _nsamples; } + void SetCalib(MbdCalib *mcal); TH1 *GetHist() { return hpulse; } From 47ab938f88fedef594dd30a2a29ce9522ead5c16 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 12 Jan 2026 17:02:32 -0500 Subject: [PATCH 051/866] call script before opening --- offline/framework/fun4all/InputFileHandler.cc | 50 +++++++++++++++++-- offline/framework/fun4all/InputFileHandler.h | 13 ++--- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/offline/framework/fun4all/InputFileHandler.cc b/offline/framework/fun4all/InputFileHandler.cc index 0e0333f4a6..a20a6befe9 100644 --- a/offline/framework/fun4all/InputFileHandler.cc +++ b/offline/framework/fun4all/InputFileHandler.cc @@ -3,10 +3,13 @@ #include +#include + #include #include #include #include +#include int InputFileHandler::AddFile(const std::string &filename) { @@ -93,13 +96,15 @@ int InputFileHandler::OpenNextFile() { std::vector stringvec; stringvec.push_back(*iter); - if (! m_FileName.empty()) + if (!m_FileName.empty()) + { + stringvec.push_back(m_FileName); + } + if (RunBeforeOpening(stringvec)) { - stringvec.push_back(m_FileName); + std::cout << PHWHERE << " RunBeforeOpening() failed" << std::endl; } - RunBeforeOpening(stringvec); } - std::cout << "closing " << m_FileName << ", opening " << *iter << std::endl; if (fileopen(*iter)) { std::cout << PHWHERE << " could not open file: " << *iter << std::endl; @@ -156,3 +161,40 @@ int InputFileHandler::fileopen(const std::string &fname) std::cout << "InputFileHandler::fileopen opening " << fname << std::endl; return 0; } + +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 << "RunAfterClosing() closing script " + << m_RunBeforeOpeningScript << " is not owner executable" << std::endl; + return -1; + } + std::string fullcmd = m_RunBeforeOpeningScript + " " + m_OpeningArgs; + for (auto iter : stringvec) + { + fullcmd += " " + iter; + } + + if (m_Verbosity > 1) + { + std::cout << PHWHERE << " running " << fullcmd << std::endl; + } + int iret = gSystem->Exec(fullcmd.c_str()); + + if (iret) + { + iret = iret >> 8U; + } + return iret; +} diff --git a/offline/framework/fun4all/InputFileHandler.h b/offline/framework/fun4all/InputFileHandler.h index 646c42b055..49df4aa379 100644 --- a/offline/framework/fun4all/InputFileHandler.h +++ b/offline/framework/fun4all/InputFileHandler.h @@ -4,13 +4,14 @@ #include #include #include +#include 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,11 +33,11 @@ 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; } - void SetOpeningScript(const std::string &script) {m_RunBeforeOpeningScript = script;} - const std::string &GetOpeningScript() const {return m_RunBeforeOpeningScript;} - void SetOpeningScriptArgs(const std::string &args) {m_OpeningArgs = args;} - const std::string &GetOpeningScriptArgs() const {return m_OpeningArgs;} - void RunBeforeOpening(const std::vector &stringvec); + void SetOpeningScript(const std::string &script) { m_RunBeforeOpeningScript = script; } + const std::string &GetOpeningScript() const { return m_RunBeforeOpeningScript; } + 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}; From 7eb599f293223b5530071e4ba02bfe301e2edbe9 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 12 Jan 2026 17:17:20 -0500 Subject: [PATCH 052/866] make rabbit happy --- offline/framework/fun4all/InputFileHandler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4all/InputFileHandler.cc b/offline/framework/fun4all/InputFileHandler.cc index a20a6befe9..4e285f3b5d 100644 --- a/offline/framework/fun4all/InputFileHandler.cc +++ b/offline/framework/fun4all/InputFileHandler.cc @@ -176,7 +176,7 @@ int InputFileHandler::RunBeforeOpening(const std::vector &stringvec } if (!((std::filesystem::status(m_RunBeforeOpeningScript).permissions() & std::filesystem::perms::owner_exec) == std::filesystem::perms::owner_exec)) { - std::cout << PHWHERE << "RunAfterClosing() closing script " + std::cout << PHWHERE << "RunBeforeOpeningScript script " << m_RunBeforeOpeningScript << " is not owner executable" << std::endl; return -1; } From 5d10d3e240bbbbf4720810f486b25202ae9abc38 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 12 Jan 2026 20:18:02 -0500 Subject: [PATCH 053/866] fix clang-tidy for InputFileHandler --- offline/framework/fun4all/InputFileHandler.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4all/InputFileHandler.cc b/offline/framework/fun4all/InputFileHandler.cc index 4e285f3b5d..0fdc858db8 100644 --- a/offline/framework/fun4all/InputFileHandler.cc +++ b/offline/framework/fun4all/InputFileHandler.cc @@ -181,7 +181,7 @@ int InputFileHandler::RunBeforeOpening(const std::vector &stringvec return -1; } std::string fullcmd = m_RunBeforeOpeningScript + " " + m_OpeningArgs; - for (auto iter : stringvec) + for (const auto& iter : stringvec) { fullcmd += " " + iter; } @@ -190,11 +190,11 @@ int InputFileHandler::RunBeforeOpening(const std::vector &stringvec { std::cout << PHWHERE << " running " << fullcmd << std::endl; } - int iret = gSystem->Exec(fullcmd.c_str()); + unsigned int iret = gSystem->Exec(fullcmd.c_str()); if (iret) { iret = iret >> 8U; } - return iret; + return static_cast (iret); } From f9373cf567102acb861ddebec86acf21f4fe0a65 Mon Sep 17 00:00:00 2001 From: silas-gross Date: Mon, 12 Jan 2026 22:18:10 -0500 Subject: [PATCH 054/866] Fixed issues around the edges of Jet, set better default behavior of Particle. Keeping the Pythia Trigger style for now --- generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc | 3 +++ .../Herwig/HepMCTrigger/HepMCParticleTrigger.cc | 15 +++++++-------- .../Herwig/HepMCTrigger/HepMCParticleTrigger.h | 12 ++++++------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc index 02ca208f25..b22db801b5 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc @@ -96,6 +96,8 @@ 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); @@ -122,6 +124,7 @@ 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++; diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 00620e8378..db5fff40f0 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -24,19 +24,19 @@ HepMCParticleTrigger::HepMCParticleTrigger(float trigger_thresh, int n_incom, bo , threshold(trigger_thresh) , goal_event_number(n_incom) , set_event_limit(up_lim) - , _theEtaHigh(-999.9) - , _theEtaLow(-999.9) + , _theEtaHigh(1) + , _theEtaLow(-1) , _thePtHigh(999.9) - , _thePtLow(-999.9) + , _thePtLow(0) , _thePHigh(999.9) , _thePLow(-999.9) , _thePzHigh(999.9) , _thePzLow(-999.9) , - _doEtaHighCut(false) - , _doEtaLowCut(false) - , _doBothEtaCut(false) + _doEtaHighCut(true) + , _doEtaLowCut(true) + , _doBothEtaCut(true) , _doAbsEtaHighCut(false) @@ -48,8 +48,7 @@ HepMCParticleTrigger::HepMCParticleTrigger(float trigger_thresh, int n_incom, bo , _doPtLowCut(false) , _doBothPtCut(false) , - - _doPHighCut(false) + _doPHighCut(false) , _doPLowCut(false) , _doBothPCut(false) , diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index a0124f5292..054a7958e3 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -49,7 +49,7 @@ class HepMCParticleTrigger : public SubsysReco /// Called at the end of all processing. /// Reset - void AddParticles(std::vector); + void AddParticles(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); @@ -91,8 +91,8 @@ class HepMCParticleTrigger : public SubsysReco int n_good{0}; bool set_event_limit{false}; - float _theEtaHigh{-999.9}; - float _theEtaLow{-999.9}; + float _theEtaHigh{1.1}; + float _theEtaLow{-1.1}; float _thePtHigh{999.9}; float _thePtLow{-999.9}; float _thePHigh{999.9}; @@ -100,9 +100,9 @@ class HepMCParticleTrigger : public SubsysReco float _thePzHigh{999.9}; float _thePzLow{-999.9}; - bool _doEtaHighCut{false}; - bool _doEtaLowCut{false}; - bool _doBothEtaCut{false}; + bool _doEtaHighCut{true}; + bool _doEtaLowCut{true}; + bool _doBothEtaCut{true}; bool _doAbsEtaHighCut{false}; bool _doAbsEtaLowCut{false}; From a284e7e6ed03611202bb5747d14bc9b68a4a6470 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:44:06 -0500 Subject: [PATCH 055/866] sEPD Event Plane Calibration This commit introduces the sEPD Q Vector calibration engine and CDB generation components for the sEPD Event Plane calibration pipeline. It establishes a centralized definition system and implements the physics logic for re-centering, flattening, and database payload generation. Summary: - sEPD_TreeGen.h/cc: Extract event-level and tower-level sEPD data into TTrees and QA histograms. - QVecDefs.h: Establishes a shared namespace for harmonics, centrality bins, and standardized naming conventions for histograms. - QVecCalib.h/cc: Orchestrates the three-pass calibration logic (Re-centering, Flattening, and Validation). - QVecCDB.h/cc: Manages the transformation of calibration moments and bad tower maps into standardized CDB payloads. - GenQVecCalib.cc & GenQVecCDB.cc: Executable drivers for the calibration processing and database commitment stages. --- .../sepd/sepd_eventplanecalib/GenQVecCDB.cc | 43 + .../sepd/sepd_eventplanecalib/GenQVecCalib.cc | 54 + .../sepd/sepd_eventplanecalib/Makefile.am | 68 + .../sepd/sepd_eventplanecalib/QVecCDB.cc | 192 +++ .../sepd/sepd_eventplanecalib/QVecCDB.h | 139 ++ .../sepd/sepd_eventplanecalib/QVecCalib.cc | 1172 +++++++++++++++++ .../sepd/sepd_eventplanecalib/QVecCalib.h | 386 ++++++ .../sepd/sepd_eventplanecalib/QVecDefs.h | 55 + .../sepd/sepd_eventplanecalib/autogen.sh | 8 + .../sepd/sepd_eventplanecalib/configure.ac | 16 + .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 289 ++++ .../sepd/sepd_eventplanecalib/sEPD_TreeGen.h | 177 +++ 12 files changed, 2599 insertions(+) create mode 100644 calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc create mode 100644 calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc create mode 100644 calibrations/sepd/sepd_eventplanecalib/Makefile.am create mode 100644 calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc create mode 100644 calibrations/sepd/sepd_eventplanecalib/QVecCDB.h create mode 100644 calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc create mode 100644 calibrations/sepd/sepd_eventplanecalib/QVecCalib.h create mode 100644 calibrations/sepd/sepd_eventplanecalib/QVecDefs.h create mode 100644 calibrations/sepd/sepd_eventplanecalib/autogen.sh create mode 100644 calibrations/sepd/sepd_eventplanecalib/configure.ac create mode 100644 calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc create mode 100644 calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h diff --git a/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc new file mode 100644 index 0000000000..7118d71b99 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc @@ -0,0 +1,43 @@ +#include "QVecCDB.h" + +#include +#include + +int main(int argc, const char* const argv[]) +{ + const std::vector args(argv, argv + argc); + + if (args.size() < 3 || args.size() > 5) + { + std::cout << "Usage: " << args[0] << " input_file runnumber [output_dir] [cdb_tag]" << std::endl; + return 1; + } + + const std::string &input_file = args[1]; + int runnumber = std::stoi(args[2]); + const std::string output_dir = (args.size() >= 4) ? args[3] : "."; + const std::string cdb_tag = (args.size() >= 5) ? args[4] : "new_newcdbtag_v008"; + + std::cout << std::format("{:#<20}\n", ""); + std::cout << std::format("Analysis Params\n"); + std::cout << std::format("Input File: {}\n", input_file); + std::cout << std::format("Run: {}\n", runnumber); + std::cout << std::format("Output Dir: {}\n", output_dir); + std::cout << std::format("CDB Tag: {}\n", cdb_tag); + std::cout << std::format("{:#<20}\n", ""); + + try + { + QVecCDB analysis(input_file, runnumber, output_dir, cdb_tag); + analysis.run(); + } + catch (const std::exception& e) + { + std::cout << "An exception occurred: " << e.what() << std::endl; + return 1; + } + + std::cout << "======================================" << std::endl; + std::cout << "done" << std::endl; + return 0; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc new file mode 100644 index 0000000000..67ec64fbeb --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc @@ -0,0 +1,54 @@ +#include "QVecCalib.h" + +#include + +int main(int argc, const char* const argv[]) +{ + const std::vector args(argv, argv + argc); + + if (args.size() < 4 || args.size() > 7) + { + std::cout << "Usage: " << args[0] << " [pass] [events] [output_directory]" << std::endl; + return 1; // Indicate error + } + + const std::string &input_file = args[1]; + const std::string &input_hist = args[2]; + const std::string &input_Q_calib = args[3]; + const std::string &pass_str = (argc >= 5) ? args[4] : "ComputeRecentering"; // Default to the first pass + long long events = (argc >= 6) ? std::stoll(args[5]) : 0; + std::string output_dir = (argc >= 7) ? args[6] : "."; + + const std::map pass_map = { + {"ComputeRecentering", QVecCalib::Pass::ComputeRecentering}, + {"ApplyRecentering", QVecCalib::Pass::ApplyRecentering}, + {"ApplyFlattening", QVecCalib::Pass::ApplyFlattening} + }; + + QVecCalib::Pass pass = QVecCalib::Pass::ComputeRecentering; + if (pass_map.contains(pass_str)) + { + pass = pass_map.at(pass_str); + } + else + { + std::cout << "Error: Invalid pass specified: " << pass_str << std::endl; + std::cout << "Available passes are: ComputeRecentering, ApplyRecentering, ApplyFlattening" << std::endl; + return 1; + } + + try + { + QVecCalib analysis(input_file, input_hist, input_Q_calib, static_cast(pass), events, output_dir); + analysis.run(); + } + catch (const std::exception& e) + { + std::cout << "An exception occurred: " << e.what() << std::endl; + return 1; + } + + std::cout << "======================================" << std::endl; + std::cout << "done" << std::endl; + return 0; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/Makefile.am b/calibrations/sepd/sepd_eventplanecalib/Makefile.am new file mode 100644 index 0000000000..f1da8a7800 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/Makefile.am @@ -0,0 +1,68 @@ +AUTOMAKE_OPTIONS = foreign + +bin_PROGRAMS = \ + GenQVecCalib \ + GenQVecCDB + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -I$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 \ + `root-config --libs` + +pkginclude_HEADERS = \ + sEPD_TreeGen.h \ + QVecCalib.h \ + QVecCDB.h \ + QVecDefs.h + +lib_LTLIBRARIES = \ + libsepd_eventplanecalib.la + +libsepd_eventplanecalib_la_SOURCES = \ + sEPD_TreeGen.cc \ + QVecCalib.cc \ + QVecCDB.cc + +libsepd_eventplanecalib_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lcentrality_io \ + -lfun4all \ + -lffamodules \ + -lglobalvertex_io \ + -lcalotrigger_io \ + -lcalotrigger \ + -lcdbobjects \ + -lepd_io + +GenQVecCalib_SOURCES = GenQVecCalib.cc +# GenQVecCalib_CXXFLAGS = -fsanitize=address +GenQVecCalib_LDADD = libsepd_eventplanecalib.la + +GenQVecCDB_SOURCES = GenQVecCDB.cc +# GenQVecCDB_CXXFLAGS = -fsanitize=address +GenQVecCDB_LDADD = libsepd_eventplanecalib.la + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libsepd_eventplanecalib.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc new file mode 100644 index 0000000000..96e18d1ffe --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc @@ -0,0 +1,192 @@ +#include "QVecCDB.h" + +// ==================================================================== +// sPHENIX Includes +// ==================================================================== +#include +#include + +// ==================================================================== +// ROOT Includes +// ==================================================================== +#include + +// ==================================================================== +// Standard C++ Includes +// ==================================================================== +#include +#include +#include +#include +#include + +template +std::unique_ptr QVecCDB::load_and_clone(const std::string& name) { + auto* obj = dynamic_cast(m_tfile->Get(name.c_str())); + if (!obj) + { + throw std::runtime_error(std::format("Could not find histogram '{}' in file '{}'", name, m_tfile->GetName())); + } + return std::unique_ptr(static_cast(obj->Clone())); +} + +QVecShared::CorrectionMoments& QVecCDB::getData(size_t h_idx, size_t cent_bin, QVecShared::Subdetector sub) { + return m_correction_data[h_idx][cent_bin][static_cast(sub)]; +} + +void QVecCDB::load_data() +{ + m_tfile = std::unique_ptr(TFile::Open(m_input_file.c_str())); + + // Check if the file was opened successfully. + if (!m_tfile || m_tfile->IsZombie()) + { + throw std::runtime_error(std::format("Could not open file '{}'", m_input_file)); + } + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + load_correction_data(h_idx); + } +} + +void QVecCDB::load_correction_data(size_t h_idx) +{ + int n = m_harmonics[h_idx]; + + // Load recentering terms (x, y) + auto pS_x = load_and_clone(QVecShared::get_hist_name("S", "x", n)); + auto pS_y = load_and_clone(QVecShared::get_hist_name("S", "y", n)); + auto pN_x = load_and_clone(QVecShared::get_hist_name("N", "x", n)); + auto pN_y = load_and_clone(QVecShared::get_hist_name("N", "y", n)); + + // Load flattening terms (xx, yy, xy) + auto pS_xx = load_and_clone(QVecShared::get_hist_name("S", "xx", n)); + auto pS_yy = load_and_clone(QVecShared::get_hist_name("S", "yy", n)); + auto pS_xy = load_and_clone(QVecShared::get_hist_name("S", "xy", n)); + auto pN_xx = load_and_clone(QVecShared::get_hist_name("N", "xx", n)); + auto pN_yy = load_and_clone(QVecShared::get_hist_name("N", "yy", n)); + auto pN_xy = load_and_clone(QVecShared::get_hist_name("N", "xy", n)); + + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int bin = static_cast(cent_bin) + 1; // ROOT bins start at 1 + + // South + auto& dataS = getData(h_idx, cent_bin, QVecShared::Subdetector::S); + dataS.avg_Q = {pS_x->GetBinContent(bin), pS_y->GetBinContent(bin)}; + dataS.avg_Q_xx = pS_xx->GetBinContent(bin); + dataS.avg_Q_yy = pS_yy->GetBinContent(bin); + dataS.avg_Q_xy = pS_xy->GetBinContent(bin); + + // North + auto& dataN = getData(h_idx, cent_bin, QVecShared::Subdetector::N); + dataN.avg_Q = {pN_x->GetBinContent(bin), pN_y->GetBinContent(bin)}; + dataN.avg_Q_xx = pN_xx->GetBinContent(bin); + dataN.avg_Q_yy = pN_yy->GetBinContent(bin); + dataN.avg_Q_xy = pN_xy->GetBinContent(bin); + } +} + +void QVecCDB::write_cdb() +{ + std::string output_dir = std::format("{}/{}", m_output_dir, m_runnumber); + + if (std::filesystem::create_directories(output_dir)) + { + std::cout << std::format("Success: Directory {} created.\n", output_dir); + } + else + { + std::cout << std::format("Info: Directory {} already exists.\n", output_dir); + } + + write_cdb_EventPlane(output_dir); + write_cdb_BadTowers(output_dir); +} + +void QVecCDB::write_cdb_BadTowers(const std::string &output_dir) +{ + std::string payload = "SEPD_HotMap"; + std::string fieldname_status = "status"; + std::string fieldname_sigma = "SEPD_sigma"; + std::string output_file = std::format("{}/{}-{}-{}.root", output_dir, payload, m_cdb_tag, m_runnumber); + + std::unique_ptr cdbttree = std::make_unique(output_file); + + auto h_sEPD_Bad_Channels = load_and_clone("h_sEPD_Bad_Channels"); + + for (int channel = 0; channel < h_sEPD_Bad_Channels->GetNbinsX(); ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(channel); + int status = h_sEPD_Bad_Channels->GetBinContent(channel+1); + + float sigma = 0; + + // Hot + if (status == 2) + { + sigma = SIGMA_HOT; + } + + // Cold + else if (status == 3) + { + sigma = SIGMA_COLD; + } + + cdbttree->SetIntValue(key, fieldname_status, status); + cdbttree->SetFloatValue(key, fieldname_sigma, sigma); + } + + std::cout << std::format("Saving CDB: {} to {}\n", payload, output_file); + + cdbttree->Commit(); + cdbttree->WriteCDBTTree(); +} + +void QVecCDB::write_cdb_EventPlane(const std::string &output_dir) +{ + std::string payload = "SEPD_EventPlaneCalib"; + std::string output_file = std::format("{}/{}-{}-{}.root", output_dir, payload, m_cdb_tag, m_runnumber); + + std::unique_ptr cdbttree = std::make_unique(output_file); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + // Define lambdas to generate field names consistently + auto field = [&](const char* det, const char* var) { + return std::format("Q_{}_{}_{}_avg", det, var, n); + }; + + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int key = static_cast(cent_bin); + + // Access data references to clean up the calls + const auto& S = getData(h_idx, cent_bin, QVecShared::Subdetector::S); + const auto& N = getData(h_idx, cent_bin, QVecShared::Subdetector::N); + + // South + cdbttree->SetDoubleValue(key, field("S", "x"), S.avg_Q.x); + cdbttree->SetDoubleValue(key, field("S", "y"), S.avg_Q.y); + cdbttree->SetDoubleValue(key, field("S", "xx"), S.avg_Q_xx); + cdbttree->SetDoubleValue(key, field("S", "yy"), S.avg_Q_yy); + cdbttree->SetDoubleValue(key, field("S", "xy"), S.avg_Q_xy); + + // North + cdbttree->SetDoubleValue(key, field("N", "x"), N.avg_Q.x); + cdbttree->SetDoubleValue(key, field("N", "y"), N.avg_Q.y); + cdbttree->SetDoubleValue(key, field("N", "xx"), N.avg_Q_xx); + cdbttree->SetDoubleValue(key, field("N", "yy"), N.avg_Q_yy); + cdbttree->SetDoubleValue(key, field("N", "xy"), N.avg_Q_xy); + } + } + + std::cout << std::format("Saving CDB: {} to {}\n", payload, output_file); + + cdbttree->Commit(); + cdbttree->WriteCDBTTree(); +} diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h new file mode 100644 index 0000000000..1840b2b52b --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h @@ -0,0 +1,139 @@ +#ifndef QVECCDB_H +#define QVECCDB_H + +#include "QVecDefs.h" + +// ==================================================================== +// ROOT Includes +// ==================================================================== +#include + +// ==================================================================== +// Standard C++ Includes +// ==================================================================== +#include +#include + +/** + * @class QVecCDB + * @brief Generates sPHENIX Calibration Database (CDB) payloads for sEPD calibrations. + * + * QVecCDB is responsible for consolidating the correction parameters derived + * during the calibration stage into standardized database formats: + * * - **SEPD_EventPlaneCalib**: Encapsulates re-centering offsets (, ) and + * flattening moments (, , ) indexed by centrality bin. + * - **SEPD_HotMap**: Maps sEPD tower statuses (Dead, Hot, or Cold) to their + * respective channel IDs for use in reconstruction. + * * The class interfaces with the `CDBTTree` object to commit these payloads + * for a specific run number and database tag. + */ +class QVecCDB +{ + public: + // The constructor takes the configuration + QVecCDB(std::string input_file, int runnumber, std::string output_dir, std::string cdb_tag) + : m_input_file(std::move(input_file)) + , m_runnumber(runnumber) + , m_output_dir(std::move(output_dir)) + , m_cdb_tag(std::move(cdb_tag)) + { + } + + void run() + { + load_data(); + write_cdb(); + } + + private: + + static constexpr size_t m_cent_bins = QVecShared::CENT_BINS; + static constexpr auto m_harmonics = QVecShared::HARMONICS; + + static constexpr float SIGMA_HOT = 6.0F; + static constexpr float SIGMA_COLD = -6.0F; + + // Holds all correction data + // key: [Harmonic][Cent][Subdetector] + // Harmonics {2,3,4} -> 3 elements + // Subdetectors {S,N} -> 2 elements + std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; + + // --- Member Variables --- + std::string m_input_file; + int m_runnumber; + std::string m_output_dir; + std::string m_cdb_tag; + + std::unique_ptr m_tfile; + + // --- Private Helper Methods --- +/** + * @brief Safely retrieves a ROOT object from the internal TFile and returns a managed unique_ptr. + * * Utilizes the internal m_tfile member to locate the object. Performs a + * dynamic_cast for type safety and Clones the object for persistent use. + * * @tparam T The ROOT class type (e.g., TProfile, TH3). + * @param name The name of the object within the internal file. + * @return std::unique_ptr A managed pointer to the cloned object. + * @throws std::runtime_error If the object is not found or type mismatch occurs. + */ + template + std::unique_ptr load_and_clone(const std::string& name); + +/** + * @brief Provides safe access to the internal correction data storage. + * * This accessor handles the mapping between the physics-based Subdetector enum + * and the zero-based indexing of the underlying multi-dimensional array. + * * @param h_idx The index of the harmonic order in the m_harmonics array. + * @param cent_bin The index of the centrality bin. + * @param sub The subdetector arm (South or North) using the QVecShared enum. + * @return QVecShared::CorrectionMoments& A reference to the specific data entry. + */ + QVecShared::CorrectionMoments& getData(size_t h_idx, size_t cent_bin, QVecShared::Subdetector sub); + +/** + * @brief High-level orchestrator for loading calibration input from a ROOT file. + * * Opens the input file specified in the constructor and validates its integrity + * before iteratively calling load_correction_data() for every defined harmonic. + * * Throws a std::runtime_error if the file cannot be opened or is found to be + * a "zombie" file. + */ + void load_data(); + +/** + * @brief Loads 1st and 2nd order correction parameters from a calibration file. + * * Iterates through harmonics and centrality bins to populate the internal + * correction matrix using the centralized QVecShared naming scheme. + * * @param h_idx The index of the harmonic to load. + */ + void load_correction_data(size_t h_idx); + +/** + * @brief Top-level orchestrator for the CDB writing phase. + * + * This method manages the creation of the run-specific directory structure + * (e.g., [output_dir]/[runnumber]) within the base output path. Once the + * filesystem is prepared, it delegates the generation and commitment of + * specific calibration payloads to write_cdb_EventPlane() and + * write_cdb_BadTowers(). + */ + void write_cdb(); + +/** + * @brief Writes the Event Plane calibration constants to a CDB-formatted TTree. + * * Formats the re-centering and flattening moments into a CDBTTree payload + * indexed by centrality bin for sPHENIX database integration. + * * @param output_dir The filesystem directory where the .root payload will be saved. + */ + void write_cdb_EventPlane(const std::string &output_dir); + +/** + * @brief Writes the Hot/Cold tower status map to a CDB-formatted TTree. + * * Encodes sEPD channel indices into TowerInfo keys and maps status codes (1=Dead, + * 2=Hot, 3=Cold) to the final database payload. + * * @param output_dir The filesystem directory where the .root payload will be saved. + */ + void write_cdb_BadTowers(const std::string &output_dir); +}; + +#endif // QVECCDB_H diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc new file mode 100644 index 0000000000..afa9eb8ed8 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -0,0 +1,1172 @@ +#include "QVecCalib.h" + +// ==================================================================== +// sPHENIX Includes +// ==================================================================== +#include + +// ==================================================================== +// Standard C++ Includes +// ==================================================================== +#include +#include +#include +#include +#include + +// ==================================================================== +// ROOT Includes +// ==================================================================== +#include + +std::unique_ptr QVecCalib::setupTChain(const std::string& input_filepath, const std::string& tree_name_in_file) +{ + // 1. Pre-check: Does the file exist at all? (C++17 filesystem or traditional fstream) + if (!std::filesystem::exists(input_filepath)) + { + std::cout << "Error: Input file does not exist: " << input_filepath << std::endl; + return nullptr; // Return a null unique_ptr indicating failure + } + + // 2. Open the file to check for the TTree directly + // Use TFile::Open and unique_ptr for robust file handling (RAII) + std::unique_ptr file_checker(TFile::Open(input_filepath.c_str(), "READ")); + + if (!file_checker || file_checker->IsZombie()) + { + std::cout << "Error: Could not open file " << input_filepath << " to check for TTree." << std::endl; + return nullptr; + } + + // Check if the TTree exists in the file + // Get() returns a TObject*, which can be cast to TTree*. + // If the object doesn't exist or isn't a TTree, Get() returns nullptr. + TTree* tree_obj = dynamic_cast(file_checker->Get(tree_name_in_file.c_str())); + if (!tree_obj) + { + std::cout << "Error: TTree '" << tree_name_in_file << "' not found in file " << input_filepath << std::endl; + return nullptr; + } + // File will be automatically closed by file_checker's unique_ptr destructor + + // 3. If everything checks out, create and configure the TChain + std::unique_ptr chain = std::make_unique(tree_name_in_file.c_str()); + if (!chain) + { // Check if make_unique failed (e.g. out of memory) + std::cout << "Error: Could not create TChain object." << std::endl; + return nullptr; + } + + chain->Add(input_filepath.c_str()); + + // 4. Verify TChain's state (optional but good final check) + // GetEntries() will be -1 if no valid trees were added. + if (chain->GetEntries() == 0) + { + std::cout << "Warning: TChain has 0 entries after adding file. This might indicate a problem." << std::endl; + // Depending on your logic, you might return nullptr here too. + } + else + { + std::cout << "Successfully set up TChain for tree '" << tree_name_in_file + << "' from file '" << input_filepath << "'. Entries: " << chain->GetEntries() << std::endl; + } + + return chain; // Return the successfully created and configured TChain +} + +void QVecCalib::setup_chain() +{ + std::cout << "Processing... setup_chain" << std::endl; + + m_chain = setupTChain(m_input_file, "T"); + + if (m_chain == nullptr) + { + throw std::runtime_error(std::format("Error in TChain Setup from file: {}", m_input_file)); + } + + // Setup branches + m_chain->SetBranchStatus("*", false); + m_chain->SetBranchStatus("event_id", true); + m_chain->SetBranchStatus("event_centrality", true); + m_chain->SetBranchStatus("sepd_totalcharge", true); + m_chain->SetBranchStatus("sepd_channel", true); + m_chain->SetBranchStatus("sepd_charge", true); + m_chain->SetBranchStatus("sepd_phi", true); + + m_chain->SetBranchAddress("event_id", &m_event_data.event_id); + m_chain->SetBranchAddress("event_centrality", &m_event_data.event_centrality); + m_chain->SetBranchAddress("sepd_totalcharge", &m_event_data.sepd_totalcharge); + m_chain->SetBranchAddress("sepd_channel", &m_event_data.sepd_channel); + m_chain->SetBranchAddress("sepd_charge", &m_event_data.sepd_charge); + m_chain->SetBranchAddress("sepd_phi", &m_event_data.sepd_phi); + + std::cout << "Finished... setup_chain" << std::endl; +} + +void QVecCalib::process_QA_hist() +{ + TH1::AddDirectory(kFALSE); + auto file = std::unique_ptr(TFile::Open(m_input_hist.c_str())); + + // Check if the file was opened successfully. + if (!file || file->IsZombie()) + { + throw std::runtime_error(std::format("Could not open file '{}'", m_input_hist)); + } + + // Get List of Bad Channels + process_bad_channels(file.get()); + + // Get sEPD Total Charge Bounds as function of centrality + process_sEPD_event_thresholds(file.get()); +} + +void QVecCalib::process_sEPD_event_thresholds(TFile* file) +{ + std::string sepd_totalcharge_centrality = "h2SEPD_totalcharge_centrality"; + + auto* hist = file->Get(sepd_totalcharge_centrality.c_str()); + + // Check if the hist is stored in the file + if (hist == nullptr) + { + throw std::runtime_error(std::format("Cannot find hist: {}", sepd_totalcharge_centrality)); + } + + m_hists2D["h2SEPD_Charge"] = std::unique_ptr(static_cast(hist->Clone("h2SEPD_Charge"))); + m_hists2D["h2SEPD_Chargev2"] = std::unique_ptr(static_cast(hist->Clone("h2SEPD_Chargev2"))); + + auto* h2SEPD_Charge = m_hists2D["h2SEPD_Charge"].get(); + auto* h2SEPD_Chargev2 = m_hists2D["h2SEPD_Chargev2"].get(); + + auto* h2SEPD_Charge_py = h2SEPD_Charge->ProfileY("h2SEPD_Charge_py", 1, -1, "s"); + + int binsx = h2SEPD_Charge->GetNbinsX(); + int binsy = h2SEPD_Charge->GetNbinsY(); + int ymin = h2SEPD_Charge->GetYaxis()->GetXmin(); + int ymax = h2SEPD_Charge->GetYaxis()->GetXmax(); + + m_profiles["hSEPD_Charge_Min"] = std::make_unique("hSEPD_Charge_Min", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); + m_profiles["hSEPD_Charge_Max"] = std::make_unique("hSEPD_Charge_Max", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); + + auto* hSEPD_Charge_Min = m_profiles["hSEPD_Charge_Min"].get(); + auto* hSEPD_Charge_Max = m_profiles["hSEPD_Charge_Max"].get(); + + for (int y = 1; y <= binsy; ++y) + { + double cent = h2SEPD_Charge_py->GetBinCenter(y); + double mean = h2SEPD_Charge_py->GetBinContent(y); + double sigma = h2SEPD_Charge_py->GetBinError(y); + double charge_low = mean - m_sEPD_sigma_threshold * sigma; + double charge_high = mean + m_sEPD_sigma_threshold * sigma; + + hSEPD_Charge_Min->Fill(cent, charge_low); + hSEPD_Charge_Max->Fill(cent, charge_high); + + for (int x = 1; x <= binsx; ++x) + { + double charge = h2SEPD_Charge->GetXaxis()->GetBinCenter(x); + double zscore = (charge - mean) / sigma; + + if (std::fabs(zscore) > m_sEPD_sigma_threshold) + { + h2SEPD_Chargev2->SetBinContent(x, y, 0); + } + } + } +} + +void QVecCalib::process_bad_channels(TFile* file) +{ + std::string sepd_charge_hist = "hSEPD_Charge"; + + auto* hist = file->Get(sepd_charge_hist.c_str()); + + // Check if the hist is stored in the file + if (hist == nullptr) + { + throw std::runtime_error(std::format("Cannot find hist: {}", sepd_charge_hist)); + } + + auto* hSEPD_Charge = dynamic_cast(hist); + + int sepd_channels = 744; + int rbins = 16; + int bins_charge = 40; + + m_hists2D["h2SEPD_South_Charge_rbin"] = std::make_unique("h2SEPD_South_Charge_rbin", + "sEPD South; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); + + m_hists2D["h2SEPD_North_Charge_rbin"] = std::make_unique("h2SEPD_North_Charge_rbin", + "sEPD North; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); + + m_hists2D["h2SEPD_South_Charge_rbinv2"] = std::make_unique("h2SEPD_South_Charge_rbinv2", + "sEPD South; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); + + m_hists2D["h2SEPD_North_Charge_rbinv2"] = std::make_unique("h2SEPD_North_Charge_rbinv2", + "sEPD North; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); + + m_profiles["h_sEPD_Bad_Channels"] = std::make_unique("h_sEPD_Bad_Channels", "sEPD Bad Channels; Channel; Status", sepd_channels, -0.5, sepd_channels-0.5); + + auto* h2S = m_hists2D["h2SEPD_South_Charge_rbin"].get(); + auto* h2N = m_hists2D["h2SEPD_North_Charge_rbin"].get(); + + auto* h2Sv2 = m_hists2D["h2SEPD_South_Charge_rbinv2"].get(); + auto* h2Nv2 = m_hists2D["h2SEPD_North_Charge_rbinv2"].get(); + + auto* hBad = m_profiles["h_sEPD_Bad_Channels"].get(); + + for (int channel = 0; channel < sepd_channels; ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); + int rbin = static_cast(TowerInfoDefs::get_epd_rbin(key)); + unsigned int arm = TowerInfoDefs::get_epd_arm(key); + + double avg_charge = hSEPD_Charge->GetBinContent(channel + 1); + + auto* h2 = (arm == 0) ? h2S : h2N; + + h2->Fill(rbin, avg_charge); + } + + auto* hSpx = h2S->ProfileX("hSpx", 2, -1, "s"); + auto* hNpx = h2N->ProfileX("hNpx", 2, -1, "s"); + + int ctr_dead = 0; + int ctr_hot = 0; + int ctr_cold = 0; + + for (int channel = 0; channel < sepd_channels; ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); + int rbin = static_cast(TowerInfoDefs::get_epd_rbin(key)); + unsigned int arm = TowerInfoDefs::get_epd_arm(key); + + auto* h2 = (arm == 0) ? h2Sv2 : h2Nv2; + auto* hprof = (arm == 0) ? hSpx : hNpx; + + double charge = hSEPD_Charge->GetBinContent(channel + 1); + double mean_charge = hprof->GetBinContent(rbin + 1); + double sigma = hprof->GetBinError(rbin + 1); + double zscore = (charge - mean_charge) / sigma; + + if (charge < m_sEPD_min_avg_charge_threshold || std::fabs(zscore) > m_sEPD_sigma_threshold) + { + m_bad_channels.insert(channel); + + std::string type; + int status_fill; + + // dead channel + if (charge == 0) + { + type = "Dead"; + status_fill = 1; + ++ctr_dead; + } + // hot channel + else if (zscore > m_sEPD_sigma_threshold) + { + type = "Hot"; + status_fill = 2; + ++ctr_hot; + } + // cold channel + else + { + type = "Cold"; + status_fill = 3; + ++ctr_cold; + } + + hBad->Fill(channel, status_fill); + std::cout << std::format("{:4} Channel: {:3d}, arm: {}, rbin: {:2d}, Mean: {:5.2f}, Charge: {:5.2f}, Z-Score: {:5.2f}\n", type, channel, arm, rbin, mean_charge, charge, zscore); + } + else + { + h2->Fill(rbin, charge); + } + } + + std::cout << std::format("Total Bad Channels: {}, Dead: {}, Hot: {}, Cold: {}\n", m_bad_channels.size(), ctr_dead, ctr_hot, ctr_cold); + + std::cout << "Finished processing Hot sEPD channels" << std::endl; +} + +void QVecCalib::init_hists() +{ + unsigned int bins_Q = 100; + double Q_low = -1; + double Q_high = 1; + + unsigned int bins_psi = 126; + double psi_low = -std::numbers::pi; + double psi_high = std::numbers::pi; + + m_hists1D["h_Cent"] = std::make_unique("h_Cent", "", m_cent_bins, m_cent_low, m_cent_high); + + std::string pass_suffix; + if (m_pass == Pass::ApplyRecentering) + { + pass_suffix = "_corr"; + } + else if (m_pass == Pass::ApplyFlattening) + { + pass_suffix = "_corr2"; + } + + // n = 2, 3, 4, etc. + for (int n : m_harmonics) + { + std::string psi_hist_name = std::format("h3_sEPD_Psi_{}", n); + std::string psi_hist_title = std::format("sEPD #Psi (Order {0}): |z| < 10 cm and MB; {0}#Psi^{{S}}_{{{0}}}; {0}#Psi^{{N}}_{{{0}}}; Centrality [%]", n); + + if (m_pass == Pass::ComputeRecentering) + { + psi_hist_name = std::format("h3_sEPD_Psi_{}", n); + } + + if (m_pass == Pass::ApplyRecentering) + { + psi_hist_name = std::format("h3_sEPD_Psi_{}_corr", n); + } + + if (m_pass == Pass::ApplyFlattening) + { + psi_hist_name = std::format("h3_sEPD_Psi_{}_corr2", n); + } + + m_hists3D[psi_hist_name] = std::make_unique(psi_hist_name.c_str(), psi_hist_title.c_str(), bins_psi, psi_low, psi_high, bins_psi, psi_low, psi_high, m_cent_bins, m_cent_low, m_cent_high); + + // South, North + for (auto det : m_subdetectors) + { + std::string det_str = (det == QVecShared::Subdetector::S) ? "S" : "N"; + std::string det_name = (det == QVecShared::Subdetector::S) ? "South" : "North"; + + if (m_pass == Pass::ComputeRecentering) + { + std::string q_hist_name = std::format("h3_sEPD_Q_{}_{}", det_str, n); + std::string q_hist_title = std::format("sEPD {} Q (Order {}): |z| < 10 cm and MB; Q_{{x}}; Q_{{y}}; Centrality [%]", det_name, n); + m_hists3D[q_hist_name] = std::make_unique(q_hist_name.c_str(), q_hist_title.c_str(), + bins_Q, Q_low, Q_high, bins_Q, Q_low, Q_high, m_cent_bins, m_cent_low, m_cent_high); + } + + std::string q_avg_sq_cross_name; + std::string q_avg_sq_cross_title = std::format("sEPD {0}; Centrality [%]; ", det_name, n); + + if (m_pass == Pass::ApplyRecentering) + { + q_avg_sq_cross_name = QVecShared::get_hist_name(det_str, "xy", n); + } + + if (m_pass == Pass::ApplyFlattening) + { + q_avg_sq_cross_name = QVecShared::get_hist_name(det_str, "xy", n, "_corr"); + } + + if (!q_avg_sq_cross_name.empty()) + { + m_profiles[q_avg_sq_cross_name] = std::make_unique(q_avg_sq_cross_name.c_str(), q_avg_sq_cross_title.c_str(), + m_cent_bins, m_cent_low, m_cent_high); + } + + for (auto comp : m_components) + { + std::string comp_str = (comp == QVecShared::QComponent::X) ? "x" : "y"; + std::string name = QVecShared::get_hist_name(det_str, comp_str, n, pass_suffix); + + auto add_profile = [&](const std::string& prof_name, std::string_view label_suffix = "") + { + std::string title = std::format("sEPD {}; Centrality [%]; ", det_name, n, comp_str, label_suffix); + m_profiles[prof_name] = std::make_unique(prof_name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + }; + + add_profile(name); + + // 2. Only generate strings and profiles for the current pass + switch (m_pass) + { + case Pass::ComputeRecentering: + { + break; + } + + case Pass::ApplyRecentering: + { + std::string name_sq = QVecShared::get_hist_name(det_str, comp_str+comp_str, n); + add_profile(name_sq, "^{2}"); + break; + } + + case Pass::ApplyFlattening: + { + std::string name_sq_corr = QVecShared::get_hist_name(det_str, comp_str+comp_str, n, "_corr"); + add_profile(name_sq_corr, "^{2}"); + break; + } + } + } + } + } +} + +void QVecCalib::process_averages(double cent, QVecShared::QVec q_S, QVecShared::QVec q_N, const AverageHists& h) +{ + double psi_S = std::atan2(q_S.y, q_S.x); + double psi_N = std::atan2(q_N.y, q_N.x); + + h.S_x_avg->Fill(cent, q_S.x); + h.S_y_avg->Fill(cent, q_S.y); + h.N_x_avg->Fill(cent, q_N.x); + h.N_y_avg->Fill(cent, q_N.y); + + h.Q_S->Fill(q_S.x, q_S.y, cent); + h.Q_N->Fill(q_N.x, q_N.y, cent); + h.Psi->Fill(psi_S, psi_N, cent); +} + +void QVecCalib::process_recentering(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const RecenterHists& h) +{ + size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); + + double Q_S_x_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.x; + double Q_S_y_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.y; + double Q_N_x_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.x; + double Q_N_y_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.y; + + QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; + QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + + double psi_S_corr = std::atan2(q_S_corr.y, q_S_corr.x); + double psi_N_corr = std::atan2(q_N_corr.y, q_N_corr.x); + + h.S_x_corr_avg->Fill(cent, q_S_corr.x); + h.S_y_corr_avg->Fill(cent, q_S_corr.y); + h.N_x_corr_avg->Fill(cent, q_N_corr.x); + h.N_y_corr_avg->Fill(cent, q_N_corr.y); + + h.S_xx_avg->Fill(cent, q_S_corr.x * q_S_corr.x); + h.S_yy_avg->Fill(cent, q_S_corr.y * q_S_corr.y); + h.S_xy_avg->Fill(cent, q_S_corr.x * q_S_corr.y); + h.N_xx_avg->Fill(cent, q_N_corr.x * q_N_corr.x); + h.N_yy_avg->Fill(cent, q_N_corr.y * q_N_corr.y); + h.N_xy_avg->Fill(cent, q_N_corr.x * q_N_corr.y); + + h.Psi_corr->Fill(psi_S_corr, psi_N_corr, cent); +} + +void QVecCalib::process_flattening(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const FlatteningHists& h) +{ + size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); + + double Q_S_x_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.x; + double Q_S_y_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.y; + double Q_N_x_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.x; + double Q_N_y_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.y; + + QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; + QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + + const auto& X_S = m_correction_data[cent_bin][h_idx][0].X_matrix; + const auto& X_N = m_correction_data[cent_bin][h_idx][1].X_matrix; + + double Q_S_x_corr2 = X_S[0][0] * q_S_corr.x + X_S[0][1] * q_S_corr.y; + double Q_S_y_corr2 = X_S[1][0] * q_S_corr.x + X_S[1][1] * q_S_corr.y; + double Q_N_x_corr2 = X_N[0][0] * q_N_corr.x + X_N[0][1] * q_N_corr.y; + double Q_N_y_corr2 = X_N[1][0] * q_N_corr.x + X_N[1][1] * q_N_corr.y; + + QVecShared::QVec q_S_corr2 = {Q_S_x_corr2, Q_S_y_corr2}; + QVecShared::QVec q_N_corr2 = {Q_N_x_corr2, Q_N_y_corr2}; + + double psi_S = std::atan2(q_S_corr2.y, q_S_corr2.x); + double psi_N = std::atan2(q_N_corr2.y, q_N_corr2.x); + + h.S_x_corr2_avg->Fill(cent, q_S_corr2.x); + h.S_y_corr2_avg->Fill(cent, q_S_corr2.y); + h.N_x_corr2_avg->Fill(cent, q_N_corr2.x); + h.N_y_corr2_avg->Fill(cent, q_N_corr2.y); + + h.S_xx_corr_avg->Fill(cent, q_S_corr2.x * q_S_corr2.x); + h.S_yy_corr_avg->Fill(cent, q_S_corr2.y * q_S_corr2.y); + h.S_xy_corr_avg->Fill(cent, q_S_corr2.x * q_S_corr2.y); + h.N_xx_corr_avg->Fill(cent, q_N_corr2.x * q_N_corr2.x); + h.N_yy_corr_avg->Fill(cent, q_N_corr2.y * q_N_corr2.y); + h.N_xy_corr_avg->Fill(cent, q_N_corr2.x * q_N_corr2.y); + + h.Psi_corr2->Fill(psi_S, psi_N, cent); +} + +void QVecCalib::compute_averages(size_t cent_bin, int h_idx) +{ + int n = m_harmonics[h_idx]; + + std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); + std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); + std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); + std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + + int bin = static_cast(cent_bin + 1); + + double Q_S_x_avg = m_profiles[S_x_avg_name]->GetBinContent(bin); + double Q_S_y_avg = m_profiles[S_y_avg_name]->GetBinContent(bin); + double Q_N_x_avg = m_profiles[N_x_avg_name]->GetBinContent(bin); + double Q_N_y_avg = m_profiles[N_y_avg_name]->GetBinContent(bin); + + m_correction_data[cent_bin][h_idx][0].avg_Q = {Q_S_x_avg, Q_S_y_avg}; + m_correction_data[cent_bin][h_idx][1].avg_Q = {Q_N_x_avg, Q_N_y_avg}; + + std::cout << std::format( + "Centrality Bin: {}, " + "Harmonic: {}, " + "Q_S_x_avg: {:13.10f}, " + "Q_S_y_avg: {:13.10f}, " + "Q_N_x_avg: {:13.10f}, " + "Q_N_y_avg: {:13.10f}\n", + cent_bin, + n, + Q_S_x_avg, + Q_S_y_avg, + Q_N_x_avg, + Q_N_y_avg); +} + +std::array, 2> QVecCalib::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) +{ + double D_arg = (xx * yy) - (xy * xy); + if (D_arg <= 0) + { + throw std::runtime_error(std::format( + "Invalid D-term ({}) for n={}, cent={}, det={}", D_arg, n, cent_bin, det_label)); + } + double D = std::sqrt(D_arg); + + double N_term = D * (xx + yy + (2 * D)); + if (N_term <= 0) + { + throw std::runtime_error(std::format( + "Invalid N-term ({}) for n={}, cent={}, det={}", N_term, n, cent_bin, det_label)); + } + double inv_sqrt_N = 1.0 / std::sqrt(N_term); + + std::array, 2> mat{}; + mat[0][0] = inv_sqrt_N * (yy + D); + mat[0][1] = -inv_sqrt_N * xy; + mat[1][0] = mat[0][1]; + mat[1][1] = inv_sqrt_N * (xx + D); + return mat; +} + +void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) +{ + int n = m_harmonics[h_idx]; + + std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr"); + std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr"); + std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr"); + std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr"); + + int bin = static_cast(cent_bin + 1); + + double Q_S_x_corr_avg = m_profiles[S_x_corr_avg_name]->GetBinContent(bin); + double Q_S_y_corr_avg = m_profiles[S_y_corr_avg_name]->GetBinContent(bin); + double Q_N_x_corr_avg = m_profiles[N_x_corr_avg_name]->GetBinContent(bin); + double Q_N_y_corr_avg = m_profiles[N_y_corr_avg_name]->GetBinContent(bin); + + // -- Compute 2nd Order Correction -- + std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); + std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); + std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); + std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); + std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); + std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); + + double Q_S_xx_avg = m_profiles[S_xx_avg_name]->GetBinContent(bin); + double Q_S_yy_avg = m_profiles[S_yy_avg_name]->GetBinContent(bin); + double Q_S_xy_avg = m_profiles[S_xy_avg_name]->GetBinContent(bin); + double Q_N_xx_avg = m_profiles[N_xx_avg_name]->GetBinContent(bin); + double Q_N_yy_avg = m_profiles[N_yy_avg_name]->GetBinContent(bin); + double Q_N_xy_avg = m_profiles[N_xy_avg_name]->GetBinContent(bin); + + m_correction_data[cent_bin][h_idx][0].avg_Q_xx = Q_S_xx_avg; + m_correction_data[cent_bin][h_idx][0].avg_Q_yy = Q_S_yy_avg; + m_correction_data[cent_bin][h_idx][0].avg_Q_xy = Q_S_xy_avg; + m_correction_data[cent_bin][h_idx][1].avg_Q_xx = Q_N_xx_avg; + m_correction_data[cent_bin][h_idx][1].avg_Q_yy = Q_N_yy_avg; + m_correction_data[cent_bin][h_idx][1].avg_Q_xy = Q_N_xy_avg; + + for (size_t det_idx = 0; det_idx < 2; ++det_idx) + { + double xx = (det_idx == 0) ? Q_S_xx_avg : Q_N_xx_avg; + double yy = (det_idx == 0) ? Q_S_yy_avg : Q_N_yy_avg; + double xy = (det_idx == 0) ? Q_S_xy_avg : Q_N_xy_avg; + + std::string label = (det_idx == 0) ? "S" : "N"; + + m_correction_data[cent_bin][h_idx][det_idx].X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, label); + } + + std::cout << std::format( + "Centrality Bin: {}, " + "Harmonic: {}, " + "Q_S_x_corr_avg: {:13.10f}, " + "Q_S_y_corr_avg: {:13.10f}, " + "Q_N_x_corr_avg: {:13.10f}, " + "Q_N_y_corr_avg: {:13.10f}, " + "Q_S_xx_avg / Q_S_yy_avg: {:13.10f}, " + "Q_N_xx_avg / Q_N_yy_avg: {:13.10f}, " + "Q_S_xy_avg: {:13.10f}, " + "Q_N_xy_avg: {:13.10f}\n", + cent_bin, + n, + Q_S_x_corr_avg, + Q_S_y_corr_avg, + Q_N_x_corr_avg, + Q_N_y_corr_avg, + Q_S_xx_avg / Q_S_yy_avg, + Q_N_xx_avg / Q_N_yy_avg, + Q_S_xy_avg, + Q_N_xy_avg); +} + +void QVecCalib::print_flattening(size_t cent_bin, int n) const +{ + std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2"); + std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2"); + std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2"); + std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2"); + + std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr"); + std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr"); + std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr"); + std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr"); + std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); + std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); + + int bin = static_cast(cent_bin + 1); + + double Q_S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name)->GetBinContent(bin); + double Q_S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name)->GetBinContent(bin); + double Q_N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name)->GetBinContent(bin); + double Q_N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name)->GetBinContent(bin); + + double Q_S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name)->GetBinContent(bin); + double Q_S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name)->GetBinContent(bin); + double Q_S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name)->GetBinContent(bin); + double Q_N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name)->GetBinContent(bin); + double Q_N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name)->GetBinContent(bin); + double Q_N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name)->GetBinContent(bin); + + std::cout << std::format( + "Centrality Bin: {}, " + "Harmonic: {}, " + "Q_S_x_corr2_avg: {:13.10f}, " + "Q_S_y_corr2_avg: {:13.10f}, " + "Q_N_x_corr2_avg: {:13.10f}, " + "Q_N_y_corr2_avg: {:13.10f}, " + "Q_S_xx_corr_avg / Q_S_yy_corr_avg: {:13.10f}, " + "Q_N_xx_corr_avg / Q_N_yy_corr_avg: {:13.10f}, " + "Q_S_xy_corr_avg: {:13.10f}, " + "Q_N_xy_corr_avg: {:13.10f}\n", + cent_bin, + n, + Q_S_x_corr2_avg, + Q_S_y_corr2_avg, + Q_N_x_corr2_avg, + Q_N_y_corr2_avg, + Q_S_xx_corr_avg / Q_S_yy_corr_avg, + Q_N_xx_corr_avg / Q_N_yy_corr_avg, + Q_S_xy_corr_avg, + Q_N_xy_corr_avg); +} + +std::vector QVecCalib::prepare_average_hists() +{ + std::vector hists_cache; + for (int n : m_harmonics) + { + + std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); + std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); + std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); + std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + + std::string hist_Q_S_name = std::format("h3_sEPD_Q_S_{}", n); + std::string hist_Q_N_name = std::format("h3_sEPD_Q_N_{}", n); + std::string psi_Q_name = std::format("h3_sEPD_Psi_{}", n); + + AverageHists h; + + h.S_x_avg = m_profiles.at(S_x_avg_name).get(); + h.S_y_avg = m_profiles.at(S_y_avg_name).get(); + h.N_x_avg = m_profiles.at(N_x_avg_name).get(); + h.N_y_avg = m_profiles.at(N_y_avg_name).get(); + + h.Q_S = m_hists3D.at(hist_Q_S_name).get(); + h.Q_N = m_hists3D.at(hist_Q_N_name).get(); + + h.Psi = m_hists3D.at(psi_Q_name).get(); + + hists_cache.push_back(h); + } + + return hists_cache; +} + +bool QVecCalib::process_sEPD() +{ + size_t nChannels = m_event_data.sepd_channel->size(); + + double sepd_total_charge_south = 0; + double sepd_total_charge_north = 0; + + // Loop over all sEPD Channels + for (size_t idx = 0; idx < nChannels; ++idx) + { + int channel = m_event_data.sepd_channel->at(idx); + double charge = m_event_data.sepd_charge->at(idx); + double phi = m_event_data.sepd_phi->at(idx); + + // Skip Bad Channels + if (m_bad_channels.contains(channel)) + { + continue; + } + + unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); + unsigned int arm = TowerInfoDefs::get_epd_arm(key); + + // arm = 0: South + // arm = 1: North + double& sepd_total_charge = (arm == 0) ? sepd_total_charge_south : sepd_total_charge_north; + + // Compute total charge for the respective sEPD arm + sepd_total_charge += charge; + + // Compute Raw Q vectors for each harmonic and respective arm + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + m_event_data.q_vectors[h_idx][arm].x += charge * std::cos(n * phi); + m_event_data.q_vectors[h_idx][arm].y += charge * std::sin(n * phi); + } + } + + // Skip Events with Zero sEPD Total Charge in either arm + if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) + { + return false; + } + + // Normalize the Q-vectors by total charge + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + for (auto det : m_subdetectors) + { + size_t det_idx = (det == QVecShared::Subdetector::S) ? 0 : 1; + double sepd_total_charge = (det_idx == 0) ? sepd_total_charge_south : sepd_total_charge_north; + m_event_data.q_vectors[h_idx][det_idx].x /= sepd_total_charge; + m_event_data.q_vectors[h_idx][det_idx].y /= sepd_total_charge; + } + } + + return true; +} + +std::vector QVecCalib::prepare_recenter_hists() +{ + std::vector hists_cache; + for (int n : m_harmonics) + { + std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr"); + std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr"); + std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr"); + std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr"); + + std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); + std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); + std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); + std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); + std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); + std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); + + std::string psi_Q_corr_name = std::format("h3_sEPD_Psi_{}_corr", n); + + RecenterHists h; + + h.S_x_corr_avg = m_profiles.at(S_x_corr_avg_name).get(); + h.S_y_corr_avg = m_profiles.at(S_y_corr_avg_name).get(); + h.N_x_corr_avg = m_profiles.at(N_x_corr_avg_name).get(); + h.N_y_corr_avg = m_profiles.at(N_y_corr_avg_name).get(); + + h.S_xx_avg = m_profiles.at(S_xx_avg_name).get(); + h.S_yy_avg = m_profiles.at(S_yy_avg_name).get(); + h.S_xy_avg = m_profiles.at(S_xy_avg_name).get(); + h.N_xx_avg = m_profiles.at(N_xx_avg_name).get(); + h.N_yy_avg = m_profiles.at(N_yy_avg_name).get(); + h.N_xy_avg = m_profiles.at(N_xy_avg_name).get(); + + h.Psi_corr = m_hists3D.at(psi_Q_corr_name).get(); + + hists_cache.push_back(h); + } + + return hists_cache; +} + +std::vector QVecCalib::prepare_flattening_hists() +{ + std::vector hists_cache; + for (int n : m_harmonics) + { + + std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2"); + std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2"); + std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2"); + std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2"); + + std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr"); + std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr"); + std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr"); + std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr"); + std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); + std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); + + std::string psi_Q_corr2_name = std::format("h3_sEPD_Psi_{}_corr2", n); + + FlatteningHists h; + + h.S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name).get(); + h.S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name).get(); + h.N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name).get(); + h.N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name).get(); + + h.S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name).get(); + h.S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name).get(); + h.S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name).get(); + + h.N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name).get(); + h.N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name).get(); + h.N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name).get(); + + h.Psi_corr2 = m_hists3D.at(psi_Q_corr2_name).get(); + + hists_cache.push_back(h); + } + + return hists_cache; +} + +bool QVecCalib::process_event_check() +{ + auto* hSEPD_Charge_Min = m_profiles["hSEPD_Charge_Min"].get(); + auto* hSEPD_Charge_Max = m_profiles["hSEPD_Charge_Max"].get(); + + double cent = m_event_data.event_centrality; + int cent_bin = hSEPD_Charge_Min->FindBin(cent); + + double sepd_totalcharge = m_event_data.sepd_totalcharge; + + double sepd_totalcharge_min = hSEPD_Charge_Min->GetBinContent(cent_bin); + double sepd_totalcharge_max = hSEPD_Charge_Max->GetBinContent(cent_bin); + + return sepd_totalcharge > sepd_totalcharge_min && sepd_totalcharge < sepd_totalcharge_max; +} + +void QVecCalib::run_event_loop() +{ + std::cout << std::format("Pass: {}\n", static_cast(m_pass)); + + long long n_entries = m_chain->GetEntries(); + if (m_events_to_process > 0) + { + n_entries = std::min(m_events_to_process, n_entries); + } + + std::vector average_hists; + std::vector recenter_hists; + std::vector flattening_hists; + + if (m_pass == Pass::ComputeRecentering) + { + average_hists = prepare_average_hists(); + } + else if (m_pass == Pass::ApplyRecentering) + { + recenter_hists = prepare_recenter_hists(); + } + else if (m_pass == Pass::ApplyFlattening) + { + flattening_hists = prepare_flattening_hists(); + } + + std::map ctr; + // Event Loop + for (long long i = 0; i < n_entries; ++i) + { + // Load Event Data from TChain + m_chain->GetEntry(i); + m_event_data.reset(); + + if (i % 10000 == 0) + { + std::cout << std::format("Processing {}/{}: {:.2f} %", i, n_entries, static_cast(i) * 100. / static_cast(n_entries)) << std::endl; + } + + double cent = m_event_data.event_centrality; + + // Identify Centrality Bin + size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); + + // ensure centrality is valid + if (cent_bin >= m_cent_bins) + { + std::cout << std::format("Weird Centrality: {}, Skipping Event: {}\n", cent, m_event_data.event_id); + ++ctr["invalid_cent_bin"]; + continue; + } + + bool isGood = process_event_check(); + + // Skip Events with non correlation between centrality and sEPD + if (!isGood) + { + ++ctr["bad_centrality_sepd_correlation"]; + continue; + } + + isGood = process_sEPD(); + + // Skip Events with Zero sEPD Total Charge in either arm + if (!isGood) + { + ++ctr["zero_sepd_total_charge"]; + continue; + } + + m_hists1D["h_Cent"]->Fill(cent); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + const auto& q_S = m_event_data.q_vectors[h_idx][0]; // 0 for South + const auto& q_N = m_event_data.q_vectors[h_idx][1]; // 1 for North + + // --- First Pass: Derive 1st Order --- + if (m_pass == Pass::ComputeRecentering) + { + process_averages(cent, q_S, q_N, average_hists[h_idx]); + } + + // --- Second Pass: Apply 1st Order, Derive 2nd Order --- + else if (m_pass == Pass::ApplyRecentering) + { + process_recentering(cent, h_idx, q_S, q_N, recenter_hists[h_idx]); + } + + // --- Third Pass: Apply 2nd Order, Validate --- + else if (m_pass == Pass::ApplyFlattening) + { + process_flattening(cent, h_idx, q_S, q_N, flattening_hists[h_idx]); + } + } + } + + std::cout << "Skipped Event Types\n"; + for (const auto& [name, events] : ctr) + { + std::cout << std::format("{}: {}, {:.2f} %\n", name, events, events * 100. / static_cast(n_entries)); + } + + // --------------- + + std::cout << std::format("{:#<20}\n", ""); + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + if (m_pass == Pass::ComputeRecentering) + { + compute_averages(cent_bin, h_idx); + } + + else if (m_pass == Pass::ApplyRecentering) + { + compute_recentering(cent_bin, h_idx); + } + + else if (m_pass == Pass::ApplyFlattening) + { + print_flattening(cent_bin, n); + } + } + } + + std::cout << "Event loop finished." << std::endl; +} + +template +std::unique_ptr QVecCalib::load_and_clone(TFile* file, const std::string& name) { + auto* obj = dynamic_cast(file->Get(name.c_str())); + if (!obj) + { + throw std::runtime_error(std::format("Could not find histogram '{}' in file '{}'", name, file->GetName())); + } + return std::unique_ptr(static_cast(obj->Clone())); +} + +void QVecCalib::load_correction_data() +{ + TH1::AddDirectory(kFALSE); + + auto file = std::unique_ptr(TFile::Open(m_input_Q_calib.c_str())); + + // Check if the file was opened successfully. + if (!file || file->IsZombie()) + { + throw std::runtime_error(std::format("Could not open file '{}'", m_input_Q_calib)); + } + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); + std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); + std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); + std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + + std::string psi_hist_name = std::format("h3_sEPD_Psi_{}", n); + + m_profiles[S_x_avg_name] = load_and_clone(file.get(), S_x_avg_name); + m_profiles[S_y_avg_name] = load_and_clone(file.get(), S_y_avg_name); + m_profiles[N_x_avg_name] = load_and_clone(file.get(), N_x_avg_name); + m_profiles[N_y_avg_name] = load_and_clone(file.get(), N_y_avg_name); + + m_hists3D[psi_hist_name] = load_and_clone(file.get(), psi_hist_name); + + std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); + std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); + std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); + std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); + std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); + std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); + + std::string psi_corr_hist_name = std::format("h3_sEPD_Psi_{}_corr", n); + + if(m_pass == Pass::ApplyFlattening) + { + m_profiles[S_xx_avg_name] = load_and_clone(file.get(), S_xx_avg_name); + m_profiles[S_yy_avg_name] = load_and_clone(file.get(), S_yy_avg_name); + m_profiles[S_xy_avg_name] = load_and_clone(file.get(), S_xy_avg_name); + m_profiles[N_xx_avg_name] = load_and_clone(file.get(), N_xx_avg_name); + m_profiles[N_yy_avg_name] = load_and_clone(file.get(), N_yy_avg_name); + m_profiles[N_xy_avg_name] = load_and_clone(file.get(), N_xy_avg_name); + + m_hists3D[psi_corr_hist_name] = load_and_clone(file.get(), psi_corr_hist_name); + } + + size_t south_idx = static_cast(QVecShared::Subdetector::S); + size_t north_idx = static_cast(QVecShared::Subdetector::N); + + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int bin = static_cast(cent_bin) + 1; + + double Q_S_x_avg = m_profiles[S_x_avg_name]->GetBinContent(bin); + double Q_S_y_avg = m_profiles[S_y_avg_name]->GetBinContent(bin); + double Q_N_x_avg = m_profiles[N_x_avg_name]->GetBinContent(bin); + double Q_N_y_avg = m_profiles[N_y_avg_name]->GetBinContent(bin); + + // Recentering Params + m_correction_data[cent_bin][h_idx][south_idx].avg_Q = {Q_S_x_avg, Q_S_y_avg}; + m_correction_data[cent_bin][h_idx][north_idx].avg_Q = {Q_N_x_avg, Q_N_y_avg}; + + if (m_pass == Pass::ApplyFlattening) + { + double Q_S_xx_avg = m_profiles[S_xx_avg_name]->GetBinContent(bin); + double Q_S_yy_avg = m_profiles[S_yy_avg_name]->GetBinContent(bin); + double Q_S_xy_avg = m_profiles[S_xy_avg_name]->GetBinContent(bin); + double Q_N_xx_avg = m_profiles[N_xx_avg_name]->GetBinContent(bin); + double Q_N_yy_avg = m_profiles[N_yy_avg_name]->GetBinContent(bin); + double Q_N_xy_avg = m_profiles[N_xy_avg_name]->GetBinContent(bin); + + // Flattening Params + m_correction_data[cent_bin][h_idx][south_idx].avg_Q_xx = Q_S_xx_avg; + m_correction_data[cent_bin][h_idx][south_idx].avg_Q_yy = Q_S_yy_avg; + m_correction_data[cent_bin][h_idx][south_idx].avg_Q_xy = Q_S_xy_avg; + + m_correction_data[cent_bin][h_idx][north_idx].avg_Q_xx = Q_N_xx_avg; + m_correction_data[cent_bin][h_idx][north_idx].avg_Q_yy = Q_N_yy_avg; + m_correction_data[cent_bin][h_idx][north_idx].avg_Q_xy = Q_N_xy_avg; + + for (size_t det_idx = 0; det_idx < 2; ++det_idx) + { + double xx = (det_idx == 0) ? Q_S_xx_avg : Q_N_xx_avg; + double yy = (det_idx == 0) ? Q_S_yy_avg : Q_N_yy_avg; + double xy = (det_idx == 0) ? Q_S_xy_avg : Q_N_xy_avg; + + std::string label = (det_idx == 0) ? "S" : "N"; + + m_correction_data[cent_bin][h_idx][det_idx].X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, label); + } + } + } + } +} + +void QVecCalib::process_events() +{ + if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening) + { + load_correction_data(); + } + + run_event_loop(); +} + +void QVecCalib::save_results() const +{ + std::filesystem::create_directories(m_output_dir); + + std::filesystem::path input_path(m_input_file); + std::string output_stem = input_path.stem().string(); + std::string output_filename = std::format("{}/Q-vec-corr_Pass-{}_{}.root", m_output_dir, static_cast(m_pass), output_stem); + + auto output_file = std::make_unique(output_filename.c_str(), "RECREATE"); + + for (const auto& [name, hist] : m_hists1D) + { + std::cout << std::format("Saving 1D: {}\n", name); + hist->Write(); + } + for (const auto& [name, hist] : m_hists2D) + { + std::cout << std::format("Saving 2D: {}\n", name); + hist->Write(); + } + for (const auto& [name, hist] : m_hists3D) + { + std::cout << std::format("Saving 3D: {}\n", name); + hist->Write(); + } + for (const auto& [name, hist] : m_profiles) + { + std::cout << std::format("Saving Profile: {}\n", name); + hist->Write(); + } + output_file->Close(); + + std::cout << std::format("Results saved to: {}", output_filename) << std::endl; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h new file mode 100644 index 0000000000..7317ae1488 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -0,0 +1,386 @@ +#ifndef QVECCALIB_H +#define QVECCALIB_H + +#include "QVecDefs.h" + +// ==================================================================== +// ROOT Includes +// ==================================================================== + +#include +#include +#include +#include +#include +#include + +// ==================================================================== +// Standard C++ Includes +// ==================================================================== +#include +#include +#include + +/** + * @class QVecCalib + * @brief Orchestrates the multi-pass anisotropy calibration for the sEPD Q-vectors. + * + * This class implements a three-pass correction procedure designed to remove + * detector-induced biases from the sEPD event plane reconstruction: + * * 1. **ComputeRecentering**: Calculates the first-order vector offsets (re-centering) + * per centrality bin. + * 2. **ApplyRecentering**: Applies the first-order offsets and computes the + * second-order whitening/flattening matrix. + * 3. **ApplyFlattening**: Applies the full correction (re-centering + flattening) + * to produce final validated event planes. + * * The class manages event-level selections based on charge-centrality correlations + * and handles the exclusion of "bad" (hot/cold/dead) sEPD channels. + */ +class QVecCalib +{ + public: + // The constructor takes the configuration + QVecCalib(std::string input_file, std::string input_hist, std::string input_Q_calib, int pass, long long events, std::string output_dir) + : m_input_file(std::move(input_file)) + , m_input_hist(std::move(input_hist)) + , m_input_Q_calib(std::move(input_Q_calib)) + , m_pass(static_cast(pass)) + , m_events_to_process(events) + , m_output_dir(std::move(output_dir)) + { + } + + void run() + { + setup_chain(); + process_QA_hist(); + init_hists(); + process_events(); + save_results(); + } + + enum class Pass + { + ComputeRecentering, + ApplyRecentering, + ApplyFlattening + }; + + private: + + struct CorrectionData : public QVecShared::CorrectionMoments + { + std::array, 2> X_matrix{}; + }; + + static constexpr size_t m_cent_bins = QVecShared::CENT_BINS; + static constexpr auto m_harmonics = QVecShared::HARMONICS; + double m_cent_low = -0.5; + double m_cent_high = 79.5; + + // Holds all correction data + // key: [Cent][Harmonic][Subdetector] + // Harmonics {2,3,4} -> 3 elements + // Subdetectors {S,N} -> 2 elements + std::array, m_harmonics.size()>, m_cent_bins> m_correction_data; + + // Store harmonic orders and subdetectors for easy iteration + static constexpr std::array m_subdetectors = {QVecShared::Subdetector::S, QVecShared::Subdetector::N}; + static constexpr std::array m_components = {QVecShared::QComponent::X, QVecShared::QComponent::Y}; + + struct EventData + { + int event_id{0}; // NOLINT(misc-non-private-member-variables-in-classes) + double event_zvertex{0.0}; // NOLINT(misc-non-private-member-variables-in-classes) + double event_centrality{0.0}; // NOLINT(misc-non-private-member-variables-in-classes) + double sepd_totalcharge{0.0}; // NOLINT(misc-non-private-member-variables-in-classes) + + std::array, m_harmonics.size()> q_vectors; // NOLINT(misc-non-private-member-variables-in-classes) + + void reset() + { + for (auto& q_vec_harmonic : q_vectors) + { + for (auto& q_vec : q_vec_harmonic) + { + q_vec.x = 0.0; + q_vec.y = 0.0; + } + } + } + + std::vector* sepd_channel{nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) + std::vector* sepd_charge{nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) + std::vector* sepd_phi{nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) + }; + + struct AverageHists + { + TProfile* S_x_avg{nullptr}; + TProfile* S_y_avg{nullptr}; + TProfile* N_x_avg{nullptr}; + TProfile* N_y_avg{nullptr}; + + TH3* Q_S{nullptr}; + TH3* Q_N{nullptr}; + + TH3* Psi{nullptr}; + }; + + struct RecenterHists + { + TProfile* S_x_corr_avg{nullptr}; + TProfile* S_y_corr_avg{nullptr}; + TProfile* N_x_corr_avg{nullptr}; + TProfile* N_y_corr_avg{nullptr}; + + TProfile* S_xx_avg{nullptr}; + TProfile* S_yy_avg{nullptr}; + TProfile* S_xy_avg{nullptr}; + TProfile* N_xx_avg{nullptr}; + TProfile* N_yy_avg{nullptr}; + TProfile* N_xy_avg{nullptr}; + + TH3* Psi_corr{nullptr}; + }; + + struct FlatteningHists + { + TProfile* S_x_corr2_avg{nullptr}; + TProfile* S_y_corr2_avg{nullptr}; + TProfile* N_x_corr2_avg{nullptr}; + TProfile* N_y_corr2_avg{nullptr}; + + TProfile* S_xx_corr_avg{nullptr}; + TProfile* S_yy_corr_avg{nullptr}; + TProfile* S_xy_corr_avg{nullptr}; + + TProfile* N_xx_corr_avg{nullptr}; + TProfile* N_yy_corr_avg{nullptr}; + TProfile* N_xy_corr_avg{nullptr}; + + TH3* Psi_corr2{nullptr}; + }; + + // --- Member Variables --- + EventData m_event_data; + std::unique_ptr m_chain; + + // Configuration stored as members + std::string m_input_file; + std::string m_input_hist; + std::string m_input_Q_calib; + Pass m_pass{0}; + long long m_events_to_process; + std::string m_output_dir; + + // Hists + std::map> m_hists1D; + std::map> m_hists2D; + std::map> m_hists3D; + std::map> m_profiles; + + // sEPD Bad Channels + std::unordered_set m_bad_channels; + + double m_sEPD_min_avg_charge_threshold{1}; + double m_sEPD_sigma_threshold{3}; + + // --- Private Helper Methods --- + +/** + * @brief Sets up a TChain and performs structural validation of the input ROOT file. + * * Verifies file existence, ensures the requested TTree exists, and checks for + * non-zero entries before returning a configured chain. + * * @param input_filepath Path to the input .root file. + * @param tree_name_in_file Name of the TTree inside the file. + * @return std::unique_ptr A configured TChain, or nullptr if validation fails. + */ + std::unique_ptr setupTChain(const std::string& input_filepath, const std::string& tree_name_in_file); + +/** + * @brief Orchestrates the TChain initialization and branch configuration. + * * Sets the branch statuses and addresses for event-level data (ID, centrality, charge) + * and sEPD tower-level data (channel, charge, phi) needed for the calibration. + */ + void setup_chain(); + +/** + * @brief Initializes all output histograms and profiles. + * * Dynamically generates histogram names using the shared naming helper based on + * the current calibration pass (e.g., adding "_corr" or "_corr2" suffixes). + */ + void init_hists(); + +/** + * @brief Safely retrieves a ROOT object from a file and returns a managed unique_ptr. + * * Performs a dynamic_cast to verify the requested type T and Clones the object + * to ensure it remains valid after the source file is closed. + * * @tparam T The ROOT class type (e.g., TProfile, TH3). + * @param file Pointer to the source TFile. + * @param name The name of the object within the file. + * @return std::unique_ptr A managed pointer to the cloned object. + * @throws std::runtime_error If the object is not found or type mismatch occurs. + */ + template + std::unique_ptr load_and_clone(TFile* file, const std::string& name); + +/** + * @brief Loads the results of previous passes from a calibration file. + * * Populates the internal correction data structure with averages and/or + * matrices required for the current processing pass. + */ + void load_correction_data(); + +/** + * @brief High-level orchestrator for the event processing phase. + * * If the current pass requires existing calibration data (Recentering or Flattening), + * it triggers the data loading sequence before starting the main event loop. + */ + void process_events(); + +/** + * @brief Validates events based on sEPD total charge vs. centrality correlation. + * * Compares the current event's total charge against the 3-sigma bounds derived + * from the QA histograms to reject pile-up or background-dominated events. + * @return True if the event falls within the acceptable charge window. + */ + bool process_event_check(); + +/** + * @brief Performs the primary tower-by-tower Q-vector calculation and normalization. + * * Loops through sEPD channels, excludes bad channels, calculates the raw Q-vector + * for all harmonics, and normalizes the results by the total arm charge. + * @return True if both South and North arms have non-zero total charge. + */ + bool process_sEPD(); + +/** + * @brief Primary event loop orchestrator. + * * Iterates through the TChain entries, performs event selection, executes + * normalization/re-centering/flattening logic based on the current pass, + * and fills the output histograms. + */ + void run_event_loop(); + +/** + * @brief Finalizes the analysis by writing all histograms to the output ROOT file. + * * Creates the output directory if it does not exist and ensures all 1D, 2D, + * 3D histograms and TProfiles are safely persisted to disk. + */ + void save_results() const; + +/** + * @brief Calculates and fills profiles for the initial Q-vector averages. + * @param cent The event centrality. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the first pass. + */ + static void process_averages(double cent, QVecShared::QVec q_S, QVecShared::QVec q_N, const AverageHists& h); + +/** + * @brief Applies re-centering offsets and fills profiles for second-moment calculation. + * @param cent The event centrality. + * @param h_idx Harmonic index. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the second pass. + */ + void process_recentering(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const RecenterHists& h); + +/** + * @brief Applies the full correction (re-centering + flattening) for validation. + * @param cent The event centrality. + * @param h_idx Harmonic index. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the third pass. + */ + void process_flattening(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const FlatteningHists& h); + +/** + * @brief Calculates the 2x2 anisotropy correction (whitening) matrix. + * * This matrix transforms the elliptical Q-vector distribution into a circularly + * symmetric (isotropic) distribution. It effectively corrects for detector + * acceptance effects and gain non-uniformities by normalizing the second-order + * moments of the Q-vector. + * * @param xx The second moment. + * @param yy The second moment. + * @param xy The cross-moment. + * @param n Harmonic order (used for error logging context). + * @param cent_bin Centrality bin (used for error logging context). + * @param det_label Detector label ("S" or "N"). + * @return std::array, 2> The 2x2 correction matrix. + */ + std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); + + +/** + * @brief Computes 1st-order re-centering offsets for a specific centrality bin. + * * Extracts average Q-vector components from histograms and stores them in the + * correction data matrix for use in subsequent processing passes. + * * @param cent_bin The index of the centrality bin. + * @param h_idx The index of the harmonic order in the harmonics array. + */ + void compute_averages(size_t cent_bin, int h_idx); + +/** + * @brief Computes re-centering parameters and solves the flattening matrices. + * * Extracts the re-centered second moments from the profiles and populates the + * internal CorrectionData matrix with calculated flattening coefficients. + * @param cent_bin The centrality bin index. + * @param h_idx The harmonic index. + */ + void compute_recentering(size_t cent_bin, int h_idx); + +/** + * @brief Logs the final corrected moments to verify successful flattening. + * @param cent_bin The centrality bin index. + * @param n The harmonic order. + */ + void print_flattening(size_t cent_bin, int n) const; + +/** + * @brief Prepares a vector of pointers to histograms used in the first pass. + * @return A vector of AverageHists structs, indexed by harmonic. + */ + std::vector prepare_average_hists(); + +/** + * @brief Prepares a vector of pointers to histograms used in the second pass. + * @return A vector of RecenterHists structs, indexed by harmonic. + */ + std::vector prepare_recenter_hists(); + +/** + * @brief Prepares a vector of pointers to histograms used in the third pass. + * @return A vector of FlatteningHists structs, indexed by harmonic. + */ + std::vector prepare_flattening_hists(); + +/** + * @brief Top-level driver for processing Quality Assurance histograms. + * * Loads the reference histogram file to identify bad channels and establish + * event-level charge thresholds as a function of centrality. + */ + void process_QA_hist(); + +/** + * @brief Identifies and catalogs "Bad" (Hot, Cold, or Dead) sEPD channels. + * * Uses a reference charge histogram to compute Z-scores based on mean charge + * per radial bin. Channels exceeding the sigma threshold are added to the internal exclusion set. + * * @param file Pointer to the open TFile containing QA histograms. + */ + void process_bad_channels(TFile* file); + +/** + * @brief Establishes sEPD charge-cut thresholds for event selection. + * * Uses the 2D total charge vs. centrality distribution to derive mean and + * sigma values, generating a 1D profile of the selection window. + * @param file Pointer to the open QA histogram file. + */ + void process_sEPD_event_thresholds(TFile* file); +}; + +#endif // QVECCALIB_H diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h new file mode 100644 index 0000000000..f74c62f574 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -0,0 +1,55 @@ +#ifndef QVECDEFS_H +#define QVECDEFS_H + +#include +#include +#include +#include + +namespace QVecShared +{ + static constexpr size_t CENT_BINS = 8; + static constexpr std::array HARMONICS = {2, 3, 4}; + + enum class Subdetector + { + S, // South + N // North + }; + + enum class QComponent + { + X, + Y + }; + + struct QVec + { + double x{0.0}; + double y{0.0}; + }; + + struct CorrectionMoments + { + QVec avg_Q{}; // Mean Q vector + double avg_Q_xx{0.0}; + double avg_Q_yy{0.0}; + double avg_Q_xy{0.0}; + }; + + /** + * @brief Centralized helper to generate standard histogram names for the sEPD calibration. + * * Standardizes the naming convention: h_sEPD_Q_{det}_{var}_{n}{suffix}_avg + * * @param det The detector arm ("S" for South, "N" for North). + * @param var The physics variable or moment (e.g., "x", "y", "xx", "xy"). + * @param n The harmonic order (e.g., 2, 3, 4). + * @param suffix Optional pass-specific suffix (e.g., "_corr", "_corr2"). + * @return A formatted std::string representing the ROOT histogram name. + */ + inline std::string get_hist_name(const std::string& det, const std::string& var, int n, const std::string& suffix = "") + { + return std::format("h_sEPD_Q_{}_{}_{}{}_avg", det, var, n, suffix); + } +} // namespace QVecShared + +#endif // QVECDEFS_H diff --git a/calibrations/sepd/sepd_eventplanecalib/autogen.sh b/calibrations/sepd/sepd_eventplanecalib/autogen.sh new file mode 100644 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/sepd/sepd_eventplanecalib/configure.ac b/calibrations/sepd/sepd_eventplanecalib/configure.ac new file mode 100644 index 0000000000..4abe4ad0ce --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/configure.ac @@ -0,0 +1,16 @@ +AC_INIT(sepd_eventplanecalib,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wshadow -Wall -Wextra -Werror" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc new file mode 100644 index 0000000000..be03589d40 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -0,0 +1,289 @@ +#include "sEPD_TreeGen.h" + +// -- c++ +#include +#include + +// -- event +#include + +// -- Fun4All +#include +#include + +// -- Nodes +#include +#include + +// -- Calo +#include +#include +#include + +// -- Vtx +#include +#include + +// -- MB +#include +#include +#include + +// -- sEPD +#include + +//____________________________________________________________________________.. +sEPD_TreeGen::sEPD_TreeGen(const std::string &name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::Init([[maybe_unused]] PHCompositeNode *topNode) +{ + Fun4AllServer *se = Fun4AllServer::instance(); + se->Print("NODETREE"); + + unsigned int bins_sepd_totalcharge{100}; + double sepd_totalcharge_low{0}; + double sepd_totalcharge_high{2e4}; + + unsigned int bins_centrality{80}; + double centrality_low{-0.5}; + double centrality_high{79.5}; + + hSEPD_Charge = std::make_unique("hSEPD_Charge", "|z| < 10 cm and MB; Channel; Avg Charge", m_sepd_channels, 0, m_sepd_channels); + hSEPD_Charge->Sumw2(); + + h2SEPD_totalcharge_centrality = std::make_unique("h2SEPD_totalcharge_centrality", "|z| < 10 cm and MB; sEPD Total Charge; Centrality [%]", bins_sepd_totalcharge, sepd_totalcharge_low, sepd_totalcharge_high, bins_centrality, centrality_low, centrality_high); + + m_output = std::make_unique(m_outtree_name.c_str(), "recreate"); + m_output->cd(); + + // TTree + m_tree = std::make_unique("T", "T"); + m_tree->SetDirectory(m_output.get()); + m_tree->Branch("event_id", &m_data.event_id); + m_tree->Branch("event_zvertex", &m_data.event_zvertex); + m_tree->Branch("event_centrality", &m_data.event_centrality); + m_tree->Branch("sepd_totalcharge", &m_data.sepd_totalcharge); + m_tree->Branch("sepd_channel", &m_data.sepd_channel); + m_tree->Branch("sepd_charge", &m_data.sepd_charge); + m_tree->Branch("sepd_phi", &m_data.sepd_phi); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_event_check(PHCompositeNode *topNode) +{ + GlobalVertexMap *vertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + + if (!vertexmap) + { + std::cout << PHWHERE << "GlobalVertexMap Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + if (!vertexmap->empty()) + { + GlobalVertex *vtx = vertexmap->begin()->second; + m_data.event_zvertex = vtx->get_z(); + } + + MinimumBiasInfo *m_mb_info = findNode::getClass(topNode, "MinimumBiasInfo"); + if (!m_mb_info) + { + std::cout << PHWHERE << "MinimumBiasInfo Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // skip event if not minimum bias + if (!m_mb_info->isAuAuMinimumBias()) + { + if (Verbosity() > 2) + { + std::cout << "Event: " << m_data.event_id << ", Not Min Bias, Skipping" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + // skip event if zvtx is too large + if (std::abs(m_data.event_zvertex) >= m_cuts.m_zvtx_max) + { + if (Verbosity() > 2) + { + std::cout << "Event: " << m_data.event_id << ", Z: " << m_data.event_zvertex << " cm, Skipping" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_centrality(PHCompositeNode *topNode) +{ + CentralityInfo *centInfo = findNode::getClass(topNode, "CentralityInfo"); + if (!centInfo) + { + std::cout << PHWHERE << "CentralityInfo Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_data.event_centrality = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; + + // skip event if centrality is too peripheral + if (!std::isfinite(m_data.event_centrality) || m_data.event_centrality < 0 || m_data.event_centrality >= m_cuts.m_cent_max) + { + if(Verbosity() > 2) + { + std::cout << "Event: " << m_data.event_id << ", Centrality: " << m_data.event_centrality << ", Skipping" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) +{ + TowerInfoContainer *towerinfosEPD = findNode::getClass(topNode, "TOWERINFO_CALIB_SEPD"); + if (!towerinfosEPD) + { + std::cout << PHWHERE << "TOWERINFO_CALIB_SEPD Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + EpdGeom *epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << "TOWERGEOM_EPD Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // sepd + unsigned int sepd_channels = towerinfosEPD->size(); + + if(sepd_channels != m_sepd_channels) + { + if (Verbosity() > 2) + { + std::cout << "Event: " << m_data.event_id << ", SEPD Channels = " << sepd_channels << " != " << m_sepd_channels << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_data.sepd_totalcharge = 0; + + for (unsigned int channel = 0; channel < sepd_channels; ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(channel); + + TowerInfo *tower = towerinfosEPD->get_tower_at_channel(channel); + + double charge = tower->get_energy(); + bool isZS = tower->get_isZS(); + double phi = epdgeom->get_phi(key); + + // exclude ZS + // exclude Nmips + if (isZS || charge < m_cuts.m_sepd_charge_min) + { + continue; + } + + m_data.sepd_channel.push_back(channel); + m_data.sepd_charge.push_back(charge); + m_data.sepd_phi.push_back(phi); + + m_data.sepd_totalcharge += charge; + + hSEPD_Charge->Fill(channel, charge); + } + + h2SEPD_totalcharge_centrality->Fill(m_data.sepd_totalcharge, m_data.event_centrality); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_event(PHCompositeNode *topNode) +{ + EventHeader *eventInfo = findNode::getClass(topNode, "EventHeader"); + if (!eventInfo) + { + std::cout << PHWHERE << "EventHeader Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_data.event_id = eventInfo->get_EvtSequence(); + + if (Verbosity() > 1 && m_event % 20 == 0) + { + std::cout << "Progress: " << m_event << ", Global: " << m_data.event_id << std::endl; + } + ++m_event; + + int ret = process_event_check(topNode); + if (ret) + { + return ret; + } + + ret = process_centrality(topNode); + if (ret) + { + return ret; + } + + ret = process_sEPD(topNode); + if (ret) + { + return ret; + } + + // Fill the TTree + m_tree->Fill(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) +{ + // Event + m_data.event_id = -1; + m_data.event_zvertex = 9999; + m_data.event_centrality = 9999; + + // sEPD + m_data.sepd_totalcharge = 0; + m_data.sepd_channel.clear(); + m_data.sepd_charge.clear(); + m_data.sepd_phi.clear(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::End([[maybe_unused]] PHCompositeNode *topNode) +{ + std::cout << "sEPD_TreeGen::End" << std::endl; + + TFile output(m_outfile_name.c_str(), "recreate"); + output.cd(); + + hSEPD_Charge->Write(); + h2SEPD_totalcharge_centrality->Write(); + + output.Close(); + + // TTree + m_output->cd(); + m_tree->Write(); + m_output->Close(); + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h new file mode 100644 index 0000000000..225e62cc8f --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h @@ -0,0 +1,177 @@ +#ifndef SEPD_TREEGEN_H +#define SEPD_TREEGEN_H + +// -- sPHENIX +#include + +// -- c++ +#include +#include +#include +#include +#include + +// -- ROOT +#include +#include +#include +#include + +class PHCompositeNode; + +/** + * @class sEPD_TreeGen + * @brief SubsysReco module to produce flat TTrees and QA histograms for sEPD calibration. + * + * This module extracts event-level info (vertex, centrality) and sEPD tower-level info + * (charge, phi, channel ID), applying basic event selections (Minimum Bias, Z-vertex) + * and tower-level cuts (charge threshold, zero-suppression). + */ +class sEPD_TreeGen : public SubsysReco +{ + public: + /** + * @brief Constructor for sEPD_TreeGen. + * @param name The name assigned to this SubsysReco module. + */ + explicit sEPD_TreeGen(const std::string &name = "sEPD_TreeGen"); + + /** + * @brief Initializes the module and creates the output TTree and QA histograms. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int Init(PHCompositeNode *topNode) override; + + /** + * @brief Main event-by-event processing method. + * @details Orchestrates event checks, centrality retrieval, sEPD tower processing, + * and fills the TTree for valid events. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_event(PHCompositeNode *topNode) override; + + /** + * @brief Resets event-level data structures before the next event. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int ResetEvent(PHCompositeNode *topNode) override; + + /** + * @brief Finalizes the module, writing all histograms and the TTree to disk. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int End(PHCompositeNode *topNode) override; + + /** + * @brief Sets the filename for the QA histograms ROOT file. + * @param file Output path for histograms. + */ + void set_filename(const std::string &file) + { + m_outfile_name = file; + } + + /** + * @brief Sets the filename for the flat TTree ROOT file. + * @param file Output path for the TTree. + */ + void set_tree_filename(const std::string &file) + { + m_outtree_name = file; + } + + /** + * @brief Sets the maximum allowed Z-vertex position for event selection. + * @param zvtx_max Maximum vertex Z in cm. + */ + void set_zvtx_max(double zvtx_max) + { + m_cuts.m_zvtx_max = zvtx_max; + } + + /** + * @brief Sets the minimum charge threshold for individual sEPD towers. + * @param charge_min Minimum charge to include a tower in the TTree. + */ + void set_sepd_charge_threshold(double charge_min) + { + m_cuts.m_sepd_charge_min= charge_min; + } + + /** + * @brief Sets the maximum centrality centile allowed for processing. + * @param cent_max Maximum centile (e.g., 80 for 0-80%). + */ + void set_cent_max(double cent_max) + { + m_cuts.m_cent_max = cent_max; + } + + private: + /** + * @brief Validates event-level conditions (GlobalVertex, Minimum Bias). + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_event_check(PHCompositeNode *topNode); + + /** + * @brief Processes individual sEPD towers and calculates total charge. + * @details Applies tower cuts, fills QA histograms, and stores tower data in vectors. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_sEPD(PHCompositeNode *topNode); + + /** + * @brief Retrieves and validates centrality information. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_centrality(PHCompositeNode *topNode); + + int m_event{0}; + + std::string m_outfile_name{"test.root"}; + std::string m_outtree_name{"tree.root"}; + + static constexpr int m_sepd_channels = 744; + + // Cuts + struct Cuts + { + double m_zvtx_max{10}; /*cm*/ + double m_sepd_charge_min{0.2}; + double m_cent_max{80}; + }; + + Cuts m_cuts; + + struct EventData + { + int event_id{0}; + double event_zvertex{9999}; + double event_centrality{9999}; + + double sepd_totalcharge{-9999}; + + std::vector sepd_channel; + std::vector sepd_charge; + std::vector sepd_phi; + }; + + EventData m_data; + + std::unique_ptr m_output; + std::unique_ptr m_tree; + + std::unique_ptr hSEPD_Charge; + std::unique_ptr h2SEPD_totalcharge_centrality; +}; + + +#endif // SEPD_TREEGEN_H From 5b6afdad8db9020398c62b702844714cfdda6619 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 14 Jan 2026 12:19:16 -0500 Subject: [PATCH 056/866] add type 37: hijing O+O 0-15fm --- offline/framework/frog/CreateFileList.pl | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index cc59083d8c..19b552b764 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -74,7 +74,8 @@ "33" => "JS pythia8 Jet ptmin = 15GeV", "34" => "JS pythia8 Jet ptmin = 50GeV", "35" => "JS pythia8 Jet ptmin = 70GeV", - "36" => "JS pythia8 Jet ptmin = 5GeV" + "36" => "JS pythia8 Jet ptmin = 5GeV", + "37" => "hijing O+O (0-15fm)" ); my %pileupdesc = ( @@ -926,6 +927,20 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 37) + { + if (defined $nopileup) + { + $filenamestring = sprintf("sHijing_OO_0_15fm"); + } + else + { + $filenamestring = sprintf("sHijing_OO_0_15fm%s",$AuAu_pileupstring); + } + $notlike{$filenamestring} = ["pythia8" ,"single", "special"]; + $pileupstring = $AuAu_pileupstring; + &commonfiletypes(); + } else { From 85e50bbfda8ad12507ea9416f698e6c37857e7e6 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 14 Jan 2026 13:18:51 -0500 Subject: [PATCH 057/866] clang-tidy for HepMCJetTrigger --- generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc index b22db801b5..792720a962 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc @@ -97,7 +97,10 @@ std::vector HepMCJetTrigger::findAllJets(HepMC::GenEvent* e1 { auto p = (*iter)->momentum(); auto pd = std::abs((*iter)->pdg_id()); - if( pd >=12 && pd <=18) continue; //keep jet in the expected behavioro + 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); @@ -124,7 +127,10 @@ 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 (std::abs(j.eta()) > 1.1) + { + continue; + } if (pt > this->threshold) { n_good_jets++; From e3fffcefbc47645a4973ffab7209b6956eec9238 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Wed, 14 Jan 2026 15:04:20 -0500 Subject: [PATCH 058/866] Fixed bug in logic for using existing parameter sets --- .../trackbase/AlignmentTransformation.cc | 121 ++++++++++-------- .../trackbase/AlignmentTransformation.h | 3 +- 2 files changed, 71 insertions(+), 53 deletions(-) diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index b3eb79fcb0..2e8647ab01 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -277,6 +277,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 +286,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; @@ -417,70 +421,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; } diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index 7055d6c65a..e8eb3882d1 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -128,7 +128,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); From d7d58e14c6c7b42e216013978b7c7678a0319892 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 14 Jan 2026 21:22:31 -0500 Subject: [PATCH 059/866] this change fixes the tpc drift velocity being set to zero --- generators/PHPythia8/PHPythia8.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 9aa14d4684..64010072ad 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -45,8 +45,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); @@ -92,8 +96,19 @@ int PHPythia8::Init(PHCompositeNode *topNode) // print out seed so we can make this is reproducible std::cout << "PHPythia8 random seed: " << seed << std::endl; + + // this is empirical - something in the pythia8::init() method interferes + // with our macros (it sets the tpc drift verlocity back to 0) + // not the feintest idea right now what this could be + // but saving the old cout state and restoring it aftwerwards + // gets our tpc drift velocity back + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); + m_Pythia8->init(); + std::cout.copyfmt(old_state); + return Fun4AllReturnCodes::EVENT_OK; } From 04e747faa66d7639f44ca83177286d894b5b6437 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:17:58 +0000 Subject: [PATCH 060/866] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20?= =?UTF-8?q?`fix-tpc-drift-pythia8`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @pinkenburg. * https://github.com/sPHENIX-Collaboration/coresoftware/pull/4111#issuecomment-3752587001 The following files were modified: * `generators/PHPythia8/PHPythia8.cc` --- generators/PHPythia8/PHPythia8.cc | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 64010072ad..1be3aa9edc 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) { @@ -59,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()) @@ -336,4 +362,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 From 1fe3891016c2d54c2234f779caaf090aff5989ea Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 15 Jan 2026 09:24:08 -0500 Subject: [PATCH 061/866] Fix missing newline at end of PHPythia8.cc Add newline at the end of PHPythia8.cc file --- generators/PHPythia8/PHPythia8.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 1be3aa9edc..56f2b2bb9c 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -362,4 +362,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 +} From 69de5bb2327e92359b07d420c31cc82be47c0e73 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 15 Jan 2026 14:30:14 -0500 Subject: [PATCH 062/866] do not read flow angles if flow afterburner was not run --- offline/framework/ffamodules/HeadReco.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/offline/framework/ffamodules/HeadReco.cc b/offline/framework/ffamodules/HeadReco.cc index 75e879fdff..17214758c8 100644 --- a/offline/framework/ffamodules/HeadReco.cc +++ b/offline/framework/ffamodules/HeadReco.cc @@ -84,10 +84,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()); From 3d192990eaa8a96baa4b7b9e604c0287b7dd666d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 15 Jan 2026 14:34:23 -0500 Subject: [PATCH 063/866] return NAN if flow psi vector is empty --- generators/phhepmc/PHHepMCGenEventv1.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/generators/phhepmc/PHHepMCGenEventv1.cc b/generators/phhepmc/PHHepMCGenEventv1.cc index bc8eef6f41..3aa7515365 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 @@ -109,6 +110,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(); } From b209d8585c6ec207b4c60215f8996bb185be86ad Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Thu, 15 Jan 2026 16:34:44 -0500 Subject: [PATCH 064/866] dEdxFitter initial commit --- calibrations/tpc/dEdx/GlobaldEdxFitter.h | 404 +++++++++++++++++++++++ calibrations/tpc/dEdx/Makefile.am | 49 +++ calibrations/tpc/dEdx/autogen.sh | 8 + calibrations/tpc/dEdx/bethe_bloch.h | 208 ++++++++++++ calibrations/tpc/dEdx/configure.ac | 16 + calibrations/tpc/dEdx/dEdxFitter.cc | 228 +++++++++++++ calibrations/tpc/dEdx/dEdxFitter.h | 88 +++++ calibrations/tpc/dEdx/test_sample_size.C | 185 +++++++++++ 8 files changed, 1186 insertions(+) create mode 100644 calibrations/tpc/dEdx/GlobaldEdxFitter.h create mode 100644 calibrations/tpc/dEdx/Makefile.am create mode 100755 calibrations/tpc/dEdx/autogen.sh create mode 100644 calibrations/tpc/dEdx/bethe_bloch.h create mode 100644 calibrations/tpc/dEdx/configure.ac create mode 100644 calibrations/tpc/dEdx/dEdxFitter.cc create mode 100644 calibrations/tpc/dEdx/dEdxFitter.h create mode 100644 calibrations/tpc/dEdx/test_sample_size.C diff --git a/calibrations/tpc/dEdx/GlobaldEdxFitter.h b/calibrations/tpc/dEdx/GlobaldEdxFitter.h new file mode 100644 index 0000000000..267e30f0a4 --- /dev/null +++ b/calibrations/tpc/dEdx/GlobaldEdxFitter.h @@ -0,0 +1,404 @@ +#ifndef GLOBALDEDXFITTER_H +#define GLOBALDEDXFITTER_H + +#include "bethe_bloch.h" +#include "TF1.h" +#include "TF2.h" +#include "TF3.h" +#include "TChain.h" +#include "TGraph.h" +#include "Math/Minimizer.h" +#include "Math/Functor.h" +#include "Math/Factory.h" + +const double m_pi = 0.1396; // GeV +const double m_K = 0.4937; // GeV +const double m_p = 0.9382; // GeV +const double m_d = 1.876; // GeV + +class GlobaldEdxFitter +{ + public: + GlobaldEdxFitter(double xmin = 10., double xmax = 50.) + { + min_norm = xmin; + max_norm = xmax; + }; + void processResidualData(size_t ntracks = 200000, + size_t skip = 0, + std::string infile="/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/track_output_53877*.root_resid.root"); + void addTrack(double trk_dEdx, double trk_p); + size_t getNtracks() + { + return dEdx.size(); + } + + double get_fitquality(double norm, double ZS_loss = 0.); + double get_fitquality_new(double A); + TF1* create_TF1(std::string name); + TF2* create_TF2(std::string name); + TF3* create_TF3_new(std::string name); + double get_minimum(); + double get_minimum_new(); + std::pair get_minimum_ZS(); + void set_range(double xmin, double xmax, double ZSmin, double ZSmax) + { + min_norm = xmin; + max_norm = xmax; + min_ZS = ZSmin; + max_ZS = ZSmax; + } + void reset() + { + p.clear(); + dEdx.clear(); + betagamma.clear(); + } + std::vector get_betagamma(double A); + TGraph* graph_vsbetagamma(double A); + TGraph* graph_vsp(); + private: + std::vector p; + std::vector dEdx; + std::vector betagamma; + + double get_fitquality_functor(const double* x); + + double get_fitquality_wrapper(double* x, double* p); + double get_fitquality_wrapper_ZS(double* x, double* p); + double get_fitquality_wrapper_new(double* x, double* p); + double min_norm = 10.; + double max_norm = 50.; + double min_ZS = 0.; + double max_ZS = 200.; + double min_B = 8.; + double max_B = 12.; +}; + +void GlobaldEdxFitter::processResidualData(size_t ntracks, size_t skip, std::string infile) +{ + std::unique_ptr t = std::make_unique(); + t->Add((infile+"?#residualtree").c_str()); +// TFile* f = TFile::Open(infile.c_str()); +// TTree* t = (TTree*)f->Get("residualtree"); + + float px; + float py; + float pz; + float dedx; + float eta; + int nmaps; + int nintt; + int ntpc; + float dcaxy; + + t->SetBranchAddress("px",&px); + t->SetBranchAddress("py",&py); + t->SetBranchAddress("pz",&pz); + t->SetBranchAddress("dedx",&dedx); + t->SetBranchAddress("eta",&eta); + t->SetBranchAddress("nmaps",&nmaps); + t->SetBranchAddress("nintt",&nintt); + t->SetBranchAddress("ntpc",&ntpc); + t->SetBranchAddress("dcaxy",&dcaxy); + + for(size_t entry=skip; entry<(skip+ntracks); entry++) + { + //if(entry==t->GetEntries()-1) break; + if(entry % 1000 == 0) std::cout << entry << std::endl; + t->GetEntry(entry); + if(nmaps>0 && nintt>0 && fabs(eta)<1. && dcaxy<0.5 && ntpc>30) + { + p.push_back(sqrt(px*px+py*py+pz*pz)); + dEdx.push_back(dedx); + } + } + std::cout << "number of good tracks: " << p.size() << std::endl; + //f->Close(); +} + +void GlobaldEdxFitter::addTrack(double trk_dEdx, double trk_p) +{ + dEdx.push_back(trk_dEdx); + p.push_back(trk_p); +} + +double GlobaldEdxFitter::get_fitquality_new(double A) +{ + double chi2 = 0.; + double ndf = -1.; + + double pi_chi2 = 0.; + double K_chi2 = 0.; + double p_chi2 = 0.; + double d_chi2 = 0.; + double pi_ndf = -1.; + double K_ndf = -1.; + double p_ndf = -1.; + double d_ndf = -1.; + + for(size_t i=0; i GlobaldEdxFitter::get_betagamma(double A) +{ + std::vector betagamma; + for(size_t i=0; iGetMinimumXYZ(minA,minB,minC); + delete f; + return std::make_tuple(minA,minB,minC); +*/ + ROOT::Math::Minimizer* minimizer = ROOT::Math::Factory::CreateMinimizer("Minuit2"); + minimizer->SetMaxFunctionCalls(1000000); + minimizer->SetMaxIterations(10000); + minimizer->SetTolerance(0.1); + minimizer->SetPrintLevel(1); + ROOT::Math::Functor f(this,&GlobaldEdxFitter::get_fitquality_functor,1); + double step[1] = {.01}; + double variable[1] = {20.}; + minimizer->SetFunction(f); + minimizer->SetVariable(0,"A",variable[0],step[0]); + minimizer->Minimize(); + const double *xs = minimizer->X(); + return xs[0]; +} + +double GlobaldEdxFitter::get_minimum() +{ + TF1* f = create_TF1("temp"); + f->SetNpx(1000); + double minX = f->GetMinimumX(); + delete f; + return minX; +} + +std::pair GlobaldEdxFitter::get_minimum_ZS() +{ + TF2* f = create_TF2("temp"); + double minX; + double minY; + f->GetMinimumXY(minX,minY); + delete f; + return std::make_pair(minX,minY); +} + +TGraph* GlobaldEdxFitter::graph_vsbetagamma(double A) +{ + std::vector betagamma = get_betagamma(A); + TGraph* g = new TGraph(dEdx.size(),betagamma.data(),dEdx.data()); + return g; +} + +TGraph* GlobaldEdxFitter::graph_vsp() +{ + TGraph* g = new TGraph(dEdx.size(),p.data(),dEdx.data()); + return g; +} + +#endif diff --git a/calibrations/tpc/dEdx/Makefile.am b/calibrations/tpc/dEdx/Makefile.am new file mode 100644 index 0000000000..03dda87d60 --- /dev/null +++ b/calibrations/tpc/dEdx/Makefile.am @@ -0,0 +1,49 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + dEdxFitter.h \ + GlobaldEdxFitter.h \ + bethe_bloch.h + +lib_LTLIBRARIES = \ + libdedxfitter.la + +libdedxfitter_la_SOURCES = \ + dEdxFitter.cc + +libdedxfitter_la_LIBADD = \ + -lphool \ + -ltrack_io \ + -lg4detectors \ + -ltrackbase_historic_io \ + -ltrack_reco \ + -lglobalvertex \ + -lSubsysReco + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libdedxfitter.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/tpc/dEdx/autogen.sh b/calibrations/tpc/dEdx/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/tpc/dEdx/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/tpc/dEdx/bethe_bloch.h b/calibrations/tpc/dEdx/bethe_bloch.h new file mode 100644 index 0000000000..3b134224ee --- /dev/null +++ b/calibrations/tpc/dEdx/bethe_bloch.h @@ -0,0 +1,208 @@ +#ifndef BETHE_BLOCH_H +#define BETHE_BLOCH_H + +#include "TMath.h" + +namespace dedx_constants +{ + // hadron masses + constexpr double m_pi = 0.1396; // GeV + constexpr double m_K = 0.4937; // GeV + constexpr double m_p = 0.9382; // GeV + constexpr double m_d = 1.876; // GeV + + // electron mass [eV] + constexpr double m_e = 511e3; + + // TPC gas fractions + constexpr double ar_frac = 0.75; + constexpr double cf4_frac = 0.2; + constexpr double isobutane_frac = 0.05; + + // Mean excitation [src: W. Blum, W. Riegler, L. Rolandi, "Particle Detection with Drift Chambers"] + constexpr double ar_I = 188; // eV + constexpr double cf4_I = 115; // eV + constexpr double isobutane_I = 48.3; // eV + + // Mean excitation of mixture approximated using Bragg additivity rule + constexpr double sphenix_I = ar_frac*ar_I + cf4_frac*cf4_I + isobutane_frac*isobutane_I; +} + +// Bethe-Bloch fit function, vs. betagamma +// A = normalization constant, equal to (ADC conversion)*4pi*n*Z^2*e^4/(m_e*c^2*4pi*epsilon_0^2) +// B = A*(ln(2*m_e/I)-1) - (zero-suppression loss factor) +const double bethe_bloch_new(const double betagamma, const double A, const double B, const double C) +{ + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return A/(beta*beta)*TMath::Log(betagamma) + A/(beta*beta)*B - A - C; +} + +const double bethe_bloch_new_2D(const double betagamma, const double A, const double B) +{ + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return A/(beta*beta)*(2.*TMath::Log(2.*dedx_constants::m_e/dedx_constants::sphenix_I * betagamma) - beta*beta) - B; +} + +const double bethe_bloch_new_1D(const double betagamma, const double A) +{ + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return A/(beta*beta)*(2.*TMath::Log(2.*dedx_constants::m_e/dedx_constants::sphenix_I * betagamma) - beta*beta); +} + +// dE/dx for one gas species, up to normalization +const double bethe_bloch_species(const double betagamma, const double I) +{ + const double m_e = 511e3; // eV + + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return 1./(beta*beta)*(TMath::Log(2.*m_e/I*betagamma*betagamma)-beta*beta); +} + +// dE/dx for TPC gas mixture, up to normalization +const double bethe_bloch_total(const double betagamma) +{ + return dedx_constants::ar_frac * bethe_bloch_species(betagamma,dedx_constants::ar_I) + + dedx_constants::cf4_frac * bethe_bloch_species(betagamma,dedx_constants::cf4_I) + + dedx_constants::isobutane_frac * bethe_bloch_species(betagamma,dedx_constants::isobutane_I); +} + +Double_t bethe_bloch_new_wrapper(Double_t* x, Double_t* par) +{ + Double_t betagamma = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + Double_t C = par[2]; + + return bethe_bloch_new(betagamma,A,B,C); +} + +Double_t bethe_bloch_new_2D_wrapper(Double_t* x, Double_t* par) +{ + Double_t betagamma = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + + return bethe_bloch_new_2D(betagamma,A,B); +} + +Double_t bethe_bloch_new_1D_wrapper(Double_t* x, Double_t* par) +{ + Double_t betagamma = x[0]; + Double_t A = par[0]; + + return bethe_bloch_new_1D(betagamma,A); +} + +// wrapper function for TF1 constructor, for fitting +Double_t bethe_bloch_wrapper(Double_t* ln_bg, Double_t* par) +{ + Double_t betagamma = exp(ln_bg[0]); + + Double_t norm = par[0]; + + return norm * bethe_bloch_total(betagamma); +} + +Double_t bethe_bloch_vs_p_wrapper(Double_t* x, Double_t* par) +{ + Double_t p = x[0]; + Double_t norm = par[0]; + Double_t m = par[1]; + + return norm * bethe_bloch_total(fabs(p)/m); +} + +Double_t bethe_bloch_vs_logp_wrapper(Double_t* x, Double_t* par) +{ + Double_t p = pow(10.,x[0]); + Double_t norm = par[0]; + Double_t m = par[1]; + + return norm * bethe_bloch_total(fabs(p)/m); +} + +Double_t bethe_bloch_vs_p_wrapper_ZS(Double_t* x, Double_t* par) +{ + Double_t p = x[0]; + Double_t norm = par[0]; + Double_t m = par[1]; + Double_t ZS_loss = par[2]; + + return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; +} + +Double_t bethe_bloch_vs_p_wrapper_new(Double_t* x, Double_t* par) +{ + Double_t p = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + Double_t C = par[2]; + Double_t m = par[3]; + + return bethe_bloch_new(fabs(p)/m,A,B,C); +} + +Double_t bethe_bloch_vs_p_wrapper_new_2D(Double_t* x, Double_t* par) +{ + Double_t p = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + Double_t m = par[2]; + + return bethe_bloch_new_2D(fabs(p)/m,A,B); +} + +Double_t bethe_bloch_vs_p_wrapper_new_1D(Double_t* x, Double_t* par) +{ + Double_t p = x[0]; + Double_t A = par[0]; + Double_t m = par[1]; + + return bethe_bloch_new_1D(fabs(p)/m,A); +} + +Double_t bethe_bloch_vs_logp_wrapper_ZS(Double_t* x, Double_t* par) +{ + Double_t p = pow(10.,x[0]); + Double_t norm = par[0]; + Double_t m = par[1]; + Double_t ZS_loss = par[2]; + + return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; +} + +Double_t bethe_bloch_vs_logp_wrapper_new(Double_t* x, Double_t* par) +{ + Double_t p = pow(10.,x[0]); + Double_t A = par[0]; + Double_t B = par[1]; + Double_t C = par[2]; + Double_t m = par[3]; + + return bethe_bloch_new(fabs(p)/m,A,B,C); +} + +Double_t bethe_bloch_vs_logp_wrapper_new_1D(Double_t* x, Double_t* par) +{ + Double_t p = pow(10.,x[0]); + Double_t A = par[0]; + Double_t m = par[1]; + + return bethe_bloch_new_1D(fabs(p)/m,A); +} + +// ratio of dE/dx between two particle species at the same momentum +// (useful for dE/dx peak fits) +const double dedx_ratio(const double p, const double m1, const double m2) +{ + const double betagamma1 = fabs(p)/m1; + const double betagamma2 = fabs(p)/m2; + + return bethe_bloch_total(betagamma1)/bethe_bloch_total(betagamma2); +} + +#endif // BETHE_BLOCH_H diff --git a/calibrations/tpc/dEdx/configure.ac b/calibrations/tpc/dEdx/configure.ac new file mode 100644 index 0000000000..aed59969a8 --- /dev/null +++ b/calibrations/tpc/dEdx/configure.ac @@ -0,0 +1,16 @@ +AC_INIT( dEdxFitter,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/calibrations/tpc/dEdx/dEdxFitter.cc b/calibrations/tpc/dEdx/dEdxFitter.cc new file mode 100644 index 0000000000..01c867f601 --- /dev/null +++ b/calibrations/tpc/dEdx/dEdxFitter.cc @@ -0,0 +1,228 @@ +#include "dEdxFitter.h" + +#include +#include +#include +#include +#include +#include + +#include + +//____________________________________ +dEdxFitter::dEdxFitter(const std::string &name): + SubsysReco(name) +{ + //initialize + fitter = std::make_unique(); +} + +//___________________________________ +int dEdxFitter::InitRun(PHCompositeNode *topNode) +{ + std::cout << PHWHERE << " Opening file " << _outfile << std::endl; + PHTFileServer::get().open( _outfile, "RECREATE"); + + return 0; +} + +//__________________________________ +//Call user instructions for every event +int dEdxFitter::process_event(PHCompositeNode *topNode) +{ + _event++; + if(_event%1000==0) std::cout << PHWHERE << "Events processed: " << _event << std::endl; + + GetNodes(topNode); + + if(Verbosity()>1) + { + std::cout << "--------------------------------" << std::endl; + std::cout << "event " << _event << std::endl; + } + + process_tracks(topNode); + + return 0; +} + +//_____________________________________ +void dEdxFitter::process_tracks(PHCompositeNode *topNode) +{ + + for(const auto &[key, track] : *_trackmap) + { + if(!track) continue; + + double trackID = track->get_id(); + if(Verbosity()>1) std::cout << "track ID " << trackID << std::endl; + if(std::isnan(track->get_x()) || + std::isnan(track->get_y()) || + std::isnan(track->get_z()) || + std::isnan(track->get_px()) || + std::isnan(track->get_py()) || + std::isnan(track->get_pz())) + { + std::cout << "malformed track:" << std::endl; + track->identify(); + std::cout << "skipping..." << std::endl; + continue; + } + + // ignore TPC-only tracks + if(!track->get_silicon_seed()) + { + if(Verbosity()>1) std::cout << "TPC-only track, skipping..." << std::endl; + continue; + } + + std::tuple nclus = get_nclus(track); + int nmaps = std::get<0>(nclus); + int nintt = std::get<1>(nclus); + int ntpc = std::get<2>(nclus); + + if(nmaps>=nmaps_cut && nintt>=nintt_cut && ntpc>=ntpc_cut && fabs(track->get_eta())addTrack(get_dedx(track),track->get_p()); + } + + if(fitter->getNtracks() > ntracks_to_fit) + { + minima.push_back(fitter->get_minimum()); + fitter->reset(); + } + } +} + +std::tuple dEdxFitter::get_nclus(SvtxTrack* track) +{ + int nmaps = 0; + int nintt = 0; + int ntpc = 0; + + for(auto it = track->get_silicon_seed()->begin_cluster_keys(); it != track->get_silicon_seed()->end_cluster_keys(); ++it) + { + TrkrDefs::cluskey ckey = *it; + auto trkrid = TrkrDefs::getTrkrId(ckey); + if(trkrid == TrkrDefs::mvtxId) + { + nmaps++; + } + else if(trkrid == TrkrDefs::inttId) + { + nintt++; + } + } + for(auto it = track->get_tpc_seed()->begin_cluster_keys(); it != track->get_tpc_seed()->end_cluster_keys(); ++it) + { + ntpc++; + } + + return std::make_tuple(nmaps,nintt,ntpc); +} + +double dEdxFitter::get_dedx(SvtxTrack* track) +{ + float layerThicknesses[4] = {0.0, 0.0, 0.0, 0.0}; + // These are randomly chosen layer thicknesses for the TPC, to get the + // correct region thicknesses in an easy to pass way to the helper fxn + layerThicknesses[0] = _tpcgeom->GetLayerCellGeom(7)->get_thickness(); + layerThicknesses[1] = _tpcgeom->GetLayerCellGeom(8)->get_thickness(); + layerThicknesses[2] = _tpcgeom->GetLayerCellGeom(27)->get_thickness(); + layerThicknesses[3] = _tpcgeom->GetLayerCellGeom(50)->get_thickness(); + + return TrackAnalysisUtils::calc_dedx(track->get_tpc_seed(), _clustermap, _geometry, layerThicknesses); +} + +double dEdxFitter::get_dcaxy(SvtxTrack* track) +{ + auto vertexit = _vertexmap->find(track->get_vertex_id()); + if(vertexit != _vertexmap->end()) + { + SvtxVertex* vtx = vertexit->second; + Acts::Vector3 vertex(vtx->get_x(),vtx->get_y(),vtx->get_z()); + auto dcapair = TrackAnalysisUtils::get_dca(track,vertex); + return dcapair.first.first; + } + else + { + return std::numeric_limits::quiet_NaN(); + } +} + +//___________________________________ +void dEdxFitter::GetNodes(PHCompositeNode *topNode) +{ + + _trackmap = findNode::getClass(topNode,"SvtxTrackMap"); + if(!_trackmap && _event<2) + { + std::cout << PHWHERE << " cannot find SvtxTrackMap" << std::endl; + } + + _clustermap = findNode::getClass(topNode,"TRKR_CLUSTER"); + if(!_clustermap && _event<2) + { + std::cout << PHWHERE << " cannot find TrkrClusterContainer TRKR_CLUSTER" << std::endl; + } + + _geometry = findNode::getClass(topNode,"ActsGeometry"); + if(!_geometry && _event<2) + { + std::cout << PHWHERE << " cannot find ActsGeometry" << std::endl; + } + + _tpcgeom = findNode::getClass(topNode,"TPCGEOMCONTAINER"); + if(!_tpcgeom && _event<2) + { + std::cout << PHWHERE << " cannot find PHG4TpcGeomContainer TPCGEOMCONTAINER" << std::endl; + } + + _vertexmap = findNode::getClass(topNode,"SvtxVertexMap"); + if(!_vertexmap && _event<2) + { + std::cout << PHWHERE << " cannot find SvtxVertexMap" << std::endl; + } +} + +//______________________________________ +int dEdxFitter::End(PHCompositeNode *topNode) +{ + if(minima.size()==0) + { + minima.push_back(fitter->get_minimum()); + } + + PHTFileServer::get().cd( _outfile ); + + double avg_minimum = 0.; + for(double m : minima) + { + avg_minimum += m; + } + avg_minimum /= (double)minima.size(); + + TF1* pi_band = new TF1("pi_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + pi_band->SetParameter(0,avg_minimum); + pi_band->SetParameter(1,dedx_constants::m_pi); + pi_band->Write(); + + TF1* K_band = new TF1("K_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + K_band->SetParameter(0,avg_minimum); + K_band->SetParameter(1,dedx_constants::m_K); + K_band->Write(); + + TF1* p_band = new TF1("p_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + p_band->SetParameter(0,avg_minimum); + p_band->SetParameter(1,dedx_constants::m_p); + p_band->Write(); + + TF1* d_band = new TF1("d_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + d_band->SetParameter(0,avg_minimum); + d_band->SetParameter(1,dedx_constants::m_d); + d_band->Write(); + + if(Verbosity()>0) std::cout << "dEdxFitter extracted minimum: " << avg_minimum << std::endl; + + return 0; +} diff --git a/calibrations/tpc/dEdx/dEdxFitter.h b/calibrations/tpc/dEdx/dEdxFitter.h new file mode 100644 index 0000000000..ca4fca546d --- /dev/null +++ b/calibrations/tpc/dEdx/dEdxFitter.h @@ -0,0 +1,88 @@ +#ifndef __DEDXFITTER_H__ +#define __DEDXFITTER_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include "GlobaldEdxFitter.h" + +//Forward declerations +class PHCompositeNode; +class TFile; + +// dEdx fit analysis module +class dEdxFitter: public SubsysReco +{ + public: + //Default constructor + dEdxFitter(const std::string &name="dEdxFitter"); + + //Initialization, called for initialization + int InitRun(PHCompositeNode *); + + //Process Event, called for each event + int process_event(PHCompositeNode *); + + //End, write and close files + int End(PHCompositeNode *); + + //Change output filename + void set_filename(const char* file) + { if(file) _outfile = file; } + + void set_nmaps_cut(int nmaps) + { nmaps_cut = nmaps; } + + void set_nintt_cut(int nintt) + { nintt_cut = nintt; } + + void set_ntpc_cut(int ntpc) + { ntpc_cut = ntpc; } + + void set_eta_cut(float eta) + { eta_cut = eta; } + + void set_dcaxy_cut(float dcaxy) + { dcaxy_cut = dcaxy; } + + void set_ntracks_to_fit(size_t ntrk) + { ntracks_to_fit = ntrk; } + + private: + //output filename + std::string _outfile = "dedx_outfile.root"; + size_t _event; + + SvtxTrackMap* _trackmap = nullptr; + TrkrClusterContainer* _clustermap = nullptr; + ActsGeometry* _geometry = nullptr; + PHG4TpcGeomContainer* _tpcgeom = nullptr; + SvtxVertexMap* _vertexmap = nullptr; + + //Get all the nodes + void GetNodes(PHCompositeNode *); + + void process_tracks(PHCompositeNode *); + + int nmaps_cut = 1; + int nintt_cut = 1; + int ntpc_cut = 30; + float eta_cut = 1.; + float dcaxy_cut = 0.5; + + size_t ntracks_to_fit = 40000; + std::vector minima; + std::unique_ptr fitter; + + std::tuple get_nclus(SvtxTrack* track); + double get_dedx(SvtxTrack* track); + double get_dcaxy(SvtxTrack* track); + +}; + +#endif //* __DEDXFITTER_H__ *// diff --git a/calibrations/tpc/dEdx/test_sample_size.C b/calibrations/tpc/dEdx/test_sample_size.C new file mode 100644 index 0000000000..30d4b5cb00 --- /dev/null +++ b/calibrations/tpc/dEdx/test_sample_size.C @@ -0,0 +1,185 @@ +#include "GlobaldEdxFitter.h" + +void test_sample_size(std::string infile="/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/track_output_53877_02613_53877-2613.root_resid.root") +{ + std::vector samplesizes = {1000,2000,5000,10000,20000,50000,100000,200000,500000,1000000};//,2000000,5000000}; + + const int n_samples = 20; + const float fluctuation_ymin = 5.; + const float fluctuation_ymax = 26.; + const int distribution_nbins = 30; + const float distribution_xmin = 5.; + const float distribution_xmax = 26.; + + + EColor base_color = kRed; + + std::vector> fitvalues_all; + std::vector fitvalues_avg; + std::vector fitvalues_stdev; + + std::vector fluctuations; + std::vector distributions; + + std::vector dist_h; + + std::vector> gfs; + + for(int i=0; i()); + + std::string fluctuation_canvasname = "fluctuations_"+std::to_string((int)floor(samplesizes[i])); + std::string distribution_canvasname = "distributions_"+std::to_string((int)floor(samplesizes[i])); + fluctuations.push_back(new TCanvas(fluctuation_canvasname.c_str(),fluctuation_canvasname.c_str(),600,600)); + distributions.push_back(new TCanvas(distribution_canvasname.c_str(),distribution_canvasname.c_str(),600,600)); + + for(int j=0;jprocessResidualData(floor(samplesizes[i]),j*samplesizes[i]); + double min = gfs[i]->get_minimum(); + std::cout << "minimum: " << min << std::endl; + fitvalues_all[i].push_back(min); + if(jreset(); +/* + tf1s[i]->cd(); + TF1* tf1copy = gfs[i]->create_TF1(("ntrk_"+std::to_string(samplesizes[i])).c_str()); + tf1copy->SetLineColor(base_color); + tf1copy->GetYaxis()->SetRangeUser(1.,tf1copy->GetMaximum()); + if(i==0) tf1copy->Draw(); + else tf1copy->Draw("SAME"); +*/ + } + } + + std::vector sample_index(n_samples); + std::iota(sample_index.begin(),sample_index.end(),0.); + + for(int i=0; icd(); + TGraph* g = new TGraph(n_samples,sample_index.data(),fitvalues_all[i].data()); + g->GetYaxis()->SetRangeUser(fluctuation_ymin,fluctuation_ymax); + g->SetMarkerStyle(kFullCircle); + g->SetMarkerSize(1.); + g->Draw("APL"); + + distributions[i]->cd(); + std::string hname = "h_"+std::to_string(floor(samplesizes[i])); + std::string htitle = "Distribution of fit results for sample size "+std::to_string(floor(samplesizes[i])); +/* + auto bounds = std::minmax_element(fitvalues_all[i].begin(),fitvalues_all[i].end()); + float lowerbound = floor(*bounds.first); + float upperbound = ceil(*bounds.second); +*/ + TH1F* h = new TH1F(hname.c_str(),htitle.c_str(),distribution_nbins,distribution_xmin,distribution_xmax); + for(int j=0; jFill(fitvalues_all[i][j]); + } + h->Draw(); + } + + for(int i=0; i errx(n_samples,0.); + + TCanvas* cg = new TCanvas("cg","sizes",600,600); + TGraph* g = new TGraphErrors(samplesizes.size(),samplesizes.data(),fitvalues_avg.data(),errx.data(),fitvalues_stdev.data()); + g->SetMarkerStyle(kFullCircle); + g->SetMarkerSize(1); + g->Draw("APL"); + cg->SetLogx(); + + TCanvas* cbg = new TCanvas("vsbetagamma","vsbetagamma",600,600); + TGraph* gbg = gfs.back()->graph_vsbetagamma(fitvalues_avg.back()); + gbg->SetMarkerStyle(kFullCircle); + gbg->SetMarkerSize(0.2); + gbg->Draw("AP"); + cbg->SetLogx(); + + double best_A = fitvalues_avg.back(); + + TF1* bethe = new TF1("bethebloch_vslnbg",bethe_bloch_new_1D_wrapper,0.,100.,2,1); + bethe->SetParameter(0,best_A); + bethe->SetNpx(1000); + bethe->Draw("SAME"); + + TF1* bethe_directfit = new TF1("bethebloch_directfit",bethe_bloch_new_1D_wrapper,0.,10.,1,1); + bethe_directfit->SetParameter(0,best_A); + bethe_directfit->SetLineColor(kBlue); + gbg->Fit(bethe_directfit); + double newbest_A = bethe_directfit->GetParameter(0); + std::cout << "new best: " << newbest_A << std::endl; + + TCanvas* cbands = new TCanvas("bands","bands",600,600); + TGraph* gp = gfs.back()->graph_vsp(); + gp->SetMarkerStyle(kFullCircle); + gp->SetMarkerSize(0.1); + gp->Draw("AP"); + cbands->SetLogx(); + + for(double mass : {m_pi, m_K, m_p, m_d}) + { + TF1* band = new TF1(("band_"+std::to_string(mass)).c_str(),bethe_bloch_vs_p_wrapper_new_1D,0.,10.,2,1); + band->SetParameter(0,best_A); + band->SetParameter(1,mass); + band->SetNpx(1000); + band->Draw("SAME"); + + TF1* directband = new TF1(("directband_"+std::to_string(mass)).c_str(),bethe_bloch_vs_p_wrapper_new_1D,0.,10.,2,1); + directband->SetLineColor(kBlue); + directband->SetParameters(best_A,mass); + directband->SetNpx(1000); + directband->Draw("SAME"); + } + + TCanvas* cb = new TCanvas("fullbands","fullbands",600,600); + TFile* f_h = TFile::Open("/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/dedx/merged_dedx.root"); + TH2F* dedx_h = (TH2F*)f_h->Get("dedx_log_30"); + dedx_h->Draw("COLZ"); + cb->SetLogz(); + + for(float mass : {m_pi, m_K, m_p, m_d}) + { + TF1* band = new TF1(("band_"+std::to_string(mass)).c_str(),bethe_bloch_vs_logp_wrapper_new_1D,-1.,5.,2,1); + band->SetParameter(0,best_A); + band->SetParameter(1,mass); + band->Draw("SAME"); + + TF1* directband = new TF1(("directband_"+std::to_string(mass)).c_str(),bethe_bloch_vs_logp_wrapper_new_1D,-1.,5.,2,1); + directband->SetLineColor(kBlue); + directband->SetParameters(newbest_A,mass); + directband->SetNpx(1000); + directband->Draw("SAME"); + } + + TFile* fout = new TFile("dedxfitvals.root","RECREATE"); + for(auto& c : fluctuations) c->Write(); + for(auto& c : distributions) c->Write(); + cg->Write(); + cbg->Write(); + cbands->Write(); + cb->Write(); + +} From 2525b3b9ba9979a96302e781f8d9afe5c9f549e2 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 15 Jan 2026 16:37:33 -0500 Subject: [PATCH 065/866] restor cout state after every call to pythia8 --- generators/PHPythia8/PHPythia8.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 56f2b2bb9c..35f219771d 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -123,17 +123,13 @@ int PHPythia8::Init(PHCompositeNode *topNode) std::cout << "PHPythia8 random seed: " << seed << std::endl; - // this is empirical - something in the pythia8::init() method interferes - // with our macros (it sets the tpc drift verlocity back to 0) - // not the feintest idea right now what this could be - // but saving the old cout state and restoring it aftwerwards - // gets our tpc drift velocity back +// pythia again messes with the cout formatting std::ios old_state(nullptr); - old_state.copyfmt(std::cout); + old_state.copyfmt(std::cout); // save current state m_Pythia8->init(); - std::cout.copyfmt(old_state); + std::cout.copyfmt(old_state); // restore state to saved state return Fun4AllReturnCodes::EVENT_OK; } @@ -211,6 +207,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) { @@ -306,6 +305,8 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) ++m_EventCount; + std::cout.copyfmt(old_state); // restore state to saved state + // save statistics if (m_IntegralNode) { From bd1ae49728ee04de2524280630f1e9956fd76d7d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 15 Jan 2026 17:04:52 -0500 Subject: [PATCH 066/866] restore cout state after each call to subsystem code --- offline/framework/fun4all/Fun4AllServer.cc | 9 +++++++-- offline/framework/fun4all/Fun4AllServer.h | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4all/Fun4AllServer.cc b/offline/framework/fun4all/Fun4AllServer.cc index 9d8779204e..9dc68afbb0 100644 --- a/offline/framework/fun4all/Fun4AllServer.cc +++ b/offline/framework/fun4all/Fun4AllServer.cc @@ -128,9 +128,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; @@ -245,6 +245,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) { @@ -576,6 +577,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 @@ -899,6 +901,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()) { @@ -1092,6 +1095,7 @@ 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()); @@ -1144,6 +1148,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); diff --git a/offline/framework/fun4all/Fun4AllServer.h b/offline/framework/fun4all/Fun4AllServer.h index 0c7ea72c14..9f360b9502 100644 --- a/offline/framework/fun4all/Fun4AllServer.h +++ b/offline/framework/fun4all/Fun4AllServer.h @@ -143,7 +143,8 @@ class Fun4AllServer : public Fun4AllBase int eventnumber{0}; int eventcounter{0}; int keep_db_connected{0}; - + + std::ios m_saved_cout_state{nullptr}; std::vector ComplaintList; std::vector ResetNodeList {"DST"}; std::vector> Subsystems; From 04d53767137b4b03b84e5aeef28e911b6f304b1b Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 15 Jan 2026 17:22:26 -0500 Subject: [PATCH 067/866] resotre cout before sending abortrun --- generators/PHPythia8/PHPythia8.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 35f219771d..58b1f67e5d 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -285,6 +285,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; } From 99b5ed4a7777366a35aa162f080cd2e03780fad8 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 15 Jan 2026 23:28:33 -0500 Subject: [PATCH 068/866] abort events with any mbd packet empty --- offline/packages/mbd/MbdCalib.cc | 2 +- offline/packages/mbd/MbdEvent.cc | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 22b1e9930d..0b02908adb 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -1331,7 +1331,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 } diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index 9b68641cbd..cdab537f45 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -451,6 +451,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 +461,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")); @@ -556,7 +564,6 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer // int flag_err = 0; Packet *p[2]{nullptr}; - int tot_nsamples{0}; for (int ipkt = 0; ipkt < 2; ipkt++) { int pktid = 1001 + ipkt; // packet id @@ -574,7 +581,7 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer if (p[ipkt]) { _nsamples = p[ipkt]->iValue(0, "SAMPLES"); - tot_nsamples += _nsamples; + { static int counter = 0; if ( counter<1 ) @@ -584,6 +591,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")); @@ -628,12 +644,6 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer } } - // If packets are missing, stop processing - if ( tot_nsamples == 0 ) - { - return -1002; - } - // Fill MbdRawContainer int status = ProcessPackets(bbcraws); if ( _fitsonly ) From 8cbb1765262ad38a115da7eb771819a1fb82cc37 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Fri, 16 Jan 2026 00:37:54 -0500 Subject: [PATCH 069/866] coderabbit and clang-tidy fixes --- calibrations/tpc/dEdx/GlobaldEdxFitter.cc | 346 +++++++++++++++++++++ calibrations/tpc/dEdx/GlobaldEdxFitter.h | 353 +--------------------- calibrations/tpc/dEdx/Makefile.am | 3 +- calibrations/tpc/dEdx/bethe_bloch.h | 40 +-- calibrations/tpc/dEdx/dEdxFitter.cc | 61 ++-- calibrations/tpc/dEdx/dEdxFitter.h | 2 +- calibrations/tpc/dEdx/test_sample_size.C | 22 +- 7 files changed, 433 insertions(+), 394 deletions(-) create mode 100644 calibrations/tpc/dEdx/GlobaldEdxFitter.cc diff --git a/calibrations/tpc/dEdx/GlobaldEdxFitter.cc b/calibrations/tpc/dEdx/GlobaldEdxFitter.cc new file mode 100644 index 0000000000..8fa5045cba --- /dev/null +++ b/calibrations/tpc/dEdx/GlobaldEdxFitter.cc @@ -0,0 +1,346 @@ +#include "GlobaldEdxFitter.h" + +#include "bethe_bloch.h" +#include "TF1.h" +#include "TF2.h" +#include "TF3.h" +#include "TChain.h" +#include "TGraph.h" +#include "Math/Minimizer.h" +#include "Math/Functor.h" +#include "Math/Factory.h" + +void GlobaldEdxFitter::processResidualData(const std::string& infile, size_t ntracks, size_t skip) +{ + std::unique_ptr t = std::make_unique(); + t->Add((infile+"?#residualtree").c_str()); +// TFile* f = TFile::Open(infile.c_str()); +// TTree* t = (TTree*)f->Get("residualtree"); + + float px; + float py; + float pz; + float dedx; + float eta; + int nmaps; + int nintt; + int ntpc; + float dcaxy; + + t->SetBranchAddress("px",&px); + t->SetBranchAddress("py",&py); + t->SetBranchAddress("pz",&pz); + t->SetBranchAddress("dedx",&dedx); + t->SetBranchAddress("eta",&eta); + t->SetBranchAddress("nmaps",&nmaps); + t->SetBranchAddress("nintt",&nintt); + t->SetBranchAddress("ntpc",&ntpc); + t->SetBranchAddress("dcaxy",&dcaxy); + + size_t total_entries = t->GetEntriesFast(); + + for(size_t entry=skip; entry<(skip+ntracks); entry++) + { + if(entry==total_entries) + { + break; + } + if(entry % 1000 == 0) + { + std::cout << entry << std::endl; + } + t->GetEntry(entry); + if(nmaps>0 && nintt>0 && fabs(eta)<1. && dcaxy<0.5 && ntpc>30) + { + p.push_back(sqrt(px*px+py*py+pz*pz)); + dEdx.push_back(dedx); + } + } + std::cout << "number of good tracks: " << p.size() << std::endl; + //f->Close(); +} + +void GlobaldEdxFitter::addTrack(double trk_dEdx, double trk_p) +{ + dEdx.push_back(trk_dEdx); + p.push_back(trk_p); +} + +double GlobaldEdxFitter::get_fitquality_new(double A) +{ + //double chi2 = 0.; + //double ndf = -1.; + + double pi_chi2 = 0.; + double K_chi2 = 0.; + double p_chi2 = 0.; + double d_chi2 = 0.; + double pi_ndf = -1.; + double K_ndf = -1.; + double p_ndf = -1.; + double d_ndf = -1.; + + for(size_t i=0; i GlobaldEdxFitter::get_betagamma(double A) +{ + std::vector betagamma; + for(size_t i=0; iGetMinimumXYZ(minA,minB,minC); + delete f; + return std::make_tuple(minA,minB,minC); +*/ + ROOT::Math::Minimizer* minimizer = ROOT::Math::Factory::CreateMinimizer("Minuit2"); + minimizer->SetMaxFunctionCalls(1000000); + minimizer->SetMaxIterations(10000); + minimizer->SetTolerance(0.1); + minimizer->SetPrintLevel(1); + ROOT::Math::Functor f(this,&GlobaldEdxFitter::get_fitquality_functor,1); + double step[1] = {.01}; + double variable[1] = {20.}; + minimizer->SetFunction(f); + minimizer->SetVariable(0,"A",variable[0],step[0]); + minimizer->Minimize(); + const double *xs = minimizer->X(); + delete minimizer; + return xs[0]; +} + +double GlobaldEdxFitter::get_minimum() +{ + TF1* f = create_TF1("temp"); + f->SetNpx(1000); + double minX = f->GetMinimumX(); + delete f; + return minX; +} + +std::pair GlobaldEdxFitter::get_minimum_ZS() +{ + TF2* f = create_TF2("temp"); + double minX; + double minY; + f->GetMinimumXY(minX,minY); + delete f; + return std::make_pair(minX,minY); +} + +TGraph* GlobaldEdxFitter::graph_vsbetagamma(double A) +{ + std::vector betagamma = get_betagamma(A); + TGraph* g = new TGraph(dEdx.size(),betagamma.data(),dEdx.data()); + return g; +} + +TGraph* GlobaldEdxFitter::graph_vsp() +{ + TGraph* g = new TGraph(dEdx.size(),p.data(),dEdx.data()); + return g; +} diff --git a/calibrations/tpc/dEdx/GlobaldEdxFitter.h b/calibrations/tpc/dEdx/GlobaldEdxFitter.h index 267e30f0a4..122ec94769 100644 --- a/calibrations/tpc/dEdx/GlobaldEdxFitter.h +++ b/calibrations/tpc/dEdx/GlobaldEdxFitter.h @@ -11,11 +11,6 @@ #include "Math/Functor.h" #include "Math/Factory.h" -const double m_pi = 0.1396; // GeV -const double m_K = 0.4937; // GeV -const double m_p = 0.9382; // GeV -const double m_d = 1.876; // GeV - class GlobaldEdxFitter { public: @@ -24,9 +19,9 @@ class GlobaldEdxFitter min_norm = xmin; max_norm = xmax; }; - void processResidualData(size_t ntracks = 200000, - size_t skip = 0, - std::string infile="/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/track_output_53877*.root_resid.root"); + void processResidualData(const std::string& infile, + size_t ntracks = 200000, + size_t skip = 0); void addTrack(double trk_dEdx, double trk_p); size_t getNtracks() { @@ -35,9 +30,9 @@ class GlobaldEdxFitter double get_fitquality(double norm, double ZS_loss = 0.); double get_fitquality_new(double A); - TF1* create_TF1(std::string name); - TF2* create_TF2(std::string name); - TF3* create_TF3_new(std::string name); + TF1* create_TF1(const std::string& name); + TF2* create_TF2(const std::string& name); + TF3* create_TF3_new(const std::string& name); double get_minimum(); double get_minimum_new(); std::pair get_minimum_ZS(); @@ -52,7 +47,6 @@ class GlobaldEdxFitter { p.clear(); dEdx.clear(); - betagamma.clear(); } std::vector get_betagamma(double A); TGraph* graph_vsbetagamma(double A); @@ -60,13 +54,12 @@ class GlobaldEdxFitter private: std::vector p; std::vector dEdx; - std::vector betagamma; double get_fitquality_functor(const double* x); - double get_fitquality_wrapper(double* x, double* p); - double get_fitquality_wrapper_ZS(double* x, double* p); - double get_fitquality_wrapper_new(double* x, double* p); + double get_fitquality_wrapper(double* x, double* par); + double get_fitquality_wrapper_ZS(double* x, double* par); + double get_fitquality_wrapper_new(double* x, double* par); double min_norm = 10.; double max_norm = 50.; double min_ZS = 0.; @@ -75,330 +68,4 @@ class GlobaldEdxFitter double max_B = 12.; }; -void GlobaldEdxFitter::processResidualData(size_t ntracks, size_t skip, std::string infile) -{ - std::unique_ptr t = std::make_unique(); - t->Add((infile+"?#residualtree").c_str()); -// TFile* f = TFile::Open(infile.c_str()); -// TTree* t = (TTree*)f->Get("residualtree"); - - float px; - float py; - float pz; - float dedx; - float eta; - int nmaps; - int nintt; - int ntpc; - float dcaxy; - - t->SetBranchAddress("px",&px); - t->SetBranchAddress("py",&py); - t->SetBranchAddress("pz",&pz); - t->SetBranchAddress("dedx",&dedx); - t->SetBranchAddress("eta",&eta); - t->SetBranchAddress("nmaps",&nmaps); - t->SetBranchAddress("nintt",&nintt); - t->SetBranchAddress("ntpc",&ntpc); - t->SetBranchAddress("dcaxy",&dcaxy); - - for(size_t entry=skip; entry<(skip+ntracks); entry++) - { - //if(entry==t->GetEntries()-1) break; - if(entry % 1000 == 0) std::cout << entry << std::endl; - t->GetEntry(entry); - if(nmaps>0 && nintt>0 && fabs(eta)<1. && dcaxy<0.5 && ntpc>30) - { - p.push_back(sqrt(px*px+py*py+pz*pz)); - dEdx.push_back(dedx); - } - } - std::cout << "number of good tracks: " << p.size() << std::endl; - //f->Close(); -} - -void GlobaldEdxFitter::addTrack(double trk_dEdx, double trk_p) -{ - dEdx.push_back(trk_dEdx); - p.push_back(trk_p); -} - -double GlobaldEdxFitter::get_fitquality_new(double A) -{ - double chi2 = 0.; - double ndf = -1.; - - double pi_chi2 = 0.; - double K_chi2 = 0.; - double p_chi2 = 0.; - double d_chi2 = 0.; - double pi_ndf = -1.; - double K_ndf = -1.; - double p_ndf = -1.; - double d_ndf = -1.; - - for(size_t i=0; i GlobaldEdxFitter::get_betagamma(double A) -{ - std::vector betagamma; - for(size_t i=0; iGetMinimumXYZ(minA,minB,minC); - delete f; - return std::make_tuple(minA,minB,minC); -*/ - ROOT::Math::Minimizer* minimizer = ROOT::Math::Factory::CreateMinimizer("Minuit2"); - minimizer->SetMaxFunctionCalls(1000000); - minimizer->SetMaxIterations(10000); - minimizer->SetTolerance(0.1); - minimizer->SetPrintLevel(1); - ROOT::Math::Functor f(this,&GlobaldEdxFitter::get_fitquality_functor,1); - double step[1] = {.01}; - double variable[1] = {20.}; - minimizer->SetFunction(f); - minimizer->SetVariable(0,"A",variable[0],step[0]); - minimizer->Minimize(); - const double *xs = minimizer->X(); - return xs[0]; -} - -double GlobaldEdxFitter::get_minimum() -{ - TF1* f = create_TF1("temp"); - f->SetNpx(1000); - double minX = f->GetMinimumX(); - delete f; - return minX; -} - -std::pair GlobaldEdxFitter::get_minimum_ZS() -{ - TF2* f = create_TF2("temp"); - double minX; - double minY; - f->GetMinimumXY(minX,minY); - delete f; - return std::make_pair(minX,minY); -} - -TGraph* GlobaldEdxFitter::graph_vsbetagamma(double A) -{ - std::vector betagamma = get_betagamma(A); - TGraph* g = new TGraph(dEdx.size(),betagamma.data(),dEdx.data()); - return g; -} - -TGraph* GlobaldEdxFitter::graph_vsp() -{ - TGraph* g = new TGraph(dEdx.size(),p.data(),dEdx.data()); - return g; -} - -#endif +#endif // GLOBALDEDXFITTER_H diff --git a/calibrations/tpc/dEdx/Makefile.am b/calibrations/tpc/dEdx/Makefile.am index 03dda87d60..e057d9dffe 100644 --- a/calibrations/tpc/dEdx/Makefile.am +++ b/calibrations/tpc/dEdx/Makefile.am @@ -19,7 +19,8 @@ lib_LTLIBRARIES = \ libdedxfitter.la libdedxfitter_la_SOURCES = \ - dEdxFitter.cc + dEdxFitter.cc \ + GlobaldEdxFitter.cc libdedxfitter_la_LIBADD = \ -lphool \ diff --git a/calibrations/tpc/dEdx/bethe_bloch.h b/calibrations/tpc/dEdx/bethe_bloch.h index 3b134224ee..9bbb6e1962 100644 --- a/calibrations/tpc/dEdx/bethe_bloch.h +++ b/calibrations/tpc/dEdx/bethe_bloch.h @@ -1,7 +1,7 @@ #ifndef BETHE_BLOCH_H #define BETHE_BLOCH_H -#include "TMath.h" +#include namespace dedx_constants { @@ -31,21 +31,21 @@ namespace dedx_constants // Bethe-Bloch fit function, vs. betagamma // A = normalization constant, equal to (ADC conversion)*4pi*n*Z^2*e^4/(m_e*c^2*4pi*epsilon_0^2) // B = A*(ln(2*m_e/I)-1) - (zero-suppression loss factor) -const double bethe_bloch_new(const double betagamma, const double A, const double B, const double C) +inline const double bethe_bloch_new(const double betagamma, const double A, const double B, const double C) { const double beta = betagamma/sqrt(1.+betagamma*betagamma); return A/(beta*beta)*TMath::Log(betagamma) + A/(beta*beta)*B - A - C; } -const double bethe_bloch_new_2D(const double betagamma, const double A, const double B) +inline const double bethe_bloch_new_2D(const double betagamma, const double A, const double B) { const double beta = betagamma/sqrt(1.+betagamma*betagamma); return A/(beta*beta)*(2.*TMath::Log(2.*dedx_constants::m_e/dedx_constants::sphenix_I * betagamma) - beta*beta) - B; } -const double bethe_bloch_new_1D(const double betagamma, const double A) +inline const double bethe_bloch_new_1D(const double betagamma, const double A) { const double beta = betagamma/sqrt(1.+betagamma*betagamma); @@ -53,7 +53,7 @@ const double bethe_bloch_new_1D(const double betagamma, const double A) } // dE/dx for one gas species, up to normalization -const double bethe_bloch_species(const double betagamma, const double I) +inline const double bethe_bloch_species(const double betagamma, const double I) { const double m_e = 511e3; // eV @@ -63,14 +63,14 @@ const double bethe_bloch_species(const double betagamma, const double I) } // dE/dx for TPC gas mixture, up to normalization -const double bethe_bloch_total(const double betagamma) +inline const double bethe_bloch_total(const double betagamma) { return dedx_constants::ar_frac * bethe_bloch_species(betagamma,dedx_constants::ar_I) + dedx_constants::cf4_frac * bethe_bloch_species(betagamma,dedx_constants::cf4_I) + dedx_constants::isobutane_frac * bethe_bloch_species(betagamma,dedx_constants::isobutane_I); } -Double_t bethe_bloch_new_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_new_wrapper(Double_t* x, Double_t* par) { Double_t betagamma = x[0]; Double_t A = par[0]; @@ -80,7 +80,7 @@ Double_t bethe_bloch_new_wrapper(Double_t* x, Double_t* par) return bethe_bloch_new(betagamma,A,B,C); } -Double_t bethe_bloch_new_2D_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_new_2D_wrapper(Double_t* x, Double_t* par) { Double_t betagamma = x[0]; Double_t A = par[0]; @@ -89,7 +89,7 @@ Double_t bethe_bloch_new_2D_wrapper(Double_t* x, Double_t* par) return bethe_bloch_new_2D(betagamma,A,B); } -Double_t bethe_bloch_new_1D_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_new_1D_wrapper(Double_t* x, Double_t* par) { Double_t betagamma = x[0]; Double_t A = par[0]; @@ -98,7 +98,7 @@ Double_t bethe_bloch_new_1D_wrapper(Double_t* x, Double_t* par) } // wrapper function for TF1 constructor, for fitting -Double_t bethe_bloch_wrapper(Double_t* ln_bg, Double_t* par) +inline Double_t bethe_bloch_wrapper(Double_t* ln_bg, Double_t* par) { Double_t betagamma = exp(ln_bg[0]); @@ -107,7 +107,7 @@ Double_t bethe_bloch_wrapper(Double_t* ln_bg, Double_t* par) return norm * bethe_bloch_total(betagamma); } -Double_t bethe_bloch_vs_p_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper(Double_t* x, Double_t* par) { Double_t p = x[0]; Double_t norm = par[0]; @@ -116,7 +116,7 @@ Double_t bethe_bloch_vs_p_wrapper(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m); } -Double_t bethe_bloch_vs_logp_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper(Double_t* x, Double_t* par) { Double_t p = pow(10.,x[0]); Double_t norm = par[0]; @@ -125,7 +125,7 @@ Double_t bethe_bloch_vs_logp_wrapper(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m); } -Double_t bethe_bloch_vs_p_wrapper_ZS(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_ZS(Double_t* x, Double_t* par) { Double_t p = x[0]; Double_t norm = par[0]; @@ -135,7 +135,7 @@ Double_t bethe_bloch_vs_p_wrapper_ZS(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; } -Double_t bethe_bloch_vs_p_wrapper_new(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_new(Double_t* x, Double_t* par) { Double_t p = x[0]; Double_t A = par[0]; @@ -146,7 +146,7 @@ Double_t bethe_bloch_vs_p_wrapper_new(Double_t* x, Double_t* par) return bethe_bloch_new(fabs(p)/m,A,B,C); } -Double_t bethe_bloch_vs_p_wrapper_new_2D(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_new_2D(Double_t* x, Double_t* par) { Double_t p = x[0]; Double_t A = par[0]; @@ -156,7 +156,7 @@ Double_t bethe_bloch_vs_p_wrapper_new_2D(Double_t* x, Double_t* par) return bethe_bloch_new_2D(fabs(p)/m,A,B); } -Double_t bethe_bloch_vs_p_wrapper_new_1D(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_new_1D(Double_t* x, Double_t* par) { Double_t p = x[0]; Double_t A = par[0]; @@ -165,7 +165,7 @@ Double_t bethe_bloch_vs_p_wrapper_new_1D(Double_t* x, Double_t* par) return bethe_bloch_new_1D(fabs(p)/m,A); } -Double_t bethe_bloch_vs_logp_wrapper_ZS(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper_ZS(Double_t* x, Double_t* par) { Double_t p = pow(10.,x[0]); Double_t norm = par[0]; @@ -175,7 +175,7 @@ Double_t bethe_bloch_vs_logp_wrapper_ZS(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; } -Double_t bethe_bloch_vs_logp_wrapper_new(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper_new(Double_t* x, Double_t* par) { Double_t p = pow(10.,x[0]); Double_t A = par[0]; @@ -186,7 +186,7 @@ Double_t bethe_bloch_vs_logp_wrapper_new(Double_t* x, Double_t* par) return bethe_bloch_new(fabs(p)/m,A,B,C); } -Double_t bethe_bloch_vs_logp_wrapper_new_1D(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper_new_1D(Double_t* x, Double_t* par) { Double_t p = pow(10.,x[0]); Double_t A = par[0]; @@ -197,7 +197,7 @@ Double_t bethe_bloch_vs_logp_wrapper_new_1D(Double_t* x, Double_t* par) // ratio of dE/dx between two particle species at the same momentum // (useful for dE/dx peak fits) -const double dedx_ratio(const double p, const double m1, const double m2) +inline const double dedx_ratio(const double p, const double m1, const double m2) { const double betagamma1 = fabs(p)/m1; const double betagamma2 = fabs(p)/m2; diff --git a/calibrations/tpc/dEdx/dEdxFitter.cc b/calibrations/tpc/dEdx/dEdxFitter.cc index 01c867f601..0f03bae44e 100644 --- a/calibrations/tpc/dEdx/dEdxFitter.cc +++ b/calibrations/tpc/dEdx/dEdxFitter.cc @@ -31,7 +31,10 @@ int dEdxFitter::InitRun(PHCompositeNode *topNode) int dEdxFitter::process_event(PHCompositeNode *topNode) { _event++; - if(_event%1000==0) std::cout << PHWHERE << "Events processed: " << _event << std::endl; + if(_event%1000==0) + { + std::cout << PHWHERE << "Events processed: " << _event << std::endl; + } GetNodes(topNode); @@ -52,10 +55,16 @@ void dEdxFitter::process_tracks(PHCompositeNode *topNode) for(const auto &[key, track] : *_trackmap) { - if(!track) continue; + if(!track) + { + continue; + } double trackID = track->get_id(); - if(Verbosity()>1) std::cout << "track ID " << trackID << std::endl; + if(Verbosity()>1) + { + std::cout << "track ID " << trackID << std::endl; + } if(std::isnan(track->get_x()) || std::isnan(track->get_y()) || std::isnan(track->get_z()) || @@ -72,7 +81,10 @@ void dEdxFitter::process_tracks(PHCompositeNode *topNode) // ignore TPC-only tracks if(!track->get_silicon_seed()) { - if(Verbosity()>1) std::cout << "TPC-only track, skipping..." << std::endl; + if(Verbosity()>1) + { + std::cout << "TPC-only track, skipping..." << std::endl; + } continue; } @@ -100,22 +112,28 @@ std::tuple dEdxFitter::get_nclus(SvtxTrack* track) int nintt = 0; int ntpc = 0; - for(auto it = track->get_silicon_seed()->begin_cluster_keys(); it != track->get_silicon_seed()->end_cluster_keys(); ++it) + if(track->get_silicon_seed()) { - TrkrDefs::cluskey ckey = *it; - auto trkrid = TrkrDefs::getTrkrId(ckey); - if(trkrid == TrkrDefs::mvtxId) + for(auto it = track->get_silicon_seed()->begin_cluster_keys(); it != track->get_silicon_seed()->end_cluster_keys(); ++it) { - nmaps++; - } - else if(trkrid == TrkrDefs::inttId) - { - nintt++; + TrkrDefs::cluskey ckey = *it; + auto trkrid = TrkrDefs::getTrkrId(ckey); + if(trkrid == TrkrDefs::mvtxId) + { + nmaps++; + } + else if(trkrid == TrkrDefs::inttId) + { + nintt++; + } } } - for(auto it = track->get_tpc_seed()->begin_cluster_keys(); it != track->get_tpc_seed()->end_cluster_keys(); ++it) + if(track->get_tpc_seed()) { - ntpc++; + for(auto it = track->get_tpc_seed()->begin_cluster_keys(); it != track->get_tpc_seed()->end_cluster_keys(); ++it) + { + ntpc++; + } } return std::make_tuple(nmaps,nintt,ntpc); @@ -144,10 +162,8 @@ double dEdxFitter::get_dcaxy(SvtxTrack* track) auto dcapair = TrackAnalysisUtils::get_dca(track,vertex); return dcapair.first.first; } - else - { - return std::numeric_limits::quiet_NaN(); - } + // if no vertex found + return std::numeric_limits::quiet_NaN(); } //___________________________________ @@ -188,7 +204,7 @@ void dEdxFitter::GetNodes(PHCompositeNode *topNode) //______________________________________ int dEdxFitter::End(PHCompositeNode *topNode) { - if(minima.size()==0) + if(minima.empty()) { minima.push_back(fitter->get_minimum()); } @@ -222,7 +238,10 @@ int dEdxFitter::End(PHCompositeNode *topNode) d_band->SetParameter(1,dedx_constants::m_d); d_band->Write(); - if(Verbosity()>0) std::cout << "dEdxFitter extracted minimum: " << avg_minimum << std::endl; + if(Verbosity()>0) + { + std::cout << "dEdxFitter extracted minimum: " << avg_minimum << std::endl; + } return 0; } diff --git a/calibrations/tpc/dEdx/dEdxFitter.h b/calibrations/tpc/dEdx/dEdxFitter.h index ca4fca546d..fda3d7c124 100644 --- a/calibrations/tpc/dEdx/dEdxFitter.h +++ b/calibrations/tpc/dEdx/dEdxFitter.h @@ -56,7 +56,7 @@ class dEdxFitter: public SubsysReco private: //output filename std::string _outfile = "dedx_outfile.root"; - size_t _event; + size_t _event = 0; SvtxTrackMap* _trackmap = nullptr; TrkrClusterContainer* _clustermap = nullptr; diff --git a/calibrations/tpc/dEdx/test_sample_size.C b/calibrations/tpc/dEdx/test_sample_size.C index 30d4b5cb00..df2a39b322 100644 --- a/calibrations/tpc/dEdx/test_sample_size.C +++ b/calibrations/tpc/dEdx/test_sample_size.C @@ -1,8 +1,11 @@ #include "GlobaldEdxFitter.h" -void test_sample_size(std::string infile="/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/track_output_53877_02613_53877-2613.root_resid.root") +#include +#include + +void test_sample_size(const std::string& infile="/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/track_output_53877_*.root") { - std::vector samplesizes = {1000,2000,5000,10000,20000,50000,100000,200000,500000,1000000};//,2000000,5000000}; + std::vector samplesizes = {1000,2000,5000,10000,20000};//,50000,100000,200000,500000,1000000};//,2000000,5000000}; const int n_samples = 20; const float fluctuation_ymin = 5.; @@ -30,18 +33,21 @@ void test_sample_size(std::string infile="/sphenix/tg/tg01/hf/mjpeters/run53877_ fitvalues_all.emplace_back(); gfs.push_back(std::make_unique()); - std::string fluctuation_canvasname = "fluctuations_"+std::to_string((int)floor(samplesizes[i])); - std::string distribution_canvasname = "distributions_"+std::to_string((int)floor(samplesizes[i])); + const std::string& fluctuation_canvasname = "fluctuations_"+std::to_string((int)floor(samplesizes[i])); + const std::string& distribution_canvasname = "distributions_"+std::to_string((int)floor(samplesizes[i])); fluctuations.push_back(new TCanvas(fluctuation_canvasname.c_str(),fluctuation_canvasname.c_str(),600,600)); distributions.push_back(new TCanvas(distribution_canvasname.c_str(),distribution_canvasname.c_str(),600,600)); for(int j=0;jprocessResidualData(floor(samplesizes[i]),j*samplesizes[i]); + gfs[i]->processResidualData(infile,floor(samplesizes[i]),j*samplesizes[i]); double min = gfs[i]->get_minimum(); std::cout << "minimum: " << min << std::endl; fitvalues_all[i].push_back(min); - if(jreset(); + if(jreset(); + } /* tf1s[i]->cd(); TF1* tf1copy = gfs[i]->create_TF1(("ntrk_"+std::to_string(samplesizes[i])).c_str()); @@ -139,7 +145,7 @@ void test_sample_size(std::string infile="/sphenix/tg/tg01/hf/mjpeters/run53877_ gp->Draw("AP"); cbands->SetLogx(); - for(double mass : {m_pi, m_K, m_p, m_d}) + for(double mass : {dedx_constants::m_pi, dedx_constants::m_K, dedx_constants::m_p, dedx_constants::m_d}) { TF1* band = new TF1(("band_"+std::to_string(mass)).c_str(),bethe_bloch_vs_p_wrapper_new_1D,0.,10.,2,1); band->SetParameter(0,best_A); @@ -160,7 +166,7 @@ void test_sample_size(std::string infile="/sphenix/tg/tg01/hf/mjpeters/run53877_ dedx_h->Draw("COLZ"); cb->SetLogz(); - for(float mass : {m_pi, m_K, m_p, m_d}) + for(double mass : {dedx_constants::m_pi, dedx_constants::m_K, dedx_constants::m_p, dedx_constants::m_d}) { TF1* band = new TF1(("band_"+std::to_string(mass)).c_str(),bethe_bloch_vs_logp_wrapper_new_1D,-1.,5.,2,1); band->SetParameter(0,best_A); From d1152d0f8d158c3f7abd88006dfda222a3c0ffc3 Mon Sep 17 00:00:00 2001 From: rosstom Date: Fri, 16 Jan 2026 19:28:46 -0500 Subject: [PATCH 070/866] New QA module to make cluster-state residual plots --- offline/QA/Tracking/Makefile.am | 2 + .../QA/Tracking/StateClusterResidualsQA.cc | 245 ++++++++++++++++++ offline/QA/Tracking/StateClusterResidualsQA.h | 127 +++++++++ 3 files changed, 374 insertions(+) create mode 100644 offline/QA/Tracking/StateClusterResidualsQA.cc create mode 100644 offline/QA/Tracking/StateClusterResidualsQA.h diff --git a/offline/QA/Tracking/Makefile.am b/offline/QA/Tracking/Makefile.am index f5d87546f1..75cbdf164b 100644 --- a/offline/QA/Tracking/Makefile.am +++ b/offline/QA/Tracking/Makefile.am @@ -17,6 +17,7 @@ pkginclude_HEADERS = \ TpcSeedsQA.h \ TpcSiliconQA.h \ SiliconSeedsQA.h \ + StateClusterResidualsQA.h \ MicromegasClusterQA.h \ CosmicTrackQA.h \ TrackFittingQA.h \ @@ -32,6 +33,7 @@ libtrackingqa_la_SOURCES = \ TpcSeedsQA.cc \ TpcSiliconQA.cc \ SiliconSeedsQA.cc \ + StateClusterResidualsQA.cc \ MicromegasClusterQA.cc \ CosmicTrackQA.cc \ TrackFittingQA.cc \ diff --git a/offline/QA/Tracking/StateClusterResidualsQA.cc b/offline/QA/Tracking/StateClusterResidualsQA.cc new file mode 100644 index 0000000000..b09662ded0 --- /dev/null +++ b/offline/QA/Tracking/StateClusterResidualsQA.cc @@ -0,0 +1,245 @@ +#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 + inline T square (T const& t) { return t * t; } + + template + class range_adaptor + { + public: + explicit range_adaptor( + T const& begin, + T const& end) + : m_begin(begin) + , m_end(end) + { + } + T const& begin() { return m_begin; } + T const& end() { return m_end; } + + private: + T m_begin; + T m_end; + }; +} // namespace + +StateClusterResidualsQA::StateClusterResidualsQA(const std::string& name) + : SubsysReco(name) +{ +} + +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; +} + +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; + } + else 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; +} + +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); + } +} + +int StateClusterResidualsQA::EndRun(const int /*unused*/) +{ + auto *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/QA/Tracking/StateClusterResidualsQA.h b/offline/QA/Tracking/StateClusterResidualsQA.h new file mode 100644 index 0000000000..739c816609 --- /dev/null +++ b/offline/QA/Tracking/StateClusterResidualsQA.h @@ -0,0 +1,127 @@ +// 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; + + /// sets the name of node to retrieve the track map from (default member value is "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 From 6c11c5d5a51c7dcb4eb0ff7fcf70a64280d90d90 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 17 Jan 2026 10:25:15 -0500 Subject: [PATCH 071/866] clang-tidy --- offline/QA/Tracking/StateClusterResidualsQA.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/QA/Tracking/StateClusterResidualsQA.cc b/offline/QA/Tracking/StateClusterResidualsQA.cc index b09662ded0..1ca70dc294 100644 --- a/offline/QA/Tracking/StateClusterResidualsQA.cc +++ b/offline/QA/Tracking/StateClusterResidualsQA.cc @@ -166,7 +166,7 @@ int StateClusterResidualsQA::process_event(PHCompositeNode* top_node) { continue; } - else if ((cfg.charge > 0) && !(track->get_positive_charge())) + if ((cfg.charge > 0) && !(track->get_positive_charge())) { continue; } From ec8e8a691db902592cb26a76e72f9cc1916f7ceb Mon Sep 17 00:00:00 2001 From: cdean-github Date: Sat, 17 Jan 2026 15:16:31 -0500 Subject: [PATCH 072/866] CD: Stop KFP from aborting events --- offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 38b60d55ba..8c049f30d6 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -148,7 +148,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 +162,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 +174,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); From 68b618fe99354a605ee4e6b198babd5b47b88f5d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 17 Jan 2026 15:54:48 -0500 Subject: [PATCH 073/866] add flag to prune all seeds --- .../packages/trackreco/DSTClusterPruning.cc | 33 +++++++++++++++++++ .../packages/trackreco/DSTClusterPruning.h | 9 +++++ 2 files changed, 42 insertions(+) diff --git a/offline/packages/trackreco/DSTClusterPruning.cc b/offline/packages/trackreco/DSTClusterPruning.cc index 15bfe547ca..6314bf50b2 100644 --- a/offline/packages/trackreco/DSTClusterPruning.cc +++ b/offline/packages/trackreco/DSTClusterPruning.cc @@ -177,6 +177,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) diff --git a/offline/packages/trackreco/DSTClusterPruning.h b/offline/packages/trackreco/DSTClusterPruning.h index c9ec35ea53..5fa2ff9b4f 100644 --- a/offline/packages/trackreco/DSTClusterPruning.h +++ b/offline/packages/trackreco/DSTClusterPruning.h @@ -52,6 +52,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 +74,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 From c12d8ae33e888639e86a279ec961839332280af3 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Sat, 17 Jan 2026 18:52:34 -0500 Subject: [PATCH 074/866] adding more calo embedding tools --- .../CaloEmbedding/CombineTowerInfo.cc | 99 +++++++++++++++++++ .../packages/CaloEmbedding/CombineTowerInfo.h | 39 ++++++++ .../packages/CaloEmbedding/CopyIODataNodes.cc | 64 ++++++++++++ .../packages/CaloEmbedding/CopyIODataNodes.h | 13 +++ 4 files changed, 215 insertions(+) create mode 100644 offline/packages/CaloEmbedding/CombineTowerInfo.cc create mode 100644 offline/packages/CaloEmbedding/CombineTowerInfo.h diff --git a/offline/packages/CaloEmbedding/CombineTowerInfo.cc b/offline/packages/CaloEmbedding/CombineTowerInfo.cc new file mode 100644 index 0000000000..3e5150d194 --- /dev/null +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.cc @@ -0,0 +1,99 @@ +#include "CombineTowerInfo.h" + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +//____________________________________________________________________________ +CombineTowerInfo::CombineTowerInfo(const std::string& name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________ +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; +} + +//____________________________________________________________________________ +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"); + } +} + +//____________________________________________________________________________ +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..ab96a918e6 --- /dev/null +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.h @@ -0,0 +1,39 @@ +#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; + + void set_inputNodeA(const std::string& name) { m_inputNodeA = name; } + void set_inputNodeB(const std::string& name) { m_inputNodeB = name; } + void set_outputNode(const std::string& name) { m_outputNode = name; } + 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}; + TowerInfoContainer* m_towersOut{nullptr}; +}; + +#endif + diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.cc b/offline/packages/CaloEmbedding/CopyIODataNodes.cc index 0d4d4536ff..08428dccfe 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.cc +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.cc @@ -7,6 +7,9 @@ #include +#include +#include + #include #include @@ -57,6 +60,10 @@ int CopyIODataNodes::InitRun(PHCompositeNode *topNode) { CreateSyncObject(topNode, se->topNode()); } + if (m_CopyTowerInfoFlag) + { + CreateTowerInfo(topNode, se->topNode()); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -89,6 +96,10 @@ int CopyIODataNodes::process_event(PHCompositeNode *topNode) { CopySyncObject(topNode, se->topNode()); } + if (m_CopyTowerInfoFlag) + { + CopyTowerInfo(topNode, se->topNode()); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -293,6 +304,29 @@ void CopyIODataNodes::CopyMinimumBiasInfo(PHCompositeNode *from_topNode, PHCompo return; } +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; +} + + void CopyIODataNodes::CreateMbdOut(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { @@ -330,6 +364,36 @@ void CopyIODataNodes::CreateMbdOut(PHCompositeNode *from_topNode, PHCompositeNod } +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; +} + + + + void CopyIODataNodes::CopyMbdOut(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { MbdOut *from_mbdout = findNode::getClass(from_topNode, "MbdOut"); diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.h b/offline/packages/CaloEmbedding/CopyIODataNodes.h index 08626bdafb..a6ac065a60 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.h +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.h @@ -35,6 +35,13 @@ 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; } + void set_CopyTowerInfo(std::string set_from_towerInfo_name,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 +63,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 +73,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 From f4e898fee68b747ea56efb42ca2ee44a20b35546 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Sat, 17 Jan 2026 18:54:15 -0500 Subject: [PATCH 075/866] adding makefile update --- offline/packages/CaloEmbedding/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/offline/packages/CaloEmbedding/Makefile.am b/offline/packages/CaloEmbedding/Makefile.am index 9731b33cb8..f9dd1faa22 100644 --- a/offline/packages/CaloEmbedding/Makefile.am +++ b/offline/packages/CaloEmbedding/Makefile.am @@ -13,6 +13,7 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ caloTowerEmbed.h \ CopyIODataNodes.h \ + CombineTowerInfo.h \ HepMCCollisionVertex.h lib_LTLIBRARIES = \ @@ -21,6 +22,7 @@ lib_LTLIBRARIES = \ libCaloEmbedding_la_SOURCES = \ caloTowerEmbed.cc \ CopyIODataNodes.cc \ + CombineTowerInfo.cc \ HepMCCollisionVertex.cc libCaloEmbedding_la_LIBADD = \ From 61ecab4cbfa7b23ed2a5736ab43dbb9a32e54c8c Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Sat, 17 Jan 2026 18:56:10 -0500 Subject: [PATCH 076/866] extra feat in triggerskimmer --- .../packages/Skimmers/Trigger/TriggerDSTSkimmer.cc | 12 +++++++++++- .../packages/Skimmers/Trigger/TriggerDSTSkimmer.h | 12 ++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc index b519fd472e..224d172a24 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc @@ -20,6 +20,12 @@ TriggerDSTSkimmer::TriggerDSTSkimmer(const std::string &name) //____________________________________________________________________________.. 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 +51,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 +67,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 +81,8 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } } + + accepted_events++; + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h index dfb2c47a7c..9919df06b7 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h @@ -22,10 +22,22 @@ class TriggerDSTSkimmer : public SubsysReco void SetTrigger(std::vector &trigger_vector) {m_trigger_index = trigger_vector;} + 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}; + + int accepted_events{0}; + int max_accept{0}; + bool use_max_accept{false}; + }; #endif // JETDSTSKIMMER_H From ad7235ea509154e911069064771aa383d4052a90 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 17 Jan 2026 20:31:42 -0500 Subject: [PATCH 077/866] clang-tidy --- offline/packages/trackreco/DSTClusterPruning.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/DSTClusterPruning.cc b/offline/packages/trackreco/DSTClusterPruning.cc index 6314bf50b2..36bbe4fd0f 100644 --- a/offline/packages/trackreco/DSTClusterPruning.cc +++ b/offline/packages/trackreco/DSTClusterPruning.cc @@ -192,7 +192,7 @@ void DSTClusterPruning::prune_clusters() 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); + 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; From 2963c36785cc61b40722e0139177340f09977c7a Mon Sep 17 00:00:00 2001 From: Hao-Ren Jheng Date: Sun, 18 Jan 2026 12:42:50 -0500 Subject: [PATCH 078/866] use short int for vertex beam crossing --- offline/packages/globalvertex/MbdVertex.h | 4 ++-- offline/packages/globalvertex/MbdVertexv2.h | 6 +++--- offline/packages/globalvertex/SvtxVertex.h | 3 +++ offline/packages/globalvertex/SvtxVertex_v2.h | 6 +++--- offline/packages/globalvertex/Vertex.h | 4 ++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/offline/packages/globalvertex/MbdVertex.h b/offline/packages/globalvertex/MbdVertex.h index 6d0900b768..bda5c74597 100644 --- a/offline/packages/globalvertex/MbdVertex.h +++ b/offline/packages/globalvertex/MbdVertex.h @@ -36,8 +36,8 @@ class MbdVertex : public Vertex virtual float get_z_err() const override { return std::numeric_limits::quiet_NaN(); } virtual void set_z_err(float) override {} - virtual unsigned int get_beam_crossing() const override { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) override {} + virtual short int get_beam_crossing() const override { return std::numeric_limits::max(); } + virtual void set_beam_crossing(short int) override {} virtual void set_bbc_ns(int, int, float, float) override {} virtual int get_bbc_npmt(int) const override { return std::numeric_limits::max(); } diff --git a/offline/packages/globalvertex/MbdVertexv2.h b/offline/packages/globalvertex/MbdVertexv2.h index bee34059e4..d0aac0f70b 100644 --- a/offline/packages/globalvertex/MbdVertexv2.h +++ b/offline/packages/globalvertex/MbdVertexv2.h @@ -44,12 +44,12 @@ class MbdVertexv2 : public MbdVertex float get_position(unsigned int coor) const override; - unsigned int get_beam_crossing() const override { return _bco; } - void set_beam_crossing(unsigned int bco) override { _bco = bco; } + short int get_beam_crossing() const override { return _bco; } + void set_beam_crossing(short int bco) override { _bco = bco; } private: unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container - unsigned int _bco{std::numeric_limits::max()}; //< global bco + short int _bco{std::numeric_limits::max()}; //< global bco float _t{std::numeric_limits::quiet_NaN()}; //< collision time float _t_err{std::numeric_limits::quiet_NaN()}; //< collision time uncertainty float _z{std::numeric_limits::quiet_NaN()}; //< collision position z diff --git a/offline/packages/globalvertex/SvtxVertex.h b/offline/packages/globalvertex/SvtxVertex.h index cd9c77454c..5006784f55 100644 --- a/offline/packages/globalvertex/SvtxVertex.h +++ b/offline/packages/globalvertex/SvtxVertex.h @@ -56,6 +56,9 @@ class SvtxVertex : public Vertex virtual float get_error(unsigned int, unsigned int) const override { return std::numeric_limits::quiet_NaN(); } virtual void set_error(unsigned int, unsigned int, float) override {} + virtual short int get_beam_crossing() const override { return std::numeric_limits::max(); } + virtual void set_beam_crossing(short int) override {} + // // associated track ids methods // diff --git a/offline/packages/globalvertex/SvtxVertex_v2.h b/offline/packages/globalvertex/SvtxVertex_v2.h index 24ccbfc0ca..d1bf04e0b4 100644 --- a/offline/packages/globalvertex/SvtxVertex_v2.h +++ b/offline/packages/globalvertex/SvtxVertex_v2.h @@ -54,8 +54,8 @@ class SvtxVertex_v2 : public SvtxVertex float get_error(unsigned int i, unsigned int j) const override; //< get vertex error covar void set_error(unsigned int i, unsigned int j, float value) override; //< set vertex error covar - unsigned int get_beam_crossing() const override { return _beamcrossing; } - void set_beam_crossing(unsigned int cross) override { _beamcrossing = cross; } + short int get_beam_crossing() const override { return _beamcrossing; } + void set_beam_crossing(short int cross) override { _beamcrossing = cross; } // // associated track ids methods @@ -82,7 +82,7 @@ class SvtxVertex_v2 : public SvtxVertex unsigned int _ndof{std::numeric_limits::max()}; //< degrees of freedom float _err[6]{}; //< error covariance matrix (packed storage) (+/- cm^2) std::set _track_ids; //< list of track ids - unsigned int _beamcrossing{std::numeric_limits::max()}; + short int _beamcrossing{std::numeric_limits::max()}; ClassDefOverride(SvtxVertex_v2, 2); }; diff --git a/offline/packages/globalvertex/Vertex.h b/offline/packages/globalvertex/Vertex.h index 7bbfa5f381..e475bfb95d 100644 --- a/offline/packages/globalvertex/Vertex.h +++ b/offline/packages/globalvertex/Vertex.h @@ -62,8 +62,8 @@ class Vertex : public PHObject virtual void set_error(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} // beam crossing methods - virtual unsigned int get_beam_crossing() const { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) {} + virtual short int get_beam_crossing() const { return std::numeric_limits::max(); } + virtual void set_beam_crossing(short int) {} // bbcvertex methods virtual void set_bbc_ns(int, int, float, float) {} From 6242823fcc23e82feae15083c5a113101ffa731e Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Sun, 18 Jan 2026 15:06:15 -0500 Subject: [PATCH 079/866] add const ref --- offline/packages/CaloEmbedding/CopyIODataNodes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.h b/offline/packages/CaloEmbedding/CopyIODataNodes.h index a6ac065a60..5045792a2d 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.h +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.h @@ -35,7 +35,7 @@ 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; } - void set_CopyTowerInfo(std::string set_from_towerInfo_name,std::string set_to_towerInfo_name) + 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; From 2601ddcfccca596143f646f252303cd904a81c4a Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Mon, 19 Jan 2026 09:47:25 -0500 Subject: [PATCH 080/866] minor fix for event skipping --- .../fun4allraw/SingleTriggeredInput.cc | 99 ++++++++++++++++++- .../fun4allraw/SingleTriggeredInput.h | 7 +- 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index 3bb6b30a2b..80e9f49a64 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -352,6 +352,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 +374,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 +402,7 @@ int SingleTriggeredInput::FillEventVector() if (skip_evt->getEvtType() != DATAEVENT) { + delete skip_evt; continue; } @@ -412,14 +424,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 +574,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; @@ -1116,16 +1207,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 +1227,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); diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.h b/offline/framework/fun4allraw/SingleTriggeredInput.h index 088be73bef..d7d825b02a 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.h +++ b/offline/framework/fun4allraw/SingleTriggeredInput.h @@ -34,9 +34,6 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler virtual void FillPool(); 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; virtual int fileclose() override; virtual int AllDone() const { return m_AllDone; } @@ -45,6 +42,8 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler virtual void FilesDone(const int i) { m_FilesDone = i; } virtual void EventAlignmentProblem(const int i) { m_EventAlignmentProblem = i; } virtual int EventAlignmentProblem() const { return m_EventAlignmentProblem; } + 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 @@ -94,7 +93,6 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler 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}; int m_LastEvent{std::numeric_limits::max()}; @@ -114,6 +112,7 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler std::map m_PacketAlignmentProblem; std::map m_PrevPoolLastDiffBad; std::map m_PreviousValidBCOMap; + long long eventcounter{0}; }; #endif From 6caf8c95c3dbef1a1f984d1264131bb0c5b22bfe Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 19 Jan 2026 13:49:08 -0500 Subject: [PATCH 081/866] Add workflow to fix EOF newlines in docstring PRs This workflow fixes missing final newlines in CodeRabbit docstring pull requests by checking the relevant files and appending a newline if necessary. --- .../fix-eof-newline-coderabbit-docstrings.yml | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 .github/workflows/fix-eof-newline-coderabbit-docstrings.yml diff --git a/.github/workflows/fix-eof-newline-coderabbit-docstrings.yml b/.github/workflows/fix-eof-newline-coderabbit-docstrings.yml new file mode 100644 index 0000000000..75d43e65e5 --- /dev/null +++ b/.github/workflows/fix-eof-newline-coderabbit-docstrings.yml @@ -0,0 +1,106 @@ +name: Fix missing final newline (CodeRabbit docstring PRs) + +on: + pull_request_target: + types: [opened, synchronize, reopened] + +permissions: + contents: write + pull-requests: read + +jobs: + fix_eof_newline: + runs-on: ubuntu-latest + steps: + - name: Guard - only CodeRabbit docstring PRs from same repo + id: guard + shell: bash + run: | + set -euo pipefail + + AUTHOR='${{ github.event.pull_request.user.login }}' + BASE_REPO='${{ github.event.pull_request.base.repo.full_name }}' + HEAD_REPO='${{ github.event.pull_request.head.repo.full_name }}' + TITLE='${{ github.event.pull_request.title }}' + + if [[ "$AUTHOR" != "coderabbitai[bot]" ]]; then + echo "run=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Safety: only push to branches within the same repo + if [[ "$BASE_REPO" != "$HEAD_REPO" ]]; then + echo "run=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # only run for docstring PRs + if ! echo "$TITLE" | grep -qi "docstring"; then + echo "run=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "run=true" >> "$GITHUB_OUTPUT" + + - name: Checkout PR head + if: steps.guard.outputs.run == 'true' + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + fetch-depth: 0 + + - name: Append final newline when missing (changed files only) + if: steps.guard.outputs.run == 'true' + shell: bash + run: | + set -euo pipefail + + BASE_SHA="${{ github.event.pull_request.base.sha }}" + HEAD_SHA="${{ github.event.pull_request.head.sha }}" + + files=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- \ + '*.C' '*.c' '*.cc' '*.cpp' '*.cxx' '*.h' '*.hh' '*.hpp' '*.hxx' || true) + + if [[ -z "${files}" ]]; then + echo "No relevant files changed." + exit 0 + fi + + changed=0 + for f in $files; do + [[ -f "$f" ]] || continue + + # For non-empty files: ensure last byte is '\n' + if [[ -s "$f" ]]; then + last_byte="$(tail -c 1 "$f" || true)" + if [[ "$last_byte" != $'\n' ]]; then + printf '\n' >> "$f" + echo "Fixed EOF newline: $f" + changed=1 + fi + fi + done + + if [[ "$changed" -eq 0 ]]; then + echo "All files already end with a newline." + exit 0 + fi + + git status --porcelain + git add -A + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git commit -m "Fix missing final newline in docstring PR" + + - name: Push fix commit back to PR branch + if: steps.guard.outputs.run == 'true' + shell: bash + run: | + set -euo pipefail + # If no commit was created, pushing will fail; so only push if HEAD is ahead. + if git rev-parse HEAD~1 >/dev/null 2>&1; then + git push origin "HEAD:${{ github.event.pull_request.head.ref }}" + fi From c258c798b1adc5a4c2f84bd5620f6ec7d0e77471 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 19 Jan 2026 13:51:11 -0500 Subject: [PATCH 082/866] update calibrator --- offline/packages/trackbase/Calibrator.cc | 61 ++++++++++-------------- offline/packages/trackbase/Calibrator.h | 10 +--- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/offline/packages/trackbase/Calibrator.cc b/offline/packages/trackbase/Calibrator.cc index 44b66bce1a..ce9839e7f5 100644 --- a/offline/packages/trackbase/Calibrator.cc +++ b/offline/packages/trackbase/Calibrator.cc @@ -6,43 +6,34 @@ void Calibrator::calibrate(const Calibrator::MeasurementContainer& measurements, const Acts::SourceLink& sourceLink, Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const { - trackState.setUncalibratedSourceLink(sourceLink); + trackState.setUncalibratedSourceLink(Acts::SourceLink{sourceLink}); const ActsSourceLink sl = sourceLink.get(); - const ActsSourceLink::Index index = sl.index(); - std::visit( - [&](const auto& uncalibmeas) + const ActsExamples::ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(sl.index()); + + Acts::visit_measurement(measurement.size(), [&](auto N) -> void + { + constexpr std::size_t kMeasurementSize = decltype(N)::value; + const ActsExamples::ConstFixedBoundMeasurementProxy fixedMeasurement = + static_cast>( + measurement); + const auto cov = fixedMeasurement.covariance(); + const TrkrDefs::cluskey cluskey = sl.cluskey(); + const uint8_t layer = TrkrDefs::getLayer(cluskey); + const double misalignmentFactor = gctx.get()->getMisalignmentFactor(layer); + + Acts::ActsSquareMatrix expandedCov = Acts::ActsSquareMatrix::Zero(); + + for (int i = 0; i < cov.rows(); i++) + { + for (int j = 0; j < cov.cols(); j++) { - std::array indices{}; - indices[0] = Acts::BoundIndices::eBoundLoc0; - indices[1] = Acts::BoundIndices::eBoundLoc1; - - Acts::ActsVector<2> loc; - loc(0) = uncalibmeas.parameters()[Acts::eBoundLoc0]; - loc(1) = uncalibmeas.parameters()[Acts::eBoundLoc1]; - - auto cov = uncalibmeas.covariance(); - const TrkrDefs::cluskey cluskey = sl.cluskey(); - const uint8_t layer = TrkrDefs::getLayer(cluskey); - const double misalignmentFactor = gctx.get()->getMisalignmentFactor(layer); - - Acts::ActsSquareMatrix<2> expandedCov = Acts::ActsSquareMatrix<2>::Zero(); - - for (int i = 0; i < cov.rows(); i++) - { - for (int j = 0; j < cov.cols(); j++) - { - expandedCov(i, j) = cov(i, j) * misalignmentFactor; - } - } - - Acts::Measurement meas(sourceLink, - indices, - loc, expandedCov); - - trackState.allocateCalibrated(meas.size()); - trackState.setCalibrated(meas); - }, - (measurements)[index]); + expandedCov(i, j) = cov(i, j) * misalignmentFactor; + } + } + trackState.allocateCalibrated(fixedMeasurement.parameters().eval(), + expandedCov.eval()); + trackState.setProjectorSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } void CalibratorAdapter::calibrate( diff --git a/offline/packages/trackbase/Calibrator.h b/offline/packages/trackbase/Calibrator.h index 2f9d4f2fc0..651091ad5b 100644 --- a/offline/packages/trackbase/Calibrator.h +++ b/offline/packages/trackbase/Calibrator.h @@ -6,7 +6,7 @@ #include "TrkrDefs.h" #include "alignmentTransformationContainer.h" -#include +#include #include #include @@ -14,13 +14,7 @@ class Calibrator { public: - using Measurement = ::Acts::BoundVariantMeasurement; - /// Container of measurements. - /// - /// In contrast to the source links, the measurements themself must not be - /// orderable. The source links stored in the measurements are treated - /// as opaque here and no ordering is enforced on the stored measurements. - using MeasurementContainer = std::vector; + using MeasurementContainer = ActsExamples::MeasurementContainer; void calibrate(const MeasurementContainer& measurements, const Acts::GeometryContext& gctx, From 57a9dd2851c2a1e8a786d54258851b94feb2a060 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Mon, 19 Jan 2026 15:04:19 -0500 Subject: [PATCH 083/866] changing ADC threshold for time calib --- offline/QA/Calorimeters/CaloValid.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 19c834bdab..ab2f355c59 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -176,7 +176,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) float ihcaldownscale; float ohcaldownscale; float mbddownscale; - float adc_threshold; + float adc_threshold_hcal; + float adc_threshold_emcal; float emcal_hit_threshold; float emcal_highhit_threshold; float ohcal_hit_threshold; @@ -190,7 +191,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) ihcaldownscale = 55000. / 300.; ohcaldownscale = 265000. / 600.; mbddownscale = 2800.0; - adc_threshold = 15.; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; emcal_hit_threshold = 0.5; // GeV ohcal_hit_threshold = 0.5; @@ -206,7 +208,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) ihcaldownscale = 4000. / 300.; ohcaldownscale = 25000. / 600.; mbddownscale = 200.0; - adc_threshold = 100.; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; emcal_hit_threshold = 0.5; // GeV ohcal_hit_threshold = 0.5; @@ -528,7 +531,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_emcal) { h_cemc_etaphi_fracHitADC->Fill(ieta, iphi, 1); h_cemc_etaphi_time_raw->Fill(ieta, iphi, raw_time); @@ -558,7 +561,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_hcal) { h_ohcal_etaphi_time_raw->Fill(ieta, iphi, raw_time); h_ohcal_etaphi_fracHitADC->Fill(ieta, iphi, 1); @@ -588,7 +591,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_hcal) { h_ihcal_etaphi_time_raw->Fill(ieta, iphi, raw_time); h_ihcal_etaphi_fracHitADC->Fill(ieta, iphi, 1); From d50b1e1c04631a0bfe6f3bded4f54a8d353b4291 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 20:10:30 +0000 Subject: [PATCH 084/866] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20?= =?UTF-8?q?`embed`?= 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-Collaboration/coresoftware/pull/4125#issuecomment-3769948215 The following files were modified: * `offline/QA/Calorimeters/CaloValid.cc` --- offline/QA/Calorimeters/CaloValid.cc | 31 +++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 19c834bdab..dcd3674503 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -142,6 +142,20 @@ int CaloValid::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Process event towers, triggers, MBD, and clusters to populate QA histograms. + * + * Reads event header, vertex, trigger (GL1), calibrated and raw tower containers for + * CEMC/HCAL (inner/outer), MBD PMTs, and CEMC clusters; computes per-detector totals, + * downscaled correlations, per-channel and per-tower QA, pi0 candidate invariant masses, + * and trigger/alignment summaries, then fills the corresponding histograms and profiles. + * + * @param topNode Top-level PHCompositeNode containing event data (towers, clusters, + * trigger/GL1 packets, vertex map, and MBD PMTs). + * @return Fun4AllReturnCodes::EVENT_OK on success; may return other Fun4All return codes + * or 0 on error conditions encountered while processing nodes. + * + */ int CaloValid::process_towers(PHCompositeNode* topNode) { //---------------------------Event header--------------------------------// @@ -176,7 +190,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) float ihcaldownscale; float ohcaldownscale; float mbddownscale; - float adc_threshold; + float adc_threshold_hcal; + float adc_threshold_emcal; float emcal_hit_threshold; float emcal_highhit_threshold; float ohcal_hit_threshold; @@ -190,7 +205,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) ihcaldownscale = 55000. / 300.; ohcaldownscale = 265000. / 600.; mbddownscale = 2800.0; - adc_threshold = 15.; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; emcal_hit_threshold = 0.5; // GeV ohcal_hit_threshold = 0.5; @@ -206,7 +222,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) ihcaldownscale = 4000. / 300.; ohcaldownscale = 25000. / 600.; mbddownscale = 200.0; - adc_threshold = 100.; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; emcal_hit_threshold = 0.5; // GeV ohcal_hit_threshold = 0.5; @@ -528,7 +545,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_emcal) { h_cemc_etaphi_fracHitADC->Fill(ieta, iphi, 1); h_cemc_etaphi_time_raw->Fill(ieta, iphi, raw_time); @@ -558,7 +575,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_hcal) { h_ohcal_etaphi_time_raw->Fill(ieta, iphi, raw_time); h_ohcal_etaphi_fracHitADC->Fill(ieta, iphi, 1); @@ -588,7 +605,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_hcal) { h_ihcal_etaphi_time_raw->Fill(ieta, iphi, raw_time); h_ihcal_etaphi_fracHitADC->Fill(ieta, iphi, 1); @@ -1301,4 +1318,4 @@ void CaloValid::createHistos() } hm->registerHisto(h_triggerVec); hm->registerHisto(pr_ldClus_trig); -} +} \ No newline at end of file From 0e1aa45113e0f01ec9abc6397dc2b846d349ea5e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 Jan 2026 20:10:47 +0000 Subject: [PATCH 085/866] Fix missing final newline in docstring PR --- offline/QA/Calorimeters/CaloValid.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index dcd3674503..c51f75c200 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -1318,4 +1318,4 @@ void CaloValid::createHistos() } hm->registerHisto(h_triggerVec); hm->registerHisto(pr_ldClus_trig); -} \ No newline at end of file +} From 3b875db25f73c26fd9a473ea25bccc8383ae2ca4 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 19 Jan 2026 15:20:18 -0500 Subject: [PATCH 086/866] call wrapper tgeo builder --- offline/packages/trackbase/TGeoDetectorWithOptions.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.cc b/offline/packages/trackbase/TGeoDetectorWithOptions.cc index 4467c20754..cb29c27dc7 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.cc +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.cc @@ -108,7 +108,13 @@ auto TGeoDetectorWithOptions::finalize( readTGeoLayerBuilderConfigs(vm, config); } - return m_detector.finalize(config, std::move(mdecorator)); + auto logger = Acts::getDefaultLogger("TGeoDetector", Acts::Logging::INFO); + ContextDecorators tgeoContextDecorators = {}; + std::vector> detectorStore; + TrackingGeometryPtr tgeoTrackingGeometry = ActsExamples::buildTGeoDetectorWrapper( + config, Acts::GeometryContext(), detectorStore, std::move(mdecorator), *logger); + + return {std::move(tgeoTrackingGeometry), std::move(tgeoContextDecorators)}; } } // namespace ActsExamples From 9646765c059439aa04786e12592200b3653abce2 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 19 Jan 2026 15:20:43 -0500 Subject: [PATCH 087/866] preserve makefile while testing --- offline/packages/trackbase/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 29d090c40a..d19587bdd7 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -26,6 +26,7 @@ lib_LTLIBRARIES = \ libtrack.la AM_CPPFLAGS = \ + -I$(MYINSTALL)/include \ -I$(includedir) \ -isystem$(OFFLINE_MAIN)/include \ -isystem$(ROOTSYS)/include @@ -33,7 +34,7 @@ AM_CPPFLAGS = \ AM_LDFLAGS = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 \ + -L$(MYINSTALL)/lib64 \ -L$(ROOTSYS)/lib From e219ff4ce68c639cdd5f98aaf4b7d639f70b1f49 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 19 Jan 2026 16:56:40 -0500 Subject: [PATCH 088/866] use helper functions --- .../trackbase/ResidualOutlierFinder.h | 48 +++++-------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/offline/packages/trackbase/ResidualOutlierFinder.h b/offline/packages/trackbase/ResidualOutlierFinder.h index 593f5df981..904aa474d0 100644 --- a/offline/packages/trackbase/ResidualOutlierFinder.h +++ b/offline/packages/trackbase/ResidualOutlierFinder.h @@ -6,10 +6,12 @@ #include #include #include -#include + +#include #include #include #include +#include #include struct ResidualOutlierFinder @@ -49,44 +51,14 @@ struct ResidualOutlierFinder auto sourceLink = state.getUncalibratedSourceLink().template get(); const auto& cluskey = sourceLink.cluskey(); - const auto predicted = state.predicted(); - const auto predictedCovariance = state.predictedCovariance(); - float chi2 = std::numeric_limits::max(); - - auto fullCalibrated = state - .template calibrated() - .data(); - auto fullCalibratedCovariance = state - .template calibratedCovariance() - .data(); - - chi2 = Acts::visit_measurement(state.calibratedSize(), [&](auto N) -> double - { - constexpr size_t kMeasurementSize = decltype(N)::value; - typename Acts::TrackStateTraits::Measurement calibrated{ - fullCalibrated}; - - typename Acts::TrackStateTraits::MeasurementCovariance - calibratedCovariance{fullCalibratedCovariance}; - - using ParametersVector = Acts::ActsVector; - const auto H = state.projector().template topLeftCorner().eval(); - ParametersVector res; - res = calibrated - H * predicted; - chi2 = (res.transpose() * ((calibratedCovariance + H * predictedCovariance * H.transpose())).inverse() * res).eval()(0, 0); - - return chi2; }); + double chi2 = Acts::calculatePredictedChi2(state); float distance = Acts::visit_measurement(state.calibratedSize(), [&](auto N) { constexpr size_t kMeasurementSize = decltype(N)::value; - auto residuals = - state.template calibrated() - - state.projector() - .template topLeftCorner() * - state.predicted(); - auto cdistance = residuals.norm(); - return cdistance; }); + auto [residual, residualCovariance] = + calculatePredictedResidual(state); + return residual.norm(); }); if (verbosity > 2) { @@ -108,6 +80,10 @@ struct ResidualOutlierFinder std::cout << PHWHERE << "no geometry set in residual outlier finder" << std::endl; exit(1); } + const auto predicted = state.predicted(); + auto fullCalibrated = state + .template calibrated() + .data(); Acts::FreeVector freeParams = Acts::transformBoundToFreeParameters(state.referenceSurface(), m_tGeometry->geometry().getGeoContext(), @@ -117,7 +93,7 @@ struct ResidualOutlierFinder m_tGeometry->geometry().getGeoContext(), local, Acts::Vector3(1, 1, 1)); float data[] = { - (float) sphenixlayer, (float) layer, (float) volume, distance, chi2, + (float) sphenixlayer, (float) layer, (float) volume, distance, (float)chi2, (float) freeParams[Acts::eFreePos0], (float) freeParams[Acts::eFreePos1], (float) freeParams[Acts::eFreePos2], (float) predicted[Acts::eBoundLoc0], (float) predicted[Acts::eBoundLoc1], (float) global[Acts::eFreePos0], (float) global[Acts::eFreePos1], (float) global[Acts::eFreePos2], From 1f11a69946026f7a53903e7382857b2ee6bee031 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 19 Jan 2026 16:57:07 -0500 Subject: [PATCH 089/866] abolished measurement object --- offline/packages/trackbase/ActsTrackFittingAlgorithm.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase/ActsTrackFittingAlgorithm.h b/offline/packages/trackbase/ActsTrackFittingAlgorithm.h index 425c669da2..c68698b9d7 100644 --- a/offline/packages/trackbase/ActsTrackFittingAlgorithm.h +++ b/offline/packages/trackbase/ActsTrackFittingAlgorithm.h @@ -11,7 +11,7 @@ #include #include #include - +#include #pragma GCC diagnostic push // needed for local Act compilation #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include @@ -32,8 +32,7 @@ class ActsTrackFittingAlgorithm final { public: using TrackParameters = ::Acts::BoundTrackParameters; - using Measurement = ::Acts::BoundVariantMeasurement; - using MeasurementContainer = std::vector; + using MeasurementContainer = ActsExamples::MeasurementContainer; using TrackContainer = Acts::TrackContainer Date: Mon, 19 Jan 2026 16:57:21 -0500 Subject: [PATCH 090/866] update gsf apis --- .../trackbase/ActsGsfTrackFittingAlgorithm.h | 26 ++++++++++--------- .../TrackFittingAlgorithmFunctionsGsf.cc | 6 +++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h b/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h index fd144c1163..7b418a0b62 100644 --- a/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h +++ b/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h @@ -62,7 +62,7 @@ namespace MixtureReductionAlgorithm::KLDistance; Acts::ComponentMergeMethod mergeMethod = Acts::ComponentMergeMethod::eMaxWeight; - + double reverseFilteringCovarianceScaling = 1.0; ActsSourceLink::SurfaceAccessor m_slSurfaceAccessor; GsfFitterFunctionImpl(Fitter&& f, @@ -83,17 +83,18 @@ namespace extensions.updater.connect<&Acts::GainMatrixUpdater::operator()>(&updater); Acts::GsfOptions gsfOptions{ - options.geoContext, - options.magFieldContext, - options.calibrationContext, - extensions, - options.propOptions, - &(*options.referenceSurface), - maxComponents, - weightCutoff, - abortOnError, - disableAllMaterialHandling}; + options.geoContext, options.magFieldContext, + options.calibrationContext}; + gsfOptions.extensions = extensions; + gsfOptions.propagatorPlainOptions = options.propOptions; + gsfOptions.referenceSurface = options.referenceSurface; + gsfOptions.maxComponents = maxComponents; + gsfOptions.weightCutoff = weightCutoff; + gsfOptions.abortOnError = abortOnError; + gsfOptions.disableAllMaterialHandling = disableAllMaterialHandling; gsfOptions.componentMergeMethod = mergeMethod; + gsfOptions.reverseFilteringCovarianceScaling = + reverseFilteringCovarianceScaling; gsfOptions.extensions.calibrator.connect<&calibrator_t::calibrate>( &calibrator); gsfOptions.extensions.surfaceAccessor.connect<&ActsSourceLink::SurfaceAccessor::operator()>(&m_slSurfaceAccessor); @@ -152,5 +153,6 @@ class ActsGsfTrackFittingAlgorithm BetheHeitlerApprox betheHeitlerApprox, std::size_t maxComponents, double weightCutoff, MixtureReductionAlgorithm finalReductionMethod, bool abortOnError, - bool disableAllMaterialHandling, const Acts::Logger& logger = *Acts::getDefaultLogger("GSF", Acts::Logging::FATAL)); + bool disableAllMaterialHandling, double reverseFilteringCovarianceScaling, + const Acts::Logger& logger = *Acts::getDefaultLogger("GSF", Acts::Logging::FATAL)); }; diff --git a/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc b/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc index cecd2898b9..16d5912532 100644 --- a/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc +++ b/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc @@ -9,7 +9,8 @@ ActsGsfTrackFittingAlgorithm::makeGsfFitterFunction( BetheHeitlerApprox betheHeitlerApprox, std::size_t maxComponents, double weightCutoff, MixtureReductionAlgorithm finalReductionMethod, bool abortOnError, - bool disableAllMaterialHandling, const Acts::Logger& logger) + bool disableAllMaterialHandling, double reverseFilteringCovarianceScaling, + const Acts::Logger& logger) { MultiStepper stepper(std::move(magneticField), logger.cloneWithSuffix("GSFStep")); @@ -35,6 +36,7 @@ ActsGsfTrackFittingAlgorithm::makeGsfFitterFunction( fitterFunction->abortOnError = abortOnError; fitterFunction->disableAllMaterialHandling = disableAllMaterialHandling; fitterFunction->reductionAlg = finalReductionMethod; - + fitterFunction->reverseFilteringCovarianceScaling = + reverseFilteringCovarianceScaling; return fitterFunction; } From 147009b249d97bd8d5ef7d60f25800e833763e49 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 20 Jan 2026 09:45:44 -0500 Subject: [PATCH 091/866] add api to reject clusters on edge, reject clusters with edge>0 --- offline/packages/trackreco/MakeSourceLinks.cc | 482 ++++++++++-------- offline/packages/trackreco/MakeSourceLinks.h | 56 +- offline/packages/trackreco/PHActsTrkFitter.cc | 2 + offline/packages/trackreco/PHActsTrkFitter.h | 3 +- 4 files changed, 291 insertions(+), 252 deletions(-) diff --git a/offline/packages/trackreco/MakeSourceLinks.cc b/offline/packages/trackreco/MakeSourceLinks.cc index efbbe92853..5bb00293a9 100644 --- a/offline/packages/trackreco/MakeSourceLinks.cc +++ b/offline/packages/trackreco/MakeSourceLinks.cc @@ -1,13 +1,12 @@ #include "MakeSourceLinks.h" -#include +#include +#include #include #include #include -#include #include #include -#include #include #include @@ -16,8 +15,8 @@ #include #include -#include #include +#include #include @@ -29,26 +28,25 @@ namespace { - template + template inline T square(const T& x) { return x * x; } - [[maybe_unused]] std::ostream& operator << (std::ostream& out, const Acts::Vector3& v ) + [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector3& v) { out << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")"; return out; } - - [[maybe_unused]] std::ostream& operator << (std::ostream& out, const Acts::Vector2& v ) + [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector2& v) { out << "(" << v.x() << ", " << v.y() << ")"; return out; } -} +} // namespace void MakeSourceLinks::initialize(PHG4TpcGeomContainer* cellgeo) { @@ -57,30 +55,33 @@ void MakeSourceLinks::initialize(PHG4TpcGeomContainer* cellgeo) { _clusterMover.initialize_geometry(cellgeo); } - } - //___________________________________________________________________________________ +//___________________________________________________________________________________ SourceLinkVec MakeSourceLinks::getSourceLinks( - TrackSeed* track, - ActsTrackFittingAlgorithm::MeasurementContainer& measurements, - TrkrClusterContainer* clusterContainer, - ActsGeometry* tGeometry, - const TpcGlobalPositionWrapper& globalPositionWrapper, - alignmentTransformationContainer* transformMapTransient, - std::set< Acts::GeometryIdentifier>& transient_id_set, - short int crossing - ) + TrackSeed* track, + ActsTrackFittingAlgorithm::MeasurementContainer& measurements, + TrkrClusterContainer* clusterContainer, + ActsGeometry* tGeometry, + const TpcGlobalPositionWrapper& globalPositionWrapper, + alignmentTransformationContainer* transformMapTransient, + std::set& transient_id_set, + short int crossing) { - if(m_verbosity > 1) { std::cout << "Entering MakeSourceLinks::getSourceLinks " << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Entering MakeSourceLinks::getSourceLinks " << std::endl; + } SourceLinkVec sourcelinks; if (m_pp_mode && crossing == SHRT_MAX) { // Need to skip this in the pp case, for AuAu it should not happen - if(m_verbosity > 1) - { std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; + } return sourcelinks; } @@ -98,82 +99,88 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( auto key = *clusIter; auto cluster = clusterContainer->findCluster(key); if (!cluster) + { + if (m_verbosity > 0) { - if (m_verbosity > 0) - {std::cout << "MakeSourceLinks: Failed to get cluster with key " << key << " for track seed" << std::endl;} - continue; + std::cout << "MakeSourceLinks: Failed to get cluster with key " << key << " for track seed" << std::endl; } - else - if(m_verbosity > 0) - {std::cout << "MakeSourceLinks: Found cluster with key " << key << " for track seed " << std::endl;} - + continue; + } + else if (m_verbosity > 0) + { + std::cout << "MakeSourceLinks: Found cluster with key " << key << " for track seed " << std::endl; + } + /// Make a safety check for clusters that couldn't be attached to a surface auto surf = tGeometry->maps().getSurface(key, cluster); if (!surf) - { - continue; - } - + { + continue; + } + const unsigned int trkrid = TrkrDefs::getTrkrId(key); const unsigned int clus_layer = TrkrDefs::getLayer(key); - if(m_verbosity > 1) { std::cout << " Cluster key " << key << " layer " << clus_layer << " trkrid " << trkrid << " crossing " << crossing << std::endl; } + if (m_verbosity > 1) + { + std::cout << " Cluster key " << key << " layer " << clus_layer << " trkrid " << trkrid << " crossing " << crossing << std::endl; + } // For the TPC, cluster z has to be corrected for the crossing z offset, distortion, and TOF z offset // we do this by modifying the fake surface transform, to move the cluster to the corrected position if (trkrid == TrkrDefs::tpcId) { - Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing ); + Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing); Acts::Vector3 nominal_global_in = tGeometry->getGlobalPosition(key, cluster); Acts::Vector3 global_in = tGeometry->getGlobalPosition(key, cluster); // The wrapper returns the global position corrected for distortion and the cluster crossing z offset // The cluster z crossing correction has to be applied to the nominal global position (global_in) - double cluster_crossing_corrected_z= TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); - double crossing_correction = cluster_crossing_corrected_z - global_in.z(); + double cluster_crossing_corrected_z = TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); + double crossing_correction = cluster_crossing_corrected_z - global_in.z(); global_in.z() = cluster_crossing_corrected_z; - - if(m_verbosity > 2) + + if (m_verbosity > 2) { - unsigned int this_layer = TrkrDefs::getLayer(key); - unsigned int this_side = TpcDefs::getSide(key); - if(this_layer == 28) - { - std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl - << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) - << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) - << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl - << " distortion " << global(0)-global_in(0) << " " - << global(1) - global_in(1) << " " << global(2) - global_in(2) - << " cluster crossing z correction " << crossing_correction - << std::endl; - } + unsigned int this_layer = TrkrDefs::getLayer(key); + unsigned int this_side = TpcDefs::getSide(key); + if (this_layer == 28) + { + std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl + << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) + << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) + << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl + << " distortion " << global(0) - global_in(0) << " " + << global(1) - global_in(1) << " " << global(2) - global_in(2) + << " cluster crossing z correction " << crossing_correction + << std::endl; + } } - + // Make an afine transform that implements the distortion correction as a translation - auto correction_translation = (global - global_in)*Acts::UnitConstants::cm; - Acts::Vector3 correction_rotation(0,0,0); // null rotation + auto correction_translation = (global - global_in) * Acts::UnitConstants::cm; + Acts::Vector3 correction_rotation(0, 0, 0); // null rotation Acts::Transform3 tcorr = tGeometry->makeAffineTransform(correction_rotation, correction_translation); auto this_surf = tGeometry->maps().getSurface(key, cluster); Acts::GeometryIdentifier id = this_surf->geometryId(); auto check_cluster = clusterContainer->findCluster(key); - Acts::Vector2 check_local2d = tGeometry->getLocalCoords(key, check_cluster) * Acts::UnitConstants::cm; // need mm - Acts::Vector3 check_local3d (check_local2d(0), check_local2d(1), 0); + Acts::Vector2 check_local2d = tGeometry->getLocalCoords(key, check_cluster) * Acts::UnitConstants::cm; // need mm + Acts::Vector3 check_local3d(check_local2d(0), check_local2d(1), 0); Acts::GeometryContext temp_transient_geocontext; - temp_transient_geocontext = transformMapTransient; - Acts::Vector3 check_before_pos_surf = this_surf->localToGlobal( temp_transient_geocontext, - check_local2d, - Acts::Vector3(1,1,1)); - if(m_verbosity > 2) - { - unsigned int this_layer = TrkrDefs::getLayer(key); - if(this_layer == 28) - { - std::cout << "Check global from transient transform BEFORE via surface method " << check_before_pos_surf(0)/10.0 << " " - << " " << check_before_pos_surf(1)/10.0 << " " << check_before_pos_surf(2)/10.0 << std::endl; - } - } - + temp_transient_geocontext = transformMapTransient; + Acts::Vector3 check_before_pos_surf = this_surf->localToGlobal(temp_transient_geocontext, + check_local2d, + Acts::Vector3(1, 1, 1)); + if (m_verbosity > 2) + { + unsigned int this_layer = TrkrDefs::getLayer(key); + if (this_layer == 28) + { + std::cout << "Check global from transient transform BEFORE via surface method " << check_before_pos_surf(0) / 10.0 << " " + << " " << check_before_pos_surf(1) / 10.0 << " " << check_before_pos_surf(2) / 10.0 << std::endl; + } + } + // replace the the default alignment transform with the corrected one auto ctxt = tGeometry->geometry().getGeoContext(); alignmentTransformationContainer* transformMap = ctxt.get(); @@ -181,18 +188,18 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( transformMapTransient->replaceTransform(id, corrected_transform); transient_id_set.insert(id); - Acts::Vector3 check_after_pos_surf = this_surf->localToGlobal( temp_transient_geocontext, - check_local2d, - Acts::Vector3(1,1,1)); - if(m_verbosity > 2) - { - unsigned int this_layer = TrkrDefs::getLayer(key); - if(this_layer == 28) - { - std::cout << "Check global from transient transform AFTER via surface method " << check_after_pos_surf(0)/10.0 << " " - << " " << check_after_pos_surf(1)/10.0 << " " << check_after_pos_surf(2)/10.0 << std::endl; - } - } + Acts::Vector3 check_after_pos_surf = this_surf->localToGlobal(temp_transient_geocontext, + check_local2d, + Acts::Vector3(1, 1, 1)); + if (m_verbosity > 2) + { + unsigned int this_layer = TrkrDefs::getLayer(key); + if (this_layer == 28) + { + std::cout << "Check global from transient transform AFTER via surface method " << check_after_pos_surf(0) / 10.0 << " " + << " " << check_after_pos_surf(1) / 10.0 << " " << check_after_pos_surf(2) / 10.0 << std::endl; + } + } } // end TPC specific treatment // corrected TPC transforms are installed, capture the cluster key @@ -201,128 +208,143 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( } // end loop over clusters here Acts::GeometryContext transient_geocontext; - transient_geocontext = transformMapTransient; + transient_geocontext = transformMapTransient; // loop over cluster_vec and make source links - for(auto& cluskey : cluster_vec) + for (auto& cluskey : cluster_vec) + { + if (m_ignoreLayer.contains(TrkrDefs::getLayer(cluskey))) { - if (m_ignoreLayer.contains(TrkrDefs::getLayer(cluskey))) - { - if (m_verbosity > 3) - { - std::cout << PHWHERE << "skipping cluster in layer " - << (unsigned int) TrkrDefs::getLayer(cluskey) << std::endl; - } - continue; - } - - // get local coordinates (TPC time needs conversion to cm) - auto cluster = clusterContainer->findCluster(cluskey); - Acts::Vector2 localPos = tGeometry->getLocalCoords(cluskey, cluster, crossing); // cm - - Surface surf = tGeometry->maps().getSurface(cluskey, cluster); - - Acts::ActsVector<2> loc; - loc[Acts::eBoundLoc0] = localPos(0) * Acts::UnitConstants::cm; // mm - loc[Acts::eBoundLoc1] = localPos(1) * Acts::UnitConstants::cm; - - std::array indices = - {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; - Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero(); - - // get errors - Acts::Vector3 global = tGeometry->getGlobalPosition(cluskey, cluster); - double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); - auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; - cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; - - ActsSourceLink::Index index = measurements.size(); - - SourceLink sl(surf->geometryId(), index, cluskey); - Acts::SourceLink actsSL{sl}; - Acts::Measurement meas(actsSL, indices, loc, cov); if (m_verbosity > 3) - { - unsigned int this_layer = TrkrDefs::getLayer(cluskey); - if (this_layer == 28) - { - std::cout << "source link in layer " << this_layer << " for cluskey " << cluskey << " is " << sl.index() << ", loc : " - << loc.transpose() << std::endl - << ", cov : " << cov.transpose() << std::endl - << " geo id " << sl.geometryId() << std::endl; - std::cout << "Surface original transform: " << std::endl; - surf.get()->toStream(tGeometry->geometry().getGeoContext(), std::cout); - std::cout << std::endl << "Surface transient transform: " << std::endl; - surf.get()->toStream(transient_geocontext, std::cout); - std::cout << std::endl; - std::cout << "Corrected surface transform:" << std::endl; - std::cout << transformMapTransient->getTransform(surf->geometryId()).matrix() << std::endl; - std::cout << "Cluster error " << cluster->getRPhiError() << " , " << cluster->getZError() << std::endl; - std::cout << "For key " << cluskey << " with local pos " << std::endl - << localPos(0) << ", " << localPos(1) - << std::endl << std::endl; - } + { + std::cout << PHWHERE << "skipping cluster in layer " + << (unsigned int) TrkrDefs::getLayer(cluskey) << std::endl; + } + continue; + } + + // get local coordinates (TPC time needs conversion to cm) + auto cluster = clusterContainer->findCluster(cluskey); + if(TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId) + { + if(cluster->getEdge() > m_cluster_edge_rejection) + { + continue; + } } + Acts::Vector2 localPos = tGeometry->getLocalCoords(cluskey, cluster, crossing); // cm + + Surface surf = tGeometry->maps().getSurface(cluskey, cluster); + + Acts::ActsVector<2> loc; + loc[Acts::eBoundLoc0] = localPos(0) * Acts::UnitConstants::cm; // mm + loc[Acts::eBoundLoc1] = localPos(1) * Acts::UnitConstants::cm; + + std::array indices = + {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; + Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero(); + + // get errors + Acts::Vector3 global = tGeometry->getGlobalPosition(cluskey, cluster); + double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); + auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; + cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; + + ActsSourceLink::Index index = measurements.size(); - sourcelinks.push_back(actsSL); - measurements.push_back(meas); + SourceLink sl(surf->geometryId(), index, cluskey); + Acts::SourceLink actsSL{sl}; + Acts::Measurement meas(actsSL, indices, loc, cov); + if (m_verbosity > 3) + { + unsigned int this_layer = TrkrDefs::getLayer(cluskey); + if (this_layer == 28) + { + std::cout << "source link in layer " << this_layer << " for cluskey " << cluskey << " is " << sl.index() << ", loc : " + << loc.transpose() << std::endl + << ", cov : " << cov.transpose() << std::endl + << " geo id " << sl.geometryId() << std::endl; + std::cout << "Surface original transform: " << std::endl; + surf.get()->toStream(tGeometry->geometry().getGeoContext(), std::cout); + std::cout << std::endl + << "Surface transient transform: " << std::endl; + surf.get()->toStream(transient_geocontext, std::cout); + std::cout << std::endl; + std::cout << "Corrected surface transform:" << std::endl; + std::cout << transformMapTransient->getTransform(surf->geometryId()).matrix() << std::endl; + std::cout << "Cluster error " << cluster->getRPhiError() << " , " << cluster->getZError() << std::endl; + std::cout << "For key " << cluskey << " with local pos " << std::endl + << localPos(0) << ", " << localPos(1) + << std::endl + << std::endl; + } } + sourcelinks.push_back(actsSL); + measurements.push_back(meas); + } + SLTrackTimer.stop(); auto SLTime = SLTrackTimer.get_accumulated_time(); if (m_verbosity > 1) - { - std::cout << "PHActsTrkFitter Source Links generation time: " + { + std::cout << "PHActsTrkFitter Source Links generation time: " << SLTime << std::endl; - } + } return sourcelinks; } void MakeSourceLinks::resetTransientTransformMap( - alignmentTransformationContainer* transformMapTransient, - std::set< Acts::GeometryIdentifier>& transient_id_set, - ActsGeometry* tGeometry ) + alignmentTransformationContainer* transformMapTransient, + std::set& transient_id_set, + ActsGeometry* tGeometry) { - if(m_verbosity > 2) { std::cout << "Resetting TransientTransformMap with transient_id_set size " << transient_id_set.size() << std::endl; } + if (m_verbosity > 2) + { + std::cout << "Resetting TransientTransformMap with transient_id_set size " << transient_id_set.size() << std::endl; + } // loop over modifiedTransformSet and replace transient elements modified for the last track with the default transforms - for(auto& id : transient_id_set) - { - auto ctxt = tGeometry->geometry().getGeoContext(); - alignmentTransformationContainer* transformMap = ctxt.get(); - auto transform = transformMap->getTransform(id); - transformMapTransient->replaceTransform(id, transform); - // std::cout << "replaced transform for id " << id << std::endl; - } + for (auto& id : transient_id_set) + { + auto ctxt = tGeometry->geometry().getGeoContext(); + alignmentTransformationContainer* transformMap = ctxt.get(); + auto transform = transformMap->getTransform(id); + transformMapTransient->replaceTransform(id, transform); + // std::cout << "replaced transform for id " << id << std::endl; + } transient_id_set.clear(); } - //___________________________________________________________________________________ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( - TrackSeed* track, - ActsTrackFittingAlgorithm::MeasurementContainer& measurements, - TrkrClusterContainer* clusterContainer, - ActsGeometry* tGeometry, - const TpcGlobalPositionWrapper& globalPositionWrapper, - short int crossing - ) + TrackSeed* track, + ActsTrackFittingAlgorithm::MeasurementContainer& measurements, + TrkrClusterContainer* clusterContainer, + ActsGeometry* tGeometry, + const TpcGlobalPositionWrapper& globalPositionWrapper, + short int crossing) { - if(m_verbosity > 1) { std::cout << "Entering MakeSourceLinks::getSourceLinksClusterMover for seed " - << " with crossing " << crossing - << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Entering MakeSourceLinks::getSourceLinksClusterMover for seed " + << " with crossing " << crossing + << std::endl; + } SourceLinkVec sourcelinks; if (m_pp_mode && crossing == SHRT_MAX) { // Need to skip this in the pp case, for AuAu it should not happen - if(m_verbosity > 1) - { std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; + } return sourcelinks; } @@ -343,9 +365,13 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( if (!cluster) { if (m_verbosity > 0) - {std::cout << "Failed to get cluster with key " << key << " for track " << track << std::endl;} + { + std::cout << "Failed to get cluster with key " << key << " for track " << track << std::endl; + } else - {std::cout << "PHActsTrkFitter :: Key: " << key << " for track " << track << std::endl;} + { + std::cout << "PHActsTrkFitter :: Key: " << key << " for track " << track << std::endl; + } continue; } @@ -359,36 +385,39 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( const unsigned int trkrid = TrkrDefs::getTrkrId(key); - if(m_verbosity > 1) { std::cout << " Cluster key " << key << " trkrid " << trkrid << " crossing " << crossing << std::endl; } + if (m_verbosity > 1) + { + std::cout << " Cluster key " << key << " trkrid " << trkrid << " crossing " << crossing << std::endl; + } // For the TPC, cluster z has to be corrected for the crossing z offset, distortion, and TOF z offset // we do this locally here and do not modify the cluster, since the cluster may be associated with multiple silicon tracks - const Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing ); + const Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing); if (trkrid == TrkrDefs::tpcId) { - if(m_verbosity > 2) - { - unsigned int this_layer = TrkrDefs::getLayer(key); - if(this_layer == 28) - { - unsigned int this_side = TpcDefs::getSide(key); - Acts::Vector3 nominal_global_in = tGeometry->getGlobalPosition(key, cluster); - Acts::Vector3 global_in = tGeometry->getGlobalPosition(key, cluster); - double cluster_crossing_corrected_z= TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); - double crossing_correction = cluster_crossing_corrected_z - global_in.z(); - global_in.z() = cluster_crossing_corrected_z; - - std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl - << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) << std::endl - << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) << std::endl - << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl - << " distortion " << global(0)-global_in(0) << " " - << global(1) - global_in(1) << " " << global(2) - global_in(2) - << " cluster crossing z correction " << crossing_correction - << std::endl; - } - } + if (m_verbosity > 2) + { + unsigned int this_layer = TrkrDefs::getLayer(key); + if (this_layer == 28) + { + unsigned int this_side = TpcDefs::getSide(key); + Acts::Vector3 nominal_global_in = tGeometry->getGlobalPosition(key, cluster); + Acts::Vector3 global_in = tGeometry->getGlobalPosition(key, cluster); + double cluster_crossing_corrected_z = TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); + double crossing_correction = cluster_crossing_corrected_z - global_in.z(); + global_in.z() = cluster_crossing_corrected_z; + + std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl + << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) << std::endl + << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) << std::endl + << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl + << " distortion " << global(0) - global_in(0) << " " + << global(1) - global_in(1) << " " << global(2) - global_in(2) + << " cluster crossing z correction " << crossing_correction + << std::endl; + } + } } // add the global positions to a vector to give to the cluster mover @@ -405,10 +434,10 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } // loop over global positions returned by cluster mover - for(auto&& [cluskey, global] : global_moved) + for (auto&& [cluskey, global] : global_moved) { // std::cout << "Global moved: " << global.x() << " " << global.y() << " " << global.z() << std::endl; - + if (m_ignoreLayer.contains(TrkrDefs::getLayer(cluskey))) { if (m_verbosity > 3) @@ -421,19 +450,24 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( auto cluster = clusterContainer->findCluster(cluskey); Surface surf = tGeometry->maps().getSurface(cluskey, cluster); - if(std::isnan(global.x()) || std::isnan(global.y())) + if (std::isnan(global.x()) || std::isnan(global.y())) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - invalid position" - << " key: " << cluskey - << " layer: " << (int)TrkrDefs::getLayer(cluskey) - << " position: " << global - << std::endl; + << " key: " << cluskey + << " layer: " << (int) TrkrDefs::getLayer(cluskey) + << " position: " << global + << std::endl; } // if this is a TPC cluster, the crossing correction may have moved it across the central membrane, check the surface auto trkrid = TrkrDefs::getTrkrId(cluskey); if (trkrid == TrkrDefs::tpcId) { + if (cluster->getEdge() > m_cluster_edge_rejection) + { + continue; + } + TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); TrkrDefs::subsurfkey new_subsurfkey = 0; surf = tGeometry->get_tpc_surface_from_coords(hitsetkey, global, new_subsurfkey); @@ -441,7 +475,10 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( if (!surf) { - if(m_verbosity > 2) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Failed to find surface for cluskey " << cluskey << std::endl; } + if (m_verbosity > 2) + { + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Failed to find surface for cluskey " << cluskey << std::endl; + } continue; } @@ -449,7 +486,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( Acts::Vector2 localPos; global *= Acts::UnitConstants::cm; // we want mm for transformations - Acts::Vector3 normal = surf->normal(tGeometry->geometry().getGeoContext(),Acts::Vector3(1,1,1), Acts::Vector3(1,1,1)); + Acts::Vector3 normal = surf->normal(tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); auto local = surf->globalToLocal(tGeometry->geometry().getGeoContext(), global, normal); if (local.ok()) @@ -458,11 +495,14 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } else { - if(m_verbosity > 2) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Taking manual calculation for global to local " << std::endl; } + if (m_verbosity > 2) + { + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Taking manual calculation for global to local " << std::endl; + } /// otherwise take the manual calculation for the TPC // doing it this way just avoids the bounds check that occurs in the surface class method - Acts::Vector3 loct = surf->transform(tGeometry->geometry().getGeoContext()).inverse() * global ; // global is in mm + Acts::Vector3 loct = surf->transform(tGeometry->geometry().getGeoContext()).inverse() * global; // global is in mm loct /= Acts::UnitConstants::cm; localPos(0) = loct(0); @@ -474,22 +514,22 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Cluster " << cluskey << " cluster global after mover: " << global << std::endl; std::cout << "MakeSourceLinks::getSourceLinksClusterMover - stored: cluster local X " << cluster->getLocalX() << " cluster local Y " << cluster->getLocalY() << std::endl; - const Acts::Vector2 localTest = tGeometry->getLocalCoords(cluskey, cluster); // cm + const Acts::Vector2 localTest = tGeometry->getLocalCoords(cluskey, cluster); // cm std::cout << "MakeSourceLinks::getSourceLinksClusterMover - localTest from getLocalCoords: " << localTest << std::endl; std::cout << "MakeSourceLinks::getSourceLinksClusterMover - new from inverse transform of cluster global after mover: " << std::endl; - const Acts::Vector3 globalTest = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localTest*Acts::UnitConstants::cm, normal); - std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from localTest: " << Acts::Vector3(globalTest/Acts::UnitConstants::cm) << std::endl; + const Acts::Vector3 globalTest = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localTest * Acts::UnitConstants::cm, normal); + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from localTest: " << Acts::Vector3(globalTest / Acts::UnitConstants::cm) << std::endl; - const Acts::Vector3 globalNew = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localPos*Acts::UnitConstants::cm, normal); - std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from new local: " << Acts::Vector3(globalNew/Acts::UnitConstants::cm) << std::endl; + const Acts::Vector3 globalNew = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localPos * Acts::UnitConstants::cm, normal); + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from new local: " << Acts::Vector3(globalNew / Acts::UnitConstants::cm) << std::endl; } Acts::ActsVector<2> loc; loc[Acts::eBoundLoc0] = localPos(0) * Acts::UnitConstants::cm; loc[Acts::eBoundLoc1] = localPos(1) * Acts::UnitConstants::cm; std::array indices = - {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; + {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero(); @@ -501,7 +541,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; ActsSourceLink::Index index = measurements.size(); - + SourceLink sl(surf->geometryId(), index, cluskey); Acts::SourceLink actsSL{sl}; Acts::Measurement meas(actsSL, indices, loc, cov); @@ -528,9 +568,9 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( auto SLTime = SLTrackTimer.get_accumulated_time(); if (m_verbosity > 1) - { - std::cout << "PHMakeSourceLinks::getSourceLinksClusterMover - ActsTrkFitter Source Links generation time: " + { + std::cout << "PHMakeSourceLinks::getSourceLinksClusterMover - ActsTrkFitter Source Links generation time: " << SLTime << std::endl; - } + } return sourcelinks; } diff --git a/offline/packages/trackreco/MakeSourceLinks.h b/offline/packages/trackreco/MakeSourceLinks.h index 8acf4f8272..c0d5a31683 100644 --- a/offline/packages/trackreco/MakeSourceLinks.h +++ b/offline/packages/trackreco/MakeSourceLinks.h @@ -1,17 +1,17 @@ #ifndef TRACKRECO_MAKESOURCELINKS_H #define TRACKRECO_MAKESOURCELINKS_H -#include #include #include -#include #include +#include +#include #include /// Acts includes to create all necessary definitions -#include #include +#include #include @@ -40,51 +40,47 @@ class TrackSeed; class MakeSourceLinks { public: - MakeSourceLinks() = default; + MakeSourceLinks() = default; - void initialize(PHG4TpcGeomContainer* cellgeo); + void initialize(PHG4TpcGeomContainer* cellgeo); - void setVerbosity(int verbosity) {m_verbosity = verbosity;} - - void set_pp_mode(bool ispp) { m_pp_mode = ispp; } + void setVerbosity(int verbosity) { m_verbosity = verbosity; } + void set_pp_mode(bool ispp) { m_pp_mode = ispp; } + void set_cluster_edge_rejection(int edge) { m_cluster_edge_rejection = edge; } void ignoreLayer(int layer) { m_ignoreLayer.insert(layer); } SourceLinkVec getSourceLinks( - TrackSeed* /*seed*/, - ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, - TrkrClusterContainer* /*clusters*/, - ActsGeometry* /*geometry*/, - const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, - alignmentTransformationContainer* /*transformMapTransient*/, - std::set< Acts::GeometryIdentifier>& /*transient_id_set*/, - short int /*crossing*/); + TrackSeed* /*seed*/, + ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, + TrkrClusterContainer* /*clusters*/, + ActsGeometry* /*geometry*/, + const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, + alignmentTransformationContainer* /*transformMapTransient*/, + std::set& /*transient_id_set*/, + short int /*crossing*/); void resetTransientTransformMap( - alignmentTransformationContainer* /*transformMapTransient*/, - std::set< Acts::GeometryIdentifier>& /*transient_id_set*/, - ActsGeometry* /*tGeometry*/ ); + alignmentTransformationContainer* /*transformMapTransient*/, + std::set& /*transient_id_set*/, + ActsGeometry* /*tGeometry*/); SourceLinkVec getSourceLinksClusterMover( - TrackSeed* /*seed*/, - ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, - TrkrClusterContainer* /*clusters*/, - ActsGeometry* /*geometry*/, - const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, - short int crossing - ); + TrackSeed* /*seed*/, + ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, + TrkrClusterContainer* /*clusters*/, + ActsGeometry* /*geometry*/, + const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, + short int crossing); private: int m_verbosity = 0; bool m_pp_mode = false; std::set m_ignoreLayer; - + int m_cluster_edge_rejection = 0; TpcClusterMover _clusterMover; ClusterErrorPara _ClusErrPara; - - }; - #endif diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 2ca1426301..5a92307b81 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -145,6 +145,7 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) chi2Cuts.insert(std::make_pair(14, 9)); chi2Cuts.insert(std::make_pair(16, 4)); m_outlierFinder.chi2Cuts = chi2Cuts; + if (m_useOutlierFinder) { m_outlierFinder.m_tGeometry = m_tGeometry; @@ -439,6 +440,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) makeSourceLinks.initialize(_tpccellgeo); makeSourceLinks.setVerbosity(Verbosity()); makeSourceLinks.set_pp_mode(m_pp_mode); + makeSourceLinks.set_cluster_edge_rejection(m_cluster_edge_rejection); for (const auto& layer : m_ignoreLayer) { makeSourceLinks.ignoreLayer(layer); diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index cca5095c79..09a8ab9d1d 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -144,7 +144,7 @@ class PHActsTrkFitter : public SubsysReco void ignoreLayer(int layer) { m_ignoreLayer.insert(layer); } void setTrkrClusterContainerName(const std::string& name) { m_clusterContainerName = name; } void setDirectNavigation(bool flag) { m_directNavigation = flag; } - + void setClusterEdgeRejection(int edge ) { m_cluster_edge_rejection = edge; } private: /// Get all the nodes int getNodes(PHCompositeNode* topNode); @@ -244,6 +244,7 @@ class PHActsTrkFitter : public SubsysReco // name of TRKR_CLUSTER container std::string m_clusterContainerName = "TRKR_CLUSTER"; + int m_cluster_edge_rejection = 0; //!@name evaluator //@{ bool m_actsEvaluator = false; From febf1e238dcb3500c420e031ca61d3eee43297db Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 20 Jan 2026 12:40:07 -0500 Subject: [PATCH 092/866] Add type 38: 60GeV jets --- offline/framework/frog/CreateFileList.pl | 32 +++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 19b552b764..19456cbc09 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -75,7 +75,8 @@ "34" => "JS pythia8 Jet ptmin = 50GeV", "35" => "JS pythia8 Jet ptmin = 70GeV", "36" => "JS pythia8 Jet ptmin = 5GeV", - "37" => "hijing O+O (0-15fm)" + "37" => "hijing O+O (0-15fm)", + "38" => "JS pythia8 Jet ptmin = 60GeV", ); my %pileupdesc = ( @@ -941,6 +942,35 @@ $pileupstring = $AuAu_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 38) + { + $embedok = 1; + $filenamestring = "pythia8_Jet60"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { From 6ce581e35841fffaf9e131986ede27c969427ed3 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 20 Jan 2026 13:46:11 -0500 Subject: [PATCH 093/866] clang-tidy and clang-format --- offline/packages/trackreco/MakeSourceLinks.cc | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/offline/packages/trackreco/MakeSourceLinks.cc b/offline/packages/trackreco/MakeSourceLinks.cc index 5bb00293a9..f9038d182e 100644 --- a/offline/packages/trackreco/MakeSourceLinks.cc +++ b/offline/packages/trackreco/MakeSourceLinks.cc @@ -97,7 +97,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( ++clusIter) { auto key = *clusIter; - auto cluster = clusterContainer->findCluster(key); + auto* cluster = clusterContainer->findCluster(key); if (!cluster) { if (m_verbosity > 0) @@ -106,7 +106,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( } continue; } - else if (m_verbosity > 0) + if (m_verbosity > 0) { std::cout << "MakeSourceLinks: Found cluster with key " << key << " for track seed " << std::endl; } @@ -163,7 +163,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( auto this_surf = tGeometry->maps().getSurface(key, cluster); Acts::GeometryIdentifier id = this_surf->geometryId(); - auto check_cluster = clusterContainer->findCluster(key); + auto* check_cluster = clusterContainer->findCluster(key); Acts::Vector2 check_local2d = tGeometry->getLocalCoords(key, check_cluster) * Acts::UnitConstants::cm; // need mm Acts::Vector3 check_local3d(check_local2d(0), check_local2d(1), 0); Acts::GeometryContext temp_transient_geocontext; @@ -224,10 +224,10 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( } // get local coordinates (TPC time needs conversion to cm) - auto cluster = clusterContainer->findCluster(cluskey); - if(TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId) + auto* cluster = clusterContainer->findCluster(cluskey); + if (TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId) { - if(cluster->getEdge() > m_cluster_edge_rejection) + if (cluster->getEdge() > m_cluster_edge_rejection) { continue; } @@ -247,7 +247,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( // get errors Acts::Vector3 global = tGeometry->getGlobalPosition(cluskey, cluster); double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); - auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey); + auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, clusRadius, cluskey); cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; @@ -284,7 +284,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( } sourcelinks.push_back(actsSL); - measurements.push_back(meas); + measurements.emplace_back(meas); } SLTrackTimer.stop(); @@ -301,7 +301,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( void MakeSourceLinks::resetTransientTransformMap( alignmentTransformationContainer* transformMapTransient, std::set& transient_id_set, - ActsGeometry* tGeometry) + ActsGeometry* tGeometry) const { if (m_verbosity > 2) { @@ -309,7 +309,7 @@ void MakeSourceLinks::resetTransientTransformMap( } // loop over modifiedTransformSet and replace transient elements modified for the last track with the default transforms - for (auto& id : transient_id_set) + for (const auto& id : transient_id_set) { auto ctxt = tGeometry->geometry().getGeoContext(); alignmentTransformationContainer* transformMap = ctxt.get(); @@ -361,7 +361,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( ++clusIter) { auto key = *clusIter; - auto cluster = clusterContainer->findCluster(key); + auto* cluster = clusterContainer->findCluster(key); if (!cluster) { if (m_verbosity > 0) @@ -421,7 +421,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } // add the global positions to a vector to give to the cluster mover - global_raw.emplace_back(std::make_pair(key, global)); + global_raw.emplace_back(key, global); } // end loop over clusters here @@ -448,7 +448,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( continue; } - auto cluster = clusterContainer->findCluster(cluskey); + auto* cluster = clusterContainer->findCluster(cluskey); Surface surf = tGeometry->maps().getSurface(cluskey, cluster); if (std::isnan(global.x()) || std::isnan(global.y())) { @@ -464,10 +464,10 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( if (trkrid == TrkrDefs::tpcId) { if (cluster->getEdge() > m_cluster_edge_rejection) - { - continue; - } - + { + continue; + } + TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); TrkrDefs::subsurfkey new_subsurfkey = 0; surf = tGeometry->get_tpc_surface_from_coords(hitsetkey, global, new_subsurfkey); @@ -534,7 +534,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero(); double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); - auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey); + auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, clusRadius, cluskey); cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; @@ -561,7 +561,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } sourcelinks.push_back(actsSL); - measurements.push_back(meas); + measurements.emplace_back(meas); } SLTrackTimer.stop(); From 435537f4adb086205857a252f97ee8911af17037 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 20 Jan 2026 13:47:27 -0500 Subject: [PATCH 094/866] clang-tidy --- offline/packages/trackreco/MakeSourceLinks.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/MakeSourceLinks.h b/offline/packages/trackreco/MakeSourceLinks.h index c0d5a31683..d22acc4881 100644 --- a/offline/packages/trackreco/MakeSourceLinks.h +++ b/offline/packages/trackreco/MakeSourceLinks.h @@ -63,7 +63,7 @@ class MakeSourceLinks void resetTransientTransformMap( alignmentTransformationContainer* /*transformMapTransient*/, std::set& /*transient_id_set*/, - ActsGeometry* /*tGeometry*/); + ActsGeometry* /*tGeometry*/) const; SourceLinkVec getSourceLinksClusterMover( TrackSeed* /*seed*/, From 7c3201954d3f506ad240cb3af4004d9e3e31be08 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 20 Jan 2026 13:48:10 -0500 Subject: [PATCH 095/866] take first and last cluster in charge sign determination --- offline/packages/trackbase_historic/TrackSeedHelper.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeedHelper.cc b/offline/packages/trackbase_historic/TrackSeedHelper.cc index 99a9198811..0fba4fb80a 100644 --- a/offline/packages/trackbase_historic/TrackSeedHelper.cc +++ b/offline/packages/trackbase_historic/TrackSeedHelper.cc @@ -142,8 +142,8 @@ void TrackSeedHelper::circleFitByTaubin( float qOverR = 1./r; /// Set the charge - const auto& firstpos = positions_2d.at(0); - const auto& secondpos = positions_2d.at(1); + const auto& firstpos = *(positions_2d.begin()); + const auto& secondpos = *(positions_2d.rbegin()); const auto firstphi = atan2(firstpos.second, firstpos.first); const auto secondphi = atan2(secondpos.second, secondpos.first); From 300975c3c0c3f9a96bbd5051993ec45743bd067f Mon Sep 17 00:00:00 2001 From: silas-gross Date: Tue, 20 Jan 2026 16:22:26 -0500 Subject: [PATCH 096/866] moved the ngood nevts to public variables to allow for better usage --- generators/Herwig/HepMCTrigger/HepMCJetTrigger.h | 4 ++-- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h index 67a1a4fbe5..74ee855493 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h @@ -47,6 +47,8 @@ class HepMCJetTrigger : public SubsysReco /// Called at the end of all processing. /// Reset + int n_evts{0}; + int n_good{0}; private: bool isGoodEvent(HepMC::GenEvent* e1); @@ -54,8 +56,6 @@ class HepMCJetTrigger : public SubsysReco int jetsAboveThreshold(const std::vector& jets) const; float threshold{0.}; int goal_event_number{1000}; - int n_evts{0}; - int n_good{0}; bool set_event_limit{false}; }; diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index 1b77724c0a..4900bad5ad 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -29,6 +29,8 @@ class HepMCParticleTrigger : public SubsysReco This is where you do the real work. */ int process_event(PHCompositeNode* topNode) override; + int n_evts{0}; + int n_good{0}; /// Clean up internals after each event. @@ -76,8 +78,6 @@ class HepMCParticleTrigger : public SubsysReco bool m_doStableParticleOnly{true}; float threshold{0.}; int goal_event_number{1000}; - int n_evts{0}; - int n_good{0}; bool set_event_limit{false}; float _theEtaHigh{1.1}; From 2f01ab562a041546fab06579c672cbacb2734568 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Tue, 20 Jan 2026 18:09:41 -0500 Subject: [PATCH 097/866] add functional fit --- offline/packages/CaloReco/CaloTowerBuilder.cc | 9 + offline/packages/CaloReco/CaloTowerBuilder.h | 29 ++ .../packages/CaloReco/CaloWaveformFitting.cc | 252 ++++++++++++++++++ .../packages/CaloReco/CaloWaveformFitting.h | 44 +++ .../CaloReco/CaloWaveformProcessing.cc | 17 ++ .../CaloReco/CaloWaveformProcessing.h | 30 +++ 6 files changed, 381 insertions(+) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 632cd8161d..a84706599d 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -75,6 +75,14 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) WaveformProcessing->set_bitFlipRecovery(m_dobitfliprecovery); } + // Set functional fit parameters + if (_processingtype == CaloWaveformProcessing::FUNCFIT) + { + WaveformProcessing->set_funcfit_type(m_funcfit_type); + WaveformProcessing->set_powerlaw_params(m_powerlaw_power, m_powerlaw_decay); + WaveformProcessing->set_doubleexp_params(m_doubleexp_power, m_doubleexp_peaktime1, m_doubleexp_peaktime2, m_doubleexp_ratio); + } + if (m_dettype == CaloTowerDefs::CEMC) { m_detector = "CEMC"; @@ -476,6 +484,7 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) towerinfo->set_pedestal(processed_waveforms.at(idx).at(2)); towerinfo->set_chi2(processed_waveforms.at(idx).at(3)); bool SZS = isSZS(processed_waveforms.at(idx).at(1), processed_waveforms.at(idx).at(3)); + if (processed_waveforms.at(idx).at(4) == 0) { towerinfo->set_isRecovered(false); diff --git a/offline/packages/CaloReco/CaloTowerBuilder.h b/offline/packages/CaloReco/CaloTowerBuilder.h index cb22806903..0fc5694638 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.h +++ b/offline/packages/CaloReco/CaloTowerBuilder.h @@ -94,6 +94,26 @@ class CaloTowerBuilder : public SubsysReco m_dobitfliprecovery = dobitfliprecovery; } + // Functional fit options: 0 = PowerLawExp, 1 = PowerLawDoubleExp + void set_funcfit_type(int type) + { + m_funcfit_type = type; + } + + void set_powerlaw_params(double power, double decay) + { + m_powerlaw_power = power; + m_powerlaw_decay = decay; + } + + void set_doubleexp_params(double power, double peaktime1, double peaktime2, double ratio) + { + m_doubleexp_power = power; + m_doubleexp_peaktime1 = peaktime1; + m_doubleexp_peaktime2 = peaktime2; + m_doubleexp_ratio = ratio; + } + void set_tbt_softwarezerosuppression(const std::string &url) { m_zsURL = url; @@ -150,6 +170,15 @@ class CaloTowerBuilder : public SubsysReco std::string m_directURL; std::string m_zsURL; std::string m_zs_fieldname{"zs_threshold"}; + + // Functional fit parameters + int m_funcfit_type{1}; // 0 = PowerLawExp, 1 = PowerLawDoubleExp + double m_powerlaw_power{4.0}; + double m_powerlaw_decay{1.5}; + double m_doubleexp_power{2.0}; + double m_doubleexp_peaktime1{5.0}; + double m_doubleexp_peaktime2{5.0}; + double m_doubleexp_ratio{0.3}; }; #endif // CALOTOWERBUILDER_H diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index f5163275a0..e84ec84874 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -619,3 +620,254 @@ float CaloWaveformFitting::psinc(float time, std::vector &vec_signal_samp return sum; } + +double CaloWaveformFitting::SignalShape_PowerLawExp(double *x, double *par) +{ + // par[0]: Amplitude + // par[1]: Sample Start (t0) + // par[2]: Power + // par[3]: Decay + // par[4]: Pedestal + double pedestal = par[4]; + if (x[0] < par[1]) + { + return pedestal; + } + double signal = par[0] * pow((x[0] - par[1]), par[2]) * exp(-(x[0] - par[1]) * par[3]); + return pedestal + signal; +} + +double CaloWaveformFitting::SignalShape_PowerLawDoubleExp(double *x, double *par) +{ + // par[0]: Amplitude + // par[1]: Sample Start (t0) + // par[2]: Power + // par[3]: Peak Time 1 + // par[4]: Pedestal + // par[5]: Amplitude ratio + // par[6]: Peak Time 2 + double pedestal = par[4]; + if (x[0] < par[1]) + { + return pedestal; + } + double signal = par[0] * pow((x[0] - par[1]), par[2]) * + (((1.0 - par[5]) / pow(par[3], par[2]) * exp(par[2])) * + exp(-(x[0] - par[1]) * (par[2] / par[3])) + + (par[5] / pow(par[6], par[2]) * exp(par[2])) * + exp(-(x[0] - par[1]) * (par[2] / par[6]))); + return pedestal + signal; +} + +std::vector> CaloWaveformFitting::calo_processing_funcfit(const std::vector> &chnlvector) +{ + std::vector> fit_values; + int nchnls = chnlvector.size(); + + for (int m = 0; m < nchnls; m++) + { + const std::vector &v = chnlvector.at(m); + int nsamples = v.size(); + + float amp = 0; + float time = 0; + float ped = 0; + float chi2 = std::numeric_limits::quiet_NaN(); + + // Handle zero-suppressed samples (2-sample case) + if (nsamples == _nzerosuppresssamples) + { + amp = v.at(1) - v.at(0); + time = std::numeric_limits::quiet_NaN(); + ped = v.at(0); + if (v.at(0) != 0 && v.at(1) == 0) + { + chi2 = 1000000; + } + fit_values.push_back({amp, time, ped, chi2, 0}); + continue; + } + + // Find peak position and estimate pedestal + float maxheight = 0; + int maxbin = 0; + for (int i = 0; i < nsamples; i++) + { + if (v.at(i) > maxheight) + { + maxheight = v.at(i); + maxbin = i; + } + } + + float pedestal = 1500; + if (maxbin > 4) + { + pedestal = 0.5 * (v.at(maxbin - 4) + v.at(maxbin - 5)); + } + else if (maxbin > 3) + { + pedestal = v.at(maxbin - 4); + } + else + { + pedestal = 0.5 * (v.at(nsamples - 3) + v.at(nsamples - 2)); + } + + // Software zero suppression check + if ((_bdosoftwarezerosuppression && v.at(6) - v.at(0) < _nsoftwarezerosuppression) || + (_maxsoftwarezerosuppression && maxheight - pedestal < _nsoftwarezerosuppression)) + { + amp = v.at(6) - v.at(0); + time = std::numeric_limits::quiet_NaN(); + ped = v.at(0); + if (v.at(0) != 0 && v.at(1) == 0) + { + chi2 = 1000000; + } + fit_values.push_back({amp, time, ped, chi2, 0}); + continue; + } + + // Create histogram for fitting + TH1F h("h_funcfit", "", nsamples, -0.5, nsamples - 0.5); + int ndata = 0; + for (int i = 0; i < nsamples; ++i) + { + if ((v.at(i) == 16383) && _handleSaturation) + { + continue; + } + h.SetBinContent(i + 1, v.at(i)); + h.SetBinError(i + 1, 1); + ndata++; + } + + // If too many saturated, use all data + if (ndata < (nsamples - 4)) + { + ndata = nsamples; + for (int i = 0; i < nsamples; ++i) + { + h.SetBinContent(i + 1, v.at(i)); + h.SetBinError(i + 1, 1); + } + } + + double fit_amp = 0; + double fit_time = 0; + double fit_ped = 0; + double chi2val = 0; + int npar = 0; + + if (m_funcfit_type == POWERLAWEXP) + { + // Create fit function with 5 parameters + TF1 f("f_powerlaw", SignalShape_PowerLawExp, 0, nsamples, 5); + npar = 5; + + // Set initial parameters + double risetime = m_powerlaw_power / m_powerlaw_decay; + double par[5]; + par[0] = maxheight - pedestal; // Amplitude + par[1] = maxbin - risetime; // t0 + if (par[1] < 0) + { + par[1] = 0; + } + par[2] = m_powerlaw_power; // Power + par[3] = m_powerlaw_decay; // Decay + par[4] = pedestal; // Pedestal + + f.SetParameters(par); + f.SetParLimits(0, (maxheight - pedestal) * 0.5, (maxheight - pedestal) * 10); + f.SetParLimits(1, 0, nsamples); + f.SetParLimits(2, 0, 10.0); + f.SetParLimits(3, 0, 10.0); + f.SetParLimits(4, pedestal - std::abs(maxheight - pedestal), pedestal + std::abs(maxheight - pedestal)); + + // Perform fit + h.Fit(&f, "QRN0W", "", 0, nsamples); + + // Calculate peak amplitude and time from fit parameters + // Peak height is (p0 * Power(p2/p3, p2)) / exp(p2) + fit_amp = (f.GetParameter(0) * pow(f.GetParameter(2) / f.GetParameter(3), f.GetParameter(2))) / exp(f.GetParameter(2)); + // Peak time is t0 + power/decay + fit_time = f.GetParameter(1) + f.GetParameter(2) / f.GetParameter(3); + fit_ped = f.GetParameter(4); + + // Calculate chi2 + for (int i = 0; i < nsamples; i++) + { + if (h.GetBinContent(i + 1) > 0) + { + double diff = h.GetBinContent(i + 1) - f.Eval(i); + chi2val += diff * diff; + } + } + } + else // POWERLAWDOUBLEEXP + { + // Create fit function with 7 parameters + TF1 f("f_doubleexp", SignalShape_PowerLawDoubleExp, 0, nsamples, 7); + npar = 7; + + // Set initial parameters + double risetime = 2.0; + double par[7]; + par[0] = (maxheight - pedestal) * 0.7; // Amplitude + par[1] = maxbin - risetime; // t0 + if (par[1] < 0) + { + par[1] = 0; + } + par[2] = m_doubleexp_power; // Power + par[3] = m_doubleexp_peaktime1; // Peak Time 1 + par[4] = pedestal; // Pedestal + par[5] = m_doubleexp_ratio; // Amplitude ratio + par[6] = m_doubleexp_peaktime2; // Peak Time 2 + + f.SetParameters(par); + f.SetParLimits(0, (maxheight - pedestal) * -1.5, (maxheight - pedestal) * 1.5); + f.SetParLimits(1, maxbin - 3 * risetime, maxbin + risetime); + f.SetParLimits(2, 1, 5.0); + f.SetParLimits(3, risetime * 0.5, risetime * 4); + f.SetParLimits(4, pedestal - std::abs(maxheight - pedestal), pedestal + std::abs(maxheight - pedestal)); + f.SetParLimits(5, 0, 1); + f.SetParLimits(6, risetime * 0.5, risetime * 4); + + // Perform fit + h.Fit(&f, "QRN0W", "", 0, nsamples); + + // Find peak by evaluating the function + double peakpos1 = f.GetParameter(3); + double peakpos2 = f.GetParameter(6); + double max_peakpos = f.GetParameter(1) + (peakpos1 > peakpos2 ? peakpos1 : peakpos2); + if (max_peakpos > nsamples - 1) + { + max_peakpos = nsamples - 1; + } + + fit_time = f.GetMaximumX(f.GetParameter(1), max_peakpos); + fit_amp = f.Eval(fit_time) - f.GetParameter(4); + fit_ped = f.GetParameter(4); + + // Calculate chi2 + for (int i = 0; i < nsamples; i++) + { + if (h.GetBinContent(i + 1) > 0) + { + double diff = h.GetBinContent(i + 1) - f.Eval(i); + chi2val += diff * diff; + } + } + } + + chi2val /= (ndata - npar); // divide by ndf + + fit_values.push_back({static_cast(fit_amp), static_cast(fit_time), + static_cast(fit_ped), static_cast(chi2val), 0}); + } + + return fit_values; +} diff --git a/offline/packages/CaloReco/CaloWaveformFitting.h b/offline/packages/CaloReco/CaloWaveformFitting.h index 1a9f887305..fcc6783d67 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.h +++ b/offline/packages/CaloReco/CaloWaveformFitting.h @@ -9,6 +9,12 @@ class TProfile; class CaloWaveformFitting { public: + enum FuncFitType + { + POWERLAWEXP = 0, + POWERLAWDOUBLEEXP = 1, + }; + CaloWaveformFitting() = default; ~CaloWaveformFitting(); @@ -61,9 +67,34 @@ class CaloWaveformFitting std::vector> calo_processing_templatefit(std::vector> chnlvector); static std::vector> calo_processing_fast(const std::vector> &chnlvector); std::vector> calo_processing_nyquist(const std::vector> &chnlvector); + std::vector> calo_processing_funcfit(const std::vector> &chnlvector); void initialize_processing(const std::string &templatefile); + // Power-law fit function: amplitude * (x-t0)^power * exp(-(x-t0)*decay) + pedestal + static double SignalShape_PowerLawExp(double *x, double *par); + // Double exponential power-law fit function + static double SignalShape_PowerLawDoubleExp(double *x, double *par); + + void set_funcfit_type(FuncFitType type) + { + m_funcfit_type = type; + } + + void set_powerlaw_params(double power, double decay) + { + m_powerlaw_power = power; + m_powerlaw_decay = decay; + } + + void set_doubleexp_params(double power, double peaktime1, double peaktime2, double ratio) + { + m_doubleexp_power = power; + m_doubleexp_peaktime1 = peaktime1; + m_doubleexp_peaktime2 = peaktime2; + m_doubleexp_ratio = ratio; + } + private: static void FastMax(float x0, float x1, float x2, float y0, float y1, float y2, float &xmax, float &ymax); std::vector NyquistInterpolation(std::vector &vec_signal_samples); @@ -97,5 +128,18 @@ class CaloWaveformFitting std::string url_template; std::string url_onnx; std::string m_model_name; + + // Functional fit type selector + FuncFitType m_funcfit_type{POWERLAWEXP}; + + // Power-law fit parameters + double m_powerlaw_power{4.0}; + double m_powerlaw_decay{1.5}; + + // Double exponential fit parameters + double m_doubleexp_power{2.0}; + double m_doubleexp_peaktime1{5.0}; + double m_doubleexp_peaktime2{5.0}; + double m_doubleexp_ratio{0.3}; }; #endif diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 4e51f71f45..3954cd608e 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -65,6 +65,19 @@ void CaloWaveformProcessing::initialize_processing() m_Fitter = new CaloWaveformFitting(); m_Fitter->initialize_processing(url_template); } + else if (m_processingtype == CaloWaveformProcessing::FUNCFIT) + { + m_Fitter = new CaloWaveformFitting(); + // Set functional fit type and parameters + m_Fitter->set_funcfit_type(static_cast(_funcfit_type)); + m_Fitter->set_powerlaw_params(_powerlaw_power, _powerlaw_decay); + m_Fitter->set_doubleexp_params(_doubleexp_power, _doubleexp_peaktime1, _doubleexp_peaktime2, _doubleexp_ratio); + if (_bdosoftwarezerosuppression) + { + m_Fitter->set_softwarezerosuppression(_bdosoftwarezerosuppression, _nsoftwarezerosuppression); + } + m_Fitter->set_handleSaturation(true); + } } std::vector> CaloWaveformProcessing::process_waveform(std::vector> waveformvector) @@ -91,6 +104,10 @@ std::vector> CaloWaveformProcessing::process_waveform(std::ve { fitresults = m_Fitter->calo_processing_nyquist(waveformvector); } + if (m_processingtype == CaloWaveformProcessing::FUNCFIT) + { + fitresults = m_Fitter->calo_processing_funcfit(waveformvector); + } return fitresults; } diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.h b/offline/packages/CaloReco/CaloWaveformProcessing.h index 8a5a5bbbe6..1ffa7aa265 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.h +++ b/offline/packages/CaloReco/CaloWaveformProcessing.h @@ -20,6 +20,7 @@ class CaloWaveformProcessing : public SubsysReco FAST = 3, NYQUIST = 4, TEMPLATE_NOSAT = 5, + FUNCFIT = 6, }; CaloWaveformProcessing() = default; @@ -75,6 +76,26 @@ class CaloWaveformProcessing : public SubsysReco _dobitfliprecovery = dobitfliprecovery; } + // Functional fit options: 0 = PowerLawExp, 1 = PowerLawDoubleExp + void set_funcfit_type(int type) + { + _funcfit_type = type; + } + + void set_powerlaw_params(double power, double decay) + { + _powerlaw_power = power; + _powerlaw_decay = decay; + } + + void set_doubleexp_params(double power, double peaktime1, double peaktime2, double ratio) + { + _doubleexp_power = power; + _doubleexp_peaktime1 = peaktime1; + _doubleexp_peaktime2 = peaktime2; + _doubleexp_ratio = ratio; + } + std::vector> process_waveform(std::vector> waveformvector); std::vector> calo_processing_ONNX(const std::vector> &chnlvector); @@ -108,6 +129,15 @@ class CaloWaveformProcessing : public SubsysReco std::string m_model_name{"CEMC_ONNX"}; std::array m_Onnx_factor{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; std::array m_Onnx_offset{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + + // Functional fit parameters + int _funcfit_type{0}; // 0 = PowerLawExp, 1 = PowerLawDoubleExp + double _powerlaw_power{4.0}; + double _powerlaw_decay{1.5}; + double _doubleexp_power{2.0}; + double _doubleexp_peaktime1{5.0}; + double _doubleexp_peaktime2{5.0}; + double _doubleexp_ratio{0.3}; }; #endif From 5334735d2a18c44a0d1737216fcf1cdb1d36e4fb Mon Sep 17 00:00:00 2001 From: Shuonli <71942661+Shuonli@users.noreply.github.com> Date: Tue, 20 Jan 2026 19:09:37 -0500 Subject: [PATCH 098/866] Update offline/packages/CaloReco/CaloWaveformFitting.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/CaloReco/CaloWaveformFitting.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index e84ec84874..fb793bb4eb 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -863,7 +863,15 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con } } - chi2val /= (ndata - npar); // divide by ndf + int ndf = ndata - npar; + if (ndf > 0) + { + chi2val /= ndf; + } + else + { + chi2val = std::numeric_limits::quiet_NaN(); + } fit_values.push_back({static_cast(fit_amp), static_cast(fit_time), static_cast(fit_ped), static_cast(chi2val), 0}); From 0296552dac10e4de6182cf5c8138940d1297436e Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Tue, 20 Jan 2026 22:37:26 -0500 Subject: [PATCH 099/866] clang-tidy fixes --- calibrations/tpc/dEdx/GlobaldEdxFitter.cc | 20 +++++------ calibrations/tpc/dEdx/GlobaldEdxFitter.h | 8 ++--- calibrations/tpc/dEdx/bethe_bloch.h | 44 +++++++++++------------ calibrations/tpc/dEdx/dEdxFitter.cc | 18 +++++----- calibrations/tpc/dEdx/dEdxFitter.h | 26 ++++++++------ calibrations/tpc/dEdx/test_sample_size.C | 23 ++++++++---- 6 files changed, 77 insertions(+), 62 deletions(-) diff --git a/calibrations/tpc/dEdx/GlobaldEdxFitter.cc b/calibrations/tpc/dEdx/GlobaldEdxFitter.cc index 8fa5045cba..1cefa44dcd 100644 --- a/calibrations/tpc/dEdx/GlobaldEdxFitter.cc +++ b/calibrations/tpc/dEdx/GlobaldEdxFitter.cc @@ -50,9 +50,9 @@ void GlobaldEdxFitter::processResidualData(const std::string& infile, size_t ntr std::cout << entry << std::endl; } t->GetEntry(entry); - if(nmaps>0 && nintt>0 && fabs(eta)<1. && dcaxy<0.5 && ntpc>30) + if(nmaps>0 && nintt>0 && std::fabs(eta)<1. && dcaxy<0.5 && ntpc>30) { - p.push_back(sqrt(px*px+py*py+pz*pz)); + p.push_back(std::sqrt(px*px+py*py+pz*pz)); dEdx.push_back(dedx); } } @@ -172,28 +172,28 @@ double GlobaldEdxFitter::get_fitquality(double norm, double ZS_loss) if(pi_dist @@ -31,21 +31,21 @@ namespace dedx_constants // Bethe-Bloch fit function, vs. betagamma // A = normalization constant, equal to (ADC conversion)*4pi*n*Z^2*e^4/(m_e*c^2*4pi*epsilon_0^2) // B = A*(ln(2*m_e/I)-1) - (zero-suppression loss factor) -inline const double bethe_bloch_new(const double betagamma, const double A, const double B, const double C) +inline double bethe_bloch_new(const double betagamma, const double A, const double B, const double C) { const double beta = betagamma/sqrt(1.+betagamma*betagamma); return A/(beta*beta)*TMath::Log(betagamma) + A/(beta*beta)*B - A - C; } -inline const double bethe_bloch_new_2D(const double betagamma, const double A, const double B) +inline double bethe_bloch_new_2D(const double betagamma, const double A, const double B) { const double beta = betagamma/sqrt(1.+betagamma*betagamma); return A/(beta*beta)*(2.*TMath::Log(2.*dedx_constants::m_e/dedx_constants::sphenix_I * betagamma) - beta*beta) - B; } -inline const double bethe_bloch_new_1D(const double betagamma, const double A) +inline double bethe_bloch_new_1D(const double betagamma, const double A) { const double beta = betagamma/sqrt(1.+betagamma*betagamma); @@ -53,7 +53,7 @@ inline const double bethe_bloch_new_1D(const double betagamma, const double A) } // dE/dx for one gas species, up to normalization -inline const double bethe_bloch_species(const double betagamma, const double I) +inline double bethe_bloch_species(const double betagamma, const double I) { const double m_e = 511e3; // eV @@ -63,14 +63,14 @@ inline const double bethe_bloch_species(const double betagamma, const double I) } // dE/dx for TPC gas mixture, up to normalization -inline const double bethe_bloch_total(const double betagamma) +inline double bethe_bloch_total(const double betagamma) { return dedx_constants::ar_frac * bethe_bloch_species(betagamma,dedx_constants::ar_I) + dedx_constants::cf4_frac * bethe_bloch_species(betagamma,dedx_constants::cf4_I) + dedx_constants::isobutane_frac * bethe_bloch_species(betagamma,dedx_constants::isobutane_I); } -inline Double_t bethe_bloch_new_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_new_wrapper(const Double_t* const x, const Double_t* const par) { Double_t betagamma = x[0]; Double_t A = par[0]; @@ -80,7 +80,7 @@ inline Double_t bethe_bloch_new_wrapper(Double_t* x, Double_t* par) return bethe_bloch_new(betagamma,A,B,C); } -inline Double_t bethe_bloch_new_2D_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_new_2D_wrapper(const Double_t* const x, const Double_t* const par) { Double_t betagamma = x[0]; Double_t A = par[0]; @@ -89,7 +89,7 @@ inline Double_t bethe_bloch_new_2D_wrapper(Double_t* x, Double_t* par) return bethe_bloch_new_2D(betagamma,A,B); } -inline Double_t bethe_bloch_new_1D_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_new_1D_wrapper(const Double_t* const x, const Double_t* const par) { Double_t betagamma = x[0]; Double_t A = par[0]; @@ -98,7 +98,7 @@ inline Double_t bethe_bloch_new_1D_wrapper(Double_t* x, Double_t* par) } // wrapper function for TF1 constructor, for fitting -inline Double_t bethe_bloch_wrapper(Double_t* ln_bg, Double_t* par) +inline Double_t bethe_bloch_wrapper(const Double_t* const ln_bg, const Double_t* const par) { Double_t betagamma = exp(ln_bg[0]); @@ -107,7 +107,7 @@ inline Double_t bethe_bloch_wrapper(Double_t* ln_bg, Double_t* par) return norm * bethe_bloch_total(betagamma); } -inline Double_t bethe_bloch_vs_p_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper(const Double_t* const x, const Double_t* const par) { Double_t p = x[0]; Double_t norm = par[0]; @@ -116,7 +116,7 @@ inline Double_t bethe_bloch_vs_p_wrapper(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m); } -inline Double_t bethe_bloch_vs_logp_wrapper(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper(const Double_t* const x, const Double_t* const par) { Double_t p = pow(10.,x[0]); Double_t norm = par[0]; @@ -125,7 +125,7 @@ inline Double_t bethe_bloch_vs_logp_wrapper(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m); } -inline Double_t bethe_bloch_vs_p_wrapper_ZS(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_ZS(const Double_t* const x, const Double_t* const par) { Double_t p = x[0]; Double_t norm = par[0]; @@ -135,7 +135,7 @@ inline Double_t bethe_bloch_vs_p_wrapper_ZS(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; } -inline Double_t bethe_bloch_vs_p_wrapper_new(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_new(const Double_t* const x, const Double_t* const par) { Double_t p = x[0]; Double_t A = par[0]; @@ -146,7 +146,7 @@ inline Double_t bethe_bloch_vs_p_wrapper_new(Double_t* x, Double_t* par) return bethe_bloch_new(fabs(p)/m,A,B,C); } -inline Double_t bethe_bloch_vs_p_wrapper_new_2D(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_new_2D(const Double_t* const x, const Double_t* const par) { Double_t p = x[0]; Double_t A = par[0]; @@ -156,7 +156,7 @@ inline Double_t bethe_bloch_vs_p_wrapper_new_2D(Double_t* x, Double_t* par) return bethe_bloch_new_2D(fabs(p)/m,A,B); } -inline Double_t bethe_bloch_vs_p_wrapper_new_1D(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_p_wrapper_new_1D(const Double_t* const x, const Double_t* const par) { Double_t p = x[0]; Double_t A = par[0]; @@ -165,7 +165,7 @@ inline Double_t bethe_bloch_vs_p_wrapper_new_1D(Double_t* x, Double_t* par) return bethe_bloch_new_1D(fabs(p)/m,A); } -inline Double_t bethe_bloch_vs_logp_wrapper_ZS(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper_ZS(const Double_t* const x, const Double_t* const par) { Double_t p = pow(10.,x[0]); Double_t norm = par[0]; @@ -175,7 +175,7 @@ inline Double_t bethe_bloch_vs_logp_wrapper_ZS(Double_t* x, Double_t* par) return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; } -inline Double_t bethe_bloch_vs_logp_wrapper_new(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper_new(const Double_t* const x, const Double_t* const par) { Double_t p = pow(10.,x[0]); Double_t A = par[0]; @@ -186,7 +186,7 @@ inline Double_t bethe_bloch_vs_logp_wrapper_new(Double_t* x, Double_t* par) return bethe_bloch_new(fabs(p)/m,A,B,C); } -inline Double_t bethe_bloch_vs_logp_wrapper_new_1D(Double_t* x, Double_t* par) +inline Double_t bethe_bloch_vs_logp_wrapper_new_1D(const Double_t* const x, const Double_t* const par) { Double_t p = pow(10.,x[0]); Double_t A = par[0]; @@ -197,7 +197,7 @@ inline Double_t bethe_bloch_vs_logp_wrapper_new_1D(Double_t* x, Double_t* par) // ratio of dE/dx between two particle species at the same momentum // (useful for dE/dx peak fits) -inline const double dedx_ratio(const double p, const double m1, const double m2) +inline double dedx_ratio(const double p, const double m1, const double m2) { const double betagamma1 = fabs(p)/m1; const double betagamma2 = fabs(p)/m2; @@ -205,4 +205,4 @@ inline const double dedx_ratio(const double p, const double m1, const double m2) return bethe_bloch_total(betagamma1)/bethe_bloch_total(betagamma2); } -#endif // BETHE_BLOCH_H +#endif // BETHE_BLOCH_H_ diff --git a/calibrations/tpc/dEdx/dEdxFitter.cc b/calibrations/tpc/dEdx/dEdxFitter.cc index 0f03bae44e..e46004624a 100644 --- a/calibrations/tpc/dEdx/dEdxFitter.cc +++ b/calibrations/tpc/dEdx/dEdxFitter.cc @@ -18,10 +18,10 @@ dEdxFitter::dEdxFitter(const std::string &name): } //___________________________________ -int dEdxFitter::InitRun(PHCompositeNode *topNode) +int dEdxFitter::InitRun(PHCompositeNode * /*topNode*/) { std::cout << PHWHERE << " Opening file " << _outfile << std::endl; - PHTFileServer::get().open( _outfile, "RECREATE"); + outf = new TFile( _outfile.c_str(), "RECREATE"); return 0; } @@ -44,13 +44,13 @@ int dEdxFitter::process_event(PHCompositeNode *topNode) std::cout << "event " << _event << std::endl; } - process_tracks(topNode); + process_tracks(); return 0; } //_____________________________________ -void dEdxFitter::process_tracks(PHCompositeNode *topNode) +void dEdxFitter::process_tracks() { for(const auto &[key, track] : *_trackmap) @@ -93,7 +93,7 @@ void dEdxFitter::process_tracks(PHCompositeNode *topNode) int nintt = std::get<1>(nclus); int ntpc = std::get<2>(nclus); - if(nmaps>=nmaps_cut && nintt>=nintt_cut && ntpc>=ntpc_cut && fabs(track->get_eta())=nmaps_cut && nintt>=nintt_cut && ntpc>=ntpc_cut && std::fabs(track->get_eta())addTrack(get_dedx(track),track->get_p()); } @@ -202,15 +202,13 @@ void dEdxFitter::GetNodes(PHCompositeNode *topNode) } //______________________________________ -int dEdxFitter::End(PHCompositeNode *topNode) +int dEdxFitter::End(PHCompositeNode * /*topNode*/) { if(minima.empty()) { minima.push_back(fitter->get_minimum()); } - PHTFileServer::get().cd( _outfile ); - double avg_minimum = 0.; for(double m : minima) { @@ -218,6 +216,8 @@ int dEdxFitter::End(PHCompositeNode *topNode) } avg_minimum /= (double)minima.size(); + outf->cd(); + TF1* pi_band = new TF1("pi_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); pi_band->SetParameter(0,avg_minimum); pi_band->SetParameter(1,dedx_constants::m_pi); @@ -243,5 +243,7 @@ int dEdxFitter::End(PHCompositeNode *topNode) std::cout << "dEdxFitter extracted minimum: " << avg_minimum << std::endl; } + outf->Close(); + return 0; } diff --git a/calibrations/tpc/dEdx/dEdxFitter.h b/calibrations/tpc/dEdx/dEdxFitter.h index fda3d7c124..0dc4da0f0c 100644 --- a/calibrations/tpc/dEdx/dEdxFitter.h +++ b/calibrations/tpc/dEdx/dEdxFitter.h @@ -1,5 +1,5 @@ -#ifndef __DEDXFITTER_H__ -#define __DEDXFITTER_H__ +#ifndef DEDXFITTER_H_ +#define DEDXFITTER_H_ #include #include @@ -20,20 +20,25 @@ class dEdxFitter: public SubsysReco { public: //Default constructor - dEdxFitter(const std::string &name="dEdxFitter"); + explicit dEdxFitter(const std::string &name="dEdxFitter"); //Initialization, called for initialization - int InitRun(PHCompositeNode *); + int InitRun(PHCompositeNode * /*topNode*/) override; //Process Event, called for each event - int process_event(PHCompositeNode *); + int process_event(PHCompositeNode *topNode) override; //End, write and close files - int End(PHCompositeNode *); + int End(PHCompositeNode * /*topNode*/) override; //Change output filename void set_filename(const char* file) - { if(file) _outfile = file; } + { + if(file) + { + _outfile = file; + } + } void set_nmaps_cut(int nmaps) { nmaps_cut = nmaps; } @@ -56,6 +61,7 @@ class dEdxFitter: public SubsysReco private: //output filename std::string _outfile = "dedx_outfile.root"; + TFile* outf = nullptr; size_t _event = 0; SvtxTrackMap* _trackmap = nullptr; @@ -65,9 +71,9 @@ class dEdxFitter: public SubsysReco SvtxVertexMap* _vertexmap = nullptr; //Get all the nodes - void GetNodes(PHCompositeNode *); + void GetNodes(PHCompositeNode * /*topNode*/); - void process_tracks(PHCompositeNode *); + void process_tracks(); int nmaps_cut = 1; int nintt_cut = 1; @@ -85,4 +91,4 @@ class dEdxFitter: public SubsysReco }; -#endif //* __DEDXFITTER_H__ *// +#endif //* DEDXFITTER_H_ *// diff --git a/calibrations/tpc/dEdx/test_sample_size.C b/calibrations/tpc/dEdx/test_sample_size.C index df2a39b322..8464aba486 100644 --- a/calibrations/tpc/dEdx/test_sample_size.C +++ b/calibrations/tpc/dEdx/test_sample_size.C @@ -1,7 +1,13 @@ #include "GlobaldEdxFitter.h" #include +#include +#include +#include +#include + #include +#include void test_sample_size(const std::string& infile="/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/track_output_53877_*.root") { @@ -14,9 +20,6 @@ void test_sample_size(const std::string& infile="/sphenix/tg/tg01/hf/mjpeters/ru const float distribution_xmin = 5.; const float distribution_xmax = 26.; - - EColor base_color = kRed; - std::vector> fitvalues_all; std::vector fitvalues_avg; std::vector fitvalues_stdev; @@ -102,7 +105,7 @@ void test_sample_size(const std::string& infile="/sphenix/tg/tg01/hf/mjpeters/ru stdev += pow(fitvalues_all[i][j]-avg,2.); } stdev /= (float)n_samples; - stdev = sqrt(stdev); + stdev = std::sqrt(stdev); fitvalues_avg.push_back(avg); fitvalues_stdev.push_back(stdev); @@ -181,11 +184,17 @@ void test_sample_size(const std::string& infile="/sphenix/tg/tg01/hf/mjpeters/ru } TFile* fout = new TFile("dedxfitvals.root","RECREATE"); - for(auto& c : fluctuations) c->Write(); - for(auto& c : distributions) c->Write(); + for(auto& c : fluctuations) + { + c->Write(); + } + for(auto& c : distributions) + { + c->Write(); + } cg->Write(); cbg->Write(); cbands->Write(); cb->Write(); - + fout->Close(); } From db1ed97bfdb779c337d2f911b048296bf622cf2a Mon Sep 17 00:00:00 2001 From: Shuonli Date: Tue, 20 Jan 2026 23:08:17 -0500 Subject: [PATCH 100/866] change default --- offline/packages/CaloReco/CaloWaveformProcessing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.h b/offline/packages/CaloReco/CaloWaveformProcessing.h index 1ffa7aa265..b657459d6c 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.h +++ b/offline/packages/CaloReco/CaloWaveformProcessing.h @@ -131,7 +131,7 @@ class CaloWaveformProcessing : public SubsysReco std::array m_Onnx_offset{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; // Functional fit parameters - int _funcfit_type{0}; // 0 = PowerLawExp, 1 = PowerLawDoubleExp + int _funcfit_type{1}; // 0 = PowerLawExp, 1 = PowerLawDoubleExp double _powerlaw_power{4.0}; double _powerlaw_decay{1.5}; double _doubleexp_power{2.0}; From 0d8b5fc4fd281a852503bb9c20df765a061945b6 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Tue, 20 Jan 2026 23:39:00 -0500 Subject: [PATCH 101/866] clang tidy --- .../packages/CaloReco/CaloWaveformFitting.cc | 19 +++++-------------- .../CaloReco/CaloWaveformProcessing.cc | 2 +- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index fb793bb4eb..266072dfbe 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -22,7 +22,7 @@ #include #include -static ROOT::TThreadExecutor *t = new ROOT::TThreadExecutor(1);// NOLINT(misc-use-anonymous-namespace) +static ROOT::TThreadExecutor *t = new ROOT::TThreadExecutor(1); // NOLINT(misc-use-anonymous-namespace) double CaloWaveformFitting::template_function(double *x, double *par) { Double_t v1 = (par[0] * h_template->Interpolate(x[0] - par[1])) + par[2]; @@ -771,10 +771,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con double par[5]; par[0] = maxheight - pedestal; // Amplitude par[1] = maxbin - risetime; // t0 - if (par[1] < 0) - { - par[1] = 0; - } + par[1] = std::max(par[1], 0); par[2] = m_powerlaw_power; // Power par[3] = m_powerlaw_decay; // Decay par[4] = pedestal; // Pedestal @@ -816,11 +813,8 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con double risetime = 2.0; double par[7]; par[0] = (maxheight - pedestal) * 0.7; // Amplitude - par[1] = maxbin - risetime; // t0 - if (par[1] < 0) - { - par[1] = 0; - } + par[1] = maxbin - risetime; // t0 + par[1] = std::max(par[1], 0); par[2] = m_doubleexp_power; // Power par[3] = m_doubleexp_peaktime1; // Peak Time 1 par[4] = pedestal; // Pedestal @@ -843,10 +837,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con double peakpos1 = f.GetParameter(3); double peakpos2 = f.GetParameter(6); double max_peakpos = f.GetParameter(1) + (peakpos1 > peakpos2 ? peakpos1 : peakpos2); - if (max_peakpos > nsamples - 1) - { - max_peakpos = nsamples - 1; - } + max_peakpos = std::min(max_peakpos, nsamples - 1); fit_time = f.GetMaximumX(f.GetParameter(1), max_peakpos); fit_amp = f.Eval(fit_time) - f.GetParameter(4); diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 3954cd608e..057e427627 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -186,7 +186,7 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con { // downstream onnx does not have a static input vector API, // so we need to make a copy - std::vector vtmp(v); //NOLINT(performance-unnecessary-copy-initialization) + std::vector vtmp(v); // NOLINT(performance-unnecessary-copy-initialization) val = onnxInference(onnxmodule, vtmp, 1, onnxlib::n_input, onnxlib::n_output); unsigned int nvals = val.size(); for (unsigned int i = 0; i < nvals; i++) From 47d0f386183507d42c2bd37a2751c83b354d73b5 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Wed, 21 Jan 2026 10:43:48 -0500 Subject: [PATCH 102/866] make default consistant --- offline/packages/CaloReco/CaloWaveformFitting.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.h b/offline/packages/CaloReco/CaloWaveformFitting.h index fcc6783d67..648d6ab0fa 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.h +++ b/offline/packages/CaloReco/CaloWaveformFitting.h @@ -130,7 +130,7 @@ class CaloWaveformFitting std::string m_model_name; // Functional fit type selector - FuncFitType m_funcfit_type{POWERLAWEXP}; + FuncFitType m_funcfit_type{POWERLAWDOUBLEEXP}; // Power-law fit parameters double m_powerlaw_power{4.0}; From 74e453377053707818b5e21f0cbaf433349be06b Mon Sep 17 00:00:00 2001 From: silas-gross Date: Wed, 21 Jan 2026 13:30:49 -0500 Subject: [PATCH 103/866] Allowed for access to n_good and n_evts while keeping the variables private --- generators/Herwig/HepMCTrigger/HepMCJetTrigger.h | 6 ++++-- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h index 74ee855493..0917e42cdc 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h @@ -47,8 +47,8 @@ class HepMCJetTrigger : public SubsysReco /// Called at the end of all processing. /// Reset - int n_evts{0}; - int n_good{0}; + int getNevts(){return this->n_evts;} + int getNgood(){return this->n_good;} private: bool isGoodEvent(HepMC::GenEvent* e1); @@ -57,6 +57,8 @@ class HepMCJetTrigger : public SubsysReco float threshold{0.}; int goal_event_number{1000}; bool set_event_limit{false}; + int n_evts{0}; + int n_good{0}; }; #endif // HEPMCJETTRIGGER_H diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index 4900bad5ad..e0494cb3e7 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -29,8 +29,6 @@ class HepMCParticleTrigger : public SubsysReco This is where you do the real work. */ int process_event(PHCompositeNode* topNode) override; - int n_evts{0}; - int n_good{0}; /// Clean up internals after each event. @@ -68,6 +66,8 @@ class HepMCParticleTrigger : public SubsysReco void SetPzHighLow(double, double); void SetStableParticleOnly(bool b) { m_doStableParticleOnly = b; } + int getNevts(){return this->n_evts;} + int getNgood(){return this->n_good;} private: bool isGoodEvent(HepMC::GenEvent* e1); @@ -79,6 +79,8 @@ class HepMCParticleTrigger : public SubsysReco float threshold{0.}; int goal_event_number{1000}; bool set_event_limit{false}; + int n_evts{0}; + int n_good{0}; float _theEtaHigh{1.1}; float _theEtaLow{-1.1}; From b56ed66c1776e7b31936c2b5a5da349ceab6df0b Mon Sep 17 00:00:00 2001 From: silas-gross Date: Wed, 21 Jan 2026 16:16:17 -0500 Subject: [PATCH 104/866] event counter was in the wrong place --- generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc | 2 +- generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc index 792720a962..506799c874 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc @@ -31,7 +31,6 @@ HepMCJetTrigger::HepMCJetTrigger(float trigger_thresh, int n_incom, bool up_lim, int HepMCJetTrigger::process_event(PHCompositeNode* topNode) { // std::cout << "HepMCJetTrigger::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) @@ -39,6 +38,7 @@ int HepMCJetTrigger::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } } + n_evts++; PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); if (!phg) { diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index fe1193cba0..81d594e528 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -68,7 +68,6 @@ HepMCParticleTrigger::HepMCParticleTrigger(float trigger_thresh, int n_incom, bo 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) @@ -76,6 +75,7 @@ int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } } + n_evts++; bool good_event{false}; PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); if (!phg) From 9a19bb92da1535491aeb611f05c6161932b82d11 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Wed, 21 Jan 2026 22:25:40 -0500 Subject: [PATCH 105/866] cppcheck fix --- calibrations/tpc/dEdx/dEdxFitter.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calibrations/tpc/dEdx/dEdxFitter.cc b/calibrations/tpc/dEdx/dEdxFitter.cc index e46004624a..4277d3f059 100644 --- a/calibrations/tpc/dEdx/dEdxFitter.cc +++ b/calibrations/tpc/dEdx/dEdxFitter.cc @@ -11,10 +11,10 @@ //____________________________________ dEdxFitter::dEdxFitter(const std::string &name): - SubsysReco(name) + SubsysReco(name), + fitter(std::make_unique()) { //initialize - fitter = std::make_unique(); } //___________________________________ From d9bda1e7d5934eecebd02594e0d4454300f5b404 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 22 Jan 2026 12:17:46 -0500 Subject: [PATCH 106/866] fix pileup handling for oo in CreateFileList.pl --- offline/framework/frog/CreateFileList.pl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 19456cbc09..7e87a97278 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -149,6 +149,7 @@ my $AuAu_pileupstring; my $pp_pileupstring; my $pAu_pileupstring; +my $OO_pileupstring; my $pileupstring; if (! defined $runnumber && $#newargs >= 0) @@ -169,6 +170,7 @@ } my $pAu_bkgpileup = sprintf("_bkg_0_20fm"); my $AuAu_bkgpileup = sprintf("_bkg_0_10fm"); +my $OO_bkgpileup = sprintf("_bkg_0_15fm"); if ($pileup == 1) { $AuAu_pileupstring = sprintf("_50kHz%s",$AuAu_bkgpileup); @@ -194,12 +196,14 @@ else { $pp_pileupstring = sprintf("_%dkHz",$pileup); - $AuAu_pileupstring = sprintf("_%dkHz%s",$AuAu_bkgpileup); + $AuAu_pileupstring = sprintf("_%dkHz%s",$pileup, $AuAu_bkgpileup); + $OO_pileupstring = sprintf("_%dkHz%s",$pileup,$ OO_bkgpileup); } if (defined $nobkgpileup) { $pp_pileupstring = sprintf(""); $AuAu_pileupstring = sprintf(""); + $OO_pileupstring = sprintf(""); } my $embedok = 0; @@ -936,7 +940,7 @@ } else { - $filenamestring = sprintf("sHijing_OO_0_15fm%s",$AuAu_pileupstring); + $filenamestring = sprintf("sHijing_OO_0_15fm%s",$OO_pileupstring); } $notlike{$filenamestring} = ["pythia8" ,"single", "special"]; $pileupstring = $AuAu_pileupstring; From 45f47ca1d3d1268874fcc86e76782200a2880e7b Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 22 Jan 2026 12:26:17 -0500 Subject: [PATCH 107/866] fix typo --- offline/framework/frog/CreateFileList.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 7e87a97278..1f71d9897f 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -197,7 +197,7 @@ { $pp_pileupstring = sprintf("_%dkHz",$pileup); $AuAu_pileupstring = sprintf("_%dkHz%s",$pileup, $AuAu_bkgpileup); - $OO_pileupstring = sprintf("_%dkHz%s",$pileup,$ OO_bkgpileup); + $OO_pileupstring = sprintf("_%dkHz%s",$pileup,$OO_bkgpileup); } if (defined $nobkgpileup) { From 0efe275ed4d914af0f2d2b14031c29fa75a56cba Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Thu, 22 Jan 2026 13:40:37 -0500 Subject: [PATCH 108/866] Several updates: Add clusterlayer to clustertree, calculate cluster phi relative to beamspot, circle uses MVTX barrel center and not zero, changes strobe check to +/- 1, reduce MVTX cluster requirement to 2. --- .../TrackingDiagnostics/TrackResiduals.cc | 1 + .../trackreco/PHActsSiliconSeeding.cc | 75 +++++++++++++++---- .../packages/trackreco/PHActsSiliconSeeding.h | 21 ++++++ .../packages/trackreco/PHSimpleVertexFinder.h | 2 +- 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 894dfb4d3c..d029ded711 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -1728,6 +1728,7 @@ void TrackResiduals::createBranches() m_clustree->Branch("timebucket", &m_timebucket, "m_timebucket/I"); m_clustree->Branch("segtype", &m_segtype, "m_segtype/I"); m_clustree->Branch("tile", &m_tileid, "m_tileid/I"); + m_clustree->Branch("layer", &m_scluslayer, "m_scluslayer/I"); m_tree = new TTree("residualtree", "A tree with track, cluster, and state info"); m_tree->Branch("run", &m_runnumber, "m_runnumber/I"); diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index d4741a2ca9..e7a8cde39d 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -818,10 +818,12 @@ std::vector PHActsSiliconSeeding::findMatches( float avgtriplety = 0; for (auto& pos : clusters) { - avgtripletx += std::cos(std::atan2(pos(1), pos(0))); - avgtriplety += std::sin(std::atan2(pos(1), pos(0))); + + avgtripletx += std::cos(getPhiFromBeamSpot(pos(1), pos(0))); + avgtriplety += std::sin(getPhiFromBeamSpot(pos(1), pos(0))); } - float avgtripletphi = std::atan2(avgtriplety, avgtripletx); + float avgtripletphi = getPhiFromBeamSpot(avgtriplety, avgtripletx); + std::vector dummykeys = keys; std::vector dummyclusters = clusters; @@ -889,6 +891,9 @@ std::vector PHActsSiliconSeeding::findMatches( // get an estimate of the phi of the track at this layer // to know which hitsetkeys to look at float layerradius = 0; + float x0 = 0.0; + float y0 = 0.0; + if (layer > 2) { layerradius = m_geomContainerIntt->GetLayerGeom(layer)->get_radius(); @@ -896,12 +901,21 @@ std::vector PHActsSiliconSeeding::findMatches( else { layerradius = m_geomContainerMvtx->GetLayerGeom(layer)->get_radius(); + x0 = m_mvtx_x0; + y0 = m_mvtx_y0; } + float xfitradius_moved = fitpars[1] - x0; + float yfitradius_moved = fitpars[1] - y0; const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], - fitpars[1], fitpars[2]); - - float approximate_phi1 = atan2(yplus, xplus); - float approximate_phi2 = atan2(yminus, xminus); + xfitradius_moved, yfitradius_moved); + float xp = xplus + x0; + float xm = xminus + x0; + float yp = yplus + y0; + float ym = yminus + y0; + + + float approximate_phi1 = getPhiFromBeamSpot(yp, xp); + float approximate_phi2 = getPhiFromBeamSpot(ym, xm); float approximatephi = approximate_phi1; if (std::fabs(normPhi2Pi(approximate_phi2 - avgtripletphi)) < std::fabs(normPhi2Pi(approximate_phi1 - avgtripletphi))) { @@ -911,7 +925,7 @@ std::vector PHActsSiliconSeeding::findMatches( { auto surf = m_tGeometry->maps().getSiliconSurface(hitsetkey); auto surfcenter = surf->center(m_tGeometry->geometry().geoContext); - float surfphi = atan2(surfcenter.y(), surfcenter.x()); + float surfphi = getPhiFromBeamSpot(surfcenter.y(), surfcenter.x()); float dphi = normPhi2Pi(approximatephi - surfphi); /// Check that the projection is within some reasonable amount of the segment @@ -1141,10 +1155,11 @@ std::vector> PHActsSiliconSeeding::iterateLayers( float avgtriplety = 0; for (const auto& pos : positions) { - avgtripletx += std::cos(std::atan2(pos(1), pos(0))); - avgtriplety += std::sin(std::atan2(pos(1), pos(0))); + avgtripletx += std::cos(getPhiFromBeamSpot(pos(1), pos(0))); + avgtriplety += std::sin(getPhiFromBeamSpot(pos(1), pos(0))); } - float avgtripletphi = std::atan2(avgtriplety, avgtripletx); + + float avgtripletphi = getPhiFromBeamSpot(avgtriplety, avgtripletx); int layer34timebucket = std::numeric_limits::max(); for (const auto& key : keys) @@ -1155,13 +1170,31 @@ std::vector> PHActsSiliconSeeding::iterateLayers( } } + // move the fitted circle center the negative of the MVTX center position + float x0 = 0.0; // cm + float y0 = 0.0; for (int layer = startLayer; layer < endLayer; ++layer) { float layerradius = m_geomContainerIntt->GetLayerGeom(layer)->get_radius(); - const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], fitpars[1], fitpars[2]); + //const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], fitpars[1], fitpars[2]); + + if(layer < 3) + { + x0 = m_mvtx_x0; + y0 = m_mvtx_y0; + } - float approximate_phi1 = atan2(yplus, xplus); - float approximate_phi2 = atan2(yminus, xminus); + float xfitradius_moved = fitpars[1] - x0; + float yfitradius_moved = fitpars[2] - y0; + + const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], xfitradius_moved, yfitradius_moved); + + float xp = xplus + x0; + float xm = xminus + x0; + float yp = yplus + y0; + float ym = yminus + y0; + float approximate_phi1 = getPhiFromBeamSpot(yp, xp); + float approximate_phi2 = getPhiFromBeamSpot(ym, xm); float approximatephi = approximate_phi1; if (std::fabs(normPhi2Pi(approximate_phi2 - avgtripletphi)) < std::fabs(normPhi2Pi(approximate_phi1 - avgtripletphi))) { @@ -1171,7 +1204,7 @@ std::vector> PHActsSiliconSeeding::iterateLayers( { auto surf = m_tGeometry->maps().getSiliconSurface(hitsetkey); auto surfcenter = surf->center(m_tGeometry->geometry().geoContext); - float surfphi = atan2(surfcenter.y(), surfcenter.x()); + float surfphi = getPhiFromBeamSpot(surfcenter.y(), surfcenter.x()); if(Verbosity() > 5) { std::cout << "approximate phis " << approximate_phi1 << " " << approximate_phi2 << " using " << approximatephi @@ -1404,7 +1437,8 @@ std::vector PHActsSiliconSeeding::getSiliconSpacePoints(Acts: if (det == TrkrDefs::TrkrId::mvtxId) { auto strobeId = MvtxDefs::getStrobeId(hitsetkey); - if (strobeId != strobe) + //if (strobeId != strobe) + if (abs(strobeId - strobe) > 1) { continue; } @@ -1713,6 +1747,15 @@ double PHActsSiliconSeeding::normPhi2Pi(const double phi) return returnPhi; } +float PHActsSiliconSeeding::getPhiFromBeamSpot(float clusy, float clusx) +{ + // Calculate the phi value for (clusx, clusy) relative to the beam spot (x,y) position + + float phirel = std::atan2(clusy - m_beamSpoty, clusx - m_beamSpotx); + + return phirel; +} + void PHActsSiliconSeeding::largeGridSpacing(const bool spacing) { if (!spacing) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.h b/offline/packages/trackreco/PHActsSiliconSeeding.h index ea3fe2c1ad..f37937903b 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.h +++ b/offline/packages/trackreco/PHActsSiliconSeeding.h @@ -176,6 +176,16 @@ class PHActsSiliconSeeding : public SubsysReco { m_minSeedPt = pt; } + void set_mvtxCenterXY(const float X, const float Y) + { + m_mvtx_x0 = X; + m_mvtx_y0 = Y; + } + void set_beamSpotXY(const float X, const float Y) + { + m_beamSpotx = X; + m_beamSpoty = Y; + } /// A function to run the seeder with large (true) /// or small (false) grid spacing @@ -243,6 +253,8 @@ class PHActsSiliconSeeding : public SubsysReco short int getCrossingIntt(TrackSeed &si_track); std::vector getInttCrossings(TrackSeed &si_track); + float getPhiFromBeamSpot(float clusy, float clusx); + void createHistograms(); void writeHistograms(); double normPhi2Pi(const double phi); @@ -354,6 +366,15 @@ class PHActsSiliconSeeding : public SubsysReco float m_inttzSearchWin = 2.0; // default to one strip width double m_mvtxrPhiSearchWin = 0.2; float m_mvtxzSearchWin = 0.5; + + // collision point in sPHENIX coordinates, from vertex finder (pp run 3) + float m_beamSpotx = -0.072; // cm + float m_beamSpoty = 0.141; // cm + + // center of MVTX barrel in sPHENIX coordinates - default is for Run 3 pp + float m_mvtx_x0 = 0.6; // cm + float m_mvtx_y0 = -0.1; + /// Whether or not to use truth clusters in hit lookup bool m_useTruthClusters = false; diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index 6915693c4b..de5cff940b 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -91,7 +91,7 @@ class PHSimpleVertexFinder : public SubsysReco double _beamline_y_cut_hi = 0.2; double _qual_cut = 10.0; bool _require_mvtx = true; - unsigned int _nmvtx_required = 3; + unsigned int _nmvtx_required = 2; double _track_pt_cut = 0.0; double _outlier_cut = 0.015; From 3fa48da17176b340a61716e6a0ab2aa69ea4894d Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:18:18 -0500 Subject: [PATCH 109/866] DetermineTowerBackground - Add Psi2 Safety Check - Ensure Psi2 from EventplaneinfoMap is finite and not NaN which can corrupt downstream calculations. --- .../jetbackground/DetermineTowerBackground.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index c359b6914c..78a930a8a0 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -610,6 +610,17 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) _is_flow_failure = true; _Psi2 = 0; } + + // Safety check + if (!std::isfinite(_Psi2)) + { + if (Verbosity() > 0) + { + std::cout << "DetermineTowerBackground::process_event: WARNING Psi2 is non-finite (NaN or Inf), setting Psi2 = 0." << std::endl; + } + _is_flow_failure = true; + _Psi2 = 0; + } if (Verbosity() > 0) { From 80be7af4900f3dd4828a4c2df4697d30395804c2 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Fri, 23 Jan 2026 14:38:39 -0500 Subject: [PATCH 110/866] Bug fix. --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index e7a8cde39d..fb1c4b6de9 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -905,7 +905,7 @@ std::vector PHActsSiliconSeeding::findMatches( y0 = m_mvtx_y0; } float xfitradius_moved = fitpars[1] - x0; - float yfitradius_moved = fitpars[1] - y0; + float yfitradius_moved = fitpars[2] - y0; const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], xfitradius_moved, yfitradius_moved); float xp = xplus + x0; @@ -1176,8 +1176,6 @@ std::vector> PHActsSiliconSeeding::iterateLayers( for (int layer = startLayer; layer < endLayer; ++layer) { float layerradius = m_geomContainerIntt->GetLayerGeom(layer)->get_radius(); - //const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], fitpars[1], fitpars[2]); - if(layer < 3) { x0 = m_mvtx_x0; From 79a16396e0af741d3aeb53e96dd05c79f4993f3e Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Fri, 23 Jan 2026 18:24:47 -0500 Subject: [PATCH 111/866] Adds local PID parametrization file option to KFParticle_sPHENIX --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 36 +++++++++++++++---- .../KFParticle_sPHENIX/KFParticle_Tools.h | 2 ++ .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 4 +++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index b319af5b56..14958f22c9 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1184,7 +1184,16 @@ float KFParticle_Tools::get_dEdx(PHCompositeNode *topNode, const KFParticle &dau void KFParticle_Tools::init_dEdx_fits() { - std::string dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); + std::string dedx_fitparams; + if (m_use_local_PID_file) + { + dedx_fitparams = m_local_PID_filename; + } + else + { + dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); + } + TFile *filefit = TFile::Open(dedx_fitparams.c_str()); if (!filefit->IsOpen()) @@ -1193,12 +1202,25 @@ void KFParticle_Tools::init_dEdx_fits() return; } - filefit->GetObject("f_piband", f_pion_plus); - filefit->GetObject("f_Kband", f_kaon_plus); - filefit->GetObject("f_pband", f_proton_plus); - filefit->GetObject("f_piminus_band", f_pion_minus); - filefit->GetObject("f_Kminus_band", f_kaon_minus); - filefit->GetObject("f_pbar_band", f_proton_minus); + if (m_use_local_PID_file) + { + // new method is independent of charge + filefit->GetObject("pi_band",f_pion_plus); + filefit->GetObject("K_band",f_kaon_plus); + filefit->GetObject("p_band",f_proton_plus); + filefit->GetObject("pi_band",f_pion_minus); + filefit->GetObject("K_band",f_kaon_minus); + filefit->GetObject("p_band",f_proton_minus); + } + else + { + filefit->GetObject("f_piband", f_pion_plus); + filefit->GetObject("f_Kband", f_kaon_plus); + filefit->GetObject("f_pband", f_proton_plus); + filefit->GetObject("f_piminus_band", f_pion_minus); + filefit->GetObject("f_Kminus_band", f_kaon_minus); + filefit->GetObject("f_pbar_band", f_proton_minus); + } pidMap.insert(std::pair(-11, f_pion_plus)); pidMap.insert(std::pair(211, f_pion_plus)); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 4e722a15db..126c331c13 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -149,6 +149,8 @@ class KFParticle_Tools : protected KFParticle_MVA std::vector m_intermediate_vertex_volume; bool m_use_PID{false}; + bool m_use_local_PID_file{false}; + std::string m_local_PID_filename = ""; float m_dEdx_band_width{0.2}; // Fraction of expected dE/dx TF1 *f_pion_plus{nullptr}; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 64fc3f37bb..e537d63dd4 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -394,6 +394,10 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void selectMotherByMassError(bool select = true) { m_select_by_mass_error = select; } void usePID(bool use = true){ m_use_PID = use; } + + void useLocalPIDFile(bool use = false){ m_use_local_PID_file = use; } + + void setLocalPIDFilename(std::string name){ m_local_PID_filename = name; } void setPIDacceptFraction(float frac = 0.2){ m_dEdx_band_width = frac; } From dc058d601aed5d41569bea1123e05ead6b675b80 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Sat, 24 Jan 2026 14:20:23 -0500 Subject: [PATCH 112/866] key the vertex using both position and process id --- .../g4main/PHG4TruthTrackingAction.cc | 35 ++++++++++++------- .../g4main/PHG4TruthTrackingAction.h | 5 ++- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc index 4db6ecbd51..da01d9d5e3 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc @@ -308,20 +308,27 @@ PHG4Particle* PHG4TruthTrackingAction::AddParticle(PHG4TruthInfoContainer& truth PHG4VtxPoint* PHG4TruthTrackingAction::AddVertex(PHG4TruthInfoContainer& truth, const G4Track& track) { G4ThreeVector v = track.GetVertexPosition(); + + // Get G4Track creator process FIRST (needed for vertex map key) + const auto* const g4Process = track.GetCreatorProcess(); + // Convert G4 Process to MC process + const auto process = PHG4ProcessMapPhysics::Instance().GetMCProcess(g4Process); + int vtxindex = (track.GetParentID() == 0 ? truth.maxvtxindex() + 1 : truth.minvtxindex() - 1); - auto [iter, inserted] = m_VertexMap.insert(std::make_pair(v, vtxindex)); + // Use (position, process) as key to distinguish vertices at same location but different processes + // This is important for cases like K0 -> K0_S/K0_L mixing where particles are produced + // at the same position but by different physics processes + auto key = std::make_pair(v, process); + auto [iter, inserted] = m_VertexMap.insert(std::make_pair(key, vtxindex)); // If could not add a unique vertex => return the existing one if (!inserted) { return truth.GetVtxMap().find(iter->second)->second; } - // get G4Track creator process - const auto* const g4Process = track.GetCreatorProcess(); - // convert G4 Process to MC process - const auto process = PHG4ProcessMapPhysics::Instance().GetMCProcess(g4Process); - // otherwise, create and add a new one + + // Create and add a new vertex PHG4VtxPoint* vtxpt = new PHG4VtxPointv2(v[0] / cm, v[1] / cm, v[2] / cm, track.GetGlobalTime() / ns, vtxindex, process); return truth.AddVertex(vtxindex, vtxpt)->second; @@ -346,13 +353,15 @@ bool PHG4TruthTrackingAction::issPHENIXPrimary(PHG4TruthInfoContainer& truth, PH // check the production process // if not decay or primary, then it is not a primary // debug print for pid, track id, parent id, and process - /* - std::cout << "PHG4TruthTrackingAction::issPHENIXPrimary - checking particle with track id " << particle->get_track_id() - << ", pid: " << pdgid - << ", parent id: " << particle->get_parent_id() - << ", process: " << process - << std::endl; - */ + // if (pdgid == 311 || pdgid == 130 || pdgid == 310) + //{ + // std::cout << "PHG4TruthTrackingAction::issPHENIXPrimary - checking particle with track id " << particle->get_track_id() + // << ", pid: " << pdgid + // << ", parent id: " << particle->get_parent_id() + // << ", process: " << process + // << std::endl; + //} + if (!(process == PHG4MCProcess::kPPrimary || process == PHG4MCProcess::kPDecay) && particle->get_parent_id()) // all primary particles seems to have unkown process id { return false; diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h index 5ad050c898..8025d7c9bb 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h @@ -4,10 +4,12 @@ #define G4MAIN_PHG4TRUTHTRACKINGACTION_H #include "PHG4TrackingAction.h" +#include "PHG4MCProcessDefs.h" #include #include +#include #include class G4Track; @@ -37,7 +39,8 @@ class PHG4TruthTrackingAction : public PHG4TrackingAction int ResetEvent(PHCompositeNode*) override; private: - std::map m_VertexMap; + // Key is (position, process) to distinguish vertices at the same location but different processes + std::map, int> m_VertexMap; //! pointer to the "owning" event action PHG4TruthEventAction* m_EventAction; From 4a03dcf163dccb67645ec0f28dfd05efc19b6aae Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 24 Jan 2026 18:45:44 -0500 Subject: [PATCH 113/866] this package uses openmp, clang needs -fopenmp to link this --- calibrations/tpc/dEdx/Makefile.am | 4 ++-- calibrations/tpc/dEdx/configure.ac | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/calibrations/tpc/dEdx/Makefile.am b/calibrations/tpc/dEdx/Makefile.am index e057d9dffe..e91bd83664 100644 --- a/calibrations/tpc/dEdx/Makefile.am +++ b/calibrations/tpc/dEdx/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign AM_CPPFLAGS = \ -I$(includedir) \ - -I$(OFFLINE_MAIN)/include \ + -isystem$(OFFLINE_MAIN)/include \ -isystem$(ROOTSYS)/include AM_LDFLAGS = \ @@ -14,7 +14,7 @@ pkginclude_HEADERS = \ dEdxFitter.h \ GlobaldEdxFitter.h \ bethe_bloch.h - + lib_LTLIBRARIES = \ libdedxfitter.la diff --git a/calibrations/tpc/dEdx/configure.ac b/calibrations/tpc/dEdx/configure.ac index aed59969a8..eae253f50e 100644 --- a/calibrations/tpc/dEdx/configure.ac +++ b/calibrations/tpc/dEdx/configure.ac @@ -6,10 +6,10 @@ AC_PROG_CXX(CC g++) LT_INIT([disable-static]) -dnl no point in suppressing warnings people should -dnl at least see them, so here we go for g++: -Wall +dnl enable more warnings and make them fatal +dnl this package needs openmp which requires -fopenmp for clang if test $ac_cv_prog_gxx = yes; then - CXXFLAGS="$CXXFLAGS -Wall -Werror" + CXXFLAGS="$CXXFLAGS -fopenmp -Wall -Wshadow -Wextra -Werror" fi AC_CONFIG_FILES([Makefile]) From 66a0623afdcaf2e26ded719457ef85d44604426b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 25 Jan 2026 20:32:32 -0500 Subject: [PATCH 114/866] trigger jenkins From 8213894265f6042d88ac26f4536868fd97d5db83 Mon Sep 17 00:00:00 2001 From: Shuonli Date: Mon, 26 Jan 2026 01:42:07 -0500 Subject: [PATCH 115/866] empty commit to trigger checks From fdfe0bee75e98d0b6a3e59918774f51456982c13 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 26 Jan 2026 10:56:38 -0500 Subject: [PATCH 116/866] Fixed library dependency (libtrack_reco -> libtrackbase_historic). This allows to remove openmp configuration flag, introduced in https://github.com/sPHENIX-Collaboration/coresoftware/pull/4139 --- calibrations/tpc/dEdx/Makefile.am | 2 +- calibrations/tpc/dEdx/configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/calibrations/tpc/dEdx/Makefile.am b/calibrations/tpc/dEdx/Makefile.am index e91bd83664..d0eeaa9c5a 100644 --- a/calibrations/tpc/dEdx/Makefile.am +++ b/calibrations/tpc/dEdx/Makefile.am @@ -26,8 +26,8 @@ libdedxfitter_la_LIBADD = \ -lphool \ -ltrack_io \ -lg4detectors \ + -ltrackbase_historic \ -ltrackbase_historic_io \ - -ltrack_reco \ -lglobalvertex \ -lSubsysReco diff --git a/calibrations/tpc/dEdx/configure.ac b/calibrations/tpc/dEdx/configure.ac index eae253f50e..efef9411e9 100644 --- a/calibrations/tpc/dEdx/configure.ac +++ b/calibrations/tpc/dEdx/configure.ac @@ -9,7 +9,7 @@ LT_INIT([disable-static]) dnl enable more warnings and make them fatal dnl this package needs openmp which requires -fopenmp for clang if test $ac_cv_prog_gxx = yes; then - CXXFLAGS="$CXXFLAGS -fopenmp -Wall -Wshadow -Wextra -Werror" + CXXFLAGS="$CXXFLAGS -Wall -Wshadow -Wextra -Werror" fi AC_CONFIG_FILES([Makefile]) From a95f3ef6e0ad56c46905dddf0aa3632b68a51096 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 26 Jan 2026 14:48:07 -0500 Subject: [PATCH 117/866] modify seed merger to just remove duplicates --- .../packages/trackreco/PHSiliconSeedMerger.cc | 45 ++++++++++++++++--- .../packages/trackreco/PHSiliconSeedMerger.h | 4 +- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 16c0848456..943873950d 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -74,7 +74,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { continue; } + if(TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + { track1Strobe = MvtxDefs::getStrobeId(ckey); + } mvtx1Keys.insert(ckey); } @@ -110,7 +113,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) continue; } mvtx2Keys.insert(ckey); + if(TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + { track2Strobe = MvtxDefs::getStrobeId(ckey); + } } std::vector intersection; @@ -120,9 +126,8 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) mvtx2Keys.end(), std::back_inserter(intersection)); - /// If we have two clusters in common in the triplet, it is likely - /// from the same track - if (intersection.size() > m_clusterOverlap && track1Strobe == track2Strobe) + /// If the intersection fully encompasses one of the tracks, it is completely duplicated + if (intersection.size() == mvtx1Keys.size() || intersection.size() == mvtx2Keys.size()) { if (Verbosity() > 2) { @@ -143,9 +148,35 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) } } - for (auto& key : mvtx2Keys) + /// one of the tracks is encompassed in the other. Take the larger one + std::set keysToKeep; + if(mvtx1Keys.size() >= mvtx2Keys.size()) + { + keysToKeep = mvtx1Keys; + if(track1Strobe == track2Strobe && m_mergeSeeds) + { + keysToKeep.insert(mvtx2Keys.begin(), mvtx2Keys.end()); + } + matches.insert(std::make_pair(track1ID, mvtx1Keys)); + seedsToDelete.insert(track2ID); + if(Verbosity() > 2) + { + std::cout << " will delete seed " << track2ID << std::endl; + } + } + else { - mvtx1Keys.insert(key); + keysToKeep = mvtx2Keys; + if (track1Strobe == track2Strobe && m_mergeSeeds) + { + keysToKeep.insert(mvtx1Keys.begin(), mvtx1Keys.end()); + } + matches.insert(std::make_pair(track2ID, mvtx2Keys)); + seedsToDelete.insert(track1ID); + if(Verbosity() > 2) + { + std::cout << " will delete seed " << track1ID << std::endl; + } } if (Verbosity() > 2) @@ -179,7 +210,9 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { track->insert_cluster_key(key); if (Verbosity() > 2) + { std::cout << "adding " << key << std::endl; + } } } } @@ -197,7 +230,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { for (const auto& seed : *m_siliconTracks) { - if (!seed) continue; + if (!seed){ continue; } seed->identify(); } } diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index b8227cd581..802c610e60 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -28,6 +28,7 @@ class PHSiliconSeedMerger : public SubsysReco void trackMapName(const std::string &name) { m_trackMapName = name; } void clusterOverlap(const unsigned int nclusters) { m_clusterOverlap = nclusters; } void searchIntt() { m_mvtxOnly = false; } + void mergeSeeds() { m_mergeSeeds = true; } private: int getNodes(PHCompositeNode *topNode); @@ -35,7 +36,8 @@ class PHSiliconSeedMerger : public SubsysReco TrackSeedContainer *m_siliconTracks{nullptr}; std::string m_trackMapName{"SiliconTrackSeedContainer"}; unsigned int m_clusterOverlap{1}; - bool m_mvtxOnly{true}; + bool m_mergeSeeds{false}; + bool m_mvtxOnly{false}; }; #endif // PHSILICONSEEDMERGER_H From 3d56c1866aef3f47e04379671e9e9ebbef1445b9 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 26 Jan 2026 14:50:18 -0500 Subject: [PATCH 118/866] clang tidy and format --- .../packages/trackreco/PHSiliconSeedMerger.cc | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 943873950d..fea5a7f447 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -14,8 +14,6 @@ #include #include -#include - //____________________________________________________________________________.. PHSiliconSeedMerger::PHSiliconSeedMerger(const std::string& name) : SubsysReco(name) @@ -23,12 +21,10 @@ PHSiliconSeedMerger::PHSiliconSeedMerger(const std::string& name) } //____________________________________________________________________________.. -PHSiliconSeedMerger::~PHSiliconSeedMerger() -{ -} +PHSiliconSeedMerger::~PHSiliconSeedMerger() = default; //____________________________________________________________________________.. -int PHSiliconSeedMerger::Init(PHCompositeNode*) +int PHSiliconSeedMerger::Init(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } @@ -41,7 +37,7 @@ int PHSiliconSeedMerger::InitRun(PHCompositeNode* topNode) } //____________________________________________________________________________.. -int PHSiliconSeedMerger::process_event(PHCompositeNode*) +int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) { std::multimap> matches; std::set seedsToDelete; @@ -57,7 +53,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { TrackSeed* track1 = m_siliconTracks->get(track1ID); - if (seedsToDelete.find(track1ID) != seedsToDelete.end()) + if (seedsToDelete.contains(track1ID)) { continue; } @@ -74,9 +70,9 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { continue; } - if(TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) { - track1Strobe = MvtxDefs::getStrobeId(ckey); + track1Strobe = MvtxDefs::getStrobeId(ckey); } mvtx1Keys.insert(ckey); } @@ -113,9 +109,9 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) continue; } mvtx2Keys.insert(ckey); - if(TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) { - track2Strobe = MvtxDefs::getStrobeId(ckey); + track2Strobe = MvtxDefs::getStrobeId(ckey); } } @@ -132,12 +128,12 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) if (Verbosity() > 2) { std::cout << "Track " << track1ID << " keys " << std::endl; - for (auto& key : mvtx1Keys) + for (const auto& key : mvtx1Keys) { std::cout << " ckey: " << key << std::endl; } std::cout << "Track " << track2ID << " keys " << std::endl; - for (auto& key : mvtx2Keys) + for (const auto& key : mvtx2Keys) { std::cout << " ckey: " << key << std::endl; } @@ -150,16 +146,16 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) /// one of the tracks is encompassed in the other. Take the larger one std::set keysToKeep; - if(mvtx1Keys.size() >= mvtx2Keys.size()) + if (mvtx1Keys.size() >= mvtx2Keys.size()) { keysToKeep = mvtx1Keys; - if(track1Strobe == track2Strobe && m_mergeSeeds) - { - keysToKeep.insert(mvtx2Keys.begin(), mvtx2Keys.end()); - } + if (track1Strobe == track2Strobe && m_mergeSeeds) + { + keysToKeep.insert(mvtx2Keys.begin(), mvtx2Keys.end()); + } matches.insert(std::make_pair(track1ID, mvtx1Keys)); seedsToDelete.insert(track2ID); - if(Verbosity() > 2) + if (Verbosity() > 2) { std::cout << " will delete seed " << track2ID << std::endl; } @@ -173,7 +169,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) } matches.insert(std::make_pair(track2ID, mvtx2Keys)); seedsToDelete.insert(track1ID); - if(Verbosity() > 2) + if (Verbosity() > 2) { std::cout << " will delete seed " << track1ID << std::endl; } @@ -182,7 +178,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) if (Verbosity() > 2) { std::cout << "Match IDed" << std::endl; - for (auto& key : mvtx1Keys) + for (const auto& key : mvtx1Keys) { std::cout << " total track keys " << key << std::endl; } @@ -197,14 +193,14 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) for (const auto& [trackKey, mvtxKeys] : matches) { - auto track = m_siliconTracks->get(trackKey); + auto* track = m_siliconTracks->get(trackKey); if (Verbosity() > 2) { std::cout << "original track: " << std::endl; track->identify(); } - for (auto& key : mvtxKeys) + for (const auto& key : mvtxKeys) { if (track->find_cluster_key(key) == track->end_cluster_keys()) { @@ -230,7 +226,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { for (const auto& seed : *m_siliconTracks) { - if (!seed){ continue; } + if (!seed) + { + continue; + } seed->identify(); } } @@ -239,20 +238,20 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) } //____________________________________________________________________________.. -int PHSiliconSeedMerger::ResetEvent(PHCompositeNode*) +int PHSiliconSeedMerger::ResetEvent(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } //____________________________________________________________________________.. -int PHSiliconSeedMerger::End(PHCompositeNode*) +int PHSiliconSeedMerger::End(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) { - m_siliconTracks = findNode::getClass(topNode, m_trackMapName.c_str()); + m_siliconTracks = findNode::getClass(topNode, m_trackMapName); if (!m_siliconTracks) { std::cout << PHWHERE << "No silicon track container, can't merge seeds" From 7ef17b304a8cc118b706b3e9e58388bb61964e4d Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 03:23:10 +0000 Subject: [PATCH 119/866] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20?= =?UTF-8?q?`silicon=5Fduplicate=5Fremoval`?= 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-Collaboration/coresoftware/pull/4141#issuecomment-3801456929 The following files were modified: * `offline/packages/trackreco/PHSiliconSeedMerger.cc` * `offline/packages/trackreco/PHSiliconSeedMerger.h` --- .../packages/trackreco/PHSiliconSeedMerger.cc | 154 ++++++++++++++---- .../packages/trackreco/PHSiliconSeedMerger.h | 46 +++++- 2 files changed, 161 insertions(+), 39 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 16c0848456..4d5dfcf676 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -1,4 +1,3 @@ - #include "PHSiliconSeedMerger.h" #include @@ -14,34 +13,67 @@ #include #include -#include - -//____________________________________________________________________________.. +/** + * @brief Construct a PHSiliconSeedMerger with the given subsystem name. + * + * Initializes the PHSiliconSeedMerger and forwards the provided subsystem + * name to the base SubsysReco constructor. + * + * @param name Subsystem name used to register this module in the node tree. + */ PHSiliconSeedMerger::PHSiliconSeedMerger(const std::string& name) : SubsysReco(name) { } -//____________________________________________________________________________.. -PHSiliconSeedMerger::~PHSiliconSeedMerger() -{ -} +/** + * @brief Default destructor for PHSiliconSeedMerger. + * + * Performs default cleanup of the merger object and its owned resources. + */ +PHSiliconSeedMerger::~PHSiliconSeedMerger() = default; -//____________________________________________________________________________.. -int PHSiliconSeedMerger::Init(PHCompositeNode*) +/** + * @brief Perform module initialization (no operation required). + * + * This implementation does not perform any setup and always succeeds. + * + * @return int `EVENT_OK` indicating initialization succeeded. + */ +int PHSiliconSeedMerger::Init(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. +/** + * @brief Initializes run-time resources by retrieving required nodes. + * + * Calls getNodes(topNode) to locate and cache containers needed for processing this run. + * + * @param topNode Root of the node tree from which required nodes are retrieved. + * @return int `EVENT_OK` on success, `ABORTEVENT` or another non-zero code on failure. + */ int PHSiliconSeedMerger::InitRun(PHCompositeNode* topNode) { int ret = getNodes(topNode); return ret; } -//____________________________________________________________________________.. -int PHSiliconSeedMerger::process_event(PHCompositeNode*) +/** + * @brief Merge overlapping silicon seed tracks by consolidating MVTX cluster keys. + * + * Detects seeds whose MVTX cluster key sets fully overlap (one set equals the + * intersection) and treats one seed as a duplicate of the other. The merger + * preserves the seed with the larger MVTX key set; if both seeds share the + * same MVTX strobe and seed merging is enabled, the smaller seed's MVTX keys + * are merged into the preserved seed. After consolidation, duplicate seeds are + * erased from the silicon track container and preserved seeds are updated to + * include any newly merged MVTX cluster keys. + * + * @return Fun4AllReturnCodes::EVENT_OK on successful processing. + * + */ +int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) { std::multimap> matches; std::set seedsToDelete; @@ -57,7 +89,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { TrackSeed* track1 = m_siliconTracks->get(track1ID); - if (seedsToDelete.find(track1ID) != seedsToDelete.end()) + if (seedsToDelete.contains(track1ID)) { continue; } @@ -74,7 +106,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { continue; } - track1Strobe = MvtxDefs::getStrobeId(ckey); + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + { + track1Strobe = MvtxDefs::getStrobeId(ckey); + } mvtx1Keys.insert(ckey); } @@ -110,7 +145,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) continue; } mvtx2Keys.insert(ckey); - track2Strobe = MvtxDefs::getStrobeId(ckey); + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + { + track2Strobe = MvtxDefs::getStrobeId(ckey); + } } std::vector intersection; @@ -120,19 +158,18 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) mvtx2Keys.end(), std::back_inserter(intersection)); - /// If we have two clusters in common in the triplet, it is likely - /// from the same track - if (intersection.size() > m_clusterOverlap && track1Strobe == track2Strobe) + /// If the intersection fully encompasses one of the tracks, it is completely duplicated + if (intersection.size() == mvtx1Keys.size() || intersection.size() == mvtx2Keys.size()) { if (Verbosity() > 2) { std::cout << "Track " << track1ID << " keys " << std::endl; - for (auto& key : mvtx1Keys) + for (const auto& key : mvtx1Keys) { std::cout << " ckey: " << key << std::endl; } std::cout << "Track " << track2ID << " keys " << std::endl; - for (auto& key : mvtx2Keys) + for (const auto& key : mvtx2Keys) { std::cout << " ckey: " << key << std::endl; } @@ -143,15 +180,41 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) } } - for (auto& key : mvtx2Keys) + /// one of the tracks is encompassed in the other. Take the larger one + std::set keysToKeep; + if (mvtx1Keys.size() >= mvtx2Keys.size()) { - mvtx1Keys.insert(key); + keysToKeep = mvtx1Keys; + if (track1Strobe == track2Strobe && m_mergeSeeds) + { + keysToKeep.insert(mvtx2Keys.begin(), mvtx2Keys.end()); + } + matches.insert(std::make_pair(track1ID, mvtx1Keys)); + seedsToDelete.insert(track2ID); + if (Verbosity() > 2) + { + std::cout << " will delete seed " << track2ID << std::endl; + } + } + else + { + keysToKeep = mvtx2Keys; + if (track1Strobe == track2Strobe && m_mergeSeeds) + { + keysToKeep.insert(mvtx1Keys.begin(), mvtx1Keys.end()); + } + matches.insert(std::make_pair(track2ID, mvtx2Keys)); + seedsToDelete.insert(track1ID); + if (Verbosity() > 2) + { + std::cout << " will delete seed " << track1ID << std::endl; + } } if (Verbosity() > 2) { std::cout << "Match IDed" << std::endl; - for (auto& key : mvtx1Keys) + for (const auto& key : mvtx1Keys) { std::cout << " total track keys " << key << std::endl; } @@ -166,20 +229,22 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) for (const auto& [trackKey, mvtxKeys] : matches) { - auto track = m_siliconTracks->get(trackKey); + auto* track = m_siliconTracks->get(trackKey); if (Verbosity() > 2) { std::cout << "original track: " << std::endl; track->identify(); } - for (auto& key : mvtxKeys) + for (const auto& key : mvtxKeys) { if (track->find_cluster_key(key) == track->end_cluster_keys()) { track->insert_cluster_key(key); if (Verbosity() > 2) + { std::cout << "adding " << key << std::endl; + } } } } @@ -197,7 +262,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { for (const auto& seed : *m_siliconTracks) { - if (!seed) continue; + if (!seed) + { + continue; + } seed->identify(); } } @@ -205,21 +273,41 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. -int PHSiliconSeedMerger::ResetEvent(PHCompositeNode*) +/** + * @brief Reset per-event state for the merger. + * + * This implementation performs no per-event cleanup and always reports success. + * + * @return Integer status code: `Fun4AllReturnCodes::EVENT_OK`. + */ +int PHSiliconSeedMerger::ResetEvent(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. -int PHSiliconSeedMerger::End(PHCompositeNode*) +/** + * @brief Perform end-of-run shutdown for the silicon seed merger. + * + * @return int EVENT_OK on successful completion. + */ +int PHSiliconSeedMerger::End(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Retrieve required nodes from the top-level node tree and validate availability. + * + * Locates the silicon TrackSeedContainer using m_trackMapName and stores it in + * m_siliconTracks. If the container is not found, the function logs an error + * message and signals an abort for the current event. + * + * @param topNode Root node used to search for the TrackSeedContainer. + * @return int Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTEVENT if the silicon TrackSeedContainer is not present. + */ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) { - m_siliconTracks = findNode::getClass(topNode, m_trackMapName.c_str()); + m_siliconTracks = findNode::getClass(topNode, m_trackMapName); if (!m_siliconTracks) { std::cout << PHWHERE << "No silicon track container, can't merge seeds" @@ -228,4 +316,4 @@ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) } return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index b8227cd581..afef3571a5 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -25,17 +25,51 @@ class PHSiliconSeedMerger : public SubsysReco int ResetEvent(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; - void trackMapName(const std::string &name) { m_trackMapName = name; } - void clusterOverlap(const unsigned int nclusters) { m_clusterOverlap = nclusters; } - void searchIntt() { m_mvtxOnly = false; } + /** + * Set the name of the track seed container to use when retrieving silicon tracks. + * + * @param name Name of the TrackSeedContainer node (defaults to "SiliconTrackSeedContainer"). + */ +void trackMapName(const std::string &name) { m_trackMapName = name; } + /** + * Set the maximum number of overlapping clusters considered during seed merging. + * @param nclusters Maximum number of clusters that may overlap (overlap threshold). + */ +void clusterOverlap(const unsigned int nclusters) { m_clusterOverlap = nclusters; } + /** + * @brief Allow seed searches to include the INTT detector. + * + * Configure the merger to include INTT seeds in subsequent processing by disabling the MVTX-only restriction. + */ +void searchIntt() { m_mvtxOnly = false; } + /** + * Enable merging of silicon seed tracks during event processing. + * + * When enabled, the module will merge overlapping silicon seed tracks where applicable. + */ +void mergeSeeds() { m_mergeSeeds = true; } private: int getNodes(PHCompositeNode *topNode); TrackSeedContainer *m_siliconTracks{nullptr}; std::string m_trackMapName{"SiliconTrackSeedContainer"}; - unsigned int m_clusterOverlap{1}; - bool m_mvtxOnly{true}; + /** + * Minimum number of clusters that must be shared between two silicon track seeds + * for them to be considered overlapping. + * + * Defaults to 1. + */ +unsigned int m_clusterOverlap{1}; + bool m_mergeSeeds{false}; + /** + * Restrict seed processing to the MVTX detector only. + * + * When set to `true`, operations that iterate or merge silicon seed tracks + * will be limited to seeds originating from the MVTX vertex detector. + * When `false`, seeds from other silicon detectors are included. + */ +bool m_mvtxOnly{false}; }; -#endif // PHSILICONSEEDMERGER_H +#endif // PHSILICONSEEDMERGER_H \ No newline at end of file From e53dbd487446eb28b5ca682cae7cff2ac762cd2b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 27 Jan 2026 03:23:27 +0000 Subject: [PATCH 120/866] Fix missing final newline in docstring PR --- offline/packages/trackreco/PHSiliconSeedMerger.cc | 2 +- offline/packages/trackreco/PHSiliconSeedMerger.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 4d5dfcf676..8edb5816c3 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -316,4 +316,4 @@ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index afef3571a5..7ab50a44df 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -72,4 +72,4 @@ unsigned int m_clusterOverlap{1}; bool m_mvtxOnly{false}; }; -#endif // PHSILICONSEEDMERGER_H \ No newline at end of file +#endif // PHSILICONSEEDMERGER_H From 9ced97a03a5fb410bab67df8bc8f4a59009ca164 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Mon, 26 Jan 2026 22:47:58 -0500 Subject: [PATCH 121/866] Combined North-South Q-vector Calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the QVecCalib and QVecCDB modules to support a third "Combined NS" calibration slot. This update ensures that the combined North-South event plane is derived from individually recentered sub-detectors and then flattened as a single entity, significantly improving event plane resolution and flatness. Changes to QVecCalib: - Calibration Logic: Implemented a "Best of Both Worlds" approach where North and South vectors are recentered individually to preserve natural multiplicity weighting before being summed to form the NS vector. - Flattening Procedure: Added logic to calculate a unique flattening matrix for the combined NS vector, ensuring its final distribution is circular (⟨Qx2​⟩/⟨Qy2​⟩=1 and ⟨Qx​Qy​⟩=0). - Memory Optimization: Simplified the CorrectionData struct by removing intermediate second-moment storage (avg_Q_xx, avg_Q_yy, avg_Q_xy), utilizing local variables during matrix computation instead. - Histogram Refactoring: Replaced high-memory TH3 histograms with a suite of TH2 histograms (Psi_S, Psi_N, Psi_NS) to track event plane angles against centrality. Changes to QVecCDB: - Database Schema: Expanded the m_correction_data array and the SEPD_EventPlaneCalib payload to include the 3rd calibration slot for the NS detector. - IO Updates: Updated load_correction_data and write_cdb_EventPlane to process and commit the NS-specific 2nd moments (xx, yy, xy) to the Calibration Database (CDB). Technical Notes: - Satisfies the requirement that the NS combination treats the sum of recentered sub-detectors as a distinct third detector for whitening. - Prevents the resolution degradation caused by equal-weighting individually flattened sub-detectors. --- .../sepd/sepd_eventplanecalib/QVecCDB.cc | 17 ++ .../sepd/sepd_eventplanecalib/QVecCDB.h | 4 +- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 216 ++++++++++++------ .../sepd/sepd_eventplanecalib/QVecCalib.h | 40 ++-- .../sepd/sepd_eventplanecalib/QVecDefs.h | 3 +- 5 files changed, 190 insertions(+), 90 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc index 96e18d1ffe..b18bf4c345 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc @@ -68,6 +68,11 @@ void QVecCDB::load_correction_data(size_t h_idx) auto pN_yy = load_and_clone(QVecShared::get_hist_name("N", "yy", n)); auto pN_xy = load_and_clone(QVecShared::get_hist_name("N", "xy", n)); + // Load NS flattening terms + auto pNS_xx = load_and_clone(QVecShared::get_hist_name("NS", "xx", n)); + auto pNS_yy = load_and_clone(QVecShared::get_hist_name("NS", "yy", n)); + auto pNS_xy = load_and_clone(QVecShared::get_hist_name("NS", "xy", n)); + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) { int bin = static_cast(cent_bin) + 1; // ROOT bins start at 1 @@ -85,6 +90,12 @@ void QVecCDB::load_correction_data(size_t h_idx) dataN.avg_Q_xx = pN_xx->GetBinContent(bin); dataN.avg_Q_yy = pN_yy->GetBinContent(bin); dataN.avg_Q_xy = pN_xy->GetBinContent(bin); + + // North South + auto& dataNS = getData(h_idx, cent_bin, QVecShared::Subdetector::NS); + dataNS.avg_Q_xx = pNS_xx->GetBinContent(bin); + dataNS.avg_Q_yy = pNS_yy->GetBinContent(bin); + dataNS.avg_Q_xy = pNS_xy->GetBinContent(bin); } } @@ -168,6 +179,7 @@ void QVecCDB::write_cdb_EventPlane(const std::string &output_dir) // Access data references to clean up the calls const auto& S = getData(h_idx, cent_bin, QVecShared::Subdetector::S); const auto& N = getData(h_idx, cent_bin, QVecShared::Subdetector::N); + const auto& NS = getData(h_idx, cent_bin, QVecShared::Subdetector::NS); // South cdbttree->SetDoubleValue(key, field("S", "x"), S.avg_Q.x); @@ -182,6 +194,11 @@ void QVecCDB::write_cdb_EventPlane(const std::string &output_dir) cdbttree->SetDoubleValue(key, field("N", "xx"), N.avg_Q_xx); cdbttree->SetDoubleValue(key, field("N", "yy"), N.avg_Q_yy); cdbttree->SetDoubleValue(key, field("N", "xy"), N.avg_Q_xy); + + // North South + cdbttree->SetDoubleValue(key, field("NS", "xx"), NS.avg_Q_xx); + cdbttree->SetDoubleValue(key, field("NS", "yy"), NS.avg_Q_yy); + cdbttree->SetDoubleValue(key, field("NS", "xy"), NS.avg_Q_xy); } } diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h index 1840b2b52b..54b9b37901 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h @@ -56,8 +56,8 @@ class QVecCDB // Holds all correction data // key: [Harmonic][Cent][Subdetector] // Harmonics {2,3,4} -> 3 elements - // Subdetectors {S,N} -> 2 elements - std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; // --- Member Variables --- std::string m_input_file; diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index afa9eb8ed8..2148124032 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -305,10 +305,6 @@ void QVecCalib::process_bad_channels(TFile* file) void QVecCalib::init_hists() { - unsigned int bins_Q = 100; - double Q_low = -1; - double Q_high = 1; - unsigned int bins_psi = 126; double psi_low = -std::numbers::pi; double psi_high = std::numbers::pi; @@ -328,25 +324,17 @@ void QVecCalib::init_hists() // n = 2, 3, 4, etc. for (int n : m_harmonics) { - std::string psi_hist_name = std::format("h3_sEPD_Psi_{}", n); - std::string psi_hist_title = std::format("sEPD #Psi (Order {0}): |z| < 10 cm and MB; {0}#Psi^{{S}}_{{{0}}}; {0}#Psi^{{N}}_{{{0}}}; Centrality [%]", n); - - if (m_pass == Pass::ComputeRecentering) - { - psi_hist_name = std::format("h3_sEPD_Psi_{}", n); - } - - if (m_pass == Pass::ApplyRecentering) - { - psi_hist_name = std::format("h3_sEPD_Psi_{}_corr", n); - } + std::string name_S = std::format("h2_sEPD_Psi_S_{}{}", n, pass_suffix); + std::string name_N = std::format("h2_sEPD_Psi_N_{}{}", n, pass_suffix); + std::string name_NS = std::format("h2_sEPD_Psi_NS_{}{}", n, pass_suffix); - if (m_pass == Pass::ApplyFlattening) - { - psi_hist_name = std::format("h3_sEPD_Psi_{}_corr2", n); - } + std::string title_S = std::format("sEPD South #Psi (Order {0}); Centrality [%]; {0}#Psi^{{S}}_{{{0}}}", n); + std::string title_N = std::format("sEPD North #Psi (Order {0}); Centrality [%]; {0}#Psi^{{N}}_{{{0}}}", n); + std::string title_NS = std::format("sEPD North South #Psi (Order {0}); Centrality [%]; {0}#Psi^{{NS}}_{{{0}}}", n); - m_hists3D[psi_hist_name] = std::make_unique(psi_hist_name.c_str(), psi_hist_title.c_str(), bins_psi, psi_low, psi_high, bins_psi, psi_low, psi_high, m_cent_bins, m_cent_low, m_cent_high); + m_hists2D[name_S] = std::make_unique(name_S.c_str(), title_S.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + m_hists2D[name_N] = std::make_unique(name_N.c_str(), title_N.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + m_hists2D[name_NS] = std::make_unique(name_NS.c_str(), title_NS.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); // South, North for (auto det : m_subdetectors) @@ -354,14 +342,6 @@ void QVecCalib::init_hists() std::string det_str = (det == QVecShared::Subdetector::S) ? "S" : "N"; std::string det_name = (det == QVecShared::Subdetector::S) ? "South" : "North"; - if (m_pass == Pass::ComputeRecentering) - { - std::string q_hist_name = std::format("h3_sEPD_Q_{}_{}", det_str, n); - std::string q_hist_title = std::format("sEPD {} Q (Order {}): |z| < 10 cm and MB; Q_{{x}}; Q_{{y}}; Centrality [%]", det_name, n); - m_hists3D[q_hist_name] = std::make_unique(q_hist_name.c_str(), q_hist_title.c_str(), - bins_Q, Q_low, Q_high, bins_Q, Q_low, Q_high, m_cent_bins, m_cent_low, m_cent_high); - } - std::string q_avg_sq_cross_name; std::string q_avg_sq_cross_title = std::format("sEPD {0}; Centrality [%]; ", det_name, n); @@ -418,6 +398,31 @@ void QVecCalib::init_hists() } } } + + // Init for Combined NS Histograms + if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening) + { + std::string det_str = "NS"; + + // Initialize 2nd Moment Profiles for NS (needed to compute flattening) + for (const auto* comp : {"xx", "yy", "xy"}) + { + std::string name = QVecShared::get_hist_name(det_str, comp, n); + std::string title = std::format("sEPD NS; Centrality [%]; ", n, comp); + m_profiles[name] = std::make_unique(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + } + + // Initialize Validation Profiles (Flattened NS) + if (m_pass == Pass::ApplyFlattening) + { + for (const auto* comp : {"xx", "yy", "xy"}) + { + std::string name = QVecShared::get_hist_name(det_str, comp, n, "_corr"); + std::string title = std::format("sEPD NS Corrected; Centrality [%]; ", n, comp); + m_profiles[name] = std::make_unique(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + } + } + } } } @@ -425,15 +430,16 @@ void QVecCalib::process_averages(double cent, QVecShared::QVec q_S, QVecShared:: { double psi_S = std::atan2(q_S.y, q_S.x); double psi_N = std::atan2(q_N.y, q_N.x); + double psi_NS = std::atan2(q_S.y + q_N.y, q_S.x + q_N.x); h.S_x_avg->Fill(cent, q_S.x); h.S_y_avg->Fill(cent, q_S.y); h.N_x_avg->Fill(cent, q_N.x); h.N_y_avg->Fill(cent, q_N.y); - h.Q_S->Fill(q_S.x, q_S.y, cent); - h.Q_N->Fill(q_N.x, q_N.y, cent); - h.Psi->Fill(psi_S, psi_N, cent); + h.Psi_S->Fill(cent, psi_S); + h.Psi_N->Fill(cent, psi_N); + h.Psi_NS->Fill(cent, psi_NS); } void QVecCalib::process_recentering(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const RecenterHists& h) @@ -448,8 +454,13 @@ void QVecCalib::process_recentering(double cent, size_t h_idx, QVecShared::QVec QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + // Construct Combined Recentered Vector + // We use the sum of the individually recentered vectors + QVecShared::QVec q_NS_corr = {q_S_corr.x + q_N_corr.x, q_S_corr.y + q_N_corr.y}; + double psi_S_corr = std::atan2(q_S_corr.y, q_S_corr.x); double psi_N_corr = std::atan2(q_N_corr.y, q_N_corr.x); + double psi_NS_corr = std::atan2(q_NS_corr.y, q_NS_corr.x); h.S_x_corr_avg->Fill(cent, q_S_corr.x); h.S_y_corr_avg->Fill(cent, q_S_corr.y); @@ -463,7 +474,13 @@ void QVecCalib::process_recentering(double cent, size_t h_idx, QVecShared::QVec h.N_yy_avg->Fill(cent, q_N_corr.y * q_N_corr.y); h.N_xy_avg->Fill(cent, q_N_corr.x * q_N_corr.y); - h.Psi_corr->Fill(psi_S_corr, psi_N_corr, cent); + h.NS_xx_avg->Fill(cent, q_NS_corr.x * q_NS_corr.x); + h.NS_yy_avg->Fill(cent, q_NS_corr.y * q_NS_corr.y); + h.NS_xy_avg->Fill(cent, q_NS_corr.x * q_NS_corr.y); + + h.Psi_S_corr->Fill(cent, psi_S_corr); + h.Psi_N_corr->Fill(cent, psi_N_corr); + h.Psi_NS_corr->Fill(cent, psi_NS_corr); } void QVecCalib::process_flattening(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const FlatteningHists& h) @@ -478,19 +495,28 @@ void QVecCalib::process_flattening(double cent, size_t h_idx, QVecShared::QVec q QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + // Construct Combined Recentered Vector + QVecShared::QVec q_NS_corr = {q_S_corr.x + q_N_corr.x, q_S_corr.y + q_N_corr.y}; + const auto& X_S = m_correction_data[cent_bin][h_idx][0].X_matrix; const auto& X_N = m_correction_data[cent_bin][h_idx][1].X_matrix; + const auto& X_NS = m_correction_data[cent_bin][h_idx][IDX_NS].X_matrix; double Q_S_x_corr2 = X_S[0][0] * q_S_corr.x + X_S[0][1] * q_S_corr.y; double Q_S_y_corr2 = X_S[1][0] * q_S_corr.x + X_S[1][1] * q_S_corr.y; double Q_N_x_corr2 = X_N[0][0] * q_N_corr.x + X_N[0][1] * q_N_corr.y; double Q_N_y_corr2 = X_N[1][0] * q_N_corr.x + X_N[1][1] * q_N_corr.y; + double Q_NS_x_corr2 = X_NS[0][0] * q_NS_corr.x + X_NS[0][1] * q_NS_corr.y; + double Q_NS_y_corr2 = X_NS[1][0] * q_NS_corr.x + X_NS[1][1] * q_NS_corr.y; + QVecShared::QVec q_S_corr2 = {Q_S_x_corr2, Q_S_y_corr2}; QVecShared::QVec q_N_corr2 = {Q_N_x_corr2, Q_N_y_corr2}; + QVecShared::QVec q_NS_corr2 = {Q_NS_x_corr2, Q_NS_y_corr2}; double psi_S = std::atan2(q_S_corr2.y, q_S_corr2.x); double psi_N = std::atan2(q_N_corr2.y, q_N_corr2.x); + double psi_NS = std::atan2(q_NS_corr2.y, q_NS_corr2.x); h.S_x_corr2_avg->Fill(cent, q_S_corr2.x); h.S_y_corr2_avg->Fill(cent, q_S_corr2.y); @@ -504,7 +530,13 @@ void QVecCalib::process_flattening(double cent, size_t h_idx, QVecShared::QVec q h.N_yy_corr_avg->Fill(cent, q_N_corr2.y * q_N_corr2.y); h.N_xy_corr_avg->Fill(cent, q_N_corr2.x * q_N_corr2.y); - h.Psi_corr2->Fill(psi_S, psi_N, cent); + h.NS_xx_corr_avg->Fill(cent, q_NS_corr2.x * q_NS_corr2.x); + h.NS_yy_corr_avg->Fill(cent, q_NS_corr2.y * q_NS_corr2.y); + h.NS_xy_corr_avg->Fill(cent, q_NS_corr2.x * q_NS_corr2.y); + + h.Psi_S_corr2->Fill(cent, psi_S); + h.Psi_N_corr2->Fill(cent, psi_N); + h.Psi_NS_corr2->Fill(cent, psi_NS); } void QVecCalib::compute_averages(size_t cent_bin, int h_idx) @@ -598,12 +630,16 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) double Q_N_yy_avg = m_profiles[N_yy_avg_name]->GetBinContent(bin); double Q_N_xy_avg = m_profiles[N_xy_avg_name]->GetBinContent(bin); - m_correction_data[cent_bin][h_idx][0].avg_Q_xx = Q_S_xx_avg; - m_correction_data[cent_bin][h_idx][0].avg_Q_yy = Q_S_yy_avg; - m_correction_data[cent_bin][h_idx][0].avg_Q_xy = Q_S_xy_avg; - m_correction_data[cent_bin][h_idx][1].avg_Q_xx = Q_N_xx_avg; - m_correction_data[cent_bin][h_idx][1].avg_Q_yy = Q_N_yy_avg; - m_correction_data[cent_bin][h_idx][1].avg_Q_xy = Q_N_xy_avg; + // -- Compute NS Matrix -- + std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); + std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); + std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); + + double Q_NS_xx_avg = m_profiles[NS_xx_avg_name]->GetBinContent(bin); + double Q_NS_yy_avg = m_profiles[NS_yy_avg_name]->GetBinContent(bin); + double Q_NS_xy_avg = m_profiles[NS_xy_avg_name]->GetBinContent(bin); + + m_correction_data[cent_bin][h_idx][IDX_NS].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); for (size_t det_idx = 0; det_idx < 2; ++det_idx) { @@ -625,8 +661,10 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) "Q_N_y_corr_avg: {:13.10f}, " "Q_S_xx_avg / Q_S_yy_avg: {:13.10f}, " "Q_N_xx_avg / Q_N_yy_avg: {:13.10f}, " + "Q_NS_xx_avg / Q_NS_yy_avg: {:13.10f}, " "Q_S_xy_avg: {:13.10f}, " - "Q_N_xy_avg: {:13.10f}\n", + "Q_N_xy_avg: {:13.10f}, " + "Q_NS_xy_avg: {:13.10f}\n", cent_bin, n, Q_S_x_corr_avg, @@ -635,8 +673,10 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) Q_N_y_corr_avg, Q_S_xx_avg / Q_S_yy_avg, Q_N_xx_avg / Q_N_yy_avg, + Q_NS_xx_avg / Q_NS_yy_avg, Q_S_xy_avg, - Q_N_xy_avg); + Q_N_xy_avg, + Q_NS_xy_avg); } void QVecCalib::print_flattening(size_t cent_bin, int n) const @@ -653,6 +693,10 @@ void QVecCalib::print_flattening(size_t cent_bin, int n) const std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); + std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr"); + std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr"); + std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr"); + int bin = static_cast(cent_bin + 1); double Q_S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name)->GetBinContent(bin); @@ -667,6 +711,10 @@ void QVecCalib::print_flattening(size_t cent_bin, int n) const double Q_N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name)->GetBinContent(bin); double Q_N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name)->GetBinContent(bin); + double Q_NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name)->GetBinContent(bin); + double Q_NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name)->GetBinContent(bin); + double Q_NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name)->GetBinContent(bin); + std::cout << std::format( "Centrality Bin: {}, " "Harmonic: {}, " @@ -676,8 +724,10 @@ void QVecCalib::print_flattening(size_t cent_bin, int n) const "Q_N_y_corr2_avg: {:13.10f}, " "Q_S_xx_corr_avg / Q_S_yy_corr_avg: {:13.10f}, " "Q_N_xx_corr_avg / Q_N_yy_corr_avg: {:13.10f}, " + "Q_NS_xx_corr_avg / Q_NS_yy_corr_avg: {:13.10f}, " "Q_S_xy_corr_avg: {:13.10f}, " - "Q_N_xy_corr_avg: {:13.10f}\n", + "Q_N_xy_corr_avg: {:13.10f}, " + "Q_NS_xy_corr_avg: {:13.10f}\n", cent_bin, n, Q_S_x_corr2_avg, @@ -686,8 +736,10 @@ void QVecCalib::print_flattening(size_t cent_bin, int n) const Q_N_y_corr2_avg, Q_S_xx_corr_avg / Q_S_yy_corr_avg, Q_N_xx_corr_avg / Q_N_yy_corr_avg, + Q_NS_xx_corr_avg / Q_NS_yy_corr_avg, Q_S_xy_corr_avg, - Q_N_xy_corr_avg); + Q_N_xy_corr_avg, + Q_NS_xy_corr_avg); } std::vector QVecCalib::prepare_average_hists() @@ -701,9 +753,9 @@ std::vector QVecCalib::prepare_average_hists() std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); - std::string hist_Q_S_name = std::format("h3_sEPD_Q_S_{}", n); - std::string hist_Q_N_name = std::format("h3_sEPD_Q_N_{}", n); - std::string psi_Q_name = std::format("h3_sEPD_Psi_{}", n); + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}", n); AverageHists h; @@ -712,10 +764,9 @@ std::vector QVecCalib::prepare_average_hists() h.N_x_avg = m_profiles.at(N_x_avg_name).get(); h.N_y_avg = m_profiles.at(N_y_avg_name).get(); - h.Q_S = m_hists3D.at(hist_Q_S_name).get(); - h.Q_N = m_hists3D.at(hist_Q_N_name).get(); - - h.Psi = m_hists3D.at(psi_Q_name).get(); + h.Psi_S = m_hists2D.at(psi_S_name).get(); + h.Psi_N = m_hists2D.at(psi_N_name).get(); + h.Psi_NS = m_hists2D.at(psi_NS_name).get(); hists_cache.push_back(h); } @@ -800,7 +851,13 @@ std::vector QVecCalib::prepare_recenter_hists() std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); - std::string psi_Q_corr_name = std::format("h3_sEPD_Psi_{}_corr", n); + std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); + std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); + std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr", n); RecenterHists h; @@ -816,7 +873,13 @@ std::vector QVecCalib::prepare_recenter_hists() h.N_yy_avg = m_profiles.at(N_yy_avg_name).get(); h.N_xy_avg = m_profiles.at(N_xy_avg_name).get(); - h.Psi_corr = m_hists3D.at(psi_Q_corr_name).get(); + h.NS_xx_avg = m_profiles.at(NS_xx_avg_name).get(); + h.NS_yy_avg = m_profiles.at(NS_yy_avg_name).get(); + h.NS_xy_avg = m_profiles.at(NS_xy_avg_name).get(); + + h.Psi_S_corr = m_hists2D.at(psi_S_name).get(); + h.Psi_N_corr = m_hists2D.at(psi_N_name).get(); + h.Psi_NS_corr = m_hists2D.at(psi_NS_name).get(); hists_cache.push_back(h); } @@ -842,7 +905,13 @@ std::vector QVecCalib::prepare_flattening_hists() std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); - std::string psi_Q_corr2_name = std::format("h3_sEPD_Psi_{}_corr2", n); + std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr"); + std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr"); + std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr"); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr2", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr2", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr2", n); FlatteningHists h; @@ -859,7 +928,13 @@ std::vector QVecCalib::prepare_flattening_hists() h.N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name).get(); h.N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name).get(); - h.Psi_corr2 = m_hists3D.at(psi_Q_corr2_name).get(); + h.NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name).get(); + h.NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name).get(); + h.NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name).get(); + + h.Psi_S_corr2 = m_hists2D.at(psi_S_name).get(); + h.Psi_N_corr2 = m_hists2D.at(psi_N_name).get(); + h.Psi_NS_corr2 = m_hists2D.at(psi_NS_name).get(); hists_cache.push_back(h); } @@ -1047,15 +1122,11 @@ void QVecCalib::load_correction_data() std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); - std::string psi_hist_name = std::format("h3_sEPD_Psi_{}", n); - m_profiles[S_x_avg_name] = load_and_clone(file.get(), S_x_avg_name); m_profiles[S_y_avg_name] = load_and_clone(file.get(), S_y_avg_name); m_profiles[N_x_avg_name] = load_and_clone(file.get(), N_x_avg_name); m_profiles[N_y_avg_name] = load_and_clone(file.get(), N_y_avg_name); - m_hists3D[psi_hist_name] = load_and_clone(file.get(), psi_hist_name); - std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); @@ -1063,18 +1134,23 @@ void QVecCalib::load_correction_data() std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); - std::string psi_corr_hist_name = std::format("h3_sEPD_Psi_{}_corr", n); + std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); + std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); + std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); if(m_pass == Pass::ApplyFlattening) { m_profiles[S_xx_avg_name] = load_and_clone(file.get(), S_xx_avg_name); m_profiles[S_yy_avg_name] = load_and_clone(file.get(), S_yy_avg_name); m_profiles[S_xy_avg_name] = load_and_clone(file.get(), S_xy_avg_name); + m_profiles[N_xx_avg_name] = load_and_clone(file.get(), N_xx_avg_name); m_profiles[N_yy_avg_name] = load_and_clone(file.get(), N_yy_avg_name); m_profiles[N_xy_avg_name] = load_and_clone(file.get(), N_xy_avg_name); - m_hists3D[psi_corr_hist_name] = load_and_clone(file.get(), psi_corr_hist_name); + m_profiles[NS_xx_avg_name] = load_and_clone(file.get(), NS_xx_avg_name); + m_profiles[NS_yy_avg_name] = load_and_clone(file.get(), NS_yy_avg_name); + m_profiles[NS_xy_avg_name] = load_and_clone(file.get(), NS_xy_avg_name); } size_t south_idx = static_cast(QVecShared::Subdetector::S); @@ -1098,19 +1174,18 @@ void QVecCalib::load_correction_data() double Q_S_xx_avg = m_profiles[S_xx_avg_name]->GetBinContent(bin); double Q_S_yy_avg = m_profiles[S_yy_avg_name]->GetBinContent(bin); double Q_S_xy_avg = m_profiles[S_xy_avg_name]->GetBinContent(bin); + double Q_N_xx_avg = m_profiles[N_xx_avg_name]->GetBinContent(bin); double Q_N_yy_avg = m_profiles[N_yy_avg_name]->GetBinContent(bin); double Q_N_xy_avg = m_profiles[N_xy_avg_name]->GetBinContent(bin); - // Flattening Params - m_correction_data[cent_bin][h_idx][south_idx].avg_Q_xx = Q_S_xx_avg; - m_correction_data[cent_bin][h_idx][south_idx].avg_Q_yy = Q_S_yy_avg; - m_correction_data[cent_bin][h_idx][south_idx].avg_Q_xy = Q_S_xy_avg; + double Q_NS_xx_avg = m_profiles[NS_xx_avg_name]->GetBinContent(bin); + double Q_NS_yy_avg = m_profiles[NS_yy_avg_name]->GetBinContent(bin); + double Q_NS_xy_avg = m_profiles[NS_xy_avg_name]->GetBinContent(bin); - m_correction_data[cent_bin][h_idx][north_idx].avg_Q_xx = Q_N_xx_avg; - m_correction_data[cent_bin][h_idx][north_idx].avg_Q_yy = Q_N_yy_avg; - m_correction_data[cent_bin][h_idx][north_idx].avg_Q_xy = Q_N_xy_avg; + m_correction_data[cent_bin][h_idx][IDX_NS].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); + // Flattening Params for (size_t det_idx = 0; det_idx < 2; ++det_idx) { double xx = (det_idx == 0) ? Q_S_xx_avg : Q_N_xx_avg; @@ -1156,11 +1231,6 @@ void QVecCalib::save_results() const std::cout << std::format("Saving 2D: {}\n", name); hist->Write(); } - for (const auto& [name, hist] : m_hists3D) - { - std::cout << std::format("Saving 3D: {}\n", name); - hist->Write(); - } for (const auto& [name, hist] : m_profiles) { std::cout << std::format("Saving Profile: {}\n", name); diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index 7317ae1488..a10c3e14f9 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -11,7 +11,6 @@ #include #include #include -#include #include // ==================================================================== @@ -68,8 +67,9 @@ class QVecCalib private: - struct CorrectionData : public QVecShared::CorrectionMoments + struct CorrectionData { + QVecShared::QVec avg_Q{}; std::array, 2> X_matrix{}; }; @@ -81,8 +81,10 @@ class QVecCalib // Holds all correction data // key: [Cent][Harmonic][Subdetector] // Harmonics {2,3,4} -> 3 elements - // Subdetectors {S,N} -> 2 elements - std::array, m_harmonics.size()>, m_cent_bins> m_correction_data; + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_harmonics.size()>, m_cent_bins> m_correction_data; + + static constexpr size_t IDX_NS = 2; // Store harmonic orders and subdetectors for easy iteration static constexpr std::array m_subdetectors = {QVecShared::Subdetector::S, QVecShared::Subdetector::N}; @@ -121,10 +123,9 @@ class QVecCalib TProfile* N_x_avg{nullptr}; TProfile* N_y_avg{nullptr}; - TH3* Q_S{nullptr}; - TH3* Q_N{nullptr}; - - TH3* Psi{nullptr}; + TH2* Psi_S{nullptr}; + TH2* Psi_N{nullptr}; + TH2* Psi_NS{nullptr}; }; struct RecenterHists @@ -141,7 +142,13 @@ class QVecCalib TProfile* N_yy_avg{nullptr}; TProfile* N_xy_avg{nullptr}; - TH3* Psi_corr{nullptr}; + TProfile* NS_xx_avg{nullptr}; + TProfile* NS_yy_avg{nullptr}; + TProfile* NS_xy_avg{nullptr}; + + TH2* Psi_S_corr{nullptr}; + TH2* Psi_N_corr{nullptr}; + TH2* Psi_NS_corr{nullptr}; }; struct FlatteningHists @@ -159,7 +166,13 @@ class QVecCalib TProfile* N_yy_corr_avg{nullptr}; TProfile* N_xy_corr_avg{nullptr}; - TH3* Psi_corr2{nullptr}; + TProfile* NS_xx_corr_avg{nullptr}; + TProfile* NS_yy_corr_avg{nullptr}; + TProfile* NS_xy_corr_avg{nullptr}; + + TH2* Psi_S_corr2{nullptr}; + TH2* Psi_N_corr2{nullptr}; + TH2* Psi_NS_corr2{nullptr}; }; // --- Member Variables --- @@ -177,7 +190,6 @@ class QVecCalib // Hists std::map> m_hists1D; std::map> m_hists2D; - std::map> m_hists3D; std::map> m_profiles; // sEPD Bad Channels @@ -216,7 +228,7 @@ class QVecCalib * @brief Safely retrieves a ROOT object from a file and returns a managed unique_ptr. * * Performs a dynamic_cast to verify the requested type T and Clones the object * to ensure it remains valid after the source file is closed. - * * @tparam T The ROOT class type (e.g., TProfile, TH3). + * * @tparam T The ROOT class type (e.g., TProfile). * @param file Pointer to the source TFile. * @param name The name of the object within the file. * @return std::unique_ptr A managed pointer to the cloned object. @@ -265,8 +277,8 @@ class QVecCalib /** * @brief Finalizes the analysis by writing all histograms to the output ROOT file. - * * Creates the output directory if it does not exist and ensures all 1D, 2D, - * 3D histograms and TProfiles are safely persisted to disk. + * * Creates the output directory if it does not exist and ensures all 1D, 2D + * and TProfiles are safely persisted to disk. */ void save_results() const; diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h index f74c62f574..bea362b661 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -14,7 +14,8 @@ namespace QVecShared enum class Subdetector { S, // South - N // North + N, // North + NS // North South }; enum class QComponent From c38e2000cb52d9d00fe8eee961b398aff745a349 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 27 Jan 2026 09:52:12 -0500 Subject: [PATCH 122/866] trigger jenkins From 9d25f5e0f5fed1f09fa66ac3d5f0b1b0c6c38081 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 27 Jan 2026 09:59:41 -0500 Subject: [PATCH 123/866] trigger jenkins From 5e38c107eb93abe133ef477bc60ab25b3848b1a6 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 27 Jan 2026 10:00:49 -0500 Subject: [PATCH 124/866] trigger jenkins From 382455af6c7c081ff2c7e7d01139b608921922ba Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Tue, 27 Jan 2026 12:14:18 -0500 Subject: [PATCH 125/866] added mbd_status calib, overlapping waveforms (pileup) fit --- offline/packages/mbd/MbdCalib.cc | 120 ++++++++++++++++++++++ offline/packages/mbd/MbdCalib.h | 8 ++ offline/packages/mbd/MbdEvent.cc | 29 ++++-- offline/packages/mbd/MbdEvent.h | 7 +- offline/packages/mbd/MbdSig.cc | 164 ++++++++++++++++++++++++++----- offline/packages/mbd/MbdSig.h | 11 ++- 6 files changed, 301 insertions(+), 38 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 0b02908adb..1367b375c8 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -86,6 +86,13 @@ int MbdCalib::Download_All() } Download_SampMax(sampmax_url); + std::string status_url = _cdb->getUrl("MBD_STATUS"); + if (Verbosity() > 0) + { + std::cout << "status_url " << status_url << std::endl; + } + Download_Status(status_url); + if ( !_rawdstflag ) { std::string ped_url = _cdb->getUrl("MBD_PED"); @@ -176,6 +183,9 @@ int MbdCalib::Download_All() std::string sampmax_file = bbc_caldir + "/mbd_sampmax.calib"; Download_SampMax(sampmax_file); + std::string status_file = bbc_caldir + "/mbd_status.calib"; + Download_Status(status_file); + if ( !_rawdstflag ) { std::string ped_file = bbc_caldir + "/mbd_ped.calib"; @@ -688,6 +698,70 @@ int MbdCalib::Download_SampMax(const std::string& dbase_location) return 1; } +int MbdCalib::Download_Status(const std::string& dbase_location) +{ + // Reset All Values + _mbdstatus.fill(-1); + + TString dbase_file = dbase_location; + +#ifndef ONLINE + if (dbase_file.EndsWith(".root")) // read from database + { + CDBTTree* cdbttree = new CDBTTree(dbase_location); + cdbttree->LoadCalibrations(); + + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + _mbdstatus[ifeech] = cdbttree->GetIntValue(ifeech, "status"); + if (Verbosity() > 0) + { + if (ifeech < 5 || ifeech >= MbdDefs::MBD_N_FEECH - 5) + { + std::cout << ifeech << "\t" << _mbdstatus[ifeech] << std::endl; + } + } + } + delete cdbttree; + } +#endif + + if (dbase_file.EndsWith(".calib")) // read from text file + { + std::ifstream infile(dbase_location); + if (!infile.is_open()) + { + std::cout << PHWHERE << "unable to open " << dbase_location << std::endl; + _status = -3; + return _status; + } + + int feech = -1; + while (infile >> feech) + { + infile >> _mbdstatus[feech]; + if (Verbosity() > 0) + { + if (feech < 5 || feech >= MbdDefs::MBD_N_FEECH - 5) + { + std::cout << "status\t" << feech << "\t" << _mbdstatus[feech] << std::endl; + } + } + } + infile.close(); + } + + + if ( _mbdstatus[0] == -1 ) + { + std::cout << PHWHERE << ", WARNING, sampmax calib missing, " << dbase_location << std::endl; + _status = -1; + return _status; // file not found + } + + return 1; +} + int MbdCalib::Download_Shapes(const std::string& dbase_location) { // Verbosity(100); @@ -1591,6 +1665,52 @@ int MbdCalib::Write_SampMax(const std::string& dbfile) return 1; } +#ifndef ONLINE +int MbdCalib::Write_CDB_Status(const std::string& dbfile) +{ + CDBTTree* cdbttree{ nullptr }; + + std::cout << "Creating " << dbfile << std::endl; + cdbttree = new CDBTTree( dbfile ); + cdbttree->SetSingleIntValue("version", 1); + cdbttree->CommitSingle(); + + std::cout << "STATUS" << std::endl; + for (size_t ifeech = 0; ifeech < _mbdstatus.size(); ifeech++) + { + // store in a CDBTree + cdbttree->SetIntValue(ifeech, "status", _mbdstatus[ifeech]); + + if (ifeech < 12 || ifeech >= MbdDefs::MBD_N_FEECH - 5) + { + std::cout << ifeech << "\t" << std::hex << cdbttree->GetIntValue(ifeech, "status") << std::dec << std::endl; + } + } + + cdbttree->Commit(); + // cdbttree->Print(); + + // for now we create the tree after reading it + cdbttree->WriteCDBTTree(); + delete cdbttree; + + return 1; +} +#endif + +int MbdCalib::Write_Status(const std::string& dbfile) +{ + std::ofstream cal_file; + cal_file.open(dbfile); + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + cal_file << ifeech << "\t0x" << std::hex << _mbdstatus[ifeech] << std::dec << std::endl; + } + cal_file.close(); + + return 1; +} + #ifndef ONLINE int MbdCalib::Write_CDB_TTT0(const std::string& dbfile) { diff --git a/offline/packages/mbd/MbdCalib.h b/offline/packages/mbd/MbdCalib.h index 6d7208f631..1f450cb5be 100644 --- a/offline/packages/mbd/MbdCalib.h +++ b/offline/packages/mbd/MbdCalib.h @@ -37,6 +37,7 @@ class MbdCalib float get_ped(const int ifeech) const { return _pedmean[ifeech]; } float get_pedrms(const int ifeech) const { return _pedsigma[ifeech]; } int get_sampmax(const int ifeech) const { return _sampmax[ifeech]; } + int get_status(const int ifeech) const { return _mbdstatus[ifeech]; } float get_tcorr(const int ifeech, const int tdc) const { if (tdc<0) { @@ -108,6 +109,7 @@ class MbdCalib TGraph *get_lut_graph(const int pmtch, std::string_view type); void set_sampmax(const int ifeech, const int val) { _sampmax[ifeech] = val; } + void set_status(const int ifeech, const int val) { _mbdstatus[ifeech] = val; } void set_ped(const int ifeech, const float m, const float merr, const float s, const float serr); void set_tt0(const int ipmt, const float t0) { _ttfit_t0mean[ipmt] = t0; } void set_tq0(const int ipmt, const float t0) { _tqfit_t0mean[ipmt] = t0; } @@ -118,6 +120,7 @@ class MbdCalib int Download_T0Corr(const std::string& dbase_location); int Download_Ped(const std::string& dbase_location); int Download_SampMax(const std::string& dbase_location); + int Download_Status(const std::string& dbase_location); int Download_Shapes(const std::string& dbase_location); int Download_TimeCorr(const std::string& dbase_location); int Download_SlewCorr(const std::string& dbase_location); @@ -128,6 +131,7 @@ class MbdCalib #ifndef ONLINE int Write_CDB_SampMax(const std::string& dbfile); + int Write_CDB_Status(const std::string& dbfile); int Write_CDB_TTT0(const std::string& dbfile); int Write_CDB_TQT0(const std::string& dbfile); int Write_CDB_T0Corr(const std::string& dbfile); @@ -143,6 +147,7 @@ class MbdCalib #endif int Write_SampMax(const std::string& dbfile); + int Write_Status(const std::string& dbfile); int Write_TQT0(const std::string& dbfile); int Write_TTT0(const std::string& dbfile); int Write_T0Corr(const std::string& dbfile); @@ -231,6 +236,9 @@ class MbdCalib // SampMax (Peak of waveform) std::array _sampmax{}; + // Status (MBD Channel Status) + std::array _mbdstatus{}; + // Pileup waveform correction std::array _pileup_p0{}; std::array _pileup_p0err{}; diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index cdab537f45..04287aae2c 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -361,6 +361,22 @@ int MbdEvent::End() orig_dir->cd(); } + // Write out MbdSig eval histograms + if ( _doeval ) + { + TDirectory *orig_dir = gDirectory; + + TString savefname = "mbdeval_"; savefname += _runnum; savefname += ".root"; + _evalfile = std::make_unique(savefname,"RECREATE"); + + for (auto & sig : _mbdsig) + { + sig.WriteChi2Hist(); + } + + orig_dir->cd(); + } + return 1; } @@ -741,11 +757,6 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) // calpass 2, uncal_mbd. template fit. make sure qgain = 1, tq_t0 = 0 - // In Run 1 (runs before 40000), we didn't set hardware thresholds, and instead set a software threshold of 0.25 - if ( ((m_ampl[ifeech] < (_mbdcal->get_qgain(pmtch) * 0.25)) && (_runnum < 40000)) || std::fabs(_mbdcal->get_tq0(pmtch))>100. ) - { - m_qtdc[pmtch] = std::numeric_limits::quiet_NaN(); - } } } @@ -799,6 +810,12 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc m_pmttq[pmtch] = bbcraws->get_pmt(pmtch)->get_qtdc(); + // In Run 1 (runs before 40000), we didn't set hardware thresholds, and instead set a software threshold of 0.25 + if ( ((bbcraws->get_pmt(pmtch)->get_adc() < (_mbdcal->get_qgain(pmtch) * 0.25)) && (_runnum < 40000)) || std::fabs(_mbdcal->get_tq0(pmtch))>100. ) + { + m_qtdc[pmtch] = std::numeric_limits::quiet_NaN(); + } + if ( !std::isnan(m_pmttq[pmtch]) ) { m_pmttq[pmtch] -= (_mbdcal->get_sampmax(ifeech) - 2); @@ -809,7 +826,7 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc // if ( arm==1 ) std::cout << "hit_times " << ifeech << "\t" << setw(10) << m_pmttq[pmtch] << "\t" << board << "\t" << TRIG_SAMP[board] << std::endl; // if tt is bad, use tq - if ( std::fabs(_mbdcal->get_tt0(pmtch))>100. ) + if ( _mbdcal->get_status(ifeech-8)>0 ) { m_pmttt[pmtch] = m_pmttq[pmtch]; } diff --git a/offline/packages/mbd/MbdEvent.h b/offline/packages/mbd/MbdEvent.h index ede1670171..5abd48aeae 100644 --- a/offline/packages/mbd/MbdEvent.h +++ b/offline/packages/mbd/MbdEvent.h @@ -74,6 +74,7 @@ class MbdEvent void set_EventNumber(int ievt) { m_evt = ievt; } void set_debug(const int d) { _debug = d; } + void set_doeval(const int d) { _doeval = d; } MbdSig *GetSig(const int ipmt) { return &_mbdsig[ipmt]; } @@ -196,12 +197,14 @@ class MbdEvent // debug stuff TCanvas *ac{nullptr}; // for plots used during debugging void PlotDebug(); + int _doeval{0}; + std::unique_ptr _evalfile{nullptr}; std::unique_ptr _synctfile{nullptr}; TTree *_syncttree{nullptr}; Double_t _refz{ std::numeric_limits::quiet_NaN() }; - std::vector bbevt; + std::vector bbevt; std::vector bbclk; - std::vector mybbz; + std::vector mybbz; std::vector bco; std::vector intz; std::vector bbz; diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index ae1f821a4e..72438e4046 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -74,10 +74,13 @@ void MbdSig::Init() ped_tail = new TF1("ped_tail","[0]+[1]*exp(-[2]*x)",0,2); ped_tail->SetLineColor(2); - // uncomment this to write out waveforms from events that have pileup from prev. crossing + name = "h_chi2ndf"; name += _ch; + h_chi2ndf = new TH1F(name,name,2000,0,100); + + // uncomment this to write out waveforms from events that have pileup from prev. crossing or next crossing /* name = "mbdsig"; name += _ch; name += ".txt"; - _pileupfile = new ofstream(name); + _pileupfile = new std::ofstream(name); */ } @@ -251,6 +254,7 @@ void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert) { gRawPulse->Draw("ap"); gRawPulse->GetHistogram()->SetTitle(gRawPulse->GetName()); + gPad->SetGridx(1); gPad->SetGridy(1); PadUpdate(); } @@ -412,6 +416,11 @@ Double_t MbdSig::GetSplineAmpl() return f_ampl; } +void MbdSig::WriteChi2Hist() +{ + h_chi2ndf->Write(); +} + void MbdSig::WritePedHist() { hPed0->Write(); @@ -619,6 +628,7 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) //std::cout << PHWHERE << std::endl; gRawPulse->Fit( ped_fcn, "RNQ" ); + /* double chi2ndf = ped_fcn->GetChisquare()/ped_fcn->GetNDF(); if ( _pileupfile != nullptr && chi2ndf > 4.0 ) { @@ -629,6 +639,7 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) } *_pileupfile << std::endl; } + */ } double chi2 = ped_fcn->GetChisquare(); @@ -988,6 +999,12 @@ void MbdSig::PadUpdate() const } } +Double_t MbdSig::TwoTemplateFcn(const Double_t* x, const Double_t* par) +{ + Double_t f = TemplateFcn(x,par) + TemplateFcn(x,par+2); + return f; +} + Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) { // par[0] is the amplitude (relative to the spline amplitude) @@ -1106,8 +1123,13 @@ Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) int MbdSig::FitTemplate( const Int_t sampmax ) { //std::cout << PHWHERE << std::endl; //chiu - //_verbose = 100; // uncomment to see fits - //_verbose = 12; // don't see pedestal fits + /* + if ( _evt_counter==2142 && _ch==92 ) + { + _verbose = 100; // uncomment to see fits + //_verbose = 12; // don't see pedestal fits + } + */ // Check if channel is empty if (gSubPulse->GetN() == 0) @@ -1124,22 +1146,22 @@ int MbdSig::FitTemplate( const Int_t sampmax ) int nsaturated = 0; for (int ipt=0; ipt 16370. ) + if ( rawsamps[ipt] > 16370. ) // don't trust adc near edge { nsaturated++; } } /* - if ( nsaturated>2 && _ch==185 ) + //if ( nsaturated>2 && _ch==185 ) + if ( nsaturated>2 ) { _verbose = 12; } */ - if (_verbose > 0) { - std::cout << "Fitting ch " << _ch << std::endl; + std::cout << "Fitting ch sampmax " << _ch << "\t" << sampmax << std::endl; } // Get x and y of maximum @@ -1147,7 +1169,17 @@ int MbdSig::FitTemplate( const Int_t sampmax ) Double_t ymax{0.}; if ( sampmax>=0 ) { - gSubPulse->GetPoint(sampmax, x_at_max, ymax); + for (int isamp=sampmax-1; isamp<=sampmax+1; isamp++) + { + double adcval = gSubPulse->GetPointY(isamp); + if ( adcval>ymax ) + { + ymax = adcval; + x_at_max = isamp; + } + } + + //gSubPulse->GetPoint(sampmax, x_at_max, ymax); if ( nsaturated<=3 ) { x_at_max -= 2.0; @@ -1176,6 +1208,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) gSubPulse->Draw("ap"); gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); gPad->SetGridy(1); + gPad->SetGridx(1); PadUpdate(); } @@ -1184,23 +1217,15 @@ int MbdSig::FitTemplate( const Int_t sampmax ) } template_fcn->SetParameters(ymax, x_at_max); - // template_fcn->SetParLimits(1, fit_min_time, fit_max_time); - // template_fcn->SetParLimits(1, 3, 15); - // template_fcn->SetRange(template_min_xrange,template_max_xrange); if ( nsaturated<=3 ) { - template_fcn->SetRange(0, _nsamples); + template_fcn->SetRange(0, x_at_max+4.2); } else { template_fcn->SetRange(0, sampmax + nsaturated - 0.5); } - if ( gSubPulse->GetN()==0 )//chiu - { - std::cout << PHWHERE << " gSubPulse 0" << std::endl; - } - if (_verbose == 0) { //std::cout << PHWHERE << std::endl; @@ -1214,24 +1239,88 @@ int MbdSig::FitTemplate( const Int_t sampmax ) gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); gPad->SetGridy(1); PadUpdate(); - //std::cout << "doing fit2 " << _verbose << std::endl; - //std::cout << "doing fit3 " << _verbose << std::endl; //gSubPulse->Print("ALL"); } // Get fit parameters f_ampl = template_fcn->GetParameter(0); f_time = template_fcn->GetParameter(1); - if ( f_time<0. || f_time>_nsamples ) + f_chi2 = template_fcn->GetChisquare(); + f_ndf = template_fcn->GetNDF(); + + // Good fit + if ( (f_chi2/f_ndf) < 5. && f_ndf>6. ) { + h_chi2ndf->Fill( f_chi2/f_ndf ); + _verbose = 0; + return 1; + } + + // fit was out of time, likely from pileup, try two waveforms + if ( (f_time<(sampmax-2.5) || f_time>sampmax) && (nsaturated<=3) ) + { + //_verbose = 100; //chiu + + if ( _verbose ) + { + std::cout << "BADTIME " << _evt_counter << "\t" << _ch << "\t" << sampmax << "\t" << f_ampl << "\t" << f_time << std::endl; + gSubPulse->Draw("ap"); + template_fcn->Draw("same"); + PadUpdate(); + } + + twotemplate_fcn->SetParameters(ymax,x_at_max,ymax,10); + twotemplate_fcn->SetRange(0,_nsamples); + + if (_verbose == 0) + { + gSubPulse->Fit(twotemplate_fcn, "RNQ"); + } + else + { + std::cout << "doing fit1 " << x_at_max << "\t" << ymax << std::endl; + gSubPulse->Fit(twotemplate_fcn, "R"); + gSubPulse->Draw("ap"); + gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); + gPad->SetGridy(1); + PadUpdate(); + //gSubPulse->Print("ALL"); + } + + //PadUpdate(); + + // Get fit parameters + f_ampl = template_fcn->GetParameter(0); + f_time = template_fcn->GetParameter(1); + f_chi2 = template_fcn->GetChisquare(); + f_ndf = template_fcn->GetNDF(); + + // Good fit + if ( (f_chi2/f_ndf) < 5. && f_ndf>6. ) + { + h_chi2ndf->Fill( f_chi2/f_ndf ); + _verbose = 0; + return 1; + } + } + + + /* chiu + if ( f_time<0. || f_time>9 ) + { + _verbose = 100; f_time = _nsamples*0.5; // bad fit last time } + */ // refit with new range to exclude after-pulses - template_fcn->SetParameters( f_ampl, f_time ); + template_fcn->SetParameters(ymax, x_at_max); + //template_fcn->SetParameters( f_ampl, f_time ); + if ( nsaturated<=3 ) { - template_fcn->SetRange( 0., f_time+4.0 ); + template_fcn->SetRange(0, x_at_max+4.2); + //template_fcn->SetRange( 0., f_time+4.0 ); } else { @@ -1242,16 +1331,16 @@ int MbdSig::FitTemplate( const Int_t sampmax ) { //std::cout << PHWHERE << std::endl; int fit_status = gSubPulse->Fit(template_fcn, "RNQ"); - if ( fit_status<0 ) + if ( fit_status<0 && _verbose>0 ) { std::cout << PHWHERE << "\t" << fit_status << std::endl; gSubPulse->Print("ALL"); gSubPulse->Draw("ap"); gSubPulse->Fit(template_fcn, "R"); - std::cout << "ampl time before refit " << f_ampl << "\t" << f_time << std::endl; + std::cout << "ampl time before refit " << _ch << "\t" << f_ampl << "\t" << f_time << std::endl; f_ampl = template_fcn->GetParameter(0); f_time = template_fcn->GetParameter(1); - std::cout << "ampl time after refit " << f_ampl << "\t" << f_time << std::endl; + std::cout << "ampl time after refit " << _ch << "\t" << f_ampl << "\t" << f_time << std::endl; PadUpdate(); std::string junk; std::cin >> junk; @@ -1269,6 +1358,18 @@ int MbdSig::FitTemplate( const Int_t sampmax ) f_ampl = template_fcn->GetParameter(0); f_time = template_fcn->GetParameter(1); + f_chi2 = template_fcn->GetChisquare(); + f_ndf = template_fcn->GetNDF(); + + h_chi2ndf->Fill( f_chi2/f_ndf ); + + /* + if ( (f_chi2/f_ndf) > 100. ) //chiu + { + std::cout << "very bad chi2ndf after refit " << f_ampl << "\t" << f_time << "\t" << f_chi2/f_ndf << std::endl; + //_verbose = 100; + } + */ //if ( f_time<0 || f_time>30 ) //if ( (_ch==185||_ch==155||_ch==249) && (fabs(f_ampl) > 44000.) ) @@ -1282,6 +1383,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) std::cout << " " << template_fcn->GetChisquare()/template_fcn->GetNDF() << std::endl; gSubPulse->Draw("ap"); gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); + gPad->SetGridx(1); gPad->SetGridy(1); template_fcn->SetLineColor(4); template_fcn->Draw("same"); @@ -1323,6 +1425,16 @@ int MbdSig::SetTemplate(const std::vector& shape, const std::vectorSetParName(1, "time"); SetTemplateSize(900, 1000, -10., 20.); + name = "twotemplate_fcn"; + name += _ch; + twotemplate_fcn = new TF1(name, this, &MbdSig::TwoTemplateFcn, 0, _nsamples, 4, "MbdSig", "TwoTemplateFcn"); + twotemplate_fcn->SetLineColor(3); + twotemplate_fcn->SetParameters(1, 6, 1,8); + twotemplate_fcn->SetParName(0, "ampl"); + twotemplate_fcn->SetParName(1, "time"); + twotemplate_fcn->SetParName(2, "ampl2"); + twotemplate_fcn->SetParName(3, "time2"); + if (_verbose) { std::cout << "SHAPE " << _ch << std::endl; diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index e933f33392..a3ee986c33 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -111,10 +111,12 @@ class MbdSig // Double_t FitPulse(); void SetTimeOffset(const Double_t o) { f_time_offset = o; } Double_t TemplateFcn(const Double_t *x, const Double_t *par); + Double_t TwoTemplateFcn(const Double_t *x, const Double_t *par); TF1 *GetTemplateFcn() { return template_fcn; } void SetMinMaxFitTime(const Double_t mintime, const Double_t maxtime); void WritePedHist(); + void WriteChi2Hist(); void DrawWaveform(); /// Draw Subtracted Waveform void PadUpdate() const; @@ -144,6 +146,9 @@ class MbdSig Double_t f_integral{0.}; /** integral */ + Double_t f_chi2{0.}; + Double_t f_ndf{0.}; + TH1 *hRawPulse{nullptr}; //! TH1 *hSubPulse{nullptr}; //! TH1 *hpulse{nullptr}; //! @@ -182,19 +187,17 @@ class MbdSig Int_t template_npointsy{0}; Double_t template_begintime{0.}; Double_t template_endtime{0.}; - // Double_t template_min_good_amplitude{20.}; //! for template, in original units of waveform data - // Double_t template_max_good_amplitude{4080.}; //! for template, in original units of waveform data - // Double_t template_min_xrange{0.}; //! for template, in original units of waveform data - // Double_t template_max_xrange{0.}; //! for template, in original units of waveform data std::vector template_y; std::vector template_yrms; TF1 *template_fcn{nullptr}; + TF1 *twotemplate_fcn{nullptr}; Double_t fit_min_time{}; //! min time for fit, in original units of waveform data Double_t fit_max_time{}; //! max time for fit, in original units of waveform data std::ofstream *_pileupfile{nullptr}; // for writing out waveforms from prev. crossing pileup // use for calibrating out the tail from these events + TH1 *h_chi2ndf{nullptr}; //! for eval int _verbose{0}; }; From d7dc7f81f699f3c8861376349b808df1a972e55e Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Tue, 27 Jan 2026 13:01:38 -0500 Subject: [PATCH 126/866] rabbit fixes --- offline/packages/mbd/MbdCalib.cc | 4 ++-- offline/packages/mbd/MbdSig.cc | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 1367b375c8..e76763c9b7 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -1683,7 +1683,7 @@ int MbdCalib::Write_CDB_Status(const std::string& dbfile) if (ifeech < 12 || ifeech >= MbdDefs::MBD_N_FEECH - 5) { - std::cout << ifeech << "\t" << std::hex << cdbttree->GetIntValue(ifeech, "status") << std::dec << std::endl; + std::cout << ifeech << "\t" << cdbttree->GetIntValue(ifeech, "status") << std::endl; } } @@ -1704,7 +1704,7 @@ int MbdCalib::Write_Status(const std::string& dbfile) cal_file.open(dbfile); for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) { - cal_file << ifeech << "\t0x" << std::hex << _mbdstatus[ifeech] << std::dec << std::endl; + cal_file << ifeech << "\t" << _mbdstatus[ifeech] << std::endl; } cal_file.close(); diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index 72438e4046..65359d197a 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -145,8 +145,10 @@ MbdSig::~MbdSig() delete hAmpl; delete hTime; delete template_fcn; + delete twotemplate_fcn; delete ped_fcn; delete ped_tail; + delete h_chi2ndf; } void MbdSig::SetEventPed0PreSamp(const Int_t presample, const Int_t nsamps, const int max_samp) @@ -1167,10 +1169,14 @@ int MbdSig::FitTemplate( const Int_t sampmax ) // Get x and y of maximum Double_t x_at_max{-1.}; Double_t ymax{0.}; - if ( sampmax>=0 ) + if ( sampmax>0 ) { for (int isamp=sampmax-1; isamp<=sampmax+1; isamp++) { + if ( (isamp>=gSubPulse->GetN()) ) + { + continue; + } double adcval = gSubPulse->GetPointY(isamp); if ( adcval>ymax ) { From 49276961b21d048882ceefa3a4e6e48d2fd49cee Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Tue, 27 Jan 2026 13:48:27 -0500 Subject: [PATCH 127/866] rabbit fixes part deux, plus added fiteval --- offline/packages/mbd/MbdCalib.cc | 8 +++++++- offline/packages/mbd/MbdEvent.cc | 6 ++++-- offline/packages/mbd/MbdReco.cc | 1 + offline/packages/mbd/MbdReco.h | 6 ++++-- offline/packages/mbd/MbdSig.cc | 8 ++++---- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index e76763c9b7..0ce5b4cd32 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -739,6 +739,12 @@ int MbdCalib::Download_Status(const std::string& dbase_location) int feech = -1; while (infile >> feech) { + if (feech < 0 || feech >= MbdDefs::MBD_N_FEECH) + { + std::cout << "ERROR, invalid FEECH " << feech << " in MBD status calibration" << std::endl; + _status = -4; + return _status; + } infile >> _mbdstatus[feech]; if (Verbosity() > 0) { @@ -750,7 +756,7 @@ int MbdCalib::Download_Status(const std::string& dbase_location) } infile.close(); } - + if ( _mbdstatus[0] == -1 ) { diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index 04287aae2c..ed5047f2a8 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -35,6 +35,7 @@ #include #include #include +#include MbdEvent::MbdEvent(const int cal_pass, const bool proc_charge) : _nsamples(MbdDefs::MAX_SAMPLES), @@ -366,8 +367,9 @@ int MbdEvent::End() { TDirectory *orig_dir = gDirectory; - TString savefname = "mbdeval_"; savefname += _runnum; savefname += ".root"; - _evalfile = std::make_unique(savefname,"RECREATE"); + // _doeval is overloaded with segment_number+1 + std::string savefname = std::format("mbdfiteval_{:08}-{:05}.root",_runnum,_doeval-1); + _evalfile = std::make_unique(savefname.c_str(),"RECREATE"); for (auto & sig : _mbdsig) { diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index 004e191e78..5b070929ac 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -65,6 +65,7 @@ int MbdReco::InitRun(PHCompositeNode *topNode) m_mbdevent->SetSim(_simflag); m_mbdevent->SetRawDstFlag(_rawdstflag); m_mbdevent->SetFitsOnly(_fitsonly); + m_mbdevent->set_doeval(_fiteval); m_mbdevent->InitRun(); return ret; diff --git a/offline/packages/mbd/MbdReco.h b/offline/packages/mbd/MbdReco.h index 6e00de68f3..eced3b89e9 100644 --- a/offline/packages/mbd/MbdReco.h +++ b/offline/packages/mbd/MbdReco.h @@ -34,10 +34,11 @@ class MbdReco : public SubsysReco int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; - void DoOnlyFits() { _fitsonly = 1; } + void DoOnlyFits() { _fitsonly = 1; } + void DoFitEval(const int s) { _fiteval = s; } void SetCalPass(const int calpass) { _calpass = calpass; } void SetProcChargeCh(const bool s) { _always_process_charge = s; } - void SetMbdTrigOnly(const int m) { _mbdonly = m; } + void SetMbdTrigOnly(const int m) { _mbdonly = m; } private: int createNodes(PHCompositeNode *topNode); @@ -48,6 +49,7 @@ class MbdReco : public SubsysReco int _mbdonly{0}; // only use mbd triggers int _rawdstflag{0}; // dst with raw container int _fitsonly{0}; // stop reco after waveform fits (for DST_CALOFIT pass) + int _fiteval{0}; // overload with segment+1 float m_tres = 0.05; std::unique_ptr m_gaussian = nullptr; diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index 65359d197a..1118ba2e60 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -1296,10 +1296,10 @@ int MbdSig::FitTemplate( const Int_t sampmax ) //PadUpdate(); // Get fit parameters - f_ampl = template_fcn->GetParameter(0); - f_time = template_fcn->GetParameter(1); - f_chi2 = template_fcn->GetChisquare(); - f_ndf = template_fcn->GetNDF(); + f_ampl = twotemplate_fcn->GetParameter(0); + f_time = twotemplate_fcn->GetParameter(1); + f_chi2 = twotemplate_fcn->GetChisquare(); + f_ndf = twotemplate_fcn->GetNDF(); // Good fit if ( (f_chi2/f_ndf) < 5. && f_ndf>6. ) From 5c8076fe632e6fd3735b9c93724c4a899513327f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 27 Jan 2026 19:40:29 +0000 Subject: [PATCH 128/866] Fix missing final newline in docstring PR --- offline/packages/trackreco/PHSiliconSeedMerger.cc | 1 + offline/packages/trackreco/PHSiliconSeedMerger.h | 1 + 2 files changed, 2 insertions(+) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 8edb5816c3..6e012a606d 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -317,3 +317,4 @@ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } + diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index 7ab50a44df..54d4758739 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -73,3 +73,4 @@ bool m_mvtxOnly{false}; }; #endif // PHSILICONSEEDMERGER_H + From 924e18e72bca44b23c29afe36fd47b143a238d52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 27 Jan 2026 19:44:56 +0000 Subject: [PATCH 129/866] Fix missing final newline in docstring PR --- offline/packages/trackreco/PHSiliconSeedMerger.cc | 1 + offline/packages/trackreco/PHSiliconSeedMerger.h | 1 + 2 files changed, 2 insertions(+) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 6e012a606d..263fdd6b35 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -318,3 +318,4 @@ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } + diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index db80f35259..fcd741e688 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -74,3 +74,4 @@ bool m_mvtxOnly{false}; #endif // PHSILICONSEEDMERGER_H + From 34a2897407c7c5b732feb420a7a3eb76a3fc1af4 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:17:55 +0000 Subject: [PATCH 130/866] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20?= =?UTF-8?q?`function=5Ffit`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @pinkenburg. * https://github.com/sPHENIX-Collaboration/coresoftware/pull/4138#issuecomment-3795382670 The following files were modified: * `simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc` * `simulation/g4simulation/g4main/PHG4TruthTrackingAction.h` --- .../g4main/PHG4TruthTrackingAction.cc | 25 +++++++- .../g4main/PHG4TruthTrackingAction.h | 64 ++++++++++++++++++- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc index da01d9d5e3..330167495d 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc @@ -305,6 +305,17 @@ PHG4Particle* PHG4TruthTrackingAction::AddParticle(PHG4TruthInfoContainer& truth return truth.AddParticle(trackid, ti)->second; } +/** + * @brief Create or retrieve a truth vertex for a Geant4 track keyed by position and production process. + * + * Uses the track vertex position combined with the mapped MC production process to look up an existing + * vertex or create a new PHG4VtxPoint and register it in the truth container. The vertex index is chosen + * positive for primary tracks and negative for secondaries. + * + * @param truth Container in which to find or register the vertex. + * @param track Geant4 track whose production vertex and creator process determine the vertex key. + * @return PHG4VtxPoint* Pointer to the vertex instance stored in the truth container. + */ PHG4VtxPoint* PHG4TruthTrackingAction::AddVertex(PHG4TruthInfoContainer& truth, const G4Track& track) { G4ThreeVector v = track.GetVertexPosition(); @@ -334,6 +345,18 @@ PHG4VtxPoint* PHG4TruthTrackingAction::AddVertex(PHG4TruthInfoContainer& truth, return truth.AddVertex(vtxindex, vtxpt)->second; } +/** + * @brief Determine whether a PHG4Particle should be considered an sPHENIX primary. + * + * Evaluates the particle's production vertex, PDG id longevity, and ancestry to decide + * if it originates as an sPHENIX primary (produced as a primary or from a decay and + * having no long-lived ancestor produced by material interactions). + * + * @param truth Truth container used to look up particle parents and production vertices. + * @param particle Particle to evaluate. + * @return true if the particle is classified as an sPHENIX primary, `false` otherwise. + * + */ bool PHG4TruthTrackingAction::issPHENIXPrimary(PHG4TruthInfoContainer& truth, PHG4Particle* particle) const { PHG4VtxPoint* vtx = truth.GetVtx(particle->get_vtx_id()); @@ -453,4 +476,4 @@ bool PHG4TruthTrackingAction::isLongLived(int pid) const default: return false; } -} +} \ No newline at end of file diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h index 8025d7c9bb..0602025889 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h @@ -19,6 +19,68 @@ class PHG4TruthEventAction; class PHG4Particle; class PHG4VtxPoint; +/** + * Construct a PHG4TruthTrackingAction associated with an event action. + * @param eventAction Pointer to the owning PHG4TruthEventAction used to record per-event truth information. + */ + +/** + * Destroy the PHG4TruthTrackingAction. + */ + +/** + * Handle actions to perform before Geant4 begins tracking a G4 track. + * @param track The Geant4 track about to be processed. + */ + +/** + * Handle actions to perform after Geant4 finishes tracking a G4 track. + * @param track The Geant4 track that has just been processed. + */ + +/** + * Set required node/interface pointers from the given top-level node. + * @param topNode Pointer to the PHCompositeNode root from which required I/O nodes are retrieved. + * @returns Zero on success, non-zero on failure. + */ + +/** + * Reset per-event state using nodes found under the given composite node. + * @param topNode Pointer to the PHCompositeNode for the current event. + * @returns Zero on success, non-zero on failure. + */ + +/** + * Create or update a truth particle entry corresponding to the provided Geant4 track. + * @param truth Container to which the particle entry will be added or updated. + * @param track Geant4 track from which particle information is derived. + * @returns Pointer to the created or updated PHG4Particle. + */ + +/** + * Create or update a truth vertex entry corresponding to the provided Geant4 track. + * @param truth Container to which the vertex entry will be added or updated. + * @param track Geant4 track whose production point will be recorded as a vertex. + * @returns Pointer to the created or updated PHG4VtxPoint. + */ + +/** + * Determine whether a particle type is considered long-lived for truth-building. + * @param pid Particle PDG identifier. + * @returns `true` if the particle with the given PDG id is treated as long-lived, `false` otherwise. + */ + +/** + * Determine whether a particle should be flagged as an sPHENIX primary. + * @param truth Truth information container used to evaluate primary status. + * @param particle Particle to evaluate. + * @returns `true` if the particle is considered an sPHENIX primary, `false` otherwise. + */ + +/** + * Update the internal upstream G4 particle stack when processing a new Geant4 track. + * @param track Geant4 track used to update parent/ancestor particle bookkeeping. + */ class PHG4TruthTrackingAction : public PHG4TrackingAction { public: @@ -73,4 +135,4 @@ class PHG4TruthTrackingAction : public PHG4TrackingAction ///@} }; -#endif +#endif \ No newline at end of file From a9adfb154472086a9ee43dbcbe047ff1ce48c84e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 27 Jan 2026 22:18:12 +0000 Subject: [PATCH 131/866] Fix missing final newline in docstring PR --- simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc | 2 +- simulation/g4simulation/g4main/PHG4TruthTrackingAction.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc index 330167495d..614712d4d3 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc @@ -476,4 +476,4 @@ bool PHG4TruthTrackingAction::isLongLived(int pid) const default: return false; } -} \ No newline at end of file +} diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h index 0602025889..99e0c4669e 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h @@ -135,4 +135,4 @@ class PHG4TruthTrackingAction : public PHG4TrackingAction ///@} }; -#endif \ No newline at end of file +#endif From f493c6eb0512565fb0ba363549ac1d5e89814e21 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Tue, 27 Jan 2026 22:01:06 -0500 Subject: [PATCH 132/866] aborts run if calibration is missing for doing fits --- offline/packages/mbd/MbdCalib.cc | 25 +++++++++++++++++++++++++ offline/packages/mbd/MbdEvent.cc | 14 ++++++++++---- offline/packages/mbd/MbdReco.cc | 7 ++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 0ce5b4cd32..a6e5c773b1 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -80,6 +80,11 @@ int MbdCalib::Download_All() if (!_rc->FlagExist("MBD_CALDIR")) { std::string sampmax_url = _cdb->getUrl("MBD_SAMPMAX"); + if ( sampmax_url.empty() ) + { + std::cerr << "ERROR, MBD_SAMPMAX missing" << std::endl; + return -1; + } if (Verbosity() > 0) { std::cout << "sampmax_url " << sampmax_url << std::endl; @@ -87,6 +92,11 @@ int MbdCalib::Download_All() Download_SampMax(sampmax_url); std::string status_url = _cdb->getUrl("MBD_STATUS"); + if ( status_url.empty() ) + { + std::cerr << "ERROR, MBD_STATUS missing" << std::endl; + return -1; + } if (Verbosity() > 0) { std::cout << "status_url " << status_url << std::endl; @@ -96,6 +106,11 @@ int MbdCalib::Download_All() if ( !_rawdstflag ) { std::string ped_url = _cdb->getUrl("MBD_PED"); + if ( ped_url.empty() ) + { + std::cerr << "ERROR, MBD_PED missing" << std::endl; + return -1; + } if (Verbosity() > 0) { std::cout << "ped_url " << ped_url << std::endl; @@ -104,6 +119,11 @@ int MbdCalib::Download_All() std::string pileup_url = _cdb->getUrl("MBD_PILEUP"); + if ( pileup_url.empty() ) + { + std::cerr << "ERROR, MBD_PILEUP missing" << std::endl; + return -1; + } if (Verbosity() > 0) { std::cout << "pileup_url " << pileup_url << std::endl; @@ -113,6 +133,11 @@ int MbdCalib::Download_All() if (do_templatefit) { std::string shape_url = _cdb->getUrl("MBD_SHAPES"); + if ( shape_url.empty() ) + { + std::cerr << "ERROR, MBD_SHAPES missing" << std::endl; + return -1; + } if (Verbosity() > 0) { std::cout << "shape_url " << shape_url << std::endl; diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index ed5047f2a8..0ed3886a60 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -151,7 +151,11 @@ int MbdEvent::InitRun() _mbdcal->SetRawDstFlag( _rawdstflag ); _mbdcal->SetFitsOnly( _fitsonly ); - _mbdcal->Download_All(); + int status = _mbdcal->Download_All(); + if ( status == -1 ) + { + return Fun4AllReturnCodes::ABORTRUN; + } if ( _simflag == 0 ) // do following for real data { @@ -810,12 +814,14 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc // or have time channels marked as bad // or have always_process_charge set to 1 (useful for threshold studies) - m_pmttq[pmtch] = bbcraws->get_pmt(pmtch)->get_qtdc(); - // In Run 1 (runs before 40000), we didn't set hardware thresholds, and instead set a software threshold of 0.25 if ( ((bbcraws->get_pmt(pmtch)->get_adc() < (_mbdcal->get_qgain(pmtch) * 0.25)) && (_runnum < 40000)) || std::fabs(_mbdcal->get_tq0(pmtch))>100. ) { - m_qtdc[pmtch] = std::numeric_limits::quiet_NaN(); + m_pmttq[pmtch] = std::numeric_limits::quiet_NaN(); + } + else + { + m_pmttq[pmtch] = bbcraws->get_pmt(pmtch)->get_qtdc(); } if ( !std::isnan(m_pmttq[pmtch]) ) diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index 5b070929ac..26f53ba70c 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -61,12 +61,17 @@ int MbdReco::InitRun(PHCompositeNode *topNode) } int ret = getNodes(topNode); + if ( ret != Fun4AllReturnCodes::EVENT_OK ) + { + return ret; + } m_mbdevent->SetSim(_simflag); m_mbdevent->SetRawDstFlag(_rawdstflag); m_mbdevent->SetFitsOnly(_fitsonly); m_mbdevent->set_doeval(_fiteval); - m_mbdevent->InitRun(); + + ret = m_mbdevent->InitRun(); return ret; } From 8bc0f1f7ceaa9e5342674eca1691d8db28bc0628 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 28 Jan 2026 09:06:19 -0500 Subject: [PATCH 133/866] make function const --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 2 +- offline/packages/trackreco/PHActsSiliconSeeding.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index fb1c4b6de9..aba61d0943 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -1745,7 +1745,7 @@ double PHActsSiliconSeeding::normPhi2Pi(const double phi) return returnPhi; } -float PHActsSiliconSeeding::getPhiFromBeamSpot(float clusy, float clusx) +float PHActsSiliconSeeding::getPhiFromBeamSpot(float clusy, float clusx) const { // Calculate the phi value for (clusx, clusy) relative to the beam spot (x,y) position diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.h b/offline/packages/trackreco/PHActsSiliconSeeding.h index f37937903b..506f9c225c 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.h +++ b/offline/packages/trackreco/PHActsSiliconSeeding.h @@ -253,7 +253,7 @@ class PHActsSiliconSeeding : public SubsysReco short int getCrossingIntt(TrackSeed &si_track); std::vector getInttCrossings(TrackSeed &si_track); - float getPhiFromBeamSpot(float clusy, float clusx); + float getPhiFromBeamSpot(float clusy, float clusx) const; void createHistograms(); void writeHistograms(); From 8fb707e05cbc56c6c6f81f8b83a5b6ecbf6c15d0 Mon Sep 17 00:00:00 2001 From: Hao-Ren Jheng Date: Wed, 28 Jan 2026 11:35:59 -0500 Subject: [PATCH 134/866] Revert "use short int for vertex beam crossing" This reverts commit 2963c36785cc61b40722e0139177340f09977c7a. --- offline/packages/globalvertex/MbdVertex.h | 4 ++-- offline/packages/globalvertex/MbdVertexv2.h | 6 +++--- offline/packages/globalvertex/SvtxVertex.h | 3 --- offline/packages/globalvertex/SvtxVertex_v2.h | 6 +++--- offline/packages/globalvertex/Vertex.h | 4 ++-- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/offline/packages/globalvertex/MbdVertex.h b/offline/packages/globalvertex/MbdVertex.h index bda5c74597..6d0900b768 100644 --- a/offline/packages/globalvertex/MbdVertex.h +++ b/offline/packages/globalvertex/MbdVertex.h @@ -36,8 +36,8 @@ class MbdVertex : public Vertex virtual float get_z_err() const override { return std::numeric_limits::quiet_NaN(); } virtual void set_z_err(float) override {} - virtual short int get_beam_crossing() const override { return std::numeric_limits::max(); } - virtual void set_beam_crossing(short int) override {} + virtual unsigned int get_beam_crossing() const override { return std::numeric_limits::max(); } + virtual void set_beam_crossing(unsigned int) override {} virtual void set_bbc_ns(int, int, float, float) override {} virtual int get_bbc_npmt(int) const override { return std::numeric_limits::max(); } diff --git a/offline/packages/globalvertex/MbdVertexv2.h b/offline/packages/globalvertex/MbdVertexv2.h index d0aac0f70b..bee34059e4 100644 --- a/offline/packages/globalvertex/MbdVertexv2.h +++ b/offline/packages/globalvertex/MbdVertexv2.h @@ -44,12 +44,12 @@ class MbdVertexv2 : public MbdVertex float get_position(unsigned int coor) const override; - short int get_beam_crossing() const override { return _bco; } - void set_beam_crossing(short int bco) override { _bco = bco; } + unsigned int get_beam_crossing() const override { return _bco; } + void set_beam_crossing(unsigned int bco) override { _bco = bco; } private: unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container - short int _bco{std::numeric_limits::max()}; //< global bco + unsigned int _bco{std::numeric_limits::max()}; //< global bco float _t{std::numeric_limits::quiet_NaN()}; //< collision time float _t_err{std::numeric_limits::quiet_NaN()}; //< collision time uncertainty float _z{std::numeric_limits::quiet_NaN()}; //< collision position z diff --git a/offline/packages/globalvertex/SvtxVertex.h b/offline/packages/globalvertex/SvtxVertex.h index 5006784f55..cd9c77454c 100644 --- a/offline/packages/globalvertex/SvtxVertex.h +++ b/offline/packages/globalvertex/SvtxVertex.h @@ -56,9 +56,6 @@ class SvtxVertex : public Vertex virtual float get_error(unsigned int, unsigned int) const override { return std::numeric_limits::quiet_NaN(); } virtual void set_error(unsigned int, unsigned int, float) override {} - virtual short int get_beam_crossing() const override { return std::numeric_limits::max(); } - virtual void set_beam_crossing(short int) override {} - // // associated track ids methods // diff --git a/offline/packages/globalvertex/SvtxVertex_v2.h b/offline/packages/globalvertex/SvtxVertex_v2.h index d1bf04e0b4..24ccbfc0ca 100644 --- a/offline/packages/globalvertex/SvtxVertex_v2.h +++ b/offline/packages/globalvertex/SvtxVertex_v2.h @@ -54,8 +54,8 @@ class SvtxVertex_v2 : public SvtxVertex float get_error(unsigned int i, unsigned int j) const override; //< get vertex error covar void set_error(unsigned int i, unsigned int j, float value) override; //< set vertex error covar - short int get_beam_crossing() const override { return _beamcrossing; } - void set_beam_crossing(short int cross) override { _beamcrossing = cross; } + unsigned int get_beam_crossing() const override { return _beamcrossing; } + void set_beam_crossing(unsigned int cross) override { _beamcrossing = cross; } // // associated track ids methods @@ -82,7 +82,7 @@ class SvtxVertex_v2 : public SvtxVertex unsigned int _ndof{std::numeric_limits::max()}; //< degrees of freedom float _err[6]{}; //< error covariance matrix (packed storage) (+/- cm^2) std::set _track_ids; //< list of track ids - short int _beamcrossing{std::numeric_limits::max()}; + unsigned int _beamcrossing{std::numeric_limits::max()}; ClassDefOverride(SvtxVertex_v2, 2); }; diff --git a/offline/packages/globalvertex/Vertex.h b/offline/packages/globalvertex/Vertex.h index e475bfb95d..7bbfa5f381 100644 --- a/offline/packages/globalvertex/Vertex.h +++ b/offline/packages/globalvertex/Vertex.h @@ -62,8 +62,8 @@ class Vertex : public PHObject virtual void set_error(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} // beam crossing methods - virtual short int get_beam_crossing() const { return std::numeric_limits::max(); } - virtual void set_beam_crossing(short int) {} + virtual unsigned int get_beam_crossing() const { return std::numeric_limits::max(); } + virtual void set_beam_crossing(unsigned int) {} // bbcvertex methods virtual void set_bbc_ns(int, int, float, float) {} From 71c84483e3f9a8c8153b4767cdbe3d90313b8064 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Wed, 28 Jan 2026 14:12:00 -0500 Subject: [PATCH 135/866] Coderabbit was correct, bug fix. --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index fb1c4b6de9..c7f44d396b 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -822,7 +822,8 @@ std::vector PHActsSiliconSeeding::findMatches( avgtripletx += std::cos(getPhiFromBeamSpot(pos(1), pos(0))); avgtriplety += std::sin(getPhiFromBeamSpot(pos(1), pos(0))); } - float avgtripletphi = getPhiFromBeamSpot(avgtriplety, avgtripletx); + + float avgtripletphi = std::atan2(avgtriplety, avgtripletx); std::vector dummykeys = keys; std::vector dummyclusters = clusters; @@ -1159,7 +1160,7 @@ std::vector> PHActsSiliconSeeding::iterateLayers( avgtriplety += std::sin(getPhiFromBeamSpot(pos(1), pos(0))); } - float avgtripletphi = getPhiFromBeamSpot(avgtriplety, avgtripletx); + float avgtripletphi = std::atan2(avgtriplety, avgtripletx); int layer34timebucket = std::numeric_limits::max(); for (const auto& key : keys) From 918880db72cf231d36fa2d565849075c4353c76d Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:52:43 -0500 Subject: [PATCH 136/866] CaloValid - O+O Update - Updated downscale factors for the calorimeters and mbd by the ratio of nucleons: OO / AuAu - Add "OO" as a m_species option - Updated RunnumberRange to place temporary first and last for OO as well as update the last runnumber for proton+proton. --- offline/QA/Calorimeters/CaloValid.cc | 28 ++++++++++++++++++++++++ offline/framework/phool/RunnumberRange.h | 4 +++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index c51f75c200..54598ceaf0 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -117,6 +117,14 @@ int CaloValid::InitRun(PHCompositeNode* topNode) std::cout << "This run is from Run-3 Au+Au.\n"; } } + else if (runnumber >= RunnumberRange::RUN3OO_FIRST && runnumber <= RunnumberRange::RUN3OO_LAST) + { + m_species = "OO"; + if (Verbosity() > 0) + { + std::cout << "This run is from Run-3 O+O.\n"; + } + } else { if (Verbosity() > 0) @@ -216,6 +224,26 @@ int CaloValid::process_towers(PHCompositeNode* topNode) ohcal_highhit_threshold = 3.0; ihcal_highhit_threshold = 3.0; } + else if (m_species == "OO") + { + // Scale by the ratio of nucleons: OO/AuAu + float scale_factor = 16. / 197.; + + emcaldownscale = (1350000. / 800.) * scale_factor; + ihcaldownscale = (55000. / 300.) * scale_factor; + ohcaldownscale = (265000. / 600.) * scale_factor; + mbddownscale = 2800.0 * scale_factor; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; + + emcal_hit_threshold = 0.5; // GeV + ohcal_hit_threshold = 0.5; + ihcal_hit_threshold = 0.25; + + emcal_highhit_threshold = 3.0; + ohcal_highhit_threshold = 3.0; + ihcal_highhit_threshold = 3.0; + } else { emcaldownscale = 100000. / 800.; diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index a9a860e583..5d14a79350 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -12,7 +12,9 @@ namespace RunnumberRange static const int RUN3AUAU_FIRST = 66457; static const int RUN3AUAU_LAST = 78954; static const int RUN3PP_FIRST = 79146; // first beam data - static const int RUN3PP_LAST = 100000; + static const int RUN3PP_LAST = 81668; + static const int RUN3OO_FIRST = 82300; // TEMP (to be updated once OO starts) + static const int RUN3OO_LAST = 200000; } #endif From 3c966d3934fc23cb1be61bef7171d51167de2140 Mon Sep 17 00:00:00 2001 From: Hao-Ren Jheng Date: Wed, 28 Jan 2026 17:52:24 -0500 Subject: [PATCH 137/866] New version of SvtxVertex, MbdVertex, and GlovalVertex to use short instead of unsigned int --- offline/packages/globalvertex/GlobalVertex.h | 4 +- .../packages/globalvertex/GlobalVertexv2.h | 37 ++- .../packages/globalvertex/GlobalVertexv3.cc | 231 ++++++++++++++++++ .../packages/globalvertex/GlobalVertexv3.h | 73 ++++++ .../globalvertex/GlobalVertexv3LinkDef.h | 5 + offline/packages/globalvertex/Makefile.am | 9 + offline/packages/globalvertex/MbdVertex.h | 8 +- offline/packages/globalvertex/MbdVertexv2.h | 50 +++- offline/packages/globalvertex/MbdVertexv3.cc | 60 +++++ offline/packages/globalvertex/MbdVertexv3.h | 60 +++++ .../globalvertex/MbdVertexv3LinkDef.h | 5 + offline/packages/globalvertex/SvtxVertex_v2.h | 48 +++- .../packages/globalvertex/SvtxVertex_v3.cc | 113 +++++++++ offline/packages/globalvertex/SvtxVertex_v3.h | 89 +++++++ .../globalvertex/SvtxVertex_v3LinkDef.h | 5 + offline/packages/globalvertex/Vertex.h | 4 +- 16 files changed, 788 insertions(+), 13 deletions(-) create mode 100644 offline/packages/globalvertex/GlobalVertexv3.cc create mode 100644 offline/packages/globalvertex/GlobalVertexv3.h create mode 100644 offline/packages/globalvertex/GlobalVertexv3LinkDef.h create mode 100644 offline/packages/globalvertex/MbdVertexv3.cc create mode 100644 offline/packages/globalvertex/MbdVertexv3.h create mode 100644 offline/packages/globalvertex/MbdVertexv3LinkDef.h create mode 100644 offline/packages/globalvertex/SvtxVertex_v3.cc create mode 100644 offline/packages/globalvertex/SvtxVertex_v3.h create mode 100644 offline/packages/globalvertex/SvtxVertex_v3LinkDef.h diff --git a/offline/packages/globalvertex/GlobalVertex.h b/offline/packages/globalvertex/GlobalVertex.h index 2a42abbba6..3124cea282 100644 --- a/offline/packages/globalvertex/GlobalVertex.h +++ b/offline/packages/globalvertex/GlobalVertex.h @@ -78,8 +78,8 @@ class GlobalVertex : public PHObject virtual float get_error(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual void set_error(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) { return; } - virtual unsigned int get_beam_crossing() const { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) { return; } + virtual short int get_beam_crossing() const { return std::numeric_limits::max(); } + virtual void set_beam_crossing(short int) { return; } virtual bool empty_vtxs() const { return true; } virtual size_t size_vtxs() const { return 0; } diff --git a/offline/packages/globalvertex/GlobalVertexv2.h b/offline/packages/globalvertex/GlobalVertexv2.h index 06a4d637f0..4c7a077df7 100644 --- a/offline/packages/globalvertex/GlobalVertexv2.h +++ b/offline/packages/globalvertex/GlobalVertexv2.h @@ -29,8 +29,22 @@ class GlobalVertexv2 : public GlobalVertex unsigned int get_id() const override { return _id; } void set_id(unsigned int id) override { _id = id; } - unsigned int get_beam_crossing() const override { return _bco; } - void set_beam_crossing(unsigned int bco) override { _bco = bco; } + short int get_beam_crossing() const override + { + return rollover_from_unsignedint(_bco); + } + + void set_beam_crossing(short int bco) override + { + if (bco == short_int_max) + { + _bco = std::numeric_limits::max(); + return; + } + + const short int bco_ro = rollover_short(bco); + _bco = static_cast(bco_ro); + } float get_t() const override; float get_t_err() const override; @@ -65,6 +79,25 @@ class GlobalVertexv2 : public GlobalVertex GlobalVertex::VertexIter end_vertexes() override { return _vtxs.end(); } private: + static constexpr short int short_int_max = std::numeric_limits::max(); + + static short int rollover_short(short int bco) + { + if (bco == short_int_max) return short_int_max; + if (bco >= 0) return bco; + return static_cast(static_cast(short_int_max) + static_cast(bco)); + } + + static short int rollover_from_unsignedint(unsigned int bco) + { + if (bco == std::numeric_limits::max()) return short_int_max; + if (bco <= static_cast(short_int_max)) return static_cast(bco); + + const short int bco_ro = static_cast(static_cast(bco)); + if (bco_ro >= 0) return bco_ro; + return rollover_short(bco_ro); + } + unsigned int _id{std::numeric_limits::max()}; unsigned int _bco{std::numeric_limits::max()}; //< global bco std::map _vtxs; //< list of vtxs diff --git a/offline/packages/globalvertex/GlobalVertexv3.cc b/offline/packages/globalvertex/GlobalVertexv3.cc new file mode 100644 index 0000000000..1504a7cd3d --- /dev/null +++ b/offline/packages/globalvertex/GlobalVertexv3.cc @@ -0,0 +1,231 @@ +#include "GlobalVertexv3.h" + +#include + +GlobalVertexv3::GlobalVertexv3(const unsigned int id) + : _id(id) +{ +} + +GlobalVertexv3::~GlobalVertexv3() +{ + GlobalVertexv3::Reset(); +} + +void GlobalVertexv3::Reset() +{ + for (auto& _vtx : _vtxs) + { + for (const auto* vertex : _vtx.second) + { + delete vertex; + } + } + _vtxs.clear(); +} + +void GlobalVertexv3::identify(std::ostream& os) const +{ + os << "---GlobalVertexv3-----------------------" << std::endl; + + os << " list of vtx ids: " << std::endl; + for (ConstVertexIter iter = begin_vertexes(); iter != end_vertexes(); ++iter) + { + os << " Vertex type " << iter->first << " has " << iter->second.size() + << " vertices associated to it" << std::endl; + for (const auto& vertex : iter->second) + { + vertex->identify(); + } + } + + os << "-----------------------------------------------" << std::endl; +} + +int GlobalVertexv3::isValid() const +{ + if (_vtxs.empty()) + { + return 0; + } + return 1; +} + +void GlobalVertexv3::insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) +{ + auto it = _vtxs.find(type); + if (it == _vtxs.end()) + { + VertexVector vector; + vector.push_back(vertex); + _vtxs.insert(std::make_pair(type, vector)); + return; + } + + it->second.push_back(vertex); +} + +void GlobalVertexv3::clone_insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) +{ + auto it = _vtxs.find(type); + Vertex* clone = dynamic_cast(vertex->CloneMe()); + if (it == _vtxs.end()) + { + VertexVector vector; + vector.push_back(clone); + _vtxs.insert(std::make_pair(type, vector)); + return; + } + + it->second.push_back(clone); +} + +size_t GlobalVertexv3::count_vtxs(GlobalVertex::VTXTYPE type) const +{ + auto it = _vtxs.find(type); + if (it == _vtxs.end()) + { + return 0; + } + + return it->second.size(); +} + +float GlobalVertexv3::get_t() const +{ + auto it = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (it == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + + return it->second[0]->get_t(); +} + +float GlobalVertexv3::get_t_err() const +{ + auto it = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (it == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + + return it->second[0]->get_t_err(); +} + +float GlobalVertexv3::get_x() const { return get_position(0); } +float GlobalVertexv3::get_y() const { return get_position(1); } +float GlobalVertexv3::get_z() const { return get_position(2); } + +float GlobalVertexv3::get_position(unsigned int coor) const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + auto mbdit = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (mbdit == _vtxs.end()) + { + auto caloit = _vtxs.find(GlobalVertex::VTXTYPE::CALO); + if (caloit == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + return caloit->second[0]->get_position(coor); + } + return mbdit->second[0]->get_position(coor); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + float pos = std::numeric_limits::quiet_NaN(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + pos = vertex->get_position(coor); + } + } + + return pos; +} + +float GlobalVertexv3::get_chisq() const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + float chisq = std::numeric_limits::quiet_NaN(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + chisq = vertex->get_chisq(); + } + } + + return chisq; +} + +unsigned int GlobalVertexv3::get_ndof() const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + return std::numeric_limits::max(); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + unsigned int ndf = std::numeric_limits::max(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + ndf = vertex->get_ndof(); + } + } + + return ndf; +} + +float GlobalVertexv3::get_error(unsigned int i, unsigned int j) const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + auto mbdit = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (mbdit == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + // MBD only has z error defined + if (i == 2 && j == 2) + { + return mbdit->second[0]->get_z_err(); + } + + return std::numeric_limits::quiet_NaN(); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + float err = std::numeric_limits::quiet_NaN(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + err = vertex->get_error(i, j); + } + } + + return err; +} diff --git a/offline/packages/globalvertex/GlobalVertexv3.h b/offline/packages/globalvertex/GlobalVertexv3.h new file mode 100644 index 0000000000..c89e51e5c9 --- /dev/null +++ b/offline/packages/globalvertex/GlobalVertexv3.h @@ -0,0 +1,73 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef GLOBALVERTEX_GLOBALVERTEXV3_H +#define GLOBALVERTEX_GLOBALVERTEXV3_H + +#include "GlobalVertex.h" + +#include // for size_t +#include +#include +#include + +class PHObject; + +class GlobalVertexv3 : public GlobalVertex +{ + public: + GlobalVertexv3() = default; + GlobalVertexv3(const unsigned int id); + ~GlobalVertexv3() override; + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override; + int isValid() const override; + PHObject* CloneMe() const override { return new GlobalVertexv3(*this); } + + unsigned int get_id() const override { return _id; } + void set_id(unsigned int id) override { _id = id; } + + short int get_beam_crossing() const override { return _bco; } + void set_beam_crossing(short int bco) override { _bco = bco; } + + float get_t() const override; + float get_t_err() const override; + float get_x() const override; + float get_y() const override; + float get_z() const override; + float get_chisq() const override; + unsigned int get_ndof() const override; + float get_position(unsigned int coor) const override; + float get_error(unsigned int i, unsigned int j) const override; + + // + // associated vertex methods + // + bool empty_vtxs() const override { return _vtxs.empty(); } + size_t size_vtxs() const override { return _vtxs.size(); } + size_t count_vtxs(GlobalVertex::VTXTYPE type) const override; + + void clear_vtxs() override { _vtxs.clear(); } + void insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) override; + void clone_insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) override; + size_t erase_vtxs(GlobalVertex::VTXTYPE type) override { return _vtxs.erase(type); } + void erase_vtxs(GlobalVertex::VertexIter iter) override { _vtxs.erase(iter); } + + GlobalVertex::ConstVertexIter begin_vertexes() const override { return _vtxs.begin(); } + GlobalVertex::ConstVertexIter find_vertexes(GlobalVertex::VTXTYPE type) const override { return _vtxs.find(type); } + GlobalVertex::ConstVertexIter end_vertexes() const override { return _vtxs.end(); } + + GlobalVertex::VertexIter begin_vertexes() override { return _vtxs.begin(); } + GlobalVertex::VertexIter find_vertexes(GlobalVertex::VTXTYPE type) override { return _vtxs.find(type); } + GlobalVertex::VertexIter end_vertexes() override { return _vtxs.end(); } + + private: + unsigned int _id{std::numeric_limits::max()}; + short int _bco{std::numeric_limits::max()}; //< global bco (signed short) + std::map _vtxs; //< list of vtxs + + ClassDefOverride(GlobalVertexv3, 3); +}; + +#endif diff --git a/offline/packages/globalvertex/GlobalVertexv3LinkDef.h b/offline/packages/globalvertex/GlobalVertexv3LinkDef.h new file mode 100644 index 0000000000..8cd2f1abf7 --- /dev/null +++ b/offline/packages/globalvertex/GlobalVertexv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class GlobalVertexv3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/globalvertex/Makefile.am b/offline/packages/globalvertex/Makefile.am index 5cedef884d..0ff0587389 100644 --- a/offline/packages/globalvertex/Makefile.am +++ b/offline/packages/globalvertex/Makefile.am @@ -30,17 +30,20 @@ pkginclude_HEADERS = \ GlobalVertex.h \ GlobalVertexv1.h \ GlobalVertexv2.h \ + GlobalVertexv3.h \ GlobalVertexMap.h \ GlobalVertexMapv1.h \ GlobalVertexReco.h \ MbdVertex.h \ MbdVertexv1.h \ MbdVertexv2.h \ + MbdVertexv3.h \ MbdVertexMap.h \ MbdVertexMapv1.h \ SvtxVertex.h \ SvtxVertex_v1.h \ SvtxVertex_v2.h \ + SvtxVertex_v3.h \ SvtxVertexMap.h \ SvtxVertexMap_v1.h \ TruthVertex.h \ @@ -57,16 +60,19 @@ ROOTDICTS = \ GlobalVertex_Dict.cc \ GlobalVertexv1_Dict.cc \ GlobalVertexv2_Dict.cc \ + GlobalVertexv3_Dict.cc \ GlobalVertexMap_Dict.cc \ GlobalVertexMapv1_Dict.cc \ MbdVertex_Dict.cc \ MbdVertexv1_Dict.cc \ MbdVertexv2_Dict.cc \ + MbdVertexv3_Dict.cc \ MbdVertexMap_Dict.cc \ MbdVertexMapv1_Dict.cc \ SvtxVertex_Dict.cc \ SvtxVertex_v1_Dict.cc \ SvtxVertex_v2_Dict.cc \ + SvtxVertex_v3_Dict.cc \ SvtxVertexMap_Dict.cc \ SvtxVertexMap_v1_Dict.cc \ TruthVertex_Dict.cc \ @@ -87,15 +93,18 @@ libglobalvertex_io_la_SOURCES = \ GlobalVertex.cc \ GlobalVertexv1.cc \ GlobalVertexv2.cc \ + GlobalVertexv3.cc \ GlobalVertexMap.cc \ GlobalVertexMapv1.cc \ MbdVertexv1.cc \ MbdVertexv2.cc \ + MbdVertexv3.cc \ MbdVertexMap.cc \ MbdVertexMapv1.cc \ SvtxVertex.cc \ SvtxVertex_v1.cc \ SvtxVertex_v2.cc \ + SvtxVertex_v3.cc \ SvtxVertexMap.cc \ SvtxVertexMap_v1.cc \ TruthVertex.cc \ diff --git a/offline/packages/globalvertex/MbdVertex.h b/offline/packages/globalvertex/MbdVertex.h index 6d0900b768..ed8d18e1d8 100644 --- a/offline/packages/globalvertex/MbdVertex.h +++ b/offline/packages/globalvertex/MbdVertex.h @@ -36,8 +36,12 @@ class MbdVertex : public Vertex virtual float get_z_err() const override { return std::numeric_limits::quiet_NaN(); } virtual void set_z_err(float) override {} - virtual unsigned int get_beam_crossing() const override { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) override {} + virtual short int get_beam_crossing() const override + { + return std::numeric_limits::max(); + } + virtual void set_beam_crossing(short int) override {} + virtual void set_bbc_ns(int, int, float, float) override {} virtual int get_bbc_npmt(int) const override { return std::numeric_limits::max(); } diff --git a/offline/packages/globalvertex/MbdVertexv2.h b/offline/packages/globalvertex/MbdVertexv2.h index bee34059e4..3b3482ed4f 100644 --- a/offline/packages/globalvertex/MbdVertexv2.h +++ b/offline/packages/globalvertex/MbdVertexv2.h @@ -44,12 +44,56 @@ class MbdVertexv2 : public MbdVertex float get_position(unsigned int coor) const override; - unsigned int get_beam_crossing() const override { return _bco; } - void set_beam_crossing(unsigned int bco) override { _bco = bco; } + short int get_beam_crossing() const override + { + return rollover_from_unsignedint(_bco); + } + void set_beam_crossing(short int bco) override + { + if (bco == short_int_max) + { + _bco = std::numeric_limits::max(); + return; + } + + const short int bco_ro = rollover_short(bco); + _bco = static_cast(bco_ro); + } private: + static constexpr short int short_int_max = std::numeric_limits::max(); // 32767 + + static short int rollover_short(short int bco) + { + if (bco == short_int_max) return short_int_max; + if (bco >= 0) return bco; + + const int bco_ro = static_cast(short_int_max) + static_cast(bco); // bco negative + return static_cast(bco_ro); + } + + static short int rollover_from_unsignedint(unsigned int bco) + { + // if unsigned int max, return short int max + if (bco == std::numeric_limits::max()) + { + return short_int_max; + } + + // common case: [0, 32767] + if (bco <= static_cast(short_int_max)) + { + return static_cast(bco); + } + + const short int bco_ro = static_cast(static_cast(bco)); + if (bco_ro >= 0) return bco_ro; + + return rollover_short(bco_ro); + } + unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container - unsigned int _bco{std::numeric_limits::max()}; //< global bco + unsigned int _bco{std::numeric_limits::max()}; //< global bco (legacy storage) float _t{std::numeric_limits::quiet_NaN()}; //< collision time float _t_err{std::numeric_limits::quiet_NaN()}; //< collision time uncertainty float _z{std::numeric_limits::quiet_NaN()}; //< collision position z diff --git a/offline/packages/globalvertex/MbdVertexv3.cc b/offline/packages/globalvertex/MbdVertexv3.cc new file mode 100644 index 0000000000..9c76f521a3 --- /dev/null +++ b/offline/packages/globalvertex/MbdVertexv3.cc @@ -0,0 +1,60 @@ +#include "MbdVertexv3.h" + +#include +#include + +void MbdVertexv3::identify(std::ostream& os) const +{ + os << "---MbdVertexv3--------------------------------" << std::endl; + os << "vertexid: " << get_id() << std::endl; + os << " t = " << get_t() << " +/- " << get_t_err() << std::endl; + os << " z = " << get_z() << " +/- " << get_z_err() << std::endl; + os << " bco = " << get_beam_crossing() << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int MbdVertexv3::isValid() const +{ + if (_id == std::numeric_limits::max()) + { + return 0; + } + if (std::isnan(_t)) + { + return 0; + } + if (std::isnan(_t_err)) + { + return 0; + } + if (std::isnan(_z)) + { + return 0; + } + if (std::isnan(_z_err)) + { + return 0; + } + + return 1; +} + +float MbdVertexv3::get_position(unsigned int coor) const +{ + if (coor == 0) + { + return get_x(); + } + if (coor == 1) + { + return get_y(); + } + if (coor == 2) + { + return get_z(); + } + + return std::numeric_limits::quiet_NaN(); +} diff --git a/offline/packages/globalvertex/MbdVertexv3.h b/offline/packages/globalvertex/MbdVertexv3.h new file mode 100644 index 0000000000..7d59c82d79 --- /dev/null +++ b/offline/packages/globalvertex/MbdVertexv3.h @@ -0,0 +1,60 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef GLOBALVERTEX_MBDVERTEXV3_H +#define GLOBALVERTEX_MBDVERTEXV3_H + +#include "MbdVertex.h" + +#include +#include + +class MbdVertexv3 : public MbdVertex +{ + public: + MbdVertexv3() = default; + ~MbdVertexv3() override = default; + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = MbdVertexv3(); } + int isValid() const override; + PHObject* CloneMe() const override { return new MbdVertexv3(*this); } + + // vertex info + unsigned int get_id() const override { return _id; } + void set_id(unsigned int id) override { _id = id; } + + float get_t() const override { return _t; } + void set_t(float t) override { _t = t; } + + float get_t_err() const override { return _t_err; } + void set_t_err(float t_err) override { _t_err = t_err; } + + // Return 0 for now, can implement beam spot + float get_x() const override { return 0; } + float get_y() const override { return 0; } + + float get_z() const override { return _z; } + void set_z(float z) override { _z = z; } + + float get_z_err() const override { return _z_err; } + void set_z_err(float z_err) override { _z_err = z_err; } + + float get_position(unsigned int coor) const override; + + // beam crossing methods (v3: native signed short storage) + short int get_beam_crossing() const override { return _bco; } + void set_beam_crossing(short int bco) override { _bco = bco; } + + private: + unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container + short int _bco{std::numeric_limits::max()}; //< global bco (signed short) + float _t{std::numeric_limits::quiet_NaN()}; //< collision time + float _t_err{std::numeric_limits::quiet_NaN()}; //< collision time uncertainty + float _z{std::numeric_limits::quiet_NaN()}; //< collision position z + float _z_err{std::numeric_limits::quiet_NaN()}; //< collision position z uncertainty + + ClassDefOverride(MbdVertexv3, 1); +}; + +#endif diff --git a/offline/packages/globalvertex/MbdVertexv3LinkDef.h b/offline/packages/globalvertex/MbdVertexv3LinkDef.h new file mode 100644 index 0000000000..b55e4bf42d --- /dev/null +++ b/offline/packages/globalvertex/MbdVertexv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class MbdVertexv3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/globalvertex/SvtxVertex_v2.h b/offline/packages/globalvertex/SvtxVertex_v2.h index 24ccbfc0ca..32d19eda66 100644 --- a/offline/packages/globalvertex/SvtxVertex_v2.h +++ b/offline/packages/globalvertex/SvtxVertex_v2.h @@ -54,8 +54,21 @@ class SvtxVertex_v2 : public SvtxVertex float get_error(unsigned int i, unsigned int j) const override; //< get vertex error covar void set_error(unsigned int i, unsigned int j, float value) override; //< set vertex error covar - unsigned int get_beam_crossing() const override { return _beamcrossing; } - void set_beam_crossing(unsigned int cross) override { _beamcrossing = cross; } + short int get_beam_crossing() const override + { + return rollover_from_unsignedint(_beamcrossing); + } + void set_beam_crossing(short int cross) override + { + if (cross == short_int_max) + { + _beamcrossing = std::numeric_limits::max(); + return; + } + + const short int cross_ro = rollover_short(cross); + _beamcrossing = static_cast(cross_ro); + } // // associated track ids methods @@ -73,6 +86,37 @@ class SvtxVertex_v2 : public SvtxVertex TrackIter end_tracks() override { return _track_ids.end(); } private: + static constexpr short int short_int_max = std::numeric_limits::max(); // 32767 + // for unsigned int to short int conversion (rollover) + static short int rollover_short(short int cross) + { + if (cross == short_int_max) return short_int_max; + if (cross >= 0) return cross; + + const int cross_ro = static_cast(short_int_max) + static_cast(cross); // cross negative + return static_cast(cross_ro); + } + + static short int rollover_from_unsignedint(unsigned int cross) + { + // if unsigned int max, return short int max + if (cross == std::numeric_limits::max()) + { + return short_int_max; + } + + // Common case: [0, 32767] + if (cross <= static_cast(short_int_max)) + { + return static_cast(cross); + } + + const short int cross_ro = static_cast(static_cast(cross)); + if (cross_ro >= 0) return cross_ro; + + return rollover_short(cross_ro); + } + unsigned int covar_index(unsigned int i, unsigned int j) const; unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container diff --git a/offline/packages/globalvertex/SvtxVertex_v3.cc b/offline/packages/globalvertex/SvtxVertex_v3.cc new file mode 100644 index 0000000000..731a2c841f --- /dev/null +++ b/offline/packages/globalvertex/SvtxVertex_v3.cc @@ -0,0 +1,113 @@ +#include "SvtxVertex_v3.h" + +#include +#include +#include +#include // for swap + +SvtxVertex_v3::SvtxVertex_v3() +{ + std::fill(std::begin(_pos), std::end(_pos), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(_err), std::end(_err), std::numeric_limits::quiet_NaN()); +} + +void SvtxVertex_v3::identify(std::ostream& os) const +{ + os << "---SvtxVertex_v3--------------------" << std::endl; + os << "vertexid: " << get_id() << std::endl; + + os << " t0 = " << get_t() << std::endl; + os << " beam crossing = " << get_beam_crossing() << std::endl; + os << " (x,y,z) = (" << get_position(0); + os << ", " << get_position(1) << ", "; + os << get_position(2) << ") cm" << std::endl; + + os << " chisq = " << get_chisq() << ", "; + os << " ndof = " << get_ndof() << std::endl; + + os << " ( "; + os << get_error(0, 0) << " , "; + os << get_error(0, 1) << " , "; + os << get_error(0, 2) << " )" << std::endl; + os << " err = ( "; + os << get_error(1, 0) << " , "; + os << get_error(1, 1) << " , "; + os << get_error(1, 2) << " )" << std::endl; + os << " ( "; + os << get_error(2, 0) << " , "; + os << get_error(2, 1) << " , "; + os << get_error(2, 2) << " )" << std::endl; + + os << " list of tracks ids: "; + for (ConstTrackIter iter = begin_tracks(); iter != end_tracks(); ++iter) + { + os << *iter << " "; + } + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int SvtxVertex_v3::isValid() const +{ + if (_id == std::numeric_limits::max()) + { + return 0; + } + if (std::isnan(_t0)) + { + return 0; + } + if (std::isnan(_chisq)) + { + return 0; + } + if (_ndof == std::numeric_limits::max()) + { + return 0; + } + + for (float _po : _pos) + { + if (std::isnan(_po)) + { + return 0; + } + } + for (int j = 0; j < 3; ++j) + { + for (int i = j; i < 3; ++i) + { + if (std::isnan(get_error(i, j))) + { + return 0; + } + } + } + if (_track_ids.empty()) + { + return 0; + } + return 1; +} + +void SvtxVertex_v3::set_error(unsigned int i, unsigned int j, float value) +{ + _err[covar_index(i, j)] = value; + return; +} + +float SvtxVertex_v3::get_error(unsigned int i, unsigned int j) const +{ + return _err[covar_index(i, j)]; +} + +unsigned int SvtxVertex_v3::covar_index(unsigned int i, unsigned int j) const +{ + if (i > j) + { + std::swap(i, j); + } + return i + 1 + (j + 1) * (j) / 2 - 1; +} diff --git a/offline/packages/globalvertex/SvtxVertex_v3.h b/offline/packages/globalvertex/SvtxVertex_v3.h new file mode 100644 index 0000000000..74a75d90ea --- /dev/null +++ b/offline/packages/globalvertex/SvtxVertex_v3.h @@ -0,0 +1,89 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef GLOBALVERTEX_SVTXVERTEXV3_H +#define GLOBALVERTEX_SVTXVERTEXV3_H + +#include "SvtxVertex.h" + +#include // for size_t +#include +#include +#include + +class PHObject; + +class SvtxVertex_v3 : public SvtxVertex +{ + public: + SvtxVertex_v3(); + ~SvtxVertex_v3() override {} + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = SvtxVertex_v3(); } + int isValid() const override; + PHObject* CloneMe() const override { return new SvtxVertex_v3(*this); } + + // vertex info + unsigned int get_id() const override { return _id; } + void set_id(unsigned int id) override { _id = id; } + + float get_t() const override { return _t0; } + void set_t(float t0) override { _t0 = t0; } + + float get_x() const override { return _pos[0]; } + void set_x(float x) override { _pos[0] = x; } + + float get_y() const override { return _pos[1]; } + void set_y(float y) override { _pos[1] = y; } + + float get_z() const override { return _pos[2]; } + void set_z(float z) override { _pos[2] = z; } + + float get_chisq() const override { return _chisq; } + void set_chisq(float chisq) override { _chisq = chisq; } + + unsigned int get_ndof() const override { return _ndof; } + void set_ndof(unsigned int ndof) override { _ndof = ndof; } + + float get_position(unsigned int coor) const override { return _pos[coor]; } + void set_position(unsigned int coor, float xi) override { _pos[coor] = xi; } + + float get_error(unsigned int i, unsigned int j) const override; //< get vertex error covar + void set_error(unsigned int i, unsigned int j, float value) override; //< set vertex error covar + + // v3 uses signed short + short int get_beam_crossing() const override { return _beamcrossing; } + void set_beam_crossing(short int cross) override { _beamcrossing = cross; } + + // + // associated track ids methods + // + void clear_tracks() override { _track_ids.clear(); } + bool empty_tracks() override { return _track_ids.empty(); } + size_t size_tracks() const override { return _track_ids.size(); } + void insert_track(unsigned int trackid) override { _track_ids.insert(trackid); } + size_t erase_track(unsigned int trackid) override { return _track_ids.erase(trackid); } + ConstTrackIter begin_tracks() const override { return _track_ids.begin(); } + ConstTrackIter find_track(unsigned int trackid) const override { return _track_ids.find(trackid); } + ConstTrackIter end_tracks() const override { return _track_ids.end(); } + TrackIter begin_tracks() override { return _track_ids.begin(); } + TrackIter find_track(unsigned int trackid) override { return _track_ids.find(trackid); } + TrackIter end_tracks() override { return _track_ids.end(); } + + private: + unsigned int covar_index(unsigned int i, unsigned int j) const; + + unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container + float _t0{std::numeric_limits::quiet_NaN()}; //< collision time + float _pos[3]{}; //< collision position x,y,z + float _chisq{std::numeric_limits::quiet_NaN()}; //< vertex fit chisq + unsigned int _ndof{std::numeric_limits::max()}; //< degrees of freedom + float _err[6]{}; //< error covariance matrix (packed storage) (+/- cm^2) + std::set _track_ids; //< list of track ids + short int _beamcrossing{std::numeric_limits::max()}; + + ClassDefOverride(SvtxVertex_v3, 3); +}; + +#endif diff --git a/offline/packages/globalvertex/SvtxVertex_v3LinkDef.h b/offline/packages/globalvertex/SvtxVertex_v3LinkDef.h new file mode 100644 index 0000000000..7b6506845d --- /dev/null +++ b/offline/packages/globalvertex/SvtxVertex_v3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class SvtxVertex_v3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/globalvertex/Vertex.h b/offline/packages/globalvertex/Vertex.h index 7bbfa5f381..e475bfb95d 100644 --- a/offline/packages/globalvertex/Vertex.h +++ b/offline/packages/globalvertex/Vertex.h @@ -62,8 +62,8 @@ class Vertex : public PHObject virtual void set_error(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} // beam crossing methods - virtual unsigned int get_beam_crossing() const { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) {} + virtual short int get_beam_crossing() const { return std::numeric_limits::max(); } + virtual void set_beam_crossing(short int) {} // bbcvertex methods virtual void set_bbc_ns(int, int, float, float) {} From 4814fd2321bcdd15089fcfc46565ba9e425759b6 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Wed, 28 Jan 2026 21:48:29 -0500 Subject: [PATCH 138/866] remove need for status calib - defaults to all good --- offline/packages/mbd/MbdCalib.cc | 10 +++++----- offline/packages/mbd/MbdEvent.cc | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index a6e5c773b1..6cc02b0692 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -92,16 +92,15 @@ int MbdCalib::Download_All() Download_SampMax(sampmax_url); std::string status_url = _cdb->getUrl("MBD_STATUS"); - if ( status_url.empty() ) + if ( ! status_url.empty() ) { - std::cerr << "ERROR, MBD_STATUS missing" << std::endl; - return -1; + // if this doesn't exist, the status is assumed to be all good + Download_Status(status_url); } if (Verbosity() > 0) { std::cout << "status_url " << status_url << std::endl; } - Download_Status(status_url); if ( !_rawdstflag ) { @@ -785,7 +784,7 @@ int MbdCalib::Download_Status(const std::string& dbase_location) if ( _mbdstatus[0] == -1 ) { - std::cout << PHWHERE << ", WARNING, sampmax calib missing, " << dbase_location << std::endl; + std::cout << PHWHERE << ", WARNING, status calib seems bad, " << dbase_location << std::endl; _status = -1; return _status; // file not found } @@ -2504,6 +2503,7 @@ void MbdCalib::Reset() Reset_Thresholds(); _sampmax.fill(-1); + _mbdstatus.fill(0); } void MbdCalib::set_ped(const int ifeech, const float m, const float merr, const float s, const float serr) diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index 0ed3886a60..b8782b8044 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -419,7 +419,13 @@ void MbdEvent::Clear() bool MbdEvent::isbadtch(const int ipmtch) { - return std::fabs(_mbdcal->get_tt0(ipmtch))>100.; + int feech = _mbdgeom->get_feech(ipmtch,0); + if ( _mbdcal->get_status(feech) > 0 ) + { + return true; + } + + return false; } @@ -687,6 +693,7 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR, xmitclocks don't agree, evt " << m_evt << std::endl; } + /* // format changed in run2024, need to update check for (auto &femclock : femclocks) @@ -731,15 +738,14 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) { m_ttdc[pmtch] = _mbdsig[ifeech].MBDTDC(_mbdcal->get_sampmax(ifeech)); - if ( m_ttdc[pmtch] < 40. || std::isnan(m_ttdc[pmtch]) || isbadtch(pmtch) ) + if ( m_ttdc[pmtch] < 40. || std::isnan(m_ttdc[pmtch]) ) { m_ttdc[pmtch] = std::numeric_limits::quiet_NaN(); // no hit } } - else if ( type == 1 && (!std::isnan(m_ttdc[pmtch]) || isbadtch(pmtch) || _always_process_charge ) ) + else if ( type == 1 && (!std::isnan(m_ttdc[pmtch]) || _always_process_charge ) ) { // we process charge channels which have good time hit - // or have time channels marked as bad // or have always_process_charge set to 1 (useful for threshold studies) // Use dCFD method to seed time in charge channels (or as primary if not fitting template) @@ -753,10 +759,12 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) //std::cout << "fittemplate" << std::endl; _mbdsig[ifeech].FitTemplate( _mbdcal->get_sampmax(ifeech) ); + /* if ( _verbose ) { std::cout << "tt " << ifeech << " " << pmtch << " " << m_pmttt[pmtch] << std::endl; } + */ m_qtdc[pmtch] = _mbdsig[ifeech].GetTime(); // in units of sample number m_ampl[ifeech] = _mbdsig[ifeech].GetAmpl(); // in units of adc } @@ -797,6 +805,7 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc { if ( std::isnan(bbcraws->get_pmt(pmtch)->get_ttdc()) || isbadtch(pmtch) ) { + // time channel has no hit or is marked as bad m_pmttt[pmtch] = std::numeric_limits::quiet_NaN(); // no hit } else From d87e7150086359696e27c54635f97e2394d255ad Mon Sep 17 00:00:00 2001 From: Hao-Ren Jheng Date: Thu, 29 Jan 2026 09:52:11 -0500 Subject: [PATCH 139/866] update to v3 --- .../packages/globalvertex/GlobalVertexReco.cc | 16 ++++++++-------- offline/packages/jetbase/TowerJetInput.cc | 2 +- offline/packages/mbd/MbdReco.cc | 4 ++-- .../packages/trackreco/PHSimpleVertexFinder.cc | 4 ++-- offline/packages/trackreco/WeightedFitter.cc | 2 +- .../g4simulation/g4bbc/MbdVertexFastSimReco.cc | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 4f50bbc1b6..73681759cc 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -3,7 +3,7 @@ //#include "GlobalVertex.h" // for GlobalVertex, GlobalVe... #include "GlobalVertexMap.h" // for GlobalVertexMap #include "GlobalVertexMapv1.h" -#include "GlobalVertexv2.h" +#include "GlobalVertexv3.h" #include "MbdVertex.h" #include "MbdVertexMap.h" #include "CaloVertex.h" @@ -140,7 +140,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } // we have a matching pair - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::SVTX, svtx); @@ -193,7 +193,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } // we have a standalone SVTX vertex - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); @@ -243,7 +243,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) continue; } - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::MBD, mbd); @@ -282,7 +282,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) continue; } - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::CALO, calo); @@ -337,7 +337,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) continue; } - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::CALO, calo); @@ -354,7 +354,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } else { - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::MBD, mbd); @@ -393,7 +393,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) tvertex->set_t(0); tvertex->set_t_err(0); // 0.1 - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->clone_insert_vtx(GlobalVertex::TRUTH, tvertex); globalmap->insert(vertex); if (truthmap) diff --git a/offline/packages/jetbase/TowerJetInput.cc b/offline/packages/jetbase/TowerJetInput.cc index f58249ad04..052a6c1828 100644 --- a/offline/packages/jetbase/TowerJetInput.cc +++ b/offline/packages/jetbase/TowerJetInput.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index 004e191e78..a2801f41f9 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -7,7 +7,7 @@ #include "MbdPmtSimContainerV1.h" #include -#include +#include #include @@ -172,7 +172,7 @@ int MbdReco::process_event(PHCompositeNode *topNode) // For multiple global vertex if (m_mbdevent->get_bbcn(0) > 0 && m_mbdevent->get_bbcn(1) > 0 && _calpass==0 ) { - auto *vertex = new MbdVertexv2(); + auto *vertex = new MbdVertexv3(); vertex->set_t(m_mbdevent->get_bbct0()); vertex->set_z(m_mbdevent->get_bbcz()); vertex->set_z_err(0.6); diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index 3d3e4a9fda..5f9340d8f6 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include @@ -263,7 +263,7 @@ int PHSimpleVertexFinder::process_event(PHCompositeNode * /*topNode*/) { unsigned int thisid = it + vertex_id; // the address of the vertex in the event - auto svtxVertex = std::make_unique(); + auto svtxVertex = std::make_unique(); svtxVertex->set_chisq(0.0); svtxVertex->set_ndof(0); diff --git a/offline/packages/trackreco/WeightedFitter.cc b/offline/packages/trackreco/WeightedFitter.cc index af7677f5b8..e35919c479 100644 --- a/offline/packages/trackreco/WeightedFitter.cc +++ b/offline/packages/trackreco/WeightedFitter.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include diff --git a/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc b/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc index 45458b9b49..97f801771c 100644 --- a/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc +++ b/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc @@ -2,7 +2,7 @@ #include "MbdVertexFastSimReco.h" #include -#include +#include #include #include @@ -95,7 +95,7 @@ int MbdVertexFastSimReco::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } - MbdVertex *vertex = new MbdVertexv2(); + MbdVertex *vertex = new MbdVertexv3(); if (m_T_Smear >= 0.0) { From 6946cba0986c7c4f5a458562a5aedc9cf5cf1380 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 14:53:47 +0000 Subject: [PATCH 140/866] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20?= =?UTF-8?q?`CaloValid-OO-update`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @pinkenburg. * https://github.com/sPHENIX-Collaboration/coresoftware/pull/4145#issuecomment-3813903526 The following files were modified: * `offline/QA/Calorimeters/CaloValid.cc` * `offline/framework/phool/RunnumberRange.h` --- offline/QA/Calorimeters/CaloValid.cc | 20 ++++++++++++++++++-- offline/framework/phool/RunnumberRange.h | 20 ++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 54598ceaf0..655fa8903e 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -84,7 +84,23 @@ int CaloValid::Init(PHCompositeNode* /*unused*/) return Fun4AllReturnCodes::EVENT_OK; } -// Note: InitRun cannot be made static as it modifies member variable m_species +/** + * @brief Determine the collision species for the current run and set m_species. + * + * Reads the RunHeader from the provided node tree, inspects the run number, and sets + * the member variable `m_species` to one of the recognized values ("pp", "AuAu", "OO"). + * If the run number does not match any known range or the RunHeader is missing, + * `m_species` remains unchanged (default behavior uses "pp" elsewhere) and a diagnostic + * message may be printed depending on verbosity. + * + * Recognized mappings: + * - RUN2PP_* -> "pp" + * - RUN2AUAU_* or RUN3AUAU_* -> "AuAu" + * - RUN3OO_* -> "OO" + * + * @param topNode Top-level node of the event tree used to locate the RunHeader. + * @return int EVENT_OK on success. + */ int CaloValid::InitRun(PHCompositeNode* topNode) { RunHeader* runhdr = findNode::getClass(topNode, "RunHeader"); @@ -1346,4 +1362,4 @@ void CaloValid::createHistos() } hm->registerHisto(h_triggerVec); hm->registerHisto(pr_ldClus_trig); -} +} \ No newline at end of file diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index 5d14a79350..7d942ca791 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -1,7 +1,23 @@ #ifndef PHOOL_RUNNUMBERRANGE_H #define PHOOL_RUNNUMBERRANGE_H -// first and last physics run +/** + * Defines run-number range constants and special run markers used to identify physics data-taking periods. + * + * Each constant names the first or last run number (or a special marker) for a given data-taking period. + * + * @var RUN2PP_FIRST First Run 2 proton-proton physics run. + * @var RUN2PP_LAST Last Run 2 proton-proton physics run. + * @var RUN2AUAU_FIRST First Run 2 Au+Au (heavy-ion) physics run. + * @var RUN2AUAU_LAST Last Run 2 Au+Au (heavy-ion) physics run. + * @var RUN3_TPCFW_CLOCK_CHANGE Run 3 marker for the TPC Forward clock change. + * @var RUN3AUAU_FIRST First Run 3 Au+Au (heavy-ion) physics run. + * @var RUN3AUAU_LAST Last Run 3 Au+Au (heavy-ion) physics run. + * @var RUN3PP_FIRST First Run 3 proton-proton (beam) physics run. + * @var RUN3PP_LAST Last Run 3 proton-proton physics run. + * @var RUN3OO_FIRST Temporary placeholder for the first Run 3 OO run (to be updated once OO starts). + * @var RUN3OO_LAST Temporary upper bound for Run 3 OO runs. + */ namespace RunnumberRange { static const int RUN2PP_FIRST = 47286; @@ -17,4 +33,4 @@ namespace RunnumberRange static const int RUN3OO_LAST = 200000; } -#endif +#endif \ No newline at end of file From 72f7c46d28be735247d81cb0e1bfd45a206e44bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 29 Jan 2026 14:54:05 +0000 Subject: [PATCH 141/866] Fix missing final newline in docstring PR --- offline/QA/Calorimeters/CaloValid.cc | 2 +- offline/framework/phool/RunnumberRange.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 655fa8903e..fe815df37f 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -1362,4 +1362,4 @@ void CaloValid::createHistos() } hm->registerHisto(h_triggerVec); hm->registerHisto(pr_ldClus_trig); -} \ No newline at end of file +} diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index 7d942ca791..2c809f2fb9 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -33,4 +33,4 @@ namespace RunnumberRange static const int RUN3OO_LAST = 200000; } -#endif \ No newline at end of file +#endif From 9bb1cc1a382444b80f1086e1c204166e2312c995 Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 29 Jan 2026 19:53:11 -0500 Subject: [PATCH 142/866] Increased Cluster State Residual QA capabilites --- .../QA/Tracking/StateClusterResidualsQA.cc | 205 +++++++++++++++--- offline/QA/Tracking/StateClusterResidualsQA.h | 60 ++++- 2 files changed, 235 insertions(+), 30 deletions(-) diff --git a/offline/QA/Tracking/StateClusterResidualsQA.cc b/offline/QA/Tracking/StateClusterResidualsQA.cc index b09662ded0..828c662d34 100644 --- a/offline/QA/Tracking/StateClusterResidualsQA.cc +++ b/offline/QA/Tracking/StateClusterResidualsQA.cc @@ -24,6 +24,7 @@ #include #include +#include #include @@ -112,9 +113,32 @@ int StateClusterResidualsQA::InitRun( 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")))); + if (m_use_local_coords) + { + m_histograms_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_rphi")))); + m_histograms_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_z")))); + m_histograms_layer_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_layer_rphi")))); + m_histograms_layer_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_layer_z")))); + m_histograms_phi_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_phi_rphi")))); + m_histograms_phi_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_phi_z")))); + m_histograms_eta_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_eta_rphi")))); + m_histograms_eta_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_eta_z")))); + } + else + { + 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")))); + m_histograms_layer_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_layer_x")))); + m_histograms_layer_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_layer_y")))); + m_histograms_layer_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_layer_z")))); + m_histograms_phi_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_phi_x")))); + m_histograms_phi_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_phi_y")))); + m_histograms_phi_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_phi_z")))); + m_histograms_eta_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_eta_x")))); + m_histograms_eta_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_eta_y")))); + m_histograms_eta_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_eta_z")))); + } } return Fun4AllReturnCodes::EVENT_OK; @@ -181,20 +205,52 @@ int StateClusterResidualsQA::process_event(PHCompositeNode* top_node) 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) + if (!cluster) + { + continue; + } + + float state_x, state_y, state_z; + float cluster_x, cluster_y, cluster_z; + if (m_use_local_coords == true) { + state_x = state->get_localX(); + state_y = state->get_localY(); + Acts::Vector2 loc = geometry->getLocalCoords(state->get_cluskey(), cluster); + cluster_x = loc.x(); + cluster_y = loc.y(); + m_histograms_x[h]->Fill(state_x - cluster_x); + m_histograms_y[h]->Fill(state_y - cluster_y); + m_histograms_layer_x[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_x - cluster_x); + m_histograms_layer_y[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_y - cluster_y); + m_histograms_phi_x[h]->Fill(state->get_phi(), state_x - cluster_x); + m_histograms_phi_y[h]->Fill(state->get_phi(), state_y - cluster_y); + m_histograms_eta_x[h]->Fill(state->get_eta(), state_x - cluster_x); + m_histograms_eta_y[h]->Fill(state->get_eta(), state_y - cluster_y); + } + else + { + state_x = state->get_x(); + state_y = state->get_y(); + state_z = state->get_z(); + Acts::Vector3 glob = geometry->getGlobalPosition(state->get_cluskey(), cluster); + cluster_x = glob.x(); + cluster_y = glob.y(); + cluster_z = glob.z(); 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); + m_histograms_layer_x[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_x - cluster_x); + m_histograms_layer_y[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_y - cluster_y); + m_histograms_layer_z[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_z - cluster_z); + m_histograms_phi_x[h]->Fill(state->get_phi(), state_x - cluster_x); + m_histograms_phi_y[h]->Fill(state->get_phi(), state_y - cluster_y); + m_histograms_phi_z[h]->Fill(state->get_phi(), state_z - cluster_z); + m_histograms_eta_x[h]->Fill(state->get_eta(), state_x - cluster_x); + m_histograms_eta_y[h]->Fill(state->get_eta(), state_y - cluster_y); + m_histograms_eta_z[h]->Fill(state->get_eta(), state_z - cluster_z); } } } @@ -212,27 +268,122 @@ void StateClusterResidualsQA::createHistos() for (const auto& cfg : m_pending) { - TH1F* h_new_x = new TH1F( + if (m_use_local_coords) + { + TH1F* h_new_x = new TH1F( + (cfg.name + "_local_rphi").c_str(), + ";State-Cluster Local r#phi Residual [cm];Entries", + m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + h_new_x->SetMarkerColor(kBlue); + h_new_x->SetLineColor(kBlue); + hm->registerHisto(h_new_x); + TH1F* h_new_y = new TH1F( + (cfg.name + "_local_z").c_str(), + ";State-Cluster Local Z Residual [cm];Entries", + m_nBins, cfg.z_local_lower, cfg.z_local_upper); + h_new_y->SetMarkerColor(kBlue); + h_new_y->SetLineColor(kBlue); + hm->registerHisto(h_new_y); + TH2F* h_new_layer_x = new TH2F( + (cfg.name + "_local_layer_rphi").c_str(), + ";Layer Number;State-Cluster Local r#phi Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + hm->registerHisto(h_new_layer_x); + TH2F* h_new_layer_y = new TH2F( + (cfg.name + "_local_layer_z").c_str(), + ";Layer Number;State-Cluster Local Z Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.z_local_lower, cfg.z_local_upper); + hm->registerHisto(h_new_layer_y); + TH2F* h_new_phi_x = new TH2F( + (cfg.name + "_local_phi_rphi").c_str(), + ";#phi [rad];State-Cluster Local r#phi Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + hm->registerHisto(h_new_phi_x); + TH2F* h_new_phi_y = new TH2F( + (cfg.name + "_local_phi_z").c_str(), + ";#phi [rad];State-Cluster Local Z Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.z_local_lower, cfg.z_local_upper); + hm->registerHisto(h_new_phi_y); + TH2F* h_new_eta_x = new TH2F( + (cfg.name + "_local_eta_rphi").c_str(), + ";#eta;State-Cluster Local r#phi Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + hm->registerHisto(h_new_eta_x); + TH2F* h_new_eta_y = new TH2F( + (cfg.name + "_local_eta_z").c_str(), + ";#eta;State-Cluster Local Z Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.z_local_lower, cfg.z_local_upper); + hm->registerHisto(h_new_eta_y); + } + else + { + 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( + m_nBins, cfg.x_lower, cfg.x_upper); + 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( + m_nBins, cfg.y_lower, cfg.y_upper); + 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); + m_nBins, cfg.z_lower, cfg.z_upper); + h_new_z->SetMarkerColor(kBlue); + h_new_z->SetLineColor(kBlue); + hm->registerHisto(h_new_z); + TH2F* h_new_layer_x = new TH2F( + (cfg.name + "_layer_x").c_str(), + ";Layer Number;State-Cluster Local X Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.x_lower, cfg.x_upper); + hm->registerHisto(h_new_layer_x); + TH2F* h_new_layer_y = new TH2F( + (cfg.name + "_layer_y").c_str(), + ";Layer Number;State-Cluster Local Y Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.y_lower, cfg.y_upper); + hm->registerHisto(h_new_layer_y); + TH2F* h_new_layer_z = new TH2F( + (cfg.name + "_layer_z").c_str(), + ";Layer Number;State-Cluster Local Z Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.z_lower, cfg.z_upper); + hm->registerHisto(h_new_layer_z); + TH2F* h_new_phi_x = new TH2F( + (cfg.name + "_phi_x").c_str(), + ";#phi [rad];State-Cluster Local X Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.x_lower, cfg.x_upper); + hm->registerHisto(h_new_phi_x); + TH2F* h_new_phi_y = new TH2F( + (cfg.name + "_phi_y").c_str(), + ";#phi [rad];State-Cluster Local Y Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.y_lower, cfg.y_upper); + hm->registerHisto(h_new_phi_y); + TH2F* h_new_phi_z = new TH2F( + (cfg.name + "_phi_z").c_str(), + ";#phi [rad];State-Cluster Local Z Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.z_lower, cfg.z_upper); + hm->registerHisto(h_new_phi_z); + TH2F* h_new_eta_x = new TH2F( + (cfg.name + "_eta_x").c_str(), + ";#eta;State-Cluster Local X Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.x_lower, cfg.x_upper); + hm->registerHisto(h_new_eta_x); + TH2F* h_new_eta_y = new TH2F( + (cfg.name + "_eta_y").c_str(), + ";#eta;State-Cluster Local Y Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.y_lower, cfg.y_upper); + hm->registerHisto(h_new_eta_y); + TH2F* h_new_eta_z = new TH2F( + (cfg.name + "_eta_z").c_str(), + ";#eta;State-Cluster Local Z Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.z_lower, cfg.z_upper); + hm->registerHisto(h_new_eta_z); + } } } diff --git a/offline/QA/Tracking/StateClusterResidualsQA.h b/offline/QA/Tracking/StateClusterResidualsQA.h index 739c816609..ddde8032cc 100644 --- a/offline/QA/Tracking/StateClusterResidualsQA.h +++ b/offline/QA/Tracking/StateClusterResidualsQA.h @@ -13,6 +13,7 @@ class PHCompositeNode; class TH1; +class TH2; struct ResidualHistConfig { @@ -35,6 +36,17 @@ struct ResidualHistConfig float pt_max = FLT_MAX; int charge = 0; + + float rphi_local_lower = -0.5; + float rphi_local_upper = 0.5; + float z_local_lower = -0.5; + float z_local_upper = 0.5; + float x_lower = -0.5; + float x_upper = 0.5; + float y_lower = -0.5; + float y_upper = 0.5; + float z_lower = -0.5; + float z_upper = 0.5; }; class StateClusterResidualsQA : public SubsysReco @@ -89,6 +101,36 @@ class StateClusterResidualsQA : public SubsysReco m_pending.back().pt_max = max; return *this; } + StateClusterResidualsQA& setXRange(float min, float max) + { + m_pending.back().x_lower = min; + m_pending.back().x_upper = max; + return *this; + } + StateClusterResidualsQA& setYRange(float min, float max) + { + m_pending.back().y_lower = min; + m_pending.back().y_upper = max; + return *this; + } + StateClusterResidualsQA& setZRange(float min, float max) + { + m_pending.back().z_lower = min; + m_pending.back().z_upper = max; + return *this; + } + StateClusterResidualsQA& setLocalRphiRange(float min, float max) + { + m_pending.back().rphi_local_lower = min; + m_pending.back().rphi_local_upper = max; + return *this; + } + StateClusterResidualsQA& setLocalZRange(float min, float max) + { + m_pending.back().z_local_lower = min; + m_pending.back().z_local_upper = max; + return *this; + } StateClusterResidualsQA& setPositiveTracks() { m_pending.back().charge = 1; @@ -99,6 +141,11 @@ class StateClusterResidualsQA : public SubsysReco m_pending.back().charge = -1; return *this; } + + void setUseLocalCoords() + { + m_use_local_coords = true; + } void createHistos(); @@ -115,13 +162,20 @@ class StateClusterResidualsQA : public SubsysReco 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}; + bool m_use_local_coords = false; std::vector m_histograms_x{}; std::vector m_histograms_y{}; std::vector m_histograms_z{}; + std::vector m_histograms_layer_x{}; + std::vector m_histograms_layer_y{}; + std::vector m_histograms_layer_z{}; + std::vector m_histograms_phi_x{}; + std::vector m_histograms_phi_y{}; + std::vector m_histograms_phi_z{}; + std::vector m_histograms_eta_x{}; + std::vector m_histograms_eta_y{}; + std::vector m_histograms_eta_z{}; }; #endif // TRACKFITTINGQA_H From 3ab3316d1593fc99b5e70a704614c0e95b743eaf Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 30 Jan 2026 09:39:48 -0500 Subject: [PATCH 143/866] do not abort for missing trms calib --- offline/packages/mbd/MbdCalib.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 6cc02b0692..1217ebc782 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -1329,7 +1329,6 @@ int MbdCalib::Download_TimeRMS(const std::string& dbase_location) trms.clear(); } std::fill(_trms_npts.begin(), _trms_npts.end(), 0); - TString dbase_file = dbase_location; #ifndef ONLINE @@ -1436,8 +1435,9 @@ int MbdCalib::Download_TimeRMS(const std::string& dbase_location) if ( _trms_y[0].empty() ) { std::cout << PHWHERE << ", WARNING, trms calib missing " << dbase_location << std::endl; - _status = -1; - return _status; // file not found +// _status = -1; +// return _status; // file not found + return 0; } // Now we interpolate the trms From c09d98c9ad2981c0452b7e446276304f7e26d7cb Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:51:05 -0500 Subject: [PATCH 144/866] Code Review Fixes Addresses Major Issues: - Guard cd against failure to prevent silent misbehavior. - std::stoll can throw if events argument is non-numeric; exception is unhandled. - std::stoi can throw if runnumber argument is non-numeric; exception is unhandled. - Guard zero/NaN sigma before z-score calculations. - Validate pass before casting to Pass to avoid silent no-op runs. --- .../sepd/sepd_eventplanecalib/GenQVecCDB.cc | 29 +++++++++---- .../sepd/sepd_eventplanecalib/GenQVecCalib.cc | 11 +++-- .../sepd/sepd_eventplanecalib/Makefile.am | 2 - .../sepd/sepd_eventplanecalib/QVecCDB.cc | 4 +- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 42 +++++++++++-------- .../sepd/sepd_eventplanecalib/QVecCalib.h | 27 +++++++++--- .../sepd/sepd_eventplanecalib/QVecDefs.h | 9 ++++ .../sepd/sepd_eventplanecalib/autogen.sh | 4 +- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 9 ++-- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.h | 4 +- 10 files changed, 95 insertions(+), 46 deletions(-) mode change 100644 => 100755 calibrations/sepd/sepd_eventplanecalib/autogen.sh diff --git a/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc index 7118d71b99..324f774950 100644 --- a/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc +++ b/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc @@ -14,23 +14,34 @@ int main(int argc, const char* const argv[]) } const std::string &input_file = args[1]; - int runnumber = std::stoi(args[2]); const std::string output_dir = (args.size() >= 4) ? args[3] : "."; const std::string cdb_tag = (args.size() >= 5) ? args[4] : "new_newcdbtag_v008"; - std::cout << std::format("{:#<20}\n", ""); - std::cout << std::format("Analysis Params\n"); - std::cout << std::format("Input File: {}\n", input_file); - std::cout << std::format("Run: {}\n", runnumber); - std::cout << std::format("Output Dir: {}\n", output_dir); - std::cout << std::format("CDB Tag: {}\n", cdb_tag); - std::cout << std::format("{:#<20}\n", ""); - try { + int runnumber = std::stoi(args[2]); + + std::cout << std::format("{:#<20}\n", ""); + std::cout << std::format("Analysis Params\n"); + std::cout << std::format("Input File: {}\n", input_file); + std::cout << std::format("Run: {}\n", runnumber); + std::cout << std::format("Output Dir: {}\n", output_dir); + std::cout << std::format("CDB Tag: {}\n", cdb_tag); + std::cout << std::format("{:#<20}\n", ""); + QVecCDB analysis(input_file, runnumber, output_dir, cdb_tag); analysis.run(); } + catch (const std::invalid_argument& e) + { + std::cout << "Error: runnumber must be an integer: " << args[2] << std::endl; + return 1; + } + catch (const std::out_of_range& e) + { + std::cout << "Error: runnumber is out of range for an integer." << std::endl; + return 1; + } catch (const std::exception& e) { std::cout << "An exception occurred: " << e.what() << std::endl; diff --git a/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc index 67ec64fbeb..0dd1fa1fbe 100644 --- a/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc @@ -15,9 +15,8 @@ int main(int argc, const char* const argv[]) const std::string &input_file = args[1]; const std::string &input_hist = args[2]; const std::string &input_Q_calib = args[3]; - const std::string &pass_str = (argc >= 5) ? args[4] : "ComputeRecentering"; // Default to the first pass - long long events = (argc >= 6) ? std::stoll(args[5]) : 0; - std::string output_dir = (argc >= 7) ? args[6] : "."; + const std::string &pass_str = (args.size() >= 5) ? args[4] : "ComputeRecentering"; // Default to the first pass + std::string output_dir = (args.size() >= 7) ? args[6] : "."; const std::map pass_map = { {"ComputeRecentering", QVecCalib::Pass::ComputeRecentering}, @@ -39,9 +38,15 @@ int main(int argc, const char* const argv[]) try { + long long events = (args.size() >= 6) ? std::stoll(args[5]) : 0; QVecCalib analysis(input_file, input_hist, input_Q_calib, static_cast(pass), events, output_dir); analysis.run(); } + catch (const std::invalid_argument& e) + { + std::cout << "Error: events must be an integer" << std::endl; + return 1; + } catch (const std::exception& e) { std::cout << "An exception occurred: " << e.what() << std::endl; diff --git a/calibrations/sepd/sepd_eventplanecalib/Makefile.am b/calibrations/sepd/sepd_eventplanecalib/Makefile.am index f1da8a7800..145947f5e7 100644 --- a/calibrations/sepd/sepd_eventplanecalib/Makefile.am +++ b/calibrations/sepd/sepd_eventplanecalib/Makefile.am @@ -42,11 +42,9 @@ libsepd_eventplanecalib_la_LIBADD = \ -lepd_io GenQVecCalib_SOURCES = GenQVecCalib.cc -# GenQVecCalib_CXXFLAGS = -fsanitize=address GenQVecCalib_LDADD = libsepd_eventplanecalib.la GenQVecCDB_SOURCES = GenQVecCDB.cc -# GenQVecCDB_CXXFLAGS = -fsanitize=address GenQVecCDB_LDADD = libsepd_eventplanecalib.la BUILT_SOURCES = testexternals.cc diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc index b18bf4c345..4719821868 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc @@ -135,13 +135,13 @@ void QVecCDB::write_cdb_BadTowers(const std::string &output_dir) float sigma = 0; // Hot - if (status == 2) + if (status == static_cast(QVecShared::ChannelStatus::Hot)) { sigma = SIGMA_HOT; } // Cold - else if (status == 3) + else if (status == static_cast(QVecShared::ChannelStatus::Cold)) { sigma = SIGMA_COLD; } diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index 2148124032..b8c26dab28 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -165,6 +165,11 @@ void QVecCalib::process_sEPD_event_thresholds(TFile* file) hSEPD_Charge_Min->Fill(cent, charge_low); hSEPD_Charge_Max->Fill(cent, charge_high); + if (sigma == 0) + { + continue; + } + for (int x = 1; x <= binsx; ++x) { double charge = h2SEPD_Charge->GetXaxis()->GetBinCenter(x); @@ -192,7 +197,6 @@ void QVecCalib::process_bad_channels(TFile* file) auto* hSEPD_Charge = dynamic_cast(hist); - int sepd_channels = 744; int rbins = 16; int bins_charge = 40; @@ -216,7 +220,7 @@ void QVecCalib::process_bad_channels(TFile* file) rbins, -0.5, rbins - 0.5, bins_charge, 0, bins_charge); - m_profiles["h_sEPD_Bad_Channels"] = std::make_unique("h_sEPD_Bad_Channels", "sEPD Bad Channels; Channel; Status", sepd_channels, -0.5, sepd_channels-0.5); + m_profiles["h_sEPD_Bad_Channels"] = std::make_unique("h_sEPD_Bad_Channels", "sEPD Bad Channels; Channel; Status", QVecShared::sepd_channels, -0.5, QVecShared::sepd_channels-0.5); auto* h2S = m_hists2D["h2SEPD_South_Charge_rbin"].get(); auto* h2N = m_hists2D["h2SEPD_North_Charge_rbin"].get(); @@ -226,7 +230,7 @@ void QVecCalib::process_bad_channels(TFile* file) auto* hBad = m_profiles["h_sEPD_Bad_Channels"].get(); - for (int channel = 0; channel < sepd_channels; ++channel) + for (int channel = 0; channel < QVecShared::sepd_channels; ++channel) { unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); int rbin = static_cast(TowerInfoDefs::get_epd_rbin(key)); @@ -246,7 +250,7 @@ void QVecCalib::process_bad_channels(TFile* file) int ctr_hot = 0; int ctr_cold = 0; - for (int channel = 0; channel < sepd_channels; ++channel) + for (int channel = 0; channel < QVecShared::sepd_channels; ++channel) { unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); int rbin = static_cast(TowerInfoDefs::get_epd_rbin(key)); @@ -258,7 +262,12 @@ void QVecCalib::process_bad_channels(TFile* file) double charge = hSEPD_Charge->GetBinContent(channel + 1); double mean_charge = hprof->GetBinContent(rbin + 1); double sigma = hprof->GetBinError(rbin + 1); - double zscore = (charge - mean_charge) / sigma; + double zscore = 0.0; + + if (sigma > 0) + { + zscore = (charge - mean_charge) / sigma; + } if (charge < m_sEPD_min_avg_charge_threshold || std::fabs(zscore) > m_sEPD_sigma_threshold) { @@ -271,21 +280,21 @@ void QVecCalib::process_bad_channels(TFile* file) if (charge == 0) { type = "Dead"; - status_fill = 1; + status_fill = static_cast(QVecShared::ChannelStatus::Dead); ++ctr_dead; } // hot channel else if (zscore > m_sEPD_sigma_threshold) { type = "Hot"; - status_fill = 2; + status_fill = static_cast(QVecShared::ChannelStatus::Hot); ++ctr_hot; } // cold channel else { type = "Cold"; - status_fill = 3; + status_fill = static_cast(QVecShared::ChannelStatus::Cold); ++ctr_cold; } @@ -426,7 +435,7 @@ void QVecCalib::init_hists() } } -void QVecCalib::process_averages(double cent, QVecShared::QVec q_S, QVecShared::QVec q_N, const AverageHists& h) +void QVecCalib::process_averages(double cent, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const AverageHists& h) { double psi_S = std::atan2(q_S.y, q_S.x); double psi_N = std::atan2(q_N.y, q_N.x); @@ -442,7 +451,7 @@ void QVecCalib::process_averages(double cent, QVecShared::QVec q_S, QVecShared:: h.Psi_NS->Fill(cent, psi_NS); } -void QVecCalib::process_recentering(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const RecenterHists& h) +void QVecCalib::process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h) { size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); @@ -483,7 +492,7 @@ void QVecCalib::process_recentering(double cent, size_t h_idx, QVecShared::QVec h.Psi_NS_corr->Fill(cent, psi_NS_corr); } -void QVecCalib::process_flattening(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const FlatteningHists& h) +void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h) { size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); @@ -993,18 +1002,17 @@ void QVecCalib::run_event_loop() m_chain->GetEntry(i); m_event_data.reset(); - if (i % 10000 == 0) + if (i % PROGRESS_REPORT_INTERVAL == 0) { - std::cout << std::format("Processing {}/{}: {:.2f} %", i, n_entries, static_cast(i) * 100. / static_cast(n_entries)) << std::endl; + std::cout << std::format("Processing {}/{}: {:.2f} %", i, n_entries, static_cast(i) / n_entries * 100.) << std::endl; } double cent = m_event_data.event_centrality; - // Identify Centrality Bin - size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); + int cent_bin_int = m_hists1D["h_Cent"]->FindBin(cent) - 1; // ensure centrality is valid - if (cent_bin >= m_cent_bins) + if (cent_bin_int < 0 || static_cast(cent_bin_int) >= m_cent_bins) { std::cout << std::format("Weird Centrality: {}, Skipping Event: {}\n", cent, m_event_data.event_id); ++ctr["invalid_cent_bin"]; @@ -1059,7 +1067,7 @@ void QVecCalib::run_event_loop() std::cout << "Skipped Event Types\n"; for (const auto& [name, events] : ctr) { - std::cout << std::format("{}: {}, {:.2f} %\n", name, events, events * 100. / static_cast(n_entries)); + std::cout << std::format("{}: {}, {:.2f} %\n", name, events, static_cast(events) / n_entries * 100.); } // --------------- diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index a10c3e14f9..7a70cfb03e 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -19,6 +19,7 @@ #include #include #include +#include /** * @class QVecCalib @@ -43,7 +44,7 @@ class QVecCalib : m_input_file(std::move(input_file)) , m_input_hist(std::move(input_hist)) , m_input_Q_calib(std::move(input_Q_calib)) - , m_pass(static_cast(pass)) + , m_pass(validate_pass(pass)) , m_events_to_process(events) , m_output_dir(std::move(output_dir)) { @@ -66,6 +67,20 @@ class QVecCalib }; private: + static Pass validate_pass(int pass) + { + switch (pass) + { + case 0: + return Pass::ComputeRecentering; + case 1: + return Pass::ApplyRecentering; + case 2: + return Pass::ApplyFlattening; + default: + throw std::invalid_argument("Invalid pass value"); + } + } struct CorrectionData { @@ -78,6 +93,8 @@ class QVecCalib double m_cent_low = -0.5; double m_cent_high = 79.5; + static constexpr int PROGRESS_REPORT_INTERVAL = 10000; + // Holds all correction data // key: [Cent][Harmonic][Subdetector] // Harmonics {2,3,4} -> 3 elements @@ -183,7 +200,7 @@ class QVecCalib std::string m_input_file; std::string m_input_hist; std::string m_input_Q_calib; - Pass m_pass{0}; + Pass m_pass{Pass::ComputeRecentering}; long long m_events_to_process; std::string m_output_dir; @@ -289,7 +306,7 @@ class QVecCalib * @param q_N The North arm normalized Q-vector. * @param h Reference to the cache of profiles for the first pass. */ - static void process_averages(double cent, QVecShared::QVec q_S, QVecShared::QVec q_N, const AverageHists& h); + static void process_averages(double cent, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const AverageHists& h); /** * @brief Applies re-centering offsets and fills profiles for second-moment calculation. @@ -299,7 +316,7 @@ class QVecCalib * @param q_N The North arm normalized Q-vector. * @param h Reference to the cache of profiles for the second pass. */ - void process_recentering(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const RecenterHists& h); + void process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h); /** * @brief Applies the full correction (re-centering + flattening) for validation. @@ -309,7 +326,7 @@ class QVecCalib * @param q_N The North arm normalized Q-vector. * @param h Reference to the cache of profiles for the third pass. */ - void process_flattening(double cent, size_t h_idx, QVecShared::QVec q_S, QVecShared::QVec q_N, const FlatteningHists& h); + void process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h); /** * @brief Calculates the 2x2 anisotropy correction (whitening) matrix. diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h index bea362b661..0b42e1f105 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -10,6 +10,15 @@ namespace QVecShared { static constexpr size_t CENT_BINS = 8; static constexpr std::array HARMONICS = {2, 3, 4}; + static constexpr int sepd_channels = 744; + + enum class ChannelStatus : int + { + Good = 0, + Dead = 1, + Hot = 2, + Cold = 3 + }; enum class Subdetector { diff --git a/calibrations/sepd/sepd_eventplanecalib/autogen.sh b/calibrations/sepd/sepd_eventplanecalib/autogen.sh old mode 100644 new mode 100755 index dea267bbfd..18aced5f8f --- a/calibrations/sepd/sepd_eventplanecalib/autogen.sh +++ b/calibrations/sepd/sepd_eventplanecalib/autogen.sh @@ -2,7 +2,7 @@ srcdir=`dirname $0` test -z "$srcdir" && srcdir=. -(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ -libtoolize --force; automake -a --add-missing; autoconf) +(cd "$srcdir" || exit 1; aclocal -I "${OFFLINE_MAIN}/share" && +libtoolize --force && automake -a --add-missing && autoconf) $srcdir/configure "$@" diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index be03589d40..7b5c3867a9 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -1,4 +1,5 @@ #include "sEPD_TreeGen.h" +#include "QVecDefs.h" // -- c++ #include @@ -52,7 +53,7 @@ int sEPD_TreeGen::Init([[maybe_unused]] PHCompositeNode *topNode) double centrality_low{-0.5}; double centrality_high{79.5}; - hSEPD_Charge = std::make_unique("hSEPD_Charge", "|z| < 10 cm and MB; Channel; Avg Charge", m_sepd_channels, 0, m_sepd_channels); + hSEPD_Charge = std::make_unique("hSEPD_Charge", "|z| < 10 cm and MB; Channel; Avg Charge", QVecShared::sepd_channels, 0, QVecShared::sepd_channels); hSEPD_Charge->Sumw2(); h2SEPD_totalcharge_centrality = std::make_unique("h2SEPD_totalcharge_centrality", "|z| < 10 cm and MB; sEPD Total Charge; Centrality [%]", bins_sepd_totalcharge, sepd_totalcharge_low, sepd_totalcharge_high, bins_centrality, centrality_low, centrality_high); @@ -166,11 +167,11 @@ int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) // sepd unsigned int sepd_channels = towerinfosEPD->size(); - if(sepd_channels != m_sepd_channels) + if(sepd_channels != QVecShared::sepd_channels) { if (Verbosity() > 2) { - std::cout << "Event: " << m_data.event_id << ", SEPD Channels = " << sepd_channels << " != " << m_sepd_channels << std::endl; + std::cout << "Event: " << m_data.event_id << ", SEPD Channels = " << sepd_channels << " != " << QVecShared::sepd_channels << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } @@ -220,7 +221,7 @@ int sEPD_TreeGen::process_event(PHCompositeNode *topNode) m_data.event_id = eventInfo->get_EvtSequence(); - if (Verbosity() > 1 && m_event % 20 == 0) + if (Verbosity() > 1 && m_event % PROGRESS_PRINT_INTERVAL == 0) { std::cout << "Progress: " << m_event << ", Global: " << m_data.event_id << std::endl; } diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h index 225e62cc8f..57436314fb 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h @@ -99,7 +99,7 @@ class sEPD_TreeGen : public SubsysReco */ void set_sepd_charge_threshold(double charge_min) { - m_cuts.m_sepd_charge_min= charge_min; + m_cuts.m_sepd_charge_min = charge_min; } /** @@ -139,7 +139,7 @@ class sEPD_TreeGen : public SubsysReco std::string m_outfile_name{"test.root"}; std::string m_outtree_name{"tree.root"}; - static constexpr int m_sepd_channels = 744; + static constexpr int PROGRESS_PRINT_INTERVAL = 20; // Cuts struct Cuts From 32892881d48e294245287b22dd09eb0befc05375 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 30 Jan 2026 17:41:14 -0500 Subject: [PATCH 145/866] Code Review Fixes 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses Major Issues: - Type truncation: GetXmin()/GetXmax() return Double_t, stored as int. - Sigma guard placed after Fill — degenerate thresholds when sigma is zero. - Differentiate “already exists” from directory-creation failure. - Guard against null TowerInfo* to avoid crashes. The get_tower_at_channel() method returns. --- calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc | 7 ++++++- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 15 ++++++++------- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 9 +++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc index 4719821868..ef284faa9d 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc @@ -103,10 +103,15 @@ void QVecCDB::write_cdb() { std::string output_dir = std::format("{}/{}", m_output_dir, m_runnumber); - if (std::filesystem::create_directories(output_dir)) + std::error_code ec; + if (std::filesystem::create_directories(output_dir, ec)) { std::cout << std::format("Success: Directory {} created.\n", output_dir); } + else if (ec) + { + throw std::runtime_error(std::format("Failed to create directory {}: {}", output_dir, ec.message())); + } else { std::cout << std::format("Info: Directory {} already exists.\n", output_dir); diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index b8c26dab28..02a13c896b 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -145,8 +145,8 @@ void QVecCalib::process_sEPD_event_thresholds(TFile* file) int binsx = h2SEPD_Charge->GetNbinsX(); int binsy = h2SEPD_Charge->GetNbinsY(); - int ymin = h2SEPD_Charge->GetYaxis()->GetXmin(); - int ymax = h2SEPD_Charge->GetYaxis()->GetXmax(); + double ymin = h2SEPD_Charge->GetYaxis()->GetXmin(); + double ymax = h2SEPD_Charge->GetYaxis()->GetXmax(); m_profiles["hSEPD_Charge_Min"] = std::make_unique("hSEPD_Charge_Min", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); m_profiles["hSEPD_Charge_Max"] = std::make_unique("hSEPD_Charge_Max", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); @@ -159,17 +159,18 @@ void QVecCalib::process_sEPD_event_thresholds(TFile* file) double cent = h2SEPD_Charge_py->GetBinCenter(y); double mean = h2SEPD_Charge_py->GetBinContent(y); double sigma = h2SEPD_Charge_py->GetBinError(y); - double charge_low = mean - m_sEPD_sigma_threshold * sigma; - double charge_high = mean + m_sEPD_sigma_threshold * sigma; - - hSEPD_Charge_Min->Fill(cent, charge_low); - hSEPD_Charge_Max->Fill(cent, charge_high); if (sigma == 0) { continue; } + double charge_low = mean - m_sEPD_sigma_threshold * sigma; + double charge_high = mean + m_sEPD_sigma_threshold * sigma; + + hSEPD_Charge_Min->Fill(cent, charge_low); + hSEPD_Charge_Max->Fill(cent, charge_high); + for (int x = 1; x <= binsx; ++x) { double charge = h2SEPD_Charge->GetXaxis()->GetBinCenter(x); diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index 7b5c3867a9..2f333b78f3 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -184,6 +184,15 @@ int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) TowerInfo *tower = towerinfosEPD->get_tower_at_channel(channel); + if (!tower) + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << "Null SEPD tower at channel " << channel << std::endl; + } + continue; + } + double charge = tower->get_energy(); bool isZS = tower->get_isZS(); double phi = epdgeom->get_phi(key); From 89bb30bbe4ce00b5112f95e5534d047dda8cfc01 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 30 Jan 2026 18:05:18 -0500 Subject: [PATCH 146/866] Code Review Fixes 3 Addresses Major Issues: - Potential undefined behavior from unchecked cast; memory leak from ProfileY. - Memory leak from ProfileX calls. - Output file creation not validated. - Add guard to prevent histogram and tree filename collision. - Add error checking for TFile creation before writing. --- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 23 ++++++++++++++----- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 14 +++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index 02a13c896b..762588a0da 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -135,13 +135,19 @@ void QVecCalib::process_sEPD_event_thresholds(TFile* file) throw std::runtime_error(std::format("Cannot find hist: {}", sepd_totalcharge_centrality)); } - m_hists2D["h2SEPD_Charge"] = std::unique_ptr(static_cast(hist->Clone("h2SEPD_Charge"))); - m_hists2D["h2SEPD_Chargev2"] = std::unique_ptr(static_cast(hist->Clone("h2SEPD_Chargev2"))); + auto* h2_check = dynamic_cast(hist); + if (!h2_check) + { + throw std::runtime_error(std::format("Histogram '{}' is not a TH2", sepd_totalcharge_centrality)); + } + + m_hists2D["h2SEPD_Charge"] = std::unique_ptr(static_cast(h2_check->Clone("h2SEPD_Charge"))); + m_hists2D["h2SEPD_Chargev2"] = std::unique_ptr(static_cast(h2_check->Clone("h2SEPD_Chargev2"))); auto* h2SEPD_Charge = m_hists2D["h2SEPD_Charge"].get(); auto* h2SEPD_Chargev2 = m_hists2D["h2SEPD_Chargev2"].get(); - auto* h2SEPD_Charge_py = h2SEPD_Charge->ProfileY("h2SEPD_Charge_py", 1, -1, "s"); + std::unique_ptr h2SEPD_Charge_py(h2SEPD_Charge->ProfileY("h2SEPD_Charge_py", 1, -1, "s")); int binsx = h2SEPD_Charge->GetNbinsX(); int binsy = h2SEPD_Charge->GetNbinsY(); @@ -244,8 +250,8 @@ void QVecCalib::process_bad_channels(TFile* file) h2->Fill(rbin, avg_charge); } - auto* hSpx = h2S->ProfileX("hSpx", 2, -1, "s"); - auto* hNpx = h2N->ProfileX("hNpx", 2, -1, "s"); + std::unique_ptr hSpx(h2S->ProfileX("hSpx", 2, -1, "s")); + std::unique_ptr hNpx(h2N->ProfileX("hNpx", 2, -1, "s")); int ctr_dead = 0; int ctr_hot = 0; @@ -258,7 +264,7 @@ void QVecCalib::process_bad_channels(TFile* file) unsigned int arm = TowerInfoDefs::get_epd_arm(key); auto* h2 = (arm == 0) ? h2Sv2 : h2Nv2; - auto* hprof = (arm == 0) ? hSpx : hNpx; + auto* hprof = (arm == 0) ? hSpx.get() : hNpx.get(); double charge = hSEPD_Charge->GetBinContent(channel + 1); double mean_charge = hprof->GetBinContent(rbin + 1); @@ -1230,6 +1236,11 @@ void QVecCalib::save_results() const auto output_file = std::make_unique(output_filename.c_str(), "RECREATE"); + if (!output_file || output_file->IsZombie()) + { + throw std::runtime_error(std::format("Failed to create output file: {}", output_filename)); + } + for (const auto& [name, hist] : m_hists1D) { std::cout << std::format("Saving 1D: {}\n", name); diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index 2f333b78f3..38c9a25c18 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -42,6 +42,13 @@ sEPD_TreeGen::sEPD_TreeGen(const std::string &name) //____________________________________________________________________________.. int sEPD_TreeGen::Init([[maybe_unused]] PHCompositeNode *topNode) { + // Early guard against filename collision + if (m_outfile_name == m_outtree_name) + { + std::cout << PHWHERE << " Error: Histogram filename and Tree filename are identical: " << m_outfile_name << ". This will cause data loss." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + Fun4AllServer *se = Fun4AllServer::instance(); se->Print("NODETREE"); @@ -59,6 +66,13 @@ int sEPD_TreeGen::Init([[maybe_unused]] PHCompositeNode *topNode) h2SEPD_totalcharge_centrality = std::make_unique("h2SEPD_totalcharge_centrality", "|z| < 10 cm and MB; sEPD Total Charge; Centrality [%]", bins_sepd_totalcharge, sepd_totalcharge_low, sepd_totalcharge_high, bins_centrality, centrality_low, centrality_high); m_output = std::make_unique(m_outtree_name.c_str(), "recreate"); + + if (!m_output || m_output->IsZombie()) + { + std::cout << PHWHERE << "Failed to open tree output file: " << m_outtree_name << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + m_output->cd(); // TTree From 5a30bf17e5be129d13c314818e7238da22084f35 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Fri, 30 Jan 2026 18:09:09 -0500 Subject: [PATCH 147/866] doesn't try to download sampmax calibs etc for sims --- offline/packages/mbd/MbdCalib.cc | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 1217ebc782..8f2245d1ca 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -2080,6 +2080,35 @@ int MbdCalib::Write_CDB_TimeCorr(const std::string& dbfile) } #endif +int MbdCalib::Write_TimeCorr(const std::string& dbfile) +{ + std::ofstream cal_timecorr_file; + cal_timecorr_file.open(dbfile); + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + if ( _mbdgeom->get_type(ifeech) == 1 ) + { + continue; // skip q-channels + } + cal_timecorr_file << ifeech << "\t" << _tcorr_npts[ifeech] << "\t" << _tcorr_minrange[ifeech] << "\t" << _tcorr_maxrange[ifeech] << std::endl; + for (int ipt=0; ipt<_tcorr_npts[ifeech]; ipt++) + { + cal_timecorr_file << _tcorr_y[ifeech][ipt]; + if ( ipt%10 == 9 ) + { + cal_timecorr_file << std::endl; + } + else + { + cal_timecorr_file << " "; + } + } + } + cal_timecorr_file.close(); + + return 1; +} + #ifndef ONLINE int MbdCalib::Write_CDB_SlewCorr(const std::string& dbfile) { From 2d1a74a2ea14888af525b3dd549015ca127684e2 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 30 Jan 2026 18:14:07 -0500 Subject: [PATCH 148/866] Code Review Fixes 4 Addresses Major Issues: - Missing null check after dynamic_cast. --- calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index 762588a0da..b2a4a97e55 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -204,6 +204,11 @@ void QVecCalib::process_bad_channels(TFile* file) auto* hSEPD_Charge = dynamic_cast(hist); + if (!hSEPD_Charge) + { + throw std::runtime_error(std::format("Histogram '{}' is not a TH1", sepd_charge_hist)); + } + int rbins = 16; int bins_charge = 40; From fde222e972808184602e8af9ca51cef370d1286c Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Fri, 30 Jan 2026 18:21:03 -0500 Subject: [PATCH 149/866] fixed rabbit error --- offline/packages/mbd/MbdCalib.cc | 5 +++ offline/packages/mbd/MbdCalib.h | 1 + offline/packages/mbd/MbdEvent.cc | 75 ++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 8f2245d1ca..946b9658db 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -2084,6 +2084,11 @@ int MbdCalib::Write_TimeCorr(const std::string& dbfile) { std::ofstream cal_timecorr_file; cal_timecorr_file.open(dbfile); + if (!cal_timecorr_file.is_open()) + { + std::cout << PHWHERE << "unable to open " << dbfile << std::endl; + return -1; + } for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) { if ( _mbdgeom->get_type(ifeech) == 1 ) diff --git a/offline/packages/mbd/MbdCalib.h b/offline/packages/mbd/MbdCalib.h index 1f450cb5be..49129ac749 100644 --- a/offline/packages/mbd/MbdCalib.h +++ b/offline/packages/mbd/MbdCalib.h @@ -152,6 +152,7 @@ class MbdCalib int Write_TTT0(const std::string& dbfile); int Write_T0Corr(const std::string& dbfile); int Write_Ped(const std::string& dbfile); + int Write_TimeCorr(const std::string& dbfile); int Write_Gains(const std::string& dbfile); int Write_Pileup(const std::string& dbfile); int Write_Thresholds(const std::string& dbfile); diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index b8782b8044..72cecb212d 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -151,14 +151,16 @@ int MbdEvent::InitRun() _mbdcal->SetRawDstFlag( _rawdstflag ); _mbdcal->SetFitsOnly( _fitsonly ); - int status = _mbdcal->Download_All(); - if ( status == -1 ) - { - return Fun4AllReturnCodes::ABORTRUN; - } if ( _simflag == 0 ) // do following for real data { + // Download calibrations + int status = _mbdcal->Download_All(); + if ( status == -1 ) + { + return Fun4AllReturnCodes::ABORTRUN; + } + // load pass1 calibs from local file for calpass2+ if ( _calpass>1 ) { @@ -180,35 +182,36 @@ int MbdEvent::InitRun() _calib_done = 0; std::cout << PHWHERE << ",no sampmax calib, determining it on the fly using first " << _no_sampmax << " evts." << std::endl; } - } - - // Init parameters of the signal processing - for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++) - { - _mbdsig[ifeech].SetCalib(_mbdcal); - // Do evt-by-evt pedestal using sample range below - if ( _calpass==1 || _is_online || _no_sampmax>0 ) - { - _mbdsig[ifeech].SetEventPed0Range(0,1); - } - else + // Init parameters of the signal processing + for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++) { - const int presamp = 5; // start from 5 samples before sampmax - const int nsamps = -1; // use all to sample 0 - _mbdsig[ifeech].SetEventPed0PreSamp(presamp, nsamps, _mbdcal->get_sampmax(ifeech)); - } + _mbdsig[ifeech].SetCalib(_mbdcal); - // Read in template if specified - if ( do_templatefit && _mbdgeom->get_type(ifeech)==1 ) - { - // std::cout << PHWHERE << "Reading template " << ifeech << std::endl; - // std::cout << "SIZES0 " << _mbdcal->get_shape(ifeech).size() << std::endl; - // Should set template size automatically here - _mbdsig[ifeech].SetTemplate(_mbdcal->get_shape(ifeech), _mbdcal->get_sherr(ifeech)); - _mbdsig[ifeech].SetMinMaxFitTime(_mbdcal->get_sampmax(ifeech) - 2 - 3, _mbdcal->get_sampmax(ifeech) - 2 + 3); - //_mbdsig[ifeech].SetMinMaxFitTime( 0, 31 ); + // Do evt-by-evt pedestal using sample range below + if ( _calpass==1 || _is_online || _no_sampmax>0 ) + { + _mbdsig[ifeech].SetEventPed0Range(0,1); + } + else + { + const int presamp = 5; // start from 5 samples before sampmax + const int nsamps = -1; // use all to sample 0 + _mbdsig[ifeech].SetEventPed0PreSamp(presamp, nsamps, _mbdcal->get_sampmax(ifeech)); + } + + // Read in template if specified + if ( do_templatefit && _mbdgeom->get_type(ifeech)==1 ) + { + // std::cout << PHWHERE << "Reading template " << ifeech << std::endl; + // std::cout << "SIZES0 " << _mbdcal->get_shape(ifeech).size() << std::endl; + // Should set template size automatically here + _mbdsig[ifeech].SetTemplate(_mbdcal->get_shape(ifeech), _mbdcal->get_sherr(ifeech)); + _mbdsig[ifeech].SetMinMaxFitTime(_mbdcal->get_sampmax(ifeech) - 2 - 3, _mbdcal->get_sampmax(ifeech) - 2 + 3); + //_mbdsig[ifeech].SetMinMaxFitTime( 0, 31 ); + } } + } if ( _calpass > 0 ) @@ -816,6 +819,16 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc m_pmttt[pmtch] -= _mbdcal->get_tt0(pmtch); } + /* + if ( !std::isnan(m_pmttt[pmtch]) ) + { + std::cout << "pmttt " << m_evt << "\t" << pmtch << "\t" << m_pmttt[pmtch] << "\t" + << bbcraws->get_pmt(pmtch)->get_ttdc() << "\t" + << _mbdcal->get_tcorr(ifeech,bbcraws->get_pmt(pmtch)->get_ttdc()) << "\t" + << _mbdcal->get_tt0(pmtch) << std::endl; + } + */ + } else if ( type == 1 && (!std::isnan(bbcraws->get_pmt(pmtch)->get_ttdc()) || isbadtch(pmtch) || _always_process_charge ) ) { @@ -840,7 +853,6 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc m_pmttq[pmtch] = m_pmttq[pmtch] - _mbdcal->get_tq0(pmtch); // if ( m_pmttq[pmtch]<-50. && ifeech==255 ) std::cout << "hit_times " << ifeech << "\t" << m_pmttq[pmtch] << std::endl; - // if ( arm==1 ) std::cout << "hit_times " << ifeech << "\t" << setw(10) << m_pmttq[pmtch] << "\t" << board << "\t" << TRIG_SAMP[board] << std::endl; // if tt is bad, use tq if ( _mbdcal->get_status(ifeech-8)>0 ) @@ -850,7 +862,6 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc else { // we have a good tt ch. correct for slew if there is a hit - //if ( ifeech==0 ) std::cout << "applying scorr" << std::endl; if ( !std::isnan(m_pmttt[pmtch]) ) { m_pmttt[pmtch] -= _mbdcal->get_scorr(ifeech-8,bbcraws->get_pmt(pmtch)->get_adc()); From 18821af5218bafe61ebabdf447fc29defec31d1f Mon Sep 17 00:00:00 2001 From: rosstom Date: Fri, 30 Jan 2026 19:32:34 -0500 Subject: [PATCH 150/866] Fixing clang tidy issue and TH2 typo --- offline/QA/Tracking/StateClusterResidualsQA.cc | 8 ++++++-- offline/QA/Tracking/StateClusterResidualsQA.h | 12 ++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/offline/QA/Tracking/StateClusterResidualsQA.cc b/offline/QA/Tracking/StateClusterResidualsQA.cc index d92f45a425..d2239ede5d 100644 --- a/offline/QA/Tracking/StateClusterResidualsQA.cc +++ b/offline/QA/Tracking/StateClusterResidualsQA.cc @@ -212,8 +212,12 @@ int StateClusterResidualsQA::process_event(PHCompositeNode* top_node) continue; } - float state_x, state_y, state_z; - float cluster_x, cluster_y, cluster_z; + float state_x; + float state_y; + float state_z; + float cluster_x; + float cluster_y; + float cluster_z; if (m_use_local_coords == true) { state_x = state->get_localX(); diff --git a/offline/QA/Tracking/StateClusterResidualsQA.h b/offline/QA/Tracking/StateClusterResidualsQA.h index ddde8032cc..587178ef9b 100644 --- a/offline/QA/Tracking/StateClusterResidualsQA.h +++ b/offline/QA/Tracking/StateClusterResidualsQA.h @@ -170,12 +170,12 @@ class StateClusterResidualsQA : public SubsysReco std::vector m_histograms_layer_x{}; std::vector m_histograms_layer_y{}; std::vector m_histograms_layer_z{}; - std::vector m_histograms_phi_x{}; - std::vector m_histograms_phi_y{}; - std::vector m_histograms_phi_z{}; - std::vector m_histograms_eta_x{}; - std::vector m_histograms_eta_y{}; - std::vector m_histograms_eta_z{}; + std::vector m_histograms_phi_x{}; + std::vector m_histograms_phi_y{}; + std::vector m_histograms_phi_z{}; + std::vector m_histograms_eta_x{}; + std::vector m_histograms_eta_y{}; + std::vector m_histograms_eta_z{}; }; #endif // TRACKFITTINGQA_H From 317ac39a05d64991eaf3a97102600fde88653bca Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 31 Jan 2026 18:39:11 -0500 Subject: [PATCH 151/866] suppress clang-tidywarnings for ActsPropagator.cc --- offline/packages/trackreco/ActsPropagator.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 8cd4942ea4..2578f05e61 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -48,7 +48,7 @@ ActsPropagator::makeTrackParams(SvtxTrackState* state, Acts::BoundSquareMatrix cov = transformer.rotateSvtxTrackCovToActs(state); return ActsTrackFittingAlgorithm::TrackParameters::create( - surf, + surf, // NOLINT (performance-unnecessary-value-param) m_geometry->geometry().getGeoContext(), actsFourPos, momentum, trackCharge / momentum.norm(), @@ -98,7 +98,8 @@ ActsPropagator::BTPPairResult ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const unsigned int sphenixLayer) { - unsigned int actsvolume, actslayer; + unsigned int actsvolume; + unsigned int actslayer; if (!checkLayer(sphenixLayer, actsvolume, actslayer) || !m_geometry) { return Acts::Result::failure(std::error_code(0, std::generic_category())); @@ -125,7 +126,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, if (result.ok()) { - auto finalparams = *result.value().endParameters; + auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); @@ -154,7 +155,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, if (result.ok()) { - auto finalparams = *result.value().endParameters; + auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); @@ -183,7 +184,7 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, if (result.ok()) { - auto finalparams = *result.value().endParameters; + auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); From 467d93ef75da30a9f631a19300e796cf7c0672fe Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 31 Jan 2026 18:45:00 -0500 Subject: [PATCH 152/866] prevent misleading printout --- generators/PHPythia8/PHPythia8.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 58b1f67e5d..ab059542b4 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -176,7 +176,7 @@ int PHPythia8::read_config(const std::string &cfg_file) if (Verbosity() >= VERBOSITY_SOME) { - std::cout << "PHPythia8::read_config - Reading " << m_ConfigFileName << std::endl; + std::cout << Name() << " PHPythia8::read_config - Reading " << m_ConfigFileName << std::endl; } std::ifstream infile(m_ConfigFileName); @@ -201,7 +201,7 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) { if (Verbosity() >= VERBOSITY_MORE) { - std::cout << "PHPythia8::process_event - event: " << m_EventCount << std::endl; + std::cout << Name() << " PHPythia8::process_event - event: " << m_EventCount << std::endl; } bool passedGen = false; @@ -248,7 +248,7 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) andScoreKeeper &= trigResult; } - if (Verbosity() >= VERBOSITY_EVEN_MORE && !passedTrigger) + if (Verbosity() >= VERBOSITY_EVEN_MORE && !passedTrigger && !andScoreKeeper) { std::cout << "PHPythia8::process_event - failed trigger: " << m_RegisteredTrigger->GetName() << std::endl; From be6271bccf3b767e0e3317bffc1484afef64c241 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Sun, 1 Feb 2026 09:41:11 -0500 Subject: [PATCH 153/866] undo checks for existence of calibs - this breaks ability to calc these on the fly --- offline/packages/mbd/MbdCalib.cc | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 946b9658db..e1faec09b8 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -80,11 +80,6 @@ int MbdCalib::Download_All() if (!_rc->FlagExist("MBD_CALDIR")) { std::string sampmax_url = _cdb->getUrl("MBD_SAMPMAX"); - if ( sampmax_url.empty() ) - { - std::cerr << "ERROR, MBD_SAMPMAX missing" << std::endl; - return -1; - } if (Verbosity() > 0) { std::cout << "sampmax_url " << sampmax_url << std::endl; @@ -105,18 +100,12 @@ int MbdCalib::Download_All() if ( !_rawdstflag ) { std::string ped_url = _cdb->getUrl("MBD_PED"); - if ( ped_url.empty() ) - { - std::cerr << "ERROR, MBD_PED missing" << std::endl; - return -1; - } if (Verbosity() > 0) { std::cout << "ped_url " << ped_url << std::endl; } Download_Ped(ped_url); - std::string pileup_url = _cdb->getUrl("MBD_PILEUP"); if ( pileup_url.empty() ) { @@ -128,6 +117,7 @@ int MbdCalib::Download_All() std::cout << "pileup_url " << pileup_url << std::endl; } Download_Pileup(pileup_url); + if (do_templatefit) { @@ -651,8 +641,6 @@ int MbdCalib::Download_Ped(const std::string& dbase_location) if ( std::isnan(_pedmean[0]) ) { std::cout << PHWHERE << ", WARNING, ped calib missing, " << dbase_location << std::endl; - _status = -1; - return _status; } return 1; @@ -715,8 +703,6 @@ int MbdCalib::Download_SampMax(const std::string& dbase_location) if ( _sampmax[0] == -1 ) { std::cout << PHWHERE << ", WARNING, sampmax calib missing, " << dbase_location << std::endl; - _status = -1; - return _status; // file not found } return 1; @@ -781,14 +767,6 @@ int MbdCalib::Download_Status(const std::string& dbase_location) infile.close(); } - - if ( _mbdstatus[0] == -1 ) - { - std::cout << PHWHERE << ", WARNING, status calib seems bad, " << dbase_location << std::endl; - _status = -1; - return _status; // file not found - } - return 1; } From 278cf7399958ccde29102c461c49a212b972a31b Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Sun, 1 Feb 2026 09:47:31 -0500 Subject: [PATCH 154/866] undo checks for existence of calibs - this breaks ability to calc these on the fly --- offline/packages/mbd/MbdCalib.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index e1faec09b8..3ebe139ffb 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -106,6 +106,7 @@ int MbdCalib::Download_All() } Download_Ped(ped_url); + std::string pileup_url = _cdb->getUrl("MBD_PILEUP"); if ( pileup_url.empty() ) { @@ -117,7 +118,6 @@ int MbdCalib::Download_All() std::cout << "pileup_url " << pileup_url << std::endl; } Download_Pileup(pileup_url); - if (do_templatefit) { @@ -767,6 +767,14 @@ int MbdCalib::Download_Status(const std::string& dbase_location) infile.close(); } + + if ( _mbdstatus[0] == -1 ) + { + std::cout << PHWHERE << ", WARNING, status calib seems bad, " << dbase_location << std::endl; + _status = -1; + return _status; // file not found + } + return 1; } From 09d7e633aa063a50e94c38d66d23856c6c346812 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 1 Feb 2026 21:49:58 -0500 Subject: [PATCH 155/866] expand crossing range --- offline/QA/Tracking/SiliconSeedsQA.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/QA/Tracking/SiliconSeedsQA.cc b/offline/QA/Tracking/SiliconSeedsQA.cc index 14a9feeaed..012caf26ff 100644 --- a/offline/QA/Tracking/SiliconSeedsQA.cc +++ b/offline/QA/Tracking/SiliconSeedsQA.cc @@ -248,7 +248,7 @@ void SiliconSeedsQA::createHistos() } { - h_trackcrossing = new TH1F(std::string(getHistoPrefix() + "trackcrossing").c_str(), "Track beam bunch crossing;Track crossing;Entries", 110, -10, 100); + h_trackcrossing = new TH1F(std::string(getHistoPrefix() + "trackcrossing").c_str(), "Track beam bunch crossing;Track crossing;Entries", 1000, -200, 800); hm->registerHisto(h_trackcrossing); } From 479fedcf8483db511b9df38fd5be20aee0c66473 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Mon, 2 Feb 2026 00:41:25 -0500 Subject: [PATCH 156/866] TrkrNtuplizer hit analysis and PID fixes --- .../TrackingDiagnostics/TrkrNtuplizer.cc | 85 ++++++++++++++++--- .../TrackingDiagnostics/TrkrNtuplizer.h | 2 + 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index 6ee6d35395..abc91cbf52 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -31,10 +31,15 @@ #include #include +#include + +#include + #include #include #include +#include #include @@ -158,6 +163,7 @@ enum n_hit // NOLINT(readability-enum-initial-value, performance-enum-size) nhitcellID, nhitecell, nhitphibin, + nhitzbin, nhittbin, nhitphi, nhitr, @@ -330,7 +336,7 @@ int TrkrNtuplizer::Init(PHCompositeNode* /*unused*/) std::string str_vertex = {"vertexID:vx:vy:vz:ntracks:chi2:ndof"}; std::string str_event = {"event:seed:run:seg:job"}; - std::string str_hit = {"hitID:e:adc:layer:phielem:zelem:cellID:ecell:phibin:tbin:phi:r:x:y:z"}; + std::string str_hit = {"hitID:e:adc:layer:phielem:zelem:cellID:ecell:phibin:zbin:tbin:phi:r:x:y:z"}; std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:ovlp:trackID:niter"}; std::string str_seed = {"seedID:siter:spt:sptot:seta:sphi:syxint:srzint:sxyslope:srzslope:sX0:sY0:sdZ0:sR0:scharge:sdedx:spidedx:skdedx:sprdedx:sn1pix:snsil:sntpc:snhits"}; std::string str_residual = {"alpha:beta:resphio:resphi:resz"}; @@ -560,6 +566,13 @@ int TrkrNtuplizer::InitRun(PHCompositeNode* topNode) } AdcClockPeriod = geom->GetFirstLayerCellGeom()->get_zstep(); + _inttGeom = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); + if (_do_hit_eval && !_inttGeom) + { + std::cout << PHWHERE << "ERROR: Can't find node CYLINDERGEOM_INTT" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + // Create Fee Map auto* geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); { @@ -1464,6 +1477,11 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) fx_hit[n_hit::nhitphielem] = -666; fx_hit[n_hit::nhitzelem] = -666; + if (layer_local < 3) + { + fx_hit[n_hit::nhitphielem] = MvtxDefs::getStaveId(hitset_key); + fx_hit[n_hit::nhitzelem] = MvtxDefs::getChipId(hitset_key); + } if (layer_local >= 3 && layer_local < 7) { fx_hit[n_hit::nhitphielem] = InttDefs::getLadderPhiId(hitset_key); @@ -1485,18 +1503,65 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } } */ - fx_hit[n_hit::nhitphielem] = TpcDefs::getSectorId(hitset_key); - fx_hit[n_hit::nhitzelem] = TpcDefs::getSide(hitset_key); + //fx_hit[n_hit::nhitphielem] = TpcDefs::getSectorId(hitset_key); + //fx_hit[n_hit::nhitzelem] = TpcDefs::getSide(hitset_key); fx_hit[n_hit::nhitcellID] = 0; fx_hit[n_hit::nhitecell] = hit->getAdc(); fx_hit[n_hit::nhitphibin] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhittbin] = std::numeric_limits::quiet_NaN(); + fx_hit[n_hit::nhitzbin] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitphi] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitr] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitx] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhity] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitz] = std::numeric_limits::quiet_NaN(); + if (layer_local < _nlayers_maps) + { + int row = MvtxDefs::getRow(hit_key); + int col = MvtxDefs::getCol(hit_key); + + float localX = std::numeric_limits::quiet_NaN(); + float localZ = std::numeric_limits::quiet_NaN(); + SegmentationAlpide::detectorToLocal(row,col,localX,localZ); + Acts::Vector2 local(localX * Acts::UnitConstants::cm, localZ * Acts::UnitConstants::cm); + + const auto& surface = m_tGeometry->maps().getSiliconSurface(hitset_key); + auto glob = surface->localToGlobal(m_tGeometry->geometry().getGeoContext(), local, Acts::Vector3()); + + fx_hit[n_hit::nhitphibin] = row; + fx_hit[n_hit::nhitzbin] = col; + fx_hit[n_hit::nhittbin] = MvtxDefs::getStrobeId(hitset_key); + fx_hit[n_hit::nhitx] = glob.x() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhity] = glob.y() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitz] = glob.z() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitr] = sqrt(glob.x()*glob.x()+glob.y()*glob.y()) / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitphi] = atan2(glob.y(),glob.x()); + } + + if (layer_local >= _nlayers_maps && layer_local < _nlayers_intt) + { + int row = InttDefs::getRow(hit_key); + int col = InttDefs::getCol(hit_key); + + CylinderGeomIntt* intt_cylinder = dynamic_cast(_inttGeom->GetLayerGeom(layer_local)); + double localcoords[3]; + intt_cylinder->find_strip_center_localcoords(InttDefs::getLadderZId(hitset_key),row,col,localcoords); + + Acts::Vector2 local(localcoords[1]*Acts::UnitConstants::cm,localcoords[2]*Acts::UnitConstants::cm); + const auto& surface = m_tGeometry->maps().getSiliconSurface(hitset_key); + auto glob = surface->localToGlobal(m_tGeometry->geometry().getGeoContext(), local, Acts::Vector3()); + + fx_hit[n_hit::nhitphibin] = row; + fx_hit[n_hit::nhitzbin] = col; + fx_hit[n_hit::nhittbin] = InttDefs::getTimeBucketId(hitset_key); + fx_hit[n_hit::nhitx] = glob.x() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhity] = glob.y() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitz] = glob.z() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitr] = sqrt(glob.x()*glob.x()+glob.y()*glob.y()) / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitphi] = atan2(glob.y(),glob.x()); + } + if (layer_local >= _nlayers_maps + _nlayers_intt && layer_local < _nlayers_maps + _nlayers_intt + _nlayers_tpc) { PHG4TpcGeom* GeoLayer_local = _geom_container->GetLayerCellGeom(layer_local); @@ -1618,7 +1683,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } TrackSeedContainer* _tpc_seeds = findNode::getClass(topNode, "TpcTrackSeedContainer"); - if (!_tpc_seeds) + if (!_tpc_seeds && _do_tpcseed_eval) { std::cout << PHWHERE << " ERROR: Can't find " << "TpcTrackSeedContainer" << std::endl; @@ -1737,9 +1802,9 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } else { - pidedx = f_pion_minus->Eval(tptot); - kdedx = f_kaon_minus->Eval(tptot); - prdedx = f_proton_plus->Eval(tptot); + pidedx = f_pion_minus->Eval(-tptot); + kdedx = f_kaon_minus->Eval(-tptot); + prdedx = f_proton_minus->Eval(-tptot); } float n1pix = get_n1pix(tpcseed); float fx_seed[n_seed::seedsize] = {(float) trackID, 0, tpt, tptot, teta, tphi, xyint, rzint, xyslope, rzslope, tX0, tY0, tZ0, R0, charge, dedx, pidedx, kdedx, prdedx, n1pix, nsil_local, ntpc_local, nhits_local}; @@ -1933,9 +1998,9 @@ void TrkrNtuplizer::FillTrack(float fX[50], SvtxTrack* track, GlobalVertexMap* v } else { - fX[n_track::ntrknpidedx] = f_pion_minus->Eval(trptot); - fX[n_track::ntrknkdedx] = f_kaon_minus->Eval(trptot); - fX[n_track::ntrknprdedx] = f_proton_minus->Eval(trptot); + fX[n_track::ntrknpidedx] = f_pion_minus->Eval(-trptot); + fX[n_track::ntrknkdedx] = f_kaon_minus->Eval(-trptot); + fX[n_track::ntrknprdedx] = f_proton_minus->Eval(-trptot); } for (SvtxTrack::ConstClusterKeyIter iter_local = tpcseed->begin_cluster_keys(); diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h index 4e9df30628..ac341f1a45 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h @@ -35,6 +35,7 @@ class SvtxVertexMap; class TrkrClusterContainer; class ActsGeometry; class PHG4TpcGeomContainer; +class PHG4CylinderGeomContainer; class GlobalVertexMap; // class ClusterErrorPara; @@ -157,6 +158,7 @@ class TrkrNtuplizer : public SubsysReco SvtxTrackMap *_trackmap{nullptr}; ActsGeometry *_tgeometry{nullptr}; PHG4TpcGeomContainer *_geom_container{nullptr}; + PHG4CylinderGeomContainer *_inttGeom{nullptr}; float m_ZDC_coincidence{0}; float m_mbd_rate{0}; float m_rawzdc{0}; From 8b00901783e04541fc5b4985b04f84646bba71a6 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Mon, 2 Feb 2026 02:30:58 -0500 Subject: [PATCH 157/866] reverse commit mixup --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 36 ++++--------------- .../KFParticle_sPHENIX/KFParticle_Tools.h | 2 -- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 4 --- 3 files changed, 7 insertions(+), 35 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 14958f22c9..b319af5b56 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1184,16 +1184,7 @@ float KFParticle_Tools::get_dEdx(PHCompositeNode *topNode, const KFParticle &dau void KFParticle_Tools::init_dEdx_fits() { - std::string dedx_fitparams; - if (m_use_local_PID_file) - { - dedx_fitparams = m_local_PID_filename; - } - else - { - dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); - } - + std::string dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); TFile *filefit = TFile::Open(dedx_fitparams.c_str()); if (!filefit->IsOpen()) @@ -1202,25 +1193,12 @@ void KFParticle_Tools::init_dEdx_fits() return; } - if (m_use_local_PID_file) - { - // new method is independent of charge - filefit->GetObject("pi_band",f_pion_plus); - filefit->GetObject("K_band",f_kaon_plus); - filefit->GetObject("p_band",f_proton_plus); - filefit->GetObject("pi_band",f_pion_minus); - filefit->GetObject("K_band",f_kaon_minus); - filefit->GetObject("p_band",f_proton_minus); - } - else - { - filefit->GetObject("f_piband", f_pion_plus); - filefit->GetObject("f_Kband", f_kaon_plus); - filefit->GetObject("f_pband", f_proton_plus); - filefit->GetObject("f_piminus_band", f_pion_minus); - filefit->GetObject("f_Kminus_band", f_kaon_minus); - filefit->GetObject("f_pbar_band", f_proton_minus); - } + filefit->GetObject("f_piband", f_pion_plus); + filefit->GetObject("f_Kband", f_kaon_plus); + filefit->GetObject("f_pband", f_proton_plus); + filefit->GetObject("f_piminus_band", f_pion_minus); + filefit->GetObject("f_Kminus_band", f_kaon_minus); + filefit->GetObject("f_pbar_band", f_proton_minus); pidMap.insert(std::pair(-11, f_pion_plus)); pidMap.insert(std::pair(211, f_pion_plus)); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 126c331c13..4e722a15db 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -149,8 +149,6 @@ class KFParticle_Tools : protected KFParticle_MVA std::vector m_intermediate_vertex_volume; bool m_use_PID{false}; - bool m_use_local_PID_file{false}; - std::string m_local_PID_filename = ""; float m_dEdx_band_width{0.2}; // Fraction of expected dE/dx TF1 *f_pion_plus{nullptr}; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index e537d63dd4..64fc3f37bb 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -394,10 +394,6 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void selectMotherByMassError(bool select = true) { m_select_by_mass_error = select; } void usePID(bool use = true){ m_use_PID = use; } - - void useLocalPIDFile(bool use = false){ m_use_local_PID_file = use; } - - void setLocalPIDFilename(std::string name){ m_local_PID_filename = name; } void setPIDacceptFraction(float frac = 0.2){ m_dEdx_band_width = frac; } From 18e35f21f40b773a7548a45714447db6670c23bd Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Mon, 2 Feb 2026 11:25:53 -0500 Subject: [PATCH 158/866] Adding fermi-exp for ZDC --- .../packages/CaloReco/CaloWaveformFitting.cc | 77 ++++++++++++++++++- .../packages/CaloReco/CaloWaveformFitting.h | 2 + .../CaloReco/CaloWaveformProcessing.cc | 1 + .../CaloReco/CaloWaveformProcessing.h | 2 +- 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 266072dfbe..c0117c51af 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -659,6 +659,42 @@ double CaloWaveformFitting::SignalShape_PowerLawDoubleExp(double *x, double *par return pedestal + signal; } + +double CaloWaveformFitting::SignalShape_FermiExp(double *x, double *par) +{ + // par[0]: Amplitude + // par[1]: Midpoint (t0) + // par[2]: Rise width (w) + // par[3]: Decay time (tau) + // par[4]: Pedestal + + double tt = x[0]; + double A = par[0]; + double t0 = par[1]; + double w = par[2]; + double tau = par[3]; + double ped = par[4]; + + // Protect against bad values + if (w <= 0 || tau <= 0) + return ped; + + // Fermi turn-on + double fermi = 1.0 / (1.0 + exp(-(tt - t0) / w)); + + // Exponential decay (starts at t0) + double expo = exp(-(tt - t0) / tau); + + // Suppress before turn-on + if (tt < t0) + expo = 1.0; // flat before midpoint + + double signal = A * fermi * expo; + + return ped + signal; +} + + std::vector> CaloWaveformFitting::calo_processing_funcfit(const std::vector> &chnlvector) { std::vector> fit_values; @@ -803,7 +839,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con } } } - else // POWERLAWDOUBLEEXP + else if(m_funcfit_type == POWERLAWDOUBLEEXP) // POWERLAWDOUBLEEXP { // Create fit function with 7 parameters TF1 f("f_doubleexp", SignalShape_PowerLawDoubleExp, 0, nsamples, 7); @@ -853,6 +889,45 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con } } } + else if(m_funcfit_type == FERMIEXP) // POWERLAWDOUBLEEXP + { + TF1 f("f_fermiexp", SignalShape_FermiExp, 0, nsamples, 5); + npar = 5; + + // Set initial parameters + double par[5]; + par[0] = maxheight - pedestal; // Amplitude + par[1] = maxbin ; // t0 + par[2] = 1.0; + par[3] = 2.0; // Peak Time 1 + par[4] = pedestal; // Pedestal + + f.SetParameters(par); + f.SetParLimits(0, maxheight-pedestal, 3*(maxheight-pedestal)); + f.SetParLimits(1, maxbin-1, maxbin); + f.SetParLimits(2, 0.025, 5.0); + f.SetParLimits(3, 0.5, 5.0); + f.SetParLimits(4, pedestal-500, pedestal+500); + + f.FixParameter(2, 0.10); // width + + // Perform fit + h.Fit(&f, "QRN0W", "", 0, nsamples); + + fit_time = f.GetParameter(1); + fit_amp = f.GetParameter(0); + fit_ped = f.GetParameter(4); + + // Calculate chi2 + for (int i = 0; i < nsamples; i++) + { + if (h.GetBinContent(i + 1) > 0) + { + double diff = h.GetBinContent(i + 1) - f.Eval(i); + chi2val += diff * diff; + } + } + } int ndf = ndata - npar; if (ndf > 0) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.h b/offline/packages/CaloReco/CaloWaveformFitting.h index 648d6ab0fa..1064dcd68e 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.h +++ b/offline/packages/CaloReco/CaloWaveformFitting.h @@ -13,6 +13,7 @@ class CaloWaveformFitting { POWERLAWEXP = 0, POWERLAWDOUBLEEXP = 1, + FERMIEXP = 2, }; CaloWaveformFitting() = default; @@ -75,6 +76,7 @@ class CaloWaveformFitting static double SignalShape_PowerLawExp(double *x, double *par); // Double exponential power-law fit function static double SignalShape_PowerLawDoubleExp(double *x, double *par); + static double SignalShape_FermiExp(double *x, double *par); void set_funcfit_type(FuncFitType type) { diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 057e427627..2ffe1d4277 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -31,6 +31,7 @@ void CaloWaveformProcessing::initialize_processing() { std::string calibrations_repo_template = std::string(calibrationsroot) + "/WaveformProcessing/templates/" + m_template_input_file; url_template = CDBInterface::instance()->getUrl(m_template_name, calibrations_repo_template); + url_template = "/sphenix/u/bseidlitz/work/zdcStuff/templateFile.root"; m_Fitter = new CaloWaveformFitting(); m_Fitter->initialize_processing(url_template); if (m_processingtype == CaloWaveformProcessing::TEMPLATE_NOSAT) diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.h b/offline/packages/CaloReco/CaloWaveformProcessing.h index b657459d6c..608811a5e6 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.h +++ b/offline/packages/CaloReco/CaloWaveformProcessing.h @@ -116,7 +116,7 @@ class CaloWaveformProcessing : public SubsysReco bool _bdosoftwarezerosuppression{false}; bool _dobitfliprecovery{false}; - std::string m_template_input_file; + std::string m_template_input_file = "testbeam_cemc_template.root"; std::string url_template; std::string m_template_name{"NONE"}; From 0b26d1890b69c537c0be708da91bfe2497996df8 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Mon, 2 Feb 2026 13:46:05 -0500 Subject: [PATCH 159/866] To include the dead/hot counters inside the edge counter as well as allowing people to use dead/hot maps both in simulation and data. --- offline/packages/tpc/TpcClusterizer.cc | 164 +++++++++++++++++++++++-- offline/packages/tpc/TpcClusterizer.h | 35 +++++- 2 files changed, 183 insertions(+), 16 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index c0137613f5..28c203553b 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -35,6 +35,9 @@ #include #include +#include +#include + #include #include // for PHIODataNode #include // for PHNode @@ -118,6 +121,13 @@ namespace unsigned short maxHalfSizeT = 0; unsigned short maxHalfSizePhi = 0; double m_tdriftmax = 0; + + // --- new members for dead/hot map --- + hitMaskTpc *deadMap = nullptr; + hitMaskTpc *hotMap = nullptr; + bool maskDead = false; + bool maskHot = false; + std::vector association_vector; std::vector cluster_vector; std::vector v_hits; @@ -360,7 +370,7 @@ namespace int is_hit_isolated(int iphi, int it, int NPhiBinsMax, int NTBinsMax, const std::vector> &adcval) { // check isolated hits - // const int NPhiBinsMax = (int) my_data.phibins; + // const int NPhiBinsMax = (int) my_data.phibins; // const int NTBinsMax = (int) my_data.tbins; int isosum = 0; @@ -484,6 +494,7 @@ namespace int tbinlo = 666666; int clus_size = ihit_list.size(); int max_adc = 0; + if (clus_size <= my_data.min_clus_size) { return; @@ -513,7 +524,7 @@ namespace training_hits->v_adc.fill(0); } - // std::cout << "process list" << std::endl; + // std::cout << "process list" << std::endl; std::vector hitkeyvec; // keep track of the hit locations in a given cluster @@ -592,6 +603,46 @@ namespace return; // skip obvious noise "clusters" } + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); + + // --- Dead channels --- + if (my_data.maskDead && my_data.deadMap->count(tpcHitSetKey)) + { + const auto &deadvec = (*my_data.deadMap)[tpcHitSetKey]; + + for (const auto &deadkey : deadvec) + { + int dphi = TpcDefs::getPad(deadkey); + + bool touch = (dphi == phibinlo - 1 || dphi == phibinhi + 1); + + if (touch) + { + nedge++; + continue; + } + } + } + + // --- Hot channels --- + if (my_data.maskHot && my_data.hotMap->count(tpcHitSetKey)) + { + const auto &hotvec = (*my_data.hotMap)[tpcHitSetKey]; + + for (const auto &hotkey : hotvec) + { + int hphi = TpcDefs::getPad(hotkey); + + bool touch = (hphi == phibinlo -1 || hphi == phibinhi + 1); + + if (touch) + { + nedge++; + continue; + } + } + } + // This is the global position double clusiphi = iphi_sum / adc_sum; double clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); @@ -612,7 +663,7 @@ namespace const double t_cov = t2_sum / adc_sum - square(clust); // Get the surface key to find the surface from the - TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); + // TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); Acts::Vector3 global(clusx, clusy, clusz); TrkrDefs::subsurfkey subsurfkey = 0; @@ -784,7 +835,34 @@ namespace tbinmax -= etacut; } } - // std::cout << PHWHERE << " maxz " << maxz << " tbinmin " << tbinmin << " tbinmax " << tbinmax << std::endl; + // std::cout << PHWHERE << " maxz " << maxz << " tbinmin " << tbinmin << " tbinmax " << tbinmax << std::endl; + + TrkrDefs::hitsetkey tpcHitSetKey = + TpcDefs::genHitSetKey(my_data->layer, my_data->sector, my_data->side); + + // Helper function to check if a pad is masked + auto is_pad_masked = [&](int abs_pad) -> bool + { + if (my_data->maskDead && my_data->deadMap->count(tpcHitSetKey)) + { + const auto &deadvec = (*my_data->deadMap)[tpcHitSetKey]; + for (const auto &deadkey : deadvec) + { + if (TpcDefs::getPad(deadkey) == abs_pad) + return true; + } + } + if (my_data->maskHot && my_data->hotMap->count(tpcHitSetKey)) + { + const auto &hotvec = (*my_data->hotMap)[tpcHitSetKey]; + for (const auto &hotkey : hotvec) + { + if (TpcDefs::getPad(hotkey) == abs_pad) + return true; + } + } + return false; + }; if (my_data->hitset != nullptr) { @@ -821,21 +899,16 @@ namespace { continue; } + if (is_pad_masked(phibin + phioffset)) + { + continue; + } float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 unsigned short adc = 0; if (fadc > 0) { adc = (unsigned short) fadc; } - if (phibin >= phibins) - { - continue; - } - if (tbin >= tbins) - { - continue; // tbin is unsigned int, <0 cannot happen - } - if (adc > 0) { if (adc > (my_data->seed_threshold)) @@ -877,6 +950,11 @@ namespace { unsigned short val = (*(hitset->getHits(nphi)))[nt]; + if (is_pad_masked(nphi + phioffset)) + { + pindex++; + continue; + } if (val == 0) { pindex++; @@ -1038,6 +1116,7 @@ namespace */ // pthread_exit(nullptr); } + void *ProcessSector(void *threadarg) { auto *my_data = static_cast(threadarg); @@ -1211,6 +1290,15 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) auto *g3 = static_cast (geom->GetLayerCellGeom(40)); // cast because << not in the base class std::cout << *g3 << std::endl; + if (m_maskDeadChannels) + { + makeChannelMask(m_deadChannelMap, m_deadChannelMapName, "TotalDeadChannels"); + } + if (m_maskHotChannels) + { + makeChannelMask(m_hotChannelMap, m_hotChannelMapName, "TotalHotChannels"); + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -1397,6 +1485,13 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.min_err_squared = min_err_squared; thread_pair.data.min_clus_size = min_clus_size; thread_pair.data.min_adc_sum = min_adc_sum; + + // --- pass dead/hot map info --- + thread_pair.data.deadMap = &m_deadChannelMap; + thread_pair.data.hotMap = &m_hotChannelMap; + thread_pair.data.maskDead = m_maskDeadChannels; + thread_pair.data.maskHot = m_maskHotChannels; + unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); unsigned short NPhiBinsSector = NPhiBins / 12; unsigned short NTBins = 0; @@ -1517,6 +1612,12 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.maxHalfSizePhi = MaxClusterHalfSizePhi; thread_pair.data.verbosity = Verbosity(); + // --- pass dead/hot map info --- + thread_pair.data.deadMap = &m_deadChannelMap; + thread_pair.data.hotMap = &m_hotChannelMap; + thread_pair.data.maskDead = m_maskDeadChannels; + thread_pair.data.maskHot = m_maskHotChannels; + unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); unsigned short NPhiBinsSector = NPhiBins / 12; unsigned short NTBins = (unsigned short) layergeom->get_zbins(); @@ -1702,3 +1803,40 @@ int TpcClusterizer::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; } + +void TpcClusterizer::makeChannelMask(hitMaskTpc &aMask, const std::string &dbName, const std::string &totalChannelsToMask) +{ + CDBTTree *cdbttree; + if (m_maskFromFile) + { + cdbttree = new CDBTTree(dbName); + } + else // mask using CDB TTree, default + { + std::string database = CDBInterface::instance()->getUrl(dbName); + cdbttree = new CDBTTree(database); + } + + std::cout << "Masking TPC Channel Map: " << dbName << std::endl; + + int NChan = -1; + NChan = cdbttree->GetSingleIntValue(totalChannelsToMask); + + for (int i = 0; i < NChan; i++) + { + int Layer = cdbttree->GetIntValue(i, "layer"); + int Sector = cdbttree->GetIntValue(i, "sector"); + int Side = cdbttree->GetIntValue(i, "side"); + int Pad = cdbttree->GetIntValue(i, "pad"); + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << dbName << ": Will mask layer: " << Layer << ", sector: " << Sector << ", side: " << Side << ", Pad: " << Pad << std::endl; + } + + TrkrDefs::hitsetkey DeadChannelHitKey = TpcDefs::genHitSetKey(Layer, Sector, Side); + TrkrDefs::hitkey DeadHitKey = TpcDefs::genHitKey((unsigned int) Pad, 0); + aMask[DeadChannelHitKey].push_back(DeadHitKey); + } + + delete cdbttree; +} diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index e7dd61f0bc..6ec5c18b1c 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -9,6 +9,8 @@ #include #include +typedef std::map> hitMaskTpc; + class ClusHitsVerbosev1; class PHCompositeNode; class TrkrHitSet; @@ -69,13 +71,31 @@ class TpcClusterizer : public SubsysReco set_max_cluster_half_size_z(20); set_fixed_window(3); }; - + ClusHitsVerbosev1 *mClusHitsVerbose{nullptr}; - + + void SetMaskChannelsFromFile() + { + m_maskFromFile = true; + } + + void SetDeadChannelMapName(const std::string& dcmap) + { + m_maskDeadChannels = true; + m_deadChannelMapName = dcmap; + } + void SetHotChannelMapName(const std::string& hmap) + { + m_maskHotChannels = true; + m_hotChannelMapName = hmap; + } + private: bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; + void makeChannelMask(hitMaskTpc& aMask, const std::string& dbName, const std::string& totalChannelsToMask); + TrkrHitSetContainer *m_hits = nullptr; RawHitSetContainer *m_rawhits = nullptr; TrkrClusterContainer *m_clusterlist = nullptr; @@ -105,8 +125,17 @@ class TpcClusterizer : public SubsysReco double m_tdriftmax = 0; double AdcClockPeriod = 53.0; // ns double NZBinsSide = 249; - + TrainingHitsContainer *m_training; + + hitMaskTpc m_deadChannelMap; + hitMaskTpc m_hotChannelMap; + + bool m_maskDeadChannels {false}; + bool m_maskHotChannels {false}; + bool m_maskFromFile {false}; + std::string m_deadChannelMapName; + std::string m_hotChannelMapName; }; #endif From 80ba49aca3ed8cee96d1b890d98ad5b813e36b54 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Mon, 2 Feb 2026 14:20:38 -0500 Subject: [PATCH 160/866] Some additional fix --- offline/packages/tpc/TpcClusterizer.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 28c203553b..881bc7f681 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1292,10 +1292,12 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) if (m_maskDeadChannels) { + m_deadChannelMap.clear(); makeChannelMask(m_deadChannelMap, m_deadChannelMapName, "TotalDeadChannels"); } if (m_maskHotChannels) { + m_hotChannelMap.clear(); makeChannelMask(m_hotChannelMap, m_hotChannelMapName, "TotalHotChannels"); } From 89b1112e5c1f9451deeda5caea5f54c6686d1da2 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Mon, 2 Feb 2026 19:27:49 -0500 Subject: [PATCH 161/866] clean up --- .../packages/CaloReco/CaloWaveformFitting.cc | 27 +++++++++---------- .../CaloReco/CaloWaveformProcessing.cc | 1 - .../CaloReco/CaloWaveformProcessing.h | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index c0117c51af..3d2223abab 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -675,19 +675,19 @@ double CaloWaveformFitting::SignalShape_FermiExp(double *x, double *par) double tau = par[3]; double ped = par[4]; - // Protect against bad values if (w <= 0 || tau <= 0) + { return ped; + } - // Fermi turn-on double fermi = 1.0 / (1.0 + exp(-(tt - t0) / w)); - // Exponential decay (starts at t0) double expo = exp(-(tt - t0) / tau); - // Suppress before turn-on if (tt < t0) - expo = 1.0; // flat before midpoint + { + expo = 1.0; + } double signal = A * fermi * expo; @@ -896,22 +896,21 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con // Set initial parameters double par[5]; - par[0] = maxheight - pedestal; // Amplitude - par[1] = maxbin ; // t0 - par[2] = 1.0; - par[3] = 2.0; // Peak Time 1 - par[4] = pedestal; // Pedestal + par[0] = maxheight - pedestal; // Amplitude + par[1] = maxbin ; // t0 + par[2] = 1.0; // width + par[3] = 2.0; // Peak Time 1 + par[4] = pedestal; // Pedestal f.SetParameters(par); f.SetParLimits(0, maxheight-pedestal, 3*(maxheight-pedestal)); f.SetParLimits(1, maxbin-1, maxbin); - f.SetParLimits(2, 0.025, 5.0); - f.SetParLimits(3, 0.5, 5.0); + f.SetParLimits(2, 0.025, 2.0); + f.SetParLimits(3, 0.5, 4.0); f.SetParLimits(4, pedestal-500, pedestal+500); - f.FixParameter(2, 0.10); // width + f.FixParameter(2, 0.2); - // Perform fit h.Fit(&f, "QRN0W", "", 0, nsamples); fit_time = f.GetParameter(1); diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 2ffe1d4277..057e427627 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -31,7 +31,6 @@ void CaloWaveformProcessing::initialize_processing() { std::string calibrations_repo_template = std::string(calibrationsroot) + "/WaveformProcessing/templates/" + m_template_input_file; url_template = CDBInterface::instance()->getUrl(m_template_name, calibrations_repo_template); - url_template = "/sphenix/u/bseidlitz/work/zdcStuff/templateFile.root"; m_Fitter = new CaloWaveformFitting(); m_Fitter->initialize_processing(url_template); if (m_processingtype == CaloWaveformProcessing::TEMPLATE_NOSAT) diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.h b/offline/packages/CaloReco/CaloWaveformProcessing.h index 608811a5e6..b657459d6c 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.h +++ b/offline/packages/CaloReco/CaloWaveformProcessing.h @@ -116,7 +116,7 @@ class CaloWaveformProcessing : public SubsysReco bool _bdosoftwarezerosuppression{false}; bool _dobitfliprecovery{false}; - std::string m_template_input_file = "testbeam_cemc_template.root"; + std::string m_template_input_file; std::string url_template; std::string m_template_name{"NONE"}; From eb15d524f286b41c660ce963c28171ad2f8d5940 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Tue, 3 Feb 2026 13:13:08 -0500 Subject: [PATCH 162/866] Christof's new error parameterization. --- .../packages/trackbase/ClusterErrorPara.cc | 138 +++++++++++++++++- offline/packages/trackbase/ClusterErrorPara.h | 2 + 2 files changed, 135 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index cb62ed10f5..67ce0e2b9e 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -18,10 +18,18 @@ namespace { return x * x; } + } // namespace ClusterErrorPara::ClusterErrorPara() { + /* + ftpcR1 = new TF1("ftpcR1", "pol2", 0, 10); + ftpcR1->SetParameter(0, 3.206); + ftpcR1->SetParameter(1, -0.252); + ftpcR1->SetParameter(2, 0.007); + */ + f0 = new TF1("f0", "pol1", 0, 10); f0->SetParameter(0, 0.0163943); f0->SetParameter(1, 0.0192931); @@ -482,7 +490,7 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu double zerror = cluster->getZError(); if (TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId) { - if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39) + if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39 || layer == 54) { phierror *= 4; zerror *= 4; @@ -495,21 +503,141 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu { phierror *= 2; } - if (cluster->getPhiSize() == 1) - { - phierror *= 10; + if(layer>=7&&layer<=(7+48)){ + //Set phi error + if (cluster->getPhiSize() == 1) + { + phierror *= 1.0; + } + if (cluster->getPhiSize() == 2) + { + phierror*=3.15; + } + if (cluster->getPhiSize() == 3) + { + phierror *=3.5; + } + if (cluster->getPhiSize() >3) + { + phierror *= 4; + } + //Set Z Error + if (cluster->getZSize() == 1){ + zerror*=1.0; + } + if (cluster->getZSize() == 2){ + if(layer>=7&&layer<=(7+16)){ + zerror*=7; + } + if(layer>=(7+16)&&layer<=(7+32)){ + zerror*=4.5; + } + if(layer>=(7+32)&&layer<=(7+48)){ + zerror*=4.5; + } + + } + if ((cluster->getZSize() == 3) || (cluster->getZSize() == 4)){ + if(layer>=7&&layer<=(7+16)){ + zerror*=7; + } + if(layer>=(7+16)&&layer<=(7+32)){ + zerror*=5; + } + if(layer>=(7+32)&&layer<=(7+48)){ + zerror*=5; + } + // zerror*=6; + } + if (cluster->getZSize() >5){ + if(layer>=7&&layer<=(7+16)){ + zerror*=20; + } + if(layer>=(7+16)&&layer<=(7+32)){ + zerror*=6; + } + if(layer>=(7+32)&&layer<=(7+48)){ + zerror*=7; + } + } + TF1 ftpcR1("ftpcR1", "pol2", 0, 60); + ftpcR1.SetParameter(0, 3.206); + ftpcR1.SetParameter(1, -0.252); + ftpcR1.SetParameter(2, 0.007); + + TF1 ftpcR2("ftpcR2", "pol2", 0, 60); + ftpcR2.SetParameter(0, 4.48); + ftpcR2.SetParameter(1, -0.226); + ftpcR2.SetParameter(2, 0.00362); + + TF1 ftpcR3("ftpcR3", "pol2", 0, 60); + ftpcR3.SetParameter(0, 14.8112); + ftpcR3.SetParameter(1, -0.577); + ftpcR3.SetParameter(2, 0.00605); + + if(layer>=7&&layer<=(7+16)){ + phierror*= ftpcR1.Eval(layer); + } + if(layer>=(7+16)&&layer<=(7+32)){ + phierror*= ftpcR2.Eval(layer); + } + if(layer>=(7+32)&&layer<=(7+48)){ + phierror*= ftpcR3.Eval(layer); + } + ftpcR2.SetParameter(0, 5.593); + ftpcR2.SetParameter(1, -0.2458); + ftpcR2.SetParameter(2, 0.00333455); + + ftpcR3.SetParameter(0, 5.6964); + ftpcR3.SetParameter(1, -0.21338); + ftpcR3.SetParameter(2, 0.002502); + + if(layer>=(7+16)&&layer<=(7+32)){ + zerror*= ftpcR2.Eval(layer); + } + if(layer>=(7+32)&&layer<=(7+48)){ + zerror*= ftpcR3.Eval(layer); + } + + } - if (cluster->getPhiSize() >= 5) + /* if (cluster->getPhiSize() >= 5) { phierror *= 10; } + + if(layer>=7){ + } + phierror = std::min(phierror, 0.1); if (phierror < 0.0005) { phierror = 0.1; } + */ + } + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::mvtxId){ + phierror*=2; + zerror*=2; + } + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::inttId){ + phierror*=9; + if (cluster->getPhiSize() == 1){ + phierror *= 1.25; + } + if (cluster->getPhiSize() == 2){ + phierror *= 2.25; + } + if(layer==3||layer==4) + phierror*=0.8; + if(layer==5||layer==6) + phierror*=1.2; } + + return std::make_pair(square(phierror), square(zerror)); } diff --git a/offline/packages/trackbase/ClusterErrorPara.h b/offline/packages/trackbase/ClusterErrorPara.h index b125858217..902a749f1b 100644 --- a/offline/packages/trackbase/ClusterErrorPara.h +++ b/offline/packages/trackbase/ClusterErrorPara.h @@ -17,6 +17,7 @@ class ClusterErrorPara virtual ~ClusterErrorPara() { + //delete ftpcR1; delete f0; delete f1; delete f2; @@ -71,6 +72,7 @@ class ClusterErrorPara double tpc_z_error(int layer, double beta, TrkrCluster *cluster); private: + // TF1 *ftpcR1 {nullptr}; TF1 *f0 {nullptr}; TF1 *f1 {nullptr}; TF1 *f2 {nullptr}; From 1922e63257fea90ba637d514c35633cefa57b11e Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Tue, 3 Feb 2026 13:14:23 -0500 Subject: [PATCH 163/866] add fiber unpacking in JET trigger that matches what the firmware does... --- offline/packages/trigger/CaloTriggerEmulator.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/offline/packages/trigger/CaloTriggerEmulator.cc b/offline/packages/trigger/CaloTriggerEmulator.cc index eaf00e4f33..9397288033 100644 --- a/offline/packages/trigger/CaloTriggerEmulator.cc +++ b/offline/packages/trigger/CaloTriggerEmulator.cc @@ -1767,8 +1767,17 @@ int CaloTriggerEmulator::process_organizer() } TriggerDefs::TriggerSumKey jet_skey = (*iter_sum).first; - - TriggerDefs::TriggerSumKey hcal_skey = TriggerDefs::getTriggerSumKey(TriggerDefs::TriggerId::jetTId, TriggerDefs::GetDetectorId("HCAL"), TriggerDefs::GetPrimitiveId("JET"), TriggerDefs::getPrimitiveLocId_from_TriggerPrimKey(jet_pkey), TriggerDefs::getSumLocId(jet_skey)); + uint16_t jet_sum_loc = TriggerDefs::getSumLocId(jet_skey); + uint16_t jet_prim_loc = TriggerDefs::getPrimitiveLocId_from_TriggerSumKey(jet_skey); + if (jet_prim_loc >= 12) + { + uint16_t sumeta = TriggerDefs::getSumEtaId(jet_skey); + uint16_t sumphi = TriggerDefs::getSumPhiId(jet_skey); + jet_sum_loc = sumphi%2 + sumeta*2; + } + TriggerDefs::TriggerSumKey hcal_skey = TriggerDefs::getTriggerSumKey(TriggerDefs::TriggerId::jetTId, TriggerDefs::GetDetectorId("HCAL"), TriggerDefs::GetPrimitiveId("JET"), TriggerDefs::getPrimitiveLocId_from_TriggerPrimKey(jet_pkey), jet_sum_loc); + + TriggerDefs::TriggerSumKey emcal_skey = TriggerDefs::getTriggerSumKey(TriggerDefs::TriggerId::jetTId, TriggerDefs::GetDetectorId("EMCAL"), TriggerDefs::GetPrimitiveId("JET"), TriggerDefs::getPrimitiveLocId_from_TriggerPrimKey(jet_pkey), TriggerDefs::getSumLocId(jet_skey)); int i = 0; From e9df8c5a0596e8ec88f973d6f414f880a05e901c Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Tue, 3 Feb 2026 14:08:09 -0500 Subject: [PATCH 164/866] add enum for species in MinBiasClassifier --- .../packages/trigger/MinimumBiasClassifier.cc | 33 ++++++++++++++++--- .../packages/trigger/MinimumBiasClassifier.h | 12 +++++++ offline/packages/trigger/MinimumBiasInfo.h | 8 +++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index b9e7f18460..db3acba38e 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -39,6 +39,29 @@ int MinimumBiasClassifier::InitRun(PHCompositeNode *topNode) { std::cout << __FILE__ << " :: " << __FUNCTION__ << std::endl; } + + if (m_species == MinimumBiasInfo::SPECIES::AUAU) + { + m_useZDC = true; + m_max_charge_cut = 2100; + m_box_cut = true; + m_hit_cut = 2; + } + if (m_species == MinimumBiasInfo::SPECIES::OO) + { + m_useZDC = false; + m_max_charge_cut = 300; + m_box_cut = false; + m_hit_cut = 1; + } + if (m_species == MinimumBiasInfo::SPECIES::PP) + { + m_useZDC = false; + m_max_charge_cut = 300; + m_box_cut = false; + m_hit_cut = 1; + } + CDBInterface *m_cdb = CDBInterface::instance(); std::string centscale_url = m_cdb->getUrl("CentralityScale"); @@ -132,7 +155,7 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() { std::cout << "Getting ZDC" << std::endl; } - if (!m_issim) + if (!m_issim && !m_useZDC) { if (!m_zdcinfo) { @@ -169,7 +192,7 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() } // MBD Background cut - if (m_mbd_charge_sum[1] < m_mbd_north_cut && m_mbd_charge_sum[0] > m_mbd_south_cut && minbiascheck) + if (m_box_cut && m_mbd_charge_sum[1] < m_mbd_north_cut && m_mbd_charge_sum[0] > m_mbd_south_cut && minbiascheck) { minbiascheck = false; // m_mb_info->setIsAuAuMinimumBias(false); @@ -179,13 +202,13 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() // Mbd two hit requirement and ZDC energy sum coincidence requirement for (int iside = 0; iside < 2; iside++) { - if (m_mbd_hit[iside] < 2 && minbiascheck) + if (m_mbd_hit[iside] < m_hit_cut && minbiascheck) { minbiascheck = false; // m_mb_info->setIsAuAuMinimumBias(false); // return Fun4AllReturnCodes::EVENT_OK; } - if (!m_issim) + if (!m_issim && m_useZDC) { if (m_zdcinfo->get_zdc_energy(iside) <= m_zdc_cut && minbiascheck) { @@ -195,7 +218,7 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() } } } - if ((m_mbd_charge_sum[0] + m_mbd_charge_sum[1]) > 2100 && minbiascheck) + if ((m_mbd_charge_sum[0] + m_mbd_charge_sum[1]) > m_max_charge_cut && minbiascheck) { minbiascheck = false; // m_mb_info->setIsAuAuMinimumBias(false); diff --git a/offline/packages/trigger/MinimumBiasClassifier.h b/offline/packages/trigger/MinimumBiasClassifier.h index f84add84f8..5f32c10a62 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.h +++ b/offline/packages/trigger/MinimumBiasClassifier.h @@ -8,6 +8,7 @@ #include #include +#include "MinimumBiasInfo.h" // Forward declarations class MinimumBiasInfo; @@ -21,6 +22,8 @@ class MinimumBiasClassifier : public SubsysReco { public: //! constructor + + explicit MinimumBiasClassifier(const std::string &name = "MinimumBiasClassifier"); //! destructor @@ -56,8 +59,17 @@ class MinimumBiasClassifier : public SubsysReco } void setIsSim(const bool sim) { m_issim = sim; } + void setSpecies(MinimumBiasInfo::SPECIES spec) { m_species = spec; }; + private: bool m_issim{false}; + bool m_useZDC{true}; + bool m_box_cut{true}; + int m_hit_cut{2}; + double m_max_charge_cut{2100}; + + MinimumBiasInfo::SPECIES m_species{MinimumBiasInfo::SPECIES::AUAU}; + float getVertexScale(); std::string m_dbfilename; diff --git a/offline/packages/trigger/MinimumBiasInfo.h b/offline/packages/trigger/MinimumBiasInfo.h index 8cd8472e87..94f38b1a8d 100644 --- a/offline/packages/trigger/MinimumBiasInfo.h +++ b/offline/packages/trigger/MinimumBiasInfo.h @@ -6,6 +6,14 @@ class MinimumBiasInfo : public PHObject { public: + + enum SPECIES + { + AUAU = 0, + OO = 1, + PP = 2 + }; + ~MinimumBiasInfo() override {}; void identify(std::ostream &os = std::cout) const override { os << "MinimumBiasInfo base class" << std::endl; }; From 90f4f0103389d1b0b1931f3846bc61c98b593b8c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 4 Feb 2026 13:30:02 -0500 Subject: [PATCH 165/866] add root i/o object --- .../sepd_eventplanecalib/EventPlaneData.cc | 9 ++++ .../sepd_eventplanecalib/EventPlaneData.h | 44 +++++++++++++++++++ .../EventPlaneDataLinkDef.h | 5 +++ .../sepd/sepd_eventplanecalib/Makefile.am | 17 ++++++- .../sepd/sepd_eventplanecalib/configure.ac | 3 ++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc create mode 100644 calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h create mode 100644 calibrations/sepd/sepd_eventplanecalib/EventPlaneDataLinkDef.h diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc new file mode 100644 index 0000000000..67223236eb --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc @@ -0,0 +1,9 @@ +#include "EventPlaneData.h" + +EventPlaneData::EventPlaneData() +{ + sepd_charge.fill(0); + sepd_phi.fill(0); +} + + diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h new file mode 100644 index 0000000000..b68fdfb5ff --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h @@ -0,0 +1,44 @@ +#ifndef SEPD_EVENTPLANECALIB_EVENTPLANEDATA_H +#define SEPD_EVENTPLANECALIB_EVENTPLANEDATA_H + +#include + +#include +#include + +class EventPlaneData : public PHObject +{ + public: + EventPlaneData(); + ~EventPlaneData() override = default; + + void Reset() override {*this = EventPlaneData();} // check if this works + // this should be in an sepd define (e.g. ../../../offline/packages/epd/EPDDefs.h) + static constexpr int SEPD_CHANNELS = 744; + void set_event_id(int id) {event_id = id;} + int get_event_id() const {return event_id;} + + void set_event_zvertex(double vtx) {event_zvertex = vtx;} + double get_event_zvertex() const {return event_zvertex;} + + void set_sepd_totalcharge(double chg) {sepd_totalcharge = chg;} + double get_sepd_totalcharge() const {return sepd_totalcharge;} + + void set_sepd_charge(int channel, double chg) {sepd_charge[channel] = chg;} + double get_sepd_charge(int channel) const {return sepd_charge[channel];} + + void set_sepd_phi(int channel, double phi) {sepd_phi[channel] = phi;} + double get_sepd_phi(int channel) const {return sepd_phi[channel];} + + private: + int event_id {0}; + double event_zvertex {std::numeric_limits::quiet_NaN()}; + double event_centrality{std::numeric_limits::quiet_NaN()}; + double sepd_totalcharge{std::numeric_limits::quiet_NaN()}; + + std::array sepd_charge {}; + std::array sepd_phi {}; + ClassDefOverride(EventPlaneData, 1); +}; + +#endif diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneDataLinkDef.h b/calibrations/sepd/sepd_eventplanecalib/EventPlaneDataLinkDef.h new file mode 100644 index 0000000000..9c56106475 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneDataLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class EventPlaneData + ; + +#endif /* __CINT__ */ diff --git a/calibrations/sepd/sepd_eventplanecalib/Makefile.am b/calibrations/sepd/sepd_eventplanecalib/Makefile.am index 145947f5e7..3576435566 100644 --- a/calibrations/sepd/sepd_eventplanecalib/Makefile.am +++ b/calibrations/sepd/sepd_eventplanecalib/Makefile.am @@ -6,8 +6,8 @@ bin_PROGRAMS = \ AM_CPPFLAGS = \ -I$(includedir) \ - -I$(OFFLINE_MAIN)/include \ - -I$(ROOTSYS)/include + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include AM_LDFLAGS = \ -L$(libdir) \ @@ -24,7 +24,13 @@ pkginclude_HEADERS = \ lib_LTLIBRARIES = \ libsepd_eventplanecalib.la +ROOTDICTS = \ + EventPlaneData_Dict.cc + +# EventPlaneData is a locally used root i/o object - no need to create an io library libsepd_eventplanecalib_la_SOURCES = \ + $(ROOTDICTS) \ + EventPlaneData.cc \ sEPD_TreeGen.cc \ QVecCalib.cc \ QVecCDB.cc @@ -47,6 +53,13 @@ GenQVecCalib_LDADD = libsepd_eventplanecalib.la GenQVecCDB_SOURCES = GenQVecCDB.cc GenQVecCDB_LDADD = libsepd_eventplanecalib.la +# Rule for generating table CINT dictionaries. +%_Dict.cc: %.h %LinkDef.h + rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ + +#just to get the dependency +%_Dict_rdict.pcm: %_Dict.cc ; + BUILT_SOURCES = testexternals.cc noinst_PROGRAMS = \ diff --git a/calibrations/sepd/sepd_eventplanecalib/configure.ac b/calibrations/sepd/sepd_eventplanecalib/configure.ac index 4abe4ad0ce..5fcb1af63a 100644 --- a/calibrations/sepd/sepd_eventplanecalib/configure.ac +++ b/calibrations/sepd/sepd_eventplanecalib/configure.ac @@ -12,5 +12,8 @@ if test $ac_cv_prog_gxx = yes; then CXXFLAGS="$CXXFLAGS -Wshadow -Wall -Wextra -Werror" fi +CINTDEFS=" -noIncludePaths -inlineInputHeader " +AC_SUBST(CINTDEFS) + AC_CONFIG_FILES([Makefile]) AC_OUTPUT From 505d785b74c1efdbb25133d74a7c0b3de7e4fae1 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 4 Feb 2026 13:30:49 -0500 Subject: [PATCH 166/866] New changes --- offline/packages/tpc/TpcClusterizer.cc | 103 ++++++++++++++----------- offline/packages/tpc/TpcClusterizer.h | 11 +-- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 881bc7f681..5be76aca3e 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -61,6 +61,7 @@ #include #include // for pair #include +#include // Terra incognita.... #include @@ -123,8 +124,8 @@ namespace double m_tdriftmax = 0; // --- new members for dead/hot map --- - hitMaskTpc *deadMap = nullptr; - hitMaskTpc *hotMap = nullptr; + hitMaskTpcSet *deadMap = nullptr; + hitMaskTpcSet *hotMap = nullptr; bool maskDead = false; bool maskHot = false; @@ -605,43 +606,53 @@ namespace TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); + // pads just outside the cluster in phi + const int left_pad = phibinlo - 1; + const int right_pad = phibinhi + 1; + // --- Dead channels --- - if (my_data.maskDead && my_data.deadMap->count(tpcHitSetKey)) + if (my_data.maskDead) + { + auto it = my_data.deadMap->find(tpcHitSetKey); + if (it != my_data.deadMap->end()) { - const auto &deadvec = (*my_data.deadMap)[tpcHitSetKey]; - - for (const auto &deadkey : deadvec) - { - int dphi = TpcDefs::getPad(deadkey); + const auto &deadset = it->second; - bool touch = (dphi == phibinlo - 1 || dphi == phibinhi + 1); + if (left_pad >= 0 && + deadset.count(TpcDefs::genHitKey(left_pad, 0))) + { + nedge++; + } - if (touch) - { - nedge++; - continue; - } - } + if (right_pad < my_data.phibins && + deadset.count(TpcDefs::genHitKey(right_pad, 0))) + { + nedge++; + } } + } // --- Hot channels --- - if (my_data.maskHot && my_data.hotMap->count(tpcHitSetKey)) + if (my_data.maskHot) + { + auto it = my_data.hotMap->find(tpcHitSetKey); + if (it != my_data.hotMap->end()) { - const auto &hotvec = (*my_data.hotMap)[tpcHitSetKey]; - - for (const auto &hotkey : hotvec) - { - int hphi = TpcDefs::getPad(hotkey); + const auto &hotset = it->second; - bool touch = (hphi == phibinlo -1 || hphi == phibinhi + 1); + if (left_pad >= 0 && + hotset.count(TpcDefs::genHitKey(left_pad, 0))) + { + nedge++; + } - if (touch) - { - nedge++; - continue; - } - } + if (right_pad < my_data.phibins && + hotset.count(TpcDefs::genHitKey(right_pad, 0))) + { + nedge++; + } } + } // This is the global position double clusiphi = iphi_sum / adc_sum; @@ -843,24 +854,28 @@ namespace // Helper function to check if a pad is masked auto is_pad_masked = [&](int abs_pad) -> bool { - if (my_data->maskDead && my_data->deadMap->count(tpcHitSetKey)) + TrkrDefs::hitkey key = TpcDefs::genHitKey(abs_pad, 0); + + if (my_data->maskDead) + { + auto it = my_data->deadMap->find(tpcHitSetKey); + if (it != my_data->deadMap->end() && + it->second.count(key)) { - const auto &deadvec = (*my_data->deadMap)[tpcHitSetKey]; - for (const auto &deadkey : deadvec) - { - if (TpcDefs::getPad(deadkey) == abs_pad) - return true; - } + return true; } - if (my_data->maskHot && my_data->hotMap->count(tpcHitSetKey)) + } + + if (my_data->maskHot) + { + auto it = my_data->hotMap->find(tpcHitSetKey); + if (it != my_data->hotMap->end() && + it->second.count(key)) { - const auto &hotvec = (*my_data->hotMap)[tpcHitSetKey]; - for (const auto &hotkey : hotvec) - { - if (TpcDefs::getPad(hotkey) == abs_pad) - return true; - } + return true; } + } + return false; }; @@ -1806,7 +1821,7 @@ int TpcClusterizer::End(PHCompositeNode * /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } -void TpcClusterizer::makeChannelMask(hitMaskTpc &aMask, const std::string &dbName, const std::string &totalChannelsToMask) +void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &dbName, const std::string &totalChannelsToMask) { CDBTTree *cdbttree; if (m_maskFromFile) @@ -1837,7 +1852,7 @@ void TpcClusterizer::makeChannelMask(hitMaskTpc &aMask, const std::string &dbNam TrkrDefs::hitsetkey DeadChannelHitKey = TpcDefs::genHitSetKey(Layer, Sector, Side); TrkrDefs::hitkey DeadHitKey = TpcDefs::genHitKey((unsigned int) Pad, 0); - aMask[DeadChannelHitKey].push_back(DeadHitKey); + aMask[DeadChannelHitKey].insert(DeadHitKey); } delete cdbttree; diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index 6ec5c18b1c..84a58ceca6 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -4,12 +4,13 @@ #include #include #include +#include #include #include -#include +#include -typedef std::map> hitMaskTpc; +typedef std::map> hitMaskTpcSet; class ClusHitsVerbosev1; class PHCompositeNode; @@ -94,7 +95,7 @@ class TpcClusterizer : public SubsysReco bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; - void makeChannelMask(hitMaskTpc& aMask, const std::string& dbName, const std::string& totalChannelsToMask); + void makeChannelMask(hitMaskTpcSet& aMask, const std::string& dbName, const std::string& totalChannelsToMask); TrkrHitSetContainer *m_hits = nullptr; RawHitSetContainer *m_rawhits = nullptr; @@ -128,8 +129,8 @@ class TpcClusterizer : public SubsysReco TrainingHitsContainer *m_training; - hitMaskTpc m_deadChannelMap; - hitMaskTpc m_hotChannelMap; + hitMaskTpcSet m_deadChannelMap; + hitMaskTpcSet m_hotChannelMap; bool m_maskDeadChannels {false}; bool m_maskHotChannels {false}; From 59ef9fc067e139b916051d8d6a99762825601f6c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 4 Feb 2026 13:54:31 -0500 Subject: [PATCH 167/866] add EventPlaneData node --- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index 38c9a25c18..279577e295 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -1,21 +1,11 @@ #include "sEPD_TreeGen.h" #include "QVecDefs.h" +#include "EventPlaneData.h" // -- c++ #include #include -// -- event -#include - -// -- Fun4All -#include -#include - -// -- Nodes -#include -#include - // -- Calo #include #include @@ -33,6 +23,18 @@ // -- sEPD #include +// -- event +#include + +// -- Fun4All +#include +#include + +// -- Nodes +#include +#include +#include + //____________________________________________________________________________.. sEPD_TreeGen::sEPD_TreeGen(const std::string &name) : SubsysReco(name) @@ -40,7 +42,7 @@ sEPD_TreeGen::sEPD_TreeGen(const std::string &name) } //____________________________________________________________________________.. -int sEPD_TreeGen::Init([[maybe_unused]] PHCompositeNode *topNode) +int sEPD_TreeGen::Init(PHCompositeNode *topNode) { // Early guard against filename collision if (m_outfile_name == m_outtree_name) @@ -85,6 +87,16 @@ int sEPD_TreeGen::Init([[maybe_unused]] PHCompositeNode *topNode) m_tree->Branch("sepd_channel", &m_data.sepd_channel); m_tree->Branch("sepd_charge", &m_data.sepd_charge); m_tree->Branch("sepd_phi", &m_data.sepd_phi); + PHNodeIterator node_itr(topNode); + PHCompositeNode *dstNode = dynamic_cast(node_itr.findFirst("PHCompositeNode", "DST")); + + EventPlaneData *evtdata = findNode::getClass(topNode, "EventPlaneData"); + if (!evtdata) + { + evtdata = new EventPlaneData(); + PHIODataNode *newNode = new PHIODataNode(evtdata, "EventPlaneData", "PHObject"); + dstNode->addNode(newNode); + } return Fun4AllReturnCodes::EVENT_OK; } From f683f68bb17547a627e002e0a380707a17e82ac5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 4 Feb 2026 14:36:28 -0500 Subject: [PATCH 168/866] add forgotten pcm file installation --- calibrations/sepd/sepd_eventplanecalib/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/calibrations/sepd/sepd_eventplanecalib/Makefile.am b/calibrations/sepd/sepd_eventplanecalib/Makefile.am index 3576435566..d09895d691 100644 --- a/calibrations/sepd/sepd_eventplanecalib/Makefile.am +++ b/calibrations/sepd/sepd_eventplanecalib/Makefile.am @@ -27,6 +27,10 @@ lib_LTLIBRARIES = \ ROOTDICTS = \ EventPlaneData_Dict.cc +pcmdir = $(libdir) +# more elegant way to create pcm files (without listing them) +nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) + # EventPlaneData is a locally used root i/o object - no need to create an io library libsepd_eventplanecalib_la_SOURCES = \ $(ROOTDICTS) \ From 1a6a8c0fbfb27ebb550ed507935023139f373dea Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 4 Feb 2026 14:47:49 -0500 Subject: [PATCH 169/866] Some more --- offline/packages/tpc/TpcClusterizer.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 5be76aca3e..e9e5d6212e 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -619,12 +619,13 @@ namespace const auto &deadset = it->second; if (left_pad >= 0 && + left_pad >= my_data.phioffset && deadset.count(TpcDefs::genHitKey(left_pad, 0))) { nedge++; } - if (right_pad < my_data.phibins && + if (right_pad < (my_data.phibins + my_data.phioffset) && deadset.count(TpcDefs::genHitKey(right_pad, 0))) { nedge++; @@ -641,12 +642,13 @@ namespace const auto &hotset = it->second; if (left_pad >= 0 && + left_pad >= my_data.phioffset && hotset.count(TpcDefs::genHitKey(left_pad, 0))) { nedge++; } - if (right_pad < my_data.phibins && + if (right_pad < (my_data.phibins + my_data.phioffset) && hotset.count(TpcDefs::genHitKey(right_pad, 0))) { nedge++; @@ -1823,15 +1825,15 @@ int TpcClusterizer::End(PHCompositeNode * /*topNode*/) void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &dbName, const std::string &totalChannelsToMask) { - CDBTTree *cdbttree; + std::unique_ptr cdbttree; if (m_maskFromFile) { - cdbttree = new CDBTTree(dbName); + cdbttree = std::make_unique(dbName); } else // mask using CDB TTree, default { std::string database = CDBInterface::instance()->getUrl(dbName); - cdbttree = new CDBTTree(database); + cdbttree = std::make_unique(database); } std::cout << "Masking TPC Channel Map: " << dbName << std::endl; @@ -1855,5 +1857,4 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db aMask[DeadChannelHitKey].insert(DeadHitKey); } - delete cdbttree; } From 86043f34caca553c863a08e21d1be7b52931ca4b Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 4 Feb 2026 14:57:30 -0500 Subject: [PATCH 170/866] Another change --- offline/packages/tpc/TpcClusterizer.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index e9e5d6212e..5885f03e2d 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1841,6 +1841,13 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db int NChan = -1; NChan = cdbttree->GetSingleIntValue(totalChannelsToMask); + if (NChan < 0) + { + std::cout << PHWHERE << "ERROR: Invalid or missing " << totalChannelsToMask + << " for " << dbName << ". Masking disabled for this map." << std::endl; + return; + } + for (int i = 0; i < NChan; i++) { int Layer = cdbttree->GetIntValue(i, "layer"); From 85003e4a20ef8bbcdd0aa6c516e8261c13661dfc Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 4 Feb 2026 15:16:11 -0500 Subject: [PATCH 171/866] New --- offline/packages/tpc/TpcClusterizer.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 5885f03e2d..834491e3b4 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1833,6 +1833,14 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db else // mask using CDB TTree, default { std::string database = CDBInterface::instance()->getUrl(dbName); + + if (database.empty()) + { + std::cout << PHWHERE << "ERROR: CDB URL not found for " << dbName + << ". Masking disabled for this map." << std::endl; + return; + } + cdbttree = std::make_unique(database); } From 40660d1532e54f5c5aab4a2f86d8510823a25b23 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 4 Feb 2026 15:34:04 -0500 Subject: [PATCH 172/866] More change. --- offline/packages/tpc/TpcClusterizer.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 834491e3b4..c5334ab6e0 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -962,16 +962,16 @@ namespace continue; } - int pindex = 0; + if (is_pad_masked(nphi + phioffset)) + { + continue; + } + + int pindex = 0; for (unsigned int nt = 0; nt < hitset->size(nphi); nt++) { unsigned short val = (*(hitset->getHits(nphi)))[nt]; - if (is_pad_masked(nphi + phioffset)) - { - pindex++; - continue; - } if (val == 0) { pindex++; From 2110245677195fc344372268bc0b40f8947fb239 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 4 Feb 2026 15:40:46 -0500 Subject: [PATCH 173/866] Good --- offline/packages/tpc/TpcClusterizer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index c5334ab6e0..ef22dea7d0 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -52,6 +52,7 @@ #include +#include #include #include #include // for sqrt, cos, sin From 83a66dbe76cb5dcb3eaccbe002fac9f171bd2321 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Feb 2026 21:29:59 -0500 Subject: [PATCH 174/866] add setter for cluster map name --- .../TrackingDiagnostics/TrackSeedTrackMapConverter.cc | 5 +++-- .../TrackingDiagnostics/TrackSeedTrackMapConverter.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc index 02a10baea3..969e746c82 100644 --- a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc +++ b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc @@ -588,10 +588,11 @@ int TrackSeedTrackMapConverter::getNodes(PHCompositeNode* topNode) std::cout << PHWHERE << "WARNING, TrackSeedTrackMapConverter may seg fault depending on what seeding algorithm this is run after" << std::endl; } - m_clusters = findNode::getClass(topNode, "TRKR_CLUSTER"); + m_clusters = findNode::getClass(topNode, m_clusterMapName); if (!m_clusters) { - std::cout << PHWHERE << " Can't find cluster container, can't continue." + std::cout << PHWHERE << " Can't find cluster container " << m_clusterMapName + << ", can't continue." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h index 1cff3281d7..ef9c48766e 100644 --- a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h +++ b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h @@ -29,6 +29,7 @@ class TrackSeedTrackMapConverter : public SubsysReco void setFieldMap(const std::string &name) { m_fieldMap = name; } void setTrackMapName(const std::string &name) { m_trackMapName = name; } void setTrackSeedName(const std::string &name) { m_trackSeedName = name; } + void setClusterMapName(const std::string& name) {m_clusterMapName = name; } void cosmics() { m_cosmics = true; } void constField() { m_ConstField = true; } @@ -56,6 +57,7 @@ class TrackSeedTrackMapConverter : public SubsysReco std::string m_fieldMap; std::string m_trackMapName{"SvtxTrackMap"}; std::string m_trackSeedName{"TpcTrackSeedContainer"}; + std::string m_clusterMapName{"TRKR_CLUSTER"}; }; #endif // TRACKSEEDTRACKMAPCONVERTER_H From 6974a5765ea61cd4e88a38b3561e5014376c3543 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Feb 2026 09:50:11 -0500 Subject: [PATCH 175/866] add diagnostic print out for checking for remaining duplicates --- .../packages/trackreco/PHSiliconSeedMerger.cc | 78 ++++++++++++++++++- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 263fdd6b35..5e47ebd548 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -88,7 +88,6 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) ++track1ID) { TrackSeed* track1 = m_siliconTracks->get(track1ID); - if (seedsToDelete.contains(track1ID)) { continue; @@ -125,7 +124,6 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) { continue; } - TrackSeed* track2 = m_siliconTracks->get(track2ID); if (track2 == nullptr) { @@ -260,13 +258,85 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) if (Verbosity() > 2) { - for (const auto& seed : *m_siliconTracks) + + for (unsigned int track1ID = 0; + track1ID != m_siliconTracks->size(); + ++track1ID) { + std::set mvtx1Keyscheck; + + TrackSeed* seed = m_siliconTracks->get(track1ID); if (!seed) { continue; } - seed->identify(); + int strobe1 = -9999; + for (auto iter = seed->begin_cluster_keys(); + iter != seed->end_cluster_keys(); + ++iter) + { + mvtx1Keyscheck.insert(*iter); + if( TrkrDefs::getTrkrId(*iter) == TrkrDefs::mvtxId) + { + strobe1 = MvtxDefs::getStrobeId(*iter); + } + } + + + + for (unsigned int track2ID = 0; + track2ID != m_siliconTracks->size(); + ++track2ID) + { + std::set mvtx2Keyscheck; + TrackSeed* seed2 = m_siliconTracks->get(track2ID); + if (!seed2) + { + continue; + } + int strobe2 = -9999; + for (auto iter2 = seed2->begin_cluster_keys(); + iter2 != seed2->end_cluster_keys(); + ++iter2) + { + mvtx2Keyscheck.insert(*iter2); + if (TrkrDefs::getTrkrId(*iter2) == TrkrDefs::mvtxId) + { + strobe2 = MvtxDefs::getStrobeId(*iter2); + } + } + std::vector intersectioncheck; + std::set_intersection(mvtx1Keyscheck.begin(), + mvtx1Keyscheck.end(), + mvtx2Keyscheck.begin(), + mvtx2Keyscheck.end(), + std::back_inserter(intersectioncheck)); + if(track1ID != track2ID) + { + if(intersectioncheck.size() == mvtx1Keyscheck.size() || intersectioncheck.size() == mvtx2Keyscheck.size()) + { + std::cout << "After merge, still have duplicate seeds: " + << " seed1 ID " << track1ID << " strobe " << strobe1 << " nkeys " << mvtx1Keyscheck.size() + << " seed2 ID " << track2ID << " strobe " << strobe2 << " nkeys " << mvtx2Keyscheck.size() + << " intersection size " << intersectioncheck.size() + << std::endl; + std::cout << "seed 1 keys " << std::endl; + std::cout << " "; + for (const auto& key : mvtx1Keyscheck) + { + std::cout << key << ", "; + } + std::cout << std::endl; + std::cout << "seed 2 keys " << std::endl; + std::cout << " "; + for (const auto& key : mvtx2Keyscheck) + { + std::cout << key << ", "; + } + std::cout << std::endl; + } + } + } } } From 56fd8e5dca5f1969a7299c7482f8731f7fa66c68 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Feb 2026 09:50:26 -0500 Subject: [PATCH 176/866] fix duplicate bug --- offline/packages/trackreco/PHSiliconSeedMerger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 5e47ebd548..c522700ff3 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -220,7 +220,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) matches.insert(std::make_pair(track1ID, mvtx1Keys)); seedsToDelete.insert(track2ID); - break; + } } } From 77ed93afaafa2f84882b5811d78d4bb6f920ff5f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Feb 2026 09:55:01 -0500 Subject: [PATCH 177/866] move diagnostic to function --- .../packages/trackreco/PHSiliconSeedMerger.cc | 106 +++++++++--------- .../packages/trackreco/PHSiliconSeedMerger.h | 5 +- 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index c522700ff3..acf6c9f1cd 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -258,8 +258,60 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) if (Verbosity() > 2) { + printRemainingDuplicates(); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +/** + * @brief Reset per-event state for the merger. + * + * This implementation performs no per-event cleanup and always reports success. + * + * @return Integer status code: `Fun4AllReturnCodes::EVENT_OK`. + */ +int PHSiliconSeedMerger::ResetEvent(PHCompositeNode* /*unused*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +/** + * @brief Perform end-of-run shutdown for the silicon seed merger. + * + * @return int EVENT_OK on successful completion. + */ +int PHSiliconSeedMerger::End(PHCompositeNode* /*unused*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} - for (unsigned int track1ID = 0; +/** + * @brief Retrieve required nodes from the top-level node tree and validate availability. + * + * Locates the silicon TrackSeedContainer using m_trackMapName and stores it in + * m_siliconTracks. If the container is not found, the function logs an error + * message and signals an abort for the current event. + * + * @param topNode Root node used to search for the TrackSeedContainer. + * @return int Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTEVENT if the silicon TrackSeedContainer is not present. + */ +int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) +{ + m_siliconTracks = findNode::getClass(topNode, m_trackMapName); + if (!m_siliconTracks) + { + std::cout << PHWHERE << "No silicon track container, can't merge seeds" + << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHSiliconSeedMerger::printRemainingDuplicates() +{ + for (unsigned int track1ID = 0; track1ID != m_siliconTracks->size(); ++track1ID) { @@ -338,54 +390,4 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) } } } - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -/** - * @brief Reset per-event state for the merger. - * - * This implementation performs no per-event cleanup and always reports success. - * - * @return Integer status code: `Fun4AllReturnCodes::EVENT_OK`. - */ -int PHSiliconSeedMerger::ResetEvent(PHCompositeNode* /*unused*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - -/** - * @brief Perform end-of-run shutdown for the silicon seed merger. - * - * @return int EVENT_OK on successful completion. - */ -int PHSiliconSeedMerger::End(PHCompositeNode* /*unused*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - -/** - * @brief Retrieve required nodes from the top-level node tree and validate availability. - * - * Locates the silicon TrackSeedContainer using m_trackMapName and stores it in - * m_siliconTracks. If the container is not found, the function logs an error - * message and signals an abort for the current event. - * - * @param topNode Root node used to search for the TrackSeedContainer. - * @return int Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTEVENT if the silicon TrackSeedContainer is not present. - */ -int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) -{ - m_siliconTracks = findNode::getClass(topNode, m_trackMapName); - if (!m_siliconTracks) - { - std::cout << PHWHERE << "No silicon track container, can't merge seeds" - << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - - return Fun4AllReturnCodes::EVENT_OK; -} - - +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index fcd741e688..d3d828d565 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -51,7 +51,7 @@ void mergeSeeds() { m_mergeSeeds = true; } private: int getNodes(PHCompositeNode *topNode); - + void printRemainingDuplicates(); TrackSeedContainer *m_siliconTracks{nullptr}; std::string m_trackMapName{"SiliconTrackSeedContainer"}; /** @@ -60,7 +60,8 @@ void mergeSeeds() { m_mergeSeeds = true; } * * Defaults to 1. */ -unsigned int m_clusterOverlap{1}; + unsigned int m_clusterOverlap{1}; + bool m_mergeSeeds{false}; /** * Restrict seed processing to the MVTX detector only. From cb381d6853ee81bf7b8d9d25d55aa42596706d1b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Feb 2026 10:23:58 -0500 Subject: [PATCH 178/866] fix logic bug noticed by rabbit --- offline/packages/trackreco/PHSiliconSeedMerger.cc | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index acf6c9f1cd..cd9de3c95c 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -208,19 +208,6 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) std::cout << " will delete seed " << track1ID << std::endl; } } - - if (Verbosity() > 2) - { - std::cout << "Match IDed" << std::endl; - for (const auto& key : mvtx1Keys) - { - std::cout << " total track keys " << key << std::endl; - } - } - - matches.insert(std::make_pair(track1ID, mvtx1Keys)); - seedsToDelete.insert(track2ID); - } } } From 932b4105604efb57296653dc8def1a4a30e5bd39 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 5 Feb 2026 12:21:50 -0500 Subject: [PATCH 179/866] Additional changes to matching and lamination fitting --- .../tpccalib/TpcCentralMembraneMatching.cc | 236 +++++++++++++++++- .../tpccalib/TpcCentralMembraneMatching.h | 15 ++ .../packages/tpccalib/TpcLaminationFitting.cc | 51 +++- .../packages/tpccalib/TpcLaminationFitting.h | 3 + 4 files changed, 285 insertions(+), 20 deletions(-) diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index fa73218b7a..2e85f78a0c 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -981,6 +981,9 @@ int TpcCentralMembraneMatching::getClusterRMatch(double clusterR, int side) //____________________________________________________________________________.. int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) { + + std::cout << "skipOutliers? " << m_skipOutliers << " manualInterp? " << m_manualInterp << std::endl; + if (!m_fieldOn) { m_useHeader = false; @@ -2266,12 +2269,20 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) ckey++; } - + // std::cout << "about to fill fluct hist" << std::endl; for (int s = 0; s < 2; s++) { + /* int N = gr_dR[s]->GetN(); + std::vector dataX(N), dataY(N); + for(int k=0; kGetY()[k]*cos(gr_dR[s]->GetX()[k]); + dataY[k] = gr_dR[s]->GetY()[k]*sin(gr_dR[s]->GetX()[k]); + } + */ bool firstGoodR = false; for (int j = 1; j <= m_dcc_out->m_hDRint[s]->GetNbinsY(); j++) @@ -2297,18 +2308,22 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) { double phiVal = m_dcc_out->m_hDRint[s]->GetXaxis()->GetBinCenter(i); + /* double num_dPhi = 0.0; double num_dR = 0.0; double den = 0.0; double smoothing_parameter = 2.0; + double hX = RVal*cos(phiVal); + double hY = RVal*sin(phiVal); + + + for(int k=0; kGetX()[k]); - double interp_RdPhi = RVal*interp_dPhi; - double interp_dR = RVal - gr_dR[s]->GetY()[k]; - - double distSq = (interp_RdPhi*interp_RdPhi) + (interp_dR*interp_dR); + double dx = hX - dataX[k]; + double dy = hY - dataY[k]; + double distSq = (dx*dx) + (dy*dy); if(distSq > 100.0) continue; @@ -2334,8 +2349,9 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) m_dcc_out->m_hDRint[s]->SetBinContent(i, j, num_dR / den); m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); } - //m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal,RVal)); - //m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); + */ + m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal,RVal)); + m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); } } } @@ -2427,15 +2443,146 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) } } + for(int s=0; s<2; s++) + { + gr_dR_toInterp[s] = (TGraph2D*)gr_dR[s]->Clone(); + gr_dPhi_toInterp[s] = (TGraph2D*)gr_dPhi[s]->Clone(); + } + + //figure out anomolous points to skip and make list + std::vector pointsToSkip[2]; + if(m_skipOutliers) + { + for(int s=0; s<2; s++) + { + std::vector peakBins; + std::vector peakVals; + TH1D *hPeaks = new TH1D("hPeaks","",500,26,80); + int N = gr_dR[s]->GetN(); + + //Make R histogram + for(int i=0; iFill(gr_dR[s]->GetY()[i]); + } + + int bc = 0; + int pbc = 0; + //loop over and find peaks by identifying hist bins where content is higher than adjacent bins + for(int i=1; i<=500; i++) + { + bc = hPeaks->GetBinContent(i); + if(bc > 10 && bc > pbc) + { + if(peakBins.size() == 0 || i > peakBins[peakBins.size()-1] + 1) + { + peakBins.push_back(i); + } + else + { + peakBins[peakBins.size()-1] = i; + } + } + pbc = bc; + } + + //Convert bins to R values, but if two bins are closer than 0.5 cm, pick the one with the largest bin content + for(int i=0; i<(int)peakBins.size(); i++) + { + if(i<(int)peakBins.size()-1 && hPeaks->GetBinCenter(peakBins[i+1]) - hPeaks->GetBinCenter(peakBins[i]) < 0.5) + { + peakVals.push_back((hPeaks->GetBinContent(peakBins[i]) > hPeaks->GetBinContent(peakBins[i+1]) ? hPeaks->GetBinCenter(peakBins[i]) : hPeaks->GetBinCenter(peakBins[i+1]))); + i++; + } + else + { + peakVals.push_back(hPeaks->GetBinCenter(peakBins[i])); + } + } + + std::vector mu; + std::vector sig; + + //fit each peak with a gaussian to get mean and sigma + TF1 *f1 = new TF1("f1","gaus(0)",26,80); + for(int i=0; i<(int)peakVals.size(); i++) + { + f1->SetParameters(hPeaks->GetBinContent(hPeaks->FindBin(peakVals[i])),peakVals[i],0.2); + if(i == 0) hPeaks->Fit(f1,"Q","",peakVals[i]-0.5,(peakVals[i]+peakVals[i+1])/2); + else if (i<(int)peakVals.size()-1) hPeaks->Fit(f1,"Q","",(peakVals[i-1]+peakVals[i])/2,(peakVals[i]+peakVals[i+1])/2); + else hPeaks->Fit(f1,"Q","",(peakVals[i-1]+peakVals[i])/2,peakVals[i]+1); + mu.push_back(f1->GetParameter(1)); + sig.push_back(f1->GetParameter(2)); + } + + //for each point in histogram, identify if within 3 sigma from mean of any of the peaks + //if not within 3 sigma from any of them, add to list of points to skip + for(int i=0; iGetY()[i]; + if(RVal_gr > mu[j] - 3*sig[j] && RVal_gr < mu[j] + 3*sig[j]) + { + good = true; + break; + } + } + if(!good) + { + pointsToSkip[s].push_back(i); + } + } + } + } + for (int s = 0; s < 2; s++) { - bool firstGoodR = false; + int N = gr_dR[s]->GetN(); + std::vector dataX(N), dataY(N); + double minR = 99.0; + double maxR = 0.0; + + if(m_skipOutliers) + { + int N_toInterp = (int)gr_dR_toInterp[s]->GetN(); + for(int i=N_toInterp-1; i>=0; i--) + { + for(int j=0; j<(int)pointsToSkip[s].size(); j++) + { + if(i == pointsToSkip[s][j]) + { + gr_dR_toInterp[s]->RemovePoint(i); + gr_dPhi_toInterp[s]->RemovePoint(i); + gr_points[s]->RemovePoint(i); + break; + } + } + } + } + + for(int k=0; kGetY()[k]; + + dataX[k] = RVal*cos(gr_dR[s]->GetX()[k]); + dataY[k] = RVal*sin(gr_dR[s]->GetX()[k]); + + if(RVal < minR) minR = RVal; + if(RVal > maxR) maxR = RVal; + } + + //bool firstGoodR = false; for (int j = 1; j <= m_dcc_out_aggregated->m_hDRint[s]->GetNbinsY(); j++) { double RVal = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinCenter(j); double Rlow = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinLowEdge(j); double Rhigh = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinLowEdge(j + 1); + + if(Rhigh < minR || Rlow > maxR) continue; + /* if (!firstGoodR) { for (int p = 0; p < gr_dR[s]->GetN(); p++) @@ -2448,14 +2595,76 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) } continue; } + */ for (int i = 2; i <= m_dcc_out_aggregated->m_hDRint[s]->GetNbinsX() - 1; i++) { double phiVal = m_dcc_out_aggregated->m_hDRint[s]->GetXaxis()->GetBinCenter(i); - m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal, RVal)); - m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal * gr_dPhi[s]->Interpolate(phiVal, RVal)); - } + if(m_manualInterp) + { + double num_dPhi = 0.0; + double num_dR = 0.0; + double den = 0.0; + double smoothing_parameter = 2.0; + + double hX = RVal*cos(phiVal); + double hY = RVal*sin(phiVal); + + for(int k=0; k 100.0) continue; + + if(distSq < 1e-9) + { + num_dPhi = gr_dPhi[s]->GetZ()[k]; + num_dR = gr_dR[s]->GetZ()[k]; + + den = 1.0; + + break; + } + + double weight = 1.0 / pow(distSq, smoothing_parameter / 2.0); + num_dPhi += weight * gr_dPhi[s]->GetZ()[k]; + num_dR += weight * gr_dR[s]->GetZ()[k]; + den += weight; + } + + if(den > 0.0) + { + m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, num_dR / den); + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); + } + } + else + { + m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, gr_dR_toInterp[s]->Interpolate(phiVal,RVal)); + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + } + } } } @@ -2480,6 +2689,9 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) gr_points[i]->Write(std::format("gr_points_{}z", (i == 1 ? "pos" : "neg")).c_str()); gr_dR[i]->Write(std::format("gr_dr_{}z", (i == 1 ? "pos" : "neg")).c_str()); gr_dPhi[i]->Write(std::format("gr_dPhi_{}z", (i == 1 ? "pos" : "neg")).c_str()); + + gr_dR_toInterp[i]->Write(std::format("gr_dr_toInterp_{}z", (i == 1 ? "pos" : "neg")).c_str()); + gr_dPhi_toInterp[i]->Write(std::format("gr_dPhi_toInterp_{}z", (i == 1 ? "pos" : "neg")).c_str()); } } diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.h b/offline/packages/tpccalib/TpcCentralMembraneMatching.h index f55bfe3a0e..2c2bce46b8 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.h +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.h @@ -103,6 +103,16 @@ class TpcCentralMembraneMatching : public SubsysReco m_totalDistMode = totalDistMode; } + void set_skipOutliers(bool skipOutliers) + { + m_skipOutliers = skipOutliers; + } + + void set_manualInterp(bool manualInterp) + { + m_manualInterp = manualInterp; + } + void set_event_sequence(int seq) { m_event_sequence = seq; @@ -281,6 +291,9 @@ class TpcCentralMembraneMatching : public SubsysReco TGraph2D *gr_dPhi[2]{nullptr, nullptr}; TGraph *gr_points[2]{nullptr, nullptr}; + TGraph2D *gr_dR_toInterp[2]{nullptr, nullptr}; + TGraph2D *gr_dPhi_toInterp[2]{nullptr, nullptr}; + /// phi cut for matching clusters to pad /** TODO: this will need to be adjusted to match beam-induced time averaged distortions */ double m_phi_cut{0.025}; @@ -387,6 +400,8 @@ class TpcCentralMembraneMatching : public SubsysReco bool m_fieldOn{true}; bool m_doFancy{false}; bool m_doHadd{false}; + bool m_skipOutliers{false}; + bool m_manualInterp{false}; std::vector m_reco_RPeaks[2]; double m_m[2]{}; diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index ee23e9d0db..acf2604125 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -33,6 +33,10 @@ #include #include +#include +#include + + #include #include #include @@ -61,6 +65,8 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) m_hPetal[s] = new TH2D((boost::format("hPetal_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s;#phi;R [cm]") %(s == 1 ? "North" : "South")).str().c_str(), 500, m_phiModMin[s], m_phiModMax[s], 500, 30, 80); m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;m;B") %(s == 1 ? "North" : "South")).str().c_str(), 41, -0.0205, 0.0205, 49, -3.0625, 3.0625); + //m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;m;B") %(s == 1 ? "North" : "South")).str().c_str(), 101, -0.101, 0.101, 101, -10.1, 10.1); + //m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;A (asymptote);C (decay constant)") %(s == 1 ? "North" : "South")).str().c_str(), 101, -1.005, 0.005, 101, -0.0025, 0.5025); for (int l = 0; l < 18; l++) { @@ -329,6 +335,7 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) m_laminationTree->Branch("C_err",&m_C_err); m_laminationTree->Branch("distanceToFit",&m_dist); m_laminationTree->Branch("nBinsFit",&m_nBins); + m_laminationTree->Branch("RMSE",&m_rmse); return Fun4AllReturnCodes::EVENT_OK; @@ -632,6 +639,9 @@ int TpcLaminationFitting::fitLaminations() int nBinsUsed = 0; int nBinsUsed_R_lt_45 = 0; + double wc = 0.0; + double c = 0.0; + for (int i = 1; i <= m_hLamination[l][s]->GetNbinsX(); i++) { double R = m_hLamination[l][s]->GetXaxis()->GetBinCenter(i); @@ -663,10 +673,25 @@ int TpcLaminationFitting::fitLaminations() break; } } + for(int j=0; j<= nBinAvg; j++) + { + if(m_hLamination[l][s]->GetBinContent(i,funcBin + j) > 0) + { + wc += m_hLamination[l][s]->GetBinContent(i,funcBin + j) * pow(j,2); + c += m_hLamination[l][s]->GetBinContent(i,funcBin + j); + } + if(j != 0 && m_hLamination[l][s]->GetBinContent(i,funcBin - j) > 0) + { + wc += m_hLamination[l][s]->GetBinContent(i,funcBin - j) * pow(j,2); + c += m_hLamination[l][s]->GetBinContent(i,funcBin - j); + } + } } m_distanceToFit[l][s] = distToFunc / nBinsUsed; m_nBinsFit[l][s] = nBinsUsed; + if(c>0) m_fitRMSE[l][s] = sqrt(wc / c); + else m_fitRMSE[l][s] = -999; if (nBinsUsed < 10 || distToFunc / nBinsUsed > 1.0 || nBinsUsed_R_lt_45 < 5) { m_laminationGoodFit[l][s] = false; @@ -800,14 +825,16 @@ int TpcLaminationFitting::doGlobalRMatching(int side) std::vector distortedPhi; TF1 *tmpLamFit = (TF1*)m_fLamination[0][side]->Clone(); + double meanB = 0.0; + if(m_fieldOff) { tmpLamFit->SetParameters(0.0, 0.0); + meanB = -999.99; } else { double meanA = 0.0; - double meanB = 0.0; double meanC = 0.0; double meanOffset = 0.0; int nGoodFits = 0; @@ -854,16 +881,21 @@ int TpcLaminationFitting::doGlobalRMatching(int side) double maxSum = 0.0; double best_m = 0.0; double best_b = 0.0; - int mStep = 0; - int bStep = 0; - for(double m = -0.02; m<=0.02; m+=0.001) + //int mStep = 0; + //int bStep = 0; + //for(double m = -0.02; m<=0.02; m+=0.001) + for(int xbin=1; xbin<=m_parameterScan[side]->GetNbinsX(); xbin++) { - for(double b=-3.0; b<=3.0; b+=0.125) + double m = m_parameterScan[side]->GetXaxis()->GetBinCenter(xbin); + //for(double b=-3.0; b<=3.0; b+=0.125) + for(int ybin=1; ybin<=m_parameterScan[side]->GetNbinsY(); ybin++) { + double b = m_parameterScan[side]->GetYaxis()->GetBinCenter(ybin); double sum = 0.0; for(int i=0; i<(int)m_truthR[side].size(); i++) { double distortedTruthR = (m_truthR[side][i] + b)/(1.0 - m); + //double distortedTruthR = boost::math::lambert_w0(-m*b*exp(meanB-m_truthR[side][i]-m))/b + m_truthR[side][i] + m; int binR = m_hPetal[side]->GetYaxis()->FindBin(distortedTruthR); int binPhi = m_hPetal[side]->GetXaxis()->FindBin(distortedPhi[i]); for(int j=-2; j<=2; j++) @@ -885,7 +917,7 @@ int TpcLaminationFitting::doGlobalRMatching(int side) } } } - std::cout << "working on side " << side << " m step " << mStep << " b step " << bStep << " with m = " << m << " and b = " << b << " with sum = " << sum << std::endl; + std::cout << "working on side " << side << " m step " << xbin-1 << " b step " << ybin-1 << " with m = " << m << " and b = " << b << " with sum = " << sum << std::endl; m_parameterScan[side]->Fill(m, b, sum); @@ -895,9 +927,9 @@ int TpcLaminationFitting::doGlobalRMatching(int side) best_m = m; best_b = b; } - bStep++; + //bStep++; } - mStep++; + //mStep++; } std::cout << "Best R distortion for side " << side << " is m = " << best_m << " and b = " << best_b << " with sum of " << maxSum << std::endl; @@ -1021,6 +1053,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) pars->AddText((boost::format("#phi_{offset}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); + pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); } else { @@ -1033,6 +1066,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) pars->AddText((boost::format("C=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(2) %m_fLamination[l][s]->GetParError(2)).str().c_str()); pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); + pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); } pars->Draw("same"); c1->SaveAs(m_QAFileName.c_str()); @@ -1135,6 +1169,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } m_dist = m_distanceToFit[l][s]; m_nBins = m_nBinsFit[l][s]; + m_rmse = m_fitRMSE[l][s]; m_laminationTree->Fill(); } } diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index a44160ca02..44e8b56868 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -89,6 +89,8 @@ class TpcLaminationFitting : public SubsysReco bool m_laminationGoodFit[18][2]{{false}}; double m_distanceToFit[18][2]{{0.0}}; int m_nBinsFit[18][2]{{0}}; + double m_fitRMSE[18][2]{{0.0}}; + TH2 *m_hPetal[2]{nullptr}; TGraph *m_bestRMatch[2]{nullptr}; @@ -129,6 +131,7 @@ class TpcLaminationFitting : public SubsysReco double m_B_err{0}; double m_C_err{0}; double m_dist{0}; + double m_rmse{}; int m_nBins{0}; int m_phibins{80}; From 5acea88d0f9f20b2724c96a30a3a57bc4d2668b4 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Feb 2026 12:33:46 -0500 Subject: [PATCH 180/866] fix merge seeds keys --- offline/packages/trackreco/PHSiliconSeedMerger.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index cd9de3c95c..c49c522420 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -187,7 +187,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) { keysToKeep.insert(mvtx2Keys.begin(), mvtx2Keys.end()); } - matches.insert(std::make_pair(track1ID, mvtx1Keys)); + matches.insert(std::make_pair(track1ID, keysToKeep)); seedsToDelete.insert(track2ID); if (Verbosity() > 2) { @@ -201,7 +201,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) { keysToKeep.insert(mvtx1Keys.begin(), mvtx1Keys.end()); } - matches.insert(std::make_pair(track2ID, mvtx2Keys)); + matches.insert(std::make_pair(track2ID, keysToKeep)); seedsToDelete.insert(track1ID); if (Verbosity() > 2) { @@ -211,7 +211,9 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) } } } - + + if (m_mergeSeeds) + { for (const auto& [trackKey, mvtxKeys] : matches) { auto* track = m_siliconTracks->get(trackKey); @@ -233,7 +235,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) } } } - + } for (const auto& key : seedsToDelete) { if (Verbosity() > 2) From 756f1ffafab76a35c4c7a7d2f5a4e0af89a2576d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Feb 2026 12:34:46 -0500 Subject: [PATCH 181/866] clang-format --- .../packages/trackreco/PHSiliconSeedMerger.cc | 148 +++++++++--------- .../packages/trackreco/PHSiliconSeedMerger.h | 64 ++++---- 2 files changed, 104 insertions(+), 108 deletions(-) diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index c49c522420..c2e2d3e9b4 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -211,31 +211,31 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) } } } - + if (m_mergeSeeds) { - for (const auto& [trackKey, mvtxKeys] : matches) - { - auto* track = m_siliconTracks->get(trackKey); - if (Verbosity() > 2) + for (const auto& [trackKey, mvtxKeys] : matches) { - std::cout << "original track: " << std::endl; - track->identify(); - } + auto* track = m_siliconTracks->get(trackKey); + if (Verbosity() > 2) + { + std::cout << "original track: " << std::endl; + track->identify(); + } - for (const auto& key : mvtxKeys) - { - if (track->find_cluster_key(key) == track->end_cluster_keys()) + for (const auto& key : mvtxKeys) { - track->insert_cluster_key(key); - if (Verbosity() > 2) + if (track->find_cluster_key(key) == track->end_cluster_keys()) { - std::cout << "adding " << key << std::endl; + track->insert_cluster_key(key); + if (Verbosity() > 2) + { + std::cout << "adding " << key << std::endl; + } } } } } - } for (const auto& key : seedsToDelete) { if (Verbosity() > 2) @@ -301,82 +301,80 @@ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) void PHSiliconSeedMerger::printRemainingDuplicates() { for (unsigned int track1ID = 0; - track1ID != m_siliconTracks->size(); - ++track1ID) + track1ID != m_siliconTracks->size(); + ++track1ID) + { + std::set mvtx1Keyscheck; + + TrackSeed* seed = m_siliconTracks->get(track1ID); + if (!seed) { - std::set mvtx1Keyscheck; + continue; + } + int strobe1 = -9999; + for (auto iter = seed->begin_cluster_keys(); + iter != seed->end_cluster_keys(); + ++iter) + { + mvtx1Keyscheck.insert(*iter); + if (TrkrDefs::getTrkrId(*iter) == TrkrDefs::mvtxId) + { + strobe1 = MvtxDefs::getStrobeId(*iter); + } + } - TrackSeed* seed = m_siliconTracks->get(track1ID); - if (!seed) + for (unsigned int track2ID = 0; + track2ID != m_siliconTracks->size(); + ++track2ID) + { + std::set mvtx2Keyscheck; + TrackSeed* seed2 = m_siliconTracks->get(track2ID); + if (!seed2) { continue; } - int strobe1 = -9999; - for (auto iter = seed->begin_cluster_keys(); - iter != seed->end_cluster_keys(); - ++iter) + int strobe2 = -9999; + for (auto iter2 = seed2->begin_cluster_keys(); + iter2 != seed2->end_cluster_keys(); + ++iter2) { - mvtx1Keyscheck.insert(*iter); - if( TrkrDefs::getTrkrId(*iter) == TrkrDefs::mvtxId) + mvtx2Keyscheck.insert(*iter2); + if (TrkrDefs::getTrkrId(*iter2) == TrkrDefs::mvtxId) { - strobe1 = MvtxDefs::getStrobeId(*iter); + strobe2 = MvtxDefs::getStrobeId(*iter2); } } - - - - for (unsigned int track2ID = 0; - track2ID != m_siliconTracks->size(); - ++track2ID) + std::vector intersectioncheck; + std::set_intersection(mvtx1Keyscheck.begin(), + mvtx1Keyscheck.end(), + mvtx2Keyscheck.begin(), + mvtx2Keyscheck.end(), + std::back_inserter(intersectioncheck)); + if (track1ID != track2ID) { - std::set mvtx2Keyscheck; - TrackSeed* seed2 = m_siliconTracks->get(track2ID); - if (!seed2) - { - continue; - } - int strobe2 = -9999; - for (auto iter2 = seed2->begin_cluster_keys(); - iter2 != seed2->end_cluster_keys(); - ++iter2) + if (intersectioncheck.size() == mvtx1Keyscheck.size() || intersectioncheck.size() == mvtx2Keyscheck.size()) { - mvtx2Keyscheck.insert(*iter2); - if (TrkrDefs::getTrkrId(*iter2) == TrkrDefs::mvtxId) + std::cout << "After merge, still have duplicate seeds: " + << " seed1 ID " << track1ID << " strobe " << strobe1 << " nkeys " << mvtx1Keyscheck.size() + << " seed2 ID " << track2ID << " strobe " << strobe2 << " nkeys " << mvtx2Keyscheck.size() + << " intersection size " << intersectioncheck.size() + << std::endl; + std::cout << "seed 1 keys " << std::endl; + std::cout << " "; + for (const auto& key : mvtx1Keyscheck) { - strobe2 = MvtxDefs::getStrobeId(*iter2); + std::cout << key << ", "; } - } - std::vector intersectioncheck; - std::set_intersection(mvtx1Keyscheck.begin(), - mvtx1Keyscheck.end(), - mvtx2Keyscheck.begin(), - mvtx2Keyscheck.end(), - std::back_inserter(intersectioncheck)); - if(track1ID != track2ID) - { - if(intersectioncheck.size() == mvtx1Keyscheck.size() || intersectioncheck.size() == mvtx2Keyscheck.size()) + std::cout << std::endl; + std::cout << "seed 2 keys " << std::endl; + std::cout << " "; + for (const auto& key : mvtx2Keyscheck) { - std::cout << "After merge, still have duplicate seeds: " - << " seed1 ID " << track1ID << " strobe " << strobe1 << " nkeys " << mvtx1Keyscheck.size() - << " seed2 ID " << track2ID << " strobe " << strobe2 << " nkeys " << mvtx2Keyscheck.size() - << " intersection size " << intersectioncheck.size() - << std::endl; - std::cout << "seed 1 keys " << std::endl; - std::cout << " "; - for (const auto& key : mvtx1Keyscheck) - { - std::cout << key << ", "; - } - std::cout << std::endl; - std::cout << "seed 2 keys " << std::endl; - std::cout << " "; - for (const auto& key : mvtx2Keyscheck) - { - std::cout << key << ", "; - } - std::cout << std::endl; + std::cout << key << ", "; } + std::cout << std::endl; } } } + } } \ No newline at end of file diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index d3d828d565..b07551977d 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -26,28 +26,28 @@ class PHSiliconSeedMerger : public SubsysReco int End(PHCompositeNode *topNode) override; /** - * Set the name of the track seed container to use when retrieving silicon tracks. - * - * @param name Name of the TrackSeedContainer node (defaults to "SiliconTrackSeedContainer"). - */ -void trackMapName(const std::string &name) { m_trackMapName = name; } + * Set the name of the track seed container to use when retrieving silicon tracks. + * + * @param name Name of the TrackSeedContainer node (defaults to "SiliconTrackSeedContainer"). + */ + void trackMapName(const std::string &name) { m_trackMapName = name; } /** - * Set the maximum number of overlapping clusters considered during seed merging. - * @param nclusters Maximum number of clusters that may overlap (overlap threshold). - */ -void clusterOverlap(const unsigned int nclusters) { m_clusterOverlap = nclusters; } + * Set the maximum number of overlapping clusters considered during seed merging. + * @param nclusters Maximum number of clusters that may overlap (overlap threshold). + */ + void clusterOverlap(const unsigned int nclusters) { m_clusterOverlap = nclusters; } /** - * @brief Allow merging searches to include the INTT detector. - * - * Configure the merger to include INTT clusters in subsequent processing by disabling the MVTX-only restriction. - */ -void searchIntt() { m_mvtxOnly = false; } + * @brief Allow merging searches to include the INTT detector. + * + * Configure the merger to include INTT clusters in subsequent processing by disabling the MVTX-only restriction. + */ + void searchIntt() { m_mvtxOnly = false; } /** - * Enable merging of silicon seed tracks during event processing. - * - * When enabled, the module will merge overlapping silicon seed tracks where applicable. - */ -void mergeSeeds() { m_mergeSeeds = true; } + * Enable merging of silicon seed tracks during event processing. + * + * When enabled, the module will merge overlapping silicon seed tracks where applicable. + */ + void mergeSeeds() { m_mergeSeeds = true; } private: int getNodes(PHCompositeNode *topNode); @@ -55,24 +55,22 @@ void mergeSeeds() { m_mergeSeeds = true; } TrackSeedContainer *m_siliconTracks{nullptr}; std::string m_trackMapName{"SiliconTrackSeedContainer"}; /** - * Minimum number of clusters that must be shared between two silicon track seeds - * for them to be considered overlapping. - * - * Defaults to 1. - */ + * Minimum number of clusters that must be shared between two silicon track seeds + * for them to be considered overlapping. + * + * Defaults to 1. + */ unsigned int m_clusterOverlap{1}; bool m_mergeSeeds{false}; /** - * Restrict seed processing to the MVTX detector only. - * - * When set to `true`, operations that iterate or merge silicon seed tracks - * will be limited to clusters originating from the MVTX vertex detector. - * When `false`, clusters from other silicon detectors are included. - */ -bool m_mvtxOnly{false}; + * Restrict seed processing to the MVTX detector only. + * + * When set to `true`, operations that iterate or merge silicon seed tracks + * will be limited to clusters originating from the MVTX vertex detector. + * When `false`, clusters from other silicon detectors are included. + */ + bool m_mvtxOnly{false}; }; #endif // PHSILICONSEEDMERGER_H - - From a0c4f0024bf1d9fc1f5e4874d3f99283fe073c03 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Thu, 5 Feb 2026 13:36:26 -0500 Subject: [PATCH 182/866] Final Change (Hopefully) --- offline/packages/tpc/TpcClusterizer.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index ef22dea7d0..24405c8df4 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -621,13 +621,13 @@ namespace if (left_pad >= 0 && left_pad >= my_data.phioffset && - deadset.count(TpcDefs::genHitKey(left_pad, 0))) + deadset.contains(TpcDefs::genHitKey(left_pad, 0))) { nedge++; } if (right_pad < (my_data.phibins + my_data.phioffset) && - deadset.count(TpcDefs::genHitKey(right_pad, 0))) + deadset.contains(TpcDefs::genHitKey(right_pad, 0))) { nedge++; } @@ -644,13 +644,13 @@ namespace if (left_pad >= 0 && left_pad >= my_data.phioffset && - hotset.count(TpcDefs::genHitKey(left_pad, 0))) + hotset.contains(TpcDefs::genHitKey(left_pad, 0))) { nedge++; } if (right_pad < (my_data.phibins + my_data.phioffset) && - hotset.count(TpcDefs::genHitKey(right_pad, 0))) + hotset.contains(TpcDefs::genHitKey(right_pad, 0))) { nedge++; } @@ -863,7 +863,7 @@ namespace { auto it = my_data->deadMap->find(tpcHitSetKey); if (it != my_data->deadMap->end() && - it->second.count(key)) + it->second.contains(key)) { return true; } @@ -873,7 +873,7 @@ namespace { auto it = my_data->hotMap->find(tpcHitSetKey); if (it != my_data->hotMap->end() && - it->second.count(key)) + it->second.contains(key)) { return true; } From 062f669b7a372955653d0c982d4c9e045c72eed7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 5 Feb 2026 14:10:43 -0500 Subject: [PATCH 183/866] move OnCal to Fun4Cal --- calibrations/framework/fun4cal/CalReco.cc | 48 + calibrations/framework/fun4cal/CalReco.h | 59 + .../framework/fun4cal/Fun4CalDBCodes.h | 19 + .../framework/fun4cal/Fun4CalHistoBinDefs.h | 16 + .../framework/fun4cal/Fun4CalServer.cc | 2439 +++++++++++++++++ .../framework/fun4cal/Fun4CalServer.h | 140 + calibrations/framework/fun4cal/Makefile.am | 48 + calibrations/framework/fun4cal/autogen.sh | 8 + calibrations/framework/fun4cal/configure.ac | 16 + 9 files changed, 2793 insertions(+) create mode 100644 calibrations/framework/fun4cal/CalReco.cc create mode 100644 calibrations/framework/fun4cal/CalReco.h create mode 100644 calibrations/framework/fun4cal/Fun4CalDBCodes.h create mode 100644 calibrations/framework/fun4cal/Fun4CalHistoBinDefs.h create mode 100644 calibrations/framework/fun4cal/Fun4CalServer.cc create mode 100644 calibrations/framework/fun4cal/Fun4CalServer.h create mode 100644 calibrations/framework/fun4cal/Makefile.am create mode 100755 calibrations/framework/fun4cal/autogen.sh create mode 100644 calibrations/framework/fun4cal/configure.ac diff --git a/calibrations/framework/fun4cal/CalReco.cc b/calibrations/framework/fun4cal/CalReco.cc new file mode 100644 index 0000000000..46ad141654 --- /dev/null +++ b/calibrations/framework/fun4cal/CalReco.cc @@ -0,0 +1,48 @@ +#include "CalReco.h" + +#include // for SubsysReco + +#include // for PHWHERE + +#include + +CalReco::CalReco(const std::string &Name) + : SubsysReco(Name) +{ +} + +int CalReco::process_event(PHCompositeNode * /*topNode*/) +{ + std::cout << "process_event(PHCompositeNode *topNode) not implemented by daughter class: " << Name() << std::endl; + return -1; +} + +int CalReco::End(PHCompositeNode * /*topNode*/) +{ + std::cout << "EndOfAnalysis not implemented by subsystem!" << std::endl; + std::cout << "Use this signal for computing your calibrations and commit." << std::endl; + std::cout << "Dont do these operations at EndOfRun since subsystems may be feeded events from different runs." << std::endl; + std::cout << "The number of events is the real parameter here, not the runnumber." << std::endl; + return 0; +} + +void CalReco::AddComment(const std::string &adcom) +{ + if (m_Comment.empty()) + { + m_Comment = adcom; + } + else + { + m_Comment += ":"; + m_Comment += adcom; + } + return; +} + +int CalReco::CopyTables(const int /*FromRun*/, const int /*ToRun*/, const int /*commit*/) const +{ + std::cout << PHWHERE << " CopyTables not implemented" << std::endl + << "this calibrator cannot copy its own tables" << std::endl; + return -1; +} diff --git a/calibrations/framework/fun4cal/CalReco.h b/calibrations/framework/fun4cal/CalReco.h new file mode 100644 index 0000000000..e2ba725884 --- /dev/null +++ b/calibrations/framework/fun4cal/CalReco.h @@ -0,0 +1,59 @@ +#ifndef FUN4CAL_CALRECO_H +#define FUN4CAL_CALRECO_H + +#include +#include +#include +#include // for pair +#include + +class CalReco : public SubsysReco +{ + public: + ~CalReco() override = default; + + // These might be overwritten by everyone... + int process_event(PHCompositeNode *topNode) override; + int End(PHCompositeNode *topNode) override = 0; // Here you analyze and commit (if committing flag is set) + + // Thsse control committing to the database... + virtual void CommitToPdbCal(const int value) = 0; // Set the flag for whether EndOfAnalysis will commit or not + virtual int VerificationOK() const = 0; // Tell us whether the new calib is close enough to the old one + virtual int CommitedToPdbCalOK() const = 0; // Tell us whether committing was successful by re-reading the data + + // commit without verification, needed for bootstrap calib + // which is too different from previous calibs (e.g. begin of new Run) + virtual void CommitNoVerify(const int) { return; } + + // These default behaviors from SubsysReco base class + virtual void identify(std::ostream &out = std::cout) const { out << Name() << std::endl; } + virtual int BeginRun(const int) { return 0; } + int EndRun(const int) override { return 0; } + int Reset(PHCompositeNode * /*topNode*/) override { return 0; } + int ResetEvent(PHCompositeNode * /*topNode*/) override { return 0; } + virtual void DumpCalib() const { return; } + + unsigned int AllDone() const { return alldone; } + void AllDone(const int i) { alldone = i; } + void AddComment(const std::string &adcom); + const std::string &Comment() const { return m_Comment; } + int GetPdbCalTables(std::vector &vec) const + { + vec = pdbcaltables; + return 0; + } + virtual int CopyTables(const int FromRun, const int ToRun, const int commit) const; + virtual int CreateCalibration(const int /*runnumber*/, const std::string & /*what*/, std::string & /*comment*/, const int /*commit*/) { return -1; } + virtual std::vector GetLocalFileList() const { return localfilelist; } + + protected: + CalReco(const std::string &Name); // so noone can call it from outside + unsigned int alldone{0}; + std::string m_Comment; + std::vector pdbcaltables; + std::vector pdbcalclasses; + std::vector > bankids; + std::vector localfilelist; +}; + +#endif /* CALRECO_CALRECO_H */ diff --git a/calibrations/framework/fun4cal/Fun4CalDBCodes.h b/calibrations/framework/fun4cal/Fun4CalDBCodes.h new file mode 100644 index 0000000000..7964f6679c --- /dev/null +++ b/calibrations/framework/fun4cal/Fun4CalDBCodes.h @@ -0,0 +1,19 @@ +#ifndef FUN4CAL_FUN4CALDBCODES_H +#define FUN4CAL_FUN4CALDBCODES_H + +namespace Fun4CalDBCodes +{ + enum + { + INIT = -2, + STARTED = -1, + FAILED = 0, + SUCCESS = 1, + COPIEDPREVIOUS = 2, + COPIEDLATER = 3, + COVERED = 4, + SUBSYSTEM = 5 + }; +} + +#endif diff --git a/calibrations/framework/fun4cal/Fun4CalHistoBinDefs.h b/calibrations/framework/fun4cal/Fun4CalHistoBinDefs.h new file mode 100644 index 0000000000..36c62bd3ec --- /dev/null +++ b/calibrations/framework/fun4cal/Fun4CalHistoBinDefs.h @@ -0,0 +1,16 @@ +#ifndef FUN4CAL_FUN4CALHISTOBINDEFS_H +#define FUN4CAL_FUN4CALHISTOBINDEFS_H + +namespace Fun4CalHistoBinDefs +{ + enum + { + FIRSTRUNBIN = 1, + LASTRUNBIN, + BORTIMEBIN, + EORTIMEBIN, + LASTBINPLUSONE + }; +}; + +#endif /* FUN4CAL_FUN4CALHISTOBINDEFS_H */ diff --git a/calibrations/framework/fun4cal/Fun4CalServer.cc b/calibrations/framework/fun4cal/Fun4CalServer.cc new file mode 100644 index 0000000000..5f9ec55b05 --- /dev/null +++ b/calibrations/framework/fun4cal/Fun4CalServer.cc @@ -0,0 +1,2439 @@ +#include "Fun4CalServer.h" +#include "CalReco.h" +#include "Fun4CalDBCodes.h" +#include "Fun4CalHistoBinDefs.h" + +#include +#include +#include // for Fun4AllServer, Fun4AllServe... +#include +#include +#include // for SubsysReco + +#include +#include // for PHTimeStamp, operator<< +#include +#include + +#include + +#include // for Stat_t +#include // for TDirectoryAtomicAdapter +#include +#include +#include // for TNamed +#include +#include // for TString + +// odbc++ classes +#include +#include +#include +#include +#include +#include // for Statement +#include // for SQLException, Timestamp + +#include +#include +#include // for tolower +#include +#include // for strcmp +#include +#include // for reverse_iterator +#include +#include +#include +#include // for pair + +namespace +{ + const std::string cvstag = "OnCalv86"; + + odbc::Connection *DBconnection{nullptr}; +} // namespace + +Fun4CalServer *Fun4CalServer::instance() +{ + if (__instance) + { + Fun4CalServer *oncal = dynamic_cast(__instance); + return oncal; + } + __instance = new Fun4CalServer(); + Fun4CalServer *oncal = dynamic_cast(__instance); + return oncal; +} + +//--------------------------------------------------------------------- + +Fun4CalServer::Fun4CalServer(const std::string &name) + : Fun4AllServer(name) + , Fun4CalServerVars(new TH1D("Fun4CalServerVars", "Fun4CalServerVars", Fun4CalHistoBinDefs::LASTBINPLUSONE, -0.5, (int) (Fun4CalHistoBinDefs::LASTBINPLUSONE) -0.5)) +{ + beginTimeStamp.setTics(0); + endTimeStamp.setTics(0); + + Fun4AllServer::registerHisto(Fun4CalServerVars); + return; +} +//--------------------------------------------------------------------- + +Fun4CalServer::~Fun4CalServer() +{ + delete DBconnection; + return; +} +//--------------------------------------------------------------------- + +PHTimeStamp * +Fun4CalServer::GetEndValidityTS() +{ + if (endTimeStamp.getTics()) + { + PHTimeStamp *ts = new PHTimeStamp(endTimeStamp); + return ts; + } + + std::cout << PHWHERE << "Screwup - the end validity time is not set" << std::endl; + exit(1); +} +//--------------------------------------------------------------------- + +PHTimeStamp *Fun4CalServer::GetBeginValidityTS() +{ + if (beginTimeStamp.getTics()) + { + PHTimeStamp *ts = new PHTimeStamp(beginTimeStamp); + return ts; + } + + std::cout << PHWHERE << "Screwup - the begin validity time is not set" << std::endl; + exit(1); +} +//--------------------------------------------------------------------- + +void Fun4CalServer::dumpHistos() +{ + std::ostringstream filename; + std::string fileprefix = "./"; + + if (getenv("ONCAL_SAVEDIR")) + { + fileprefix = getenv("ONCAL_SAVEDIR"); + fileprefix += "/"; + } + + int compress = 3; + std::map >::const_iterator iter; + // std::map::const_iterator hiter; + TH1 *histo; + std::set::const_iterator siter; + for (iter = calibratorhistomap.begin(); iter != calibratorhistomap.end(); ++iter) + { + filename.str(""); + filename << fileprefix << "Run_" + << RunNumber() + << "_" << iter->first << ".root"; + TFile *hfile = new TFile(filename.str().c_str(), "RECREATE", + "Created by Online Calibrator", compress); + std::cout << "Fun4CalServer::dumpHistos() Output root file: " << filename.str() << std::endl; + for (siter = (iter->second).begin(); siter != (iter->second).end(); ++siter) + { + histo = dynamic_cast(getHisto(*siter)); + if (histo) + { + histo->Write(); + } + else + { + std::cout << PHWHERE << "Histogram " + << *siter << " not found, will not be saved in " + << filename.str() << std::endl; + } + } + hfile->Close(); + + delete hfile; + } + return; +} + +void Fun4CalServer::registerHisto(TH1 *h1d, CalReco *Calibrator, const int replace) +{ + if (Calibrator) + { + std::string calibratorname = Calibrator->Name(); + std::map >::iterator iter; + iter = calibratorhistomap.find(calibratorname); + if (iter != calibratorhistomap.end()) + { + (iter->second).insert(h1d->GetName()); + } + else + { + std::set newset; + newset.insert(h1d->GetName()); + newset.insert("Fun4CalServerVars"); + calibratorhistomap[calibratorname] = newset; + } + } + Fun4AllServer::registerHisto(h1d, replace); + return; +} + +void Fun4CalServer::unregisterHisto(const std::string &calibratorname) +{ + calibratorhistomap.erase(calibratorname); + return; +} + +int Fun4CalServer::process_event() +{ + Fun4AllServer::process_event(); + int i = 0; + nEvents++; + if ((nEvents % eventcheckfrequency) == 0) // check every 1000 events + { + std::cout << nEvents << " events, testing" << std::endl; + unsigned int j = 0; + unsigned int ical = 0; + std::vector >::const_iterator iter; + for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) + { + CalReco *oncal = dynamic_cast(iter->first); + if (oncal) + { + ical++; + std::cout << "Name: " << oncal->Name() + << " is " << oncal->AllDone() << std::endl; + j += oncal->AllDone(); + } + } + if (j == ical) + { + std::cout << "Everyone is done after " + << nEvents << " Events" << std::endl; + i = 1; + } + } + return i; +} + +int Fun4CalServer::BeginRun(const int runno) +{ + if (runno <= 0) + { + std::cout << PHWHERE << "Invalid Run Number: " << runno << std::endl; + exit(1); + } + FillRunListFromFileList(); + recoConsts *rc = recoConsts::instance(); + // we stick to the first runnumber, but after inheriting from + // Fun4All we get a EndRun/BeginRun when the run number changes + // so we have to catch this here + if (RunNumber() != 0) + { + rc->set_IntFlag("RUNNUMBER", RunNumber()); // set rc flag back to previous run + analysed_runs.push_back(runno); + return 0; + } + RunNumber(runno); + std::vector >::iterator iter; + // copy the subsys reco pointers to another set for + // easier search (we only need the pointers to find + // the subsystems with special timestamp/runnumber needs + std::set NeedOtherTimeStamp; + std::map >::const_iterator miter; + std::set::const_iterator siter; + for (miter = requiredCalibrators.begin(); + miter != requiredCalibrators.end(); ++miter) + { + for (siter = miter->second.begin(); siter != miter->second.end(); ++siter) + { + NeedOtherTimeStamp.insert(*siter); + } + } + + int iret; + int i = 0; + int oncalrun = runno; + int fun4allrun = runno; + + RunToTime *runTime = RunToTime::instance(); + PHTimeStamp *ts = runTime->getBeginTime(fun4allrun); + PHTimeStamp OnCalBORTimeStamp = *ts; + PHTimeStamp Fun4AllBORTimeStamp(OnCalBORTimeStamp); + delete ts; + if (!requiredCalibrators.empty()) + { + fun4allrun = FindClosestCalibratedRun(runno); + ts = runTime->getBeginTime(fun4allrun); + Fun4AllBORTimeStamp = *ts; + delete ts; + } + + // we have to do the same TDirectory games as in the Init methods + // save the current dir, cd to the subsystem name dir (which was + // created in init) call the InitRun of the module and cd back + + gROOT->cd(default_Tdirectory.c_str()); + std::string currdir = gDirectory->GetPath(); + std::set droplist; + for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) + { + std::ostringstream newdirname; + newdirname << (*iter).second->getName() << "/" << (*iter).first->Name(); + if (!gROOT->cd(newdirname.str().c_str())) + { + std::cout << PHWHERE << "Unexpected TDirectory Problem cd'ing to " + << (*iter).second->getName() + << " - send e-mail to off-l with your macro" << std::endl; + exit(1); + } + CalReco *oncal = dynamic_cast((*iter).first); + if (oncal) + { + std::string table = "CalReco"; + table += (*iter).first->Name(); + check_create_subsystable(table); + insertRunNumInDB(table, runNum); + std::string calibname = (*iter).first->Name(); + add_calibrator_to_statustable(calibname); + std::set::const_iterator runiter; + int calibstatus = GetCalibStatus(calibname, runNum); + if (calibstatus > 0 && testmode == 0) + { + std::cout << calibname << " already ran for run " << runNum << std::endl; + droplist.insert(calibname); + unregisterSubsystem(oncal); + unregisterHisto(calibname); + } + else + { + std::ostringstream stringarg; + stringarg << Fun4CalDBCodes::STARTED; + for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) + { + updateDB(successTable, calibname, stringarg.str(), *runiter); + } + } + } + if (NeedOtherTimeStamp.contains((*iter).first)) + { + std::cout << "changing timestamp for " << (*iter).first->Name() << std::endl; + rc->set_IntFlag("RUNNUMBER", fun4allrun); + // rc->set_TimeStamp(Fun4AllBORTimeStamp); + } + else + { + rc->set_IntFlag("RUNNUMBER", oncalrun); + // rc->set_TimeStamp(CalRecoBORTimeStamp); + } + if (!droplist.contains((*iter).first->Name())) + { + iret = (*iter).first->InitRun(TopNode); + if (iret == Fun4AllReturnCodes::ABORTRUN) + { + std::cout << PHWHERE << "Module " << (*iter).first->Name() << " issued Abort Run, exiting" << std::endl; + exit(-1); + } + i += iret; + } + } + gROOT->cd(currdir.c_str()); + + rc->set_IntFlag("RUNNUMBER", oncalrun); + // rc->set_TimeStamp(CalRecoBORTimeStamp); + if (Fun4CalServerVars->GetBinContent(Fun4CalHistoBinDefs::FIRSTRUNBIN) == 0) + { + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::FIRSTRUNBIN, runno); + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::BORTIMEBIN, (Stat_t) OnCalBORTimeStamp.getTics()); + } + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::LASTRUNBIN, (Stat_t) runno); + ts = runTime->getEndTime(runno); + if (ts) + { + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::EORTIMEBIN, (Stat_t) ts->getTics()); + delete ts; + } + + // disconnect from DB to save resources on DB machine + // PdbCal leaves the DB connection open (PdbCal will reconnect without + // problem if neccessary) + DisconnectDB(); + // finally drop calibrators which have run already from module list + unregisterSubsystemsNow(); + return i; +} + +int Fun4CalServer::End() +{ + if (nEvents == 0) + { + std::cout << "No Events read, you probably gave me an empty filelist" << std::endl; + return -1; + } + int i = 0; + std::vector >::iterator iter; + gROOT->cd(default_Tdirectory.c_str()); + std::string currdir = gDirectory->GetPath(); + + for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) + { + std::ostringstream newdirname; + newdirname << (*iter).second->getName() << "/" << (*iter).first->Name(); + if (!gROOT->cd(newdirname.str().c_str())) + { + std::cout << PHWHERE << "Unexpected TDirectory Problem cd'ing to " + << (*iter).second->getName() + << " - send e-mail to off-l with your macro" << std::endl; + exit(1); + } + else + { + if (Verbosity() > 2) + { + std::cout << "End: cded to " << newdirname.str().c_str() << std::endl; + } + } + i += (*iter).first->End((*iter).second); + } + + gROOT->cd(default_Tdirectory.c_str()); + currdir = gDirectory->GetPath(); + for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) + { + CalReco *oncal = dynamic_cast((*iter).first); + if (!oncal) + { + continue; + } + std::ostringstream newdirname; + newdirname << (*iter).second->getName() << "/" << (*iter).first->Name(); + if (!gROOT->cd(newdirname.str().c_str())) + { + std::cout << PHWHERE << "Unexpected TDirectory Problem cd'ing to " + << (*iter).second->getName() + << " - send e-mail to off-l with your macro" << std::endl; + exit(1); + } + + std::string CalibratorName = oncal->Name(); + + int verificationstatus = oncal->VerificationOK(); + int databasecommitstatus = oncal->CommitedToPdbCalOK(); + + // report success database the status of the calibration + if (recordDB) + { + std::string table = "CalReco"; + table += CalibratorName; + + std::ostringstream stringarg; + if (databasecommitstatus == Fun4CalDBCodes::SUCCESS) + { + stringarg << Fun4CalDBCodes::COVERED; + } + else + { + stringarg << Fun4CalDBCodes::FAILED; + } + std::set::const_iterator runiter; + for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) + { + updateDB(successTable, CalibratorName, stringarg.str(), *runiter); + } + // update the first run which was used in the calibration + // with the real status + updateDB(successTable, CalibratorName, databasecommitstatus); + + stringarg.str(""); + stringarg << databasecommitstatus; + updateDB(table, "committed", stringarg.str(), RunNumber()); + + stringarg.str(""); + stringarg << verificationstatus; + updateDB(table, "verified", stringarg.str(), RunNumber()); + + odbc::Timestamp stp(time(nullptr)); + updateDB(table, "date", stp.toString(), RunNumber()); + updateDB(table, "comment", oncal->Comment(), RunNumber()); + time_t beginticks = beginTimeStamp.getTics(); + stringarg.str(""); + stringarg << beginticks; + updateDB(table, "startvaltime", stringarg.str(), RunNumber()); + stp.setTime(beginticks); + updateDB(table, "begintime", stp.toString(), RunNumber()); + time_t endticks = endTimeStamp.getTics(); + stringarg.str(""); + stringarg << endticks; + updateDB(table, "endvaltime", stringarg.str(), RunNumber()); + stp.setTime(endticks); + updateDB(table, "endtime", stp.toString(), RunNumber()); + + std::string filelist; + for (Fun4AllSyncManager *sync : SyncManagers) + { + for (Fun4AllInputManager *inmgr : sync->GetInputManagers()) + { + for (const std::string &infile : inmgr->GetFileOpenedList()) + { + filelist += (infile).substr(((infile).find_last_of('/') + 1), (infile).size()); + filelist += " "; // this needs to be stripped again for last entry + } + } + } + filelist.pop_back(); // strip empty space at end from loop + std::cout << "FileList: " << filelist << std::endl; + updateDB(table, "files", filelist, RunNumber()); + updateDB(table, "cvstag", cvstag, RunNumber()); + } + + std::cout << "SERVER SUMMARY: " << oncal->Name() << " " + << (verificationstatus == 1 ? "Verification: SUCCESS " : "Verification: FAILURE ") + << (databasecommitstatus == 1 ? "DB commit: SUCCESS " : "DB commit: FAILURE ") + << std::endl; + + printStamps(); + } + gROOT->cd(currdir.c_str()); + dumpHistos(); // save the histograms in files + return i; +} +//--------------------------------------------------------------------- + +void Fun4CalServer::Print(const std::string &what) const +{ + Fun4AllServer::Print(what); + if (what == "ALL" || what == "CALIBRATOR") + { + // loop over the map and print out the content + // (name and location in memory) + + std::cout << "--------------------------------------" << std::endl + << std::endl; + std::cout << "List of Calibrators in Fun4CalServer:" << std::endl; + + std::vector >::const_iterator miter; + for (miter = Subsystems.begin(); + miter != Subsystems.end(); ++miter) + { + CalReco *oncal = dynamic_cast((*miter).first); + if (oncal) + { + std::cout << oncal->Name() << std::endl; + } + } + std::cout << std::endl; + } + if (what == "ALL" || what == "REQUIRED") + { + // loop over the map and print out the content + // (name and location in memory) + + std::cout << "--------------------------------------" << std::endl + << std::endl; + std::cout << "List of required Calibrations in Fun4CalServer:" << std::endl; + + std::map >::const_iterator iter; + std::set::const_iterator siter; + for (iter = requiredCalibrators.begin(); + iter != requiredCalibrators.end(); ++iter) + { + std::cout << iter->first << " calibrations are needed by " << std::endl; + for (siter = iter->second.begin(); siter != iter->second.end(); ++siter) + { + std::cout << (*siter)->Name() << std::endl; + } + } + std::cout << std::endl; + } + if (what == "ALL" || what == "FILES") + { + std::cout << "--------------------------------------" << std::endl + << std::endl; + std::cout << "List of PRDF Files in Fun4CalServer:" << std::endl; + for (Fun4AllSyncManager *sync : SyncManagers) + { + for (Fun4AllInputManager *inmgr : sync->GetInputManagers()) + { + for (const std::string &infile : inmgr->GetFileList()) + { + std::cout << "File: " << infile << std::endl; + } + } + } + } + if (what == "ALL" || what == "RUNS") + { + std::cout << "--------------------------------------" << std::endl + << std::endl; + std::cout << "List of Run Numbers in Fun4CalServer:" << std::endl; + std::set::const_iterator liter; + for (liter = runlist.begin(); liter != runlist.end(); ++liter) + { + std::cout << "Run : " << *liter << std::endl; + } + } + + return; +} + +void Fun4CalServer::printStamps() +{ + std::cout << std::endl + << std::endl; + std::cout << "*******************************************" << std::endl; + std::cout << "* VALIDITY RANGE FOR THIS CALIBRATION *" << std::endl; + std::cout << "* *" << std::endl; + std::cout << "* Used Run : "; + std::cout << runNum << std::endl; + std::cout << std::endl; + std::cout << "* Begin Valid : "; + beginTimeStamp.print(); + std::cout << std::endl; + std::cout << "* End Valid : "; + endTimeStamp.print(); + std::cout << std::endl; + std::cout << "* *" << std::endl; + std::cout << "*******************************************" << std::endl; + std::cout << std::endl + << std::endl + << std::endl; +} + +//--------------------------------------------------------------------- + +void Fun4CalServer::RunNumber(const int runnum) +{ + runNum = runnum; + SetBorTime(runnum); + if (recordDB) + { + std::set::const_iterator runiter; + time_t beginrunticks; + time_t endrunticks; + std::ostringstream stringarg; + odbc::Timestamp stp; + for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) + { + insertRunNumInDB(successTable, *runiter); + GetRunTimeTicks(*runiter, beginrunticks, endrunticks); + stringarg.str(""); + stringarg << beginrunticks; + updateDB(successTable, "startvaltime", stringarg.str(), *runiter); + stp.setTime(beginrunticks); + updateDB(successTable, "beginrun", stp.toString(), *runiter); + stringarg.str(""); + stringarg << endrunticks; + updateDB(successTable, "endvaltime", stringarg.str(), *runiter); + stp.setTime(endrunticks); + updateDB(successTable, "endrun", stp.toString(), *runiter); + } + } + if (!runlist.empty()) + { + SetEorTime(*runlist.rbegin()); + } + return; +} + +//--------------------------------------------------------------------- + +bool Fun4CalServer::connectDB() +{ + if (DBconnection) + { + return true; + } + + bool failure = true; + int countdown = 10; + while (failure && countdown > 0) + { + failure = false; + try + { + DBconnection = + odbc::DriverManager::getConnection(database, "phnxrc", ""); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << e.getMessage() << std::endl; + std::cout << "countdown: " << countdown << std::endl; + countdown--; + failure = true; + sleep(100); // try again in 100 secs + } + } + if (failure) + { + std::cout << "could not connect to DB after 10 tries in 1000 secs, giving up" << std::endl; + exit(-1); + } + std::cout << "connected to " << database.c_str() << " database." << std::endl; + return true; +} +//--------------------------------------------------------------------- + +int Fun4CalServer::DisconnectDB() +{ + delete DBconnection; + DBconnection = nullptr; + return 0; +} +//--------------------------------------------------------------------- + +bool Fun4CalServer::insertRunNumInDB(const std::string &DBtable, const int runno) +{ + if (findRunNumInDB(DBtable, runno)) + { + return true; + } + + std::cout << "new row will be created in DB for run " << runno << std::endl; + + odbc::Statement *statement = nullptr; + statement = DBconnection->createStatement(); + std::ostringstream cmd; + cmd << "INSERT INTO " + << DBtable + << " (runnumber) VALUES (" + << runno << ")"; + + if (Verbosity() == 1) + { + std::cout << "in function Fun4CalServer::insertRunNumInDB() ... "; + std::cout << "executing SQL statements ..." << std::endl; + std::cout << cmd.str() << std::endl; + } + + try + { + statement->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << e.getMessage() << std::endl; + return false; + } + + return true; +} + +//--------------------------------------------------------------------- + +bool Fun4CalServer::findRunNumInDB(const std::string &DBtable, const int runno) +{ + if (!DBconnection) + { + connectDB(); + } + odbc::Statement *statement = nullptr; + odbc::ResultSet *rs = nullptr; + std::ostringstream cmd; + cmd << "SELECT runnumber FROM " + << DBtable + << " WHERE runnumber = " + << runno; + + statement = DBconnection->createStatement(); + + if (Verbosity() == 1) + { + std::cout << "in function Fun4CalServer::findRunNumInDB() "; + std::cout << "executing SQL statement ..." << std::endl + << cmd.str() << std::endl; + } + + try + { + rs = statement->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << PHWHERE << " exception caught: " << e.getMessage() << std::endl; + return false; + } + + int entry = 0; + if (rs->next()) + { + try + { + entry = rs->getInt("runnumber"); + } + catch (odbc::SQLException &e) + { + std::cout << PHWHERE << " exception caught: " << e.getMessage() << std::endl; + return false; + } + } + else + { + return false; + } + std::cout << "run number " << entry << " already exists in DB" << std::endl; + return true; +} + +bool Fun4CalServer::updateDBRunRange(const std::string &table, const std::string &column, const int entry, const int firstrun, const int lastrun) +{ + if (!DBconnection) + { + connectDB(); + } + + odbc::Statement *statement = nullptr; + + std::string command = "UPDATE "; + command += table; + command += " SET "; + command += column; + command += " = "; + command += std::to_string(entry); + command += " WHERE runnumber >= "; + command += std::to_string(firstrun); + command += " and runnumber <= "; + command += std::to_string(lastrun); + + if (Verbosity() == 1) + { + std::cout << "in function Fun4CalServer::updateDB() ... "; + std::cout << "executin SQL statement ... " << std::endl; + std::cout << command << std::endl; + } + statement = DBconnection->createStatement(); + + try + { + statement->executeUpdate(command); + } + catch (odbc::SQLException &e) + { + std::cout << e.getMessage() << std::endl; + return false; + } + + return true; +} + +//--------------------------------------------------------------------- + +bool Fun4CalServer::updateDB(const std::string &table, const std::string &column, int entry) +{ + if (!DBconnection) + { + connectDB(); + } + + odbc::Statement *statement = nullptr; + + TString command = "UPDATE "; + command += table; + command += " SET "; + command += column; + command += " = "; + command += entry; + command += " WHERE runnumber = "; + command += runNum; + + if (Verbosity() == 1) + { + std::cout << "in function Fun4CalServer::updateDB() ... "; + std::cout << "executin SQL statement ... " << std::endl; + std::cout << command.Data() << std::endl; + } + statement = DBconnection->createStatement(); + + try + { + statement->executeUpdate(command.Data()); + } + catch (odbc::SQLException &e) + { + std::cout << e.getMessage() << std::endl; + return false; + } + + return true; +} +//--------------------------------------------------------------------- + +bool Fun4CalServer::updateDB(const std::string &table, const std::string &column, bool entry) +{ + if (!DBconnection) + { + connectDB(); + } + odbc::Statement *statement = nullptr; + + TString command = "UPDATE "; + command += table; + command += " set "; + command += column; + command += " = '"; + command += static_cast(entry); + command += "' WHERE runnumber = "; + command += runNum; + + if (Verbosity() == 1) + { + std::cout << "in function Fun4CalServer::updateDB() ... "; + std::cout << "executin SQL statement ... " << std::endl; + std::cout << command.Data() << std::endl; + } + statement = DBconnection->createStatement(); + + try + { + statement->executeUpdate(command.Data()); + } + catch (odbc::SQLException &e) + { + std::cout << e.getMessage() << std::endl; + return false; + } + + return true; +} + +//--------------------------------------------------------------------- + +int Fun4CalServer::updateDB(const std::string &table, const std::string &column, + const time_t ticks) +{ + if (!DBconnection) + { + connectDB(); + } + odbc::Statement *statement = nullptr; + + std::ostringstream cmd; + statement = DBconnection->createStatement(); + cmd << "UPDATE " + << table + << " set " + << column + << " = " + << ticks + << " WHERE runnumber = " + << runNum; + + if (Verbosity() == 1) + { + std::cout << "in function Fun4CalServer::updateDB() ... "; + std::cout << "executin SQL statement ... " << std::endl; + std::cout << cmd.str() << std::endl; + } + + try + { + statement->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << e.getMessage() << std::endl; + return -1; + } + return 0; +} +//--------------------------------------------------------------------- + +bool Fun4CalServer::updateDB(const std::string &table, const std::string &column, + const std::string &entry, const int runno, const bool append) +{ + if (!DBconnection) + { + connectDB(); + } + + odbc::Statement *statement = nullptr; + + statement = DBconnection->createStatement(); + + std::string comment; + std::ostringstream cmd; + if (append) + { + odbc::ResultSet *rs = nullptr; + std::ostringstream query; + query << "SELECT * FROM " + << table + << " WHERE runnumber = " + << runno; + + try + { + rs = statement->executeQuery(query.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "in function Fun4CalServer::updateDB() ... "; + std::cout << "run number " << runno << "not found in DB" << std::endl; + std::cout << e.getMessage() << std::endl; + } + + rs->next(); + try + { + comment = rs->getString(column); + comment += " "; // add empty space between comments + } + catch (odbc::SQLException &e) + { + std::cout << "in function Fun4CalServer::updateDB() ... " << std::endl; + std::cout << "nothing to append." << std::endl; + std::cout << e.getMessage() << std::endl; + } + delete rs; + } + + comment += entry; + cmd << "UPDATE " + << table + << " set " + << column + << " = '" + << comment + << "' WHERE runnumber = " + << runno; + + if (Verbosity() == 1) + { + std::cout << "in function Fun4CalServer::updateDB() ... "; + std::cout << "executin SQL statement ... " << std::endl; + std::cout << cmd.str() << std::endl; + } + + try + { + statement->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << e.getMessage() << std::endl; + return false; + } + delete statement; + return true; +} + +//--------------------------------------------------------------------- + +int Fun4CalServer::check_create_subsystable(const std::string &tablename) +{ + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + std::vector > calibrator_columns; + std::vector >::const_iterator coliter; + calibrator_columns.emplace_back("runnumber", "int NOT NULL"); + calibrator_columns.emplace_back("verified", "int default -2"); + calibrator_columns.emplace_back("committed", "int default -2"); + calibrator_columns.emplace_back("date", "timestamp(0) with time zone"); + calibrator_columns.emplace_back("comment", "text"); + calibrator_columns.emplace_back("files", "text"); + calibrator_columns.emplace_back("cvstag", "text"); + calibrator_columns.emplace_back("startvaltime", "bigint"); + calibrator_columns.emplace_back("endvaltime", "bigint"); + calibrator_columns.emplace_back("begintime", "timestamp(0) with time zone"); + calibrator_columns.emplace_back("endtime", "timestamp(0) with time zone"); + + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + cmd << "SELECT * FROM " << tablename << " LIMIT 1" << std::ends; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << tablename << " does not exist, will create it" << std::endl; + // std::cout << "Message: " << e.getMessage() << std::endl; + } + if (!rs) + { + cmd.str(""); + cmd << "CREATE TABLE " + << tablename + << "("; + for (coliter = calibrator_columns.begin(); coliter != calibrator_columns.end(); ++coliter) + { + cmd << (*coliter).first << " " << (*coliter).second << ", "; + } + + cmd << "primary key(runnumber))"; + stmt->executeUpdate(cmd.str()); + } + else // check if the all columns exist + { + for (coliter = calibrator_columns.begin(); coliter != calibrator_columns.end(); ++coliter) + { + try + { + rs->findColumn((*coliter).first); + } + catch (odbc::SQLException &e) + { + const std::string &exceptionmessage = e.getMessage(); + if (exceptionmessage.find("not found in result set") != std::string::npos) + { + std::cout << "Column " << (*coliter).first << " does not exist in " + << tablename << ", creating it" << std::endl; + cmd.str(""); + cmd << "ALTER TABLE " + << tablename + << " ADD " + << (*coliter).first + << " " + << (*coliter).second; + try + { + odbc::Statement *stmtup = DBconnection->createStatement(); + stmtup->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e1) + { + std::cout << PHWHERE << " Exception caught: " << e1.getMessage() << std::endl; + } + } + } + } + delete rs; + } + return 0; +} + +int Fun4CalServer::add_calibrator_to_statustable(const std::string &calibratorname) +{ + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + if (check_calibrator_in_statustable(calibratorname) == 0) + { + return 0; + } + const std::string &calibname = calibratorname; + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + cmd.str(""); + cmd << "ALTER TABLE " << successTable << " ADD COLUMN " + << calibname << " int"; + try + { + stmt->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Message: " << e.getMessage() << std::endl; + std::cout << "cmd: " << cmd.str() << std::endl; + exit(1); + } + cmd.str(""); + cmd << "ALTER TABLE " << successTable << " ALTER COLUMN " + << calibname << " SET DEFAULT " << Fun4CalDBCodes::INIT; + try + { + stmt->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Message: " << e.getMessage() << std::endl; + std::cout << "cmd: " << cmd.str() << std::endl; + exit(1); + } + cmd.str(""); + cmd << "UPDATE " << successTable << " SET " + << calibname << " = " << Fun4CalDBCodes::INIT; + try + { + stmt->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Message: " << e.getMessage() << std::endl; + std::cout << "cmd: " << cmd.str() << std::endl; + exit(1); + } + + return 0; +} + +int Fun4CalServer::check_calibrator_in_statustable(const std::string &calibratorname) +{ + // replace this contraption by this sql command which returns 1 row if column exists + // select * from information_schema.columns where table_name = 'oncal_status' and column_name = 'svxstripdeadmapcal'; + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + std::string calibname = calibratorname; + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + cmd << "SELECT * FROM " << successTable << " LIMIT 1" << std::ends; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Message: " << e.getMessage() << std::endl; + std::cout << "Table " << successTable << " does not exist, your logic is off" << std::endl; + exit(1); + } + odbc::ResultSetMetaData *meta = rs->getMetaData(); + unsigned int nocolumn = rs->getMetaData()->getColumnCount(); + // column names are lower case only, so convert string to lowercase + // The bizarre cast here is needed for newer gccs + transform(calibname.begin(), calibname.end(), calibname.begin(), (int (*)(int)) tolower); + + for (unsigned int i = 1; i <= nocolumn; i++) + { + if (meta->getColumnName(i) == calibname) + { + if (Verbosity() > 0) + { + std::cout << calibname << " is in " << successTable << std::endl; + } + return 0; + } + } + // if we get here, the calibrator is not yet in the table + delete rs; + return -1; +} + +int Fun4CalServer::check_create_successtable(const std::string &tablename) +{ + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + cmd << "SELECT runnumber FROM " << tablename << " LIMIT 1" << std::ends; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << tablename << " does not exist, will create it" << std::endl; + // std::cout << "Message: " << e.getMessage() << std::endl; + } + if (!rs) + { + cmd.str(""); + cmd << "CREATE TABLE " << tablename << "(runnumber int NOT NULL, " + << "startvaltime bigint, " + << "endvaltime bigint, " + << "beginrun timestamp(0) with time zone, " + << "endrun timestamp(0) with time zone, " + << "comment text, " + << "primary key(runnumber))"; + std::cout << cmd.str() << std::endl; + try + { + stmt->executeUpdate(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Error, Message: " << e.getMessage() << std::endl; + // std::cout << "Message: " << e.getMessage() << std::endl; + } + } + return 0; +} + +void Fun4CalServer::recordDataBase(const bool bookkeep) +{ + recordDB = bookkeep; + if (recordDB) + { + check_create_successtable(successTable); + } + return; +} + +void Fun4CalServer::BeginTimeStamp(const PHTimeStamp &TimeStp) +{ + beginTimeStamp = TimeStp; + std::cout << "Fun4CalServer::BeginTimeStamp: Setting BOR TimeStamp to " << beginTimeStamp << std::endl; +} + +void Fun4CalServer::EndTimeStamp(const PHTimeStamp &TimeStp) +{ + endTimeStamp = TimeStp; + std::cout << "Fun4CalServer::EndTimeStamp: Setting EOR TimeStamp to " << endTimeStamp << std::endl; +} + +PHTimeStamp * +Fun4CalServer::GetLastGoodRunTS(CalReco *calibrator, const int irun) +{ + PHTimeStamp *ts = nullptr; + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return ts; + } + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + std::ostringstream subsystable; + subsystable << "oncal" << calibrator->Name(); + cmd << "SELECT runnumber FROM " << successTable << " where runnumber < " + << irun << " and " + << calibrator->Name() << " > 0 order by runnumber desc limit 1"; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << subsystable.str() << " does not exist" << std::endl; + return ts; + } + if (rs->next()) + { + RunToTime *rt = RunToTime::instance(); + int oldrun = rs->getInt("runnumber"); + ts = rt->getBeginTime(oldrun); + std::cout << "Getting previous good run, current run: " << irun + << ", previous good run: " << oldrun + << " began "; + ts->print(); + std::cout << std::endl; + } + else + { + std::cout << PHWHERE << " No previous good run found for run " << irun << std::endl; + } + delete rs; + return ts; +} + +int Fun4CalServer::SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const int commit) +{ + std::vector caltab; + calibrator->GetPdbCalTables(caltab); + std::vector::const_iterator iter; + for (iter = caltab.begin(); iter != caltab.end(); ++iter) + { + std::cout << "dealing with table: " << *iter << std::endl; + SyncCalibTimeStampsToOnCal(calibrator, *iter, commit); + } + return 0; +} + +int Fun4CalServer::SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const std::string &table, const int commit) +{ + std::string name = calibrator->Name(); + odbc::Connection *con = nullptr; + odbc::Connection *concalib = nullptr; + std::ostringstream cmd; + try + { + con = odbc::DriverManager::getConnection(database, "phnxrc", ""); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + try + { + concalib = odbc::DriverManager::getConnection("oncal", "phnxrc", ""); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot connect to " + << "oncal" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + odbc::Statement *stmt = nullptr; + try + { + stmt = con->createStatement(); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot create statement" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + + odbc::PreparedStatement *stmt1 = nullptr; + odbc::ResultSet *rs1 = nullptr; + try + { + cmd.str(""); + cmd << "SELECT * from " << table << " where startvaltime = ?"; + stmt1 = concalib->prepareStatement(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot create statement" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + + odbc::PreparedStatement *stmtupd = nullptr; + try + { + cmd.str(""); + cmd << "update " << table << " set endvaltime = ? where startvaltime = ?"; + stmtupd = concalib->prepareStatement(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot create statement" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + + cmd.str(""); + cmd << "select * from " + << successTable + << " where " + << name + << " > 0"; + // << " > 0 and runnumber < 150000"; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Message: " << e.getMessage() << std::endl; + return -1; + } + while (rs->next()) + { + int run = rs->getInt("runnumber"); + int startticks = rs->getLong("startvaltime"); + int endticks = rs->getLong("endvaltime"); + // int status = rs->getInt(name); + // std::cout << "run: " << run + // << ", status: " << status + // << ", startticks: " << startticks + // << ", endticks: " << endticks << std::endl; + stmt1->setInt(1, startticks); + try + { + rs1 = stmt1->executeQuery(); + } + catch (odbc::SQLException &e) + { + std::cout << "Message: " << e.getMessage() << std::endl; + return -1; + } + int ionce = 0; + int isproblem = 0; + int calibendval = 0; + while (rs1->next()) + { + calibendval = rs1->getInt("endvaltime"); + if (endticks != rs1->getInt("endvaltime")) + { + if (!isproblem) + { + std::cout << "endvaltime problem with run " << run << std::endl; + std::cout << "endvaltime from oncal_status: " << endticks << std::endl; + std::cout << "startvaltime from oncal_status: " << startticks << std::endl; + std::cout << "endvaltime from calibrations DB: " << rs1->getInt("endvaltime") << std::endl; + if (endticks < rs1->getInt("endvaltime")) + { + std::cout << "ENDTICKS smaller CALIB" << std::endl; + // return -1; + } + } + isproblem = 1; + } + else + { + if (isproblem) + { + std::cout << "endvaltime changes, check run " << run << std::endl; + // return -1; + } + } + // std::cout << "starttime: " << rs1->getInt("startvaltime") << std::endl; + // std::cout << "endtime: " << rs1->getInt("endvaltime") << std::endl; + ionce++; + } + if (isproblem) + { + std::cout << "Adjusting run " << run << std::endl; + std::cout << "changing endvaltime from " << calibendval + << " to " << endticks << std::endl; + if (commit) + { + stmtupd->setInt(1, endticks); + stmtupd->setInt(2, startticks); + stmtupd->executeUpdate(); + } + } + if (!ionce) + { + std::cout << "Run " << run << " not found" << std::endl; + } + delete rs1; + } + delete rs; + delete con; + delete concalib; + return 0; +} + +int Fun4CalServer::SyncOncalTimeStampsToRunDB(const int commit) +{ + odbc::Connection *con = nullptr; + RunToTime *rt = RunToTime::instance(); + std::ostringstream cmd; + try + { + con = odbc::DriverManager::getConnection(database, "phnxrc", ""); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + odbc::Statement *stmt = nullptr; + try + { + stmt = con->createStatement(); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot create statement" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + + odbc::PreparedStatement *stmtupd = nullptr; + try + { + cmd.str(""); + cmd << "UPDATE oncal_status set endvaltime = ? where runnumber = ?"; + stmtupd = con->prepareStatement(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Cannot create statement" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + + cmd.str(""); + cmd << "select * from " + << successTable; //<< " where runnumber > 160000"; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Message: " << e.getMessage() << std::endl; + return -1; + } + while (rs->next()) + { + int run = rs->getInt("runnumber"); + int startticks = rs->getLong("startvaltime"); + int endticks = rs->getLong("endvaltime"); + int rtstartticks = 0; + int rtendticks = 0; + PHTimeStamp *rtstart = rt->getBeginTime(run); + PHTimeStamp *rtend = rt->getEndTime(run); + if (rtstart) + { + rtstartticks = rtstart->getTics(); + delete rtstart; + } + if (rtend) + { + rtendticks = rtend->getTics(); + delete rtend; + } + if (rtstartticks != startticks) + { + std::cout << "Run " << run + << ": Start mismatch, oncal: " << startticks + << ", rt: " << rtstartticks << std::endl; + } + if (rtendticks != endticks) + { + // exclude starttime=endtime in runtotime (some crashed calibrations can do this) + // in this case the calibration adds 1 sec to starttime + if (rtstartticks != rtendticks) + { + std::cout << "Run " << run + << ": End mismatch, oncal: " << endticks + << ", rt: " << rtendticks << std::endl; + if (endticks > rtendticks) + { + std::cout << "BAD: endticks: " << endticks + << ", rtendticks: " << rtendticks + << std::endl; + return -1; + } + if (commit) + { + stmtupd->setLong(1, rtendticks); + stmtupd->setLong(2, run); + stmtupd->executeUpdate(); + } + } + else + { + if (startticks != endticks - 1) + { + std::cout << "Run " << run + << ": Start/End mismatch, Start: " << startticks + << ", End: " << endticks << std::endl; + endticks = startticks + 1; + if (commit) + { + stmtupd->setLong(1, endticks); + stmtupd->setLong(2, run); + stmtupd->executeUpdate(); + } + } + else + { + if (Verbosity() > 0) + { + std::cout << "run " << run << " was twiddled by OnCal" << std::endl; + } + } + } + } + // std::cout << "run: " << run + // << ", status: " << status + // << ", startticks: " << startticks + // << ", endticks: " << endticks << std::endl; + } + delete rs; + delete con; + return 0; +} + +int Fun4CalServer::CopyTables(const CalReco *calibrator, const int FromRun, const int ToRun, const int commit) +{ + int iret = calibrator->CopyTables(FromRun, ToRun, commit); + return iret; +} + +int Fun4CalServer::CreateCalibration(CalReco *calibrator, const int myrunnumber, const std::string &what, const int commit) +{ + int iret = -1; + runNum = myrunnumber; + SetBorTime(myrunnumber); + SetEorTime(myrunnumber); + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + add_calibrator_to_statustable(calibrator->Name()); + std::string table = "OnCal"; + table += calibrator->Name(); + check_create_subsystable(table); + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + + cmd << "SELECT runnumber FROM " + << successTable << " where runnumber = " + << myrunnumber; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << successTable << " does not exist" << std::endl; + return -1; + } + if (!rs->next()) + { + insertRunNumInDB(successTable, myrunnumber); + } + delete rs; + cmd.str(""); + cmd << "SELECT runnumber FROM " + << successTable << " where runnumber = " + << myrunnumber << " and " + << calibrator->Name() << " <= 0"; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << PHWHERE << " Exception caught, Message: " + << e.getMessage() << std::endl; + return -1; + } + if (rs->next() || testmode) + { + std::string tablecomment = "Subsytem provided"; + iret = calibrator->CreateCalibration(runnumber, what, tablecomment, commit); + if (!iret) + { + std::cout << "Comment: " << tablecomment << std::endl; + std::cout << "updating oncal status tables for " << runnumber << std::endl; + if (commit) + { + CreateCalibrationUpdateStatus(calibrator, table, tablecomment, Fun4CalDBCodes::SUBSYSTEM); + } + } + else + { + std::cout << "Calibratior " << calibrator->Name() << " for run " << runnumber << " failed" << std::endl; + if (commit) + { + CreateCalibrationUpdateStatus(calibrator, table, tablecomment, Fun4CalDBCodes::FAILED); + } + } + } + else + { + std::cout << PHWHERE << " Run " << runnumber << " is already successfully calibrated for " + << calibrator->Name() << std::endl; + } + return iret; +} + +void Fun4CalServer::CreateCalibrationUpdateStatus(CalReco *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode) +{ + updateDB(successTable, calibrator->Name(), dbcode); + insertRunNumInDB(table, RunNumber()); + updateDB(table, "comment", tablecomment, RunNumber(), true); + std::ostringstream stringarg; + stringarg.str(""); + stringarg << calibrator->CommitedToPdbCalOK(); + updateDB(table, "committed", stringarg.str(), RunNumber()); + stringarg.str(""); + stringarg << calibrator->VerificationOK(); + updateDB(table, "verified", stringarg.str(), RunNumber()); + odbc::Timestamp stp(time(nullptr)); + updateDB(table, "date", stp.toString(), RunNumber()); + time_t beginticks = beginTimeStamp.getTics(); + stringarg.str(""); + stringarg << beginticks; + updateDB(table, "startvaltime", stringarg.str(), RunNumber()); + stp.setTime(beginticks); + updateDB(table, "begintime", stp.toString(), RunNumber()); + time_t endticks = endTimeStamp.getTics(); + stringarg.str(""); + stringarg << endticks; + updateDB(table, "endvaltime", stringarg.str(), RunNumber()); + stp.setTime(endticks); + updateDB(table, "endtime", stp.toString(), RunNumber()); + updateDB(table, "cvstag", cvstag, RunNumber()); + std::vector flist = calibrator->GetLocalFileList(); + if (!flist.empty()) + { + std::string filelist; + for (const std::string &infile : flist) + { + filelist += infile; + filelist += " "; + } + filelist.pop_back(); // strip empty space at end from loop + std::cout << "FileList: " << filelist << std::endl; + updateDB(table, "files", filelist, RunNumber()); + } + return; +} + +int Fun4CalServer::ClosestGoodRun(CalReco *calibrator, const int irun, const int previous) +{ + RunToTime *rt = RunToTime::instance(); + PHTimeStamp *ts = rt->getBeginTime(irun); + if (!ts) + { + std::cout << PHWHERE << "Unknown Run " << irun << std::endl; + return -1; + } + int curstart = ts->getTics(); + delete ts; + ts = rt->getEndTime(irun); + int curend = curstart; + if (ts) + { + curend = ts->getTics(); + delete ts; + } + int closestrun = -1; + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + + // look only for runs which were actually successfully calibrated (status = 1) + cmd << "SELECT runnumber,startvaltime,endvaltime FROM " + << successTable << " where runnumber < " + << irun << " and " + << calibrator->Name() << " = 1 order by runnumber desc limit 1"; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << successTable << " does not exist" << std::endl; + return -1; + } + int prevrun = -1; + unsigned int prevend = 0; + if (rs->next()) + { + prevrun = rs->getInt("runnumber"); + unsigned int prevstart = rs->getLong("startvaltime"); + prevend = rs->getLong("endvaltime"); + std::cout << "previous run: " << prevrun + << ", start: " << prevstart + << ", end: " << prevend + << std::endl; + } + else + { + if (Verbosity() > 0) + { + std::cout << PHWHERE << " No previous good run found for run " << irun << std::endl; + } + } + delete rs; + closestrun = prevrun; + if (previous == fetchrun::PREVIOUS) + { + if (Verbosity() > 0) + { + std::cout << "Closest previous run is " << closestrun << std::endl; + } + return closestrun; + } + cmd.str(""); + cmd << "SELECT runnumber,startvaltime,endvaltime FROM " + << successTable << " where runnumber > " + << irun << " and " + << calibrator->Name() << " = 1 order by runnumber asc limit 1"; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << successTable << " does not exist" << std::endl; + return -1; + } + int nextrun = -1; + unsigned int nextstart = 0; + if (rs->next()) + { + nextrun = rs->getInt("runnumber"); + nextstart = rs->getLong("startvaltime"); + unsigned int nextend = rs->getLong("endvaltime"); + if (Verbosity() > 0) + { + std::cout << "next run: " << nextrun + << ", start: " << nextstart + << ", end: " << nextend + << std::endl; + } + } + else + { + if (Verbosity() > 0) + { + std::cout << PHWHERE << " No next good run found for run " << irun << std::endl; + } + } + delete rs; + int tdiffprev = curstart - prevend; + int tdiffnext; + if (nextstart > 0) + { + tdiffnext = nextstart - curend; + } + else + { + // just make it larger then previous run time diff + tdiffnext = tdiffprev + 1; + } + if (Verbosity() > 0) + { + std::cout << "diff prev: " << tdiffprev + << ", next: " << tdiffnext + << std::endl; + } + if (tdiffprev < tdiffnext) + { + closestrun = prevrun; + } + else + { + closestrun = nextrun; + } + if (Verbosity() > 0) + { + std::cout << "closest run: " << closestrun << std::endl; + } + return closestrun; +} + +int Fun4CalServer::OverwriteCalibration(CalReco *calibrator, const int runno, const int commit, const int FromRun) +{ + if (FromRun < 0) + { + return -1; + } + int iret = CopyTables(calibrator, FromRun, runno, commit); + return iret; +} + +int Fun4CalServer::FixMissingCalibration(CalReco *calibrator, const int runno, const int commit, const int fromrun) +{ + int iret = -1; + // find this run in oncal_status + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + runNum = runno; + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + + cmd << "SELECT runnumber FROM " + << successTable << " where runnumber = " + << runno; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << successTable << " does not exist" << std::endl; + return -1; + } + if (!rs->next()) + { + insertRunNumInDB(successTable, runNum); + } + delete rs; + cmd.str(""); + cmd << "SELECT runnumber FROM " + << successTable << " where runnumber = " + << runno << " and " + << calibrator->Name() << " <= 0"; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << PHWHERE << " Exception caught, Message: " + << e.getMessage() << std::endl; + return -1; + } + if (rs->next()) + { + int FromRun; + if (fromrun > 0) + { + FromRun = fromrun; + } + else + { + FromRun = ClosestGoodRun(calibrator, runno); + if (FromRun < 0) + { + std::cout << "ClosestGoodRun returned bad runnumber: " << FromRun << std::endl; + return -1; + } + } + std::cout << "Going to copy calibration for run " << runno + << " from run " << FromRun << std::endl; + + iret = OverwriteCalibration(calibrator, runno, commit, FromRun); + if (!iret) + { + int newstatus = 0; + if (FromRun < runno) + { + newstatus = Fun4CalDBCodes::COPIEDPREVIOUS; + } + else + { + newstatus = Fun4CalDBCodes::COPIEDLATER; + } + std::string table = "OnCal"; + table += calibrator->Name(); + std::ostringstream comment; + comment << " CopiedRun(" << FromRun << ")"; + std::cout << "updating oncal status tables for " << runno << std::endl; + if (commit) + { + updateDB(successTable, calibrator->Name(), newstatus); + insertRunNumInDB(table, runNum); + updateDB(table, "comment", comment.str(), runNum, true); + updateDB(table, "committed", true); + } + } + } + else + { + std::cout << "Run " << runno + << " has a good calibrations, doing nothing" << std::endl; + } + delete rs; + return iret; +} + +int Fun4CalServer::SetBorTime(const int runno) +{ + // recoConsts *rc = recoConsts::instance(); + RunToTime *runTime = RunToTime::instance(); + + PHTimeStamp *BorTimeStp(runTime->getBeginTime(runno)); + if (!BorTimeStp) + { + std::cout << PHWHERE << "Cannot get begin time for run " << runno << std::endl; + std::cout << "Exiting" << std::endl; + exit(1); + } + BeginTimeStamp(*BorTimeStp); + + // enter begin run timestamp into rc flags + PHTimeStamp BeginRunTimeStamp(*BorTimeStp); + // rc->set_TimeStamp(BeginRunTimeStamp); + std::cout << "Fun4CalServer::SetBorTime from RunToTime was found for run : " << runno << " to "; + BeginRunTimeStamp.print(); + std::cout << std::endl; + + delete BorTimeStp; + return 0; +} + +int Fun4CalServer::SetEorTime(const int runno) +{ + // recoConsts *rc = recoConsts::instance(); + RunToTime *runTime = RunToTime::instance(); + + time_t eorticks = 0; + + time_t borticks = 0; //(rc->get_TimeStamp()).getTics(); + PHTimeStamp *EorTimeStp(runTime->getEndTime(runno)); + if (EorTimeStp) + { + eorticks = EorTimeStp->getTics(); + } + else + { + EorTimeStp = new PHTimeStamp(eorticks); + } + // if end of run timestamp missing or smaller-equal borstamp eor = bor+1 sec + if (eorticks <= borticks) + { + eorticks = borticks + 1; + EorTimeStp->setTics(eorticks); + } + EndTimeStamp(*EorTimeStp); + std::cout << "Fun4CalServer::SetEorTime: setting eor time to "; + EorTimeStp->print(); + std::cout << std::endl; + delete EorTimeStp; + return 0; +} + +int Fun4CalServer::GetRunTimeTicks(const int runno, time_t &borticks, time_t &eorticks) +{ + RunToTime *runTime = RunToTime::instance(); + PHTimeStamp *TimeStp(runTime->getBeginTime(runno)); + if (!TimeStp) + { + std::cout << PHWHERE << "Cannot get begin time for run " << runno << std::endl; + std::cout << "Exiting" << std::endl; + exit(1); + } + borticks = TimeStp->getTics(); + delete TimeStp; + TimeStp = runTime->getEndTime(runno); + if (TimeStp) + { + eorticks = TimeStp->getTics(); + delete TimeStp; + } + else + { + eorticks = 0; + } + // if end of run timestamp missing or smaller-equal borstamp eor = bor+1 sec + if (eorticks <= borticks) + { + eorticks = borticks + 1; + } + return 0; +} + +int Fun4CalServer::requiredCalibration(SubsysReco *reco, const std::string &calibratorname) +{ + std::map >::iterator iter; + if (check_calibrator_in_statustable(calibratorname)) + { + std::cout << PHWHERE << " the calibrator " << calibratorname << " is unknown to me" << std::endl; + return -1; + } + iter = requiredCalibrators.find(calibratorname); + if (iter != requiredCalibrators.end()) + { + iter->second.insert(reco); + } + else + { + std::set subsys; + subsys.insert(reco); + requiredCalibrators[calibratorname] = subsys; + } + return 0; +} + +int Fun4CalServer::FindClosestCalibratedRun(const int irun) +{ + RunToTime *rt = RunToTime::instance(); + PHTimeStamp *ts = rt->getBeginTime(irun); + if (!ts) + { + std::cout << PHWHERE << "Unknown Run " << irun << std::endl; + return -1; + } + if (requiredCalibrators.empty()) + { + std::cout << PHWHERE << "No required calibrations given" << std::endl; + return irun; + } + int curstart = ts->getTics(); + delete ts; + ts = rt->getEndTime(irun); + int curend = curstart; + if (ts) + { + curend = ts->getTics(); + delete ts; + } + int closestrun = -1; + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -1; + } + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + std::map >::const_iterator iter; + // look only for runs which were actually successfully calibrated (status = 1) + cmd << "SELECT runnumber,startvaltime,endvaltime FROM " + << successTable << " where runnumber <= " + << irun; + for (iter = requiredCalibrators.begin(); iter != requiredCalibrators.end(); ++iter) + { + cmd << " and " << iter->first << " > 0 "; + } + + cmd << " order by runnumber desc limit 1"; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << successTable << " does not exist" << std::endl; + return -1; + } + int prevrun = 0; + unsigned int prevend = 0; + if (rs->next()) + { + prevrun = rs->getInt("runnumber"); + unsigned int prevstart = rs->getLong("startvaltime"); + prevend = rs->getLong("endvaltime"); + if (prevrun != irun) + { + std::cout << "previous run: " << prevrun + << ", start: " << prevstart + << ", end: " << prevend + << std::endl; + } + } + else + { + std::cout << PHWHERE << " No previous good run found for run " << irun << std::endl; + } + delete rs; + // if the current run fullfills requirements return immediately + if (prevrun == irun) + { + std::cout << "closest run with required calibs is current run: " << irun << std::endl; + return irun; + } + cmd.str(""); + cmd << "SELECT runnumber,startvaltime,endvaltime FROM " + << successTable << " where runnumber > " + << irun; + for (iter = requiredCalibrators.begin(); iter != requiredCalibrators.end(); ++iter) + { + cmd << " and " << iter->first << " > 0 "; + } + + cmd << " order by runnumber asc limit 1"; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << successTable << " does not exist" << std::endl; + return -1; + } + int nextrun = 0; + unsigned int nextstart = 0; + if (rs->next()) + { + nextrun = rs->getInt("runnumber"); + nextstart = rs->getLong("startvaltime"); + unsigned int nextend = rs->getLong("endvaltime"); + std::cout << "next run: " << nextrun + << ", start: " << nextstart + << ", end: " << nextend + << std::endl; + } + else + { + std::cout << PHWHERE << " No next good run found for run " << irun << std::endl; + } + delete rs; + int tdiffprev = curstart - prevend; + int tdiffnext; + if (nextstart > 0) + { + tdiffnext = nextstart - curend; + } + else + { + // just make it larger then previous run time diff + tdiffnext = tdiffprev + 1; + } + if (tdiffprev < tdiffnext) + { + closestrun = prevrun; + } + else + { + closestrun = nextrun; + } + std::cout << "closest run with required calibs: " << closestrun << std::endl; + return closestrun; +} + +int Fun4CalServer::FillRunListFromFileList() +{ + for (Fun4AllSyncManager *sync : SyncManagers) + { + for (Fun4AllInputManager *inmgr : sync->GetInputManagers()) + { + for (const std::string &infile : inmgr->GetFileList()) + { + std::pair runseg = Fun4AllUtils::GetRunSegment(infile); + runlist.insert(runseg.first); + } + } + } + return 0; +} + +int Fun4CalServer::AdjustRichTimeStampForMultipleRuns() +{ + int firstrun = *runlist.begin(); + int lastrun = *runlist.rbegin(); + time_t dummy; + time_t beginticks; + time_t endticks; + std::string table = "OnCalRichCal"; + check_create_subsystable(table); + GetRunTimeTicks(firstrun, beginticks, dummy); + GetRunTimeTicks(lastrun, dummy, endticks); + std::ostringstream stringarg; + stringarg << Fun4CalDBCodes::COVERED; + // std::set::const_iterator runiter; + /* + for (runiter = runlist.begin(); runiter != runlist.end(); runiter++) + { + updateDB(successTable, "RichCal", stringarg.str(), *runiter); + } + stringarg.str(""); + stringarg << Fun4CalDBCodes::SUCCESS; + + updateDB(successTable, "RichCal", stringarg.str(), firstrun); + */ + odbc::Timestamp stp; + stringarg.str(""); + stringarg << beginticks; + updateDB(table, "startvaltime", stringarg.str(), firstrun); + stp.setTime(beginticks); + updateDB(table, "begintime", stp.toString(), firstrun); + stringarg.str(""); + stringarg << endticks; + updateDB(table, "endvaltime", stringarg.str(), firstrun); + stp.setTime(endticks); + updateDB(table, "endtime", stp.toString(), firstrun); + /* + std::string tablename = "calibrichadc"; + odbc::Connection *con = 0; + std::ostringstream cmd; + try + { + con = odbc::DriverManager::getConnection("oncal", "phnxrc", ""); + } + catch (odbc::SQLException& e) + { + std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + odbc::Statement *stmt = 0; + odbc::Statement *stmtup = 0; + try + { + stmt = con->createStatement(); + stmtup = con->createStatement(); + } + catch (odbc::SQLException& e) + { + std::cout << "Cannot create statement" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + + odbc::ResultSet *rs1 = 0; + cmd.str(""); + cmd << "SELECT endvaltime from " << tablename + << " where bankid = 1 and startvaltime = " << beginticks; + std::cout << "sql cmd: " << cmd.str() << std::endl; + try + { + rs1 = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException& e) + { + std::cout << "Cannot create statement" << std::endl; + std::cout << e.getMessage() << std::endl; + return -1; + } + if (rs1->next()) + { + std::cout << "Endcaltime: " << rs1->getInt("endvaltime") << std::endl; + std::cout << "future endvaltime: " << endticks << std::endl; + cmd.str(""); + cmd << "Update " << tablename + << " set endvaltime = " << endticks + << " where bankid = 1 and startvaltime = " + << beginticks; + stmtup->executeUpdate(cmd.str()); + + } + else + { + std::cout << "Could not find startvaltime " << beginticks + << "from run " << firstrun << std::endl; + } + + */ + + return 0; +} + +int Fun4CalServer::GetCalibStatus(const std::string &calibname, const int runno) +{ + int iret = -3; + if (!connectDB()) + { + std::cout << "could not connect to " << database << std::endl; + return -4; + } + odbc::Statement *stmt = DBconnection->createStatement(); + std::ostringstream cmd; + + // look only for runs which were actually successfully calibrated (status = 1) + cmd << "SELECT " << calibname << " FROM " + << successTable << " where runnumber = " + << runno; + std::cout << "exec " << cmd.str() << std::endl; + odbc::ResultSet *rs = nullptr; + try + { + rs = stmt->executeQuery(cmd.str()); + } + catch (odbc::SQLException &e) + { + std::cout << "Table " << successTable << " does not exist" << std::endl; + return -5; + } + if (rs->next()) + { + iret = rs->getInt(calibname); + } + else + { + std::cout << PHWHERE << " No calib status for " << calibname + << " for " << runno << std::endl; + } + delete rs; + return iret; +} + +void Fun4CalServer::TestMode(const int i) +{ + const char *logname = getenv("LOGNAME"); + if (logname) + { + if (strcmp(logname, "sphnxpro") == 0 || strcmp(logname, "anatrain") == 0) + { + std::cout << "phnxcal,anatrain account is not allowed to run in testmode" << std::endl; + } + else + { + testmode = i; + } + } + else + { + std::cout << "could not get account via env var LOGNAME, not setting testmode" << std::endl; + } + return; +} diff --git a/calibrations/framework/fun4cal/Fun4CalServer.h b/calibrations/framework/fun4cal/Fun4CalServer.h new file mode 100644 index 0000000000..47e0777ab8 --- /dev/null +++ b/calibrations/framework/fun4cal/Fun4CalServer.h @@ -0,0 +1,140 @@ +#ifndef FUN4CAL_FUN4CALSERVER_H +#define FUN4CAL_FUN4CALSERVER_H + +#include +#include + +#include // for time_t +#include +#include +#include +#include + +class CalReco; +class SubsysReco; +class TH1; + +namespace fetchrun +{ + enum + { + CLOSEST, + PREVIOUS + }; +}; + +class Fun4CalServer : public Fun4AllServer +{ + public: + static Fun4CalServer *instance(); + ~Fun4CalServer() override; + using Fun4AllServer::registerHisto; + void registerHisto(TH1 *h1d, CalReco *Calibrator, const int replace = 0); + void unregisterHisto(const std::string &calibratorname); + void Print(const std::string &what = "ALL") const override; + + void dumpHistos(); + int process_event() override; + int BeginRun(const int runno) override; + int EndRun(const int /*runno*/) override { return 0; } // do not execute EndRun + int End() override; + + PHTimeStamp *GetEndValidityTS(); + + PHTimeStamp *GetBeginValidityTS(); + void printStamps(); + PHTimeStamp *GetLastGoodRunTS(CalReco *calibrator, const int irun); + + void recordDataBase(const bool bookkeep = false); + + // RunNumber() tells the server which run is being analyzed. + // and if recordDB is true, this will insert the run number in + // calprocess_stat table in calBookKeep database. + // All updates are made to the row in the database containing this runNum. + // Note that the run number is the primary key in the tables. + // If calBookKeep database is not to be updated, this function + // should not be called. + void RunNumber(const int runnum); + int RunNumber() const { return runNum; } + + void BeginTimeStamp(const PHTimeStamp &TimeStp); + void EndTimeStamp(const PHTimeStamp &TimeStp); + + int SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const std::string &table, const int commit = 0); + int SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const int commit = 0); + int SyncOncalTimeStampsToRunDB(const int commit = 0); + int ClosestGoodRun(CalReco *calibrator, const int irun, const int previous = fetchrun::CLOSEST); + static int CopyTables(const CalReco *calibrator, const int FromRun, const int ToRun, const int commit = 0); + static int OverwriteCalibration(CalReco *calibrator, const int runno, const int commit = 0, const int fromrun = -1); + int FixMissingCalibration(CalReco *calibrator, const int runno, const int commit = 0, const int fromrun = -1); + + int SetBorTime(const int runno); + int SetEorTime(const int runno); + int requiredCalibration(SubsysReco *reco, const std::string &calibratorname); + int FindClosestCalibratedRun(const int irun); + int FillRunListFromFileList(); + int AdjustRichTimeStampForMultipleRuns(); + int CreateCalibration(CalReco *calibrator, const int myrunnumber, const std::string &what, const int commit = 0); + int GetCalibStatus(const std::string &calibname, const int runno); + static int DisconnectDB(); + void TestMode(const int i = 1); + // need to be able to call this from the outside + bool updateDBRunRange(const std::string &table, const std::string &column, const int entry, const int firstrun, const int lastrun); + void EventCheckFrequency(const unsigned int i) { eventcheckfrequency = i; } + + protected: + //------------------------------------- + // following functions access DB using odbc++ library + // these are designed to insert status in calBookKeep (or success) database. + // setDB() sets the name of the database to connect to. e.g., calibration + // this database should exist in the odbc.ini file. + // void setDB(const char* DBname){database = DBname;} + bool connectDB(); + + // insertRunNumInDB enters the run number in the calBookKeep database. + // All other updates are made to rows in the database containing the runNum. + // This function should be called before any updates are made. + // Returns true on successful DB insert. + bool insertRunNumInDB(const std::string &DBtable, const int runno); + + bool findRunNumInDB(const std::string &DBtable, const int runno); + + // these functions update different columns in the success database tables. + // Ony the row with the run number set by setRunNum() is updated. + + bool updateDB(const std::string &table, const std::string &column, int entry); + bool updateDB(const std::string &table, const std::string &column, bool entry); + bool updateDB(const std::string &table, const std::string &column, const std::string &entry, + const int runno, const bool append = false); + int updateDB(const std::string &table, const std::string &column, const time_t ticks); + + int check_create_subsystable(const std::string &tablename); + int check_create_successtable(const std::string &tablename); + int add_calibrator_to_statustable(const std::string &calibratorname); + int check_calibrator_in_statustable(const std::string &calibratorname); + static int GetRunTimeTicks(const int runno, time_t &borticks, time_t &eorticks); + void CreateCalibrationUpdateStatus(CalReco *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode); + Fun4CalServer(const std::string &name = "Fun4CalServer"); + PHTimeStamp beginTimeStamp; // begin run timestamp of run analysing + PHTimeStamp endTimeStamp; // end run timestamp of run analysing + int testmode{0}; + bool recordDB{false}; + TH1 *Fun4CalServerVars{nullptr}; + std::map Histo; + std::map > calibratorhistomap; + bool SetEndTimeStampByHand{false}; + bool SetBeginTimeStampByHand{false}; + + std::string successTable; + unsigned int runNum{0}; + unsigned int nEvents{0}; + unsigned int eventcheckfrequency{1000}; + std::string database{"calBookKeep"}; // this holds the name of the database + // should be set to calibrations for normal running + std::map > requiredCalibrators; + std::vector analysed_runs; + std::vector inputfilelist; + std::set runlist; +}; + +#endif /* __FUN4CALSERVER_H */ diff --git a/calibrations/framework/fun4cal/Makefile.am b/calibrations/framework/fun4cal/Makefile.am new file mode 100644 index 0000000000..02ad88ff18 --- /dev/null +++ b/calibrations/framework/fun4cal/Makefile.am @@ -0,0 +1,48 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(OPT_SPHENIX)/include \ + -isystem$(ROOTSYS)/include + +lib_LTLIBRARIES = \ + libfun4cal.la + +libfun4cal_la_LIBADD = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OPT_SPHENIX)/lib \ + -lfun4all \ + -lodbc++ \ + -lpdbcalBase \ + -lphool + +pkginclude_HEADERS = \ + Fun4CalDBCodes.h \ + Fun4CalHistoBinDefs.h \ + CalReco.h \ + Fun4CalServer.h + +libfun4cal_la_SOURCES = \ + CalReco.cc \ + Fun4CalServer.cc + +BUILT_SOURCES = \ + testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = \ + testexternals.cc + +testexternals_LDADD = \ + libfun4cal.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ diff --git a/calibrations/framework/fun4cal/autogen.sh b/calibrations/framework/fun4cal/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/framework/fun4cal/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/framework/fun4cal/configure.ac b/calibrations/framework/fun4cal/configure.ac new file mode 100644 index 0000000000..a665c5357c --- /dev/null +++ b/calibrations/framework/fun4cal/configure.ac @@ -0,0 +1,16 @@ +AC_INIT(fun4cal,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE + +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" +fi + +AC_OUTPUT(Makefile) From 3e39da384c10824fa0155d6e64f9a013190ea8ba Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Thu, 5 Feb 2026 15:23:40 -0500 Subject: [PATCH 184/866] Update logic to correct timing cut based on fit to oh fraction vs t distribution. Further commits to come. --- offline/packages/jetbackground/TimingCut.cc | 37 +++++++++++++++++---- offline/packages/jetbackground/TimingCut.h | 23 +++++++++++-- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index 69ab008124..81053863f6 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -18,10 +18,11 @@ #include // for pair #include // for vector //____________________________________________________________________________.. -TimingCut::TimingCut(const std::string &jetNodeName, const std::string &name, const bool doAbort) +TimingCut::TimingCut(const std::string &jetNodeName, const std::string &name, const bool doAbort, const std::string &ohTowerName) : SubsysReco(name) , _doAbort(doAbort) , _jetNodeName(jetNodeName) + , _ohTowerName(ohTowerName) , _cutParams(name) { SetDefaultParams(); @@ -57,11 +58,12 @@ int TimingCut::CreateNodeTree(PHCompositeNode *topNode) int TimingCut::process_event(PHCompositeNode *topNode) { JetContainer *jets = findNode::getClass(topNode, _jetNodeName); - if (!jets) + TowerInfoContainer* towersOH = findNode::getClas(topNode, _ohTowerName); + if (!jets || !towersOH) { if (Verbosity() > 0 && !_missingInfoWarningPrinted) { - std::cout << "Missing jets; abort event. Further warnings will be suppressed." << std::endl; + std::cout << "Missing jets or OHCal towers; abort event. Further warnings will be suppressed." << std::endl; } _missingInfoWarningPrinted = true; return Fun4AllReturnCodes::ABORTEVENT; @@ -69,6 +71,8 @@ int TimingCut::process_event(PHCompositeNode *topNode) float maxJetpT = 0; float subJetpT = 0; + float maxJetOHFrac = std::numeric_limits::quiet_NaN(); + float subJetOHFrac = std::numeric_limits::quiet_NaN(); float maxJett = std::numeric_limits::quiet_NaN(); float subJett = std::numeric_limits::quiet_NaN(); float maxJetPhi = std::numeric_limits::quiet_NaN(); @@ -86,12 +90,23 @@ int TimingCut::process_event(PHCompositeNode *topNode) float jetpT = 0; float jett = std::numeric_limits::quiet_NaN(); float jetPhi = std::numeric_limits::quiet_NaN(); + float jetOHFrac = 0; Jet *jet = jets->get_jet(i); if (jet) { jetpT = jet->get_pt(); jett = jet->get_property(Jet::PROPERTY::prop_t); jetPhi = jet->get_phi(); + for(auto comp: jet->get_comp_vec()) + { + if(comp.first == 7 || comp.first == 27) + { + unsigned int channel = comp.second; + TowerInfo* tower = towersOH->get_tower_at_channel(channel); + jetOHFrac += tower->get_energy(); + } + } + jetOHFrac /= jet->get_e(); } else { @@ -104,16 +119,19 @@ int TimingCut::process_event(PHCompositeNode *topNode) subJetpT = maxJetpT; subJett = maxJett; subJetPhi = maxJetPhi; + subJetOHFrac = maxJetOHFrac; } maxJetpT = jetpT; maxJett = jett; maxJetPhi = jetPhi; + maxJetOHFrac = jetOHFrac; } else if (jetpT > subJetpT) { subJetpT = jetpT; subJett = jett; subJetPhi = jetPhi; + subJetOHFrac = jetOHFrac; } } } @@ -126,8 +144,11 @@ int TimingCut::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - bool passDeltat = Pass_Delta_t(maxJett, subJett, maxJetPhi, subJetPhi); - bool passLeadt = Pass_Lead_t(maxJett); + float corrMaxJett = Correct_Time_Ohfrac(maxJett, maxJetOHFrac); + float corrSubJett = Correct_Time_Ohfrac(subJett, subJetOHFrac); + + bool passDeltat = Pass_Delta_t(corrMaxJett, corrSubJett, maxJetPhi, subJetPhi); + bool passLeadt = Pass_Lead_t(corrMaxJett); MbdOut * mbdout = static_cast(findNode::getClass(topNode,"MbdOut")); float m_mbd_t0 = std::numeric_limits::quiet_NaN(); @@ -157,7 +178,7 @@ int TimingCut::process_event(PHCompositeNode *topNode) bool passMbdt = false; if(!std::isnan(mbd_time)) { - passMbdt = Pass_Mbd_dt(maxJett, mbd_time); + passMbdt = Pass_Mbd_dt(corrMaxJett, mbd_time); } bool failAnyCut = !passDeltat || !passLeadt || !passMbdt; @@ -174,7 +195,11 @@ int TimingCut::process_event(PHCompositeNode *topNode) _cutParams.set_int_param("failAnyTimeCut", failAnyCut); _cutParams.set_double_param("maxJett",maxJett); _cutParams.set_double_param("subJett",subJett); + _cutParams.set_double_param("corrMaxJett",corrMaxJett); + _cutParams.set_double_param("corrSubJett",corrSubJett); _cutParams.set_double_param("mbd_time",mbd_time); + _cutParams.set_double_param("leadOhFrac",maxJetOHFrac); + _cutParams.set_double_param("subOhFrac",subJetOHFrac); _cutParams.set_double_param("dPhi",calc_dphi(maxJetPhi, subJetPhi)); _cutParams.UpdateNodeTree(parNode, "TimingCutParams"); diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index 2e426a82da..ad212d1146 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -7,6 +7,9 @@ #include + +#include +#include #include #include @@ -15,10 +18,16 @@ class PHCompositeNode; class TimingCut : public SubsysReco { public: - explicit TimingCut(const std::string &jetNodeName, const std::string &name = "TimingCutModule", bool doAbort = false); + explicit TimingCut(const std::string &jetNodeName, const std::string &name = "TimingCutModule", bool doAbort = false, const std::string &ohTowerName = "TOWERINFO_CALIB_HCALOUT"); ~TimingCut() override = default; + float Correct_Time_Ohfrac(float t, float ohfrac) + { + float corrt = t + _fitFunc->Eval(ohfrac); + return corrt; + } + float calc_dphi(float maxJetPhi, float subJetPhi) { float dPhi = std::abs(maxJetPhi - subJetPhi); @@ -76,23 +85,31 @@ class TimingCut : public SubsysReco _cutParams.set_int_param("passLeadtCut", 0); _cutParams.set_int_param("passDeltatCut", 0); _cutParams.set_int_param("passMbdDtCut", 0); - _cutParams.set_int_param("failAnyTimeCut",0); + _cutParams.set_int_param("failAnyTimeCut",1); _cutParams.set_double_param("maxJett",9999); _cutParams.set_double_param("subJett",9999); _cutParams.set_double_param("mbd_time",9999); _cutParams.set_double_param("dPhi",9999); + _cutParams.set_double_param("leadOhFrac",-1); + _cutParams.set_double_param("subOhFrac",-1); + _cutParams.set_double_param("corrMaxJett",9999); + _cutParams.set_double_param("corrSubJett",9999); + } private: bool _doAbort; bool _missingInfoWarningPrinted = false; std::string _jetNodeName; + std::string _ohTowerName; PHParameters _cutParams; float _t_width{6.0}; float _dt_width{3.0}; - float _t_shift{2.0}; + float _t_shift{0.0}; float _mbd_dt_width{3.0}; float _min_dphi{3*M_PI/4}; + TFile* _fitFile = nullptr; + TF1* _fitFunc = nullptr; }; #endif From e6b5ace497fbadcce284e31208a59c302fc23e40 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Thu, 5 Feb 2026 19:00:59 -0500 Subject: [PATCH 185/866] fixed cluster tbin and INTT hit gathering --- .../TrackingDiagnostics/TrkrNtuplizer.cc | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index abc91cbf52..eae111fe10 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -854,8 +854,9 @@ ::endl; //-------------------------------------------------- // printOutputInfo(topNode); - /* + ++_ievent; +/* if(m_rawzdc_hist.size()==50){ m_rawzdc_hist.pop(); m_rawmbd_hist.pop(); @@ -866,7 +867,7 @@ ::endl; m_rawmbdlast = m_rawmbd; m_rawmbdv10last = m_rawmbdv10; m_bcolast =m_bco; - */ +*/ return Fun4AllReturnCodes::EVENT_OK; } @@ -1539,7 +1540,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) fx_hit[n_hit::nhitphi] = atan2(glob.y(),glob.x()); } - if (layer_local >= _nlayers_maps && layer_local < _nlayers_intt) + if (layer_local >= _nlayers_maps && layer_local < _nlayers_maps + _nlayers_intt) { int row = InttDefs::getRow(hit_key); int col = InttDefs::getCol(hit_key); @@ -2233,10 +2234,20 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c fXcluster[n_cluster::ncludcal] = 1; } } + else if (layer_local < 3) + { + phibin = std::numeric_limits::quiet_NaN(); + tbin = MvtxDefs::getStrobeId(cluster_key); + } + else if (layer_local >= 3 && layer_local < 7) + { + phibin = std::numeric_limits::quiet_NaN(); + tbin = InttDefs::getTimeBucketId(cluster_key); + } else { - phibin = locx; - tbin = locy; + phibin = std::numeric_limits::quiet_NaN(); + tbin = std::numeric_limits::quiet_NaN(); } fXcluster[n_cluster::nclulocx] = locx; fXcluster[n_cluster::nclulocy] = locy; From 804a7fac2232fbb49fabf43a9f97edc23662e693 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Thu, 5 Feb 2026 23:05:40 -0500 Subject: [PATCH 186/866] KFParticle: added local dE/dx file option, removed condition on import of daughter BCOs --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 40 +++++++++++++++---- .../KFParticle_sPHENIX/KFParticle_Tools.h | 4 ++ .../KFParticle_sPHENIX/KFParticle_nTuple.cc | 5 ++- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 4 ++ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index b319af5b56..12f6614bc7 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1184,7 +1184,18 @@ float KFParticle_Tools::get_dEdx(PHCompositeNode *topNode, const KFParticle &dau void KFParticle_Tools::init_dEdx_fits() { - std::string dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); + std::string dedx_fitparams; + if (m_use_local_PID_file) + { + dedx_fitparams = m_local_PID_filename; + } + else + { + dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); + } + + std::cout << "opening " << dedx_fitparams << std::endl; + TFile *filefit = TFile::Open(dedx_fitparams.c_str()); if (!filefit->IsOpen()) @@ -1193,12 +1204,26 @@ void KFParticle_Tools::init_dEdx_fits() return; } - filefit->GetObject("f_piband", f_pion_plus); - filefit->GetObject("f_Kband", f_kaon_plus); - filefit->GetObject("f_pband", f_proton_plus); - filefit->GetObject("f_piminus_band", f_pion_minus); - filefit->GetObject("f_Kminus_band", f_kaon_minus); - filefit->GetObject("f_pbar_band", f_proton_minus); + if (m_use_local_PID_file) + { + std::cout << "using local" << std::endl; + // new method is independent of charge + filefit->GetObject("pi_band",f_pion_plus); + filefit->GetObject("K_band",f_kaon_plus); + filefit->GetObject("p_band",f_proton_plus); + filefit->GetObject("pi_band",f_pion_minus); + filefit->GetObject("K_band",f_kaon_minus); + filefit->GetObject("p_band",f_proton_minus); + } + else + { + filefit->GetObject("f_piband", f_pion_plus); + filefit->GetObject("f_Kband", f_kaon_plus); + filefit->GetObject("f_pband", f_proton_plus); + filefit->GetObject("f_piminus_band", f_pion_minus); + filefit->GetObject("f_Kminus_band", f_kaon_minus); + filefit->GetObject("f_pbar_band", f_proton_minus); + } pidMap.insert(std::pair(-11, f_pion_plus)); pidMap.insert(std::pair(211, f_pion_plus)); @@ -1212,6 +1237,7 @@ void KFParticle_Tools::init_dEdx_fits() double KFParticle_Tools::get_dEdx_fitValue(float momentum, int PID) { + std::cout << "eval of PID " << PID << " returns " << pidMap[PID]->Eval(momentum) << std::endl; return pidMap[PID]->Eval(momentum); } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 4e722a15db..feabd4aafc 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -27,6 +27,8 @@ #include #include +#include // included here so inline functions are defined on user end + #include #include @@ -149,6 +151,8 @@ class KFParticle_Tools : protected KFParticle_MVA std::vector m_intermediate_vertex_volume; bool m_use_PID{false}; + bool m_use_local_PID_file{false}; + std::string m_local_PID_filename = ""; float m_dEdx_band_width{0.2}; // Fraction of expected dE/dx TF1 *f_pion_plus{nullptr}; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index 1770870bb3..b4659e1b8d 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -672,7 +672,8 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, { gl1packet = findNode::getClass(topNode, "GL1Packet"); } - m_bco = m_trigger_info_available ? gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0] : 0; + m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; + //m_bco = m_trigger_info_available ? gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0] : 0; } else { @@ -741,4 +742,4 @@ bool KFParticle_nTuple::fillConditionMet() const // if requiring track-calo matching, the match result is returned return isTrackEMCalmatch; -} \ No newline at end of file +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 64fc3f37bb..d5905d443c 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -394,6 +394,10 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void selectMotherByMassError(bool select = true) { m_select_by_mass_error = select; } void usePID(bool use = true){ m_use_PID = use; } + + void useLocalPIDFile(bool use = true){ m_use_local_PID_file = use; } + + void setLocalPIDFilename(const std::string &filename){ m_local_PID_filename = filename; } void setPIDacceptFraction(float frac = 0.2){ m_dEdx_band_width = frac; } From c37ffe92cbd1700573b83a0814d743489bedb407 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Thu, 5 Feb 2026 23:12:47 -0500 Subject: [PATCH 187/866] reverse commit mixup --- .../TrackingDiagnostics/TrkrNtuplizer.cc | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index eae111fe10..abc91cbf52 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -854,9 +854,8 @@ ::endl; //-------------------------------------------------- // printOutputInfo(topNode); - + /* ++_ievent; -/* if(m_rawzdc_hist.size()==50){ m_rawzdc_hist.pop(); m_rawmbd_hist.pop(); @@ -867,7 +866,7 @@ ::endl; m_rawmbdlast = m_rawmbd; m_rawmbdv10last = m_rawmbdv10; m_bcolast =m_bco; -*/ + */ return Fun4AllReturnCodes::EVENT_OK; } @@ -1540,7 +1539,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) fx_hit[n_hit::nhitphi] = atan2(glob.y(),glob.x()); } - if (layer_local >= _nlayers_maps && layer_local < _nlayers_maps + _nlayers_intt) + if (layer_local >= _nlayers_maps && layer_local < _nlayers_intt) { int row = InttDefs::getRow(hit_key); int col = InttDefs::getCol(hit_key); @@ -2234,20 +2233,10 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c fXcluster[n_cluster::ncludcal] = 1; } } - else if (layer_local < 3) - { - phibin = std::numeric_limits::quiet_NaN(); - tbin = MvtxDefs::getStrobeId(cluster_key); - } - else if (layer_local >= 3 && layer_local < 7) - { - phibin = std::numeric_limits::quiet_NaN(); - tbin = InttDefs::getTimeBucketId(cluster_key); - } else { - phibin = std::numeric_limits::quiet_NaN(); - tbin = std::numeric_limits::quiet_NaN(); + phibin = locx; + tbin = locy; } fXcluster[n_cluster::nclulocx] = locx; fXcluster[n_cluster::nclulocy] = locy; From 96944238e5e4cb0feddcfce1627e00d20f1f6db8 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Thu, 5 Feb 2026 23:17:46 -0500 Subject: [PATCH 188/866] cleaned up debug logging --- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 12f6614bc7..7d48ed6b75 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1194,7 +1194,7 @@ void KFParticle_Tools::init_dEdx_fits() dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); } - std::cout << "opening " << dedx_fitparams << std::endl; + std::cout << PHWHERE << " opening " << dedx_fitparams << std::endl; TFile *filefit = TFile::Open(dedx_fitparams.c_str()); @@ -1206,7 +1206,7 @@ void KFParticle_Tools::init_dEdx_fits() if (m_use_local_PID_file) { - std::cout << "using local" << std::endl; + std::cout << PHWHERE << " using local file " << m_local_PID_filename << std::endl; // new method is independent of charge filefit->GetObject("pi_band",f_pion_plus); filefit->GetObject("K_band",f_kaon_plus); @@ -1237,7 +1237,6 @@ void KFParticle_Tools::init_dEdx_fits() double KFParticle_Tools::get_dEdx_fitValue(float momentum, int PID) { - std::cout << "eval of PID " << PID << " returns " << pidMap[PID]->Eval(momentum) << std::endl; return pidMap[PID]->Eval(momentum); } From de58c9b37797b28482b324d0d0518ffc63f990af Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 6 Feb 2026 10:15:07 -0500 Subject: [PATCH 189/866] add fun4cal --- calibrations/framework/oncal/Makefile.am | 48 - calibrations/framework/oncal/OnCal.cc | 48 - calibrations/framework/oncal/OnCal.h | 59 - calibrations/framework/oncal/OnCalDBCodes.h | 19 - .../framework/oncal/OnCalHistoBinDefs.h | 16 - calibrations/framework/oncal/OnCalServer.cc | 2439 ----------------- calibrations/framework/oncal/OnCalServer.h | 140 - calibrations/framework/oncal/autogen.sh | 8 - calibrations/framework/oncal/configure.ac | 16 - 9 files changed, 2793 deletions(-) delete mode 100644 calibrations/framework/oncal/Makefile.am delete mode 100644 calibrations/framework/oncal/OnCal.cc delete mode 100644 calibrations/framework/oncal/OnCal.h delete mode 100644 calibrations/framework/oncal/OnCalDBCodes.h delete mode 100644 calibrations/framework/oncal/OnCalHistoBinDefs.h delete mode 100644 calibrations/framework/oncal/OnCalServer.cc delete mode 100644 calibrations/framework/oncal/OnCalServer.h delete mode 100755 calibrations/framework/oncal/autogen.sh delete mode 100644 calibrations/framework/oncal/configure.ac diff --git a/calibrations/framework/oncal/Makefile.am b/calibrations/framework/oncal/Makefile.am deleted file mode 100644 index bb0b3674c1..0000000000 --- a/calibrations/framework/oncal/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -AUTOMAKE_OPTIONS = foreign - -AM_CPPFLAGS = \ - -I$(includedir) \ - -isystem$(OFFLINE_MAIN)/include \ - -isystem$(OPT_SPHENIX)/include \ - -isystem$(ROOTSYS)/include - -lib_LTLIBRARIES = \ - liboncal.la - -liboncal_la_LIBADD = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib \ - -L$(OPT_SPHENIX)/lib \ - -lfun4all \ - -lodbc++ \ - -lpdbcalBase \ - -lphool - -pkginclude_HEADERS = \ - OnCalDBCodes.h \ - OnCalHistoBinDefs.h \ - OnCal.h \ - OnCalServer.h - -liboncal_la_SOURCES = \ - OnCal.cc \ - OnCalServer.cc - -BUILT_SOURCES = \ - testexternals.cc - -noinst_PROGRAMS = \ - testexternals - -testexternals_SOURCES = \ - testexternals.cc - -testexternals_LDADD = \ - liboncal.la - -testexternals.cc: - echo "//*** this is a generated file. Do not commit, do not edit" > $@ - echo "int main()" >> $@ - echo "{" >> $@ - echo " return 0;" >> $@ - echo "}" >> $@ diff --git a/calibrations/framework/oncal/OnCal.cc b/calibrations/framework/oncal/OnCal.cc deleted file mode 100644 index ae652adbc8..0000000000 --- a/calibrations/framework/oncal/OnCal.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "OnCal.h" - -#include // for SubsysReco - -#include // for PHWHERE - -#include - -OnCal::OnCal(const std::string &Name) - : SubsysReco(Name) -{ -} - -int OnCal::process_event(PHCompositeNode * /*topNode*/) -{ - std::cout << "process_event(PHCompositeNode *topNode) not implemented by daughter class: " << Name() << std::endl; - return -1; -} - -int OnCal::End(PHCompositeNode * /*topNode*/) -{ - std::cout << "EndOfAnalysis not implemented by subsystem!" << std::endl; - std::cout << "Use this signal for computing your calibrations and commit." << std::endl; - std::cout << "Dont do these operations at EndOfRun since subsystems may be feeded events from different runs." << std::endl; - std::cout << "The number of events is the real parameter here, not the runnumber." << std::endl; - return 0; -} - -void OnCal::AddComment(const std::string &adcom) -{ - if (m_Comment.empty()) - { - m_Comment = adcom; - } - else - { - m_Comment += ":"; - m_Comment += adcom; - } - return; -} - -int OnCal::CopyTables(const int /*FromRun*/, const int /*ToRun*/, const int /*commit*/) const -{ - std::cout << PHWHERE << " CopyTables not implemented" << std::endl - << "this calibrator cannot copy its own tables" << std::endl; - return -1; -} diff --git a/calibrations/framework/oncal/OnCal.h b/calibrations/framework/oncal/OnCal.h deleted file mode 100644 index 454e240aaa..0000000000 --- a/calibrations/framework/oncal/OnCal.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef ONCAL_ONCAL_H -#define ONCAL_ONCAL_H - -#include -#include -#include -#include // for pair -#include - -class OnCal : public SubsysReco -{ - public: - ~OnCal() override = default; - - // These might be overwritten by everyone... - int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode *topNode) override = 0; // Here you analyze and commit (if committing flag is set) - - // Thsse control committing to the database... - virtual void CommitToPdbCal(const int value) = 0; // Set the flag for whether EndOfAnalysis will commit or not - virtual int VerificationOK() const = 0; // Tell us whether the new calib is close enough to the old one - virtual int CommitedToPdbCalOK() const = 0; // Tell us whether committing was successful by re-reading the data - - // commit without verification, needed for bootstrap calib - // which is too different from previous calibs (e.g. begin of new Run) - virtual void CommitNoVerify(const int) { return; } - - // These default behaviors from SubsysReco base class - virtual void identify(std::ostream &out = std::cout) const { out << Name() << std::endl; } - virtual int BeginRun(const int) { return 0; } - int EndRun(const int) override { return 0; } - int Reset(PHCompositeNode * /*topNode*/) override { return 0; } - int ResetEvent(PHCompositeNode * /*topNode*/) override { return 0; } - virtual void DumpCalib() const { return; } - - unsigned int AllDone() const { return alldone; } - void AllDone(const int i) { alldone = i; } - void AddComment(const std::string &adcom); - const std::string &Comment() const { return m_Comment; } - int GetPdbCalTables(std::vector &vec) const - { - vec = pdbcaltables; - return 0; - } - virtual int CopyTables(const int FromRun, const int ToRun, const int commit) const; - virtual int CreateCalibration(const int /*runnumber*/, const std::string & /*what*/, std::string & /*comment*/, const int /*commit*/) { return -1; } - virtual std::vector GetLocalFileList() const { return localfilelist; } - - protected: - OnCal(const std::string &Name); // so noone can call it from outside - unsigned int alldone{0}; - std::string m_Comment; - std::vector pdbcaltables; - std::vector pdbcalclasses; - std::vector > bankids; - std::vector localfilelist; -}; - -#endif /* ONCAL_ONCAL_H */ diff --git a/calibrations/framework/oncal/OnCalDBCodes.h b/calibrations/framework/oncal/OnCalDBCodes.h deleted file mode 100644 index 707c72f859..0000000000 --- a/calibrations/framework/oncal/OnCalDBCodes.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ONCALDBCODES_H__ -#define ONCALDBCODES_H__ - -namespace OnCalDBCodes -{ - enum - { - INIT = -2, - STARTED = -1, - FAILED = 0, - SUCCESS = 1, - COPIEDPREVIOUS = 2, - COPIEDLATER = 3, - COVERED = 4, - SUBSYSTEM = 5 - }; -} - -#endif diff --git a/calibrations/framework/oncal/OnCalHistoBinDefs.h b/calibrations/framework/oncal/OnCalHistoBinDefs.h deleted file mode 100644 index d030b6dce2..0000000000 --- a/calibrations/framework/oncal/OnCalHistoBinDefs.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __ONCALHISTOBINDEFS_H__ -#define __ONCALHISTOBINDEFS_H__ - -namespace OnCalHistoBinDefs -{ - enum - { - FIRSTRUNBIN = 1, - LASTRUNBIN, - BORTIMEBIN, - EORTIMEBIN, - LASTBINPLUSONE - }; -}; - -#endif /* __ONCALHISTOBINDEFS_H__ */ diff --git a/calibrations/framework/oncal/OnCalServer.cc b/calibrations/framework/oncal/OnCalServer.cc deleted file mode 100644 index 5593b84188..0000000000 --- a/calibrations/framework/oncal/OnCalServer.cc +++ /dev/null @@ -1,2439 +0,0 @@ -#include "OnCalServer.h" -#include "OnCal.h" -#include "OnCalDBCodes.h" -#include "OnCalHistoBinDefs.h" - -#include -#include -#include // for Fun4AllServer, Fun4AllServe... -#include -#include -#include // for SubsysReco - -#include -#include // for PHTimeStamp, operator<< -#include -#include - -#include - -#include // for Stat_t -#include // for TDirectoryAtomicAdapter -#include -#include -#include // for TNamed -#include -#include // for TString - -// odbc++ classes -#include -#include -#include -#include -#include -#include // for Statement -#include // for SQLException, Timestamp - -#include -#include -#include // for tolower -#include -#include // for strcmp -#include -#include // for reverse_iterator -#include -#include -#include -#include // for pair - -namespace -{ - const std::string cvstag = "OnCalv86"; - - odbc::Connection *DBconnection{nullptr}; -} // namespace - -OnCalServer *OnCalServer::instance() -{ - if (__instance) - { - OnCalServer *oncal = dynamic_cast(__instance); - return oncal; - } - __instance = new OnCalServer(); - OnCalServer *oncal = dynamic_cast(__instance); - return oncal; -} - -//--------------------------------------------------------------------- - -OnCalServer::OnCalServer(const std::string &name) - : Fun4AllServer(name) - , OnCalServerVars(new TH1D("OnCalServerVars", "OnCalServerVars", OnCalHistoBinDefs::LASTBINPLUSONE, -0.5, (int) (OnCalHistoBinDefs::LASTBINPLUSONE) -0.5)) -{ - beginTimeStamp.setTics(0); - endTimeStamp.setTics(0); - - Fun4AllServer::registerHisto(OnCalServerVars); - return; -} -//--------------------------------------------------------------------- - -OnCalServer::~OnCalServer() -{ - delete DBconnection; - return; -} -//--------------------------------------------------------------------- - -PHTimeStamp * -OnCalServer::GetEndValidityTS() -{ - if (endTimeStamp.getTics()) - { - PHTimeStamp *ts = new PHTimeStamp(endTimeStamp); - return ts; - } - - std::cout << PHWHERE << "Screwup - the end validity time is not set" << std::endl; - exit(1); -} -//--------------------------------------------------------------------- - -PHTimeStamp *OnCalServer::GetBeginValidityTS() -{ - if (beginTimeStamp.getTics()) - { - PHTimeStamp *ts = new PHTimeStamp(beginTimeStamp); - return ts; - } - - std::cout << PHWHERE << "Screwup - the begin validity time is not set" << std::endl; - exit(1); -} -//--------------------------------------------------------------------- - -void OnCalServer::dumpHistos() -{ - std::ostringstream filename; - std::string fileprefix = "./"; - - if (getenv("ONCAL_SAVEDIR")) - { - fileprefix = getenv("ONCAL_SAVEDIR"); - fileprefix += "/"; - } - - int compress = 3; - std::map >::const_iterator iter; - // std::map::const_iterator hiter; - TH1 *histo; - std::set::const_iterator siter; - for (iter = calibratorhistomap.begin(); iter != calibratorhistomap.end(); ++iter) - { - filename.str(""); - filename << fileprefix << "Run_" - << RunNumber() - << "_" << iter->first << ".root"; - TFile *hfile = new TFile(filename.str().c_str(), "RECREATE", - "Created by Online Calibrator", compress); - std::cout << "OnCalServer::dumpHistos() Output root file: " << filename.str() << std::endl; - for (siter = (iter->second).begin(); siter != (iter->second).end(); ++siter) - { - histo = dynamic_cast(getHisto(*siter)); - if (histo) - { - histo->Write(); - } - else - { - std::cout << PHWHERE << "Histogram " - << *siter << " not found, will not be saved in " - << filename.str() << std::endl; - } - } - hfile->Close(); - - delete hfile; - } - return; -} - -void OnCalServer::registerHisto(TH1 *h1d, OnCal *Calibrator, const int replace) -{ - if (Calibrator) - { - std::string calibratorname = Calibrator->Name(); - std::map >::iterator iter; - iter = calibratorhistomap.find(calibratorname); - if (iter != calibratorhistomap.end()) - { - (iter->second).insert(h1d->GetName()); - } - else - { - std::set newset; - newset.insert(h1d->GetName()); - newset.insert("OnCalServerVars"); - calibratorhistomap[calibratorname] = newset; - } - } - Fun4AllServer::registerHisto(h1d, replace); - return; -} - -void OnCalServer::unregisterHisto(const std::string &calibratorname) -{ - calibratorhistomap.erase(calibratorname); - return; -} - -int OnCalServer::process_event() -{ - Fun4AllServer::process_event(); - int i = 0; - nEvents++; - if ((nEvents % eventcheckfrequency) == 0) // check every 1000 events - { - std::cout << nEvents << " events, testing" << std::endl; - unsigned int j = 0; - unsigned int ical = 0; - std::vector >::const_iterator iter; - for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) - { - OnCal *oncal = dynamic_cast(iter->first); - if (oncal) - { - ical++; - std::cout << "Name: " << oncal->Name() - << " is " << oncal->AllDone() << std::endl; - j += oncal->AllDone(); - } - } - if (j == ical) - { - std::cout << "Everyone is done after " - << nEvents << " Events" << std::endl; - i = 1; - } - } - return i; -} - -int OnCalServer::BeginRun(const int runno) -{ - if (runno <= 0) - { - std::cout << PHWHERE << "Invalid Run Number: " << runno << std::endl; - exit(1); - } - FillRunListFromFileList(); - recoConsts *rc = recoConsts::instance(); - // we stick to the first runnumber, but after inheriting from - // Fun4All we get a EndRun/BeginRun when the run number changes - // so we have to catch this here - if (RunNumber() != 0) - { - rc->set_IntFlag("RUNNUMBER", RunNumber()); // set rc flag back to previous run - analysed_runs.push_back(runno); - return 0; - } - RunNumber(runno); - std::vector >::iterator iter; - // copy the subsys reco pointers to another set for - // easier search (we only need the pointers to find - // the subsystems with special timestamp/runnumber needs - std::set NeedOtherTimeStamp; - std::map >::const_iterator miter; - std::set::const_iterator siter; - for (miter = requiredCalibrators.begin(); - miter != requiredCalibrators.end(); ++miter) - { - for (siter = miter->second.begin(); siter != miter->second.end(); ++siter) - { - NeedOtherTimeStamp.insert(*siter); - } - } - - int iret; - int i = 0; - int oncalrun = runno; - int fun4allrun = runno; - - RunToTime *runTime = RunToTime::instance(); - PHTimeStamp *ts = runTime->getBeginTime(fun4allrun); - PHTimeStamp OnCalBORTimeStamp = *ts; - PHTimeStamp Fun4AllBORTimeStamp(OnCalBORTimeStamp); - delete ts; - if (!requiredCalibrators.empty()) - { - fun4allrun = FindClosestCalibratedRun(runno); - ts = runTime->getBeginTime(fun4allrun); - Fun4AllBORTimeStamp = *ts; - delete ts; - } - - // we have to do the same TDirectory games as in the Init methods - // save the current dir, cd to the subsystem name dir (which was - // created in init) call the InitRun of the module and cd back - - gROOT->cd(default_Tdirectory.c_str()); - std::string currdir = gDirectory->GetPath(); - std::set droplist; - for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) - { - std::ostringstream newdirname; - newdirname << (*iter).second->getName() << "/" << (*iter).first->Name(); - if (!gROOT->cd(newdirname.str().c_str())) - { - std::cout << PHWHERE << "Unexpected TDirectory Problem cd'ing to " - << (*iter).second->getName() - << " - send e-mail to off-l with your macro" << std::endl; - exit(1); - } - OnCal *oncal = dynamic_cast((*iter).first); - if (oncal) - { - std::string table = "OnCal"; - table += (*iter).first->Name(); - check_create_subsystable(table); - insertRunNumInDB(table, runNum); - std::string calibname = (*iter).first->Name(); - add_calibrator_to_statustable(calibname); - std::set::const_iterator runiter; - int calibstatus = GetCalibStatus(calibname, runNum); - if (calibstatus > 0 && testmode == 0) - { - std::cout << calibname << " already ran for run " << runNum << std::endl; - droplist.insert(calibname); - unregisterSubsystem(oncal); - unregisterHisto(calibname); - } - else - { - std::ostringstream stringarg; - stringarg << OnCalDBCodes::STARTED; - for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) - { - updateDB(successTable, calibname, stringarg.str(), *runiter); - } - } - } - if (NeedOtherTimeStamp.contains((*iter).first)) - { - std::cout << "changing timestamp for " << (*iter).first->Name() << std::endl; - rc->set_IntFlag("RUNNUMBER", fun4allrun); - // rc->set_TimeStamp(Fun4AllBORTimeStamp); - } - else - { - rc->set_IntFlag("RUNNUMBER", oncalrun); - // rc->set_TimeStamp(OnCalBORTimeStamp); - } - if (!droplist.contains((*iter).first->Name())) - { - iret = (*iter).first->InitRun(TopNode); - if (iret == Fun4AllReturnCodes::ABORTRUN) - { - std::cout << PHWHERE << "Module " << (*iter).first->Name() << " issued Abort Run, exiting" << std::endl; - exit(-1); - } - i += iret; - } - } - gROOT->cd(currdir.c_str()); - - rc->set_IntFlag("RUNNUMBER", oncalrun); - // rc->set_TimeStamp(OnCalBORTimeStamp); - if (OnCalServerVars->GetBinContent(OnCalHistoBinDefs::FIRSTRUNBIN) == 0) - { - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::FIRSTRUNBIN, runno); - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::BORTIMEBIN, (Stat_t) OnCalBORTimeStamp.getTics()); - } - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::LASTRUNBIN, (Stat_t) runno); - ts = runTime->getEndTime(runno); - if (ts) - { - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::EORTIMEBIN, (Stat_t) ts->getTics()); - delete ts; - } - - // disconnect from DB to save resources on DB machine - // PdbCal leaves the DB connection open (PdbCal will reconnect without - // problem if neccessary) - DisconnectDB(); - // finally drop calibrators which have run already from module list - unregisterSubsystemsNow(); - return i; -} - -int OnCalServer::End() -{ - if (nEvents == 0) - { - std::cout << "No Events read, you probably gave me an empty filelist" << std::endl; - return -1; - } - int i = 0; - std::vector >::iterator iter; - gROOT->cd(default_Tdirectory.c_str()); - std::string currdir = gDirectory->GetPath(); - - for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) - { - std::ostringstream newdirname; - newdirname << (*iter).second->getName() << "/" << (*iter).first->Name(); - if (!gROOT->cd(newdirname.str().c_str())) - { - std::cout << PHWHERE << "Unexpected TDirectory Problem cd'ing to " - << (*iter).second->getName() - << " - send e-mail to off-l with your macro" << std::endl; - exit(1); - } - else - { - if (Verbosity() > 2) - { - std::cout << "End: cded to " << newdirname.str().c_str() << std::endl; - } - } - i += (*iter).first->End((*iter).second); - } - - gROOT->cd(default_Tdirectory.c_str()); - currdir = gDirectory->GetPath(); - for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) - { - OnCal *oncal = dynamic_cast((*iter).first); - if (!oncal) - { - continue; - } - std::ostringstream newdirname; - newdirname << (*iter).second->getName() << "/" << (*iter).first->Name(); - if (!gROOT->cd(newdirname.str().c_str())) - { - std::cout << PHWHERE << "Unexpected TDirectory Problem cd'ing to " - << (*iter).second->getName() - << " - send e-mail to off-l with your macro" << std::endl; - exit(1); - } - - std::string CalibratorName = oncal->Name(); - - int verificationstatus = oncal->VerificationOK(); - int databasecommitstatus = oncal->CommitedToPdbCalOK(); - - // report success database the status of the calibration - if (recordDB) - { - std::string table = "OnCal"; - table += CalibratorName; - - std::ostringstream stringarg; - if (databasecommitstatus == OnCalDBCodes::SUCCESS) - { - stringarg << OnCalDBCodes::COVERED; - } - else - { - stringarg << OnCalDBCodes::FAILED; - } - std::set::const_iterator runiter; - for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) - { - updateDB(successTable, CalibratorName, stringarg.str(), *runiter); - } - // update the first run which was used in the calibration - // with the real status - updateDB(successTable, CalibratorName, databasecommitstatus); - - stringarg.str(""); - stringarg << databasecommitstatus; - updateDB(table, "committed", stringarg.str(), RunNumber()); - - stringarg.str(""); - stringarg << verificationstatus; - updateDB(table, "verified", stringarg.str(), RunNumber()); - - odbc::Timestamp stp(time(nullptr)); - updateDB(table, "date", stp.toString(), RunNumber()); - updateDB(table, "comment", oncal->Comment(), RunNumber()); - time_t beginticks = beginTimeStamp.getTics(); - stringarg.str(""); - stringarg << beginticks; - updateDB(table, "startvaltime", stringarg.str(), RunNumber()); - stp.setTime(beginticks); - updateDB(table, "begintime", stp.toString(), RunNumber()); - time_t endticks = endTimeStamp.getTics(); - stringarg.str(""); - stringarg << endticks; - updateDB(table, "endvaltime", stringarg.str(), RunNumber()); - stp.setTime(endticks); - updateDB(table, "endtime", stp.toString(), RunNumber()); - - std::string filelist; - for (Fun4AllSyncManager *sync : SyncManagers) - { - for (Fun4AllInputManager *inmgr : sync->GetInputManagers()) - { - for (const std::string &infile : inmgr->GetFileOpenedList()) - { - filelist += (infile).substr(((infile).find_last_of('/') + 1), (infile).size()); - filelist += " "; // this needs to be stripped again for last entry - } - } - } - filelist.pop_back(); // strip empty space at end from loop - std::cout << "FileList: " << filelist << std::endl; - updateDB(table, "files", filelist, RunNumber()); - updateDB(table, "cvstag", cvstag, RunNumber()); - } - - std::cout << "SERVER SUMMARY: " << oncal->Name() << " " - << (verificationstatus == 1 ? "Verification: SUCCESS " : "Verification: FAILURE ") - << (databasecommitstatus == 1 ? "DB commit: SUCCESS " : "DB commit: FAILURE ") - << std::endl; - - printStamps(); - } - gROOT->cd(currdir.c_str()); - dumpHistos(); // save the histograms in files - return i; -} -//--------------------------------------------------------------------- - -void OnCalServer::Print(const std::string &what) const -{ - Fun4AllServer::Print(what); - if (what == "ALL" || what == "CALIBRATOR") - { - // loop over the map and print out the content - // (name and location in memory) - - std::cout << "--------------------------------------" << std::endl - << std::endl; - std::cout << "List of Calibrators in OnCalServer:" << std::endl; - - std::vector >::const_iterator miter; - for (miter = Subsystems.begin(); - miter != Subsystems.end(); ++miter) - { - OnCal *oncal = dynamic_cast((*miter).first); - if (oncal) - { - std::cout << oncal->Name() << std::endl; - } - } - std::cout << std::endl; - } - if (what == "ALL" || what == "REQUIRED") - { - // loop over the map and print out the content - // (name and location in memory) - - std::cout << "--------------------------------------" << std::endl - << std::endl; - std::cout << "List of required Calibrations in OnCalServer:" << std::endl; - - std::map >::const_iterator iter; - std::set::const_iterator siter; - for (iter = requiredCalibrators.begin(); - iter != requiredCalibrators.end(); ++iter) - { - std::cout << iter->first << " calibrations are needed by " << std::endl; - for (siter = iter->second.begin(); siter != iter->second.end(); ++siter) - { - std::cout << (*siter)->Name() << std::endl; - } - } - std::cout << std::endl; - } - if (what == "ALL" || what == "FILES") - { - std::cout << "--------------------------------------" << std::endl - << std::endl; - std::cout << "List of PRDF Files in OnCalServer:" << std::endl; - for (Fun4AllSyncManager *sync : SyncManagers) - { - for (Fun4AllInputManager *inmgr : sync->GetInputManagers()) - { - for (const std::string &infile : inmgr->GetFileList()) - { - std::cout << "File: " << infile << std::endl; - } - } - } - } - if (what == "ALL" || what == "RUNS") - { - std::cout << "--------------------------------------" << std::endl - << std::endl; - std::cout << "List of Run Numbers in OnCalServer:" << std::endl; - std::set::const_iterator liter; - for (liter = runlist.begin(); liter != runlist.end(); ++liter) - { - std::cout << "Run : " << *liter << std::endl; - } - } - - return; -} - -void OnCalServer::printStamps() -{ - std::cout << std::endl - << std::endl; - std::cout << "*******************************************" << std::endl; - std::cout << "* VALIDITY RANGE FOR THIS CALIBRATION *" << std::endl; - std::cout << "* *" << std::endl; - std::cout << "* Used Run : "; - std::cout << runNum << std::endl; - std::cout << std::endl; - std::cout << "* Begin Valid : "; - beginTimeStamp.print(); - std::cout << std::endl; - std::cout << "* End Valid : "; - endTimeStamp.print(); - std::cout << std::endl; - std::cout << "* *" << std::endl; - std::cout << "*******************************************" << std::endl; - std::cout << std::endl - << std::endl - << std::endl; -} - -//--------------------------------------------------------------------- - -void OnCalServer::RunNumber(const int runnum) -{ - runNum = runnum; - SetBorTime(runnum); - if (recordDB) - { - std::set::const_iterator runiter; - time_t beginrunticks; - time_t endrunticks; - std::ostringstream stringarg; - odbc::Timestamp stp; - for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) - { - insertRunNumInDB(successTable, *runiter); - GetRunTimeTicks(*runiter, beginrunticks, endrunticks); - stringarg.str(""); - stringarg << beginrunticks; - updateDB(successTable, "startvaltime", stringarg.str(), *runiter); - stp.setTime(beginrunticks); - updateDB(successTable, "beginrun", stp.toString(), *runiter); - stringarg.str(""); - stringarg << endrunticks; - updateDB(successTable, "endvaltime", stringarg.str(), *runiter); - stp.setTime(endrunticks); - updateDB(successTable, "endrun", stp.toString(), *runiter); - } - } - if (!runlist.empty()) - { - SetEorTime(*runlist.rbegin()); - } - return; -} - -//--------------------------------------------------------------------- - -bool OnCalServer::connectDB() -{ - if (DBconnection) - { - return true; - } - - bool failure = true; - int countdown = 10; - while (failure && countdown > 0) - { - failure = false; - try - { - DBconnection = - odbc::DriverManager::getConnection(database, "phnxrc", ""); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot connect to " << database.c_str() << std::endl; - std::cout << e.getMessage() << std::endl; - std::cout << "countdown: " << countdown << std::endl; - countdown--; - failure = true; - sleep(100); // try again in 100 secs - } - } - if (failure) - { - std::cout << "could not connect to DB after 10 tries in 1000 secs, giving up" << std::endl; - exit(-1); - } - std::cout << "connected to " << database.c_str() << " database." << std::endl; - return true; -} -//--------------------------------------------------------------------- - -int OnCalServer::DisconnectDB() -{ - delete DBconnection; - DBconnection = nullptr; - return 0; -} -//--------------------------------------------------------------------- - -bool OnCalServer::insertRunNumInDB(const std::string &DBtable, const int runno) -{ - if (findRunNumInDB(DBtable, runno)) - { - return true; - } - - std::cout << "new row will be created in DB for run " << runno << std::endl; - - odbc::Statement *statement = nullptr; - statement = DBconnection->createStatement(); - std::ostringstream cmd; - cmd << "INSERT INTO " - << DBtable - << " (runnumber) VALUES (" - << runno << ")"; - - if (Verbosity() == 1) - { - std::cout << "in function OnCalServer::insertRunNumInDB() ... "; - std::cout << "executing SQL statements ..." << std::endl; - std::cout << cmd.str() << std::endl; - } - - try - { - statement->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << e.getMessage() << std::endl; - return false; - } - - return true; -} - -//--------------------------------------------------------------------- - -bool OnCalServer::findRunNumInDB(const std::string &DBtable, const int runno) -{ - if (!DBconnection) - { - connectDB(); - } - odbc::Statement *statement = nullptr; - odbc::ResultSet *rs = nullptr; - std::ostringstream cmd; - cmd << "SELECT runnumber FROM " - << DBtable - << " WHERE runnumber = " - << runno; - - statement = DBconnection->createStatement(); - - if (Verbosity() == 1) - { - std::cout << "in function OnCalServer::findRunNumInDB() "; - std::cout << "executing SQL statement ..." << std::endl - << cmd.str() << std::endl; - } - - try - { - rs = statement->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << PHWHERE << " exception caught: " << e.getMessage() << std::endl; - return false; - } - - int entry = 0; - if (rs->next()) - { - try - { - entry = rs->getInt("runnumber"); - } - catch (odbc::SQLException &e) - { - std::cout << PHWHERE << " exception caught: " << e.getMessage() << std::endl; - return false; - } - } - else - { - return false; - } - std::cout << "run number " << entry << " already exists in DB" << std::endl; - return true; -} - -bool OnCalServer::updateDBRunRange(const std::string &table, const std::string &column, const int entry, const int firstrun, const int lastrun) -{ - if (!DBconnection) - { - connectDB(); - } - - odbc::Statement *statement = nullptr; - - std::string command = "UPDATE "; - command += table; - command += " SET "; - command += column; - command += " = "; - command += std::to_string(entry); - command += " WHERE runnumber >= "; - command += std::to_string(firstrun); - command += " and runnumber <= "; - command += std::to_string(lastrun); - - if (Verbosity() == 1) - { - std::cout << "in function OnCalServer::updateDB() ... "; - std::cout << "executin SQL statement ... " << std::endl; - std::cout << command << std::endl; - } - statement = DBconnection->createStatement(); - - try - { - statement->executeUpdate(command); - } - catch (odbc::SQLException &e) - { - std::cout << e.getMessage() << std::endl; - return false; - } - - return true; -} - -//--------------------------------------------------------------------- - -bool OnCalServer::updateDB(const std::string &table, const std::string &column, int entry) -{ - if (!DBconnection) - { - connectDB(); - } - - odbc::Statement *statement = nullptr; - - TString command = "UPDATE "; - command += table; - command += " SET "; - command += column; - command += " = "; - command += entry; - command += " WHERE runnumber = "; - command += runNum; - - if (Verbosity() == 1) - { - std::cout << "in function OnCalServer::updateDB() ... "; - std::cout << "executin SQL statement ... " << std::endl; - std::cout << command.Data() << std::endl; - } - statement = DBconnection->createStatement(); - - try - { - statement->executeUpdate(command.Data()); - } - catch (odbc::SQLException &e) - { - std::cout << e.getMessage() << std::endl; - return false; - } - - return true; -} -//--------------------------------------------------------------------- - -bool OnCalServer::updateDB(const std::string &table, const std::string &column, bool entry) -{ - if (!DBconnection) - { - connectDB(); - } - odbc::Statement *statement = nullptr; - - TString command = "UPDATE "; - command += table; - command += " set "; - command += column; - command += " = '"; - command += static_cast(entry); - command += "' WHERE runnumber = "; - command += runNum; - - if (Verbosity() == 1) - { - std::cout << "in function OnCalServer::updateDB() ... "; - std::cout << "executin SQL statement ... " << std::endl; - std::cout << command.Data() << std::endl; - } - statement = DBconnection->createStatement(); - - try - { - statement->executeUpdate(command.Data()); - } - catch (odbc::SQLException &e) - { - std::cout << e.getMessage() << std::endl; - return false; - } - - return true; -} - -//--------------------------------------------------------------------- - -int OnCalServer::updateDB(const std::string &table, const std::string &column, - const time_t ticks) -{ - if (!DBconnection) - { - connectDB(); - } - odbc::Statement *statement = nullptr; - - std::ostringstream cmd; - statement = DBconnection->createStatement(); - cmd << "UPDATE " - << table - << " set " - << column - << " = " - << ticks - << " WHERE runnumber = " - << runNum; - - if (Verbosity() == 1) - { - std::cout << "in function OnCalServer::updateDB() ... "; - std::cout << "executin SQL statement ... " << std::endl; - std::cout << cmd.str() << std::endl; - } - - try - { - statement->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << e.getMessage() << std::endl; - return -1; - } - return 0; -} -//--------------------------------------------------------------------- - -bool OnCalServer::updateDB(const std::string &table, const std::string &column, - const std::string &entry, const int runno, const bool append) -{ - if (!DBconnection) - { - connectDB(); - } - - odbc::Statement *statement = nullptr; - - statement = DBconnection->createStatement(); - - std::string comment; - std::ostringstream cmd; - if (append) - { - odbc::ResultSet *rs = nullptr; - std::ostringstream query; - query << "SELECT * FROM " - << table - << " WHERE runnumber = " - << runno; - - try - { - rs = statement->executeQuery(query.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "in function OnCalServer::updateDB() ... "; - std::cout << "run number " << runno << "not found in DB" << std::endl; - std::cout << e.getMessage() << std::endl; - } - - rs->next(); - try - { - comment = rs->getString(column); - comment += " "; // add empty space between comments - } - catch (odbc::SQLException &e) - { - std::cout << "in function OnCalServer::updateDB() ... " << std::endl; - std::cout << "nothing to append." << std::endl; - std::cout << e.getMessage() << std::endl; - } - delete rs; - } - - comment += entry; - cmd << "UPDATE " - << table - << " set " - << column - << " = '" - << comment - << "' WHERE runnumber = " - << runno; - - if (Verbosity() == 1) - { - std::cout << "in function OnCalServer::updateDB() ... "; - std::cout << "executin SQL statement ... " << std::endl; - std::cout << cmd.str() << std::endl; - } - - try - { - statement->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << e.getMessage() << std::endl; - return false; - } - delete statement; - return true; -} - -//--------------------------------------------------------------------- - -int OnCalServer::check_create_subsystable(const std::string &tablename) -{ - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - std::vector > calibrator_columns; - std::vector >::const_iterator coliter; - calibrator_columns.emplace_back("runnumber", "int NOT NULL"); - calibrator_columns.emplace_back("verified", "int default -2"); - calibrator_columns.emplace_back("committed", "int default -2"); - calibrator_columns.emplace_back("date", "timestamp(0) with time zone"); - calibrator_columns.emplace_back("comment", "text"); - calibrator_columns.emplace_back("files", "text"); - calibrator_columns.emplace_back("cvstag", "text"); - calibrator_columns.emplace_back("startvaltime", "bigint"); - calibrator_columns.emplace_back("endvaltime", "bigint"); - calibrator_columns.emplace_back("begintime", "timestamp(0) with time zone"); - calibrator_columns.emplace_back("endtime", "timestamp(0) with time zone"); - - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - cmd << "SELECT * FROM " << tablename << " LIMIT 1" << std::ends; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << tablename << " does not exist, will create it" << std::endl; - // std::cout << "Message: " << e.getMessage() << std::endl; - } - if (!rs) - { - cmd.str(""); - cmd << "CREATE TABLE " - << tablename - << "("; - for (coliter = calibrator_columns.begin(); coliter != calibrator_columns.end(); ++coliter) - { - cmd << (*coliter).first << " " << (*coliter).second << ", "; - } - - cmd << "primary key(runnumber))"; - stmt->executeUpdate(cmd.str()); - } - else // check if the all columns exist - { - for (coliter = calibrator_columns.begin(); coliter != calibrator_columns.end(); ++coliter) - { - try - { - rs->findColumn((*coliter).first); - } - catch (odbc::SQLException &e) - { - const std::string &exceptionmessage = e.getMessage(); - if (exceptionmessage.find("not found in result set") != std::string::npos) - { - std::cout << "Column " << (*coliter).first << " does not exist in " - << tablename << ", creating it" << std::endl; - cmd.str(""); - cmd << "ALTER TABLE " - << tablename - << " ADD " - << (*coliter).first - << " " - << (*coliter).second; - try - { - odbc::Statement *stmtup = DBconnection->createStatement(); - stmtup->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e1) - { - std::cout << PHWHERE << " Exception caught: " << e1.getMessage() << std::endl; - } - } - } - } - delete rs; - } - return 0; -} - -int OnCalServer::add_calibrator_to_statustable(const std::string &calibratorname) -{ - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - if (check_calibrator_in_statustable(calibratorname) == 0) - { - return 0; - } - const std::string &calibname = calibratorname; - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - cmd.str(""); - cmd << "ALTER TABLE " << successTable << " ADD COLUMN " - << calibname << " int"; - try - { - stmt->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Message: " << e.getMessage() << std::endl; - std::cout << "cmd: " << cmd.str() << std::endl; - exit(1); - } - cmd.str(""); - cmd << "ALTER TABLE " << successTable << " ALTER COLUMN " - << calibname << " SET DEFAULT " << OnCalDBCodes::INIT; - try - { - stmt->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Message: " << e.getMessage() << std::endl; - std::cout << "cmd: " << cmd.str() << std::endl; - exit(1); - } - cmd.str(""); - cmd << "UPDATE " << successTable << " SET " - << calibname << " = " << OnCalDBCodes::INIT; - try - { - stmt->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Message: " << e.getMessage() << std::endl; - std::cout << "cmd: " << cmd.str() << std::endl; - exit(1); - } - - return 0; -} - -int OnCalServer::check_calibrator_in_statustable(const std::string &calibratorname) -{ - // replace this contraption by this sql command which returns 1 row if column exists - // select * from information_schema.columns where table_name = 'oncal_status' and column_name = 'svxstripdeadmapcal'; - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - std::string calibname = calibratorname; - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - cmd << "SELECT * FROM " << successTable << " LIMIT 1" << std::ends; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Message: " << e.getMessage() << std::endl; - std::cout << "Table " << successTable << " does not exist, your logic is off" << std::endl; - exit(1); - } - odbc::ResultSetMetaData *meta = rs->getMetaData(); - unsigned int nocolumn = rs->getMetaData()->getColumnCount(); - // column names are lower case only, so convert string to lowercase - // The bizarre cast here is needed for newer gccs - transform(calibname.begin(), calibname.end(), calibname.begin(), (int (*)(int)) tolower); - - for (unsigned int i = 1; i <= nocolumn; i++) - { - if (meta->getColumnName(i) == calibname) - { - if (Verbosity() > 0) - { - std::cout << calibname << " is in " << successTable << std::endl; - } - return 0; - } - } - // if we get here, the calibrator is not yet in the table - delete rs; - return -1; -} - -int OnCalServer::check_create_successtable(const std::string &tablename) -{ - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - cmd << "SELECT runnumber FROM " << tablename << " LIMIT 1" << std::ends; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << tablename << " does not exist, will create it" << std::endl; - // std::cout << "Message: " << e.getMessage() << std::endl; - } - if (!rs) - { - cmd.str(""); - cmd << "CREATE TABLE " << tablename << "(runnumber int NOT NULL, " - << "startvaltime bigint, " - << "endvaltime bigint, " - << "beginrun timestamp(0) with time zone, " - << "endrun timestamp(0) with time zone, " - << "comment text, " - << "primary key(runnumber))"; - std::cout << cmd.str() << std::endl; - try - { - stmt->executeUpdate(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Error, Message: " << e.getMessage() << std::endl; - // std::cout << "Message: " << e.getMessage() << std::endl; - } - } - return 0; -} - -void OnCalServer::recordDataBase(const bool bookkeep) -{ - recordDB = bookkeep; - if (recordDB) - { - check_create_successtable(successTable); - } - return; -} - -void OnCalServer::BeginTimeStamp(const PHTimeStamp &TimeStp) -{ - beginTimeStamp = TimeStp; - std::cout << "OnCalServer::BeginTimeStamp: Setting BOR TimeStamp to " << beginTimeStamp << std::endl; -} - -void OnCalServer::EndTimeStamp(const PHTimeStamp &TimeStp) -{ - endTimeStamp = TimeStp; - std::cout << "OnCalServer::EndTimeStamp: Setting EOR TimeStamp to " << endTimeStamp << std::endl; -} - -PHTimeStamp * -OnCalServer::GetLastGoodRunTS(OnCal *calibrator, const int irun) -{ - PHTimeStamp *ts = nullptr; - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return ts; - } - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - std::ostringstream subsystable; - subsystable << "oncal" << calibrator->Name(); - cmd << "SELECT runnumber FROM " << successTable << " where runnumber < " - << irun << " and " - << calibrator->Name() << " > 0 order by runnumber desc limit 1"; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << subsystable.str() << " does not exist" << std::endl; - return ts; - } - if (rs->next()) - { - RunToTime *rt = RunToTime::instance(); - int oldrun = rs->getInt("runnumber"); - ts = rt->getBeginTime(oldrun); - std::cout << "Getting previous good run, current run: " << irun - << ", previous good run: " << oldrun - << " began "; - ts->print(); - std::cout << std::endl; - } - else - { - std::cout << PHWHERE << " No previous good run found for run " << irun << std::endl; - } - delete rs; - return ts; -} - -int OnCalServer::SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const int commit) -{ - std::vector caltab; - calibrator->GetPdbCalTables(caltab); - std::vector::const_iterator iter; - for (iter = caltab.begin(); iter != caltab.end(); ++iter) - { - std::cout << "dealing with table: " << *iter << std::endl; - SyncCalibTimeStampsToOnCal(calibrator, *iter, commit); - } - return 0; -} - -int OnCalServer::SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const std::string &table, const int commit) -{ - std::string name = calibrator->Name(); - odbc::Connection *con = nullptr; - odbc::Connection *concalib = nullptr; - std::ostringstream cmd; - try - { - con = odbc::DriverManager::getConnection(database, "phnxrc", ""); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot connect to " << database.c_str() << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - try - { - concalib = odbc::DriverManager::getConnection("oncal", "phnxrc", ""); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot connect to " - << "oncal" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - odbc::Statement *stmt = nullptr; - try - { - stmt = con->createStatement(); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot create statement" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - - odbc::PreparedStatement *stmt1 = nullptr; - odbc::ResultSet *rs1 = nullptr; - try - { - cmd.str(""); - cmd << "SELECT * from " << table << " where startvaltime = ?"; - stmt1 = concalib->prepareStatement(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot create statement" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - - odbc::PreparedStatement *stmtupd = nullptr; - try - { - cmd.str(""); - cmd << "update " << table << " set endvaltime = ? where startvaltime = ?"; - stmtupd = concalib->prepareStatement(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot create statement" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - - cmd.str(""); - cmd << "select * from " - << successTable - << " where " - << name - << " > 0"; - // << " > 0 and runnumber < 150000"; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Message: " << e.getMessage() << std::endl; - return -1; - } - while (rs->next()) - { - int run = rs->getInt("runnumber"); - int startticks = rs->getLong("startvaltime"); - int endticks = rs->getLong("endvaltime"); - // int status = rs->getInt(name); - // std::cout << "run: " << run - // << ", status: " << status - // << ", startticks: " << startticks - // << ", endticks: " << endticks << std::endl; - stmt1->setInt(1, startticks); - try - { - rs1 = stmt1->executeQuery(); - } - catch (odbc::SQLException &e) - { - std::cout << "Message: " << e.getMessage() << std::endl; - return -1; - } - int ionce = 0; - int isproblem = 0; - int calibendval = 0; - while (rs1->next()) - { - calibendval = rs1->getInt("endvaltime"); - if (endticks != rs1->getInt("endvaltime")) - { - if (!isproblem) - { - std::cout << "endvaltime problem with run " << run << std::endl; - std::cout << "endvaltime from oncal_status: " << endticks << std::endl; - std::cout << "startvaltime from oncal_status: " << startticks << std::endl; - std::cout << "endvaltime from calibrations DB: " << rs1->getInt("endvaltime") << std::endl; - if (endticks < rs1->getInt("endvaltime")) - { - std::cout << "ENDTICKS smaller CALIB" << std::endl; - // return -1; - } - } - isproblem = 1; - } - else - { - if (isproblem) - { - std::cout << "endvaltime changes, check run " << run << std::endl; - // return -1; - } - } - // std::cout << "starttime: " << rs1->getInt("startvaltime") << std::endl; - // std::cout << "endtime: " << rs1->getInt("endvaltime") << std::endl; - ionce++; - } - if (isproblem) - { - std::cout << "Adjusting run " << run << std::endl; - std::cout << "changing endvaltime from " << calibendval - << " to " << endticks << std::endl; - if (commit) - { - stmtupd->setInt(1, endticks); - stmtupd->setInt(2, startticks); - stmtupd->executeUpdate(); - } - } - if (!ionce) - { - std::cout << "Run " << run << " not found" << std::endl; - } - delete rs1; - } - delete rs; - delete con; - delete concalib; - return 0; -} - -int OnCalServer::SyncOncalTimeStampsToRunDB(const int commit) -{ - odbc::Connection *con = nullptr; - RunToTime *rt = RunToTime::instance(); - std::ostringstream cmd; - try - { - con = odbc::DriverManager::getConnection(database, "phnxrc", ""); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot connect to " << database.c_str() << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - odbc::Statement *stmt = nullptr; - try - { - stmt = con->createStatement(); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot create statement" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - - odbc::PreparedStatement *stmtupd = nullptr; - try - { - cmd.str(""); - cmd << "UPDATE oncal_status set endvaltime = ? where runnumber = ?"; - stmtupd = con->prepareStatement(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Cannot create statement" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - - cmd.str(""); - cmd << "select * from " - << successTable; //<< " where runnumber > 160000"; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Message: " << e.getMessage() << std::endl; - return -1; - } - while (rs->next()) - { - int run = rs->getInt("runnumber"); - int startticks = rs->getLong("startvaltime"); - int endticks = rs->getLong("endvaltime"); - int rtstartticks = 0; - int rtendticks = 0; - PHTimeStamp *rtstart = rt->getBeginTime(run); - PHTimeStamp *rtend = rt->getEndTime(run); - if (rtstart) - { - rtstartticks = rtstart->getTics(); - delete rtstart; - } - if (rtend) - { - rtendticks = rtend->getTics(); - delete rtend; - } - if (rtstartticks != startticks) - { - std::cout << "Run " << run - << ": Start mismatch, oncal: " << startticks - << ", rt: " << rtstartticks << std::endl; - } - if (rtendticks != endticks) - { - // exclude starttime=endtime in runtotime (some crashed calibrations can do this) - // in this case the calibration adds 1 sec to starttime - if (rtstartticks != rtendticks) - { - std::cout << "Run " << run - << ": End mismatch, oncal: " << endticks - << ", rt: " << rtendticks << std::endl; - if (endticks > rtendticks) - { - std::cout << "BAD: endticks: " << endticks - << ", rtendticks: " << rtendticks - << std::endl; - return -1; - } - if (commit) - { - stmtupd->setLong(1, rtendticks); - stmtupd->setLong(2, run); - stmtupd->executeUpdate(); - } - } - else - { - if (startticks != endticks - 1) - { - std::cout << "Run " << run - << ": Start/End mismatch, Start: " << startticks - << ", End: " << endticks << std::endl; - endticks = startticks + 1; - if (commit) - { - stmtupd->setLong(1, endticks); - stmtupd->setLong(2, run); - stmtupd->executeUpdate(); - } - } - else - { - if (Verbosity() > 0) - { - std::cout << "run " << run << " was twiddled by OnCal" << std::endl; - } - } - } - } - // std::cout << "run: " << run - // << ", status: " << status - // << ", startticks: " << startticks - // << ", endticks: " << endticks << std::endl; - } - delete rs; - delete con; - return 0; -} - -int OnCalServer::CopyTables(const OnCal *calibrator, const int FromRun, const int ToRun, const int commit) -{ - int iret = calibrator->CopyTables(FromRun, ToRun, commit); - return iret; -} - -int OnCalServer::CreateCalibration(OnCal *calibrator, const int myrunnumber, const std::string &what, const int commit) -{ - int iret = -1; - runNum = myrunnumber; - SetBorTime(myrunnumber); - SetEorTime(myrunnumber); - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - add_calibrator_to_statustable(calibrator->Name()); - std::string table = "OnCal"; - table += calibrator->Name(); - check_create_subsystable(table); - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - - cmd << "SELECT runnumber FROM " - << successTable << " where runnumber = " - << myrunnumber; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << successTable << " does not exist" << std::endl; - return -1; - } - if (!rs->next()) - { - insertRunNumInDB(successTable, myrunnumber); - } - delete rs; - cmd.str(""); - cmd << "SELECT runnumber FROM " - << successTable << " where runnumber = " - << myrunnumber << " and " - << calibrator->Name() << " <= 0"; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << PHWHERE << " Exception caught, Message: " - << e.getMessage() << std::endl; - return -1; - } - if (rs->next() || testmode) - { - std::string tablecomment = "Subsytem provided"; - iret = calibrator->CreateCalibration(runnumber, what, tablecomment, commit); - if (!iret) - { - std::cout << "Comment: " << tablecomment << std::endl; - std::cout << "updating oncal status tables for " << runnumber << std::endl; - if (commit) - { - CreateCalibrationUpdateStatus(calibrator, table, tablecomment, OnCalDBCodes::SUBSYSTEM); - } - } - else - { - std::cout << "Calibratior " << calibrator->Name() << " for run " << runnumber << " failed" << std::endl; - if (commit) - { - CreateCalibrationUpdateStatus(calibrator, table, tablecomment, OnCalDBCodes::FAILED); - } - } - } - else - { - std::cout << PHWHERE << " Run " << runnumber << " is already successfully calibrated for " - << calibrator->Name() << std::endl; - } - return iret; -} - -void OnCalServer::CreateCalibrationUpdateStatus(OnCal *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode) -{ - updateDB(successTable, calibrator->Name(), dbcode); - insertRunNumInDB(table, RunNumber()); - updateDB(table, "comment", tablecomment, RunNumber(), true); - std::ostringstream stringarg; - stringarg.str(""); - stringarg << calibrator->CommitedToPdbCalOK(); - updateDB(table, "committed", stringarg.str(), RunNumber()); - stringarg.str(""); - stringarg << calibrator->VerificationOK(); - updateDB(table, "verified", stringarg.str(), RunNumber()); - odbc::Timestamp stp(time(nullptr)); - updateDB(table, "date", stp.toString(), RunNumber()); - time_t beginticks = beginTimeStamp.getTics(); - stringarg.str(""); - stringarg << beginticks; - updateDB(table, "startvaltime", stringarg.str(), RunNumber()); - stp.setTime(beginticks); - updateDB(table, "begintime", stp.toString(), RunNumber()); - time_t endticks = endTimeStamp.getTics(); - stringarg.str(""); - stringarg << endticks; - updateDB(table, "endvaltime", stringarg.str(), RunNumber()); - stp.setTime(endticks); - updateDB(table, "endtime", stp.toString(), RunNumber()); - updateDB(table, "cvstag", cvstag, RunNumber()); - std::vector flist = calibrator->GetLocalFileList(); - if (!flist.empty()) - { - std::string filelist; - for (const std::string &infile : flist) - { - filelist += infile; - filelist += " "; - } - filelist.pop_back(); // strip empty space at end from loop - std::cout << "FileList: " << filelist << std::endl; - updateDB(table, "files", filelist, RunNumber()); - } - return; -} - -int OnCalServer::ClosestGoodRun(OnCal *calibrator, const int irun, const int previous) -{ - RunToTime *rt = RunToTime::instance(); - PHTimeStamp *ts = rt->getBeginTime(irun); - if (!ts) - { - std::cout << PHWHERE << "Unknown Run " << irun << std::endl; - return -1; - } - int curstart = ts->getTics(); - delete ts; - ts = rt->getEndTime(irun); - int curend = curstart; - if (ts) - { - curend = ts->getTics(); - delete ts; - } - int closestrun = -1; - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - - // look only for runs which were actually successfully calibrated (status = 1) - cmd << "SELECT runnumber,startvaltime,endvaltime FROM " - << successTable << " where runnumber < " - << irun << " and " - << calibrator->Name() << " = 1 order by runnumber desc limit 1"; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << successTable << " does not exist" << std::endl; - return -1; - } - int prevrun = -1; - unsigned int prevend = 0; - if (rs->next()) - { - prevrun = rs->getInt("runnumber"); - unsigned int prevstart = rs->getLong("startvaltime"); - prevend = rs->getLong("endvaltime"); - std::cout << "previous run: " << prevrun - << ", start: " << prevstart - << ", end: " << prevend - << std::endl; - } - else - { - if (Verbosity() > 0) - { - std::cout << PHWHERE << " No previous good run found for run " << irun << std::endl; - } - } - delete rs; - closestrun = prevrun; - if (previous == fetchrun::PREVIOUS) - { - if (Verbosity() > 0) - { - std::cout << "Closest previous run is " << closestrun << std::endl; - } - return closestrun; - } - cmd.str(""); - cmd << "SELECT runnumber,startvaltime,endvaltime FROM " - << successTable << " where runnumber > " - << irun << " and " - << calibrator->Name() << " = 1 order by runnumber asc limit 1"; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << successTable << " does not exist" << std::endl; - return -1; - } - int nextrun = -1; - unsigned int nextstart = 0; - if (rs->next()) - { - nextrun = rs->getInt("runnumber"); - nextstart = rs->getLong("startvaltime"); - unsigned int nextend = rs->getLong("endvaltime"); - if (Verbosity() > 0) - { - std::cout << "next run: " << nextrun - << ", start: " << nextstart - << ", end: " << nextend - << std::endl; - } - } - else - { - if (Verbosity() > 0) - { - std::cout << PHWHERE << " No next good run found for run " << irun << std::endl; - } - } - delete rs; - int tdiffprev = curstart - prevend; - int tdiffnext; - if (nextstart > 0) - { - tdiffnext = nextstart - curend; - } - else - { - // just make it larger then previous run time diff - tdiffnext = tdiffprev + 1; - } - if (Verbosity() > 0) - { - std::cout << "diff prev: " << tdiffprev - << ", next: " << tdiffnext - << std::endl; - } - if (tdiffprev < tdiffnext) - { - closestrun = prevrun; - } - else - { - closestrun = nextrun; - } - if (Verbosity() > 0) - { - std::cout << "closest run: " << closestrun << std::endl; - } - return closestrun; -} - -int OnCalServer::OverwriteCalibration(OnCal *calibrator, const int runno, const int commit, const int FromRun) -{ - if (FromRun < 0) - { - return -1; - } - int iret = CopyTables(calibrator, FromRun, runno, commit); - return iret; -} - -int OnCalServer::FixMissingCalibration(OnCal *calibrator, const int runno, const int commit, const int fromrun) -{ - int iret = -1; - // find this run in oncal_status - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - runNum = runno; - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - - cmd << "SELECT runnumber FROM " - << successTable << " where runnumber = " - << runno; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << successTable << " does not exist" << std::endl; - return -1; - } - if (!rs->next()) - { - insertRunNumInDB(successTable, runNum); - } - delete rs; - cmd.str(""); - cmd << "SELECT runnumber FROM " - << successTable << " where runnumber = " - << runno << " and " - << calibrator->Name() << " <= 0"; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << PHWHERE << " Exception caught, Message: " - << e.getMessage() << std::endl; - return -1; - } - if (rs->next()) - { - int FromRun; - if (fromrun > 0) - { - FromRun = fromrun; - } - else - { - FromRun = ClosestGoodRun(calibrator, runno); - if (FromRun < 0) - { - std::cout << "ClosestGoodRun returned bad runnumber: " << FromRun << std::endl; - return -1; - } - } - std::cout << "Going to copy calibration for run " << runno - << " from run " << FromRun << std::endl; - - iret = OverwriteCalibration(calibrator, runno, commit, FromRun); - if (!iret) - { - int newstatus = 0; - if (FromRun < runno) - { - newstatus = OnCalDBCodes::COPIEDPREVIOUS; - } - else - { - newstatus = OnCalDBCodes::COPIEDLATER; - } - std::string table = "OnCal"; - table += calibrator->Name(); - std::ostringstream comment; - comment << " CopiedRun(" << FromRun << ")"; - std::cout << "updating oncal status tables for " << runno << std::endl; - if (commit) - { - updateDB(successTable, calibrator->Name(), newstatus); - insertRunNumInDB(table, runNum); - updateDB(table, "comment", comment.str(), runNum, true); - updateDB(table, "committed", true); - } - } - } - else - { - std::cout << "Run " << runno - << " has a good calibrations, doing nothing" << std::endl; - } - delete rs; - return iret; -} - -int OnCalServer::SetBorTime(const int runno) -{ - // recoConsts *rc = recoConsts::instance(); - RunToTime *runTime = RunToTime::instance(); - - PHTimeStamp *BorTimeStp(runTime->getBeginTime(runno)); - if (!BorTimeStp) - { - std::cout << PHWHERE << "Cannot get begin time for run " << runno << std::endl; - std::cout << "Exiting" << std::endl; - exit(1); - } - BeginTimeStamp(*BorTimeStp); - - // enter begin run timestamp into rc flags - PHTimeStamp BeginRunTimeStamp(*BorTimeStp); - // rc->set_TimeStamp(BeginRunTimeStamp); - std::cout << "OnCalServer::SetBorTime from RunToTime was found for run : " << runno << " to "; - BeginRunTimeStamp.print(); - std::cout << std::endl; - - delete BorTimeStp; - return 0; -} - -int OnCalServer::SetEorTime(const int runno) -{ - // recoConsts *rc = recoConsts::instance(); - RunToTime *runTime = RunToTime::instance(); - - time_t eorticks = 0; - - time_t borticks = 0; //(rc->get_TimeStamp()).getTics(); - PHTimeStamp *EorTimeStp(runTime->getEndTime(runno)); - if (EorTimeStp) - { - eorticks = EorTimeStp->getTics(); - } - else - { - EorTimeStp = new PHTimeStamp(eorticks); - } - // if end of run timestamp missing or smaller-equal borstamp eor = bor+1 sec - if (eorticks <= borticks) - { - eorticks = borticks + 1; - EorTimeStp->setTics(eorticks); - } - EndTimeStamp(*EorTimeStp); - std::cout << "OnCalServer::SetEorTime: setting eor time to "; - EorTimeStp->print(); - std::cout << std::endl; - delete EorTimeStp; - return 0; -} - -int OnCalServer::GetRunTimeTicks(const int runno, time_t &borticks, time_t &eorticks) -{ - RunToTime *runTime = RunToTime::instance(); - PHTimeStamp *TimeStp(runTime->getBeginTime(runno)); - if (!TimeStp) - { - std::cout << PHWHERE << "Cannot get begin time for run " << runno << std::endl; - std::cout << "Exiting" << std::endl; - exit(1); - } - borticks = TimeStp->getTics(); - delete TimeStp; - TimeStp = runTime->getEndTime(runno); - if (TimeStp) - { - eorticks = TimeStp->getTics(); - delete TimeStp; - } - else - { - eorticks = 0; - } - // if end of run timestamp missing or smaller-equal borstamp eor = bor+1 sec - if (eorticks <= borticks) - { - eorticks = borticks + 1; - } - return 0; -} - -int OnCalServer::requiredCalibration(SubsysReco *reco, const std::string &calibratorname) -{ - std::map >::iterator iter; - if (check_calibrator_in_statustable(calibratorname)) - { - std::cout << PHWHERE << " the calibrator " << calibratorname << " is unknown to me" << std::endl; - return -1; - } - iter = requiredCalibrators.find(calibratorname); - if (iter != requiredCalibrators.end()) - { - iter->second.insert(reco); - } - else - { - std::set subsys; - subsys.insert(reco); - requiredCalibrators[calibratorname] = subsys; - } - return 0; -} - -int OnCalServer::FindClosestCalibratedRun(const int irun) -{ - RunToTime *rt = RunToTime::instance(); - PHTimeStamp *ts = rt->getBeginTime(irun); - if (!ts) - { - std::cout << PHWHERE << "Unknown Run " << irun << std::endl; - return -1; - } - if (requiredCalibrators.empty()) - { - std::cout << PHWHERE << "No required calibrations given" << std::endl; - return irun; - } - int curstart = ts->getTics(); - delete ts; - ts = rt->getEndTime(irun); - int curend = curstart; - if (ts) - { - curend = ts->getTics(); - delete ts; - } - int closestrun = -1; - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -1; - } - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - std::map >::const_iterator iter; - // look only for runs which were actually successfully calibrated (status = 1) - cmd << "SELECT runnumber,startvaltime,endvaltime FROM " - << successTable << " where runnumber <= " - << irun; - for (iter = requiredCalibrators.begin(); iter != requiredCalibrators.end(); ++iter) - { - cmd << " and " << iter->first << " > 0 "; - } - - cmd << " order by runnumber desc limit 1"; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << successTable << " does not exist" << std::endl; - return -1; - } - int prevrun = 0; - unsigned int prevend = 0; - if (rs->next()) - { - prevrun = rs->getInt("runnumber"); - unsigned int prevstart = rs->getLong("startvaltime"); - prevend = rs->getLong("endvaltime"); - if (prevrun != irun) - { - std::cout << "previous run: " << prevrun - << ", start: " << prevstart - << ", end: " << prevend - << std::endl; - } - } - else - { - std::cout << PHWHERE << " No previous good run found for run " << irun << std::endl; - } - delete rs; - // if the current run fullfills requirements return immediately - if (prevrun == irun) - { - std::cout << "closest run with required calibs is current run: " << irun << std::endl; - return irun; - } - cmd.str(""); - cmd << "SELECT runnumber,startvaltime,endvaltime FROM " - << successTable << " where runnumber > " - << irun; - for (iter = requiredCalibrators.begin(); iter != requiredCalibrators.end(); ++iter) - { - cmd << " and " << iter->first << " > 0 "; - } - - cmd << " order by runnumber asc limit 1"; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << successTable << " does not exist" << std::endl; - return -1; - } - int nextrun = 0; - unsigned int nextstart = 0; - if (rs->next()) - { - nextrun = rs->getInt("runnumber"); - nextstart = rs->getLong("startvaltime"); - unsigned int nextend = rs->getLong("endvaltime"); - std::cout << "next run: " << nextrun - << ", start: " << nextstart - << ", end: " << nextend - << std::endl; - } - else - { - std::cout << PHWHERE << " No next good run found for run " << irun << std::endl; - } - delete rs; - int tdiffprev = curstart - prevend; - int tdiffnext; - if (nextstart > 0) - { - tdiffnext = nextstart - curend; - } - else - { - // just make it larger then previous run time diff - tdiffnext = tdiffprev + 1; - } - if (tdiffprev < tdiffnext) - { - closestrun = prevrun; - } - else - { - closestrun = nextrun; - } - std::cout << "closest run with required calibs: " << closestrun << std::endl; - return closestrun; -} - -int OnCalServer::FillRunListFromFileList() -{ - for (Fun4AllSyncManager *sync : SyncManagers) - { - for (Fun4AllInputManager *inmgr : sync->GetInputManagers()) - { - for (const std::string &infile : inmgr->GetFileList()) - { - std::pair runseg = Fun4AllUtils::GetRunSegment(infile); - runlist.insert(runseg.first); - } - } - } - return 0; -} - -int OnCalServer::AdjustRichTimeStampForMultipleRuns() -{ - int firstrun = *runlist.begin(); - int lastrun = *runlist.rbegin(); - time_t dummy; - time_t beginticks; - time_t endticks; - std::string table = "OnCalRichCal"; - check_create_subsystable(table); - GetRunTimeTicks(firstrun, beginticks, dummy); - GetRunTimeTicks(lastrun, dummy, endticks); - std::ostringstream stringarg; - stringarg << OnCalDBCodes::COVERED; - // std::set::const_iterator runiter; - /* - for (runiter = runlist.begin(); runiter != runlist.end(); runiter++) - { - updateDB(successTable, "RichCal", stringarg.str(), *runiter); - } - stringarg.str(""); - stringarg << OnCalDBCodes::SUCCESS; - - updateDB(successTable, "RichCal", stringarg.str(), firstrun); - */ - odbc::Timestamp stp; - stringarg.str(""); - stringarg << beginticks; - updateDB(table, "startvaltime", stringarg.str(), firstrun); - stp.setTime(beginticks); - updateDB(table, "begintime", stp.toString(), firstrun); - stringarg.str(""); - stringarg << endticks; - updateDB(table, "endvaltime", stringarg.str(), firstrun); - stp.setTime(endticks); - updateDB(table, "endtime", stp.toString(), firstrun); - /* - std::string tablename = "calibrichadc"; - odbc::Connection *con = 0; - std::ostringstream cmd; - try - { - con = odbc::DriverManager::getConnection("oncal", "phnxrc", ""); - } - catch (odbc::SQLException& e) - { - std::cout << "Cannot connect to " << database.c_str() << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - odbc::Statement *stmt = 0; - odbc::Statement *stmtup = 0; - try - { - stmt = con->createStatement(); - stmtup = con->createStatement(); - } - catch (odbc::SQLException& e) - { - std::cout << "Cannot create statement" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - - odbc::ResultSet *rs1 = 0; - cmd.str(""); - cmd << "SELECT endvaltime from " << tablename - << " where bankid = 1 and startvaltime = " << beginticks; - std::cout << "sql cmd: " << cmd.str() << std::endl; - try - { - rs1 = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException& e) - { - std::cout << "Cannot create statement" << std::endl; - std::cout << e.getMessage() << std::endl; - return -1; - } - if (rs1->next()) - { - std::cout << "Endcaltime: " << rs1->getInt("endvaltime") << std::endl; - std::cout << "future endvaltime: " << endticks << std::endl; - cmd.str(""); - cmd << "Update " << tablename - << " set endvaltime = " << endticks - << " where bankid = 1 and startvaltime = " - << beginticks; - stmtup->executeUpdate(cmd.str()); - - } - else - { - std::cout << "Could not find startvaltime " << beginticks - << "from run " << firstrun << std::endl; - } - - */ - - return 0; -} - -int OnCalServer::GetCalibStatus(const std::string &calibname, const int runno) -{ - int iret = -3; - if (!connectDB()) - { - std::cout << "could not connect to " << database << std::endl; - return -4; - } - odbc::Statement *stmt = DBconnection->createStatement(); - std::ostringstream cmd; - - // look only for runs which were actually successfully calibrated (status = 1) - cmd << "SELECT " << calibname << " FROM " - << successTable << " where runnumber = " - << runno; - std::cout << "exec " << cmd.str() << std::endl; - odbc::ResultSet *rs = nullptr; - try - { - rs = stmt->executeQuery(cmd.str()); - } - catch (odbc::SQLException &e) - { - std::cout << "Table " << successTable << " does not exist" << std::endl; - return -5; - } - if (rs->next()) - { - iret = rs->getInt(calibname); - } - else - { - std::cout << PHWHERE << " No calib status for " << calibname - << " for " << runno << std::endl; - } - delete rs; - return iret; -} - -void OnCalServer::TestMode(const int i) -{ - const char *logname = getenv("LOGNAME"); - if (logname) - { - if (strcmp(logname, "sphnxpro") == 0 || strcmp(logname, "anatrain") == 0) - { - std::cout << "phnxcal,anatrain account is not allowed to run in testmode" << std::endl; - } - else - { - testmode = i; - } - } - else - { - std::cout << "could not get account via env var LOGNAME, not setting testmode" << std::endl; - } - return; -} diff --git a/calibrations/framework/oncal/OnCalServer.h b/calibrations/framework/oncal/OnCalServer.h deleted file mode 100644 index 890901207c..0000000000 --- a/calibrations/framework/oncal/OnCalServer.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef ONCAL_ONCALSERVER_H -#define ONCAL_ONCALSERVER_H - -#include -#include - -#include // for time_t -#include -#include -#include -#include - -class OnCal; -class SubsysReco; -class TH1; - -namespace fetchrun -{ - enum - { - CLOSEST, - PREVIOUS - }; -}; - -class OnCalServer : public Fun4AllServer -{ - public: - static OnCalServer *instance(); - ~OnCalServer() override; - using Fun4AllServer::registerHisto; - void registerHisto(TH1 *h1d, OnCal *Calibrator, const int replace = 0); - void unregisterHisto(const std::string &calibratorname); - void Print(const std::string &what = "ALL") const override; - - void dumpHistos(); - int process_event() override; - int BeginRun(const int runno) override; - int EndRun(const int /*runno*/) override { return 0; } // do not execute EndRun - int End() override; - - PHTimeStamp *GetEndValidityTS(); - - PHTimeStamp *GetBeginValidityTS(); - void printStamps(); - PHTimeStamp *GetLastGoodRunTS(OnCal *calibrator, const int irun); - - void recordDataBase(const bool bookkeep = false); - - // RunNumber() tells the server which run is being analyzed. - // and if recordDB is true, this will insert the run number in - // calprocess_stat table in calBookKeep database. - // All updates are made to the row in the database containing this runNum. - // Note that the run number is the primary key in the tables. - // If calBookKeep database is not to be updated, this function - // should not be called. - void RunNumber(const int runnum); - int RunNumber() const { return runNum; } - - void BeginTimeStamp(const PHTimeStamp &TimeStp); - void EndTimeStamp(const PHTimeStamp &TimeStp); - - int SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const std::string &table, const int commit = 0); - int SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const int commit = 0); - int SyncOncalTimeStampsToRunDB(const int commit = 0); - int ClosestGoodRun(OnCal *calibrator, const int irun, const int previous = fetchrun::CLOSEST); - static int CopyTables(const OnCal *calibrator, const int FromRun, const int ToRun, const int commit = 0); - static int OverwriteCalibration(OnCal *calibrator, const int runno, const int commit = 0, const int fromrun = -1); - int FixMissingCalibration(OnCal *calibrator, const int runno, const int commit = 0, const int fromrun = -1); - - int SetBorTime(const int runno); - int SetEorTime(const int runno); - int requiredCalibration(SubsysReco *reco, const std::string &calibratorname); - int FindClosestCalibratedRun(const int irun); - int FillRunListFromFileList(); - int AdjustRichTimeStampForMultipleRuns(); - int CreateCalibration(OnCal *calibrator, const int myrunnumber, const std::string &what, const int commit = 0); - int GetCalibStatus(const std::string &calibname, const int runno); - static int DisconnectDB(); - void TestMode(const int i = 1); - // need to be able to call this from the outside - bool updateDBRunRange(const std::string &table, const std::string &column, const int entry, const int firstrun, const int lastrun); - void EventCheckFrequency(const unsigned int i) { eventcheckfrequency = i; } - - protected: - //------------------------------------- - // following functions access DB using odbc++ library - // these are designed to insert status in calBookKeep (or success) database. - // setDB() sets the name of the database to connect to. e.g., calibration - // this database should exist in the odbc.ini file. - // void setDB(const char* DBname){database = DBname;} - bool connectDB(); - - // insertRunNumInDB enters the run number in the calBookKeep database. - // All other updates are made to rows in the database containing the runNum. - // This function should be called before any updates are made. - // Returns true on successful DB insert. - bool insertRunNumInDB(const std::string &DBtable, const int runno); - - bool findRunNumInDB(const std::string &DBtable, const int runno); - - // these functions update different columns in the success database tables. - // Ony the row with the run number set by setRunNum() is updated. - - bool updateDB(const std::string &table, const std::string &column, int entry); - bool updateDB(const std::string &table, const std::string &column, bool entry); - bool updateDB(const std::string &table, const std::string &column, const std::string &entry, - const int runno, const bool append = false); - int updateDB(const std::string &table, const std::string &column, const time_t ticks); - - int check_create_subsystable(const std::string &tablename); - int check_create_successtable(const std::string &tablename); - int add_calibrator_to_statustable(const std::string &calibratorname); - int check_calibrator_in_statustable(const std::string &calibratorname); - static int GetRunTimeTicks(const int runno, time_t &borticks, time_t &eorticks); - void CreateCalibrationUpdateStatus(OnCal *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode); - OnCalServer(const std::string &name = "OnCalServer"); - PHTimeStamp beginTimeStamp; // begin run timestamp of run analysing - PHTimeStamp endTimeStamp; // end run timestamp of run analysing - int testmode{0}; - bool recordDB{false}; - TH1 *OnCalServerVars{nullptr}; - std::map Histo; - std::map > calibratorhistomap; - bool SetEndTimeStampByHand{false}; - bool SetBeginTimeStampByHand{false}; - - std::string successTable; - unsigned int runNum{0}; - unsigned int nEvents{0}; - unsigned int eventcheckfrequency{1000}; - std::string database{"calBookKeep"}; // this holds the name of the database - // should be set to calibrations for normal running - std::map > requiredCalibrators; - std::vector analysed_runs; - std::vector inputfilelist; - std::set runlist; -}; - -#endif /* __ONCALSERVER_H */ diff --git a/calibrations/framework/oncal/autogen.sh b/calibrations/framework/oncal/autogen.sh deleted file mode 100755 index dea267bbfd..0000000000 --- a/calibrations/framework/oncal/autogen.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ -libtoolize --force; automake -a --add-missing; autoconf) - -$srcdir/configure "$@" diff --git a/calibrations/framework/oncal/configure.ac b/calibrations/framework/oncal/configure.ac deleted file mode 100644 index e5467a38b0..0000000000 --- a/calibrations/framework/oncal/configure.ac +++ /dev/null @@ -1,16 +0,0 @@ -AC_INIT(oncal,[2.00]) -AC_CONFIG_SRCDIR([configure.ac]) - -AM_INIT_AUTOMAKE - -AC_PROG_CXX(CC g++) - -LT_INIT([disable-static]) - -dnl no point in suppressing warnings people should -dnl at least see them, so here we go for g++: -Wall -if test $ac_cv_prog_gxx = yes; then - CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" -fi - -AC_OUTPUT(Makefile) From dfe01e0187ff9d1492c33ac0890b8e81b328ad7e Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 6 Feb 2026 10:44:52 -0500 Subject: [PATCH 190/866] Changes to fix issues identified by coderabbit and clang-tidy --- offline/packages/tpc/LaserClusterizer.cc | 39 +++++++++++-------- .../tpccalib/TpcCentralMembraneMatching.cc | 9 +++-- .../tpccalib/TpcCentralMembraneMatching.h | 7 ++++ .../packages/tpccalib/TpcLaminationFitting.cc | 12 +++--- .../packages/tpccalib/TpcLaminationFitting.h | 11 +++++- 5 files changed, 51 insertions(+), 27 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 8ffaa10433..a875747201 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -47,6 +47,7 @@ #include #include #include // for _Rb_tree_cons... +#include #include #include #include @@ -145,7 +146,7 @@ namespace return par[0] * g * cdf; } - void splitWeaklyConnectedRegion(const std::vector ®ion, std::vector> &outputRegions) + void splitWeaklyConnectedRegion(const std::vector ®ion, std::vector> &outputRegions, int aVerbosity) { int N = region.size(); std::vector> adj(N); @@ -153,7 +154,7 @@ namespace { for(int j=i+1; j() + neigh.get<0>() - region[j].first.get<0>()) < 0.01 && fabs(region[i].first.get<1>() + neigh.get<1>() - region[j].first.get<1>()) < 0.01 && @@ -167,9 +168,11 @@ namespace } } - std::cout << " constructed adjacency list, average degree = " << std::accumulate(adj.begin(), adj.end(), 0.0, [](double s, auto &v) { return s + v.size(); }) / N << ")" << std::endl; + if(aVerbosity > 3) std::cout << " constructed adjacency list, average degree = " << std::accumulate(adj.begin(), adj.end(), 0.0, [](double s, auto &v) { return s + v.size(); }) / N << ")" << std::endl; - std::vector disc(N, -1), low(N, -1), parent(N, -1); + std::vector disc(N, -1); + std::vector low(N, -1); + std::vector parent(N, -1); std::vector> bridges; int time=0; @@ -200,7 +203,7 @@ namespace if(disc[i] == -1) dfs(i); } - std::cout << " Found " << bridges.size() << " bridges in region of size " << N << std::endl; + if(aVerbosity > 2) std::cout << " Found " << bridges.size() << " bridges in region of size " << N << std::endl; std::vector> adj2 = adj; int removed = 0; @@ -211,11 +214,11 @@ namespace adj2[u].erase(std::remove(adj2[u].begin(), adj2[u].end(), v), adj2[u].end()); adj2[v].erase(std::remove(adj2[v].begin(), adj2[v].end(), u), adj2[v].end()); removed++; - std::cout << " removed weak bridge between nodes " << u << " (deg = " << adj[u].size() << ") and " << v << " (deg = " << adj[v].size() << ")" << std::endl; + if(aVerbosity > 3) std::cout << " removed weak bridge between nodes " << u << " (deg = " << adj[u].size() << ") and " << v << " (deg = " << adj[v].size() << ")" << std::endl; } } - std::cout << " Removed " << removed << " weak bridges, now finding connected components" << std::endl; + if(aVerbosity > 3) std::cout << " Removed " << removed << " weak bridges, now finding connected components" << std::endl; std::vector visited(N, false); for(int i=0; i 3) std::cout << " found subregion of size " << sub.size() << std::endl; } - std::cout << " finished splitting region into " << outputRegions.size() << " subregions" << std::endl; + if(aVerbosity > 2) std::cout << " finished splitting region into " << outputRegions.size() << " subregions" << std::endl; } - void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey) + void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey, int aVerbosity) { std::vector> regions; @@ -307,22 +310,22 @@ namespace regions.push_back(region); } - std::cout << "finished with normal region finding, now splitting weakly connected regions" << std::endl; + if(aVerbosity > 2) std::cout << "finished with normal region finding, now splitting weakly connected regions" << std::endl; std::vector> refinedRegions; int regionNum = 0; for(auto ®ion : regions) { std::vector> tmpRefinedRegions; - std::cout << "starting to split region " << regionNum << " with " << region.size() << " hits" << std::endl; + if(aVerbosity > 2) std::cout << "starting to split region " << regionNum << " with " << region.size() << " hits" << std::endl; regionNum++; - splitWeaklyConnectedRegion(region, tmpRefinedRegions); - std::cout << "finished splitting region into " << tmpRefinedRegions.size() << std::endl; + splitWeaklyConnectedRegion(region, tmpRefinedRegions, aVerbosity); + if(aVerbosity > 2) std::cout << "finished splitting region into " << tmpRefinedRegions.size() << std::endl; for(auto &subregion : tmpRefinedRegions) { refinedRegions.push_back(subregion); } - std::cout << "total refined regions so far: " << refinedRegions.size() << std::endl; + if(aVerbosity > 2) std::cout << "total refined regions so far: " << refinedRegions.size() << std::endl; } std::sort(refinedRegions.begin(), refinedRegions.end(), [&](const auto &a, const auto &b) @@ -353,6 +356,10 @@ namespace }); clusHits.clear(); + if(refinedRegions[0].size() == 0) + { + return; + } for(auto hit : refinedRegions[0]) { clusHits.push_back(hit); @@ -382,7 +389,7 @@ namespace void calc_cluster_parameter(std::vector &clusHits, thread_data &my_data, std::pair maxADCKey) { - findConnectedRegions3(clusHits, maxADCKey); + findConnectedRegions3(clusHits, maxADCKey, my_data.Verbosity); double rSum = 0.0; double phiSum = 0.0; diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index 2e85f78a0c..aae5dbc901 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -1093,7 +1093,7 @@ int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) // Get truth cluster positions //===================== - CDBTTree *cdbttree = new CDBTTree("/sphenix/u/bkimelman/CMStripePattern.root"); + CDBTTree *cdbttree = new CDBTTree(m_stripePatternFile); cdbttree->LoadCalibrations(); auto cdbMap = cdbttree->GetDoubleEntryMap(); for (const auto &[index, values] : cdbMap) @@ -2196,7 +2196,7 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) dr = static_pos[reco_index].Perp() - m_truth_pos[i].Perp(); dphi = delta_phi(static_pos[reco_index].Phi() - m_truth_pos[i].Phi()); } - if(m_totalDistMode) + else if(m_totalDistMode) { clus_r = raw_pos[reco_index].Perp(); clus_phi = raw_pos[reco_index].Phi(); @@ -2540,7 +2540,8 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) for (int s = 0; s < 2; s++) { int N = gr_dR[s]->GetN(); - std::vector dataX(N), dataY(N); + std::vector dataX(N); + std::vector dataY(N); double minR = 99.0; double maxR = 0.0; @@ -2555,7 +2556,7 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) { gr_dR_toInterp[s]->RemovePoint(i); gr_dPhi_toInterp[s]->RemovePoint(i); - gr_points[s]->RemovePoint(i); + //gr_points[s]->RemovePoint(i); break; } } diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.h b/offline/packages/tpccalib/TpcCentralMembraneMatching.h index 2c2bce46b8..ef5ba5e600 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.h +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.h @@ -119,6 +119,11 @@ class TpcCentralMembraneMatching : public SubsysReco m_event_index = 100 * seq; } + void set_stripePatternFile(std::string stripePatternFile) + { + m_stripePatternFile = stripePatternFile; + } + // void set_laminationFile(const std::string& filename) //{ // m_lamfilename = filename; @@ -212,6 +217,8 @@ class TpcCentralMembraneMatching : public SubsysReco TTree *match_tree{nullptr}; TTree *event_tree{nullptr}; + std::string m_stripePatternFile = "/sphenix/u/bkimelman/CMStripePattern.root"; + bool m_useHeader{true}; bool m_averageMode{false}; bool m_totalDistMode{false}; diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index acf2604125..f6d09275a9 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -184,7 +184,7 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) } } */ - CDBTTree *cdbttree = new CDBTTree("/sphenix/u/bkimelman/CMStripePattern.root"); + CDBTTree *cdbttree = new CDBTTree(m_stripePatternFile); cdbttree->LoadCalibrations(); auto cdbMap = cdbttree->GetDoubleEntryMap(); for (const auto &[index, values] : cdbMap) @@ -200,6 +200,11 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) m_truthPhi[1].push_back(cdbttree->GetDoubleValue(index, "truthPhi")); } } + if(m_truthR[0].size() == 0 || m_truthPhi[0].size() == 0 || m_truthR[1].size() == 0 || m_truthPhi[1].size() == 0) + { + std::cerr << "stripe pattern file passed has no stripes on one side. Exiting" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } /* for(int i=0; i<32; i++) { @@ -836,7 +841,6 @@ int TpcLaminationFitting::doGlobalRMatching(int side) { double meanA = 0.0; double meanC = 0.0; - double meanOffset = 0.0; int nGoodFits = 0; for(int l = 0; l < 18; l++) { @@ -847,7 +851,6 @@ int TpcLaminationFitting::doGlobalRMatching(int side) meanA += m_fLamination[l][side]->GetParameter(0); meanB += m_fLamination[l][side]->GetParameter(1); meanC += m_fLamination[l][side]->GetParameter(2); - meanOffset += m_laminationOffset[l][side]; nGoodFits++; } if(nGoodFits == 0) @@ -858,7 +861,6 @@ int TpcLaminationFitting::doGlobalRMatching(int side) meanA /= nGoodFits; meanB /= nGoodFits; meanC /= nGoodFits; - meanOffset /= nGoodFits; //tmpLamFit->SetParameters(meanA, meanB, meanC, meanOffset); tmpLamFit->SetParameters(meanA, meanB, meanC, 0.0); } @@ -1188,7 +1190,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) phiDistortionLamination[s]->Write(); //scaleFactorMap[s]->Write(); m_hPetal[s]->Write(); - m_bestRMatch[s]->Write(); + if(m_bestRMatch[s]) m_bestRMatch[s]->Write(); m_parameterScan[s]->Write(); } m_laminationTree->Write(); diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 44e8b56868..86c0448f00 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -43,6 +43,11 @@ class TpcLaminationFitting : public SubsysReco m_QAFileName = QAFileName; } + void set_stripePatternFile(std::string stripePatternFile) + { + m_stripePatternFile = stripePatternFile; + } + void set_ppMode(bool mode){ ppMode = mode; } void set_fieldOff(bool fieldOff){ m_fieldOff = fieldOff; } @@ -98,7 +103,7 @@ class TpcLaminationFitting : public SubsysReco TH2 *phiDistortionLamination[2]{nullptr}; - TH2 *scaleFactorMap[2]{nullptr}; + //TH2 *scaleFactorMap[2]{nullptr}; unsigned int m_nLayerCut{1}; @@ -115,7 +120,9 @@ class TpcLaminationFitting : public SubsysReco double m_ZDC_coincidence{0}; //std::map m_run_ZDC_map_pp; //std::map m_run_ZDC_map_auau; - + + std::string m_stripePatternFile = "/sphenix/u/bkimelman/CMStripePattern.root"; + bool m_fieldOff{false}; TTree *m_laminationTree{nullptr}; From 26c30d88a24d279c464587dfc5028fbbec6931b4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 6 Feb 2026 10:55:45 -0500 Subject: [PATCH 191/866] remove dependency on liboncal --- calibrations/xingshift/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calibrations/xingshift/Makefile.am b/calibrations/xingshift/Makefile.am index 81ea4dbca4..08c0220b6b 100644 --- a/calibrations/xingshift/Makefile.am +++ b/calibrations/xingshift/Makefile.am @@ -23,9 +23,9 @@ libXingShiftCal_la_SOURCES = \ libXingShiftCal_la_LIBADD = \ -lcdbobjects \ -lfun4all \ + -lfun4cal \ -lphool \ - -lSubsysReco \ - -loncal + -lSubsysReco BUILT_SOURCES = testexternals.cc From 29702424b82425068a93f50429329862be50cce2 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 6 Feb 2026 11:59:08 -0500 Subject: [PATCH 192/866] More changes to appease clang-tidy and cppcheck in addition to some coderabbit suggestions --- offline/packages/tpc/LaserClusterizer.cc | 66 +++++++++++++++---- .../tpccalib/TpcCentralMembraneMatching.cc | 23 ++++--- .../tpccalib/TpcCentralMembraneMatching.h | 2 +- .../packages/tpccalib/TpcLaminationFitting.cc | 25 ++++--- .../packages/tpccalib/TpcLaminationFitting.h | 2 +- 5 files changed, 84 insertions(+), 34 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index a875747201..177cd6fc5f 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -149,6 +149,7 @@ namespace void splitWeaklyConnectedRegion(const std::vector ®ion, std::vector> &outputRegions, int aVerbosity) { int N = region.size(); + /* std::vector> adj(N); for(int i=0; i, int> coordIndex; + for(int i=0; i(std::round(region[i].first.get<0>())); + int p = static_cast(std::round(region[i].first.get<1>())); + int t = static_cast(std::round(region[i].first.get<2>())); + coordIndex[{l,p,t}] = i; + } + std::vector> adj(N); + for(int i=0; i(std::round(region[i].first.get<0>())); + int p = static_cast(std::round(region[i].first.get<1>())); + int t = static_cast(std::round(region[i].first.get<2>())); + for(const auto &neigh : neighborOffsets) + { + int nl = l + static_cast(neigh.get<0>()); + int np = p + static_cast(neigh.get<1>()); + int nt = t + static_cast(neigh.get<2>()); + auto it = coordIndex.find[{nl,np,nt}]; + if(it != coordIndex.end()) + { + adj[i].push_back(it.second); + } + } + } - if(aVerbosity > 3) std::cout << " constructed adjacency list, average degree = " << std::accumulate(adj.begin(), adj.end(), 0.0, [](double s, auto &v) { return s + v.size(); }) / N << ")" << std::endl; + if(aVerbosity > 3) { std::cout << " constructed adjacency list, average degree = " << std::accumulate(adj.begin(), adj.end(), 0.0, [](double s, auto &v) { return s + v.size(); }) / N << ")" << std::endl; +} std::vector disc(N, -1); std::vector low(N, -1); @@ -200,10 +229,12 @@ namespace for(int i=0; i 2) std::cout << " Found " << bridges.size() << " bridges in region of size " << N << std::endl; + if(aVerbosity > 2) { std::cout << " Found " << bridges.size() << " bridges in region of size " << N << std::endl; +} std::vector> adj2 = adj; int removed = 0; @@ -214,16 +245,19 @@ namespace adj2[u].erase(std::remove(adj2[u].begin(), adj2[u].end(), v), adj2[u].end()); adj2[v].erase(std::remove(adj2[v].begin(), adj2[v].end(), u), adj2[v].end()); removed++; - if(aVerbosity > 3) std::cout << " removed weak bridge between nodes " << u << " (deg = " << adj[u].size() << ") and " << v << " (deg = " << adj[v].size() << ")" << std::endl; + if(aVerbosity > 3) { std::cout << " removed weak bridge between nodes " << u << " (deg = " << adj[u].size() << ") and " << v << " (deg = " << adj[v].size() << ")" << std::endl; +} } } - if(aVerbosity > 3) std::cout << " Removed " << removed << " weak bridges, now finding connected components" << std::endl; + if(aVerbosity > 3) { std::cout << " Removed " << removed << " weak bridges, now finding connected components" << std::endl; +} std::vector visited(N, false); for(int i=0; i sub; std::queue q; q.push(i); @@ -243,9 +277,11 @@ namespace } } outputRegions.push_back(sub); - if(aVerbosity > 3) std::cout << " found subregion of size " << sub.size() << std::endl; + if(aVerbosity > 3) { std::cout << " found subregion of size " << sub.size() << std::endl; +} } - if(aVerbosity > 2) std::cout << " finished splitting region into " << outputRegions.size() << " subregions" << std::endl; + if(aVerbosity > 2) { std::cout << " finished splitting region into " << outputRegions.size() << " subregions" << std::endl; +} } void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey, int aVerbosity) @@ -310,22 +346,26 @@ namespace regions.push_back(region); } - if(aVerbosity > 2) std::cout << "finished with normal region finding, now splitting weakly connected regions" << std::endl; + if(aVerbosity > 2) { std::cout << "finished with normal region finding, now splitting weakly connected regions" << std::endl; +} std::vector> refinedRegions; int regionNum = 0; for(auto ®ion : regions) { std::vector> tmpRefinedRegions; - if(aVerbosity > 2) std::cout << "starting to split region " << regionNum << " with " << region.size() << " hits" << std::endl; + if(aVerbosity > 2) { std::cout << "starting to split region " << regionNum << " with " << region.size() << " hits" << std::endl; +} regionNum++; splitWeaklyConnectedRegion(region, tmpRefinedRegions, aVerbosity); - if(aVerbosity > 2) std::cout << "finished splitting region into " << tmpRefinedRegions.size() << std::endl; + if(aVerbosity > 2) { std::cout << "finished splitting region into " << tmpRefinedRegions.size() << std::endl; +} for(auto &subregion : tmpRefinedRegions) { refinedRegions.push_back(subregion); } - if(aVerbosity > 2) std::cout << "total refined regions so far: " << refinedRegions.size() << std::endl; + if(aVerbosity > 2) { std::cout << "total refined regions so far: " << refinedRegions.size() << std::endl; +} } std::sort(refinedRegions.begin(), refinedRegions.end(), [&](const auto &a, const auto &b) @@ -356,7 +396,7 @@ namespace }); clusHits.clear(); - if(refinedRegions[0].size() == 0) + if(refinedRegions.empty() || refinedRegions[0].empty()) { return; } diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index aae5dbc901..2cb4942994 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -2474,7 +2474,7 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) bc = hPeaks->GetBinContent(i); if(bc > 10 && bc > pbc) { - if(peakBins.size() == 0 || i > peakBins[peakBins.size()-1] + 1) + if(peakBins.empty() || i > peakBins[peakBins.size()-1] + 1) { peakBins.push_back(i); } @@ -2508,9 +2508,10 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) for(int i=0; i<(int)peakVals.size(); i++) { f1->SetParameters(hPeaks->GetBinContent(hPeaks->FindBin(peakVals[i])),peakVals[i],0.2); - if(i == 0) hPeaks->Fit(f1,"Q","",peakVals[i]-0.5,(peakVals[i]+peakVals[i+1])/2); - else if (i<(int)peakVals.size()-1) hPeaks->Fit(f1,"Q","",(peakVals[i-1]+peakVals[i])/2,(peakVals[i]+peakVals[i+1])/2); - else hPeaks->Fit(f1,"Q","",(peakVals[i-1]+peakVals[i])/2,peakVals[i]+1); + double lo = (i == 0) ? peakVals[i] - 0.5 : (peakVals[i-1] + peakVals[i])/2.0; + double hi = (i < (int)peakVals.size() - 1) ? (peakVals[i] + peakVals[i+1])/2.0 : peakVals[i] + 1.0; + hPeaks->Fit(f1,"Q","",lo,hi); + mu.push_back(f1->GetParameter(1)); sig.push_back(f1->GetParameter(2)); } @@ -2570,8 +2571,8 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) dataX[k] = RVal*cos(gr_dR[s]->GetX()[k]); dataY[k] = RVal*sin(gr_dR[s]->GetX()[k]); - if(RVal < minR) minR = RVal; - if(RVal > maxR) maxR = RVal; + minR = std::min(RVal, minR); + maxR = std::max(RVal, maxR); } //bool firstGoodR = false; @@ -2581,7 +2582,8 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) double Rlow = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinLowEdge(j); double Rhigh = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinLowEdge(j + 1); - if(Rhigh < minR || Rlow > maxR) continue; + if(Rhigh < minR || Rlow > maxR) { continue; +} /* if (!firstGoodR) @@ -2617,9 +2619,9 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) bool skipPoint = false; if(m_skipOutliers) { - for(int l=0; l<(int)pointsToSkip[s].size(); l++) + for(int l : pointsToSkip[s]) { - if(k == pointsToSkip[s][l]) + if(k == l) { skipPoint = true; break; @@ -2636,7 +2638,8 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) double dy = hY - dataY[k]; double distSq = (dx*dx) + (dy*dy); - if(distSq > 100.0) continue; + if(distSq > 100.0) { continue; +} if(distSq < 1e-9) { diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.h b/offline/packages/tpccalib/TpcCentralMembraneMatching.h index ef5ba5e600..cdde093629 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.h +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.h @@ -119,7 +119,7 @@ class TpcCentralMembraneMatching : public SubsysReco m_event_index = 100 * seq; } - void set_stripePatternFile(std::string stripePatternFile) + void set_stripePatternFile(const std::string &stripePatternFile) { m_stripePatternFile = stripePatternFile; } diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index f6d09275a9..2eaf6fcf4c 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -200,7 +200,7 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) m_truthPhi[1].push_back(cdbttree->GetDoubleValue(index, "truthPhi")); } } - if(m_truthR[0].size() == 0 || m_truthPhi[0].size() == 0 || m_truthR[1].size() == 0 || m_truthPhi[1].size() == 0) + if(m_truthR[0].empty() || m_truthPhi[0].empty() || m_truthR[1].empty() || m_truthPhi[1].empty()) { std::cerr << "stripe pattern file passed has no stripes on one side. Exiting" << std::endl; return Fun4AllReturnCodes::ABORTRUN; @@ -695,8 +695,9 @@ int TpcLaminationFitting::fitLaminations() m_distanceToFit[l][s] = distToFunc / nBinsUsed; m_nBinsFit[l][s] = nBinsUsed; - if(c>0) m_fitRMSE[l][s] = sqrt(wc / c); - else m_fitRMSE[l][s] = -999; + if(c>0) { m_fitRMSE[l][s] = sqrt(wc / c); + } else { m_fitRMSE[l][s] = -999; +} if (nBinsUsed < 10 || distToFunc / nBinsUsed > 1.0 || nBinsUsed_R_lt_45 < 5) { m_laminationGoodFit[l][s] = false; @@ -903,7 +904,8 @@ int TpcLaminationFitting::doGlobalRMatching(int side) for(int j=-2; j<=2; j++) { int neighborBinR = binR + j; - if(neighborBinR < 1 || neighborBinR > m_hPetal[side]->GetNbinsY()) continue; + if(neighborBinR < 1 || neighborBinR > m_hPetal[side]->GetNbinsY()) { continue; +} for(int k=-5; k<=5; k++) { int neighborBinPhi = binPhi + k; @@ -919,7 +921,11 @@ int TpcLaminationFitting::doGlobalRMatching(int side) } } } - std::cout << "working on side " << side << " m step " << xbin-1 << " b step " << ybin-1 << " with m = " << m << " and b = " << b << " with sum = " << sum << std::endl; + + if(Verbosity() > 2) + { + std::cout << "working on side " << side << " m step " << xbin-1 << " b step " << ybin-1 << " with m = " << m << " and b = " << b << " with sum = " << sum << std::endl; + } m_parameterScan[side]->Fill(m, b, sum); @@ -947,13 +953,13 @@ int TpcLaminationFitting::doGlobalRMatching(int side) } std::vector bestDistortedR; - for(int i=0; i<(int)m_truthR[side].size(); i++) + for(double i : m_truthR[side]) { - double distortedR = (m_truthR[side][i] + best_b)/(1.0 - best_m); + double distortedR = (i + best_b)/(1.0 - best_m); bestDistortedR.push_back(distortedR); } - m_bestRMatch[side] = new TGraph(distortedPhi.size(), &distortedPhi[0], &bestDistortedR[0]); + m_bestRMatch[side] = new TGraph(distortedPhi.size(), distortedPhi.data(), bestDistortedR.data()); m_bestRMatch[side]->SetTitle((boost::format("Best R matching TPC %s, m = %.3f b = %.3f") %(side == 0 ? "South" : "North") %best_m %best_b).str().c_str()); m_bestRMatch[side]->SetName((boost::format("bestRMatch_side%d") %side).str().c_str()); m_bestRMatch[side]->SetMarkerStyle(25); @@ -1190,7 +1196,8 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) phiDistortionLamination[s]->Write(); //scaleFactorMap[s]->Write(); m_hPetal[s]->Write(); - if(m_bestRMatch[s]) m_bestRMatch[s]->Write(); + if(m_bestRMatch[s]) { m_bestRMatch[s]->Write(); +} m_parameterScan[s]->Write(); } m_laminationTree->Write(); diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 86c0448f00..561a9ab199 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -43,7 +43,7 @@ class TpcLaminationFitting : public SubsysReco m_QAFileName = QAFileName; } - void set_stripePatternFile(std::string stripePatternFile) + void set_stripePatternFile(const std::string &stripePatternFile) { m_stripePatternFile = stripePatternFile; } From 54c8a9eda7c85ed830305b4448cb65efa73ff376 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 6 Feb 2026 12:06:05 -0500 Subject: [PATCH 193/866] Fixed issue with brackets instead of parentheses --- offline/packages/tpc/LaserClusterizer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 177cd6fc5f..3d9d1ca2e5 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -188,7 +188,7 @@ namespace int nl = l + static_cast(neigh.get<0>()); int np = p + static_cast(neigh.get<1>()); int nt = t + static_cast(neigh.get<2>()); - auto it = coordIndex.find[{nl,np,nt}]; + auto it = coordIndex.find({nl,np,nt}); if(it != coordIndex.end()) { adj[i].push_back(it.second); From 4dfbee8874259f8c65b43ada8fc5e678d96604a4 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 6 Feb 2026 12:07:09 -0500 Subject: [PATCH 194/866] Fixed pointer issue --- offline/packages/tpc/LaserClusterizer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 3d9d1ca2e5..cea92afe11 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -191,7 +191,7 @@ namespace auto it = coordIndex.find({nl,np,nt}); if(it != coordIndex.end()) { - adj[i].push_back(it.second); + adj[i].push_back(it->second); } } } From f310306304826443ee4e2d8217fbd4c1efcd70f1 Mon Sep 17 00:00:00 2001 From: Antonio Silva Date: Fri, 6 Feb 2026 12:22:44 -0500 Subject: [PATCH 195/866] Fix to the cluster key init --- offline/packages/trackbase_historic/SvtxTrackState_v3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackbase_historic/SvtxTrackState_v3.h b/offline/packages/trackbase_historic/SvtxTrackState_v3.h index 8f32d0e872..a29bd179ca 100644 --- a/offline/packages/trackbase_historic/SvtxTrackState_v3.h +++ b/offline/packages/trackbase_historic/SvtxTrackState_v3.h @@ -78,7 +78,7 @@ class SvtxTrackState_v3 : public SvtxTrackState float _pos[3]{}; float _mom[3]{}; float _covar[21]{}; // 6x6 triangular packed storage - TrkrDefs::cluskey _ckey{}; // clusterkey that is associated with this state + TrkrDefs::cluskey _ckey{std::numeric_limits::max()}; // clusterkey that is associated with this state std::string state_name; ClassDefOverride(SvtxTrackState_v3, 1) From 494b21b830d682437c6ccc3e7a1a878be097844c Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:41:26 -0500 Subject: [PATCH 196/866] RunnumberRange - O+O - Update the first and last runnumbers for Run 3 O+O. --- offline/framework/phool/RunnumberRange.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index 2c809f2fb9..0a447f259b 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -15,8 +15,8 @@ * @var RUN3AUAU_LAST Last Run 3 Au+Au (heavy-ion) physics run. * @var RUN3PP_FIRST First Run 3 proton-proton (beam) physics run. * @var RUN3PP_LAST Last Run 3 proton-proton physics run. - * @var RUN3OO_FIRST Temporary placeholder for the first Run 3 OO run (to be updated once OO starts). - * @var RUN3OO_LAST Temporary upper bound for Run 3 OO runs. + * @var RUN3OO_FIRST First Run 3 O+O physics run. + * @var RUN3OO_LAST Last Run 3 O+O physics run. */ namespace RunnumberRange { @@ -29,8 +29,8 @@ namespace RunnumberRange static const int RUN3AUAU_LAST = 78954; static const int RUN3PP_FIRST = 79146; // first beam data static const int RUN3PP_LAST = 81668; - static const int RUN3OO_FIRST = 82300; // TEMP (to be updated once OO starts) - static const int RUN3OO_LAST = 200000; + static const int RUN3OO_FIRST = 82374; + static const int RUN3OO_LAST = 82703; } #endif From 00ecb7f952ed535bec20cb1cdde6f8807bfd790d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 6 Feb 2026 17:13:45 -0500 Subject: [PATCH 197/866] replace Form or boost::format with std::format --- .../packages/tpccalib/TpcLaminationFitting.cc | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 2eaf6fcf4c..cc811e8e90 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -1033,18 +1033,18 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) { lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); lineIdeal->SetLineColor(kBlue); - leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); + leg->AddEntry(lineIdeal,std::format("#phi_{{ideal}}={:.6f}",m_laminationIdeal[l][s]).c_str(), "l"); } else { lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); lineIdeal->SetLineColor(kBlue); - leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); + leg->AddEntry(lineIdeal,std::format("#phi_{{ideal}}={:.6f}",m_laminationIdeal[l][s]).c_str(), "l"); lineOffset = new TLine(30,m_laminationIdeal[l][s]+m_laminationOffset[l][s],80,m_laminationIdeal[l][s]+m_laminationOffset[l][s]); lineOffset->SetLineColor(kGreen+2); lineOffset->SetLineStyle(2); - leg->AddEntry(lineOffset,Form("#phi_{ideal}+#phi_{offset}=%.6f",m_laminationOffset[l][s]), "l"); + leg->AddEntry(lineOffset,std::format("#phi_{{ideal}}+#phi_{{offset}}={:.6f}",m_laminationOffset[l][s]).c_str(), "l"); lineOffset->Draw("same"); } lineIdeal->Draw("same"); @@ -1054,27 +1054,27 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) TPaveText *pars = new TPaveText(0.6, 0.55, 0.85, 0.85, "NDC"); - if(m_fieldOff) - { - pars->AddText("#phi = #phi_{ideal} + #phi_{offset}"); - pars->AddText((boost::format("#phi_{ideal}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(1) %m_fLamination[l][s]->GetParError(1)).str().c_str()); - pars->AddText((boost::format("#phi_{offset}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); - pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); - pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); - pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); - } + if(m_fieldOff) + { + pars->AddText("#phi = #phi_{ideal} + #phi_{offset}"); + pars->AddText(std::format("#phi_{{ideal}}={:.3f}#pm {:.3f}",m_fLamination[l][s]->GetParameter(1), m_fLamination[l][s]->GetParError(1)).c_str()); + pars->AddText(std::format("#phi_{{offset}}={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(0), m_fLamination[l][s]->GetParError(0)).c_str()); + pars->AddText(std::format("Distance to line={:.2f}", m_distanceToFit[l][s]).c_str()); + pars->AddText(std::format("Number of Bins used={}", m_nBinsFit[l][s]).c_str()); + pars->AddText(std::format("WRMSE={:.2f}", m_fitRMSE[l][s]).c_str()); + } else { pars->AddText("#phi = #phi_{ideal} + A#times (1 - e^{-C#times (R - B)})"); - pars->AddText((boost::format("A=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); - //pars->AddText((boost::format("#phi_{ideal}=%.3f#pm 0.000") %m_laminationIdeal[l][s]).str().c_str()); - pars->AddText((boost::format("#phi_{nominal}=%.3f#pm 0.000") %(m_laminationIdeal[l][s]+m_laminationOffset[l][s])).str().c_str()); - //pars->AddText((boost::format("#phi_{offset}=%.3f#pm 0.000") %m_laminationOffset[l][s]).str().c_str()); - pars->AddText((boost::format("B=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(1) %m_fLamination[l][s]->GetParError(1)).str().c_str()); - pars->AddText((boost::format("C=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(2) %m_fLamination[l][s]->GetParError(2)).str().c_str()); - pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); - pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); - pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); + pars->AddText(std::format("A={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(0), m_fLamination[l][s]->GetParError(0)).c_str()); + //pars->AddText(std::format("#phi_{{ideal}}=%.3f#pm 0.000", m_laminationIdeal[l][s]).c_str()); + pars->AddText(std::format("#phi_{{nominal}}={:.3f}#pm 0.000", (m_laminationIdeal[l][s]+m_laminationOffset[l][s])).c_str()); + //pars->AddText(std::format("#phi_{{offset}}={:.3f}#pm 0.000", m_laminationOffset[l][s]).c_str()); + pars->AddText(std::format("B={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(1), m_fLamination[l][s]->GetParError(1)).c_str()); + pars->AddText(std::format("C={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(2), m_fLamination[l][s]->GetParError(2)).c_str()); + pars->AddText(std::format("Distance to line={:.2f}", m_distanceToFit[l][s]).c_str()); +pars->AddText(std::format("Number of Bins used={}", m_nBinsFit[l][s]).c_str()); +pars->AddText(std::format("WRMSE={:.2f}", m_fitRMSE[l][s]).c_str()); } pars->Draw("same"); c1->SaveAs(m_QAFileName.c_str()); @@ -1139,7 +1139,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } */ //m_dcc_out->m_hDRint[s] = (TH2 *) simRDistortion[s]->Clone(); - //m_dcc_out->m_hDRint[s]->SetName((boost::format("hIntDistortionR%s") %(s == 0 ? "_negz" : "_posz")).str().c_str()); + //m_dcc_out->m_hDRint[s]->SetName(std::format("hIntDistortionR{}", (s == 0 ? "_negz" : "_posz")).c_str()); //m_dcc_out->m_hDRint[s]->Multiply(scaleFactorMap[s]); } From 21d54afaa9f82570a70e3502c954fb9d5f16f9de Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 7 Feb 2026 10:00:13 -0500 Subject: [PATCH 198/866] suppress clang-tidy warning in CaloWaveformFitting --- offline/packages/CaloReco/CaloWaveformFitting.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 3d2223abab..74aa269c17 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -659,8 +659,8 @@ double CaloWaveformFitting::SignalShape_PowerLawDoubleExp(double *x, double *par return pedestal + signal; } - -double CaloWaveformFitting::SignalShape_FermiExp(double *x, double *par) +// chp: needs to be verified, but I can vaguely recall that making the args const fails in root +double CaloWaveformFitting::SignalShape_FermiExp(double *x, double *par) //NOLINT(readability-non-const-parameter) { // par[0]: Amplitude // par[1]: Midpoint (t0) From 41a3e8f6899573060c035e678230631529719b27 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 7 Feb 2026 10:20:39 -0500 Subject: [PATCH 199/866] remove redundant comment --- offline/packages/CaloReco/CaloWaveformFitting.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 74aa269c17..ba59367542 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -839,7 +839,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con } } } - else if(m_funcfit_type == POWERLAWDOUBLEEXP) // POWERLAWDOUBLEEXP + else if(m_funcfit_type == POWERLAWDOUBLEEXP) { // Create fit function with 7 parameters TF1 f("f_doubleexp", SignalShape_PowerLawDoubleExp, 0, nsamples, 7); @@ -889,7 +889,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con } } } - else if(m_funcfit_type == FERMIEXP) // POWERLAWDOUBLEEXP + else if(m_funcfit_type == FERMIEXP) { TF1 f("f_fermiexp", SignalShape_FermiExp, 0, nsamples, 5); npar = 5; From 9a0ede1040dc08e650edd48e46e2e1c498b52601 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 7 Feb 2026 18:43:41 -0500 Subject: [PATCH 200/866] sEPD_TreeGen: Cleanup and Refactor - Remove saving to regular TTrees, instead only save to DST - No need to save sepd channel phi as it can be reconstructed from the EpdGeom node that's saved to the DST by default - Remove usage of std::format - Remove usage of unique_ptr - Add Print Method for verbosity and debug - Ensure EventPlaneData has proper Reset Method to refresh buffer between events --- .../sepd_eventplanecalib/EventPlaneData.cc | 37 +++- .../sepd_eventplanecalib/EventPlaneData.h | 24 ++- .../sepd/sepd_eventplanecalib/QVecDefs.h | 2 +- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 176 ++++++++++-------- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.h | 44 +---- 5 files changed, 158 insertions(+), 125 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc index 67223236eb..6dedea4a15 100644 --- a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc @@ -3,7 +3,40 @@ EventPlaneData::EventPlaneData() { sepd_charge.fill(0); - sepd_phi.fill(0); } - +void EventPlaneData::Reset() +{ + event_id = 0; + event_zvertex = std::numeric_limits::quiet_NaN(); + event_centrality = std::numeric_limits::quiet_NaN(); + sepd_totalcharge = std::numeric_limits::quiet_NaN(); + sepd_charge.fill(0); +} + +void EventPlaneData::identify(std::ostream& os) const +{ + os << "--- EventPlaneData Identify ---" << std::endl; + os << "Event ID: " << event_id << std::endl; + os << "Z-Vertex: " << event_zvertex << std::endl; + os << "Centrality: " << event_centrality << std::endl; + os << "sEPD Total Charge: " << sepd_totalcharge << std::endl; + os << "-------------------------------" << std::endl; +} + +int EventPlaneData::isValid() const +{ + // An object is considered invalid if the Z-vertex is still NaN + // or if the event ID hasn't been set (remains 0). + if (std::isnan(event_zvertex)) + { + return 0; + } + + if (event_id == 0) + { + return 0; + } + + return 1; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h index b68fdfb5ff..255f488712 100644 --- a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h @@ -1,9 +1,12 @@ #ifndef SEPD_EVENTPLANECALIB_EVENTPLANEDATA_H #define SEPD_EVENTPLANECALIB_EVENTPLANEDATA_H +#include "QVecDefs.h" + #include #include +#include #include class EventPlaneData : public PHObject @@ -12,9 +15,12 @@ class EventPlaneData : public PHObject EventPlaneData(); ~EventPlaneData() override = default; - void Reset() override {*this = EventPlaneData();} // check if this works - // this should be in an sepd define (e.g. ../../../offline/packages/epd/EPDDefs.h) - static constexpr int SEPD_CHANNELS = 744; + EventPlaneData(const EventPlaneData&) = default; + EventPlaneData& operator=(const EventPlaneData&) = default; + EventPlaneData(EventPlaneData&&) = default; + EventPlaneData& operator=(EventPlaneData&&) = default; + + void Reset() override; void set_event_id(int id) {event_id = id;} int get_event_id() const {return event_id;} @@ -27,17 +33,19 @@ class EventPlaneData : public PHObject void set_sepd_charge(int channel, double chg) {sepd_charge[channel] = chg;} double get_sepd_charge(int channel) const {return sepd_charge[channel];} - void set_sepd_phi(int channel, double phi) {sepd_phi[channel] = phi;} - double get_sepd_phi(int channel) const {return sepd_phi[channel];} - + void set_event_centrality(double cent) { event_centrality = cent; } + double get_event_centrality() const { return event_centrality; } + + void identify(std::ostream& os = std::cout) const override; + int isValid() const override; + private: int event_id {0}; double event_zvertex {std::numeric_limits::quiet_NaN()}; double event_centrality{std::numeric_limits::quiet_NaN()}; double sepd_totalcharge{std::numeric_limits::quiet_NaN()}; - std::array sepd_charge {}; - std::array sepd_phi {}; + std::array sepd_charge {}; ClassDefOverride(EventPlaneData, 1); }; diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h index 0b42e1f105..3bc58344fe 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -10,7 +10,7 @@ namespace QVecShared { static constexpr size_t CENT_BINS = 8; static constexpr std::array HARMONICS = {2, 3, 4}; - static constexpr int sepd_channels = 744; + static constexpr int SEPD_CHANNELS = 744; enum class ChannelStatus : int { diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index 279577e295..3570fb6bc7 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -3,13 +3,12 @@ #include "EventPlaneData.h" // -- c++ -#include +#include #include // -- Calo #include #include -#include // -- Vtx #include @@ -44,13 +43,6 @@ sEPD_TreeGen::sEPD_TreeGen(const std::string &name) //____________________________________________________________________________.. int sEPD_TreeGen::Init(PHCompositeNode *topNode) { - // Early guard against filename collision - if (m_outfile_name == m_outtree_name) - { - std::cout << PHWHERE << " Error: Histogram filename and Tree filename are identical: " << m_outfile_name << ". This will cause data loss." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - Fun4AllServer *se = Fun4AllServer::instance(); se->Print("NODETREE"); @@ -62,34 +54,26 @@ int sEPD_TreeGen::Init(PHCompositeNode *topNode) double centrality_low{-0.5}; double centrality_high{79.5}; - hSEPD_Charge = std::make_unique("hSEPD_Charge", "|z| < 10 cm and MB; Channel; Avg Charge", QVecShared::sepd_channels, 0, QVecShared::sepd_channels); + hSEPD_Charge = new TProfile("hSEPD_Charge", "|z| < 10 cm and MB; Channel; Avg Charge", QVecShared::SEPD_CHANNELS, 0, QVecShared::SEPD_CHANNELS); hSEPD_Charge->Sumw2(); - h2SEPD_totalcharge_centrality = std::make_unique("h2SEPD_totalcharge_centrality", "|z| < 10 cm and MB; sEPD Total Charge; Centrality [%]", bins_sepd_totalcharge, sepd_totalcharge_low, sepd_totalcharge_high, bins_centrality, centrality_low, centrality_high); + h2SEPD_totalcharge_centrality = new TH2F("h2SEPD_totalcharge_centrality", + "|z| < 10 cm and MB; sEPD Total Charge; Centrality [%]", + bins_sepd_totalcharge, sepd_totalcharge_low, sepd_totalcharge_high, + bins_centrality, centrality_low, centrality_high); + + se->registerHisto(hSEPD_Charge); + se->registerHisto(h2SEPD_totalcharge_centrality); - m_output = std::make_unique(m_outtree_name.c_str(), "recreate"); + PHNodeIterator node_itr(topNode); + PHCompositeNode *dstNode = dynamic_cast(node_itr.findFirst("PHCompositeNode", "DST")); - if (!m_output || m_output->IsZombie()) + if (!dstNode) { - std::cout << PHWHERE << "Failed to open tree output file: " << m_outtree_name << std::endl; + std::cout << PHWHERE << "DST node missing, cannot attach EventPlaneData." << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - m_output->cd(); - - // TTree - m_tree = std::make_unique("T", "T"); - m_tree->SetDirectory(m_output.get()); - m_tree->Branch("event_id", &m_data.event_id); - m_tree->Branch("event_zvertex", &m_data.event_zvertex); - m_tree->Branch("event_centrality", &m_data.event_centrality); - m_tree->Branch("sepd_totalcharge", &m_data.sepd_totalcharge); - m_tree->Branch("sepd_channel", &m_data.sepd_channel); - m_tree->Branch("sepd_charge", &m_data.sepd_charge); - m_tree->Branch("sepd_phi", &m_data.sepd_phi); - PHNodeIterator node_itr(topNode); - PHCompositeNode *dstNode = dynamic_cast(node_itr.findFirst("PHCompositeNode", "DST")); - EventPlaneData *evtdata = findNode::getClass(topNode, "EventPlaneData"); if (!evtdata) { @@ -112,12 +96,18 @@ int sEPD_TreeGen::process_event_check(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - if (!vertexmap->empty()) + if (vertexmap->empty()) { - GlobalVertex *vtx = vertexmap->begin()->second; - m_data.event_zvertex = vtx->get_z(); + if (Verbosity() > 1) + { + std::cout << PHWHERE << "GlobalVertexMap Empty, Skipping Event: " << m_data.event_id << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; } + GlobalVertex *vtx = vertexmap->begin()->second; + double zvtx = vtx->get_z(); + MinimumBiasInfo *m_mb_info = findNode::getClass(topNode, "MinimumBiasInfo"); if (!m_mb_info) { @@ -128,7 +118,7 @@ int sEPD_TreeGen::process_event_check(PHCompositeNode *topNode) // skip event if not minimum bias if (!m_mb_info->isAuAuMinimumBias()) { - if (Verbosity() > 2) + if (Verbosity() > 1) { std::cout << "Event: " << m_data.event_id << ", Not Min Bias, Skipping" << std::endl; } @@ -136,15 +126,17 @@ int sEPD_TreeGen::process_event_check(PHCompositeNode *topNode) } // skip event if zvtx is too large - if (std::abs(m_data.event_zvertex) >= m_cuts.m_zvtx_max) + if (std::abs(zvtx) >= m_cuts.m_zvtx_max) { - if (Verbosity() > 2) + if (Verbosity() > 1) { - std::cout << "Event: " << m_data.event_id << ", Z: " << m_data.event_zvertex << " cm, Skipping" << std::endl; + std::cout << "Event: " << m_data.event_id << ", Z: " << zvtx << " cm, Skipping" << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } + m_evtdata->set_event_zvertex(zvtx); + return Fun4AllReturnCodes::EVENT_OK; } @@ -158,18 +150,21 @@ int sEPD_TreeGen::process_centrality(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_data.event_centrality = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; + double cent = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; // skip event if centrality is too peripheral - if (!std::isfinite(m_data.event_centrality) || m_data.event_centrality < 0 || m_data.event_centrality >= m_cuts.m_cent_max) + if (!std::isfinite(cent) || cent < 0 || cent >= m_cuts.m_cent_max) { - if(Verbosity() > 2) + if (Verbosity() > 1) { - std::cout << "Event: " << m_data.event_id << ", Centrality: " << m_data.event_centrality << ", Skipping" << std::endl; + std::cout << "Event: " << m_data.event_id << ", Centrality: " << cent << ", Skipping" << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } + m_evtdata->set_event_centrality(cent); + m_data.event_centrality = cent; + return Fun4AllReturnCodes::EVENT_OK; } @@ -193,26 +188,24 @@ int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) // sepd unsigned int sepd_channels = towerinfosEPD->size(); - if(sepd_channels != QVecShared::sepd_channels) + if(sepd_channels != QVecShared::SEPD_CHANNELS) { - if (Verbosity() > 2) + if (Verbosity() > 1) { - std::cout << "Event: " << m_data.event_id << ", SEPD Channels = " << sepd_channels << " != " << QVecShared::sepd_channels << std::endl; + std::cout << "Event: " << m_data.event_id << ", SEPD Channels = " << sepd_channels << " != " << QVecShared::SEPD_CHANNELS << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } - m_data.sepd_totalcharge = 0; + double sepd_totalcharge = 0; for (unsigned int channel = 0; channel < sepd_channels; ++channel) { - unsigned int key = TowerInfoDefs::encode_epd(channel); - TowerInfo *tower = towerinfosEPD->get_tower_at_channel(channel); if (!tower) { - if (Verbosity() > 2) + if (Verbosity() > 1) { std::cout << PHWHERE << "Null SEPD tower at channel " << channel << std::endl; } @@ -221,7 +214,6 @@ int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) double charge = tower->get_energy(); bool isZS = tower->get_isZS(); - double phi = epdgeom->get_phi(key); // exclude ZS // exclude Nmips @@ -230,20 +222,57 @@ int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) continue; } - m_data.sepd_channel.push_back(channel); - m_data.sepd_charge.push_back(charge); - m_data.sepd_phi.push_back(phi); + m_evtdata->set_sepd_charge(channel, charge); - m_data.sepd_totalcharge += charge; + sepd_totalcharge += charge; hSEPD_Charge->Fill(channel, charge); } - h2SEPD_totalcharge_centrality->Fill(m_data.sepd_totalcharge, m_data.event_centrality); + m_evtdata->set_sepd_totalcharge(sepd_totalcharge); + h2SEPD_totalcharge_centrality->Fill(sepd_totalcharge, m_data.event_centrality); return Fun4AllReturnCodes::EVENT_OK; } +//____________________________________________________________________________.. +void sEPD_TreeGen::Print([[maybe_unused]] const std::string &what) const +{ + // Only execute if Verbosity is high enough + if (Verbosity() <= 2) return; + + std::cout << "\n============================================================" << std::endl; + std::cout << "sEPD_TreeGen::Print -> Event Data State" << std::endl; + + if (!m_evtdata) + { + std::cout << " [WARNING] m_evtdata is null." << std::endl; + return; + } + + // Verbosity > 2: Print basic scalars + std::cout << " Event ID: " << m_evtdata->get_event_id() << std::endl; + std::cout << " Z-Vertex: " << m_evtdata->get_event_zvertex() << " cm" << std::endl; + std::cout << " Centrality: " << m_evtdata->get_event_centrality() << " %" << std::endl; + std::cout << " sEPD Total Charge: " << m_evtdata->get_sepd_totalcharge() << std::endl; + + // Verbosity > 3: Print channel arrays + if (Verbosity() > 3) + { + std::cout << " Active Towers (Charge > 0):" << std::endl; + for (int i = 0; i < QVecShared::SEPD_CHANNELS; ++i) + { + double charge = m_evtdata->get_sepd_charge(i); + if (charge > 0) + { + std::cout << " Channel: " << std::setw(3) << i + << " | Charge: " << std::fixed << std::setprecision(4) << charge << std::endl; + } + } + } + std::cout << "============================================================\n" << std::endl; +} + //____________________________________________________________________________.. int sEPD_TreeGen::process_event(PHCompositeNode *topNode) { @@ -256,12 +285,21 @@ int sEPD_TreeGen::process_event(PHCompositeNode *topNode) m_data.event_id = eventInfo->get_EvtSequence(); - if (Verbosity() > 1 && m_event % PROGRESS_PRINT_INTERVAL == 0) + if (Verbosity() && m_event % PROGRESS_PRINT_INTERVAL == 0) { std::cout << "Progress: " << m_event << ", Global: " << m_data.event_id << std::endl; } ++m_event; + m_evtdata = findNode::getClass(topNode, "EventPlaneData"); + if (!m_evtdata) + { + std::cout << PHWHERE << "EventPlaneData Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_evtdata->set_event_id(m_data.event_id); + int ret = process_event_check(topNode); if (ret) { @@ -279,9 +317,8 @@ int sEPD_TreeGen::process_event(PHCompositeNode *topNode) { return ret; } - - // Fill the TTree - m_tree->Fill(); + + Print(); return Fun4AllReturnCodes::EVENT_OK; } @@ -291,14 +328,13 @@ int sEPD_TreeGen::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) { // Event m_data.event_id = -1; - m_data.event_zvertex = 9999; m_data.event_centrality = 9999; - // sEPD - m_data.sepd_totalcharge = 0; - m_data.sepd_channel.clear(); - m_data.sepd_charge.clear(); - m_data.sepd_phi.clear(); + // DST + if (m_evtdata) + { + m_evtdata->Reset(); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -307,19 +343,5 @@ int sEPD_TreeGen::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) int sEPD_TreeGen::End([[maybe_unused]] PHCompositeNode *topNode) { std::cout << "sEPD_TreeGen::End" << std::endl; - - TFile output(m_outfile_name.c_str(), "recreate"); - output.cd(); - - hSEPD_Charge->Write(); - h2SEPD_totalcharge_centrality->Write(); - - output.Close(); - - // TTree - m_output->cd(); - m_tree->Write(); - m_output->Close(); - return Fun4AllReturnCodes::EVENT_OK; } diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h index 57436314fb..0c735cda36 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h @@ -5,19 +5,14 @@ #include // -- c++ -#include -#include -#include #include -#include // -- ROOT -#include #include #include -#include class PHCompositeNode; +class EventPlaneData; /** * @class sEPD_TreeGen @@ -67,22 +62,10 @@ class sEPD_TreeGen : public SubsysReco int End(PHCompositeNode *topNode) override; /** - * @brief Sets the filename for the QA histograms ROOT file. - * @param file Output path for histograms. + * @brief Prints the current state of the EventPlaneData object. + * @param what Optional string to specify what to print (default "ALL"). */ - void set_filename(const std::string &file) - { - m_outfile_name = file; - } - - /** - * @brief Sets the filename for the flat TTree ROOT file. - * @param file Output path for the TTree. - */ - void set_tree_filename(const std::string &file) - { - m_outtree_name = file; - } + void Print(const std::string &what = "ALL") const override; /** * @brief Sets the maximum allowed Z-vertex position for event selection. @@ -136,9 +119,6 @@ class sEPD_TreeGen : public SubsysReco int m_event{0}; - std::string m_outfile_name{"test.root"}; - std::string m_outtree_name{"tree.root"}; - static constexpr int PROGRESS_PRINT_INTERVAL = 20; // Cuts @@ -154,24 +134,14 @@ class sEPD_TreeGen : public SubsysReco struct EventData { int event_id{0}; - double event_zvertex{9999}; double event_centrality{9999}; - - double sepd_totalcharge{-9999}; - - std::vector sepd_channel; - std::vector sepd_charge; - std::vector sepd_phi; }; EventData m_data; + EventPlaneData* m_evtdata{nullptr}; - std::unique_ptr m_output; - std::unique_ptr m_tree; - - std::unique_ptr hSEPD_Charge; - std::unique_ptr h2SEPD_totalcharge_centrality; + TProfile *hSEPD_Charge{nullptr}; + TH2 *h2SEPD_totalcharge_centrality{nullptr}; }; - #endif // SEPD_TREEGEN_H From ddacfb7b8db24faa079fd7bd0f5051937a4588df Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sun, 8 Feb 2026 17:53:31 -0500 Subject: [PATCH 201/866] QVecCalib - Refactor Executable to Fun4All - Transformed QVecCalib into a Fun4All module - Reads from slim DST instead of TTree - Merged Functionality of QVecCDB into QVecCalib - Remove QVecCDB and it's corresponding executable - Removed usage of unique_ptr - Using Fun4All server HistoManager to keep track of the histograms --- .../sepd/sepd_eventplanecalib/GenQVecCDB.cc | 54 - .../sepd/sepd_eventplanecalib/Makefile.am | 14 +- .../sepd/sepd_eventplanecalib/QVecCDB.cc | 214 --- .../sepd/sepd_eventplanecalib/QVecCDB.h | 139 -- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 1423 +++++++++-------- .../sepd/sepd_eventplanecalib/QVecCalib.h | 516 +++--- .../sepd/sepd_eventplanecalib/QVecDefs.h | 17 +- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 5 +- 8 files changed, 1061 insertions(+), 1321 deletions(-) delete mode 100644 calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc delete mode 100644 calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc delete mode 100644 calibrations/sepd/sepd_eventplanecalib/QVecCDB.h diff --git a/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc deleted file mode 100644 index 324f774950..0000000000 --- a/calibrations/sepd/sepd_eventplanecalib/GenQVecCDB.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include "QVecCDB.h" - -#include -#include - -int main(int argc, const char* const argv[]) -{ - const std::vector args(argv, argv + argc); - - if (args.size() < 3 || args.size() > 5) - { - std::cout << "Usage: " << args[0] << " input_file runnumber [output_dir] [cdb_tag]" << std::endl; - return 1; - } - - const std::string &input_file = args[1]; - const std::string output_dir = (args.size() >= 4) ? args[3] : "."; - const std::string cdb_tag = (args.size() >= 5) ? args[4] : "new_newcdbtag_v008"; - - try - { - int runnumber = std::stoi(args[2]); - - std::cout << std::format("{:#<20}\n", ""); - std::cout << std::format("Analysis Params\n"); - std::cout << std::format("Input File: {}\n", input_file); - std::cout << std::format("Run: {}\n", runnumber); - std::cout << std::format("Output Dir: {}\n", output_dir); - std::cout << std::format("CDB Tag: {}\n", cdb_tag); - std::cout << std::format("{:#<20}\n", ""); - - QVecCDB analysis(input_file, runnumber, output_dir, cdb_tag); - analysis.run(); - } - catch (const std::invalid_argument& e) - { - std::cout << "Error: runnumber must be an integer: " << args[2] << std::endl; - return 1; - } - catch (const std::out_of_range& e) - { - std::cout << "Error: runnumber is out of range for an integer." << std::endl; - return 1; - } - catch (const std::exception& e) - { - std::cout << "An exception occurred: " << e.what() << std::endl; - return 1; - } - - std::cout << "======================================" << std::endl; - std::cout << "done" << std::endl; - return 0; -} diff --git a/calibrations/sepd/sepd_eventplanecalib/Makefile.am b/calibrations/sepd/sepd_eventplanecalib/Makefile.am index d09895d691..d17c56b4a0 100644 --- a/calibrations/sepd/sepd_eventplanecalib/Makefile.am +++ b/calibrations/sepd/sepd_eventplanecalib/Makefile.am @@ -1,9 +1,5 @@ AUTOMAKE_OPTIONS = foreign -bin_PROGRAMS = \ - GenQVecCalib \ - GenQVecCDB - AM_CPPFLAGS = \ -I$(includedir) \ -isystem$(OFFLINE_MAIN)/include \ @@ -18,7 +14,6 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ sEPD_TreeGen.h \ QVecCalib.h \ - QVecCDB.h \ QVecDefs.h lib_LTLIBRARIES = \ @@ -36,8 +31,7 @@ libsepd_eventplanecalib_la_SOURCES = \ $(ROOTDICTS) \ EventPlaneData.cc \ sEPD_TreeGen.cc \ - QVecCalib.cc \ - QVecCDB.cc + QVecCalib.cc libsepd_eventplanecalib_la_LIBADD = \ -lphool \ @@ -51,12 +45,6 @@ libsepd_eventplanecalib_la_LIBADD = \ -lcdbobjects \ -lepd_io -GenQVecCalib_SOURCES = GenQVecCalib.cc -GenQVecCalib_LDADD = libsepd_eventplanecalib.la - -GenQVecCDB_SOURCES = GenQVecCDB.cc -GenQVecCDB_LDADD = libsepd_eventplanecalib.la - # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc deleted file mode 100644 index ef284faa9d..0000000000 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.cc +++ /dev/null @@ -1,214 +0,0 @@ -#include "QVecCDB.h" - -// ==================================================================== -// sPHENIX Includes -// ==================================================================== -#include -#include - -// ==================================================================== -// ROOT Includes -// ==================================================================== -#include - -// ==================================================================== -// Standard C++ Includes -// ==================================================================== -#include -#include -#include -#include -#include - -template -std::unique_ptr QVecCDB::load_and_clone(const std::string& name) { - auto* obj = dynamic_cast(m_tfile->Get(name.c_str())); - if (!obj) - { - throw std::runtime_error(std::format("Could not find histogram '{}' in file '{}'", name, m_tfile->GetName())); - } - return std::unique_ptr(static_cast(obj->Clone())); -} - -QVecShared::CorrectionMoments& QVecCDB::getData(size_t h_idx, size_t cent_bin, QVecShared::Subdetector sub) { - return m_correction_data[h_idx][cent_bin][static_cast(sub)]; -} - -void QVecCDB::load_data() -{ - m_tfile = std::unique_ptr(TFile::Open(m_input_file.c_str())); - - // Check if the file was opened successfully. - if (!m_tfile || m_tfile->IsZombie()) - { - throw std::runtime_error(std::format("Could not open file '{}'", m_input_file)); - } - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - load_correction_data(h_idx); - } -} - -void QVecCDB::load_correction_data(size_t h_idx) -{ - int n = m_harmonics[h_idx]; - - // Load recentering terms (x, y) - auto pS_x = load_and_clone(QVecShared::get_hist_name("S", "x", n)); - auto pS_y = load_and_clone(QVecShared::get_hist_name("S", "y", n)); - auto pN_x = load_and_clone(QVecShared::get_hist_name("N", "x", n)); - auto pN_y = load_and_clone(QVecShared::get_hist_name("N", "y", n)); - - // Load flattening terms (xx, yy, xy) - auto pS_xx = load_and_clone(QVecShared::get_hist_name("S", "xx", n)); - auto pS_yy = load_and_clone(QVecShared::get_hist_name("S", "yy", n)); - auto pS_xy = load_and_clone(QVecShared::get_hist_name("S", "xy", n)); - auto pN_xx = load_and_clone(QVecShared::get_hist_name("N", "xx", n)); - auto pN_yy = load_and_clone(QVecShared::get_hist_name("N", "yy", n)); - auto pN_xy = load_and_clone(QVecShared::get_hist_name("N", "xy", n)); - - // Load NS flattening terms - auto pNS_xx = load_and_clone(QVecShared::get_hist_name("NS", "xx", n)); - auto pNS_yy = load_and_clone(QVecShared::get_hist_name("NS", "yy", n)); - auto pNS_xy = load_and_clone(QVecShared::get_hist_name("NS", "xy", n)); - - for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) - { - int bin = static_cast(cent_bin) + 1; // ROOT bins start at 1 - - // South - auto& dataS = getData(h_idx, cent_bin, QVecShared::Subdetector::S); - dataS.avg_Q = {pS_x->GetBinContent(bin), pS_y->GetBinContent(bin)}; - dataS.avg_Q_xx = pS_xx->GetBinContent(bin); - dataS.avg_Q_yy = pS_yy->GetBinContent(bin); - dataS.avg_Q_xy = pS_xy->GetBinContent(bin); - - // North - auto& dataN = getData(h_idx, cent_bin, QVecShared::Subdetector::N); - dataN.avg_Q = {pN_x->GetBinContent(bin), pN_y->GetBinContent(bin)}; - dataN.avg_Q_xx = pN_xx->GetBinContent(bin); - dataN.avg_Q_yy = pN_yy->GetBinContent(bin); - dataN.avg_Q_xy = pN_xy->GetBinContent(bin); - - // North South - auto& dataNS = getData(h_idx, cent_bin, QVecShared::Subdetector::NS); - dataNS.avg_Q_xx = pNS_xx->GetBinContent(bin); - dataNS.avg_Q_yy = pNS_yy->GetBinContent(bin); - dataNS.avg_Q_xy = pNS_xy->GetBinContent(bin); - } -} - -void QVecCDB::write_cdb() -{ - std::string output_dir = std::format("{}/{}", m_output_dir, m_runnumber); - - std::error_code ec; - if (std::filesystem::create_directories(output_dir, ec)) - { - std::cout << std::format("Success: Directory {} created.\n", output_dir); - } - else if (ec) - { - throw std::runtime_error(std::format("Failed to create directory {}: {}", output_dir, ec.message())); - } - else - { - std::cout << std::format("Info: Directory {} already exists.\n", output_dir); - } - - write_cdb_EventPlane(output_dir); - write_cdb_BadTowers(output_dir); -} - -void QVecCDB::write_cdb_BadTowers(const std::string &output_dir) -{ - std::string payload = "SEPD_HotMap"; - std::string fieldname_status = "status"; - std::string fieldname_sigma = "SEPD_sigma"; - std::string output_file = std::format("{}/{}-{}-{}.root", output_dir, payload, m_cdb_tag, m_runnumber); - - std::unique_ptr cdbttree = std::make_unique(output_file); - - auto h_sEPD_Bad_Channels = load_and_clone("h_sEPD_Bad_Channels"); - - for (int channel = 0; channel < h_sEPD_Bad_Channels->GetNbinsX(); ++channel) - { - unsigned int key = TowerInfoDefs::encode_epd(channel); - int status = h_sEPD_Bad_Channels->GetBinContent(channel+1); - - float sigma = 0; - - // Hot - if (status == static_cast(QVecShared::ChannelStatus::Hot)) - { - sigma = SIGMA_HOT; - } - - // Cold - else if (status == static_cast(QVecShared::ChannelStatus::Cold)) - { - sigma = SIGMA_COLD; - } - - cdbttree->SetIntValue(key, fieldname_status, status); - cdbttree->SetFloatValue(key, fieldname_sigma, sigma); - } - - std::cout << std::format("Saving CDB: {} to {}\n", payload, output_file); - - cdbttree->Commit(); - cdbttree->WriteCDBTTree(); -} - -void QVecCDB::write_cdb_EventPlane(const std::string &output_dir) -{ - std::string payload = "SEPD_EventPlaneCalib"; - std::string output_file = std::format("{}/{}-{}-{}.root", output_dir, payload, m_cdb_tag, m_runnumber); - - std::unique_ptr cdbttree = std::make_unique(output_file); - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - - // Define lambdas to generate field names consistently - auto field = [&](const char* det, const char* var) { - return std::format("Q_{}_{}_{}_avg", det, var, n); - }; - - for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) - { - int key = static_cast(cent_bin); - - // Access data references to clean up the calls - const auto& S = getData(h_idx, cent_bin, QVecShared::Subdetector::S); - const auto& N = getData(h_idx, cent_bin, QVecShared::Subdetector::N); - const auto& NS = getData(h_idx, cent_bin, QVecShared::Subdetector::NS); - - // South - cdbttree->SetDoubleValue(key, field("S", "x"), S.avg_Q.x); - cdbttree->SetDoubleValue(key, field("S", "y"), S.avg_Q.y); - cdbttree->SetDoubleValue(key, field("S", "xx"), S.avg_Q_xx); - cdbttree->SetDoubleValue(key, field("S", "yy"), S.avg_Q_yy); - cdbttree->SetDoubleValue(key, field("S", "xy"), S.avg_Q_xy); - - // North - cdbttree->SetDoubleValue(key, field("N", "x"), N.avg_Q.x); - cdbttree->SetDoubleValue(key, field("N", "y"), N.avg_Q.y); - cdbttree->SetDoubleValue(key, field("N", "xx"), N.avg_Q_xx); - cdbttree->SetDoubleValue(key, field("N", "yy"), N.avg_Q_yy); - cdbttree->SetDoubleValue(key, field("N", "xy"), N.avg_Q_xy); - - // North South - cdbttree->SetDoubleValue(key, field("NS", "xx"), NS.avg_Q_xx); - cdbttree->SetDoubleValue(key, field("NS", "yy"), NS.avg_Q_yy); - cdbttree->SetDoubleValue(key, field("NS", "xy"), NS.avg_Q_xy); - } - } - - std::cout << std::format("Saving CDB: {} to {}\n", payload, output_file); - - cdbttree->Commit(); - cdbttree->WriteCDBTTree(); -} diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h b/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h deleted file mode 100644 index 54b9b37901..0000000000 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCDB.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef QVECCDB_H -#define QVECCDB_H - -#include "QVecDefs.h" - -// ==================================================================== -// ROOT Includes -// ==================================================================== -#include - -// ==================================================================== -// Standard C++ Includes -// ==================================================================== -#include -#include - -/** - * @class QVecCDB - * @brief Generates sPHENIX Calibration Database (CDB) payloads for sEPD calibrations. - * - * QVecCDB is responsible for consolidating the correction parameters derived - * during the calibration stage into standardized database formats: - * * - **SEPD_EventPlaneCalib**: Encapsulates re-centering offsets (, ) and - * flattening moments (, , ) indexed by centrality bin. - * - **SEPD_HotMap**: Maps sEPD tower statuses (Dead, Hot, or Cold) to their - * respective channel IDs for use in reconstruction. - * * The class interfaces with the `CDBTTree` object to commit these payloads - * for a specific run number and database tag. - */ -class QVecCDB -{ - public: - // The constructor takes the configuration - QVecCDB(std::string input_file, int runnumber, std::string output_dir, std::string cdb_tag) - : m_input_file(std::move(input_file)) - , m_runnumber(runnumber) - , m_output_dir(std::move(output_dir)) - , m_cdb_tag(std::move(cdb_tag)) - { - } - - void run() - { - load_data(); - write_cdb(); - } - - private: - - static constexpr size_t m_cent_bins = QVecShared::CENT_BINS; - static constexpr auto m_harmonics = QVecShared::HARMONICS; - - static constexpr float SIGMA_HOT = 6.0F; - static constexpr float SIGMA_COLD = -6.0F; - - // Holds all correction data - // key: [Harmonic][Cent][Subdetector] - // Harmonics {2,3,4} -> 3 elements - // Subdetectors {S,N,NS} -> 3 elements - std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; - - // --- Member Variables --- - std::string m_input_file; - int m_runnumber; - std::string m_output_dir; - std::string m_cdb_tag; - - std::unique_ptr m_tfile; - - // --- Private Helper Methods --- -/** - * @brief Safely retrieves a ROOT object from the internal TFile and returns a managed unique_ptr. - * * Utilizes the internal m_tfile member to locate the object. Performs a - * dynamic_cast for type safety and Clones the object for persistent use. - * * @tparam T The ROOT class type (e.g., TProfile, TH3). - * @param name The name of the object within the internal file. - * @return std::unique_ptr A managed pointer to the cloned object. - * @throws std::runtime_error If the object is not found or type mismatch occurs. - */ - template - std::unique_ptr load_and_clone(const std::string& name); - -/** - * @brief Provides safe access to the internal correction data storage. - * * This accessor handles the mapping between the physics-based Subdetector enum - * and the zero-based indexing of the underlying multi-dimensional array. - * * @param h_idx The index of the harmonic order in the m_harmonics array. - * @param cent_bin The index of the centrality bin. - * @param sub The subdetector arm (South or North) using the QVecShared enum. - * @return QVecShared::CorrectionMoments& A reference to the specific data entry. - */ - QVecShared::CorrectionMoments& getData(size_t h_idx, size_t cent_bin, QVecShared::Subdetector sub); - -/** - * @brief High-level orchestrator for loading calibration input from a ROOT file. - * * Opens the input file specified in the constructor and validates its integrity - * before iteratively calling load_correction_data() for every defined harmonic. - * * Throws a std::runtime_error if the file cannot be opened or is found to be - * a "zombie" file. - */ - void load_data(); - -/** - * @brief Loads 1st and 2nd order correction parameters from a calibration file. - * * Iterates through harmonics and centrality bins to populate the internal - * correction matrix using the centralized QVecShared naming scheme. - * * @param h_idx The index of the harmonic to load. - */ - void load_correction_data(size_t h_idx); - -/** - * @brief Top-level orchestrator for the CDB writing phase. - * - * This method manages the creation of the run-specific directory structure - * (e.g., [output_dir]/[runnumber]) within the base output path. Once the - * filesystem is prepared, it delegates the generation and commitment of - * specific calibration payloads to write_cdb_EventPlane() and - * write_cdb_BadTowers(). - */ - void write_cdb(); - -/** - * @brief Writes the Event Plane calibration constants to a CDB-formatted TTree. - * * Formats the re-centering and flattening moments into a CDBTTree payload - * indexed by centrality bin for sPHENIX database integration. - * * @param output_dir The filesystem directory where the .root payload will be saved. - */ - void write_cdb_EventPlane(const std::string &output_dir); - -/** - * @brief Writes the Hot/Cold tower status map to a CDB-formatted TTree. - * * Encodes sEPD channel indices into TowerInfo keys and maps status codes (1=Dead, - * 2=Hot, 3=Cold) to the final database payload. - * * @param output_dir The filesystem directory where the .root payload will be saved. - */ - void write_cdb_BadTowers(const std::string &output_dir); -}; - -#endif // QVECCDB_H diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index b2a4a97e55..f14b0cc536 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -1,164 +1,154 @@ #include "QVecCalib.h" +#include "EventPlaneData.h" // ==================================================================== // sPHENIX Includes // ==================================================================== #include +// -- Fun4All +#include +#include + +// -- Nodes +#include +#include + +// -- sEPD +#include + +// -- Run +#include + +// -- CDBTTree +#include + // ==================================================================== // Standard C++ Includes // ==================================================================== -#include -#include -#include -#include +#include #include +#include -// ==================================================================== -// ROOT Includes -// ==================================================================== -#include +//____________________________________________________________________________.. +QVecCalib::QVecCalib(const std::string &name): + SubsysReco(name) +{ + std::cout << "QVecCalib::QVecCalib(const std::string &name) Calling ctor" << std::endl; +} -std::unique_ptr QVecCalib::setupTChain(const std::string& input_filepath, const std::string& tree_name_in_file) +//____________________________________________________________________________.. +int QVecCalib::Init([[maybe_unused]] PHCompositeNode *topNode) { - // 1. Pre-check: Does the file exist at all? (C++17 filesystem or traditional fstream) - if (!std::filesystem::exists(input_filepath)) - { - std::cout << "Error: Input file does not exist: " << input_filepath << std::endl; - return nullptr; // Return a null unique_ptr indicating failure - } + std::cout << "QVecCalib::Init(PHCompositeNode *topNode) Initializing" << std::endl; - // 2. Open the file to check for the TTree directly - // Use TFile::Open and unique_ptr for robust file handling (RAII) - std::unique_ptr file_checker(TFile::Open(input_filepath.c_str(), "READ")); + Fun4AllServer *se = Fun4AllServer::instance(); + se->Print("NODETREE"); - if (!file_checker || file_checker->IsZombie()) + int ret = process_QA_hist(); + if (ret) { - std::cout << "Error: Could not open file " << input_filepath << " to check for TTree." << std::endl; - return nullptr; + return ret; } - // Check if the TTree exists in the file - // Get() returns a TObject*, which can be cast to TTree*. - // If the object doesn't exist or isn't a TTree, Get() returns nullptr. - TTree* tree_obj = dynamic_cast(file_checker->Get(tree_name_in_file.c_str())); - if (!tree_obj) + init_hists(); + + if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening) { - std::cout << "Error: TTree '" << tree_name_in_file << "' not found in file " << input_filepath << std::endl; - return nullptr; - } - // File will be automatically closed by file_checker's unique_ptr destructor - - // 3. If everything checks out, create and configure the TChain - std::unique_ptr chain = std::make_unique(tree_name_in_file.c_str()); - if (!chain) - { // Check if make_unique failed (e.g. out of memory) - std::cout << "Error: Could not create TChain object." << std::endl; - return nullptr; + ret = load_correction_data(); + if (ret) + { + return ret; + } } - chain->Add(input_filepath.c_str()); + prepare_hists(); + + return Fun4AllReturnCodes::EVENT_OK; +} - // 4. Verify TChain's state (optional but good final check) - // GetEntries() will be -1 if no valid trees were added. - if (chain->GetEntries() == 0) +void QVecCalib::prepare_hists() +{ + if (m_pass == Pass::ComputeRecentering) { - std::cout << "Warning: TChain has 0 entries after adding file. This might indicate a problem." << std::endl; - // Depending on your logic, you might return nullptr here too. + prepare_average_hists(); } - else + else if (m_pass == Pass::ApplyRecentering) { - std::cout << "Successfully set up TChain for tree '" << tree_name_in_file - << "' from file '" << input_filepath << "'. Entries: " << chain->GetEntries() << std::endl; + prepare_recenter_hists(); } - - return chain; // Return the successfully created and configured TChain -} - -void QVecCalib::setup_chain() -{ - std::cout << "Processing... setup_chain" << std::endl; - - m_chain = setupTChain(m_input_file, "T"); - - if (m_chain == nullptr) + else if (m_pass == Pass::ApplyFlattening) { - throw std::runtime_error(std::format("Error in TChain Setup from file: {}", m_input_file)); + prepare_flattening_hists(); } - - // Setup branches - m_chain->SetBranchStatus("*", false); - m_chain->SetBranchStatus("event_id", true); - m_chain->SetBranchStatus("event_centrality", true); - m_chain->SetBranchStatus("sepd_totalcharge", true); - m_chain->SetBranchStatus("sepd_channel", true); - m_chain->SetBranchStatus("sepd_charge", true); - m_chain->SetBranchStatus("sepd_phi", true); - - m_chain->SetBranchAddress("event_id", &m_event_data.event_id); - m_chain->SetBranchAddress("event_centrality", &m_event_data.event_centrality); - m_chain->SetBranchAddress("sepd_totalcharge", &m_event_data.sepd_totalcharge); - m_chain->SetBranchAddress("sepd_channel", &m_event_data.sepd_channel); - m_chain->SetBranchAddress("sepd_charge", &m_event_data.sepd_charge); - m_chain->SetBranchAddress("sepd_phi", &m_event_data.sepd_phi); - - std::cout << "Finished... setup_chain" << std::endl; } -void QVecCalib::process_QA_hist() +int QVecCalib::process_QA_hist() { TH1::AddDirectory(kFALSE); - auto file = std::unique_ptr(TFile::Open(m_input_hist.c_str())); + auto* file = TFile::Open(m_input_hist.c_str()); // Check if the file was opened successfully. if (!file || file->IsZombie()) { - throw std::runtime_error(std::format("Could not open file '{}'", m_input_hist)); + std::cout << PHWHERE << "Error! Cannot not open file: " << m_input_hist << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // Get sEPD Total Charge Bounds as function of centrality + int ret = process_sEPD_event_thresholds(file); + if (ret) + { + return ret; } // Get List of Bad Channels - process_bad_channels(file.get()); + ret = process_bad_channels(file); + if (ret) + { + return ret; + } - // Get sEPD Total Charge Bounds as function of centrality - process_sEPD_event_thresholds(file.get()); + // cleanup + file->Close(); + delete file; + + return Fun4AllReturnCodes::EVENT_OK; } -void QVecCalib::process_sEPD_event_thresholds(TFile* file) +int QVecCalib::process_sEPD_event_thresholds(TFile* file) { + Fun4AllServer *se = Fun4AllServer::instance(); + std::string sepd_totalcharge_centrality = "h2SEPD_totalcharge_centrality"; - auto* hist = file->Get(sepd_totalcharge_centrality.c_str()); + auto* hist = file->Get(sepd_totalcharge_centrality.c_str()); // Check if the hist is stored in the file if (hist == nullptr) { - throw std::runtime_error(std::format("Cannot find hist: {}", sepd_totalcharge_centrality)); - } - - auto* h2_check = dynamic_cast(hist); - if (!h2_check) - { - throw std::runtime_error(std::format("Histogram '{}' is not a TH2", sepd_totalcharge_centrality)); + std::cout << PHWHERE << "Error! Cannot find hist: " << sepd_totalcharge_centrality << std::endl; + return Fun4AllReturnCodes::ABORTRUN; } - m_hists2D["h2SEPD_Charge"] = std::unique_ptr(static_cast(h2_check->Clone("h2SEPD_Charge"))); - m_hists2D["h2SEPD_Chargev2"] = std::unique_ptr(static_cast(h2_check->Clone("h2SEPD_Chargev2"))); + h2SEPD_Charge = static_cast(hist->Clone("h2SEPD_Charge")); + h2SEPD_Chargev2 = static_cast(hist->Clone("h2SEPD_Chargev2")); - auto* h2SEPD_Charge = m_hists2D["h2SEPD_Charge"].get(); - auto* h2SEPD_Chargev2 = m_hists2D["h2SEPD_Chargev2"].get(); + se->registerHisto(h2SEPD_Charge); + se->registerHisto(h2SEPD_Chargev2); - std::unique_ptr h2SEPD_Charge_py(h2SEPD_Charge->ProfileY("h2SEPD_Charge_py", 1, -1, "s")); + auto* h2SEPD_Charge_py = h2SEPD_Charge->ProfileY("h2SEPD_Charge_py", 1, -1, "s"); int binsx = h2SEPD_Charge->GetNbinsX(); int binsy = h2SEPD_Charge->GetNbinsY(); double ymin = h2SEPD_Charge->GetYaxis()->GetXmin(); double ymax = h2SEPD_Charge->GetYaxis()->GetXmax(); - m_profiles["hSEPD_Charge_Min"] = std::make_unique("hSEPD_Charge_Min", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); - m_profiles["hSEPD_Charge_Max"] = std::make_unique("hSEPD_Charge_Max", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); + hSEPD_Charge_Min = new TProfile("hSEPD_Charge_Min", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); + hSEPD_Charge_Max = new TProfile("hSEPD_Charge_Max", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); - auto* hSEPD_Charge_Min = m_profiles["hSEPD_Charge_Min"].get(); - auto* hSEPD_Charge_Max = m_profiles["hSEPD_Charge_Max"].get(); + se->registerHisto(hSEPD_Charge_Min); + se->registerHisto(hSEPD_Charge_Max); for (int y = 1; y <= binsy; ++y) { @@ -182,70 +172,75 @@ void QVecCalib::process_sEPD_event_thresholds(TFile* file) double charge = h2SEPD_Charge->GetXaxis()->GetBinCenter(x); double zscore = (charge - mean) / sigma; - if (std::fabs(zscore) > m_sEPD_sigma_threshold) + if (std::abs(zscore) > m_sEPD_sigma_threshold) { h2SEPD_Chargev2->SetBinContent(x, y, 0); + h2SEPD_Chargev2->SetBinError(x, y, 0); } } } + + return Fun4AllReturnCodes::EVENT_OK; } -void QVecCalib::process_bad_channels(TFile* file) +int QVecCalib::process_bad_channels(TFile* file) { + Fun4AllServer *se = Fun4AllServer::instance(); + std::string sepd_charge_hist = "hSEPD_Charge"; - auto* hist = file->Get(sepd_charge_hist.c_str()); + auto* hSEPD_Charge = file->Get(sepd_charge_hist.c_str()); // Check if the hist is stored in the file - if (hist == nullptr) - { - throw std::runtime_error(std::format("Cannot find hist: {}", sepd_charge_hist)); - } - - auto* hSEPD_Charge = dynamic_cast(hist); - - if (!hSEPD_Charge) + if (hSEPD_Charge == nullptr) { - throw std::runtime_error(std::format("Histogram '{}' is not a TH1", sepd_charge_hist)); + std::cout << PHWHERE << "Error! Cannot find hist: " << sepd_charge_hist << ", in file: " << file->GetName() << std::endl; + return Fun4AllReturnCodes::ABORTRUN; } int rbins = 16; int bins_charge = 40; - m_hists2D["h2SEPD_South_Charge_rbin"] = std::make_unique("h2SEPD_South_Charge_rbin", - "sEPD South; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); + h2SEPD_South_Charge_rbin = new TH2F("h2SEPD_South_Charge_rbin", + "sEPD South; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); + + h2SEPD_North_Charge_rbin = new TH2F("h2SEPD_North_Charge_rbin", + "sEPD North; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); - m_hists2D["h2SEPD_North_Charge_rbin"] = std::make_unique("h2SEPD_North_Charge_rbin", - "sEPD North; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); + h2SEPD_South_Charge_rbinv2 = new TH2F("h2SEPD_South_Charge_rbinv2", + "sEPD South; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); - m_hists2D["h2SEPD_South_Charge_rbinv2"] = std::make_unique("h2SEPD_South_Charge_rbinv2", - "sEPD South; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); + h2SEPD_North_Charge_rbinv2 = new TH2F("h2SEPD_North_Charge_rbinv2", + "sEPD North; r_{bin}; Avg Charge", + rbins, -0.5, rbins - 0.5, + bins_charge, 0, bins_charge); - m_hists2D["h2SEPD_North_Charge_rbinv2"] = std::make_unique("h2SEPD_North_Charge_rbinv2", - "sEPD North; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); + hSEPD_Bad_Channels = new TProfile("h_sEPD_Bad_Channels", "sEPD Bad Channels; Channel; Status", QVecShared::SEPD_CHANNELS, -0.5, QVecShared::SEPD_CHANNELS-0.5); - m_profiles["h_sEPD_Bad_Channels"] = std::make_unique("h_sEPD_Bad_Channels", "sEPD Bad Channels; Channel; Status", QVecShared::sepd_channels, -0.5, QVecShared::sepd_channels-0.5); + se->registerHisto(h2SEPD_South_Charge_rbin); + se->registerHisto(h2SEPD_North_Charge_rbin); + se->registerHisto(h2SEPD_South_Charge_rbinv2); + se->registerHisto(h2SEPD_North_Charge_rbinv2); + se->registerHisto(hSEPD_Bad_Channels); - auto* h2S = m_hists2D["h2SEPD_South_Charge_rbin"].get(); - auto* h2N = m_hists2D["h2SEPD_North_Charge_rbin"].get(); + auto* h2S = h2SEPD_South_Charge_rbin; + auto* h2N = h2SEPD_North_Charge_rbin; - auto* h2Sv2 = m_hists2D["h2SEPD_South_Charge_rbinv2"].get(); - auto* h2Nv2 = m_hists2D["h2SEPD_North_Charge_rbinv2"].get(); + auto* h2Sv2 = h2SEPD_South_Charge_rbinv2; + auto* h2Nv2 = h2SEPD_North_Charge_rbinv2; - auto* hBad = m_profiles["h_sEPD_Bad_Channels"].get(); + auto* hBad = hSEPD_Bad_Channels; - for (int channel = 0; channel < QVecShared::sepd_channels; ++channel) + for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) { - unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); - int rbin = static_cast(TowerInfoDefs::get_epd_rbin(key)); + unsigned int key = TowerInfoDefs::encode_epd(channel); + int rbin = TowerInfoDefs::get_epd_rbin(key); unsigned int arm = TowerInfoDefs::get_epd_arm(key); double avg_charge = hSEPD_Charge->GetBinContent(channel + 1); @@ -255,21 +250,21 @@ void QVecCalib::process_bad_channels(TFile* file) h2->Fill(rbin, avg_charge); } - std::unique_ptr hSpx(h2S->ProfileX("hSpx", 2, -1, "s")); - std::unique_ptr hNpx(h2N->ProfileX("hNpx", 2, -1, "s")); + auto* hSpx = h2S->ProfileX("hSpx", 2, -1, "s"); + auto* hNpx = h2N->ProfileX("hNpx", 2, -1, "s"); int ctr_dead = 0; int ctr_hot = 0; int ctr_cold = 0; - for (int channel = 0; channel < QVecShared::sepd_channels; ++channel) + for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) { - unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); - int rbin = static_cast(TowerInfoDefs::get_epd_rbin(key)); + unsigned int key = TowerInfoDefs::encode_epd(channel); + int rbin = TowerInfoDefs::get_epd_rbin(key); unsigned int arm = TowerInfoDefs::get_epd_arm(key); auto* h2 = (arm == 0) ? h2Sv2 : h2Nv2; - auto* hprof = (arm == 0) ? hSpx.get() : hNpx.get(); + auto* hprof = (arm == 0) ? hSpx : hNpx; double charge = hSEPD_Charge->GetBinContent(channel + 1); double mean_charge = hprof->GetBinContent(rbin + 1); @@ -281,7 +276,7 @@ void QVecCalib::process_bad_channels(TFile* file) zscore = (charge - mean_charge) / sigma; } - if (charge < m_sEPD_min_avg_charge_threshold || std::fabs(zscore) > m_sEPD_sigma_threshold) + if (charge < m_sEPD_min_avg_charge_threshold || std::abs(zscore) > m_sEPD_sigma_threshold) { m_bad_channels.insert(channel); @@ -311,7 +306,8 @@ void QVecCalib::process_bad_channels(TFile* file) } hBad->Fill(channel, status_fill); - std::cout << std::format("{:4} Channel: {:3d}, arm: {}, rbin: {:2d}, Mean: {:5.2f}, Charge: {:5.2f}, Z-Score: {:5.2f}\n", type, channel, arm, rbin, mean_charge, charge, zscore); + std::cout << std::format("{:4} Channel: {:3d}, arm: {}, rbin: {:2d}, Mean: {:5.2f}, Charge: {:5.2f}, Z-Score: {:5.2f}", + type, channel, arm, rbin, mean_charge, charge, zscore) << std::endl; } else { @@ -319,9 +315,10 @@ void QVecCalib::process_bad_channels(TFile* file) } } - std::cout << std::format("Total Bad Channels: {}, Dead: {}, Hot: {}, Cold: {}\n", m_bad_channels.size(), ctr_dead, ctr_hot, ctr_cold); + std::cout << std::format("Total Bad Channels: {}, Dead: {}, Hot: {}, Cold: {}", m_bad_channels.size(), ctr_dead, ctr_hot, ctr_cold) << std::endl; std::cout << "Finished processing Hot sEPD channels" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; } void QVecCalib::init_hists() @@ -330,7 +327,10 @@ void QVecCalib::init_hists() double psi_low = -std::numbers::pi; double psi_high = std::numbers::pi; - m_hists1D["h_Cent"] = std::make_unique("h_Cent", "", m_cent_bins, m_cent_low, m_cent_high); + Fun4AllServer *se = Fun4AllServer::instance(); + + hCentrality = new TH1F("hCentrality", "|z| < 10 cm and MB; Centrality [%]; Events", m_cent_bins, m_cent_low, m_cent_high); + se->registerHisto(hCentrality); std::string pass_suffix; if (m_pass == Pass::ApplyRecentering) @@ -353,9 +353,9 @@ void QVecCalib::init_hists() std::string title_N = std::format("sEPD North #Psi (Order {0}); Centrality [%]; {0}#Psi^{{N}}_{{{0}}}", n); std::string title_NS = std::format("sEPD North South #Psi (Order {0}); Centrality [%]; {0}#Psi^{{NS}}_{{{0}}}", n); - m_hists2D[name_S] = std::make_unique(name_S.c_str(), title_S.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); - m_hists2D[name_N] = std::make_unique(name_N.c_str(), title_N.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); - m_hists2D[name_NS] = std::make_unique(name_NS.c_str(), title_NS.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + m_hists2D[name_S] = new TH2F(name_S.c_str(), title_S.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + m_hists2D[name_N] = new TH2F(name_N.c_str(), title_N.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + m_hists2D[name_NS] = new TH2F(name_NS.c_str(), title_NS.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); // South, North for (auto det : m_subdetectors) @@ -378,7 +378,7 @@ void QVecCalib::init_hists() if (!q_avg_sq_cross_name.empty()) { - m_profiles[q_avg_sq_cross_name] = std::make_unique(q_avg_sq_cross_name.c_str(), q_avg_sq_cross_title.c_str(), + m_profiles[q_avg_sq_cross_name] = new TProfile(q_avg_sq_cross_name.c_str(), q_avg_sq_cross_title.c_str(), m_cent_bins, m_cent_low, m_cent_high); } @@ -390,7 +390,7 @@ void QVecCalib::init_hists() auto add_profile = [&](const std::string& prof_name, std::string_view label_suffix = "") { std::string title = std::format("sEPD {}; Centrality [%]; ", det_name, n, comp_str, label_suffix); - m_profiles[prof_name] = std::make_unique(prof_name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + m_profiles[prof_name] = new TProfile(prof_name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); }; add_profile(name); @@ -430,7 +430,7 @@ void QVecCalib::init_hists() { std::string name = QVecShared::get_hist_name(det_str, comp, n); std::string title = std::format("sEPD NS; Centrality [%]; ", n, comp); - m_profiles[name] = std::make_unique(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + m_profiles[name] = new TProfile(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); } // Initialize Validation Profiles (Flattened NS) @@ -440,11 +440,355 @@ void QVecCalib::init_hists() { std::string name = QVecShared::get_hist_name(det_str, comp, n, "_corr"); std::string title = std::format("sEPD NS Corrected; Centrality [%]; ", n, comp); - m_profiles[name] = std::make_unique(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + m_profiles[name] = new TProfile(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + } + } + } + } +} + +std::array, 2> QVecCalib::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) +{ + double D_arg = (xx * yy) - (xy * xy); + if (D_arg < 1e-12) + { + std::cout << "Warning: Near-zero determinant in bin " << cent_bin << ". Skipping matrix calc." << std::endl; + return std::array, 2>{{{1, 0}, {0, 1}}}; // Return Identity + } + double D = std::sqrt(D_arg); + + double N_term = D * (xx + yy + (2 * D)); + if (N_term <= 0) + { + throw std::runtime_error(std::format( + "Invalid N-term ({}) for n={}, cent={}, det={}", N_term, n, cent_bin, det_label)); + } + double inv_sqrt_N = 1.0 / std::sqrt(N_term); + + std::array, 2> mat{}; + mat[0][0] = inv_sqrt_N * (yy + D); + mat[0][1] = -inv_sqrt_N * xy; + mat[1][0] = mat[0][1]; + mat[1][1] = inv_sqrt_N * (xx + D); + return mat; +} + +template +T* QVecCalib::load_and_clone(TFile* file, const std::string& name) { + auto* obj = file->Get(name.c_str()); + if (!obj) + { + throw std::runtime_error(std::format("Could not find histogram '{}' in file '{}'", name, file->GetName())); + } + return static_cast(obj->Clone()); +} + +int QVecCalib::load_correction_data() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + auto* file = TFile::Open(m_input_Q_calib.c_str()); + + if (!file || file->IsZombie()) + { + std::cout << PHWHERE << "Error! Cannot open: " << m_input_Q_calib << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + using SD = QVecShared::Subdetector; + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + // Helper to load and register histograms automatically + auto load_reg = [&](const std::string& det, const std::string& var, const std::string& suffix = "") + { + std::string name = QVecShared::get_hist_name(det, var, n, suffix); + m_profiles[name] = load_and_clone(file, name); + se->registerHisto(m_profiles[name]); + return name; + }; + + // Load standard Recentering averages for S and N + std::string s_names[2][2]; // [det][comp] + for (int d = 0; d < 2; ++d) + { + std::string det_str = (d == 0) ? "S" : "N"; + s_names[d][0] = load_reg(det_str, "x"); + s_names[d][1] = load_reg(det_str, "y"); + } + + // Load Flattening (2nd moment) data if needed + if (m_pass == Pass::ApplyFlattening) + { + for (const auto& det_str : {"S", "N", "NS"}) + { + for (const auto& var : {"xx", "yy", "xy"}) + { + load_reg(det_str, var); + } + } + } + + // Populate the CorrectionData matrix + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int bin = static_cast(cent_bin) + 1; + + // Populate Recentering (S, N) + for (int d = 0; d < 2; ++d) + { + m_correction_data[cent_bin][h_idx][d].avg_Q = {m_profiles[s_names[d][0]]->GetBinContent(bin), m_profiles[s_names[d][1]]->GetBinContent(bin)}; + } + + if (m_pass == Pass::ApplyFlattening) + { + // Populate Flattening for S, N, and NS + for (int d = 0; d < (int) SD::Count; ++d) + { + std::string det_str = (d == 0) ? "S" : (d == 1) ? "N" : "NS"; + double xx = m_profiles[QVecShared::get_hist_name(det_str, "xx", n)]->GetBinContent(bin); + double yy = m_profiles[QVecShared::get_hist_name(det_str, "yy", n)]->GetBinContent(bin); + double xy = m_profiles[QVecShared::get_hist_name(det_str, "xy", n)]->GetBinContent(bin); + + auto& data = m_correction_data[cent_bin][h_idx][d]; + data.X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, det_str); + data.avg_Q_xx = xx; + data.avg_Q_yy = yy; + data.avg_Q_xy = xy; } } } } + + file->Close(); + delete file; + return Fun4AllReturnCodes::EVENT_OK; +} + +void QVecCalib::prepare_average_hists() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + + for (int n : m_harmonics) + { + std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); + std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); + std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); + std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}", n); + + AverageHists h; + + h.S_x_avg = m_profiles.at(S_x_avg_name); + h.S_y_avg = m_profiles.at(S_y_avg_name); + h.N_x_avg = m_profiles.at(N_x_avg_name); + h.N_y_avg = m_profiles.at(N_y_avg_name); + + h.Psi_S = m_hists2D.at(psi_S_name); + h.Psi_N = m_hists2D.at(psi_N_name); + h.Psi_NS = m_hists2D.at(psi_NS_name); + + se->registerHisto(h.S_x_avg); + se->registerHisto(h.S_y_avg); + se->registerHisto(h.N_x_avg); + se->registerHisto(h.N_y_avg); + + se->registerHisto(h.Psi_S); + se->registerHisto(h.Psi_N); + se->registerHisto(h.Psi_NS); + + m_average_hists.push_back(h); + } +} + +void QVecCalib::prepare_recenter_hists() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + + for (int n : m_harmonics) + { + std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr"); + std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr"); + std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr"); + std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr"); + + std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); + std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); + std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); + std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); + std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); + std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); + + std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); + std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); + std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr", n); + + RecenterHists h; + + h.S_x_corr_avg = m_profiles.at(S_x_corr_avg_name); + h.S_y_corr_avg = m_profiles.at(S_y_corr_avg_name); + h.N_x_corr_avg = m_profiles.at(N_x_corr_avg_name); + h.N_y_corr_avg = m_profiles.at(N_y_corr_avg_name); + + h.S_xx_avg = m_profiles.at(S_xx_avg_name); + h.S_yy_avg = m_profiles.at(S_yy_avg_name); + h.S_xy_avg = m_profiles.at(S_xy_avg_name); + + h.N_xx_avg = m_profiles.at(N_xx_avg_name); + h.N_yy_avg = m_profiles.at(N_yy_avg_name); + h.N_xy_avg = m_profiles.at(N_xy_avg_name); + + h.NS_xx_avg = m_profiles.at(NS_xx_avg_name); + h.NS_yy_avg = m_profiles.at(NS_yy_avg_name); + h.NS_xy_avg = m_profiles.at(NS_xy_avg_name); + + h.Psi_S_corr = m_hists2D.at(psi_S_name); + h.Psi_N_corr = m_hists2D.at(psi_N_name); + h.Psi_NS_corr = m_hists2D.at(psi_NS_name); + + se->registerHisto(h.S_x_corr_avg); + se->registerHisto(h.S_y_corr_avg); + se->registerHisto(h.N_x_corr_avg); + se->registerHisto(h.N_y_corr_avg); + + se->registerHisto(h.S_xx_avg); + se->registerHisto(h.S_yy_avg); + se->registerHisto(h.S_xy_avg); + + se->registerHisto(h.N_xx_avg); + se->registerHisto(h.N_yy_avg); + se->registerHisto(h.N_xy_avg); + + se->registerHisto(h.NS_xx_avg); + se->registerHisto(h.NS_yy_avg); + se->registerHisto(h.NS_xy_avg); + + se->registerHisto(h.Psi_S_corr); + se->registerHisto(h.Psi_N_corr); + se->registerHisto(h.Psi_NS_corr); + + m_recenter_hists.push_back(h); + } +} + +void QVecCalib::prepare_flattening_hists() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + + for (int n : m_harmonics) + { + std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2"); + std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2"); + std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2"); + std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2"); + + std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr"); + std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr"); + std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr"); + std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr"); + std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); + std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); + + std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr"); + std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr"); + std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr"); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr2", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr2", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr2", n); + + FlatteningHists h; + + h.S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name); + h.S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name); + h.N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name); + h.N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name); + + h.S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name); + h.S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name); + h.S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name); + + h.N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name); + h.N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name); + h.N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name); + + h.NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name); + h.NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name); + h.NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name); + + h.Psi_S_corr2 = m_hists2D.at(psi_S_name); + h.Psi_N_corr2 = m_hists2D.at(psi_N_name); + h.Psi_NS_corr2 = m_hists2D.at(psi_NS_name); + + se->registerHisto(h.S_x_corr2_avg); + se->registerHisto(h.S_y_corr2_avg); + se->registerHisto(h.N_x_corr2_avg); + se->registerHisto(h.N_y_corr2_avg); + + se->registerHisto(h.S_xx_corr_avg); + se->registerHisto(h.S_yy_corr_avg); + se->registerHisto(h.S_xy_corr_avg); + + se->registerHisto(h.N_xx_corr_avg); + se->registerHisto(h.N_yy_corr_avg); + se->registerHisto(h.N_xy_corr_avg); + + se->registerHisto(h.NS_xx_corr_avg); + se->registerHisto(h.NS_yy_corr_avg); + se->registerHisto(h.NS_xy_corr_avg); + + se->registerHisto(h.Psi_S_corr2); + se->registerHisto(h.Psi_N_corr2); + se->registerHisto(h.Psi_NS_corr2); + + m_flattening_hists.push_back(h); + } +} + +int QVecCalib::InitRun(PHCompositeNode *topNode) +{ + RunHeader* run_header = findNode::getClass(topNode, "RunHeader"); + if (!run_header) + { + std::cout << PHWHERE << "RunHeader Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_runnumber = run_header->get_RunNumber(); + + EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << "TOWERGEOM_EPD Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_trig_cache.assign(m_harmonics.size(), std::vector>(QVecShared::SEPD_CHANNELS)); + + for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(channel); + double phi = epdgeom->get_phi(key); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + m_trig_cache[h_idx][channel] = {std::cos(n * phi), std::sin(n * phi)}; + } + } + + std::cout << "QVecCalib::InitRun - Trigonometry cache initialized for " + << QVecShared::SEPD_CHANNELS << " channels." << std::endl; + + return Fun4AllReturnCodes::EVENT_OK; } void QVecCalib::process_averages(double cent, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const AverageHists& h) @@ -465,12 +809,15 @@ void QVecCalib::process_averages(double cent, const QVecShared::QVec& q_S, const void QVecCalib::process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h) { - size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); + size_t cent_bin = static_cast(hCentrality->FindBin(cent) - 1); - double Q_S_x_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.x; - double Q_S_y_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.y; - double Q_N_x_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.x; - double Q_N_y_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.y; + const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S]; + const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N]; + + double Q_S_x_avg = S.avg_Q.x; + double Q_S_y_avg = S.avg_Q.y; + double Q_N_x_avg = N.avg_Q.x; + double Q_N_y_avg = N.avg_Q.y; QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; @@ -506,12 +853,16 @@ void QVecCalib::process_recentering(double cent, size_t h_idx, const QVecShared: void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h) { - size_t cent_bin = static_cast(m_hists1D["h_Cent"]->FindBin(cent) - 1); + size_t cent_bin = static_cast(hCentrality->FindBin(cent) - 1); + + const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S]; + const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N]; + const auto& NS = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::NS]; - double Q_S_x_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.x; - double Q_S_y_avg = m_correction_data[cent_bin][h_idx][0].avg_Q.y; - double Q_N_x_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.x; - double Q_N_y_avg = m_correction_data[cent_bin][h_idx][1].avg_Q.y; + double Q_S_x_avg = S.avg_Q.x; + double Q_S_y_avg = S.avg_Q.y; + double Q_N_x_avg = N.avg_Q.x; + double Q_N_y_avg = N.avg_Q.y; QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; @@ -519,9 +870,9 @@ void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared:: // Construct Combined Recentered Vector QVecShared::QVec q_NS_corr = {q_S_corr.x + q_N_corr.x, q_S_corr.y + q_N_corr.y}; - const auto& X_S = m_correction_data[cent_bin][h_idx][0].X_matrix; - const auto& X_N = m_correction_data[cent_bin][h_idx][1].X_matrix; - const auto& X_NS = m_correction_data[cent_bin][h_idx][IDX_NS].X_matrix; + const auto& X_S = S.X_matrix; + const auto& X_N = N.X_matrix; + const auto& X_NS = NS.X_matrix; double Q_S_x_corr2 = X_S[0][0] * q_S_corr.x + X_S[0][1] * q_S_corr.y; double Q_S_y_corr2 = X_S[1][0] * q_S_corr.x + X_S[1][1] * q_S_corr.y; @@ -560,24 +911,174 @@ void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared:: h.Psi_NS_corr2->Fill(cent, psi_NS); } -void QVecCalib::compute_averages(size_t cent_bin, int h_idx) +bool QVecCalib::process_sEPD() { - int n = m_harmonics[h_idx]; + double sepd_total_charge_south = 0; + double sepd_total_charge_north = 0; - std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); - std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); - std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); - std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + // Loop over all sEPD Channels + for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) + { + double charge = m_evtdata->get_sepd_charge(channel); - int bin = static_cast(cent_bin + 1); + // Skip Bad Channels + if (m_bad_channels.contains(channel) || charge <= 0) + { + continue; + } + + unsigned int key = TowerInfoDefs::encode_epd(channel); + unsigned int arm = TowerInfoDefs::get_epd_arm(key); + + // arm = 0: South + // arm = 1: North + if (arm == 0) + { + sepd_total_charge_south += charge; + } + else + { + sepd_total_charge_north += charge; + } + + // Compute Raw Q vectors for each harmonic and respective arm + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + // Optimized lookup instead of std::cos/std::sin calls + const auto& [cached_cos, cached_sin] = m_trig_cache[h_idx][channel]; + + m_q_vectors[h_idx][arm].x += charge * cached_cos; + m_q_vectors[h_idx][arm].y += charge * cached_sin; + } + } + + // Skip Events with Zero sEPD Total Charge in either arm + if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) + { + return false; + } + + // Normalize the Q-vectors by total charge + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + for (auto det : m_subdetectors) + { + size_t det_idx = (det == QVecShared::Subdetector::S) ? 0 : 1; + double sepd_total_charge = (det_idx == 0) ? sepd_total_charge_south : sepd_total_charge_north; + m_q_vectors[h_idx][det_idx].x /= sepd_total_charge; + m_q_vectors[h_idx][det_idx].y /= sepd_total_charge; + } + } + + return true; +} + +bool QVecCalib::process_event_check() +{ + double cent = m_evtdata->get_event_centrality(); + int cent_bin = hSEPD_Charge_Min->FindBin(cent); + + double sepd_totalcharge = m_evtdata->get_sepd_totalcharge(); + + double sepd_totalcharge_min = hSEPD_Charge_Min->GetBinContent(cent_bin); + double sepd_totalcharge_max = hSEPD_Charge_Max->GetBinContent(cent_bin); + + return sepd_totalcharge > sepd_totalcharge_min && sepd_totalcharge < sepd_totalcharge_max; +} + +//____________________________________________________________________________.. +int QVecCalib::process_event([[maybe_unused]] PHCompositeNode *topNode) +{ + m_evtdata = findNode::getClass(topNode, "EventPlaneData"); + if (!m_evtdata) + { + std::cout << PHWHERE << "EventPlaneData Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + int event_id = m_evtdata->get_event_id(); + + if (Verbosity() && m_event % PROGRESS_REPORT_INTERVAL == 0) + { + std::cout << "Progress: " << m_event << ", Global: " << event_id << std::endl; + } + ++m_event; + + double cent = m_evtdata->get_event_centrality(); + + bool isGood = process_event_check(); + + // Skip Events with non correlation between centrality and sEPD + if (!isGood) + { + ++m_event_counters.bad_centrality_sepd_correlation; + return Fun4AllReturnCodes::ABORTEVENT; + } + + isGood = process_sEPD(); + + // Skip Events with Zero sEPD Total Charge in either arm + if (!isGood) + { + ++m_event_counters.zero_sepd_total_charge; + return Fun4AllReturnCodes::ABORTEVENT; + } + + hCentrality->Fill(cent); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + const auto& q_S = m_q_vectors[h_idx][0]; // 0 for South + const auto& q_N = m_q_vectors[h_idx][1]; // 1 for North + + // --- First Pass: Derive 1st Order --- + if (m_pass == Pass::ComputeRecentering) + { + process_averages(cent, q_S, q_N, m_average_hists[h_idx]); + } + + // --- Second Pass: Apply 1st Order, Derive 2nd Order --- + else if (m_pass == Pass::ApplyRecentering) + { + process_recentering(cent, h_idx, q_S, q_N, m_recenter_hists[h_idx]); + } + + // --- Third Pass: Apply 2nd Order, Validate --- + else if (m_pass == Pass::ApplyFlattening) + { + process_flattening(cent, h_idx, q_S, q_N, m_flattening_hists[h_idx]); + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int QVecCalib::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) +{ + m_q_vectors = {}; + + return Fun4AllReturnCodes::EVENT_OK; +} + +void QVecCalib::compute_averages(size_t cent_bin, int h_idx) +{ + int n = m_harmonics[h_idx]; + + std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); + std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); + std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); + std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + + int bin = static_cast(cent_bin + 1); double Q_S_x_avg = m_profiles[S_x_avg_name]->GetBinContent(bin); double Q_S_y_avg = m_profiles[S_y_avg_name]->GetBinContent(bin); double Q_N_x_avg = m_profiles[N_x_avg_name]->GetBinContent(bin); double Q_N_y_avg = m_profiles[N_y_avg_name]->GetBinContent(bin); - m_correction_data[cent_bin][h_idx][0].avg_Q = {Q_S_x_avg, Q_S_y_avg}; - m_correction_data[cent_bin][h_idx][1].avg_Q = {Q_N_x_avg, Q_N_y_avg}; + m_correction_data[cent_bin][h_idx][(size_t)QVecShared::Subdetector::S].avg_Q = {Q_S_x_avg, Q_S_y_avg}; + m_correction_data[cent_bin][h_idx][(size_t)QVecShared::Subdetector::N].avg_Q = {Q_N_x_avg, Q_N_y_avg}; std::cout << std::format( "Centrality Bin: {}, " @@ -585,39 +1086,13 @@ void QVecCalib::compute_averages(size_t cent_bin, int h_idx) "Q_S_x_avg: {:13.10f}, " "Q_S_y_avg: {:13.10f}, " "Q_N_x_avg: {:13.10f}, " - "Q_N_y_avg: {:13.10f}\n", + "Q_N_y_avg: {:13.10f}", cent_bin, n, Q_S_x_avg, Q_S_y_avg, Q_N_x_avg, - Q_N_y_avg); -} - -std::array, 2> QVecCalib::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) -{ - double D_arg = (xx * yy) - (xy * xy); - if (D_arg <= 0) - { - throw std::runtime_error(std::format( - "Invalid D-term ({}) for n={}, cent={}, det={}", D_arg, n, cent_bin, det_label)); - } - double D = std::sqrt(D_arg); - - double N_term = D * (xx + yy + (2 * D)); - if (N_term <= 0) - { - throw std::runtime_error(std::format( - "Invalid N-term ({}) for n={}, cent={}, det={}", N_term, n, cent_bin, det_label)); - } - double inv_sqrt_N = 1.0 / std::sqrt(N_term); - - std::array, 2> mat{}; - mat[0][0] = inv_sqrt_N * (yy + D); - mat[0][1] = -inv_sqrt_N * xy; - mat[1][0] = mat[0][1]; - mat[1][1] = inv_sqrt_N * (xx + D); - return mat; + Q_N_y_avg) << std::endl; } void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) @@ -660,7 +1135,7 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) double Q_NS_yy_avg = m_profiles[NS_yy_avg_name]->GetBinContent(bin); double Q_NS_xy_avg = m_profiles[NS_xy_avg_name]->GetBinContent(bin); - m_correction_data[cent_bin][h_idx][IDX_NS].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); + m_correction_data[cent_bin][h_idx][(size_t)QVecShared::Subdetector::NS].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); for (size_t det_idx = 0; det_idx < 2; ++det_idx) { @@ -685,7 +1160,7 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) "Q_NS_xx_avg / Q_NS_yy_avg: {:13.10f}, " "Q_S_xy_avg: {:13.10f}, " "Q_N_xy_avg: {:13.10f}, " - "Q_NS_xy_avg: {:13.10f}\n", + "Q_NS_xy_avg: {:13.10f}", cent_bin, n, Q_S_x_corr_avg, @@ -697,7 +1172,7 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) Q_NS_xx_avg / Q_NS_yy_avg, Q_S_xy_avg, Q_N_xy_avg, - Q_NS_xy_avg); + Q_NS_xy_avg) << std::endl; } void QVecCalib::print_flattening(size_t cent_bin, int n) const @@ -748,7 +1223,7 @@ void QVecCalib::print_flattening(size_t cent_bin, int n) const "Q_NS_xx_corr_avg / Q_NS_yy_corr_avg: {:13.10f}, " "Q_S_xy_corr_avg: {:13.10f}, " "Q_N_xy_corr_avg: {:13.10f}, " - "Q_NS_xy_corr_avg: {:13.10f}\n", + "Q_NS_xy_corr_avg: {:13.10f}", cent_bin, n, Q_S_x_corr2_avg, @@ -760,331 +1235,149 @@ void QVecCalib::print_flattening(size_t cent_bin, int n) const Q_NS_xx_corr_avg / Q_NS_yy_corr_avg, Q_S_xy_corr_avg, Q_N_xy_corr_avg, - Q_NS_xy_corr_avg); + Q_NS_xy_corr_avg) << std::endl; } -std::vector QVecCalib::prepare_average_hists() +void QVecCalib::write_cdb() { - std::vector hists_cache; - for (int n : m_harmonics) + std::error_code ec; + if (std::filesystem::create_directories(m_cdb_output_dir, ec)) { - - std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); - std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); - std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); - std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); - - std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}", n); - std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}", n); - std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}", n); - - AverageHists h; - - h.S_x_avg = m_profiles.at(S_x_avg_name).get(); - h.S_y_avg = m_profiles.at(S_y_avg_name).get(); - h.N_x_avg = m_profiles.at(N_x_avg_name).get(); - h.N_y_avg = m_profiles.at(N_y_avg_name).get(); - - h.Psi_S = m_hists2D.at(psi_S_name).get(); - h.Psi_N = m_hists2D.at(psi_N_name).get(); - h.Psi_NS = m_hists2D.at(psi_NS_name).get(); - - hists_cache.push_back(h); + std::cout << "Success: Directory " << m_cdb_output_dir << " created" << std::endl; } - - return hists_cache; -} - -bool QVecCalib::process_sEPD() -{ - size_t nChannels = m_event_data.sepd_channel->size(); - - double sepd_total_charge_south = 0; - double sepd_total_charge_north = 0; - - // Loop over all sEPD Channels - for (size_t idx = 0; idx < nChannels; ++idx) - { - int channel = m_event_data.sepd_channel->at(idx); - double charge = m_event_data.sepd_charge->at(idx); - double phi = m_event_data.sepd_phi->at(idx); - - // Skip Bad Channels - if (m_bad_channels.contains(channel)) - { - continue; - } - - unsigned int key = TowerInfoDefs::encode_epd(static_cast(channel)); - unsigned int arm = TowerInfoDefs::get_epd_arm(key); - - // arm = 0: South - // arm = 1: North - double& sepd_total_charge = (arm == 0) ? sepd_total_charge_south : sepd_total_charge_north; - - // Compute total charge for the respective sEPD arm - sepd_total_charge += charge; - - // Compute Raw Q vectors for each harmonic and respective arm - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - m_event_data.q_vectors[h_idx][arm].x += charge * std::cos(n * phi); - m_event_data.q_vectors[h_idx][arm].y += charge * std::sin(n * phi); - } - } - - // Skip Events with Zero sEPD Total Charge in either arm - if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) + else if (ec) { - return false; + throw std::runtime_error(std::format("Failed to create directory {}: {}", m_cdb_output_dir, ec.message())); } - - // Normalize the Q-vectors by total charge - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + else { - for (auto det : m_subdetectors) - { - size_t det_idx = (det == QVecShared::Subdetector::S) ? 0 : 1; - double sepd_total_charge = (det_idx == 0) ? sepd_total_charge_south : sepd_total_charge_north; - m_event_data.q_vectors[h_idx][det_idx].x /= sepd_total_charge; - m_event_data.q_vectors[h_idx][det_idx].y /= sepd_total_charge; - } + std::cout << "Info: Directory " << m_cdb_output_dir << " already exists." << std::endl; } - return true; + write_cdb_BadTowers(); + write_cdb_EventPlane(); } -std::vector QVecCalib::prepare_recenter_hists() +void QVecCalib::write_cdb_BadTowers() { - std::vector hists_cache; - for (int n : m_harmonics) - { - std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr"); - std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr"); - std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr"); - std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr"); + std::cout << "Writing Bad Towers CDB" << std::endl; - std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); - std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); - std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); - std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); - std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); - std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); + std::string payload = "SEPD_HotMap"; + std::string fieldname_status = "status"; + std::string fieldname_sigma = "SEPD_sigma"; + std::string output_file = std::format("{}/{}-{}-{}.root", m_cdb_output_dir, payload, m_dst_tag, m_runnumber); - std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); - std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); - std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); - - std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr", n); - std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr", n); - std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr", n); - - RecenterHists h; - - h.S_x_corr_avg = m_profiles.at(S_x_corr_avg_name).get(); - h.S_y_corr_avg = m_profiles.at(S_y_corr_avg_name).get(); - h.N_x_corr_avg = m_profiles.at(N_x_corr_avg_name).get(); - h.N_y_corr_avg = m_profiles.at(N_y_corr_avg_name).get(); - - h.S_xx_avg = m_profiles.at(S_xx_avg_name).get(); - h.S_yy_avg = m_profiles.at(S_yy_avg_name).get(); - h.S_xy_avg = m_profiles.at(S_xy_avg_name).get(); - h.N_xx_avg = m_profiles.at(N_xx_avg_name).get(); - h.N_yy_avg = m_profiles.at(N_yy_avg_name).get(); - h.N_xy_avg = m_profiles.at(N_xy_avg_name).get(); - - h.NS_xx_avg = m_profiles.at(NS_xx_avg_name).get(); - h.NS_yy_avg = m_profiles.at(NS_yy_avg_name).get(); - h.NS_xy_avg = m_profiles.at(NS_xy_avg_name).get(); - - h.Psi_S_corr = m_hists2D.at(psi_S_name).get(); - h.Psi_N_corr = m_hists2D.at(psi_N_name).get(); - h.Psi_NS_corr = m_hists2D.at(psi_NS_name).get(); + CDBTTree cdbttree(output_file); - hists_cache.push_back(h); - } - - return hists_cache; -} - -std::vector QVecCalib::prepare_flattening_hists() -{ - std::vector hists_cache; - for (int n : m_harmonics) + for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) { + unsigned int key = TowerInfoDefs::encode_epd(channel); + int status = hSEPD_Bad_Channels->GetBinContent(channel+1); - std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2"); - std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2"); - std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2"); - std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2"); + float sigma = 0; - std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr"); - std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr"); - std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr"); - std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr"); - std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); - std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); - - std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr"); - std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr"); - std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr"); - - std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr2", n); - std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr2", n); - std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr2", n); - - FlatteningHists h; - - h.S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name).get(); - h.S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name).get(); - h.N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name).get(); - h.N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name).get(); - - h.S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name).get(); - h.S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name).get(); - h.S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name).get(); - - h.N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name).get(); - h.N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name).get(); - h.N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name).get(); - - h.NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name).get(); - h.NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name).get(); - h.NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name).get(); + // Hot + if (status == static_cast(QVecShared::ChannelStatus::Hot)) + { + sigma = SIGMA_HOT; + } - h.Psi_S_corr2 = m_hists2D.at(psi_S_name).get(); - h.Psi_N_corr2 = m_hists2D.at(psi_N_name).get(); - h.Psi_NS_corr2 = m_hists2D.at(psi_NS_name).get(); + // Cold + else if (status == static_cast(QVecShared::ChannelStatus::Cold)) + { + sigma = SIGMA_COLD; + } - hists_cache.push_back(h); + cdbttree.SetIntValue(key, fieldname_status, status); + cdbttree.SetFloatValue(key, fieldname_sigma, sigma); } - return hists_cache; -} + std::cout << "Saving CDB: " << payload << " to " << output_file << std::endl; -bool QVecCalib::process_event_check() -{ - auto* hSEPD_Charge_Min = m_profiles["hSEPD_Charge_Min"].get(); - auto* hSEPD_Charge_Max = m_profiles["hSEPD_Charge_Max"].get(); - - double cent = m_event_data.event_centrality; - int cent_bin = hSEPD_Charge_Min->FindBin(cent); - - double sepd_totalcharge = m_event_data.sepd_totalcharge; - - double sepd_totalcharge_min = hSEPD_Charge_Min->GetBinContent(cent_bin); - double sepd_totalcharge_max = hSEPD_Charge_Max->GetBinContent(cent_bin); - - return sepd_totalcharge > sepd_totalcharge_min && sepd_totalcharge < sepd_totalcharge_max; + cdbttree.Commit(); + cdbttree.WriteCDBTTree(); } -void QVecCalib::run_event_loop() +void QVecCalib::write_cdb_EventPlane() { - std::cout << std::format("Pass: {}\n", static_cast(m_pass)); + std::cout << "Writing Event Plane CDB" << std::endl; - long long n_entries = m_chain->GetEntries(); - if (m_events_to_process > 0) - { - n_entries = std::min(m_events_to_process, n_entries); - } + std::string payload = "SEPD_EventPlaneCalib"; + std::string output_file = std::format("{}/{}-{}-{}.root", m_cdb_output_dir, payload, m_dst_tag, m_runnumber); - std::vector average_hists; - std::vector recenter_hists; - std::vector flattening_hists; + CDBTTree cdbttree(output_file); - if (m_pass == Pass::ComputeRecentering) - { - average_hists = prepare_average_hists(); - } - else if (m_pass == Pass::ApplyRecentering) - { - recenter_hists = prepare_recenter_hists(); - } - else if (m_pass == Pass::ApplyFlattening) - { - flattening_hists = prepare_flattening_hists(); - } + using SD = QVecShared::Subdetector; - std::map ctr; - // Event Loop - for (long long i = 0; i < n_entries; ++i) + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { - // Load Event Data from TChain - m_chain->GetEntry(i); - m_event_data.reset(); - - if (i % PROGRESS_REPORT_INTERVAL == 0) - { - std::cout << std::format("Processing {}/{}: {:.2f} %", i, n_entries, static_cast(i) / n_entries * 100.) << std::endl; - } - - double cent = m_event_data.event_centrality; - - int cent_bin_int = m_hists1D["h_Cent"]->FindBin(cent) - 1; - - // ensure centrality is valid - if (cent_bin_int < 0 || static_cast(cent_bin_int) >= m_cent_bins) - { - std::cout << std::format("Weird Centrality: {}, Skipping Event: {}\n", cent, m_event_data.event_id); - ++ctr["invalid_cent_bin"]; - continue; - } - - bool isGood = process_event_check(); - - // Skip Events with non correlation between centrality and sEPD - if (!isGood) - { - ++ctr["bad_centrality_sepd_correlation"]; - continue; - } - - isGood = process_sEPD(); + int n = m_harmonics[h_idx]; - // Skip Events with Zero sEPD Total Charge in either arm - if (!isGood) + // Define lambdas to generate field names consistently + auto field = [&](const std::string& det, const std::string& var) { - ++ctr["zero_sepd_total_charge"]; - continue; - } + return std::format("Q_{}_{}_{}_avg", det, var, n); + }; - m_hists1D["h_Cent"]->Fill(cent); - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) { - const auto& q_S = m_event_data.q_vectors[h_idx][0]; // 0 for South - const auto& q_N = m_event_data.q_vectors[h_idx][1]; // 1 for North + int key = static_cast(cent_bin); - // --- First Pass: Derive 1st Order --- - if (m_pass == Pass::ComputeRecentering) + // Iterate through all subdetectors (S, N, NS) using the Enum Count + for (size_t d = 0; d < static_cast(SD::Count); ++d) { - process_averages(cent, q_S, q_N, average_hists[h_idx]); - } + auto det_enum = static_cast(d); - // --- Second Pass: Apply 1st Order, Derive 2nd Order --- - else if (m_pass == Pass::ApplyRecentering) - { - process_recentering(cent, h_idx, q_S, q_N, recenter_hists[h_idx]); - } + // Map enum to the string labels used in the CDB field names + std::string det_label; + switch (det_enum) + { + case SD::S: + det_label = "S"; + break; + case SD::N: + det_label = "N"; + break; + case SD::NS: + det_label = "NS"; + break; + default: + continue; + } - // --- Third Pass: Apply 2nd Order, Validate --- - else if (m_pass == Pass::ApplyFlattening) - { - process_flattening(cent, h_idx, q_S, q_N, flattening_hists[h_idx]); + const auto& data = m_correction_data[cent_bin][h_idx][d]; + // 1st Order Moments (Recentering) - Skip for NS as it is a combined vector + if (det_enum != SD::NS) + { + cdbttree.SetDoubleValue(key, field(det_label, "x"), data.avg_Q.x); + cdbttree.SetDoubleValue(key, field(det_label, "y"), data.avg_Q.y); + } + + // 2nd Order Moments (Flattening) - Applicable to S, N, and NS + cdbttree.SetDoubleValue(key, field(det_label, "xx"), data.avg_Q_xx); + cdbttree.SetDoubleValue(key, field(det_label, "yy"), data.avg_Q_yy); + cdbttree.SetDoubleValue(key, field(det_label, "xy"), data.avg_Q_xy); } } } - std::cout << "Skipped Event Types\n"; - for (const auto& [name, events] : ctr) - { - std::cout << std::format("{}: {}, {:.2f} %\n", name, events, static_cast(events) / n_entries * 100.); - } + std::cout << "Saving CDB: " << payload << " to " << output_file << std::endl; + + cdbttree.Commit(); + cdbttree.WriteCDBTTree(); +} + +//____________________________________________________________________________.. +int QVecCalib::End([[maybe_unused]] PHCompositeNode *topNode) +{ + std::cout << "QVecCalib::End(PHCompositeNode *topNode) This is the End..." << std::endl; - // --------------- + std::cout << "\n--- Event Counter Summary ---" << std::endl; + std::cout << "Bad Centrality/sEPD corr: " << m_event_counters.bad_centrality_sepd_correlation << std::endl; + std::cout << "Zero sEPD Charge: " << m_event_counters.zero_sepd_total_charge << std::endl; + std::cout << "Total Events Seen: " << m_event << std::endl; + std::cout << "-----------------------------\n" << std::endl; - std::cout << std::format("{:#<20}\n", ""); for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) { for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) @@ -1108,160 +1401,10 @@ void QVecCalib::run_event_loop() } } - std::cout << "Event loop finished." << std::endl; -} - -template -std::unique_ptr QVecCalib::load_and_clone(TFile* file, const std::string& name) { - auto* obj = dynamic_cast(file->Get(name.c_str())); - if (!obj) - { - throw std::runtime_error(std::format("Could not find histogram '{}' in file '{}'", name, file->GetName())); - } - return std::unique_ptr(static_cast(obj->Clone())); -} - -void QVecCalib::load_correction_data() -{ - TH1::AddDirectory(kFALSE); - - auto file = std::unique_ptr(TFile::Open(m_input_Q_calib.c_str())); - - // Check if the file was opened successfully. - if (!file || file->IsZombie()) - { - throw std::runtime_error(std::format("Could not open file '{}'", m_input_Q_calib)); - } - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - - std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); - std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); - std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); - std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); - - m_profiles[S_x_avg_name] = load_and_clone(file.get(), S_x_avg_name); - m_profiles[S_y_avg_name] = load_and_clone(file.get(), S_y_avg_name); - m_profiles[N_x_avg_name] = load_and_clone(file.get(), N_x_avg_name); - m_profiles[N_y_avg_name] = load_and_clone(file.get(), N_y_avg_name); - - std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); - std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); - std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); - std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); - std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); - std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); - - std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); - std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); - std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); - - if(m_pass == Pass::ApplyFlattening) - { - m_profiles[S_xx_avg_name] = load_and_clone(file.get(), S_xx_avg_name); - m_profiles[S_yy_avg_name] = load_and_clone(file.get(), S_yy_avg_name); - m_profiles[S_xy_avg_name] = load_and_clone(file.get(), S_xy_avg_name); - - m_profiles[N_xx_avg_name] = load_and_clone(file.get(), N_xx_avg_name); - m_profiles[N_yy_avg_name] = load_and_clone(file.get(), N_yy_avg_name); - m_profiles[N_xy_avg_name] = load_and_clone(file.get(), N_xy_avg_name); - - m_profiles[NS_xx_avg_name] = load_and_clone(file.get(), NS_xx_avg_name); - m_profiles[NS_yy_avg_name] = load_and_clone(file.get(), NS_yy_avg_name); - m_profiles[NS_xy_avg_name] = load_and_clone(file.get(), NS_xy_avg_name); - } - - size_t south_idx = static_cast(QVecShared::Subdetector::S); - size_t north_idx = static_cast(QVecShared::Subdetector::N); - - for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) - { - int bin = static_cast(cent_bin) + 1; - - double Q_S_x_avg = m_profiles[S_x_avg_name]->GetBinContent(bin); - double Q_S_y_avg = m_profiles[S_y_avg_name]->GetBinContent(bin); - double Q_N_x_avg = m_profiles[N_x_avg_name]->GetBinContent(bin); - double Q_N_y_avg = m_profiles[N_y_avg_name]->GetBinContent(bin); - - // Recentering Params - m_correction_data[cent_bin][h_idx][south_idx].avg_Q = {Q_S_x_avg, Q_S_y_avg}; - m_correction_data[cent_bin][h_idx][north_idx].avg_Q = {Q_N_x_avg, Q_N_y_avg}; - - if (m_pass == Pass::ApplyFlattening) - { - double Q_S_xx_avg = m_profiles[S_xx_avg_name]->GetBinContent(bin); - double Q_S_yy_avg = m_profiles[S_yy_avg_name]->GetBinContent(bin); - double Q_S_xy_avg = m_profiles[S_xy_avg_name]->GetBinContent(bin); - - double Q_N_xx_avg = m_profiles[N_xx_avg_name]->GetBinContent(bin); - double Q_N_yy_avg = m_profiles[N_yy_avg_name]->GetBinContent(bin); - double Q_N_xy_avg = m_profiles[N_xy_avg_name]->GetBinContent(bin); - - double Q_NS_xx_avg = m_profiles[NS_xx_avg_name]->GetBinContent(bin); - double Q_NS_yy_avg = m_profiles[NS_yy_avg_name]->GetBinContent(bin); - double Q_NS_xy_avg = m_profiles[NS_xy_avg_name]->GetBinContent(bin); - - m_correction_data[cent_bin][h_idx][IDX_NS].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); - - // Flattening Params - for (size_t det_idx = 0; det_idx < 2; ++det_idx) - { - double xx = (det_idx == 0) ? Q_S_xx_avg : Q_N_xx_avg; - double yy = (det_idx == 0) ? Q_S_yy_avg : Q_N_yy_avg; - double xy = (det_idx == 0) ? Q_S_xy_avg : Q_N_xy_avg; - - std::string label = (det_idx == 0) ? "S" : "N"; - - m_correction_data[cent_bin][h_idx][det_idx].X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, label); - } - } - } - } -} - -void QVecCalib::process_events() -{ - if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening) - { - load_correction_data(); - } - - run_event_loop(); -} - -void QVecCalib::save_results() const -{ - std::filesystem::create_directories(m_output_dir); - - std::filesystem::path input_path(m_input_file); - std::string output_stem = input_path.stem().string(); - std::string output_filename = std::format("{}/Q-vec-corr_Pass-{}_{}.root", m_output_dir, static_cast(m_pass), output_stem); - - auto output_file = std::make_unique(output_filename.c_str(), "RECREATE"); - - if (!output_file || output_file->IsZombie()) - { - throw std::runtime_error(std::format("Failed to create output file: {}", output_filename)); - } - - for (const auto& [name, hist] : m_hists1D) - { - std::cout << std::format("Saving 1D: {}\n", name); - hist->Write(); - } - for (const auto& [name, hist] : m_hists2D) - { - std::cout << std::format("Saving 2D: {}\n", name); - hist->Write(); - } - for (const auto& [name, hist] : m_profiles) + if (m_pass == Pass::ApplyFlattening) { - std::cout << std::format("Saving Profile: {}\n", name); - hist->Write(); + write_cdb(); } - output_file->Close(); - std::cout << std::format("Results saved to: {}", output_filename) << std::endl; + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index 7a70cfb03e..a0029949d8 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -3,23 +3,22 @@ #include "QVecDefs.h" -// ==================================================================== -// ROOT Includes -// ==================================================================== +#include + +#include +#include +#include +#include +#include -#include #include #include #include #include -// ==================================================================== -// Standard C++ Includes -// ==================================================================== -#include -#include -#include -#include +class PHCompositeNode; +class EventPlaneData; +class EpdGeom; /** * @class QVecCalib @@ -36,28 +35,34 @@ * * The class manages event-level selections based on charge-centrality correlations * and handles the exclusion of "bad" (hot/cold/dead) sEPD channels. */ -class QVecCalib +class QVecCalib : public SubsysReco { public: - // The constructor takes the configuration - QVecCalib(std::string input_file, std::string input_hist, std::string input_Q_calib, int pass, long long events, std::string output_dir) - : m_input_file(std::move(input_file)) - , m_input_hist(std::move(input_hist)) - , m_input_Q_calib(std::move(input_Q_calib)) - , m_pass(validate_pass(pass)) - , m_events_to_process(events) - , m_output_dir(std::move(output_dir)) - { - } + explicit QVecCalib(const std::string& name = "QVecCalib"); - void run() - { - setup_chain(); - process_QA_hist(); - init_hists(); - process_events(); - save_results(); - } + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode* topNode) override; + + /** Called for first event when run number is known. + Typically this is where you may want to fetch data from + database, because you know the run number. + */ + int InitRun(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode* topNode) override; + + /// Clean up internals after each event. + int ResetEvent(PHCompositeNode* topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode* topNode) override; enum class Pass { @@ -66,6 +71,31 @@ class QVecCalib ApplyFlattening }; + void set_pass(int pass) + { + m_pass = validate_pass(pass); + } + + void set_input_hist(std::string_view file) + { + m_input_hist = file; + } + + void set_input_Q_calib(std::string_view file) + { + m_input_Q_calib = file; + } + + void set_dst_tag(std::string_view tag) + { + m_dst_tag = tag; + } + + void set_cdb_output_dir(std::string_view cdb_dir) + { + m_cdb_output_dir = cdb_dir; + } + private: static Pass validate_pass(int pass) { @@ -85,15 +115,45 @@ class QVecCalib struct CorrectionData { QVecShared::QVec avg_Q{}; + + double avg_Q_xx{0.0}; + double avg_Q_yy{0.0}; + double avg_Q_xy{0.0}; + std::array, 2> X_matrix{}; }; static constexpr size_t m_cent_bins = QVecShared::CENT_BINS; static constexpr auto m_harmonics = QVecShared::HARMONICS; - double m_cent_low = -0.5; - double m_cent_high = 79.5; - static constexpr int PROGRESS_REPORT_INTERVAL = 10000; + static constexpr float SIGMA_HOT = 6.0F; + static constexpr float SIGMA_COLD = -6.0F; + + double m_cent_low{-0.5}; + double m_cent_high{79.5}; + + std::string m_input_hist; + std::string m_input_Q_calib; + std::string m_dst_tag; + std::string m_cdb_output_dir{"."}; + Pass m_pass{Pass::ComputeRecentering}; + EventPlaneData* m_evtdata{nullptr}; + + int m_event{0}; + int m_runnumber{0}; + + struct EventCounters + { + int bad_centrality_sepd_correlation{0}; + int zero_sepd_total_charge{0}; + int total_processed{0}; + }; + + EventCounters m_event_counters; + + std::array, m_harmonics.size()> m_q_vectors{}; + + static constexpr int PROGRESS_REPORT_INTERVAL = 1000; // Holds all correction data // key: [Cent][Harmonic][Subdetector] @@ -101,37 +161,12 @@ class QVecCalib // Subdetectors {S,N,NS} -> 3 elements std::array, m_harmonics.size()>, m_cent_bins> m_correction_data; - static constexpr size_t IDX_NS = 2; - // Store harmonic orders and subdetectors for easy iteration static constexpr std::array m_subdetectors = {QVecShared::Subdetector::S, QVecShared::Subdetector::N}; static constexpr std::array m_components = {QVecShared::QComponent::X, QVecShared::QComponent::Y}; - struct EventData - { - int event_id{0}; // NOLINT(misc-non-private-member-variables-in-classes) - double event_zvertex{0.0}; // NOLINT(misc-non-private-member-variables-in-classes) - double event_centrality{0.0}; // NOLINT(misc-non-private-member-variables-in-classes) - double sepd_totalcharge{0.0}; // NOLINT(misc-non-private-member-variables-in-classes) - - std::array, m_harmonics.size()> q_vectors; // NOLINT(misc-non-private-member-variables-in-classes) - - void reset() - { - for (auto& q_vec_harmonic : q_vectors) - { - for (auto& q_vec : q_vec_harmonic) - { - q_vec.x = 0.0; - q_vec.y = 0.0; - } - } - } - - std::vector* sepd_channel{nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) - std::vector* sepd_charge{nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) - std::vector* sepd_phi{nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) - }; + // [Harmonic Index][Channel Index] -> {cos, sin} + std::vector>> m_trig_cache; struct AverageHists { @@ -192,224 +227,209 @@ class QVecCalib TH2* Psi_NS_corr2{nullptr}; }; - // --- Member Variables --- - EventData m_event_data; - std::unique_ptr m_chain; - - // Configuration stored as members - std::string m_input_file; - std::string m_input_hist; - std::string m_input_Q_calib; - Pass m_pass{Pass::ComputeRecentering}; - long long m_events_to_process; - std::string m_output_dir; - - // Hists - std::map> m_hists1D; - std::map> m_hists2D; - std::map> m_profiles; - // sEPD Bad Channels std::unordered_set m_bad_channels; double m_sEPD_min_avg_charge_threshold{1}; double m_sEPD_sigma_threshold{3}; - // --- Private Helper Methods --- + // Hists + TH1* hCentrality{nullptr}; + + TH2* h2SEPD_Charge{nullptr}; + TH2* h2SEPD_Chargev2{nullptr}; -/** - * @brief Sets up a TChain and performs structural validation of the input ROOT file. - * * Verifies file existence, ensures the requested TTree exists, and checks for - * non-zero entries before returning a configured chain. - * * @param input_filepath Path to the input .root file. - * @param tree_name_in_file Name of the TTree inside the file. - * @return std::unique_ptr A configured TChain, or nullptr if validation fails. - */ - std::unique_ptr setupTChain(const std::string& input_filepath, const std::string& tree_name_in_file); + TH2* h2SEPD_South_Charge_rbin{nullptr}; + TH2* h2SEPD_North_Charge_rbin{nullptr}; -/** - * @brief Orchestrates the TChain initialization and branch configuration. - * * Sets the branch statuses and addresses for event-level data (ID, centrality, charge) - * and sEPD tower-level data (channel, charge, phi) needed for the calibration. - */ - void setup_chain(); + TH2* h2SEPD_South_Charge_rbinv2{nullptr}; + TH2* h2SEPD_North_Charge_rbinv2{nullptr}; -/** - * @brief Initializes all output histograms and profiles. - * * Dynamically generates histogram names using the shared naming helper based on - * the current calibration pass (e.g., adding "_corr" or "_corr2" suffixes). - */ - void init_hists(); + TProfile* hSEPD_Charge_Min{nullptr}; + TProfile* hSEPD_Charge_Max{nullptr}; -/** - * @brief Safely retrieves a ROOT object from a file and returns a managed unique_ptr. - * * Performs a dynamic_cast to verify the requested type T and Clones the object - * to ensure it remains valid after the source file is closed. - * * @tparam T The ROOT class type (e.g., TProfile). - * @param file Pointer to the source TFile. - * @param name The name of the object within the file. - * @return std::unique_ptr A managed pointer to the cloned object. - * @throws std::runtime_error If the object is not found or type mismatch occurs. - */ - template - std::unique_ptr load_and_clone(TFile* file, const std::string& name); + TProfile* hSEPD_Bad_Channels{nullptr}; -/** - * @brief Loads the results of previous passes from a calibration file. - * * Populates the internal correction data structure with averages and/or - * matrices required for the current processing pass. - */ - void load_correction_data(); + std::map m_hists2D; + std::map m_profiles; -/** - * @brief High-level orchestrator for the event processing phase. - * * If the current pass requires existing calibration data (Recentering or Flattening), - * it triggers the data loading sequence before starting the main event loop. - */ - void process_events(); + std::vector m_average_hists; + std::vector m_recenter_hists; + std::vector m_flattening_hists; -/** - * @brief Validates events based on sEPD total charge vs. centrality correlation. - * * Compares the current event's total charge against the 3-sigma bounds derived - * from the QA histograms to reject pile-up or background-dominated events. - * @return True if the event falls within the acceptable charge window. - */ + /** + * @brief Initializes all output histograms and profiles. + * * Dynamically generates histogram names using the shared naming helper based on + * the current calibration pass (e.g., adding "_corr" or "_corr2" suffixes). + */ + void init_hists(); + + /** + * @brief Safely retrieves a ROOT object from a file and returns a managed pointer. + * * Performs a dynamic_cast to verify the requested type T and Clones the object + * to ensure it remains valid after the source file is closed. + * * @tparam T The ROOT class type (e.g., TProfile). + * @param file Pointer to the source TFile. + * @param name The name of the object within the file. + * @return T* A managed pointer to the cloned object. + * @throws std::runtime_error If the object is not found or type mismatch occurs. + */ + template + T* load_and_clone(TFile* file, const std::string& name); + + /** + * @brief Loads the results of previous passes from a calibration file. + * * Populates the internal correction data structure with averages and/or + * matrices required for the current processing pass. + */ + int load_correction_data(); + + /** + * @brief Validates events based on sEPD total charge vs. centrality correlation. + * * Compares the current event's total charge against the 3-sigma bounds derived + * from the QA histograms to reject pile-up or background-dominated events. + * @return True if the event falls within the acceptable charge window. + */ bool process_event_check(); -/** - * @brief Performs the primary tower-by-tower Q-vector calculation and normalization. - * * Loops through sEPD channels, excludes bad channels, calculates the raw Q-vector - * for all harmonics, and normalizes the results by the total arm charge. - * @return True if both South and North arms have non-zero total charge. - */ + /** + * @brief Performs the primary tower-by-tower Q-vector calculation and normalization. + * * Loops through sEPD channels, excludes bad channels, calculates the raw Q-vector + * for all harmonics, and normalizes the results by the total arm charge. + * @return True if both South and North arms have non-zero total charge. + */ bool process_sEPD(); -/** - * @brief Primary event loop orchestrator. - * * Iterates through the TChain entries, performs event selection, executes - * normalization/re-centering/flattening logic based on the current pass, - * and fills the output histograms. - */ - void run_event_loop(); - -/** - * @brief Finalizes the analysis by writing all histograms to the output ROOT file. - * * Creates the output directory if it does not exist and ensures all 1D, 2D - * and TProfiles are safely persisted to disk. - */ - void save_results() const; - -/** - * @brief Calculates and fills profiles for the initial Q-vector averages. - * @param cent The event centrality. - * @param q_S The South arm normalized Q-vector. - * @param q_N The North arm normalized Q-vector. - * @param h Reference to the cache of profiles for the first pass. - */ + /** + * @brief Calculates and fills profiles for the initial Q-vector averages. + * @param cent The event centrality. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the first pass. + */ static void process_averages(double cent, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const AverageHists& h); -/** - * @brief Applies re-centering offsets and fills profiles for second-moment calculation. - * @param cent The event centrality. - * @param h_idx Harmonic index. - * @param q_S The South arm normalized Q-vector. - * @param q_N The North arm normalized Q-vector. - * @param h Reference to the cache of profiles for the second pass. - */ + /** + * @brief Applies re-centering offsets and fills profiles for second-moment calculation. + * @param cent The event centrality. + * @param h_idx Harmonic index. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the second pass. + */ void process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h); -/** - * @brief Applies the full correction (re-centering + flattening) for validation. - * @param cent The event centrality. - * @param h_idx Harmonic index. - * @param q_S The South arm normalized Q-vector. - * @param q_N The North arm normalized Q-vector. - * @param h Reference to the cache of profiles for the third pass. - */ + /** + * @brief Applies the full correction (re-centering + flattening) for validation. + * @param cent The event centrality. + * @param h_idx Harmonic index. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the third pass. + */ void process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h); -/** - * @brief Calculates the 2x2 anisotropy correction (whitening) matrix. - * * This matrix transforms the elliptical Q-vector distribution into a circularly - * symmetric (isotropic) distribution. It effectively corrects for detector - * acceptance effects and gain non-uniformities by normalizing the second-order - * moments of the Q-vector. - * * @param xx The second moment. - * @param yy The second moment. - * @param xy The cross-moment. - * @param n Harmonic order (used for error logging context). - * @param cent_bin Centrality bin (used for error logging context). - * @param det_label Detector label ("S" or "N"). - * @return std::array, 2> The 2x2 correction matrix. - */ + /** + * @brief Calculates the 2x2 anisotropy correction (whitening) matrix. + * * This matrix transforms the elliptical Q-vector distribution into a circularly + * symmetric (isotropic) distribution. It effectively corrects for detector + * acceptance effects and gain non-uniformities by normalizing the second-order + * moments of the Q-vector. + * * @param xx The second moment. + * @param yy The second moment. + * @param xy The cross-moment. + * @param n Harmonic order (used for error logging context). + * @param cent_bin Centrality bin (used for error logging context). + * @param det_label Detector label ("S" or "N"). + * @return std::array, 2> The 2x2 correction matrix. + */ std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); - -/** - * @brief Computes 1st-order re-centering offsets for a specific centrality bin. - * * Extracts average Q-vector components from histograms and stores them in the - * correction data matrix for use in subsequent processing passes. - * * @param cent_bin The index of the centrality bin. - * @param h_idx The index of the harmonic order in the harmonics array. - */ + /** + * @brief Computes 1st-order re-centering offsets for a specific centrality bin. + * * Extracts average Q-vector components from histograms and stores them in the + * correction data matrix for use in subsequent processing passes. + * * @param cent_bin The index of the centrality bin. + * @param h_idx The index of the harmonic order in the harmonics array. + */ void compute_averages(size_t cent_bin, int h_idx); -/** - * @brief Computes re-centering parameters and solves the flattening matrices. - * * Extracts the re-centered second moments from the profiles and populates the - * internal CorrectionData matrix with calculated flattening coefficients. - * @param cent_bin The centrality bin index. - * @param h_idx The harmonic index. - */ + /** + * @brief Computes re-centering parameters and solves the flattening matrices. + * * Extracts the re-centered second moments from the profiles and populates the + * internal CorrectionData matrix with calculated flattening coefficients. + * @param cent_bin The centrality bin index. + * @param h_idx The harmonic index. + */ void compute_recentering(size_t cent_bin, int h_idx); -/** - * @brief Logs the final corrected moments to verify successful flattening. - * @param cent_bin The centrality bin index. - * @param n The harmonic order. - */ + /** + * @brief Logs the final corrected moments to verify successful flattening. + * @param cent_bin The centrality bin index. + * @param n The harmonic order. + */ void print_flattening(size_t cent_bin, int n) const; -/** - * @brief Prepares a vector of pointers to histograms used in the first pass. - * @return A vector of AverageHists structs, indexed by harmonic. - */ - std::vector prepare_average_hists(); - -/** - * @brief Prepares a vector of pointers to histograms used in the second pass. - * @return A vector of RecenterHists structs, indexed by harmonic. - */ - std::vector prepare_recenter_hists(); - -/** - * @brief Prepares a vector of pointers to histograms used in the third pass. - * @return A vector of FlatteningHists structs, indexed by harmonic. - */ - std::vector prepare_flattening_hists(); - -/** - * @brief Top-level driver for processing Quality Assurance histograms. - * * Loads the reference histogram file to identify bad channels and establish - * event-level charge thresholds as a function of centrality. - */ - void process_QA_hist(); - -/** - * @brief Identifies and catalogs "Bad" (Hot, Cold, or Dead) sEPD channels. - * * Uses a reference charge histogram to compute Z-scores based on mean charge - * per radial bin. Channels exceeding the sigma threshold are added to the internal exclusion set. - * * @param file Pointer to the open TFile containing QA histograms. - */ - void process_bad_channels(TFile* file); - -/** - * @brief Establishes sEPD charge-cut thresholds for event selection. - * * Uses the 2D total charge vs. centrality distribution to derive mean and - * sigma values, generating a 1D profile of the selection window. - * @param file Pointer to the open QA histogram file. - */ - void process_sEPD_event_thresholds(TFile* file); + void prepare_hists(); + + /** + * @brief Prepares a vector of pointers to histograms used in the first pass. + * @return A vector of AverageHists structs, indexed by harmonic. + */ + void prepare_average_hists(); + + /** + * @brief Prepares a vector of pointers to histograms used in the second pass. + * @return A vector of RecenterHists structs, indexed by harmonic. + */ + void prepare_recenter_hists(); + + /** + * @brief Prepares a vector of pointers to histograms used in the third pass. + * @return A vector of FlatteningHists structs, indexed by harmonic. + */ + void prepare_flattening_hists(); + + /** + * @brief Top-level driver for processing Quality Assurance histograms. + * * Loads the reference histogram file to identify bad channels and establish + * event-level charge thresholds as a function of centrality. + */ + int process_QA_hist(); + + /** + * @brief Identifies and catalogs "Bad" (Hot, Cold, or Dead) sEPD channels. + * * Uses a reference charge histogram to compute Z-scores based on mean charge + * per radial bin. Channels exceeding the sigma threshold are added to the internal exclusion set. + * * @param file Pointer to the open TFile containing QA histograms. + */ + int process_bad_channels(TFile* file); + + /** + * @brief Establishes sEPD charge-cut thresholds for event selection. + * * Uses the 2D total charge vs. centrality distribution to derive mean and + * sigma values, generating a 1D profile of the selection window. + * @param file Pointer to the open QA histogram file. + */ + int process_sEPD_event_thresholds(TFile* file); + + void write_cdb(); + + /** + * @brief Writes the Event Plane calibration constants to a CDB-formatted TTree. + * * Formats the re-centering and flattening moments into a CDBTTree payload + * indexed by centrality bin for sPHENIX database integration. + * * @param output_dir The filesystem directory where the .root payload will be saved. + */ + void write_cdb_EventPlane(); + + /** + * @brief Writes the Hot/Cold tower status map to a CDB-formatted TTree. + * * Encodes sEPD channel indices into TowerInfo keys and maps status codes (1=Dead, + * 2=Hot, 3=Cold) to the final database payload. + * * @param output_dir The filesystem directory where the .root payload will be saved. + */ + void write_cdb_BadTowers(); }; -#endif // QVECCALIB_H +#endif // QVECCALIB_H diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h index 3bc58344fe..ebbeec8743 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -20,11 +20,12 @@ namespace QVecShared Cold = 3 }; - enum class Subdetector + enum class Subdetector : size_t { - S, // South - N, // North - NS // North South + S = 0, + N = 1, + NS = 2, + Count = 3 }; enum class QComponent @@ -39,14 +40,6 @@ namespace QVecShared double y{0.0}; }; - struct CorrectionMoments - { - QVec avg_Q{}; // Mean Q vector - double avg_Q_xx{0.0}; - double avg_Q_yy{0.0}; - double avg_Q_xy{0.0}; - }; - /** * @brief Centralized helper to generate standard histogram names for the sEPD calibration. * * Standardizes the naming convention: h_sEPD_Q_{det}_{var}_{n}{suffix}_avg diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index 3570fb6bc7..5ce0e97a58 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -239,7 +239,10 @@ int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) void sEPD_TreeGen::Print([[maybe_unused]] const std::string &what) const { // Only execute if Verbosity is high enough - if (Verbosity() <= 2) return; + if (Verbosity() <= 2) + { + return; + } std::cout << "\n============================================================" << std::endl; std::cout << "sEPD_TreeGen::Print -> Event Data State" << std::endl; From 6e237318746a2dbfa20c83483c1184feaf705886 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:02:10 -0500 Subject: [PATCH 202/866] Debug Counter Increase - Prevent lots of output by increasing the progress report counter --- calibrations/sepd/sepd_eventplanecalib/QVecCalib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index a0029949d8..5fceb0f47e 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -153,7 +153,7 @@ class QVecCalib : public SubsysReco std::array, m_harmonics.size()> m_q_vectors{}; - static constexpr int PROGRESS_REPORT_INTERVAL = 1000; + static constexpr int PROGRESS_REPORT_INTERVAL = 10000; // Holds all correction data // key: [Cent][Harmonic][Subdetector] From 4aacac3f41e2980b17ff0b1385d8113d0beaed86 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Mon, 9 Feb 2026 00:47:35 -0500 Subject: [PATCH 203/866] clang-tidy fix - removed GenQVecCalib.cc - Address readability-avoid-nested-conditional-operator --- .../sepd/sepd_eventplanecalib/GenQVecCalib.cc | 59 ------------------- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 15 ++++- 2 files changed, 14 insertions(+), 60 deletions(-) delete mode 100644 calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc diff --git a/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc deleted file mode 100644 index 0dd1fa1fbe..0000000000 --- a/calibrations/sepd/sepd_eventplanecalib/GenQVecCalib.cc +++ /dev/null @@ -1,59 +0,0 @@ -#include "QVecCalib.h" - -#include - -int main(int argc, const char* const argv[]) -{ - const std::vector args(argv, argv + argc); - - if (args.size() < 4 || args.size() > 7) - { - std::cout << "Usage: " << args[0] << " [pass] [events] [output_directory]" << std::endl; - return 1; // Indicate error - } - - const std::string &input_file = args[1]; - const std::string &input_hist = args[2]; - const std::string &input_Q_calib = args[3]; - const std::string &pass_str = (args.size() >= 5) ? args[4] : "ComputeRecentering"; // Default to the first pass - std::string output_dir = (args.size() >= 7) ? args[6] : "."; - - const std::map pass_map = { - {"ComputeRecentering", QVecCalib::Pass::ComputeRecentering}, - {"ApplyRecentering", QVecCalib::Pass::ApplyRecentering}, - {"ApplyFlattening", QVecCalib::Pass::ApplyFlattening} - }; - - QVecCalib::Pass pass = QVecCalib::Pass::ComputeRecentering; - if (pass_map.contains(pass_str)) - { - pass = pass_map.at(pass_str); - } - else - { - std::cout << "Error: Invalid pass specified: " << pass_str << std::endl; - std::cout << "Available passes are: ComputeRecentering, ApplyRecentering, ApplyFlattening" << std::endl; - return 1; - } - - try - { - long long events = (args.size() >= 6) ? std::stoll(args[5]) : 0; - QVecCalib analysis(input_file, input_hist, input_Q_calib, static_cast(pass), events, output_dir); - analysis.run(); - } - catch (const std::invalid_argument& e) - { - std::cout << "Error: events must be an integer" << std::endl; - return 1; - } - catch (const std::exception& e) - { - std::cout << "An exception occurred: " << e.what() << std::endl; - return 1; - } - - std::cout << "======================================" << std::endl; - std::cout << "done" << std::endl; - return 0; -} diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index f14b0cc536..4a1c9d7e51 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -546,7 +546,20 @@ int QVecCalib::load_correction_data() // Populate Flattening for S, N, and NS for (int d = 0; d < (int) SD::Count; ++d) { - std::string det_str = (d == 0) ? "S" : (d == 1) ? "N" : "NS"; + std::string det_str; + switch (d) + { + case 0: + det_str = "S"; + break; + case 1: + det_str = "N"; + break; + default: + det_str = "NS"; + break; + } + double xx = m_profiles[QVecShared::get_hist_name(det_str, "xx", n)]->GetBinContent(bin); double yy = m_profiles[QVecShared::get_hist_name(det_str, "yy", n)]->GetBinContent(bin); double xy = m_profiles[QVecShared::get_hist_name(det_str, "xy", n)]->GetBinContent(bin); From 8ddb0ce8dffd87c672ea20ec970dcdc920939fea Mon Sep 17 00:00:00 2001 From: bkimelman Date: Mon, 9 Feb 2026 10:17:45 -0500 Subject: [PATCH 204/866] Fixed indentation issue that clang-tidy complained about --- .../packages/tpccalib/TpcLaminationFitting.cc | 176 +++++++++--------- 1 file changed, 92 insertions(+), 84 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 2eaf6fcf4c..f2dcb09ed9 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -80,18 +80,20 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) //m_laminationOffset[l][s] = -0.00296837 + 0.0014604 * cos(shift - 1.2246); if(s == 0) { - m_laminationOffset[l][s] = -0.00236289 + 0.00143918 * cos(shift - 1.31782); + //m_laminationOffset[l][s] = -0.00236289 + 0.00143918 * cos(shift - 1.31782); + m_laminationOffset[l][s] = -0.00148465 + 0.00219335 * cos(shift - 1.24219); } else { - m_laminationOffset[l][s] = -0.00323259 + 0.00138333 * cos(shift - 1.25373); + //m_laminationOffset[l][s] = -0.00323259 + 0.00138333 * cos(shift - 1.25373); + m_laminationOffset[l][s] = -0.00303345 + 0.0010828 * cos(shift - 1.03718); } if(m_fieldOff) { m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{ideal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %m_laminationIdeal[l][s]).str().c_str(), 200, 30, 80, 200, m_laminationIdeal[l][s] - 0.2, m_laminationIdeal[l][s] + 0.2); m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[0]+[1]", 30, 80); - m_fLamination[l][s]->SetParameters(-0.003, m_laminationIdeal[l][s]); + m_fLamination[l][s]->SetParameters(m_laminationOffset[l][s], m_laminationIdeal[l][s]); m_fLamination[l][s]->SetParLimits(0, -0.05, 0.05); m_fLamination[l][s]->FixParameter(1, m_laminationIdeal[l][s]); } @@ -559,7 +561,7 @@ int TpcLaminationFitting::fitLaminations() if(m_fieldOff) { - m_fLamination[l][s]->SetParameters(0.003, m_laminationIdeal[l][s]); + m_fLamination[l][s]->SetParameters(m_laminationOffset[l][s], m_laminationIdeal[l][s]); m_fLamination[l][s]->FixParameter(1, m_laminationIdeal[l][s]); } else @@ -743,6 +745,7 @@ int TpcLaminationFitting::InterpolatePhiDistortions() int phiBin = phiDistortionLamination[s]->GetXaxis()->FindBin(phi); if(m_fieldOff) { + m_laminationOffset[l][s] = m_fLamination[l][s]->GetParameter(0); m_fLamination[l][s]->SetParameter(1, 0.0); } else @@ -971,7 +974,7 @@ int TpcLaminationFitting::doGlobalRMatching(int side) int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) { - + std::string sql = "SELECT * FROM gl1_scalers WHERE runnumber = " + std::to_string(m_runnumber) + ";"; odbc::Statement *stmt = DBInterface::instance()->getStatement("daq"); odbc::ResultSet *resultSet = stmt->executeQuery(sql); @@ -982,7 +985,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) delete resultSet; return Fun4AllReturnCodes::ABORTRUN; } - + while (resultSet->next()) { int index = resultSet->getInt("index"); @@ -991,20 +994,20 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) scalers[index][1] = resultSet->getLong("live"); scalers[index][2] = resultSet->getLong("raw"); } - + delete resultSet; - + m_ZDC_coincidence = (1.0*scalers[3][2]/scalers[0][2])/(106e-9); - + std::cout << "Runnumber: " << m_runnumber << " ppMode: " << ppMode << " ZDC coindicence rate: " << m_ZDC_coincidence << std::endl; - + int fitSuccess = fitLaminations(); if (fitSuccess != Fun4AllReturnCodes::EVENT_OK) { std::cout << PHWHERE << " Return code for lamination fitting was " << fitSuccess << " and not successful" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + if(!m_QAFileName.empty()) { TCanvas *c1 = new TCanvas(); @@ -1025,46 +1028,49 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } m_fLamination[l][s]->Draw("same"); - TLegend *leg = new TLegend(0.15,0.15,0.45,0.4); - + TLegend *leg = new TLegend(0.15,0.15,0.45,0.4); + TLine *lineIdeal; - TLine *lineOffset; - if(m_fieldOff) - { - lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); - lineIdeal->SetLineColor(kBlue); - leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); - } - else - { - lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); - lineIdeal->SetLineColor(kBlue); - leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); - - lineOffset = new TLine(30,m_laminationIdeal[l][s]+m_laminationOffset[l][s],80,m_laminationIdeal[l][s]+m_laminationOffset[l][s]); - lineOffset->SetLineColor(kGreen+2); - lineOffset->SetLineStyle(2); - leg->AddEntry(lineOffset,Form("#phi_{ideal}+#phi_{offset}=%.6f",m_laminationOffset[l][s]), "l"); - lineOffset->Draw("same"); - } + TLine *lineOffset; + if(m_fieldOff) + { + lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); + lineIdeal->SetLineColor(kBlue); + leg->AddEntry(lineIdeal,(boost::format("#phi_{ideal}=%.6f") %m_laminationIdeal[l][s]).str().c_str(), "l"); + //leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); + } + else + { + lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); + lineIdeal->SetLineColor(kBlue); + leg->AddEntry(lineIdeal,(boost::format("#phi_{ideal}=%.6f") %m_laminationIdeal[l][s]).str().c_str(), "l"); + //leg->AddEntry(lineIdeal,Form("#phi_{ideal}=%.6f",m_laminationIdeal[l][s]), "l"); + + lineOffset = new TLine(30,m_laminationIdeal[l][s]+m_laminationOffset[l][s],80,m_laminationIdeal[l][s]+m_laminationOffset[l][s]); + lineOffset->SetLineColor(kGreen+2); + lineOffset->SetLineStyle(2); + leg->AddEntry(lineOffset,(boost::format("#phi_{ideal}+#phi_{offset}=%.6f") %m_laminationOffset[l][s]).str().c_str(), "l"); + //leg->AddEntry(lineOffset,Form("#phi_{ideal}+#phi_{offset}=%.6f",m_laminationOffset[l][s]), "l"); + lineOffset->Draw("same"); + } lineIdeal->Draw("same"); - - leg->Draw("same"); - - + + leg->Draw("same"); + + TPaveText *pars = new TPaveText(0.6, 0.55, 0.85, 0.85, "NDC"); - if(m_fieldOff) - { - pars->AddText("#phi = #phi_{ideal} + #phi_{offset}"); - pars->AddText((boost::format("#phi_{ideal}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(1) %m_fLamination[l][s]->GetParError(1)).str().c_str()); - pars->AddText((boost::format("#phi_{offset}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); - pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); - pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); - pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); - } - else - { + if(m_fieldOff) + { + pars->AddText("#phi = #phi_{ideal} + #phi_{offset}"); + pars->AddText((boost::format("#phi_{ideal}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(1) %m_fLamination[l][s]->GetParError(1)).str().c_str()); + pars->AddText((boost::format("#phi_{offset}=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); + pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); + pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); + pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); + } + else + { pars->AddText("#phi = #phi_{ideal} + A#times (1 - e^{-C#times (R - B)})"); pars->AddText((boost::format("A=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(0) %m_fLamination[l][s]->GetParError(0)).str().c_str()); //pars->AddText((boost::format("#phi_{ideal}=%.3f#pm 0.000") %m_laminationIdeal[l][s]).str().c_str()); @@ -1074,8 +1080,8 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) pars->AddText((boost::format("C=%.3f#pm %.3f") %m_fLamination[l][s]->GetParameter(2) %m_fLamination[l][s]->GetParError(2)).str().c_str()); pars->AddText((boost::format("Distance to line=%.2f") %m_distanceToFit[l][s]).str().c_str()); pars->AddText((boost::format("Number of Bins used=%d") %m_nBinsFit[l][s]).str().c_str()); - pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); - } + pars->AddText((boost::format("WRMSE=%.2f") %m_fitRMSE[l][s]).str().c_str()); + } pars->Draw("same"); c1->SaveAs(m_QAFileName.c_str()); } @@ -1091,32 +1097,32 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) //TH3 *hIntDistortionP_negz = (TH3 *) simDistortion->Get("hIntDistortionP_negz"); //hIntDistortionP_negz->GetZaxis()->SetRange(hIntDistortionP_negz->GetNbinsZ() - 1, hIntDistortionP_negz->GetNbinsZ() - 1); //simPhiDistortion[0] = (TH2 *) hIntDistortionP_negz->Project3D("yx"); - + int interpolateSuccess = InterpolatePhiDistortions(); if (interpolateSuccess != Fun4AllReturnCodes::EVENT_OK) { std::cout << PHWHERE << " Return code for lamination interpolation was " << interpolateSuccess << " and not successful" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + /* - for (int s = 0; s < 2; s++) - { + for (int s = 0; s < 2; s++) + { scaleFactorMap[s] = (TH2 *) m_dcc_out->m_hDPint[s]->Clone(); scaleFactorMap[s]->SetName(std::format("scaleFactorMap{}", s).c_str()); scaleFactorMap[s]->Divide(simPhiDistortion[s]); - } - - TH3 *hIntDistortionR_posz = (TH3 *) simDistortion->Get("hIntDistortionR_posz"); - hIntDistortionR_posz->GetZaxis()->SetRange(2, 2); - TH2 *simRDistortion[2]; - simRDistortion[1] = (TH2 *) hIntDistortionR_posz->Project3D("yx"); - TH3 *hIntDistortionR_negz = (TH3 *) simDistortion->Get("hIntDistortionR_negz"); - hIntDistortionR_negz->GetZaxis()->SetRange(hIntDistortionR_negz->GetNbinsZ() - 1, hIntDistortionR_negz->GetNbinsZ() - 1); - simRDistortion[0] = (TH2 *) hIntDistortionR_negz->Project3D("yx"); + } + + TH3 *hIntDistortionR_posz = (TH3 *) simDistortion->Get("hIntDistortionR_posz"); + hIntDistortionR_posz->GetZaxis()->SetRange(2, 2); + TH2 *simRDistortion[2]; + simRDistortion[1] = (TH2 *) hIntDistortionR_posz->Project3D("yx"); + TH3 *hIntDistortionR_negz = (TH3 *) simDistortion->Get("hIntDistortionR_negz"); + hIntDistortionR_negz->GetZaxis()->SetRange(hIntDistortionR_negz->GetNbinsZ() - 1, hIntDistortionR_negz->GetNbinsZ() - 1); + simRDistortion[0] = (TH2 *) hIntDistortionR_negz->Project3D("yx"); */ - - + + for (int s = 0; s < 2; s++) { @@ -1127,27 +1133,27 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) return Fun4AllReturnCodes::ABORTRUN; } /* - for(int i=1; i<=m_dcc_out->m_hDRint[s]->GetNbinsX(); i++) - { - for(int j=1; j<=m_dcc_out->m_hDRint[s]->GetNbinsY(); j++) - { - if(simRDistortion[s]->GetBinContent(i,j) != 0.0) - { - m_dcc_out->m_hDRint[s]->SetBinContent(i,j, simRDistortion[s]->GetBinContent(i,j)); - } - } - } + for(int i=1; i<=m_dcc_out->m_hDRint[s]->GetNbinsX(); i++) + { + for(int j=1; j<=m_dcc_out->m_hDRint[s]->GetNbinsY(); j++) + { + if(simRDistortion[s]->GetBinContent(i,j) != 0.0) + { + m_dcc_out->m_hDRint[s]->SetBinContent(i,j, simRDistortion[s]->GetBinContent(i,j)); + } + } + } */ //m_dcc_out->m_hDRint[s] = (TH2 *) simRDistortion[s]->Clone(); //m_dcc_out->m_hDRint[s]->SetName((boost::format("hIntDistortionR%s") %(s == 0 ? "_negz" : "_posz")).str().c_str()); //m_dcc_out->m_hDRint[s]->Multiply(scaleFactorMap[s]); } - - + + fill_guarding_bins(m_dcc_out); - - + + for(int s=0; s<2; s++) { for(int l=0; l<18; l++) @@ -1181,7 +1187,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) m_laminationTree->Fill(); } } - + TFile *outputfile = new TFile(m_outputfile.c_str(), "RECREATE"); outputfile->cd(); for (int s = 0; s < 2; s++) @@ -1196,19 +1202,21 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) phiDistortionLamination[s]->Write(); //scaleFactorMap[s]->Write(); m_hPetal[s]->Write(); - if(m_bestRMatch[s]) { m_bestRMatch[s]->Write(); -} + if(m_bestRMatch[s]) + { + m_bestRMatch[s]->Write(); + } m_parameterScan[s]->Write(); } m_laminationTree->Write(); - + m_hLamination[13][0]->Write(); m_hLamination[13][1]->Write(); m_hLamination[14][1]->Write(); - + outputfile->Close(); - + return Fun4AllReturnCodes::EVENT_OK; } From 6ce3aea5ce9fd373a4d45f2c18192a3dacfac9b2 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Mon, 19 Jan 2026 21:26:29 -0500 Subject: [PATCH 205/866] sEPD Event Plane Calibration - Application Introduces a new sEPD event plane reconstruction module (v2) and an expanded info container (v2) to support a full calibration chain including recentering and flattening. Eventplaneinfov2: - Inherits from Eventplaneinfo. - Adds dedicated storage for raw, recentered, and final (flattened) Q-vectors. - Provides getters/setters for extended Q-vector stages to allow for systematic studies of calibration effects. EventPlaneRecov2: - New SubsysReco module specifically for sEPD Q-vector calibration. - Implements a multi-step calibration workflow: 1. Raw Q-vector calculation from sEPD channel charges and geometry. 2. Recentering: Subtracts offsets per centrality bin. 3. Flattening: Applies a 2x2 correction matrix calculated from Q-vector variances (Qxx, Qyy, Qxy). - Features integration with CDBTTree to load calibration parameters dynamically via the Calibration Database. - Processes harmonics n=2,3, and 4 for South, North, and Combined (NS) subdetectors. - Automatically handles centrality-based binning (8 bins) for calibrations. - Populates EventplaneinfoMap with Eventplaneinfov2 objects for downstream analysis. - Includes diagnostic verbosity levels for inspecting calibration matrices and per-event vector transformations. --- .../eventplaneinfo/EventPlaneRecov2.cc | 625 ++++++++++++++++++ .../eventplaneinfo/EventPlaneRecov2.h | 136 ++++ .../packages/eventplaneinfo/Eventplaneinfo.h | 4 + .../eventplaneinfo/Eventplaneinfov2.cc | 23 + .../eventplaneinfo/Eventplaneinfov2.h | 55 ++ .../eventplaneinfo/Eventplaneinfov2LinkDef.h | 5 + offline/packages/eventplaneinfo/Makefile.am | 9 +- 7 files changed, 855 insertions(+), 2 deletions(-) create mode 100644 offline/packages/eventplaneinfo/EventPlaneRecov2.cc create mode 100644 offline/packages/eventplaneinfo/EventPlaneRecov2.h create mode 100644 offline/packages/eventplaneinfo/Eventplaneinfov2.cc create mode 100644 offline/packages/eventplaneinfo/Eventplaneinfov2.h create mode 100644 offline/packages/eventplaneinfo/Eventplaneinfov2LinkDef.h diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc new file mode 100644 index 0000000000..8a468a1acb --- /dev/null +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -0,0 +1,625 @@ +#include "EventPlaneRecov2.h" + +#include "EventplaneinfoMapv1.h" +#include "Eventplaneinfov2.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include + +// -- event +#include + +// -- Centrality +#include + +// -- sEPD +#include + +// -- root includes -- +#include +#include + +// c++ includes -- +#include +#include +#include +#include +#include +#include + +//____________________________________________________________________________.. +EventPlaneRecov2::EventPlaneRecov2(const std::string &name): + SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +EventPlaneRecov2::~EventPlaneRecov2() +{ + std::cout << "EventPlaneRecov2::~EventPlaneRecov2() Calling dtor" << std::endl; +} + +bool EventPlaneRecov2::hasValidTree(const std::string &filePath) +{ + // 1. Attempt to open the file + // "READ" is the default, but being explicit is good practice + std::unique_ptr file(TFile::Open(filePath.c_str(), "READ")); + + // 2. Validate the file pointer and check if the file is "Zombie" (corrupt/unreadable) + if (!file || file->IsZombie()) + { + std::cout << "Error: Could not open file: " << filePath << std::endl; + return false; + } + + // 3. Attempt to get the object by name + TObject *obj = file->Get("Multiple"); + + // 4. Validate existence and check if it actually inherits from TTree + if (obj && obj->InheritsFrom(TTree::Class())) + { + return true; + } + + std::cout << "Error: Object 'Multiple' not found or is not a TTree." << std::endl; + return false; +} + +//____________________________________________________________________________.. +int EventPlaneRecov2::Init([[maybe_unused]] PHCompositeNode *topNode) +{ + std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); + + if (hasValidTree(m_directURL_EventPlaneCalib)) + { + m_cdbttree = std::make_unique(m_directURL_EventPlaneCalib); + std::cout << PHWHERE << " Custom Event Plane Calib Found: " << m_directURL_EventPlaneCalib << std::endl; + } + else if (!calibdir.empty()) + { + m_cdbttree = std::make_unique(calibdir); + std::cout << PHWHERE << " Event Plane Calib Found: " << calibdir << std::endl; + } + else if (m_doAbortNoEventPlaneCalib) + { + std::cout << PHWHERE << " Error: No Event Plane Calib Found and m_doAbortNoEventPlaneCalib is true. Aborting." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + else + { + std::cout << PHWHERE << " Error: No Event Plane Calib Found. Skipping Event Plane Calibrations." << std::endl; + m_doNotCalib = true; + } + + if (!m_doNotCalib) + { + LoadCalib(); + } + + if (Verbosity() > 0) + { + print_correction_data(); + } + + CreateNodes(topNode); + + return Fun4AllReturnCodes::EVENT_OK; +} + +std::array, 2> EventPlaneRecov2::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) +{ + std::array, 2> mat{}; + + double D_arg = (xx * yy) - (xy * xy); + if (D_arg <= 0) + { + std::cout << PHWHERE << "Invalid D-term " << D_arg << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; + // Return Identity Matrix to preserve Recentered vector + mat[0][0] = 1.0; + mat[1][1] = 1.0; + return mat; + } + double D = std::sqrt(D_arg); + + double N_term = D * (xx + yy + (2 * D)); + if (N_term <= 0) + { + std::cout << PHWHERE << "Invalid N-term " << N_term << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; + // Return Identity Matrix to preserve Recentered vector + mat[0][0] = 1.0; + mat[1][1] = 1.0; + return mat; + } + double inv_sqrt_N = 1.0 / std::sqrt(N_term); + + mat[0][0] = inv_sqrt_N * (yy + D); + mat[0][1] = -inv_sqrt_N * xy; + mat[1][0] = mat[0][1]; + mat[1][1] = inv_sqrt_N * (xx + D); + return mat; +} + +//____________________________________________________________________________.. +void EventPlaneRecov2::LoadCalib() +{ + size_t south_idx = static_cast(Subdetector::S); + size_t north_idx = static_cast(Subdetector::N); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + std::string S_x_avg_name = std::format("Q_S_x_{}_avg", n); + std::string S_y_avg_name = std::format("Q_S_y_{}_avg", n); + std::string N_x_avg_name = std::format("Q_N_x_{}_avg", n); + std::string N_y_avg_name = std::format("Q_N_y_{}_avg", n); + + std::string S_xx_avg_name = std::format("Q_S_xx_{}_avg", n); + std::string S_yy_avg_name = std::format("Q_S_yy_{}_avg", n); + std::string S_xy_avg_name = std::format("Q_S_xy_{}_avg", n); + std::string N_xx_avg_name = std::format("Q_N_xx_{}_avg", n); + std::string N_yy_avg_name = std::format("Q_N_yy_{}_avg", n); + std::string N_xy_avg_name = std::format("Q_N_xy_{}_avg", n); + + for (size_t cent_bin = 0; cent_bin < m_bins_cent; ++cent_bin) + { + int key = static_cast(cent_bin); + + // South + auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; + dataS.avg_Q.x = m_cdbttree->GetDoubleValue(key, S_x_avg_name); + dataS.avg_Q.y = m_cdbttree->GetDoubleValue(key, S_y_avg_name); + + dataS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, S_xx_avg_name); + dataS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, S_yy_avg_name); + dataS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, S_xy_avg_name); + + dataS.X_matrix = calculate_flattening_matrix(dataS.avg_Q_xx, dataS.avg_Q_yy, dataS.avg_Q_xy, n, cent_bin, "South"); + + // North + auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; + dataN.avg_Q.x = m_cdbttree->GetDoubleValue(key, N_x_avg_name); + dataN.avg_Q.y = m_cdbttree->GetDoubleValue(key, N_y_avg_name); + + dataN.avg_Q_xx = m_cdbttree->GetDoubleValue(key, N_xx_avg_name); + dataN.avg_Q_yy = m_cdbttree->GetDoubleValue(key, N_yy_avg_name); + dataN.avg_Q_xy = m_cdbttree->GetDoubleValue(key, N_xy_avg_name); + + dataN.X_matrix = calculate_flattening_matrix(dataN.avg_Q_xx, dataN.avg_Q_yy, dataN.avg_Q_xy, n, cent_bin, "North"); + } + } +} + +//____________________________________________________________________________.. +void EventPlaneRecov2::print_correction_data() +{ + std::cout << std::format("\n{:=>60}\n", ""); + std::cout << std::format("{:^60}\n", "EVENT PLANE CORRECTION DATA SUMMARY"); + std::cout << std::format("{:=>60}\n", ""); + + // Iterate through harmonics {2, 3, 4} + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + std::cout << std::format("\n>>> HARMONIC n = {} <<<\n", n); + + // Iterate through Centrality Bins (0-7) + for (size_t cent = 0; cent < m_bins_cent; ++cent) + { + std::cout << std::format("\n Centrality Bin: {}\n", cent); + std::cout << std::format(" {:->30}\n", ""); + + // Header with fixed column widths + std::cout << std::format(" {:<12} {:>10} {:>10} {:>10} {:>10} {:>10}\n", + "Detector", "Avg Qx", "Avg Qy", "Avg Qxx", "Avg Qyy", "Avg Qxy"); + + // Iterate through Subdetectors {S, N} + for (size_t det_idx = 0; det_idx < 2; ++det_idx) + { + std::string det_name = (det_idx == static_cast(Subdetector::S)) ? "South" : "North"; + const auto& data = m_correction_data[h_idx][cent][det_idx]; // + + std::cout << std::format(" {:<12} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n", + det_name, + data.avg_Q.x, data.avg_Q.y, + data.avg_Q_xx, data.avg_Q_yy, data.avg_Q_xy); + + // Print X-Matrix in a bracketed layout + std::cout << std::format(" X-Matrix: [ {:>8.6f}, {:>8.6f} ]\n", + data.X_matrix[0][0], data.X_matrix[0][1]); + std::cout << std::format(" [ {:>8.6f}, {:>8.6f} ]\n", + data.X_matrix[1][0], data.X_matrix[1][1]); + } + } + } + std::cout << std::format("\n{:=>60}\n", ""); +} + +int EventPlaneRecov2::CreateNodes(PHCompositeNode *topNode) { + PHNodeIterator iter(topNode); + + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + PHCompositeNode *globalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "GLOBAL")); + if (!globalNode) + { + auto global_ptr = std::make_unique("GLOBAL"); + globalNode = global_ptr.get(); + dstNode->addNode(global_ptr.release()); + } + + EventplaneinfoMap *eps = findNode::getClass(topNode, "EventplaneinfoMap"); + if (!eps) + { + auto eps_ptr = std::make_unique(); + auto epMapNode_ptr = std::make_unique>(eps_ptr.release(), "EventplaneinfoMap", "PHObject"); + globalNode->addNode(epMapNode_ptr.release()); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int EventPlaneRecov2::process_centrality(PHCompositeNode *topNode) +{ + CentralityInfo* centInfo = findNode::getClass(topNode, "CentralityInfo"); + if (!centInfo) + { + std::cout << PHWHERE << " CentralityInfo is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_cent = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; + + if (!std::isfinite(m_cent) || m_cent < 0) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Warning Centrality is out of range. Cent: " << m_cent << ". Cannot calibrate Q vector for this event." << std::endl; + } + m_doNotCalibEvent = true; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int EventPlaneRecov2::process_sEPD(PHCompositeNode* topNode) +{ + TowerInfoContainer* towerinfosEPD = findNode::getClass(topNode, m_inputNode); + if (!towerinfosEPD) + { + std::cout << PHWHERE << " TOWERINFO_CALIB_SEPD is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << " TOWERGEOM_EPD is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // sepd + unsigned int nchannels_epd = towerinfosEPD->size(); + + double sepd_total_charge_south = 0; + double sepd_total_charge_north = 0; + + for (unsigned int channel = 0; channel < nchannels_epd; ++channel) + { + TowerInfo* tower = towerinfosEPD->get_tower_at_channel(channel); + + unsigned int key = TowerInfoDefs::encode_epd(channel); + double charge = tower->get_energy(); + double phi = epdgeom->get_phi(key); + + // skip bad channels + // skip channels with very low charge + if (!tower->get_isGood() || charge < m_sepd_min_channel_charge) + { + continue; + } + + // arm = 0: South + // arm = 1: North + unsigned int arm = TowerInfoDefs::get_epd_arm(key); + + // sepd charge sums + double& sepd_total_charge = (arm == 0) ? sepd_total_charge_south : sepd_total_charge_north; + + // Compute total charge for the respective sEPD arm + sepd_total_charge += charge; + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + QVec q_n = {charge * std::cos(n * phi), charge * std::sin(n * phi)}; + m_Q_raw[h_idx][arm].x += q_n.x; + m_Q_raw[h_idx][arm].y += q_n.y; + } + } + + // ensure both total charges are nonzero + if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Error: Total sEPD Charge is Zero: " + << "South = " << sepd_total_charge_south + << ", North = " << sepd_total_charge_north << std::endl; + } + + // ensure raw Q vec is reset + m_Q_raw = {}; + m_doNotCalibEvent = true; + return Fun4AllReturnCodes::EVENT_OK; + } + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + m_Q_raw[h_idx][0].x /= sepd_total_charge_south; + m_Q_raw[h_idx][0].y /= sepd_total_charge_south; + + m_Q_raw[h_idx][1].x /= sepd_total_charge_north; + m_Q_raw[h_idx][1].y /= sepd_total_charge_north; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void EventPlaneRecov2::correct_QVecs() +{ + size_t cent_bin = static_cast(m_cent / 10.0); + if (cent_bin >= m_bins_cent) + { + cent_bin = m_bins_cent - 1; // Clamp max + } + + size_t south_idx = static_cast(Subdetector::S); + size_t north_idx = static_cast(Subdetector::N); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; + auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; + + double Q_S_x_avg = dataS.avg_Q.x; + double Q_S_y_avg = dataS.avg_Q.y; + double Q_N_x_avg = dataN.avg_Q.x; + double Q_N_y_avg = dataN.avg_Q.y; + + QVec q_S = m_Q_raw[h_idx][south_idx]; + QVec q_N = m_Q_raw[h_idx][north_idx]; + + // Apply Recentering + QVec q_S_recenter = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; + QVec q_N_recenter = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + + m_Q_recentered[h_idx][0] = q_S_recenter; + m_Q_recentered[h_idx][1] = q_N_recenter; + + const auto &X_S = dataS.X_matrix; + const auto &X_N = dataN.X_matrix; + + // Apply Flattening + double Q_S_x_flat = X_S[0][0] * q_S_recenter.x + X_S[0][1] * q_S_recenter.y; + double Q_S_y_flat = X_S[1][0] * q_S_recenter.x + X_S[1][1] * q_S_recenter.y; + double Q_N_x_flat = X_N[0][0] * q_N_recenter.x + X_N[0][1] * q_N_recenter.y; + double Q_N_y_flat = X_N[1][0] * q_N_recenter.x + X_N[1][1] * q_N_recenter.y; + + QVec q_S_flat = {Q_S_x_flat, Q_S_y_flat}; + QVec q_N_flat = {Q_N_x_flat, Q_N_y_flat}; + + m_Q_flat[h_idx][south_idx] = q_S_flat; + m_Q_flat[h_idx][north_idx] = q_N_flat; + } +} + +void EventPlaneRecov2::print_QVectors() +{ + std::string header_text = std::format("EVENT Q-VECTOR SUMMARY (Event: {}, CENTRALITY: {:.0f}%)", m_globalEvent, m_cent); + + std::cout << std::format("\n{:*>100}\n", ""); + std::cout << std::format("{:^100}\n", header_text); + std::cout << std::format("{:*>100}\n", ""); + + // Table Header + std::cout << std::format(" {:<10} {:<10} | {:>21} | {:>21} | {:>21}\n", + "Harmonic", "Detector", "Raw (x, y)", "Recentered (x, y)", "Flattened (x, y)"); + std::cout << std::format(" {:-<100}\n", ""); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + for (size_t det_idx = 0; det_idx < 2; ++det_idx) + { + std::string det_name = (det_idx == static_cast(Subdetector::S)) ? "South" : "North"; + + const auto& raw = m_Q_raw[h_idx][det_idx]; + const auto& rec = m_Q_recentered[h_idx][det_idx]; + const auto& flat = m_Q_flat[h_idx][det_idx]; + + std::string h_label = (det_idx == 0) ? std::format("n={}", n) : ""; + + // Groups x and y into (val, val) pairs for better scannability + std::string raw_str = std::format("({:>8.5f}, {:>8.5f})", raw.x, raw.y); + std::string rec_str = std::format("({:>8.5f}, {:>8.5f})", rec.x, rec.y); + std::string flat_str = std::format("({:>8.5f}, {:>8.5f})", flat.x, flat.y); + + std::cout << std::format(" {:<10} {:<10} | {:<21} | {:<21} | {:10}\n", + h_label, det_name, raw_str, rec_str, flat_str); + } + if (h_idx < m_harmonics.size() - 1) + { + std::cout << std::format(" {:.>100}\n", ""); + } + } + std::cout << std::format("{:*>100}\n\n", ""); +} + +int EventPlaneRecov2::FillNode([[maybe_unused]] PHCompositeNode *topNode) +{ + EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); + if (!epmap) + { + std::cout << PHWHERE << " EventplaneinfoMap is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + size_t vec_size = static_cast(*std::ranges::max_element(m_harmonics)); + + std::vector> south_Qvec_raw(vec_size, {NAN, NAN}); + std::vector> south_Qvec_recentered(vec_size, {NAN, NAN}); + std::vector> south_Qvec(vec_size, {NAN, NAN}); + + std::vector> north_Qvec_raw(vec_size, {NAN, NAN}); + std::vector> north_Qvec_recentered(vec_size, {NAN, NAN}); + std::vector> north_Qvec(vec_size, {NAN, NAN}); + + std::vector> northsouth_Qvec_raw(vec_size, {NAN, NAN}); + std::vector> northsouth_Qvec_recentered(vec_size, {NAN, NAN}); + std::vector> northsouth_Qvec(vec_size, {NAN, NAN}); + + std::vector south_psi(vec_size, NAN); + std::vector north_psi(vec_size, NAN); + std::vector northsouth_psi(vec_size, NAN); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + int idx = n - 1; + + // Fallback logic: Use raw if calibration failed or centrality is out of range + const auto& Q_S = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][0] : m_Q_flat[h_idx][0]; + const auto& Q_N = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][1] : m_Q_flat[h_idx][1]; + + const auto& Q_S_raw = m_Q_raw[h_idx][0]; + const auto& Q_S_recentered = m_Q_recentered[h_idx][0]; + + const auto& Q_N_raw = m_Q_raw[h_idx][1]; + const auto& Q_N_recentered = m_Q_recentered[h_idx][1]; + + // South + south_Qvec_raw[idx] = {Q_S_raw.x, Q_S_raw.y}; + south_Qvec_recentered[idx] = {Q_S_recentered.x, Q_S_recentered.y}; + south_Qvec[idx] = {Q_S.x, Q_S.y}; + + // North + north_Qvec_raw[idx] = {Q_N_raw.x, Q_N_raw.y}; + north_Qvec_recentered[idx] = {Q_N_recentered.x, Q_N_recentered.y}; + north_Qvec[idx] = {Q_N.x, Q_N.y}; + + // Combined (North + South) + double Qx_NS_raw = Q_S_raw.x + Q_N_raw.x; + double Qy_NS_raw = Q_S_raw.y + Q_N_raw.y; + + double Qx_NS_recentered = Q_S_recentered.x + Q_N_recentered.x; + double Qy_NS_recentered = Q_S_recentered.y + Q_N_recentered.y; + + double Qx_NS = Q_S.x + Q_N.x; + double Qy_NS = Q_S.y + Q_N.y; + + northsouth_Qvec_raw[idx] = {Qx_NS_raw, Qy_NS_raw}; + northsouth_Qvec_recentered[idx] = {Qx_NS_recentered, Qy_NS_recentered}; + northsouth_Qvec[idx] = {Qx_NS, Qy_NS}; + } + + // Helper lambda to fill nodes using the class's GetPsi method + auto create_and_fill = [&](const std::vector>& qvecs_raw, const std::vector>& qvecs_recentered, const std::vector>& qvecs) { + auto node = std::make_unique(); + node->set_qvector_raw(qvecs_raw); + node->set_qvector_recentered(qvecs_recentered); + node->set_qvector(qvecs); + + std::vector psi_vec(vec_size, NAN); + for (int n : m_harmonics) { + psi_vec[n-1] = node->GetPsi(qvecs[n-1].first, qvecs[n-1].second, n); + } + node->set_shifted_psi(psi_vec); + return node; + }; + + epmap->insert(create_and_fill(south_Qvec_raw, south_Qvec_recentered, south_Qvec).release(), EventplaneinfoMap::sEPDS); + epmap->insert(create_and_fill(north_Qvec_raw, north_Qvec_recentered, north_Qvec).release(), EventplaneinfoMap::sEPDN); + epmap->insert(create_and_fill(northsouth_Qvec_raw, northsouth_Qvec_recentered, northsouth_Qvec).release(), EventplaneinfoMap::sEPDNS); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int EventPlaneRecov2::process_event([[maybe_unused]] PHCompositeNode *topNode) +{ + + EventHeader *eventInfo = findNode::getClass(topNode, "EventHeader"); + if (!eventInfo) + { + return Fun4AllReturnCodes::ABORTRUN; + } + + m_globalEvent = eventInfo->get_EvtSequence(); + + int ret = process_centrality(topNode); + if (ret) + { + return ret; + } + + ret = process_sEPD(topNode); + if (ret) + { + return ret; + } + + // Calibrate Q Vectors + if (!m_doNotCalib && !m_doNotCalibEvent) + { + correct_QVecs(); + } + + ret = FillNode(topNode); + if (ret) + { + return ret; + } + + if (Verbosity() > 1) + { + print_QVectors(); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int EventPlaneRecov2::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) +{ + m_doNotCalibEvent = false; + + m_Q_raw = {}; + m_Q_recentered = {}; + m_Q_flat = {}; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int EventPlaneRecov2::End([[maybe_unused]] PHCompositeNode *topNode) +{ + std::cout << "EventPlaneRecov2::End(PHCompositeNode *topNode) This is the End..." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h new file mode 100644 index 0000000000..a1d5017ca3 --- /dev/null +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.h @@ -0,0 +1,136 @@ +#ifndef EVENTPLANEINFO_EVENTPLANERECOV2_H +#define EVENTPLANEINFO_EVENTPLANERECOV2_H + +#include +#include // for CDBTTree + +#include +#include +#include + +class PHCompositeNode; + +class EventPlaneRecov2 : public SubsysReco +{ + public: + + explicit EventPlaneRecov2(const std::string &name = "EventPlaneRecov2"); + ~EventPlaneRecov2() override; + + // Explicitly disable copying and moving + EventPlaneRecov2(const EventPlaneRecov2&) = delete; + EventPlaneRecov2& operator=(const EventPlaneRecov2&) = delete; + EventPlaneRecov2(EventPlaneRecov2&&) = delete; + EventPlaneRecov2& operator=(EventPlaneRecov2&&) = delete; + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Clean up internals after each event. + int ResetEvent(PHCompositeNode *topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + + void set_inputNode(const std::string &inputNode) + { + m_inputNode = inputNode; + } + + void set_directURL_EventPlaneCalib(const std::string &directURL_EventPlaneCalib) + { + m_directURL_EventPlaneCalib = directURL_EventPlaneCalib; + } + + void set_doAbortNoEventPlaneCalib(bool status = true) + { + m_doAbortNoEventPlaneCalib = status; + } + + void set_sepd_min_channel_charge(double sepd_min_channel_charge) + { + m_sepd_min_channel_charge = sepd_min_channel_charge; + } + + private: + + static bool hasValidTree(const std::string &filePath); + static int CreateNodes(PHCompositeNode *topNode); + + std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); + void LoadCalib(); + + void print_correction_data(); + void print_QVectors(); + + int process_centrality(PHCompositeNode *topNode); + int process_sEPD(PHCompositeNode *topNode); + void correct_QVecs(); + + int FillNode(PHCompositeNode *topNode); + + std::string m_directURL_EventPlaneCalib; + bool m_doAbortNoEventPlaneCalib{false}; + bool m_doNotCalib{false}; + bool m_doNotCalibEvent{false}; + + double m_cent{0.0}; + double m_globalEvent{0}; + double m_sepd_min_channel_charge{0.2}; + + std::string m_calibName{"SEPD_EventPlaneCalib"}; + std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; + + std::unique_ptr m_cdbttree; + + enum class Subdetector + { + S, + N + }; + + struct QVec + { + double x{0.0}; + double y{0.0}; + }; + + struct CorrectionData + { + // Averages of Qx, Qy, Qx^2, Qy^2, Qxy + QVec avg_Q{}; + double avg_Q_xx{0.0}; + double avg_Q_yy{0.0}; + double avg_Q_xy{0.0}; + + // Correction matrix + std::array, 2> X_matrix{}; + }; + + static constexpr size_t m_bins_cent = 8; + static constexpr std::array m_harmonics = {2, 3, 4}; + + // Holds all correction data + // key: [Harmonic][Cent][Subdetector] + // Harmonics {2,3,4} -> 3 elements + // Subdetectors {S,N} -> 2 elements + std::array, m_bins_cent>, m_harmonics.size()> m_correction_data; + + // sEPD Q Vectors + // key: [Harmonic][Subdetector] + // Subdetectors {S,N} -> 2 elements + std::array, m_harmonics.size()> m_Q_raw{}; + std::array, m_harmonics.size()> m_Q_recentered{}; + std::array, m_harmonics.size()> m_Q_flat{}; +}; +#endif diff --git a/offline/packages/eventplaneinfo/Eventplaneinfo.h b/offline/packages/eventplaneinfo/Eventplaneinfo.h index 1ad2665881..32dbb4ca54 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfo.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfo.h @@ -23,8 +23,12 @@ class Eventplaneinfo : public PHObject PHObject* CloneMe() const override { return nullptr; } virtual void set_qvector(std::vector> /*Qvec*/) { return; } + virtual void set_qvector_raw(const std::vector>& /*Qvec*/) { return; } + virtual void set_qvector_recentered(const std::vector>& /*Qvec*/) { return; } virtual void set_shifted_psi(std::vector /*Psi_Shifted*/) { return; } virtual std::pair get_qvector(int /*order*/) const { return std::make_pair(NAN, NAN); } + virtual std::pair get_qvector_raw(int /*order*/) const { return std::make_pair(NAN, NAN); } + virtual std::pair get_qvector_recentered(int /*order*/) const { return std::make_pair(NAN, NAN); } virtual double get_psi(int /*order*/) const { return NAN; } virtual double get_shifted_psi(int /*order*/) const { return NAN; } virtual double GetPsi(const double /*Qx*/, const double /*Qy*/, const unsigned int /*order*/) const { return NAN; } diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc new file mode 100644 index 0000000000..7f35820034 --- /dev/null +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc @@ -0,0 +1,23 @@ +#include "Eventplaneinfov2.h" + +#include + +void Eventplaneinfov2::identify(std::ostream& os) const +{ + os << "---------Eventplaneinfov2------------------" << std::endl; + return; +} + +double Eventplaneinfov2::GetPsi(const double Qx, const double Qy, const unsigned int order) const +{ + double temp; + if ((Qx == 0.0) && (Qy == 0.0)) + { + temp = NAN; + } + else + { + temp = atan2(Qy, Qx) / ((double) order); + } + return temp; +} diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.h b/offline/packages/eventplaneinfo/Eventplaneinfov2.h new file mode 100644 index 0000000000..c447316590 --- /dev/null +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.h @@ -0,0 +1,55 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef EVENTPLANEINFOV2_H +#define EVENTPLANEINFOV2_H + +#include "Eventplaneinfo.h" + +#include // for size_t +#include +#include +#include // for pair, make_pair +#include + +class PHObject; + +class Eventplaneinfov2 : public Eventplaneinfo +{ + public: + Eventplaneinfov2() = default; + ~Eventplaneinfov2() override = default; + + Eventplaneinfov2(const Eventplaneinfov2&) = default; + Eventplaneinfov2& operator=(const Eventplaneinfov2&) = default; + Eventplaneinfov2(Eventplaneinfov2&&) = default; + Eventplaneinfov2& operator=(Eventplaneinfov2&&) = default; + + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = Eventplaneinfov2(); } + PHObject* CloneMe() const override { return new Eventplaneinfov2(*this); } + + void set_qvector(std::vector> Qvec) override { mQvec = Qvec; } + void set_qvector_raw(const std::vector>& Qvec) override { mQvec_raw = Qvec; } + void set_qvector_recentered(const std::vector>& Qvec) override { mQvec_recentered = Qvec; } + void set_shifted_psi(std::vector Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } + std::pair get_qvector(int order) const override { return std::make_pair(mQvec[order - 1].first, mQvec[order - 1].second); } + std::pair get_qvector_raw(int order) const override { return std::make_pair(mQvec_raw[order - 1].first, mQvec_raw[order - 1].second); } + std::pair get_qvector_recentered(int order) const override { return std::make_pair(mQvec_recentered[order - 1].first, mQvec_recentered[order - 1].second); } + void set_ring_qvector(std::vector>> Qvec) override { ring_Qvec = Qvec; } + std::pair get_ring_qvector(int ring_index, int order) const override { return ring_Qvec[ring_index][order - 1]; } + double get_ring_psi(int ring_index, int order) const override {return GetPsi(ring_Qvec[ring_index][order - 1].first,ring_Qvec[ring_index][order - 1].second,order);} + double GetPsi(double Qx, double Qy, unsigned int order) const override; + double get_psi(int order) const override { return GetPsi(mQvec[order - 1].first, mQvec[order - 1].second, order);} + double get_shifted_psi(int order) const override { return mPsi_Shifted[order - 1]; } + + private: + std::vector> mQvec; + std::vector> mQvec_raw; + std::vector> mQvec_recentered; + std::vector mPsi_Shifted; + std::vector>> ring_Qvec; + ClassDefOverride(Eventplaneinfov2, 1); +}; + +#endif + diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2LinkDef.h b/offline/packages/eventplaneinfo/Eventplaneinfov2LinkDef.h new file mode 100644 index 0000000000..961c0446cf --- /dev/null +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class Eventplaneinfov2 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/eventplaneinfo/Makefile.am b/offline/packages/eventplaneinfo/Makefile.am index 3a1192095d..293e3675d6 100644 --- a/offline/packages/eventplaneinfo/Makefile.am +++ b/offline/packages/eventplaneinfo/Makefile.am @@ -32,13 +32,16 @@ pkginclude_HEADERS = \ EventPlaneCalibration.h \ Eventplaneinfo.h \ Eventplaneinfov1.h \ + Eventplaneinfov2.h \ EventplaneinfoMap.h \ EventplaneinfoMapv1.h \ - EventPlaneReco.h + EventPlaneReco.h \ + EventPlaneRecov2.h ROOTDICTS = \ Eventplaneinfo_Dict.cc \ Eventplaneinfov1_Dict.cc \ + Eventplaneinfov2_Dict.cc \ EventplaneinfoMap_Dict.cc \ EventplaneinfoMapv1_Dict.cc @@ -50,12 +53,14 @@ libeventplaneinfo_io_la_SOURCES = \ $(ROOTDICTS) \ Eventplaneinfo.cc \ Eventplaneinfov1.cc \ + Eventplaneinfov2.cc \ EventplaneinfoMap.cc \ EventplaneinfoMapv1.cc libeventplaneinfo_la_SOURCES = \ EventPlaneCalibration.cc \ - EventPlaneReco.cc + EventPlaneReco.cc \ + EventPlaneRecov2.cc # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h From aedac34906cd32551f024a3d44b37d9491b8478e Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 23 Jan 2026 14:01:49 -0500 Subject: [PATCH 206/866] CaloTowerStatus - sEPD Bad Tower Maps - Allow the sEPD bad tower maps to be processed via the CaloTowerStatus module. --- offline/packages/CaloReco/CaloTowerStatus.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index c5401edb33..954c0a2b3b 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -144,7 +144,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) } m_calibName_hotMap = m_detector + "nome"; - if (m_dettype == CaloTowerDefs::CEMC) + if (m_dettype == CaloTowerDefs::CEMC || m_dettype == CaloTowerDefs::SEPD) { m_calibName_hotMap = m_detector + "_BadTowerMap"; } From 6fb59afba8cf615bebe50a1805850a00a328a0f8 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Thu, 29 Jan 2026 22:37:40 -0500 Subject: [PATCH 207/866] Combined North-South Q-vector Calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrate the "Combined NS" calibration strategy into the reconstruction pipeline to improve event plane resolution and flatness. This update treats the combined North-South detector as a distinct third entity for flattening, while preserving multiplicity-based resolution weighting through individual sub-detector recentering. Core Logic Updates: - Calibration Loading: Updated LoadCalib to retrieve North-South specific second moments (⟨Qx2​⟩, ⟨Qy2​⟩, ⟨Qx​Qy​⟩) from the Calibration Database (CDB). - Matrix Computation: Implemented unique flattening matrix calculation for the NS detector slot (Index 2) during initialization. 1) "Best of Both Worlds" Correction: Refactored correct_QVecs to implement the optimized combination logic: 2) Recenters South and North vectors individually. 3) Sums the recentered components to form the combined recentered vector: Q_NS,rec​ = Q_S,rec ​+ Q_N,rec​. - Applies the dedicated NS flattening matrix to the resulting sum to ensure a circular (flat) distribution. - Raw Vector Summation: Updated process_sEPD to populate the raw NS vector by summing normalized sub-detector components, facilitating direct QA comparisons. Infrastructure & Efficiency: - Array Expansion: Increased internal storage arrays for m_correction_data, m_Q_raw, m_Q_recentered, and m_Q_flat from size 2 to size 3 to accommodate the NS detector index. Diagnostics & Quality Assurance: - Print Methods: Expanded print_correction_data and print_QVectors to display diagnostic information for all three detector slots (South, North, and NorthSouth). - Fallback Safety: Maintained fallback logic that utilizes raw Q-vectors in the event of missing calibration data or invalid event centrality, preventing empty output nodes. --- .../eventplaneinfo/EventPlaneRecov2.cc | 99 ++++++++++++++----- .../eventplaneinfo/EventPlaneRecov2.h | 15 +-- 2 files changed, 83 insertions(+), 31 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc index 8a468a1acb..f475f0ef57 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -74,7 +74,7 @@ bool EventPlaneRecov2::hasValidTree(const std::string &filePath) } //____________________________________________________________________________.. -int EventPlaneRecov2::Init([[maybe_unused]] PHCompositeNode *topNode) +int EventPlaneRecov2::Init(PHCompositeNode *topNode) { std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); @@ -152,6 +152,7 @@ void EventPlaneRecov2::LoadCalib() { size_t south_idx = static_cast(Subdetector::S); size_t north_idx = static_cast(Subdetector::N); + size_t ns_idx = static_cast(Subdetector::NS); for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { @@ -169,6 +170,10 @@ void EventPlaneRecov2::LoadCalib() std::string N_yy_avg_name = std::format("Q_N_yy_{}_avg", n); std::string N_xy_avg_name = std::format("Q_N_xy_{}_avg", n); + std::string NS_xx_avg_name = std::format("Q_NS_xx_{}_avg", n); + std::string NS_yy_avg_name = std::format("Q_NS_yy_{}_avg", n); + std::string NS_xy_avg_name = std::format("Q_NS_xy_{}_avg", n); + for (size_t cent_bin = 0; cent_bin < m_bins_cent; ++cent_bin) { int key = static_cast(cent_bin); @@ -194,6 +199,16 @@ void EventPlaneRecov2::LoadCalib() dataN.avg_Q_xy = m_cdbttree->GetDoubleValue(key, N_xy_avg_name); dataN.X_matrix = calculate_flattening_matrix(dataN.avg_Q_xx, dataN.avg_Q_yy, dataN.avg_Q_xy, n, cent_bin, "North"); + + // North South + // Note: We do NOT load avg_Q (x,y) for NS because NS is recentered by summing the recentered S and N vectors. + auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; + + dataNS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, NS_xx_avg_name); + dataNS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, NS_yy_avg_name); + dataNS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, NS_xy_avg_name); + + dataNS.X_matrix = calculate_flattening_matrix(dataNS.avg_Q_xx, dataNS.avg_Q_yy, dataNS.avg_Q_xy, n, cent_bin, "NorthSouth"); } } } @@ -222,11 +237,26 @@ void EventPlaneRecov2::print_correction_data() "Detector", "Avg Qx", "Avg Qy", "Avg Qxx", "Avg Qyy", "Avg Qxy"); // Iterate through Subdetectors {S, N} - for (size_t det_idx = 0; det_idx < 2; ++det_idx) + for (size_t det_idx = 0; det_idx < 3; ++det_idx) { - std::string det_name = (det_idx == static_cast(Subdetector::S)) ? "South" : "North"; - const auto& data = m_correction_data[h_idx][cent][det_idx]; // - + std::string det_name; + if (det_idx == 0) + { + det_name = "South"; + } + else if (det_idx == 1) + { + det_name = "North"; + } + else + { + det_name = "NorthSouth"; + } + + const auto& data = m_correction_data[h_idx][cent][det_idx]; + + // For NS, Avg Qx/Qy will be 0.0 because they are not loaded from CDB. + // This is expected behavior. std::cout << std::format(" {:<12} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n", det_name, data.avg_Q.x, data.avg_Q.y, @@ -376,6 +406,10 @@ int EventPlaneRecov2::process_sEPD(PHCompositeNode* topNode) m_Q_raw[h_idx][1].x /= sepd_total_charge_north; m_Q_raw[h_idx][1].y /= sepd_total_charge_north; + + // NEW: Calculate Raw NS (Sum of Raw S + Raw N) + m_Q_raw[h_idx][2].x = m_Q_raw[h_idx][0].x + m_Q_raw[h_idx][1].x; + m_Q_raw[h_idx][2].y = m_Q_raw[h_idx][0].y + m_Q_raw[h_idx][1].y; } return Fun4AllReturnCodes::EVENT_OK; @@ -391,11 +425,13 @@ void EventPlaneRecov2::correct_QVecs() size_t south_idx = static_cast(Subdetector::S); size_t north_idx = static_cast(Subdetector::N); + size_t ns_idx = static_cast(Subdetector::NS); for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; + auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; double Q_S_x_avg = dataS.avg_Q.x; double Q_S_y_avg = dataS.avg_Q.y; @@ -408,12 +444,16 @@ void EventPlaneRecov2::correct_QVecs() // Apply Recentering QVec q_S_recenter = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; QVec q_N_recenter = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + QVec q_NS_recenter = {q_S_recenter.x + q_N_recenter.x, q_S_recenter.y + q_N_recenter.y}; - m_Q_recentered[h_idx][0] = q_S_recenter; - m_Q_recentered[h_idx][1] = q_N_recenter; + m_Q_recentered[h_idx][south_idx] = q_S_recenter; + m_Q_recentered[h_idx][north_idx] = q_N_recenter; + m_Q_recentered[h_idx][ns_idx] = q_NS_recenter; + // Flattening Matrix const auto &X_S = dataS.X_matrix; const auto &X_N = dataN.X_matrix; + const auto &X_NS = dataNS.X_matrix; // Apply Flattening double Q_S_x_flat = X_S[0][0] * q_S_recenter.x + X_S[0][1] * q_S_recenter.y; @@ -421,11 +461,16 @@ void EventPlaneRecov2::correct_QVecs() double Q_N_x_flat = X_N[0][0] * q_N_recenter.x + X_N[0][1] * q_N_recenter.y; double Q_N_y_flat = X_N[1][0] * q_N_recenter.x + X_N[1][1] * q_N_recenter.y; + double Q_NS_x_flat = X_NS[0][0] * q_NS_recenter.x + X_NS[0][1] * q_NS_recenter.y; + double Q_NS_y_flat = X_NS[1][0] * q_NS_recenter.x + X_NS[1][1] * q_NS_recenter.y; + QVec q_S_flat = {Q_S_x_flat, Q_S_y_flat}; QVec q_N_flat = {Q_N_x_flat, Q_N_y_flat}; + QVec q_NS_flat = {Q_NS_x_flat, Q_NS_y_flat}; m_Q_flat[h_idx][south_idx] = q_S_flat; m_Q_flat[h_idx][north_idx] = q_N_flat; + m_Q_flat[h_idx][ns_idx] = q_NS_flat; } } @@ -446,9 +491,21 @@ void EventPlaneRecov2::print_QVectors() { int n = m_harmonics[h_idx]; - for (size_t det_idx = 0; det_idx < 2; ++det_idx) + for (size_t det_idx = 0; det_idx < 3; ++det_idx) { - std::string det_name = (det_idx == static_cast(Subdetector::S)) ? "South" : "North"; + std::string det_name; + if (det_idx == 0) + { + det_name = "South"; + } + else if (det_idx == 1) + { + det_name = "North"; + } + else + { + det_name = "NorthSouth"; + } const auto& raw = m_Q_raw[h_idx][det_idx]; const auto& rec = m_Q_recentered[h_idx][det_idx]; @@ -472,7 +529,7 @@ void EventPlaneRecov2::print_QVectors() std::cout << std::format("{:*>100}\n\n", ""); } -int EventPlaneRecov2::FillNode([[maybe_unused]] PHCompositeNode *topNode) +int EventPlaneRecov2::FillNode(PHCompositeNode *topNode) { EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); if (!epmap) @@ -507,6 +564,7 @@ int EventPlaneRecov2::FillNode([[maybe_unused]] PHCompositeNode *topNode) // Fallback logic: Use raw if calibration failed or centrality is out of range const auto& Q_S = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][0] : m_Q_flat[h_idx][0]; const auto& Q_N = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][1] : m_Q_flat[h_idx][1]; + const auto& Q_NS = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][2] : m_Q_flat[h_idx][2]; const auto& Q_S_raw = m_Q_raw[h_idx][0]; const auto& Q_S_recentered = m_Q_recentered[h_idx][0]; @@ -514,6 +572,9 @@ int EventPlaneRecov2::FillNode([[maybe_unused]] PHCompositeNode *topNode) const auto& Q_N_raw = m_Q_raw[h_idx][1]; const auto& Q_N_recentered = m_Q_recentered[h_idx][1]; + const auto& Q_NS_raw = m_Q_raw[h_idx][2]; + const auto& Q_NS_recentered = m_Q_recentered[h_idx][2]; + // South south_Qvec_raw[idx] = {Q_S_raw.x, Q_S_raw.y}; south_Qvec_recentered[idx] = {Q_S_recentered.x, Q_S_recentered.y}; @@ -525,18 +586,9 @@ int EventPlaneRecov2::FillNode([[maybe_unused]] PHCompositeNode *topNode) north_Qvec[idx] = {Q_N.x, Q_N.y}; // Combined (North + South) - double Qx_NS_raw = Q_S_raw.x + Q_N_raw.x; - double Qy_NS_raw = Q_S_raw.y + Q_N_raw.y; - - double Qx_NS_recentered = Q_S_recentered.x + Q_N_recentered.x; - double Qy_NS_recentered = Q_S_recentered.y + Q_N_recentered.y; - - double Qx_NS = Q_S.x + Q_N.x; - double Qy_NS = Q_S.y + Q_N.y; - - northsouth_Qvec_raw[idx] = {Qx_NS_raw, Qy_NS_raw}; - northsouth_Qvec_recentered[idx] = {Qx_NS_recentered, Qy_NS_recentered}; - northsouth_Qvec[idx] = {Qx_NS, Qy_NS}; + northsouth_Qvec_raw[idx] = {Q_NS_raw.x, Q_NS_raw.y}; + northsouth_Qvec_recentered[idx] = {Q_NS_recentered.x, Q_NS_recentered.y}; + northsouth_Qvec[idx] = {Q_NS.x, Q_NS.y}; } // Helper lambda to fill nodes using the class's GetPsi method @@ -562,9 +614,8 @@ int EventPlaneRecov2::FillNode([[maybe_unused]] PHCompositeNode *topNode) } //____________________________________________________________________________.. -int EventPlaneRecov2::process_event([[maybe_unused]] PHCompositeNode *topNode) +int EventPlaneRecov2::process_event(PHCompositeNode *topNode) { - EventHeader *eventInfo = findNode::getClass(topNode, "EventHeader"); if (!eventInfo) { diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h index a1d5017ca3..4d12aca1bd 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.h +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.h @@ -96,7 +96,8 @@ class EventPlaneRecov2 : public SubsysReco enum class Subdetector { S, - N + N, + NS }; struct QVec @@ -123,14 +124,14 @@ class EventPlaneRecov2 : public SubsysReco // Holds all correction data // key: [Harmonic][Cent][Subdetector] // Harmonics {2,3,4} -> 3 elements - // Subdetectors {S,N} -> 2 elements - std::array, m_bins_cent>, m_harmonics.size()> m_correction_data; + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_bins_cent>, m_harmonics.size()> m_correction_data; // sEPD Q Vectors // key: [Harmonic][Subdetector] - // Subdetectors {S,N} -> 2 elements - std::array, m_harmonics.size()> m_Q_raw{}; - std::array, m_harmonics.size()> m_Q_recentered{}; - std::array, m_harmonics.size()> m_Q_flat{}; + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_harmonics.size()> m_Q_raw{}; + std::array, m_harmonics.size()> m_Q_recentered{}; + std::array, m_harmonics.size()> m_Q_flat{}; }; #endif From 8b5c354c39a7ed64cae634b3bc9139e6a699c85d Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 31 Jan 2026 22:41:34 -0500 Subject: [PATCH 208/866] Code Review Address Major Issues: - Ensure m_directURL_EventPlaneCalib is not empty before passing it to hasValidTree - Removed unused vectors in EventPlaneRecov2 (south_psi, north_psi, northsouth_psi) - Guard against order == 0 to avoid divide-by-zero. - Add bounds checks before indexing Q-vector storage. --- .../eventplaneinfo/EventPlaneRecov2.cc | 6 +-- .../eventplaneinfo/Eventplaneinfov2.cc | 11 ++--- .../eventplaneinfo/Eventplaneinfov2.h | 48 +++++++++++++++---- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc index f475f0ef57..c2cd8e3360 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -78,7 +78,7 @@ int EventPlaneRecov2::Init(PHCompositeNode *topNode) { std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); - if (hasValidTree(m_directURL_EventPlaneCalib)) + if (!m_directURL_EventPlaneCalib.empty() && hasValidTree(m_directURL_EventPlaneCalib)) { m_cdbttree = std::make_unique(m_directURL_EventPlaneCalib); std::cout << PHWHERE << " Custom Event Plane Calib Found: " << m_directURL_EventPlaneCalib << std::endl; @@ -552,10 +552,6 @@ int EventPlaneRecov2::FillNode(PHCompositeNode *topNode) std::vector> northsouth_Qvec_recentered(vec_size, {NAN, NAN}); std::vector> northsouth_Qvec(vec_size, {NAN, NAN}); - std::vector south_psi(vec_size, NAN); - std::vector north_psi(vec_size, NAN); - std::vector northsouth_psi(vec_size, NAN); - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { int n = m_harmonics[h_idx]; diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc index 7f35820034..e8ff5385b8 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc @@ -10,14 +10,13 @@ void Eventplaneinfov2::identify(std::ostream& os) const double Eventplaneinfov2::GetPsi(const double Qx, const double Qy, const unsigned int order) const { - double temp; - if ((Qx == 0.0) && (Qy == 0.0)) + if (order == 0) { - temp = NAN; + return NAN; } - else + if ((Qx == 0.0) && (Qy == 0.0)) { - temp = atan2(Qy, Qx) / ((double) order); + return NAN; } - return temp; + return atan2(Qy, Qx) / static_cast(order); } diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.h b/offline/packages/eventplaneinfo/Eventplaneinfov2.h index c447316590..d69bc9a5ae 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov2.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.h @@ -32,17 +32,49 @@ class Eventplaneinfov2 : public Eventplaneinfo void set_qvector_raw(const std::vector>& Qvec) override { mQvec_raw = Qvec; } void set_qvector_recentered(const std::vector>& Qvec) override { mQvec_recentered = Qvec; } void set_shifted_psi(std::vector Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } - std::pair get_qvector(int order) const override { return std::make_pair(mQvec[order - 1].first, mQvec[order - 1].second); } - std::pair get_qvector_raw(int order) const override { return std::make_pair(mQvec_raw[order - 1].first, mQvec_raw[order - 1].second); } - std::pair get_qvector_recentered(int order) const override { return std::make_pair(mQvec_recentered[order - 1].first, mQvec_recentered[order - 1].second); } + std::pair get_qvector(int order) const override { return safe_qvec(mQvec, order); } + std::pair get_qvector_raw(int order) const override { return safe_qvec(mQvec_raw, order); } + std::pair get_qvector_recentered(int order) const override { return safe_qvec(mQvec_recentered, order); } void set_ring_qvector(std::vector>> Qvec) override { ring_Qvec = Qvec; } - std::pair get_ring_qvector(int ring_index, int order) const override { return ring_Qvec[ring_index][order - 1]; } - double get_ring_psi(int ring_index, int order) const override {return GetPsi(ring_Qvec[ring_index][order - 1].first,ring_Qvec[ring_index][order - 1].second,order);} + std::pair get_ring_qvector(int ring_index, int order) const override + { + if (ring_index < 0 || static_cast(ring_index) >= ring_Qvec.size()) + { + return {NAN, NAN}; + } + return safe_qvec(ring_Qvec[ring_index], order); + } + double get_ring_psi(int ring_index, int order) const override + { + auto q = get_ring_qvector(ring_index, order); + return GetPsi(q.first, q.second, static_cast(order)); + } + double GetPsi(double Qx, double Qy, unsigned int order) const override; - double get_psi(int order) const override { return GetPsi(mQvec[order - 1].first, mQvec[order - 1].second, order);} - double get_shifted_psi(int order) const override { return mPsi_Shifted[order - 1]; } - + double get_psi(int order) const override + { + auto q = get_qvector(order); + return GetPsi(q.first, q.second, static_cast(order)); + } + double get_shifted_psi(int order) const override + { + if (order <= 0 || static_cast(order) > mPsi_Shifted.size()) + { + return NAN; + } + return mPsi_Shifted[order - 1]; + } + private: + static std::pair safe_qvec(const std::vector>& v, int order) + { + if (order <= 0 || static_cast(order) > v.size()) + { + return {NAN, NAN}; + } + return v[order - 1]; + } + std::vector> mQvec; std::vector> mQvec_raw; std::vector> mQvec_recentered; From db925a71d75d22494ba41cd548e03fed517940e1 Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Mon, 9 Feb 2026 16:46:18 -0500 Subject: [PATCH 209/866] fix typo --- offline/packages/jetbackground/TimingCut.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index ad212d1146..a12c432c31 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -24,7 +24,7 @@ class TimingCut : public SubsysReco float Correct_Time_Ohfrac(float t, float ohfrac) { - float corrt = t + _fitFunc->Eval(ohfrac); + float corrt = t - _fitFunc->Eval(ohfrac); return corrt; } From 0e80888920b77df04b0f548bb9bdb7bbbba9c00a Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Mon, 9 Feb 2026 17:12:04 -0500 Subject: [PATCH 210/866] add includes and cdb stuff --- offline/packages/jetbackground/TimingCut.cc | 11 ++++++++++- offline/packages/jetbackground/TimingCut.h | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index 81053863f6..7d63e5c432 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -12,6 +12,11 @@ #include #include +#include // for CDBTF1 + +#include +#include +#include #include #include // for basic_ostream, operator<< #include // for _Rb_tree_iterator, opera... @@ -36,6 +41,10 @@ int TimingCut::Init(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } + _fitFile = new CDBTF(CDBInterface::instance()->getUrl("t_ohfrac_calib_Default")); + _fitFile->LoadCalibrations(); + _fitFunc = _fitFile->getTF("t_ohcal_calib_function_Default"); + return Fun4AllReturnCodes::EVENT_OK; } @@ -58,7 +67,7 @@ int TimingCut::CreateNodeTree(PHCompositeNode *topNode) int TimingCut::process_event(PHCompositeNode *topNode) { JetContainer *jets = findNode::getClass(topNode, _jetNodeName); - TowerInfoContainer* towersOH = findNode::getClas(topNode, _ohTowerName); + TowerInfoContainer* towersOH = findNode::getClass(topNode, _ohTowerName); if (!jets || !towersOH) { if (Verbosity() > 0 && !_missingInfoWarningPrinted) diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index a12c432c31..d932c4cac5 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -13,6 +13,7 @@ #include #include +class CDBTF; class PHCompositeNode; class TimingCut : public SubsysReco @@ -108,8 +109,8 @@ class TimingCut : public SubsysReco float _t_shift{0.0}; float _mbd_dt_width{3.0}; float _min_dphi{3*M_PI/4}; - TFile* _fitFile = nullptr; - TF1* _fitFunc = nullptr; + CDBTF* _fitFile{nullptr}; + TF1* _fitFunc{nullptr}; }; #endif From 7722e11146d6c4bf231bf71331eb0c5b4d816464 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 9 Feb 2026 21:34:37 -0500 Subject: [PATCH 211/866] Mods to allow different decay masses for the two decay particles --- .../KshortReconstruction.cc | 237 +++++++++++++++--- .../KshortReconstruction.h | 17 +- 2 files changed, 220 insertions(+), 34 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index f92bfc9581..a7a240ffcf 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -260,36 +260,63 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) // if(pair_dca_proj > pair_dca_cut) continue; - // invariant mass is calculated in this method - fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity); - fillNtp(tr1, tr2, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); - - if (Verbosity() > 1) - { - std::cout << " Accepted Track Pair" << std::endl; - std::cout << " id1 " << id1 << " id2 " << id2 << std::endl; - std::cout << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; - std::cout << " invariant mass: " << invariantMass << std::endl; - std::cout << " track1 dca_cut: " << this_dca_cut << " track2 dca_cut: " << this_dca_cut2 << std::endl; - std::cout << " dca3dxy1,dca3dz1,phi1: " << dcaVals1 << std::endl; - std::cout << " dca3dxy2,dca3dz2,phi2: " << dcaVals2 << std::endl; - std::cout << "Initial: pca_rel1: " << pca_rel1 << " pca_rel2: " << pca_rel2 << std::endl; - std::cout << " Initial: mom1: " << mom1 << " mom2: " << mom2 << std::endl; - std::cout << "Proj_pca_rel: proj_pos1: " << projected_pos1 << " proj_pos2: " << projected_pos2 << " proj_mom1: " << projected_mom1 << " proj_mom2: " << projected_mom2 << std::endl; - std::cout << " Relative PCA = " << abs(pair_dca) << " pca_cut = " << pair_dca_cut << std::endl; - std::cout << " charge 1: " << tr1->get_charge() << " charge2: " << tr2->get_charge() << std::endl; - std::cout << "found viable projection" << std::endl; - std::cout << "Final: pca_rel1_proj: " << pca_rel1_proj << " pca_rel2_proj: " << pca_rel2_proj << " mom1: " << projected_mom1 << " mom2: " << projected_mom2 << std::endl - << std::endl; - } - + // calculate both ways if decaymass1 and decaymass2 are different + int ncombinations = 1; + if(decaymass1 != decaymass2) + { + ncombinations = 2; + } + for(int icomb=0;icomb < ncombinations; ++icomb) + { + float decaymassa = decaymass1; + float decaymassb = decaymass2; + if(icomb == 1) + { + decaymassa = decaymass2; + decaymassb = decaymass1; + } + + // invariant mass is calculated in this method + fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity,decaymassa, decaymassb); + fillNtp(tr1, tr2, decaymassa, decaymassb, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); + + + + + + + /* + // invariant mass is calculated in this method + fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity); + fillNtp(tr1, tr2, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); + */ + + if (Verbosity() > 1) + { + std::cout << " Accepted Track Pair" << std::endl; + std::cout << " id1 " << id1 << " id2 " << id2 << std::endl; + std::cout << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; + std::cout << " invariant mass: " << invariantMass << std::endl; + std::cout << " track1 dca_cut: " << this_dca_cut << " track2 dca_cut: " << this_dca_cut2 << std::endl; + std::cout << " dca3dxy1,dca3dz1,phi1: " << dcaVals1 << std::endl; + std::cout << " dca3dxy2,dca3dz2,phi2: " << dcaVals2 << std::endl; + std::cout << "Initial: pca_rel1: " << pca_rel1 << " pca_rel2: " << pca_rel2 << std::endl; + std::cout << " Initial: mom1: " << mom1 << " mom2: " << mom2 << std::endl; + std::cout << "Proj_pca_rel: proj_pos1: " << projected_pos1 << " proj_pos2: " << projected_pos2 << " proj_mom1: " << projected_mom1 << " proj_mom2: " << projected_mom2 << std::endl; + std::cout << " Relative PCA = " << abs(pair_dca) << " pca_cut = " << pair_dca_cut << std::endl; + std::cout << " charge 1: " << tr1->get_charge() << " charge2: " << tr2->get_charge() << std::endl; + std::cout << "found viable projection" << std::endl; + std::cout << "Final: pca_rel1_proj: " << pca_rel1_proj << " pca_rel2_proj: " << pca_rel2_proj << " mom1: " << projected_mom1 << " mom2: " << projected_mom2 << std::endl + << std::endl; + } + } if (m_save_tracks) - { - m_output_trackMap = findNode::getClass(topNode, m_output_trackMap_node_name); - m_output_trackMap->insertWithKey(tr1, tr1->get_id()); - m_output_trackMap->insertWithKey(tr2, tr2->get_id()); - } - + { + m_output_trackMap = findNode::getClass(topNode, m_output_trackMap_node_name); + m_output_trackMap->insertWithKey(tr1, tr1->get_id()); + m_output_trackMap->insertWithKey(tr2, tr2->get_id()); + } + } } } @@ -340,6 +367,53 @@ std::vector KshortReconstruction::getTrackStates(SvtxTrack *track) return nstates; } +void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float mass1, float mass2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj, unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber) +{ + double px1 = track1->get_px(); + double py1 = track1->get_py(); + double pz1 = track1->get_pz(); + auto *tpcSeed1 = track1->get_tpc_seed(); + size_t tpcClusters1 = tpcSeed1->size_cluster_keys(); + double eta1 = asinh(pz1 / sqrt(pow(px1, 2) + pow(py1, 2))); + + double px2 = track2->get_px(); + double py2 = track2->get_py(); + double pz2 = track2->get_pz(); + auto *tpcSeed2 = track2->get_tpc_seed(); + size_t tpcClusters2 = tpcSeed2->size_cluster_keys(); + double eta2 = asinh(pz2 / sqrt(pow(px2, 2) + pow(py2, 2))); + + auto vtxid = track1->get_vertex_id(); + + int ntracks_vertex = 0; + Acts::Vector3 vertex(0, 0, track1->get_z()); // fake primary vertex + auto *svtxVertex = m_vertexMap->get(vtxid); + if (svtxVertex) + { + vertex(0) = svtxVertex->get_x(); + vertex(1) = svtxVertex->get_y(); + vertex(2) = svtxVertex->get_z(); + ntracks_vertex = svtxVertex->size_tracks(); + } + + Acts::Vector3 pathLength = (pca_rel1 + pca_rel2) * 0.5 - vertex; + Acts::Vector3 pathLength_proj = (pca_rel1_proj + pca_rel2_proj) * 0.5 - vertex; + + float mag_pathLength = sqrt(pow(pathLength(0), 2) + pow(pathLength(1), 2) + pow(pathLength(2), 2)); + float mag_pathLength_proj = sqrt(pow(pathLength_proj(0), 2) + pow(pathLength_proj(1), 2) + pow(pathLength_proj(2), 2)); + + Acts::Vector3 projected_momentum = projected_mom1 + projected_mom2; + float cos_theta_reco = pathLength_proj.dot(projected_momentum) / (projected_momentum.norm() * pathLength_proj.norm()); + + + float reco_info[] = {(float) track1->get_id(), (float) mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), (float) mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; + + ntp_reco_info->Fill(reco_info); +} + + + +/* void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj, unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber) { double px1 = track1->get_px(); @@ -381,6 +455,40 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::V ntp_reco_info->Fill(reco_info); } +*/ + +void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float &decaymassa, float &decaymassb) +{ + double E1 = sqrt(pow(mom1(0), 2) + pow(mom1(1), 2) + pow(mom1(2), 2) + pow(decaymassa, 2)); + double E2 = sqrt(pow(mom2(0), 2) + pow(mom2(1), 2) + pow(mom2(2), 2) + pow(decaymassb, 2)); + + TLorentzVector v1(mom1(0), mom1(1), mom1(2), E1); + TLorentzVector v2(mom2(0), mom2(1), mom2(2), E2); + + TLorentzVector tsum; + tsum = v1 + v2; + + rapidity = tsum.Rapidity(); + pseudorapidity = tsum.Eta(); + invariantMass = tsum.M(); + invariantPt = tsum.Pt(); + invariantPhi = tsum.Phi(); + + if (Verbosity() > 1) + { + std::cout << "px1: " << mom1(0) << " py1: " << mom1(1) << " pz1: " << mom1(2) << " mass " << decaymassa << " E1: " << E1 << std::endl; + std::cout << "px2: " << mom2(0) << " py2: " << mom2(1) << " pz2: " << mom2(2) << " mass2 " << decaymassb << " E2: " << E2 << std::endl; + std::cout << "tsum: " << tsum(0) << " " << tsum(1) << " " << tsum(2) << " " << tsum(3) << std::endl; + std::cout << "invariant mass: " << invariantMass << " invariant Pt: " << invariantPt << " invariantPhi: " << invariantPhi << std::endl; + } + + if (invariantPt > invariant_pt_cut) + { + massreco->Fill(invariantMass); + } +} + +/* void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity) { @@ -412,6 +520,7 @@ void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d m massreco->Fill(invariantMass); } } +*/ bool KshortReconstruction::projectTrackToPoint(SvtxTrack* track, Eigen::Vector3d PCA, Eigen::Vector3d& pos, Eigen::Vector3d& mom) { @@ -529,6 +638,66 @@ Acts::Vector3 KshortReconstruction::getVertex(SvtxTrack* track) return vertex; } +void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Acts::Vector3& pos2, Acts::Vector3 mom1, Acts::Vector3 mom2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca) const +{ + TLorentzVector v1; + TLorentzVector v2; + + double px1 = mom1(0); + double py1 = mom1(1); + double pz1 = mom1(2); + double px2 = mom2(0); + double py2 = mom2(1); + double pz2 = mom2(2); + + // calculate lorentz vector + const Eigen::Vector3d& a1 = pos1; + const Eigen::Vector3d& a2 = pos2; + + Eigen::Vector3d b1(px1, py1, pz1); + Eigen::Vector3d b2(px2, py2, pz2); + + // The shortest distance between two skew lines described by + // a1 + c * b1 + // a2 + d * b2 + // where a1, a2, are vectors representing points on the lines, b1, b2 are direction vectors, and c and d are scalars + // dca = (b1 x b2) .(a2-a1) / |b1 x b2| + + // bcrossb/mag_bcrossb is a unit vector perpendicular to both direction vectors b1 and b2 + auto bcrossb = b1.cross(b2); + auto mag_bcrossb = bcrossb.norm(); + // a2-a1 is the vector joining any arbitrary points on the two lines + auto aminusa = a2 - a1; + + // The DCA of these two lines is the projection of a2-a1 along the direction of the perpendicular to both + // remember that a2-a1 is longer than (or equal to) the dca by definition + dca = 999; + if (mag_bcrossb != 0) + { + dca = bcrossb.dot(aminusa) / mag_bcrossb; + } + else + { + return; // same track, skip combination + } + + // get the points at which the normal to the lines intersect the lines, where the lines are perpendicular + double X = b1.dot(b2) - (b1.dot(b1) * b2.dot(b2) / b2.dot(b1)); + double Y = (a2.dot(b2) - a1.dot(b2)) - ((a2.dot(b1) - a1.dot(b1)) * b2.dot(b2) / b2.dot(b1)); + double c = Y / X; + + double F = b1.dot(b1) / b2.dot(b1); + double G = -(a2.dot(b1) - a1.dot(b1)) / b2.dot(b1); + double d = (c * F) + G; + + // then the points of closest approach are: + pca1 = a1 + c * b1; + pca2 = a2 + d * b2; + + return; +} + +/* void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Acts::Vector3& pos2, Acts::Vector3 mom1, Acts::Vector3 mom2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca) const { TLorentzVector v1; @@ -593,6 +762,7 @@ void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Act return; } +*/ KshortReconstruction::KshortReconstruction(const std::string& name) : SubsysReco(name) @@ -653,8 +823,15 @@ int KshortReconstruction::InitRun(PHCompositeNode* topNode) { const char* cfilepath = filepath.c_str(); fout = new TFile(cfilepath, "recreate"); - ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "id1:crossing1:x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:id2:crossing2:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:invariantPhi:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco:track1_silicon_clusters:track2_silicon_clusters:track1_mvtx_clusters:track1_mvtx_states:track1_intt_clusters:track1_intt_states:track2_mvtx_clusters:track2_mvtx_states:track2_intt_clusters:track2_intt_states:runNumber:eventNumber"); +ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "id1:mass1:crossing1:x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:id2:mass2:crossing2:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:ntracks_vertex:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:invariantPhi:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco:track1_silicon_clusters:track2_silicon_clusters:track1_mvtx_clusters:track1_mvtx_states:track1_intt_clusters:track1_intt_states:track2_mvtx_clusters:track2_mvtx_states:track2_intt_clusters:track2_intt_states:runNumber:eventNumber"); + + + +/* + ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "id1:crossing1:x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:id2:crossing2:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:invariantPhi:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco:track1_silicon_clusters:track2_silicon_clusters:track1_mvtx_clusters:track1_mvtx_states:track1_intt_clusters:track1_intt_states:track2_mvtx_clusters:track2_mvtx_states:track2_intt_clusters:track2_intt_states:runNumber:eventNumber"); +*/ + getNodes(topNode); recomass = new TH1D("recomass", "recomass", 1000, 0.0, 1); // root histogram arguments: name,title,bins,minvalx,maxvalx diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.h b/offline/packages/TrackingDiagnostics/KshortReconstruction.h index 3ff1ae3501..2057ed18e2 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.h +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.h @@ -33,14 +33,20 @@ class KshortReconstruction : public SubsysReco void setPairDCACut(double cut) { pair_dca_cut = cut; } void setTrackDCACut(double cut) { track_dca_cut = cut; } void setRequireMVTX(bool set) { _require_mvtx = set; } - void setDecayMass(float decayMassSet) { decaymass = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) + void setDecayMass1(float decayMassSet) { decaymass1 = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) + void setDecayMass2(float decayMassSet) { decaymass2 = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) + // void setDecayMass(float decayMassSet) { decaymass = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) void set_output_file(const std::string& outputfile) { filepath = outputfile; } void save_tracks(bool save = true) { m_save_tracks = save; } private: - void fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); + void fillNtp(SvtxTrack* track1, SvtxTrack* track2, float mass1, float mass2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); - void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity); + // void fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); + + void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymass1, float& decaymass2); + + // void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity); // void findPcaTwoTracks(SvtxTrack *track1, SvtxTrack *track2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca); void findPcaTwoTracks(const Acts::Vector3& pos1, const Acts::Vector3& pos2, Acts::Vector3 mom1, Acts::Vector3 mom2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca) const; @@ -61,7 +67,10 @@ class KshortReconstruction : public SubsysReco SvtxVertexMap* m_vertexMap {nullptr}; std::string filepath {""}; - float decaymass {0.13957}; // pion decay mass + float decaymass1 = 0.13957; // pion decay mass + float decaymass2 = 0.13957; // pion decay mass + + //float decaymass {0.13957}; // pion decay mass bool _require_mvtx {true}; double _qual_cut {1000.0}; double pair_dca_cut {0.05}; // kshort relative cut 500 microns From 0b274287ca69bcb31f580b11166f95237ce2aaa0 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 10 Feb 2026 12:54:13 -0500 Subject: [PATCH 212/866] streamlined disabling distortion corrections in the TpcGlobalPosition wrapper using local variables to store the information is unnecessary. --- offline/packages/tpccalib/PHTpcResiduals.cc | 16 ------------ offline/packages/tpccalib/PHTpcResiduals.h | 29 ++++++++++++++------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 54bcb5b42e..4360bc7d1b 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -769,22 +769,6 @@ int PHTpcResiduals::getNodes(PHCompositeNode* topNode) // tpc global position wrapper m_globalPositionWrapper.loadNodes(topNode); - if (m_disable_module_edge_corr) - { - m_globalPositionWrapper.set_enable_module_edge_corr(false); - } - if (m_disable_static_corr) - { - m_globalPositionWrapper.set_enable_static_corr(false); - } - if (m_disable_average_corr) - { - m_globalPositionWrapper.set_enable_average_corr(false); - } - if (m_disable_fluctuation_corr) - { - m_globalPositionWrapper.set_enable_fluctuation_corr(false); - } return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index 66da67239d..62609e9400 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -106,10 +106,25 @@ class PHTpcResiduals : public SubsysReco m_useMicromegas = value; } - void disableModuleEdgeCorr() { m_disable_module_edge_corr = true; } - void disableStaticCorr() { m_disable_static_corr = true; } - void disableAverageCorr() { m_disable_average_corr = true; } - void disableFluctuationCorr() { m_disable_fluctuation_corr = true; } + void disableModuleEdgeCorr() + { + m_globalPositionWrapper.set_enable_module_edge_corr(false); + } + + void disableStaticCorr() + { + m_globalPositionWrapper.set_enable_static_corr(false); + } + + void disableAverageCorr() + { + m_globalPositionWrapper.set_enable_average_corr(false); + } + + void disableFluctuationCorr() + { + m_globalPositionWrapper.set_enable_fluctuation_corr(false); + } /// modify track map name void setTrackMapName( const std::string& value ) @@ -178,12 +193,6 @@ class PHTpcResiduals : public SubsysReco /// require track crossing zero bool m_requireCrossing = false; - /// disable distortion correction - bool m_disable_module_edge_corr = false; - bool m_disable_static_corr = false; - bool m_disable_average_corr = false; - bool m_disable_fluctuation_corr = false; - /// output file std::string m_outputfile = "TpcSpaceChargeMatrices.root"; From 4020ff11ae31044510947679a59996418887be33 Mon Sep 17 00:00:00 2001 From: Luke Legnosky Date: Tue, 10 Feb 2026 16:17:50 -0500 Subject: [PATCH 213/866] Updating TPC modules to replace floats with doubles. --- offline/packages/tpc/LaserClusterizer.cc | 32 ++++----- offline/packages/tpc/LaserClusterizer.h | 6 +- offline/packages/tpc/LaserEventIdentifier.cc | 2 +- offline/packages/tpc/LaserEventIdentifier.h | 4 +- offline/packages/tpc/LaserEventInfo.h | 4 +- offline/packages/tpc/LaserEventInfov1.cc | 2 +- offline/packages/tpc/LaserEventInfov1.h | 6 +- offline/packages/tpc/LaserEventInfov2.cc | 2 +- offline/packages/tpc/Tpc3DClusterizer.cc | 26 ++++---- offline/packages/tpc/Tpc3DClusterizer.h | 14 ++-- .../tpc/TpcClusterZCrossingCorrection.cc | 16 ++--- .../tpc/TpcClusterZCrossingCorrection.h | 14 ++-- offline/packages/tpc/TpcClusterizer.cc | 48 +++++++------- offline/packages/tpc/TpcClusterizer.h | 12 ++-- .../tpc/TpcCombinedRawDataUnpacker.cc | 56 ++++++++-------- .../packages/tpc/TpcCombinedRawDataUnpacker.h | 8 +-- .../tpc/TpcCombinedRawDataUnpackerDebug.cc | 66 +++++++++---------- .../tpc/TpcCombinedRawDataUnpackerDebug.h | 10 +-- .../tpc/TpcDistortionCorrectionContainer.h | 2 +- .../tpc/TpcLoadDistortionCorrection.h | 4 +- offline/packages/tpc/TpcRawWriter.cc | 4 +- offline/packages/tpc/TpcSimpleClusterizer.cc | 4 +- 22 files changed, 171 insertions(+), 171 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 754ee8d248..535e744ef1 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -59,7 +59,7 @@ namespace bg = boost::geometry; namespace bgi = boost::geometry::index; -using point = bg::model::point; +using point = bg::model::point; using box = bg::model::box; using specHitKey = std::pair; using adcKey = std::pair; @@ -180,16 +180,16 @@ namespace while (!q.empty()) { - float ix = q.front().first.get<0>(); - float iy = q.front().first.get<1>(); - float iz = q.front().first.get<2>(); + double ix = q.front().first.get<0>(); + double iy = q.front().first.get<1>(); + double iz = q.front().first.get<2>(); q.pop(); for (auto neigh : neighborOffsets) { - float nx = ix + neigh.get<0>(); - float ny = iy + neigh.get<1>(); - float nz = iz + neigh.get<2>(); + double nx = ix + neigh.get<0>(); + double ny = iy + neigh.get<1>(); + double nz = iz + neigh.get<2>(); for (unsigned int v = 0; v < unvisited.size(); v++) { @@ -258,9 +258,9 @@ namespace int meanSide = 0; - std::vector usedLayer; - std::vector usedIPhi; - std::vector usedIT; + std::vector usedLayer; + std::vector usedIPhi; + std::vector usedIT; double meanLayer = 0.0; double meanIPhi = 0.0; @@ -268,7 +268,7 @@ namespace for (auto &clusHit : clusHits) { - float coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; + double coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; std::pair spechitkey = clusHit.second.second; unsigned int adc = clusHit.second.first; @@ -293,7 +293,7 @@ namespace double hitZ = my_data.tdriftmax * my_data.tGeometry->get_drift_velocity() - hitzdriftlength; bool foundLayer = false; - for (float i : usedLayer) + for (double i : usedLayer) { if (coords[0] == i) { @@ -308,7 +308,7 @@ namespace } bool foundIPhi = false; - for (float i : usedIPhi) + for (double i : usedIPhi) { if (coords[1] == i) { @@ -323,7 +323,7 @@ namespace } bool foundIT = false; - for (float i : usedIT) + for (double i : usedIT) { if (coords[2] == i) { @@ -344,7 +344,7 @@ namespace 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); + clus->setHitAdc(clus->getNhits() - 1, (double) adc); rSum += r * adc; phiSum += phi * adc; @@ -669,7 +669,7 @@ namespace for (TrkrHitSet::ConstIterator hitr = hitrangei.first; hitr != hitrangei.second; ++hitr) { - float_t fadc = hitr->second->getAdc(); + double_t fadc = hitr->second->getAdc(); unsigned short adc = 0; if (fadc > my_data->adc_threshold) { diff --git a/offline/packages/tpc/LaserClusterizer.h b/offline/packages/tpc/LaserClusterizer.h index 8dc501a64f..28e4aaac73 100644 --- a/offline/packages/tpc/LaserClusterizer.h +++ b/offline/packages/tpc/LaserClusterizer.h @@ -40,9 +40,9 @@ class LaserClusterizer : public SubsysReco //void calc_cluster_parameter(std::vector &clusHits, std::multimap, std::array>> &adcMap, bool isLamination); //void remove_hits(std::vector &clusHits, boost::geometry::index::rtree> &rtree, std::multimap, std::array>> &adcMap); - void set_adc_threshold(float val) { m_adc_threshold = val; } - void set_min_clus_size(float val) { min_clus_size = val; } - void set_min_adc_sum(float val) { min_adc_sum = val; } + void set_adc_threshold(double val) { m_adc_threshold = val; } + void set_min_clus_size(double val) { min_clus_size = val; } + void set_min_adc_sum(double val) { min_adc_sum = val; } void set_max_time_samples(int val) { m_time_samples_max = val; } void set_lamination(bool val) { m_lamination = val; } void set_do_sequential(bool val) { m_do_sequential = val; } diff --git a/offline/packages/tpc/LaserEventIdentifier.cc b/offline/packages/tpc/LaserEventIdentifier.cc index 5968d2f09f..3c214161ae 100644 --- a/offline/packages/tpc/LaserEventIdentifier.cc +++ b/offline/packages/tpc/LaserEventIdentifier.cc @@ -89,7 +89,7 @@ int LaserEventIdentifier::InitRun(PHCompositeNode *topNode) { m_debugFile = new TFile(m_debugFileName.c_str(), "RECREATE"); } - float timeHistMax = m_time_samples_max; + double timeHistMax = m_time_samples_max; timeHistMax -= 0.5; m_itHist_0 = new TH1I("m_itHist_0", "side 0;it", m_time_samples_max, -0.5, timeHistMax); m_itHist_1 = new TH1I("m_itHist_1", "side 1;it", m_time_samples_max, -0.5, timeHistMax); diff --git a/offline/packages/tpc/LaserEventIdentifier.h b/offline/packages/tpc/LaserEventIdentifier.h index 5c0c5faf54..fa4f43733f 100644 --- a/offline/packages/tpc/LaserEventIdentifier.h +++ b/offline/packages/tpc/LaserEventIdentifier.h @@ -53,8 +53,8 @@ class LaserEventIdentifier : public SubsysReco bool isGl1LaserPileupEvent = false; int peakSample0 = -999; int peakSample1 = -999; - float peakWidth0 = -999; - float peakWidth1 = -999; + double peakWidth0 = -999; + double peakWidth1 = -999; int m_runnumber = 0; uint64_t prev_BCO = 0; diff --git a/offline/packages/tpc/LaserEventInfo.h b/offline/packages/tpc/LaserEventInfo.h index 48e5379b70..5379862549 100644 --- a/offline/packages/tpc/LaserEventInfo.h +++ b/offline/packages/tpc/LaserEventInfo.h @@ -32,8 +32,8 @@ class LaserEventInfo : public PHObject virtual int getPeakSample(const bool /*side*/) const { return std::numeric_limits::max(); } virtual void setPeakSample(const bool /*side*/, const int /*sample*/) {} - virtual float getPeakWidth(const bool /*side*/) const { return std::numeric_limits::quiet_NaN(); } - virtual void setPeakWidth(const bool /*side*/, const float /*width*/) {} + virtual double getPeakWidth(const bool /*side*/) const { return std::numeric_limits::quiet_NaN(); } + virtual void setPeakWidth(const bool /*side*/, const double /*width*/) {} protected: LaserEventInfo() = default; diff --git a/offline/packages/tpc/LaserEventInfov1.cc b/offline/packages/tpc/LaserEventInfov1.cc index 448cbb7e2b..9e68e0baba 100644 --- a/offline/packages/tpc/LaserEventInfov1.cc +++ b/offline/packages/tpc/LaserEventInfov1.cc @@ -20,7 +20,7 @@ void LaserEventInfov1::Reset() for (int i = 0; i < 2; i++) { m_peakSample[i] = std::numeric_limits::max(); - m_peakWidth[i] = std::numeric_limits::quiet_NaN(); + m_peakWidth[i] = std::numeric_limits::quiet_NaN(); } return; diff --git a/offline/packages/tpc/LaserEventInfov1.h b/offline/packages/tpc/LaserEventInfov1.h index 7497fdd780..e032736b01 100644 --- a/offline/packages/tpc/LaserEventInfov1.h +++ b/offline/packages/tpc/LaserEventInfov1.h @@ -23,14 +23,14 @@ class LaserEventInfov1 : public LaserEventInfo int getPeakSample(const bool side) const override { return m_peakSample[side]; } void setPeakSample(const bool side, const int sample) override { m_peakSample[side] = sample; } - float getPeakWidth(const bool side) const override { return m_peakWidth[side]; } - void setPeakWidth(const bool side, const float width) override { m_peakWidth[side] = width; } + double getPeakWidth(const bool side) const override { return m_peakWidth[side]; } + void setPeakWidth(const bool side, const double width) override { m_peakWidth[side] = width; } protected: bool m_isLaserEvent{false}; int m_peakSample[2] = {std::numeric_limits::max(), std::numeric_limits::max()}; - float m_peakWidth[2] = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + double m_peakWidth[2] = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; ClassDefOverride(LaserEventInfov1, 1); }; diff --git a/offline/packages/tpc/LaserEventInfov2.cc b/offline/packages/tpc/LaserEventInfov2.cc index c5f2ab60f4..ae40a14c62 100644 --- a/offline/packages/tpc/LaserEventInfov2.cc +++ b/offline/packages/tpc/LaserEventInfov2.cc @@ -24,7 +24,7 @@ void LaserEventInfov2::Reset() for (int i = 0; i < 2; i++) { m_peakSample[i] = std::numeric_limits::max(); - m_peakWidth[i] = std::numeric_limits::quiet_NaN(); + m_peakWidth[i] = std::numeric_limits::quiet_NaN(); } return; diff --git a/offline/packages/tpc/Tpc3DClusterizer.cc b/offline/packages/tpc/Tpc3DClusterizer.cc index 562231b71b..bdbfbb99e4 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.cc +++ b/offline/packages/tpc/Tpc3DClusterizer.cc @@ -50,7 +50,7 @@ namespace bg = boost::geometry; namespace bgi = boost::geometry::index; -using point = bg::model::point; +using point = bg::model::point; using box = bg::model::box; using specHitKey = std::pair; using pointKeyLaser = std::pair; @@ -215,7 +215,7 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) 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 + double_t fadc = (hitr->second->getAdc()); // - m_pedestal; // proper int rounding +0.5 unsigned short adc = 0; if (fadc > 0) { @@ -270,7 +270,7 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) 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 + double_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) @@ -347,9 +347,9 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) 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; + double x = r * cos(phi); + double y = r * sin(phi); + double z = m_tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength; if (side == 0){ z = -z; it = -it; @@ -524,13 +524,13 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi int iphimax = -1; int ilaymin = 6666; int ilaymax = -1; - float itmin = 66666666.6; - float itmax = -6666666666.6; + double itmin = 66666666.6; + double itmax = -6666666666.6; auto *clus = new LaserClusterv1; for (auto &clusHit : clusHits) { - float coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; + double coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; std::pair spechitkey = clusHit.second; int side = TpcDefs::getSide(spechitkey.second); @@ -555,8 +555,8 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi 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); + itmin = std::min(tbin, itmin); + itmax = std::max(tbin, itmax); for (auto &iterKey : adcMap) { @@ -571,7 +571,7 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi 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); + clus->setHitAdc(clus->getNhits() - 1, (double) adc); rSum += r * adc; phiSum += phi * adc; @@ -657,7 +657,7 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi << std::endl; */ // if (m_output){ - float fX[20] = {0}; + double fX[20] = {0}; int n = 0; fX[n++] = m_event; fX[n++] = m_seed; diff --git a/offline/packages/tpc/Tpc3DClusterizer.h b/offline/packages/tpc/Tpc3DClusterizer.h index 54175a3c9a..3e6ad621a9 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.h +++ b/offline/packages/tpc/Tpc3DClusterizer.h @@ -34,7 +34,7 @@ class PHG4TpcGeomContainer; class Tpc3DClusterizer : public SubsysReco { public: -typedef boost::geometry::model::point point; +typedef boost::geometry::model::point point; typedef boost::geometry::model::box box; typedef std::pair specHitKey; typedef std::pair pointKeyLaser; @@ -49,7 +49,7 @@ typedef std::pair pointKeyLaser; // void calc_cluster_parameter(std::vector &clusHits, std::multimap> &adcMap); void calc_cluster_parameter(std::vector &clusHits, std::multimap, std::array>> &adcMap); - // void remove_hits(std::vector &clusHits, boost::geometry::index::rtree > &rtree, std::multimap > &adcMap, std::multimap &adcCoords); + // void remove_hits(std::vector &clusHits, boost::geometry::index::rtree > &rtree, std::multimap > &adcMap, std::multimap &adcCoords); void remove_hits(std::vector &clusHits, boost::geometry::index::rtree> &rtree, std::multimap, std::array>> &adcMap); void set_debug(bool debug) { m_debug = debug; } @@ -57,9 +57,9 @@ typedef std::pair pointKeyLaser; void set_output(bool output) { m_output = output; } void set_output_name(const std::string &name) { m_outputFileName = name; } - void set_pedestal(float val) { pedestal = val; } - void set_min_clus_size(float val) { min_clus_size = val; } - void set_min_adc_sum(float val) { min_adc_sum = val; } + void set_pedestal(double val) { pedestal = val; } + void set_min_clus_size(double val) { min_clus_size = val; } + void set_min_adc_sum(double val) { min_adc_sum = val; } private: int m_event {-1}; @@ -106,8 +106,8 @@ typedef std::pair pointKeyLaser; LaserCluster *m_currentCluster {nullptr}; std::vector m_eventClusters; - std::vector m_currentHit; - std::vector m_currentHit_hardware; + std::vector m_currentHit; + std::vector m_currentHit_hardware; std::unique_ptr t_all; std::unique_ptr t_search; diff --git a/offline/packages/tpc/TpcClusterZCrossingCorrection.cc b/offline/packages/tpc/TpcClusterZCrossingCorrection.cc index 24c2552f55..dc4f8589fc 100644 --- a/offline/packages/tpc/TpcClusterZCrossingCorrection.cc +++ b/offline/packages/tpc/TpcClusterZCrossingCorrection.cc @@ -13,32 +13,32 @@ #include // default value, override from macro (cm/ns) -float TpcClusterZCrossingCorrection::_vdrift = 8.0e-03; +double TpcClusterZCrossingCorrection::_vdrift = 8.0e-03; // ns, same value as in pileup generator -float TpcClusterZCrossingCorrection::_time_between_crossings = sphenix_constants::time_between_crossings; +double TpcClusterZCrossingCorrection::_time_between_crossings = sphenix_constants::time_between_crossings; //______________________________________________________________________________________________ -float TpcClusterZCrossingCorrection::correctZ(float zinit, unsigned int side, short int crossing) +double TpcClusterZCrossingCorrection::correctZ(double zinit, unsigned int side, short int crossing) { if (crossing == std::numeric_limits::max()) { - return std::numeric_limits::quiet_NaN(); + return std::numeric_limits::quiet_NaN(); } - float z_bunch_separation = _time_between_crossings * _vdrift; + double z_bunch_separation = _time_between_crossings * _vdrift; // +ve crossing occurs in the future relative to time zero // -ve z side (south, side 0), cluster arrives late, so z seems more positive // +ve z side (north, side 1), cluster arrives late, so z seems more negative - float corrected_z; + double corrected_z; if (side == 0) { - corrected_z = zinit - (float) crossing * z_bunch_separation; + corrected_z = zinit - (double) crossing * z_bunch_separation; } else { - corrected_z = zinit + (float) crossing * z_bunch_separation; + corrected_z = zinit + (double) crossing * z_bunch_separation; } // std::cout << " TpcClusterZCrossingCorrection: crossing " << crossing << " _vdrift " << _vdrift << " zinit " << zinit << " side " << side << " z_bunch_separation " << z_bunch_separation << " corrected_z " << corrected_z << std::endl; diff --git a/offline/packages/tpc/TpcClusterZCrossingCorrection.h b/offline/packages/tpc/TpcClusterZCrossingCorrection.h index 5a95ca7f86..8321d31f7d 100644 --- a/offline/packages/tpc/TpcClusterZCrossingCorrection.h +++ b/offline/packages/tpc/TpcClusterZCrossingCorrection.h @@ -15,34 +15,34 @@ class TpcClusterZCrossingCorrection //@{ //! drift velocity (cm/ns) - static float get_vdrift() { return _vdrift; } + static double get_vdrift() { return _vdrift; } //! time between crossing (ns) - static float get_time_between_crossings() { return _time_between_crossings; } + static double get_time_between_crossings() { return _time_between_crossings; } //! apply correction on a given z - static float correctZ(float zinit, unsigned int side, short int crossing); + static double correctZ(double zinit, unsigned int side, short int crossing); //@} //!@name modifiers //@{ //! drift velocity (cm/ns) - static void set_vdrift( float value ) { _vdrift = value; } + static void set_vdrift( double value ) { _vdrift = value; } //! time between crossing (ns) - static void set_time_between_crossings( float value ) { _time_between_crossings = value; } + static void set_time_between_crossings( double value ) { _time_between_crossings = value; } //@} // TODO: move to private //!@name parameters //@{ //! drift velocity (cm/ns) - static float _vdrift; + static double _vdrift; private: //! time between crossing (ns) - static float _time_between_crossings; + static double _time_between_crossings; //@} diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 24405c8df4..f402f3e60f 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -101,16 +101,16 @@ namespace unsigned int layer = 0; int side = 0; unsigned int sector = 0; - float radius = 0; - float drift_velocity = 0; + double radius = 0; + double drift_velocity = 0; unsigned short pads_per_sector = 0; - float phistep = 0; - float pedestal = 0; - float seed_threshold = 0; - float edge_threshold = 0; - float min_err_squared = 0; - float min_clus_size = 0; - float min_adc_sum = 0; + double phistep = 0; + double pedestal = 0; + double seed_threshold = 0; + double edge_threshold = 0; + double min_err_squared = 0; + double min_clus_size = 0; + double min_adc_sum = 0; bool do_assoc = true; bool do_wedge_emulation = true; bool do_singles = true; @@ -661,8 +661,8 @@ namespace double clusiphi = iphi_sum / adc_sum; double clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); - float clusx = radius * cos(clusphi); - float clusy = radius * sin(clusphi); + double clusx = radius * cos(clusphi); + double clusy = radius * sin(clusphi); double clust = t_sum / adc_sum; // needed for surface identification double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); @@ -750,22 +750,22 @@ namespace { // Create a vector of inputs std::vector inputs; - inputs.emplace_back(torch::stack({torch::from_blob(std::vector(training_hits->v_adc.begin(), training_hits->v_adc.end()).data(), {1, 2 * nd + 1, 2 * nd + 1}, torch::kFloat32), + inputs.emplace_back(torch::stack({torch::from_blob(std::vector(training_hits->v_adc.begin(), training_hits->v_adc.end()).data(), {1, 2 * nd + 1, 2 * nd + 1}, torch::kFloat32), torch::full({1, 2 * nd + 1, 2 * nd + 1}, std::clamp((training_hits->layer - 7) / 16, 0, 2), torch::kFloat32), torch::full({1, 2 * nd + 1, 2 * nd + 1}, training_hits->z / radius, torch::kFloat32)}, 1)); // Execute the model and turn its output into a tensor at::Tensor ten_pos = module_pos.forward(inputs).toTensor(); - float nn_phi = training_hits->phi + std::clamp(ten_pos[0][0][0].item(), -(float) nd, (float) nd) * training_hits->phistep; - float nn_z = training_hits->z + std::clamp(ten_pos[0][1][0].item(), -(float) nd, (float) nd) * training_hits->zstep; - float nn_x = radius * std::cos(nn_phi); - float nn_y = radius * std::sin(nn_phi); + double nn_phi = training_hits->phi + std::clamp(ten_pos[0][0][0].item(), -(double) nd, (double) nd) * training_hits->phistep; + double nn_z = training_hits->z + std::clamp(ten_pos[0][1][0].item(), -(double) nd, (double) nd) * training_hits->zstep; + double nn_x = radius * std::cos(nn_phi); + double nn_y = radius * std::sin(nn_phi); Acts::Vector3 nn_global(nn_x, nn_y, nn_z); nn_global *= Acts::UnitConstants::cm; Acts::Vector3 nn_local = surface->transform(my_data.tGeometry->geometry().geoContext).inverse() * nn_global; nn_local /= Acts::UnitConstants::cm; - float nn_t = my_data.m_tdriftmax - std::fabs(nn_z) / my_data.tGeometry->get_drift_velocity(); + double nn_t = my_data.m_tdriftmax - std::fabs(nn_z) / my_data.tGeometry->get_drift_velocity(); clus_base->setLocalX(nn_local(0)); clus_base->setLocalY(nn_t); } @@ -921,7 +921,7 @@ namespace { continue; } - float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + double_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 unsigned short adc = 0; if (fadc > 0) { @@ -1657,13 +1657,13 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) /* PHG4TpcGeom *testlayergeom = geom_container->GetLayerCellGeom(32); - for( float iphi = 1408; iphi < 1408+ 128;iphi+=0.1){ + for( double iphi = 1408; iphi < 1408+ 128;iphi+=0.1){ double clusiphi = iphi; double clusphi = testlayergeom->get_phi(clusiphi); double radius = layergeom->get_radius(); - float clusx = radius * cos(clusphi); - float clusy = radius * sin(clusphi); - float clusz = -37.524; + double clusx = radius * cos(clusphi); + double clusy = radius * sin(clusphi); + double clusz = -37.524; TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey( 32,11, 0 ); Acts::Vector3 global(clusx, clusy, clusz); @@ -1762,11 +1762,11 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) { for (const auto &hit : data.phivec_ClusHitsVerbose[index]) { - mClusHitsVerbose->addPhiHit(hit.first, (float) hit.second); + mClusHitsVerbose->addPhiHit(hit.first, (double) hit.second); } for (const auto &hit : data.zvec_ClusHitsVerbose[index]) { - mClusHitsVerbose->addZHit(hit.first, (float) hit.second); + mClusHitsVerbose->addZHit(hit.first, (double) hit.second); } mClusHitsVerbose->push_hits(ckey); } diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index 84a58ceca6..801207654e 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -44,12 +44,12 @@ class TpcClusterizer : public SubsysReco void set_do_sequential(bool do_seq) { do_sequential = do_seq; } void set_do_split(bool split) { do_split = split; } void set_fixed_window(int fixed) { do_fixed_window = fixed; } - void set_pedestal(float val) { pedestal = val; } - void set_seed_threshold(float val) { seed_threshold = val; } - void set_edge_threshold(float val) { edge_threshold = val; } - void set_min_err_squared(float val) { min_err_squared = val; } - void set_min_clus_size(float val) { min_clus_size = val; } - void set_min_adc_sum(float val) { min_adc_sum = val; } + void set_pedestal(double val) { pedestal = val; } + void set_seed_threshold(double val) { seed_threshold = val; } + void set_edge_threshold(double val) { edge_threshold = val; } + void set_min_err_squared(double val) { min_err_squared = val; } + void set_min_clus_size(double val) { min_clus_size = val; } + void set_min_adc_sum(double val) { min_adc_sum = val; } void set_remove_singles(bool do_sing) { do_singles = do_sing; } void set_read_raw(bool read_raw) { do_read_raw = read_raw; } void set_max_cluster_half_size_phi(unsigned short size) { MaxClusterHalfSizePhi = size; } diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc index 5f276c3c3a..5abec18a2c 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc @@ -324,8 +324,8 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) hit_set_key = TpcDefs::genHitSetKey(layer, (mc_sectors[sector % 12]), side); hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); - float hpedestal = 0; - float hpedwidth = 0; + double hpedestal = 0; + double hpedwidth = 0; if (Verbosity() > 2) { @@ -372,7 +372,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) auto fee_entries_it = feeentries_map.find(fee_key); std::vector& fee_entries_vec = (*fee_entries_it).second; - float threshold_cut = m_zs_threshold[region]; + double threshold_cut = m_zs_threshold[region]; int nhitschan = 0; @@ -391,7 +391,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) { if (adc > 0) { - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { nhitschan++; } @@ -424,7 +424,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) { if (adc > 0) { - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { feehist->Fill(t, adc - hpedestal); if (t < (int) fee_entries_vec.size()) @@ -435,7 +435,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) } } - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { hit_key = TpcDefs::genHitKey(phibin, (unsigned int) t); // find existing hit, or create new one @@ -443,13 +443,13 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) if (!hit) { hit = new TrkrHitv2(); - hit->setAdc(float(adc) - hpedestal); + hit->setAdc(double(adc) - hpedestal); hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } if (m_writeTree) { - float fXh[18]; + double fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -462,10 +462,10 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) fXh[nh++] = channel; // channel; fXh[nh++] = sampadd; // sampadd; fXh[nh++] = sampch; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) t; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) t; fXh[nh++] = layer; - fXh[nh++] = (float(adc) - hpedestal); + fXh[nh++] = (double(adc) - hpedestal); fXh[nh++] = hpedestal; fXh[nh++] = hpedwidth; m_ntup_hits->Fill(fXh); @@ -499,18 +499,18 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) } std::vector::iterator fee_entries_vec_it = (*fee_entries_it).second.begin(); - std::vector pedvec(hist2d->GetNbinsX(), 0); + std::vector pedvec(hist2d->GetNbinsX(), 0); feebaseline_map.insert(std::make_pair(hiter.first, pedvec)); - std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); + std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); (*fee_blm_it).second.resize(hist2d->GetNbinsX(), 0); for (int binx = 1; binx < hist2d->GetNbinsX(); binx++) { double timebin = (hist2d->GetXaxis())->GetBinCenter(binx); std::string histname1d = "h" + std::to_string(hiter.first) + "_" + std::to_string((int) timebin); nhisttotal++; - float local_ped = 0; - float local_width = 0; - float entries = fee_entries_vec_it[timebin]; + double local_ped = 0; + double local_width = 0; + double entries = fee_entries_vec_it[timebin]; if (fee_entries_vec_it[timebin] > 100) { nhistfilled++; @@ -532,8 +532,8 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) for (int isum = -3; isum <= 3; isum++) { - float val = hist1d->GetBinContent(maxbin + isum); - float center = hist1d->GetBinCenter(maxbin + isum); + double val = hist1d->GetBinContent(maxbin + isum); + double center = hist1d->GetBinCenter(maxbin + isum); hibin_sum += center * val; hibin2_sum += center * center * val; hadc_sum += val; @@ -547,7 +547,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) if (m_writeTree) { - float fXh[11]; + double fXh[11]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -601,7 +601,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) unsigned int pad_key = create_pad_key(side, layer, phibin); - float fee = 0; + double fee = 0; std::map::iterator chan_it = chan_map.find(pad_key); if (chan_it != chan_map.end()) { @@ -612,10 +612,10 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) } int rx = get_rx(layer); - float corr = 0; + double corr = 0; unsigned int fee_key = create_fee_key(side, sector, rx, fee); - std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); + std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); if (fee_blm_it != feebaseline_map.end()) { if (tbin < (int) (*fee_blm_it).second.size()) @@ -623,13 +623,13 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) corr = (*fee_blm_it).second[tbin]; } hitr->second->setAdc(0); - float nuadc = (float(adc) - corr); - nuadc = std::max(nuadc, 0); + double nuadc = (double(adc) - corr); + nuadc = std::max(nuadc, 0); hitr->second->setAdc(nuadc); if (m_writeTree) { - float fXh[18]; + double fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -642,10 +642,10 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) fXh[nh++] = 0; // channel; fXh[nh++] = 0; // sampadd; fXh[nh++] = 0; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) tbin; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) tbin; fXh[nh++] = layer; - fXh[nh++] = float(adc); + fXh[nh++] = double(adc); fXh[nh++] = 0; // hpedestal2; fXh[nh++] = 0; // hpedwidth2; fXh[nh++] = corr; diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.h b/offline/packages/tpc/TpcCombinedRawDataUnpacker.h index 8c8bfd353b..0dcb0e555e 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.h +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.h @@ -88,8 +88,8 @@ class TpcCombinedRawDataUnpacker : public SubsysReco struct chan_info { unsigned int fee = std::numeric_limits::max(); - float ped = -1; - float width = -1; + double ped = -1; + double width = -1; int entries = 0; }; TNtuple *m_ntup{nullptr}; @@ -113,7 +113,7 @@ class TpcCombinedRawDataUnpacker : public SubsysReco bool m_doChanHitsCut{false}; int m_ChanHitsCut{9999}; - float m_ped_sig_cut{4.0}; + double m_ped_sig_cut{4.0}; bool m_writeTree{false}; bool m_do_baseline_corr{false}; @@ -125,7 +125,7 @@ class TpcCombinedRawDataUnpacker : public SubsysReco std::map chan_map; // stays in place std::map feeadc_map; // histos reset after each event std::map> feeentries_map; // cleared after each event - std::map> feebaseline_map; // cleared after each event + std::map> feebaseline_map; // cleared after each event }; #endif // TPC_COMBINEDRAWDATAUNPACKER_H diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc index 803a822aa9..c7dfe58261 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc @@ -278,7 +278,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) unsigned int phibin = layergeom->get_phibin(phi, side); if (m_writeTree) { - float fX[12]; + double fX[12]; int n = 0; fX[n++] = _ievent - 1; @@ -298,8 +298,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) hit_set_key = TpcDefs::genHitSetKey(layer, (mc_sectors[sector % 12]), side); hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); - float hpedestal = 0; - float hpedwidth = 0; + double hpedestal = 0; + double hpedwidth = 0; pedhist.Reset(); if (!m_do_zerosup) @@ -323,7 +323,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) if (!hit) { hit = new TrkrHitv2(); - hit->setAdc(float(adc)); + hit->setAdc(double(adc)); hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } @@ -357,7 +357,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) int hmaxbin = 0; for (int nbin = 1; nbin <= pedhist.GetNbinsX(); nbin++) { - float val = pedhist.GetBinContent(nbin); + double val = pedhist.GetBinContent(nbin); if (val > hmax) { hmaxbin = nbin; @@ -381,8 +381,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) for (int isum = -3; isum <= 3; isum++) { - float val = pedhist.GetBinContent(hmaxbin + isum); - float center = pedhist.GetBinCenter(hmaxbin + isum); + double val = pedhist.GetBinContent(hmaxbin + isum); + double center = pedhist.GetBinCenter(hmaxbin + isum); ibin_sum += center * val; ibin2_sum += center * center * val; adc_sum += val; @@ -462,12 +462,12 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) feehist->Fill(t, adc - hpedestal + pedestal_offset); } } - float threshold_cut = (hpedwidth * m_ped_sig_cut); + double threshold_cut = (hpedwidth * m_ped_sig_cut); if (m_do_zs_emulation) { threshold_cut = m_zs_threshold; } - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { hit_key = TpcDefs::genHitKey(phibin, (unsigned int) t); // find existing hit, or create new one @@ -477,17 +477,17 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) hit = new TrkrHitv2(); if (m_do_baseline_corr) { - hit->setAdc(float(adc) - hpedestal + pedestal_offset); + hit->setAdc(double(adc) - hpedestal + pedestal_offset); } else { - hit->setAdc(float(adc) - hpedestal); + hit->setAdc(double(adc) - hpedestal); } hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } if (m_writeTree) { - float fXh[18]; + double fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -500,10 +500,10 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) fXh[nh++] = 0; // channel; fXh[nh++] = 0; // sampadd; fXh[nh++] = 0; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) t; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) t; fXh[nh++] = layer; - fXh[nh++] = (float(adc) - hpedestal + pedestal_offset); + fXh[nh++] = (double(adc) - hpedestal + pedestal_offset); fXh[nh++] = hpedestal; fXh[nh++] = hpedwidth; @@ -527,9 +527,9 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) if (hiter.second != nullptr) { TH2I* hist2d = hiter.second; - std::vector pedvec(hist2d->GetNbinsX(), 0); + std::vector pedvec(hist2d->GetNbinsX(), 0); feebaseline_map.insert(std::make_pair(hiter.first, pedvec)); - std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); + std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); (*fee_blm_it).second.resize(hist2d->GetNbinsX(), 0); for (int binx = 1; binx < hist2d->GetNbinsX(); binx++) @@ -537,7 +537,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) 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; + double local_ped = 0; #ifdef DEBUG // if((*hiter).first == 210802&&timebin==383){ @@ -557,8 +557,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) for (int isum = -3; isum <= 3; isum++) { - float val = hist1d->GetBinContent(maxbin + isum); - float center = hist1d->GetBinCenter(maxbin + isum); + double val = hist1d->GetBinContent(maxbin + isum); + double center = hist1d->GetBinCenter(maxbin + isum); hibin_sum += center * val; // hibin2_sum += center * center * val; hadc_sum += val; @@ -624,9 +624,9 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) unsigned int pad_key = create_pad_key(side, layer, phibin); - float fee = 0; - float hpedestal2 = 0; - float hpedwidth2 = 0; + double fee = 0; + double hpedestal2 = 0; + double hpedwidth2 = 0; std::map::iterator chan_it = chan_map.find(pad_key); if (chan_it != chan_map.end()) { @@ -637,10 +637,10 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) } int rx = get_rx(layer); - float corr = 0; + double corr = 0; unsigned int fee_key = create_fee_key(side, sector, rx, fee); - std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); + std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); if (fee_blm_it != feebaseline_map.end()) { corr = (*fee_blm_it).second[tbin] - pedestal_offset; @@ -689,10 +689,10 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) } if (hpedwidth2 > -100 && hpedestal2 > -100) { - if ((float(adc) - pedestal_offset - corr) > (hpedwidth2 * m_ped_sig_cut)) + if ((double(adc) - pedestal_offset - corr) > (hpedwidth2 * m_ped_sig_cut)) { - float nuadc = (float(adc) - corr - pedestal_offset); - nuadc = std::max(nuadc, 0); + double nuadc = (double(adc) - corr - pedestal_offset); + nuadc = std::max(nuadc, 0); hitr->second->setAdc(nuadc); #ifdef DEBUG // hitr->second->setAdc(10); @@ -709,14 +709,14 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) << " phibin " << phibin << " adc " << adc << " corr: " << corr - << " adcnu " << (float(adc) - corr - pedestal_offset) + << " adcnu " << (double(adc) - corr - pedestal_offset) << " adc in " << hitr->second->getAdc() << std::endl; } #endif if (m_writeTree) { - float fXh[18]; + double fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -729,10 +729,10 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) fXh[nh++] = 0; // channel; fXh[nh++] = 0; // sampadd; fXh[nh++] = 0; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) tbin; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) tbin; fXh[nh++] = layer; - fXh[nh++] = float(adc); + fXh[nh++] = double(adc); fXh[nh++] = hpedestal2; fXh[nh++] = hpedwidth2; fXh[nh++] = corr; diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h index baca369042..dd68e55863 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h +++ b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h @@ -28,7 +28,7 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco int End(PHCompositeNode *topNode) override; void writeTree() { m_writeTree = true; } void do_zero_suppression(bool b) { m_do_zerosup = b; } - void set_pedestalSigmaCut(float b) { m_ped_sig_cut = b; } + void set_pedestalSigmaCut(double b) { m_ped_sig_cut = b; } void do_noise_rejection(bool b) { m_do_noise_rejection = b; } void doBaselineCorr(bool val) { m_do_baseline_corr = val; } void doZSEmulation(bool val) { m_do_zs_emulation = val; } @@ -49,8 +49,8 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco struct chan_info { unsigned int fee = std::numeric_limits::max(); - float ped = -1; - float width = -1; + double ped = -1; + double width = -1; }; unsigned int get_rx(unsigned int layer) { @@ -104,7 +104,7 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco int FEE_map[26]{4, 5, 0, 2, 1, 11, 9, 10, 8, 7, 6, 0, 1, 3, 7, 6, 5, 4, 3, 2, 0, 2, 1, 3, 5, 4}; int FEE_R[26]{2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; - float m_ped_sig_cut{4.0}; + double m_ped_sig_cut{4.0}; bool m_writeTree{false}; bool m_do_zerosup{true}; @@ -117,7 +117,7 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco std::string outfile_name; std::map chan_map; // stays in place std::map feeadc_map; // histos reset after each event - std::map> feebaseline_map; // cleared after each event + std::map> feebaseline_map; // cleared after each event }; #endif // TPC_COMBINEDRAWDATAUNPACKER_H diff --git a/offline/packages/tpc/TpcDistortionCorrectionContainer.h b/offline/packages/tpc/TpcDistortionCorrectionContainer.h index c7ba14937b..2d65ca79dd 100644 --- a/offline/packages/tpc/TpcDistortionCorrectionContainer.h +++ b/offline/packages/tpc/TpcDistortionCorrectionContainer.h @@ -21,7 +21,7 @@ class TpcDistortionCorrectionContainer int m_dimensions = 3; bool m_use_scalefactor = false; - float m_scalefactor = 1.0; + double m_scalefactor = 1.0; //! set the phi histogram to be interpreted as radians rather than mm bool m_phi_hist_in_radians = true; diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.h b/offline/packages/tpc/TpcLoadDistortionCorrection.h index 6727957487..276d18fec4 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.h +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.h @@ -48,7 +48,7 @@ class TpcLoadDistortionCorrection : public SubsysReco } //! set the scale factor to be applied to the correction - void set_scale_factor(DistortionType i, float value) + void set_scale_factor(DistortionType i, double value) { m_use_scalefactor[i] = true; m_scalefactor[i] = value; @@ -97,7 +97,7 @@ class TpcLoadDistortionCorrection : public SubsysReco std::array m_use_scalefactor = {}; //! scale factors - std::array m_scalefactor = {1.0,1.0,1.0,1.0}; + std::array m_scalefactor = {1.0,1.0,1.0,1.0}; //! set the phi histogram to be interpreted as radians rather than mm std::array m_phi_hist_in_radians = {true,true,true,true}; diff --git a/offline/packages/tpc/TpcRawWriter.cc b/offline/packages/tpc/TpcRawWriter.cc index 41c5f26df3..bc217516d7 100644 --- a/offline/packages/tpc/TpcRawWriter.cc +++ b/offline/packages/tpc/TpcRawWriter.cc @@ -311,7 +311,7 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) // count++; } std::cout << "processing tpc" << std::endl; - float tpc_zmax = m_tGeometry->get_max_driftlength() + m_tGeometry->get_CM_halfwidth(); + double tpc_zmax = m_tGeometry->get_max_driftlength() + m_tGeometry->get_CM_halfwidth(); // loop over the TPC HitSet objects TrkrHitSetContainer::ConstRange tpc_hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId); @@ -405,7 +405,7 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) { continue; } - float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + double_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 unsigned short adc = 0; if (fadc > 0) { diff --git a/offline/packages/tpc/TpcSimpleClusterizer.cc b/offline/packages/tpc/TpcSimpleClusterizer.cc index f1fb0d5b76..ec49c51aec 100644 --- a/offline/packages/tpc/TpcSimpleClusterizer.cc +++ b/offline/packages/tpc/TpcSimpleClusterizer.cc @@ -64,7 +64,7 @@ namespace unsigned int layer = 0; int side = 0; unsigned int sector = 0; - float pedestal = 0; + double pedestal = 0; bool do_assoc = true; unsigned short phibins = 0; unsigned short phioffset = 0; @@ -292,7 +292,7 @@ namespace unsigned short phibin = TpcDefs::getPad(hitr->first) - phioffset; unsigned short zbin = TpcDefs::getTBin(hitr->first) - zoffset; - float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + double_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 // std::cout << " layer: " << my_data->layer << " phibin " << phibin << " zbin " << zbin << " fadc " << hitr->second->getAdc() << " pedestal " << pedestal << " fadc " << std::endl unsigned short adc = 0; From 24b32d04cb306e399d3db156e5ed1b8aa32ba79a Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Wed, 11 Feb 2026 18:25:24 -0500 Subject: [PATCH 214/866] add protection against missing calib file or function --- offline/packages/jetbackground/TimingCut.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index 7d63e5c432..719fc8181c 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -42,8 +42,21 @@ int TimingCut::Init(PHCompositeNode *topNode) } _fitFile = new CDBTF(CDBInterface::instance()->getUrl("t_ohfrac_calib_Default")); - _fitFile->LoadCalibrations(); - _fitFunc = _fitFile->getTF("t_ohcal_calib_function_Default"); + if(_fitFile) + { + _fitFile->LoadCalibrations(); + _fitFunc = _fitFile->getTF("t_ohcal_calib_function_Default"); + if(!_fitFunc) + { + std::cout << "ERROR: NO CALIBRATION TF1 FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! This should never happen. ABORT RUN!" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + } + else + { + std::cout << "ERROR: NO CALIBRATION FILE FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! ABORT RUN!" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } return Fun4AllReturnCodes::EVENT_OK; } From 3fd2a487f9877573ef098986a781258ab695ae7b Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 11 Feb 2026 21:40:21 -0500 Subject: [PATCH 215/866] Fixes for maps --- offline/packages/tpc/TpcClusterizer.cc | 30 ++++++++++++++++++++++---- offline/packages/tpc/TpcClusterizer.h | 3 +++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 24405c8df4..17d7a0b4d1 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -29,6 +29,8 @@ #include #include // for SubsysReco +#include + #include #include @@ -1308,6 +1310,19 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) auto *g3 = static_cast (geom->GetLayerCellGeom(40)); // cast because << not in the base class std::cout << *g3 << std::endl; + auto evtHeader = findNode::getClass(topNode, "EVENTHEADER"); + if (evtHeader) + { + m_runNumber = evtHeader->get_RunNumber(); + m_isSimulation = (m_runNumber < 1000); // Threshold: < 1000 is simulation + std::cout << PHWHERE << "Run number = " << m_runNumber << ", isSimulation = " << m_isSimulation << std::endl; + } + else + { + std::cout << PHWHERE << "WARNING: EventHeader node not found; defaulting to simulation." << std::endl; + m_isSimulation = true; + } + if (m_maskDeadChannels) { m_deadChannelMap.clear(); @@ -1859,10 +1874,17 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db for (int i = 0; i < NChan; i++) { - int Layer = cdbttree->GetIntValue(i, "layer"); - int Sector = cdbttree->GetIntValue(i, "sector"); - int Side = cdbttree->GetIntValue(i, "side"); - int Pad = cdbttree->GetIntValue(i, "pad"); + int Layer0 = cdbttree->GetIntValue(i, "layer0"); // Simulation layer + int Layer1 = cdbttree->GetIntValue(i, "layer1"); // Data layer + int Sec = cdbttree->GetIntValue(i, "sector"); // Stored sector + int Side = cdbttree->GetIntValue(i, "side"); // 0 or 1 + int Pad0 = cdbttree->GetIntValue(i, "pad0"); // Simulation pad + int Pad1 = cdbttree->GetIntValue(i, "pad1"); // Data pad + + int Layer = (m_isSimulation) ? Layer0 : Layer1; + int Pad = (m_isSimulation) ? Pad0 : Pad1; + int Sector = (m_isSimulation) ? mc_sectors[Sec] : Sec; + if (Verbosity() > VERBOSITY_A_LOT) { std::cout << dbName << ": Will mask layer: " << Layer << ", sector: " << Sector << ", side: " << Side << ", Pad: " << Pad << std::endl; diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index 84a58ceca6..e8ceb04983 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -95,6 +95,9 @@ class TpcClusterizer : public SubsysReco bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; + int m_runNumber = -1; // Store run number from Event Header + bool m_isSimulation = true; // Default true; Updated based on run number + int mc_sectors[12]{5, 4, 3, 2, 1, 0, 11, 10, 9, 8, 7, 6}; void makeChannelMask(hitMaskTpcSet& aMask, const std::string& dbName, const std::string& totalChannelsToMask); TrkrHitSetContainer *m_hits = nullptr; From edb448dc40e7f45f05790f4baddd6c2c779a39be Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 11 Feb 2026 22:10:51 -0500 Subject: [PATCH 216/866] Fix --- offline/packages/tpc/TpcClusterizer.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 17d7a0b4d1..cd27eeb8f0 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1881,6 +1881,14 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db int Pad0 = cdbttree->GetIntValue(i, "pad0"); // Simulation pad int Pad1 = cdbttree->GetIntValue(i, "pad1"); // Data pad + if (Sec < 0 || Sec >= 12) + { + std::cout << PHWHERE << "WARNING: sector index " << Sec + << " out of range [0,11] in " << dbName + << ", skipping channel " << i << std::endl; + continue; + } + int Layer = (m_isSimulation) ? Layer0 : Layer1; int Pad = (m_isSimulation) ? Pad0 : Pad1; int Sector = (m_isSimulation) ? mc_sectors[Sec] : Sec; From 2305b2220986f5576c5fcd7782d2e79a0c7bd1b7 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 11 Feb 2026 22:25:46 -0500 Subject: [PATCH 217/866] Fix2 --- offline/packages/tpc/TpcClusterizer.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index cd27eeb8f0..dba038abe6 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1893,6 +1893,22 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db int Pad = (m_isSimulation) ? Pad0 : Pad1; int Sector = (m_isSimulation) ? mc_sectors[Sec] : Sec; + if (Layer < 7 || Layer > 48) + { + std::cout << PHWHERE << "WARNING: layer " << Layer + << " out of TPC range [7,48] in " << dbName + << ", skipping channel " << i << std::endl; + continue; + } + + if (Side < 0 || Side > 1) + { + std::cout << PHWHERE << "WARNING: side " << Side + << " out of range [0,1] in " << dbName + << ", skipping channel " << i << std::endl; + continue; + } + if (Verbosity() > VERBOSITY_A_LOT) { std::cout << dbName << ": Will mask layer: " << Layer << ", sector: " << Sector << ", side: " << Side << ", Pad: " << Pad << std::endl; From 0bc9fe491953708645e1909132a86570ebad9d9d Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Wed, 11 Feb 2026 22:41:21 -0500 Subject: [PATCH 218/866] Some --- offline/packages/tpc/TpcClusterizer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index dba038abe6..9217ebc40a 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1310,7 +1310,7 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) auto *g3 = static_cast (geom->GetLayerCellGeom(40)); // cast because << not in the base class std::cout << *g3 << std::endl; - auto evtHeader = findNode::getClass(topNode, "EVENTHEADER"); + auto *evtHeader = findNode::getClass(topNode, "EVENTHEADER"); if (evtHeader) { m_runNumber = evtHeader->get_RunNumber(); From f34b4423c5e8e2d12394c46a3f52fd9ac84f397c Mon Sep 17 00:00:00 2001 From: bogui56 Date: Thu, 12 Feb 2026 07:22:24 -0500 Subject: [PATCH 219/866] reco error update --- .../packages/trackbase/ClusterErrorPara.cc | 235 ++++++++++++++++-- offline/packages/trackbase/ClusterErrorPara.h | 1 + 2 files changed, 209 insertions(+), 27 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index cb62ed10f5..18e6a999b1 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -1,7 +1,8 @@ #include "ClusterErrorPara.h" #include "TrkrCluster.h" - +//#include +#include #include #include @@ -18,10 +19,18 @@ namespace { return x * x; } + } // namespace ClusterErrorPara::ClusterErrorPara() { + /* + ftpcR1 = new TF1("ftpcR1", "pol2", 0, 10); + ftpcR1->SetParameter(0, 3.206); + ftpcR1->SetParameter(1, -0.252); + ftpcR1->SetParameter(2, 0.007); + */ + f0 = new TF1("f0", "pol1", 0, 10); f0->SetParameter(0, 0.0163943); f0->SetParameter(1, 0.0192931); @@ -476,40 +485,212 @@ ClusterErrorPara::ClusterErrorPara() //_________________________________________________________________________________ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrCluster* cluster, double /*unused*/, TrkrDefs::cluskey key) { + bool is_data_reco; + recoConsts* rc = recoConsts::instance(); + if(rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos){ + is_data_reco = false; + } + else{ + // std::cout << "CHECK Setting reconstruction for data with CDB tag " << rc->get_StringFlag("CDB_GLOBALTAG") << std::endl; + is_data_reco = true; + } + int layer = TrkrDefs::getLayer(key); double phierror = cluster->getRPhiError(); double zerror = cluster->getZError(); - if (TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId) - { - if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39) - { - phierror *= 4; - zerror *= 4; - } - if (cluster->getEdge() >= 3) - { - phierror *= 4; - } - if (cluster->getOverlap() >= 2) - { - phierror *= 2; - } - if (cluster->getPhiSize() == 1) - { - phierror *= 10; + if(is_data_reco==false){ + if (TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId) + { + if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39) + { + phierror *= 4; + zerror *= 4; + } + if (cluster->getEdge() >= 3) + { + phierror *= 4; + } + if (cluster->getOverlap() >= 2) + { + phierror *= 2; + } + if (cluster->getPhiSize() == 1) + { + phierror *= 10; + } + if (cluster->getPhiSize() >= 5) + { + phierror *= 10; + } + + phierror = std::min(phierror, 0.1); + if (phierror < 0.0005) + { + phierror = 0.1; + } + } + }else{ + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId) + { + if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39 || layer == 54) + { + phierror *= 4; + zerror *= 4; + } + if (cluster->getEdge() >= 3) + { + phierror *= 4; + } + if (cluster->getOverlap() >= 2) + { + phierror *= 2; + } + if(layer>=7&&layer<(7+48)){ + //Set phi error + if (cluster->getPhiSize() == 1) + { + phierror *= 1.0; + } + if (cluster->getPhiSize() == 2) + { + phierror*=3.15; + } + if (cluster->getPhiSize() == 3) + { + phierror *=3.5; + } + if (cluster->getPhiSize() >3) + { + phierror *= 4; + } + //Set Z Error + if (cluster->getZSize() == 1){ + zerror*=1.0; + } + if (cluster->getZSize() == 2){ + if(layer>=7&&layer<(7+16)){ + zerror*=7; + } + if(layer>=(7+16)&&layer<(7+32)){ + zerror*=4.5; + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*=4.5; + } + + } + if ((cluster->getZSize() == 3) || (cluster->getZSize() == 4)){ + if(layer>=7&&layer<(7+16)){ + zerror*=7; + } + if(layer>=(7+16)&&layer<(7+32)){ + zerror*=5; + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*=5; + } + // zerror*=6; + } + if (cluster->getZSize() >5){ + if(layer>=7&&layer<(7+16)){ + zerror*=20; + } + if(layer>=(7+16)&&layer<(7+32)){ + zerror*=6; + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*=7; + } + } + TF1 ftpcR1("ftpcR1", "pol2", 0, 60); + ftpcR1.SetParameter(0, 3.206); + ftpcR1.SetParameter(1, -0.252); + ftpcR1.SetParameter(2, 0.007); + + TF1 ftpcR2("ftpcR2", "pol2", 0, 60); + ftpcR2.SetParameter(0, 4.48); + ftpcR2.SetParameter(1, -0.226); + ftpcR2.SetParameter(2, 0.00362); + + TF1 ftpcR3("ftpcR3", "pol2", 0, 60); + ftpcR3.SetParameter(0, 14.8112); + ftpcR3.SetParameter(1, -0.577); + ftpcR3.SetParameter(2, 0.00605); + + if(layer>=7&&layer<(7+16)){ + phierror*= ftpcR1.Eval(layer); + } + if(layer>=(7+16)&&layer<(7+32)){ + phierror*= ftpcR2.Eval(layer); + } + if(layer>=(7+32)&&layer<(7+48)){ + phierror*= ftpcR3.Eval(layer); + } + ftpcR2.SetParameter(0, 5.593); + ftpcR2.SetParameter(1, -0.2458); + ftpcR2.SetParameter(2, 0.00333455); + + ftpcR3.SetParameter(0, 5.6964); + ftpcR3.SetParameter(1, -0.21338); + ftpcR3.SetParameter(2, 0.002502); + + if(layer>=(7+16)&&layer<(7+32)){ + zerror*= ftpcR2.Eval(layer); + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*= ftpcR3.Eval(layer); + } + } + if (cluster->getPhiSize() >= 5) + { + phierror *= 10; + } + } + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::mvtxId){ + phierror*=2; + zerror*=2; } - if (cluster->getPhiSize() >= 5) - { - phierror *= 10; + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::inttId){ + phierror*=9; + if (cluster->getPhiSize() == 1){ + phierror *= 1.25; + } + if (cluster->getPhiSize() == 2){ + phierror *= 2.25; + } + if(layer==3||layer==4) + phierror*=0.8; + if(layer==5||layer==6) + phierror*=1.2; } - - phierror = std::min(phierror, 0.1); - if (phierror < 0.0005) - { - phierror = 0.1; + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::micromegasId){ + if(layer==55){ + /* + phierror*=5.4; + phierror*=4.6; + phierror*=3.0; + zerror*=0.82; + */ + phierror = 0.0289; + } + + if(layer==56){ + /* + phierror*=0.9; + phierror*=0.95; + zerror*=4.5; + zerror*=3.4; + */ + zerror = 0.577; + } } } + return std::make_pair(square(phierror), square(zerror)); } diff --git a/offline/packages/trackbase/ClusterErrorPara.h b/offline/packages/trackbase/ClusterErrorPara.h index b125858217..ad12c1b522 100644 --- a/offline/packages/trackbase/ClusterErrorPara.h +++ b/offline/packages/trackbase/ClusterErrorPara.h @@ -128,6 +128,7 @@ class ClusterErrorPara double scale_mm_1 {1.5}; double pull_fine_phi[60]{}; double pull_fine_z[60]{}; + }; #endif From e13fbb091d87c78fdadf87e397640bad2df84d07 Mon Sep 17 00:00:00 2001 From: bogui56 Date: Thu, 12 Feb 2026 07:52:14 -0500 Subject: [PATCH 220/866] jenkins 1 --- offline/packages/trackbase/ClusterErrorPara.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 18e6a999b1..965f1db09a 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -22,7 +22,7 @@ namespace } // namespace -ClusterErrorPara::ClusterErrorPara() +ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} { /* ftpcR1 = new TF1("ftpcR1", "pol2", 0, 10); From 89772f9056642c741f192da7953b23a5002c3df1 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Thu, 12 Feb 2026 12:48:03 -0500 Subject: [PATCH 221/866] Requested fixes. --- offline/packages/tpc/TpcClusterizer.cc | 61 ++++++++++++++------------ offline/packages/tpc/TpcClusterizer.h | 8 +++- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 9217ebc40a..0de48f2cdd 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -29,8 +29,6 @@ #include #include // for SubsysReco -#include - #include #include @@ -1310,19 +1308,6 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) auto *g3 = static_cast (geom->GetLayerCellGeom(40)); // cast because << not in the base class std::cout << *g3 << std::endl; - auto *evtHeader = findNode::getClass(topNode, "EVENTHEADER"); - if (evtHeader) - { - m_runNumber = evtHeader->get_RunNumber(); - m_isSimulation = (m_runNumber < 1000); // Threshold: < 1000 is simulation - std::cout << PHWHERE << "Run number = " << m_runNumber << ", isSimulation = " << m_isSimulation << std::endl; - } - else - { - std::cout << PHWHERE << "WARNING: EventHeader node not found; defaulting to simulation." << std::endl; - m_isSimulation = true; - } - if (m_maskDeadChannels) { m_deadChannelMap.clear(); @@ -1883,29 +1868,51 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db if (Sec < 0 || Sec >= 12) { - std::cout << PHWHERE << "WARNING: sector index " << Sec - << " out of range [0,11] in " << dbName - << ", skipping channel " << i << std::endl; + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << PHWHERE << "WARNING: sector index " << Sec + << " out of range [0,11] in " << dbName + << ", skipping channel " << i << std::endl; + } continue; } - int Layer = (m_isSimulation) ? Layer0 : Layer1; - int Pad = (m_isSimulation) ? Pad0 : Pad1; - int Sector = (m_isSimulation) ? mc_sectors[Sec] : Sec; + int Layer; + int Pad; + int Sector; + + if (!m_is_data) + { + Layer = Layer0; + Pad = Pad0; + Sector = mc_sectors[Sec]; + } + else + { + Layer = Layer1; + Pad = Pad1; + Sector = Sec; + } if (Layer < 7 || Layer > 48) { - std::cout << PHWHERE << "WARNING: layer " << Layer - << " out of TPC range [7,48] in " << dbName - << ", skipping channel " << i << std::endl; + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << PHWHERE << "WARNING: layer " << Layer + << " out of TPC range [7,48] in " << dbName + << ", skipping channel " << i << std::endl; + } continue; } if (Side < 0 || Side > 1) { - std::cout << PHWHERE << "WARNING: side " << Side - << " out of range [0,1] in " << dbName - << ", skipping channel " << i << std::endl; + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << PHWHERE << "WARNING: side " << Side + << " out of range [0,1] in " << dbName + << ", skipping channel " << i << std::endl; + } continue; } diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index e8ceb04983..8eaf47e02d 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -75,6 +75,11 @@ class TpcClusterizer : public SubsysReco ClusHitsVerbosev1 *mClusHitsVerbose{nullptr}; + void SetSimDataFlag(bool flag) + { + m_is_data = flag; + } + void SetMaskChannelsFromFile() { m_maskFromFile = true; @@ -95,8 +100,6 @@ class TpcClusterizer : public SubsysReco bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; - int m_runNumber = -1; // Store run number from Event Header - bool m_isSimulation = true; // Default true; Updated based on run number int mc_sectors[12]{5, 4, 3, 2, 1, 0, 11, 10, 9, 8, 7, 6}; void makeChannelMask(hitMaskTpcSet& aMask, const std::string& dbName, const std::string& totalChannelsToMask); @@ -137,6 +140,7 @@ class TpcClusterizer : public SubsysReco bool m_maskDeadChannels {false}; bool m_maskHotChannels {false}; + bool m_is_data {false}; bool m_maskFromFile {false}; std::string m_deadChannelMapName; std::string m_hotChannelMapName; From b42fdf57f3efbd78048290d274d421ac2e8478ca Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Thu, 12 Feb 2026 12:54:17 -0500 Subject: [PATCH 222/866] More --- offline/packages/tpc/TpcClusterizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index 8eaf47e02d..550301f813 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -75,7 +75,7 @@ class TpcClusterizer : public SubsysReco ClusHitsVerbosev1 *mClusHitsVerbose{nullptr}; - void SetSimDataFlag(bool flag) + void SetIsData(bool flag) { m_is_data = flag; } From 4a18fc36a8b4747579510b222890db26799e2a96 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Thu, 12 Feb 2026 23:55:14 -0500 Subject: [PATCH 223/866] Another fix. --- offline/packages/tpc/TpcClusterizer.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 0de48f2cdd..e7fa17fa9e 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1859,8 +1859,7 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db for (int i = 0; i < NChan; i++) { - int Layer0 = cdbttree->GetIntValue(i, "layer0"); // Simulation layer - int Layer1 = cdbttree->GetIntValue(i, "layer1"); // Data layer + int Layer = cdbttree->GetIntValue(i, "layer"); // Stored layer int Sec = cdbttree->GetIntValue(i, "sector"); // Stored sector int Side = cdbttree->GetIntValue(i, "side"); // 0 or 1 int Pad0 = cdbttree->GetIntValue(i, "pad0"); // Simulation pad @@ -1877,19 +1876,16 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db continue; } - int Layer; int Pad; int Sector; if (!m_is_data) { - Layer = Layer0; Pad = Pad0; Sector = mc_sectors[Sec]; } else { - Layer = Layer1; Pad = Pad1; Sector = Sec; } From 3d74e878218b940240de2922392be3fd02545830 Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 13 Feb 2026 05:16:36 -0500 Subject: [PATCH 224/866] thanks for coderabbits help --- .../packages/trackbase/ClusterErrorPara.cc | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 965f1db09a..7e7ec8fca5 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -485,14 +485,15 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} //_________________________________________________________________________________ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrCluster* cluster, double /*unused*/, TrkrDefs::cluskey key) { - bool is_data_reco; + recoConsts* rc = recoConsts::instance(); - if(rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos){ - is_data_reco = false; - } - else{ - // std::cout << "CHECK Setting reconstruction for data with CDB tag " << rc->get_StringFlag("CDB_GLOBALTAG") << std::endl; - is_data_reco = true; + bool is_data_reco = true; // default to data + if(rc->FlagExist("CDB_GLOBALTAG")) + { + if(rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos) + { + is_data_reco = false; + } } int layer = TrkrDefs::getLayer(key); @@ -593,7 +594,7 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu } // zerror*=6; } - if (cluster->getZSize() >5){ + if (cluster->getZSize() >=5){ if(layer>=7&&layer<(7+16)){ zerror*=20; } @@ -604,17 +605,17 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu zerror*=7; } } - TF1 ftpcR1("ftpcR1", "pol2", 0, 60); + static TF1 ftpcR1("ftpcR1", "pol2", 0, 60); ftpcR1.SetParameter(0, 3.206); ftpcR1.SetParameter(1, -0.252); ftpcR1.SetParameter(2, 0.007); - TF1 ftpcR2("ftpcR2", "pol2", 0, 60); + static TF1 ftpcR2("ftpcR2", "pol2", 0, 60); ftpcR2.SetParameter(0, 4.48); ftpcR2.SetParameter(1, -0.226); ftpcR2.SetParameter(2, 0.00362); - TF1 ftpcR3("ftpcR3", "pol2", 0, 60); + static TF1 ftpcR3("ftpcR3", "pol2", 0, 60); ftpcR3.SetParameter(0, 14.8112); ftpcR3.SetParameter(1, -0.577); ftpcR3.SetParameter(2, 0.00605); From 0ae0e709d54e7f8ae674289c036dff0f79a4778a Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 13 Feb 2026 06:37:34 -0500 Subject: [PATCH 225/866] more rabbits --- .../packages/trackbase/ClusterErrorPara.cc | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 7e7ec8fca5..6baf4bc291 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -486,14 +486,18 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrCluster* cluster, double /*unused*/, TrkrDefs::cluskey key) { - recoConsts* rc = recoConsts::instance(); - bool is_data_reco = true; // default to data - if(rc->FlagExist("CDB_GLOBALTAG")) - { - if(rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos) - { - is_data_reco = false; - } + static bool is_data_reco{true}; // default to data + static bool is_data_reco_set{false}; // default to data + if(!is_data_reco_set){ + recoConsts* rc = recoConsts::instance(); + if(rc->FlagExist("CDB_GLOBALTAG")) + { + if(rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos) + { + is_data_reco = false; + } + } + is_data_reco_set = true; } int layer = TrkrDefs::getLayer(key); @@ -605,6 +609,7 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu zerror*=7; } } + /* static TF1 ftpcR1("ftpcR1", "pol2", 0, 60); ftpcR1.SetParameter(0, 3.206); ftpcR1.SetParameter(1, -0.252); @@ -642,6 +647,29 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu } if(layer>=(7+32)&&layer<(7+48)){ zerror*= ftpcR3.Eval(layer); + } + */ + + // Inline pol2 evaluation: p0 + p1*x + p2*x^2 + auto pol2 = [](double x, double p0, double p1, double p2) { + return p0 + p1 * x + p2 * x * x; + }; + + if(layer>=7&&layer<(7+16)){ + phierror *= pol2(layer, 3.206, -0.252, 0.007); + } + if(layer>=(7+16)&&layer<(7+32)){ + phierror *= pol2(layer, 4.48, -0.226, 0.00362); + } + if(layer>=(7+32)&&layer<(7+48)){ + phierror *= pol2(layer, 14.8112, -0.577, 0.00605); + } + + if(layer>=(7+16)&&layer<(7+32)){ + zerror *= pol2(layer, 5.593, -0.2458, 0.00333455); + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror *= pol2(layer, 5.6964, -0.21338, 0.002502); } } if (cluster->getPhiSize() >= 5) From ee1177c011476e8f7a8d535dd08ea25b3a5d04af Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 13 Feb 2026 06:53:17 -0500 Subject: [PATCH 226/866] and another rabbit --- offline/packages/trackbase/ClusterErrorPara.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 6baf4bc291..f2df20c0f9 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -486,6 +486,18 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrCluster* cluster, double /*unused*/, TrkrDefs::cluskey key) { + static const bool is_data_reco = []() { + recoConsts* rc = recoConsts::instance(); + if (rc->FlagExist("CDB_GLOBALTAG")) + { + if (rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos) + { + return false; + } + } + return true; // default to data + }(); + /* static bool is_data_reco{true}; // default to data static bool is_data_reco_set{false}; // default to data if(!is_data_reco_set){ @@ -499,7 +511,7 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu } is_data_reco_set = true; } - + */ int layer = TrkrDefs::getLayer(key); double phierror = cluster->getRPhiError(); From e18101b7274693507df186e239b1d9751a6ea263 Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 13 Feb 2026 08:23:31 -0500 Subject: [PATCH 227/866] now to jenkins --- .../packages/trackbase/ClusterErrorPara.cc | 88 +++++++++++++------ 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index f2df20c0f9..16fe2066b4 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -22,7 +22,37 @@ namespace } // namespace -ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} +ClusterErrorPara::ClusterErrorPara(): + f0{new TF1("f0", "pol1", 0, 10)}, + f1{new TF1("f1", "pol2", 0, 10)}, + f2{new TF1("f2", "pol2", 0, 10)}, + f0fine{new TF1("f0fine", "pol2", 0, 20000)}, + f1fine{new TF1("f1fine", "pol3", 0, 20000)}, + f2fine{new TF1("f2fine", "pol5", 0, 20000)}, + f2fine2{new TF1("f2fine", "pol5", 0, 20000)}, + fz0{new TF1("fz0", "pol2", -2, 2)}, + fz1{new TF1("fz1", "pol4", -2, 2)}, + fz2{new TF1("fz2", "pol2", -2, 2)}, + fz0fine{new TF1("fz0fine", "pol2", 0, 20000)}, + fz1fine{new TF1("fz1fine", "pol3", 0, 20000)}, + fz2fine{new TF1("fz2fine", "pol5", 0, 20000)}, + fmm_55_2{new TF1("fmm_55_2", "pol2", -2, 2)}, + fmm_56_2{new TF1("fmm_56_2", "pol2", -2, 2)}, + fmm_3{new TF1("fmm_3", "pol2", -2, 2)}, + fadcz0{new TF1("fadcz0", "pol5", 0, 20000)}, + fadcz1{new TF1("fadcz1", "pol5", 0, 20000)}, + fadcz2{new TF1("fadcz2", "pol5", 0, 20000)}, + fadcz0fine{new TF1("fadcz0fine", "[0]+([1]/pow(x-[2],2))", 0, 20000)}, + fadcz1fine{new TF1("fadcz1fine", "[0]+([1]/pow(x-[2],2))", 0, 20000)}, + fadcz2fine{new TF1("fadcz2fine", "[0]+([1]/pow(x-[2],2))", 0, 20000)}, + fadcphi0{new TF1("fadcphi0", "pol4", 0, 20000)}, + fadcphi0fine{new TF1("fadcphi0fine", "pol2", 0, 20000)}, + fadcphi1{new TF1("fadcphi1", "pol4", 0, 20000)}, + fadcphi1fine{new TF1("fadcphi1fine", "pol4", 0, 20000)}, + fadcphi2{new TF1("fadcphi2", "pol5", 0, 20000)}, + fadcphi2fine1{new TF1("fadcphi2fine1", "pol4", 0, 20000)}, + fadcphi2fine2{new TF1("fadcphi2fine2", "pol1", 0, 20000)} + { /* ftpcR1 = new TF1("ftpcR1", "pol2", 0, 10); @@ -31,54 +61,54 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} ftpcR1->SetParameter(2, 0.007); */ - f0 = new TF1("f0", "pol1", 0, 10); + // f0 = new TF1("f0", "pol1", 0, 10); f0->SetParameter(0, 0.0163943); f0->SetParameter(1, 0.0192931); - f1 = new TF1("f1", "pol2", 0, 10); + // f1 = new TF1("f1", "pol2", 0, 10); f1->SetParameter(0, 0.0119384); f1->SetParameter(1, 0.0253197); f1->SetParameter(2, 0.0404213); - f2 = new TF1("f2", "pol2", 0, 10); + // f2 = new TF1("f2", "pol2", 0, 10); f2->SetParameter(0, 0.0107316); f2->SetParameter(1, 0.0294968); f2->SetParameter(2, 0.0414098); // f2->SetParameter(3,9.75877); - fz0 = new TF1("fz0", "pol2", -2, 2); + // fz0 = new TF1("fz0", "pol2", -2, 2); fz0->SetParameter(0, 0.0520278); fz0->SetParameter(1, -0.00578699); fz0->SetParameter(2, 0.0156972); - fz1 = new TF1("fz1", "pol4", -2, 2); + // fz1 = new TF1("fz1", "pol4", -2, 2); fz1->SetParameter(0, 0.0383233); fz1->SetParameter(1, -0.00577128); fz1->SetParameter(2, 0.0770914); fz1->SetParameter(3, -0.0818139); fz1->SetParameter(4, 0.050305); - fz2 = new TF1("fz2", "pol2", -2, 2); + // fz2 = new TF1("fz2", "pol2", -2, 2); fz2->SetParameter(0, 0.0371611); fz2->SetParameter(1, -0.000694558); fz2->SetParameter(2, 0.0437917); - fmm_55_2 = new TF1("fmm_55_2", "pol2", -2, 2); + // fmm_55_2 = new TF1("fmm_55_2", "pol2", -2, 2); fmm_55_2->SetParameter(0, 0.0430592); fmm_55_2->SetParameter(1, -0.000177174); fmm_55_2->SetParameter(2, 0.0914288); - fmm_56_2 = new TF1("fmm_56_2", "pol2", -2, 2); + // fmm_56_2 = new TF1("fmm_56_2", "pol2", -2, 2); fmm_56_2->SetParameter(0, 0.00363897); fmm_56_2->SetParameter(1, 0.0109713); fmm_56_2->SetParameter(2, 0.032354); - fmm_3 = new TF1("fmm_3", "pol2", -2, 2); + // fmm_3 = new TF1("fmm_3", "pol2", -2, 2); fmm_3->SetParameter(0, 0.00305396); fmm_3->SetParameter(1, 0.00505814); fmm_3->SetParameter(2, 0.0395137); - fadcz0 = new TF1("fadcz0", "pol5", 0, 20000); + // fadcz0 = new TF1("fadcz0", "pol5", 0, 20000); fadcz0->SetParameter(0, 2.08854); fadcz0->SetParameter(1, -0.0536847); fadcz0->SetParameter(2, 0.000989393); @@ -86,7 +116,7 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} fadcz0->SetParameter(4, 4.42178e-08); fadcz0->SetParameter(5, -7.79669e-11); - fadcz1 = new TF1("fadcz1", "pol5", 0, 20000); + // fadcz1 = new TF1("fadcz1", "pol5", 0, 20000); fadcz1->SetParameter(0, 2.35278); fadcz1->SetParameter(1, -0.0535903); fadcz1->SetParameter(2, 0.00088052); @@ -94,7 +124,7 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} fadcz1->SetParameter(4, 3.35361e-08); fadcz1->SetParameter(5, -5.61371e-11); - fadcz2 = new TF1("fadcz2", "pol5", 0, 20000); + // fadcz2 = new TF1("fadcz2", "pol5", 0, 20000); fadcz2->SetParameter(0, 2.53191); fadcz2->SetParameter(1, -0.062285); fadcz2->SetParameter(2, 0.00103893); @@ -102,22 +132,22 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} fadcz2->SetParameter(4, 3.9802e-08); fadcz2->SetParameter(5, -6.67137e-11); - fadcz0fine = new TF1("fadcz0fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); + // fadcz0fine = new TF1("fadcz0fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); fadcz0fine->SetParameter(0, 9.63983e-01); fadcz0fine->SetParameter(1, 2.68585e+01); fadcz0fine->SetParameter(2, -4.78664e+00); - fadcz1fine = new TF1("fadcz1fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); + // fadcz1fine = new TF1("fadcz1fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); fadcz1fine->SetParameter(0, 9.85546e-01); fadcz1fine->SetParameter(1, 1.12622e+02); fadcz1fine->SetParameter(2, -1.26552e+01); - fadcz2fine = new TF1("fadcz2fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); + // fadcz2fine = new TF1("fadcz2fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); fadcz2fine->SetParameter(0, 9.71125e-01); fadcz2fine->SetParameter(1, 6.67244e+01); fadcz2fine->SetParameter(2, -3.55034e+00); - fadcphi0 = new TF1("fadcphi0", "pol4", 0, 20000); + // fadcphi0 = new TF1("fadcphi0", "pol4", 0, 20000); fadcphi0->SetParameter(0, 1.79273); fadcphi0->SetParameter(1, -0.0306044); fadcphi0->SetParameter(2, 0.000355984); @@ -125,26 +155,26 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} fadcphi0->SetParameter(4, 4.26161e-09); // fadcphi0->SetParameter(5,-4.22758e-11); - fadcphi0fine = new TF1("fadcphi0fine", "pol2", 0, 20000); + // fadcphi0fine = new TF1("fadcphi0fine", "pol2", 0, 20000); fadcphi0fine->SetParameter(0, 1.02625); fadcphi0fine->SetParameter(1, -0.00167294); fadcphi0fine->SetParameter(2, 2.2912e-5); - fadcphi1 = new TF1("fadcphi1", "pol4", 0, 20000); + // fadcphi1 = new TF1("fadcphi1", "pol4", 0, 20000); fadcphi1->SetParameter(0, 2.12873); fadcphi1->SetParameter(1, -0.0369604); fadcphi1->SetParameter(2, 0.00042828); fadcphi1->SetParameter(3, -2.3665e-06); fadcphi1->SetParameter(4, 4.87683e-09); - fadcphi1fine = new TF1("fadcphi1fine", "pol4", 0, 20000); + // fadcphi1fine = new TF1("fadcphi1fine", "pol4", 0, 20000); fadcphi1fine->SetParameter(0, 1.11749); fadcphi1fine->SetParameter(1, -0.00354277); fadcphi1fine->SetParameter(2, 5.60236e-05); fadcphi1fine->SetParameter(3, -4.46412e-07); fadcphi1fine->SetParameter(4, 1.22689e-09); - fadcphi2 = new TF1("fadcphi2", "pol5", 0, 20000); + // fadcphi2 = new TF1("fadcphi2", "pol5", 0, 20000); fadcphi2->SetParameter(0, 2.29); fadcphi2->SetParameter(1, -0.0474362); fadcphi2->SetParameter(2, 0.000717789); @@ -152,23 +182,23 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} fadcphi2->SetParameter(4, 2.52007e-08); fadcphi2->SetParameter(5, -4.14747e-11); - fadcphi2fine1 = new TF1("fadcphi2fine1", "pol4", 0, 20000); + // fadcphi2fine1 = new TF1("fadcphi2fine1", "pol4", 0, 20000); fadcphi2fine1->SetParameter(0, 1.39404); fadcphi2fine1->SetParameter(1, -0.0202245); fadcphi2fine1->SetParameter(2, 0.000394666); fadcphi2fine1->SetParameter(3, -3.37831e-06); fadcphi2fine1->SetParameter(4, 1.05017e-08); - fadcphi2fine2 = new TF1("fadcphi2fine2", "pol1", 0, 20000); + // fadcphi2fine2 = new TF1("fadcphi2fine2", "pol1", 0, 20000); fadcphi2fine2->SetParameter(0, 0.997); fadcphi2fine2->SetParameter(1, 0.00047); - f0fine = new TF1("f0fine", "pol2", 0, 20000); + // f0fine = new TF1("f0fine", "pol2", 0, 20000); f0fine->SetParameter(0, 0.98611); f0fine->SetParameter(1, -0.169505); f0fine->SetParameter(2, 1.12907); - f1fine = new TF1("f1fine", "pol3", 0, 20000); + // f1fine = new TF1("f1fine", "pol3", 0, 20000); f1fine->SetParameter(0, 0.968625); f1fine->SetParameter(1, -0.38894); f1fine->SetParameter(2, 3.36493); @@ -181,7 +211,7 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} f2fine->SetParameter(3,-42.4668); f2fine->SetParameter(4,43.6083); */ - f2fine = new TF1("f2fine", "pol5", 0, 20000); + // f2fine = new TF1("f2fine", "pol5", 0, 20000); f2fine->SetLineColor(kBlue); f2fine->SetParameter(0, 1.14119); f2fine->SetParameter(1, -2.81483); @@ -190,18 +220,18 @@ ClusterErrorPara::ClusterErrorPara(): f0{new TF1("f0", "pol1", 0, 10)} f2fine->SetParameter(4, 72.2359); f2fine->SetParameter(5, -20.3802); - fz0fine = new TF1("fz0fine", "pol2", 0, 20000); + // fz0fine = new TF1("fz0fine", "pol2", 0, 20000); fz0fine->SetParameter(0, 0.96933); fz0fine->SetParameter(1, -0.0458534); fz0fine->SetParameter(2, 0.231419); - fz1fine = new TF1("fz1fine", "pol3", 0, 20000); + // fz1fine = new TF1("fz1fine", "pol3", 0, 20000); fz1fine->SetParameter(0, 0.886262); fz1fine->SetParameter(1, -0.0818167); fz1fine->SetParameter(2, 0.805824); fz1fine->SetParameter(3, -0.425423); - fz2fine = new TF1("fz2fine", "pol5", 0, 20000); + // fz2fine = new TF1("fz2fine", "pol5", 0, 20000); fz2fine->SetLineColor(kBlue); fz2fine->SetParameter(0, 0.880153); fz2fine->SetParameter(1, 0.552461); From e11adf0566fe8cfa6db382c1499077fabf2d29cd Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 13 Feb 2026 10:02:26 -0500 Subject: [PATCH 228/866] jenkins 2 --- offline/packages/trackbase/ClusterErrorPara.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 16fe2066b4..5795f24347 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -733,9 +733,9 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu if (cluster->getPhiSize() == 2){ phierror *= 2.25; } - if(layer==3||layer==4) + if((layer==3)||(layer==4)) phierror*=0.8; - if(layer==5||layer==6) + if((layer==5)||(layer==6)) phierror*=1.2; } From 4c4088d2cf901636843a4fdfb79731a895e818f4 Mon Sep 17 00:00:00 2001 From: bogui56 Date: Fri, 13 Feb 2026 10:56:30 -0500 Subject: [PATCH 229/866] clang 1 --- offline/packages/trackbase/ClusterErrorPara.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index 5795f24347..1d6bf4b924 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -733,10 +733,12 @@ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrClu if (cluster->getPhiSize() == 2){ phierror *= 2.25; } - if((layer==3)||(layer==4)) + if((layer==3)||(layer==4)){ phierror*=0.8; - if((layer==5)||(layer==6)) + } + if((layer==5)||(layer==6)){ phierror*=1.2; + } } if (TrkrDefs::getTrkrId(key) == TrkrDefs::micromegasId){ From 0a41d07cf2e4fcfaa240632a2a7b4be646bbcfdc Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 13 Feb 2026 15:25:30 -0500 Subject: [PATCH 230/866] do not reference data for qa filling --- offline/framework/fun4allraw/TpcTimeFrameBuilder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index 8eeca60c88..309e7bf391 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -713,7 +713,7 @@ int TpcTimeFrameBuilder::process_fee_data(unsigned int fee) } // valid packet - const uint16_t& pkt_length = data_buffer[0]; // this is indeed the number of 10-bit words + 5 in this packet + const uint16_t pkt_length = data_buffer[0]; // this is indeed the number of 10-bit words + 5 in this packet if (pkt_length > MAX_PACKET_LENGTH) { if (m_verbosity > 1) From f03fde5c4c04238a0c4d157abe7ec30dfc10a669 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Sat, 14 Feb 2026 20:54:06 -0500 Subject: [PATCH 231/866] Finally fixed the bugs. --- offline/packages/tpc/TpcClusterizer.cc | 31 +++++++------------------- offline/packages/tpc/TpcClusterizer.h | 6 ----- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index e7fa17fa9e..85fdd151fc 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1859,43 +1859,28 @@ void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &db for (int i = 0; i < NChan; i++) { - int Layer = cdbttree->GetIntValue(i, "layer"); // Stored layer - int Sec = cdbttree->GetIntValue(i, "sector"); // Stored sector - int Side = cdbttree->GetIntValue(i, "side"); // 0 or 1 - int Pad0 = cdbttree->GetIntValue(i, "pad0"); // Simulation pad - int Pad1 = cdbttree->GetIntValue(i, "pad1"); // Data pad + int Layer = cdbttree->GetIntValue(i, "layer"); + int Sector = cdbttree->GetIntValue(i, "sector"); + int Side = cdbttree->GetIntValue(i, "side"); + int Pad = cdbttree->GetIntValue(i, "pad"); - if (Sec < 0 || Sec >= 12) + if (Sector < 0 || Sector >= 12) { if (Verbosity() > VERBOSITY_A_LOT) { - std::cout << PHWHERE << "WARNING: sector index " << Sec + std::cout << PHWHERE << "WARNING: sector index " << Sector << " out of range [0,11] in " << dbName << ", skipping channel " << i << std::endl; } continue; } - int Pad; - int Sector; - - if (!m_is_data) - { - Pad = Pad0; - Sector = mc_sectors[Sec]; - } - else - { - Pad = Pad1; - Sector = Sec; - } - - if (Layer < 7 || Layer > 48) + if (Layer < 7 || Layer > 54) { if (Verbosity() > VERBOSITY_A_LOT) { std::cout << PHWHERE << "WARNING: layer " << Layer - << " out of TPC range [7,48] in " << dbName + << " out of TPC range [7,54] in " << dbName << ", skipping channel " << i << std::endl; } continue; diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index 550301f813..dc325a05ca 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -75,11 +75,6 @@ class TpcClusterizer : public SubsysReco ClusHitsVerbosev1 *mClusHitsVerbose{nullptr}; - void SetIsData(bool flag) - { - m_is_data = flag; - } - void SetMaskChannelsFromFile() { m_maskFromFile = true; @@ -140,7 +135,6 @@ class TpcClusterizer : public SubsysReco bool m_maskDeadChannels {false}; bool m_maskHotChannels {false}; - bool m_is_data {false}; bool m_maskFromFile {false}; std::string m_deadChannelMapName; std::string m_hotChannelMapName; From 70b8bd9b95015b806190b0e29dd06b7e90da6d60 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Sat, 14 Feb 2026 21:05:25 -0500 Subject: [PATCH 232/866] changed running ped to 8 samples, added ped study, handle contamination to waveform due to events from prior crossings better --- offline/packages/mbd/MbdCalib.cc | 30 +++- offline/packages/mbd/MbdCalib.h | 49 +++--- offline/packages/mbd/MbdEvent.cc | 10 +- offline/packages/mbd/MbdSig.cc | 259 ++++++++++++++++++++----------- offline/packages/mbd/MbdSig.h | 24 +-- 5 files changed, 243 insertions(+), 129 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 3ebe139ffb..e8d10ba00a 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -2497,7 +2497,7 @@ void MbdCalib::Reset_Pileup() _pileup_p0err.fill(std::numeric_limits::quiet_NaN()); _pileup_p1err.fill(std::numeric_limits::quiet_NaN()); _pileup_p2err.fill(std::numeric_limits::quiet_NaN()); - _qfit_chi2ndf.fill(std::numeric_limits::quiet_NaN()); + _pileup_chi2ndf.fill(std::numeric_limits::quiet_NaN()); } void MbdCalib::Reset_Thresholds() @@ -2590,3 +2590,31 @@ TGraph *MbdCalib::get_lut_graph(const int pmtch, std::string_view type) return g; } + +void MbdCalib::set_pileup(const int ifeech, const int ipar, const float pval) +{ + int chtype = (ifeech / 8) % 2; // 0=T-ch, 1=Q-ch + + if (ipar==0) + { + _pileup_p0[ifeech] = pval; + } + else if (ipar==1) + { + _pileup_p1[ifeech] = pval; + } + else if (ipar==2) + { + _pileup_p2[ifeech] = pval; + } + else if (ipar==3 && chtype==0) + { + _pileup_p1err[ifeech] = pval; + } + else if (ipar==4 && chtype==0) + { + _pileup_p2err[ifeech] = pval; + } +} + + diff --git a/offline/packages/mbd/MbdCalib.h b/offline/packages/mbd/MbdCalib.h index 49129ac749..6f0a6e579a 100644 --- a/offline/packages/mbd/MbdCalib.h +++ b/offline/packages/mbd/MbdCalib.h @@ -38,6 +38,36 @@ class MbdCalib float get_pedrms(const int ifeech) const { return _pedsigma[ifeech]; } int get_sampmax(const int ifeech) const { return _sampmax[ifeech]; } int get_status(const int ifeech) const { return _mbdstatus[ifeech]; } + + float get_pileup(const int ifeech, const int ipar) const + { + int chtype = (ifeech / 8) % 2; // 0=T-ch, 1=Q-ch + + if (ipar==0) + { + return _pileup_p0[ifeech]; + } + else if (ipar==1) + { + return _pileup_p1[ifeech]; + } + else if (ipar==2) + { + return _pileup_p2[ifeech]; + } + else if (ipar==3 && chtype==0) + { + return _pileup_p1err[ifeech]; + } + else if (ipar==4 && chtype==0) + { + return _pileup_p2err[ifeech]; + } + + return std::numeric_limits::quiet_NaN(); + } + + float get_tcorr(const int ifeech, const int tdc) const { if (tdc<0) { @@ -86,24 +116,6 @@ class MbdCalib std::vector get_shape(const int ifeech) const { return _shape_y[ifeech]; } std::vector get_sherr(const int ifeech) const { return _sherr_yerr[ifeech]; } - float get_pileup(const int ifeech, const int ipar) const { - - if (ipar==0) - { - return _pileup_p0[ifeech]; - } - else if (ipar==1) - { - return _pileup_p1[ifeech]; - } - else if (ipar==2) - { - return _pileup_p2[ifeech]; - } - - return std::numeric_limits::quiet_NaN(); - } - float get_threshold(const int pmtch, const int rel_or_abs = 0); TGraph *get_lut_graph(const int pmtch, std::string_view type); @@ -111,6 +123,7 @@ class MbdCalib void set_sampmax(const int ifeech, const int val) { _sampmax[ifeech] = val; } void set_status(const int ifeech, const int val) { _mbdstatus[ifeech] = val; } void set_ped(const int ifeech, const float m, const float merr, const float s, const float serr); + void set_pileup(const int ifeech, const int ipar, const float val); void set_tt0(const int ipmt, const float t0) { _ttfit_t0mean[ipmt] = t0; } void set_tq0(const int ipmt, const float t0) { _tqfit_t0mean[ipmt] = t0; } diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index 72cecb212d..62a6c96fe7 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -380,6 +380,7 @@ int MbdEvent::End() for (auto & sig : _mbdsig) { + sig.WritePedvsEvent(); sig.WriteChi2Hist(); } @@ -1127,11 +1128,6 @@ int MbdEvent::Calculate(MbdPmtContainer *bbcpmts, MbdOut *bbcout, PHCompositeNod gausfit[iarm]->SetRange(hevt_bbct[iarm]->GetMean() - 5, hevt_bbct[iarm]->GetMean() + 5); */ - if ( hevt_bbct[iarm]->GetEntries()==0 )//chiu - { - std::cout << PHWHERE << " hevt_bbct EMPTY" << std::endl; - } - hevt_bbct[iarm]->Fit(gausfit[iarm], "BNQLR"); // m_bbct[iarm] = m_bbct[iarm] / m_bbcn[iarm]; @@ -1462,10 +1458,6 @@ int MbdEvent::CalcPedCalib() pedgaus->SetParameters(ampl,mean,sigma); pedgaus->SetRange(mean-(4*sigma), mean+(4*sigma)); - if ( hped0->GetEntries()==0 ) //chiu - { - std::cout << "HPED0 EMPTY" << std::endl; - } hped0->Fit(pedgaus,"RNQ"); mean = pedgaus->GetParameter(1); diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index 1118ba2e60..57a9615f13 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -49,12 +49,13 @@ void MbdSig::Init() gSubPulse->SetName(name); gSubPulse->GetHistogram()->SetXTitle("sample"); gSubPulse->GetHistogram()->SetYTitle("ADC"); + gSubPulse->GetHistogram()->SetTitle(name); hpulse = hRawPulse; // hpulse,gpulse point to raw by default gpulse = gRawPulse; // we switch to sub for default if ped is applied - //ped0stats = std::make_unique(100); // use the last 100 events for running pedestal - ped0stats = new MbdRunningStats(100); // use the last 100 events for running pedestal + ped0stats = new MbdRunningStats(8); // use the last 8 samples for running pedestal + name = "hPed0_"; name += _ch; hPed0 = new TH1F(name, name, 3000, -0.5, 2999.5); @@ -62,6 +63,15 @@ void MbdSig::Init() name = "hPedEvt_"; name += _ch; hPedEvt = new TH1F(name, name, 3000, -0.5, 2999.5); + if ( _pedstudyflag ) + { + gPedvsEvent = new TGraphErrors(); + name = "gpedvsevent"; + name += _ch; + gPedvsEvent->SetName(name); + gPedvsEvent->GetHistogram()->SetXTitle("evtnum"); + gPedvsEvent->GetHistogram()->SetYTitle("ped"); + } SetTemplateSize(900, 1000, -10., 20.); // SetTemplateSize(300,300,0.,15.); @@ -137,9 +147,9 @@ MbdSig::~MbdSig() delete hSubPulse; delete gRawPulse; delete gSubPulse; - delete hPed0; delete ped0stats; - // h2Template->Write(); + delete hPed0; + delete hPedEvt; delete h2Template; delete h2Residuals; delete hAmpl; @@ -149,6 +159,10 @@ MbdSig::~MbdSig() delete ped_fcn; delete ped_tail; delete h_chi2ndf; + if ( _pedstudyflag ) + { + delete gPedvsEvent; + } } void MbdSig::SetEventPed0PreSamp(const Int_t presample, const Int_t nsamps, const int max_samp) @@ -327,54 +341,123 @@ void MbdSig::Remove_Pileup() if ( (_ch/8)%2 == 0 ) // time ch { - float offset = _pileup_p0*gSubPulse->GetPointY(0); + double x_at_max = TMath::LocMax( 5, gSubPulse->GetY() ); - for (int isamp = 0; isamp < _nsamples; isamp++) + if ( x_at_max != 0 ) { - double x = gSubPulse->GetPointX(isamp); - double y = gSubPulse->GetPointY(isamp); + // time hit in prev crossing + if ( fit_pileup == nullptr ) + { + TString name = "fit_pileup"; name += _ch; + fit_pileup = new TF1(name,"pol3",0,16000); + for (int ipar=0; ipar<4; ipar++) + { + fit_pileup->SetParameter( ipar, _mbdcal->get_pileup(_ch,ipar+1) ); + } + } + + int sampmax = _mbdcal->get_sampmax(_ch); + double x_sampmax = gSubPulse->GetPointX(sampmax); + double y_sampmax = gSubPulse->GetPointY(sampmax); + double y_min6 = gSubPulse->GetPointY(sampmax-6); + + double offset = y_min6*fit_pileup->Eval(y_min6); + + hSubPulse->SetBinContent( sampmax + 1, y_sampmax - offset ); + gSubPulse->SetPoint( sampmax, x_sampmax, y_sampmax - offset ); - hSubPulse->SetBinContent( isamp + 1, y - offset ); - gSubPulse->SetPoint( isamp, x, y - offset ); } - } - else - { - if ( fit_pileup == nullptr ) + else { - TString name = "fit_pileup"; name += _ch; - fit_pileup = new TF1(name,"gaus",-0.1,4.1); - fit_pileup->SetLineColor(2); - } + // time hit in 2 crossings before + float offset = _pileup_p0*gSubPulse->GetPointY(0); - fit_pileup->SetRange(-0.1,4.1); - fit_pileup->SetParameters( _pileup_p0*gSubPulse->GetPointY(0), _pileup_p1, _pileup_p2 ); - - // fix par limits - double plow{0.}; - double phigh{0.}; - fit_pileup->GetParLimits(2,plow,phigh); - if ( phigh < _pileup_p2 ) - { - phigh = 2*_pileup_p2; - fit_pileup->SetParLimits(2,plow,phigh); + for (int isamp = 0; isamp < _nsamples; isamp++) + { + double x = gSubPulse->GetPointX(isamp); + double y = gSubPulse->GetPointY(isamp); + + hSubPulse->SetBinContent( isamp + 1, y - offset ); + gSubPulse->SetPoint( isamp, x, y - offset ); + } } + } + else // charge ch + { + double ymax = TMath::MaxElement( 5, gSubPulse->GetY() ); + double x_at_max = TMath::LocMax( 5, gSubPulse->GetY() ); - if ( _verbose ) + if ( x_at_max != 0 ) { - gSubPulse->Fit( fit_pileup, "R" ); - gSubPulse->Draw("ap"); - PadUpdate(); + // Fit a pulse in prev crossing + template_fcn->SetParameters(ymax, x_at_max); + template_fcn->SetRange(0, x_at_max+2.1); + + if (_verbose == 0) + { + //std::cout << PHWHERE << std::endl; + gSubPulse->Fit(template_fcn, "RNQ"); + } + else + { + std::cout << "pre-pileup " << _ch << "\t" << x_at_max << "\t" << ymax << std::endl; + gSubPulse->Fit(template_fcn, "R"); + gSubPulse->Draw("ap"); + gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); + gPad->SetGridy(1); + PadUpdate(); + //gSubPulse->Print("ALL"); + } + } else { - gSubPulse->Fit( fit_pileup, "RNQ" ); + // Fit the tail + if ( fit_pileup == nullptr ) + { + TString name = "fit_pileup"; name += _ch; + fit_pileup = new TF1(name,"gaus",-0.1,4.1); + fit_pileup->SetLineColor(2); + } + + fit_pileup->SetRange(-0.1,4.1); + fit_pileup->SetParameters( _pileup_p0*gSubPulse->GetPointY(0), _pileup_p1, _pileup_p2 ); + + // fix par limits + double plow{0.}; + double phigh{0.}; + fit_pileup->GetParLimits(2,plow,phigh); + if ( phigh < _pileup_p2 ) + { + phigh = 2*_pileup_p2; + fit_pileup->SetParLimits(2,plow,phigh); + } + + if ( _verbose ) + { + gSubPulse->Fit( fit_pileup, "R" ); + gSubPulse->Draw("ap"); + PadUpdate(); + } + else + { + gSubPulse->Fit( fit_pileup, "RNQ" ); + } } + // subtract pre-pulse for (int isamp = 0; isamp < _nsamples; isamp++) { - double bkg = fit_pileup->Eval(isamp); + double bkg = 0.; + if ( x_at_max != 0 ) + { + bkg = template_fcn->Eval(isamp); + } + else + { + bkg = fit_pileup->Eval(isamp); + } double x = gSubPulse->GetPointX(isamp); double y = gSubPulse->GetPointY(isamp); @@ -388,6 +471,7 @@ void MbdSig::Remove_Pileup() if ( _verbose ) { + std::cout << "pileup sub " << _ch << std::endl; gSubPulse->Draw("ap"); PadUpdate(); } @@ -428,6 +512,14 @@ void MbdSig::WritePedHist() hPed0->Write(); } +void MbdSig::WritePedvsEvent() +{ + if ( _pedstudyflag ) + { + gPedvsEvent->Write(); + } +} + void MbdSig::FillPed0(const Int_t sampmin, const Int_t sampmax) { Double_t x; @@ -438,13 +530,6 @@ void MbdSig::FillPed0(const Int_t sampmin, const Int_t sampmax) // gRawPulse->Print("all"); hPed0->Fill(y); - /* - // chiu taken out - ped0stats->Push( y ); - ped0 = ped0stats->Mean(); - ped0rms = ped0stats->RMS(); - */ - // std::cout << "ped0 " << _ch << " " << n << "\t" << ped0 << std::endl; // std::cout << "ped0 " << _ch << "\t" << ped0 << std::endl; } @@ -463,10 +548,10 @@ void MbdSig::FillPed0(const Double_t begin, const Double_t end) hPed0->Fill(y); /* - ped0stats->Push( y ); - ped0 = ped0stats->Mean(); - ped0rms = ped0stats->RMS(); - */ + ped0stats->Push( y ); + ped0 = ped0stats->Mean(); + ped0rms = ped0stats->RMS(); + */ // std::cout << "ped0 " << _ch << " " << n << "\t" << x << "\t" << y << std::endl; } @@ -548,9 +633,7 @@ void MbdSig::CalcEventPed0(const Double_t minpedx, const Double_t maxpedx) // If a prev event pileup is detected, return 1, otherwise, return 0 int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) { - //std::cout << PHWHERE << std::endl; //chiu //_verbose = 100; - //ped0stats->Clear(); int status = 0; // assume no pileup @@ -608,11 +691,6 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) ped_fcn->SetRange(minsamp-0.1,maxsamp+0.1); ped_fcn->SetParameter(0,1500.); - if ( gRawPulse->GetN()==0 )//chiu - { - std::cout << PHWHERE << " gRawPulse 0" << std::endl; - } - if ( _verbose ) { gRawPulse->Fit( ped_fcn, "RQ" ); @@ -630,18 +708,6 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) //std::cout << PHWHERE << std::endl; gRawPulse->Fit( ped_fcn, "RNQ" ); - /* - double chi2ndf = ped_fcn->GetChisquare()/ped_fcn->GetNDF(); - if ( _pileupfile != nullptr && chi2ndf > 4.0 ) - { - *_pileupfile << "ped " << _ch << " mean " << mean << "\t"; - for ( int i=0; iGetN(); i++) - { - *_pileupfile << std::setw(6) << gRawPulse->GetPointY(i); - } - *_pileupfile << std::endl; - } - */ } double chi2 = ped_fcn->GetChisquare(); @@ -670,6 +736,28 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) << "isamp " << isamp << "\t" << x << "\t" << y << std::endl; } } + + // study pedestal vs event + if ( _pedstudyflag ) + { + // running pedestal (replace with mean and meanerr for evt-by-evt) + double ped_evtnum = _evt_counter; + double ped_mean = ped0stats->Mean(); + double ped_meanerr = rms; + if ( ped0stats->Size()>1 ) + { + ped_meanerr = ped0stats->RMS()/std::sqrt(ped0stats->Size()); + } + else + { + ped_meanerr = _mbdcal->get_pedrms(_ch); + } + + int n = gPedvsEvent->GetN(); + gPedvsEvent->SetPoint(n,ped_evtnum,ped_mean); + gPedvsEvent->SetPointError(n,0,ped_meanerr); + } + } else { @@ -700,11 +788,18 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) } } - // use straight mean for pedestal - // Could consider using fit to hPed0 to remove outliers - //rms = ped0stats->RMS(); - //Double_t mean = hPed0->GetMean(); - //Double_t rms = hPed0->GetRMS(); + // uncomment this to write out file with pileup waveforms + /* + if ( _pileupfile != nullptr ) + { + *_pileupfile << "ped " << _ch << " mean " << mean << "\t"; + for ( int i=0; iGetN(); i++) + { + *_pileupfile << std::setw(6) << gRawPulse->GetPointY(i); + } + *_pileupfile << std::endl; + } + */ } SetPed0(mean, rms); @@ -982,9 +1077,10 @@ void MbdSig::PadUpdate() const std::cout << PHWHERE << " PadUpdate\t_verbose = " << _verbose << std::endl; if ( _verbose>5 ) { + gPad->SetGridy(1); gPad->Modified(); gPad->Update(); - std::cout << _ch << " ? "; + std::cout << _evt_counter << ": " << _ch << " ? "; if ( _verbose>10 ) { std::string junk; @@ -1124,7 +1220,7 @@ Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) // sampmax>0 means fit to the peak near sampmax int MbdSig::FitTemplate( const Int_t sampmax ) { - //std::cout << PHWHERE << std::endl; //chiu + //std::cout << PHWHERE << std::endl; /* if ( _evt_counter==2142 && _ch==92 ) { @@ -1265,7 +1361,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) // fit was out of time, likely from pileup, try two waveforms if ( (f_time<(sampmax-2.5) || f_time>sampmax) && (nsaturated<=3) ) { - //_verbose = 100; //chiu + //_verbose = 100; if ( _verbose ) { @@ -1310,15 +1406,6 @@ int MbdSig::FitTemplate( const Int_t sampmax ) } } - - /* chiu - if ( f_time<0. || f_time>9 ) - { - _verbose = 100; - f_time = _nsamples*0.5; // bad fit last time - } - */ - // refit with new range to exclude after-pulses template_fcn->SetParameters(ymax, x_at_max); //template_fcn->SetParameters( f_ampl, f_time ); @@ -1369,14 +1456,6 @@ int MbdSig::FitTemplate( const Int_t sampmax ) h_chi2ndf->Fill( f_chi2/f_ndf ); - /* - if ( (f_chi2/f_ndf) > 100. ) //chiu - { - std::cout << "very bad chi2ndf after refit " << f_ampl << "\t" << f_time << "\t" << f_chi2/f_ndf << std::endl; - //_verbose = 100; - } - */ - //if ( f_time<0 || f_time>30 ) //if ( (_ch==185||_ch==155||_ch==249) && (fabs(f_ampl) > 44000.) ) //double chi2 = template_fcn->GetChisquare(); diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index a3ee986c33..bafdd9339c 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -116,6 +116,7 @@ class MbdSig void SetMinMaxFitTime(const Double_t mintime, const Double_t maxtime); void WritePedHist(); + void WritePedvsEvent(); void WriteChi2Hist(); void DrawWaveform(); /// Draw Subtracted Waveform @@ -157,22 +158,22 @@ class MbdSig TGraphErrors *gpulse{nullptr}; //! /** for CalcPed0 */ - //std::unique_ptr ped0stats{nullptr}; //! - MbdRunningStats *ped0stats{nullptr}; //! - TH1 *hPed0{nullptr}; //! all events - TH1 *hPedEvt{nullptr}; //! evt-by-event pedestal + MbdRunningStats *ped0stats{nullptr}; //! running pedestal + TH1 *hPed0{nullptr}; //! all events + TH1 *hPedEvt{nullptr}; //! evt-by-event pedestal + TGraphErrors *gPedvsEvent{nullptr}; //! Keep track of pedestal vs evtnum TF1 *ped_fcn{nullptr}; - TF1 *ped_tail{nullptr}; //! tail of prev signal + TF1 *ped_tail{nullptr}; //! tail of prev signal Double_t ped0{0.}; //! Double_t ped0rms{0.}; //! - int use_ped0{0}; //! whether to apply ped0 - Int_t minped0samp{-9999}; //! min sample for event-by-event ped, inclusive - Int_t maxped0samp{-9999}; //! max sample for event-by-event ped, inclusive + int use_ped0{0}; //! whether to apply ped0 + Int_t minped0samp{-9999}; //! min sample for event-by-event ped, inclusive + Int_t maxped0samp{-9999}; //! max sample for event-by-event ped, inclusive Double_t minped0x{0.}; //! min x for event-by-event ped, inclusive Double_t maxped0x{0.}; //! max x for event-by-event ped, inclusive - Double_t ped_presamp{}; //! presamples for ped calculation - Double_t ped_presamp_nsamps{}; //! num of presamples for ped calculation - Double_t ped_presamp_maxsamp{-1}; //! a peak sample for ped calc (-1 = use max) + Double_t ped_presamp{}; //! presamples for ped calculation + Double_t ped_presamp_nsamps{}; //! num of presamples for ped calculation + Double_t ped_presamp_maxsamp{-1}; //! a peak sample for ped calc (-1 = use max) /** for time calibration */ // Double_t time_calib; @@ -200,6 +201,7 @@ class MbdSig TH1 *h_chi2ndf{nullptr}; //! for eval int _verbose{0}; + bool _pedstudyflag{false}; }; #endif // __MBDSIG_H__ From a07fca0c6093a63463753a2ebf05e00f9f4cc6de Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Sat, 14 Feb 2026 22:03:39 -0500 Subject: [PATCH 233/866] check we don't underflow the sample number --- offline/packages/mbd/MbdSig.cc | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index 57a9615f13..9b270e8ee8 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -357,15 +357,26 @@ void MbdSig::Remove_Pileup() } int sampmax = _mbdcal->get_sampmax(_ch); - double x_sampmax = gSubPulse->GetPointX(sampmax); - double y_sampmax = gSubPulse->GetPointY(sampmax); - double y_min6 = gSubPulse->GetPointY(sampmax-6); - - double offset = y_min6*fit_pileup->Eval(y_min6); + if ( (sampmax-6) > 0 ) + { + double x_sampmax = gSubPulse->GetPointX(sampmax); + double y_sampmax = gSubPulse->GetPointY(sampmax); + double y_min6 = gSubPulse->GetPointY(sampmax-6); - hSubPulse->SetBinContent( sampmax + 1, y_sampmax - offset ); - gSubPulse->SetPoint( sampmax, x_sampmax, y_sampmax - offset ); + double offset = y_min6*fit_pileup->Eval(y_min6); + hSubPulse->SetBinContent( sampmax + 1, y_sampmax - offset ); + gSubPulse->SetPoint( sampmax, x_sampmax, y_sampmax - offset ); + } + else + { + static int ctr = 0; + if ( ctr<10 ) + { + std::cout << PHWHERE << " WARNING, sampmax too early for time pileup corr" << std::endl; + ctr++; + } + } } else { From 4c4fdf492349cc2d3b8fd16219d98ffde2260131 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Sun, 15 Feb 2026 09:16:56 -0500 Subject: [PATCH 234/866] Minor fix. --- offline/packages/tpc/TpcClusterizer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index dc325a05ca..84a58ceca6 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -95,7 +95,6 @@ class TpcClusterizer : public SubsysReco bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; - int mc_sectors[12]{5, 4, 3, 2, 1, 0, 11, 10, 9, 8, 7, 6}; void makeChannelMask(hitMaskTpcSet& aMask, const std::string& dbName, const std::string& totalChannelsToMask); TrkrHitSetContainer *m_hits = nullptr; From 28b0d9537d0d92e071ac7dd56e17956977db4dad Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 16 Feb 2026 10:40:10 -0500 Subject: [PATCH 235/866] add 12 GeV jets to CreateFileList.pl --- offline/framework/frog/CreateFileList.pl | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 1f71d9897f..bc8135ec6d 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -77,6 +77,7 @@ "36" => "JS pythia8 Jet ptmin = 5GeV", "37" => "hijing O+O (0-15fm)", "38" => "JS pythia8 Jet ptmin = 60GeV", + "39" => "JS pythia8 Jet ptmin = 12GeV" ); my %pileupdesc = ( @@ -975,6 +976,35 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 39) + { + $embedok = 1; + $filenamestring = "pythia8_Jet12"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { From c700d69e3c66f9874bccded3051adbeb6ef1e162 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Tue, 17 Feb 2026 11:29:36 -0500 Subject: [PATCH 236/866] QVecDefs - Update Centrality Binning - Use 1% centrality bins instead of 10% - Allows to capture the finer variations of calibraitons that change on the order of 1% centrality --- calibrations/sepd/sepd_eventplanecalib/QVecDefs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h index ebbeec8743..8b9e4ebcd7 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -8,7 +8,7 @@ namespace QVecShared { - static constexpr size_t CENT_BINS = 8; + static constexpr size_t CENT_BINS = 80; static constexpr std::array HARMONICS = {2, 3, 4}; static constexpr int SEPD_CHANNELS = 744; From 388a36bd33b650b008df3a3f56c70d3ec345bb9c Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Tue, 17 Feb 2026 13:00:51 -0500 Subject: [PATCH 237/866] add method to get MbdEvent, bypass calibration existence check during calibration runs --- offline/packages/mbd/MbdEvent.cc | 2 +- offline/packages/mbd/MbdReco.h | 2 ++ offline/packages/mbd/MbdSig.cc | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index 62a6c96fe7..e5ae966587 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -156,7 +156,7 @@ int MbdEvent::InitRun() { // Download calibrations int status = _mbdcal->Download_All(); - if ( status == -1 ) + if ( status < 0 && _calpass==0 ) // only abort for normal processing { return Fun4AllReturnCodes::ABORTRUN; } diff --git a/offline/packages/mbd/MbdReco.h b/offline/packages/mbd/MbdReco.h index eced3b89e9..13a635d602 100644 --- a/offline/packages/mbd/MbdReco.h +++ b/offline/packages/mbd/MbdReco.h @@ -40,6 +40,8 @@ class MbdReco : public SubsysReco void SetProcChargeCh(const bool s) { _always_process_charge = s; } void SetMbdTrigOnly(const int m) { _mbdonly = m; } + MbdEvent* GetMbdEvent() { return m_mbdevent.get(); } + private: int createNodes(PHCompositeNode *topNode); int getNodes(PHCompositeNode *topNode); diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index 9b270e8ee8..155d731719 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -311,11 +311,13 @@ void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert) Remove_Pileup(); } + /* if ( _verbose && _ch==9 ) { std::cout << "SetXY: ch " << _ch << std::endl; gSubPulse->Print("ALL"); } + */ } _evt_counter++; From 09e88174e67d2280cc6f3c24d625cf746782791c Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Tue, 17 Feb 2026 18:26:09 -0500 Subject: [PATCH 238/866] Adding exit for missing calibrations --- offline/packages/CaloReco/CaloTowerCalib.cc | 16 +++++++++++ offline/packages/CaloReco/CaloTowerCalib.h | 30 ++++++++++++++++++++ offline/packages/CaloReco/CaloTowerStatus.cc | 12 +++++++- offline/packages/CaloReco/CaloTowerStatus.h | 19 +++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloTowerCalib.cc b/offline/packages/CaloReco/CaloTowerCalib.cc index cbd13ce4ed..ecc7da5157 100644 --- a/offline/packages/CaloReco/CaloTowerCalib.cc +++ b/offline/packages/CaloReco/CaloTowerCalib.cc @@ -114,6 +114,12 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoEnergyCalib) + { + std::cout << "CaloTowerCalib::InitRun: No energy calibration found for " << m_calibName << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } + calibdir = CDBInterface::instance()->getUrl(default_time_independent_calib); if (calibdir.empty()) @@ -151,6 +157,11 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoTimeCalib) + { + std::cout << "CaloTowerCalib::InitRun: No time calibration found for " << m_calibName_time << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_dotimecalib = false; if (Verbosity() > 0) { @@ -185,6 +196,11 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoZSCalib) + { + std::cout << "CaloTowerCalib::InitRun: No ZS cross calibration found for " << m_calibName_ZScrosscalib << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_doZScrosscalib = false; if (Verbosity() > 0) { diff --git a/offline/packages/CaloReco/CaloTowerCalib.h b/offline/packages/CaloReco/CaloTowerCalib.h index 06ae6148a1..10a3f2771f 100644 --- a/offline/packages/CaloReco/CaloTowerCalib.h +++ b/offline/packages/CaloReco/CaloTowerCalib.h @@ -92,6 +92,32 @@ class CaloTowerCalib : public SubsysReco } } + void set_doAbortNoEnergyCalib(bool doAbort = true) + { + m_doAbortNoEnergyCalib = doAbort; + return; + } + + void set_doAbortNoTimeCalib(bool doAbort = true) + { + m_doAbortNoTimeCalib = doAbort; + return; + } + + void set_doAbortNoZSCalib(bool doAbort = true) + { + m_doAbortNoZSCalib = doAbort; + return; + } + + void set_doAbortMissingCalib(bool doAbort = true) + { + m_doAbortNoEnergyCalib = doAbort; + m_doAbortNoTimeCalib = doAbort; + m_doAbortNoZSCalib = doAbort; + return; + } + void set_use_TowerInfov2(bool use) { m_use_TowerInfov2 = use; } private: @@ -125,6 +151,10 @@ class CaloTowerCalib : public SubsysReco std::string m_directURL_ZScrosscalib = ""; bool m_doZScrosscalib = true; + bool m_doAbortNoEnergyCalib{false}; + bool m_doAbortNoTimeCalib{false}; + bool m_doAbortNoZSCalib{false}; + CDBTTree *cdbttree = nullptr; CDBTTree *cdbttree_time = nullptr; CDBTTree *cdbttree_ZScrosscalib = nullptr; diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index c5401edb33..0445dc9374 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -105,6 +105,11 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoChi2) + { + std::cout << "CaloTowerStatus::InitRun: No chi2 calibration found for " << m_calibName_chi2 << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_doHotChi2 = false; if (Verbosity() > 0) { @@ -135,6 +140,11 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoTime) + { + std::cout << "CaloTowerStatus::InitRun: No time calibration found for " << m_calibName_time << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_doTime = false; if (Verbosity() > 1) { @@ -164,7 +174,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) { if (m_doAbortNoHotMap) { - std::cout << "CaloTowerStatus::InitRun: No hot map.. exiting" << std::endl; + std::cout << "CaloTowerStatus::InitRun: No hot map found for " << m_calibName_hotMap << " and abort mode is set. Exiting." << std::endl; gSystem->Exit(1); } if (use_directURL_hotMap) diff --git a/offline/packages/CaloReco/CaloTowerStatus.h b/offline/packages/CaloReco/CaloTowerStatus.h index 8c6f20ecf6..1c961c9f0e 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.h +++ b/offline/packages/CaloReco/CaloTowerStatus.h @@ -91,6 +91,23 @@ class CaloTowerStatus : public SubsysReco m_doAbortNoHotMap = status; return; } + void set_doAbortNoTime(bool status = true) + { + m_doAbortNoTime = status; + return; + } + void set_doAbortNoChi2(bool status = true) + { + m_doAbortNoChi2 = status; + return; + } + void set_doAbortMissingCalib(bool status = true) + { + m_doAbortNoHotMap = status; + m_doAbortNoTime = status; + m_doAbortNoChi2 = status; + return; + } private: TowerInfoContainer *m_raw_towers{nullptr}; @@ -103,6 +120,8 @@ class CaloTowerStatus : public SubsysReco bool m_doTime{true}; bool m_doHotMap{true}; bool m_doAbortNoHotMap{false}; + bool m_doAbortNoTime{false}; + bool m_doAbortNoChi2{false}; CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::DETECTOR_INVALID}; From ccc849875701d1dbb6a9869763296a5a3babdfcc Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Wed, 18 Feb 2026 10:49:41 -0500 Subject: [PATCH 239/866] inital commit of calostatusskimmer This module will be used to skim on the status of packets. Specifically we are re-using the not instrumented status bit to flag empty and missing packets. The number of these status bits are counted, and if they pass a certain number of towers, the event will be aborted. --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 190 ++++++++++++++++++ .../CaloStatusSkimmer/CaloStatusSkimmer.h | 80 ++++++++ .../Skimmers/CaloStatusSkimmer/Makefile.am | 43 ++++ .../Skimmers/CaloStatusSkimmer/autogen.sh | 8 + .../Skimmers/CaloStatusSkimmer/configure.ac | 16 ++ 5 files changed, 337 insertions(+) create mode 100644 offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc create mode 100644 offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h create mode 100644 offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am create mode 100644 offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh create mode 100644 offline/packages/Skimmers/CaloStatusSkimmer/configure.ac diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc new file mode 100644 index 0000000000..726afac8e1 --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -0,0 +1,190 @@ +#include "CaloStatusSkimmer.h" + +#include +#include + +#include +#include +#include + +// Tower stuff +#include +#include +// #include +#include +#include + +// ROOT stuff +#include +#include +#include +#include +#include + +// for cluster vertex correction +#include +#include +#include +#include +#include +#include +#include + + +//____________________________________________________________________________.. +CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) : SubsysReco(name) +{ + n_eventcounter = 0; + n_skimcounter = 0; + n_notowernodecounter = 0; + std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) Calling ctor" << std::endl; +} + +//____________________________________________________________________________.. +CaloStatusSkimmer::~CaloStatusSkimmer() +{ + //std::cout << "CaloStatusSkimmer::~CaloStatusSkimmer() Calling dtor" << std::endl; +} + +//____________________________________________________________________________.. +int CaloStatusSkimmer::Init(PHCompositeNode *topNode) +{ + std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) Initializing" << std::endl; + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) +{ + n_eventcounter++; + if (b_do_skim_EMCal) + { + TowerInfoContainer *towers = findNode::getClass(topNode, "TOWERS_CEMC"); + if (!towers) + { + n_notowernodecounter++; + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_CEMC\n"; + return Fun4AllReturnCodes::ABORTEVENT; + } + const UInt_t ntowers = towers->size(); + uint16_t notinstr_count = 0; + for (UInt_t ch = 0; ch < ntowers; ++ch) + { + TowerInfo *tower = towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_count; + } + } + if (notinstr_count >= m_EMC_skim_threshold) + { + n_skimcounter++; + return Fun4AllReturnCodes::ABORTEVENT; + } + } + + if (b_do_skim_HCal) + { + TowerInfoContainer *hcalin_towers = findNode::getClass(topNode, "TOWERS_HCALIN"); + TowerInfoContainer *hcalout_towers = findNode::getClass(topNode, "TOWERS_HCALOUT"); + if (!hcalin_towers || !hcalout_towers) + { + n_notowernodecounter++; + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT\n"; + return Fun4AllReturnCodes::ABORTEVENT;// do I want ABORTPROCESSING or just ABORTEVENT here? ABORTPROCESSING will stop the entire job, while ABORTEVENT will just skip this event and continue with the next one. + } + + const UInt_t ntowers_hcalin = hcalin_towers->size(); + uint16_t notinstr_count_hcalin = 0; + for (UInt_t ch = 0; ch < ntowers_hcalin; ++ch) + { + TowerInfo *tower_in = hcalin_towers->get_tower_at_channel(ch); + if (tower_in->get_isNotInstr()) + { + ++notinstr_count_hcalin; + } + } + + const UInt_t ntowers_hcalout = hcalout_towers->size(); + uint16_t notinstr_count_hcalout = 0; + for (UInt_t ch = 0; ch < ntowers_hcalout; ++ch) + { + TowerInfo *tower_out = hcalout_towers->get_tower_at_channel(ch); + if (tower_out->get_isNotInstr()) + { + ++notinstr_count_hcalout; + } + } + + if (notinstr_count_hcalin >= m_HCal_skim_threshold || notinstr_count_hcalout >= m_HCal_skim_threshold) + { + n_skimcounter++; + return Fun4AllReturnCodes::ABORTEVENT; + } + } + + if (b_do_skim_sEPD) + { + TowerInfoContainer *sepd_towers = findNode::getClass(topNode, "TOWERS_SEPD"); + if (!sepd_towers) + { + n_notowernodecounter++; + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_SEPD\n"; + return Fun4AllReturnCodes::ABORTEVENT; + } + const UInt_t ntowers = sepd_towers->size(); + uint16_t notinstr_count = 0; + for (UInt_t ch = 0; ch < ntowers; ++ch) + { + TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_count; + } + } + if (notinstr_count >= m_sEPD_skim_threshold) + { + n_skimcounter++; + return Fun4AllReturnCodes::ABORTEVENT; + } + } + + if (b_do_skim_ZDC) + { + TowerInfoContainer *zdc_towers = findNode::getClass(topNode, "TOWERS_ZDC"); + if (!zdc_towers) + { + n_notowernodecounter++; + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_ZDC\n"; + return Fun4AllReturnCodes::ABORTEVENT; + } + const UInt_t ntowers = zdc_towers->size(); + uint16_t notinstr_count = 0; + for (UInt_t ch = 0; ch < ntowers; ++ch) + { + TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_count; + } + } + if (notinstr_count >= m_ZDC_skim_threshold) + { + n_skimcounter++; + return Fun4AllReturnCodes::ABORTEVENT; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int CaloStatusSkimmer::End(PHCompositeNode *topNode) +{ + std::cout << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." << std::endl; + std::cout << "Total events processed: " << n_eventcounter << std::endl; + std::cout << "Total events skimmed: " << n_skimcounter << std::endl; + std::cout << "Total events with missing tower nodes: " << n_notowernodecounter << std::endl; + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h new file mode 100644 index 0000000000..965a42abe2 --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -0,0 +1,80 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef CALOSTATUSSKIMMER_H +#define CALOSTATUSSKIMMER_H + +#include + +#include +#include +#include +#include + +class PHCompositeNode; + +class CaloStatusSkimmer : public SubsysReco +{ +public: + CaloStatusSkimmer(const std::string &name = "CaloStatusSkimmer"); + + ~CaloStatusSkimmer() override; + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + void do_skim_EMCal(bool do_skim, uint16_t threshold) + { + b_do_skim_EMCal = do_skim; + m_EMC_skim_threshold = threshold; + } + + void do_skim_HCal(bool do_skim, uint16_t threshold) + { + b_do_skim_HCal = do_skim; + m_HCal_skim_threshold = threshold; + } + + void do_skim_sEPD(bool do_skim, uint16_t threshold) + { + b_do_skim_sEPD = do_skim; + m_sEPD_skim_threshold = threshold; + } + + void do_skim_ZDC(bool do_skim, uint16_t threshold) + { + b_do_skim_ZDC = do_skim; + m_ZDC_skim_threshold = threshold; + } + +private: + + uint32_t n_eventcounter{0}; + uint32_t n_skimcounter{0}; + uint32_t n_notowernodecounter{0}; + + bool b_do_skim_EMCal{false}; + uint16_t m_EMC_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in EMCal + + bool b_do_skim_HCal{false}; + uint16_t m_HCal_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in HCal + + bool b_do_skim_sEPD{false}; + uint16_t m_sEPD_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in sEPD + + bool b_do_skim_ZDC{false}; + uint16_t m_ZDC_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in ZDC +}; + +#endif // CALOSTATUSSKIMMER_H diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am b/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am new file mode 100644 index 0000000000..9f496c8587 --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am @@ -0,0 +1,43 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + CaloStatusSkimmer.h + +lib_LTLIBRARIES = \ + libCaloStatusSkimmer.la + +libCaloStatusSkimmer_la_SOURCES = \ + CaloStatusSkimmer.cc + +libCaloStatusSkimmer_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lcalo_io + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libCaloStatusSkimmer.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh b/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh new file mode 100644 index 0000000000..dea267bbfd --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac b/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac new file mode 100644 index 0000000000..3934c375e4 --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac @@ -0,0 +1,16 @@ +AC_INIT(calostatusskimmer,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT From 0a29355aa458408d1454b959fdebe49a319810fd Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Wed, 18 Feb 2026 12:06:51 -0500 Subject: [PATCH 240/866] CaloTowerStatus - Add inputNode Option - Allow for providing a generic input node name that does not strictly adhere to the suffix from `m_detector`. - By default this is empty and does not override existing functionality unless explicity set via the `set_inputNode` method. --- offline/packages/CaloReco/CaloTowerStatus.cc | 4 ++++ offline/packages/CaloReco/CaloTowerStatus.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 0445dc9374..a98a64a27b 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -309,6 +309,10 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) void CaloTowerStatus::CreateNodeTree(PHCompositeNode *topNode) { std::string RawTowerNodeName = m_inputNodePrefix + m_detector; + if (!m_inputNode.empty()) + { + RawTowerNodeName = m_inputNode; + } m_raw_towers = findNode::getClass(topNode, RawTowerNodeName); if (!m_raw_towers) { diff --git a/offline/packages/CaloReco/CaloTowerStatus.h b/offline/packages/CaloReco/CaloTowerStatus.h index 1c961c9f0e..646116368d 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.h +++ b/offline/packages/CaloReco/CaloTowerStatus.h @@ -38,6 +38,11 @@ class CaloTowerStatus : public SubsysReco m_inputNodePrefix = name; return; } + void set_inputNode(const std::string &name) + { + m_inputNode = name; + return; + } void set_badChi2_const_threshold(float threshold) { badChi2_treshold_const = threshold; @@ -134,6 +139,7 @@ class CaloTowerStatus : public SubsysReco std::string m_fieldname_z_score; std::string m_calibName_hotMap; std::string m_inputNodePrefix{"TOWERS_"}; + std::string m_inputNode; std::string m_directURL_time; std::string m_directURL_hotMap; From 95d02470facc7e52b179c09194fbb2da01a3ea7f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Feb 2026 13:04:57 -0500 Subject: [PATCH 241/866] residual calculator compiles --- .../trackbase_historic/TrackAnalysisUtils.cc | 126 +++++++++++++++--- .../trackbase_historic/TrackAnalysisUtils.h | 8 ++ 2 files changed, 116 insertions(+), 18 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 744949c8fe..6dd4085a9b 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -1,12 +1,11 @@ #include "TrackAnalysisUtils.h" +#include #include #include #include #include -#include -#include #include "SvtxTrack.h" #include "TrackSeed.h" @@ -98,7 +97,7 @@ namespace TrackAnalysisUtils float thickness_per_region[4]) { auto clusterKeys = get_cluster_keys(track->get_tpc_seed()); - + std::vector dedxlist; for (unsigned long cluster_key : clusterKeys) { @@ -150,14 +149,14 @@ namespace TrackAnalysisUtils { betacorr = 4; } - if(track->get_crossing() < SHRT_MAX) + if (track->get_crossing() < SHRT_MAX) { - double z_crossing_corrected = - TpcClusterZCrossingCorrection::correctZ(cglob.z(), - TpcDefs::getSide(cluster_key), track->get_crossing()); + double z_crossing_corrected = + TpcClusterZCrossingCorrection::correctZ(cglob.z(), + TpcDefs::getSide(cluster_key), track->get_crossing()); - double maxz = tgeometry->get_max_driftlength() + tgeometry->get_CM_halfwidth(); - adc /= (1 - ((maxz - abs(z_crossing_corrected)) * 0.50 / maxz)); + double maxz = tgeometry->get_max_driftlength() + tgeometry->get_CM_halfwidth(); + adc /= (1 - ((maxz - abs(z_crossing_corrected)) * 0.50 / maxz)); } adc /= thickness; adc *= alphacorr; @@ -178,7 +177,7 @@ namespace TrackAnalysisUtils return sumdedx; } - TrackAnalysisUtils::DCAPair get_dca(SvtxTrack *track, + TrackAnalysisUtils::DCAPair get_dca(SvtxTrack* track, GlobalVertex* vertex) { Acts::Vector3 vpos(vertex->get_x(), @@ -201,9 +200,8 @@ namespace TrackAnalysisUtils vertexCov(i, j) = vertex->get_error(i, j); } } - - Acts::ActsSquareMatrix<3> rotCov = rot * (posCov+vertexCov) * rot_T; + Acts::ActsSquareMatrix<3> rotCov = rot * (posCov + vertexCov) * rot_T; dca.first.second = sqrt(rotCov(0, 0)); dca.second.second = sqrt(rotCov(2, 2)); @@ -274,12 +272,12 @@ namespace TrackAnalysisUtils std::vector get_cluster_keys(TrackSeed* seed) { std::vector out; - - if (seed) - { - std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out)); - } - + + if (seed) + { + std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out)); + } + return out; } @@ -296,4 +294,96 @@ namespace TrackAnalysisUtils return out; } + std::pair + get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, + TpcGlobalPositionWrapper& globalWrapper, TrkrClusterContainer* clustermap, + ActsGeometry* geometry, TpcClusterMover& mover) + { + auto* cluster = clustermap->findCluster(ckey); + std::vector> global_raw; + for (const auto& key : get_cluster_keys(track)) + { + auto* clus = clustermap->findCluster(ckey); + + // Fully correct the cluster positions for the crossing and all distortions + Acts::Vector3 global = globalWrapper.getGlobalPositionDistortionCorrected(key, clus, track->get_crossing()); + + // add the global positions to a vector to give to the cluster mover + global_raw.emplace_back(key, global); + } + + auto global_moved = mover.processTrack(global_raw); + // loop over global vectors and get this cluster + Acts::Vector3 clusglob(0, 0, 0); + for (const auto& pair : global_raw) + { + auto thiskey = pair.first; + clusglob = pair.second; + if (thiskey == ckey) + { + break; + } + } + + Acts::Vector3 clusglob_moved(0, 0, 0); + for (const auto& pair : global_moved) + { + auto thiskey = pair.first; + clusglob_moved = pair.second; + if (thiskey == ckey) + { + break; + } + } + SvtxTrackState* state = nullptr; + for (auto state_iter = track->begin_states(); + state_iter != track->end_states(); + ++state_iter) + { + SvtxTrackState* tstate = state_iter->second; + auto stateckey = tstate->get_cluskey(); + if (stateckey == ckey) + { + state = tstate; + break; + } + } + Surface surf = geometry->maps().getSurface(ckey, cluster); + Surface surf_ideal = geometry->maps().getSurface(ckey, cluster); // Unchanged by distortion corrections + // if this is a TPC cluster, the crossing correction may have moved it across the central membrane, check the surface + auto trkrid = TrkrDefs::getTrkrId(ckey); + if (trkrid == TrkrDefs::tpcId) + { + TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(ckey); + TrkrDefs::subsurfkey new_subsurfkey = 0; + surf = geometry->get_tpc_surface_from_coords(hitsetkey, clusglob_moved, new_subsurfkey); + } + + auto loc = geometry->getLocalCoords(ckey, cluster, track->get_crossing()); + // in this case we get local coords from transform of corrected global coords + clusglob_moved *= Acts::UnitConstants::cm; // we want mm for transformations + Acts::Vector3 normal = surf->normal(geometry->geometry().getGeoContext(), + Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); + auto local = surf->globalToLocal(geometry->geometry().getGeoContext(), + clusglob_moved, normal); + if (local.ok()) + { + loc = local.value() / Acts::UnitConstants::cm; + } + else + { + // otherwise take the manual calculation for the TPC + // doing it this way just avoids the bounds check that occurs in the surface class method + Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm + loct /= Acts::UnitConstants::cm; + + loc(0) = loct(0); + loc(1) = loct(1); + } + clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree + Acts::Vector2 stateloc(state->get_localX(), state->get_localY()); + Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); + return std::make_pair(stateloc - loc, stateglob - clusglob_moved); + } + } // namespace TrackAnalysisUtils diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index 168ff7495f..a7d9fbd1ed 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #include class SvtxTrack; @@ -32,6 +35,11 @@ namespace TrackAnalysisUtils float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, float thickness_per_region[4]); + std::pair + get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, + TpcGlobalPositionWrapper& globalWrapper, TrkrClusterContainer* clustermap, + ActsGeometry* geometry, TpcClusterMover& mover); + }; // namespace TrackAnalysisUtils #endif From e13a266985d582cff23dfca2d8525a99a25833d2 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 18 Feb 2026 13:34:35 -0500 Subject: [PATCH 242/866] Added toggles for storting CM phi distortions as r*dPhi vs dPhi (default is now in dPhi) --- .../packages/tpccalib/TpcCentralMembraneMatching.cc | 13 ++++++++----- .../packages/tpccalib/TpcCentralMembraneMatching.h | 5 +++++ offline/packages/tpccalib/TpcLaminationFitting.h | 4 ++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index 2cb4942994..ec488c9d68 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -2351,7 +2351,8 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) } */ m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal,RVal)); - m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); + if(!m_phiHist_in_rad) m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); + else m_dcc_out->m_hDPint[s]->SetBinContent(i, j, gr_dPhi[s]->Interpolate(phiVal,RVal)); } } } @@ -2660,13 +2661,15 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) if(den > 0.0) { m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, num_dR / den); - m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); + if(!m_phiHist_in_rad) m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); + else m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, num_dPhi / den); } } else { m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, gr_dR_toInterp[s]->Interpolate(phiVal,RVal)); - m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + if(!m_phiHist_in_rad) m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + else m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); } } } @@ -2873,8 +2876,8 @@ int TpcCentralMembraneMatching::GetNodes(PHCompositeNode* topNode) std::cout << "TpcCentralMembraneMatching::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; m_dcc_out = new TpcDistortionCorrectionContainer; m_dcc_out->m_dimensions = 2; - m_dcc_out->m_phi_hist_in_radians = false; - m_dcc_out->m_interpolate_z = true; + m_dcc_out->m_phi_hist_in_radians = m_phiHist_in_rad; + m_dcc_out->m_interpolate_z = false; auto* node = new PHDataNode(m_dcc_out, dcc_out_node_name); runNode->addNode(node); } diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.h b/offline/packages/tpccalib/TpcCentralMembraneMatching.h index cdde093629..2bc44e5ede 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.h +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.h @@ -124,6 +124,9 @@ class TpcCentralMembraneMatching : public SubsysReco m_stripePatternFile = stripePatternFile; } + void set_phiHistInRad(bool rad){ m_phiHist_in_rad = rad; } + + // void set_laminationFile(const std::string& filename) //{ // m_lamfilename = filename; @@ -156,6 +159,8 @@ class TpcCentralMembraneMatching : public SubsysReco //! tpc distortion correction utility class TpcDistortionCorrection m_distortionCorrection; + bool m_phiHist_in_rad{true}; + //! CMFlashClusterContainer *m_corrected_CMcluster_map{nullptr}; LaserClusterContainer *m_corrected_CMcluster_map{nullptr}; CMFlashDifferenceContainer *m_cm_flash_diffs{nullptr}; diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 561a9ab199..d9aeddf75e 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -50,6 +50,8 @@ class TpcLaminationFitting : public SubsysReco void set_ppMode(bool mode){ ppMode = mode; } + void set_phiHistInRad(bool rad){ m_phiHist_in_rad = rad; } + void set_fieldOff(bool fieldOff){ m_fieldOff = fieldOff; } void set_grid_dimensions(int phibins, int rbins); @@ -121,6 +123,8 @@ class TpcLaminationFitting : public SubsysReco //std::map m_run_ZDC_map_pp; //std::map m_run_ZDC_map_auau; + bool m_phiHist_in_rad{true}; + std::string m_stripePatternFile = "/sphenix/u/bkimelman/CMStripePattern.root"; bool m_fieldOff{false}; From 5951a0eb5ca60474018159618df5b8ec84041721 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 18 Feb 2026 13:54:02 -0500 Subject: [PATCH 243/866] Added lamination fitting cc that was missed in previous commit --- offline/packages/tpccalib/TpcLaminationFitting.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 1b3062dd7d..617e9a9387 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -745,7 +745,7 @@ int TpcLaminationFitting::InterpolatePhiDistortions() int phiBin = phiDistortionLamination[s]->GetXaxis()->FindBin(phi); if(m_fieldOff) { - m_laminationOffset[l][s] = m_fLamination[l][s]->GetParameter(0); + m_laminationOffset[l][s] = m_fLamination[l][s]->GetParameter(0); m_fLamination[l][s]->SetParameter(1, 0.0); } else @@ -753,7 +753,8 @@ int TpcLaminationFitting::InterpolatePhiDistortions() //m_fLamination[l][s]->SetParameter(3, -1.0*m_laminationOffset[l][s]); m_fLamination[l][s]->SetParameter(3, 0.0); } - double phiDistortion = R * m_fLamination[l][s]->Integral(phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i), phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1)) / (phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1) - phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i)); + double phiDistortion = m_fLamination[l][s]->Integral(phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i), phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1)) / (phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1) - phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i)); + if(!m_phiHist_in_rad) phiDistortion *= R; if(m_fieldOff) { m_fLamination[l][s]->SetParameter(1, m_laminationIdeal[l][s]); From 347fb4fe1cbaf2a47da87ae2bb97faf31d8ec315 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Feb 2026 14:38:41 -0500 Subject: [PATCH 244/866] fix stupid bug --- offline/packages/trackbase_historic/TrackAnalysisUtils.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 6dd4085a9b..42450833d2 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -303,16 +303,16 @@ namespace TrackAnalysisUtils std::vector> global_raw; for (const auto& key : get_cluster_keys(track)) { - auto* clus = clustermap->findCluster(ckey); + auto* clus = clustermap->findCluster(key); // Fully correct the cluster positions for the crossing and all distortions Acts::Vector3 global = globalWrapper.getGlobalPositionDistortionCorrected(key, clus, track->get_crossing()); - // add the global positions to a vector to give to the cluster mover global_raw.emplace_back(key, global); } auto global_moved = mover.processTrack(global_raw); + // loop over global vectors and get this cluster Acts::Vector3 clusglob(0, 0, 0); for (const auto& pair : global_raw) @@ -380,9 +380,10 @@ namespace TrackAnalysisUtils loc(0) = loct(0); loc(1) = loct(1); } - clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree + clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree Acts::Vector2 stateloc(state->get_localX(), state->get_localY()); Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); + return std::make_pair(stateloc - loc, stateglob - clusglob_moved); } From d98db224ce7c2c63e127168be998e1dbfd110ab2 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Feb 2026 15:22:38 -0500 Subject: [PATCH 245/866] consolidate --- .../trackbase_historic/TrackAnalysisUtils.cc | 18 +++++++++++++++--- .../trackbase_historic/TrackAnalysisUtils.h | 5 ++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 42450833d2..c4c80fb77e 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -1,11 +1,16 @@ #include "TrackAnalysisUtils.h" #include + +#include +#include + #include #include #include #include +#include #include "SvtxTrack.h" #include "TrackSeed.h" @@ -295,10 +300,17 @@ namespace TrackAnalysisUtils } std::pair - get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, - TpcGlobalPositionWrapper& globalWrapper, TrkrClusterContainer* clustermap, - ActsGeometry* geometry, TpcClusterMover& mover) + get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, TrkrClusterContainer* clustermap, + PHCompositeNode* topNode) { + TpcGlobalPositionWrapper globalWrapper; + globalWrapper.loadNodes(topNode); + globalWrapper.set_suppressCrossing(true); + TpcClusterMover mover; + auto* tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + mover.initialize_geometry(tpccellgeo); + mover.set_verbosity(0); + auto* geometry = findNode::getClass(topNode, "ActsGeometry"); auto* cluster = clustermap->findCluster(ckey); std::vector> global_raw; for (const auto& key : get_cluster_keys(track)) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index a7d9fbd1ed..1756a8c751 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -36,9 +36,8 @@ namespace TrackAnalysisUtils float thickness_per_region[4]); std::pair - get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, - TpcGlobalPositionWrapper& globalWrapper, TrkrClusterContainer* clustermap, - ActsGeometry* geometry, TpcClusterMover& mover); + get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, TrkrClusterContainer* clustermap, + PHCompositeNode *topNode); }; // namespace TrackAnalysisUtils From 5e828de02b47122896da7daf8de64278598e5d52 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Feb 2026 15:22:54 -0500 Subject: [PATCH 246/866] clang-format --- offline/packages/trackbase_historic/TrackAnalysisUtils.cc | 4 ++-- offline/packages/trackbase_historic/TrackAnalysisUtils.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index c4c80fb77e..cacbab9aec 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -301,7 +301,7 @@ namespace TrackAnalysisUtils std::pair get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, TrkrClusterContainer* clustermap, - PHCompositeNode* topNode) + PHCompositeNode* topNode) { TpcGlobalPositionWrapper globalWrapper; globalWrapper.loadNodes(topNode); @@ -392,7 +392,7 @@ namespace TrackAnalysisUtils loc(0) = loct(0); loc(1) = loct(1); } - clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree + clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree Acts::Vector2 stateloc(state->get_localX(), state->get_localY()); Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index 1756a8c751..00cca752f7 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -37,7 +37,7 @@ namespace TrackAnalysisUtils std::pair get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, TrkrClusterContainer* clustermap, - PHCompositeNode *topNode); + PHCompositeNode* topNode); }; // namespace TrackAnalysisUtils From 806959a9a6598ac5abf9146373659c4e72bbe2b6 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 18 Feb 2026 15:01:55 -0500 Subject: [PATCH 247/866] Moved filtering sourcelinks to a separate methods, so that one can remove measurements whether or not we run the direct navigations. GetSurfaceVect, as used for the direct navigation, does not apply any filtering. --- offline/packages/trackreco/PHActsTrkFitter.cc | 72 ++++++++----------- offline/packages/trackreco/PHActsTrkFitter.h | 26 +++---- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 5a92307b81..d361af240a 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -543,17 +543,21 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) continue; } + // filter sourcelinks to remove detectors that we don't want to include in the fit + sourceLinks = filterSourceLinks( sourceLinks ); + if (sourceLinks.empty()) { continue; } /// If using directed navigation, collect surface list to navigate - SurfacePtrVec surfaces_tmp; SurfacePtrVec surfaces; if (m_fitSiliconMMs || m_directNavigation) { - sourceLinks = getSurfaceVector(sourceLinks, surfaces_tmp); + + // get surfaces matching source links + const auto surfaces_tmp = getSurfaceVector(sourceLinks); // skip if there is no surfaces if (surfaces_tmp.empty()) @@ -960,59 +964,45 @@ ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack( } //__________________________________________________________________________________ -SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks, SurfacePtrVec& surfaces) const +SourceLinkVec PHActsTrkFitter::filterSourceLinks(const SourceLinkVec& sourceLinks ) const { - SourceLinkVec siliconMMSls; - - // if(Verbosity() > 1) - // std::cout << "Sorting " << sourceLinks.size() << " SLs" << std::endl; - + SourceLinkVec filtered; for (const auto& sl : sourceLinks) { const ActsSourceLink asl = sl.get(); - if (Verbosity() > 1) - { - std::cout << "SL available on : " << asl.geometryId() << std::endl; - } - const auto* const surf = m_tGeometry->geometry().tGeometry->findSurface(asl.geometryId()); - if (m_fitSiliconMMs) - { - // skip TPC surfaces - if (m_tGeometry->maps().isTpcSurface(surf)) - { - continue; - } - // also skip micromegas surfaces if not used - if (m_tGeometry->maps().isMicromegasSurface(surf) && !m_useMicromegas) - { - continue; - } - } + // skip TPC surfaces for fitSilicon MMs + if (m_tGeometry->maps().isTpcSurface(surf) && m_fitSiliconMMs) + { continue; } - if (m_forceSiOnlyFit) - { - if (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isTpcSurface(surf)) - { - continue; - } - } + // skip micromegas surfaces if not used + if (m_tGeometry->maps().isMicromegasSurface(surf) && !m_useMicromegas) + { continue; } + + // skip everything but silicons if only silicon fit is required + if (m_forceSiOnlyFit && (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isTpcSurface(surf)) ) + { continue; } // update vectors - siliconMMSls.push_back(sl); - surfaces.push_back(surf); + filtered.push_back(sl); } - if (Verbosity() > 10) + return filtered; +} + +//__________________________________________________________________________________ +SurfacePtrVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks) const +{ + SurfacePtrVec surfaces; + for (const auto& sl : sourceLinks) { - for (const auto& surf : surfaces) - { - std::cout << "Surface vector : " << surf->geometryId() << std::endl; - } + const ActsSourceLink asl = sl.get(); + const auto* const surf = m_tGeometry->geometry().tGeometry->findSurface(asl.geometryId()); + surfaces.push_back(surf); } - return siliconMMSls; + return surfaces; } void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 09a8ab9d1d..056c3e88b3 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -164,18 +164,20 @@ class PHActsTrkFitter : public SubsysReco /// Helper function to call either the regular navigation or direct /// navigation, depending on m_fitSiliconMMs ActsTrackFittingAlgorithm::TrackFitterResult fitTrack( - const std::vector& sourceLinks, - const ActsTrackFittingAlgorithm::TrackParameters& seed, - const ActsTrackFittingAlgorithm::GeneralFitterOptions& - kfOptions, - const SurfacePtrVec& surfSequence, - const CalibratorAdapter& calibrator, - ActsTrackFittingAlgorithm::TrackContainer& tracks); - - /// Functions to get list of sorted surfaces for direct navigation, if - /// applicable - SourceLinkVec getSurfaceVector(const SourceLinkVec& sourceLinks, - SurfacePtrVec& surfaces) const; + const std::vector& sourceLinks, + const ActsTrackFittingAlgorithm::TrackParameters& seed, + const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, + const SurfacePtrVec& surfSequence, + const CalibratorAdapter& calibrator, + ActsTrackFittingAlgorithm::TrackContainer& tracks); + + // remove all source links for detectors that we don't want to include in the fit + SourceLinkVec filterSourceLinks(const SourceLinkVec& sourceLinks ) const; + + /// get list of sorted surfaces for direct navigation, if applicable + SurfacePtrVec getSurfaceVector(const SourceLinkVec& sourceLinks) const; + + /// check ordering of the surfaces void checkSurfaceVec(SurfacePtrVec& surfaces) const; bool getTrackFitResult(const FitResult& fitOutput, TrackSeed* seed, From 42a15a95d59ece20f48cbfb224b359fda7d28285 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Wed, 18 Feb 2026 15:43:17 -0500 Subject: [PATCH 248/866] Update CaloTowerBuilder.cc --- offline/packages/CaloReco/CaloTowerBuilder.cc | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index a84706599d..736479fba0 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -307,6 +307,25 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vectoriValue(0, "CHANNELS"); unsigned int adc_skip_mask = 0; + if (nchannels == 0)// push back -1 and return for empty packets + { + for (int channel = 0; channel < m_nchannels; channel++) + { + if (skipChannel(channel, pid)) + { + continue; + } + std::vector waveform; + waveform.reserve(m_nzerosuppsamples); + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { + waveform.push_back(-1); + } + waveforms.push_back(waveform); + } + return Fun4AllReturnCodes::EVENT_OK; + } + if (m_dettype == CaloTowerDefs::CEMC) { adc_skip_mask = cdbttree->GetIntValue(pid, m_fieldname); @@ -406,7 +425,7 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vectorset_isNotInstr(true); } From 9d02849111da5374214e5d150025c8aceb06cd49 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 18 Feb 2026 17:14:52 -0500 Subject: [PATCH 249/866] Add additional compiler warnings for g++ need to update the perl script to update the compiler flags --- offline/packages/Skimmers/CaloStatusSkimmer/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac b/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac index 3934c375e4..d31173586b 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac +++ b/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac @@ -9,7 +9,7 @@ LT_INIT([disable-static]) dnl no point in suppressing warnings people should dnl at least see them, so here we go for g++: -Wall if test $ac_cv_prog_gxx = yes; then - CXXFLAGS="$CXXFLAGS -Wall -Werror" + CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" fi AC_CONFIG_FILES([Makefile]) From c0b2905148d13e0e26c15597d6afb6844405251d Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Wed, 18 Feb 2026 19:37:57 -0500 Subject: [PATCH 250/866] remove skip channels in empty packet loop, and clang-format --- offline/packages/CaloReco/CaloTowerBuilder.cc | 463 +++++++----------- 1 file changed, 176 insertions(+), 287 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 736479fba0..2584302138 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -14,17 +14,17 @@ #include #include -#include // for SubsysReco +#include // for SubsysReco #include #include -#include // for PHIODataNode -#include // for PHNode -#include // for PHNodeIterator -#include // for PHObject +#include // for PHIODataNode +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject #include -#include // for CDBTTree +#include // for CDBTTree #include @@ -35,10 +35,10 @@ #include #include -#include // for operator<<, endl, basic... -#include // for allocator_traits<>::val... +#include // for operator<<, endl, basic... +#include // for allocator_traits<>::val... #include -#include // for vector +#include // for vector static const std::map nodemap{ {CaloTowerDefs::CEMC, "CEMCPackets"}, @@ -48,50 +48,43 @@ static const std::map nodemap{ {CaloTowerDefs::SEPD, "SEPDPackets"}}; //____________________________________________________________________________.. CaloTowerBuilder::CaloTowerBuilder(const std::string &name) - : SubsysReco(name) - , WaveformProcessing(new CaloWaveformProcessing()) -{ -} + : SubsysReco(name), WaveformProcessing(new CaloWaveformProcessing()) {} //____________________________________________________________________________.. -CaloTowerBuilder::~CaloTowerBuilder() -{ +CaloTowerBuilder::~CaloTowerBuilder() { delete cdbttree; delete cdbttree_tbt_zs; delete WaveformProcessing; } //____________________________________________________________________________.. -int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) -{ +int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { WaveformProcessing->set_processing_type(_processingtype); - WaveformProcessing->set_softwarezerosuppression(m_bdosoftwarezerosuppression, m_nsoftwarezerosuppression); - if (m_setTimeLim) - { + WaveformProcessing->set_softwarezerosuppression(m_bdosoftwarezerosuppression, + m_nsoftwarezerosuppression); + if (m_setTimeLim) { WaveformProcessing->set_timeFitLim(m_timeLim_low, m_timeLim_high); } - if (m_dobitfliprecovery) - { + if (m_dobitfliprecovery) { WaveformProcessing->set_bitFlipRecovery(m_dobitfliprecovery); } // Set functional fit parameters - if (_processingtype == CaloWaveformProcessing::FUNCFIT) - { + if (_processingtype == CaloWaveformProcessing::FUNCFIT) { WaveformProcessing->set_funcfit_type(m_funcfit_type); WaveformProcessing->set_powerlaw_params(m_powerlaw_power, m_powerlaw_decay); - WaveformProcessing->set_doubleexp_params(m_doubleexp_power, m_doubleexp_peaktime1, m_doubleexp_peaktime2, m_doubleexp_ratio); + WaveformProcessing->set_doubleexp_params( + m_doubleexp_power, m_doubleexp_peaktime1, m_doubleexp_peaktime2, + m_doubleexp_ratio); } - if (m_dettype == CaloTowerDefs::CEMC) - { + if (m_dettype == CaloTowerDefs::CEMC) { m_detector = "CEMC"; m_packet_low = 6001; m_packet_high = 6128; m_nchannels = 192; WaveformProcessing->set_template_name("CEMC_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) - { + if (_processingtype == CaloWaveformProcessing::NONE) { WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); } @@ -104,47 +97,41 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) m_fieldname = "adcskipmask"; calibdir = CDBInterface::instance()->getUrl(m_calibName); - if (calibdir.empty()) - { - std::cout << PHWHERE << "ADC Skip mask not found in CDB, not even in the default... " << std::endl; + if (calibdir.empty()) { + std::cout << PHWHERE + << "ADC Skip mask not found in CDB, not even in the default... " + << std::endl; exit(1); } cdbttree = new CDBTTree(calibdir); - } - else if (m_dettype == CaloTowerDefs::HCALIN) - { + } else if (m_dettype == CaloTowerDefs::HCALIN) { m_packet_low = 7001; m_packet_high = 7008; m_detector = "HCALIN"; m_nchannels = 192; WaveformProcessing->set_template_name("IHCAL_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) - { + if (_processingtype == CaloWaveformProcessing::NONE) { WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); } - } - else if (m_dettype == CaloTowerDefs::HCALOUT) - { + } else if (m_dettype == CaloTowerDefs::HCALOUT) { m_detector = "HCALOUT"; m_packet_low = 8001; m_packet_high = 8008; m_nchannels = 192; WaveformProcessing->set_template_name("OHCAL_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) - { + if (_processingtype == CaloWaveformProcessing::NONE) { WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); } - } - else if (m_dettype == CaloTowerDefs::SEPD) - { + } else if (m_dettype == CaloTowerDefs::SEPD) { m_detector = "SEPD"; m_packet_low = 9001; m_packet_high = 9006; m_nchannels = 128; WaveformProcessing->set_template_name("SEPD_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) - { - WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); // default the EPD to fast processing + if (_processingtype == CaloWaveformProcessing::NONE) { + WaveformProcessing->set_processing_type( + CaloWaveformProcessing::TEMPLATE); // default the EPD to fast + // processing } m_calibName = "SEPD_CHANNELMAP2"; @@ -152,28 +139,25 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) calibdir = CDBInterface::instance()->getUrl(m_calibName); - if (calibdir.empty()) - { - std::cout << PHWHERE << "No sEPD mapping file for domain " << m_calibName << " found" << std::endl; + if (calibdir.empty()) { + std::cout << PHWHERE << "No sEPD mapping file for domain " << m_calibName + << " found" << std::endl; exit(1); } cdbttree_sepd_map = new CDBTTree(calibdir); - } - else if (m_dettype == CaloTowerDefs::ZDC) - { + } else if (m_dettype == CaloTowerDefs::ZDC) { m_detector = "ZDC"; m_packet_low = 12001; m_packet_high = 12001; m_nchannels = 128; - if (_processingtype == CaloWaveformProcessing::NONE) - { - WaveformProcessing->set_processing_type(CaloWaveformProcessing::FAST); // default the ZDC to fast processing + if (_processingtype == CaloWaveformProcessing::NONE) { + WaveformProcessing->set_processing_type( + CaloWaveformProcessing::FAST); // default the ZDC to fast processing } } WaveformProcessing->initialize_processing(); - if (m_dotbtszs) - { + if (m_dotbtszs) { cdbttree_tbt_zs = new CDBTTree(m_zsURL); } @@ -181,36 +165,30 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -int CaloTowerBuilder::process_sim() -{ +int CaloTowerBuilder::process_sim() { std::vector> waveforms; - for (int ich = 0; ich < (int) m_CalowaveformContainer->size(); ich++) - { + for (int ich = 0; ich < (int)m_CalowaveformContainer->size(); ich++) { TowerInfo *towerinfo = m_CalowaveformContainer->get_tower_at_channel(ich); std::vector waveform; waveform.reserve(m_nsamples); bool fillwaveform = true; // get key - if (m_dotbtszs) - { + if (m_dotbtszs) { unsigned int key = m_CalowaveformContainer->encode_key(ich); int zs_threshold = cdbttree_tbt_zs->GetIntValue(key, m_zs_fieldname); int pre = towerinfo->get_waveform_value(0); // this is always safe since towerinfo v3 has 31 samples int post = towerinfo->get_waveform_value(6); - if ((post - pre) <= zs_threshold) - { + if ((post - pre) <= zs_threshold) { // zero suppressed fillwaveform = false; waveform.push_back(pre); waveform.push_back(post); } } - if (fillwaveform) - { - for (int samp = 0; samp < m_nsamples; samp++) - { + if (fillwaveform) { + for (int samp = 0; samp < m_nsamples; samp++) { waveform.push_back(towerinfo->get_waveform_value(samp)); } } @@ -218,10 +196,10 @@ int CaloTowerBuilder::process_sim() waveform.clear(); } - std::vector> processed_waveforms = WaveformProcessing->process_waveform(waveforms); + std::vector> processed_waveforms = + WaveformProcessing->process_waveform(waveforms); int n_channels = processed_waveforms.size(); - for (int i = 0; i < n_channels; i++) - { + for (int i = 0; i < n_channels; i++) { // this is for copying the truth info to the downstream object TowerInfo *towerwaveform = m_CalowaveformContainer->get_tower_at_channel(i); TowerInfo *towerinfo = m_CaloInfoContainer->get_tower_at_channel(i); @@ -231,25 +209,20 @@ int CaloTowerBuilder::process_sim() towerinfo->set_time(processed_waveforms.at(i).at(1)); towerinfo->set_pedestal(processed_waveforms.at(i).at(2)); towerinfo->set_chi2(processed_waveforms.at(i).at(3)); - bool SZS = isSZS(processed_waveforms.at(i).at(1), processed_waveforms.at(i).at(3)); - if (processed_waveforms.at(i).at(4) == 0) - { + bool SZS = + isSZS(processed_waveforms.at(i).at(1), processed_waveforms.at(i).at(3)); + if (processed_waveforms.at(i).at(4) == 0) { towerinfo->set_isRecovered(false); - } - else - { + } else { towerinfo->set_isRecovered(true); } int n_samples = waveforms.at(i).size(); - if (n_samples == m_nzerosuppsamples || SZS) - { + if (n_samples == m_nzerosuppsamples || SZS) { towerinfo->set_isZS(true); } - for (int j = 0; j < n_samples; j++) - { + for (int j = 0; j < n_samples; j++) { towerinfo->set_waveform_value(j, waveforms.at(i).at(j)); - if (std::round(waveforms.at(i).at(j)) >= m_saturation) - { + if (std::round(waveforms.at(i).at(j)) >= m_saturation) { towerinfo->set_isSaturated(true); } } @@ -259,66 +232,50 @@ int CaloTowerBuilder::process_sim() return Fun4AllReturnCodes::EVENT_OK; } -int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vector> &waveforms) -{ +int CaloTowerBuilder::process_data(PHCompositeNode *topNode, + std::vector> &waveforms) { std::variant event; - if (m_UseOfflinePacketFlag) - { - CaloPacketContainer *calopacketcontainer = findNode::getClass(topNode, nodemap.find(m_dettype)->second); - if (!calopacketcontainer) - { - for (int pid = m_packet_low; pid <= m_packet_high; pid++) - { - if (findNode::getClass(topNode, pid)) - { + if (m_UseOfflinePacketFlag) { + CaloPacketContainer *calopacketcontainer = + findNode::getClass( + topNode, nodemap.find(m_dettype)->second); + if (!calopacketcontainer) { + for (int pid = m_packet_low; pid <= m_packet_high; pid++) { + if (findNode::getClass(topNode, pid)) { m_PacketNodesFlag = true; break; } } - if (!m_PacketNodesFlag) - { + if (!m_PacketNodesFlag) { return Fun4AllReturnCodes::EVENT_OK; } - } - else - { + } else { event = calopacketcontainer; } - } - else - { + } else { Event *_event = findNode::getClass(topNode, "PRDF"); - if (_event == nullptr) - { + if (_event == nullptr) { std::cout << PHWHERE << " Event not found" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - if (_event->getEvtType() != DATAEVENT) - { + if (_event->getEvtType() != DATAEVENT) { return Fun4AllReturnCodes::ABORTEVENT; } event = _event; } - // since the function call on Packet and CaloPacket is the same, maybe we can use lambda? - auto process_packet = [&](auto *packet, int pid) - { - if (packet) - { + // since the function call on Packet and CaloPacket is the same, maybe we can + // use lambda? + auto process_packet = [&](auto *packet, int pid) { + if (packet) { int nchannels = packet->iValue(0, "CHANNELS"); unsigned int adc_skip_mask = 0; - if (nchannels == 0)// push back -1 and return for empty packets + if (nchannels == 0) // push back -1 and return for empty packets { - for (int channel = 0; channel < m_nchannels; channel++) - { - if (skipChannel(channel, pid)) - { - continue; - } + for (int channel = 0; channel < m_nchannels; channel++) { std::vector waveform; waveform.reserve(m_nzerosuppsamples); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) - { + for (int samp = 0; samp < m_nzerosuppsamples; samp++) { waveform.push_back(-1); } waveforms.push_back(waveform); @@ -326,41 +283,33 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vectorGetIntValue(pid, m_fieldname); } - if (m_dettype == CaloTowerDefs::ZDC) - { + if (m_dettype == CaloTowerDefs::ZDC) { nchannels = m_nchannels; } - if (nchannels > m_nchannels) // packet is corrupted and reports too many channels + if (nchannels > + m_nchannels) // packet is corrupted and reports too many channels { return Fun4AllReturnCodes::ABORTEVENT; } int n_pad_skip_mask = 0; - for (int channel = 0; channel < nchannels; channel++) - { - if (skipChannel(channel, pid)) - { + for (int channel = 0; channel < nchannels; channel++) { + if (skipChannel(channel, pid)) { continue; } - if (m_dettype == CaloTowerDefs::CEMC) - { - if (channel % 64 == 0) - { - unsigned int adcboard = (unsigned int) channel / 64; - if ((adc_skip_mask >> adcboard) & 0x1U) - { - for (int iskip = 0; iskip < 64; iskip++) - { + if (m_dettype == CaloTowerDefs::CEMC) { + if (channel % 64 == 0) { + unsigned int adcboard = (unsigned int)channel / 64; + if ((adc_skip_mask >> adcboard) & 0x1U) { + for (int iskip = 0; iskip < 64; iskip++) { n_pad_skip_mask++; std::vector waveform; waveform.reserve(m_nsamples); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) - { + for (int samp = 0; samp < m_nzerosuppsamples; samp++) { waveform.push_back(0); } waveforms.push_back(waveform); @@ -372,15 +321,11 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vector waveform; waveform.reserve(m_nsamples); - if (packet->iValue(channel, "SUPPRESSED")) - { + if (packet->iValue(channel, "SUPPRESSED")) { waveform.push_back(packet->iValue(channel, "PRE")); waveform.push_back(packet->iValue(channel, "POST")); - } - else - { - for (int samp = 0; samp < m_nsamples; samp++) - { + } else { + for (int samp = 0; samp < m_nsamples; samp++) { waveform.push_back(packet->iValue(samp, channel)); } } @@ -389,43 +334,35 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vector waveform; waveform.reserve(m_nsamples); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) - { + for (int samp = 0; samp < m_nzerosuppsamples; samp++) { waveform.push_back(0); } waveforms.push_back(waveform); waveform.clear(); } } - } - else // if the packet is missing treat constitutent channels as zero suppressed + } else // if the packet is missing treat constitutent channels as zero + // suppressed { - for (int channel = 0; channel < m_nchannels; channel++) - { - if (skipChannel(channel, pid)) - { + for (int channel = 0; channel < m_nchannels; channel++) { + if (skipChannel(channel, pid)) { continue; } std::vector waveform; waveform.reserve(2); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) - { - waveform.push_back(-1); // push back -1 for missing packets + for (int samp = 0; samp < m_nzerosuppsamples; samp++) { + waveform.push_back(-1); // push back -1 for missing packets } waveforms.push_back(waveform); waveform.clear(); @@ -434,32 +371,23 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vector(&event)) - { + for (int pid = m_packet_low; pid <= m_packet_high; pid++) { + if (!m_PacketNodesFlag) { + if (auto *hcalcont = std::get_if(&event)) { CaloPacket *packet = (*hcalcont)->getPacketbyId(pid); - if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) - { + if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) { return Fun4AllReturnCodes::ABORTEVENT; } - } - else if (auto *_event = std::get_if(&event)) - { + } else if (auto *_event = std::get_if(&event)) { Packet *packet = (*_event)->getPacket(pid); - if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) - { + if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) { // I think it is safe to delete a nullptr... delete packet; return Fun4AllReturnCodes::ABORTEVENT; } delete packet; } - } - else - { + } else { CaloPacket *calopacket = findNode::getClass(topNode, pid); process_packet(calopacket, pid); } @@ -468,32 +396,27 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vector> waveforms; - if (process_data(topNode, waveforms) == Fun4AllReturnCodes::ABORTEVENT) - { + if (process_data(topNode, waveforms) == Fun4AllReturnCodes::ABORTEVENT) { return Fun4AllReturnCodes::ABORTEVENT; } - if (waveforms.empty()) - { + if (waveforms.empty()) { return Fun4AllReturnCodes::EVENT_OK; } - // waveform vector is filled here, now fill our output. methods from the base class make sure - // we only fill what the chosen container version supports - std::vector> processed_waveforms = WaveformProcessing->process_waveform(waveforms); + // waveform vector is filled here, now fill our output. methods from the base + // class make sure we only fill what the chosen container version supports + std::vector> processed_waveforms = + WaveformProcessing->process_waveform(waveforms); int n_channels = processed_waveforms.size(); - for (int i = 0; i < n_channels; i++) - { + for (int i = 0; i < n_channels; i++) { int idx = i; // Align sEPD ADC channels to TowerInfoContainer - if (m_dettype == CaloTowerDefs::SEPD) - { + if (m_dettype == CaloTowerDefs::SEPD) { idx = cdbttree_sepd_map->GetIntValue(i, m_fieldname); } TowerInfo *towerinfo = m_CaloInfoContainer->get_tower_at_channel(i); @@ -502,33 +425,27 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) towerinfo->set_time(processed_waveforms.at(idx).at(1)); towerinfo->set_pedestal(processed_waveforms.at(idx).at(2)); towerinfo->set_chi2(processed_waveforms.at(idx).at(3)); - bool SZS = isSZS(processed_waveforms.at(idx).at(1), processed_waveforms.at(idx).at(3)); + bool SZS = isSZS(processed_waveforms.at(idx).at(1), + processed_waveforms.at(idx).at(3)); - if (processed_waveforms.at(idx).at(4) == 0) - { + if (processed_waveforms.at(idx).at(4) == 0) { towerinfo->set_isRecovered(false); - } - else - { + } else { towerinfo->set_isRecovered(true); } int n_samples = waveforms.at(idx).size(); - if (n_samples == m_nzerosuppsamples || SZS) - { - if (waveforms.at(idx).at(0) == -1) // set bit for missing and empty packets. + if (n_samples == m_nzerosuppsamples || SZS) { + if (waveforms.at(idx).at(0) == + -1) // set bit for missing and empty packets. { towerinfo->set_isNotInstr(true); - } - else - { + } else { towerinfo->set_isZS(true); } } - for (int j = 0; j < n_samples; j++) - { - if (std::round(waveforms.at(idx).at(j)) >= m_saturation) - { + for (int j = 0; j < n_samples; j++) { + if (std::round(waveforms.at(idx).at(j)) >= m_saturation) { towerinfo->set_isSaturated(true); } towerinfo->set_waveform_value(j, waveforms.at(idx).at(j)); @@ -539,30 +456,23 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -bool CaloTowerBuilder::skipChannel(int ich, int pid) -{ - if (m_dettype == CaloTowerDefs::SEPD) - { +bool CaloTowerBuilder::skipChannel(int ich, int pid) { + if (m_dettype == CaloTowerDefs::SEPD) { int sector = ((ich + 1) / 32); int emptych = -999; - if ((sector == 0) && (pid == 9001)) - { + if ((sector == 0) && (pid == 9001)) { emptych = 1; - } - else - { + } else { emptych = 14 + 32 * sector; } - if (ich == emptych) - { + if (ich == emptych) { return true; } } - if (m_dettype == CaloTowerDefs::ZDC) - { - if (((ich > 17) && (ich < 48)) || ((ich > 63) && (ich < 80)) || ((ich > 81) && (ich < 112))) - { + if (m_dettype == CaloTowerDefs::ZDC) { + if (((ich > 17) && (ich < 48)) || ((ich > 63) && (ich < 80)) || + ((ich > 81) && (ich < 112))) { return true; } } @@ -570,34 +480,31 @@ bool CaloTowerBuilder::skipChannel(int ich, int pid) return false; } -bool CaloTowerBuilder::isSZS(float time, float chi2) -{ +bool CaloTowerBuilder::isSZS(float time, float chi2) { // isfinite - if (!std::isfinite(time) && !std::isfinite(chi2)) - { + if (!std::isfinite(time) && !std::isfinite(chi2)) { return true; } return false; } -void CaloTowerBuilder::CreateNodeTree(PHCompositeNode *topNode) -{ +void CaloTowerBuilder::CreateNodeTree(PHCompositeNode *topNode) { PHNodeIterator topNodeItr(topNode); // DST node - PHCompositeNode *dstNode = dynamic_cast(topNodeItr.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { + PHCompositeNode *dstNode = dynamic_cast( + topNodeItr.findFirst("PHCompositeNode", "DST")); + if (!dstNode) { std::cout << "PHComposite node created: DST" << std::endl; dstNode = new PHCompositeNode("DST"); topNode->addNode(dstNode); } - if (!m_isdata) - { + if (!m_isdata) { std::string waveformNodeName = m_inputNodePrefix + m_detector; - m_CalowaveformContainer = findNode::getClass(topNode, waveformNodeName); - if (!m_CalowaveformContainer) - { - std::cout << PHWHERE << "simulation waveform container " << waveformNodeName << " not found" << std::endl; + m_CalowaveformContainer = + findNode::getClass(topNode, waveformNodeName); + if (!m_CalowaveformContainer) { + std::cout << PHWHERE << "simulation waveform container " + << waveformNodeName << " not found" << std::endl; gSystem->Exit(1); exit(1); } @@ -606,73 +513,55 @@ void CaloTowerBuilder::CreateNodeTree(PHCompositeNode *topNode) // towers PHNodeIterator nodeItr(dstNode); PHCompositeNode *DetNode; - // enum CaloTowerDefs::DetectorSystem and TowerInfoContainer::DETECTOR are different!!!! - TowerInfoContainer::DETECTOR DetectorEnum = TowerInfoContainer::DETECTOR::DETECTOR_INVALID; + // enum CaloTowerDefs::DetectorSystem and TowerInfoContainer::DETECTOR are + // different!!!! + TowerInfoContainer::DETECTOR DetectorEnum = + TowerInfoContainer::DETECTOR::DETECTOR_INVALID; std::string DetectorNodeName; - if (m_dettype == CaloTowerDefs::CEMC) - { + if (m_dettype == CaloTowerDefs::CEMC) { DetectorEnum = TowerInfoContainer::DETECTOR::EMCAL; DetectorNodeName = "CEMC"; - } - else if (m_dettype == CaloTowerDefs::SEPD) - { + } else if (m_dettype == CaloTowerDefs::SEPD) { DetectorEnum = TowerInfoContainer::DETECTOR::SEPD; DetectorNodeName = "SEPD"; - } - else if (m_dettype == CaloTowerDefs::ZDC) - { + } else if (m_dettype == CaloTowerDefs::ZDC) { DetectorEnum = TowerInfoContainer::DETECTOR::ZDC; DetectorNodeName = "ZDC"; - } - else if (m_dettype == CaloTowerDefs::HCALIN) - { + } else if (m_dettype == CaloTowerDefs::HCALIN) { DetectorEnum = TowerInfoContainer::DETECTOR::HCAL; DetectorNodeName = "HCALIN"; - } - else if (m_dettype == CaloTowerDefs::HCALOUT) - { + } else if (m_dettype == CaloTowerDefs::HCALOUT) { DetectorEnum = TowerInfoContainer::DETECTOR::HCAL; DetectorNodeName = "HCALOUT"; - } - else - { + } else { std::cout << PHWHERE << " Invalid detector type " << m_dettype << std::endl; gSystem->Exit(1); exit(1); } - DetNode = dynamic_cast(nodeItr.findFirst("PHCompositeNode", DetectorNodeName)); - if (!DetNode) - { + DetNode = dynamic_cast( + nodeItr.findFirst("PHCompositeNode", DetectorNodeName)); + if (!DetNode) { DetNode = new PHCompositeNode(DetectorNodeName); dstNode->addNode(DetNode); } - if (m_buildertype == CaloTowerDefs::kPRDFTowerv1) - { + if (m_buildertype == CaloTowerDefs::kPRDFTowerv1) { m_CaloInfoContainer = new TowerInfoContainerv1(DetectorEnum); - } - else if (m_buildertype == CaloTowerDefs::kPRDFWaveform) - { + } else if (m_buildertype == CaloTowerDefs::kPRDFWaveform) { m_CaloInfoContainer = new TowerInfoContainerv3(DetectorEnum); - } - else if (m_buildertype == CaloTowerDefs::kWaveformTowerv2) - { + } else if (m_buildertype == CaloTowerDefs::kWaveformTowerv2) { m_CaloInfoContainer = new TowerInfoContainerv2(DetectorEnum); - } - else if (m_buildertype == CaloTowerDefs::kPRDFTowerv4) - { + } else if (m_buildertype == CaloTowerDefs::kPRDFTowerv4) { m_CaloInfoContainer = new TowerInfoContainerv4(DetectorEnum); - } - else if (m_buildertype == CaloTowerDefs::kWaveformTowerSimv1) - { + } else if (m_buildertype == CaloTowerDefs::kWaveformTowerSimv1) { m_CaloInfoContainer = new TowerInfoContainerSimv1(DetectorEnum); - } - else - { - std::cout << PHWHERE << "invalid builder type " << m_buildertype << std::endl; + } else { + std::cout << PHWHERE << "invalid builder type " << m_buildertype + << std::endl; gSystem->Exit(1); exit(1); } TowerNodeName = m_outputNodePrefix + m_detector; - PHIODataNode *newTowerNode = new PHIODataNode(m_CaloInfoContainer, TowerNodeName, "PHObject"); + PHIODataNode *newTowerNode = new PHIODataNode( + m_CaloInfoContainer, TowerNodeName, "PHObject"); DetNode->addNode(newTowerNode); } From 8a18f615325156044d66275cc3d47aa45b594d23 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Wed, 18 Feb 2026 19:41:26 -0500 Subject: [PATCH 251/866] clang-format for the skimmer module --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 141 +++++++++--------- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 118 ++++++++------- 2 files changed, 128 insertions(+), 131 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 726afac8e1..5011e2ff44 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -24,152 +24,145 @@ // for cluster vertex correction #include #include +#include #include #include -#include -#include #include - +#include //____________________________________________________________________________.. -CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) : SubsysReco(name) -{ +CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) + : SubsysReco(name) { n_eventcounter = 0; n_skimcounter = 0; n_notowernodecounter = 0; - std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) Calling ctor" << std::endl; + std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) " + "Calling ctor" + << std::endl; } //____________________________________________________________________________.. -CaloStatusSkimmer::~CaloStatusSkimmer() -{ - //std::cout << "CaloStatusSkimmer::~CaloStatusSkimmer() Calling dtor" << std::endl; +CaloStatusSkimmer::~CaloStatusSkimmer() { + // std::cout << "CaloStatusSkimmer::~CaloStatusSkimmer() Calling dtor" << + // std::endl; } //____________________________________________________________________________.. -int CaloStatusSkimmer::Init(PHCompositeNode *topNode) -{ - std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) Initializing" << std::endl; +int CaloStatusSkimmer::Init(PHCompositeNode *topNode) { + std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) Initializing" + << std::endl; return Fun4AllReturnCodes::EVENT_OK; } //____________________________________________________________________________.. -int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) -{ +int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { n_eventcounter++; - if (b_do_skim_EMCal) - { - TowerInfoContainer *towers = findNode::getClass(topNode, "TOWERS_CEMC"); - if (!towers) - { + if (b_do_skim_EMCal) { + TowerInfoContainer *towers = + findNode::getClass(topNode, "TOWERS_CEMC"); + if (!towers) { n_notowernodecounter++; - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_CEMC\n"; + std::cout << PHWHERE + << "calostatuscheck::process_event: missing TOWERS_CEMC\n"; return Fun4AllReturnCodes::ABORTEVENT; } const UInt_t ntowers = towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) - { + for (UInt_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) - { + if (tower->get_isNotInstr()) { ++notinstr_count; } } - if (notinstr_count >= m_EMC_skim_threshold) - { + if (notinstr_count >= m_EMC_skim_threshold) { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } } - if (b_do_skim_HCal) - { - TowerInfoContainer *hcalin_towers = findNode::getClass(topNode, "TOWERS_HCALIN"); - TowerInfoContainer *hcalout_towers = findNode::getClass(topNode, "TOWERS_HCALOUT"); - if (!hcalin_towers || !hcalout_towers) - { + if (b_do_skim_HCal) { + TowerInfoContainer *hcalin_towers = + findNode::getClass(topNode, "TOWERS_HCALIN"); + TowerInfoContainer *hcalout_towers = + findNode::getClass(topNode, "TOWERS_HCALOUT"); + if (!hcalin_towers || !hcalout_towers) { n_notowernodecounter++; - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT\n"; - return Fun4AllReturnCodes::ABORTEVENT;// do I want ABORTPROCESSING or just ABORTEVENT here? ABORTPROCESSING will stop the entire job, while ABORTEVENT will just skip this event and continue with the next one. + std::cout << PHWHERE + << "calostatuscheck::process_event: missing TOWERS_HCALIN or " + "TOWERS_HCALOUT\n"; + return Fun4AllReturnCodes:: + ABORTEVENT; // do I want ABORTPROCESSING or just ABORTEVENT here? + // ABORTPROCESSING will stop the entire job, while + // ABORTEVENT will just skip this event and continue with + // the next one. } const UInt_t ntowers_hcalin = hcalin_towers->size(); uint16_t notinstr_count_hcalin = 0; - for (UInt_t ch = 0; ch < ntowers_hcalin; ++ch) - { + for (UInt_t ch = 0; ch < ntowers_hcalin; ++ch) { TowerInfo *tower_in = hcalin_towers->get_tower_at_channel(ch); - if (tower_in->get_isNotInstr()) - { + if (tower_in->get_isNotInstr()) { ++notinstr_count_hcalin; } } - + const UInt_t ntowers_hcalout = hcalout_towers->size(); uint16_t notinstr_count_hcalout = 0; - for (UInt_t ch = 0; ch < ntowers_hcalout; ++ch) - { + for (UInt_t ch = 0; ch < ntowers_hcalout; ++ch) { TowerInfo *tower_out = hcalout_towers->get_tower_at_channel(ch); - if (tower_out->get_isNotInstr()) - { + if (tower_out->get_isNotInstr()) { ++notinstr_count_hcalout; } } - if (notinstr_count_hcalin >= m_HCal_skim_threshold || notinstr_count_hcalout >= m_HCal_skim_threshold) - { + if (notinstr_count_hcalin >= m_HCal_skim_threshold || + notinstr_count_hcalout >= m_HCal_skim_threshold) { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } } - if (b_do_skim_sEPD) - { - TowerInfoContainer *sepd_towers = findNode::getClass(topNode, "TOWERS_SEPD"); - if (!sepd_towers) - { + if (b_do_skim_sEPD) { + TowerInfoContainer *sepd_towers = + findNode::getClass(topNode, "TOWERS_SEPD"); + if (!sepd_towers) { n_notowernodecounter++; - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_SEPD\n"; + std::cout << PHWHERE + << "calostatuscheck::process_event: missing TOWERS_SEPD\n"; return Fun4AllReturnCodes::ABORTEVENT; } const UInt_t ntowers = sepd_towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) - { + for (UInt_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) - { + if (tower->get_isNotInstr()) { ++notinstr_count; } } - if (notinstr_count >= m_sEPD_skim_threshold) - { + if (notinstr_count >= m_sEPD_skim_threshold) { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } } - if (b_do_skim_ZDC) - { - TowerInfoContainer *zdc_towers = findNode::getClass(topNode, "TOWERS_ZDC"); - if (!zdc_towers) - { + if (b_do_skim_ZDC) { + TowerInfoContainer *zdc_towers = + findNode::getClass(topNode, "TOWERS_ZDC"); + if (!zdc_towers) { n_notowernodecounter++; - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_ZDC\n"; + std::cout << PHWHERE + << "calostatuscheck::process_event: missing TOWERS_ZDC\n"; return Fun4AllReturnCodes::ABORTEVENT; } const UInt_t ntowers = zdc_towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) - { + for (UInt_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) - { + if (tower->get_isNotInstr()) { ++notinstr_count; } } - if (notinstr_count >= m_ZDC_skim_threshold) - { + if (notinstr_count >= m_ZDC_skim_threshold) { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } @@ -179,12 +172,14 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } //____________________________________________________________________________.. -int CaloStatusSkimmer::End(PHCompositeNode *topNode) -{ - std::cout << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." << std::endl; +int CaloStatusSkimmer::End(PHCompositeNode *topNode) { + std::cout + << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." + << std::endl; std::cout << "Total events processed: " << n_eventcounter << std::endl; std::cout << "Total events skimmed: " << n_skimcounter << std::endl; - std::cout << "Total events with missing tower nodes: " << n_notowernodecounter << std::endl; + std::cout << "Total events with missing tower nodes: " << n_notowernodecounter + << std::endl; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 965a42abe2..5126fefa05 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -5,76 +5,78 @@ #include -#include #include -#include #include +#include +#include class PHCompositeNode; -class CaloStatusSkimmer : public SubsysReco -{ +class CaloStatusSkimmer : public SubsysReco { public: - CaloStatusSkimmer(const std::string &name = "CaloStatusSkimmer"); - - ~CaloStatusSkimmer() override; - - /** Called during initialization. - Typically this is where you can book histograms, and e.g. - register them to Fun4AllServer (so they can be output to file - using Fun4AllServer::dumpHistos() method). - */ - int Init(PHCompositeNode *topNode) override; - - /** Called for each event. - This is where you do the real work. - */ - int process_event(PHCompositeNode *topNode) override; - - /// Called at the end of all processing. - int End(PHCompositeNode *topNode) override; - - void do_skim_EMCal(bool do_skim, uint16_t threshold) - { - b_do_skim_EMCal = do_skim; - m_EMC_skim_threshold = threshold; - } - - void do_skim_HCal(bool do_skim, uint16_t threshold) - { - b_do_skim_HCal = do_skim; - m_HCal_skim_threshold = threshold; - } - - void do_skim_sEPD(bool do_skim, uint16_t threshold) - { - b_do_skim_sEPD = do_skim; - m_sEPD_skim_threshold = threshold; - } - - void do_skim_ZDC(bool do_skim, uint16_t threshold) - { - b_do_skim_ZDC = do_skim; - m_ZDC_skim_threshold = threshold; - } + CaloStatusSkimmer(const std::string &name = "CaloStatusSkimmer"); -private: + ~CaloStatusSkimmer() override; - uint32_t n_eventcounter{0}; - uint32_t n_skimcounter{0}; - uint32_t n_notowernodecounter{0}; + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; - bool b_do_skim_EMCal{false}; - uint16_t m_EMC_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in EMCal + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; - bool b_do_skim_HCal{false}; - uint16_t m_HCal_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in HCal + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; - bool b_do_skim_sEPD{false}; - uint16_t m_sEPD_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in sEPD + void do_skim_EMCal(bool do_skim, uint16_t threshold) { + b_do_skim_EMCal = do_skim; + m_EMC_skim_threshold = threshold; + } - bool b_do_skim_ZDC{false}; - uint16_t m_ZDC_skim_threshold{192}; // skim if nchannels >= this many not-instrumented(empty/missing pckt) channels in ZDC + void do_skim_HCal(bool do_skim, uint16_t threshold) { + b_do_skim_HCal = do_skim; + m_HCal_skim_threshold = threshold; + } + + void do_skim_sEPD(bool do_skim, uint16_t threshold) { + b_do_skim_sEPD = do_skim; + m_sEPD_skim_threshold = threshold; + } + + void do_skim_ZDC(bool do_skim, uint16_t threshold) { + b_do_skim_ZDC = do_skim; + m_ZDC_skim_threshold = threshold; + } + +private: + uint32_t n_eventcounter{0}; + uint32_t n_skimcounter{0}; + uint32_t n_notowernodecounter{0}; + + bool b_do_skim_EMCal{false}; + uint16_t m_EMC_skim_threshold{ + 192}; // skim if nchannels >= this many not-instrumented(empty/missing + // pckt) channels in EMCal + + bool b_do_skim_HCal{false}; + uint16_t m_HCal_skim_threshold{ + 192}; // skim if nchannels >= this many not-instrumented(empty/missing + // pckt) channels in HCal + + bool b_do_skim_sEPD{false}; + uint16_t m_sEPD_skim_threshold{ + 192}; // skim if nchannels >= this many not-instrumented(empty/missing + // pckt) channels in sEPD + + bool b_do_skim_ZDC{false}; + uint16_t m_ZDC_skim_threshold{ + 192}; // skim if nchannels >= this many not-instrumented(empty/missing + // pckt) channels in ZDC }; #endif // CALOSTATUSSKIMMER_H From 008a0128e539b7b359faee88b9910ccc12d875c0 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 19 Feb 2026 08:16:57 -0500 Subject: [PATCH 252/866] clag-tidy fixes --- .../tpccalib/TpcCentralMembraneMatching.cc | 30 +++++++++++++++---- .../packages/tpccalib/TpcLaminationFitting.cc | 5 +++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index ec488c9d68..e790bb2b1d 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -2351,8 +2351,14 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) } */ m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal,RVal)); - if(!m_phiHist_in_rad) m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); - else m_dcc_out->m_hDPint[s]->SetBinContent(i, j, gr_dPhi[s]->Interpolate(phiVal,RVal)); + if(!m_phiHist_in_rad) + { + m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); + } + else + { + m_dcc_out->m_hDPint[s]->SetBinContent(i, j, gr_dPhi[s]->Interpolate(phiVal,RVal)); + } } } } @@ -2661,15 +2667,27 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) if(den > 0.0) { m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, num_dR / den); - if(!m_phiHist_in_rad) m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); - else m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, num_dPhi / den); + if(!m_phiHist_in_rad) + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); + } + else + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, num_dPhi / den); + } } } else { m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, gr_dR_toInterp[s]->Interpolate(phiVal,RVal)); - if(!m_phiHist_in_rad) m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); - else m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + if(!m_phiHist_in_rad) + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + } + else + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + } } } } diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 617e9a9387..290a1ab052 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -754,7 +754,10 @@ int TpcLaminationFitting::InterpolatePhiDistortions() m_fLamination[l][s]->SetParameter(3, 0.0); } double phiDistortion = m_fLamination[l][s]->Integral(phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i), phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1)) / (phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1) - phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i)); - if(!m_phiHist_in_rad) phiDistortion *= R; + if(!m_phiHist_in_rad) + { + phiDistortion *= R; + } if(m_fieldOff) { m_fLamination[l][s]->SetParameter(1, m_laminationIdeal[l][s]); From 3ec981b446c4f4fa72961f82f2344102f4802caa Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 19 Feb 2026 10:37:48 -0500 Subject: [PATCH 253/866] Added toggle to save all lamination fitting histograms to file if desired. Will be off by default, but allows for more in-depth QA --- .../packages/tpccalib/TpcLaminationFitting.cc | 47 ++++++++++++------- .../packages/tpccalib/TpcLaminationFitting.h | 3 ++ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 290a1ab052..68cea6f83d 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -412,22 +412,22 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) { for (int l = 0; l < 18; l++) { - double shift = m_laminationIdeal[l][side]; + double shift = m_laminationIdeal[l][side]; - double phi2pi = tmp_pos.Phi(); - if (side && phi2pi < -0.2) - { - phi2pi += 2 * M_PI; - } - if (!side && phi2pi < M_PI / 18 - 0.2) - { - phi2pi += 2 * M_PI; - } + double phi2pi = tmp_pos.Phi(); + if (side && phi2pi < -0.2) + { + phi2pi += 2 * M_PI; + } + if (!side && phi2pi < M_PI / 18 - 0.2) + { + phi2pi += 2 * M_PI; + } - if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) - { - m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi); - } + if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) + { + m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi); + } } } @@ -1211,9 +1211,22 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } m_laminationTree->Write(); - m_hLamination[13][0]->Write(); - m_hLamination[13][1]->Write(); - m_hLamination[14][1]->Write(); + if(m_saveAllLaminationHistograms) + { + for(int s=0; s<2; s++) + { + for(int l=0; l<18; l++) + { + m_hLamination[l][s]->Write(); + } + } + } + else + { + m_hLamination[13][0]->Write(); + m_hLamination[13][1]->Write(); + m_hLamination[14][1]->Write(); + } outputfile->Close(); diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index d9aeddf75e..5285dff0d2 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -52,6 +52,8 @@ class TpcLaminationFitting : public SubsysReco void set_phiHistInRad(bool rad){ m_phiHist_in_rad = rad; } + void set_saveAllLaminationHistograms(bool save){ m_saveAllLaminationHistograms = save; } + void set_fieldOff(bool fieldOff){ m_fieldOff = fieldOff; } void set_grid_dimensions(int phibins, int rbins); @@ -124,6 +126,7 @@ class TpcLaminationFitting : public SubsysReco //std::map m_run_ZDC_map_auau; bool m_phiHist_in_rad{true}; + bool m_saveAllLaminationHistograms{false}; std::string m_stripePatternFile = "/sphenix/u/bkimelman/CMStripePattern.root"; From 0eafbd462cbe1aed06c1c6619a51fd2aaae12b8f Mon Sep 17 00:00:00 2001 From: bkimelman Date: Thu, 19 Feb 2026 10:59:49 -0500 Subject: [PATCH 254/866] Changed to range-based loop --- offline/packages/tpccalib/TpcLaminationFitting.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 68cea6f83d..9e1eda849d 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -1213,11 +1213,11 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) if(m_saveAllLaminationHistograms) { - for(int s=0; s<2; s++) + for(auto &i : m_hLamination) { - for(int l=0; l<18; l++) + for(auto &j : i) { - m_hLamination[l][s]->Write(); + j->Write(); } } } From fedd13a53561f7ba72f33c291020892b9f8c5721 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 19 Feb 2026 18:51:08 -0500 Subject: [PATCH 255/866] add back the channel skip This was causing an out of bounds error --- offline/packages/CaloReco/CaloTowerBuilder.cc | 7 ++++--- offline/packages/CaloReco/CaloTowerBuilder.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 2584302138..6fb4fe9e40 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -273,6 +273,9 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, if (nchannels == 0) // push back -1 and return for empty packets { for (int channel = 0; channel < m_nchannels; channel++) { + if (skipChannel(channel, pid)) { + continue; + } std::vector waveform; waveform.reserve(m_nzerosuppsamples); for (int samp = 0; samp < m_nzerosuppsamples; samp++) { @@ -435,9 +438,7 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { } int n_samples = waveforms.at(idx).size(); if (n_samples == m_nzerosuppsamples || SZS) { - if (waveforms.at(idx).at(0) == - -1) // set bit for missing and empty packets. - { + if (waveforms.at(idx).at(0) == -1) { towerinfo->set_isNotInstr(true); } else { towerinfo->set_isZS(true); diff --git a/offline/packages/CaloReco/CaloTowerBuilder.h b/offline/packages/CaloReco/CaloTowerBuilder.h index 0fc5694638..c3b0bd2e8c 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.h +++ b/offline/packages/CaloReco/CaloTowerBuilder.h @@ -20,7 +20,7 @@ class TowerInfoContainerv3; class CaloTowerBuilder : public SubsysReco { - public: +public: explicit CaloTowerBuilder(const std::string &name = "CaloTowerBuilder"); ~CaloTowerBuilder() override; @@ -129,7 +129,7 @@ class CaloTowerBuilder : public SubsysReco CaloWaveformProcessing *get_WaveformProcessing() { return WaveformProcessing; } - private: +private: int process_sim(); bool skipChannel(int ich, int pid); static bool isSZS(float time, float chi2); From 459341aa68a6b19ed17cd3b65ff393e0a8c5a2b3 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 19 Feb 2026 20:41:52 -0500 Subject: [PATCH 256/866] one more attempt at fixing formatting.... --- offline/packages/CaloReco/CaloTowerBuilder.cc | 462 +++++++++++------- 1 file changed, 286 insertions(+), 176 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 6fb4fe9e40..53f44d9cb8 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -14,17 +14,17 @@ #include #include -#include // for SubsysReco +#include // for SubsysReco #include #include -#include // for PHIODataNode -#include // for PHNode -#include // for PHNodeIterator -#include // for PHObject +#include // for PHIODataNode +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject #include -#include // for CDBTTree +#include // for CDBTTree #include @@ -35,10 +35,10 @@ #include #include -#include // for operator<<, endl, basic... -#include // for allocator_traits<>::val... +#include // for operator<<, endl, basic... +#include // for allocator_traits<>::val... #include -#include // for vector +#include // for vector static const std::map nodemap{ {CaloTowerDefs::CEMC, "CEMCPackets"}, @@ -48,43 +48,50 @@ static const std::map nodemap{ {CaloTowerDefs::SEPD, "SEPDPackets"}}; //____________________________________________________________________________.. CaloTowerBuilder::CaloTowerBuilder(const std::string &name) - : SubsysReco(name), WaveformProcessing(new CaloWaveformProcessing()) {} + : SubsysReco(name) + , WaveformProcessing(new CaloWaveformProcessing()) +{ +} //____________________________________________________________________________.. -CaloTowerBuilder::~CaloTowerBuilder() { +CaloTowerBuilder::~CaloTowerBuilder() +{ delete cdbttree; delete cdbttree_tbt_zs; delete WaveformProcessing; } //____________________________________________________________________________.. -int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { +int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) +{ WaveformProcessing->set_processing_type(_processingtype); - WaveformProcessing->set_softwarezerosuppression(m_bdosoftwarezerosuppression, - m_nsoftwarezerosuppression); - if (m_setTimeLim) { + WaveformProcessing->set_softwarezerosuppression(m_bdosoftwarezerosuppression, m_nsoftwarezerosuppression); + if (m_setTimeLim) + { WaveformProcessing->set_timeFitLim(m_timeLim_low, m_timeLim_high); } - if (m_dobitfliprecovery) { + if (m_dobitfliprecovery) + { WaveformProcessing->set_bitFlipRecovery(m_dobitfliprecovery); } // Set functional fit parameters - if (_processingtype == CaloWaveformProcessing::FUNCFIT) { + if (_processingtype == CaloWaveformProcessing::FUNCFIT) + { WaveformProcessing->set_funcfit_type(m_funcfit_type); WaveformProcessing->set_powerlaw_params(m_powerlaw_power, m_powerlaw_decay); - WaveformProcessing->set_doubleexp_params( - m_doubleexp_power, m_doubleexp_peaktime1, m_doubleexp_peaktime2, - m_doubleexp_ratio); + WaveformProcessing->set_doubleexp_params(m_doubleexp_power, m_doubleexp_peaktime1, m_doubleexp_peaktime2, m_doubleexp_ratio); } - if (m_dettype == CaloTowerDefs::CEMC) { + if (m_dettype == CaloTowerDefs::CEMC) + { m_detector = "CEMC"; m_packet_low = 6001; m_packet_high = 6128; m_nchannels = 192; WaveformProcessing->set_template_name("CEMC_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) { + if (_processingtype == CaloWaveformProcessing::NONE) + { WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); } @@ -97,41 +104,47 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { m_fieldname = "adcskipmask"; calibdir = CDBInterface::instance()->getUrl(m_calibName); - if (calibdir.empty()) { - std::cout << PHWHERE - << "ADC Skip mask not found in CDB, not even in the default... " - << std::endl; + if (calibdir.empty()) + { + std::cout << PHWHERE << "ADC Skip mask not found in CDB, not even in the default... " << std::endl; exit(1); } cdbttree = new CDBTTree(calibdir); - } else if (m_dettype == CaloTowerDefs::HCALIN) { + } + else if (m_dettype == CaloTowerDefs::HCALIN) + { m_packet_low = 7001; m_packet_high = 7008; m_detector = "HCALIN"; m_nchannels = 192; WaveformProcessing->set_template_name("IHCAL_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) { + if (_processingtype == CaloWaveformProcessing::NONE) + { WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); } - } else if (m_dettype == CaloTowerDefs::HCALOUT) { + } + else if (m_dettype == CaloTowerDefs::HCALOUT) + { m_detector = "HCALOUT"; m_packet_low = 8001; m_packet_high = 8008; m_nchannels = 192; WaveformProcessing->set_template_name("OHCAL_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) { + if (_processingtype == CaloWaveformProcessing::NONE) + { WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); } - } else if (m_dettype == CaloTowerDefs::SEPD) { + } + else if (m_dettype == CaloTowerDefs::SEPD) + { m_detector = "SEPD"; m_packet_low = 9001; m_packet_high = 9006; m_nchannels = 128; WaveformProcessing->set_template_name("SEPD_TEMPLATE"); - if (_processingtype == CaloWaveformProcessing::NONE) { - WaveformProcessing->set_processing_type( - CaloWaveformProcessing::TEMPLATE); // default the EPD to fast - // processing + if (_processingtype == CaloWaveformProcessing::NONE) + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::TEMPLATE); // default the EPD to fast processing } m_calibName = "SEPD_CHANNELMAP2"; @@ -139,25 +152,28 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { calibdir = CDBInterface::instance()->getUrl(m_calibName); - if (calibdir.empty()) { - std::cout << PHWHERE << "No sEPD mapping file for domain " << m_calibName - << " found" << std::endl; + if (calibdir.empty()) + { + std::cout << PHWHERE << "No sEPD mapping file for domain " << m_calibName << " found" << std::endl; exit(1); } cdbttree_sepd_map = new CDBTTree(calibdir); - } else if (m_dettype == CaloTowerDefs::ZDC) { + } + else if (m_dettype == CaloTowerDefs::ZDC) + { m_detector = "ZDC"; m_packet_low = 12001; m_packet_high = 12001; m_nchannels = 128; - if (_processingtype == CaloWaveformProcessing::NONE) { - WaveformProcessing->set_processing_type( - CaloWaveformProcessing::FAST); // default the ZDC to fast processing + if (_processingtype == CaloWaveformProcessing::NONE) + { + WaveformProcessing->set_processing_type(CaloWaveformProcessing::FAST); // default the ZDC to fast processing } } WaveformProcessing->initialize_processing(); - if (m_dotbtszs) { + if (m_dotbtszs) + { cdbttree_tbt_zs = new CDBTTree(m_zsURL); } @@ -165,30 +181,36 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) { return Fun4AllReturnCodes::EVENT_OK; } -int CaloTowerBuilder::process_sim() { +int CaloTowerBuilder::process_sim() +{ std::vector> waveforms; - for (int ich = 0; ich < (int)m_CalowaveformContainer->size(); ich++) { + for (int ich = 0; ich < (int) m_CalowaveformContainer->size(); ich++) + { TowerInfo *towerinfo = m_CalowaveformContainer->get_tower_at_channel(ich); std::vector waveform; waveform.reserve(m_nsamples); bool fillwaveform = true; // get key - if (m_dotbtszs) { + if (m_dotbtszs) + { unsigned int key = m_CalowaveformContainer->encode_key(ich); int zs_threshold = cdbttree_tbt_zs->GetIntValue(key, m_zs_fieldname); int pre = towerinfo->get_waveform_value(0); // this is always safe since towerinfo v3 has 31 samples int post = towerinfo->get_waveform_value(6); - if ((post - pre) <= zs_threshold) { + if ((post - pre) <= zs_threshold) + { // zero suppressed fillwaveform = false; waveform.push_back(pre); waveform.push_back(post); } } - if (fillwaveform) { - for (int samp = 0; samp < m_nsamples; samp++) { + if (fillwaveform) + { + for (int samp = 0; samp < m_nsamples; samp++) + { waveform.push_back(towerinfo->get_waveform_value(samp)); } } @@ -196,10 +218,10 @@ int CaloTowerBuilder::process_sim() { waveform.clear(); } - std::vector> processed_waveforms = - WaveformProcessing->process_waveform(waveforms); + std::vector> processed_waveforms = WaveformProcessing->process_waveform(waveforms); int n_channels = processed_waveforms.size(); - for (int i = 0; i < n_channels; i++) { + for (int i = 0; i < n_channels; i++) + { // this is for copying the truth info to the downstream object TowerInfo *towerwaveform = m_CalowaveformContainer->get_tower_at_channel(i); TowerInfo *towerinfo = m_CaloInfoContainer->get_tower_at_channel(i); @@ -209,20 +231,25 @@ int CaloTowerBuilder::process_sim() { towerinfo->set_time(processed_waveforms.at(i).at(1)); towerinfo->set_pedestal(processed_waveforms.at(i).at(2)); towerinfo->set_chi2(processed_waveforms.at(i).at(3)); - bool SZS = - isSZS(processed_waveforms.at(i).at(1), processed_waveforms.at(i).at(3)); - if (processed_waveforms.at(i).at(4) == 0) { + bool SZS = isSZS(processed_waveforms.at(i).at(1), processed_waveforms.at(i).at(3)); + if (processed_waveforms.at(i).at(4) == 0) + { towerinfo->set_isRecovered(false); - } else { + } + else + { towerinfo->set_isRecovered(true); } int n_samples = waveforms.at(i).size(); - if (n_samples == m_nzerosuppsamples || SZS) { + if (n_samples == m_nzerosuppsamples || SZS) + { towerinfo->set_isZS(true); } - for (int j = 0; j < n_samples; j++) { + for (int j = 0; j < n_samples; j++) + { towerinfo->set_waveform_value(j, waveforms.at(i).at(j)); - if (std::round(waveforms.at(i).at(j)) >= m_saturation) { + if (std::round(waveforms.at(i).at(j)) >= m_saturation) + { towerinfo->set_isSaturated(true); } } @@ -232,53 +259,66 @@ int CaloTowerBuilder::process_sim() { return Fun4AllReturnCodes::EVENT_OK; } -int CaloTowerBuilder::process_data(PHCompositeNode *topNode, - std::vector> &waveforms) { +int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vector> &waveforms) +{ std::variant event; - if (m_UseOfflinePacketFlag) { - CaloPacketContainer *calopacketcontainer = - findNode::getClass( - topNode, nodemap.find(m_dettype)->second); - if (!calopacketcontainer) { - for (int pid = m_packet_low; pid <= m_packet_high; pid++) { - if (findNode::getClass(topNode, pid)) { + if (m_UseOfflinePacketFlag) + { + CaloPacketContainer *calopacketcontainer = findNode::getClass(topNode, nodemap.find(m_dettype)->second); + if (!calopacketcontainer) + { + for (int pid = m_packet_low; pid <= m_packet_high; pid++) + { + if (findNode::getClass(topNode, pid)) + { m_PacketNodesFlag = true; break; } } - if (!m_PacketNodesFlag) { + if (!m_PacketNodesFlag) + { return Fun4AllReturnCodes::EVENT_OK; } - } else { + } + else + { event = calopacketcontainer; } - } else { + } + else + { Event *_event = findNode::getClass(topNode, "PRDF"); - if (_event == nullptr) { + if (_event == nullptr) + { std::cout << PHWHERE << " Event not found" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - if (_event->getEvtType() != DATAEVENT) { + if (_event->getEvtType() != DATAEVENT) + { return Fun4AllReturnCodes::ABORTEVENT; } event = _event; } - // since the function call on Packet and CaloPacket is the same, maybe we can - // use lambda? - auto process_packet = [&](auto *packet, int pid) { - if (packet) { + // since the function call on Packet and CaloPacket is the same, maybe we can use lambda? + auto process_packet = [&](auto *packet, int pid) + { + if (packet) + { int nchannels = packet->iValue(0, "CHANNELS"); unsigned int adc_skip_mask = 0; - if (nchannels == 0) // push back -1 and return for empty packets + if (nchannels == 0) // push back -1 and return for empty packets { - for (int channel = 0; channel < m_nchannels; channel++) { - if (skipChannel(channel, pid)) { + for (int channel = 0; channel < m_nchannels; channel++) + { + if (skipChannel(channel, pid)) + { continue; } std::vector waveform; waveform.reserve(m_nzerosuppsamples); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) { + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { waveform.push_back(-1); } waveforms.push_back(waveform); @@ -286,33 +326,41 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, return Fun4AllReturnCodes::EVENT_OK; } - if (m_dettype == CaloTowerDefs::CEMC) { + if (m_dettype == CaloTowerDefs::CEMC) + { adc_skip_mask = cdbttree->GetIntValue(pid, m_fieldname); } - if (m_dettype == CaloTowerDefs::ZDC) { + if (m_dettype == CaloTowerDefs::ZDC) + { nchannels = m_nchannels; } - if (nchannels > - m_nchannels) // packet is corrupted and reports too many channels + if (nchannels > m_nchannels) // packet is corrupted and reports too many channels { return Fun4AllReturnCodes::ABORTEVENT; } int n_pad_skip_mask = 0; - for (int channel = 0; channel < nchannels; channel++) { - if (skipChannel(channel, pid)) { + for (int channel = 0; channel < nchannels; channel++) + { + if (skipChannel(channel, pid)) + { continue; } - if (m_dettype == CaloTowerDefs::CEMC) { - if (channel % 64 == 0) { - unsigned int adcboard = (unsigned int)channel / 64; - if ((adc_skip_mask >> adcboard) & 0x1U) { - for (int iskip = 0; iskip < 64; iskip++) { + if (m_dettype == CaloTowerDefs::CEMC) + { + if (channel % 64 == 0) + { + unsigned int adcboard = (unsigned int) channel / 64; + if ((adc_skip_mask >> adcboard) & 0x1U) + { + for (int iskip = 0; iskip < 64; iskip++) + { n_pad_skip_mask++; std::vector waveform; waveform.reserve(m_nsamples); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) { + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { waveform.push_back(0); } waveforms.push_back(waveform); @@ -324,11 +372,15 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vector waveform; waveform.reserve(m_nsamples); - if (packet->iValue(channel, "SUPPRESSED")) { + if (packet->iValue(channel, "SUPPRESSED")) + { waveform.push_back(packet->iValue(channel, "PRE")); waveform.push_back(packet->iValue(channel, "POST")); - } else { - for (int samp = 0; samp < m_nsamples; samp++) { + } + else + { + for (int samp = 0; samp < m_nsamples; samp++) + { waveform.push_back(packet->iValue(samp, channel)); } } @@ -337,35 +389,43 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, } int nch_padded = nchannels; - if (m_dettype == CaloTowerDefs::CEMC) { + if (m_dettype == CaloTowerDefs::CEMC) + { nch_padded += n_pad_skip_mask; } - if (nch_padded < m_nchannels) { - for (int channel = 0; channel < m_nchannels - nch_padded; channel++) { - if (skipChannel(channel, pid)) { + if (nch_padded < m_nchannels) + { + for (int channel = 0; channel < m_nchannels - nch_padded; channel++) + { + if (skipChannel(channel, pid)) + { continue; } std::vector waveform; waveform.reserve(m_nsamples); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) { + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { waveform.push_back(0); } waveforms.push_back(waveform); waveform.clear(); } } - } else // if the packet is missing treat constitutent channels as zero - // suppressed + } + else // if the packet is missing treat constitutent channels as zero suppressed { - for (int channel = 0; channel < m_nchannels; channel++) { - if (skipChannel(channel, pid)) { + for (int channel = 0; channel < m_nchannels; channel++) + { + if (skipChannel(channel, pid)) + { continue; } std::vector waveform; waveform.reserve(2); - for (int samp = 0; samp < m_nzerosuppsamples; samp++) { - waveform.push_back(-1); // push back -1 for missing packets + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { + waveform.push_back(-1); // push back -1 for missing packets } waveforms.push_back(waveform); waveform.clear(); @@ -374,23 +434,32 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, return Fun4AllReturnCodes::EVENT_OK; }; - for (int pid = m_packet_low; pid <= m_packet_high; pid++) { - if (!m_PacketNodesFlag) { - if (auto *hcalcont = std::get_if(&event)) { + for (int pid = m_packet_low; pid <= m_packet_high; pid++) + { + if (!m_PacketNodesFlag) + { + if (auto *hcalcont = std::get_if(&event)) + { CaloPacket *packet = (*hcalcont)->getPacketbyId(pid); - if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) { + if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) + { return Fun4AllReturnCodes::ABORTEVENT; } - } else if (auto *_event = std::get_if(&event)) { + } + else if (auto *_event = std::get_if(&event)) + { Packet *packet = (*_event)->getPacket(pid); - if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) { + if (process_packet(packet, pid) == Fun4AllReturnCodes::ABORTEVENT) + { // I think it is safe to delete a nullptr... delete packet; return Fun4AllReturnCodes::ABORTEVENT; } delete packet; } - } else { + } + else + { CaloPacket *calopacket = findNode::getClass(topNode, pid); process_packet(calopacket, pid); } @@ -399,27 +468,32 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, return Fun4AllReturnCodes::EVENT_OK; } //____________________________________________________________________________.. -int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { - if (!m_isdata) { +int CaloTowerBuilder::process_event(PHCompositeNode *topNode) +{ + if (!m_isdata) + { return process_sim(); } std::vector> waveforms; - if (process_data(topNode, waveforms) == Fun4AllReturnCodes::ABORTEVENT) { + if (process_data(topNode, waveforms) == Fun4AllReturnCodes::ABORTEVENT) + { return Fun4AllReturnCodes::ABORTEVENT; } - if (waveforms.empty()) { + if (waveforms.empty()) + { return Fun4AllReturnCodes::EVENT_OK; } - // waveform vector is filled here, now fill our output. methods from the base - // class make sure we only fill what the chosen container version supports - std::vector> processed_waveforms = - WaveformProcessing->process_waveform(waveforms); + // waveform vector is filled here, now fill our output. methods from the base class make sure + // we only fill what the chosen container version supports + std::vector> processed_waveforms = WaveformProcessing->process_waveform(waveforms); int n_channels = processed_waveforms.size(); - for (int i = 0; i < n_channels; i++) { + for (int i = 0; i < n_channels; i++) + { int idx = i; // Align sEPD ADC channels to TowerInfoContainer - if (m_dettype == CaloTowerDefs::SEPD) { + if (m_dettype == CaloTowerDefs::SEPD) + { idx = cdbttree_sepd_map->GetIntValue(i, m_fieldname); } TowerInfo *towerinfo = m_CaloInfoContainer->get_tower_at_channel(i); @@ -428,25 +502,33 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { towerinfo->set_time(processed_waveforms.at(idx).at(1)); towerinfo->set_pedestal(processed_waveforms.at(idx).at(2)); towerinfo->set_chi2(processed_waveforms.at(idx).at(3)); - bool SZS = isSZS(processed_waveforms.at(idx).at(1), - processed_waveforms.at(idx).at(3)); + bool SZS = isSZS(processed_waveforms.at(idx).at(1), processed_waveforms.at(idx).at(3)); - if (processed_waveforms.at(idx).at(4) == 0) { + if (processed_waveforms.at(idx).at(4) == 0) + { towerinfo->set_isRecovered(false); - } else { + } + else + { towerinfo->set_isRecovered(true); } int n_samples = waveforms.at(idx).size(); - if (n_samples == m_nzerosuppsamples || SZS) { - if (waveforms.at(idx).at(0) == -1) { + if (n_samples == m_nzerosuppsamples || SZS) + { + if (waveforms.at(idx).at(0) == 0) + { towerinfo->set_isNotInstr(true); - } else { + } + else + { towerinfo->set_isZS(true); } } - for (int j = 0; j < n_samples; j++) { - if (std::round(waveforms.at(idx).at(j)) >= m_saturation) { + for (int j = 0; j < n_samples; j++) + { + if (std::round(waveforms.at(idx).at(j)) >= m_saturation) + { towerinfo->set_isSaturated(true); } towerinfo->set_waveform_value(j, waveforms.at(idx).at(j)); @@ -457,23 +539,30 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { return Fun4AllReturnCodes::EVENT_OK; } -bool CaloTowerBuilder::skipChannel(int ich, int pid) { - if (m_dettype == CaloTowerDefs::SEPD) { +bool CaloTowerBuilder::skipChannel(int ich, int pid) +{ + if (m_dettype == CaloTowerDefs::SEPD) + { int sector = ((ich + 1) / 32); int emptych = -999; - if ((sector == 0) && (pid == 9001)) { + if ((sector == 0) && (pid == 9001)) + { emptych = 1; - } else { + } + else + { emptych = 14 + 32 * sector; } - if (ich == emptych) { + if (ich == emptych) + { return true; } } - if (m_dettype == CaloTowerDefs::ZDC) { - if (((ich > 17) && (ich < 48)) || ((ich > 63) && (ich < 80)) || - ((ich > 81) && (ich < 112))) { + if (m_dettype == CaloTowerDefs::ZDC) + { + if (((ich > 17) && (ich < 48)) || ((ich > 63) && (ich < 80)) || ((ich > 81) && (ich < 112))) + { return true; } } @@ -481,31 +570,34 @@ bool CaloTowerBuilder::skipChannel(int ich, int pid) { return false; } -bool CaloTowerBuilder::isSZS(float time, float chi2) { +bool CaloTowerBuilder::isSZS(float time, float chi2) +{ // isfinite - if (!std::isfinite(time) && !std::isfinite(chi2)) { + if (!std::isfinite(time) && !std::isfinite(chi2)) + { return true; } return false; } -void CaloTowerBuilder::CreateNodeTree(PHCompositeNode *topNode) { +void CaloTowerBuilder::CreateNodeTree(PHCompositeNode *topNode) +{ PHNodeIterator topNodeItr(topNode); // DST node - PHCompositeNode *dstNode = dynamic_cast( - topNodeItr.findFirst("PHCompositeNode", "DST")); - if (!dstNode) { + PHCompositeNode *dstNode = dynamic_cast(topNodeItr.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { std::cout << "PHComposite node created: DST" << std::endl; dstNode = new PHCompositeNode("DST"); topNode->addNode(dstNode); } - if (!m_isdata) { + if (!m_isdata) + { std::string waveformNodeName = m_inputNodePrefix + m_detector; - m_CalowaveformContainer = - findNode::getClass(topNode, waveformNodeName); - if (!m_CalowaveformContainer) { - std::cout << PHWHERE << "simulation waveform container " - << waveformNodeName << " not found" << std::endl; + m_CalowaveformContainer = findNode::getClass(topNode, waveformNodeName); + if (!m_CalowaveformContainer) + { + std::cout << PHWHERE << "simulation waveform container " << waveformNodeName << " not found" << std::endl; gSystem->Exit(1); exit(1); } @@ -514,55 +606,73 @@ void CaloTowerBuilder::CreateNodeTree(PHCompositeNode *topNode) { // towers PHNodeIterator nodeItr(dstNode); PHCompositeNode *DetNode; - // enum CaloTowerDefs::DetectorSystem and TowerInfoContainer::DETECTOR are - // different!!!! - TowerInfoContainer::DETECTOR DetectorEnum = - TowerInfoContainer::DETECTOR::DETECTOR_INVALID; + // enum CaloTowerDefs::DetectorSystem and TowerInfoContainer::DETECTOR are different!!!! + TowerInfoContainer::DETECTOR DetectorEnum = TowerInfoContainer::DETECTOR::DETECTOR_INVALID; std::string DetectorNodeName; - if (m_dettype == CaloTowerDefs::CEMC) { + if (m_dettype == CaloTowerDefs::CEMC) + { DetectorEnum = TowerInfoContainer::DETECTOR::EMCAL; DetectorNodeName = "CEMC"; - } else if (m_dettype == CaloTowerDefs::SEPD) { + } + else if (m_dettype == CaloTowerDefs::SEPD) + { DetectorEnum = TowerInfoContainer::DETECTOR::SEPD; DetectorNodeName = "SEPD"; - } else if (m_dettype == CaloTowerDefs::ZDC) { + } + else if (m_dettype == CaloTowerDefs::ZDC) + { DetectorEnum = TowerInfoContainer::DETECTOR::ZDC; DetectorNodeName = "ZDC"; - } else if (m_dettype == CaloTowerDefs::HCALIN) { + } + else if (m_dettype == CaloTowerDefs::HCALIN) + { DetectorEnum = TowerInfoContainer::DETECTOR::HCAL; DetectorNodeName = "HCALIN"; - } else if (m_dettype == CaloTowerDefs::HCALOUT) { + } + else if (m_dettype == CaloTowerDefs::HCALOUT) + { DetectorEnum = TowerInfoContainer::DETECTOR::HCAL; DetectorNodeName = "HCALOUT"; - } else { + } + else + { std::cout << PHWHERE << " Invalid detector type " << m_dettype << std::endl; gSystem->Exit(1); exit(1); } - DetNode = dynamic_cast( - nodeItr.findFirst("PHCompositeNode", DetectorNodeName)); - if (!DetNode) { + DetNode = dynamic_cast(nodeItr.findFirst("PHCompositeNode", DetectorNodeName)); + if (!DetNode) + { DetNode = new PHCompositeNode(DetectorNodeName); dstNode->addNode(DetNode); } - if (m_buildertype == CaloTowerDefs::kPRDFTowerv1) { + if (m_buildertype == CaloTowerDefs::kPRDFTowerv1) + { m_CaloInfoContainer = new TowerInfoContainerv1(DetectorEnum); - } else if (m_buildertype == CaloTowerDefs::kPRDFWaveform) { + } + else if (m_buildertype == CaloTowerDefs::kPRDFWaveform) + { m_CaloInfoContainer = new TowerInfoContainerv3(DetectorEnum); - } else if (m_buildertype == CaloTowerDefs::kWaveformTowerv2) { + } + else if (m_buildertype == CaloTowerDefs::kWaveformTowerv2) + { m_CaloInfoContainer = new TowerInfoContainerv2(DetectorEnum); - } else if (m_buildertype == CaloTowerDefs::kPRDFTowerv4) { + } + else if (m_buildertype == CaloTowerDefs::kPRDFTowerv4) + { m_CaloInfoContainer = new TowerInfoContainerv4(DetectorEnum); - } else if (m_buildertype == CaloTowerDefs::kWaveformTowerSimv1) { + } + else if (m_buildertype == CaloTowerDefs::kWaveformTowerSimv1) + { m_CaloInfoContainer = new TowerInfoContainerSimv1(DetectorEnum); - } else { - std::cout << PHWHERE << "invalid builder type " << m_buildertype - << std::endl; + } + else + { + std::cout << PHWHERE << "invalid builder type " << m_buildertype << std::endl; gSystem->Exit(1); exit(1); } TowerNodeName = m_outputNodePrefix + m_detector; - PHIODataNode *newTowerNode = new PHIODataNode( - m_CaloInfoContainer, TowerNodeName, "PHObject"); + PHIODataNode *newTowerNode = new PHIODataNode(m_CaloInfoContainer, TowerNodeName, "PHObject"); DetNode->addNode(newTowerNode); } From 376ab122970fc626cc30942a2346c2113e665e67 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 19 Feb 2026 20:51:55 -0500 Subject: [PATCH 257/866] add verbosity to skimmer, and fix comments/formatting --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 146 +++++++++++------- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 3 + 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 5011e2ff44..f2771a64fe 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -32,137 +32,175 @@ //____________________________________________________________________________.. CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) - : SubsysReco(name) { + : SubsysReco(name) +{ n_eventcounter = 0; n_skimcounter = 0; n_notowernodecounter = 0; - std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) " - "Calling ctor" - << std::endl; + std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; } //____________________________________________________________________________.. -CaloStatusSkimmer::~CaloStatusSkimmer() { +CaloStatusSkimmer::~CaloStatusSkimmer() +{ // std::cout << "CaloStatusSkimmer::~CaloStatusSkimmer() Calling dtor" << // std::endl; } //____________________________________________________________________________.. -int CaloStatusSkimmer::Init(PHCompositeNode *topNode) { - std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) Initializing" - << std::endl; +int CaloStatusSkimmer::Init(PHCompositeNode *topNode) +{ + std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) Initializing" << std::endl; return Fun4AllReturnCodes::EVENT_OK; } //____________________________________________________________________________.. -int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { +int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) +{ n_eventcounter++; - if (b_do_skim_EMCal) { + if (b_do_skim_EMCal) + { TowerInfoContainer *towers = findNode::getClass(topNode, "TOWERS_CEMC"); - if (!towers) { + if (!towers) + { n_notowernodecounter++; - std::cout << PHWHERE - << "calostatuscheck::process_event: missing TOWERS_CEMC\n"; + if (Verbosity > 0) + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_CEMC" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } const UInt_t ntowers = towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) { + for (UInt_t ch = 0; ch < ntowers; ++ch) + { TowerInfo *tower = towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) { + if (tower->get_isNotInstr()) + { ++notinstr_count; } } - if (notinstr_count >= m_EMC_skim_threshold) { + if (Verbosity > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in EMCal = " << ntowers << ", not-instrumented(empty/missing pckt) towers in EMCal = " << notinstr_count << std::endl; + } + + if (notinstr_count >= m_EMC_skim_threshold) + { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } } - if (b_do_skim_HCal) { - TowerInfoContainer *hcalin_towers = - findNode::getClass(topNode, "TOWERS_HCALIN"); - TowerInfoContainer *hcalout_towers = - findNode::getClass(topNode, "TOWERS_HCALOUT"); - if (!hcalin_towers || !hcalout_towers) { + if (b_do_skim_HCal) + { + TowerInfoContainer *hcalin_towers = findNode::getClass(topNode, "TOWERS_HCALIN"); + TowerInfoContainer *hcalout_towers = findNode::getClass(topNode, "TOWERS_HCALOUT"); + if (!hcalin_towers || !hcalout_towers) + { n_notowernodecounter++; - std::cout << PHWHERE - << "calostatuscheck::process_event: missing TOWERS_HCALIN or " - "TOWERS_HCALOUT\n"; - return Fun4AllReturnCodes:: - ABORTEVENT; // do I want ABORTPROCESSING or just ABORTEVENT here? - // ABORTPROCESSING will stop the entire job, while - // ABORTEVENT will just skip this event and continue with - // the next one. + if (Verbosity > 0) + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; } const UInt_t ntowers_hcalin = hcalin_towers->size(); uint16_t notinstr_count_hcalin = 0; - for (UInt_t ch = 0; ch < ntowers_hcalin; ++ch) { + for (UInt_t ch = 0; ch < ntowers_hcalin; ++ch) + { TowerInfo *tower_in = hcalin_towers->get_tower_at_channel(ch); - if (tower_in->get_isNotInstr()) { + if (tower_in->get_isNotInstr()) + { ++notinstr_count_hcalin; } } const UInt_t ntowers_hcalout = hcalout_towers->size(); uint16_t notinstr_count_hcalout = 0; - for (UInt_t ch = 0; ch < ntowers_hcalout; ++ch) { + for (UInt_t ch = 0; ch < ntowers_hcalout; ++ch) + { TowerInfo *tower_out = hcalout_towers->get_tower_at_channel(ch); - if (tower_out->get_isNotInstr()) { + if (tower_out->get_isNotInstr()) + { ++notinstr_count_hcalout; } } + if (Verbosity > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in HCalIn = " << ntowers_hcalin << ", not-instrumented(empty/missing pckt) towers in HCalIn = " << notinstr_count_hcalin << ", ntowers in HCalOut = " << ntowers_hcalout << ", not-instrumented(empty/missing pckt) towers in HCalOut = " << notinstr_count_hcalout << std::endl; + } + if (notinstr_count_hcalin >= m_HCal_skim_threshold || - notinstr_count_hcalout >= m_HCal_skim_threshold) { + notinstr_count_hcalout >= m_HCal_skim_threshold) + { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } } - if (b_do_skim_sEPD) { + if (b_do_skim_sEPD) + { TowerInfoContainer *sepd_towers = findNode::getClass(topNode, "TOWERS_SEPD"); - if (!sepd_towers) { + if (!sepd_towers) + { n_notowernodecounter++; - std::cout << PHWHERE - << "calostatuscheck::process_event: missing TOWERS_SEPD\n"; + if (Verbosity > 0) + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_SEPD" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } const UInt_t ntowers = sepd_towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) { + for (UInt_t ch = 0; ch < ntowers; ++ch) + { TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) { + if (tower->get_isNotInstr()) + { ++notinstr_count; } } - if (notinstr_count >= m_sEPD_skim_threshold) { + + if (Verbosity > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_count << std::endl; + } + + if (notinstr_count >= m_sEPD_skim_threshold) + { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } } - if (b_do_skim_ZDC) { + if (b_do_skim_ZDC) + { TowerInfoContainer *zdc_towers = findNode::getClass(topNode, "TOWERS_ZDC"); - if (!zdc_towers) { + if (!zdc_towers) + { n_notowernodecounter++; - std::cout << PHWHERE - << "calostatuscheck::process_event: missing TOWERS_ZDC\n"; + if (Verbosity > 0) + std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_ZDC" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } const UInt_t ntowers = zdc_towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) { + for (UInt_t ch = 0; ch < ntowers; ++ch) + { TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) { + if (tower->get_isNotInstr()) + { ++notinstr_count; } } - if (notinstr_count >= m_ZDC_skim_threshold) { + + if (Verbosity > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_count << std::endl; + } + + if (notinstr_count >= m_ZDC_skim_threshold) + { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; } @@ -172,14 +210,12 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { } //____________________________________________________________________________.. -int CaloStatusSkimmer::End(PHCompositeNode *topNode) { - std::cout - << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." - << std::endl; +int CaloStatusSkimmer::End(PHCompositeNode *topNode) +{ + std::cout << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." << std::endl; std::cout << "Total events processed: " << n_eventcounter << std::endl; std::cout << "Total events skimmed: " << n_skimcounter << std::endl; - std::cout << "Total events with missing tower nodes: " << n_notowernodecounter - << std::endl; + std::cout << "Total events with missing tower nodes: " << n_notowernodecounter << std::endl; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 5126fefa05..cb1adc6d78 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -53,10 +53,13 @@ class CaloStatusSkimmer : public SubsysReco { m_ZDC_skim_threshold = threshold; } + void SetVerbosity(uint8_t v) { Verbosity = v; } + private: uint32_t n_eventcounter{0}; uint32_t n_skimcounter{0}; uint32_t n_notowernodecounter{0}; + uint8_t Verbosity{0}; bool b_do_skim_EMCal{false}; uint16_t m_EMC_skim_threshold{ From 24b72924c10831b2af6e2bf915628c8b5fa94100 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 19 Feb 2026 21:11:47 -0500 Subject: [PATCH 258/866] code rabbit fixes remove includes fix revert of not instrument flag -should be if == -1, or <0, but I changed it back to ==0 when fixing the formatting. Use official verbosity method. --- offline/packages/CaloReco/CaloTowerBuilder.cc | 2 +- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 36 +++++-------------- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 3 -- 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 53f44d9cb8..5082b9e9c3 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -515,7 +515,7 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) int n_samples = waveforms.at(idx).size(); if (n_samples == m_nzerosuppsamples || SZS) { - if (waveforms.at(idx).at(0) == 0) + if (waveforms.at(idx).at(0) == -1) { towerinfo->set_isNotInstr(true); } diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index f2771a64fe..2b44734247 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -1,34 +1,16 @@ #include "CaloStatusSkimmer.h" #include -#include #include #include #include -// Tower stuff -#include #include -// #include #include -#include - -// ROOT stuff -#include -#include -#include -#include -#include - -// for cluster vertex correction -#include -#include -#include + #include #include -#include -#include //____________________________________________________________________________.. CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) @@ -65,7 +47,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) if (!towers) { n_notowernodecounter++; - if (Verbosity > 0) + if (Verbosity() > 0) std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_CEMC" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -79,7 +61,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) ++notinstr_count; } } - if (Verbosity > 9) + if (Verbosity() > 9) { std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in EMCal = " << ntowers << ", not-instrumented(empty/missing pckt) towers in EMCal = " << notinstr_count << std::endl; } @@ -98,7 +80,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) if (!hcalin_towers || !hcalout_towers) { n_notowernodecounter++; - if (Verbosity > 0) + if (Verbosity() > 0) std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -125,7 +107,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } - if (Verbosity > 9) + if (Verbosity() > 9) { std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in HCalIn = " << ntowers_hcalin << ", not-instrumented(empty/missing pckt) towers in HCalIn = " << notinstr_count_hcalin << ", ntowers in HCalOut = " << ntowers_hcalout << ", not-instrumented(empty/missing pckt) towers in HCalOut = " << notinstr_count_hcalout << std::endl; } @@ -145,7 +127,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) if (!sepd_towers) { n_notowernodecounter++; - if (Verbosity > 0) + if (Verbosity() > 0) std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_SEPD" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -160,7 +142,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } - if (Verbosity > 9) + if (Verbosity() > 9) { std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_count << std::endl; } @@ -179,7 +161,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) if (!zdc_towers) { n_notowernodecounter++; - if (Verbosity > 0) + if (Verbosity() > 0) std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_ZDC" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -194,7 +176,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } - if (Verbosity > 9) + if (Verbosity() > 9) { std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_count << std::endl; } diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index cb1adc6d78..5126fefa05 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -53,13 +53,10 @@ class CaloStatusSkimmer : public SubsysReco { m_ZDC_skim_threshold = threshold; } - void SetVerbosity(uint8_t v) { Verbosity = v; } - private: uint32_t n_eventcounter{0}; uint32_t n_skimcounter{0}; uint32_t n_notowernodecounter{0}; - uint8_t Verbosity{0}; bool b_do_skim_EMCal{false}; uint16_t m_EMC_skim_threshold{ From ce1451066fc308f9d8872a78e4ebdebf89c46578 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 20 Feb 2026 06:29:25 -0500 Subject: [PATCH 259/866] clang-tidy --- offline/packages/trackbase_historic/TrackAnalysisUtils.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index cacbab9aec..d9331a0cd6 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -22,7 +22,7 @@ namespace TrackAnalysisUtils float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, - float thickness_per_region[4]) + const float thickness_per_region[4]) { std::vector clusterKeys; clusterKeys.insert(clusterKeys.end(), tpcseed->begin_cluster_keys(), @@ -99,7 +99,7 @@ namespace TrackAnalysisUtils float calc_dedx_calib(SvtxTrack* track, TrkrClusterContainer* cluster_map, ActsGeometry* tgeometry, - float thickness_per_region[4]) + const float thickness_per_region[4]) { auto clusterKeys = get_cluster_keys(track->get_tpc_seed()); @@ -141,7 +141,7 @@ namespace TrackAnalysisUtils float adc = cluster->getAdc(); float r = std::sqrt(cglob(0) * cglob(0) + cglob(1) * cglob(1)); - auto tpcseed = track->get_tpc_seed(); + auto *tpcseed = track->get_tpc_seed(); float alpha = (r * r) / (2 * r * std::abs(1.0 / tpcseed->get_qOverR())); float beta = std::atan(tpcseed->get_slope()); float alphacorr = std::cos(alpha); From 3a04b62b11a9a8f9d5f5bbac7461fd062c950861 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 20 Feb 2026 06:29:49 -0500 Subject: [PATCH 260/866] clang-format --- offline/packages/trackbase_historic/TrackAnalysisUtils.cc | 2 +- offline/packages/trackbase_historic/TrackAnalysisUtils.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index d9331a0cd6..a31a3b8efb 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -141,7 +141,7 @@ namespace TrackAnalysisUtils float adc = cluster->getAdc(); float r = std::sqrt(cglob(0) * cglob(0) + cglob(1) * cglob(1)); - auto *tpcseed = track->get_tpc_seed(); + auto* tpcseed = track->get_tpc_seed(); float alpha = (r * r) / (2 * r * std::abs(1.0 / tpcseed->get_qOverR())); float beta = std::atan(tpcseed->get_slope()); float alphacorr = std::cos(alpha); diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index 00cca752f7..a0cc429f07 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -31,9 +31,9 @@ namespace TrackAnalysisUtils // to pass these from the geometry object, which keeps the dependencies // of this helper class minimal. This will also help us catch any changes // when/if the tpc geometry changes in the future. This is to get us going - float thickness_per_region[4]); + const float thickness_per_region[4]); float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, - float thickness_per_region[4]); + const float thickness_per_region[4]); std::pair get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, TrkrClusterContainer* clustermap, From ecddd62c08e23cb45a76caf175a5a72ffdeb7a84 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 20 Feb 2026 14:05:30 -0500 Subject: [PATCH 261/866] When disabling Micromegas clusters from fit, use acts to propagate the track parameters to any TPOT surface for which a cluster was found at the seeding stage. This is similar to the extrapolation performed to TPC layers in distortion-targeted Silicon-MM fit. This will allow to obtain unbiased residuals in the Micromegas. --- offline/packages/trackreco/PHActsTrkFitter.cc | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index d361af240a..69e6f2dea5 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1169,6 +1169,40 @@ void PHActsTrkFitter::updateSvtxTrack( } } + // also propagate to Micromegas if not used for the fit + /* this is be used to get unbiased residuals in TPOT */ + if ((!m_useMicromegas) && 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) + { + const auto& cluskey = *key_iter; + + // make sure cluster is from Micromegas (TPOT) + const auto detId = TrkrDefs::getTrkrId(cluskey); + if (detId != TrkrDefs::micromegasId) + { continue; } + + // get corresponding surface + const auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); + const auto surface = m_tGeometry->maps().getMMSurface(hitsetkey); + + // get layer, propagate + auto result = propagator.propagateTrack(params, surface); + if (!result.ok()) { continue; } + + // get path length and extrapolated parameters + auto& [pathLength, trackStateParams] = result.value(); + pathLength /= Acts::UnitConstants::cm; + + // create track state and add to track + transformer.addTrackState(track, cluskey, pathLength, trackStateParams, m_transient_geocontext); + } + } + trackStateTimer.stop(); auto stateTime = trackStateTimer.get_accumulated_time(); From 46fc8ad4f56d70641dc0808c60346c53cee8cea3 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 20 Feb 2026 15:13:25 -0500 Subject: [PATCH 262/866] use our standard compiler flags --- .../framework/fun4all/CreateSubsysRecoModule.pl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/offline/framework/fun4all/CreateSubsysRecoModule.pl b/offline/framework/fun4all/CreateSubsysRecoModule.pl index 51f64ea25c..7cd7095893 100755 --- a/offline/framework/fun4all/CreateSubsysRecoModule.pl +++ b/offline/framework/fun4all/CreateSubsysRecoModule.pl @@ -138,6 +138,8 @@ () print F "// void $classname\:\:Print(const std::string &what) const\n"; print F "// Called from the command line - useful to print information when you need it\n"; print F "//\n"; + print F "// [[maybe_unused]] suppresses compiler warnings if topNode is not used in this method\n"; + print F "//\n"; print F "//____________________________________________________________________________..\n"; print F "\n"; @@ -166,7 +168,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:Init(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:Init([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:Init(PHCompositeNode *topNode) Initializing\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -174,7 +176,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:InitRun(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:InitRun([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:InitRun(PHCompositeNode *topNode) Initializing for Run XXX\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -182,7 +184,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:process_event(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:process_event([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:process_event(PHCompositeNode *topNode) Processing Event\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -190,7 +192,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:ResetEvent(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:ResetEvent([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -206,7 +208,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:End(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:End([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:End(PHCompositeNode *topNode) This is the End...\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -214,7 +216,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:Reset(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:Reset([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:Reset(PHCompositeNode *topNode) being Reset\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -331,7 +333,7 @@ () print F "dnl no point in suppressing warnings people should \n"; print F "dnl at least see them, so here we go for g++: -Wall\n"; print F "if test \$ac_cv_prog_gxx = yes; then\n"; - print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Werror\"\n"; + print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Wextra -Wshadow -Werror\"\n"; print F "fi\n"; print F "\n"; From bd14497a9ad33636f81acb75b764b03f57672df8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 20 Feb 2026 15:18:53 -0500 Subject: [PATCH 263/866] use our standard compiler flags --- simulation/g4simulation/g4detectors/CreateG4Subsystem.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl b/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl index f74af6957d..ccb34eca34 100755 --- a/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl +++ b/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl @@ -1007,7 +1007,7 @@ () print F "dnl no point in suppressing warnings people should \n"; print F "dnl at least see them, so here we go for g++: -Wall\n"; print F "if test \$ac_cv_prog_gxx = yes; then\n"; - print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Werror\"\n"; + print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Wextra -Wshadow -Werror\"\n"; print F "fi\n"; print F "\n"; From 739117ba21196b50eaeeb76da00655fe311646be Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 20 Feb 2026 15:20:32 -0500 Subject: [PATCH 264/866] use -isystem instead of -I for include paths --- simulation/g4simulation/g4detectors/CreateG4Subsystem.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl b/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl index ccb34eca34..a1dbd352c3 100755 --- a/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl +++ b/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl @@ -1027,8 +1027,8 @@ () print F "AM_CPPFLAGS = \\\n"; print F " -I\$(includedir) \\\n"; - print F " -I\$(OFFLINE_MAIN)/include \\\n"; - print F " -I\$(ROOTSYS)/include \n"; + print F " -isystem\$(OFFLINE_MAIN)/include \\\n"; + print F " -isystem\$(ROOTSYS)/include \n"; print F "\n"; print F "AM_LDFLAGS = \\\n"; From bf4806d4c90c1ee9fbcd873c047d9fc4a65a3466 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 20 Feb 2026 15:22:23 -0500 Subject: [PATCH 265/866] use -isystem instead of -I for include paths --- offline/framework/fun4all/CreateSubsysRecoModule.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4all/CreateSubsysRecoModule.pl b/offline/framework/fun4all/CreateSubsysRecoModule.pl index 7cd7095893..f46c37053d 100755 --- a/offline/framework/fun4all/CreateSubsysRecoModule.pl +++ b/offline/framework/fun4all/CreateSubsysRecoModule.pl @@ -350,7 +350,7 @@ () print F "AM_CPPFLAGS = \\\n"; print F " -I\$(includedir) \\\n"; - print F " -I\$(OFFLINE_MAIN)/include \\\n"; + print F " -isystem\$(OFFLINE_MAIN)/include \\\n"; print F " -isystem\$(ROOTSYS)/include\n"; print F "\n"; From a139a428cc24a66a70ec0cd6af78ed4adebc6c04 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 20 Feb 2026 14:12:34 -0700 Subject: [PATCH 266/866] Update offline/packages/trackreco/PHActsTrkFitter.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/trackreco/PHActsTrkFitter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 69e6f2dea5..fc09c56067 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1189,6 +1189,7 @@ void PHActsTrkFitter::updateSvtxTrack( // get corresponding surface const auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); const auto surface = m_tGeometry->maps().getMMSurface(hitsetkey); + if (!surface) { continue; } // get layer, propagate auto result = propagator.propagateTrack(params, surface); From 2a43e6fc6d96893849cf96ab73756649282bb705 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 20 Feb 2026 16:22:56 -0500 Subject: [PATCH 267/866] make it compile --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 36 ++++++------------- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 9 +---- .../Skimmers/CaloStatusSkimmer/autogen.sh | 0 3 files changed, 12 insertions(+), 33 deletions(-) mode change 100644 => 100755 offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 2b44734247..08b3ae34a6 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -22,20 +22,6 @@ CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; } -//____________________________________________________________________________.. -CaloStatusSkimmer::~CaloStatusSkimmer() -{ - // std::cout << "CaloStatusSkimmer::~CaloStatusSkimmer() Calling dtor" << - // std::endl; -} - -//____________________________________________________________________________.. -int CaloStatusSkimmer::Init(PHCompositeNode *topNode) -{ - std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) Initializing" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - //____________________________________________________________________________.. int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { @@ -51,9 +37,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_CEMC" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - const UInt_t ntowers = towers->size(); + const uint32_t ntowers = towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) + for (uint32_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = towers->get_tower_at_channel(ch); if (tower->get_isNotInstr()) @@ -85,9 +71,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - const UInt_t ntowers_hcalin = hcalin_towers->size(); + const uint32_t ntowers_hcalin = hcalin_towers->size(); uint16_t notinstr_count_hcalin = 0; - for (UInt_t ch = 0; ch < ntowers_hcalin; ++ch) + for (uint32_t ch = 0; ch < ntowers_hcalin; ++ch) { TowerInfo *tower_in = hcalin_towers->get_tower_at_channel(ch); if (tower_in->get_isNotInstr()) @@ -96,9 +82,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } - const UInt_t ntowers_hcalout = hcalout_towers->size(); + const uint32_t ntowers_hcalout = hcalout_towers->size(); uint16_t notinstr_count_hcalout = 0; - for (UInt_t ch = 0; ch < ntowers_hcalout; ++ch) + for (uint32_t ch = 0; ch < ntowers_hcalout; ++ch) { TowerInfo *tower_out = hcalout_towers->get_tower_at_channel(ch); if (tower_out->get_isNotInstr()) @@ -131,9 +117,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_SEPD" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - const UInt_t ntowers = sepd_towers->size(); + const uint32_t ntowers = sepd_towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) + for (uint32_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); if (tower->get_isNotInstr()) @@ -165,9 +151,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_ZDC" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - const UInt_t ntowers = zdc_towers->size(); + const uint32_t ntowers = zdc_towers->size(); uint16_t notinstr_count = 0; - for (UInt_t ch = 0; ch < ntowers; ++ch) + for (uint32_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); if (tower->get_isNotInstr()) @@ -192,7 +178,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } //____________________________________________________________________________.. -int CaloStatusSkimmer::End(PHCompositeNode *topNode) +int CaloStatusSkimmer::End([[maybe_unused]] PHCompositeNode *topNode) { std::cout << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." << std::endl; std::cout << "Total events processed: " << n_eventcounter << std::endl; diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 5126fefa05..628a582917 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -16,14 +16,7 @@ class CaloStatusSkimmer : public SubsysReco { public: CaloStatusSkimmer(const std::string &name = "CaloStatusSkimmer"); - ~CaloStatusSkimmer() override; - - /** Called during initialization. - Typically this is where you can book histograms, and e.g. - register them to Fun4AllServer (so they can be output to file - using Fun4AllServer::dumpHistos() method). - */ - int Init(PHCompositeNode *topNode) override; + ~CaloStatusSkimmer() override = default; /** Called for each event. This is where you do the real work. diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh b/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh old mode 100644 new mode 100755 From ecb09d33dabd8940bd92bb8fb8aca6a5787e4fbc Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 20 Feb 2026 17:55:29 -0500 Subject: [PATCH 268/866] fixed comments --- offline/packages/trackreco/PHActsTrkFitter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index fc09c56067..d0006ac25c 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1191,7 +1191,7 @@ void PHActsTrkFitter::updateSvtxTrack( const auto surface = m_tGeometry->maps().getMMSurface(hitsetkey); if (!surface) { continue; } - // get layer, propagate + // propagate auto result = propagator.propagateTrack(params, surface); if (!result.ok()) { continue; } From 3e526f3ee6612c5d75b72a0c1ffff6f1b92f36c0 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 20 Feb 2026 17:55:32 -0500 Subject: [PATCH 269/866] clang-tidy --- .../trackbase_historic/TrackAnalysisUtils.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 744949c8fe..eee8283b61 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -18,7 +18,7 @@ namespace TrackAnalysisUtils float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, - float thickness_per_region[4]) + float const thickness_per_region[4]) { std::vector clusterKeys; clusterKeys.insert(clusterKeys.end(), tpcseed->begin_cluster_keys(), @@ -95,10 +95,10 @@ namespace TrackAnalysisUtils float calc_dedx_calib(SvtxTrack* track, TrkrClusterContainer* cluster_map, ActsGeometry* tgeometry, - float thickness_per_region[4]) + float const thickness_per_region[4]) { auto clusterKeys = get_cluster_keys(track->get_tpc_seed()); - + std::vector dedxlist; for (unsigned long cluster_key : clusterKeys) { @@ -137,7 +137,7 @@ namespace TrackAnalysisUtils float adc = cluster->getAdc(); float r = std::sqrt(cglob(0) * cglob(0) + cglob(1) * cglob(1)); - auto tpcseed = track->get_tpc_seed(); + auto* tpcseed = track->get_tpc_seed(); float alpha = (r * r) / (2 * r * std::abs(1.0 / tpcseed->get_qOverR())); float beta = std::atan(tpcseed->get_slope()); float alphacorr = std::cos(alpha); @@ -152,8 +152,8 @@ namespace TrackAnalysisUtils } if(track->get_crossing() < SHRT_MAX) { - double z_crossing_corrected = - TpcClusterZCrossingCorrection::correctZ(cglob.z(), + double z_crossing_corrected = + TpcClusterZCrossingCorrection::correctZ(cglob.z(), TpcDefs::getSide(cluster_key), track->get_crossing()); double maxz = tgeometry->get_max_driftlength() + tgeometry->get_CM_halfwidth(); @@ -201,7 +201,7 @@ namespace TrackAnalysisUtils vertexCov(i, j) = vertex->get_error(i, j); } } - + Acts::ActsSquareMatrix<3> rotCov = rot * (posCov+vertexCov) * rot_T; dca.first.second = sqrt(rotCov(0, 0)); @@ -274,12 +274,12 @@ namespace TrackAnalysisUtils std::vector get_cluster_keys(TrackSeed* seed) { std::vector out; - + if (seed) { std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out)); } - + return out; } From 7dcddfcdc133399bbaf7f8a0ca7b849a8cf7b488 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 21 Feb 2026 14:08:31 -0500 Subject: [PATCH 270/866] small cosmetic changes --- .../sepd_eventplanecalib/EventPlaneData.cc | 2 + .../sepd_eventplanecalib/EventPlaneData.h | 1 - .../sepd/sepd_eventplanecalib/QVecCalib.cc | 108 +++++++++--------- .../sepd/sepd_eventplanecalib/QVecCalib.h | 22 ++-- .../sepd/sepd_eventplanecalib/QVecDefs.h | 6 +- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 35 +++--- .../sepd/sepd_eventplanecalib/sEPD_TreeGen.h | 21 +--- 7 files changed, 92 insertions(+), 103 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc index 6dedea4a15..57c3fcfc58 100644 --- a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc @@ -1,5 +1,7 @@ #include "EventPlaneData.h" +#include + EventPlaneData::EventPlaneData() { sepd_charge.fill(0); diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h index 255f488712..d9ffea19c9 100644 --- a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h @@ -6,7 +6,6 @@ #include #include -#include #include class EventPlaneData : public PHObject diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index 4a1c9d7e51..83e0b80489 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -23,6 +23,12 @@ // -- CDBTTree #include +#include +#include +#include +#include + + // ==================================================================== // Standard C++ Includes // ==================================================================== @@ -34,16 +40,19 @@ QVecCalib::QVecCalib(const std::string &name): SubsysReco(name) { - std::cout << "QVecCalib::QVecCalib(const std::string &name) Calling ctor" << std::endl; + // std::cout << "QVecCalib::QVecCalib(const std::string &name) Calling ctor" << std::endl; } //____________________________________________________________________________.. int QVecCalib::Init([[maybe_unused]] PHCompositeNode *topNode) { - std::cout << "QVecCalib::Init(PHCompositeNode *topNode) Initializing" << std::endl; + if (Verbosity() > 1) + { + std::cout << "QVecCalib::Init(PHCompositeNode *topNode) Initializing" << std::endl; - Fun4AllServer *se = Fun4AllServer::instance(); - se->Print("NODETREE"); + Fun4AllServer *se = Fun4AllServer::instance(); + se->Print("NODETREE"); + } int ret = process_QA_hist(); if (ret) @@ -122,7 +131,8 @@ int QVecCalib::process_sEPD_event_thresholds(TFile* file) std::string sepd_totalcharge_centrality = "h2SEPD_totalcharge_centrality"; - auto* hist = file->Get(sepd_totalcharge_centrality.c_str()); + TH2 *hist {nullptr}; + file->GetObject(sepd_totalcharge_centrality.c_str(),hist); // Check if the hist is stored in the file if (hist == nullptr) @@ -189,7 +199,8 @@ int QVecCalib::process_bad_channels(TFile* file) std::string sepd_charge_hist = "hSEPD_Charge"; - auto* hSEPD_Charge = file->Get(sepd_charge_hist.c_str()); + TProfile *hSEPD_Charge{nullptr}; + file->GetObject(sepd_charge_hist.c_str(), hSEPD_Charge); // Check if the hist is stored in the file if (hSEPD_Charge == nullptr) @@ -229,14 +240,6 @@ int QVecCalib::process_bad_channels(TFile* file) se->registerHisto(h2SEPD_North_Charge_rbinv2); se->registerHisto(hSEPD_Bad_Channels); - auto* h2S = h2SEPD_South_Charge_rbin; - auto* h2N = h2SEPD_North_Charge_rbin; - - auto* h2Sv2 = h2SEPD_South_Charge_rbinv2; - auto* h2Nv2 = h2SEPD_North_Charge_rbinv2; - - auto* hBad = hSEPD_Bad_Channels; - for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) { unsigned int key = TowerInfoDefs::encode_epd(channel); @@ -245,13 +248,13 @@ int QVecCalib::process_bad_channels(TFile* file) double avg_charge = hSEPD_Charge->GetBinContent(channel + 1); - auto* h2 = (arm == 0) ? h2S : h2N; + auto* h2 = (arm == 0) ? h2SEPD_South_Charge_rbin : h2SEPD_North_Charge_rbin; h2->Fill(rbin, avg_charge); } - auto* hSpx = h2S->ProfileX("hSpx", 2, -1, "s"); - auto* hNpx = h2N->ProfileX("hNpx", 2, -1, "s"); + auto* hSpx = h2SEPD_South_Charge_rbin->ProfileX("hSpx", 2, -1, "s"); + auto* hNpx = h2SEPD_North_Charge_rbin->ProfileX("hNpx", 2, -1, "s"); int ctr_dead = 0; int ctr_hot = 0; @@ -263,7 +266,7 @@ int QVecCalib::process_bad_channels(TFile* file) int rbin = TowerInfoDefs::get_epd_rbin(key); unsigned int arm = TowerInfoDefs::get_epd_arm(key); - auto* h2 = (arm == 0) ? h2Sv2 : h2Nv2; + auto* h2 = (arm == 0) ? h2SEPD_South_Charge_rbinv2 : h2SEPD_North_Charge_rbinv2; auto* hprof = (arm == 0) ? hSpx : hNpx; double charge = hSEPD_Charge->GetBinContent(channel + 1); @@ -281,31 +284,31 @@ int QVecCalib::process_bad_channels(TFile* file) m_bad_channels.insert(channel); std::string type; - int status_fill; + QVecShared::ChannelStatus status_fill; // dead channel if (charge == 0) { type = "Dead"; - status_fill = static_cast(QVecShared::ChannelStatus::Dead); + status_fill = QVecShared::ChannelStatus::Dead; ++ctr_dead; } // hot channel else if (zscore > m_sEPD_sigma_threshold) { type = "Hot"; - status_fill = static_cast(QVecShared::ChannelStatus::Hot); + status_fill = QVecShared::ChannelStatus::Hot; ++ctr_hot; } // cold channel else { type = "Cold"; - status_fill = static_cast(QVecShared::ChannelStatus::Cold); + status_fill = QVecShared::ChannelStatus::Cold; ++ctr_cold; } - hBad->Fill(channel, status_fill); + hSEPD_Bad_Channels->Fill(channel, static_cast(status_fill)); std::cout << std::format("{:4} Channel: {:3d}, arm: {}, rbin: {:2d}, Mean: {:5.2f}, Charge: {:5.2f}, Z-Score: {:5.2f}", type, channel, arm, rbin, mean_charge, charge, zscore) << std::endl; } @@ -315,7 +318,8 @@ int QVecCalib::process_bad_channels(TFile* file) } } - std::cout << std::format("Total Bad Channels: {}, Dead: {}, Hot: {}, Cold: {}", m_bad_channels.size(), ctr_dead, ctr_hot, ctr_cold) << std::endl; + std::cout << "Total Bad Channels: " << m_bad_channels.size() << ", Dead: " + << ctr_dead << ", Hot: " << ctr_hot << ", Cold: " << ctr_cold << std::endl; std::cout << "Finished processing Hot sEPD channels" << std::endl; return Fun4AllReturnCodes::EVENT_OK; @@ -460,8 +464,9 @@ std::array, 2> QVecCalib::calculate_flattening_matrix(doub double N_term = D * (xx + yy + (2 * D)); if (N_term <= 0) { - throw std::runtime_error(std::format( - "Invalid N-term ({}) for n={}, cent={}, det={}", N_term, n, cent_bin, det_label)); + std::cout << "Invalid N-term (" << N_term << ") for n=" << n << ", cent=" << cent_bin + << ", det=" << det_label << std::endl; + exit(1); } double inv_sqrt_N = 1.0 / std::sqrt(N_term); @@ -475,10 +480,12 @@ std::array, 2> QVecCalib::calculate_flattening_matrix(doub template T* QVecCalib::load_and_clone(TFile* file, const std::string& name) { - auto* obj = file->Get(name.c_str()); + T *obj {nullptr}; + file->GetObject(name.c_str(),obj); if (!obj) { - throw std::runtime_error(std::format("Could not find histogram '{}' in file '{}'", name, file->GetName())); + std::cout << "Could not find histogram " << name << " in file " << file->GetName() << std::endl; + exit(1); } return static_cast(obj->Clone()); } @@ -494,8 +501,6 @@ int QVecCalib::load_correction_data() return Fun4AllReturnCodes::ABORTRUN; } - using SD = QVecShared::Subdetector; - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { int n = m_harmonics[h_idx]; @@ -544,7 +549,7 @@ int QVecCalib::load_correction_data() if (m_pass == Pass::ApplyFlattening) { // Populate Flattening for S, N, and NS - for (int d = 0; d < (int) SD::Count; ++d) + for (int d = 0; d < (int) QVecShared::Subdetector::Count; ++d) { std::string det_str; switch (d) @@ -822,7 +827,7 @@ void QVecCalib::process_averages(double cent, const QVecShared::QVec& q_S, const void QVecCalib::process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h) { - size_t cent_bin = static_cast(hCentrality->FindBin(cent) - 1); + int cent_bin = hCentrality->FindBin(cent) - 1; const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S]; const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N]; @@ -866,7 +871,7 @@ void QVecCalib::process_recentering(double cent, size_t h_idx, const QVecShared: void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h) { - size_t cent_bin = static_cast(hCentrality->FindBin(cent) - 1); + int cent_bin = hCentrality->FindBin(cent) - 1; const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S]; const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N]; @@ -1000,7 +1005,7 @@ bool QVecCalib::process_event_check() } //____________________________________________________________________________.. -int QVecCalib::process_event([[maybe_unused]] PHCompositeNode *topNode) +int QVecCalib::process_event(PHCompositeNode *topNode) { m_evtdata = findNode::getClass(topNode, "EventPlaneData"); if (!m_evtdata) @@ -1067,7 +1072,7 @@ int QVecCalib::process_event([[maybe_unused]] PHCompositeNode *topNode) } //____________________________________________________________________________.. -int QVecCalib::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) +int QVecCalib::ResetEvent(PHCompositeNode *) { m_q_vectors = {}; @@ -1083,15 +1088,15 @@ void QVecCalib::compute_averages(size_t cent_bin, int h_idx) std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); - int bin = static_cast(cent_bin + 1); + int bin = cent_bin + 1; double Q_S_x_avg = m_profiles[S_x_avg_name]->GetBinContent(bin); double Q_S_y_avg = m_profiles[S_y_avg_name]->GetBinContent(bin); double Q_N_x_avg = m_profiles[N_x_avg_name]->GetBinContent(bin); double Q_N_y_avg = m_profiles[N_y_avg_name]->GetBinContent(bin); - m_correction_data[cent_bin][h_idx][(size_t)QVecShared::Subdetector::S].avg_Q = {Q_S_x_avg, Q_S_y_avg}; - m_correction_data[cent_bin][h_idx][(size_t)QVecShared::Subdetector::N].avg_Q = {Q_N_x_avg, Q_N_y_avg}; + m_correction_data[cent_bin][h_idx][static_cast(QVecShared::Subdetector::S)].avg_Q = {Q_S_x_avg, Q_S_y_avg}; + m_correction_data[cent_bin][h_idx][static_cast(QVecShared::Subdetector::N)].avg_Q = {Q_N_x_avg, Q_N_y_avg}; std::cout << std::format( "Centrality Bin: {}, " @@ -1117,7 +1122,7 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr"); std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr"); - int bin = static_cast(cent_bin + 1); + int bin = cent_bin + 1; double Q_S_x_corr_avg = m_profiles[S_x_corr_avg_name]->GetBinContent(bin); double Q_S_y_corr_avg = m_profiles[S_y_corr_avg_name]->GetBinContent(bin); @@ -1148,7 +1153,7 @@ void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) double Q_NS_yy_avg = m_profiles[NS_yy_avg_name]->GetBinContent(bin); double Q_NS_xy_avg = m_profiles[NS_xy_avg_name]->GetBinContent(bin); - m_correction_data[cent_bin][h_idx][(size_t)QVecShared::Subdetector::NS].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); + m_correction_data[cent_bin][h_idx][static_cast(QVecShared::Subdetector::NS)].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); for (size_t det_idx = 0; det_idx < 2; ++det_idx) { @@ -1206,7 +1211,7 @@ void QVecCalib::print_flattening(size_t cent_bin, int n) const std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr"); std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr"); - int bin = static_cast(cent_bin + 1); + int bin = cent_bin + 1; double Q_S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name)->GetBinContent(bin); double Q_S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name)->GetBinContent(bin); @@ -1260,7 +1265,8 @@ void QVecCalib::write_cdb() } else if (ec) { - throw std::runtime_error(std::format("Failed to create directory {}: {}", m_cdb_output_dir, ec.message())); + std::cout << "Failed to create directory " << m_cdb_output_dir << ": " << ec.message() << std::endl; + exit(1); } else { @@ -1320,8 +1326,6 @@ void QVecCalib::write_cdb_EventPlane() CDBTTree cdbttree(output_file); - using SD = QVecShared::Subdetector; - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { int n = m_harmonics[h_idx]; @@ -1334,24 +1338,24 @@ void QVecCalib::write_cdb_EventPlane() for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) { - int key = static_cast(cent_bin); + int key = cent_bin; // Iterate through all subdetectors (S, N, NS) using the Enum Count - for (size_t d = 0; d < static_cast(SD::Count); ++d) + for (size_t d = 0; d < static_cast(QVecShared::Subdetector::Count); ++d) { - auto det_enum = static_cast(d); + auto det_enum = static_cast(d); // Map enum to the string labels used in the CDB field names std::string det_label; switch (det_enum) { - case SD::S: + case QVecShared::Subdetector::S: det_label = "S"; break; - case SD::N: + case QVecShared::Subdetector::N: det_label = "N"; break; - case SD::NS: + case QVecShared::Subdetector::NS: det_label = "NS"; break; default: @@ -1360,7 +1364,7 @@ void QVecCalib::write_cdb_EventPlane() const auto& data = m_correction_data[cent_bin][h_idx][d]; // 1st Order Moments (Recentering) - Skip for NS as it is a combined vector - if (det_enum != SD::NS) + if (det_enum != QVecShared::Subdetector::NS) { cdbttree.SetDoubleValue(key, field(det_label, "x"), data.avg_Q.x); cdbttree.SetDoubleValue(key, field(det_label, "y"), data.avg_Q.y); @@ -1381,7 +1385,7 @@ void QVecCalib::write_cdb_EventPlane() } //____________________________________________________________________________.. -int QVecCalib::End([[maybe_unused]] PHCompositeNode *topNode) +int QVecCalib::End(PHCompositeNode *) { std::cout << "QVecCalib::End(PHCompositeNode *topNode) This is the End..." << std::endl; diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index 5fceb0f47e..7f834273b2 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -1,24 +1,24 @@ -#ifndef QVECCALIB_H -#define QVECCALIB_H +#ifndef SEPDEVENTPLANECALIB_QVECCALIB_H +#define SEPDEVENTPLANECALIB_QVECCALIB_H #include "QVecDefs.h" #include +#include #include #include #include #include #include - -#include -#include -#include -#include +#include class PHCompositeNode; class EventPlaneData; -class EpdGeom; +class TFile; +class TH1; +class TH2; +class TProfile; /** * @class QVecCalib @@ -126,8 +126,8 @@ class QVecCalib : public SubsysReco static constexpr size_t m_cent_bins = QVecShared::CENT_BINS; static constexpr auto m_harmonics = QVecShared::HARMONICS; - static constexpr float SIGMA_HOT = 6.0F; - static constexpr float SIGMA_COLD = -6.0F; + static constexpr float SIGMA_HOT {6.0}; + static constexpr float SIGMA_COLD {-6.0}; double m_cent_low{-0.5}; double m_cent_high{79.5}; @@ -432,4 +432,4 @@ class QVecCalib : public SubsysReco void write_cdb_BadTowers(); }; -#endif // QVECCALIB_H +#endif // SEPDEVENTPLANECALIB_QVECCALIB_H diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h index 8b9e4ebcd7..656ec1dc8f 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -1,5 +1,5 @@ -#ifndef QVECDEFS_H -#define QVECDEFS_H +#ifndef SEPDEVENTPLANECALIB_QVECDEFS_H +#define SEPDEVENTPLANECALIB_QVECDEFS_H #include #include @@ -55,4 +55,4 @@ namespace QVecShared } } // namespace QVecShared -#endif // QVECDEFS_H +#endif // SEPDEVENTPLANECALIB_QVECDEFS_H diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index 5ce0e97a58..7f11a07255 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -2,10 +2,6 @@ #include "QVecDefs.h" #include "EventPlaneData.h" -// -- c++ -#include -#include - // -- Calo #include #include @@ -15,8 +11,8 @@ #include // -- MB -#include #include + #include // -- sEPD @@ -34,6 +30,14 @@ #include #include +// -- ROOT +#include +#include + +// -- c++ +#include +#include + //____________________________________________________________________________.. sEPD_TreeGen::sEPD_TreeGen(const std::string &name) : SubsysReco(name) @@ -44,8 +48,10 @@ sEPD_TreeGen::sEPD_TreeGen(const std::string &name) int sEPD_TreeGen::Init(PHCompositeNode *topNode) { Fun4AllServer *se = Fun4AllServer::instance(); - se->Print("NODETREE"); - + if (Verbosity() > 0) + { + se->Print("NODETREE"); + } unsigned int bins_sepd_totalcharge{100}; double sepd_totalcharge_low{0}; double sepd_totalcharge_high{2e4}; @@ -152,7 +158,7 @@ int sEPD_TreeGen::process_centrality(PHCompositeNode *topNode) double cent = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; - // skip event if centrality is too peripheral + // skip event if centrality is bad or too peripheral if (!std::isfinite(cent) || cent < 0 || cent >= m_cuts.m_cent_max) { if (Verbosity() > 1) @@ -333,18 +339,5 @@ int sEPD_TreeGen::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) m_data.event_id = -1; m_data.event_centrality = 9999; - // DST - if (m_evtdata) - { - m_evtdata->Reset(); - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int sEPD_TreeGen::End([[maybe_unused]] PHCompositeNode *topNode) -{ - std::cout << "sEPD_TreeGen::End" << std::endl; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h index 0c735cda36..2d777f4011 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h @@ -1,5 +1,5 @@ -#ifndef SEPD_TREEGEN_H -#define SEPD_TREEGEN_H +#ifndef SEPDEVENTPLANECALIB_SEPDTREEGEN_H +#define SEPDEVENTPLANECALIB_SEPDTREEGEN_H // -- sPHENIX #include @@ -7,12 +7,10 @@ // -- c++ #include -// -- ROOT -#include -#include - -class PHCompositeNode; class EventPlaneData; +class PHCompositeNode; +class TH2; +class TProfile; /** * @class sEPD_TreeGen @@ -54,13 +52,6 @@ class sEPD_TreeGen : public SubsysReco */ int ResetEvent(PHCompositeNode *topNode) override; - /** - * @brief Finalizes the module, writing all histograms and the TTree to disk. - * @param topNode Pointer to the node tree. - * @return Fun4All return code. - */ - int End(PHCompositeNode *topNode) override; - /** * @brief Prints the current state of the EventPlaneData object. * @param what Optional string to specify what to print (default "ALL"). @@ -144,4 +135,4 @@ class sEPD_TreeGen : public SubsysReco TH2 *h2SEPD_totalcharge_centrality{nullptr}; }; -#endif // SEPD_TREEGEN_H +#endif // SEPDEVENTPLANECALIB_SEPDTREEGEN_H From 7d79c3af890e7d39e914b0dc79af8c81fc163450 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 21 Feb 2026 15:07:30 -0500 Subject: [PATCH 271/866] fix clang-tidy --- calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index 83e0b80489..46c99354e1 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -1072,7 +1072,7 @@ int QVecCalib::process_event(PHCompositeNode *topNode) } //____________________________________________________________________________.. -int QVecCalib::ResetEvent(PHCompositeNode *) +int QVecCalib::ResetEvent(PHCompositeNode * /*topNode*/) { m_q_vectors = {}; @@ -1385,7 +1385,7 @@ void QVecCalib::write_cdb_EventPlane() } //____________________________________________________________________________.. -int QVecCalib::End(PHCompositeNode *) +int QVecCalib::End(PHCompositeNode * /*topNode*/) { std::cout << "QVecCalib::End(PHCompositeNode *topNode) This is the End..." << std::endl; From c93920c2356b49a5af3edc5479fb14d096b02ac6 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 21 Feb 2026 15:59:40 -0500 Subject: [PATCH 272/866] remove unused version includes --- offline/packages/CaloReco/CaloTowerStatus.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 954c0a2b3b..446a943531 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -3,10 +3,6 @@ #include // for TowerInfo #include -#include -#include -#include -#include #include // for CDBTTree From 9b361cd0bb73281192cfe75d9c6f2680005f7cb4 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 23 Feb 2026 09:02:27 -0500 Subject: [PATCH 273/866] return all residuals and let user look up from a struct --- .../trackbase_historic/TrackAnalysisUtils.cc | 20 +++++++++++++------ .../trackbase_historic/TrackAnalysisUtils.h | 10 ++++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index a31a3b8efb..e13601d462 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -299,10 +299,11 @@ namespace TrackAnalysisUtils return out; } - std::pair - get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, TrkrClusterContainer* clustermap, - PHCompositeNode* topNode) + TrackAnalysisUtils::TrackFitResiduals + get_residuals(SvtxTrack* track, TrkrClusterContainer* clustermap, + PHCompositeNode* topNode) { + TrackAnalysisUtils::TrackFitResiduals residuals; TpcGlobalPositionWrapper globalWrapper; globalWrapper.loadNodes(topNode); globalWrapper.set_suppressCrossing(true); @@ -310,9 +311,11 @@ namespace TrackAnalysisUtils auto* tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); mover.initialize_geometry(tpccellgeo); mover.set_verbosity(0); + auto* geometry = findNode::getClass(topNode, "ActsGeometry"); - auto* cluster = clustermap->findCluster(ckey); + std::vector> global_raw; + for (const auto& key : get_cluster_keys(track)) { auto* clus = clustermap->findCluster(key); @@ -325,6 +328,9 @@ namespace TrackAnalysisUtils auto global_moved = mover.processTrack(global_raw); + for(const auto& ckey : get_cluster_keys(track)) + { + auto *cluster = clustermap->findCluster(ckey); // loop over global vectors and get this cluster Acts::Vector3 clusglob(0, 0, 0); for (const auto& pair : global_raw) @@ -395,8 +401,10 @@ namespace TrackAnalysisUtils clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree Acts::Vector2 stateloc(state->get_localX(), state->get_localY()); Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); - - return std::make_pair(stateloc - loc, stateglob - clusglob_moved); + residuals.local_residuals[ckey] = stateloc - loc; + residuals.global_residuals[ckey] = stateglob - clusglob_moved; + } + return residuals; } } // namespace TrackAnalysisUtils diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index a0cc429f07..ef3acfcb0e 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -16,6 +16,12 @@ class TrkrClusterContainer; class GlobalVertex; namespace TrackAnalysisUtils { + +struct TrackFitResiduals { + std::map local_residuals; + std::map global_residuals; +}; + /// Returns DCA as .first and uncertainty on DCA as .second using DCA = std::pair; using DCAPair = std::pair; @@ -35,8 +41,8 @@ namespace TrackAnalysisUtils float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, const float thickness_per_region[4]); - std::pair - get_residual(TrkrDefs::cluskey& ckey, SvtxTrack* track, TrkrClusterContainer* clustermap, + TrackFitResiduals + get_residuals(SvtxTrack* track, TrkrClusterContainer* clustermap, PHCompositeNode* topNode); }; // namespace TrackAnalysisUtils From 0d62d2549025b833c6198a1da5b7a240e5c036a0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 23 Feb 2026 09:09:46 -0500 Subject: [PATCH 274/866] clang-format --- .../trackbase_historic/TrackAnalysisUtils.cc | 136 +++++++++--------- .../trackbase_historic/TrackAnalysisUtils.h | 11 +- 2 files changed, 74 insertions(+), 73 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index e13601d462..4e80918fb6 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -301,7 +301,7 @@ namespace TrackAnalysisUtils TrackAnalysisUtils::TrackFitResiduals get_residuals(SvtxTrack* track, TrkrClusterContainer* clustermap, - PHCompositeNode* topNode) + PHCompositeNode* topNode) { TrackAnalysisUtils::TrackFitResiduals residuals; TpcGlobalPositionWrapper globalWrapper; @@ -313,9 +313,9 @@ namespace TrackAnalysisUtils mover.set_verbosity(0); auto* geometry = findNode::getClass(topNode, "ActsGeometry"); - + std::vector> global_raw; - + for (const auto& key : get_cluster_keys(track)) { auto* clus = clustermap->findCluster(key); @@ -328,81 +328,81 @@ namespace TrackAnalysisUtils auto global_moved = mover.processTrack(global_raw); - for(const auto& ckey : get_cluster_keys(track)) + for (const auto& ckey : get_cluster_keys(track)) { - auto *cluster = clustermap->findCluster(ckey); - // loop over global vectors and get this cluster - Acts::Vector3 clusglob(0, 0, 0); - for (const auto& pair : global_raw) - { - auto thiskey = pair.first; - clusglob = pair.second; - if (thiskey == ckey) + auto* cluster = clustermap->findCluster(ckey); + // loop over global vectors and get this cluster + Acts::Vector3 clusglob(0, 0, 0); + for (const auto& pair : global_raw) { - break; + auto thiskey = pair.first; + clusglob = pair.second; + if (thiskey == ckey) + { + break; + } } - } - Acts::Vector3 clusglob_moved(0, 0, 0); - for (const auto& pair : global_moved) - { - auto thiskey = pair.first; - clusglob_moved = pair.second; - if (thiskey == ckey) + Acts::Vector3 clusglob_moved(0, 0, 0); + for (const auto& pair : global_moved) { - break; + auto thiskey = pair.first; + clusglob_moved = pair.second; + if (thiskey == ckey) + { + break; + } } - } - SvtxTrackState* state = nullptr; - for (auto state_iter = track->begin_states(); - state_iter != track->end_states(); - ++state_iter) - { - SvtxTrackState* tstate = state_iter->second; - auto stateckey = tstate->get_cluskey(); - if (stateckey == ckey) + SvtxTrackState* state = nullptr; + for (auto state_iter = track->begin_states(); + state_iter != track->end_states(); + ++state_iter) { - state = tstate; - break; + SvtxTrackState* tstate = state_iter->second; + auto stateckey = tstate->get_cluskey(); + if (stateckey == ckey) + { + state = tstate; + break; + } + } + Surface surf = geometry->maps().getSurface(ckey, cluster); + Surface surf_ideal = geometry->maps().getSurface(ckey, cluster); // Unchanged by distortion corrections + // if this is a TPC cluster, the crossing correction may have moved it across the central membrane, check the surface + auto trkrid = TrkrDefs::getTrkrId(ckey); + if (trkrid == TrkrDefs::tpcId) + { + TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(ckey); + TrkrDefs::subsurfkey new_subsurfkey = 0; + surf = geometry->get_tpc_surface_from_coords(hitsetkey, clusglob_moved, new_subsurfkey); } - } - Surface surf = geometry->maps().getSurface(ckey, cluster); - Surface surf_ideal = geometry->maps().getSurface(ckey, cluster); // Unchanged by distortion corrections - // if this is a TPC cluster, the crossing correction may have moved it across the central membrane, check the surface - auto trkrid = TrkrDefs::getTrkrId(ckey); - if (trkrid == TrkrDefs::tpcId) - { - TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(ckey); - TrkrDefs::subsurfkey new_subsurfkey = 0; - surf = geometry->get_tpc_surface_from_coords(hitsetkey, clusglob_moved, new_subsurfkey); - } - auto loc = geometry->getLocalCoords(ckey, cluster, track->get_crossing()); - // in this case we get local coords from transform of corrected global coords - clusglob_moved *= Acts::UnitConstants::cm; // we want mm for transformations - Acts::Vector3 normal = surf->normal(geometry->geometry().getGeoContext(), - Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); - auto local = surf->globalToLocal(geometry->geometry().getGeoContext(), - clusglob_moved, normal); - if (local.ok()) - { - loc = local.value() / Acts::UnitConstants::cm; - } - else - { - // otherwise take the manual calculation for the TPC - // doing it this way just avoids the bounds check that occurs in the surface class method - Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm - loct /= Acts::UnitConstants::cm; + auto loc = geometry->getLocalCoords(ckey, cluster, track->get_crossing()); + // in this case we get local coords from transform of corrected global coords + clusglob_moved *= Acts::UnitConstants::cm; // we want mm for transformations + Acts::Vector3 normal = surf->normal(geometry->geometry().getGeoContext(), + Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); + auto local = surf->globalToLocal(geometry->geometry().getGeoContext(), + clusglob_moved, normal); + if (local.ok()) + { + loc = local.value() / Acts::UnitConstants::cm; + } + else + { + // otherwise take the manual calculation for the TPC + // doing it this way just avoids the bounds check that occurs in the surface class method + Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm + loct /= Acts::UnitConstants::cm; - loc(0) = loct(0); - loc(1) = loct(1); - } - clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree - Acts::Vector2 stateloc(state->get_localX(), state->get_localY()); - Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); - residuals.local_residuals[ckey] = stateloc - loc; - residuals.global_residuals[ckey] = stateglob - clusglob_moved; + loc(0) = loct(0); + loc(1) = loct(1); + } + clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree + Acts::Vector2 stateloc(state->get_localX(), state->get_localY()); + Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); + residuals.local_residuals[ckey] = stateloc - loc; + residuals.global_residuals[ckey] = stateglob - clusglob_moved; } return residuals; } diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index ef3acfcb0e..09106c81e0 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -17,10 +17,11 @@ class GlobalVertex; namespace TrackAnalysisUtils { -struct TrackFitResiduals { - std::map local_residuals; - std::map global_residuals; -}; + struct TrackFitResiduals + { + std::map local_residuals; + std::map global_residuals; + }; /// Returns DCA as .first and uncertainty on DCA as .second using DCA = std::pair; @@ -43,7 +44,7 @@ struct TrackFitResiduals { TrackFitResiduals get_residuals(SvtxTrack* track, TrkrClusterContainer* clustermap, - PHCompositeNode* topNode); + PHCompositeNode* topNode); }; // namespace TrackAnalysisUtils From cf5bfc471944cbfbf8c1978886b0e0c1227f9c2f Mon Sep 17 00:00:00 2001 From: Virginia Bailey Date: Mon, 23 Feb 2026 12:16:45 -0500 Subject: [PATCH 275/866] switching to use isGood tower flag --- .../jetbackground/DetermineTowerBackground.cc | 12 ++++++------ offline/packages/jetbackground/RetowerCEMC.cc | 2 +- offline/packages/jetbase/TowerJetInput.cc | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 78a930a8a0..c3a47a6b9b 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -278,7 +278,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, comp_ieta, comp_iphi); tower_geom = geomIH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = towerinfo->get_isHot() || towerinfo->get_isNoCalib() || towerinfo->get_isNotInstr() || towerinfo->get_isBadChi2(); + comp_isBad = !tower->get_isGood(); } else if (comp.first == 7 || comp.first == 27) { @@ -289,7 +289,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, comp_ieta, comp_iphi); tower_geom = geomOH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = towerinfo->get_isHot() || towerinfo->get_isNoCalib() || towerinfo->get_isNotInstr() || towerinfo->get_isBadChi2(); + comp_isBad = !tower->get_isGood(); } else if (comp.first == 13 || comp.first == 28) { @@ -300,7 +300,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, comp_ieta, comp_iphi); tower_geom = geomIH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = towerinfo->get_isHot() || towerinfo->get_isNoCalib() || towerinfo->get_isNotInstr() || towerinfo->get_isBadChi2(); + comp_isBad = !tower->get_isGood(); } @@ -467,7 +467,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) int this_phibin = towerinfosEM3->getTowerPhiBin(key); TowerInfo *tower = towerinfosEM3->get_tower_at_channel(channel); float this_E = tower->get_energy(); - int this_isBad = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + int this_isBad = !tower->get_isGood(); _EMCAL_ISBAD[this_etabin][this_phibin] = this_isBad; if (!this_isBad) { // just in case since all energy is summed @@ -485,7 +485,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) int this_phibin = towerinfosIH3->getTowerPhiBin(key); TowerInfo *tower = towerinfosIH3->get_tower_at_channel(channel); float this_E = tower->get_energy(); - int this_isBad = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + int this_isBad = !tower->get_isGood(); _IHCAL_ISBAD[this_etabin][this_phibin] = this_isBad; if (!this_isBad) { // just in case since all energy is summed @@ -503,7 +503,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) int this_phibin = towerinfosOH3->getTowerPhiBin(key); TowerInfo *tower = towerinfosOH3->get_tower_at_channel(channel); float this_E = tower->get_energy(); - int this_isBad = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + int this_isBad = !tower->get_isGood(); _OHCAL_ISBAD[this_etabin][this_phibin] = this_isBad; if (!this_isBad) { // just in case since all energy is summed diff --git a/offline/packages/jetbackground/RetowerCEMC.cc b/offline/packages/jetbackground/RetowerCEMC.cc index 6125052a23..f9afbad6dd 100644 --- a/offline/packages/jetbackground/RetowerCEMC.cc +++ b/offline/packages/jetbackground/RetowerCEMC.cc @@ -86,7 +86,7 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) int iphi = towerinfosEM3->getTowerPhiBin(channelkey); rawtower_e[ieta][iphi] = tower->get_energy(); rawtower_time[ieta][iphi] = tower->get_time(); - rawtower_status[ieta][iphi] = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + rawtower_status[ieta][iphi] = !tower->get_isGood(); } EMRetowerName = m_towerNodePrefix + "_CEMC_RETOWER"; TowerInfoContainer *emcal_retower = findNode::getClass(topNode, EMRetowerName); diff --git a/offline/packages/jetbase/TowerJetInput.cc b/offline/packages/jetbase/TowerJetInput.cc index 052a6c1828..ca2af6ba3d 100644 --- a/offline/packages/jetbase/TowerJetInput.cc +++ b/offline/packages/jetbase/TowerJetInput.cc @@ -471,7 +471,7 @@ std::vector TowerJetInput::get_input(PHCompositeNode *topNode) int iphi = towerinfos->getTowerPhiBin(calokey); const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(geocaloid, ieta, iphi); // skip masked towers - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { continue; } From a8aa64754e306364326af2db5b65ae30cc80c0a9 Mon Sep 17 00:00:00 2001 From: Virginia Bailey Date: Mon, 23 Feb 2026 12:21:58 -0500 Subject: [PATCH 276/866] fix typo --- offline/packages/jetbackground/DetermineTowerBackground.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index c3a47a6b9b..64ffd50835 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -278,7 +278,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, comp_ieta, comp_iphi); tower_geom = geomIH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = !tower->get_isGood(); + comp_isBad = !towerinfo->get_isGood(); } else if (comp.first == 7 || comp.first == 27) { @@ -289,7 +289,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, comp_ieta, comp_iphi); tower_geom = geomOH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = !tower->get_isGood(); + comp_isBad = !towerinfo->get_isGood(); } else if (comp.first == 13 || comp.first == 28) { @@ -300,7 +300,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, comp_ieta, comp_iphi); tower_geom = geomIH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = !tower->get_isGood(); + comp_isBad = !towerinfo->get_isGood(); } From 1b27a2718beb4741d8fc67b803c9972ced63169a Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Mon, 23 Feb 2026 14:17:59 -0500 Subject: [PATCH 277/866] Fix clang-tidy issues, set threshold for ZDC and sEPD CaloStatusSkimmer changes: -fix two classes of clag-tidy warnings. First is braces for all conditional statements. 4 instances were simply indented. The second is setting member variables in the constructor. I already defined defaults in the class definition, so it was not needed anyway. - set very low defaults for ZDC and sEPD skimming. Avoids the issue of skipped channels in the sEPD. A single packet loss is huge for them anyway. --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 11 +++++++--- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 20 ++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 08b3ae34a6..0447bf5ba6 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -16,9 +16,6 @@ CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) : SubsysReco(name) { - n_eventcounter = 0; - n_skimcounter = 0; - n_notowernodecounter = 0; std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; } @@ -34,7 +31,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { n_notowernodecounter++; if (Verbosity() > 0) + { std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_CEMC" << std::endl; + } return Fun4AllReturnCodes::ABORTEVENT; } const uint32_t ntowers = towers->size(); @@ -67,7 +66,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { n_notowernodecounter++; if (Verbosity() > 0) + { std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT" << std::endl; + } return Fun4AllReturnCodes::ABORTEVENT; } @@ -114,7 +115,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { n_notowernodecounter++; if (Verbosity() > 0) + { std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_SEPD" << std::endl; + } return Fun4AllReturnCodes::ABORTEVENT; } const uint32_t ntowers = sepd_towers->size(); @@ -148,7 +151,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { n_notowernodecounter++; if (Verbosity() > 0) + { std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_ZDC" << std::endl; + } return Fun4AllReturnCodes::ABORTEVENT; } const uint32_t ntowers = zdc_towers->size(); diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 628a582917..ec03c20839 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -52,24 +52,20 @@ class CaloStatusSkimmer : public SubsysReco { uint32_t n_notowernodecounter{0}; bool b_do_skim_EMCal{false}; - uint16_t m_EMC_skim_threshold{ - 192}; // skim if nchannels >= this many not-instrumented(empty/missing - // pckt) channels in EMCal + uint16_t m_EMC_skim_threshold{192}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in EMCal bool b_do_skim_HCal{false}; - uint16_t m_HCal_skim_threshold{ - 192}; // skim if nchannels >= this many not-instrumented(empty/missing - // pckt) channels in HCal + uint16_t m_HCal_skim_threshold{192}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in HCal bool b_do_skim_sEPD{false}; - uint16_t m_sEPD_skim_threshold{ - 192}; // skim if nchannels >= this many not-instrumented(empty/missing - // pckt) channels in sEPD + uint16_t m_sEPD_skim_threshold{1}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in sEPD bool b_do_skim_ZDC{false}; - uint16_t m_ZDC_skim_threshold{ - 192}; // skim if nchannels >= this many not-instrumented(empty/missing - // pckt) channels in ZDC + uint16_t m_ZDC_skim_threshold{1}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in ZDC }; #endif // CALOSTATUSSKIMMER_H From bbdeda0523037c4e7dbbcae931ab002614eb612d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 23 Feb 2026 15:19:22 -0500 Subject: [PATCH 278/866] trackbase compiles --- .../trackbase/AlignmentTransformation.cc | 2 +- .../trackbase/MagneticFieldOptions.cc | 200 ------------------ .../packages/trackbase/MagneticFieldOptions.h | 22 -- offline/packages/trackbase/Makefile.am | 7 +- .../trackbase/TGeoDetectorWithOptions.cc | 6 +- .../trackbase/sPHENIXActsDetectorElement.cc | 11 +- .../trackbase/sPHENIXActsDetectorElement.h | 15 +- 7 files changed, 15 insertions(+), 248 deletions(-) delete mode 100644 offline/packages/trackbase/MagneticFieldOptions.cc delete mode 100644 offline/packages/trackbase/MagneticFieldOptions.h diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 2e8647ab01..aa67288bb6 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -372,7 +372,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, // get the acts transform components // Note that Acts transforms local coordinates of (x,z,y) to global (x,y,z) - Acts::Transform3 actsTransform = surf->transform(m_tGeometry->geometry().getGeoContext()); + auto actsTransform = surf->transform(m_tGeometry->geometry().getGeoContext()); Eigen::Matrix3d actsRotationPart = actsTransform.rotation(); Eigen::Vector3d actsTranslationPart = actsTransform.translation(); diff --git a/offline/packages/trackbase/MagneticFieldOptions.cc b/offline/packages/trackbase/MagneticFieldOptions.cc deleted file mode 100644 index 4043397f76..0000000000 --- a/offline/packages/trackbase/MagneticFieldOptions.cc +++ /dev/null @@ -1,200 +0,0 @@ - - -#include "MagneticFieldOptions.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -void ActsExamples::Options::addMagneticFieldOptions(Description& desc) { - using boost::program_options::bool_switch; - using boost::program_options::value; - - // avoid adding the options twice - if (desc.find_nothrow("bf-constant-tesla", true) != nullptr) { - return; - } - - auto opt = desc.add_options(); - opt("bf-constant-tesla", value>(), - "Set a constant magnetic field vector in Tesla. If given, this takes " - "preference over all other options."); - opt("bf-scalable", bool_switch(), - "If given, the constant field strength will be scaled differently in " - "every event. This is for testing only."); - opt("bf-scalable-scalor", value()->default_value(1.25), - "Scaling factor for the event-dependent field strength scaling. A unit " - "value means that the field strength stays the same for every event."); - opt("bf-map-file", value(), - "Read a magnetic field map from the given file. ROOT and text file " - "formats are supported. Only used if no constant field is given."); - opt("bf-map-tree", value()->default_value("bField"), - "Name of the TTree in the ROOT file. Only used if the field map is read " - "from a ROOT file."); - opt("bf-map-type", value()->default_value("xyz"), - "Either 'xyz' or 'rz' to define the type of the field map."); - opt("bf-map-octantonly", bool_switch(), - "If given, the field map is assumed to describe only the first " - "octant/quadrant and the field is symmetrically extended to the full " - "space."); - opt("bf-map-lengthscale-mm", value()->default_value(1.), - "Optional length scale modifier for the field map grid. This options " - "only needs to be set if the length unit in the field map file is not " - "`mm`. The value must scale from the stored unit to the equivalent value " - "in `mm`."); - opt("bf-map-fieldscale-tesla", value()->default_value(1.), - "Optional field value scale modifier for the field map value. This " - "option only needs to be set if the field value unit in the field map " - "file is not `Tesla`. The value must scale from the stored unit to the " - "equivalent value in `Tesla`."); - opt("bf-solenoid-mag-tesla", value()->default_value(0.), - "The magnitude of a solenoid magnetic field in the center in `Tesla`. " - "Only used " - "if neither constant field nor a magnetic field map is given."); - opt("bf-solenoid-length", value()->default_value(6000), - "The length of the solenoid magnetic field in `mm`."); - opt("bf-solenoid-radius", value()->default_value(1200), - "The radius of the solenoid magnetic field in `mm`."); - opt("bf-solenoid-ncoils", value()->default_value(1194), - "Number of coils for the solenoid magnetic field."); - opt("bf-solenoid-map-rlim", - value()->value_name("MIN:MAX")->default_value({0, 1200}), - "The length bounds of the grid created from the analytical solenoid " - "field in `mm`."); - opt("bf-solenoid-map-zlim", - value()->value_name("MIN:MAX")->default_value({-3000, 3000}), - "The radius bounds of the grid created from the analytical solenoid " - "field in `mm`."); - opt("bf-solenoid-map-nbins", value>()->default_value({{150, 200}}), - "The number of bins in r-z directions for the grid created from the " - "analytical solenoid field."); -} - - -std::shared_ptr -ActsExamples::Options::readMagneticField(const Variables& vars) { - using namespace ActsExamples::detail; - using std::filesystem::path; - - // first option: create a constant field - if (vars.count("bf-constant-tesla") != 0u) { - const auto values = vars["bf-constant-tesla"].as>(); - Acts::Vector3 field(values[0] * Acts::UnitConstants::T, - values[1] * Acts::UnitConstants::T, - values[2] * Acts::UnitConstants::T); - if (vars["bf-scalable"].as()) { - return std::make_shared(field); - } else { - return std::make_shared(field); - } - } - - // second option: read a field map from a file - if (vars.count("bf-map-file") != 0u) { - const path file = vars["bf-map-file"].as(); - const auto tree = vars["bf-map-tree"].as(); - const auto type = vars["bf-map-type"].as(); - const auto useOctantOnly = vars["bf-map-octantonly"].as(); - const auto lengthUnit = - vars["bf-map-lengthscale-mm"].as() * Acts::UnitConstants::mm; - const auto fieldUnit = - vars["bf-map-fieldscale-tesla"].as() * Acts::UnitConstants::T; - - bool readRoot = false; - if (file.extension() == ".root") { - readRoot = true; - } else if (file.extension() == ".txt") { - readRoot = false; - } else { - throw std::runtime_error("Unsupported magnetic field map file type"); - } - - if (type == "xyz") { - auto mapBins = [](const std::array& bins, - const std::array& sizes) { - return (bins[0] * (sizes[1] * sizes[2]) + bins[1] * sizes[2] + bins[2]); - }; - - if (readRoot) { - auto map = makeMagneticFieldMapXyzFromRoot( - std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, - useOctantOnly); - return std::make_shared(std::move(map)); - - } else { - auto map = makeMagneticFieldMapXyzFromText(std::move(mapBins), - file.native(), lengthUnit, - fieldUnit, useOctantOnly); - return std::make_shared(std::move(map)); - } - - } else if (type == "rz") { - auto mapBins = [](std::array bins, - std::array sizes) { - return (bins[1] * sizes[0] + bins[0]); - }; - - if (readRoot) { - auto map = makeMagneticFieldMapRzFromRoot( - std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, - useOctantOnly); - return std::make_shared(std::move(map)); - - } else { - auto map = makeMagneticFieldMapRzFromText(std::move(mapBins), - file.native(), lengthUnit, - fieldUnit, useOctantOnly); - return std::make_shared(std::move(map)); - } - - } else { - throw std::runtime_error("Unknown magnetic field map type"); - } - } - - // third option: create a solenoid field - if (vars["bf-solenoid-mag-tesla"].as() > 0) { - // Construct a solenoid field - Acts::SolenoidBField::Config solenoidConfig{}; - solenoidConfig.length = - vars["bf-solenoid-length"].as() * Acts::UnitConstants::mm; - solenoidConfig.radius = - vars["bf-solenoid-radius"].as() * Acts::UnitConstants::mm; - solenoidConfig.nCoils = vars["bf-solenoid-ncoils"].as(); - solenoidConfig.bMagCenter = - vars["bf-solenoid-mag-tesla"].as() * Acts::UnitConstants::T; - - const auto solenoidField = Acts::SolenoidBField(solenoidConfig); - // The parameters for creating a field map - auto getRange = [&](const char* name, auto unit, auto& lower, auto& upper) { - auto interval = vars[name].as(); - lower = interval.lower.value() * unit; - upper = interval.upper.value() * unit; - }; - std::pair rlim, zlim; - getRange("bf-solenoid-map-rlim", Acts::UnitConstants::mm, rlim.first, - rlim.second); - getRange("bf-solenoid-map-zlim", Acts::UnitConstants::mm, zlim.first, - zlim.second); - const auto nbins = vars["bf-solenoid-map-nbins"].as>(); - auto map = - Acts::solenoidFieldMap(rlim, zlim, {nbins[0], nbins[1]}, solenoidField); - return std::make_shared(std::move(map)); - } - - // default option: no field - return std::make_shared(); -} diff --git a/offline/packages/trackbase/MagneticFieldOptions.h b/offline/packages/trackbase/MagneticFieldOptions.h deleted file mode 100644 index 7604c026c4..0000000000 --- a/offline/packages/trackbase/MagneticFieldOptions.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _MAGNETICFIELDOPTIONS_H -#define _MAGNETICFIELDOPTIONS_H - -#include -#include -#include - -namespace ActsExamples { - -namespace Options { - -/// Add magnetic field options with a `bf-` prefix. -void addMagneticFieldOptions(Description& desc); - -/// Read and create the magnetic field from the given user variables. -std::shared_ptr readMagneticField( - const Variables& vars); - -} // namespace Options -} // namespace ActsExamples - -#endif // _MAGNETICFIELDOPTIONS_H \ No newline at end of file diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index d19587bdd7..1a53d8cfa4 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -32,9 +32,9 @@ AM_CPPFLAGS = \ -isystem$(ROOTSYS)/include AM_LDFLAGS = \ + -L$(MYINSTALL)/lib64 \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ - -L$(MYINSTALL)/lib64 \ -L$(ROOTSYS)/lib @@ -72,7 +72,6 @@ pkginclude_HEADERS = \ LaserClusterContainerv1.h \ LaserClusterv1.h \ LaserClusterv2.h \ - MagneticFieldOptions.h \ MaterialWiper.h \ MvtxDefs.h \ MvtxEventInfo.h \ @@ -217,7 +216,6 @@ libtrack_la_SOURCES = \ Calibrator.cc \ ClusterErrorPara.cc \ CommonOptions.cc \ - MagneticFieldOptions.cc \ sPHENIXActsDetectorElement.cc \ TGeoDetectorWithOptions.cc \ TrackFittingAlgorithmFunctionsGsf.cc \ @@ -293,8 +291,7 @@ libtrack_io_la_SOURCES = \ libtrack_la_LIBADD = \ libtrack_io.la \ -lActsCore \ - -lActsExamplesMagneticField \ - -lActsPluginTGeo \ + -lActsPluginRoot \ -lActsExamplesDetectorTGeo \ -lffamodules \ -lboost_program_options diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.cc b/offline/packages/trackbase/TGeoDetectorWithOptions.cc index cb29c27dc7..fdb81ac03d 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.cc +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.cc @@ -10,9 +10,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/offline/packages/trackbase/sPHENIXActsDetectorElement.cc b/offline/packages/trackbase/sPHENIXActsDetectorElement.cc index 3daec79ca2..2604ecaf71 100644 --- a/offline/packages/trackbase/sPHENIXActsDetectorElement.cc +++ b/offline/packages/trackbase/sPHENIXActsDetectorElement.cc @@ -23,16 +23,7 @@ const Acts::Transform3& sPHENIXActsDetectorElement::transform(const Acts::Geomet auto& layerVec = transformVec[sphlayer]; // get the vector of transforms for this layer if (layerVec.size() > sensor) - { - /* - if(sphlayer > 7) - { - std::cout << "sPHENIXActsDetectorElement: volume " << volume <<" Acts layer " << layer << " sensor " << sensor - << " sphenix layer " << sphlayer << std::endl; - std::cout << layerVec[sensor].matrix() << std::endl; - } - */ - + { return layerVec[sensor]; } diff --git a/offline/packages/trackbase/sPHENIXActsDetectorElement.h b/offline/packages/trackbase/sPHENIXActsDetectorElement.h index 7abf4a511f..87a172458b 100644 --- a/offline/packages/trackbase/sPHENIXActsDetectorElement.h +++ b/offline/packages/trackbase/sPHENIXActsDetectorElement.h @@ -2,8 +2,8 @@ #define TRACKBASE_SPHENIXACTSDETECTORELEMENT_H #include -#include -#include +#include +#include /** * This class implements an sphenix detector element to build @@ -13,9 +13,10 @@ class ActsGeometry; -class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement +class sPHENIXActsDetectorElement : public ActsPlugins::TGeoDetectorElement { public: + using Identifier = ActsPlugins::TGeoDetectorElement::Identifier; sPHENIXActsDetectorElement() = delete; sPHENIXActsDetectorElement(const Identifier& identifier, @@ -24,7 +25,7 @@ class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement const std::string& axes = "XYZ", double scalor = 10., std::shared_ptr material = nullptr) - : Acts::TGeoDetectorElement(identifier, tGeoNode, tGeoMatrix, + : ActsPlugins::TGeoDetectorElement(identifier, tGeoNode, tGeoMatrix, axes, scalor, material) { } @@ -34,7 +35,7 @@ class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement Acts::Transform3& tgTransform, std::shared_ptr tgBounds, double tgThickness = 0.) - : Acts::TGeoDetectorElement(identifier, tGeoNode, tgTransform, + : ActsPlugins::TGeoDetectorElement(identifier, tGeoNode, tgTransform, tgBounds, tgThickness) { } @@ -44,7 +45,7 @@ class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement Acts::Transform3& tgTransform, std::shared_ptr tgBounds, double tgThickness = 0.) - : Acts::TGeoDetectorElement(identifier, tGeoNode, tgTransform, tgBounds, + : ActsPlugins::TGeoDetectorElement(identifier, tGeoNode, tgTransform, tgBounds, tgThickness) { } @@ -58,7 +59,7 @@ class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement }; std::shared_ptr sPHENIXElementFactory( - const Identifier& identifier, const TGeoNode& tGeoNode, + const sPHENIXActsDetectorElement::Identifier& identifier, const TGeoNode& tGeoNode, const TGeoMatrix& tGeoMatrix, const std::string& axes, double scalor, std::shared_ptr material) { From edbc188c3aaa9019144bb04f1131f87b8f52925f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 23 Feb 2026 16:01:18 -0500 Subject: [PATCH 279/866] no need for checking cdbttree file, uniq ptr with root object can cause problems and is counter productive here, remove not needed static casts --- .../eventplaneinfo/EventPlaneRecov2.cc | 65 ++++++------------- .../eventplaneinfo/EventPlaneRecov2.h | 8 +-- .../packages/eventplaneinfo/Eventplaneinfo.h | 24 +++---- .../eventplaneinfo/Eventplaneinfov2.cc | 7 +- .../eventplaneinfo/Eventplaneinfov2.h | 11 ++-- 5 files changed, 44 insertions(+), 71 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc index c2cd8e3360..0d1e9b673e 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -3,26 +3,29 @@ #include "EventplaneinfoMapv1.h" #include "Eventplaneinfov2.h" -#include -#include - -#include -#include -#include - #include #include #include -// -- event -#include - // -- Centrality #include // -- sEPD #include +#include // for CDBTTree + +// -- event +#include + +#include + +#include + +#include +#include +#include + // -- root includes -- #include #include @@ -41,51 +44,19 @@ EventPlaneRecov2::EventPlaneRecov2(const std::string &name): { } -//____________________________________________________________________________.. -EventPlaneRecov2::~EventPlaneRecov2() -{ - std::cout << "EventPlaneRecov2::~EventPlaneRecov2() Calling dtor" << std::endl; -} - -bool EventPlaneRecov2::hasValidTree(const std::string &filePath) -{ - // 1. Attempt to open the file - // "READ" is the default, but being explicit is good practice - std::unique_ptr file(TFile::Open(filePath.c_str(), "READ")); - - // 2. Validate the file pointer and check if the file is "Zombie" (corrupt/unreadable) - if (!file || file->IsZombie()) - { - std::cout << "Error: Could not open file: " << filePath << std::endl; - return false; - } - - // 3. Attempt to get the object by name - TObject *obj = file->Get("Multiple"); - - // 4. Validate existence and check if it actually inherits from TTree - if (obj && obj->InheritsFrom(TTree::Class())) - { - return true; - } - - std::cout << "Error: Object 'Multiple' not found or is not a TTree." << std::endl; - return false; -} - //____________________________________________________________________________.. int EventPlaneRecov2::Init(PHCompositeNode *topNode) { std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); - if (!m_directURL_EventPlaneCalib.empty() && hasValidTree(m_directURL_EventPlaneCalib)) + if (!m_directURL_EventPlaneCalib.empty()) { - m_cdbttree = std::make_unique(m_directURL_EventPlaneCalib); + m_cdbttree = new CDBTTree(m_directURL_EventPlaneCalib); std::cout << PHWHERE << " Custom Event Plane Calib Found: " << m_directURL_EventPlaneCalib << std::endl; } else if (!calibdir.empty()) { - m_cdbttree = std::make_unique(calibdir); + m_cdbttree = new CDBTTree(calibdir); std::cout << PHWHERE << " Event Plane Calib Found: " << calibdir << std::endl; } else if (m_doAbortNoEventPlaneCalib) @@ -176,7 +147,7 @@ void EventPlaneRecov2::LoadCalib() for (size_t cent_bin = 0; cent_bin < m_bins_cent; ++cent_bin) { - int key = static_cast(cent_bin); + int key = cent_bin; // South auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; @@ -211,6 +182,8 @@ void EventPlaneRecov2::LoadCalib() dataNS.X_matrix = calculate_flattening_matrix(dataNS.avg_Q_xx, dataNS.avg_Q_yy, dataNS.avg_Q_xy, n, cent_bin, "NorthSouth"); } } + delete m_cdbttree; + m_cdbttree = nullptr; } //____________________________________________________________________________.. diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h index 4d12aca1bd..fa4d315cac 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.h +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.h @@ -2,12 +2,13 @@ #define EVENTPLANEINFO_EVENTPLANERECOV2_H #include -#include // for CDBTTree + #include #include #include +class CDBTTree; class PHCompositeNode; class EventPlaneRecov2 : public SubsysReco @@ -15,7 +16,7 @@ class EventPlaneRecov2 : public SubsysReco public: explicit EventPlaneRecov2(const std::string &name = "EventPlaneRecov2"); - ~EventPlaneRecov2() override; + ~EventPlaneRecov2() override = default; // Explicitly disable copying and moving EventPlaneRecov2(const EventPlaneRecov2&) = delete; @@ -64,7 +65,6 @@ class EventPlaneRecov2 : public SubsysReco private: - static bool hasValidTree(const std::string &filePath); static int CreateNodes(PHCompositeNode *topNode); std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); @@ -91,7 +91,7 @@ class EventPlaneRecov2 : public SubsysReco std::string m_calibName{"SEPD_EventPlaneCalib"}; std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; - std::unique_ptr m_cdbttree; + CDBTTree *m_cdbttree; enum class Subdetector { diff --git a/offline/packages/eventplaneinfo/Eventplaneinfo.h b/offline/packages/eventplaneinfo/Eventplaneinfo.h index 32dbb4ca54..af903b6d06 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfo.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfo.h @@ -1,12 +1,12 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -#ifndef EVENTPLANEINFO_H -#define EVENTPLANEINFO_H +#ifndef EVENTPLANEINFO_EVENTPLANEINFO_H +#define EVENTPLANEINFO_EVENTPLANEINFO_H #include -#include #include +#include #include #include @@ -26,18 +26,18 @@ class Eventplaneinfo : public PHObject virtual void set_qvector_raw(const std::vector>& /*Qvec*/) { return; } virtual void set_qvector_recentered(const std::vector>& /*Qvec*/) { return; } virtual void set_shifted_psi(std::vector /*Psi_Shifted*/) { return; } - virtual std::pair get_qvector(int /*order*/) const { return std::make_pair(NAN, NAN); } - virtual std::pair get_qvector_raw(int /*order*/) const { return std::make_pair(NAN, NAN); } - virtual std::pair get_qvector_recentered(int /*order*/) const { return std::make_pair(NAN, NAN); } - virtual double get_psi(int /*order*/) const { return NAN; } - virtual double get_shifted_psi(int /*order*/) const { return NAN; } - virtual double GetPsi(const double /*Qx*/, const double /*Qy*/, const unsigned int /*order*/) const { return NAN; } + virtual std::pair get_qvector(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual std::pair get_qvector_raw(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual std::pair get_qvector_recentered(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual double get_psi(int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual double get_shifted_psi(int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual double GetPsi(const double /*Qx*/, const double /*Qy*/, const unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } virtual void set_ring_qvector(std::vector>> /*RingQvecs*/) { return; } - virtual std::pair get_ring_qvector(int /*rbin*/, int /*order*/) const { return std::make_pair(NAN, NAN); } - virtual double get_ring_psi(int /*rbin*/, int /*order*/) const { return NAN; } + virtual std::pair get_ring_qvector(int /*rbin*/, int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual double get_ring_psi(int /*rbin*/, int /*order*/) const { return std::numeric_limits::quiet_NaN(); } protected: - Eventplaneinfo() {} + Eventplaneinfo() = default; private: ClassDefOverride(Eventplaneinfo, 1); diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc index e8ff5385b8..08bd60c9ba 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc @@ -1,6 +1,7 @@ #include "Eventplaneinfov2.h" #include +#include void Eventplaneinfov2::identify(std::ostream& os) const { @@ -12,11 +13,11 @@ double Eventplaneinfov2::GetPsi(const double Qx, const double Qy, const unsigned { if (order == 0) { - return NAN; + return std::numeric_limits::quiet_NaN(); } if ((Qx == 0.0) && (Qy == 0.0)) { - return NAN; + return std::numeric_limits::quiet_NaN(); } - return atan2(Qy, Qx) / static_cast(order); + return atan2(Qy, Qx) / order; } diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.h b/offline/packages/eventplaneinfo/Eventplaneinfov2.h index d69bc9a5ae..bd6cb553c8 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov2.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.h @@ -1,7 +1,7 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -#ifndef EVENTPLANEINFOV2_H -#define EVENTPLANEINFOV2_H +#ifndef EVENTPLANEINFO_EVENTPLANEINFOV2_H +#define EVENTPLANEINFO_EVENTPLANEINFOV2_H #include "Eventplaneinfo.h" @@ -40,7 +40,7 @@ class Eventplaneinfov2 : public Eventplaneinfo { if (ring_index < 0 || static_cast(ring_index) >= ring_Qvec.size()) { - return {NAN, NAN}; + return {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; } return safe_qvec(ring_Qvec[ring_index], order); } @@ -60,7 +60,7 @@ class Eventplaneinfov2 : public Eventplaneinfo { if (order <= 0 || static_cast(order) > mPsi_Shifted.size()) { - return NAN; + return std::numeric_limits::quiet_NaN(); } return mPsi_Shifted[order - 1]; } @@ -70,7 +70,7 @@ class Eventplaneinfov2 : public Eventplaneinfo { if (order <= 0 || static_cast(order) > v.size()) { - return {NAN, NAN}; + return {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; } return v[order - 1]; } @@ -84,4 +84,3 @@ class Eventplaneinfov2 : public Eventplaneinfo }; #endif - From 934e70d8ca4094fc6591ef2d6757e30a121bd7fe Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 23 Feb 2026 16:11:36 -0500 Subject: [PATCH 280/866] use consistent initialization --- offline/packages/eventplaneinfo/EventPlaneRecov2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h index fa4d315cac..3810935f04 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.h +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.h @@ -91,7 +91,7 @@ class EventPlaneRecov2 : public SubsysReco std::string m_calibName{"SEPD_EventPlaneCalib"}; std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; - CDBTTree *m_cdbttree; + CDBTTree *m_cdbttree {nullptr}; enum class Subdetector { @@ -118,7 +118,7 @@ class EventPlaneRecov2 : public SubsysReco std::array, 2> X_matrix{}; }; - static constexpr size_t m_bins_cent = 8; + static constexpr size_t m_bins_cent {8}; static constexpr std::array m_harmonics = {2, 3, 4}; // Holds all correction data From 714018bb29cdc3c395661734eb17a1c1b3ceb056 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 23 Feb 2026 16:12:40 -0500 Subject: [PATCH 281/866] remove redundant use of uniq_ptrs --- offline/packages/eventplaneinfo/EventPlaneRecov2.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc index 0d1e9b673e..34c28c837f 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -259,17 +259,16 @@ int EventPlaneRecov2::CreateNodes(PHCompositeNode *topNode) { PHCompositeNode *globalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "GLOBAL")); if (!globalNode) { - auto global_ptr = std::make_unique("GLOBAL"); - globalNode = global_ptr.get(); - dstNode->addNode(global_ptr.release()); + globalNode = new PHCompositeNode("GLOBAL"); + dstNode->addNode(globalNode); } EventplaneinfoMap *eps = findNode::getClass(topNode, "EventplaneinfoMap"); if (!eps) { - auto eps_ptr = std::make_unique(); - auto epMapNode_ptr = std::make_unique>(eps_ptr.release(), "EventplaneinfoMap", "PHObject"); - globalNode->addNode(epMapNode_ptr.release()); + eps = new EventplaneinfoMapv1(); + PHIODataNode *newNode = new PHIODataNode(eps , "EventplaneinfoMap", "PHObject"); + globalNode->addNode(newNode); } return Fun4AllReturnCodes::EVENT_OK; From 66b8be60aa3eebc4f47cc7115ffbfb14856515b4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 23 Feb 2026 16:33:34 -0500 Subject: [PATCH 282/866] minor cosmetics --- .../eventplaneinfo/EventPlaneRecov2.cc | 29 +++++++------------ .../eventplaneinfo/EventPlaneRecov2.h | 3 -- .../eventplaneinfo/Eventplaneinfov2.cc | 2 +- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc index 34c28c837f..9635e0f3d6 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -512,17 +512,17 @@ int EventPlaneRecov2::FillNode(PHCompositeNode *topNode) size_t vec_size = static_cast(*std::ranges::max_element(m_harmonics)); - std::vector> south_Qvec_raw(vec_size, {NAN, NAN}); - std::vector> south_Qvec_recentered(vec_size, {NAN, NAN}); - std::vector> south_Qvec(vec_size, {NAN, NAN}); + std::vector> south_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> south_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> south_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> north_Qvec_raw(vec_size, {NAN, NAN}); - std::vector> north_Qvec_recentered(vec_size, {NAN, NAN}); - std::vector> north_Qvec(vec_size, {NAN, NAN}); + std::vector> north_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> north_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> north_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> northsouth_Qvec_raw(vec_size, {NAN, NAN}); - std::vector> northsouth_Qvec_recentered(vec_size, {NAN, NAN}); - std::vector> northsouth_Qvec(vec_size, {NAN, NAN}); + std::vector> northsouth_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> northsouth_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> northsouth_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { @@ -566,7 +566,7 @@ int EventPlaneRecov2::FillNode(PHCompositeNode *topNode) node->set_qvector_recentered(qvecs_recentered); node->set_qvector(qvecs); - std::vector psi_vec(vec_size, NAN); + std::vector psi_vec(vec_size, std::numeric_limits::quiet_NaN()); for (int n : m_harmonics) { psi_vec[n-1] = node->GetPsi(qvecs[n-1].first, qvecs[n-1].second, n); } @@ -625,7 +625,7 @@ int EventPlaneRecov2::process_event(PHCompositeNode *topNode) } //____________________________________________________________________________.. -int EventPlaneRecov2::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) +int EventPlaneRecov2::ResetEvent(PHCompositeNode */*topNode*/) { m_doNotCalibEvent = false; @@ -635,10 +635,3 @@ int EventPlaneRecov2::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } - -//____________________________________________________________________________.. -int EventPlaneRecov2::End([[maybe_unused]] PHCompositeNode *topNode) -{ - std::cout << "EventPlaneRecov2::End(PHCompositeNode *topNode) This is the End..." << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h index 3810935f04..217faddf88 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.h +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.h @@ -39,9 +39,6 @@ class EventPlaneRecov2 : public SubsysReco /// Clean up internals after each event. int ResetEvent(PHCompositeNode *topNode) override; - /// Called at the end of all processing. - int End(PHCompositeNode *topNode) override; - void set_inputNode(const std::string &inputNode) { diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc index 08bd60c9ba..7331117a17 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc @@ -19,5 +19,5 @@ double Eventplaneinfov2::GetPsi(const double Qx, const double Qy, const unsigned { return std::numeric_limits::quiet_NaN(); } - return atan2(Qy, Qx) / order; + return std::atan2(Qy, Qx) / order; } From 876b96f25a59f3d5b93353a417aade587468e160 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 23 Feb 2026 16:38:55 -0500 Subject: [PATCH 283/866] fix lib dependencies --- offline/packages/eventplaneinfo/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/eventplaneinfo/Makefile.am b/offline/packages/eventplaneinfo/Makefile.am index 293e3675d6..786a285bee 100644 --- a/offline/packages/eventplaneinfo/Makefile.am +++ b/offline/packages/eventplaneinfo/Makefile.am @@ -14,8 +14,7 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib libeventplaneinfo_io_la_LIBADD = \ - -lphool \ - -lcentrality_io + -lphool libeventplaneinfo_la_LIBADD = \ libeventplaneinfo_io.la \ @@ -24,6 +23,7 @@ libeventplaneinfo_la_LIBADD = \ -lfun4all \ -lffamodules \ -lcalotrigger_io \ + -lcentrality_io \ -lffarawobjects \ -lcdbobjects \ -lglobalvertex_io From 28b6193b459ea77c8ac0dcc2e660be833c8c0d06 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 23 Feb 2026 18:18:19 -0500 Subject: [PATCH 284/866] added missing const from header declaration. This should fix compiling TrackingDiagnostics. --- offline/packages/trackbase_historic/TrackAnalysisUtils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index 168ff7495f..0f87c2a7be 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -28,9 +28,9 @@ namespace TrackAnalysisUtils // to pass these from the geometry object, which keeps the dependencies // of this helper class minimal. This will also help us catch any changes // when/if the tpc geometry changes in the future. This is to get us going - float thickness_per_region[4]); + float const thickness_per_region[4]); float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, - float thickness_per_region[4]); + float const thickness_per_region[4]); }; // namespace TrackAnalysisUtils From 0c9988a632bb6ed1fe26b41f0f414ec22ed86543 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 24 Feb 2026 13:34:58 -0500 Subject: [PATCH 285/866] update alignment states --- offline/packages/trackreco/ActsAlignmentStates.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index d99fc1c178..f9c8570274 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -127,10 +127,9 @@ void ActsAlignmentStates::fillAlignmentStateMap( auto ckey = sl.cluskey(); Acts::Vector2 localMeas = Acts::Vector2::Zero(); /// get the local measurement that acts used - std::visit([&](const auto& meas) { - localMeas(0) = meas.parameters()[0]; - localMeas(1) = meas.parameters()[1]; - }, measurements[sl.index()]); + const auto measurement = measurements.getMeasurement(sl.index()); + localMeas(0) = measurement.parameters()[0]; + localMeas(1) = measurement.parameters()[1]; if (m_verbosity > 2) { @@ -142,7 +141,9 @@ void ActsAlignmentStates::fillAlignmentStateMap( auto clus = m_clusterMap->findCluster(ckey); // local state vector - const Acts::Vector2 localState = state.effectiveProjector() * state.smoothed(); + const auto H = state.projectorSubspaceHelper().fullProjector().topLeftCorner( + state.calibratedSize(), Acts::eBoundSize); + const Acts::Vector2 localState = H * state.smoothed(); // Local residual between measurement and smoothed Acts state const Acts::Vector2 localResidual = localMeas - localState; @@ -205,8 +206,8 @@ void ActsAlignmentStates::fillAlignmentStateMap( //! this is the derivative of the state wrt to Acts track parameters //! e.g. (d_0, z_0, phi, theta, q/p, t) - auto localDeriv = state.effectiveProjector() * state.jacobian(); - if(m_verbosity > 2) + auto localDeriv = H * state.jacobian(); + if (m_verbosity > 2) { std::cout << "local deriv " << std::endl << localDeriv << std::endl; } From becbe38c45d00bee4c2a546558542115b886fa53 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Tue, 24 Feb 2026 14:16:35 -0500 Subject: [PATCH 286/866] Diagnostics added. --- .../KshortReconstruction.cc | 141 +++++++++++------- 1 file changed, 85 insertions(+), 56 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index a7a240ffcf..68ae2dae25 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -92,8 +92,6 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) std::vector nstates1 = getTrackStates(tr1); unsigned int track1_mvtx_state_size = nstates1[0]; unsigned int track1_intt_state_size = nstates1[1]; - // unsigned int track1_tpc_state_size = nstates1[2]; - // unsigned int track1_mms_state_size = nstates1[3]; unsigned int track1_silicon_cluster_size = std::numeric_limits::quiet_NaN(); if (siliconseed) @@ -125,23 +123,46 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) Acts::Vector3 pos1(tr1->get_x(), tr1->get_y(), tr1->get_z()); Acts::Vector3 mom1(tr1->get_px(), tr1->get_py(), tr1->get_pz()); Acts::Vector3 dcaVals1 = calculateDca(tr1, mom1, pos1); - // first dca cuts if (fabs(dcaVals1(0)) < this_dca_cut || fabs(dcaVals1(1)) < this_dca_cut) - { - continue; - } - + { + std::cout << " tr1 failed dca cuts " << std::endl; + continue; + } // look for close DCA matches with all other such tracks for (auto tr2_it = std::next(tr1_it); tr2_it != m_svtxTrackMap->end(); ++tr2_it) { auto id2 = tr2_it->first; auto *tr2 = tr2_it->second; + + bool diag = false; + + // dca xy and dca z cut here compare to track dca cut + Acts::Vector3 pos2(tr2->get_x(), tr2->get_y(), tr2->get_z()); + Acts::Vector3 mom2(tr2->get_px(), tr2->get_py(), tr2->get_pz()); + Acts::Vector3 dcaVals2 = calculateDca(tr2, mom2, pos2); + + if( fabs(1.0 - std::tan(dcaVals1(2))) < 0.1 && abs(dcaVals2(2)-dcaVals1(2)) < 0.1 ) + { + diag = true; + std::cout << "*** Found phi values of interest " << std::endl; + } + if(diag) { std::cout << " tr1: id, dca3dxy1,dca3dz1,phi1: " << tr1->get_id() << " " << dcaVals1(0) << " " << dcaVals1(1) << " " << dcaVals1(2) << std::endl; } + if(diag) { std::cout << " tr2: id,dca3dxy2,dca3dz2,phi2: " << tr2->get_id() << " " << dcaVals2(0) << " " << dcaVals2(1) << " " << dcaVals2(2) << std::endl; } + if (tr2->get_quality() > _qual_cut) { - continue; + if(diag) + { + std::cout << " tr2 failed quality cut " << tr2->get_quality() << std::endl; + } + continue; } if (tr2->get_pt() < track_pt_cut) { + if(diag) + { + std::cout << " tr2 failed pT cut " << tr2->get_pt() << std::endl; + } continue; } @@ -161,15 +182,17 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) } if (_require_mvtx) { - continue; - } + if(diag) + { + std::cout << " tr2 failed mvtx cut " << std::endl; + } + continue; + } } std::vector nstates2 = getTrackStates(tr2); unsigned int track2_mvtx_state_size = nstates2[0]; unsigned int track2_intt_state_size = nstates2[1]; - // unsigned int track2_tpc_state_size = nstates2[2]; - // unsigned int track2_mms_state_size = nstates2[3]; unsigned int track2_silicon_cluster_size = std::numeric_limits::quiet_NaN(); if (siliconseed2) @@ -198,20 +221,20 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) } } - // dca xy and dca z cut here compare to track dca cut - Acts::Vector3 pos2(tr2->get_x(), tr2->get_y(), tr2->get_z()); - Acts::Vector3 mom2(tr2->get_px(), tr2->get_py(), tr2->get_pz()); - Acts::Vector3 dcaVals2 = calculateDca(tr2, mom2, pos2); - + if (fabs(dcaVals2(0)) < this_dca_cut2 || fabs(dcaVals2(1)) < this_dca_cut2) { + if(diag) + { + std::cout << " tr2 failed dca cut " << std::endl; + } continue; } - // find DCA of these two tracks + // find pair DCA of these two tracks if (Verbosity() > 3) { - std::cout << "Check DCA for tracks " << id1 << " and " << id2 << std::endl; + std::cout << "Check pair DCA for tracks " << id1 << " and " << id2 << std::endl; } if (tr1->get_charge() == tr2->get_charge()) @@ -233,7 +256,7 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) // This presently assumes straight line tracks to get a rough answer // Should update to use circles instead? findPcaTwoTracks(pos1, pos2, mom1, mom2, pca_rel1, pca_rel2, pair_dca); - + if(diag) { std::cout << " pair dca " << pair_dca << " pca_rel1 " << pca_rel1(0) << " " << pca_rel1(1) << " " << pca_rel1(2) << std::endl; } // tracks with small relative pca are k short candidates if (abs(pair_dca) < pair_dca_cut) { @@ -279,35 +302,35 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) // invariant mass is calculated in this method fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity,decaymassa, decaymassb); fillNtp(tr1, tr2, decaymassa, decaymassb, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); - - - - - - /* - // invariant mass is calculated in this method - fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity); - fillNtp(tr1, tr2, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); - */ + if(diag) + { + std::cout << "Accepted Track Pair" << " id1 " << id1 << " id2 " << id2 << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; + std::cout << " invariant mass: " << invariantMass << " decaymassa " << decaymassa << " decaymassb " << decaymassb << std::endl; + } if (Verbosity() > 1) { - std::cout << " Accepted Track Pair" << std::endl; - std::cout << " id1 " << id1 << " id2 " << id2 << std::endl; - std::cout << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; - std::cout << " invariant mass: " << invariantMass << std::endl; - std::cout << " track1 dca_cut: " << this_dca_cut << " track2 dca_cut: " << this_dca_cut2 << std::endl; - std::cout << " dca3dxy1,dca3dz1,phi1: " << dcaVals1 << std::endl; - std::cout << " dca3dxy2,dca3dz2,phi2: " << dcaVals2 << std::endl; - std::cout << "Initial: pca_rel1: " << pca_rel1 << " pca_rel2: " << pca_rel2 << std::endl; - std::cout << " Initial: mom1: " << mom1 << " mom2: " << mom2 << std::endl; - std::cout << "Proj_pca_rel: proj_pos1: " << projected_pos1 << " proj_pos2: " << projected_pos2 << " proj_mom1: " << projected_mom1 << " proj_mom2: " << projected_mom2 << std::endl; - std::cout << " Relative PCA = " << abs(pair_dca) << " pca_cut = " << pair_dca_cut << std::endl; - std::cout << " charge 1: " << tr1->get_charge() << " charge2: " << tr2->get_charge() << std::endl; - std::cout << "found viable projection" << std::endl; - std::cout << "Final: pca_rel1_proj: " << pca_rel1_proj << " pca_rel2_proj: " << pca_rel2_proj << " mom1: " << projected_mom1 << " mom2: " << projected_mom2 << std::endl - << std::endl; + std::cout << "Accepted Track Pair" << " id1 " << id1 << " id2 " << id2 << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; + std::cout << " invariant mass: " << invariantMass << " decaymassa " << decaymassa << " decaymassb " << decaymassb << std::endl; + std::cout << " track1 dca_cut: " << this_dca_cut << " track2 dca_cut: " << this_dca_cut2 << std::endl; + std::cout << " dca3dxy1,dca3dz1,phi1: " << dcaVals1(0) << " " << dcaVals1(1) << " " << dcaVals1(2) << std::endl; + std::cout << " dca3dxy2,dca3dz2,phi2: " << dcaVals2(0) << " " << dcaVals2(1) << " " << dcaVals2(2) << std::endl; + std::cout << " Initial: pca_rel1: " << pca_rel1(0) << " " << pca_rel1(1) << " " << pca_rel1(2) << std::endl; + std::cout << " Initial: pca_rel2: " << pca_rel2(0) << " " << pca_rel2(1) << " " << pca_rel2(2) << std::endl; + std::cout << " Initial: mom1: " << mom1(0) << " " << mom1(1) << " " << mom1(2) << std::endl; + std::cout << " Initial: mom2: " << mom2(0) << " " << mom2(1) << " " << mom2(2) << std::endl; + std::cout << " Proj_pca_rel: proj_pos1: " << projected_pos1(0) << " " << projected_pos1(1) << " " << projected_pos1(2) << std::endl; + std::cout << " Proj_pca_rel: proj_pos2: " << projected_pos2(0) << " " << projected_pos2(1) << " " << projected_pos2(2) << std::endl; + std::cout << " proj_mom1: " << projected_mom1(0) << " " << projected_mom1(1) << " " << projected_mom1(2) << std::endl; + std::cout << " proj_mom2: " << projected_mom2(0) << " " << projected_mom2(1) << " " << projected_mom2(2) << std::endl; + std::cout << " Relative PCA = " << abs(pair_dca) << " pca_cut = " << pair_dca_cut << std::endl; + std::cout << " charge 1: " << tr1->get_charge() << " charge2: " << tr2->get_charge() << std::endl; + std::cout << " found viable projection" << std::endl; + std::cout << " Final: pca_rel1_proj: " << pca_rel1_proj(0) << " " << pca_rel1_proj(1) << " " << pca_rel1_proj(2) << std::endl; + std::cout << " Final: pca_rel2_proj: " << pca_rel2_proj(0) << " " << pca_rel2_proj(1) << " " << pca_rel2_proj(2) << std::endl; + std::cout << " Final: mom1: " << projected_mom1(0) << " " << projected_mom1(1) << " " << projected_mom1(2) << std::endl; + std::cout << " Final: mom2: " << projected_mom2(0) << " " << projected_mom2(1) << " " << projected_mom2(2) << std::endl; } } if (m_save_tracks) @@ -354,9 +377,7 @@ std::vector KshortReconstruction::getTrackStates(SvtxTrack *track) nmmsstate++; break; default: - std::cout << PHWHERE << " unknown key " << stateckey << std::endl; - gSystem->Exit(1); - exit(1); + break; } } nstates.push_back(nmapsstate); @@ -771,9 +792,16 @@ KshortReconstruction::KshortReconstruction(const std::string& name) Acts::Vector3 KshortReconstruction::calculateDca(SvtxTrack* track, const Acts::Vector3& momentum, Acts::Vector3 position) { + + /* + std::cout << " Input: pos(0) " << position(0) << " pos(1) " << position(1) << " pos(2) " << position(2) + << " mom(0) " << momentum(0) << " mom(1) " << momentum(1) << " mom(2) " << momentum(2) + << std::endl; + */ + // For the purposes of this module, we set default values to prevent this track from being rejected if the dca calc fails Acts::Vector3 r = momentum.cross(Acts::Vector3(0., 0., 1.)); - float phi = atan2(r(1), r(0)); + float phi = std::atan2(r(1), r(0)); Acts::Vector3 outVals(track_dca_cut*1.1, track_dca_cut*1.1, phi); auto vtxid = track->get_vertex_id(); if (!m_vertexMap) @@ -808,7 +836,14 @@ Acts::Vector3 KshortReconstruction::calculateDca(SvtxTrack* track, const Acts::V outVals(0) = abs(dca3dxy); outVals(1) = abs(dca3dz); outVals(2) = phi; - + /* + std::cout << " calculateDca: dca3dxy " << outVals(0) << " dca3dz " << outVals(1) << " phi " << outVals(2) << std::endl + << " vertex(0) " << vertex(0) << " vertex(1) " << vertex(1) << " vertex(2) " << vertex(2) << std::endl + << " position(0) " << position(0) << " position(1) " << position(1) << " position(2) " << position(2) << std::endl + << " momentum(0) " << momentum(0) << " momentum(1) " << momentum(1) << " momentum(2) " << momentum(2) + << std::endl; + */ + if (Verbosity() > 4) { std::cout << " pre-position: " << position << std::endl; @@ -826,12 +861,6 @@ int KshortReconstruction::InitRun(PHCompositeNode* topNode) ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "id1:mass1:crossing1:x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:id2:mass2:crossing2:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:ntracks_vertex:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:invariantPhi:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco:track1_silicon_clusters:track2_silicon_clusters:track1_mvtx_clusters:track1_mvtx_states:track1_intt_clusters:track1_intt_states:track2_mvtx_clusters:track2_mvtx_states:track2_intt_clusters:track2_intt_states:runNumber:eventNumber"); - - -/* - ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "id1:crossing1:x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:id2:crossing2:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:invariantPhi:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco:track1_silicon_clusters:track2_silicon_clusters:track1_mvtx_clusters:track1_mvtx_states:track1_intt_clusters:track1_intt_states:track2_mvtx_clusters:track2_mvtx_states:track2_intt_clusters:track2_intt_states:runNumber:eventNumber"); -*/ - getNodes(topNode); recomass = new TH1D("recomass", "recomass", 1000, 0.0, 1); // root histogram arguments: name,title,bins,minvalx,maxvalx From e9f85e6ea61a233ca0420c846a5cb63ba1b249f3 Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Tue, 24 Feb 2026 14:47:35 -0500 Subject: [PATCH 287/866] add default to not abort when abort enabled but only fail MBD cut --- offline/packages/jetbackground/TimingCut.cc | 2 +- offline/packages/jetbackground/TimingCut.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index 719fc8181c..e2949bbe7b 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -203,7 +203,7 @@ int TimingCut::process_event(PHCompositeNode *topNode) passMbdt = Pass_Mbd_dt(corrMaxJett, mbd_time); } - bool failAnyCut = !passDeltat || !passLeadt || !passMbdt; + bool failAnyCut = !passDeltat || !passLeadt || (!passMbdt && _abortFailMbd); if (failAnyCut && _doAbort) { diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index d932c4cac5..5fa3a134bc 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -67,6 +67,9 @@ class TimingCut : public SubsysReco void set_min_dphi(float new_min_dphi) { _min_dphi = new_min_dphi; } float get_min_dphi() { return _min_dphi; } + void set_abortFailMbd(bool abortFailMbd) { _abortFailMbd = abortFailMbd; } + bool get_abortFailMbd() { return _abortFailMbd; } + int Init(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -100,6 +103,7 @@ class TimingCut : public SubsysReco private: bool _doAbort; + bool _abortFailMbd = false; bool _missingInfoWarningPrinted = false; std::string _jetNodeName; std::string _ohTowerName; From 4955f457fc6a9eff49888319bdf746f9a9b64fe7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 24 Feb 2026 17:12:08 -0500 Subject: [PATCH 288/866] add MB to Detroit to make clear these are MinBias --- offline/framework/frog/CreateFileList.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index bc8135ec6d..e0eaa402f3 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -64,7 +64,7 @@ "23" => "cosmic field off", "24" => "AMPT", "25" => "EPOS", - "26" => "JS pythia8 Detroit", + "26" => "JS pythia8 Detroit (MB)", "27" => "JS pythia8 Photonjet ptmin = 5GeV", "28" => "JS pythia8 Photonjet ptmin = 10GeV", "29" => "JS pythia8 Photonjet ptmin = 20GeV", From e04bec167cc4a025bb18b9dac007ed3c9b739bd8 Mon Sep 17 00:00:00 2001 From: emclaughlin2 Date: Wed, 25 Feb 2026 12:56:51 -0500 Subject: [PATCH 289/866] Update waveform fitting to return fit status and towerinfo objects to save fit status and remove isbadtime flag --- offline/QA/Jet/CaloStatusMapperDefs.h | 7 ---- offline/packages/CaloBase/TowerInfo.h | 4 +-- offline/packages/CaloBase/TowerInfov2.h | 6 ++-- offline/packages/CaloBase/TowerInfov4.h | 6 ++-- offline/packages/CaloReco/CaloTowerBuilder.cc | 1 + offline/packages/CaloReco/CaloTowerStatus.cc | 9 ++--- .../packages/CaloReco/CaloWaveformFitting.cc | 36 ++++++++++++------- .../CaloReco/CaloWaveformProcessing.cc | 5 ++- .../NodeDump/DumpTowerInfoContainer.cc | 1 - .../packages/jetbackground/SubtractTowers.cc | 6 ++-- 10 files changed, 41 insertions(+), 40 deletions(-) diff --git a/offline/QA/Jet/CaloStatusMapperDefs.h b/offline/QA/Jet/CaloStatusMapperDefs.h index c77d1b765c..08f8289fe0 100644 --- a/offline/QA/Jet/CaloStatusMapperDefs.h +++ b/offline/QA/Jet/CaloStatusMapperDefs.h @@ -59,7 +59,6 @@ namespace CaloStatusMapperDefs { Good, Hot, - BadTime, BadChi, NotInstr, NoCalib, @@ -74,7 +73,6 @@ namespace CaloStatusMapperDefs static std::map mapStatLabels = { {Stat::Good, "Good"}, {Stat::Hot, "Hot"}, - {Stat::BadTime, "BadTime"}, {Stat::BadChi, "BadChi"}, {Stat::NotInstr, "NotInstr"}, {Stat::NoCalib, "NoCalib"}, @@ -173,10 +171,6 @@ namespace CaloStatusMapperDefs { status = Stat::Hot; } - else if (tower->get_isBadTime()) - { - status = Stat::BadTime; - } else if (tower->get_isBadChi2()) { status = Stat::BadChi; @@ -204,7 +198,6 @@ namespace CaloStatusMapperDefs { bool skip = false; if ((label == "Hot") || - (label == "BadTime") || (label == "BadChi") || (label == "NoCalib") || (label == "NotInstr") || diff --git a/offline/packages/CaloBase/TowerInfo.h b/offline/packages/CaloBase/TowerInfo.h index 821da289d7..2ec6402f2b 100644 --- a/offline/packages/CaloBase/TowerInfo.h +++ b/offline/packages/CaloBase/TowerInfo.h @@ -30,8 +30,8 @@ class TowerInfo : public PHObject virtual float get_pedestal() { return std::numeric_limits::quiet_NaN(); } virtual void set_isHot(bool /*isHot*/) { return; } virtual bool get_isHot() const { return false; } - virtual void set_isBadTime(bool /*isBadTime*/) { return; } - virtual bool get_isBadTime() const { return false; } + virtual void set_FitStatus(bool /*fitstatus*/) { return; } + virtual bool get_FitStatus() const { return false; } virtual void set_isBadChi2(bool /*isBadChi2*/) { return; } virtual bool get_isBadChi2() const { return false; } virtual void set_isNotInstr(bool /*isNotInstr*/) { return; } diff --git a/offline/packages/CaloBase/TowerInfov2.h b/offline/packages/CaloBase/TowerInfov2.h index 8d064d840f..dd8889ff48 100644 --- a/offline/packages/CaloBase/TowerInfov2.h +++ b/offline/packages/CaloBase/TowerInfov2.h @@ -24,8 +24,8 @@ class TowerInfov2 : public TowerInfov1 void set_isHot(bool isHot) override { set_status_bit(0, isHot); } bool get_isHot() const override { return get_status_bit(0); } - void set_isBadTime(bool isBadTime) override { set_status_bit(1, isBadTime); } - bool get_isBadTime() const override { return get_status_bit(1); } + void set_FitStatus(bool fitstatus) override { set_status_bit(1, fitstatus); } + bool get_FitStatus() const override { return get_status_bit(1); } void set_isBadChi2(bool isBadChi2) override { set_status_bit(2, isBadChi2); } bool get_isBadChi2() const override { return get_status_bit(2); } @@ -45,7 +45,7 @@ class TowerInfov2 : public TowerInfov1 void set_isSaturated(bool isSaturated) override { set_status_bit(7, isSaturated); } bool get_isSaturated() const override { return get_status_bit(7); } - bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib()); } + bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib() || get_isNotInstr()); } uint8_t get_status() const override { return _status; } diff --git a/offline/packages/CaloBase/TowerInfov4.h b/offline/packages/CaloBase/TowerInfov4.h index 09bd986298..6a44ca385b 100644 --- a/offline/packages/CaloBase/TowerInfov4.h +++ b/offline/packages/CaloBase/TowerInfov4.h @@ -58,8 +58,8 @@ class TowerInfov4 : public TowerInfo void set_isHot(bool isHot) override { set_status_bit(0, isHot); } bool get_isHot() const override { return get_status_bit(0); } - void set_isBadTime(bool isBadTime) override { set_status_bit(1, isBadTime); } - bool get_isBadTime() const override { return get_status_bit(1); } + void set_FitStatus(bool fitstatus) override { set_status_bit(1, fitstatus); } + bool get_FitStatus() const override { return get_status_bit(1); } void set_isBadChi2(bool isBadChi2) override { set_status_bit(2, isBadChi2); } bool get_isBadChi2() const override { return get_status_bit(2); } @@ -79,7 +79,7 @@ class TowerInfov4 : public TowerInfo void set_isSaturated(bool isSaturated) override { set_status_bit(7, isSaturated); } bool get_isSaturated() const override { return get_status_bit(7); } - bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib()); } + bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib() || get_isNotInstr()); } uint8_t get_status() const override { return status; } diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 5082b9e9c3..ae029e759e 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -240,6 +240,7 @@ int CaloTowerBuilder::process_sim() { towerinfo->set_isRecovered(true); } + towerinfo->set_FitStatus(static_cast(processed_waveforms.at(i).at(5))); int n_samples = waveforms.at(i).size(); if (n_samples == m_nzerosuppsamples || SZS) { diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 86eb680e3e..9ca24be054 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -123,7 +123,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_cdbttree_time = new CDBTTree(calibdir); if (Verbosity() > 0) { - std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_time << " not Doing isBadTime" << std::endl; + std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_time << std::endl; } } else @@ -144,7 +144,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_doTime = false; if (Verbosity() > 1) { - std::cout << "CaloTowerStatus::InitRun no timing info, " << m_calibName_time << " not found, not doing isBadTime" << std::endl; + std::cout << "CaloTowerStatus::InitRun no timing info, " << m_calibName_time << " not found" << std::endl; } } } @@ -259,7 +259,6 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) { // only reset what we will set m_raw_towers->get_tower_at_channel(channel)->set_isHot(false); - m_raw_towers->get_tower_at_channel(channel)->set_isBadTime(false); m_raw_towers->get_tower_at_channel(channel)->set_isBadChi2(false); if (m_doHotChi2) @@ -283,10 +282,6 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) { m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); } - if (!m_raw_towers->get_tower_at_channel(channel)->get_isZS() && std::fabs(time - mean_time) > time_cut && m_doTime) - { - m_raw_towers->get_tower_at_channel(channel)->set_isBadTime(true); - } if (( hotMap_val == 1 || // dead std::fabs(z_score) > z_score_threshold || // hot or cold (hotMap_val == 3 && z_score >= -1 * z_score_threshold_default)) // cold part 2 diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index ba59367542..72e6211f04 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -78,6 +78,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit v.push_back(std::numeric_limits::quiet_NaN()); } v.push_back(0); + v.push_back(0); } else { @@ -119,6 +120,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit v.push_back(std::numeric_limits::quiet_NaN()); } v.push_back(0); + v.push_back(0); } else { @@ -165,10 +167,10 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } fitter->FitFCN(*EPChi2, nullptr, data.Size(), true); ROOT::Fit::FitResult fitres = fitter->Result(); - // get the result status + // get the fit status code (0 means successful fit) + int validfit = fitres.Status(); /* - bool validfit = fitres.IsValid(); - if(!validfit) + if(validfit != 0) { std::cout<<"invalid fit"<> CaloWaveformFitting::calo_processing_templatefit recoverFitter->Config().ParSettings(1).SetLimits(-1 * m_peakTimeTemp, size1 - m_peakTimeTemp); // set lim on time par recoverFitter->FitFCN(*recoverEPChi2, nullptr, recoverData.Size(), true); ROOT::Fit::FitResult recover_fitres = recoverFitter->Result(); + int recover_validfit = recover_fitres.Status(); double recover_chi2min = recover_fitres.MinFcnValue(); recover_chi2min /= size1 - 3; // divide by the number of dof if (recover_chi2min < _chi2lowthreshold && recover_f->GetParameter(2) < _bfr_highpedestalthreshold && recover_f->GetParameter(2) > _bfr_lowpedestalthreshold) @@ -254,6 +257,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } v.push_back(recover_chi2min); v.push_back(1); + v.push_back(recover_validfit); } else { @@ -263,6 +267,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } v.push_back(chi2min); v.push_back(0); + v.push_back(validfit); } recover_f->Delete(); delete recoverFitFunction; @@ -277,6 +282,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } v.push_back(chi2min); v.push_back(0); + v.push_back(validfit); } h->Delete(); f->Delete(); @@ -295,7 +301,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit { const std::vector &tv = chnlvector.at(i); int size2 = tv.size(); - for (int q = 5; q > 0; q--) + for (int q = 6; q > 0; q--) { fit_params_tmp.push_back(tv.at(size2 - q)); } @@ -434,7 +440,7 @@ std::vector> CaloWaveformFitting::calo_processing_fast(const } } amp -= ped; - std::vector val = {amp, time, ped, chi2, 0}; + std::vector val = {amp, time, ped, chi2, 0, 0}; fit_values.push_back(val); val.clear(); } @@ -457,7 +463,7 @@ std::vector> CaloWaveformFitting::calo_processing_nyquist(con { chi2 = 1000000; } - fit_values.push_back({v.at(1) - v.at(0), std::numeric_limits::quiet_NaN(), v.at(0), chi2, 0}); + fit_values.push_back({v.at(1) - v.at(0), std::numeric_limits::quiet_NaN(), v.at(0), chi2, 0, 0}); continue; } @@ -532,7 +538,7 @@ std::vector CaloWaveformFitting::NyquistInterpolation(std::vector float diff = vec_signal_samples[i] - template_function(xval, par); chi2 += diff * diff; } - std::vector val = {max - pedestal, maxpos, pedestal, chi2, 0}; + std::vector val = {max - pedestal, maxpos, pedestal, chi2, 0, 0}; return val; } @@ -720,7 +726,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con { chi2 = 1000000; } - fit_values.push_back({amp, time, ped, chi2, 0}); + fit_values.push_back({amp, time, ped, chi2, 0, 0}); continue; } @@ -761,7 +767,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con { chi2 = 1000000; } - fit_values.push_back({amp, time, ped, chi2, 0}); + fit_values.push_back({amp, time, ped, chi2, 0, 0}); continue; } @@ -794,6 +800,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con double fit_time = 0; double fit_ped = 0; double chi2val = 0; + int validfit = 0; int npar = 0; if (m_funcfit_type == POWERLAWEXP) @@ -820,7 +827,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con f.SetParLimits(4, pedestal - std::abs(maxheight - pedestal), pedestal + std::abs(maxheight - pedestal)); // Perform fit - h.Fit(&f, "QRN0W", "", 0, nsamples); + TFitResultPtr fitres = h.Fit(&f, "SQRN0W", "", 0, nsamples); // Calculate peak amplitude and time from fit parameters // Peak height is (p0 * Power(p2/p3, p2)) / exp(p2) @@ -838,6 +845,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } + validfit = fitres.Status(); } else if(m_funcfit_type == POWERLAWDOUBLEEXP) { @@ -867,7 +875,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con f.SetParLimits(6, risetime * 0.5, risetime * 4); // Perform fit - h.Fit(&f, "QRN0W", "", 0, nsamples); + TFitResultPtr fitres = h.Fit(&f, "SQRN0W", "", 0, nsamples); // Find peak by evaluating the function double peakpos1 = f.GetParameter(3); @@ -888,6 +896,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } + validfit = fitres.Status(); } else if(m_funcfit_type == FERMIEXP) { @@ -911,7 +920,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con f.FixParameter(2, 0.2); - h.Fit(&f, "QRN0W", "", 0, nsamples); + TFitResultPtr fitres = h.Fit(&f, "SQRN0W", "", 0, nsamples); fit_time = f.GetParameter(1); fit_amp = f.GetParameter(0); @@ -926,6 +935,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } + validfit = fitres.Status(); } int ndf = ndata - npar; @@ -939,7 +949,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con } fit_values.push_back({static_cast(fit_amp), static_cast(fit_time), - static_cast(fit_ped), static_cast(chi2val), 0}); + static_cast(fit_ped), static_cast(chi2val), 0, validfit}); } return fit_values; diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 057e427627..ad4993aca4 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -135,6 +135,7 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con val.push_back(std::numeric_limits::quiet_NaN()); } val.push_back(0); + val.push_back(0); fit_values.push_back(val); } else @@ -177,6 +178,7 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con val.push_back(std::numeric_limits::quiet_NaN()); } val.push_back(0); + val.push_back(0); fit_values.push_back(val); } else @@ -195,12 +197,13 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con } val.push_back(2000); val.push_back(0); + val.push_back(0); fit_values.push_back(val); } else { float v_diff = v[1] - v[0]; - std::vector val1{v_diff, std::numeric_limits::quiet_NaN(), v[1], std::numeric_limits::quiet_NaN(), 0}; + std::vector val1{v_diff, std::numeric_limits::quiet_NaN(), v[1], std::numeric_limits::quiet_NaN(), 0, 0}; fit_values.push_back(val1); } } diff --git a/offline/packages/NodeDump/DumpTowerInfoContainer.cc b/offline/packages/NodeDump/DumpTowerInfoContainer.cc index 21f8c99c19..7ae0ae0230 100644 --- a/offline/packages/NodeDump/DumpTowerInfoContainer.cc +++ b/offline/packages/NodeDump/DumpTowerInfoContainer.cc @@ -41,7 +41,6 @@ int DumpTowerInfoContainer::process_Node(PHNode *myNode) *fout << "chi2: " << rawtwr->get_chi2() << std::endl; *fout << "pedestal: " << rawtwr->get_pedestal() << std::endl; *fout << "isHot: " << rawtwr->get_isHot() << std::endl; - *fout << "isBadTime: " << rawtwr->get_isBadTime() << std::endl; *fout << "isNotInstr: " << rawtwr->get_isNotInstr() << std::endl; *fout << "isGood: " << rawtwr->get_isGood() << std::endl; *fout << "status: " << static_cast(rawtwr->get_status()) << std::endl; diff --git a/offline/packages/jetbackground/SubtractTowers.cc b/offline/packages/jetbackground/SubtractTowers.cc index 3d0ee5532e..1c6c51a0db 100644 --- a/offline/packages/jetbackground/SubtractTowers.cc +++ b/offline/packages/jetbackground/SubtractTowers.cc @@ -166,7 +166,7 @@ int SubtractTowers::process_event(PHCompositeNode *topNode) } float new_energy = raw_energy - UE; // if a tower is masked, leave it at zero - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { new_energy = 0; } @@ -259,7 +259,7 @@ int SubtractTowers::process_event(PHCompositeNode *topNode) } float new_energy = raw_energy - UE; // if a tower is masked, leave it at zero - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { new_energy = 0; } @@ -348,7 +348,7 @@ int SubtractTowers::process_event(PHCompositeNode *topNode) } float new_energy = raw_energy - UE; // if a tower is masked, leave it at zero - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { new_energy = 0; } From 8df20942102f6823d1a8aa0c4ddf83dadea748ad Mon Sep 17 00:00:00 2001 From: emclaughlin2 Date: Wed, 25 Feb 2026 14:06:50 -0500 Subject: [PATCH 290/866] Further updates: add fitstatus setter to process data in calotowerbuilder, remove unused time variables in calotowerstatus, use TFitResult* instead of TFitResultPtr object to get status of functional fit results --- offline/packages/CaloReco/CaloTowerBuilder.cc | 1 + offline/packages/CaloReco/CaloTowerStatus.cc | 6 ------ offline/packages/CaloReco/CaloWaveformFitting.cc | 14 ++++++++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index ae029e759e..7f77e48252 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -513,6 +513,7 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { towerinfo->set_isRecovered(true); } + towerinfo->set_FitStatus(static_cast(processed_waveforms.at(i).at(5))); int n_samples = waveforms.at(idx).size(); if (n_samples == m_nzerosuppsamples || SZS) { diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 9ca24be054..6a98789c2f 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -252,7 +252,6 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) { unsigned int ntowers = m_raw_towers->size(); float fraction_badChi2 = 0; - float mean_time = 0; int hotMap_val = 0; float z_score = 0; for (unsigned int channel = 0; channel < ntowers; channel++) @@ -265,17 +264,12 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) { fraction_badChi2 = m_cdbInfo_vec[channel].fraction_badChi2; } - if (m_doTime) - { - mean_time = m_cdbInfo_vec[channel].mean_time; - } if (m_doHotMap) { hotMap_val = m_cdbInfo_vec[channel].hotMap_val; z_score = m_cdbInfo_vec[channel].z_score; } float chi2 = m_raw_towers->get_tower_at_channel(channel)->get_chi2(); - float time = m_raw_towers->get_tower_at_channel(channel)->get_time(); float adc = m_raw_towers->get_tower_at_channel(channel)->get_energy(); if (fraction_badChi2 > fraction_badChi2_threshold && m_doHotChi2) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 72e6211f04..18698ce71d 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -172,11 +173,12 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit /* if(validfit != 0) { - std::cout<<"invalid fit"<> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } - validfit = fitres.Status(); + validfit = fitres.Get()->Status(); } else if(m_funcfit_type == POWERLAWDOUBLEEXP) { @@ -896,7 +898,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } - validfit = fitres.Status(); + validfit = fitres.Get()->Status(); } else if(m_funcfit_type == FERMIEXP) { @@ -935,7 +937,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } - validfit = fitres.Status(); + validfit = fitres.Get()->Status(); } int ndf = ndata - npar; @@ -949,7 +951,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con } fit_values.push_back({static_cast(fit_amp), static_cast(fit_time), - static_cast(fit_ped), static_cast(chi2val), 0, validfit}); + static_cast(fit_ped), static_cast(chi2val), 0, static_cast(validfit)}); } return fit_values; From 8af50390f772fb46a1489a9c07a74d25ba6f67ad Mon Sep 17 00:00:00 2001 From: emclaughlin2 Date: Wed, 25 Feb 2026 14:10:04 -0500 Subject: [PATCH 291/866] Change to correct index mapping when setting FitStatus flag for use in all calorimeters --- offline/packages/CaloReco/CaloTowerBuilder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 7f77e48252..2d0f31a017 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -513,7 +513,7 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { towerinfo->set_isRecovered(true); } - towerinfo->set_FitStatus(static_cast(processed_waveforms.at(i).at(5))); + towerinfo->set_FitStatus(static_cast(processed_waveforms.at(idx).at(5))); int n_samples = waveforms.at(idx).size(); if (n_samples == m_nzerosuppsamples || SZS) { From bab80cba89128593a2b47f511bc549a75a3dc0dd Mon Sep 17 00:00:00 2001 From: emclaughlin2 Date: Wed, 25 Feb 2026 14:20:29 -0500 Subject: [PATCH 292/866] Add protections for null value returned from fit result --- offline/packages/CaloReco/CaloWaveformFitting.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 18698ce71d..307b487d1a 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -169,7 +169,8 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit fitter->FitFCN(*EPChi2, nullptr, data.Size(), true); ROOT::Fit::FitResult fitres = fitter->Result(); // get the fit status code (0 means successful fit) - int validfit = fitres.Status(); + int validfit = 1; + if (fitres) { validfit = fitres.Status(); } /* if(validfit != 0) { @@ -244,7 +245,8 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit recoverFitter->Config().ParSettings(1).SetLimits(-1 * m_peakTimeTemp, size1 - m_peakTimeTemp); // set lim on time par recoverFitter->FitFCN(*recoverEPChi2, nullptr, recoverData.Size(), true); ROOT::Fit::FitResult recover_fitres = recoverFitter->Result(); - int recover_validfit = recover_fitres.Status(); + int recover_validfit = 1; + if (recover_fitres) { recover_validfit = recover_fitres.Status(); } double recover_chi2min = recover_fitres.MinFcnValue(); recover_chi2min /= size1 - 3; // divide by the number of dof if (recover_chi2min < _chi2lowthreshold && recover_f->GetParameter(2) < _bfr_highpedestalthreshold && recover_f->GetParameter(2) > _bfr_lowpedestalthreshold) @@ -847,7 +849,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } - validfit = fitres.Get()->Status(); + if (fitres.Get()) { validfit = fitres.Get()->Status(); } } else if(m_funcfit_type == POWERLAWDOUBLEEXP) { @@ -898,7 +900,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } - validfit = fitres.Get()->Status(); + if (fitres.Get()) { validfit = fitres.Get()->Status(); } } else if(m_funcfit_type == FERMIEXP) { @@ -937,7 +939,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con chi2val += diff * diff; } } - validfit = fitres.Get()->Status(); + if (fitres.Get()) { validfit = fitres.Get()->Status(); } } int ndf = ndata - npar; From f71dca342607aadfe3c5efbd2619e5881a05c8e9 Mon Sep 17 00:00:00 2001 From: emclaughlin2 Date: Wed, 25 Feb 2026 14:27:37 -0500 Subject: [PATCH 293/866] Fix fit result extraction for template fit and recovery template fit --- offline/packages/CaloReco/CaloWaveformFitting.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 307b487d1a..3ea4e36cf1 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -169,8 +169,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit fitter->FitFCN(*EPChi2, nullptr, data.Size(), true); ROOT::Fit::FitResult fitres = fitter->Result(); // get the fit status code (0 means successful fit) - int validfit = 1; - if (fitres) { validfit = fitres.Status(); } + int validfit = fitres.Status(); /* if(validfit != 0) { @@ -245,8 +244,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit recoverFitter->Config().ParSettings(1).SetLimits(-1 * m_peakTimeTemp, size1 - m_peakTimeTemp); // set lim on time par recoverFitter->FitFCN(*recoverEPChi2, nullptr, recoverData.Size(), true); ROOT::Fit::FitResult recover_fitres = recoverFitter->Result(); - int recover_validfit = 1; - if (recover_fitres) { recover_validfit = recover_fitres.Status(); } + int recover_validfit = recover_fitres.Status(); double recover_chi2min = recover_fitres.MinFcnValue(); recover_chi2min /= size1 - 3; // divide by the number of dof if (recover_chi2min < _chi2lowthreshold && recover_f->GetParameter(2) < _bfr_highpedestalthreshold && recover_f->GetParameter(2) > _bfr_lowpedestalthreshold) From b7c498958d2ecc37cb447a7f1ae6dd2db64c1086 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 25 Feb 2026 15:00:39 -0500 Subject: [PATCH 294/866] fix acts propagator --- offline/packages/trackreco/ActsPropagator.cc | 49 ++++++++++---------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 2578f05e61..fa3e2d1152 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -48,12 +48,12 @@ ActsPropagator::makeTrackParams(SvtxTrackState* state, Acts::BoundSquareMatrix cov = transformer.rotateSvtxTrackCovToActs(state); return ActsTrackFittingAlgorithm::TrackParameters::create( - surf, // NOLINT (performance-unnecessary-value-param) - m_geometry->geometry().getGeoContext(), - actsFourPos, momentum, - trackCharge / momentum.norm(), - cov, - Acts::ParticleHypothesis::pion()); + m_geometry->geometry().getGeoContext(), + surf, // NOLINT (performance-unnecessary-value-param) + actsFourPos, momentum, + trackCharge / momentum.norm(), + cov, + Acts::ParticleHypothesis::pion()); } ActsPropagator::BoundTrackParamResult ActsPropagator::makeTrackParams(SvtxTrack* track, @@ -85,13 +85,13 @@ ActsPropagator::makeTrackParams(SvtxTrack* track, Acts::BoundSquareMatrix cov = transformer.rotateSvtxTrackCovToActs(track); - return ActsTrackFittingAlgorithm::TrackParameters::create(perigee, - m_geometry->geometry().getGeoContext(), - actsFourPos, momentum, - track->get_charge() / track->get_p(), - cov, - Acts::ParticleHypothesis::pion(), - 1*Acts::UnitConstants::cm); + return ActsTrackFittingAlgorithm::TrackParameters::create( + m_geometry->geometry().getGeoContext(), perigee, + actsFourPos, momentum, + track->get_charge() / track->get_p(), + cov, + Acts::ParticleHypothesis::pion(), + 1 * Acts::UnitConstants::cm); } ActsPropagator::BTPPairResult @@ -112,15 +112,16 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - using Actors = Acts::ActionList<>; - using Aborters = Acts::AbortList; - - Acts::PropagatorOptions options( + using Actors = Acts::ActorList<>; + using PropagatorOptions = SphenixPropagator::Options; + PropagatorOptions options( m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); + ActsAborter aborter; + aborter.abortlayer = actslayer; + aborter.abortvolume = actsvolume; + options.actorList.append(aborter); - options.abortList.get().abortlayer = actslayer; - options.abortList.get().abortvolume = actsvolume; auto result = propagator.propagate(params, options); @@ -147,7 +148,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - Acts::PropagatorOptions<> options(m_geometry->geometry().getGeoContext(), + SphenixPropagator::Options> options(m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); auto result = propagator.propagate(params, *surface, @@ -175,9 +176,9 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, } auto propagator = makeFastPropagator(); - - Acts::PropagatorOptions<> options(m_geometry->geometry().getGeoContext(), - m_geometry->geometry().magFieldContext); + using Propagator = Acts::Propagator; + Propagator::Options> options(m_geometry->geometry().getGeoContext(), + m_geometry->geometry().magFieldContext); auto result = propagator.propagate(params, *surface, options); @@ -232,7 +233,7 @@ ActsPropagator::SphenixPropagator ActsPropagator::makePropagator() } auto trackingGeometry = m_geometry->geometry().tGeometry; - Stepper stepper(field, m_overstepLimit); + Stepper stepper(field); Acts::Navigator::Config cfg{trackingGeometry}; cfg.resolvePassive = false; cfg.resolveMaterial = true; From c1bb2fe05eebb4bfbcb66bc946903d70e62953ca Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Wed, 25 Feb 2026 15:39:44 -0500 Subject: [PATCH 295/866] use calib name from DB --- offline/packages/jetbackground/TimingCut.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index e2949bbe7b..b706c635a1 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -41,11 +41,11 @@ int TimingCut::Init(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - _fitFile = new CDBTF(CDBInterface::instance()->getUrl("t_ohfrac_calib_Default")); + _fitFile = new CDBTF(CDBInterface::instance()->getUrl("OHCAL_JET_TIME_FRACTION")); if(_fitFile) { _fitFile->LoadCalibrations(); - _fitFunc = _fitFile->getTF("t_ohcal_calib_function_Default"); + _fitFunc = _fitFile->getTF("JET_TIMING_CALO_FRACTION_CALIB_fullrange"); if(!_fitFunc) { std::cout << "ERROR: NO CALIBRATION TF1 FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! This should never happen. ABORT RUN!" << std::endl; From 67f930de9f27637747f9dff340d579924d82b150 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 26 Feb 2026 09:49:09 -0500 Subject: [PATCH 296/866] fix geometry building API --- .../trackbase/TGeoDetectorWithOptions.h | 3 + .../packages/trackreco/MakeActsGeometry.cc | 85 +++++++------------ offline/packages/trackreco/MakeActsGeometry.h | 9 +- 3 files changed, 38 insertions(+), 59 deletions(-) diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.h b/offline/packages/trackbase/TGeoDetectorWithOptions.h index cc8467c92d..bb8fcf9578 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.h +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.h @@ -10,6 +10,7 @@ namespace ActsExamples { class TGeoDetectorWithOptions : public IBaseDetector { public: + TGeoDetectorWithOptions(TGeoDetector::Config config) : m_detector(config) {} TGeoDetector m_detector; void addOptions( @@ -18,6 +19,8 @@ class TGeoDetectorWithOptions : public IBaseDetector { auto finalize(const boost::program_options::variables_map& vm, std::shared_ptr mdecorator) -> std::pair override; + + }; } // namespace ActsExamples diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 07f3dbe71c..a5f196889f 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -664,7 +664,7 @@ void MakeActsGeometry::buildActsSurfaces() // acts/Examples/Run/Common/src/GeometryExampleBase::ProcessGeometry() in MakeActsGeometry() // so we get access to the results. The layer builder magically gets the TGeoManager - makeGeometry(argstr.size(), argv, m_detector); + makeGeometry(argstr.size(), argv, responseFile, materialFile); for (size_t i = 0; i < argstr.size(); ++i) { @@ -707,24 +707,46 @@ void MakeActsGeometry::setMaterialResponseFile(std::string &responseFile, return; } -void MakeActsGeometry::makeGeometry(int argc, char *argv[], - ActsExamples::TGeoDetectorWithOptions &detector) +void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& responseFile, const std::string& materialFile) { + // setup and parse options boost::program_options::options_description desc; ActsExamples::Options::addGeometryOptions(desc); ActsExamples::Options::addMaterialOptions(desc); ActsExamples::Options::addMagneticFieldOptions(desc); + ActsExamples::TGeoDetector::Config config; + config.surfaceLogLevel = Acts::Logging::FATAL; + config.layerLogLevel = Acts::Logging::FATAL; + config.volumeLogLevel = Acts::Logging::FATAL; + config.detectorElementFactory = sPHENIXElementFactory; + config.readJson(responseFile); + + std::shared_ptr matDeco = nullptr; + if (materialFile.find(".json") != std::string::npos || + materialFile.find(".cbor") != std::string::npos) + { + // Set up the converter first + Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig; + // Set up the json-based decorator + matDeco = std::make_shared( + jsonGeoConvConfig, materialFile, Acts::Logging::FATAL); + } + else + { + matDeco = std::make_shared(); + } + config.materialDecorator = matDeco; + // this does the building now. The TGeoDetector owns the + // tracking geometry + ActsExamples::TGeoDetectorWithOptions detector(config); + // Add specific options for this geometry detector.addOptions(desc); auto vm = ActsExamples::Options::parse(desc, argc, argv); - // The geometry, material and decoration - auto geometry = build(vm, detector); - // Geometry is a pair of (tgeoTrackingGeometry, tgeoContextDecorators) - - m_tGeometry = geometry.first; + m_tGeometry = detector.m_detector.trackingGeometry(); if (m_useField) { m_magneticField = ActsExamples::Options::readMagneticField(vm); @@ -741,49 +763,6 @@ void MakeActsGeometry::makeGeometry(int argc, char *argv[], return; } -std::pair, - std::vector>> -MakeActsGeometry::build(const boost::program_options::variables_map &vm, - ActsExamples::TGeoDetectorWithOptions &detector) -{ - // Material decoration - std::shared_ptr matDeco = nullptr; - - // Retrieve the filename - auto fileName = vm["mat-input-file"].template as(); - // json or root based decorator - if (fileName.find(".json") != std::string::npos || - fileName.find(".cbor") != std::string::npos) - { - // Set up the converter first - Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig; - // Set up the json-based decorator - matDeco = std::make_shared( - jsonGeoConvConfig, fileName, Acts::Logging::FATAL); - } - else - { - matDeco = std::make_shared(); - } - - ActsExamples::TGeoDetector::Config config; - - config.elementFactory = sPHENIXElementFactory; - - config.fileName = vm["geo-tgeo-filename"].as(); - - config.surfaceLogLevel = Acts::Logging::FATAL; - config.layerLogLevel = Acts::Logging::FATAL; - config.volumeLogLevel = Acts::Logging::FATAL; - - const auto path = vm["geo-tgeo-jsonconfig"].template as(); - - readTGeoLayerBuilderConfigsFile(path, config); - - // Return the geometry and context decorators - return detector.m_detector.finalize(config, matDeco); -} - void MakeActsGeometry::readTGeoLayerBuilderConfigsFile(const std::string &path, ActsExamples::TGeoDetector::Config &config) { @@ -1082,7 +1061,7 @@ void MakeActsGeometry::makeInttMapPairs(TrackingVolumePtr &inttVolume) TrkrDefs::hitsetkey hitsetkey = getInttHitSetKeyFromCoords(layer, world_center); // Add this surface to the map - std::pair tmp = make_pair(hitsetkey, surf); + std::pair tmp = std::make_pair(hitsetkey, surf); m_clusterSurfaceMapSilicon.insert(tmp); if (Verbosity() > 10) @@ -1219,7 +1198,7 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) } // Add this surface to the map - std::pair tmp = make_pair(hitsetkey, surf); + std::pair tmp = std::make_pair(hitsetkey, surf); m_clusterSurfaceMapSilicon.insert(tmp); if (Verbosity() > 10) diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index f437236131..613a045dda 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -174,13 +174,13 @@ class MakeActsGeometry : public SubsysReco void buildActsSurfaces(); /// Function that mimics ActsExamples::GeometryExampleBase - void makeGeometry(int argc, char *argv[], - ActsExamples::TGeoDetectorWithOptions &detector); + void makeGeometry(int argc, char *argv[], const std::string& responseFile, const std::string& materialFile); #ifndef __CLING__ std::pair, std::vector>> build(const boost::program_options::variables_map &vm, - ActsExamples::TGeoDetectorWithOptions &detector); + ActsExamples::TGeoDetector::Config config, + ActsExamples::TGeoDetectorWithOptions &detector); #endif void readTGeoLayerBuilderConfigsFile(const std::string &path, ActsExamples::TGeoDetector::Config &config); @@ -273,9 +273,6 @@ class MakeActsGeometry : public SubsysReco /// z does not need spacing as the boxes are rotated around the z axis const double half_width_clearance_z = 0.5; - /// The acts geometry object - ActsExamples::TGeoDetectorWithOptions m_detector; - /// Acts geometry objects that are needed to create (for example) the fitter TrackingGeometry m_tGeometry; std::shared_ptr m_magneticField; From e6240d3cd9dbaa5070d24ffc7d5c2b26dcaa2995 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 26 Feb 2026 09:49:28 -0500 Subject: [PATCH 297/866] fix acts evaluator --- offline/packages/trackreco/ActsEvaluator.cc | 12 ++++++------ offline/packages/trackreco/ActsEvaluator.h | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackreco/ActsEvaluator.cc b/offline/packages/trackreco/ActsEvaluator.cc index 9ecdbf2b7a..4a705f99fd 100644 --- a/offline/packages/trackreco/ActsEvaluator.cc +++ b/offline/packages/trackreco/ActsEvaluator.cc @@ -238,7 +238,7 @@ void ActsEvaluator::End() m_trackFile->Close(); } -void ActsEvaluator::visitTrackStates(const Acts::ConstVectorMultiTrajectory& traj, +void ActsEvaluator::visitTrackStates(const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { @@ -276,10 +276,9 @@ void ActsEvaluator::visitTrackStates(const Acts::ConstVectorMultiTrajectory& tra Acts::Vector2 local = Acts::Vector2::Zero(); /// get the local measurement that acts used - std::visit([&](const auto& meas) { - local(0) = meas.parameters()[0]; - local(1) = meas.parameters()[1]; - }, measurements[sourceLink.index()]); + const auto measurement = measurements.getMeasurement(sourceLink.index()); + local(0) = measurement.parameters()[0]; + local(1) = measurement.parameters()[1]; /// Get global position /// This is an arbitrary vector. Doesn't matter in coordinate transformation @@ -396,7 +395,8 @@ void ActsEvaluator::visitTrackStates(const Acts::ConstVectorMultiTrajectory& tra auto covariance = state.predictedCovariance(); /// Local hit residual info - auto H = state.effectiveProjector(); + const auto H = state.projectorSubspaceHelper().fullProjector().topLeftCorner( + state.calibratedSize(), Acts::eBoundSize); auto resCov = cov + H * covariance * H.transpose(); auto residual = state.effectiveCalibrated() - H * parameters; m_res_x_hit.push_back(residual(Acts::eBoundLoc0)); diff --git a/offline/packages/trackreco/ActsEvaluator.h b/offline/packages/trackreco/ActsEvaluator.h index fda1e1ebb8..4af937d018 100644 --- a/offline/packages/trackreco/ActsEvaluator.h +++ b/offline/packages/trackreco/ActsEvaluator.h @@ -9,7 +9,7 @@ #include #include - +#include #include class TTree; @@ -31,7 +31,6 @@ class TrackSeedContainer; using SourceLink = ActsSourceLink; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using Acts::VectorHelpers::eta; using Acts::VectorHelpers::perp; using Acts::VectorHelpers::phi; @@ -83,7 +82,7 @@ class ActsEvaluator void fillFittedTrackParams(const Trajectory::IndexedParameters& paramsMap, const size_t& trackTip); - void visitTrackStates(const Acts::ConstVectorMultiTrajectory& traj, + void visitTrackStates(const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); From 9ea65df7b45f76d4bc53937ce7b2f7778a3afe2a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 26 Feb 2026 09:56:04 -0500 Subject: [PATCH 298/866] geometry builder compiles --- offline/packages/trackreco/MakeActsGeometry.cc | 1 + offline/packages/trackreco/MakeActsGeometry.h | 1 + 2 files changed, 2 insertions(+) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index a5f196889f..de0e1d644f 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -59,6 +59,7 @@ #include #include #include +#include #include #include diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index 613a045dda..a362bace41 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -41,6 +41,7 @@ class TGeoVolume; namespace Acts { class Surface; + class SurfaceArray; } using Surface = std::shared_ptr; From a4193691af546c2ee17ec7a92fab5311dd27540b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 26 Feb 2026 14:17:09 -0500 Subject: [PATCH 299/866] makesourcelinks compiles --- offline/packages/trackreco/MakeSourceLinks.cc | 14 +++++++------- offline/packages/trackreco/MakeSourceLinks.h | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/offline/packages/trackreco/MakeSourceLinks.cc b/offline/packages/trackreco/MakeSourceLinks.cc index f9038d182e..d607a4be96 100644 --- a/offline/packages/trackreco/MakeSourceLinks.cc +++ b/offline/packages/trackreco/MakeSourceLinks.cc @@ -23,6 +23,8 @@ #include #include +#include + #include #include @@ -257,7 +259,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( SourceLink sl(surf->geometryId(), index, cluskey); Acts::SourceLink actsSL{sl}; - Acts::Measurement meas(actsSL, indices, loc, cov); + measurements.emplaceMeasurement<2>(surf->geometryId(), indices, loc, cov); if (m_verbosity > 3) { unsigned int this_layer = TrkrDefs::getLayer(cluskey); @@ -268,10 +270,10 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( << ", cov : " << cov.transpose() << std::endl << " geo id " << sl.geometryId() << std::endl; std::cout << "Surface original transform: " << std::endl; - surf.get()->toStream(tGeometry->geometry().getGeoContext(), std::cout); + surf.get()->toStream(tGeometry->geometry().getGeoContext()); std::cout << std::endl << "Surface transient transform: " << std::endl; - surf.get()->toStream(transient_geocontext, std::cout); + surf.get()->toStream(transient_geocontext); std::cout << std::endl; std::cout << "Corrected surface transform:" << std::endl; std::cout << transformMapTransient->getTransform(surf->geometryId()).matrix() << std::endl; @@ -284,7 +286,6 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( } sourcelinks.push_back(actsSL); - measurements.emplace_back(meas); } SLTrackTimer.stop(); @@ -544,7 +545,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( SourceLink sl(surf->geometryId(), index, cluskey); Acts::SourceLink actsSL{sl}; - Acts::Measurement meas(actsSL, indices, loc, cov); + measurements.emplaceMeasurement<2>(surf->geometryId(), indices, loc, cov); if (m_verbosity > 3) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - source link " << sl.index() << ", loc : " @@ -552,7 +553,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( << ", cov : " << cov.transpose() << std::endl << " geo id " << sl.geometryId() << std::endl; std::cout << "Surface : " << std::endl; - surf.get()->toStream(tGeometry->geometry().getGeoContext(), std::cout); + surf.get()->toStream(tGeometry->geometry().getGeoContext()); std::cout << std::endl; std::cout << "Cluster error " << cluster->getRPhiError() << " , " << cluster->getZError() << std::endl; std::cout << "For key " << cluskey << " with local pos " << std::endl @@ -561,7 +562,6 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } sourcelinks.push_back(actsSL); - measurements.emplace_back(meas); } SLTrackTimer.stop(); diff --git a/offline/packages/trackreco/MakeSourceLinks.h b/offline/packages/trackreco/MakeSourceLinks.h index d22acc4881..7cabf268dc 100644 --- a/offline/packages/trackreco/MakeSourceLinks.h +++ b/offline/packages/trackreco/MakeSourceLinks.h @@ -74,6 +74,7 @@ class MakeSourceLinks short int crossing); private: + int m_verbosity = 0; bool m_pp_mode = false; std::set m_ignoreLayer; From 47d12f1bb92ad0c8faa0df773166cee078d073c1 Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Thu, 26 Feb 2026 14:20:45 -0500 Subject: [PATCH 300/866] Implement suggested fixes from coderabbit and Chris for timing cut module. --- offline/packages/jetbackground/TimingCut.cc | 20 ++++--- offline/packages/jetbackground/TimingCut.h | 60 ++++++++++----------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index b706c635a1..c4c23a1a36 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -41,11 +41,13 @@ int TimingCut::Init(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - _fitFile = new CDBTF(CDBInterface::instance()->getUrl("OHCAL_JET_TIME_FRACTION")); - if(_fitFile) + std::string fitUrl = CDBInterface::instance()->getUrl("OHCAL_JET_TIME_FRACTION"); + if(!fitUrl.empty()) { - _fitFile->LoadCalibrations(); - _fitFunc = _fitFile->getTF("JET_TIMING_CALO_FRACTION_CALIB_fullrange"); + CDBTF* fitFile = new CDBTF(fitUrl); + fitFile->LoadCalibrations(); + _fitFunc = (TF1*)fitFile->getTF("JET_TIMING_CALO_FRACTION_CALIB_fullrange")->Clone(); + delete fitFile; if(!_fitFunc) { std::cout << "ERROR: NO CALIBRATION TF1 FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! This should never happen. ABORT RUN!" << std::endl; @@ -125,10 +127,16 @@ int TimingCut::process_event(PHCompositeNode *topNode) { unsigned int channel = comp.second; TowerInfo* tower = towersOH->get_tower_at_channel(channel); + if(!tower) + { + std::cout << "Component tower missing! This should not happen (something is wrong, check your inputs). Abort event!" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } jetOHFrac += tower->get_energy(); } } - jetOHFrac /= jet->get_e(); + jetOHFrac /= jet->get_e(); //We actually want this to be NaN when jet->get_e() == 0, because that case should fail. + //NaN always compares to false } else { @@ -166,7 +174,7 @@ int TimingCut::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - float corrMaxJett = Correct_Time_Ohfrac(maxJett, maxJetOHFrac); + float corrMaxJett = Correct_Time_Ohfrac(maxJett, maxJetOHFrac); //likewise, intentional NaNs here. float corrSubJett = Correct_Time_Ohfrac(subJett, subJetOHFrac); bool passDeltat = Pass_Delta_t(corrMaxJett, corrSubJett, maxJetPhi, subJetPhi); diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index 5fa3a134bc..c0db8a4ab0 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -23,35 +23,6 @@ class TimingCut : public SubsysReco ~TimingCut() override = default; - float Correct_Time_Ohfrac(float t, float ohfrac) - { - float corrt = t - _fitFunc->Eval(ohfrac); - return corrt; - } - - float calc_dphi(float maxJetPhi, float subJetPhi) - { - float dPhi = std::abs(maxJetPhi - subJetPhi); - if(dPhi>M_PI) dPhi -= M_PI; - return dPhi; - } - - bool Pass_Delta_t(float lead_time, float sub_time, float maxJetPhi, float subJetPhi) - { - float dPhi = calc_dphi(maxJetPhi, subJetPhi); - return (std::abs(lead_time - sub_time) < _dt_width && dPhi > _min_dphi); - } - - bool Pass_Lead_t(float lead_time) - { - return std::abs(lead_time + _t_shift) < _t_width; - } - - bool Pass_Mbd_dt(float lead_time, float mbd_time) - { - return std::abs(lead_time - mbd_time) < _mbd_dt_width; - } - void set_t_shift(float new_shift) { _t_shift = new_shift; } float get_t_shift() { return _t_shift; } @@ -102,6 +73,36 @@ class TimingCut : public SubsysReco } private: + + float Correct_Time_Ohfrac(float t, float ohfrac) + { + float corrt = t - _fitFunc->Eval(ohfrac); + return corrt; + } + + float calc_dphi(float maxJetPhi, float subJetPhi) + { + float dPhi = std::abs(maxJetPhi - subJetPhi); + if(dPhi>M_PI) dPhi -= M_PI; + return dPhi; + } + + bool Pass_Delta_t(float lead_time, float sub_time, float maxJetPhi, float subJetPhi) + { + float dPhi = calc_dphi(maxJetPhi, subJetPhi); + return (std::abs(lead_time - sub_time) < _dt_width && dPhi > _min_dphi); + } + + bool Pass_Lead_t(float lead_time) + { + return std::abs(lead_time + _t_shift) < _t_width; + } + + bool Pass_Mbd_dt(float lead_time, float mbd_time) + { + return std::abs(lead_time - mbd_time) < _mbd_dt_width; + } + bool _doAbort; bool _abortFailMbd = false; bool _missingInfoWarningPrinted = false; @@ -113,7 +114,6 @@ class TimingCut : public SubsysReco float _t_shift{0.0}; float _mbd_dt_width{3.0}; float _min_dphi{3*M_PI/4}; - CDBTF* _fitFile{nullptr}; TF1* _fitFunc{nullptr}; }; From a1b48d8f4774f51c8384ce3f7af87b02108fe438 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 26 Feb 2026 14:47:43 -0500 Subject: [PATCH 301/866] gsf compiles --- offline/packages/trackreco/PHActsGSF.cc | 8 ++++---- offline/packages/trackreco/PHActsGSF.h | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/PHActsGSF.cc b/offline/packages/trackreco/PHActsGSF.cc index 4d75b257dd..6523e87beb 100644 --- a/offline/packages/trackreco/PHActsGSF.cc +++ b/offline/packages/trackreco/PHActsGSF.cc @@ -102,7 +102,7 @@ int PHActsGSF::InitRun(PHCompositeNode* topNode) m_tGeometry->geometry().magField, bha, 12, 1e-4, - MixtureReductionAlgorithm::KLDistance, false, false); + MixtureReductionAlgorithm::KLDistance, false, false,100.); if (m_actsEvaluator) { @@ -233,7 +233,7 @@ int PHActsGSF::process_event(PHCompositeNode* topNode) auto magcontext = m_tGeometry->geometry().magFieldContext; auto calcontext = m_tGeometry->geometry().calibContext; - auto ppoptions = Acts::PropagatorPlainOptions(); + auto ppoptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); ActsTrackFittingAlgorithm::GeneralFitterOptions options{ m_transient_geocontext, @@ -294,8 +294,8 @@ ActsTrackFittingAlgorithm::TrackParameters PHActsGSF::makeSeed(SvtxTrack* track, ActsTransformations transformer; auto cov = transformer.rotateSvtxTrackCovToActs(track); - return ActsTrackFittingAlgorithm::TrackParameters::create(psurf, - m_tGeometry->geometry().getGeoContext(), + return ActsTrackFittingAlgorithm::TrackParameters::create(m_tGeometry->geometry().getGeoContext(), + psurf, fourpos, momentum, charge / momentum.norm(), diff --git a/offline/packages/trackreco/PHActsGSF.h b/offline/packages/trackreco/PHActsGSF.h index ce5bea1749..0a1561675a 100644 --- a/offline/packages/trackreco/PHActsGSF.h +++ b/offline/packages/trackreco/PHActsGSF.h @@ -37,7 +37,6 @@ class SvtxTrack; using SourceLink = ActsSourceLink; using FitResult = ActsTrackFittingAlgorithm::TrackFitterResult; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using SurfacePtrVec = std::vector; using SourceLinkVec = std::vector; From 7f2886ad4d1bb46b5d9a06d653a29509411d6cc8 Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 26 Feb 2026 16:15:06 -0500 Subject: [PATCH 302/866] Return NAN for TrackSeed calls to get seed indices --- offline/packages/trackbase_historic/TrackSeed.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeed.h b/offline/packages/trackbase_historic/TrackSeed.h index 3d99703500..4289bf4ce6 100644 --- a/offline/packages/trackbase_historic/TrackSeed.h +++ b/offline/packages/trackbase_historic/TrackSeed.h @@ -49,8 +49,8 @@ class TrackSeed : public PHObject virtual float get_py() const { return NAN; } virtual short int get_crossing() const { return 0; } - virtual unsigned int get_silicon_seed_index() const { return 0; } - virtual unsigned int get_tpc_seed_index() const { return 0; } + virtual unsigned int get_silicon_seed_index() const { return NAN; } + virtual unsigned int get_tpc_seed_index() const { return NAN; } virtual short int get_crossing_estimate() const { return 0; } virtual bool empty_cluster_keys() const { return true; } From f5df20f116bd0ccbc0c20caccaeefd15194319c2 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:24:14 -0500 Subject: [PATCH 303/866] CaloTowerStatus - Remove Remnants of Timing Status - `meanTime` calib is no longer used in CaloTowerStatus due to removal of the isBadTime method --- offline/packages/CaloReco/CaloTowerStatus.cc | 42 +------------------- offline/packages/CaloReco/CaloTowerStatus.h | 26 ------------ 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 6a98789c2f..81013f9790 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -48,7 +48,6 @@ CaloTowerStatus::~CaloTowerStatus() std::cout << "CaloTowerStatus::~CaloTowerStatus() Calling dtor" << std::endl; } delete m_cdbttree_chi2; - delete m_cdbttree_time; delete m_cdbttree_hotMap; } @@ -114,41 +113,6 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) } } - m_calibName_time = m_detector + "_meanTime"; - m_fieldname_time = "time"; - - calibdir = CDBInterface::instance()->getUrl(m_calibName_time); - if (!calibdir.empty()) - { - m_cdbttree_time = new CDBTTree(calibdir); - if (Verbosity() > 0) - { - std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_time << std::endl; - } - } - else - { - if (use_directURL_time) - { - calibdir = m_directURL_time; - std::cout << "CaloTowerStatus::InitRun: Using default time " << calibdir << std::endl; - m_cdbttree_time = new CDBTTree(calibdir); - } - else - { - if (m_doAbortNoTime) - { - std::cout << "CaloTowerStatus::InitRun: No time calibration found for " << m_calibName_time << " and abort mode is set. Exiting." << std::endl; - gSystem->Exit(1); - } - m_doTime = false; - if (Verbosity() > 1) - { - std::cout << "CaloTowerStatus::InitRun no timing info, " << m_calibName_time << " not found" << std::endl; - } - } - } - m_calibName_hotMap = m_detector + "nome"; if (m_dettype == CaloTowerDefs::CEMC || m_dettype == CaloTowerDefs::SEPD) { @@ -191,7 +155,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) if (Verbosity() > 0) { - std::cout << "CaloTowerStatus::Init " << m_detector << " doing time status =" << std::boolalpha << m_doTime << " doing hotBadChi2=" << std::boolalpha << m_doHotChi2 << " doing hot map=" << std::boolalpha << m_doHotMap << std::endl; + std::cout << "CaloTowerStatus::Init " << m_detector << " doing hotBadChi2=" << std::boolalpha << m_doHotChi2 << " doing hot map=" << std::boolalpha << m_doHotMap << std::endl; } PHNodeIterator iter(topNode); @@ -235,10 +199,6 @@ void CaloTowerStatus::LoadCalib() { m_cdbInfo_vec[channel].fraction_badChi2 = m_cdbttree_chi2->GetFloatValue(key, m_fieldname_chi2); } - if (m_doTime) - { - m_cdbInfo_vec[channel].mean_time = m_cdbttree_time->GetFloatValue(key, m_fieldname_time); - } if (m_doHotMap) { m_cdbInfo_vec[channel].hotMap_val = m_cdbttree_hotMap->GetIntValue(key, m_fieldname_hotMap); diff --git a/offline/packages/CaloReco/CaloTowerStatus.h b/offline/packages/CaloReco/CaloTowerStatus.h index 646116368d..1c50486281 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.h +++ b/offline/packages/CaloReco/CaloTowerStatus.h @@ -68,23 +68,12 @@ class CaloTowerStatus : public SubsysReco z_score_threshold = threshold; return; } - void set_time_cut(float threshold) - { - time_cut = threshold; - return; - } void set_directURL_hotMap(const std::string &str) { m_directURL_hotMap = str; use_directURL_hotMap = true; return; } - void set_directURL_time(const std::string &str) - { - m_directURL_time = str; - use_directURL_time = true; - return; - } void set_directURL_chi2(const std::string &str) { m_directURL_chi2 = str; @@ -96,11 +85,6 @@ class CaloTowerStatus : public SubsysReco m_doAbortNoHotMap = status; return; } - void set_doAbortNoTime(bool status = true) - { - m_doAbortNoTime = status; - return; - } void set_doAbortNoChi2(bool status = true) { m_doAbortNoChi2 = status; @@ -109,7 +93,6 @@ class CaloTowerStatus : public SubsysReco void set_doAbortMissingCalib(bool status = true) { m_doAbortNoHotMap = status; - m_doAbortNoTime = status; m_doAbortNoChi2 = status; return; } @@ -118,21 +101,16 @@ class CaloTowerStatus : public SubsysReco TowerInfoContainer *m_raw_towers{nullptr}; CDBTTree *m_cdbttree_chi2{nullptr}; - CDBTTree *m_cdbttree_time{nullptr}; CDBTTree *m_cdbttree_hotMap{nullptr}; bool m_doHotChi2{true}; - bool m_doTime{true}; bool m_doHotMap{true}; bool m_doAbortNoHotMap{false}; - bool m_doAbortNoTime{false}; bool m_doAbortNoChi2{false}; CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::DETECTOR_INVALID}; std::string m_detector; - std::string m_fieldname_time; - std::string m_calibName_time; std::string m_fieldname_chi2; std::string m_calibName_chi2; std::string m_fieldname_hotMap; @@ -141,10 +119,8 @@ class CaloTowerStatus : public SubsysReco std::string m_inputNodePrefix{"TOWERS_"}; std::string m_inputNode; - std::string m_directURL_time; std::string m_directURL_hotMap; std::string m_directURL_chi2; - bool use_directURL_time{false}; bool use_directURL_hotMap{false}; bool use_directURL_chi2{false}; @@ -154,14 +130,12 @@ class CaloTowerStatus : public SubsysReco float fraction_badChi2_threshold = {0.01}; float z_score_threshold = {5}; float z_score_threshold_default = {5}; - float time_cut = 2; // number of samples from the mean time for the channel in the run void LoadCalib(); struct CDBInfo { float fraction_badChi2{0}; - float mean_time{0}; float z_score{0}; int hotMap_val{0}; }; From d619a978916db9fb454ad3725d25662a77a87a3c Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 26 Feb 2026 18:21:24 -0500 Subject: [PATCH 304/866] Turn skimming on by default Request from Blair to skim by default. --- .../Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index ec03c20839..5c955f358e 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -51,19 +51,19 @@ class CaloStatusSkimmer : public SubsysReco { uint32_t n_skimcounter{0}; uint32_t n_notowernodecounter{0}; - bool b_do_skim_EMCal{false}; + bool b_do_skim_EMCal{true}; uint16_t m_EMC_skim_threshold{192}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in EMCal - bool b_do_skim_HCal{false}; + bool b_do_skim_HCal{true}; uint16_t m_HCal_skim_threshold{192}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in HCal - bool b_do_skim_sEPD{false}; + bool b_do_skim_sEPD{true}; uint16_t m_sEPD_skim_threshold{1}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in sEPD - bool b_do_skim_ZDC{false}; + bool b_do_skim_ZDC{true}; uint16_t m_ZDC_skim_threshold{1}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in ZDC }; From 4b73dffc279e56f8d6f9173989a82bc2d6be9f6c Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 26 Feb 2026 18:35:32 -0500 Subject: [PATCH 305/866] Using max unsigned int instead of NAN --- offline/packages/trackbase_historic/TrackSeed.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackbase_historic/TrackSeed.h b/offline/packages/trackbase_historic/TrackSeed.h index 4289bf4ce6..371bf557ab 100644 --- a/offline/packages/trackbase_historic/TrackSeed.h +++ b/offline/packages/trackbase_historic/TrackSeed.h @@ -49,8 +49,8 @@ class TrackSeed : public PHObject virtual float get_py() const { return NAN; } virtual short int get_crossing() const { return 0; } - virtual unsigned int get_silicon_seed_index() const { return NAN; } - virtual unsigned int get_tpc_seed_index() const { return NAN; } + virtual unsigned int get_silicon_seed_index() const { return std::numeric_limits::max(); } + virtual unsigned int get_tpc_seed_index() const { return std::numeric_limits::max(); } virtual short int get_crossing_estimate() const { return 0; } virtual bool empty_cluster_keys() const { return true; } From 31c5c2aab67b6307d55a6847c8e296bbcefd2175 Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Thu, 26 Feb 2026 19:42:04 -0500 Subject: [PATCH 306/866] fix dphi calculation, guard against memory leaks and nullptr dereference --- offline/packages/jetbackground/TimingCut.cc | 7 ++++--- offline/packages/jetbackground/TimingCut.h | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index c4c23a1a36..24dfb03c11 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -46,13 +46,14 @@ int TimingCut::Init(PHCompositeNode *topNode) { CDBTF* fitFile = new CDBTF(fitUrl); fitFile->LoadCalibrations(); - _fitFunc = (TF1*)fitFile->getTF("JET_TIMING_CALO_FRACTION_CALIB_fullrange")->Clone(); - delete fitFile; - if(!_fitFunc) + TF1* tmp = fitFile->getTF("JET_TIMING_CALO_FRACTION_CALIB_fullrange"); + if(!tmp) { std::cout << "ERROR: NO CALIBRATION TF1 FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! This should never happen. ABORT RUN!" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } + _fitFunc = std::unique_ptr((TF1*)tmp->Clone()); + delete fitFile; } else { diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index c0db8a4ab0..000dc196a7 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -12,6 +12,7 @@ #include #include #include +#include class CDBTF; class PHCompositeNode; @@ -83,7 +84,7 @@ class TimingCut : public SubsysReco float calc_dphi(float maxJetPhi, float subJetPhi) { float dPhi = std::abs(maxJetPhi - subJetPhi); - if(dPhi>M_PI) dPhi -= M_PI; + if(dPhi>M_PI) dPhi = 2*M_PI - dPhi; return dPhi; } @@ -114,7 +115,7 @@ class TimingCut : public SubsysReco float _t_shift{0.0}; float _mbd_dt_width{3.0}; float _min_dphi{3*M_PI/4}; - TF1* _fitFunc{nullptr}; + std::unique_ptr _fitFunc{nullptr}; }; #endif From 35f1556f5000291337dba26ac2525e8f4b49e612 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 26 Feb 2026 21:12:18 -0500 Subject: [PATCH 307/866] added get_pederr(), etc --- offline/packages/mbd/MbdCalib.cc | 2 +- offline/packages/mbd/MbdCalib.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index e8d10ba00a..578fead8ac 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -1540,7 +1540,7 @@ int MbdCalib::Download_Pileup(const std::string& dbase_location) if (Verbosity() > 0) { - if (feech < 2 || feech >= MbdDefs::MBD_N_PMT - 2) + if (feech < 2 || feech >= MbdDefs::MBD_N_FEECH - 2) { std::cout << feech << "\t" << _pileup_p0[feech] << "\t" << _pileup_p0err[feech] << "\t" << _pileup_p1[feech] << "\t" << _pileup_p1err[feech] diff --git a/offline/packages/mbd/MbdCalib.h b/offline/packages/mbd/MbdCalib.h index 6f0a6e579a..65b5a52fee 100644 --- a/offline/packages/mbd/MbdCalib.h +++ b/offline/packages/mbd/MbdCalib.h @@ -35,7 +35,9 @@ class MbdCalib float get_tq0(const int ipmt) const { return _tqfit_t0mean[ipmt]; } float get_t0corr() const { return _t0corrmean; } float get_ped(const int ifeech) const { return _pedmean[ifeech]; } + float get_pederr(const int ifeech) const { return _pedmeanerr[ifeech]; } float get_pedrms(const int ifeech) const { return _pedsigma[ifeech]; } + float get_pedrmserr(const int ifeech) const { return _pedsigmaerr[ifeech]; } int get_sampmax(const int ifeech) const { return _sampmax[ifeech]; } int get_status(const int ifeech) const { return _mbdstatus[ifeech]; } From 37ff672c2080c2cb37f8ab4c1e373e03f90a7d94 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 27 Feb 2026 08:57:37 -0500 Subject: [PATCH 308/866] add cluster map name setter --- offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc | 4 ++-- offline/packages/trackreco/PHMicromegasTpcTrackMatching.h | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc index 197d7039e3..a6294c7ff0 100644 --- a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc @@ -889,12 +889,12 @@ int PHMicromegasTpcTrackMatching::GetNodes(PHCompositeNode* topNode) } else { - _cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + _cluster_map = findNode::getClass(topNode, _clustermap_name); } if (!_cluster_map) { - std::cerr << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl; + std::cerr << PHWHERE << " ERROR: Can't find node " << _clustermap_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h index 58d2004041..7f9f8e2611 100644 --- a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h +++ b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h @@ -42,13 +42,13 @@ class PHMicromegasTpcTrackMatching : public SubsysReco void set_pt_cut( const float pt) { _pt_cut = pt; } void set_dphi_cut( const float dphi) { _dphi_cut = dphi; } void SetIteration(int iter) { _n_iteration = iter; } - + void set_clustermap_name(const std::string& name) { _clustermap_name = name; } void zeroField(const bool flag) { _zero_field = flag; } int Init(PHCompositeNode* topNode) override; int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode*) override; int End(PHCompositeNode*) override; - + // deprecated calls inline void set_sc_calib_mode(const bool) {} inline void set_collision_rate(const double) {} @@ -89,6 +89,8 @@ class PHMicromegasTpcTrackMatching : public SubsysReco TrackSeedContainer* _tpc_track_map{nullptr}; TrackSeedContainer* _si_track_map{nullptr}; + std::string _clustermap_name = "TRKR_CLUSTER"; + //! default rphi search window for each layer std::array _rphi_search_win{0.25, 13.0}; From 5ca6985357ee2e10b8fb661dcd3d609d39301bbe Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 27 Feb 2026 09:01:45 -0500 Subject: [PATCH 309/866] fixes bounds for histogram --- offline/QA/Tracking/SiliconSeedsQA.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/QA/Tracking/SiliconSeedsQA.cc b/offline/QA/Tracking/SiliconSeedsQA.cc index 012caf26ff..6f2ba5e91a 100644 --- a/offline/QA/Tracking/SiliconSeedsQA.cc +++ b/offline/QA/Tracking/SiliconSeedsQA.cc @@ -233,7 +233,7 @@ void SiliconSeedsQA::createHistos() } { - h_ntrack1d = new TH1F(std::string(getHistoPrefix() + "nrecotracks1d").c_str(), "Number of reconstructed tracks;Number of silicon tracklets;Entries", 50, 0, 200); + h_ntrack1d = new TH1F(std::string(getHistoPrefix() + "nrecotracks1d").c_str(), "Number of reconstructed tracks;Number of silicon tracklets;Entries", 500, 0, 2000); hm->registerHisto(h_ntrack1d); } @@ -304,7 +304,7 @@ void SiliconSeedsQA::createHistos() // vertex { - h_nvertex = new TH1F(std::string(getHistoPrefix() + "nrecovertices").c_str(), "Num of reco vertices per event;Number of vertices;Entries", 20, 0, 20); + h_nvertex = new TH1F(std::string(getHistoPrefix() + "nrecovertices").c_str(), "Num of reco vertices per event;Number of vertices;Entries", 60, 0, 60); hm->registerHisto(h_nvertex); } From 74aacf800079855e7fbd702cc6ad7e043fe27eaf Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Fri, 27 Feb 2026 12:10:41 -0500 Subject: [PATCH 310/866] do away with bools Check if the threshold is greater than 0, and If it is 0 do not skim. Modify methods to only take thresholds. --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 8 ++++---- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 17 +++++------------ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 0447bf5ba6..73dce5e912 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -23,7 +23,7 @@ CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { n_eventcounter++; - if (b_do_skim_EMCal) + if (m_EMC_skim_threshold > 0) { TowerInfoContainer *towers = findNode::getClass(topNode, "TOWERS_CEMC"); @@ -58,7 +58,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } - if (b_do_skim_HCal) + if (m_HCal_skim_threshold > 0) { TowerInfoContainer *hcalin_towers = findNode::getClass(topNode, "TOWERS_HCALIN"); TowerInfoContainer *hcalout_towers = findNode::getClass(topNode, "TOWERS_HCALOUT"); @@ -107,7 +107,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } - if (b_do_skim_sEPD) + if (m_sEPD_skim_threshold > 0) { TowerInfoContainer *sepd_towers = findNode::getClass(topNode, "TOWERS_SEPD"); @@ -143,7 +143,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } - if (b_do_skim_ZDC) + if (m_ZDC_skim_threshold > 0) { TowerInfoContainer *zdc_towers = findNode::getClass(topNode, "TOWERS_ZDC"); diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 5c955f358e..433b8d08c0 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -26,23 +26,19 @@ class CaloStatusSkimmer : public SubsysReco { /// Called at the end of all processing. int End(PHCompositeNode *topNode) override; - void do_skim_EMCal(bool do_skim, uint16_t threshold) { - b_do_skim_EMCal = do_skim; + void do_skim_EMCal( uint16_t threshold) { m_EMC_skim_threshold = threshold; } - void do_skim_HCal(bool do_skim, uint16_t threshold) { - b_do_skim_HCal = do_skim; + void do_skim_HCal( uint16_t threshold) { m_HCal_skim_threshold = threshold; } - void do_skim_sEPD(bool do_skim, uint16_t threshold) { - b_do_skim_sEPD = do_skim; + void do_skim_sEPD( uint16_t threshold) { m_sEPD_skim_threshold = threshold; } - void do_skim_ZDC(bool do_skim, uint16_t threshold) { - b_do_skim_ZDC = do_skim; + void do_skim_ZDC( uint16_t threshold) { m_ZDC_skim_threshold = threshold; } @@ -51,19 +47,16 @@ class CaloStatusSkimmer : public SubsysReco { uint32_t n_skimcounter{0}; uint32_t n_notowernodecounter{0}; - bool b_do_skim_EMCal{true}; + // If the threshold is set to 0, then the skimming for that subsystem is disabled. If threshold is > 0, then the event is skimmed if nchannels >= threshold not-instrumented (empty/missing packet) channels in that subsystem. uint16_t m_EMC_skim_threshold{192}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in EMCal - bool b_do_skim_HCal{true}; uint16_t m_HCal_skim_threshold{192}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in HCal - bool b_do_skim_sEPD{true}; uint16_t m_sEPD_skim_threshold{1}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in sEPD - bool b_do_skim_ZDC{true}; uint16_t m_ZDC_skim_threshold{1}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in ZDC }; From 8a4c1418be56e864bc5a165dea18cb55a46249fc Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 27 Feb 2026 13:16:20 -0500 Subject: [PATCH 311/866] fix include --- offline/packages/trackbase/TGeoDetectorWithOptions.h | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.h b/offline/packages/trackbase/TGeoDetectorWithOptions.h index bb8fcf9578..fa93e10b62 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.h +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.h @@ -4,7 +4,6 @@ #include "IBaseDetector.h" #include -#include namespace ActsExamples { From c547c80a0210999d7cf673397f277688c52c9595 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 27 Feb 2026 14:19:02 -0500 Subject: [PATCH 312/866] add fwd decl --- offline/packages/trackbase/IBaseDetector.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase/IBaseDetector.h b/offline/packages/trackbase/IBaseDetector.h index a52e5f1b0b..527d565307 100644 --- a/offline/packages/trackbase/IBaseDetector.h +++ b/offline/packages/trackbase/IBaseDetector.h @@ -8,12 +8,20 @@ #pragma once -#include "ActsExamples/Utilities/OptionsFwd.hpp" - #include #include #include - +namespace boost::program_options +{ + class options_description; + class variables_map; +} // namespace boost::program_options + +namespace ActsExamples::Options +{ + using Description = ::boost::program_options::options_description; + using Variables = ::boost::program_options::variables_map; +} // namespace ActsExamples::Options namespace Acts { class TrackingGeometry; class IMaterialDecorator; From d2e9a1c5dae0de2406d7eafa9c319bd7c71b302c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 27 Feb 2026 14:19:46 -0500 Subject: [PATCH 313/866] add some updates for compilation --- offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h | 2 +- offline/packages/trackbase_historic/ActsTransformations.cc | 2 +- offline/packages/trackbase_historic/ActsTransformations.h | 2 +- offline/packages/trackreco/MakeActsGeometry.h | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h b/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h index 7b418a0b62..d0de5fadbd 100644 --- a/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h +++ b/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h @@ -62,7 +62,7 @@ namespace MixtureReductionAlgorithm::KLDistance; Acts::ComponentMergeMethod mergeMethod = Acts::ComponentMergeMethod::eMaxWeight; - double reverseFilteringCovarianceScaling = 1.0; + double reverseFilteringCovarianceScaling = 100.; ActsSourceLink::SurfaceAccessor m_slSurfaceAccessor; GsfFitterFunctionImpl(Fitter&& f, diff --git a/offline/packages/trackbase_historic/ActsTransformations.cc b/offline/packages/trackbase_historic/ActsTransformations.cc index ae76cec640..f987d31cf2 100644 --- a/offline/packages/trackbase_historic/ActsTransformations.cc +++ b/offline/packages/trackbase_historic/ActsTransformations.cc @@ -286,7 +286,7 @@ void ActsTransformations::calculateDCA(const Acts::BoundTrackParameters& param, } void ActsTransformations::fillSvtxTrackStates( - const Acts::ConstVectorMultiTrajectory& traj, + const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, SvtxTrack* svtxTrack, const Acts::GeometryContext& geoContext) const diff --git a/offline/packages/trackbase_historic/ActsTransformations.h b/offline/packages/trackbase_historic/ActsTransformations.h index 3cc90b7311..986488b4ea 100644 --- a/offline/packages/trackbase_historic/ActsTransformations.h +++ b/offline/packages/trackbase_historic/ActsTransformations.h @@ -70,7 +70,7 @@ class ActsTransformations //___________________________________________________________________________________________________________ void fillSvtxTrackStates( - const Acts::ConstVectorMultiTrajectory& traj, + const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, SvtxTrack* svtxTrack, const Acts::GeometryContext& geoContext diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index a362bace41..db53aa4337 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -41,8 +41,7 @@ class TGeoVolume; namespace Acts { class Surface; - class SurfaceArray; -} +} // namespace Acts using Surface = std::shared_ptr; using TrackingGeometry = std::shared_ptr; From 380428821c41897fd83e7ca89fe639002c513aac Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 27 Feb 2026 15:45:15 -0500 Subject: [PATCH 314/866] go back to regular makefile --- offline/packages/trackbase/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 1a53d8cfa4..03c78d3b89 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -32,7 +32,7 @@ AM_CPPFLAGS = \ -isystem$(ROOTSYS)/include AM_LDFLAGS = \ - -L$(MYINSTALL)/lib64 \ + -L$(OFFLINE_MAIN)/lib64 \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ -L$(ROOTSYS)/lib From 567fda4404ef352d77435eb08194a6b549de459d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 27 Feb 2026 16:30:20 -0500 Subject: [PATCH 315/866] Return other lines from makefile to normal --- offline/packages/trackbase/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 03c78d3b89..84691993c2 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -26,15 +26,14 @@ lib_LTLIBRARIES = \ libtrack.la AM_CPPFLAGS = \ - -I$(MYINSTALL)/include \ -I$(includedir) \ -isystem$(OFFLINE_MAIN)/include \ -isystem$(ROOTSYS)/include AM_LDFLAGS = \ - -L$(OFFLINE_MAIN)/lib64 \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 \ -L$(ROOTSYS)/lib From e7eb4c1d00ac3156c095199c472076cad28cd064 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:24:50 -0500 Subject: [PATCH 316/866] EventPlaneReco - Adjust Centrality Binning - Ensure that calibrations are performed on 1% centrality binning (previously 10%) - Use isHot flag is used over the isGood for the sEPD Bad Channels - sEPD Channels don't use the isBadChi2 check that's part of the isGood check (only the isHot which covers the basic dead/hot/cold cases) --- offline/packages/eventplaneinfo/EventPlaneRecov2.cc | 6 +++--- offline/packages/eventplaneinfo/EventPlaneRecov2.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc index 9635e0f3d6..64408c36f2 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -199,7 +199,7 @@ void EventPlaneRecov2::print_correction_data() int n = m_harmonics[h_idx]; std::cout << std::format("\n>>> HARMONIC n = {} <<<\n", n); - // Iterate through Centrality Bins (0-7) + // Iterate through Centrality Bins (0-79) for (size_t cent = 0; cent < m_bins_cent; ++cent) { std::cout << std::format("\n Centrality Bin: {}\n", cent); @@ -331,7 +331,7 @@ int EventPlaneRecov2::process_sEPD(PHCompositeNode* topNode) // skip bad channels // skip channels with very low charge - if (!tower->get_isGood() || charge < m_sepd_min_channel_charge) + if (tower->get_isHot() || charge < m_sepd_min_channel_charge) { continue; } @@ -389,7 +389,7 @@ int EventPlaneRecov2::process_sEPD(PHCompositeNode* topNode) void EventPlaneRecov2::correct_QVecs() { - size_t cent_bin = static_cast(m_cent / 10.0); + size_t cent_bin = static_cast(m_cent); if (cent_bin >= m_bins_cent) { cent_bin = m_bins_cent - 1; // Clamp max diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h index 217faddf88..699d664a4c 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.h +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.h @@ -115,7 +115,7 @@ class EventPlaneRecov2 : public SubsysReco std::array, 2> X_matrix{}; }; - static constexpr size_t m_bins_cent {8}; + static constexpr size_t m_bins_cent {80}; static constexpr std::array m_harmonics = {2, 3, 4}; // Holds all correction data From afb23ff00a611f9333353ddf0a0780a25fa994eb Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:29:44 -0500 Subject: [PATCH 317/866] EventPlaneReco - Adjust var naming - Use consistent naming convention as that for QVecCalib module in the `sepd_eventplanecalib` package --- offline/packages/eventplaneinfo/EventPlaneRecov2.cc | 8 ++++---- offline/packages/eventplaneinfo/EventPlaneRecov2.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc index 64408c36f2..2b43109734 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc @@ -145,7 +145,7 @@ void EventPlaneRecov2::LoadCalib() std::string NS_yy_avg_name = std::format("Q_NS_yy_{}_avg", n); std::string NS_xy_avg_name = std::format("Q_NS_xy_{}_avg", n); - for (size_t cent_bin = 0; cent_bin < m_bins_cent; ++cent_bin) + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) { int key = cent_bin; @@ -200,7 +200,7 @@ void EventPlaneRecov2::print_correction_data() std::cout << std::format("\n>>> HARMONIC n = {} <<<\n", n); // Iterate through Centrality Bins (0-79) - for (size_t cent = 0; cent < m_bins_cent; ++cent) + for (size_t cent = 0; cent < m_cent_bins; ++cent) { std::cout << std::format("\n Centrality Bin: {}\n", cent); std::cout << std::format(" {:->30}\n", ""); @@ -390,9 +390,9 @@ int EventPlaneRecov2::process_sEPD(PHCompositeNode* topNode) void EventPlaneRecov2::correct_QVecs() { size_t cent_bin = static_cast(m_cent); - if (cent_bin >= m_bins_cent) + if (cent_bin >= m_cent_bins) { - cent_bin = m_bins_cent - 1; // Clamp max + cent_bin = m_cent_bins - 1; // Clamp max } size_t south_idx = static_cast(Subdetector::S); diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h index 699d664a4c..905e83b7bc 100644 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.h +++ b/offline/packages/eventplaneinfo/EventPlaneRecov2.h @@ -115,14 +115,14 @@ class EventPlaneRecov2 : public SubsysReco std::array, 2> X_matrix{}; }; - static constexpr size_t m_bins_cent {80}; + static constexpr size_t m_cent_bins {80}; static constexpr std::array m_harmonics = {2, 3, 4}; // Holds all correction data // key: [Harmonic][Cent][Subdetector] // Harmonics {2,3,4} -> 3 elements // Subdetectors {S,N,NS} -> 3 elements - std::array, m_bins_cent>, m_harmonics.size()> m_correction_data; + std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; // sEPD Q Vectors // key: [Harmonic][Subdetector] From d906123775233c0361ceb08b9726d48436bb1f7e Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Fri, 27 Feb 2026 18:26:58 -0500 Subject: [PATCH 318/866] More nullptr guards and explicit treatment of NaN cases for Timingcut module --- offline/packages/jetbackground/TimingCut.cc | 23 +++++++++++++++++++-- offline/packages/jetbackground/TimingCut.h | 8 +++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index 24dfb03c11..29f6e7d469 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -136,8 +136,15 @@ int TimingCut::process_event(PHCompositeNode *topNode) jetOHFrac += tower->get_energy(); } } - jetOHFrac /= jet->get_e(); //We actually want this to be NaN when jet->get_e() == 0, because that case should fail. - //NaN always compares to false + float jetE = jet->get_e(); + if(jetE == 0) + { + jetOHFrac = std::numeric_limits::quiet_NaN(); + } + else + { + jetOHFrac /= jetE; + } } else { @@ -175,8 +182,20 @@ int TimingCut::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } + if(!std::isfinite(maxJetOHFrac) || !std::isfinite(subJetOHFrac)) + { + if(Verbosity() > 1) + { + std::cout << "Warning: bad OH fraction for leading or subleading jet; this event will automatically fail cuts." << std::endl; + } + maxJetOHFrac = std::numeric_limits::quiet_NaN(); + subJetOHFrac = std::numeric_limits::quiet_NaN(); + } + float corrMaxJett = Correct_Time_Ohfrac(maxJett, maxJetOHFrac); //likewise, intentional NaNs here. float corrSubJett = Correct_Time_Ohfrac(subJett, subJetOHFrac); + + bool passDeltat = Pass_Delta_t(corrMaxJett, corrSubJett, maxJetPhi, subJetPhi); bool passLeadt = Pass_Lead_t(corrMaxJett); diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index 000dc196a7..743f8fac6b 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -77,6 +77,14 @@ class TimingCut : public SubsysReco float Correct_Time_Ohfrac(float t, float ohfrac) { + if(!_fitFunc) + { + if(Verbosity() > 0) + { + std::cout << "ERROR: mising fit function. All events will fail!" << std::endl; + } + return std::numeric_limits::quiet_NaN(); + } float corrt = t - _fitFunc->Eval(ohfrac); return corrt; } From f00f62ae243e3e6557479222560893767caf5d9f Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Fri, 27 Feb 2026 18:55:48 -0500 Subject: [PATCH 319/866] Cleanup - Replace EventPlaneReco with EventPlaneRecov2 - Remove EventPlaneCalibration (old approach) --- .../eventplaneinfo/EventPlaneCalibration.cc | 840 ------------ .../eventplaneinfo/EventPlaneCalibration.h | 121 -- .../packages/eventplaneinfo/EventPlaneReco.cc | 1198 +++++++---------- .../packages/eventplaneinfo/EventPlaneReco.h | 217 +-- .../eventplaneinfo/EventPlaneRecov2.cc | 637 --------- .../eventplaneinfo/EventPlaneRecov2.h | 134 -- offline/packages/eventplaneinfo/Makefile.am | 8 +- 7 files changed, 640 insertions(+), 2515 deletions(-) delete mode 100644 offline/packages/eventplaneinfo/EventPlaneCalibration.cc delete mode 100644 offline/packages/eventplaneinfo/EventPlaneCalibration.h delete mode 100644 offline/packages/eventplaneinfo/EventPlaneRecov2.cc delete mode 100644 offline/packages/eventplaneinfo/EventPlaneRecov2.h diff --git a/offline/packages/eventplaneinfo/EventPlaneCalibration.cc b/offline/packages/eventplaneinfo/EventPlaneCalibration.cc deleted file mode 100644 index 5e5fb01264..0000000000 --- a/offline/packages/eventplaneinfo/EventPlaneCalibration.cc +++ /dev/null @@ -1,840 +0,0 @@ -#include "EventPlaneCalibration.h" - -#include "Eventplaneinfo.h" -#include "EventplaneinfoMap.h" -#include "EventplaneinfoMapv1.h" -#include "Eventplaneinfov1.h" - -#include -#include -#include - -//#include - -//#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#include -#include // for SubsysReco - -#include -#include -#include // for PHNode -#include -#include // for PHObject -#include -#include // for PHWHERE -#include - -#include -#include - -#include -#include -#include -#include // for exit -#include -#include -#include // for _Rb_tree_const_iterator -#include // for pair -#include // for vector - -EventPlaneCalibration::EventPlaneCalibration(const std::string &name) : SubsysReco(name) { - south_q.resize(m_MaxOrder); - north_q.resize(m_MaxOrder); - northsouth_q.resize(m_MaxOrder); - south_q_subtract.resize(m_MaxOrder); - north_q_subtract.resize(m_MaxOrder); - northsouth_q_subtract.resize(m_MaxOrder); - shift_north.resize(m_MaxOrder); - shift_south.resize(m_MaxOrder); - shift_northsouth.resize(m_MaxOrder); - tmp_south_psi.resize(m_MaxOrder); - tmp_north_psi.resize(m_MaxOrder); - tmp_northsouth_psi.resize(m_MaxOrder); - - for (auto &vec : south_q) { - vec.resize(2); - } - - for (auto &vec : north_q) { - vec.resize(2); - } - - for (auto &vec : northsouth_q) { - vec.resize(2); - } - - for (auto &vec : south_q_subtract) { - vec.resize(2); - } - - for (auto &vec : north_q_subtract) { - vec.resize(2); - } - - for (auto &vec : northsouth_q_subtract) { - vec.resize(2); - } -} - -int EventPlaneCalibration::InitRun(PHCompositeNode *topNode) { - - if (_isSim) { - m_runNo = 0; - } - if (!_default_calib) { - recoConsts *rc = recoConsts::instance(); - m_runNo = rc->get_IntFlag("RUNNUMBER"); - } - - if (Verbosity() > 0) { - std::cout << "======================= EventPlaneCalibration:InitRun() " - "=======================" - << std::endl; - std::cout << PHWHERE << "RUNNUMBER " << m_runNo << std::endl; - } - - if (OutFileName.empty()) - { - OutFileName = std::format("eventplane_correction_histograms_run_{}.root",m_runNo); - } - cdbhistosOut = new CDBHistos(OutFileName); - - //-----------------------------------load calibration - //histograms-----------------------------------------// - // Create and register recentering histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - - tprof_mean_cos_south_epd[order] = new TProfile2D( - std::format("tprof_mean_cos_south_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_sin_south_epd[order] = new TProfile2D( - std::format("tprof_mean_sin_south_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_cos_north_epd[order] = new TProfile2D( - std::format("tprof_mean_cos_north_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_sin_north_epd[order] = new TProfile2D( - std::format("tprof_mean_sin_north_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - tprof_mean_cos_northsouth_epd[order] = new TProfile2D( - std::format("tprof_mean_cos_northsouth_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_sin_northsouth_epd[order] = new TProfile2D( - std::format("tprof_mean_sin_northsouth_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - cdbhistosOut->registerHisto(tprof_mean_cos_south_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_sin_south_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_cos_north_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_sin_north_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_cos_northsouth_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_sin_northsouth_epd[order]); - } - - CDBHistos *cdbhistosIn = new CDBHistos(OutFileName); - cdbhistosIn->LoadCalibrations(); - - // Create and register shifting histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - tprof_cos_north_epd_shift[order][p] = new TProfile2D( - std::format("tprof_cos_north_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_sin_north_epd_shift[order][p] = new TProfile2D( - std::format("tprof_sin_north_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_cos_south_epd_shift[order][p] = new TProfile2D( - std::format("tprof_cos_south_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_sin_south_epd_shift[order][p] = new TProfile2D( - std::format("tprof_sin_south_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - tprof_cos_northsouth_epd_shift[order][p] = new TProfile2D( - std::format("tprof_cos_northsouth_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_sin_northsouth_epd_shift[order][p] = new TProfile2D( - std::format("tprof_sin_northsouth_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - cdbhistosOut->registerHisto(tprof_cos_north_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_sin_north_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_cos_south_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_sin_south_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_cos_northsouth_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_sin_northsouth_epd_shift[order][p]); - } - } - - // Get recentering histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - tprof_mean_cos_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_south_epd_order_{}", order), false)); - tprof_mean_sin_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_south_epd_order_{}", order), false)); - tprof_mean_cos_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_north_epd_order_{}", order), false)); - tprof_mean_sin_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_north_epd_order_{}", order), false)); - tprof_mean_cos_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_northsouth_epd_order_{}", order), - false)); - tprof_mean_sin_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_northsouth_epd_order_{}", order), - false)); - } - - // Get shifting histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - tprof_cos_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - tprof_sin_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - } - } - - cdbhistosIn->Print(); - - return CreateNodes(topNode); -} - -int EventPlaneCalibration::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) { - std::cout << "EventPlaneCalibration::process_event -- entered" << std::endl; - } - - //--------------------------------- - // Get Objects off of the Node Tree - //--------------------------------- - - MbdVertexMap *mbdvtxmap = - findNode::getClass(topNode, "MbdVertexMap"); - if (!mbdvtxmap) { - std::cout << PHWHERE << "::ERROR - cannot find MbdVertexMap" << std::endl; - exit(-1); - } - - MbdVertex *mvertex = nullptr; - if (mbdvtxmap) { - for (MbdVertexMap::ConstIter mbditer = mbdvtxmap->begin(); - mbditer != mbdvtxmap->end(); ++mbditer) { - mvertex = mbditer->second; - } - if (mvertex) { - _mbdvtx = mvertex->get_z(); - } - } - - EventplaneinfoMap *epmap = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!epmap) { - std::cout << PHWHERE << "::ERROR - cannot find EventplaneinfoMap" - << std::endl; - exit(-1); - } - - Gl1Packet *gl1PacketInfo = findNode::getClass(topNode, 14001); - if (!gl1PacketInfo) { - std::cout << PHWHERE << "GlobalQA::process_event: GL1Packet node is missing" - << std::endl; - } - - uint64_t triggervec = 0; - if (gl1PacketInfo) { - triggervec = gl1PacketInfo->getScaledVector(); - } - - if (_sepdEpReco) { - - TowerInfoContainer *epd_towerinfo = - findNode::getClass(topNode, "TOWERINFO_CALIB_SEPD"); - if (!epd_towerinfo) { - epd_towerinfo = findNode::getClass( - topNode, "TOWERINFO_CALIB_EPD"); - if (!epd_towerinfo) { - std::cout << PHWHERE - << "::ERROR - cannot find sEPD Calibrated TowerInfoContainer" - << std::endl; - exit(-1); - } - } - - EpdGeom *_epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); - if (!_epdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find TOWERGEOM_EPD" - << std::endl; - exit(-1); - } - - ResetMe(); - - if ((triggervec >> 0xAU) & 0x1U) { - - if ((std::fabs(_mbdvtx) < _mbd_vertex_cut)) { - - unsigned int ntowers = epd_towerinfo->size(); - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS - { - unsigned int key = TowerInfoDefs::encode_epd(ch); - int arm = TowerInfoDefs::get_epd_arm(key); - if (arm == 0) { - _ssum += epd_e; - } else if (arm == 1) { - _nsum += epd_e; - } - } - } - - if (_ssum > _epd_charge_min && _nsum > _epd_charge_min && - _ssum < _epd_charge_max && _nsum < _epd_charge_max) { - _do_ep = true; - } - - if (_do_ep) { - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS - { - if (epd_e < 0.2) // expecting Nmips - { - continue; - } - unsigned int key = TowerInfoDefs::encode_epd(ch); - float tile_phi = _epdgeom->get_phi(key); - int arm = TowerInfoDefs::get_epd_arm(key); - float truncated_e = - (epd_e < _epd_e) ? epd_e : _epd_e; // set cutoff at _epd_e - if (arm == 0) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - south_q[order][0] += truncated_e * Cosine; // south Qn,x - south_q[order][1] += truncated_e * Sine; // south Qn,y - } - } else if (arm == 1) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - north_q[order][0] += truncated_e * Cosine; // north Qn,x - north_q[order][1] += truncated_e * Sine; // north Qn,y - } - } - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - northsouth_q[order][0] += - truncated_e * Cosine; // northsouth Qn,x - northsouth_q[order][1] += truncated_e * Sine; // northsouth Qn,y - } - } - } - - _totalcharge = _nsum + _ssum; - - // Filled during first run - for (unsigned int order = 0; order < m_MaxOrder; order++) { - // Fill recentering histograms by order - tprof_mean_cos_south_epd[order]->Fill(_ssum, _mbdvtx, - south_q[order][0] / _ssum); - tprof_mean_sin_south_epd[order]->Fill(_ssum, _mbdvtx, - south_q[order][1] / _ssum); - tprof_mean_cos_north_epd[order]->Fill(_nsum, _mbdvtx, - north_q[order][0] / _nsum); - tprof_mean_sin_north_epd[order]->Fill(_nsum, _mbdvtx, - north_q[order][1] / _nsum); - tprof_mean_cos_northsouth_epd[order]->Fill( - _totalcharge, _mbdvtx, northsouth_q[order][0] / _totalcharge); - tprof_mean_sin_northsouth_epd[order]->Fill( - _totalcharge, _mbdvtx, northsouth_q[order][1] / _totalcharge); - } - - // Get recentering histograms and do recentering - // Recentering: subtract Qn,x and Qn,y values averaged over all events - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_mean_cos_south_epd_input[order]) // check if recentering - // histograms exist - { - - // south - TAxis *south_xaxis = - tprof_mean_cos_south_epd_input[order]->GetXaxis(); - TAxis *south_yaxis = - tprof_mean_cos_south_epd_input[order]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_south = - tprof_mean_cos_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - double event_ave_sin_south = - tprof_mean_sin_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - south_q_subtract[order][0] = _ssum * event_ave_cos_south; - south_q_subtract[order][1] = _ssum * event_ave_sin_south; - south_q[order][0] -= south_q_subtract[order][0]; - south_q[order][1] -= south_q_subtract[order][1]; - - // north - TAxis *north_xaxis = - tprof_mean_cos_north_epd_input[order]->GetXaxis(); - TAxis *north_yaxis = - tprof_mean_cos_north_epd_input[order]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_north = - tprof_mean_cos_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - double event_ave_sin_north = - tprof_mean_sin_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - north_q_subtract[order][0] = _nsum * event_ave_cos_north; - north_q_subtract[order][1] = _nsum * event_ave_sin_north; - north_q[order][0] -= north_q_subtract[order][0]; - north_q[order][1] -= north_q_subtract[order][1]; - - // northsouth - TAxis *northsouth_xaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_northsouth = - tprof_mean_cos_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - double event_ave_sin_northsouth = - tprof_mean_sin_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - northsouth_q_subtract[order][0] = - _totalcharge * event_ave_cos_northsouth; - northsouth_q_subtract[order][1] = - _totalcharge * event_ave_sin_northsouth; - northsouth_q[order][0] -= northsouth_q_subtract[order][0]; - northsouth_q[order][1] -= northsouth_q_subtract[order][1]; - } - } - - // Get recentered psi_n - Eventplaneinfo *epinfo = new Eventplaneinfov1(); - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - if (tprof_mean_cos_south_epd_input[order]) // if present, Qs are - // recentered - { - tmp_south_psi[order] = - epinfo->GetPsi(south_q[order][0], south_q[order][1], n); - tmp_north_psi[order] = - epinfo->GetPsi(north_q[order][0], north_q[order][1], n); - tmp_northsouth_psi[order] = epinfo->GetPsi( - northsouth_q[order][0], northsouth_q[order][1], n); - } else { - tmp_south_psi[order] = NAN; - tmp_north_psi[order] = NAN; - tmp_northsouth_psi[order] = NAN; - } - } - - // Filled during second run - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_mean_cos_south_epd_input[order]) // if present, Qs are - // recentered - { - // Fill shifting histograms by order and terms - for (int p = 0; p < _imax; p++) { - double terms = p + 1.0; - double n = order + 1.0; - double tmp = (n * terms); - - tprof_cos_south_epd_shift[order][p]->Fill( - _ssum, _mbdvtx, - cos(tmp * tmp_south_psi[order])); // south - tprof_sin_south_epd_shift[order][p]->Fill( - _ssum, _mbdvtx, - sin(tmp * tmp_south_psi[order])); // south - tprof_cos_north_epd_shift[order][p]->Fill( - _nsum, _mbdvtx, - cos(tmp * tmp_north_psi[order])); // north - tprof_sin_north_epd_shift[order][p]->Fill( - _nsum, _mbdvtx, - sin(tmp * tmp_north_psi[order])); // north - tprof_cos_northsouth_epd_shift[order][p]->Fill( - _totalcharge, _mbdvtx, - cos(tmp * tmp_northsouth_psi[order])); // northsouth - // - tprof_sin_northsouth_epd_shift[order][p]->Fill( - _totalcharge, _mbdvtx, - sin(tmp * tmp_northsouth_psi[order])); // northsouth - // - } - } - } - - // Get shifting histograms and calculate shift - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - if (tprof_cos_south_epd_shift_input[order] - [p]) // check if shifting - // histograms exist - { - double terms = p + 1.0; - double n = order + 1.0; - double tmp = (n * terms); - double prefactor = 2.0 / terms; - - // south - TAxis *south_xaxis = - tprof_cos_south_epd_shift_input[order][p]->GetXaxis(); - TAxis *south_yaxis = - tprof_cos_south_epd_shift_input[order][p]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - // north - TAxis *north_xaxis = - tprof_cos_north_epd_shift_input[order][p]->GetXaxis(); - TAxis *north_yaxis = - tprof_cos_north_epd_shift_input[order][p]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - // // northsouth - TAxis *northsouth_xaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - // Equation (6) of arxiv:nucl-ex/9805001 - // i = terms; n = order; i*n = tmp - // (2 / i ) * * - // sin(i*n*psi_n) - * - // cos(i*n*psi_n) - - // north - shift_north[order] += - prefactor * - (tprof_cos_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - sin(tmp * tmp_north_psi[order]) - - tprof_sin_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - cos(tmp * tmp_north_psi[order])); - - // south - shift_south[order] += - prefactor * - (tprof_cos_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - sin(tmp * tmp_south_psi[order]) - - tprof_sin_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - cos(tmp * tmp_south_psi[order])); - - // // northsouth - shift_northsouth[order] += - prefactor * - (tprof_cos_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - sin(tmp * tmp_northsouth_psi[order]) - - tprof_sin_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - cos(tmp * tmp_northsouth_psi[order])); - } - } - } - - // n * deltapsi_n = (2 / i ) * * sin(i*n*psi_n) - - // * cos(i*n*psi_n) Divide out n - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - shift_north[order] /= n; - shift_south[order] /= n; - shift_northsouth[order] /= n; - } - - // Now add shift to psi_n to flatten it - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - tmp_south_psi[order] += shift_south[order]; - tmp_north_psi[order] += shift_north[order]; - tmp_northsouth_psi[order] += shift_northsouth[order]; - } - } - - // Now enforce the range - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - double range = M_PI / (double)(order + 1); - if (tmp_south_psi[order] < -1.0 * range) { - tmp_south_psi[order] += 2.0 * range; - } - if (tmp_south_psi[order] > range) { - tmp_south_psi[order] -= 2.0 * range; - } - if (tmp_north_psi[order] < -1.0 * range) { - tmp_north_psi[order] += 2.0 * range; - } - if (tmp_north_psi[order] > range) { - tmp_north_psi[order] -= 2.0 * range; - } - if (tmp_northsouth_psi[order] < -1.0 * range) { - tmp_northsouth_psi[order] += 2.0 * range; - } - if (tmp_northsouth_psi[order] > range) { - tmp_northsouth_psi[order] -= 2.0 * range; - } - } - } - - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); - northsouth_Qvec.emplace_back(northsouth_q[order][0], - northsouth_q[order][1]); - } - - if (epd_towerinfo) { - Eventplaneinfo *sepds = new Eventplaneinfov1(); - sepds->set_qvector(south_Qvec); - sepds->set_shifted_psi(tmp_south_psi); - epmap->insert(sepds, EventplaneinfoMap::sEPDS); - - Eventplaneinfo *sepdn = new Eventplaneinfov1(); - sepdn->set_qvector(north_Qvec); - sepdn->set_shifted_psi(tmp_north_psi); - epmap->insert(sepdn, EventplaneinfoMap::sEPDN); - - Eventplaneinfo *sepdns = new Eventplaneinfov1(); - sepdns->set_qvector(northsouth_Qvec); - sepdns->set_shifted_psi(tmp_northsouth_psi); - epmap->insert(sepdns, EventplaneinfoMap::sEPDNS); - - if (Verbosity() > 1) { - sepds->identify(); - sepdn->identify(); - sepdns->identify(); - } - } - } - } - } - } - - if (_mbdEpReco) { - ResetMe(); - - MbdPmtContainer *mbdpmts = - findNode::getClass(topNode, "MbdPmtContainer"); - if (!mbdpmts) { - std::cout << PHWHERE << "::ERROR - cannot find MbdPmtContainer" - << std::endl; - exit(-1); - } - - MbdGeom *mbdgeom = findNode::getClass(topNode, "MbdGeom"); - if (!mbdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find MbdGeom" << std::endl; - exit(-1); - } - - if (mbdpmts) { - if (Verbosity()) { - std::cout << "EventPlaneCalibration::process_event - mbdpmts" << std::endl; - } - - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - _mbdQ += mbd_q; - } - - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - float phi = mbdgeom->get_phi(ipmt); - int arm = mbdgeom->get_arm(ipmt); - - if (_mbdQ < _mbd_e) { - continue; - } - - if (arm == 0) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - south_q[order][0] += mbd_q * Cosine; // south Qn,x - south_q[order][1] += mbd_q * Sine; // south Qn,y - } - } else if (arm == 1) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - north_q[order][0] += mbd_q * Cosine; // north Qn,x - north_q[order][1] += mbd_q * Sine; // north Qn,y - } - } - } - } - - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); - } - - if (mbdpmts) { - Eventplaneinfo *mbds = new Eventplaneinfov1(); - mbds->set_qvector(south_Qvec); - epmap->insert(mbds, EventplaneinfoMap::MBDS); - - Eventplaneinfo *mbdn = new Eventplaneinfov1(); - mbdn->set_qvector(north_Qvec); - epmap->insert(mbdn, EventplaneinfoMap::MBDN); - - if (Verbosity() > 1) { - mbds->identify(); - mbdn->identify(); - } - } - - ResetMe(); - } - - if (Verbosity()) { - epmap->identify(); - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -int EventPlaneCalibration::CreateNodes(PHCompositeNode *topNode) { - PHNodeIterator iter(topNode); - - PHCompositeNode *dstNode = - dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - PHCompositeNode *globalNode = dynamic_cast( - iter.findFirst("PHCompositeNode", "GLOBAL")); - if (!globalNode) { - globalNode = new PHCompositeNode("GLOBAL"); - dstNode->addNode(globalNode); - } - - EventplaneinfoMap *eps = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!eps) { - eps = new EventplaneinfoMapv1(); - PHIODataNode *EpMapNode = - new PHIODataNode(eps, "EventplaneinfoMap", "PHObject"); - globalNode->addNode(EpMapNode); - } - return Fun4AllReturnCodes::EVENT_OK; -} - -void EventPlaneCalibration::ResetMe() { - for (auto &vec : south_q) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : north_q) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : northsouth_q) { - std::fill(vec.begin(), vec.end(), 0.); - } - - south_Qvec.clear(); - north_Qvec.clear(); - northsouth_Qvec.clear(); - - for (auto &vec : south_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : north_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : northsouth_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); - } - - std::fill(shift_north.begin(), shift_north.end(), 0.); - std::fill(shift_south.begin(), shift_south.end(), 0.); - std::fill(shift_northsouth.begin(), shift_northsouth.end(), 0.); - - std::fill(tmp_south_psi.begin(), tmp_south_psi.end(), NAN); - std::fill(tmp_north_psi.begin(), tmp_north_psi.end(), NAN); - std::fill(tmp_northsouth_psi.begin(), tmp_northsouth_psi.end(), NAN); - - _nsum = 0.; - _ssum = 0.; - _do_ep = false; - _mbdQ = 0.; - _totalcharge = 0.; -} - -int EventPlaneCalibration::End(PHCompositeNode * /*topNode*/) { - - cdbhistosOut->WriteCDBHistos(); - delete cdbhistosOut; - - std::cout << " EventPlaneCalibration::End() " << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} diff --git a/offline/packages/eventplaneinfo/EventPlaneCalibration.h b/offline/packages/eventplaneinfo/EventPlaneCalibration.h deleted file mode 100644 index 94875c08d2..0000000000 --- a/offline/packages/eventplaneinfo/EventPlaneCalibration.h +++ /dev/null @@ -1,121 +0,0 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. -#ifndef EVENTPLANEINFO_EVENTPLANECALIBRATION_H -#define EVENTPLANEINFO_EVENTPLANECALIBRATION_H - -//=========================================================== -/// \author Ejiro Umaka -//=========================================================== - -#include - -#include // for string -#include // for vector - -class CDBHistos; -class TProfile2D; - -class PHCompositeNode; - -class EventPlaneCalibration : public SubsysReco { -public: - EventPlaneCalibration(const std::string &name = "EventPlaneCalibration"); - ~EventPlaneCalibration() override = default; - int InitRun(PHCompositeNode *topNode) override; - int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode * /*topNode*/) override; - - void ResetMe(); - void set_sepd_epreco(bool sepdEpReco) { _sepdEpReco = sepdEpReco; } - void set_default_calibfile(bool default_calib) { - _default_calib = default_calib; - } - void set_mbd_epreco(bool mbdEpReco) { _mbdEpReco = mbdEpReco; } - void set_isSim(bool isSim) { _isSim = isSim; } - void set_sEPD_Mip_cut(const float e) { _epd_e = e; } - void set_sEPD_Charge_cut(const float c) { _epd_charge_min = c; } - void set_MBD_Min_Qcut(const float f) { _mbd_e = f; } - void set_MBD_Vetex_cut(const float v) { _mbd_vertex_cut = v; } - void set_Ep_orders(const unsigned int n) { m_MaxOrder = n; } - void set_outfilename(const std::string &name) {OutFileName = name;} - -private: - int CreateNodes(PHCompositeNode *topNode); - unsigned int m_MaxOrder{3}; - int m_runNo{0}; - std::string OutFileName; - CDBHistos *cdbhistosOut{nullptr}; - - std::vector> south_q; - std::vector> north_q; - std::vector> northsouth_q; - - std::vector> south_Qvec; - std::vector> north_Qvec; - std::vector> northsouth_Qvec; - - // recentering utility - std::vector> south_q_subtract; - std::vector> north_q_subtract; - std::vector> northsouth_q_subtract; - - // shifting utility - std::vector shift_north; - std::vector shift_south; - std::vector shift_northsouth; - std::vector tmp_south_psi; - std::vector tmp_north_psi; - std::vector tmp_northsouth_psi; - - // recentering histograms - - TProfile2D *tprof_mean_cos_north_epd[6]{}; - TProfile2D *tprof_mean_sin_north_epd[6]{}; - TProfile2D *tprof_mean_cos_south_epd[6]{}; - TProfile2D *tprof_mean_sin_south_epd[6]{}; - TProfile2D *tprof_mean_cos_northsouth_epd[6]{}; - TProfile2D *tprof_mean_sin_northsouth_epd[6]{}; - - TProfile2D *tprof_mean_cos_north_epd_input[6]{}; - TProfile2D *tprof_mean_sin_north_epd_input[6]{}; - TProfile2D *tprof_mean_cos_south_epd_input[6]{}; - TProfile2D *tprof_mean_sin_south_epd_input[6]{}; - TProfile2D *tprof_mean_cos_northsouth_epd_input[6]{}; - TProfile2D *tprof_mean_sin_northsouth_epd_input[6]{}; - - // shifting histograms - const int _imax{12}; - - TProfile2D *tprof_cos_north_epd_shift[6][12]{}; - TProfile2D *tprof_sin_north_epd_shift[6][12]{}; - TProfile2D *tprof_cos_south_epd_shift[6][12]{}; - TProfile2D *tprof_sin_south_epd_shift[6][12]{}; - TProfile2D *tprof_cos_northsouth_epd_shift[6][12]{}; - TProfile2D *tprof_sin_northsouth_epd_shift[6][12]{}; - - TProfile2D *tprof_cos_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_northsouth_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_northsouth_epd_shift_input[6][12]{}; - - bool _mbdEpReco{false}; - bool _sepdEpReco{false}; - bool _isSim{false}; - bool _do_ep{false}; - bool _default_calib{false}; - - float _nsum{0.0}; - float _ssum{0.0}; - float _mbdvtx{999.0}; - float _epd_charge_min{5.0}; - float _epd_charge_max{10000.0}; - float _epd_e{10.0}; - float _mbd_e{10.0}; - float _mbdQ{0.0}; - double _totalcharge{0.0}; - float _mbd_vertex_cut{60.0}; -}; - -#endif // EVENTPLANEINFO_EVENTPLANECALIBRATION_H diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index f0c9f73dd4..58833f0df1 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -1,803 +1,637 @@ #include "EventPlaneReco.h" -#include "Eventplaneinfo.h" -#include "EventplaneinfoMap.h" #include "EventplaneinfoMapv1.h" -#include "Eventplaneinfov1.h" +#include "Eventplaneinfov2.h" #include #include #include +// -- Centrality +#include + +// -- sEPD #include -#include -#include -#include -#include +#include // for CDBTTree -#include -#include -#include -#include +// -- event +#include -#include -#include #include #include -#include // for SubsysReco -#include -#include -#include // for PHNode -#include -#include // for PHObject #include -#include // for PHWHERE -#include +#include +#include -#include +// -- root includes -- +#include +#include -#include // for array -#include -#include -#include // for exit -#include +// c++ includes -- +#include +#include +#include #include -#include // for _Rb_tree_const_iterator -#include // for pair -#include // for vector - -EventPlaneReco::EventPlaneReco(const std::string &name) : SubsysReco(name) { - - south_q.resize(m_MaxOrder); - north_q.resize(m_MaxOrder); - northsouth_q.resize(m_MaxOrder); +#include +#include - south_q_subtract.resize(m_MaxOrder); - north_q_subtract.resize(m_MaxOrder); - northsouth_q_subtract.resize(m_MaxOrder); +//____________________________________________________________________________.. +EventPlaneReco::EventPlaneReco(const std::string &name): + SubsysReco(name) +{ +} - shift_north.resize(m_MaxOrder); - shift_south.resize(m_MaxOrder); - shift_northsouth.resize(m_MaxOrder); - tmp_south_psi.resize(m_MaxOrder); - tmp_north_psi.resize(m_MaxOrder); - tmp_northsouth_psi.resize(m_MaxOrder); +//____________________________________________________________________________.. +int EventPlaneReco::Init(PHCompositeNode *topNode) +{ + std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); - for (auto &vec : south_q) { - vec.resize(2); + if (!m_directURL_EventPlaneCalib.empty()) + { + m_cdbttree = new CDBTTree(m_directURL_EventPlaneCalib); + std::cout << PHWHERE << " Custom Event Plane Calib Found: " << m_directURL_EventPlaneCalib << std::endl; } - - for (auto &vec : north_q) { - vec.resize(2); + else if (!calibdir.empty()) + { + m_cdbttree = new CDBTTree(calibdir); + std::cout << PHWHERE << " Event Plane Calib Found: " << calibdir << std::endl; } - - for (auto &vec : northsouth_q) { - vec.resize(2); + else if (m_doAbortNoEventPlaneCalib) + { + std::cout << PHWHERE << " Error: No Event Plane Calib Found and m_doAbortNoEventPlaneCalib is true. Aborting." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; } - - for (auto &vec : south_q_subtract) { - vec.resize(2); + else + { + std::cout << PHWHERE << " Error: No Event Plane Calib Found. Skipping Event Plane Calibrations." << std::endl; + m_doNotCalib = true; } - for (auto &vec : north_q_subtract) { - vec.resize(2); + if (!m_doNotCalib) + { + LoadCalib(); } - for (auto &vec : northsouth_q_subtract) { - vec.resize(2); + if (Verbosity() > 0) + { + print_correction_data(); } - ring_q_north.resize(nRings); - ring_q_south.resize(nRings); - - for (auto &rq : ring_q_north) { - rq.resize(m_MaxOrder, std::vector(2, 0.0)); - } - for (auto &rq : ring_q_south) { - rq.resize(m_MaxOrder, std::vector(2, 0.0)); - } + CreateNodes(topNode); - all_ring_Qvecs_north.assign( - nRings, std::vector>(m_MaxOrder, {0.0, 0.0})); + return Fun4AllReturnCodes::EVENT_OK; +} - all_ring_Qvecs_south.assign( - nRings, std::vector>(m_MaxOrder, {0.0, 0.0})); +std::array, 2> EventPlaneReco::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) +{ + std::array, 2> mat{}; + + double D_arg = (xx * yy) - (xy * xy); + if (D_arg <= 0) + { + std::cout << PHWHERE << "Invalid D-term " << D_arg << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; + // Return Identity Matrix to preserve Recentered vector + mat[0][0] = 1.0; + mat[1][1] = 1.0; + return mat; + } + double D = std::sqrt(D_arg); + + double N_term = D * (xx + yy + (2 * D)); + if (N_term <= 0) + { + std::cout << PHWHERE << "Invalid N-term " << N_term << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; + // Return Identity Matrix to preserve Recentered vector + mat[0][0] = 1.0; + mat[1][1] = 1.0; + return mat; + } + double inv_sqrt_N = 1.0 / std::sqrt(N_term); + + mat[0][0] = inv_sqrt_N * (yy + D); + mat[0][1] = -inv_sqrt_N * xy; + mat[1][0] = mat[0][1]; + mat[1][1] = inv_sqrt_N * (xx + D); + return mat; } -int EventPlaneReco::InitRun(PHCompositeNode *topNode) { +//____________________________________________________________________________.. +void EventPlaneReco::LoadCalib() +{ + size_t south_idx = static_cast(Subdetector::S); + size_t north_idx = static_cast(Subdetector::N); + size_t ns_idx = static_cast(Subdetector::NS); - FileName = "EVENTPLANE_CORRECTION"; - if (_isSim) { - FileName = "EVENTPLANE_CORRECTION_SIM"; - } + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; - std::string calibdir = CDBInterface::instance()->getUrl(FileName); + std::string S_x_avg_name = std::format("Q_S_x_{}_avg", n); + std::string S_y_avg_name = std::format("Q_S_y_{}_avg", n); + std::string N_x_avg_name = std::format("Q_N_x_{}_avg", n); + std::string N_y_avg_name = std::format("Q_N_y_{}_avg", n); - if (calibdir.empty()) { - std::cout << PHWHERE << "No Eventplane calibration file for domain " - << FileName << " found" << std::endl; - std::cout << PHWHERE - << "Will only produce raw Q vectors and event plane angles " - << std::endl; - } + std::string S_xx_avg_name = std::format("Q_S_xx_{}_avg", n); + std::string S_yy_avg_name = std::format("Q_S_yy_{}_avg", n); + std::string S_xy_avg_name = std::format("Q_S_xy_{}_avg", n); + std::string N_xx_avg_name = std::format("Q_N_xx_{}_avg", n); + std::string N_yy_avg_name = std::format("Q_N_yy_{}_avg", n); + std::string N_xy_avg_name = std::format("Q_N_xy_{}_avg", n); - CDBHistos *cdbhistosIn = new CDBHistos(calibdir); - cdbhistosIn->LoadCalibrations(); - - // Get phiweights - h_phi_weight_south_input = - dynamic_cast(cdbhistosIn->getHisto("h_phi_weight_south", false)); - h_phi_weight_north_input = - dynamic_cast(cdbhistosIn->getHisto("h_phi_weight_north", false)); - - // Get recentering histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - tprof_mean_cos_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_south_epd_order_{}", order), false)); - tprof_mean_sin_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_south_epd_order_{}", order), false)); - tprof_mean_cos_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_north_epd_order_{}", order), false)); - tprof_mean_sin_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_north_epd_order_{}", order), false)); - tprof_mean_cos_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_northsouth_epd_order_{}", order), - false)); - tprof_mean_sin_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_northsouth_epd_order_{}", order), - false)); - } + std::string NS_xx_avg_name = std::format("Q_NS_xx_{}_avg", n); + std::string NS_yy_avg_name = std::format("Q_NS_yy_{}_avg", n); + std::string NS_xy_avg_name = std::format("Q_NS_xy_{}_avg", n); - // Get shifting histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - tprof_cos_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - tprof_sin_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - } - } + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int key = cent_bin; - if (Verbosity() > 1) { - cdbhistosIn->Print(); - } + // South + auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; + dataS.avg_Q.x = m_cdbttree->GetDoubleValue(key, S_x_avg_name); + dataS.avg_Q.y = m_cdbttree->GetDoubleValue(key, S_y_avg_name); - return CreateNodes(topNode); -} + dataS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, S_xx_avg_name); + dataS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, S_yy_avg_name); + dataS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, S_xy_avg_name); -int EventPlaneReco::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) { - std::cout << "EventPlaneReco::process_event -- entered" << std::endl; - } + dataS.X_matrix = calculate_flattening_matrix(dataS.avg_Q_xx, dataS.avg_Q_yy, dataS.avg_Q_xy, n, cent_bin, "South"); - //--------------------------------- - // Get Objects off of the Node Tree - //--------------------------------- - - if (_isSim) { - // Use GlobalVertexMap for simulation - GlobalVertexMap *vertexmap = - findNode::getClass(topNode, "GlobalVertexMap"); - if (!vertexmap) { - std::cout << PHWHERE << "::ERROR - cannot find GlobalVertexMap" - << std::endl; - exit(-1); - } + // North + auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; + dataN.avg_Q.x = m_cdbttree->GetDoubleValue(key, N_x_avg_name); + dataN.avg_Q.y = m_cdbttree->GetDoubleValue(key, N_y_avg_name); - if (!vertexmap->empty()) { - GlobalVertex *vtx = vertexmap->begin()->second; - if (vtx) { - _mbdvtx = vtx->get_z(); - } - } - } else { - // Use MbdVertexMap for data - MbdVertexMap *mbdvtxmap = - findNode::getClass(topNode, "MbdVertexMap"); - if (!mbdvtxmap) { - std::cout << PHWHERE << "::ERROR - cannot find MbdVertexMap" << std::endl; - exit(-1); - } + dataN.avg_Q_xx = m_cdbttree->GetDoubleValue(key, N_xx_avg_name); + dataN.avg_Q_yy = m_cdbttree->GetDoubleValue(key, N_yy_avg_name); + dataN.avg_Q_xy = m_cdbttree->GetDoubleValue(key, N_xy_avg_name); - MbdVertex *mvertex = nullptr; - if (mbdvtxmap) { - for (MbdVertexMap::ConstIter mbditer = mbdvtxmap->begin(); - mbditer != mbdvtxmap->end(); ++mbditer) { - mvertex = mbditer->second; - } - if (mvertex) { - _mbdvtx = mvertex->get_z(); - } - } - } + dataN.X_matrix = calculate_flattening_matrix(dataN.avg_Q_xx, dataN.avg_Q_yy, dataN.avg_Q_xy, n, cent_bin, "North"); - EventplaneinfoMap *epmap = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!epmap) { - std::cout << PHWHERE << "::ERROR - cannot find EventplaneinfoMap" - << std::endl; - exit(-1); - } + // North South + // Note: We do NOT load avg_Q (x,y) for NS because NS is recentered by summing the recentered S and N vectors. + auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; - if (_sepdEpReco) { - - TowerInfoContainer *epd_towerinfo = - findNode::getClass(topNode, "TOWERINFO_CALIB_SEPD"); - if (!epd_towerinfo) { - epd_towerinfo = findNode::getClass( - topNode, "TOWERINFO_CALIB_EPD"); - if (!epd_towerinfo) { - std::cout << PHWHERE - << "::ERROR - cannot find sEPD Calibrated TowerInfoContainer" - << std::endl; - exit(-1); - } - } + dataNS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, NS_xx_avg_name); + dataNS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, NS_yy_avg_name); + dataNS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, NS_xy_avg_name); - EpdGeom *_epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); - if (!_epdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find TOWERGEOM_EPD" - << std::endl; - exit(-1); + dataNS.X_matrix = calculate_flattening_matrix(dataNS.avg_Q_xx, dataNS.avg_Q_yy, dataNS.avg_Q_xy, n, cent_bin, "NorthSouth"); } + } + delete m_cdbttree; + m_cdbttree = nullptr; +} - ResetMe(); - - if ((std::fabs(_mbdvtx) < _mbd_vertex_cut)) { - - unsigned int ntowers = epd_towerinfo->size(); - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS +//____________________________________________________________________________.. +void EventPlaneReco::print_correction_data() +{ + std::cout << std::format("\n{:=>60}\n", ""); + std::cout << std::format("{:^60}\n", "EVENT PLANE CORRECTION DATA SUMMARY"); + std::cout << std::format("{:=>60}\n", ""); + + // Iterate through harmonics {2, 3, 4} + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + std::cout << std::format("\n>>> HARMONIC n = {} <<<\n", n); + + // Iterate through Centrality Bins (0-79) + for (size_t cent = 0; cent < m_cent_bins; ++cent) + { + std::cout << std::format("\n Centrality Bin: {}\n", cent); + std::cout << std::format(" {:->30}\n", ""); + + // Header with fixed column widths + std::cout << std::format(" {:<12} {:>10} {:>10} {:>10} {:>10} {:>10}\n", + "Detector", "Avg Qx", "Avg Qy", "Avg Qxx", "Avg Qyy", "Avg Qxy"); + + // Iterate through Subdetectors {S, N} + for (size_t det_idx = 0; det_idx < 3; ++det_idx) + { + std::string det_name; + if (det_idx == 0) { - unsigned int key = TowerInfoDefs::encode_epd(ch); - int arm = TowerInfoDefs::get_epd_arm(key); - if (arm == 0) { - _ssum += epd_e; - } else if (arm == 1) { - _nsum += epd_e; - } + det_name = "South"; + } + else if (det_idx == 1) + { + det_name = "North"; + } + else + { + det_name = "NorthSouth"; } - } - if (_ssum > _epd_charge_min && _nsum > _epd_charge_min && - _ssum < _epd_charge_max && _nsum < _epd_charge_max) { - _do_ep = true; - } + const auto& data = m_correction_data[h_idx][cent][det_idx]; - if (_do_ep) { - - // Apply phi weights in builiding ring Q-vectors - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS - { - if (epd_e < 0.2) // expecting Nmips - { - continue; - } - unsigned int key = TowerInfoDefs::encode_epd(ch); - float tile_phi = _epdgeom->get_phi(key); - int arm = TowerInfoDefs::get_epd_arm(key); - int rbin = TowerInfoDefs::get_epd_rbin(key); - int phibin = TowerInfoDefs::get_epd_phibin(key); - - float truncated_e = - (epd_e < _epd_e) ? epd_e : _epd_e; // set cutoff at _epd_e - - float TileWeight = truncated_e; // default - - if (h_phi_weight_south_input && h_phi_weight_north_input) { - if (arm == 0) { - TileWeight = - truncated_e * h_phi_weight_south_input->GetBinContent( - phibin + 1); // scale by 1/ - } else if (arm == 1) { - TileWeight = - truncated_e * h_phi_weight_north_input->GetBinContent( - phibin + 1); // scale by 1/ - } - } - - for (unsigned int order = 0; order < m_MaxOrder; ++order) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - - // Arm-specific Q-vectors - if (arm == 0) { - south_q[order][0] += truncated_e * Cosine; - south_q[order][1] += truncated_e * Sine; - ring_q_south[rbin][order][0] += TileWeight * Cosine; - ring_q_south[rbin][order][1] += TileWeight * Sine; - - } else if (arm == 1) { - north_q[order][0] += truncated_e * Cosine; - north_q[order][1] += truncated_e * Sine; - ring_q_north[rbin][order][0] += TileWeight * Cosine; - ring_q_north[rbin][order][1] += TileWeight * Sine; - } - - // Combined Q-vectors - northsouth_q[order][0] += truncated_e * Cosine; - northsouth_q[order][1] += truncated_e * Sine; - } - } - } + // For NS, Avg Qx/Qy will be 0.0 because they are not loaded from CDB. + // This is expected behavior. + std::cout << std::format(" {:<12} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n", + det_name, + data.avg_Q.x, data.avg_Q.y, + data.avg_Q_xx, data.avg_Q_yy, data.avg_Q_xy); - _totalcharge = _nsum + _ssum; - - // Get recentering histograms and do recentering - // Recentering: subtract Qn,x and Qn,y values averaged over all events - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_mean_cos_south_epd_input[order]) // check if recentering - // histograms exist - { - // south - TAxis *south_xaxis = - tprof_mean_cos_south_epd_input[order]->GetXaxis(); - TAxis *south_yaxis = - tprof_mean_cos_south_epd_input[order]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_south = - tprof_mean_cos_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - double event_ave_sin_south = - tprof_mean_sin_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - south_q_subtract[order][0] = _ssum * event_ave_cos_south; - south_q_subtract[order][1] = _ssum * event_ave_sin_south; - south_q[order][0] -= south_q_subtract[order][0]; - south_q[order][1] -= south_q_subtract[order][1]; - - // north - TAxis *north_xaxis = - tprof_mean_cos_north_epd_input[order]->GetXaxis(); - TAxis *north_yaxis = - tprof_mean_cos_north_epd_input[order]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_north = - tprof_mean_cos_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - double event_ave_sin_north = - tprof_mean_sin_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - north_q_subtract[order][0] = _nsum * event_ave_cos_north; - north_q_subtract[order][1] = _nsum * event_ave_sin_north; - north_q[order][0] -= north_q_subtract[order][0]; - north_q[order][1] -= north_q_subtract[order][1]; - - // northsouth - TAxis *northsouth_xaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_northsouth = - tprof_mean_cos_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - double event_ave_sin_northsouth = - tprof_mean_sin_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - northsouth_q_subtract[order][0] = - _totalcharge * event_ave_cos_northsouth; - northsouth_q_subtract[order][1] = - _totalcharge * event_ave_sin_northsouth; - northsouth_q[order][0] -= northsouth_q_subtract[order][0]; - northsouth_q[order][1] -= northsouth_q_subtract[order][1]; - } - } + // Print X-Matrix in a bracketed layout + std::cout << std::format(" X-Matrix: [ {:>8.6f}, {:>8.6f} ]\n", + data.X_matrix[0][0], data.X_matrix[0][1]); + std::cout << std::format(" [ {:>8.6f}, {:>8.6f} ]\n", + data.X_matrix[1][0], data.X_matrix[1][1]); + } + } + } + std::cout << std::format("\n{:=>60}\n", ""); +} - // Get recentered psi_n - Eventplaneinfo *epinfo = new Eventplaneinfov1(); - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - if (tprof_mean_cos_south_epd_input[order]) // if present, Qs are - // recentered - { - tmp_south_psi[order] = - epinfo->GetPsi(south_q[order][0], south_q[order][1], n); - tmp_north_psi[order] = - epinfo->GetPsi(north_q[order][0], north_q[order][1], n); - tmp_northsouth_psi[order] = epinfo->GetPsi( - northsouth_q[order][0], northsouth_q[order][1], n); - } else { - tmp_south_psi[order] = NAN; - tmp_north_psi[order] = NAN; - tmp_northsouth_psi[order] = NAN; - } - } +int EventPlaneReco::CreateNodes(PHCompositeNode *topNode) { + PHNodeIterator iter(topNode); - // Get shifting histograms and calculate shift - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - if (tprof_cos_south_epd_shift_input[order][p]) // check if shifting - // histograms exist - { - double terms = p + 1.0; - double n = order + 1.0; - double tmp = n * terms; - double prefactor = 2.0 / terms; - - // south - TAxis *south_xaxis = - tprof_cos_south_epd_shift_input[order][p]->GetXaxis(); - TAxis *south_yaxis = - tprof_cos_south_epd_shift_input[order][p]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - // north - TAxis *north_xaxis = - tprof_cos_north_epd_shift_input[order][p]->GetXaxis(); - TAxis *north_yaxis = - tprof_cos_north_epd_shift_input[order][p]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - // // northsouth - TAxis *northsouth_xaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - // Equation (6) of arxiv:nucl-ex/9805001 - // i = terms; n = order; i*n = tmp - // (2 / i ) * * sin(i*n*psi_n) - // - * cos(i*n*psi_n) - - // north - shift_north[order] += - prefactor * - (tprof_cos_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - sin(tmp * tmp_north_psi[order]) - - tprof_sin_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - cos(tmp * tmp_north_psi[order])); - - // south - shift_south[order] += - prefactor * - (tprof_cos_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - sin(tmp * tmp_south_psi[order]) - - tprof_sin_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - cos(tmp * tmp_south_psi[order])); - - // // northsouth - shift_northsouth[order] += - prefactor * - (tprof_cos_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - sin(tmp * tmp_northsouth_psi[order]) - - tprof_sin_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - cos(tmp * tmp_northsouth_psi[order])); - } - } - } + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - // n * deltapsi_n = (2 / i ) * * sin(i*n*psi_n) - - // * cos(i*n*psi_n) Divide out n - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - shift_north[order] /= n; - shift_south[order] /= n; - shift_northsouth[order] /= n; - } + PHCompositeNode *globalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "GLOBAL")); + if (!globalNode) + { + globalNode = new PHCompositeNode("GLOBAL"); + dstNode->addNode(globalNode); + } - // Now add shift to psi_n to flatten it - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - tmp_south_psi[order] += shift_south[order]; - tmp_north_psi[order] += shift_north[order]; - tmp_northsouth_psi[order] += shift_northsouth[order]; - } - } + EventplaneinfoMap *eps = findNode::getClass(topNode, "EventplaneinfoMap"); + if (!eps) + { + eps = new EventplaneinfoMapv1(); + PHIODataNode *newNode = new PHIODataNode(eps , "EventplaneinfoMap", "PHObject"); + globalNode->addNode(newNode); + } - // Now enforce the range - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - double range = M_PI / (double)(order + 1); - if (tmp_south_psi[order] < -1.0 * range) { - tmp_south_psi[order] += 2.0 * range; - } - if (tmp_south_psi[order] > range) { - tmp_south_psi[order] -= 2.0 * range; - } - if (tmp_north_psi[order] < -1.0 * range) { - tmp_north_psi[order] += 2.0 * range; - } - if (tmp_north_psi[order] > range) { - tmp_north_psi[order] -= 2.0 * range; - } - if (tmp_northsouth_psi[order] < -1.0 * range) { - tmp_northsouth_psi[order] += 2.0 * range; - } - if (tmp_northsouth_psi[order] > range) { - tmp_northsouth_psi[order] -= 2.0 * range; - } - } - } + return Fun4AllReturnCodes::EVENT_OK; +} - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); - northsouth_Qvec.emplace_back(northsouth_q[order][0], - northsouth_q[order][1]); - } +//____________________________________________________________________________.. +int EventPlaneReco::process_centrality(PHCompositeNode *topNode) +{ + CentralityInfo* centInfo = findNode::getClass(topNode, "CentralityInfo"); + if (!centInfo) + { + std::cout << PHWHERE << " CentralityInfo is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - for (int rbin = 0; rbin < nRings; ++rbin) { - for (unsigned int order = 0; order < m_MaxOrder; ++order) { - all_ring_Qvecs_north[rbin][order] = std::make_pair( - ring_q_north[rbin][order][0], ring_q_north[rbin][order][1]); - all_ring_Qvecs_south[rbin][order] = std::make_pair( - ring_q_south[rbin][order][0], ring_q_south[rbin][order][1]); - } - } + m_cent = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; - if (epd_towerinfo) { - Eventplaneinfo *sepds = new Eventplaneinfov1(); - sepds->set_qvector(south_Qvec); - sepds->set_shifted_psi(tmp_south_psi); - epmap->insert(sepds, EventplaneinfoMap::sEPDS); - - Eventplaneinfo *sepdn = new Eventplaneinfov1(); - sepdn->set_qvector(north_Qvec); - sepdn->set_shifted_psi(tmp_north_psi); - epmap->insert(sepdn, EventplaneinfoMap::sEPDN); - - Eventplaneinfo *sepdns = new Eventplaneinfov1(); - sepdns->set_qvector(northsouth_Qvec); - sepdns->set_shifted_psi(tmp_northsouth_psi); - epmap->insert(sepdns, EventplaneinfoMap::sEPDNS); - - Eventplaneinfo *epring_south = new Eventplaneinfov1(); - epring_south->set_ring_qvector(all_ring_Qvecs_south); - epmap->insert(epring_south, EventplaneinfoMap::sEPDRING_SOUTH); - - Eventplaneinfo *epring_north = new Eventplaneinfov1(); - epring_north->set_ring_qvector(all_ring_Qvecs_north); - epmap->insert(epring_north, EventplaneinfoMap::sEPDRING_NORTH); - - if (Verbosity() > 1) { - sepds->identify(); - sepdn->identify(); - sepdns->identify(); - epring_south->identify(); - epring_north->identify(); - } - } - } + if (!std::isfinite(m_cent) || m_cent < 0) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Warning Centrality is out of range. Cent: " << m_cent << ". Cannot calibrate Q vector for this event." << std::endl; } + m_doNotCalibEvent = true; } - if (_mbdEpReco) { - ResetMe(); + return Fun4AllReturnCodes::EVENT_OK; +} - MbdPmtContainer *mbdpmts = - findNode::getClass(topNode, "MbdPmtContainer"); - if (!mbdpmts) { - std::cout << PHWHERE << "::ERROR - cannot find MbdPmtContainer" - << std::endl; - exit(-1); - } +//____________________________________________________________________________.. +int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) +{ + TowerInfoContainer* towerinfosEPD = findNode::getClass(topNode, m_inputNode); + if (!towerinfosEPD) + { + std::cout << PHWHERE << " TOWERINFO_CALIB_SEPD is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - MbdGeom *mbdgeom = findNode::getClass(topNode, "MbdGeom"); - if (!mbdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find MbdGeom" << std::endl; - exit(-1); - } + EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << " TOWERGEOM_EPD is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - if (mbdpmts) { - if (Verbosity()) { - std::cout << "EventPlaneReco::process_event - mbdpmts" << std::endl; - } + // sepd + unsigned int nchannels_epd = towerinfosEPD->size(); - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - _mbdQ += mbd_q; - } + double sepd_total_charge_south = 0; + double sepd_total_charge_north = 0; - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - float phi = mbdgeom->get_phi(ipmt); - int arm = mbdgeom->get_arm(ipmt); + for (unsigned int channel = 0; channel < nchannels_epd; ++channel) + { + TowerInfo* tower = towerinfosEPD->get_tower_at_channel(channel); - if (_mbdQ < _mbd_e) { - continue; - } + unsigned int key = TowerInfoDefs::encode_epd(channel); + double charge = tower->get_energy(); + double phi = epdgeom->get_phi(key); - if (arm == 0) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - south_q[order][0] += mbd_q * Cosine; // south Qn,x - south_q[order][1] += mbd_q * Sine; // south Qn,y - } - } else if (arm == 1) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - north_q[order][0] += mbd_q * Cosine; // north Qn,x - north_q[order][1] += mbd_q * Sine; // north Qn,y - } - } - } + // skip bad channels + // skip channels with very low charge + if (tower->get_isHot() || charge < m_sepd_min_channel_charge) + { + continue; } - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); - } + // arm = 0: South + // arm = 1: North + unsigned int arm = TowerInfoDefs::get_epd_arm(key); - if (mbdpmts) { - Eventplaneinfo *mbds = new Eventplaneinfov1(); - mbds->set_qvector(south_Qvec); - epmap->insert(mbds, EventplaneinfoMap::MBDS); + // sepd charge sums + double& sepd_total_charge = (arm == 0) ? sepd_total_charge_south : sepd_total_charge_north; - Eventplaneinfo *mbdn = new Eventplaneinfov1(); - mbdn->set_qvector(north_Qvec); - epmap->insert(mbdn, EventplaneinfoMap::MBDN); + // Compute total charge for the respective sEPD arm + sepd_total_charge += charge; - if (Verbosity() > 1) { - mbds->identify(); - mbdn->identify(); - } + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + QVec q_n = {charge * std::cos(n * phi), charge * std::sin(n * phi)}; + m_Q_raw[h_idx][arm].x += q_n.x; + m_Q_raw[h_idx][arm].y += q_n.y; + } + } + + // ensure both total charges are nonzero + if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Error: Total sEPD Charge is Zero: " + << "South = " << sepd_total_charge_south + << ", North = " << sepd_total_charge_north << std::endl; } - ResetMe(); + // ensure raw Q vec is reset + m_Q_raw = {}; + m_doNotCalibEvent = true; + return Fun4AllReturnCodes::EVENT_OK; } - if (Verbosity()) { - epmap->identify(); + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + m_Q_raw[h_idx][0].x /= sepd_total_charge_south; + m_Q_raw[h_idx][0].y /= sepd_total_charge_south; + + m_Q_raw[h_idx][1].x /= sepd_total_charge_north; + m_Q_raw[h_idx][1].y /= sepd_total_charge_north; + + // NEW: Calculate Raw NS (Sum of Raw S + Raw N) + m_Q_raw[h_idx][2].x = m_Q_raw[h_idx][0].x + m_Q_raw[h_idx][1].x; + m_Q_raw[h_idx][2].y = m_Q_raw[h_idx][0].y + m_Q_raw[h_idx][1].y; } return Fun4AllReturnCodes::EVENT_OK; } -int EventPlaneReco::CreateNodes(PHCompositeNode *topNode) { - PHNodeIterator iter(topNode); - - PHCompositeNode *dstNode = - dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; +void EventPlaneReco::correct_QVecs() +{ + size_t cent_bin = static_cast(m_cent); + if (cent_bin >= m_cent_bins) + { + cent_bin = m_cent_bins - 1; // Clamp max } - PHCompositeNode *globalNode = dynamic_cast( - iter.findFirst("PHCompositeNode", "GLOBAL")); - if (!globalNode) { - globalNode = new PHCompositeNode("GLOBAL"); - dstNode->addNode(globalNode); - } + size_t south_idx = static_cast(Subdetector::S); + size_t north_idx = static_cast(Subdetector::N); + size_t ns_idx = static_cast(Subdetector::NS); - EventplaneinfoMap *eps = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!eps) { - eps = new EventplaneinfoMapv1(); - PHIODataNode *EpMapNode = - new PHIODataNode(eps, "EventplaneinfoMap", "PHObject"); - globalNode->addNode(EpMapNode); + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; + auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; + auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; + + double Q_S_x_avg = dataS.avg_Q.x; + double Q_S_y_avg = dataS.avg_Q.y; + double Q_N_x_avg = dataN.avg_Q.x; + double Q_N_y_avg = dataN.avg_Q.y; + + QVec q_S = m_Q_raw[h_idx][south_idx]; + QVec q_N = m_Q_raw[h_idx][north_idx]; + + // Apply Recentering + QVec q_S_recenter = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; + QVec q_N_recenter = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + QVec q_NS_recenter = {q_S_recenter.x + q_N_recenter.x, q_S_recenter.y + q_N_recenter.y}; + + m_Q_recentered[h_idx][south_idx] = q_S_recenter; + m_Q_recentered[h_idx][north_idx] = q_N_recenter; + m_Q_recentered[h_idx][ns_idx] = q_NS_recenter; + + // Flattening Matrix + const auto &X_S = dataS.X_matrix; + const auto &X_N = dataN.X_matrix; + const auto &X_NS = dataNS.X_matrix; + + // Apply Flattening + double Q_S_x_flat = X_S[0][0] * q_S_recenter.x + X_S[0][1] * q_S_recenter.y; + double Q_S_y_flat = X_S[1][0] * q_S_recenter.x + X_S[1][1] * q_S_recenter.y; + double Q_N_x_flat = X_N[0][0] * q_N_recenter.x + X_N[0][1] * q_N_recenter.y; + double Q_N_y_flat = X_N[1][0] * q_N_recenter.x + X_N[1][1] * q_N_recenter.y; + + double Q_NS_x_flat = X_NS[0][0] * q_NS_recenter.x + X_NS[0][1] * q_NS_recenter.y; + double Q_NS_y_flat = X_NS[1][0] * q_NS_recenter.x + X_NS[1][1] * q_NS_recenter.y; + + QVec q_S_flat = {Q_S_x_flat, Q_S_y_flat}; + QVec q_N_flat = {Q_N_x_flat, Q_N_y_flat}; + QVec q_NS_flat = {Q_NS_x_flat, Q_NS_y_flat}; + + m_Q_flat[h_idx][south_idx] = q_S_flat; + m_Q_flat[h_idx][north_idx] = q_N_flat; + m_Q_flat[h_idx][ns_idx] = q_NS_flat; } - return Fun4AllReturnCodes::EVENT_OK; } -void EventPlaneReco::ResetMe() { - for (auto &vec : south_q) { - std::fill(vec.begin(), vec.end(), 0.); - } +void EventPlaneReco::print_QVectors() +{ + std::string header_text = std::format("EVENT Q-VECTOR SUMMARY (Event: {}, CENTRALITY: {:.0f}%)", m_globalEvent, m_cent); + + std::cout << std::format("\n{:*>100}\n", ""); + std::cout << std::format("{:^100}\n", header_text); + std::cout << std::format("{:*>100}\n", ""); + + // Table Header + std::cout << std::format(" {:<10} {:<10} | {:>21} | {:>21} | {:>21}\n", + "Harmonic", "Detector", "Raw (x, y)", "Recentered (x, y)", "Flattened (x, y)"); + std::cout << std::format(" {:-<100}\n", ""); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + for (size_t det_idx = 0; det_idx < 3; ++det_idx) + { + std::string det_name; + if (det_idx == 0) + { + det_name = "South"; + } + else if (det_idx == 1) + { + det_name = "North"; + } + else + { + det_name = "NorthSouth"; + } - for (auto &vec : north_q) { - std::fill(vec.begin(), vec.end(), 0.); - } + const auto& raw = m_Q_raw[h_idx][det_idx]; + const auto& rec = m_Q_recentered[h_idx][det_idx]; + const auto& flat = m_Q_flat[h_idx][det_idx]; - for (auto &vec : northsouth_q) { - std::fill(vec.begin(), vec.end(), 0.); - } + std::string h_label = (det_idx == 0) ? std::format("n={}", n) : ""; + + // Groups x and y into (val, val) pairs for better scannability + std::string raw_str = std::format("({:>8.5f}, {:>8.5f})", raw.x, raw.y); + std::string rec_str = std::format("({:>8.5f}, {:>8.5f})", rec.x, rec.y); + std::string flat_str = std::format("({:>8.5f}, {:>8.5f})", flat.x, flat.y); - for (auto &order_vec : ring_q_north) { - for (auto &xy_vec : order_vec) { - std::fill(xy_vec.begin(), xy_vec.end(), 0.0); + std::cout << std::format(" {:<10} {:<10} | {:<21} | {:<21} | {:10}\n", + h_label, det_name, raw_str, rec_str, flat_str); + } + if (h_idx < m_harmonics.size() - 1) + { + std::cout << std::format(" {:.>100}\n", ""); } } + std::cout << std::format("{:*>100}\n\n", ""); +} - for (auto &order_vec : ring_q_south) { - for (auto &xy_vec : order_vec) { - std::fill(xy_vec.begin(), xy_vec.end(), 0.0); - } +int EventPlaneReco::FillNode(PHCompositeNode *topNode) +{ + EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); + if (!epmap) + { + std::cout << PHWHERE << " EventplaneinfoMap is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; } - south_Qvec.clear(); - north_Qvec.clear(); - northsouth_Qvec.clear(); + size_t vec_size = static_cast(*std::ranges::max_element(m_harmonics)); - for (auto &ring : all_ring_Qvecs_north) { - for (auto &q : ring) { - q = {0.0, 0.0}; - } + std::vector> south_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> south_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> south_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + + std::vector> north_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> north_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> north_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + + std::vector> northsouth_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> northsouth_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> northsouth_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + int idx = n - 1; + + // Fallback logic: Use raw if calibration failed or centrality is out of range + const auto& Q_S = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][0] : m_Q_flat[h_idx][0]; + const auto& Q_N = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][1] : m_Q_flat[h_idx][1]; + const auto& Q_NS = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][2] : m_Q_flat[h_idx][2]; + + const auto& Q_S_raw = m_Q_raw[h_idx][0]; + const auto& Q_S_recentered = m_Q_recentered[h_idx][0]; + + const auto& Q_N_raw = m_Q_raw[h_idx][1]; + const auto& Q_N_recentered = m_Q_recentered[h_idx][1]; + + const auto& Q_NS_raw = m_Q_raw[h_idx][2]; + const auto& Q_NS_recentered = m_Q_recentered[h_idx][2]; + + // South + south_Qvec_raw[idx] = {Q_S_raw.x, Q_S_raw.y}; + south_Qvec_recentered[idx] = {Q_S_recentered.x, Q_S_recentered.y}; + south_Qvec[idx] = {Q_S.x, Q_S.y}; + + // North + north_Qvec_raw[idx] = {Q_N_raw.x, Q_N_raw.y}; + north_Qvec_recentered[idx] = {Q_N_recentered.x, Q_N_recentered.y}; + north_Qvec[idx] = {Q_N.x, Q_N.y}; + + // Combined (North + South) + northsouth_Qvec_raw[idx] = {Q_NS_raw.x, Q_NS_raw.y}; + northsouth_Qvec_recentered[idx] = {Q_NS_recentered.x, Q_NS_recentered.y}; + northsouth_Qvec[idx] = {Q_NS.x, Q_NS.y}; } - for (auto &ring : all_ring_Qvecs_south) { - for (auto &q : ring) { - q = {0.0, 0.0}; - } + // Helper lambda to fill nodes using the class's GetPsi method + auto create_and_fill = [&](const std::vector>& qvecs_raw, const std::vector>& qvecs_recentered, const std::vector>& qvecs) { + auto node = std::make_unique(); + node->set_qvector_raw(qvecs_raw); + node->set_qvector_recentered(qvecs_recentered); + node->set_qvector(qvecs); + + std::vector psi_vec(vec_size, std::numeric_limits::quiet_NaN()); + for (int n : m_harmonics) { + psi_vec[n-1] = node->GetPsi(qvecs[n-1].first, qvecs[n-1].second, n); + } + node->set_shifted_psi(psi_vec); + return node; + }; + + epmap->insert(create_and_fill(south_Qvec_raw, south_Qvec_recentered, south_Qvec).release(), EventplaneinfoMap::sEPDS); + epmap->insert(create_and_fill(north_Qvec_raw, north_Qvec_recentered, north_Qvec).release(), EventplaneinfoMap::sEPDN); + epmap->insert(create_and_fill(northsouth_Qvec_raw, northsouth_Qvec_recentered, northsouth_Qvec).release(), EventplaneinfoMap::sEPDNS); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int EventPlaneReco::process_event(PHCompositeNode *topNode) +{ + EventHeader *eventInfo = findNode::getClass(topNode, "EventHeader"); + if (!eventInfo) + { + return Fun4AllReturnCodes::ABORTRUN; } - for (auto &vec : south_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); + m_globalEvent = eventInfo->get_EvtSequence(); + + int ret = process_centrality(topNode); + if (ret) + { + return ret; } - for (auto &vec : north_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); + ret = process_sEPD(topNode); + if (ret) + { + return ret; } - for (auto &vec : northsouth_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); + // Calibrate Q Vectors + if (!m_doNotCalib && !m_doNotCalibEvent) + { + correct_QVecs(); } - std::fill(shift_north.begin(), shift_north.end(), 0.); - std::fill(shift_south.begin(), shift_south.end(), 0.); - std::fill(shift_northsouth.begin(), shift_northsouth.end(), 0.); + ret = FillNode(topNode); + if (ret) + { + return ret; + } - std::fill(tmp_south_psi.begin(), tmp_south_psi.end(), NAN); - std::fill(tmp_north_psi.begin(), tmp_north_psi.end(), NAN); - std::fill(tmp_northsouth_psi.begin(), tmp_northsouth_psi.end(), NAN); + if (Verbosity() > 1) + { + print_QVectors(); + } - _nsum = 0.; - _ssum = 0.; - _do_ep = false; - _mbdQ = 0.; - _totalcharge = 0.; + return Fun4AllReturnCodes::EVENT_OK; } -int EventPlaneReco::End(PHCompositeNode * /*topNode*/) { +//____________________________________________________________________________.. +int EventPlaneReco::ResetEvent(PHCompositeNode */*topNode*/) +{ + m_doNotCalibEvent = false; + + m_Q_raw = {}; + m_Q_recentered = {}; + m_Q_flat = {}; - std::cout << " EventPlaneReco::End() " << std::endl; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.h b/offline/packages/eventplaneinfo/EventPlaneReco.h index ce4259c95e..0f356e6033 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.h +++ b/offline/packages/eventplaneinfo/EventPlaneReco.h @@ -1,107 +1,134 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. #ifndef EVENTPLANEINFO_EVENTPLANERECO_H #define EVENTPLANEINFO_EVENTPLANERECO_H -//=========================================================== -/// \author Ejiro Umaka -//=========================================================== - #include -#include // for string -#include // for vector -class TProfile2D; -class TH1; +#include +#include +#include +class CDBTTree; class PHCompositeNode; -class EventPlaneReco : public SubsysReco { -public: - EventPlaneReco(const std::string &name = "EventPlaneReco"); +class EventPlaneReco : public SubsysReco +{ + public: + + explicit EventPlaneReco(const std::string &name = "EventPlaneReco"); ~EventPlaneReco() override = default; - int InitRun(PHCompositeNode *topNode) override; + + // Explicitly disable copying and moving + EventPlaneReco(const EventPlaneReco&) = delete; + EventPlaneReco& operator=(const EventPlaneReco&) = delete; + EventPlaneReco(EventPlaneReco&&) = delete; + EventPlaneReco& operator=(EventPlaneReco&&) = delete; + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode * /*topNode*/) override; - - void ResetMe(); - void set_sepd_epreco(bool sepdEpReco) { _sepdEpReco = sepdEpReco; } - void set_mbd_epreco(bool mbdEpReco) { _mbdEpReco = mbdEpReco; } - void set_isSim(bool isSim) { _isSim = isSim; } - void set_sEPD_Mip_cut(const float e) { _epd_e = e; } - void set_sEPD_Charge_cut(const float c) { _epd_charge_min = c; } - void set_MBD_Min_Qcut(const float f) { _mbd_e = f; } - void set_MBD_Vertex_cut(const float v) { _mbd_vertex_cut = v; } - void set_Ep_orders(const unsigned int n) { m_MaxOrder = n; } - -private: - int CreateNodes(PHCompositeNode *topNode); - unsigned int m_MaxOrder{3}; - static const int nRings {16}; - - std::string FileName; - - std::vector> south_q; - std::vector> north_q; - std::vector> northsouth_q; - std::vector>> ring_q_north; - std::vector>> ring_q_south; - std::vector> south_Qvec; - std::vector> north_Qvec; - std::vector> northsouth_Qvec; - std::vector>> all_ring_Qvecs_north; - std::vector>> all_ring_Qvecs_south; - - // const int phibins{24}; - TH1* h_phi_weight_south_input{nullptr}; - TH1* h_phi_weight_north_input{nullptr}; - - // recentering utility - std::vector> south_q_subtract; - std::vector> north_q_subtract; - std::vector> northsouth_q_subtract; - - // shifting utility - std::vector shift_north; - std::vector shift_south; - std::vector shift_northsouth; - std::vector tmp_south_psi; - std::vector tmp_north_psi; - std::vector tmp_northsouth_psi; - - // recentering histograms - TProfile2D *tprof_mean_cos_north_epd_input[6]{}; - TProfile2D *tprof_mean_sin_north_epd_input[6]{}; - TProfile2D *tprof_mean_cos_south_epd_input[6]{}; - TProfile2D *tprof_mean_sin_south_epd_input[6]{}; - TProfile2D *tprof_mean_cos_northsouth_epd_input[6]{}; - TProfile2D *tprof_mean_sin_northsouth_epd_input[6]{}; - - // shifting histograms - const int _imax{12}; - TProfile2D *tprof_cos_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_northsouth_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_northsouth_epd_shift_input[6][12]{}; - - bool _mbdEpReco{false}; - bool _sepdEpReco{false}; - bool _isSim{false}; - bool _do_ep{false}; - - float _nsum{0.0}; - float _ssum{0.0}; - float _mbdvtx{999.0}; - float _epd_charge_min{5.0}; - float _epd_charge_max{10000.0}; - float _epd_e{10.0}; - float _mbd_e{10.0}; - float _mbdQ{0.0}; - double _totalcharge{0.0}; - float _mbd_vertex_cut{60.0}; -}; -#endif // EVENTPLANEINFO_EVENTPLANERECO_H + /// Clean up internals after each event. + int ResetEvent(PHCompositeNode *topNode) override; + + + void set_inputNode(const std::string &inputNode) + { + m_inputNode = inputNode; + } + + void set_directURL_EventPlaneCalib(const std::string &directURL_EventPlaneCalib) + { + m_directURL_EventPlaneCalib = directURL_EventPlaneCalib; + } + + void set_doAbortNoEventPlaneCalib(bool status = true) + { + m_doAbortNoEventPlaneCalib = status; + } + + void set_sepd_min_channel_charge(double sepd_min_channel_charge) + { + m_sepd_min_channel_charge = sepd_min_channel_charge; + } + + private: + + static int CreateNodes(PHCompositeNode *topNode); + + std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); + void LoadCalib(); + + void print_correction_data(); + void print_QVectors(); + + int process_centrality(PHCompositeNode *topNode); + int process_sEPD(PHCompositeNode *topNode); + void correct_QVecs(); + + int FillNode(PHCompositeNode *topNode); + + std::string m_directURL_EventPlaneCalib; + bool m_doAbortNoEventPlaneCalib{false}; + bool m_doNotCalib{false}; + bool m_doNotCalibEvent{false}; + + double m_cent{0.0}; + double m_globalEvent{0}; + double m_sepd_min_channel_charge{0.2}; + + std::string m_calibName{"SEPD_EventPlaneCalib"}; + std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; + + CDBTTree *m_cdbttree {nullptr}; + + enum class Subdetector + { + S, + N, + NS + }; + + struct QVec + { + double x{0.0}; + double y{0.0}; + }; + + struct CorrectionData + { + // Averages of Qx, Qy, Qx^2, Qy^2, Qxy + QVec avg_Q{}; + double avg_Q_xx{0.0}; + double avg_Q_yy{0.0}; + double avg_Q_xy{0.0}; + + // Correction matrix + std::array, 2> X_matrix{}; + }; + + static constexpr size_t m_cent_bins {80}; + static constexpr std::array m_harmonics = {2, 3, 4}; + + // Holds all correction data + // key: [Harmonic][Cent][Subdetector] + // Harmonics {2,3,4} -> 3 elements + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; + + // sEPD Q Vectors + // key: [Harmonic][Subdetector] + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_harmonics.size()> m_Q_raw{}; + std::array, m_harmonics.size()> m_Q_recentered{}; + std::array, m_harmonics.size()> m_Q_flat{}; +}; +#endif diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc b/offline/packages/eventplaneinfo/EventPlaneRecov2.cc deleted file mode 100644 index 2b43109734..0000000000 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.cc +++ /dev/null @@ -1,637 +0,0 @@ -#include "EventPlaneRecov2.h" - -#include "EventplaneinfoMapv1.h" -#include "Eventplaneinfov2.h" - -#include -#include -#include - -// -- Centrality -#include - -// -- sEPD -#include - -#include // for CDBTTree - -// -- event -#include - -#include - -#include - -#include -#include -#include - -// -- root includes -- -#include -#include - -// c++ includes -- -#include -#include -#include -#include -#include -#include - -//____________________________________________________________________________.. -EventPlaneRecov2::EventPlaneRecov2(const std::string &name): - SubsysReco(name) -{ -} - -//____________________________________________________________________________.. -int EventPlaneRecov2::Init(PHCompositeNode *topNode) -{ - std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); - - if (!m_directURL_EventPlaneCalib.empty()) - { - m_cdbttree = new CDBTTree(m_directURL_EventPlaneCalib); - std::cout << PHWHERE << " Custom Event Plane Calib Found: " << m_directURL_EventPlaneCalib << std::endl; - } - else if (!calibdir.empty()) - { - m_cdbttree = new CDBTTree(calibdir); - std::cout << PHWHERE << " Event Plane Calib Found: " << calibdir << std::endl; - } - else if (m_doAbortNoEventPlaneCalib) - { - std::cout << PHWHERE << " Error: No Event Plane Calib Found and m_doAbortNoEventPlaneCalib is true. Aborting." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - else - { - std::cout << PHWHERE << " Error: No Event Plane Calib Found. Skipping Event Plane Calibrations." << std::endl; - m_doNotCalib = true; - } - - if (!m_doNotCalib) - { - LoadCalib(); - } - - if (Verbosity() > 0) - { - print_correction_data(); - } - - CreateNodes(topNode); - - return Fun4AllReturnCodes::EVENT_OK; -} - -std::array, 2> EventPlaneRecov2::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) -{ - std::array, 2> mat{}; - - double D_arg = (xx * yy) - (xy * xy); - if (D_arg <= 0) - { - std::cout << PHWHERE << "Invalid D-term " << D_arg << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; - // Return Identity Matrix to preserve Recentered vector - mat[0][0] = 1.0; - mat[1][1] = 1.0; - return mat; - } - double D = std::sqrt(D_arg); - - double N_term = D * (xx + yy + (2 * D)); - if (N_term <= 0) - { - std::cout << PHWHERE << "Invalid N-term " << N_term << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; - // Return Identity Matrix to preserve Recentered vector - mat[0][0] = 1.0; - mat[1][1] = 1.0; - return mat; - } - double inv_sqrt_N = 1.0 / std::sqrt(N_term); - - mat[0][0] = inv_sqrt_N * (yy + D); - mat[0][1] = -inv_sqrt_N * xy; - mat[1][0] = mat[0][1]; - mat[1][1] = inv_sqrt_N * (xx + D); - return mat; -} - -//____________________________________________________________________________.. -void EventPlaneRecov2::LoadCalib() -{ - size_t south_idx = static_cast(Subdetector::S); - size_t north_idx = static_cast(Subdetector::N); - size_t ns_idx = static_cast(Subdetector::NS); - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - - std::string S_x_avg_name = std::format("Q_S_x_{}_avg", n); - std::string S_y_avg_name = std::format("Q_S_y_{}_avg", n); - std::string N_x_avg_name = std::format("Q_N_x_{}_avg", n); - std::string N_y_avg_name = std::format("Q_N_y_{}_avg", n); - - std::string S_xx_avg_name = std::format("Q_S_xx_{}_avg", n); - std::string S_yy_avg_name = std::format("Q_S_yy_{}_avg", n); - std::string S_xy_avg_name = std::format("Q_S_xy_{}_avg", n); - std::string N_xx_avg_name = std::format("Q_N_xx_{}_avg", n); - std::string N_yy_avg_name = std::format("Q_N_yy_{}_avg", n); - std::string N_xy_avg_name = std::format("Q_N_xy_{}_avg", n); - - std::string NS_xx_avg_name = std::format("Q_NS_xx_{}_avg", n); - std::string NS_yy_avg_name = std::format("Q_NS_yy_{}_avg", n); - std::string NS_xy_avg_name = std::format("Q_NS_xy_{}_avg", n); - - for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) - { - int key = cent_bin; - - // South - auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; - dataS.avg_Q.x = m_cdbttree->GetDoubleValue(key, S_x_avg_name); - dataS.avg_Q.y = m_cdbttree->GetDoubleValue(key, S_y_avg_name); - - dataS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, S_xx_avg_name); - dataS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, S_yy_avg_name); - dataS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, S_xy_avg_name); - - dataS.X_matrix = calculate_flattening_matrix(dataS.avg_Q_xx, dataS.avg_Q_yy, dataS.avg_Q_xy, n, cent_bin, "South"); - - // North - auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; - dataN.avg_Q.x = m_cdbttree->GetDoubleValue(key, N_x_avg_name); - dataN.avg_Q.y = m_cdbttree->GetDoubleValue(key, N_y_avg_name); - - dataN.avg_Q_xx = m_cdbttree->GetDoubleValue(key, N_xx_avg_name); - dataN.avg_Q_yy = m_cdbttree->GetDoubleValue(key, N_yy_avg_name); - dataN.avg_Q_xy = m_cdbttree->GetDoubleValue(key, N_xy_avg_name); - - dataN.X_matrix = calculate_flattening_matrix(dataN.avg_Q_xx, dataN.avg_Q_yy, dataN.avg_Q_xy, n, cent_bin, "North"); - - // North South - // Note: We do NOT load avg_Q (x,y) for NS because NS is recentered by summing the recentered S and N vectors. - auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; - - dataNS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, NS_xx_avg_name); - dataNS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, NS_yy_avg_name); - dataNS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, NS_xy_avg_name); - - dataNS.X_matrix = calculate_flattening_matrix(dataNS.avg_Q_xx, dataNS.avg_Q_yy, dataNS.avg_Q_xy, n, cent_bin, "NorthSouth"); - } - } - delete m_cdbttree; - m_cdbttree = nullptr; -} - -//____________________________________________________________________________.. -void EventPlaneRecov2::print_correction_data() -{ - std::cout << std::format("\n{:=>60}\n", ""); - std::cout << std::format("{:^60}\n", "EVENT PLANE CORRECTION DATA SUMMARY"); - std::cout << std::format("{:=>60}\n", ""); - - // Iterate through harmonics {2, 3, 4} - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - std::cout << std::format("\n>>> HARMONIC n = {} <<<\n", n); - - // Iterate through Centrality Bins (0-79) - for (size_t cent = 0; cent < m_cent_bins; ++cent) - { - std::cout << std::format("\n Centrality Bin: {}\n", cent); - std::cout << std::format(" {:->30}\n", ""); - - // Header with fixed column widths - std::cout << std::format(" {:<12} {:>10} {:>10} {:>10} {:>10} {:>10}\n", - "Detector", "Avg Qx", "Avg Qy", "Avg Qxx", "Avg Qyy", "Avg Qxy"); - - // Iterate through Subdetectors {S, N} - for (size_t det_idx = 0; det_idx < 3; ++det_idx) - { - std::string det_name; - if (det_idx == 0) - { - det_name = "South"; - } - else if (det_idx == 1) - { - det_name = "North"; - } - else - { - det_name = "NorthSouth"; - } - - const auto& data = m_correction_data[h_idx][cent][det_idx]; - - // For NS, Avg Qx/Qy will be 0.0 because they are not loaded from CDB. - // This is expected behavior. - std::cout << std::format(" {:<12} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n", - det_name, - data.avg_Q.x, data.avg_Q.y, - data.avg_Q_xx, data.avg_Q_yy, data.avg_Q_xy); - - // Print X-Matrix in a bracketed layout - std::cout << std::format(" X-Matrix: [ {:>8.6f}, {:>8.6f} ]\n", - data.X_matrix[0][0], data.X_matrix[0][1]); - std::cout << std::format(" [ {:>8.6f}, {:>8.6f} ]\n", - data.X_matrix[1][0], data.X_matrix[1][1]); - } - } - } - std::cout << std::format("\n{:=>60}\n", ""); -} - -int EventPlaneRecov2::CreateNodes(PHCompositeNode *topNode) { - PHNodeIterator iter(topNode); - - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - PHCompositeNode *globalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "GLOBAL")); - if (!globalNode) - { - globalNode = new PHCompositeNode("GLOBAL"); - dstNode->addNode(globalNode); - } - - EventplaneinfoMap *eps = findNode::getClass(topNode, "EventplaneinfoMap"); - if (!eps) - { - eps = new EventplaneinfoMapv1(); - PHIODataNode *newNode = new PHIODataNode(eps , "EventplaneinfoMap", "PHObject"); - globalNode->addNode(newNode); - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int EventPlaneRecov2::process_centrality(PHCompositeNode *topNode) -{ - CentralityInfo* centInfo = findNode::getClass(topNode, "CentralityInfo"); - if (!centInfo) - { - std::cout << PHWHERE << " CentralityInfo is missing doing nothing" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - m_cent = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; - - if (!std::isfinite(m_cent) || m_cent < 0) - { - if (Verbosity() > 1) - { - std::cout << PHWHERE << " Warning Centrality is out of range. Cent: " << m_cent << ". Cannot calibrate Q vector for this event." << std::endl; - } - m_doNotCalibEvent = true; - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int EventPlaneRecov2::process_sEPD(PHCompositeNode* topNode) -{ - TowerInfoContainer* towerinfosEPD = findNode::getClass(topNode, m_inputNode); - if (!towerinfosEPD) - { - std::cout << PHWHERE << " TOWERINFO_CALIB_SEPD is missing doing nothing" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); - if (!epdgeom) - { - std::cout << PHWHERE << " TOWERGEOM_EPD is missing doing nothing" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - // sepd - unsigned int nchannels_epd = towerinfosEPD->size(); - - double sepd_total_charge_south = 0; - double sepd_total_charge_north = 0; - - for (unsigned int channel = 0; channel < nchannels_epd; ++channel) - { - TowerInfo* tower = towerinfosEPD->get_tower_at_channel(channel); - - unsigned int key = TowerInfoDefs::encode_epd(channel); - double charge = tower->get_energy(); - double phi = epdgeom->get_phi(key); - - // skip bad channels - // skip channels with very low charge - if (tower->get_isHot() || charge < m_sepd_min_channel_charge) - { - continue; - } - - // arm = 0: South - // arm = 1: North - unsigned int arm = TowerInfoDefs::get_epd_arm(key); - - // sepd charge sums - double& sepd_total_charge = (arm == 0) ? sepd_total_charge_south : sepd_total_charge_north; - - // Compute total charge for the respective sEPD arm - sepd_total_charge += charge; - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - QVec q_n = {charge * std::cos(n * phi), charge * std::sin(n * phi)}; - m_Q_raw[h_idx][arm].x += q_n.x; - m_Q_raw[h_idx][arm].y += q_n.y; - } - } - - // ensure both total charges are nonzero - if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) - { - if (Verbosity() > 1) - { - std::cout << PHWHERE << " Error: Total sEPD Charge is Zero: " - << "South = " << sepd_total_charge_south - << ", North = " << sepd_total_charge_north << std::endl; - } - - // ensure raw Q vec is reset - m_Q_raw = {}; - m_doNotCalibEvent = true; - return Fun4AllReturnCodes::EVENT_OK; - } - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - m_Q_raw[h_idx][0].x /= sepd_total_charge_south; - m_Q_raw[h_idx][0].y /= sepd_total_charge_south; - - m_Q_raw[h_idx][1].x /= sepd_total_charge_north; - m_Q_raw[h_idx][1].y /= sepd_total_charge_north; - - // NEW: Calculate Raw NS (Sum of Raw S + Raw N) - m_Q_raw[h_idx][2].x = m_Q_raw[h_idx][0].x + m_Q_raw[h_idx][1].x; - m_Q_raw[h_idx][2].y = m_Q_raw[h_idx][0].y + m_Q_raw[h_idx][1].y; - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -void EventPlaneRecov2::correct_QVecs() -{ - size_t cent_bin = static_cast(m_cent); - if (cent_bin >= m_cent_bins) - { - cent_bin = m_cent_bins - 1; // Clamp max - } - - size_t south_idx = static_cast(Subdetector::S); - size_t north_idx = static_cast(Subdetector::N); - size_t ns_idx = static_cast(Subdetector::NS); - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; - auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; - auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; - - double Q_S_x_avg = dataS.avg_Q.x; - double Q_S_y_avg = dataS.avg_Q.y; - double Q_N_x_avg = dataN.avg_Q.x; - double Q_N_y_avg = dataN.avg_Q.y; - - QVec q_S = m_Q_raw[h_idx][south_idx]; - QVec q_N = m_Q_raw[h_idx][north_idx]; - - // Apply Recentering - QVec q_S_recenter = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; - QVec q_N_recenter = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; - QVec q_NS_recenter = {q_S_recenter.x + q_N_recenter.x, q_S_recenter.y + q_N_recenter.y}; - - m_Q_recentered[h_idx][south_idx] = q_S_recenter; - m_Q_recentered[h_idx][north_idx] = q_N_recenter; - m_Q_recentered[h_idx][ns_idx] = q_NS_recenter; - - // Flattening Matrix - const auto &X_S = dataS.X_matrix; - const auto &X_N = dataN.X_matrix; - const auto &X_NS = dataNS.X_matrix; - - // Apply Flattening - double Q_S_x_flat = X_S[0][0] * q_S_recenter.x + X_S[0][1] * q_S_recenter.y; - double Q_S_y_flat = X_S[1][0] * q_S_recenter.x + X_S[1][1] * q_S_recenter.y; - double Q_N_x_flat = X_N[0][0] * q_N_recenter.x + X_N[0][1] * q_N_recenter.y; - double Q_N_y_flat = X_N[1][0] * q_N_recenter.x + X_N[1][1] * q_N_recenter.y; - - double Q_NS_x_flat = X_NS[0][0] * q_NS_recenter.x + X_NS[0][1] * q_NS_recenter.y; - double Q_NS_y_flat = X_NS[1][0] * q_NS_recenter.x + X_NS[1][1] * q_NS_recenter.y; - - QVec q_S_flat = {Q_S_x_flat, Q_S_y_flat}; - QVec q_N_flat = {Q_N_x_flat, Q_N_y_flat}; - QVec q_NS_flat = {Q_NS_x_flat, Q_NS_y_flat}; - - m_Q_flat[h_idx][south_idx] = q_S_flat; - m_Q_flat[h_idx][north_idx] = q_N_flat; - m_Q_flat[h_idx][ns_idx] = q_NS_flat; - } -} - -void EventPlaneRecov2::print_QVectors() -{ - std::string header_text = std::format("EVENT Q-VECTOR SUMMARY (Event: {}, CENTRALITY: {:.0f}%)", m_globalEvent, m_cent); - - std::cout << std::format("\n{:*>100}\n", ""); - std::cout << std::format("{:^100}\n", header_text); - std::cout << std::format("{:*>100}\n", ""); - - // Table Header - std::cout << std::format(" {:<10} {:<10} | {:>21} | {:>21} | {:>21}\n", - "Harmonic", "Detector", "Raw (x, y)", "Recentered (x, y)", "Flattened (x, y)"); - std::cout << std::format(" {:-<100}\n", ""); - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - - for (size_t det_idx = 0; det_idx < 3; ++det_idx) - { - std::string det_name; - if (det_idx == 0) - { - det_name = "South"; - } - else if (det_idx == 1) - { - det_name = "North"; - } - else - { - det_name = "NorthSouth"; - } - - const auto& raw = m_Q_raw[h_idx][det_idx]; - const auto& rec = m_Q_recentered[h_idx][det_idx]; - const auto& flat = m_Q_flat[h_idx][det_idx]; - - std::string h_label = (det_idx == 0) ? std::format("n={}", n) : ""; - - // Groups x and y into (val, val) pairs for better scannability - std::string raw_str = std::format("({:>8.5f}, {:>8.5f})", raw.x, raw.y); - std::string rec_str = std::format("({:>8.5f}, {:>8.5f})", rec.x, rec.y); - std::string flat_str = std::format("({:>8.5f}, {:>8.5f})", flat.x, flat.y); - - std::cout << std::format(" {:<10} {:<10} | {:<21} | {:<21} | {:10}\n", - h_label, det_name, raw_str, rec_str, flat_str); - } - if (h_idx < m_harmonics.size() - 1) - { - std::cout << std::format(" {:.>100}\n", ""); - } - } - std::cout << std::format("{:*>100}\n\n", ""); -} - -int EventPlaneRecov2::FillNode(PHCompositeNode *topNode) -{ - EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); - if (!epmap) - { - std::cout << PHWHERE << " EventplaneinfoMap is missing doing nothing" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - size_t vec_size = static_cast(*std::ranges::max_element(m_harmonics)); - - std::vector> south_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> south_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> south_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - - std::vector> north_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> north_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> north_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - - std::vector> northsouth_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> northsouth_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - std::vector> northsouth_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); - - for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) - { - int n = m_harmonics[h_idx]; - int idx = n - 1; - - // Fallback logic: Use raw if calibration failed or centrality is out of range - const auto& Q_S = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][0] : m_Q_flat[h_idx][0]; - const auto& Q_N = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][1] : m_Q_flat[h_idx][1]; - const auto& Q_NS = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][2] : m_Q_flat[h_idx][2]; - - const auto& Q_S_raw = m_Q_raw[h_idx][0]; - const auto& Q_S_recentered = m_Q_recentered[h_idx][0]; - - const auto& Q_N_raw = m_Q_raw[h_idx][1]; - const auto& Q_N_recentered = m_Q_recentered[h_idx][1]; - - const auto& Q_NS_raw = m_Q_raw[h_idx][2]; - const auto& Q_NS_recentered = m_Q_recentered[h_idx][2]; - - // South - south_Qvec_raw[idx] = {Q_S_raw.x, Q_S_raw.y}; - south_Qvec_recentered[idx] = {Q_S_recentered.x, Q_S_recentered.y}; - south_Qvec[idx] = {Q_S.x, Q_S.y}; - - // North - north_Qvec_raw[idx] = {Q_N_raw.x, Q_N_raw.y}; - north_Qvec_recentered[idx] = {Q_N_recentered.x, Q_N_recentered.y}; - north_Qvec[idx] = {Q_N.x, Q_N.y}; - - // Combined (North + South) - northsouth_Qvec_raw[idx] = {Q_NS_raw.x, Q_NS_raw.y}; - northsouth_Qvec_recentered[idx] = {Q_NS_recentered.x, Q_NS_recentered.y}; - northsouth_Qvec[idx] = {Q_NS.x, Q_NS.y}; - } - - // Helper lambda to fill nodes using the class's GetPsi method - auto create_and_fill = [&](const std::vector>& qvecs_raw, const std::vector>& qvecs_recentered, const std::vector>& qvecs) { - auto node = std::make_unique(); - node->set_qvector_raw(qvecs_raw); - node->set_qvector_recentered(qvecs_recentered); - node->set_qvector(qvecs); - - std::vector psi_vec(vec_size, std::numeric_limits::quiet_NaN()); - for (int n : m_harmonics) { - psi_vec[n-1] = node->GetPsi(qvecs[n-1].first, qvecs[n-1].second, n); - } - node->set_shifted_psi(psi_vec); - return node; - }; - - epmap->insert(create_and_fill(south_Qvec_raw, south_Qvec_recentered, south_Qvec).release(), EventplaneinfoMap::sEPDS); - epmap->insert(create_and_fill(north_Qvec_raw, north_Qvec_recentered, north_Qvec).release(), EventplaneinfoMap::sEPDN); - epmap->insert(create_and_fill(northsouth_Qvec_raw, northsouth_Qvec_recentered, northsouth_Qvec).release(), EventplaneinfoMap::sEPDNS); - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int EventPlaneRecov2::process_event(PHCompositeNode *topNode) -{ - EventHeader *eventInfo = findNode::getClass(topNode, "EventHeader"); - if (!eventInfo) - { - return Fun4AllReturnCodes::ABORTRUN; - } - - m_globalEvent = eventInfo->get_EvtSequence(); - - int ret = process_centrality(topNode); - if (ret) - { - return ret; - } - - ret = process_sEPD(topNode); - if (ret) - { - return ret; - } - - // Calibrate Q Vectors - if (!m_doNotCalib && !m_doNotCalibEvent) - { - correct_QVecs(); - } - - ret = FillNode(topNode); - if (ret) - { - return ret; - } - - if (Verbosity() > 1) - { - print_QVectors(); - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -//____________________________________________________________________________.. -int EventPlaneRecov2::ResetEvent(PHCompositeNode */*topNode*/) -{ - m_doNotCalibEvent = false; - - m_Q_raw = {}; - m_Q_recentered = {}; - m_Q_flat = {}; - - return Fun4AllReturnCodes::EVENT_OK; -} diff --git a/offline/packages/eventplaneinfo/EventPlaneRecov2.h b/offline/packages/eventplaneinfo/EventPlaneRecov2.h deleted file mode 100644 index 905e83b7bc..0000000000 --- a/offline/packages/eventplaneinfo/EventPlaneRecov2.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef EVENTPLANEINFO_EVENTPLANERECOV2_H -#define EVENTPLANEINFO_EVENTPLANERECOV2_H - -#include - - -#include -#include -#include - -class CDBTTree; -class PHCompositeNode; - -class EventPlaneRecov2 : public SubsysReco -{ - public: - - explicit EventPlaneRecov2(const std::string &name = "EventPlaneRecov2"); - ~EventPlaneRecov2() override = default; - - // Explicitly disable copying and moving - EventPlaneRecov2(const EventPlaneRecov2&) = delete; - EventPlaneRecov2& operator=(const EventPlaneRecov2&) = delete; - EventPlaneRecov2(EventPlaneRecov2&&) = delete; - EventPlaneRecov2& operator=(EventPlaneRecov2&&) = delete; - - /** Called during initialization. - Typically this is where you can book histograms, and e.g. - register them to Fun4AllServer (so they can be output to file - using Fun4AllServer::dumpHistos() method). - */ - int Init(PHCompositeNode *topNode) override; - - /** Called for each event. - This is where you do the real work. - */ - int process_event(PHCompositeNode *topNode) override; - - /// Clean up internals after each event. - int ResetEvent(PHCompositeNode *topNode) override; - - - void set_inputNode(const std::string &inputNode) - { - m_inputNode = inputNode; - } - - void set_directURL_EventPlaneCalib(const std::string &directURL_EventPlaneCalib) - { - m_directURL_EventPlaneCalib = directURL_EventPlaneCalib; - } - - void set_doAbortNoEventPlaneCalib(bool status = true) - { - m_doAbortNoEventPlaneCalib = status; - } - - void set_sepd_min_channel_charge(double sepd_min_channel_charge) - { - m_sepd_min_channel_charge = sepd_min_channel_charge; - } - - private: - - static int CreateNodes(PHCompositeNode *topNode); - - std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); - void LoadCalib(); - - void print_correction_data(); - void print_QVectors(); - - int process_centrality(PHCompositeNode *topNode); - int process_sEPD(PHCompositeNode *topNode); - void correct_QVecs(); - - int FillNode(PHCompositeNode *topNode); - - std::string m_directURL_EventPlaneCalib; - bool m_doAbortNoEventPlaneCalib{false}; - bool m_doNotCalib{false}; - bool m_doNotCalibEvent{false}; - - double m_cent{0.0}; - double m_globalEvent{0}; - double m_sepd_min_channel_charge{0.2}; - - std::string m_calibName{"SEPD_EventPlaneCalib"}; - std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; - - CDBTTree *m_cdbttree {nullptr}; - - enum class Subdetector - { - S, - N, - NS - }; - - struct QVec - { - double x{0.0}; - double y{0.0}; - }; - - struct CorrectionData - { - // Averages of Qx, Qy, Qx^2, Qy^2, Qxy - QVec avg_Q{}; - double avg_Q_xx{0.0}; - double avg_Q_yy{0.0}; - double avg_Q_xy{0.0}; - - // Correction matrix - std::array, 2> X_matrix{}; - }; - - static constexpr size_t m_cent_bins {80}; - static constexpr std::array m_harmonics = {2, 3, 4}; - - // Holds all correction data - // key: [Harmonic][Cent][Subdetector] - // Harmonics {2,3,4} -> 3 elements - // Subdetectors {S,N,NS} -> 3 elements - std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; - - // sEPD Q Vectors - // key: [Harmonic][Subdetector] - // Subdetectors {S,N,NS} -> 3 elements - std::array, m_harmonics.size()> m_Q_raw{}; - std::array, m_harmonics.size()> m_Q_recentered{}; - std::array, m_harmonics.size()> m_Q_flat{}; -}; -#endif diff --git a/offline/packages/eventplaneinfo/Makefile.am b/offline/packages/eventplaneinfo/Makefile.am index 786a285bee..188447cd06 100644 --- a/offline/packages/eventplaneinfo/Makefile.am +++ b/offline/packages/eventplaneinfo/Makefile.am @@ -29,14 +29,12 @@ libeventplaneinfo_la_LIBADD = \ -lglobalvertex_io pkginclude_HEADERS = \ - EventPlaneCalibration.h \ Eventplaneinfo.h \ Eventplaneinfov1.h \ Eventplaneinfov2.h \ EventplaneinfoMap.h \ EventplaneinfoMapv1.h \ - EventPlaneReco.h \ - EventPlaneRecov2.h + EventPlaneReco.h ROOTDICTS = \ Eventplaneinfo_Dict.cc \ @@ -58,9 +56,7 @@ libeventplaneinfo_io_la_SOURCES = \ EventplaneinfoMapv1.cc libeventplaneinfo_la_SOURCES = \ - EventPlaneCalibration.cc \ - EventPlaneReco.cc \ - EventPlaneRecov2.cc + EventPlaneReco.cc # Rule for generating table CINT dictionaries. %_Dict.cc: %.h %LinkDef.h From 47961e58413a0b65324c07a8df95d88aca56d356 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Mon, 2 Mar 2026 00:02:34 -0500 Subject: [PATCH 320/866] changing majic param, will improve code later --- offline/packages/CaloReco/CaloWaveformFitting.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index 3ea4e36cf1..341860c754 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -920,7 +920,7 @@ std::vector> CaloWaveformFitting::calo_processing_funcfit(con f.SetParLimits(3, 0.5, 4.0); f.SetParLimits(4, pedestal-500, pedestal+500); - f.FixParameter(2, 0.2); + f.FixParameter(2, 0.1); TFitResultPtr fitres = h.Fit(&f, "SQRN0W", "", 0, nsamples); From df117a71a9bbf9a7f28bbd93117a23988823931b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 2 Mar 2026 08:56:59 -0500 Subject: [PATCH 321/866] add missing fstream include --- simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc | 1 + simulation/g4simulation/g4tpc/TpcClusterBuilder.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 6cd968883e..7006241673 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -40,6 +40,7 @@ #include #include // for getenv #include +#include #include #include // for _Rb_tree_cons... #include // for pair diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index fb6a02ba26..ed2445b1ad 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -15,7 +15,7 @@ #include - +#include #include #include // for sqrt, cos, sin #include From 100fa26788c94b20cf456d9774bb9fd54f3753b6 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 2 Mar 2026 14:08:24 -0500 Subject: [PATCH 322/866] Readd mag field options --- .../trackbase/MagneticFieldOptions.cc | 200 ++++++++++++++++++ .../packages/trackbase/MagneticFieldOptions.h | 22 ++ offline/packages/trackbase/Makefile.am | 2 + offline/packages/trackbase/SpacePoint.h | 3 +- .../packages/trackreco/PHActsKDTreeSeeding.cc | 3 +- .../trackreco/PHActsSiliconSeeding.cc | 3 +- 6 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 offline/packages/trackbase/MagneticFieldOptions.cc create mode 100644 offline/packages/trackbase/MagneticFieldOptions.h diff --git a/offline/packages/trackbase/MagneticFieldOptions.cc b/offline/packages/trackbase/MagneticFieldOptions.cc new file mode 100644 index 0000000000..4043397f76 --- /dev/null +++ b/offline/packages/trackbase/MagneticFieldOptions.cc @@ -0,0 +1,200 @@ + + +#include "MagneticFieldOptions.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +void ActsExamples::Options::addMagneticFieldOptions(Description& desc) { + using boost::program_options::bool_switch; + using boost::program_options::value; + + // avoid adding the options twice + if (desc.find_nothrow("bf-constant-tesla", true) != nullptr) { + return; + } + + auto opt = desc.add_options(); + opt("bf-constant-tesla", value>(), + "Set a constant magnetic field vector in Tesla. If given, this takes " + "preference over all other options."); + opt("bf-scalable", bool_switch(), + "If given, the constant field strength will be scaled differently in " + "every event. This is for testing only."); + opt("bf-scalable-scalor", value()->default_value(1.25), + "Scaling factor for the event-dependent field strength scaling. A unit " + "value means that the field strength stays the same for every event."); + opt("bf-map-file", value(), + "Read a magnetic field map from the given file. ROOT and text file " + "formats are supported. Only used if no constant field is given."); + opt("bf-map-tree", value()->default_value("bField"), + "Name of the TTree in the ROOT file. Only used if the field map is read " + "from a ROOT file."); + opt("bf-map-type", value()->default_value("xyz"), + "Either 'xyz' or 'rz' to define the type of the field map."); + opt("bf-map-octantonly", bool_switch(), + "If given, the field map is assumed to describe only the first " + "octant/quadrant and the field is symmetrically extended to the full " + "space."); + opt("bf-map-lengthscale-mm", value()->default_value(1.), + "Optional length scale modifier for the field map grid. This options " + "only needs to be set if the length unit in the field map file is not " + "`mm`. The value must scale from the stored unit to the equivalent value " + "in `mm`."); + opt("bf-map-fieldscale-tesla", value()->default_value(1.), + "Optional field value scale modifier for the field map value. This " + "option only needs to be set if the field value unit in the field map " + "file is not `Tesla`. The value must scale from the stored unit to the " + "equivalent value in `Tesla`."); + opt("bf-solenoid-mag-tesla", value()->default_value(0.), + "The magnitude of a solenoid magnetic field in the center in `Tesla`. " + "Only used " + "if neither constant field nor a magnetic field map is given."); + opt("bf-solenoid-length", value()->default_value(6000), + "The length of the solenoid magnetic field in `mm`."); + opt("bf-solenoid-radius", value()->default_value(1200), + "The radius of the solenoid magnetic field in `mm`."); + opt("bf-solenoid-ncoils", value()->default_value(1194), + "Number of coils for the solenoid magnetic field."); + opt("bf-solenoid-map-rlim", + value()->value_name("MIN:MAX")->default_value({0, 1200}), + "The length bounds of the grid created from the analytical solenoid " + "field in `mm`."); + opt("bf-solenoid-map-zlim", + value()->value_name("MIN:MAX")->default_value({-3000, 3000}), + "The radius bounds of the grid created from the analytical solenoid " + "field in `mm`."); + opt("bf-solenoid-map-nbins", value>()->default_value({{150, 200}}), + "The number of bins in r-z directions for the grid created from the " + "analytical solenoid field."); +} + + +std::shared_ptr +ActsExamples::Options::readMagneticField(const Variables& vars) { + using namespace ActsExamples::detail; + using std::filesystem::path; + + // first option: create a constant field + if (vars.count("bf-constant-tesla") != 0u) { + const auto values = vars["bf-constant-tesla"].as>(); + Acts::Vector3 field(values[0] * Acts::UnitConstants::T, + values[1] * Acts::UnitConstants::T, + values[2] * Acts::UnitConstants::T); + if (vars["bf-scalable"].as()) { + return std::make_shared(field); + } else { + return std::make_shared(field); + } + } + + // second option: read a field map from a file + if (vars.count("bf-map-file") != 0u) { + const path file = vars["bf-map-file"].as(); + const auto tree = vars["bf-map-tree"].as(); + const auto type = vars["bf-map-type"].as(); + const auto useOctantOnly = vars["bf-map-octantonly"].as(); + const auto lengthUnit = + vars["bf-map-lengthscale-mm"].as() * Acts::UnitConstants::mm; + const auto fieldUnit = + vars["bf-map-fieldscale-tesla"].as() * Acts::UnitConstants::T; + + bool readRoot = false; + if (file.extension() == ".root") { + readRoot = true; + } else if (file.extension() == ".txt") { + readRoot = false; + } else { + throw std::runtime_error("Unsupported magnetic field map file type"); + } + + if (type == "xyz") { + auto mapBins = [](const std::array& bins, + const std::array& sizes) { + return (bins[0] * (sizes[1] * sizes[2]) + bins[1] * sizes[2] + bins[2]); + }; + + if (readRoot) { + auto map = makeMagneticFieldMapXyzFromRoot( + std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, + useOctantOnly); + return std::make_shared(std::move(map)); + + } else { + auto map = makeMagneticFieldMapXyzFromText(std::move(mapBins), + file.native(), lengthUnit, + fieldUnit, useOctantOnly); + return std::make_shared(std::move(map)); + } + + } else if (type == "rz") { + auto mapBins = [](std::array bins, + std::array sizes) { + return (bins[1] * sizes[0] + bins[0]); + }; + + if (readRoot) { + auto map = makeMagneticFieldMapRzFromRoot( + std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, + useOctantOnly); + return std::make_shared(std::move(map)); + + } else { + auto map = makeMagneticFieldMapRzFromText(std::move(mapBins), + file.native(), lengthUnit, + fieldUnit, useOctantOnly); + return std::make_shared(std::move(map)); + } + + } else { + throw std::runtime_error("Unknown magnetic field map type"); + } + } + + // third option: create a solenoid field + if (vars["bf-solenoid-mag-tesla"].as() > 0) { + // Construct a solenoid field + Acts::SolenoidBField::Config solenoidConfig{}; + solenoidConfig.length = + vars["bf-solenoid-length"].as() * Acts::UnitConstants::mm; + solenoidConfig.radius = + vars["bf-solenoid-radius"].as() * Acts::UnitConstants::mm; + solenoidConfig.nCoils = vars["bf-solenoid-ncoils"].as(); + solenoidConfig.bMagCenter = + vars["bf-solenoid-mag-tesla"].as() * Acts::UnitConstants::T; + + const auto solenoidField = Acts::SolenoidBField(solenoidConfig); + // The parameters for creating a field map + auto getRange = [&](const char* name, auto unit, auto& lower, auto& upper) { + auto interval = vars[name].as(); + lower = interval.lower.value() * unit; + upper = interval.upper.value() * unit; + }; + std::pair rlim, zlim; + getRange("bf-solenoid-map-rlim", Acts::UnitConstants::mm, rlim.first, + rlim.second); + getRange("bf-solenoid-map-zlim", Acts::UnitConstants::mm, zlim.first, + zlim.second); + const auto nbins = vars["bf-solenoid-map-nbins"].as>(); + auto map = + Acts::solenoidFieldMap(rlim, zlim, {nbins[0], nbins[1]}, solenoidField); + return std::make_shared(std::move(map)); + } + + // default option: no field + return std::make_shared(); +} diff --git a/offline/packages/trackbase/MagneticFieldOptions.h b/offline/packages/trackbase/MagneticFieldOptions.h new file mode 100644 index 0000000000..a5254b9a6a --- /dev/null +++ b/offline/packages/trackbase/MagneticFieldOptions.h @@ -0,0 +1,22 @@ +#ifndef _MAGNETICFIELDOPTIONS_H +#define _MAGNETICFIELDOPTIONS_H + +#include +#include +#include + +namespace ActsExamples { + +namespace Options { + +/// Add magnetic field options with a `bf-` prefix. +void addMagneticFieldOptions(Description& desc); + +/// Read and create the magnetic field from the given user variables. +std::shared_ptr readMagneticField( + const Variables& vars); + +} // namespace Options +} // namespace ActsExamples + +#endif // _MAGNETICFIELDOPTIONS_H diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 84691993c2..92b4273988 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -72,6 +72,7 @@ pkginclude_HEADERS = \ LaserClusterv1.h \ LaserClusterv2.h \ MaterialWiper.h \ + MagneticFieldOptions.h \ MvtxDefs.h \ MvtxEventInfo.h \ MvtxEventInfov1.h \ @@ -215,6 +216,7 @@ libtrack_la_SOURCES = \ Calibrator.cc \ ClusterErrorPara.cc \ CommonOptions.cc \ + MagneticFieldOptions.cc \ sPHENIXActsDetectorElement.cc \ TGeoDetectorWithOptions.cc \ TrackFittingAlgorithmFunctionsGsf.cc \ diff --git a/offline/packages/trackbase/SpacePoint.h b/offline/packages/trackbase/SpacePoint.h index 74bff8b1c2..7a422de8c8 100644 --- a/offline/packages/trackbase/SpacePoint.h +++ b/offline/packages/trackbase/SpacePoint.h @@ -6,7 +6,7 @@ #include "trackbase/TrkrDefs.h" #include -#include +#include /** * A struct for Acts to take cluster information for seeding @@ -42,6 +42,7 @@ inline bool operator==(SpacePoint a, SpacePoint b) } using SpacePointPtr = std::unique_ptr; +using SpacePointContainer = std::vector; using SeedContainer = std::vector>; #endif diff --git a/offline/packages/trackreco/PHActsKDTreeSeeding.cc b/offline/packages/trackreco/PHActsKDTreeSeeding.cc index 3bd70410d9..264806af96 100644 --- a/offline/packages/trackreco/PHActsKDTreeSeeding.cc +++ b/offline/packages/trackreco/PHActsKDTreeSeeding.cc @@ -33,8 +33,7 @@ #include #include -#include -#include +#include #include #include #include diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index 8af74c701f..f131319125 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -43,9 +43,8 @@ #ifndef __clang__ #pragma GCC diagnostic pop #endif -#include #include -#include +#include #include #include From aabd8ae5b5d426f1e3d17f179c85247ccc0d129a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 2 Mar 2026 14:13:58 -0500 Subject: [PATCH 323/866] fix field map reading --- offline/packages/trackbase/MagneticFieldOptions.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackbase/MagneticFieldOptions.cc b/offline/packages/trackbase/MagneticFieldOptions.cc index 4043397f76..52ee028196 100644 --- a/offline/packages/trackbase/MagneticFieldOptions.cc +++ b/offline/packages/trackbase/MagneticFieldOptions.cc @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -129,13 +129,13 @@ ActsExamples::Options::readMagneticField(const Variables& vars) { }; if (readRoot) { - auto map = makeMagneticFieldMapXyzFromRoot( + auto map = ActsPlugins::makeMagneticFieldMapXyzFromRoot( std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); } else { - auto map = makeMagneticFieldMapXyzFromText(std::move(mapBins), + auto map = Acts::makeMagneticFieldMapXyzFromText(std::move(mapBins), file.native(), lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); @@ -148,13 +148,13 @@ ActsExamples::Options::readMagneticField(const Variables& vars) { }; if (readRoot) { - auto map = makeMagneticFieldMapRzFromRoot( + auto map = ActsPlugins::makeMagneticFieldMapRzFromRoot( std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); } else { - auto map = makeMagneticFieldMapRzFromText(std::move(mapBins), + auto map = Acts::makeMagneticFieldMapRzFromText(std::move(mapBins), file.native(), lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); From fbfe26ec3d15ac3215e95f7511877c9010dd6223 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 2 Mar 2026 14:24:12 -0500 Subject: [PATCH 324/866] add in field options --- offline/packages/trackreco/MakeActsGeometry.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index de0e1d644f..5abeaa6397 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -64,20 +65,20 @@ #include +#include +#include + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wuninitialized" #include #pragma GCC diagnostic pop -#include #include #include #include -#include -#include #include #include From 5f88c000295f34eec8dcb565ea43d8240f6079b9 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Mon, 2 Mar 2026 14:37:35 -0500 Subject: [PATCH 325/866] Remove diagnostic outputs --- .../KshortReconstruction.cc | 83 +------------------ 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index 6676d64c9e..f197a3172e 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -125,7 +125,7 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) Acts::Vector3 dcaVals1 = calculateDca(tr1, mom1, pos1); if (fabs(dcaVals1(0)) < this_dca_cut || fabs(dcaVals1(1)) < this_dca_cut) { - std::cout << " tr1 failed dca cuts " << std::endl; + // std::cout << " tr1 failed dca cuts " << std::endl; continue; } // look for close DCA matches with all other such tracks @@ -134,35 +134,17 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) auto id2 = tr2_it->first; auto *tr2 = tr2_it->second; - bool diag = false; - // dca xy and dca z cut here compare to track dca cut Acts::Vector3 pos2(tr2->get_x(), tr2->get_y(), tr2->get_z()); Acts::Vector3 mom2(tr2->get_px(), tr2->get_py(), tr2->get_pz()); Acts::Vector3 dcaVals2 = calculateDca(tr2, mom2, pos2); - if( fabs(1.0 - std::tan(dcaVals1(2))) < 0.1 && abs(dcaVals2(2)-dcaVals1(2)) < 0.1 ) - { - // diag = true; - // std::cout << "*** Found phi values of interest " << std::endl; - } - if(diag) { std::cout << " tr1: id, dca3dxy1,dca3dz1,phi1: " << tr1->get_id() << " " << dcaVals1(0) << " " << dcaVals1(1) << " " << dcaVals1(2) << std::endl; } - if(diag) { std::cout << " tr2: id,dca3dxy2,dca3dz2,phi2: " << tr2->get_id() << " " << dcaVals2(0) << " " << dcaVals2(1) << " " << dcaVals2(2) << std::endl; } - if (tr2->get_quality() > _qual_cut) { - if(diag) - { - std::cout << " tr2 failed quality cut " << tr2->get_quality() << std::endl; - } continue; } if (tr2->get_pt() < track_pt_cut) { - if(diag) - { - std::cout << " tr2 failed pT cut " << tr2->get_pt() << std::endl; - } continue; } @@ -182,10 +164,6 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) } if (_require_mvtx) { - if(diag) - { - std::cout << " tr2 failed mvtx cut " << std::endl; - } continue; } } @@ -224,10 +202,6 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) if (fabs(dcaVals2(0)) < this_dca_cut2 || fabs(dcaVals2(1)) < this_dca_cut2) { - if(diag) - { - std::cout << " tr2 failed dca cut " << std::endl; - } continue; } @@ -256,7 +230,6 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) // This presently assumes straight line tracks to get a rough answer // Should update to use circles instead? findPcaTwoTracks(pos1, pos2, mom1, mom2, pca_rel1, pca_rel2, pair_dca); - if(diag) { std::cout << " pair dca " << pair_dca << " pca_rel1 " << pca_rel1(0) << " " << pca_rel1(1) << " " << pca_rel1(2) << std::endl; } // tracks with small relative pca are k short candidates if (abs(pair_dca) < pair_dca_cut) { @@ -303,12 +276,6 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity,decaymassa, decaymassb); fillNtp(tr1, tr2, decaymassa, decaymassb, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); - if(diag) - { - std::cout << "Accepted Track Pair" << " id1 " << id1 << " id2 " << id2 << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; - std::cout << " invariant mass: " << invariantMass << " decaymassa " << decaymassa << " decaymassb " << decaymassb << std::endl; - } - if (Verbosity() > 1) { std::cout << "Accepted Track Pair" << " id1 " << id1 << " id2 " << id2 << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; @@ -509,40 +476,6 @@ void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d m } } -/* - -void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity) -{ - double E1 = sqrt(pow(mom1(0), 2) + pow(mom1(1), 2) + pow(mom1(2), 2) + pow(decaymass, 2)); - double E2 = sqrt(pow(mom2(0), 2) + pow(mom2(1), 2) + pow(mom2(2), 2) + pow(decaymass, 2)); - - TLorentzVector v1(mom1(0), mom1(1), mom1(2), E1); - TLorentzVector v2(mom2(0), mom2(1), mom2(2), E2); - - TLorentzVector tsum; - tsum = v1 + v2; - - rapidity = tsum.Rapidity(); - pseudorapidity = tsum.Eta(); - invariantMass = tsum.M(); - invariantPt = tsum.Pt(); - invariantPhi = tsum.Phi(); - - if (Verbosity() > 2) - { - std::cout << "px1: " << mom1(0) << " py1: " << mom1(1) << " pz1: " << mom1(2) << " E1: " << E1 << std::endl; - std::cout << "px2: " << mom2(0) << " py2: " << mom2(1) << " pz2: " << mom2(2) << " E2: " << E2 << std::endl; - std::cout << "tsum: " << tsum(0) << " " << tsum(1) << " " << tsum(2) << " " << tsum(3) << std::endl; - std::cout << "invariant mass: " << invariantMass << " invariant Pt: " << invariantPt << " invariantPhi: " << invariantPhi << std::endl; - } - - if (invariantPt > invariant_pt_cut) - { - massreco->Fill(invariantMass); - } -} -*/ - bool KshortReconstruction::projectTrackToPoint(SvtxTrack* track, Eigen::Vector3d PCA, Eigen::Vector3d& pos, Eigen::Vector3d& mom) { bool ret = true; @@ -792,13 +725,6 @@ KshortReconstruction::KshortReconstruction(const std::string& name) Acts::Vector3 KshortReconstruction::calculateDca(SvtxTrack* track, const Acts::Vector3& momentum, Acts::Vector3 position) { - - /* - std::cout << " Input: pos(0) " << position(0) << " pos(1) " << position(1) << " pos(2) " << position(2) - << " mom(0) " << momentum(0) << " mom(1) " << momentum(1) << " mom(2) " << momentum(2) - << std::endl; - */ - // For the purposes of this module, we set default values to prevent this track from being rejected if the dca calc fails Acts::Vector3 r = momentum.cross(Acts::Vector3(0., 0., 1.)); float phi = std::atan2(r(1), r(0)); @@ -836,13 +762,6 @@ Acts::Vector3 KshortReconstruction::calculateDca(SvtxTrack* track, const Acts::V outVals(0) = abs(dca3dxy); outVals(1) = abs(dca3dz); outVals(2) = phi; - /* - std::cout << " calculateDca: dca3dxy " << outVals(0) << " dca3dz " << outVals(1) << " phi " << outVals(2) << std::endl - << " vertex(0) " << vertex(0) << " vertex(1) " << vertex(1) << " vertex(2) " << vertex(2) << std::endl - << " position(0) " << position(0) << " position(1) " << position(1) << " position(2) " << position(2) << std::endl - << " momentum(0) " << momentum(0) << " momentum(1) " << momentum(1) << " momentum(2) " << momentum(2) - << std::endl; - */ if (Verbosity() > 4) { From 37a1689869c7e090405ac006c98da4e2261498fe Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Mon, 2 Mar 2026 15:10:51 -0500 Subject: [PATCH 326/866] added fit info --- offline/packages/mbd/Makefile.am | 16 +++- offline/packages/mbd/MbdRawContainerV2.cc | 64 ++++++++++++++ offline/packages/mbd/MbdRawContainerV2.h | 79 +++++++++++++++++ .../packages/mbd/MbdRawContainerV2LinkDef.h | 5 ++ offline/packages/mbd/MbdRawHit.h | 23 +++++ offline/packages/mbd/MbdRawHitV2.cc | 23 +++++ offline/packages/mbd/MbdRawHitV2.h | 88 +++++++++++++++++++ offline/packages/mbd/MbdRawHitV2LinkDef.h | 5 ++ 8 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 offline/packages/mbd/MbdRawContainerV2.cc create mode 100644 offline/packages/mbd/MbdRawContainerV2.h create mode 100644 offline/packages/mbd/MbdRawContainerV2LinkDef.h create mode 100644 offline/packages/mbd/MbdRawHitV2.cc create mode 100644 offline/packages/mbd/MbdRawHitV2.h create mode 100644 offline/packages/mbd/MbdRawHitV2LinkDef.h diff --git a/offline/packages/mbd/Makefile.am b/offline/packages/mbd/Makefile.am index 111f9b31df..be588c0adb 100644 --- a/offline/packages/mbd/Makefile.am +++ b/offline/packages/mbd/Makefile.am @@ -49,8 +49,10 @@ pkginclude_HEADERS = \ MbdPmtHitV1.h \ MbdRawContainer.h \ MbdRawContainerV1.h \ + MbdRawContainerV2.h \ MbdRawHit.h \ MbdRawHitV1.h \ + MbdRawHitV2.h \ MbdReturnCodes.h \ MbdRunningStats.h \ MbdCalib.h \ @@ -70,8 +72,10 @@ pkginclude_HEADERS = \ MbdPmtSimHitV1.h \ MbdRawContainer.h \ MbdRawContainerV1.h \ + MbdRawContainerV2.h \ MbdRawHit.h \ MbdRawHitV1.h \ + MbdRawHitV2.h \ MbdRunningStats.h \ MbdSig.h \ MbdEvent.h \ @@ -97,8 +101,10 @@ ROOTDICTS = \ MbdPmtHitV1_Dict.cc \ MbdRawContainer_Dict.cc \ MbdRawContainerV1_Dict.cc \ + MbdRawContainerV2_Dict.cc \ MbdRawHit_Dict.cc \ - MbdRawHitV1_Dict.cc + MbdRawHitV1_Dict.cc \ + MbdRawHitV2_Dict.cc else ROOTDICTS = \ @@ -116,8 +122,10 @@ ROOTDICTS = \ MbdPmtSimContainerV1_Dict.cc \ MbdRawHit_Dict.cc \ MbdRawHitV1_Dict.cc \ + MbdRawHitV2_Dict.cc \ MbdRawContainer_Dict.cc \ - MbdRawContainerV1_Dict.cc + MbdRawContainerV1_Dict.cc \ + MbdRawContainerV2_Dict.cc endif pcmdir = $(libdir) @@ -138,8 +146,10 @@ libmbd_io_la_SOURCES = \ MbdPmtContainerV1.cc \ MbdRawHit.cc \ MbdRawHitV1.cc \ + MbdRawHitV2.cc \ MbdRawContainer.cc \ MbdRawContainerV1.cc \ + MbdRawContainerV2.cc \ MbdRunningStats.cc \ MbdCalib.cc \ MbdSig.cc @@ -160,8 +170,10 @@ libmbd_io_la_SOURCES = \ MbdPmtSimContainerV1.cc \ MbdRawHit.cc \ MbdRawHitV1.cc \ + MbdRawHitV2.cc \ MbdRawContainer.cc \ MbdRawContainerV1.cc \ + MbdRawContainerV2.cc \ MbdRunningStats.cc \ MbdSig.cc diff --git a/offline/packages/mbd/MbdRawContainerV2.cc b/offline/packages/mbd/MbdRawContainerV2.cc new file mode 100644 index 0000000000..9b7236de4a --- /dev/null +++ b/offline/packages/mbd/MbdRawContainerV2.cc @@ -0,0 +1,64 @@ +#include "MbdRawContainerV2.h" +#include "MbdRawHitV2.h" +#include "MbdReturnCodes.h" +#include "MbdDefs.h" + +#include + +#include + +MbdRawContainerV2::MbdRawContainerV2() : MbdRawHits(new TClonesArray("MbdRawHitV2", MbdDefs::MBD_N_PMT)) +{ + // MbdRawHit is class for single hit (members: pmt,adc,ttdc,qtdc), do not mix + // with TClonesArray *MbdRawHits + +} + +MbdRawContainerV2::~MbdRawContainerV2() +{ + delete MbdRawHits; +} + +int MbdRawContainerV2::isValid() const +{ + if (npmt <= 0) + { + return 0; + } + return 1; +} + +void MbdRawContainerV2::Reset() +{ + MbdRawHits->Clear(); + npmt = 0; +} + +void MbdRawContainerV2::identify(std::ostream &out) const +{ + out << "identify yourself: I am a MbdRawContainerV2 object" << std::endl; +} + +//______________________________________ +void MbdRawContainerV2::set_clocks(const Int_t ievt, const UShort_t iclk, const UShort_t ifemclk) +{ + evt = ievt; + clk = iclk; + femclk = ifemclk; +} + +Int_t MbdRawContainerV2::get_evt() const +{ + return evt; +} + +UShort_t MbdRawContainerV2::get_clock() const +{ + return clk; +} + +UShort_t MbdRawContainerV2::get_femclock() const +{ + return femclk; +} + diff --git a/offline/packages/mbd/MbdRawContainerV2.h b/offline/packages/mbd/MbdRawContainerV2.h new file mode 100644 index 0000000000..1b028863ea --- /dev/null +++ b/offline/packages/mbd/MbdRawContainerV2.h @@ -0,0 +1,79 @@ +#ifndef MBD_MBDRAWCONTAINERV2_H__ +#define MBD_MBDRAWCONTAINERV2_H__ + +#include "MbdRawContainer.h" + +#include + +#include + +/// +class MbdRawContainerV2 : public MbdRawContainer +{ +public: + /// ctor + MbdRawContainerV2(); + + /// dtor + virtual ~MbdRawContainerV2(); + + /// Clear Event + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream &out = std::cout) const override; + + /// isValid returns non zero if object contains vailid data + int isValid() const override; + + /** Add Mbd data containing evt, clk, and femclk + @param ievt Event number + @param iclk XMIT clock + @param ifemclk FEM clock + */ + virtual void set_clocks(const Int_t ievt, const UShort_t iclk, const UShort_t ifemclk) override; + + /** get Event Number + */ + virtual Int_t get_evt() const override; + + /** get XMIT Clock Counter + */ + virtual UShort_t get_clock() const override; + + /** get FEM Clock Counter + */ + virtual UShort_t get_femclock() const override; + + /** set number of pmts for Mbd + @param ival Number of Mbd Pmt's + */ + void set_npmt(const Short_t ival) override + { + npmt = ival; + return; + } + + /// get Number of Mbd Pmt's + Short_t get_npmt() const override { return MbdRawHits->GetEntries(); } + + /** get MbdRawPmt of Pmt iPmt in TClonesArray + @param iPmt no of Pmt in TClonesArray + */ + MbdRawHit *get_pmt(const int iPmt) const override { return (MbdRawHit*)MbdRawHits->ConstructedAt(iPmt); } + +private: + TClonesArray *GetMbdRawHits() const { return MbdRawHits; } + + Int_t evt{-1}; + UShort_t clk{0}; + UShort_t femclk{0}; + Short_t npmt = 0; + TClonesArray *MbdRawHits = nullptr; + + ClassDefOverride(MbdRawContainerV2, 1) +}; + +#endif diff --git a/offline/packages/mbd/MbdRawContainerV2LinkDef.h b/offline/packages/mbd/MbdRawContainerV2LinkDef.h new file mode 100644 index 0000000000..2c3bf0df5d --- /dev/null +++ b/offline/packages/mbd/MbdRawContainerV2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class MbdRawContainerV2 + ; + +#endif diff --git a/offline/packages/mbd/MbdRawHit.h b/offline/packages/mbd/MbdRawHit.h index 45bd089d5b..d0818e0a30 100644 --- a/offline/packages/mbd/MbdRawHit.h +++ b/offline/packages/mbd/MbdRawHit.h @@ -40,11 +40,34 @@ class MbdRawHit : public PHObject return MbdReturnCodes::MBD_INVALID_FLOAT; } + virtual Float_t get_chi2ndf() const + { + PHOOL_VIRTUAL_WARNING; + return MbdReturnCodes::MBD_INVALID_FLOAT; + } + + virtual UShort_t get_fitinfo() const + { + PHOOL_VIRTUAL_WARNING; + //return MbdReturnCodes::MBD_INVALID_USHORT; + return 0; //chiu + } + virtual void set_pmt(const Short_t /*pmt*/, const Float_t /*adc*/, const Float_t /*ttdc*/, const Float_t /*qtdc*/) { PHOOL_VIRTUAL_WARNING; } + virtual void set_chi2ndf(const Double_t /*chi2ndf*/) + { + PHOOL_VIRTUAL_WARNING; + } + + virtual void set_fitinfo(const UShort_t /*fitinfo*/) + { + PHOOL_VIRTUAL_WARNING; + } + virtual void identify(std::ostream& out = std::cout) const override; virtual int isValid() const override { return 0; } diff --git a/offline/packages/mbd/MbdRawHitV2.cc b/offline/packages/mbd/MbdRawHitV2.cc new file mode 100644 index 0000000000..2f4b6ca5bc --- /dev/null +++ b/offline/packages/mbd/MbdRawHitV2.cc @@ -0,0 +1,23 @@ +#include "MbdRawHitV2.h" + +void MbdRawHitV2::Reset() +{ + Clear(); +} + +void MbdRawHitV2::Clear(Option_t* /*unused*/) +{ + std::cout << "clearing " << bpmt << std::endl; + bpmt = -1; + fitstat = 0; + badc = std::numeric_limits::quiet_NaN(); + bttdc = std::numeric_limits::quiet_NaN(); + bqtdc = std::numeric_limits::quiet_NaN(); +} + +void MbdRawHitV2::identify(std::ostream& out) const +{ + out << "identify yourself: I am a MbdRawHitV2 object" << std::endl; + out << "Pmt: " << bpmt << ", adc: " << badc << ", ttdc: " + << bttdc << ", bqtdc: " << bqtdc << std::endl; +} diff --git a/offline/packages/mbd/MbdRawHitV2.h b/offline/packages/mbd/MbdRawHitV2.h new file mode 100644 index 0000000000..61e57fd6be --- /dev/null +++ b/offline/packages/mbd/MbdRawHitV2.h @@ -0,0 +1,88 @@ +#ifndef __MBD_MBDRAWHITV2_H__ +#define __MBD_MBDRAWHITV2_H__ + +#include "MbdRawHit.h" + +#include +#include +#include + +class MbdRawHitV2 : public MbdRawHit +{ + public: + MbdRawHitV2() = default; + ~MbdRawHitV2() override = default; + + //! Just does a clear + void Reset() override; + + //! Clear is used by TClonesArray to reset the tower to initial state without calling destructor/constructor + void Clear(Option_t* = "") override; + + //! PMT number + Short_t get_pmt() const override { return bpmt; } + + //! ADC + Float_t get_adc() const override { return badc; } + + //! TDC from time channel + Float_t get_ttdc() const override { return bttdc; } + + //! TDC from charge channel + Float_t get_qtdc() const override { return bqtdc; } + + //! Chi2/NDF from charge channel waveform fit + Float_t get_chi2ndf() const override { return (fitstat&0xfff)/100.; } + + //! Info about charge channel waveform fit + UShort_t get_fitinfo() const override { return (fitstat>>12); } + + //! Set PMT data values + void set_pmt(const Short_t pmt, const Float_t a, const Float_t tt, const Float_t tq) override + { + bpmt = pmt; + badc = a; + bttdc = tt; + bqtdc = tq; + } + + //! Store chi2/ndf (encoded in fitstat) + void set_chi2ndf(const Double_t chi2ndf) override + { + unsigned short us_chi2ndf = static_cast( chi2ndf*100. ); + if ( chi2ndf>40.95 ) + { + us_chi2ndf = 4095; + } + fitstat &= 0xf000; + fitstat |= us_chi2ndf; + } + + //! Store fitinfo (encoded in fitstat) + void set_fitinfo(const UShort_t fitinfo) override + { + fitstat &= 0xfff; + fitstat |= (fitinfo<<12); + } + + //! Prints out exact identity of object + void identify(std::ostream& out = std::cout) const override; + + //! isValid returns non zero if object contains valid data + virtual int isValid() const override + { + if (std::isnan(get_ttdc())) return 0; + return 1; + } + + private: + Short_t bpmt; + UShort_t fitstat; //waveform fit status + Float_t badc; + Float_t bttdc; + Float_t bqtdc; + + ClassDefOverride(MbdRawHitV2, 1) +}; + +#endif diff --git a/offline/packages/mbd/MbdRawHitV2LinkDef.h b/offline/packages/mbd/MbdRawHitV2LinkDef.h new file mode 100644 index 0000000000..8936852bfe --- /dev/null +++ b/offline/packages/mbd/MbdRawHitV2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class MbdRawHitV2 + ; + +#endif From 6e6503f5c5261d3b311e0464287d2133361c2d98 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Mon, 2 Mar 2026 16:23:39 -0500 Subject: [PATCH 327/866] added info on waveform fit to RawHit output object, added refits to waveforms to check for better alternative fit --- offline/packages/mbd/MbdCalib.cc | 55 +++--- offline/packages/mbd/MbdEvent.cc | 18 +- offline/packages/mbd/MbdRawHit.h | 3 +- offline/packages/mbd/MbdReco.cc | 4 +- offline/packages/mbd/MbdReturnCodes.h | 5 +- offline/packages/mbd/MbdSig.cc | 234 +++++++++++++++++--------- offline/packages/mbd/MbdSig.h | 10 +- 7 files changed, 212 insertions(+), 117 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 578fead8ac..82d87b7671 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -79,13 +79,7 @@ int MbdCalib::Download_All() // if rc flag MBD_CALDIR does not exist, we create it and set it to an empty string if (!_rc->FlagExist("MBD_CALDIR")) { - std::string sampmax_url = _cdb->getUrl("MBD_SAMPMAX"); - if (Verbosity() > 0) - { - std::cout << "sampmax_url " << sampmax_url << std::endl; - } - Download_SampMax(sampmax_url); - + // Always load Status std::string status_url = _cdb->getUrl("MBD_STATUS"); if ( ! status_url.empty() ) { @@ -99,6 +93,14 @@ int MbdCalib::Download_All() if ( !_rawdstflag ) { + // sampmax and ped will be calculated on the fly if calibs don't exist + std::string sampmax_url = _cdb->getUrl("MBD_SAMPMAX"); + if (Verbosity() > 0) + { + std::cout << "sampmax_url " << sampmax_url << std::endl; + } + Download_SampMax(sampmax_url); + std::string ped_url = _cdb->getUrl("MBD_PED"); if (Verbosity() > 0) { @@ -106,7 +108,6 @@ int MbdCalib::Download_All() } Download_Ped(ped_url); - std::string pileup_url = _cdb->getUrl("MBD_PILEUP"); if ( pileup_url.empty() ) { @@ -135,29 +136,29 @@ int MbdCalib::Download_All() } } - std::string qfit_url = _cdb->getUrl("MBD_QFIT"); - if (Verbosity() > 0) + if ( !_fitsonly ) { - std::cout << "qfit_url " << qfit_url << std::endl; - } - Download_Gains(qfit_url); + std::string qfit_url = _cdb->getUrl("MBD_QFIT"); + if (Verbosity() > 0) + { + std::cout << "qfit_url " << qfit_url << std::endl; + } + Download_Gains(qfit_url); - std::string tt_t0_url = _cdb->getUrl("MBD_TT_T0"); - if ( Verbosity() > 0 ) - { - std::cout << "tt_t0_url " << tt_t0_url << std::endl; - } - Download_TTT0(tt_t0_url); + std::string tt_t0_url = _cdb->getUrl("MBD_TT_T0"); + if ( Verbosity() > 0 ) + { + std::cout << "tt_t0_url " << tt_t0_url << std::endl; + } + Download_TTT0(tt_t0_url); - std::string tq_t0_url = _cdb->getUrl("MBD_TQ_T0"); - if (Verbosity() > 0) - { - std::cout << "tq_t0_url " << tq_t0_url << std::endl; - } - Download_TQT0(tq_t0_url); + std::string tq_t0_url = _cdb->getUrl("MBD_TQ_T0"); + if (Verbosity() > 0) + { + std::cout << "tq_t0_url " << tq_t0_url << std::endl; + } + Download_TQT0(tq_t0_url); - if ( !_fitsonly ) - { std::string t0corr_url = _cdb->getUrl("MBD_T0CORR"); if ( Verbosity() > 0 ) { diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index e5ae966587..b97d750f29 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -156,7 +156,7 @@ int MbdEvent::InitRun() { // Download calibrations int status = _mbdcal->Download_All(); - if ( status < 0 && _calpass==0 ) // only abort for normal processing + if ( status < 0 && _calpass==0 && _fitsonly ) // only abort for production waveform pass { return Fun4AllReturnCodes::ABORTRUN; } @@ -444,13 +444,18 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc return Fun4AllReturnCodes::DISCARDEVENT; } + int evtseq = 0; + if ( gl1raw != nullptr ) + { + evtseq = gl1raw->getEvtSequence(); + } + // Only use MBDNS triggered events for MBD calibrations if ( _calpass>0 && gl1raw != nullptr ) { const uint64_t MBDTRIGS = 0x7c00; // MBDNS trigger bits //uint64_t trigvec = gl1raw->getTriggerVector(); // raw trigger only (obsolete, was only available in run1) uint64_t strig = gl1raw->getScaledVector(); // scaled trigger only - int evtseq = gl1raw->getEvtSequence(); if ( Verbosity() ) { static int counter = 0; @@ -528,6 +533,7 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc if ( _nsamples > 0 && _nsamples <= 30 ) { _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]); + _mbdsig[feech].SetEvtNum( evtseq ); } /* else @@ -658,6 +664,7 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer _mbdsig[feech].SetNSamples( _nsamples ); _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]); + _mbdsig[feech].SetEvtNum( m_evt ); //_mbdsig[feech].Print(); } @@ -760,7 +767,7 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) m_ampl[ifeech] = _mbdsig[ifeech].GetAmpl(); // in adc units if (do_templatefit) { - //std::cout << "fittemplate" << std::endl; + //std::cout << "fittemplate " << ifeech << std::endl; _mbdsig[ifeech].FitTemplate( _mbdcal->get_sampmax(ifeech) ); /* @@ -784,6 +791,8 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) { int feech = _mbdgeom->get_feech(ipmt); bbcraws->get_pmt(ipmt)->set_pmt(ipmt, m_ampl[feech], m_ttdc[ipmt], m_qtdc[ipmt]); + bbcraws->get_pmt(ipmt)->set_chi2ndf( _mbdsig[feech].GetChi2NDF() ); + bbcraws->get_pmt(ipmt)->set_fitinfo( _mbdsig[feech].GetFitInfo() ); } bbcraws->set_npmt(MbdDefs::BBC_N_PMT); // this would need to be changed if we zero-suppressed bbcraws->set_clocks(m_evt, m_clk, m_femclk); @@ -901,7 +910,10 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc // Copy to output for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++) { + int feech = _mbdgeom->get_feech(ipmt); bbcpmts->get_pmt(ipmt)->set_pmt(ipmt, m_pmtq[ipmt], m_pmttt[ipmt], m_pmttq[ipmt]); + bbcraws->get_pmt(ipmt)->set_chi2ndf( _mbdsig[feech].GetChi2NDF() ); + bbcraws->get_pmt(ipmt)->set_fitinfo( _mbdsig[feech].GetFitInfo() ); } bbcpmts->set_npmt(MbdDefs::BBC_N_PMT); diff --git a/offline/packages/mbd/MbdRawHit.h b/offline/packages/mbd/MbdRawHit.h index d0818e0a30..510a68b32f 100644 --- a/offline/packages/mbd/MbdRawHit.h +++ b/offline/packages/mbd/MbdRawHit.h @@ -49,8 +49,7 @@ class MbdRawHit : public PHObject virtual UShort_t get_fitinfo() const { PHOOL_VIRTUAL_WARNING; - //return MbdReturnCodes::MBD_INVALID_USHORT; - return 0; //chiu + return 0; } virtual void set_pmt(const Short_t /*pmt*/, const Float_t /*adc*/, const Float_t /*ttdc*/, const Float_t /*qtdc*/) diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index fe4dc62049..5ae4a67271 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -2,7 +2,7 @@ #include "MbdEvent.h" #include "MbdGeomV1.h" #include "MbdOutV2.h" -#include "MbdRawContainerV1.h" +#include "MbdRawContainerV2.h" #include "MbdPmtContainerV1.h" #include "MbdPmtSimContainerV1.h" @@ -262,7 +262,7 @@ int MbdReco::createNodes(PHCompositeNode *topNode) if (!m_mbdraws) { std::cout << "Creating MbdRawContainer Node " << std::endl; - m_mbdraws = new MbdRawContainerV1(); + m_mbdraws = new MbdRawContainerV2(); PHIODataNode *MbdRawContainerNode = new PHIODataNode(m_mbdraws, "MbdRawContainer", "PHObject"); bbcNode->addNode(MbdRawContainerNode); } diff --git a/offline/packages/mbd/MbdReturnCodes.h b/offline/packages/mbd/MbdReturnCodes.h index c9b1aea40e..ee808346fa 100644 --- a/offline/packages/mbd/MbdReturnCodes.h +++ b/offline/packages/mbd/MbdReturnCodes.h @@ -8,8 +8,9 @@ namespace MbdReturnCodes { - const short MBD_INVALID_SHORT = std::numeric_limits::min(); //-9999; - const int MBD_INVALID_INT = std::numeric_limits::min(); //-9999; + const short MBD_INVALID_SHORT = std::numeric_limits::min(); + const unsigned short MBD_INVALID_USHORT = std::numeric_limits::min(); + const int MBD_INVALID_INT = std::numeric_limits::min(); const float MBD_INVALID_FLOAT = std::numeric_limits::quiet_NaN(); } // namespace MbdReturnCodes diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index 155d731719..a896146770 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -80,10 +81,6 @@ void MbdSig::Init() ped_fcn = new TF1("ped_fcn","[0]",0,2); ped_fcn->SetLineColor(3); - // Set tail function - ped_tail = new TF1("ped_tail","[0]+[1]*exp(-[2]*x)",0,2); - ped_tail->SetLineColor(2); - name = "h_chi2ndf"; name += _ch; h_chi2ndf = new TH1F(name,name,2000,0,100); @@ -157,7 +154,7 @@ MbdSig::~MbdSig() delete template_fcn; delete twotemplate_fcn; delete ped_fcn; - delete ped_tail; + delete fit_pileup; delete h_chi2ndf; if ( _pedstudyflag ) { @@ -237,8 +234,6 @@ void MbdSig::SetY(const Float_t* y, const int invert) Remove_Pileup(); } } - - _evt_counter++; } void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert) @@ -320,18 +315,17 @@ void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert) */ } - _evt_counter++; _verbose = 0; } void MbdSig::Remove_Pileup() { - //_verbose = 100; _verbose = 0; /* - if ( (_ch==238&&_evt_counter==7104) || (_ch==255&&_evt_counter==7762) ) + if ( _ch==46 && (_evt_counter>200910 && _evt_counter<200920)) { + std::cout << PHWHERE << "\t" << _evt_counter << "\t" << _ch << std::endl; _verbose = 100; } */ @@ -352,6 +346,7 @@ void MbdSig::Remove_Pileup() { TString name = "fit_pileup"; name += _ch; fit_pileup = new TF1(name,"pol3",0,16000); + fit_pileup->SetLineColor(7); for (int ipar=0; ipar<4; ipar++) { fit_pileup->SetParameter( ipar, _mbdcal->get_pileup(_ch,ipar+1) ); @@ -421,7 +416,6 @@ void MbdSig::Remove_Pileup() PadUpdate(); //gSubPulse->Print("ALL"); } - } else { @@ -429,8 +423,9 @@ void MbdSig::Remove_Pileup() if ( fit_pileup == nullptr ) { TString name = "fit_pileup"; name += _ch; - fit_pileup = new TF1(name,"gaus",-0.1,4.1); - fit_pileup->SetLineColor(2); + //fit_pileup = new TF1(name,"gaus",-0.1,4.1); + fit_pileup = new TF1(name, this, &MbdSig::SignalTail, -0.1, 4.1, 3, "MbdSig", "SignalTail"); + fit_pileup->SetLineColor(6); } fit_pileup->SetRange(-0.1,4.1); @@ -704,6 +699,17 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) ped_fcn->SetRange(minsamp-0.1,maxsamp+0.1); ped_fcn->SetParameter(0,1500.); + gRawPulse->Fit( ped_fcn, "RNQ" ); + double chi2 = ped_fcn->GetChisquare(); + double ndf = ped_fcn->GetNDF(); + + /* + if ( chi2/ndf>4 ) + { + _verbose=100; + } + */ + if ( _verbose ) { gRawPulse->Fit( ped_fcn, "RQ" ); @@ -716,15 +722,6 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) PadUpdate(); } } - else - { - //std::cout << PHWHERE << std::endl; - gRawPulse->Fit( ped_fcn, "RNQ" ); - - } - - double chi2 = ped_fcn->GetChisquare(); - double ndf = ped_fcn->GetNDF(); if ( chi2/ndf < 4.0 ) { @@ -1110,6 +1107,21 @@ void MbdSig::PadUpdate() const } } +Double_t MbdSig::SignalTail(const Double_t* x, const Double_t* par) +{ + // par[0] is the amplitude (relative to the spline amplitude) + // par[1] is the time + // x[0] units are in sample number + Double_t xx = x[0]-par[1]; + if ( xx<0. ) + { + return par[0]; + } + Double_t f = par[0]*TMath::Gaus(x[0],par[1],par[2]); + + return f; +} + Double_t MbdSig::TwoTemplateFcn(const Double_t* x, const Double_t* par) { Double_t f = TemplateFcn(x,par) + TemplateFcn(x,par+2); @@ -1209,11 +1221,13 @@ Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) } // reject points with very bad rms in shape + /* if (template_yrms[ilow] >= 1.0 || template_yrms[ihigh] >= 1.0) { TF1::RejectPoint(); // return f; } + */ // Reject points where ADC saturates int samp_point = static_cast(x[0]); @@ -1231,8 +1245,16 @@ Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) } // sampmax>0 means fit to the peak near sampmax +// fitmode: +// 0 - no info or no fit +// 1 - regular template fit (shortened) +// 2 - two template fit +// 3 - two template fit, neg ampl 2nd template +// 4 - saturated template fit +// 5 - saturated and shortened template fit int MbdSig::FitTemplate( const Int_t sampmax ) { + //_verbose = 100; //std::cout << PHWHERE << std::endl; /* if ( _evt_counter==2142 && _ch==92 ) @@ -1242,6 +1264,11 @@ int MbdSig::FitTemplate( const Int_t sampmax ) } */ + // Reset Fit Quality Parameters + f_chi2 = 0.; + f_ndf = 0.; + f_fitmode = 0; + // Check if channel is empty if (gSubPulse->GetN() == 0) { @@ -1262,9 +1289,9 @@ int MbdSig::FitTemplate( const Int_t sampmax ) nsaturated++; } } + /* - //if ( nsaturated>2 && _ch==185 ) - if ( nsaturated>2 ) + if ( nsaturated>0 ) { _verbose = 12; } @@ -1294,8 +1321,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) } } - //gSubPulse->GetPoint(sampmax, x_at_max, ymax); - if ( nsaturated<=3 ) + if ( nsaturated==0 ) { x_at_max -= 2.0; } @@ -1331,14 +1357,17 @@ int MbdSig::FitTemplate( const Int_t sampmax ) return 1; } + // Start with fit over early part of waveform to reduce pileup and afterpulse effects template_fcn->SetParameters(ymax, x_at_max); - if ( nsaturated<=3 ) + if ( nsaturated==0 ) { template_fcn->SetRange(0, x_at_max+4.2); + f_fitmode = 1; } else { - template_fcn->SetRange(0, sampmax + nsaturated - 0.5); + template_fcn->SetRange(0, sampmax + nsaturated + 0.5); + f_fitmode = 4; } if (_verbose == 0) @@ -1367,25 +1396,36 @@ int MbdSig::FitTemplate( const Int_t sampmax ) if ( (f_chi2/f_ndf) < 5. && f_ndf>6. ) { h_chi2ndf->Fill( f_chi2/f_ndf ); + _verbose = 0; return 1; } - // fit was out of time, likely from pileup, try two waveforms - if ( (f_time<(sampmax-2.5) || f_time>sampmax) && (nsaturated<=3) ) + /* + _verbose = 100; + if ( _verbose ) + { + PrintResiduals(gSubPulse,template_fcn); + } + */ + + // fit was bad, refit with two templates + if ( nsaturated==0 ) { //_verbose = 100; + f_fitmode = 2; if ( _verbose ) { - std::cout << "BADTIME " << _evt_counter << "\t" << _ch << "\t" << sampmax << "\t" << f_ampl << "\t" << f_time << std::endl; + std::cout << "BADTIME " << _evt_counter << "\t" << _ch << "\t" << sampmax << "\t" << f_ampl << "\t" << f_time + << "\t" << f_chi2/f_ndf << std::endl; gSubPulse->Draw("ap"); template_fcn->Draw("same"); PadUpdate(); } twotemplate_fcn->SetParameters(ymax,x_at_max,ymax,10); - twotemplate_fcn->SetRange(0,_nsamples); + twotemplate_fcn->SetRange(0,_nsamples-0.9); if (_verbose == 0) { @@ -1393,7 +1433,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) } else { - std::cout << "doing fit1 " << x_at_max << "\t" << ymax << std::endl; + std::cout << "doing 2wave fit " << x_at_max << "\t" << ymax << std::endl; gSubPulse->Fit(twotemplate_fcn, "R"); gSubPulse->Draw("ap"); gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); @@ -1402,55 +1442,65 @@ int MbdSig::FitTemplate( const Int_t sampmax ) //gSubPulse->Print("ALL"); } - //PadUpdate(); - - // Get fit parameters - f_ampl = twotemplate_fcn->GetParameter(0); - f_time = twotemplate_fcn->GetParameter(1); - f_chi2 = twotemplate_fcn->GetChisquare(); - f_ndf = twotemplate_fcn->GetNDF(); - - // Good fit - if ( (f_chi2/f_ndf) < 5. && f_ndf>6. ) + // Check two component fit + Double_t ampl1 = twotemplate_fcn->GetParameter(0); + Double_t time1 = twotemplate_fcn->GetParameter(1); + Double_t ampl2 = twotemplate_fcn->GetParameter(2); + Double_t time2 = twotemplate_fcn->GetParameter(3); + Double_t newchi2 = twotemplate_fcn->GetChisquare(); + Double_t newndf = twotemplate_fcn->GetNDF(); + Double_t newchi2ndf = newchi2/newndf; + + // bad two component fit, use original fit + if ( time2>15. || ampl1<0 || ampl2<0. || newchi2ndf>(f_chi2/f_ndf) ) { + if (_verbose) + { + std::cout << "Using original " << newchi2ndf << std::endl; + PrintResiduals(gSubPulse,twotemplate_fcn); + } + f_fitmode = 3; h_chi2ndf->Fill( f_chi2/f_ndf ); _verbose = 0; return 1; } - } - // refit with new range to exclude after-pulses - template_fcn->SetParameters(ymax, x_at_max); - //template_fcn->SetParameters( f_ampl, f_time ); + // Get new fit parameters (pick fit closest in time to first fit + if ( std::abs(f_time-time1) < std::abs(f_time-time2) ) + { + f_ampl = ampl1; + f_time = time1; + } + else + { + f_ampl = ampl2; + f_time = time2; + } - if ( nsaturated<=3 ) - { - template_fcn->SetRange(0, x_at_max+4.2); - //template_fcn->SetRange( 0., f_time+4.0 ); - } - else - { - template_fcn->SetRange( 0., f_time+nsaturated+0.8 ); + f_chi2 = newchi2; + f_ndf = newndf; + + // poor fit + if ( _verbose && (f_chi2/f_ndf) > 5. && f_ndf>6. ) + { + std::cout << "double fit high chi2/ndf " << f_chi2/f_ndf << std::endl; + PrintResiduals(gSubPulse,twotemplate_fcn); + PadUpdate(); + } + + h_chi2ndf->Fill( f_chi2/f_ndf ); + _verbose = 0; + return 1; } + // Try a refit of saturated waveform with different range + template_fcn->SetParameters(ymax, x_at_max); + template_fcn->SetRange( 0., _nsamples-0.5 ); + if (_verbose == 0) { //std::cout << PHWHERE << std::endl; - int fit_status = gSubPulse->Fit(template_fcn, "RNQ"); - if ( fit_status<0 && _verbose>0 ) - { - std::cout << PHWHERE << "\t" << fit_status << std::endl; - gSubPulse->Print("ALL"); - gSubPulse->Draw("ap"); - gSubPulse->Fit(template_fcn, "R"); - std::cout << "ampl time before refit " << _ch << "\t" << f_ampl << "\t" << f_time << std::endl; - f_ampl = template_fcn->GetParameter(0); - f_time = template_fcn->GetParameter(1); - std::cout << "ampl time after refit " << _ch << "\t" << f_ampl << "\t" << f_time << std::endl; - PadUpdate(); - std::string junk; - std::cin >> junk; - } + gSubPulse->Fit(template_fcn, "RNQ"); } else { @@ -1462,19 +1512,21 @@ int MbdSig::FitTemplate( const Int_t sampmax ) std::cout << "ampl time after refit " << f_ampl << "\t" << f_time << std::endl; } - f_ampl = template_fcn->GetParameter(0); - f_time = template_fcn->GetParameter(1); - f_chi2 = template_fcn->GetChisquare(); - f_ndf = template_fcn->GetNDF(); + // pick lower chi2/ndf of two saturated fits + Double_t newchi2 = template_fcn->GetChisquare(); + Double_t newndf = template_fcn->GetNDF(); + if ( (newchi2/newndf)GetParameter(0); + f_time = template_fcn->GetParameter(1); + f_chi2 = newchi2; + f_ndf = newndf; + f_fitmode = 5; + } h_chi2ndf->Fill( f_chi2/f_ndf ); - //if ( f_time<0 || f_time>30 ) - //if ( (_ch==185||_ch==155||_ch==249) && (fabs(f_ampl) > 44000.) ) - //double chi2 = template_fcn->GetChisquare(); - //double ndf = template_fcn->GetNDF(); - //if ( (_ch==185||_ch==155||_ch==249) && (fabs(chi2/ndf) > 100.) && nsaturated > 3) - if (_verbose > 0 && fabs(f_ampl) > 0.) + if (_verbose > 0 && std::abs(f_ampl) > 0.) { _verbose = 12; std::cout << "FitTemplate " << _ch << "\t" << f_ampl << "\t" << f_time << std::endl; @@ -1485,6 +1537,9 @@ int MbdSig::FitTemplate( const Int_t sampmax ) gPad->SetGridy(1); template_fcn->SetLineColor(4); template_fcn->Draw("same"); + + PrintResiduals(gSubPulse,template_fcn); + PadUpdate(); } @@ -1544,3 +1599,22 @@ int MbdSig::SetTemplate(const std::vector& shape, const std::vectorGetRange(smin,smax); + + double x{0}; + double y{0}; + for (double samp=0; samp<=smax; samp+=1.0) + { + g->GetPoint(int(samp),x,y); + double yerr = g->GetErrorY(int(samp)); + double resid = (y - f->Eval(x))/yerr; + std::cout << samp << "\t" << x << "\t" << resid << "\t" << y << "\t" << f->Eval(x) << "\t" << yerr << std::endl; + } +} + diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index bafdd9339c..73d3d1791b 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -31,6 +31,7 @@ class MbdSig void SetNSamples( const int s ) { _nsamples = s; } void SetY(const Float_t *y, const int invert = 1); void SetXY(const Float_t *x, const Float_t *y, const int invert = 1); + void SetEvtNum(const int evtnum) { _evt_counter = evtnum; } int GetNSamples() { return _nsamples; } @@ -41,6 +42,10 @@ class MbdSig Double_t GetAmpl() { return f_ampl; } Double_t GetTime() { return f_time; } Double_t GetIntegral() { return f_integral; } + Double_t GetChi2() { return f_chi2; } + Double_t GetNDF() { return f_ndf; } + Double_t GetChi2NDF() { return f_chi2/f_ndf; } + UShort_t GetFitInfo() { return f_fitmode; } /** * Fill hists from data between minsamp and maxsamp bins @@ -110,11 +115,14 @@ class MbdSig // Double_t FitPulse(); void SetTimeOffset(const Double_t o) { f_time_offset = o; } + Double_t SignalTail(const Double_t *x, const Double_t *par); Double_t TemplateFcn(const Double_t *x, const Double_t *par); Double_t TwoTemplateFcn(const Double_t *x, const Double_t *par); TF1 *GetTemplateFcn() { return template_fcn; } void SetMinMaxFitTime(const Double_t mintime, const Double_t maxtime); + void PrintResiduals(TGraphErrors *g, TF1 *f); + void WritePedHist(); void WritePedvsEvent(); void WriteChi2Hist(); @@ -147,6 +155,7 @@ class MbdSig Double_t f_integral{0.}; /** integral */ + UShort_t f_fitmode{0}; Double_t f_chi2{0.}; Double_t f_ndf{0.}; @@ -163,7 +172,6 @@ class MbdSig TH1 *hPedEvt{nullptr}; //! evt-by-event pedestal TGraphErrors *gPedvsEvent{nullptr}; //! Keep track of pedestal vs evtnum TF1 *ped_fcn{nullptr}; - TF1 *ped_tail{nullptr}; //! tail of prev signal Double_t ped0{0.}; //! Double_t ped0rms{0.}; //! int use_ped0{0}; //! whether to apply ped0 From 4a0fe1f55baabba3a4f05d10e419a87e3e2282bc Mon Sep 17 00:00:00 2001 From: Joseph Clement Date: Mon, 2 Mar 2026 18:17:26 -0500 Subject: [PATCH 328/866] remove smart pointer in Timingcut module, make destructor safely delete fit function to prevent leaking memory --- offline/packages/jetbackground/TimingCut.cc | 11 ++++++++++- offline/packages/jetbackground/TimingCut.h | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index 29f6e7d469..41d8dc571d 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -33,6 +33,15 @@ TimingCut::TimingCut(const std::string &jetNodeName, const std::string &name, co SetDefaultParams(); } +TimingCut::~TimingCut() +{ + if(_fitFunc) + { + delete _fitFunc; + _fitFunc = nullptr; + } +} + //____________________________________________________________________________.. int TimingCut::Init(PHCompositeNode *topNode) { @@ -52,7 +61,7 @@ int TimingCut::Init(PHCompositeNode *topNode) std::cout << "ERROR: NO CALIBRATION TF1 FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! This should never happen. ABORT RUN!" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - _fitFunc = std::unique_ptr((TF1*)tmp->Clone()); + _fitFunc = (TF1*)tmp->Clone(); delete fitFile; } else diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index 743f8fac6b..a6c56433e8 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -22,7 +22,7 @@ class TimingCut : public SubsysReco public: explicit TimingCut(const std::string &jetNodeName, const std::string &name = "TimingCutModule", bool doAbort = false, const std::string &ohTowerName = "TOWERINFO_CALIB_HCALOUT"); - ~TimingCut() override = default; + ~TimingCut() override; void set_t_shift(float new_shift) { _t_shift = new_shift; } float get_t_shift() { return _t_shift; } @@ -123,7 +123,7 @@ class TimingCut : public SubsysReco float _t_shift{0.0}; float _mbd_dt_width{3.0}; float _min_dphi{3*M_PI/4}; - std::unique_ptr _fitFunc{nullptr}; + TF1* _fitFunc{nullptr}; }; #endif From 979697c730795d74b7f32641729e9562e4d43f57 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Mon, 2 Mar 2026 21:21:42 -0500 Subject: [PATCH 329/866] rabbit fixes --- offline/packages/mbd/MbdRawContainerV2.h | 7 ++++++- offline/packages/mbd/MbdRawHitV1.cc | 2 +- offline/packages/mbd/MbdRawHitV2.cc | 2 +- offline/packages/mbd/MbdRawHitV2.h | 7 ++++--- offline/packages/mbd/MbdSig.cc | 25 ++++++++++++++++-------- offline/packages/mbd/MbdSig.h | 2 +- 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/offline/packages/mbd/MbdRawContainerV2.h b/offline/packages/mbd/MbdRawContainerV2.h index 1b028863ea..199ab4cc73 100644 --- a/offline/packages/mbd/MbdRawContainerV2.h +++ b/offline/packages/mbd/MbdRawContainerV2.h @@ -52,7 +52,12 @@ class MbdRawContainerV2 : public MbdRawContainer */ void set_npmt(const Short_t ival) override { - npmt = ival; + if ( ival != MbdRawHits->GetEntries() ) + { + std::cout << "ERROR, " << ival << " differs from " << MbdRawHits->GetEntries() << std::endl; + std::cout << " Setting npmt to " << MbdRawHits->GetEntries() << std::endl; + } + npmt = MbdRawHits->GetEntries(); return; } diff --git a/offline/packages/mbd/MbdRawHitV1.cc b/offline/packages/mbd/MbdRawHitV1.cc index 6f4eec2001..2ea6b34c01 100644 --- a/offline/packages/mbd/MbdRawHitV1.cc +++ b/offline/packages/mbd/MbdRawHitV1.cc @@ -7,7 +7,7 @@ void MbdRawHitV1::Reset() void MbdRawHitV1::Clear(Option_t* /*unused*/) { - std::cout << "clearing " << bpmt << std::endl; + //std::cout << "clearing " << bpmt << std::endl; bpmt = -1; badc = std::numeric_limits::quiet_NaN(); bttdc = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/mbd/MbdRawHitV2.cc b/offline/packages/mbd/MbdRawHitV2.cc index 2f4b6ca5bc..695003cfb1 100644 --- a/offline/packages/mbd/MbdRawHitV2.cc +++ b/offline/packages/mbd/MbdRawHitV2.cc @@ -7,7 +7,7 @@ void MbdRawHitV2::Reset() void MbdRawHitV2::Clear(Option_t* /*unused*/) { - std::cout << "clearing " << bpmt << std::endl; + //std::cout << "clearing " << bpmt << std::endl; bpmt = -1; fitstat = 0; badc = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/mbd/MbdRawHitV2.h b/offline/packages/mbd/MbdRawHitV2.h index 61e57fd6be..4bc88f871d 100644 --- a/offline/packages/mbd/MbdRawHitV2.h +++ b/offline/packages/mbd/MbdRawHitV2.h @@ -49,10 +49,11 @@ class MbdRawHitV2 : public MbdRawHit //! Store chi2/ndf (encoded in fitstat) void set_chi2ndf(const Double_t chi2ndf) override { - unsigned short us_chi2ndf = static_cast( chi2ndf*100. ); - if ( chi2ndf>40.95 ) + UShort_t us_chi2ndf = 0; + if (std::isfinite(chi2ndf) && chi2ndf > 0.) { - us_chi2ndf = 4095; + const Double_t clipped = (chi2ndf > 40.95) ? 40.95 : chi2ndf; + us_chi2ndf = static_cast(clipped * 100.); } fitstat &= 0xf000; fitstat |= us_chi2ndf; diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index a896146770..65de1006fc 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -1391,11 +1391,16 @@ int MbdSig::FitTemplate( const Int_t sampmax ) f_time = template_fcn->GetParameter(1); f_chi2 = template_fcn->GetChisquare(); f_ndf = template_fcn->GetNDF(); + Double_t chi2ndf = 1e9; + if ( f_ndf>0. ) + { + chi2ndf = f_chi2/f_ndf; + } // Good fit - if ( (f_chi2/f_ndf) < 5. && f_ndf>6. ) + if ( f_ndf>6. && chi2ndf<5. ) { - h_chi2ndf->Fill( f_chi2/f_ndf ); + h_chi2ndf->Fill( chi2ndf ); _verbose = 0; return 1; @@ -1417,8 +1422,8 @@ int MbdSig::FitTemplate( const Int_t sampmax ) if ( _verbose ) { - std::cout << "BADTIME " << _evt_counter << "\t" << _ch << "\t" << sampmax << "\t" << f_ampl << "\t" << f_time - << "\t" << f_chi2/f_ndf << std::endl; + std::cout << "BADFIT " << _evt_counter << "\t" << _ch << "\t" << sampmax << "\t" << f_ampl << "\t" << f_time + << "\t" << chi2ndf << std::endl; gSubPulse->Draw("ap"); template_fcn->Draw("same"); PadUpdate(); @@ -1449,10 +1454,14 @@ int MbdSig::FitTemplate( const Int_t sampmax ) Double_t time2 = twotemplate_fcn->GetParameter(3); Double_t newchi2 = twotemplate_fcn->GetChisquare(); Double_t newndf = twotemplate_fcn->GetNDF(); - Double_t newchi2ndf = newchi2/newndf; + Double_t newchi2ndf = 0.; + if ( newndf>0.) + { + newchi2ndf = newchi2/newndf; + } // bad two component fit, use original fit - if ( time2>15. || ampl1<0 || ampl2<0. || newchi2ndf>(f_chi2/f_ndf) ) + if ( time2>15. || ampl1<0 || ampl2<0. || newchi2ndf>chi2ndf) { if (_verbose) { @@ -1460,7 +1469,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) PrintResiduals(gSubPulse,twotemplate_fcn); } f_fitmode = 3; - h_chi2ndf->Fill( f_chi2/f_ndf ); + h_chi2ndf->Fill( chi2ndf ); _verbose = 0; return 1; } @@ -1481,7 +1490,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) f_ndf = newndf; // poor fit - if ( _verbose && (f_chi2/f_ndf) > 5. && f_ndf>6. ) + if ( _verbose && f_ndf>6. && (f_chi2/f_ndf) > 5. ) { std::cout << "double fit high chi2/ndf " << f_chi2/f_ndf << std::endl; PrintResiduals(gSubPulse,twotemplate_fcn); diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index 73d3d1791b..69d5ca7bfd 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -44,7 +44,7 @@ class MbdSig Double_t GetIntegral() { return f_integral; } Double_t GetChi2() { return f_chi2; } Double_t GetNDF() { return f_ndf; } - Double_t GetChi2NDF() { return f_chi2/f_ndf; } + Double_t GetChi2NDF() { return (f_ndf > 0.) ? (f_chi2 / f_ndf) : std::numeric_limits::quiet_NaN(); } UShort_t GetFitInfo() { return f_fitmode; } /** From 5e88868187ec794a3506128af3c33772aa40073e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 2 Mar 2026 21:25:36 -0500 Subject: [PATCH 330/866] add fwd decl --- offline/packages/trackbase/MagneticFieldOptions.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/MagneticFieldOptions.h b/offline/packages/trackbase/MagneticFieldOptions.h index a5254b9a6a..e827e456be 100644 --- a/offline/packages/trackbase/MagneticFieldOptions.h +++ b/offline/packages/trackbase/MagneticFieldOptions.h @@ -3,7 +3,18 @@ #include #include -#include + +namespace boost::program_options +{ + class options_description; + class variables_map; +} // namespace boost::program_options + +namespace ActsExamples::Options +{ + using Description = ::boost::program_options::options_description; + using Variables = ::boost::program_options::variables_map; +} // namespace ActsExamples::Options namespace ActsExamples { From 04ac52fe260bf87b258ede2ba04f983b3c322fbe Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 3 Mar 2026 15:39:41 -0500 Subject: [PATCH 331/866] suppress verbosity --- offline/packages/trackreco/DSTClusterPruning.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/DSTClusterPruning.cc b/offline/packages/trackreco/DSTClusterPruning.cc index 36bbe4fd0f..890e465b96 100644 --- a/offline/packages/trackreco/DSTClusterPruning.cc +++ b/offline/packages/trackreco/DSTClusterPruning.cc @@ -185,8 +185,11 @@ void DSTClusterPruning::prune_clusters() { if (!trackseed) { - std::cout << "No TrackSeed" << std::endl; - continue; + if(Verbosity() > 1) + { + std::cout << "No TrackSeed" << std::endl; + } + continue; } for (auto key_iter = trackseed->begin_cluster_keys(); key_iter != trackseed->end_cluster_keys(); ++key_iter) From 5f13771a3b560c7d606232c0cfe5a12f1a3b644b Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:13:55 -0500 Subject: [PATCH 332/866] EventPlaneReco: Implement trigonometry cache for Q-vector calculation * Pre-calculate cos(n*phi) and sin(n*phi) values during InitRun * Store cached values in a nested vector indexed by harmonic and channel * Replace per-tower std::cos and std::sin calls in process_sEPD with cache lookups * Significant reduction in CPU overhead per event --- .../packages/eventplaneinfo/EventPlaneReco.cc | 47 ++++++++++++++----- .../packages/eventplaneinfo/EventPlaneReco.h | 11 +++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index 58833f0df1..900501c164 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -85,6 +85,37 @@ int EventPlaneReco::Init(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } +int EventPlaneReco::InitRun(PHCompositeNode* topNode) +{ + EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << " Error: TOWERGEOM_EPD is missing. Cannot build trig cache." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_trig_cache.assign(m_harmonics.size(), std::vector>(SEPD_CHANNELS)); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + for (int channel = 0; channel < SEPD_CHANNELS; ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(channel); + double phi = epdgeom->get_phi(key); + + m_trig_cache[h_idx][channel] = {std::cos(n * phi), std::sin(n * phi)}; + } + } + + if (Verbosity() > 0) + { + std::cout << PHWHERE << " Trigonometry cache initialized for " << SEPD_CHANNELS << " sEPD channels." << std::endl; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + std::array, 2> EventPlaneReco::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) { std::array, 2> mat{}; @@ -308,13 +339,6 @@ int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTRUN; } - EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); - if (!epdgeom) - { - std::cout << PHWHERE << " TOWERGEOM_EPD is missing doing nothing" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - // sepd unsigned int nchannels_epd = towerinfosEPD->size(); @@ -327,7 +351,6 @@ int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) unsigned int key = TowerInfoDefs::encode_epd(channel); double charge = tower->get_energy(); - double phi = epdgeom->get_phi(key); // skip bad channels // skip channels with very low charge @@ -348,10 +371,10 @@ int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) { - int n = m_harmonics[h_idx]; - QVec q_n = {charge * std::cos(n * phi), charge * std::sin(n * phi)}; - m_Q_raw[h_idx][arm].x += q_n.x; - m_Q_raw[h_idx][arm].y += q_n.y; + const auto& [cached_cos, cached_sin] = m_trig_cache[h_idx][channel]; + + m_Q_raw[h_idx][arm].x += charge * cached_cos; + m_Q_raw[h_idx][arm].y += charge * cached_sin; } } diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.h b/offline/packages/eventplaneinfo/EventPlaneReco.h index 0f356e6033..d5fe492c3b 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.h +++ b/offline/packages/eventplaneinfo/EventPlaneReco.h @@ -7,6 +7,7 @@ #include #include #include +#include class CDBTTree; class PHCompositeNode; @@ -31,6 +32,11 @@ class EventPlaneReco : public SubsysReco */ int Init(PHCompositeNode *topNode) override; + /** Called during initialization. + * geometry is available + */ + int InitRun(PHCompositeNode *topNode) override; + /** Called for each event. This is where you do the real work. */ @@ -130,5 +136,10 @@ class EventPlaneReco : public SubsysReco std::array, m_harmonics.size()> m_Q_raw{}; std::array, m_harmonics.size()> m_Q_recentered{}; std::array, m_harmonics.size()> m_Q_flat{}; + + // [Harmonic Index][Channel Index] -> {cos, sin} + std::vector>> m_trig_cache; + + static constexpr int SEPD_CHANNELS = 744; }; #endif From 4a6fc72df6dedffae09c9fb2bf918b2b026aa2f5 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 28 Feb 2026 22:16:30 -0500 Subject: [PATCH 333/866] Cleanup includes - cleanup unused includes and redundant forward declarations --- offline/packages/eventplaneinfo/EventPlaneReco.cc | 8 +------- offline/packages/eventplaneinfo/EventPlaneReco.h | 1 - offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc | 1 - offline/packages/eventplaneinfo/Eventplaneinfov1.h | 2 -- 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index 900501c164..b0bf6ec639 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -26,17 +26,11 @@ #include #include -// -- root includes -- -#include -#include - // c++ includes -- -#include -#include -#include #include #include #include +#include //____________________________________________________________________________.. EventPlaneReco::EventPlaneReco(const std::string &name): diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.h b/offline/packages/eventplaneinfo/EventPlaneReco.h index d5fe492c3b..267b52b9c8 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.h +++ b/offline/packages/eventplaneinfo/EventPlaneReco.h @@ -6,7 +6,6 @@ #include #include -#include #include class CDBTTree; diff --git a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc index a0888d4d18..4aeffdd8c9 100644 --- a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc +++ b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc @@ -3,7 +3,6 @@ #include "Eventplaneinfo.h" #include "EventplaneinfoMap.h" -#include // for reverse_iterator #include // for pair, make_pair EventplaneinfoMapv1::~EventplaneinfoMapv1() diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov1.h b/offline/packages/eventplaneinfo/Eventplaneinfov1.h index 571997b63b..5a109898ce 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov1.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov1.h @@ -11,8 +11,6 @@ #include // for pair, make_pair #include -class PHObject; - class Eventplaneinfov1 : public Eventplaneinfo { public: From e294d8840abad9fd7a6b0d814af818bb260d271e Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:25:18 -0500 Subject: [PATCH 334/866] =?UTF-8?q?Skip=20Q=20Vec=20Calib=20for=20(?= =?UTF-8?q?=E2=89=A580%=20centrality)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Peripheral events (≥80% centrality) silently use bin 79 calibration data. - Setting m_doNotCalibEvent = true for out-of-range centrality and storing raw Q-vectors --- offline/packages/eventplaneinfo/EventPlaneReco.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index b0bf6ec639..4cf2624d18 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -407,9 +407,19 @@ int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) void EventPlaneReco::correct_QVecs() { size_t cent_bin = static_cast(m_cent); + + // Skip calibration for out-of-range centrality if (cent_bin >= m_cent_bins) { - cent_bin = m_cent_bins - 1; // Clamp max + if (Verbosity() > 2) + { + std::cout << PHWHERE << " Warning: Centrality " << m_cent + << "% exceeds calibration range (0-" << m_cent_bins - 1 + << "). Using raw Q-vectors." << std::endl; + } + + m_doNotCalibEvent = true; + return; } size_t south_idx = static_cast(Subdetector::S); From f84a5ad6b659f992cc3a6d81b544ae75ecffebec Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:31:49 -0500 Subject: [PATCH 335/866] Guard channel loop against trig-cache bounds - Ensure channel count does not exceed trig-cache size - Prevent potential out-of-bounds read --- offline/packages/eventplaneinfo/EventPlaneReco.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index 4cf2624d18..df68ff20f0 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -334,12 +334,21 @@ int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) } // sepd - unsigned int nchannels_epd = towerinfosEPD->size(); + const unsigned int nchannels_epd = towerinfosEPD->size(); + const unsigned int channel_limit = std::min(nchannels_epd, static_cast(SEPD_CHANNELS)); + + if (nchannels_epd != channel_limit && Verbosity() > 1) + { + std::cout << PHWHERE + << " Warning: sEPD channel count (" << nchannels_epd + << ") exceeds trig cache size (" << SEPD_CHANNELS + << "); truncating iteration." << std::endl; + } double sepd_total_charge_south = 0; double sepd_total_charge_north = 0; - for (unsigned int channel = 0; channel < nchannels_epd; ++channel) + for (unsigned int channel = 0; channel < channel_limit; ++channel) { TowerInfo* tower = towerinfosEPD->get_tower_at_channel(channel); From f0d5a456bd8b3b818f62b45765687ac871b95a36 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:35:58 -0500 Subject: [PATCH 336/866] Propagate CreateNodes failure from Init. --- offline/packages/eventplaneinfo/EventPlaneReco.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index df68ff20f0..82361e74c6 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -74,9 +74,7 @@ int EventPlaneReco::Init(PHCompositeNode *topNode) print_correction_data(); } - CreateNodes(topNode); - - return Fun4AllReturnCodes::EVENT_OK; + return CreateNodes(topNode); } int EventPlaneReco::InitRun(PHCompositeNode* topNode) From af96639cc72d8940048b1bcb3e67be2131330f5d Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sun, 1 Mar 2026 22:56:02 -0500 Subject: [PATCH 337/866] EventPlaneReco - Output Node Name Flexibility - Keep the default output node name unchanged ("EventplaneinfoMap") - Allow adjusting of the output node name if needed --- offline/packages/eventplaneinfo/EventPlaneReco.cc | 6 +++--- offline/packages/eventplaneinfo/EventPlaneReco.h | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index 82361e74c6..0179e08926 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -286,11 +286,11 @@ int EventPlaneReco::CreateNodes(PHCompositeNode *topNode) { dstNode->addNode(globalNode); } - EventplaneinfoMap *eps = findNode::getClass(topNode, "EventplaneinfoMap"); + EventplaneinfoMap *eps = findNode::getClass(topNode, m_EventPlaneInfoNodeName); if (!eps) { eps = new EventplaneinfoMapv1(); - PHIODataNode *newNode = new PHIODataNode(eps , "EventplaneinfoMap", "PHObject"); + PHIODataNode *newNode = new PHIODataNode(eps , m_EventPlaneInfoNodeName, "PHObject"); globalNode->addNode(newNode); } @@ -537,7 +537,7 @@ void EventPlaneReco::print_QVectors() int EventPlaneReco::FillNode(PHCompositeNode *topNode) { - EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); + EventplaneinfoMap *epmap = findNode::getClass(topNode, m_EventPlaneInfoNodeName); if (!epmap) { std::cout << PHWHERE << " EventplaneinfoMap is missing doing nothing" << std::endl; diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.h b/offline/packages/eventplaneinfo/EventPlaneReco.h index 267b52b9c8..231d30a8bb 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.h +++ b/offline/packages/eventplaneinfo/EventPlaneReco.h @@ -65,9 +65,14 @@ class EventPlaneReco : public SubsysReco m_sepd_min_channel_charge = sepd_min_channel_charge; } + void set_EventPlaneInfoNodeName(const std::string &name) + { + m_EventPlaneInfoNodeName = name; + } + private: - static int CreateNodes(PHCompositeNode *topNode); + int CreateNodes(PHCompositeNode *topNode); std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); void LoadCalib(); @@ -92,6 +97,7 @@ class EventPlaneReco : public SubsysReco std::string m_calibName{"SEPD_EventPlaneCalib"}; std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; + std::string m_EventPlaneInfoNodeName{"EventplaneinfoMap"}; CDBTTree *m_cdbttree {nullptr}; From 88201372242a36404a8d4d3330870f65fee09afe Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:01:00 -0500 Subject: [PATCH 338/866] clang-tidy fixes - Address the following existing clang-tidy warnings: - [hicpp-special-member-functions] - [hicpp-use-equals-default] - [modernize-use-equals-default] - [performance-unnecessary-value-param] - [modernize-use-using] - [readability-avoid-const-params-in-decls] --- offline/packages/eventplaneinfo/Eventplaneinfo.h | 15 +++++++++++---- .../packages/eventplaneinfo/EventplaneinfoMap.h | 14 ++++++++++---- .../packages/eventplaneinfo/EventplaneinfoMapv1.h | 6 ++++++ .../packages/eventplaneinfo/Eventplaneinfov1.h | 13 +++++++++---- .../packages/eventplaneinfo/Eventplaneinfov2.h | 6 +++--- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/offline/packages/eventplaneinfo/Eventplaneinfo.h b/offline/packages/eventplaneinfo/Eventplaneinfo.h index af903b6d06..c01756deca 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfo.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfo.h @@ -13,7 +13,7 @@ class Eventplaneinfo : public PHObject { public: - ~Eventplaneinfo() override {} + ~Eventplaneinfo() override = default; void identify(std::ostream& os = std::cout) const override { @@ -22,23 +22,30 @@ class Eventplaneinfo : public PHObject PHObject* CloneMe() const override { return nullptr; } - virtual void set_qvector(std::vector> /*Qvec*/) { return; } + virtual void set_qvector(const std::vector>& /*Qvec*/) { return; } virtual void set_qvector_raw(const std::vector>& /*Qvec*/) { return; } virtual void set_qvector_recentered(const std::vector>& /*Qvec*/) { return; } - virtual void set_shifted_psi(std::vector /*Psi_Shifted*/) { return; } + virtual void set_shifted_psi(const std::vector& /*Psi_Shifted*/) { return; } virtual std::pair get_qvector(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } virtual std::pair get_qvector_raw(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } virtual std::pair get_qvector_recentered(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } virtual double get_psi(int /*order*/) const { return std::numeric_limits::quiet_NaN(); } virtual double get_shifted_psi(int /*order*/) const { return std::numeric_limits::quiet_NaN(); } virtual double GetPsi(const double /*Qx*/, const double /*Qy*/, const unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } - virtual void set_ring_qvector(std::vector>> /*RingQvecs*/) { return; } + virtual void set_ring_qvector(const std::vector>>& /*RingQvecs*/) { return; } virtual std::pair get_ring_qvector(int /*rbin*/, int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } virtual double get_ring_psi(int /*rbin*/, int /*order*/) const { return std::numeric_limits::quiet_NaN(); } protected: Eventplaneinfo() = default; + // Rule of Five: Protected allows derived classes to copy/move, + // but prevents "slicing" at the base class level. + Eventplaneinfo(const Eventplaneinfo&) = default; + Eventplaneinfo& operator=(const Eventplaneinfo&) = default; + Eventplaneinfo(Eventplaneinfo&&) = default; + Eventplaneinfo& operator=(Eventplaneinfo&&) = default; + private: ClassDefOverride(Eventplaneinfo, 1); }; diff --git a/offline/packages/eventplaneinfo/EventplaneinfoMap.h b/offline/packages/eventplaneinfo/EventplaneinfoMap.h index 247a62a1f6..ee16720cff 100644 --- a/offline/packages/eventplaneinfo/EventplaneinfoMap.h +++ b/offline/packages/eventplaneinfo/EventplaneinfoMap.h @@ -25,10 +25,10 @@ class EventplaneinfoMap : public PHObject sEPDRING_NORTH = 200 }; - typedef std::map::const_iterator ConstIter; - typedef std::map::iterator Iter; + using ConstIter = std::map::const_iterator; + using Iter = std::map::iterator; - ~EventplaneinfoMap() override {} + ~EventplaneinfoMap() override = default; void identify(std::ostream& os = std::cout) const override { os << "EventplaneinfoMap base class" << std::endl; } virtual bool empty() const {return true;} @@ -47,7 +47,13 @@ class EventplaneinfoMap : public PHObject virtual Iter end(); protected: - EventplaneinfoMap() {} + EventplaneinfoMap() = default; + + // Rule of Five: Protected to support derived classes + EventplaneinfoMap(const EventplaneinfoMap&) = default; + EventplaneinfoMap& operator=(const EventplaneinfoMap&) = default; + EventplaneinfoMap(EventplaneinfoMap&&) = default; + EventplaneinfoMap& operator=(EventplaneinfoMap&&) = default; private: ClassDefOverride(EventplaneinfoMap, 1); diff --git a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h index 5aac01a4ce..b4f10f3bed 100644 --- a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h +++ b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h @@ -16,6 +16,12 @@ class EventplaneinfoMapv1 : public EventplaneinfoMap EventplaneinfoMapv1() = default; ~EventplaneinfoMapv1() override; + // Rule of Five: Explicitly delete to prevent shallow copy/double free + EventplaneinfoMapv1(const EventplaneinfoMapv1&) = delete; + EventplaneinfoMapv1& operator=(const EventplaneinfoMapv1&) = delete; + EventplaneinfoMapv1(EventplaneinfoMapv1&&) = delete; + EventplaneinfoMapv1& operator=(EventplaneinfoMapv1&&) = delete; + void identify(std::ostream& os = std::cout) const override; void Reset() override { clear(); } // cppcheck-suppress [virtualCallInConstructor] diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov1.h b/offline/packages/eventplaneinfo/Eventplaneinfov1.h index 5a109898ce..1950e2ef31 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov1.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov1.h @@ -17,17 +17,22 @@ class Eventplaneinfov1 : public Eventplaneinfo Eventplaneinfov1() = default; ~Eventplaneinfov1() override = default; + Eventplaneinfov1(const Eventplaneinfov1&) = default; + Eventplaneinfov1& operator=(const Eventplaneinfov1&) = default; + Eventplaneinfov1(Eventplaneinfov1&&) = default; + Eventplaneinfov1& operator=(Eventplaneinfov1&&) = default; + void identify(std::ostream& os = std::cout) const override; void Reset() override { *this = Eventplaneinfov1(); } PHObject* CloneMe() const override { return new Eventplaneinfov1(*this); } - void set_qvector(std::vector> Qvec) override { mQvec = Qvec; } - void set_shifted_psi(std::vector Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } + void set_qvector(const std::vector>& Qvec) override { mQvec = Qvec; } + void set_shifted_psi(const std::vector& Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } std::pair get_qvector(int order) const override { return std::make_pair(mQvec[order - 1].first, mQvec[order - 1].second); } - void set_ring_qvector(std::vector>> Qvec) override { ring_Qvec = Qvec; } + void set_ring_qvector(const std::vector>>& Qvec) override { ring_Qvec = Qvec; } std::pair get_ring_qvector(int ring_index, int order) const override { return ring_Qvec[ring_index][order - 1]; } double get_ring_psi(int ring_index, int order) const override {return GetPsi(ring_Qvec[ring_index][order - 1].first,ring_Qvec[ring_index][order - 1].second,order);} - double GetPsi(const double Qx, const double Qy, const unsigned int order) const override; + double GetPsi(double Qx, double Qy, unsigned int order) const override; double get_psi(int order) const override { return GetPsi(mQvec[order - 1].first, mQvec[order - 1].second, order);} double get_shifted_psi(int order) const override { return mPsi_Shifted[order - 1]; } diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.h b/offline/packages/eventplaneinfo/Eventplaneinfov2.h index bd6cb553c8..b6f5bf7793 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov2.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.h @@ -28,14 +28,14 @@ class Eventplaneinfov2 : public Eventplaneinfo void Reset() override { *this = Eventplaneinfov2(); } PHObject* CloneMe() const override { return new Eventplaneinfov2(*this); } - void set_qvector(std::vector> Qvec) override { mQvec = Qvec; } + void set_qvector(const std::vector>& Qvec) override { mQvec = Qvec; } void set_qvector_raw(const std::vector>& Qvec) override { mQvec_raw = Qvec; } void set_qvector_recentered(const std::vector>& Qvec) override { mQvec_recentered = Qvec; } - void set_shifted_psi(std::vector Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } + void set_shifted_psi(const std::vector& Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } std::pair get_qvector(int order) const override { return safe_qvec(mQvec, order); } std::pair get_qvector_raw(int order) const override { return safe_qvec(mQvec_raw, order); } std::pair get_qvector_recentered(int order) const override { return safe_qvec(mQvec_recentered, order); } - void set_ring_qvector(std::vector>> Qvec) override { ring_Qvec = Qvec; } + void set_ring_qvector(const std::vector>>& Qvec) override { ring_Qvec = Qvec; } std::pair get_ring_qvector(int ring_index, int order) const override { if (ring_index < 0 || static_cast(ring_index) >= ring_Qvec.size()) From 3dedddb8d5e8b3920a7cef057ecfcd46ef8d0d13 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 3 Mar 2026 16:24:55 -0500 Subject: [PATCH 339/866] Get kd seeder to compile locally --- offline/packages/trackbase/SpacePoint.h | 5 +- .../packages/trackreco/PHActsKDTreeSeeding.cc | 42 ++--- .../packages/trackreco/PHActsKDTreeSeeding.h | 163 +++++++++--------- 3 files changed, 104 insertions(+), 106 deletions(-) diff --git a/offline/packages/trackbase/SpacePoint.h b/offline/packages/trackbase/SpacePoint.h index 7a422de8c8..afede18a3b 100644 --- a/offline/packages/trackbase/SpacePoint.h +++ b/offline/packages/trackbase/SpacePoint.h @@ -5,6 +5,7 @@ #include #include "trackbase/TrkrDefs.h" +#include #include #include @@ -40,9 +41,11 @@ inline bool operator==(SpacePoint a, SpacePoint b) { return (a.m_clusKey == b.m_clusKey); } +using SpacePointContainerType = ActsExamples::SpacePointContainer>; +using proxy_type = typename Acts::SpacePointContainer::SpacePointProxyType; using SpacePointPtr = std::unique_ptr; using SpacePointContainer = std::vector; -using SeedContainer = std::vector>; +using SeedContainer = std::vector>; #endif diff --git a/offline/packages/trackreco/PHActsKDTreeSeeding.cc b/offline/packages/trackreco/PHActsKDTreeSeeding.cc index 264806af96..ad5b25307e 100644 --- a/offline/packages/trackreco/PHActsKDTreeSeeding.cc +++ b/offline/packages/trackreco/PHActsKDTreeSeeding.cc @@ -15,8 +15,8 @@ #include #include #include -#include #include +#include #include #include @@ -59,7 +59,7 @@ PHActsKDTreeSeeding::PHActsKDTreeSeeding(const std::string& name) { } -//____________________________________________________________________________.. +//______________________ ______________________________________________________.. PHActsKDTreeSeeding::~PHActsKDTreeSeeding() { } @@ -115,23 +115,18 @@ int PHActsKDTreeSeeding::process_event(PHCompositeNode* topNode) SeedContainer PHActsKDTreeSeeding::runSeeder() { - Acts::SeedFinderOrthogonal finder(m_seedFinderConfig); + auto finder = std::make_unique>(m_seedFinderConfig); auto spacePoints = getMvtxSpacePoints(); + Acts::SpacePointContainerConfig spConfig; + Acts::SpacePointContainerOptions spOptions; + spOptions.beamPos = {0, 0}; - std::function< - std::tuple>( - const SpacePoint* sp)> - create_coordinates = [](const SpacePoint* sp) - { - Acts::Vector3 position(sp->x(), sp->y(), sp->z()); - Acts::Vector2 variance(sp->varianceR(), sp->varianceZ()); - return std::make_tuple(position, variance, sp->t()); - }; - + ActsExamples::SpacePointContainer container(spacePoints); + Acts::SpacePointContainer spContainer(spConfig, spOptions, container); /// Call acts seeding algo - SeedContainer seeds = finder.createSeeds(m_seedFinderOptions, - spacePoints, create_coordinates); + auto seeds = finder->createSeeds(m_seedFinderOptions, spContainer); + if (Verbosity() > 1) { std::cout << "Acts::OrthogonalSeeder found " << seeds.size() @@ -147,19 +142,19 @@ void PHActsKDTreeSeeding::fillTrackSeedContainer(SeedContainer& seeds) { auto siseed = std::make_unique(); std::map positions; - - for (auto& spptr : seed.sp()) + const auto& sps = seed.sp(); + for (int spid = 0; spid < 3; spid++) { - auto ckey = spptr->Id(); + auto ckey = sps[spid]->externalSpacePoint()->Id(); siseed->insert_cluster_key(ckey); auto globalPosition = m_tGeometry->getGlobalPosition( ckey, m_clusterMap->findCluster(ckey)); positions.insert(std::make_pair(ckey, globalPosition)); } - - TrackSeedHelper::circleFitByTaubin(siseed.get(),positions, 0, 8); - TrackSeedHelper::lineFit(siseed.get(),positions, 0, 8); + + TrackSeedHelper::circleFitByTaubin(siseed.get(), positions, 0, 8); + TrackSeedHelper::lineFit(siseed.get(), positions, 0, 8); /// Project to INTT and find matches to add to positions findInttMatches(positions, *siseed); @@ -438,7 +433,7 @@ SpacePointPtr PHActsKDTreeSeeding::makeSpacePoint(const Surface& surf, * uncertainties by a tuned factor that gives the v17 performance * Track reconstruction is an art as much as it is a science... */ - SpacePointPtr spPtr(new SpacePoint{key, x, y, z, r, surf->geometryId(), var[0] * m_uncfactor, var[1] * m_uncfactor,std::nullopt}); + SpacePointPtr spPtr(new SpacePoint{key, x, y, z, r, surf->geometryId(), var[0] * m_uncfactor, var[1] * m_uncfactor, std::nullopt}); if (Verbosity() > 2) { @@ -536,8 +531,7 @@ void PHActsKDTreeSeeding::configureSeedFinder() filterCfg.maxSeedsPerSpM = m_maxSeedsPerSpM; m_seedFinderConfig.seedFilter = - std::make_unique>( - Acts::SeedFilter(filterCfg)); + std::make_unique>(filterCfg); m_seedFinderConfig.rMax = m_rMax; m_seedFinderConfig.deltaRMinTopSP = m_deltaRMinTopSP; diff --git a/offline/packages/trackreco/PHActsKDTreeSeeding.h b/offline/packages/trackreco/PHActsKDTreeSeeding.h index f4db9e5f1d..b05abeb39d 100644 --- a/offline/packages/trackreco/PHActsKDTreeSeeding.h +++ b/offline/packages/trackreco/PHActsKDTreeSeeding.h @@ -28,87 +28,88 @@ class TrackSeed; class PHActsKDTreeSeeding : public SubsysReco { public: - PHActsKDTreeSeeding(const std::string& name = "PHActsKDTreeSeeding"); - - ~PHActsKDTreeSeeding() override; - - int Init(PHCompositeNode* topNode) override; - int InitRun(PHCompositeNode* topNode) override; - int process_event(PHCompositeNode* topNode) override; - int End(PHCompositeNode* topNode) override; - - void useTruthClusters(bool truth) { m_useTruthClusters = truth; } - - private: - void configureSeedFinder(); - int getNodes(PHCompositeNode* topNode); - int createNodes(PHCompositeNode* topNode); - SeedContainer runSeeder(); - void fillTrackSeedContainer(SeedContainer& seeds); - std::vector getMvtxSpacePoints(); - SpacePointPtr makeSpacePoint(const Surface& surf, - const TrkrDefs::cluskey key, - TrkrCluster* clus); - - /// Projects circle fit to INTT radii to find possible INTT clusters - /// belonging to MVTX track stub - void findInttMatches(std::map& clusters, - TrackSeed& seed); - - void matchInttClusters(std::map& clusters, - const double xProj[], - const double yProj[], - const double zProj[]); - - Acts::SeedFilterConfig m_seedFilterConfig; - Acts::SeedFinderOrthogonalConfig m_seedFinderConfig; - Acts::SeedFinderOptions m_seedFinderOptions; - - /// configured to seed in the MVTX using the middle layer - /// as the seed anchor - /// Defines volume to search for seeds in - float m_rMax = 200. * Acts::UnitConstants::mm; - float m_deltaRMinTopSP = 1. * Acts::UnitConstants::mm; - float m_deltaRMaxTopSP = 20. * Acts::UnitConstants::mm; - float m_deltaRMinBottomSP = 1. * Acts::UnitConstants::mm; - float m_deltaRMaxBottomSP = 20. * Acts::UnitConstants::mm; - float m_collisionRegionMin = -300 * Acts::UnitConstants::mm; - float m_collisionRegionMax = 300 * Acts::UnitConstants::mm; - float m_zMin = -300. * Acts::UnitConstants::mm; - float m_zMax = 300. * Acts::UnitConstants::mm; - - /// max number of seeds a single middle sp can belong to - float m_maxSeedsPerSpM = 1; - float m_cotThetaMax = 2.9; - float m_sigmaScattering = 5; - float m_radLengthPerSeed = 0.05; - float m_minPt = 100.; // MeV - float m_bFieldInZ = 0.0014; // kTesla - float m_beamPosX = 0; - float m_beamPosY = 0; - - /// Maximum transverse PCA allowed - float m_impactMax = 20. * Acts::UnitConstants::mm; - - /// Middle spacepoint must fall between these two radii - float m_rMinMiddle = 28. * Acts::UnitConstants::mm; - float m_rMaxMiddle = 36. * Acts::UnitConstants::mm; - - int m_nIteration = 0; - std::string m_trackMapName = "SiliconTrackSeedContainer"; - bool m_useTruthClusters = false; - - ClusterErrorPara m_clusErrPara; - float m_uncfactor = 3.175; - const static int m_nInttLayers = 4; - float m_nInttLayerRadii[m_nInttLayers] = {0}; - float m_rPhiSearchWin = 0.1; - - PHG4CylinderGeomContainer* m_geomContainerIntt = nullptr; - TrkrClusterIterationMapv1* m_iterationMap = nullptr; - ActsGeometry* m_tGeometry = nullptr; - TrkrClusterContainer* m_clusterMap = nullptr; - TrackSeedContainer* m_seedContainer = nullptr; +using proxy_type = typename Acts::SpacePointContainer>, Acts::detail::RefHolder>::SpacePointProxyType; + PHActsKDTreeSeeding(const std::string& name = "PHActsKDTreeSeeding"); + + ~PHActsKDTreeSeeding() override; + + int Init(PHCompositeNode* topNode) override; + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + int End(PHCompositeNode* topNode) override; + + void useTruthClusters(bool truth) { m_useTruthClusters = truth; } + +private: + void configureSeedFinder(); + int getNodes(PHCompositeNode* topNode); + int createNodes(PHCompositeNode* topNode); + SeedContainer runSeeder(); + void fillTrackSeedContainer(SeedContainer& seeds); + std::vector getMvtxSpacePoints(); + SpacePointPtr makeSpacePoint(const Surface& surf, + const TrkrDefs::cluskey key, + TrkrCluster* clus); + + /// Projects circle fit to INTT radii to find possible INTT clusters + /// belonging to MVTX track stub + void findInttMatches(std::map& clusters, + TrackSeed& seed); + + void matchInttClusters(std::map& clusters, + const double xProj[], + const double yProj[], + const double zProj[]); + + Acts::SeedFilterConfig m_seedFilterConfig; + Acts::SeedFinderOrthogonalConfig m_seedFinderConfig; + Acts::SeedFinderOptions m_seedFinderOptions; + + /// configured to seed in the MVTX using the middle layer + /// as the seed anchor + /// Defines volume to search for seeds in + float m_rMax = 200. * Acts::UnitConstants::mm; + float m_deltaRMinTopSP = 1. * Acts::UnitConstants::mm; + float m_deltaRMaxTopSP = 20. * Acts::UnitConstants::mm; + float m_deltaRMinBottomSP = 1. * Acts::UnitConstants::mm; + float m_deltaRMaxBottomSP = 20. * Acts::UnitConstants::mm; + float m_collisionRegionMin = -300 * Acts::UnitConstants::mm; + float m_collisionRegionMax = 300 * Acts::UnitConstants::mm; + float m_zMin = -300. * Acts::UnitConstants::mm; + float m_zMax = 300. * Acts::UnitConstants::mm; + + /// max number of seeds a single middle sp can belong to + float m_maxSeedsPerSpM = 1; + float m_cotThetaMax = 2.9; + float m_sigmaScattering = 5; + float m_radLengthPerSeed = 0.05; + float m_minPt = 100.; // MeV + float m_bFieldInZ = 0.0014; // kTesla + float m_beamPosX = 0; + float m_beamPosY = 0; + + /// Maximum transverse PCA allowed + float m_impactMax = 20. * Acts::UnitConstants::mm; + + /// Middle spacepoint must fall between these two radii + float m_rMinMiddle = 28. * Acts::UnitConstants::mm; + float m_rMaxMiddle = 36. * Acts::UnitConstants::mm; + + int m_nIteration = 0; + std::string m_trackMapName = "SiliconTrackSeedContainer"; + bool m_useTruthClusters = false; + + ClusterErrorPara m_clusErrPara; + float m_uncfactor = 3.175; + const static int m_nInttLayers = 4; + float m_nInttLayerRadii[m_nInttLayers] = {0}; + float m_rPhiSearchWin = 0.1; + + PHG4CylinderGeomContainer* m_geomContainerIntt = nullptr; + TrkrClusterIterationMapv1* m_iterationMap = nullptr; + ActsGeometry* m_tGeometry = nullptr; + TrkrClusterContainer* m_clusterMap = nullptr; + TrackSeedContainer* m_seedContainer = nullptr; }; #endif // PHACTSKDTREESEEDING_H From 5108c85ecf99a4a93d57a617bc8cd74b02a44d0f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 3 Mar 2026 16:54:32 -0500 Subject: [PATCH 340/866] allow integer node names upon creation --- offline/framework/phool/PHIODataNode.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/offline/framework/phool/PHIODataNode.h b/offline/framework/phool/PHIODataNode.h index 46be461793..3ee60a8e4c 100644 --- a/offline/framework/phool/PHIODataNode.h +++ b/offline/framework/phool/PHIODataNode.h @@ -23,6 +23,7 @@ class PHIODataNode : public PHDataNode T *operator*() { return this->getData(); } PHIODataNode(T *, const std::string &); PHIODataNode(T *, const std::string &, const std::string &); + PHIODataNode(T *, const int, const std::string &); virtual ~PHIODataNode() = default; typedef PHTypedNodeIterator iterator; void BufferSize(int size) { buffersize = size; } @@ -54,6 +55,16 @@ PHIODataNode::PHIODataNode(T *d, const std::string &n, this->objectclass = TO->GetName(); } +template +PHIODataNode::PHIODataNode(T *d, const int id, + const std::string &objtype) + : PHDataNode(d, std::to_string(id), objtype) +{ + this->type = "PHIODataNode"; + TObject *TO = static_cast(d); + this->objectclass = TO->GetName(); +} + template bool PHIODataNode::write(PHIOManager *IOManager, const std::string &path) { From 9c385955d57be4f64962e3e5a86a17e5807ed6f8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 3 Mar 2026 16:55:46 -0500 Subject: [PATCH 341/866] keep single packets (for zdc raw data --- .../fun4allraw/SingleTriggeredInput.cc | 274 ++++++++++-------- .../fun4allraw/SingleTriggeredInput.h | 18 +- 2 files changed, 166 insertions(+), 126 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index 80e9f49a64..999ca40531 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -26,7 +26,7 @@ #include // for pair #include -SingleTriggeredInput::SingleTriggeredInput(const std::string &name) +SingleTriggeredInput::SingleTriggeredInput(const std::string& name) : Fun4AllBase(name) { m_bclkarray.fill(std::numeric_limits::max()); @@ -35,7 +35,7 @@ SingleTriggeredInput::SingleTriggeredInput(const std::string &name) SingleTriggeredInput::~SingleTriggeredInput() { - std::set evtset; + std::set evtset; for (auto& [pid, dq] : m_PacketEventDeque) { while (!dq.empty()) @@ -44,7 +44,7 @@ SingleTriggeredInput::~SingleTriggeredInput() dq.pop_front(); } } - for (auto *evt : evtset) + for (auto* evt : evtset) { delete evt; } @@ -64,7 +64,7 @@ bool SingleTriggeredInput::CheckFemDiffIdx(int pid, size_t index, const std::deq return false; } - Packet* pkt_prev = events[index-1]->getPacket(pid); + Packet* pkt_prev = events[index - 1]->getPacket(pid); Packet* pkt_curr = events[index]->getPacket(pid); if (!pkt_prev || !pkt_curr) { @@ -73,7 +73,8 @@ bool SingleTriggeredInput::CheckFemDiffIdx(int pid, size_t index, const std::deq return false; } - auto get_majority_femclk = [](Packet* pkt) -> uint16_t { + auto get_majority_femclk = [](Packet* pkt) -> uint16_t + { int nmod = pkt->iValue(0, "NRMODULES"); std::map counts; for (int j = 0; j < nmod; ++j) @@ -85,7 +86,9 @@ bool SingleTriggeredInput::CheckFemDiffIdx(int pid, size_t index, const std::deq { return std::numeric_limits::max(); } - return std::max_element(counts.begin(), counts.end(), [](const auto& a, const auto& b) { return a.second < b.second; })->first; + return std::max_element(counts.begin(), counts.end(), [](const auto& a, const auto& b) + { return a.second < b.second; }) + ->first; }; uint16_t clk_prev = get_majority_femclk(pkt_prev); @@ -108,38 +111,38 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array bad_diff_indices; for (size_t i = 0; i < n; ++i) { - if ( sebdiff[i] != gl1diff[i] ) + if (sebdiff[i] != gl1diff[i]) { - if ( !m_packetclk_copy_runs ) + if (!m_packetclk_copy_runs) { - //backup procedure to recover stuck 16bit XMIT clock - size_t idxcheck = i == 0 ? i+1 : i; + // backup procedure to recover stuck 16bit XMIT clock + size_t idxcheck = i == 0 ? i + 1 : i; bool passFemDiffCheckIdx = CheckFemDiffIdx(pid, idxcheck, m_PacketEventDeque[pid], gl1diff[idxcheck]); - if ( passFemDiffCheckIdx ) + if (passFemDiffCheckIdx) { m_OverrideWithRepClock.insert(pid); continue; } - } + } bad_diff_indices.push_back(i); } } if (bad_diff_indices.empty()) { - if ( Verbosity() > 0 ) + if (Verbosity() > 0) { std::cout << Name() << " recovered from bad XMIT clocks. Merging pool" << std::endl; } @@ -147,14 +150,14 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array=5) + if (bad_diff_indices.size() >= 5) { std::cout << std::endl; std::cout << "----------------- " << Name() << " -----------------" << std::endl; std::cout << "More than 5 diffs are bad.. try shifting algorithm" << std::endl; move_to_shift_algo = true; } - if(!move_to_shift_algo) + if (!move_to_shift_algo) { std::cout << std::endl; std::cout << "----------------- " << Name() << " -----------------" << std::endl; @@ -164,23 +167,23 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array=5) + if (length >= 5) { std::cout << Name() << ": length of bad diffs >=5 with bad_diff_indices.size() " << bad_diff_indices.size() << ". This should not have happened.. rejecting pool" << std::endl; return false; } - if(start==static_cast(pooldepth - 1)) + if (start == static_cast(pooldepth - 1)) { bad_indices.push_back(start); - CurrentPoolLastDiffBad= true; + CurrentPoolLastDiffBad = true; } - else if (start==0) + else if (start == 0) { if (PrevPoolLastDiffBad) { @@ -202,14 +205,14 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array(pooldepth - 1) && start >0) + else if (start < static_cast(pooldepth - 1) && start > 0) { - if(length==1) + if (length == 1) { std::cout << Name() << ": Isolated bad diff[" << start << "] - rejecting pool" << std::endl; return false; } - if(length>=2) + if (length >= 2) { for (int j = start; j < end; ++j) { @@ -219,7 +222,7 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array::max()); - static bool firstclockarray=true; - if(firstclockarray){ + 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; + firstclockarray = false; } - if ( representative_pid == -1 ) + if (representative_pid == -1) { representative_pid = pid; } } - if ( !allPacketEventDequeEmpty ) + if (!allPacketEventDequeEmpty) { return 0; } @@ -381,11 +385,11 @@ int SingleTriggeredInput::FillEventVector() if (gl1) { int nskip = gl1->GetGl1SkipArray()[i]; - if(nskip >0) + if (nskip > 0) { skiptrace = true; } - + while (nskip > 0) { Event* skip_evt = GetEventIterator()->getNextEvent(); @@ -399,7 +403,7 @@ int SingleTriggeredInput::FillEventVector() } skip_evt = GetEventIterator()->getNextEvent(); } - + if (skip_evt->getEvtType() != DATAEVENT) { delete skip_evt; @@ -434,7 +438,7 @@ int SingleTriggeredInput::FillEventVector() nskip--; } - if(skiptrace) + if (skiptrace) { evt = GetEventIterator()->getNextEvent(); while (!evt) @@ -468,12 +472,12 @@ int SingleTriggeredInput::FillEventVector() int gl1pid = Gl1Input()->m_bclkdiffarray_map.begin()->first; uint64_t gl1_diff = gl1->m_bclkdiffarray_map[gl1pid][i]; - bool clockconsistency=true; + bool clockconsistency = true; if (seb_diff != gl1_diff) { - clockconsistency=false; + clockconsistency = false; int clockconstcount = 0; - while(!clockconsistency && clockconstcount<5) + 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; @@ -500,9 +504,9 @@ int SingleTriggeredInput::FillEventVector() 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) + if (seb_diff_next == gl1_diff_next) { - clockconsistency=true; + clockconsistency = true; std::cout << Name() << " : recovered by additional skip in skiptrace" << std::endl; } clockconstcount++; @@ -536,22 +540,22 @@ int SingleTriggeredInput::FillEventVector() continue; } evt->convert(); - + if (firstcall) { std::cout << "Creating DSTs first call" << std::endl; CreateDSTNodes(evt); int run = evt->getRunNumber(); - m_packetclk_copy_runs = (run >= 44000 && run < 56079); + m_packetclk_copy_runs = (run >= 44000 && run < 56079); firstcall = false; } for (int pid : m_PacketSet) { - Event *thisevt = evt; + Event* thisevt = evt; if (m_PacketShiftOffset[pid] == 1) { - if (i==0) + if (i == 0) { thisevt = m_PacketEventBackup[pid]; m_ShiftedEvents[pid] = evt; @@ -560,13 +564,13 @@ int SingleTriggeredInput::FillEventVector() { thisevt = m_ShiftedEvents[pid]; m_ShiftedEvents[pid] = evt; - if (i == pooldepth -1) + if (i == pooldepth - 1) { m_PacketEventBackup[pid] = evt; } } } - + Packet* pkt = thisevt->getPacket(pid); if (!pkt) { @@ -594,7 +598,7 @@ int SingleTriggeredInput::FillEventVector() return minSize; } -uint64_t SingleTriggeredInput::GetClock(Event *evt, int pid) +uint64_t SingleTriggeredInput::GetClock(Event* evt, int pid) { Packet* packet = evt->getPacket(pid); if (!packet) @@ -625,20 +629,19 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event auto& clkarray = m_bclkarray_map[pid]; auto& diffarray = m_bclkdiffarray_map[pid]; - // Special handling for FEM-copied clocks if (m_packetclk_copy_runs && m_CorrectCopiedClockPackets.contains(pid)) { if (event_index == 0) { - clkarray[event_index+1] = m_PreviousValidBCOMap[pid]; + clkarray[event_index + 1] = m_PreviousValidBCOMap[pid]; } - else if (event_index >=1) + else if (event_index >= 1) { Event* shifted_evt = m_PacketEventDeque[pid][event_index - 1]; - clkarray[event_index+1] = GetClock(shifted_evt, pid); + clkarray[event_index + 1] = GetClock(shifted_evt, pid); } - + uint64_t prev = clkarray[event_index]; uint64_t curr = clkarray[event_index + 1]; @@ -654,7 +657,6 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event return; } - uint64_t clk = GetClock(evt, pid); if (clk == std::numeric_limits::max()) { @@ -665,7 +667,7 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event clkarray[event_index + 1] = clk; uint64_t prev = clkarray[event_index]; - if(prev == std::numeric_limits::max()) + if (prev == std::numeric_limits::max()) { static std::unordered_set warned; @@ -689,7 +691,7 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event { int packet_number = pkt->iValue(0); gl1->SetPacketNumbers(gl1->GetCurrentPacketNumber(), packet_number); - if ( event_index < pooldepth ) + if (event_index < pooldepth) { gl1->SetGl1PacketNumber(event_index, packet_number); } @@ -697,7 +699,7 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event int skip_count = 0; if (gl1->GetLastPacketNumber() != 0) { - int diff = gl1->GetCurrentPacketNumber() - gl1->GetLastPacketNumber() ; + int diff = gl1->GetCurrentPacketNumber() - gl1->GetLastPacketNumber(); skip_count = diff - 1; } @@ -715,7 +717,8 @@ void SingleTriggeredInput::FillPool() return; } - bool all_packets_bad = !m_PacketAlignmentProblem.empty() && std::all_of(m_PacketAlignmentProblem.begin(), m_PacketAlignmentProblem.end(), [](const std::pair &entry) -> bool { return entry.second;}); + bool all_packets_bad = !m_PacketAlignmentProblem.empty() && std::all_of(m_PacketAlignmentProblem.begin(), m_PacketAlignmentProblem.end(), [](const std::pair& entry) -> bool + { return entry.second; }); if (all_packets_bad) { std::cout << Name() << ": ALL packets are marked as bad. Stop combining for this SEB." << std::endl; @@ -738,9 +741,8 @@ void SingleTriggeredInput::FillPool() int gl1pid = Gl1Input()->m_bclkdiffarray_map.begin()->first; const auto& gl1diff = Gl1Input()->m_bclkdiffarray_map.at(gl1pid); - bool allgl1max = std::all_of(gl1diff.begin(), gl1diff.end(), [](uint64_t val) { - return val == std::numeric_limits::max(); - }); + bool allgl1max = std::all_of(gl1diff.begin(), gl1diff.end(), [](uint64_t val) + { return val == std::numeric_limits::max(); }); if (allgl1max) { std::cout << Name() << " : GL1 clock diffs all filled with max 64 bit values for PID " << gl1pid << " return and try next pool" << std::endl; @@ -751,13 +753,13 @@ void SingleTriggeredInput::FillPool() for (const auto& [pid, sebdiff] : m_bclkdiffarray_map) { size_t packetpoolsize = m_PacketEventDeque[pid].size(); - if(packetpoolsize==0) + if (packetpoolsize == 0) { std::cout << Name() << ": packet pool size is zero.... something is wrong" << std::endl; return; } - if(m_PacketAlignmentProblem[pid]) + if (m_PacketAlignmentProblem[pid]) { continue; } @@ -768,22 +770,23 @@ void SingleTriggeredInput::FillPool() bool PrevPoolLastDiffBad = m_PrevPoolLastDiffBad[pid]; bool aligned = false; - if( packetpoolsize < pooldepth && FilesDone() ) + if (packetpoolsize < pooldepth && FilesDone()) { aligned = true; } - else + else { aligned = CheckPoolAlignment(pid, sebdiff, gl1diff, bad_indices, shift, CurrentPoolLastDiffBad, PrevPoolLastDiffBad); } - + if (aligned) { m_PrevPoolLastDiffBad[pid] = CurrentPoolLastDiffBad; if (!bad_indices.empty()) { std::cout << Name() << ": Packet " << pid << " has bad indices: "; - for (int bi : bad_indices){ + for (int bi : bad_indices) + { std::cout << bi << " "; m_DitchPackets[pid].insert(bi); } @@ -795,12 +798,13 @@ void SingleTriggeredInput::FillPool() uint64_t gl1_clk = Gl1Input()->m_bclkarray_map[gl1pid][i]; uint64_t seb_clk = m_bclkarray_map[pid][i]; std::cout << "pool index i " << i << ", gl1 / seb : " << gl1_clk << " / " << seb_clk; - if(im_bclkdiffarray_map[gl1pid][i]; uint64_t seb_diff = m_bclkdiffarray_map[pid][i]; std::cout << " -> diff of gl1 vs seb : " << gl1_diff << " " << seb_diff << std::endl; } - else if(i==pooldepth) + else if (i == pooldepth) { std::cout << std::endl; } @@ -810,11 +814,11 @@ void SingleTriggeredInput::FillPool() if (shift == -1) { std::cout << Name() << ": Packet " << pid << " shifted by -1 with dropping the first seb event" << std::endl; - if(m_PacketShiftOffset[pid] == -1) + if (m_PacketShiftOffset[pid] == -1) { std::cout << "Packet " << pid << " requires an additional shift -1. Lets not handle this for the moment.. stop combining" << std::endl; m_PacketAlignmentProblem[pid] = true; - } + } if (!m_PacketEventDeque[pid].empty()) { @@ -828,12 +832,12 @@ void SingleTriggeredInput::FillPool() for (size_t i = 0; i < packetpoolsize - 1; ++i) { - m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i+1]; + m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i + 1]; } for (size_t i = 0; i < packetpoolsize; ++i) { - m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i+1], m_bclkarray_map[pid][i]); + m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i + 1], m_bclkarray_map[pid][i]); } Event* evt = GetEventIterator()->getNextEvent(); if (evt) @@ -861,7 +865,7 @@ void SingleTriggeredInput::FillPool() else if (shift == 1) { std::cout << Name() << ": Packet " << pid << " requires shift +1 (insert dummy at front)" << std::endl; - + if (m_packetclk_copy_runs) { std::cout << Name() << " : runs where clocks are copied from the first XMIT. Checking FEM clock diff" << std::endl; @@ -879,7 +883,7 @@ void SingleTriggeredInput::FillPool() std::cout << Name() << " : Packet identified as misaligned also with FEMs. Do normal recovery process" << std::endl; } - if(m_PacketShiftOffset[pid] == 1) + if (m_PacketShiftOffset[pid] == 1) { std::cout << "Packet " << pid << " requires an additional shift +1. Lets not handle this for the moment.. stop combining" << std::endl; m_PacketAlignmentProblem[pid] = true; @@ -887,11 +891,11 @@ void SingleTriggeredInput::FillPool() for (size_t i = pooldepth; i > 0; --i) { - m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i-1]; + m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i - 1]; } - for (size_t i = 1 ; i < pooldepth; ++i) + for (size_t i = 1; i < pooldepth; ++i) { - m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i+1], m_bclkarray_map[pid][i]); + m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i + 1], m_bclkarray_map[pid][i]); } m_bclkarray_map[pid][0] = 0; @@ -901,7 +905,7 @@ void SingleTriggeredInput::FillPool() if (!m_PacketEventDeque[pid].empty()) { m_PacketEventBackup[pid] = m_PacketEventDeque[pid].back(); - Event* dummy_event = m_PacketEventDeque[pid][0]; + Event* dummy_event = m_PacketEventDeque[pid][0]; m_PacketEventDeque[pid].push_front(dummy_event); m_PacketEventDeque[pid].pop_back(); } @@ -924,12 +928,13 @@ void SingleTriggeredInput::FillPool() uint64_t gl1_clk = Gl1Input()->m_bclkarray_map[gl1pid][i]; uint64_t seb_clk = m_bclkarray_map[pid][i]; std::cout << "pool index i " << i << ", gl1 / seb : " << gl1_clk << " / " << seb_clk; - if(im_bclkdiffarray_map[gl1pid][i]; uint64_t seb_diff = m_bclkdiffarray_map[pid][i]; std::cout << " -- diff of gl1 vs seb : " << gl1_diff << " " << seb_diff << std::endl; } - else if(i==pooldepth) + else if (i == pooldepth) { std::cout << std::endl; } @@ -944,10 +949,10 @@ void SingleTriggeredInput::FillPool() if (m_PacketAlignmentFailCount[pid] >= m_max_alignment_retries) { std::cout << Name() << ": Max retries reached — permanently ditching packet " << pid << std::endl; - m_PacketAlignmentFailCount[pid] = 0; + m_PacketAlignmentFailCount[pid] = 0; m_PacketAlignmentProblem[pid] = true; } - + m_PrevPoolLastDiffBad[pid] = false; } } @@ -956,7 +961,7 @@ void SingleTriggeredInput::FillPool() return; } -void SingleTriggeredInput::CreateDSTNodes(Event *evt) +void SingleTriggeredInput::CreateDSTNodes(Event* evt) { std::string CompositeNodeName = "Packets"; if (KeepMyPackets()) @@ -964,31 +969,62 @@ void SingleTriggeredInput::CreateDSTNodes(Event *evt) CompositeNodeName = "PacketsKeep"; } PHNodeIterator iter(m_topNode); - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + PHCompositeNode* dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) { dstNode = new PHCompositeNode("DST"); m_topNode->addNode(dstNode); } PHNodeIterator iterDst(dstNode); - PHCompositeNode *detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", CompositeNodeName)); - if (!detNode) + PHCompositeNode* detNode{nullptr}; + PHCompositeNode* detNodeKeep{nullptr}; + if (m_KeepPacketSet.empty()) { - detNode = new PHCompositeNode(CompositeNodeName); - dstNode->addNode(detNode); + detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", CompositeNodeName)); + if (!detNode) + { + detNode = new PHCompositeNode(CompositeNodeName); + dstNode->addNode(detNode); + } + } + else + { + // if we want to keep a few packets, we need two detNodes, Packet and PacketKeep + // this construct here allows for the KeepMyPackets flag to take effect, then both + // node pointers detNode and detNodeKeep point to the same (so KeepMyPackets has precedence) + detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", CompositeNodeName)); + if (!detNode) + { + detNode = new PHCompositeNode(CompositeNodeName); + dstNode->addNode(detNode); + } + detNodeKeep = dynamic_cast(iterDst.findFirst("PHCompositeNode", "PacketsKeep")); + if (!detNode) + { + detNodeKeep = new PHCompositeNode("PacketsKeep"); + dstNode->addNode(detNodeKeep); + } } - std::vector pktvec = evt->getPacketVector(); - for (auto *piter : pktvec) + + std::vector pktvec = evt->getPacketVector(); + for (auto* piter : pktvec) { int packet_id = piter->getIdentifier(); m_PacketSet.insert(packet_id); std::string PacketNodeName = std::to_string(packet_id); - CaloPacket *calopacket = findNode::getClass(detNode, PacketNodeName); + CaloPacket* calopacket = findNode::getClass(detNode, packet_id); if (!calopacket) { calopacket = new CaloPacketv1(); - PHIODataNode *newNode = new PHIODataNode(calopacket, PacketNodeName, "PHObject"); - detNode->addNode(newNode); + PHIODataNode* newNode = new PHIODataNode(calopacket, packet_id, "PHObject"); + if (m_KeepPacketSet.contains(packet_id)) + { + detNodeKeep->addNode(newNode); + } + else + { + detNode->addNode(newNode); + } } m_PacketShiftOffset.try_emplace(packet_id, 0); delete piter; @@ -1031,8 +1067,10 @@ bool SingleTriggeredInput::FemClockAlignment(int pid, const std::deque& } int majority_clk = std::max_element( - clk_count.begin(), clk_count.end(), - [](const auto& a, const auto& b) { return a.second < b.second; })->first; + clk_count.begin(), clk_count.end(), + [](const auto& a, const auto& b) + { return a.second < b.second; }) + ->first; if (clk_count[majority_clk] < 2) { @@ -1040,7 +1078,6 @@ bool SingleTriggeredInput::FemClockAlignment(int pid, const std::deque& return false; } - if (i >= 1 && prev_clk != std::numeric_limits::max() && gl1diff[i] != std::numeric_limits::max()) { uint16_t fem_diff = static_cast(ComputeClockDiff(majority_clk, prev_clk) & 0xFFFFU); @@ -1059,9 +1096,9 @@ bool SingleTriggeredInput::FemClockAlignment(int pid, const std::deque& return true; } -int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) +int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket* pkt) { - CaloPacket *calopkt = dynamic_cast(pkt); + CaloPacket* calopkt = dynamic_cast(pkt); if (!calopkt) { return 0; @@ -1099,7 +1136,7 @@ int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) } } } - else + else { for (int j = 0; j < nrModules; j++) { @@ -1147,7 +1184,7 @@ int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) for (const auto iterA : ClockMap) { std::cout << "Clock : 0x" << std::hex << iterA.first << std::dec - << " shows up " << iterA.second << " times" << std::endl; + << " shows up " << iterA.second << " times" << std::endl; } } return -1; @@ -1158,8 +1195,8 @@ int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) void SingleTriggeredInput::dumpdeque() { - const auto *iter1 = clkdiffbegin(); - const auto *iter2 = Gl1Input()->clkdiffbegin(); + const auto* iter1 = clkdiffbegin(); + const auto* iter2 = Gl1Input()->clkdiffbegin(); while (iter1 != clkdiffend()) { std::cout << Name() << " clk: 0x" << std::hex << *iter1 @@ -1191,11 +1228,11 @@ int SingleTriggeredInput::ReadEvent() std::cout << "deque size: " << size << std::endl; } - auto *ref_evt = m_PacketEventDeque.begin()->second.front(); + auto* ref_evt = m_PacketEventDeque.begin()->second.front(); RunNumber(ref_evt->getRunNumber()); uint64_t event_number = ref_evt->getEvtSequence(); - if(event_number % 10000==0) + if (event_number % 10000 == 0) { std::cout << "processed events : " << event_number << std::endl; } @@ -1204,12 +1241,13 @@ int SingleTriggeredInput::ReadEvent() bool all_packets_unshifted = std::all_of( m_PacketShiftOffset.begin(), m_PacketShiftOffset.end(), - [](const std::pair& p) { return p.second == 0; }); + [](const std::pair& p) + { return p.second == 0; }); std::set events_to_delete; for (auto& [pid, dq] : m_PacketEventDeque) { - if(m_PacketAlignmentProblem[pid]) + if (m_PacketAlignmentProblem[pid]) { continue; } @@ -1225,7 +1263,7 @@ int SingleTriggeredInput::ReadEvent() return -1; } - CaloPacket *newhit = findNode::getClass(m_topNode, packet_id); + CaloPacket* newhit = findNode::getClass(m_topNode, packet_id); newhit->Reset(); if (m_DitchPackets.contains(packet_id) && m_DitchPackets[packet_id].contains(0)) { @@ -1253,7 +1291,7 @@ int SingleTriggeredInput::ReadEvent() { uint64_t prev_packet_clock = m_PreviousValidBCOMap[packet_id]; newhit->setBCO(prev_packet_clock); - m_PreviousValidBCOMap[packet_id] = GetClock(evt,packet_id); + m_PreviousValidBCOMap[packet_id] = GetClock(evt, packet_id); } else { @@ -1292,7 +1330,7 @@ int SingleTriggeredInput::ReadEvent() int iret = FemEventNrClockCheck(newhit); if (iret < 0) { - std::cout << Name() <<" : failed on FemEventNrClockCheck reset calo packet " << std::endl; + std::cout << Name() << " : failed on FemEventNrClockCheck reset calo packet " << std::endl; newhit->Reset(); } @@ -1302,7 +1340,7 @@ int SingleTriggeredInput::ReadEvent() } } - for(Event *evtdelete : events_to_delete) + for (Event* evtdelete : events_to_delete) { delete evtdelete; } diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.h b/offline/framework/fun4allraw/SingleTriggeredInput.h index d7d825b02a..cad0d64bf0 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.h +++ b/offline/framework/fun4allraw/SingleTriggeredInput.h @@ -17,6 +17,7 @@ #include #include #include +#include #include class Event; @@ -58,15 +59,16 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler virtual std::array::const_iterator beginclock() { return m_bclkarray.begin(); } virtual void KeepPackets() { m_KeepPacketsFlag = true; } virtual bool KeepMyPackets() const { return m_KeepPacketsFlag; } + virtual void KeepPacket(const int packetnum) { m_KeepPacketSet.insert(packetnum); } void topNode(PHCompositeNode *topNode) { m_topNode = topNode; } PHCompositeNode *topNode() { return m_topNode; } virtual void FakeProblemEvent(const int ievent) { m_ProblemEvent = ievent; } virtual int FemEventNrClockCheck(OfflinePacket *calopkt); void dumpdeque(); int checkfirstsebevent(); - virtual bool CheckFemDiffIdx(int pid, size_t index, const std::deque& events, uint64_t gl1diffidx); - virtual bool CheckPoolAlignment(int pid, const std::array& sebdiff, const std::array& gl1diff, std::vector& bad_indices, int& shift, bool& CurrentPoolLastDiffBad, bool PrevPoolLastDiffBad); - virtual bool FemClockAlignment(int pid, const std::deque& events, const std::array& gl1diff); + virtual bool CheckFemDiffIdx(int pid, size_t index, const std::deque &events, uint64_t gl1diffidx); + virtual bool CheckPoolAlignment(int pid, const std::array &sebdiff, const std::array &gl1diff, std::vector &bad_indices, int &shift, bool &CurrentPoolLastDiffBad, bool PrevPoolLastDiffBad); + virtual bool FemClockAlignment(int pid, const std::deque &events, const std::array &gl1diff); protected: PHCompositeNode *m_topNode{nullptr}; @@ -76,17 +78,16 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler // the accompanying diff to the previous beam clock with this event, so any mismatch // gives us the event index in the deque which is off std::deque m_EventDeque; - std::map> m_PacketEventDeque; - std::map m_PacketEventBackup; + std::map> m_PacketEventDeque; + std::map m_PacketEventBackup; std::map m_PacketShiftOffset; std::array m_bclkarray{}; // keep the last bco from previous loop std::array m_bclkdiffarray{}; std::map> m_bclkarray_map; - std::map> m_bclkdiffarray_map; + std::map> m_bclkdiffarray_map; std::set m_PacketSet; static uint64_t ComputeClockDiff(uint64_t curr, uint64_t prev) { return (curr - prev) & 0xFFFFFFFF; } - private: Eventiterator *m_EventIterator{nullptr}; SingleTriggeredInput *m_Gl1Input{nullptr}; @@ -104,6 +105,7 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler bool firstclockcheck{true}; bool m_KeepPacketsFlag{false}; bool m_packetclk_copy_runs{false}; + int64_t eventcounter{0}; std::set m_CorrectCopiedClockPackets; std::map> m_DitchPackets; std::set m_FEMEventNrSet; @@ -112,7 +114,7 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler std::map m_PacketAlignmentProblem; std::map m_PrevPoolLastDiffBad; std::map m_PreviousValidBCOMap; - long long eventcounter{0}; + std::unordered_set m_KeepPacketSet; }; #endif From d271e6eaa70cc63c8bdd5a995192c9fb47abfa65 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 3 Mar 2026 17:10:23 -0500 Subject: [PATCH 342/866] thanks rabbit --- offline/framework/fun4allraw/SingleTriggeredInput.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index 999ca40531..9302b9ecc0 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -999,7 +999,7 @@ void SingleTriggeredInput::CreateDSTNodes(Event* evt) dstNode->addNode(detNode); } detNodeKeep = dynamic_cast(iterDst.findFirst("PHCompositeNode", "PacketsKeep")); - if (!detNode) + if (!detNodeKeep) { detNodeKeep = new PHCompositeNode("PacketsKeep"); dstNode->addNode(detNodeKeep); From c5e71449bb66e65b42e72e17120565120e1e2854 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 3 Mar 2026 18:05:09 -0500 Subject: [PATCH 343/866] fix clang-tidy --- offline/framework/fun4allraw/SingleTriggeredInput.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index 9302b9ecc0..f2d3b34ef1 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -1011,7 +1011,6 @@ void SingleTriggeredInput::CreateDSTNodes(Event* evt) { int packet_id = piter->getIdentifier(); m_PacketSet.insert(packet_id); - std::string PacketNodeName = std::to_string(packet_id); CaloPacket* calopacket = findNode::getClass(detNode, packet_id); if (!calopacket) { From 603c32a5d17bd49ee5beea9583f985f7edf47a3c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 3 Mar 2026 21:53:23 -0500 Subject: [PATCH 344/866] working through silicon seeding API changes --- .../trackreco/PHActsSiliconSeeding.cc | 102 +++++++++++------- .../packages/trackreco/PHActsSiliconSeeding.h | 10 +- 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index f131319125..d52e2808cf 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -87,8 +87,8 @@ int PHActsSiliconSeeding::Init(PHCompositeNode* /*topNode*/) Acts::SeedFilterConfig sfCfg = configureSeedFilter(); sfCfg = sfCfg.toInternalUnits(); - m_seedFinderCfg.seedFilter = std::make_unique>( - Acts::SeedFilter(sfCfg)); + m_seedFinderCfg.seedFilter = std::make_unique>( + sfCfg); configureSeeder(); configureSPGrid(); @@ -99,10 +99,10 @@ int PHActsSiliconSeeding::Init(PHCompositeNode* /*topNode*/) } // vector containing the map of z bins in the top and bottom layers - m_bottomBinFinder = std::make_unique>( - nphineighbors, zBinNeighborsBottom); - m_topBinFinder = std::make_unique>( - nphineighbors, zBinNeighborsTop); + m_bottomBinFinder = std::make_unique>( + nphineighbors, zBinNeighborsBottom, 0); + m_topBinFinder = std::make_unique>( + nphineighbors, zBinNeighborsTop, 0); if (m_seedAnalysis) { @@ -195,7 +195,8 @@ int PHActsSiliconSeeding::End(PHCompositeNode* /*topNode*/) void PHActsSiliconSeeding::runSeeder() { - Acts::SeedFinder> seedFinder(m_seedFinderCfg); + Acts::SeedFinder> seedFinder(m_seedFinderCfg); auto eventTimer = std::make_unique("eventTimer"); eventTimer->stop(); @@ -209,20 +210,9 @@ void PHActsSiliconSeeding::runSeeder() std::cout << "Seeding for strobe " << strobe << std::endl; } GridSeeds seedVector; - /// Covariance converter functor needed by seed finder - auto covConverter = [=](const SpacePoint& sp, float zAlign, float rAlign, - float sigmaError) - { - Acts::Vector3 position{sp.x(), sp.y(), sp.z()}; - Acts::Vector2 cov; - cov[0] = (sp.m_varianceR + rAlign * rAlign) * sigmaError; - cov[1] = (sp.m_varianceZ + zAlign * zAlign) * sigmaError; - return std::make_tuple(position, cov, sp.t()); - }; - - Acts::Extent rRangeSPExtent; + eventTimer->restart(); - auto spVec = getSiliconSpacePoints(rRangeSPExtent, strobe); + auto spVec = getSiliconSpacePoints(strobe); eventTimer->stop(); spTime += eventTimer->get_accumulated_time(); if (m_seedAnalysis) @@ -230,37 +220,71 @@ void PHActsSiliconSeeding::runSeeder() h_nInputMeas->Fill(spVec.size()); } - Acts::CylindricalSpacePointGrid grid = - Acts::CylindricalSpacePointGridCreator::createGrid( + Acts::SpacePointContainerConfig spConfig; + spConfig.useDetailedDoubleMeasurementInfo = + m_seedFinderCfg.useDetailedDoubleMeasurementInfo; + // Options + // TODO - check beam pos information + Acts::SpacePointContainerOptions spOptions; + spOptions.beamPos = {0., 0.}; + + // Prepare interface SpacePoint backend-ACTS + ActsExamples::SpacePointContainer container(spVec); + // Prepare Acts API + Acts::SpacePointContainer + spContainer(spConfig, spOptions, container); + + using value_type = typename decltype(spContainer)::SpacePointProxyType; + using seed_type = Acts::Seed; + + Acts::CylindricalSpacePointGrid grid = + Acts::CylindricalSpacePointGridCreator::createGrid( m_gridCfg, m_gridOptions); - Acts::CylindricalSpacePointGridCreator::fillGrid( + Acts::CylindricalSpacePointGridCreator::fillGrid( m_seedFinderCfg, m_seedFinderOptions, grid, - spVec.begin(), spVec.end(), covConverter, - rRangeSPExtent); + spContainer); + + // Compute radius Range + // we rely on the fact the grid is storing the proxies + // with a sorting in the radius + float minRange = std::numeric_limits::max(); + float maxRange = std::numeric_limits::lowest(); + for (const auto& coll : grid) + { + if (coll.empty()) + { + continue; + } + const auto* firstEl = coll.front(); + const auto* lastEl = coll.back(); + minRange = std::min(firstEl->radius(), minRange); + maxRange = std::max(lastEl->radius(), maxRange); + } - std::array, 2UL> navigation; - navigation[1UL] = m_seedFinderCfg.zBinsCustomLooping; + std::array, 3ul> navigation; + navigation[1ul] = m_seedFinderCfg.zBinsCustomLooping; - auto spacePointsGrouping = Acts::CylindricalBinnedGroup( + auto spacePointsGrouping = Acts::CylindricalBinnedGroup( std::move(grid), *m_bottomBinFinder, *m_topBinFinder, std::move(navigation)); /// variable middle SP radial region of interest const Acts::Range1D rMiddleSPRange( - std::floor(rRangeSPExtent.min(Acts::binR) / 2) * 2 + 1.5, - std::floor(rRangeSPExtent.max(Acts::binR) / 2) * 2 - 1.5); + // TODO check these values in current code with Acts::Extent + std::floor(minRange / 2) * 2 + 1.5, + std::floor(maxRange / 2) * 2 - 1.5); eventTimer->restart(); - SeedContainer seeds; + static thread_local std::vector seeds; seeds.clear(); + decltype(seedFinder)::SeedingState state; - state.spacePointData.resize(spVec.size(), - m_seedFinderCfg.useDetailedDoubleMeasurementInfo); + state.spacePointMutableData.resize(spContainer.size()); for (const auto [bottom, middle, top] : spacePointsGrouping) { seedFinder.createSeedsForGroup(m_seedFinderOptions, state, spacePointsGrouping.grid(), - std::back_inserter(seeds), + seeds, bottom, middle, top, @@ -270,15 +294,13 @@ void PHActsSiliconSeeding::runSeeder() seederTime += eventTimer->get_accumulated_time(); eventTimer->restart(); - seedVector.push_back(seeds); - if (m_streaming) { - makeSvtxTracksWithTime(seedVector, strobe); + makeSvtxTracksWithTime(seeds, strobe); } else { - makeSvtxTracks(seedVector); + makeSvtxTracks(seeds); } eventTimer->stop(); @@ -1417,8 +1439,7 @@ SpacePointPtr PHActsSiliconSeeding::makeSpacePoint( return spPtr; } -std::vector PHActsSiliconSeeding::getSiliconSpacePoints(Acts::Extent& rRangeSPExtent, - const int strobe) +std::vector PHActsSiliconSeeding::getSiliconSpacePoints(const int strobe) { std::vector spVec; unsigned int numSiliconHits = 0; @@ -1464,7 +1485,6 @@ std::vector PHActsSiliconSeeding::getSiliconSpacePoints(Acts: auto* sp = makeSpacePoint(surface, cluskey, cluster).release(); spVec.push_back(sp); - rRangeSPExtent.extend({sp->x(), sp->y(), sp->z()}); numSiliconHits++; } } diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.h b/offline/packages/trackreco/PHActsSiliconSeeding.h index 506f9c225c..0d02295953 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.h +++ b/offline/packages/trackreco/PHActsSiliconSeeding.h @@ -33,6 +33,7 @@ class TrkrClusterIterationMap; class TrkrClusterCrossingAssoc; using GridSeeds = std::vector>>; +using SpacePointProxy_type = typename Acts::SpacePointContainer>, Acts::detail::RefHolder>::SpacePointProxyType; /** * This class runs the Acts seeder over the MVTX measurements @@ -225,8 +226,7 @@ class PHActsSiliconSeeding : public SubsysReco TrkrCluster *clus); /// Get all space points for the seeder - std::vector getSiliconSpacePoints(Acts::Extent &rRangeSPExtent, - const int strobe); + std::vector getSiliconSpacePoints(const int strobe); void printSeedConfigs(Acts::SeedFilterConfig &sfconfig); bool isTimingMismatched(TrackSeed& seed) const; @@ -288,7 +288,7 @@ class PHActsSiliconSeeding : public SubsysReco int m_lowStrobeIndex = 0; int m_highStrobeIndex = 1; /// Configuration classes for Acts seeding - Acts::SeedFinderConfig m_seedFinderCfg; + Acts::SeedFinderConfig m_seedFinderCfg; Acts::CylindricalSpacePointGridConfig m_gridCfg; Acts::CylindricalSpacePointGridOptions m_gridOptions; Acts::SeedFinderOptions m_seedFinderOptions; @@ -353,8 +353,8 @@ class PHActsSiliconSeeding : public SubsysReco std::vector> zBinNeighborsTop; std::vector> zBinNeighborsBottom; int nphineighbors = 1; - std::unique_ptr> m_bottomBinFinder; - std::unique_ptr> m_topBinFinder; + std::unique_ptr> m_bottomBinFinder; + std::unique_ptr> m_topBinFinder; int m_event = 0; From a0f0087597661e20b72cf999783354dc3d2ab384 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 09:51:44 -0500 Subject: [PATCH 345/866] finally get all templated changes sorted out --- .../trackreco/PHActsSiliconSeeding.cc | 62 +++++++------------ .../packages/trackreco/PHActsSiliconSeeding.h | 11 ++-- 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index d52e2808cf..b0b799ed38 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -43,6 +43,7 @@ #ifndef __clang__ #pragma GCC diagnostic pop #endif + #include #include #include @@ -231,11 +232,10 @@ void PHActsSiliconSeeding::runSeeder() // Prepare interface SpacePoint backend-ACTS ActsExamples::SpacePointContainer container(spVec); // Prepare Acts API - Acts::SpacePointContainer + SpacePointContainerRefHolder spContainer(spConfig, spOptions, container); - using value_type = typename decltype(spContainer)::SpacePointProxyType; - using seed_type = Acts::Seed; + Acts::CylindricalSpacePointGrid grid = Acts::CylindricalSpacePointGridCreator::createGrid( @@ -327,7 +327,7 @@ void PHActsSiliconSeeding::runSeeder() return; } -void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, +void PHActsSiliconSeeding::makeSvtxTracksWithTime(const std::vector& seedVector, const int& strobe) { @@ -335,17 +335,8 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, int numGoodSeeds = 0; m_seedid = -1; - for (const auto& seeds : seedVector) + for (const auto& seed : seedVector) { - /// loop over acts triplets - for (const auto& seed : seeds) - { - if (Verbosity() > 1) - { - std::cout << "Seed " << numSeeds << " has " - << seed.sp().size() << " measurements " - << std::endl; - } numSeeds++; if (m_seedAnalysis) { @@ -355,10 +346,10 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, std::map positions; std::vector clus_positions; - - for (const auto& spacePoint : seed.sp()) + const auto& sps = seed.sp(); + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = spacePoint->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); auto globalPosition = m_tGeometry->getGlobalPosition( cluskey, @@ -401,9 +392,10 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, { // make the svtxtrack seed with both mvtx + intt clusters auto trackSeed = std::make_unique(); - for (const auto& mvtx_clus : seed.sp()) + + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = mvtx_clus->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); trackSeed->insert_cluster_key(cluskey); } for (auto& intt_clus : intt_clus_vec) @@ -426,9 +418,9 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, { /// make a single mvtx only seed auto trackSeed = std::make_unique(); - for (const auto& mvtx_clus : seed.sp()) + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = mvtx_clus->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); trackSeed->insert_cluster_key(cluskey); } TrackSeedHelper::circleFitByTaubin(trackSeed.get(), positions, 0, 7); @@ -439,34 +431,23 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, m_seedContainer->insert(trackSeed.get()); numGoodSeeds++; } - } + } if (Verbosity() > 4) { std::cout << "num good seeds : " << numGoodSeeds << std::endl; } } -void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) +void PHActsSiliconSeeding::makeSvtxTracks(const std::vector& seedVector) { int numSeeds = 0; int numGoodSeeds = 0; m_seedid = -1; int strobe = m_lowStrobeIndex; - /// Loop over grid volumes. In our case this will be strobe - for (const auto& seeds : seedVector) + for (const auto& seed : seedVector) { - /// Loop over actual seeds in this grid volume - for (const auto& seed : seeds) - { - if (Verbosity() > 1) - { - std::cout << "Seed " << numSeeds << " has " - << seed.sp().size() << " measurements " - << std::endl; - } - - if (m_seedAnalysis) + if (m_seedAnalysis) { clearTreeVariables(); m_seedid++; @@ -479,9 +460,10 @@ void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) std::map positions; auto trackSeed = std::make_unique(); - for (const auto& spacePoint : seed.sp()) + const auto& sps = seed.sp(); + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = spacePoint->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); cluster_keys.push_back(cluskey); trackSeed->insert_cluster_key(cluskey); @@ -499,7 +481,7 @@ void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) if (Verbosity() > 1) { std::cout << "Adding cluster with x,y " - << spacePoint->x() << ", " << spacePoint->y() + << sps[spid]->externalSpacePoint()->x() << ", " << sps[spid]->externalSpacePoint()->y() << " mm in detector " << (unsigned int) TrkrDefs::getTrkrId(cluskey) << " with cluskey " << cluskey @@ -620,7 +602,7 @@ void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) std::cout << "Intt fit time " << circlefittime << " and svtx time " << svtxtracktime << std::endl; } - } + strobe++; if (strobe > m_highStrobeIndex) { diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.h b/offline/packages/trackreco/PHActsSiliconSeeding.h index 0d02295953..09081d088f 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.h +++ b/offline/packages/trackreco/PHActsSiliconSeeding.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -33,8 +34,10 @@ class TrkrClusterIterationMap; class TrkrClusterCrossingAssoc; using GridSeeds = std::vector>>; -using SpacePointProxy_type = typename Acts::SpacePointContainer>, Acts::detail::RefHolder>::SpacePointProxyType; - +using SpacePointContainerRefHolder = Acts::SpacePointContainer; +using SpacePointProxy_type = typename SpacePointContainerRefHolder::SpacePointProxyType; +using value_type = SpacePointContainerRefHolder::SpacePointProxyType; +using seed_type = Acts::Seed; /** * This class runs the Acts seeder over the MVTX measurements * to create track stubs for the rest of the stub matching pattern @@ -213,10 +216,10 @@ class PHActsSiliconSeeding : public SubsysReco Acts::SeedFilterConfig configureSeedFilter() const; /// Take final seeds and fill the TrackSeedContainer - void makeSvtxTracks(const GridSeeds &seedVector); + void makeSvtxTracks(const std::vector& seedVector); /// Take final seeds and fill the TrackSeedContainer - void makeSvtxTracksWithTime(const GridSeeds &seedVector, const int &strobe); + void makeSvtxTracksWithTime(const std::vector& seedVector, const int &strobe); /// Create a seeding space point out of an Acts::SourceLink SpacePointPtr makeSpacePoint( From c21d9d580d78fe9ef656decbe6e6fe0aa85bc5fd Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 10:45:01 -0500 Subject: [PATCH 346/866] track fitters compile --- offline/packages/trackreco/PHActsTrkFitter.cc | 10 +++------ offline/packages/trackreco/PHActsTrkFitter.h | 1 - .../packages/trackreco/PHCosmicsTrkFitter.cc | 22 ++----------------- .../packages/trackreco/PHCosmicsTrkFitter.h | 2 -- 4 files changed, 5 insertions(+), 30 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index d0006ac25c..a342ea104b 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -694,8 +694,8 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) /// Reset the track seed with the dummy covariance auto seed = ActsTrackFittingAlgorithm::TrackParameters::create( - pSurface, m_transient_geocontext, + pSurface, actsFourPos, momentum, charge / momentum.norm(), @@ -709,13 +709,12 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } /// Set host of propagator options for Acts to do e.g. material integration - Acts::PropagatorPlainOptions ppPlainOptions; - auto calibptr = std::make_unique(); CalibratorAdapter calibrator{*calibptr, measurements}; auto magcontext = m_tGeometry->geometry().magFieldContext; auto calibcontext = m_tGeometry->geometry().calibContext; + auto ppPlainOptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); ActsTrackFittingAlgorithm::GeneralFitterOptions kfOptions{ @@ -928,10 +927,7 @@ bool PHActsTrkFitter::getTrackFitResult( { h_updateTime->Fill(updateTime); } - - Trajectory trajectory(tracks.trackStateContainer(), - trackTips, indexedParams); - + if (m_actsEvaluator) { m_evaluator->evaluateTrackFit(tracks, trackTips, indexedParams, track, diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 056c3e88b3..cadfd5bec0 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -45,7 +45,6 @@ class PHG4TpcGeomContainer; using SourceLink = ActsSourceLink; using FitResult = ActsTrackFittingAlgorithm::TrackFitterResult; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using SurfacePtrVec = std::vector; using SourceLinkVec = std::vector; diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index d4664415ad..c93861b166 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -81,7 +81,6 @@ namespace PHCosmicsTrkFitter::PHCosmicsTrkFitter(const std::string& name) : SubsysReco(name) - , m_trajectories(nullptr) { } @@ -207,8 +206,6 @@ int PHCosmicsTrkFitter::ResetEvent(PHCompositeNode* /*topNode*/) std::cout << "Reset PHCosmicsTrkFitter" << std::endl; } - m_trajectories->clear(); - return Fun4AllReturnCodes::EVENT_OK; } @@ -498,8 +495,8 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } //! Reset the track seed with the dummy covariance auto seed = ActsTrackFittingAlgorithm::TrackParameters::create( - pSurface, m_transient_geocontext, + pSurface, actsFourPos, momentum, charge / momentum.norm(), @@ -519,13 +516,12 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } //! Set host of propagator options for Acts to do e.g. material integration - Acts::PropagatorPlainOptions ppPlainOptions; - auto calibptr = std::make_unique(); CalibratorAdapter calibrator{*calibptr, measurements}; auto magcontext = m_tGeometry->geometry().magFieldContext; auto calibcontext = m_tGeometry->geometry().calibContext; + auto ppPlainOptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); ActsTrackFittingAlgorithm::GeneralFitterOptions kfOptions{ @@ -608,11 +604,6 @@ bool PHCosmicsTrkFitter::getTrackFitResult(FitResult& fitOutput, std::cout << "For trackTip == " << outtrack.tipIndex() << std::endl; } - Trajectory trajectory(tracks.trackStateContainer(), - trackTips, indexedParams); - - m_trajectories->insert(std::make_pair(track->get_id(), trajectory)); - /// Get position, momentum from the Acts output. Update the values of /// the proto track updateSvtxTrack(trackTips, indexedParams, tracks, track); @@ -793,15 +784,6 @@ int PHCosmicsTrkFitter::createNodes(PHCompositeNode* topNode) dstNode->addNode(svtxNode); } - m_trajectories = findNode::getClass>(topNode, "ActsTrajectories"); - if (!m_trajectories) - { - m_trajectories = new std::map; - auto node = - new PHDataNode>(m_trajectories, "ActsTrajectories"); - svtxNode->addNode(node); - } - m_trackMap = findNode::getClass(topNode, _track_map_name); if (!m_trackMap) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index 2619cc7dd2..2dc8c579db 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -39,7 +39,6 @@ class TTree; using SourceLink = ActsSourceLink; using FitResult = ActsTrackFittingAlgorithm::TrackFitterResult; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using SurfacePtrVec = std::vector; using SourceLinkVec = std::vector; @@ -177,7 +176,6 @@ class PHCosmicsTrkFitter : public SubsysReco std::unique_ptr m_evaluator = nullptr; std::string m_evalname = "ActsEvaluator.root"; - std::map* m_trajectories = nullptr; SvtxTrackMap* m_seedTracks = nullptr; //! tpc global position wrapper From 2df35fc95f6dfda522beb71d718592717184f879 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 10:46:50 -0500 Subject: [PATCH 347/866] remove deprecated library names --- offline/packages/trackreco/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/offline/packages/trackreco/Makefile.am b/offline/packages/trackreco/Makefile.am index 3b70c0e270..4829357b0b 100644 --- a/offline/packages/trackreco/Makefile.am +++ b/offline/packages/trackreco/Makefile.am @@ -119,7 +119,7 @@ AM_CPPFLAGS += -I$(OFFLINE_MAIN)/include/ActsFatras ACTS_LIBS = \ -lActsCore \ - -lActsPluginTGeo \ + -lActsPluginRoot \ -lActsExamplesDetectorTGeo \ -lActsExamplesFramework @@ -174,7 +174,6 @@ libtrack_reco_la_SOURCES = \ libtrack_reco_la_LIBADD = \ -lActsCore \ - -lActsPluginTGeo \ -lActsExamplesDetectorTGeo \ -lActsExamplesFramework \ -lcalo_io \ From d303120b053740ec7c5321fc4a52259b5a0d5d49 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 12:40:40 -0500 Subject: [PATCH 348/866] remove missing include --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index b0b799ed38..1a9e27d5d2 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -43,8 +43,6 @@ #ifndef __clang__ #pragma GCC diagnostic pop #endif - -#include #include #include #include From 3167d915dc22eed563cffe2b44dd8d57df03df8a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 13:34:41 -0500 Subject: [PATCH 349/866] make single typename definition for new acts propagator options --- .../packages/TrackerMillepedeAlignment/MakeMilleFiles.cc | 6 +++--- offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h | 1 + offline/packages/trackreco/ActsPropagator.cc | 4 +--- offline/packages/trackreco/ActsPropagator.h | 4 +++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index c894542990..939de889a7 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -309,9 +309,9 @@ bool MakeMilleFiles::getLocalVtxDerivativesXY(SvtxTrack* track, auto param = propagator.makeTrackParams(firststate, track->get_charge(), surf).value(); auto perigee = propagator.makeVertexSurface(vertex); auto actspropagator = propagator.makePropagator(); - - Acts::PropagatorOptions<> options(_tGeometry->geometry().getGeoContext(), - _tGeometry->geometry().magFieldContext); + ActsPropagator::SphenixPropagatorOptions + options(_tGeometry->geometry().getGeoContext(), + _tGeometry->geometry().magFieldContext); auto result = actspropagator.propagate(param, *perigee, options); diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h index 25a8963987..0733e22bb6 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h @@ -23,6 +23,7 @@ #include +#include #include #include diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index fa3e2d1152..6170edb2a6 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -112,9 +112,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - using Actors = Acts::ActorList<>; - using PropagatorOptions = SphenixPropagator::Options; - PropagatorOptions options( + SphenixPropagatorOptions options( m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); ActsAborter aborter; diff --git a/offline/packages/trackreco/ActsPropagator.h b/offline/packages/trackreco/ActsPropagator.h index 95a4655f81..164145156b 100644 --- a/offline/packages/trackreco/ActsPropagator.h +++ b/offline/packages/trackreco/ActsPropagator.h @@ -38,7 +38,9 @@ class ActsPropagator using Stepper = Acts::EigenStepper<>; using FastPropagator = Acts::Propagator; using SphenixPropagator = Acts::Propagator; - + using Actors = Acts::ActorList<>; + using SphenixPropagatorOptions = SphenixPropagator::Options; + ActsPropagator() {} ActsPropagator(ActsGeometry* geometry) : m_geometry(geometry) From b2b2ba9021f08a592440c7f2608dca03a93007b9 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 14:14:31 -0500 Subject: [PATCH 350/866] fix func signature --- offline/packages/trackbase_historic/TrackAnalysisUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index aab282da20..fc53a45b2d 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -40,7 +40,7 @@ namespace TrackAnalysisUtils // when/if the tpc geometry changes in the future. This is to get us going const float thickness_per_region[4]); float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, - float const thickness_per_region[4]); + const float thickness_per_region[4]); TrackFitResiduals get_residuals(SvtxTrack* track, TrkrClusterContainer* clustermap, PHCompositeNode* topNode); From 97a7f52366690a4a655b7f11f8242bf75b150926 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 15:13:44 -0500 Subject: [PATCH 351/866] Remove acts dependency which is unneccessary --- calibrations/tpc/TpcDVCalib/Makefile.am | 4 ---- calibrations/tpc/TpcDVCalib/TrackToCalo.cc | 9 +-------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/calibrations/tpc/TpcDVCalib/Makefile.am b/calibrations/tpc/TpcDVCalib/Makefile.am index 033929f967..6ae4411894 100644 --- a/calibrations/tpc/TpcDVCalib/Makefile.am +++ b/calibrations/tpc/TpcDVCalib/Makefile.am @@ -24,10 +24,6 @@ libTpcDVCalib_la_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib libTpcDVCalib_la_LIBADD = \ - -lActsCore \ - -lActsPluginTGeo \ - -lActsExamplesDetectorTGeo \ - -lActsExamplesFramework \ -lSubsysReco \ -ltrackbase_historic_io \ -ltrack_io \ diff --git a/calibrations/tpc/TpcDVCalib/TrackToCalo.cc b/calibrations/tpc/TpcDVCalib/TrackToCalo.cc index f9707e4862..0a6bf6117f 100644 --- a/calibrations/tpc/TpcDVCalib/TrackToCalo.cc +++ b/calibrations/tpc/TpcDVCalib/TrackToCalo.cc @@ -38,14 +38,7 @@ #include #include #include -#include - -#include -#include -#include -#include -#include -#include + #include #include From 9a58c6cc3f143ccac2a5d0b63603d025ad451a0c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 15:31:12 -0500 Subject: [PATCH 352/866] fix clang-tidy warnings --- offline/packages/TrackingDiagnostics/KshortReconstruction.cc | 2 +- offline/packages/TrackingDiagnostics/KshortReconstruction.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index f197a3172e..0dd6d3c89c 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -394,7 +394,7 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float m float cos_theta_reco = pathLength_proj.dot(projected_momentum) / (projected_momentum.norm() * pathLength_proj.norm()); - float reco_info[] = {(float) track1->get_id(), (float) mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), (float) mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; + float reco_info[] = {(float) track1->get_id(), mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; ntp_reco_info->Fill(reco_info); } diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.h b/offline/packages/TrackingDiagnostics/KshortReconstruction.h index 2057ed18e2..9499c9bab8 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.h +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.h @@ -44,7 +44,7 @@ class KshortReconstruction : public SubsysReco // void fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); - void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymass1, float& decaymass2); + void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymassa, float& decaymassb); // void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity); From 01ba052b95b51785b2e81d114aa77c2e5e02b4b4 Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Wed, 4 Mar 2026 18:33:46 -0500 Subject: [PATCH 353/866] added functionality to reject particles from hadron decays + speed up filtering process --- .../HepMCTrigger/HepMCParticleTrigger.cc | 104 +++++++++++++++--- .../HepMCTrigger/HepMCParticleTrigger.h | 13 ++- 2 files changed, 98 insertions(+), 19 deletions(-) diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc index 81d594e528..eccb80ce6c 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include //____________________________________________________________________________.. // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) @@ -267,11 +269,6 @@ void HepMCParticleTrigger::SetAbsEtaHighLow(double ptHigh, double ptLow) } 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) { @@ -286,21 +283,46 @@ bool HepMCParticleTrigger::isGoodEvent(HepMC::GenEvent* e1) std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) { std::vector n_trigger{}; - std::map particle_types; + std::unordered_set particle_pids; + particle_pids.reserve(_theParticles.size()); + for (auto it : _theParticles) + { + particle_pids.insert(std::abs(it)); + } + std::unordered_map particle_types; + particle_types.reserve(particle_pids.size()); + for (HepMC::GenEvent::particle_const_iterator iter = e1->particles_begin(); iter != e1->particles_end(); ++iter) { - if (m_doStableParticleOnly && ((*iter)->end_vertex() || (*iter)->status() != 1)) + const HepMC::GenParticle *g = *iter; + if (m_doStableParticleOnly && (g->end_vertex() || g->status() != 1)) + { + continue; + } + + int pid = std::abs(g->pdg_id()); + auto ipidx = particle_pids.find(pid); + if(ipidx == particle_pids.end()) { continue; } - auto p = (*iter)->momentum(); + + if (m_rejectFromHadronDecay) + { + if(IsFromHadronDecay(g)) + { + continue; + } + } + + auto p = g->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; @@ -341,22 +363,25 @@ std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) { continue; } - if (particle_types.contains(pid)) - { - particle_types[pid]++; - } - else + + particle_types[pid]++; + + if(particle_types.size() == particle_pids.size()) { - particle_types[pid] = 1; + break; } } + n_trigger.reserve(_theParticles.size()); - for (auto p : _theParticles) + + for (auto it : _theParticles) { - n_trigger.push_back(particleAboveThreshold(particle_types, p)); // make sure we have at least one of each required particle + auto ptid = particle_types.find(std::abs(it)); + n_trigger.push_back((ptid != particle_types.end()) ? ptid->second : 0); } return n_trigger; } + int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_particles, int trigger_particle) { // search through for the number of identified trigger particles passing cuts @@ -367,3 +392,48 @@ int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_par } return 0; } + +bool HepMCParticleTrigger::IsFromHadronDecay(const HepMC::GenParticle* gp) +{ + if (!gp) + { + return false; + } + + const HepMC::GenVertex* vtx = gp->production_vertex(); + if (!vtx) + { + return false; + } + + for (auto it = vtx->particles_in_const_begin(); it != vtx->particles_in_const_end(); ++it) + { + const HepMC::GenParticle* mom = *it; + if (!mom) + { + continue; + } + + if (IsHadronPDG(mom->pdg_id())) + { + return true; + } + } + return false; +} + + +bool HepMCParticleTrigger::IsHadronPDG(int _pdg) +{ + if(IsIonPDG(_pdg)) + { + return false; + } + + if(std::abs(_pdg) < 100 ) + { + return false; + } + + return true; +} diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h index e0494cb3e7..22bcf241d4 100644 --- a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -16,6 +16,7 @@ class PHCompositeNode; namespace HepMC { class GenEvent; + class GenParticle; } class HepMCParticleTrigger : public SubsysReco @@ -65,10 +66,15 @@ class HepMCParticleTrigger : public SubsysReco void SetPzLow(double); void SetPzHighLow(double, double); + void SetRejectFromHadronDecay(bool b) {m_rejectFromHadronDecay = b;} void SetStableParticleOnly(bool b) { m_doStableParticleOnly = b; } + int getNevts(){return this->n_evts;} int getNgood(){return this->n_good;} + bool IsFromHadronDecay(const HepMC::GenParticle* gp); + bool IsIonPDG(int _pdg) { return (std::abs(_pdg) >= 1000000000); } + private: bool isGoodEvent(HepMC::GenEvent* e1); std::vector getParticles(HepMC::GenEvent* e1); @@ -76,14 +82,15 @@ class HepMCParticleTrigger : public SubsysReco // std::vector _theParentsi {}; std::vector _theParticles{}; bool m_doStableParticleOnly{true}; + bool m_rejectFromHadronDecay{true}; float threshold{0.}; int goal_event_number{1000}; bool set_event_limit{false}; int n_evts{0}; int n_good{0}; - float _theEtaHigh{1.1}; - float _theEtaLow{-1.1}; + float _theEtaHigh{2.0}; + float _theEtaLow{-2.0}; float _thePtHigh{999.9}; float _thePtLow{-999.9}; float _thePHigh{999.9}; @@ -110,6 +117,8 @@ class HepMCParticleTrigger : public SubsysReco bool _doPzHighCut{false}; bool _doPzLowCut{false}; bool _doBothPzCut{false}; + + bool IsHadronPDG(int _pdg); }; #endif // HEPMCPARTICLETRIGGER_H From a41f4ee984f8f25b6fc344486ec87bde9f25aedf Mon Sep 17 00:00:00 2001 From: bkimelman <120117749+bkimelman@users.noreply.github.com> Date: Wed, 4 Mar 2026 19:18:58 -0600 Subject: [PATCH 354/866] JetCalib Constituents Propagate constituents from uncalibrated jet to calibrated one --- offline/packages/jetbase/JetCalib.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/jetbase/JetCalib.cc b/offline/packages/jetbase/JetCalib.cc index cc2fdd11b9..a6c9b8cf4d 100644 --- a/offline/packages/jetbase/JetCalib.cc +++ b/offline/packages/jetbase/JetCalib.cc @@ -244,6 +244,7 @@ int JetCalib::process_event(PHCompositeNode *topNode) calib_jet->set_py(calib_pt * std::sin(phi)); calib_jet->set_pz(calib_pt * std::sinh(eta)); calib_jet->set_id(ijet); + calib_jet->insert_comp(jet->get_comp_vec(), true); calib_jet->set_isCalib(1); ijet++; } From 645cbf251110d3f353145b3a18f0c6b5e1903c49 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 4 Mar 2026 20:45:54 -0500 Subject: [PATCH 355/866] revert ntuple contents to float --- offline/packages/tpc/Tpc3DClusterizer.cc | 2 +- offline/packages/tpc/TpcCombinedRawDataUnpacker.cc | 6 +++--- offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/offline/packages/tpc/Tpc3DClusterizer.cc b/offline/packages/tpc/Tpc3DClusterizer.cc index bdbfbb99e4..ac2add2c37 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.cc +++ b/offline/packages/tpc/Tpc3DClusterizer.cc @@ -657,7 +657,7 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi << std::endl; */ // if (m_output){ - double fX[20] = {0}; + float fX[20] = {0}; int n = 0; fX[n++] = m_event; fX[n++] = m_seed; diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc index 5abec18a2c..f5e436c6d7 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc @@ -449,7 +449,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) if (m_writeTree) { - double fXh[18]; + float fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -547,7 +547,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) if (m_writeTree) { - double fXh[11]; + float fXh[11]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -629,7 +629,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) if (m_writeTree) { - double fXh[18]; + float fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc index c7dfe58261..2e2cc693e6 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc @@ -278,7 +278,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) unsigned int phibin = layergeom->get_phibin(phi, side); if (m_writeTree) { - double fX[12]; + float fX[12]; int n = 0; fX[n++] = _ievent - 1; @@ -487,7 +487,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) } if (m_writeTree) { - double fXh[18]; + float fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; @@ -716,7 +716,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) #endif if (m_writeTree) { - double fXh[18]; + float fXh[18]; int nh = 0; fXh[nh++] = _ievent - 1; From 6ff05b1ff14050b9efdaf89d2e5cb9745498d26e Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Thu, 5 Mar 2026 00:21:33 -0500 Subject: [PATCH 356/866] Implement some coderabbit suggestions. --- .../KshortReconstruction.cc | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index f197a3172e..11f88aec21 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -361,14 +361,14 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float m double py1 = track1->get_py(); double pz1 = track1->get_pz(); auto *tpcSeed1 = track1->get_tpc_seed(); - size_t tpcClusters1 = tpcSeed1->size_cluster_keys(); + size_t tpcClusters1 = tpcSeed1 ? tpcSeed1->size_cluster_keys() : 0; double eta1 = asinh(pz1 / sqrt(pow(px1, 2) + pow(py1, 2))); double px2 = track2->get_px(); double py2 = track2->get_py(); double pz2 = track2->get_pz(); auto *tpcSeed2 = track2->get_tpc_seed(); - size_t tpcClusters2 = tpcSeed2->size_cluster_keys(); + size_t tpcClusters2 = tpcSeed2 ? tpcSeed2->size_cluster_keys() : 0; double eta2 = asinh(pz2 / sqrt(pow(px2, 2) + pow(py2, 2))); auto vtxid = track1->get_vertex_id(); @@ -391,8 +391,12 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float m float mag_pathLength_proj = sqrt(pow(pathLength_proj(0), 2) + pow(pathLength_proj(1), 2) + pow(pathLength_proj(2), 2)); Acts::Vector3 projected_momentum = projected_mom1 + projected_mom2; - float cos_theta_reco = pathLength_proj.dot(projected_momentum) / (projected_momentum.norm() * pathLength_proj.norm()); - + const double denom = projected_momentum.norm() * pathLength_proj.norm(); + float cos_theta_reco = 0.0; + if (denom > 1e-12) + { + cos_theta_reco = pathLength_proj.dot(projected_momentum) / denom; + } float reco_info[] = {(float) track1->get_id(), (float) mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), (float) mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; @@ -636,15 +640,21 @@ void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Act } // get the points at which the normal to the lines intersect the lines, where the lines are perpendicular - double X = b1.dot(b2) - (b1.dot(b1) * b2.dot(b2) / b2.dot(b1)); - double Y = (a2.dot(b2) - a1.dot(b2)) - ((a2.dot(b1) - a1.dot(b1)) * b2.dot(b2) / b2.dot(b1)); - double c = Y / X; - double F = b1.dot(b1) / b2.dot(b1); - double G = -(a2.dot(b1) - a1.dot(b1)) / b2.dot(b1); - double d = (c * F) + G; - - // then the points of closest approach are: + // coderabbit suggestion + const double b1b1 = b1.dot(b1); + const double b2b2 = b2.dot(b2); + const double b1b2 = b1.dot(b2); + const double denom = b1b1 * b2b2 - b1b2 * b1b2; + if (std::abs(denom) < 1e-12) + { + return; + } + const Eigen::Vector3d w0 = a1 - a2; + const double c = (b1b2 * b2.dot(w0) - b2b2 * b1.dot(w0)) / denom; + const double d = (b1b1 * b2.dot(w0) - b1b2 * b1.dot(w0)) / denom; + + // then the points of closest approach are: pca1 = a1 + c * b1; pca2 = a2 + d * b2; From 378a198b99318b47020589d44f3025747f8bb152 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Mar 2026 08:37:17 -0500 Subject: [PATCH 357/866] clang-tidy --- offline/packages/tpc/Tpc3DClusterizer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpc/Tpc3DClusterizer.cc b/offline/packages/tpc/Tpc3DClusterizer.cc index ac2add2c37..71a0b0f7c0 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.cc +++ b/offline/packages/tpc/Tpc3DClusterizer.cc @@ -571,7 +571,7 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi 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, (double) adc); + clus->setHitAdc(clus->getNhits() - 1, adc); rSum += r * adc; phiSum += phi * adc; From 629b41567d9b581bf03d6d680499b44c4a3c17fa Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 5 Mar 2026 12:42:40 -0500 Subject: [PATCH 358/866] implement dummy get_chi2ndf, get_fitinfo --- offline/packages/mbd/MbdRawHitV1.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/offline/packages/mbd/MbdRawHitV1.h b/offline/packages/mbd/MbdRawHitV1.h index ddb5e593e7..3b33d62e2c 100644 --- a/offline/packages/mbd/MbdRawHitV1.h +++ b/offline/packages/mbd/MbdRawHitV1.h @@ -39,6 +39,18 @@ class MbdRawHitV1 : public MbdRawHit bqtdc = tq; } + //! dummy method, only exists in V2 + void set_chi2ndf(const Double_t /*chi2ndf*/) override + { + return; + } + + //! dummy method, only exists in V2 + void set_fitinfo(const UShort_t /*fitinfo*/) override + { + return; + } + //! Prints out exact identity of object void identify(std::ostream& out = std::cout) const override; From 693abaada34bc4f97c293359f10ed1bd3e1a4bfa Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 5 Mar 2026 13:06:45 -0500 Subject: [PATCH 359/866] limit number of times virtual function spits out warning --- offline/packages/mbd/MbdRawHit.h | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/offline/packages/mbd/MbdRawHit.h b/offline/packages/mbd/MbdRawHit.h index 510a68b32f..862194352b 100644 --- a/offline/packages/mbd/MbdRawHit.h +++ b/offline/packages/mbd/MbdRawHit.h @@ -42,13 +42,23 @@ class MbdRawHit : public PHObject virtual Float_t get_chi2ndf() const { - PHOOL_VIRTUAL_WARNING; + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } return MbdReturnCodes::MBD_INVALID_FLOAT; } virtual UShort_t get_fitinfo() const { - PHOOL_VIRTUAL_WARNING; + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } return 0; } @@ -59,12 +69,22 @@ class MbdRawHit : public PHObject virtual void set_chi2ndf(const Double_t /*chi2ndf*/) { - PHOOL_VIRTUAL_WARNING; + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } } virtual void set_fitinfo(const UShort_t /*fitinfo*/) { - PHOOL_VIRTUAL_WARNING; + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } } virtual void identify(std::ostream& out = std::cout) const override; From d91092f3c993cc1c66d19589d517be8b8ae6c9b6 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 5 Mar 2026 14:45:39 -0500 Subject: [PATCH 360/866] remove finalize method --- .../trackbase/TGeoDetectorWithOptions.cc | 38 ------------------- .../trackbase/TGeoDetectorWithOptions.h | 5 --- 2 files changed, 43 deletions(-) diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.cc b/offline/packages/trackbase/TGeoDetectorWithOptions.cc index fdb81ac03d..6c0698cec7 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.cc +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.cc @@ -79,42 +79,4 @@ void TGeoDetectorWithOptions::addOptions( "Json file to dump empty config into."); } -auto TGeoDetectorWithOptions::finalize( - const boost::program_options::variables_map& vm, - std::shared_ptr mdecorator) - -> std::pair { - TGeoDetector::Config config; - - config.fileName = vm["geo-tgeo-filename"].as(); - - config.surfaceLogLevel = - Acts::Logging::Level(vm["geo-surface-loglevel"].template as()); - config.layerLogLevel = - Acts::Logging::Level(vm["geo-layer-loglevel"].template as()); - config.volumeLogLevel = - Acts::Logging::Level(vm["geo-volume-loglevel"].template as()); - - // No valid geometry configuration. Stop - if (vm["geo-tgeo-jsonconfig"].as().empty()) { - writeTGeoDetectorConfig(vm, config); - std::exit(EXIT_SUCCESS); - } - // Enable dump from full config - else if (!(vm["geo-tgeo-dump-jsonconfig"].as().compare( - "tgeo_empty_cofig.json") == 0)) { - readTGeoLayerBuilderConfigs(vm, config); - writeTGeoDetectorConfig(vm, config); - } else { - readTGeoLayerBuilderConfigs(vm, config); - } - - auto logger = Acts::getDefaultLogger("TGeoDetector", Acts::Logging::INFO); - ContextDecorators tgeoContextDecorators = {}; - std::vector> detectorStore; - TrackingGeometryPtr tgeoTrackingGeometry = ActsExamples::buildTGeoDetectorWrapper( - config, Acts::GeometryContext(), detectorStore, std::move(mdecorator), *logger); - - return {std::move(tgeoTrackingGeometry), std::move(tgeoContextDecorators)}; -} - } // namespace ActsExamples diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.h b/offline/packages/trackbase/TGeoDetectorWithOptions.h index fa93e10b62..af3358abdf 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.h +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.h @@ -14,11 +14,6 @@ class TGeoDetectorWithOptions : public IBaseDetector { void addOptions( boost::program_options::options_description& opt) const override; - - auto finalize(const boost::program_options::variables_map& vm, - std::shared_ptr mdecorator) - -> std::pair override; - }; } // namespace ActsExamples From e58e15fd49c8289f801ec62b13816c982a0487cf Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 6 Mar 2026 10:21:45 -0500 Subject: [PATCH 361/866] Remove finalize --- offline/packages/trackbase/IBaseDetector.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/offline/packages/trackbase/IBaseDetector.h b/offline/packages/trackbase/IBaseDetector.h index 527d565307..8f1f0f16d5 100644 --- a/offline/packages/trackbase/IBaseDetector.h +++ b/offline/packages/trackbase/IBaseDetector.h @@ -42,8 +42,5 @@ class IBaseDetector { virtual void addOptions( boost::program_options::options_description& opt) const = 0; - virtual std::pair finalize( - const boost::program_options::variables_map& vm, - std::shared_ptr mdecorator) = 0; }; } // namespace ActsExamples From a15f76e587f55a7d0a894ce80e9daa35a1a44a36 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Fri, 6 Mar 2026 10:49:05 -0500 Subject: [PATCH 362/866] Kshort and KFP updates --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 4 + .../KFParticle_truthAndDetTools.cc | 6 +- .../KshortReconstruction.cc | 158 +++++++++++++++--- .../KshortReconstruction.h | 31 +++- 4 files changed, 174 insertions(+), 25 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 7d48ed6b75..9bb76608ee 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1162,6 +1162,10 @@ float KFParticle_Tools::get_dEdx(PHCompositeNode *topNode, const KFParticle &dau { m_dst_trackmap = findNode::getClass(topNode, m_trk_map_node_name); m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + if (!m_cluster_map) + { + m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER_SEED"); + } m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); auto *geometry = findNode::getClass(topNode, "ActsGeometry"); if (!m_cluster_map || !m_geom_container || !geometry) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc index f8373c9e6f..14b353ff43 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc @@ -1299,7 +1299,11 @@ void KFParticle_truthAndDetTools::fillDetectorBranch(PHCompositeNode *topNode, dst_clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); if (!dst_clustermap) { - std::cout << "KFParticle detector info: TRKR_CLUSTER does not exist" << std::endl; + dst_clustermap = findNode::getClass(topNode, "TRKR_CLUSTER_SEED"); + if (!dst_clustermap) + { + std::cout << "KFParticle detector info: TRKR_CLUSTER does not exist" << std::endl; + } } track = getTrack(daughter.Id(), dst_trackmap); diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index 53afae2b1e..9d1e868aa7 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -24,6 +25,7 @@ #include #pragma GCC diagnostic pop +#include #include #include #include @@ -56,11 +58,57 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) m_runNumber = m_evtNumber = -1; } + //Truth matching setup. Setting IDs and getting nodes + if (m_truth_match) + { + if (m_used_string) + { + m_mother_id = getMotherPDG(); + } + + m_truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + + if (!m_truthinfo) //Missing truth info container. Disable truth matching + { + m_truth_match = false; + } + + } + + // Loop over tracks and check for close DCA match with all other tracks for (auto tr1_it = m_svtxTrackMap->begin(); tr1_it != m_svtxTrackMap->end(); ++tr1_it) { + auto id1 = tr1_it->first; auto *tr1 = tr1_it->second; + + //Truth matching. Let's see if this track came from the right mother + if (m_truth_match) + { + truth_particle_1 = getTruthTrack(tr1, topNode); + + if (truth_particle_1 == nullptr) + { + continue; + } + + int parent_id = truth_particle_1->get_parent_id(); + if (parent_id == 0) //Particle is primary. Trying to access its parent returns nullptr + { + continue; + } + + PHG4Particle *g4mother = m_truthinfo->GetParticle(parent_id); + + if (g4mother == nullptr || (abs(g4mother->get_pid()) != abs(m_mother_id))) //PID check + { + continue; + } + + truth_mother_id_particle_1 = g4mother->get_barcode(); + } + if (tr1->get_quality() > _qual_cut) { continue; @@ -134,6 +182,37 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) auto id2 = tr2_it->first; auto *tr2 = tr2_it->second; + //Truth matching. Let's see if this track came from the right mother + if (m_truth_match) + { + truth_particle_2 = getTruthTrack(tr2, topNode); + + if (truth_particle_2 == nullptr) + { + continue; + } + + int parent_id = truth_particle_2->get_parent_id(); + if (parent_id == 0) //Particle is primary. Trying to access its parent returns nullptr + { + continue; + } + PHG4Particle *g4mother = m_truthinfo->GetParticle(parent_id); + + if (g4mother == nullptr || (abs(g4mother->get_pid()) != abs(m_mother_id))) //PID check + { + continue; + } + + truth_mother_id_particle_2 = g4mother->get_barcode(); + + //Check that the two tracks came from the same mother + if (truth_mother_id_particle_1 != truth_mother_id_particle_2) + { + continue; + } + } + // dca xy and dca z cut here compare to track dca cut Acts::Vector3 pos2(tr2->get_x(), tr2->get_y(), tr2->get_z()); Acts::Vector3 mom2(tr2->get_px(), tr2->get_py(), tr2->get_pz()); @@ -361,14 +440,14 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float m double py1 = track1->get_py(); double pz1 = track1->get_pz(); auto *tpcSeed1 = track1->get_tpc_seed(); - size_t tpcClusters1 = tpcSeed1 ? tpcSeed1->size_cluster_keys() : 0; + size_t tpcClusters1 = tpcSeed1->size_cluster_keys(); double eta1 = asinh(pz1 / sqrt(pow(px1, 2) + pow(py1, 2))); double px2 = track2->get_px(); double py2 = track2->get_py(); double pz2 = track2->get_pz(); auto *tpcSeed2 = track2->get_tpc_seed(); - size_t tpcClusters2 = tpcSeed2 ? tpcSeed2->size_cluster_keys() : 0; + size_t tpcClusters2 = tpcSeed2->size_cluster_keys(); double eta2 = asinh(pz2 / sqrt(pow(px2, 2) + pow(py2, 2))); auto vtxid = track1->get_vertex_id(); @@ -391,14 +470,10 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float m float mag_pathLength_proj = sqrt(pow(pathLength_proj(0), 2) + pow(pathLength_proj(1), 2) + pow(pathLength_proj(2), 2)); Acts::Vector3 projected_momentum = projected_mom1 + projected_mom2; - const double denom = projected_momentum.norm() * pathLength_proj.norm(); - float cos_theta_reco = 0.0; - if (denom > 1e-12) - { - cos_theta_reco = pathLength_proj.dot(projected_momentum) / denom; - } + float cos_theta_reco = pathLength_proj.dot(projected_momentum) / (projected_momentum.norm() * pathLength_proj.norm()); + - float reco_info[] = {(float) track1->get_id(), mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; + float reco_info[] = {(float) track1->get_id(), (float) mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), (float) mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; ntp_reco_info->Fill(reco_info); } @@ -640,21 +715,15 @@ void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Act } // get the points at which the normal to the lines intersect the lines, where the lines are perpendicular + double X = b1.dot(b2) - (b1.dot(b1) * b2.dot(b2) / b2.dot(b1)); + double Y = (a2.dot(b2) - a1.dot(b2)) - ((a2.dot(b1) - a1.dot(b1)) * b2.dot(b2) / b2.dot(b1)); + double c = Y / X; - // coderabbit suggestion - const double b1b1 = b1.dot(b1); - const double b2b2 = b2.dot(b2); - const double b1b2 = b1.dot(b2); - const double denom = b1b1 * b2b2 - b1b2 * b1b2; - if (std::abs(denom) < 1e-12) - { - return; - } - const Eigen::Vector3d w0 = a1 - a2; - const double c = (b1b2 * b2.dot(w0) - b2b2 * b1.dot(w0)) / denom; - const double d = (b1b1 * b2.dot(w0) - b1b2 * b1.dot(w0)) / denom; - - // then the points of closest approach are: + double F = b1.dot(b1) / b2.dot(b1); + double G = -(a2.dot(b1) - a1.dot(b1)) / b2.dot(b1); + double d = (c * F) + G; + + // then the points of closest approach are: pca1 = a1 + c * b1; pca2 = a2 + d * b2; @@ -851,3 +920,46 @@ int KshortReconstruction::getNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } + +int KshortReconstruction::getMotherPDG() +{ + return TDatabasePDG::Instance()->GetParticle(m_mother_name.c_str())->PdgCode(); +} + +PHG4Particle *KshortReconstruction::getTruthTrack(SvtxTrack *thisTrack, PHCompositeNode *topNode) +{ + /* + * There are two methods for getting the truth rack from the reco track + * 1. (recommended) Use the reco -> truth tables (requires SvtxPHG4ParticleMap). Introduced Summer of 2022 + * 2. Get truth track via nClusters. Older method and will work with older DSTs + */ + + PHG4Particle *particle = nullptr; + + SvtxPHG4ParticleMap *dst_reco_truth_map = findNode::getClass(topNode, "SvtxPHG4ParticleMap"); + if (dst_reco_truth_map) + { + std::map> truth_set = dst_reco_truth_map->get(thisTrack->get_id()); + if (!truth_set.empty()) + { + std::pair> best_weight = *truth_set.rbegin(); + int best_truth_id = *best_weight.second.rbegin(); + particle = m_truthinfo->GetParticle(best_truth_id); + } + } + else + { + if (!m_svtx_evalstack) + { + m_svtx_evalstack = new SvtxEvalStack(topNode); + trackeval = m_svtx_evalstack->get_track_eval(); + //trutheval = m_svtx_evalstack->get_truth_eval(); + //vertexeval = m_svtx_evalstack->get_vertex_eval(); + } + + m_svtx_evalstack->next_event(topNode); + + particle = trackeval->max_truth_particle_by_nclusters(thisTrack); + } + return particle; +} diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.h b/offline/packages/TrackingDiagnostics/KshortReconstruction.h index 9499c9bab8..7eed20507c 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.h +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.h @@ -5,6 +5,11 @@ #include +#include +#include +#include +#include + #include class TFile; @@ -39,12 +44,17 @@ class KshortReconstruction : public SubsysReco void set_output_file(const std::string& outputfile) { filepath = outputfile; } void save_tracks(bool save = true) { m_save_tracks = save; } + //Truth matching code + void truthMatch(bool match = true) { m_truth_match = match; } + void setMotherID(std::string id = "K_S0") { m_mother_name = id; m_used_string = true; } + void setMotherID(int id = 310) { m_mother_id = id; m_used_string = false; } + private: void fillNtp(SvtxTrack* track1, SvtxTrack* track2, float mass1, float mass2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); // void fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); - void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymassa, float& decaymassb); + void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymass1, float& decaymass2); // void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity); @@ -83,6 +93,25 @@ class KshortReconstruction : public SubsysReco bool m_save_tracks {false}; SvtxTrackMap *m_output_trackMap {nullptr}; std::string m_output_trackMap_node_name {"KshortReconstruction_SvtxTrackMap"}; + + //Truth matching code + bool m_truth_match {false}; + bool m_used_string {false}; + std::string m_mother_name {"K_S0"}; + int m_mother_id {310}; + + PHG4Particle *truth_particle_1 {nullptr}; + PHG4Particle *truth_particle_2 {nullptr}; + int truth_mother_id_particle_1 {0}; + int truth_mother_id_particle_2 {0}; + + PHG4TruthInfoContainer *m_truthinfo {nullptr}; + SvtxEvalStack *m_svtx_evalstack {nullptr}; + SvtxTrackEval *trackeval {nullptr}; + + int getMotherPDG(); + PHG4Particle *getTruthTrack(SvtxTrack *thisTrack, PHCompositeNode *topNode); + }; #endif // KSHORTRECONSTRUCTION_H From add82a131d1c1ee8e459990658c6928a018cc877 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:16:17 -0400 Subject: [PATCH 363/866] Eventplaneinfo - order (int -> unsigned int) - Reduce the number of static_casts by changing the type of `order` from int to unsigned int - Improve readability --- .../packages/eventplaneinfo/Eventplaneinfo.h | 14 +++++------ .../eventplaneinfo/Eventplaneinfov1.h | 10 ++++---- .../eventplaneinfo/Eventplaneinfov2.h | 24 +++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/offline/packages/eventplaneinfo/Eventplaneinfo.h b/offline/packages/eventplaneinfo/Eventplaneinfo.h index c01756deca..04b085a393 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfo.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfo.h @@ -26,15 +26,15 @@ class Eventplaneinfo : public PHObject virtual void set_qvector_raw(const std::vector>& /*Qvec*/) { return; } virtual void set_qvector_recentered(const std::vector>& /*Qvec*/) { return; } virtual void set_shifted_psi(const std::vector& /*Psi_Shifted*/) { return; } - virtual std::pair get_qvector(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } - virtual std::pair get_qvector_raw(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } - virtual std::pair get_qvector_recentered(int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } - virtual double get_psi(int /*order*/) const { return std::numeric_limits::quiet_NaN(); } - virtual double get_shifted_psi(int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual std::pair get_qvector(unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual std::pair get_qvector_raw(unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual std::pair get_qvector_recentered(unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual double get_psi(unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual double get_shifted_psi(unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } virtual double GetPsi(const double /*Qx*/, const double /*Qy*/, const unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } virtual void set_ring_qvector(const std::vector>>& /*RingQvecs*/) { return; } - virtual std::pair get_ring_qvector(int /*rbin*/, int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } - virtual double get_ring_psi(int /*rbin*/, int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual std::pair get_ring_qvector(int /*rbin*/, unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual double get_ring_psi(int /*rbin*/, unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } protected: Eventplaneinfo() = default; diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov1.h b/offline/packages/eventplaneinfo/Eventplaneinfov1.h index 1950e2ef31..2b027323ea 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov1.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov1.h @@ -28,13 +28,13 @@ class Eventplaneinfov1 : public Eventplaneinfo void set_qvector(const std::vector>& Qvec) override { mQvec = Qvec; } void set_shifted_psi(const std::vector& Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } - std::pair get_qvector(int order) const override { return std::make_pair(mQvec[order - 1].first, mQvec[order - 1].second); } + std::pair get_qvector(unsigned int order) const override { return std::make_pair(mQvec[order - 1].first, mQvec[order - 1].second); } void set_ring_qvector(const std::vector>>& Qvec) override { ring_Qvec = Qvec; } - std::pair get_ring_qvector(int ring_index, int order) const override { return ring_Qvec[ring_index][order - 1]; } - double get_ring_psi(int ring_index, int order) const override {return GetPsi(ring_Qvec[ring_index][order - 1].first,ring_Qvec[ring_index][order - 1].second,order);} + std::pair get_ring_qvector(int ring_index, unsigned int order) const override { return ring_Qvec[ring_index][order - 1]; } + double get_ring_psi(int ring_index, unsigned int order) const override {return GetPsi(ring_Qvec[ring_index][order - 1].first,ring_Qvec[ring_index][order - 1].second,order);} double GetPsi(double Qx, double Qy, unsigned int order) const override; - double get_psi(int order) const override { return GetPsi(mQvec[order - 1].first, mQvec[order - 1].second, order);} - double get_shifted_psi(int order) const override { return mPsi_Shifted[order - 1]; } + double get_psi(unsigned int order) const override { return GetPsi(mQvec[order - 1].first, mQvec[order - 1].second, order);} + double get_shifted_psi(unsigned int order) const override { return mPsi_Shifted[order - 1]; } private: std::vector> mQvec; diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.h b/offline/packages/eventplaneinfo/Eventplaneinfov2.h index b6f5bf7793..5ad62fe979 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov2.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.h @@ -32,11 +32,11 @@ class Eventplaneinfov2 : public Eventplaneinfo void set_qvector_raw(const std::vector>& Qvec) override { mQvec_raw = Qvec; } void set_qvector_recentered(const std::vector>& Qvec) override { mQvec_recentered = Qvec; } void set_shifted_psi(const std::vector& Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } - std::pair get_qvector(int order) const override { return safe_qvec(mQvec, order); } - std::pair get_qvector_raw(int order) const override { return safe_qvec(mQvec_raw, order); } - std::pair get_qvector_recentered(int order) const override { return safe_qvec(mQvec_recentered, order); } + std::pair get_qvector(unsigned int order) const override { return safe_qvec(mQvec, order); } + std::pair get_qvector_raw(unsigned int order) const override { return safe_qvec(mQvec_raw, order); } + std::pair get_qvector_recentered(unsigned int order) const override { return safe_qvec(mQvec_recentered, order); } void set_ring_qvector(const std::vector>>& Qvec) override { ring_Qvec = Qvec; } - std::pair get_ring_qvector(int ring_index, int order) const override + std::pair get_ring_qvector(int ring_index, unsigned int order) const override { if (ring_index < 0 || static_cast(ring_index) >= ring_Qvec.size()) { @@ -44,21 +44,21 @@ class Eventplaneinfov2 : public Eventplaneinfo } return safe_qvec(ring_Qvec[ring_index], order); } - double get_ring_psi(int ring_index, int order) const override + double get_ring_psi(int ring_index, unsigned int order) const override { auto q = get_ring_qvector(ring_index, order); - return GetPsi(q.first, q.second, static_cast(order)); + return GetPsi(q.first, q.second, order); } double GetPsi(double Qx, double Qy, unsigned int order) const override; - double get_psi(int order) const override + double get_psi(unsigned int order) const override { auto q = get_qvector(order); - return GetPsi(q.first, q.second, static_cast(order)); + return GetPsi(q.first, q.second, order); } - double get_shifted_psi(int order) const override + double get_shifted_psi(unsigned int order) const override { - if (order <= 0 || static_cast(order) > mPsi_Shifted.size()) + if (order <= 0 || order > mPsi_Shifted.size()) { return std::numeric_limits::quiet_NaN(); } @@ -66,9 +66,9 @@ class Eventplaneinfov2 : public Eventplaneinfo } private: - static std::pair safe_qvec(const std::vector>& v, int order) + static std::pair safe_qvec(const std::vector>& v, unsigned int order) { - if (order <= 0 || static_cast(order) > v.size()) + if (order <= 0 || order > v.size()) { return {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; } From dee334d6eec96ab0102f7f66ffd0dbd402670220 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 9 Mar 2026 19:08:39 -0400 Subject: [PATCH 364/866] syncing mod works --- offline/packages/bcolumicount/BcoInfo.cc | 26 +++++ offline/packages/bcolumicount/BcoInfo.h | 44 +++++++ .../packages/bcolumicount/BcoInfoLinkDef.h | 5 + offline/packages/bcolumicount/BcoInfov1.cc | 25 ++++ offline/packages/bcolumicount/BcoInfov1.h | 48 ++++++++ .../packages/bcolumicount/BcoInfov1LinkDef.h | 5 + offline/packages/bcolumicount/BcoLumiReco.cc | 107 ++++++++++++++++++ offline/packages/bcolumicount/BcoLumiReco.h | 31 +++++ offline/packages/bcolumicount/Makefile.am | 80 +++++++++++++ offline/packages/bcolumicount/autogen.sh | 8 ++ offline/packages/bcolumicount/configure.ac | 20 ++++ 11 files changed, 399 insertions(+) create mode 100644 offline/packages/bcolumicount/BcoInfo.cc create mode 100644 offline/packages/bcolumicount/BcoInfo.h create mode 100644 offline/packages/bcolumicount/BcoInfoLinkDef.h create mode 100644 offline/packages/bcolumicount/BcoInfov1.cc create mode 100644 offline/packages/bcolumicount/BcoInfov1.h create mode 100644 offline/packages/bcolumicount/BcoInfov1LinkDef.h create mode 100644 offline/packages/bcolumicount/BcoLumiReco.cc create mode 100644 offline/packages/bcolumicount/BcoLumiReco.h create mode 100644 offline/packages/bcolumicount/Makefile.am create mode 100755 offline/packages/bcolumicount/autogen.sh create mode 100644 offline/packages/bcolumicount/configure.ac diff --git a/offline/packages/bcolumicount/BcoInfo.cc b/offline/packages/bcolumicount/BcoInfo.cc new file mode 100644 index 0000000000..f816401b49 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfo.cc @@ -0,0 +1,26 @@ +#include "BcoInfo.h" + +#include + +#include + +class PHObject; + +void BcoInfo::Reset() +{ + std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; + return; +} + +void BcoInfo::identify(std::ostream& os) const +{ + os << "identify yourself: virtual BcoInfo Object" << std::endl; + return; +} + +int BcoInfo::isValid() const +{ + std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; + return 0; +} + diff --git a/offline/packages/bcolumicount/BcoInfo.h b/offline/packages/bcolumicount/BcoInfo.h new file mode 100644 index 0000000000..be1b0bdbf3 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfo.h @@ -0,0 +1,44 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_BCOINFO_H +#define BCOLLUMICOUNT_BCOINFO_H + +#include + +#include +#include + +/// +class BcoInfo : public PHObject +{ + public: + /// ctor - daughter class copy ctor needs this + BcoInfo() = default; + /// dtor + ~BcoInfo() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + int isValid() const override; + + uint64_t get_previous_bco() const {return 0;} + uint64_t get_current_bco() const {return 0;} + uint64_t get_future_bco() const {return 0;} + + void set_previous_bco(uint64_t /*val*/) {return;} + void set_current_bco(uint64_t /*val*/) {return;} + void set_future_bco(uint64_t /*val*/) {return;} + + + private: + + ClassDefOverride(BcoInfo, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/BcoInfoLinkDef.h b/offline/packages/bcolumicount/BcoInfoLinkDef.h new file mode 100644 index 0000000000..54907ed5fe --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfoLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BcoInfo + ; + +#endif diff --git a/offline/packages/bcolumicount/BcoInfov1.cc b/offline/packages/bcolumicount/BcoInfov1.cc new file mode 100644 index 0000000000..1d0516f375 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfov1.cc @@ -0,0 +1,25 @@ +#include "BcoInfov1.h" + +void BcoInfov1::Reset() +{ + bco.fill(0); + return; +} + +void BcoInfov1::identify(std::ostream& out) const +{ + out << "identify yourself: I am an BcoInfov1 Object\n"; + out << std::hex; + out << "bco prev event: 0x" << get_previous_bco() << "\n" + << "bco curr event: 0x" << get_current_bco() << "\n" + << "bco futu event: 0x" << get_future_bco() + << std::dec + << std::endl; + + return; +} + +int BcoInfov1::isValid() const +{ + return (bco[2] ? 1 : 0); // return 1 if future bco is not zero +} diff --git a/offline/packages/bcolumicount/BcoInfov1.h b/offline/packages/bcolumicount/BcoInfov1.h new file mode 100644 index 0000000000..03308d0b38 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfov1.h @@ -0,0 +1,48 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLUMICOUNT_BCOINFOV1_H +#define BCOLUMICOUNT_BCOINFOV1_H + +#include "BcoInfo.h" + +#include +#include + +class PHObject; + +class BcoInfov1 : public BcoInfo +{ + public: + /// ctor + BcoInfov1() = default; + + /// dtor + ~BcoInfov1() override = default; + + /// Clear Event + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& out = std::cout) const override; + + /// isValid returns non zero if object contains valid data + int isValid() const override; + + uint64_t get_previous_bco() const {return bco[0];} + uint64_t get_current_bco() const {return bco[1];} + uint64_t get_future_bco() const {return bco[2];} + + void set_previous_bco(uint64_t val) {bco[0] = val;} + void set_current_bco(uint64_t val) {bco[1] = val;} + void set_future_bco(uint64_t val) {bco[2] = val;} + + + private: + std::array bco{0}; + + ClassDefOverride(BcoInfov1, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/BcoInfov1LinkDef.h b/offline/packages/bcolumicount/BcoInfov1LinkDef.h new file mode 100644 index 0000000000..41672f57b9 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfov1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BcoInfov1 + ; + +#endif diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc new file mode 100644 index 0000000000..fd9625bfd9 --- /dev/null +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -0,0 +1,107 @@ +#include "BcoLumiReco.h" + +#include +#include + +#include +#include +#include // for SubsysReco + +#include +#include +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include // for PHWHERE +#include + +#include +#include + +#include + +BcoLumiReco::BcoLumiReco(const std::string &name) + : SubsysReco(name) +{ + return; +} + +int BcoLumiReco::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + return iret; +} + +int BcoLumiReco::InitRun(PHCompositeNode */*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +int BcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int BcoLumiReco::process_event(PHCompositeNode *topNode) +{ + static bool ifirst = true; + if (ifirst) // abort first event + { + ifirst = false; + return Fun4AllReturnCodes::ABORTEVENT; + } +// Fun4AllServer *se = Fun4AllServer::instance(); + SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); + if (!synccopy) + { + synccopy = dynamic_cast (syncobject->CloneMe()); // clone for second event + tmpsync = dynamic_cast (synccopy->CloneMe()); // just to create this object + return Fun4AllReturnCodes::ABORTEVENT; // and abort + } + Event* evt = findNode::getClass(topNode,"PRDF"); + if (evt) + { + evt->identify(); + Packet *packet = evt->getPacket(14001); +uint64_t gtm_bco = packet->lValue(0, "BCO"); +push(gtm_bco); +delete packet; + } + std::cout << "current event is: " << syncobject->EventNumber() << "\n"; + std::cout << "saving as event: " << synccopy->EventNumber() << "\n"; + *tmpsync = *syncobject; // save current version + *syncobject = *synccopy; + *synccopy = *tmpsync; + if (Verbosity() > 100) + { + std::cout << "current sync object\n"; + syncobject->identify(); + std::cout << "next sync object\n"; + synccopy->identify(); + } + std::cout << std::hex; + std::cout << "previous bco: " << get_previous_bco() << "\n"; + std::cout << "current bco: " << get_current_bco() << "\n"; + std::cout << "future bco: " << get_future_bco() << std::endl; + std::cout << std::dec; + return Fun4AllReturnCodes::EVENT_OK; +} + +void BcoLumiReco::push(uint64_t value) +{ + bco[0] = bco[1]; + bco[1] = bco[2]; + bco[2] = value; +} + + diff --git a/offline/packages/bcolumicount/BcoLumiReco.h b/offline/packages/bcolumicount/BcoLumiReco.h new file mode 100644 index 0000000000..20763cc94f --- /dev/null +++ b/offline/packages/bcolumicount/BcoLumiReco.h @@ -0,0 +1,31 @@ +#ifndef BCOLUMICOUNT_BCOLUMIRECO_H +#define BCOLUMICOUNT_BCOLUMIRECO_H + +#include + +#include +#include + +class SyncObject; + +class BcoLumiReco : public SubsysReco +{ + public: + BcoLumiReco(const std::string &name = "BCOLUMIRECO"); + ~BcoLumiReco() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + void push(uint64_t value); + uint64_t get_previous_bco() {return bco[0];} + uint64_t get_current_bco() const {return bco[1];} + uint64_t get_future_bco() const {return bco[2];} + private: + static int CreateNodeTree(PHCompositeNode *topNode); + SyncObject *synccopy {nullptr}; + SyncObject *tmpsync {nullptr}; + std::array bco; +}; + +#endif // BCOLUMICOUNT_BCOLUMIRECO_H diff --git a/offline/packages/bcolumicount/Makefile.am b/offline/packages/bcolumicount/Makefile.am new file mode 100644 index 0000000000..a4d0391cdd --- /dev/null +++ b/offline/packages/bcolumicount/Makefile.am @@ -0,0 +1,80 @@ +AUTOMAKE_OPTIONS = foreign + +lib_LTLIBRARIES = \ + libbcolumicount_io.la \ + libbcolumicount.la + +AM_CPPFLAGS = \ + -I$(includedir) \ + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +libbcolumicount_io_la_LIBADD = \ + -lphool + +libbcolumicount_la_LIBADD = \ + libbcolumicount_io.la \ + -lfun4all \ + -lffaobjects \ + -lSubsysReco + +ROOTDICTS = \ + BcoInfo_Dict.cc \ + BcoInfov1_Dict.cc + +pcmdir = $(libdir) +# more elegant way to create pcm files (without listing them) +nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) + +pkginclude_HEADERS = \ + BcoInfo.h \ + BcoInfov1.h \ + BcoLumiReco.h + + +libbcolumicount_io_la_SOURCES = \ + $(ROOTDICTS) \ + BcoInfo.cc \ + BcoInfov1.cc + +libbcolumicount_la_SOURCES = \ + BcoLumiReco.cc + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals \ + testexternals_io + +testexternals_SOURCES = \ + testexternals.cc + +testexternals_LDADD = \ + libbcolumicount.la + +testexternals_io_SOURCES = \ + testexternals.cc + +testexternals_io_LDADD = \ + libbcolumicount_io.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +%_Dict.cc: %.h %LinkDef.h + rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ + +#just to get the dependency +%_Dict_rdict.pcm: %_Dict.cc ; + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/offline/packages/bcolumicount/autogen.sh b/offline/packages/bcolumicount/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/offline/packages/bcolumicount/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/offline/packages/bcolumicount/configure.ac b/offline/packages/bcolumicount/configure.ac new file mode 100644 index 0000000000..ea3c13cc92 --- /dev/null +++ b/offline/packages/bcolumicount/configure.ac @@ -0,0 +1,20 @@ +AC_INIT(bcolumicount,[1.0]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE + +LT_INIT([disable-static]) + +AC_PROG_CXX(CC g++) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra -Wshadow" +fi + +CINTDEFS=" -noIncludePaths -inlineInputHeader " +AC_SUBST(CINTDEFS) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT From 68be6e0eb33749bc204285a46ff05fc4329d4ea8 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Tue, 10 Mar 2026 08:31:31 -0400 Subject: [PATCH 365/866] CD: KshortReco CodeRabbit suggestions --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 7 ++++ .../HFTrackEfficiency/HFTrackEfficiency.h | 1 + .../KshortReconstruction.cc | 33 ++++++++++++++----- .../KshortReconstruction.h | 2 +- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 01975c66f4..1eddbed38d 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -38,6 +38,7 @@ #include #include + //____________________________________________________________________________.. HFTrackEfficiency::HFTrackEfficiency(const std::string &name) : SubsysReco(name) @@ -218,6 +219,8 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_primary_vtx_x = thisVtx->point3d().x(); m_primary_vtx_y = thisVtx->point3d().y(); m_primary_vtx_z = thisVtx->point3d().z(); + + if (m_primary_vtx_x == 0 && m_primary_vtx_y == 0 && m_primary_vtx_z == 0) m_is_primary = true; } for (unsigned int i = 1; i < decay.size(); ++i) @@ -290,6 +293,8 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) daughterG4->identify(); } + m_is_primary = m_truthInfo->is_sPHENIX_primary(motherG4); + CLHEP::Hep3Vector *mother3Vector = new CLHEP::Hep3Vector(motherG4->get_px(), motherG4->get_py(), motherG4->get_pz()); motherTrueLV->setVectM((*mother3Vector), getParticleMass(decay[0].second)); m_true_mother_pT = motherTrueLV->perp(); @@ -429,6 +434,7 @@ void HFTrackEfficiency::initializeBranches() m_tree->SetAutoSave(-5e6); // Save the output file every 5MB m_tree->Branch("all_tracks_reconstructed", &m_all_tracks_reconstructed, "all_tracks_reconstructed/O"); + m_tree->Branch("is_primary", &m_is_primary, "is_primary/O"); m_tree->Branch("true_mother_mass", &m_true_mother_mass, "true_mother_mass/F"); m_tree->Branch("reco_mother_mass", &m_reco_mother_mass, "reco_mother_mass/F"); m_tree->Branch("true_mother_pT", &m_true_mother_pT, "true_mother_pT/F"); @@ -465,6 +471,7 @@ void HFTrackEfficiency::initializeBranches() void HFTrackEfficiency::resetBranches() { m_all_tracks_reconstructed = false; + m_is_primary = false; m_true_mother_mass = std::numeric_limits::quiet_NaN(); m_reco_mother_mass = std::numeric_limits::quiet_NaN(); m_true_mother_pT = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h index ddd346c7a4..ce1ac40be3 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h @@ -89,6 +89,7 @@ class HFTrackEfficiency : public SubsysReco static const int m_maxTracks{5}; bool m_all_tracks_reconstructed{false}; + bool m_is_primary{false}; float m_true_mother_mass{std::numeric_limits::quiet_NaN()}; float m_reco_mother_mass{std::numeric_limits::quiet_NaN()}; float m_true_mother_pT{std::numeric_limits::quiet_NaN()}; diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index 9d1e868aa7..cb344e7851 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -715,15 +715,21 @@ void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Act } // get the points at which the normal to the lines intersect the lines, where the lines are perpendicular - double X = b1.dot(b2) - (b1.dot(b1) * b2.dot(b2) / b2.dot(b1)); - double Y = (a2.dot(b2) - a1.dot(b2)) - ((a2.dot(b1) - a1.dot(b1)) * b2.dot(b2) / b2.dot(b1)); - double c = Y / X; - double F = b1.dot(b1) / b2.dot(b1); - double G = -(a2.dot(b1) - a1.dot(b1)) / b2.dot(b1); - double d = (c * F) + G; + // coderabbit suggestion + const double b1b1 = b1.dot(b1); + const double b2b2 = b2.dot(b2); + const double b1b2 = b1.dot(b2); + const double denom = b1b1 * b2b2 - b1b2 * b1b2; + if (std::abs(denom) < 1e-12) + { + return; + } + const Eigen::Vector3d w0 = a1 - a2; + const double c = (b1b2 * b2.dot(w0) - b2b2 * b1.dot(w0)) / denom; + const double d = (b1b1 * b2.dot(w0) - b1b2 * b1.dot(w0)) / denom; - // then the points of closest approach are: + // then the points of closest approach are: pca1 = a1 + c * b1; pca2 = a2 + d * b2; @@ -923,7 +929,16 @@ int KshortReconstruction::getNodes(PHCompositeNode* topNode) int KshortReconstruction::getMotherPDG() { - return TDatabasePDG::Instance()->GetParticle(m_mother_name.c_str())->PdgCode(); + TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(m_mother_name.c_str()); + if (!particle) + { + if (Verbosity() > 2) + { + std::cout << "Error: Unknown particle name '" << m_mother_name << "'" << std::endl; + } + return -1; // or throw exception + } + return particle->PdgCode(); } PHG4Particle *KshortReconstruction::getTruthTrack(SvtxTrack *thisTrack, PHCompositeNode *topNode) @@ -937,7 +952,7 @@ PHG4Particle *KshortReconstruction::getTruthTrack(SvtxTrack *thisTrack, PHCompos PHG4Particle *particle = nullptr; SvtxPHG4ParticleMap *dst_reco_truth_map = findNode::getClass(topNode, "SvtxPHG4ParticleMap"); - if (dst_reco_truth_map) + if (dst_reco_truth_map && dst_reco_truth_map->processed()) { std::map> truth_set = dst_reco_truth_map->get(thisTrack->get_id()); if (!truth_set.empty()) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.h b/offline/packages/TrackingDiagnostics/KshortReconstruction.h index 7eed20507c..16ce14aca3 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.h +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.h @@ -46,7 +46,7 @@ class KshortReconstruction : public SubsysReco //Truth matching code void truthMatch(bool match = true) { m_truth_match = match; } - void setMotherID(std::string id = "K_S0") { m_mother_name = id; m_used_string = true; } + void setMotherID(const std::string id = "K_S0") { m_mother_name = id; m_used_string = true; } void setMotherID(int id = 310) { m_mother_id = id; m_used_string = false; } private: From b0fe3635d480da680bee769b9fa0512837db4ae3 Mon Sep 17 00:00:00 2001 From: Cameron Dean <59485912+cdean-github@users.noreply.github.com> Date: Tue, 10 Mar 2026 08:40:06 -0400 Subject: [PATCH 366/866] Update offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 1eddbed38d..1f503dcc01 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -219,8 +219,13 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_primary_vtx_x = thisVtx->point3d().x(); m_primary_vtx_y = thisVtx->point3d().y(); m_primary_vtx_z = thisVtx->point3d().z(); - - if (m_primary_vtx_x == 0 && m_primary_vtx_y == 0 && m_primary_vtx_z == 0) m_is_primary = true; + constexpr float epsilon = 1e-6f; + if (std::abs(m_primary_vtx_x) < epsilon && + std::abs(m_primary_vtx_y) < epsilon && + std::abs(m_primary_vtx_z) < epsilon) + { + m_is_primary = true; + } } for (unsigned int i = 1; i < decay.size(); ++i) From b401831b8e19877c1940cfed299c41fc0507f3ca Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 10 Mar 2026 08:54:57 -0400 Subject: [PATCH 367/866] revert IO object to float --- offline/packages/tpc/LaserEventInfo.h | 4 ++-- offline/packages/tpc/LaserEventInfov1.cc | 2 +- offline/packages/tpc/LaserEventInfov1.h | 6 +++--- offline/packages/tpc/LaserEventInfov2.cc | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/offline/packages/tpc/LaserEventInfo.h b/offline/packages/tpc/LaserEventInfo.h index 5379862549..48e5379b70 100644 --- a/offline/packages/tpc/LaserEventInfo.h +++ b/offline/packages/tpc/LaserEventInfo.h @@ -32,8 +32,8 @@ class LaserEventInfo : public PHObject virtual int getPeakSample(const bool /*side*/) const { return std::numeric_limits::max(); } virtual void setPeakSample(const bool /*side*/, const int /*sample*/) {} - virtual double getPeakWidth(const bool /*side*/) const { return std::numeric_limits::quiet_NaN(); } - virtual void setPeakWidth(const bool /*side*/, const double /*width*/) {} + virtual float getPeakWidth(const bool /*side*/) const { return std::numeric_limits::quiet_NaN(); } + virtual void setPeakWidth(const bool /*side*/, const float /*width*/) {} protected: LaserEventInfo() = default; diff --git a/offline/packages/tpc/LaserEventInfov1.cc b/offline/packages/tpc/LaserEventInfov1.cc index 9e68e0baba..448cbb7e2b 100644 --- a/offline/packages/tpc/LaserEventInfov1.cc +++ b/offline/packages/tpc/LaserEventInfov1.cc @@ -20,7 +20,7 @@ void LaserEventInfov1::Reset() for (int i = 0; i < 2; i++) { m_peakSample[i] = std::numeric_limits::max(); - m_peakWidth[i] = std::numeric_limits::quiet_NaN(); + m_peakWidth[i] = std::numeric_limits::quiet_NaN(); } return; diff --git a/offline/packages/tpc/LaserEventInfov1.h b/offline/packages/tpc/LaserEventInfov1.h index e032736b01..7497fdd780 100644 --- a/offline/packages/tpc/LaserEventInfov1.h +++ b/offline/packages/tpc/LaserEventInfov1.h @@ -23,14 +23,14 @@ class LaserEventInfov1 : public LaserEventInfo int getPeakSample(const bool side) const override { return m_peakSample[side]; } void setPeakSample(const bool side, const int sample) override { m_peakSample[side] = sample; } - double getPeakWidth(const bool side) const override { return m_peakWidth[side]; } - void setPeakWidth(const bool side, const double width) override { m_peakWidth[side] = width; } + float getPeakWidth(const bool side) const override { return m_peakWidth[side]; } + void setPeakWidth(const bool side, const float width) override { m_peakWidth[side] = width; } protected: bool m_isLaserEvent{false}; int m_peakSample[2] = {std::numeric_limits::max(), std::numeric_limits::max()}; - double m_peakWidth[2] = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + float m_peakWidth[2] = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; ClassDefOverride(LaserEventInfov1, 1); }; diff --git a/offline/packages/tpc/LaserEventInfov2.cc b/offline/packages/tpc/LaserEventInfov2.cc index ae40a14c62..c5f2ab60f4 100644 --- a/offline/packages/tpc/LaserEventInfov2.cc +++ b/offline/packages/tpc/LaserEventInfov2.cc @@ -24,7 +24,7 @@ void LaserEventInfov2::Reset() for (int i = 0; i < 2; i++) { m_peakSample[i] = std::numeric_limits::max(); - m_peakWidth[i] = std::numeric_limits::quiet_NaN(); + m_peakWidth[i] = std::numeric_limits::quiet_NaN(); } return; From f73307c2e4ae9abf0a511a40bebbb46d9570348d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 10 Mar 2026 14:32:09 -0400 Subject: [PATCH 368/866] bcolumicount functional --- offline/packages/bcolumicount/BcoInfo.h | 12 +-- offline/packages/bcolumicount/BcoInfov1.cc | 8 +- offline/packages/bcolumicount/BcoInfov1.h | 12 +-- offline/packages/bcolumicount/BcoLumiCheck.cc | 76 +++++++++++++++++++ offline/packages/bcolumicount/BcoLumiCheck.h | 24 ++++++ offline/packages/bcolumicount/BcoLumiReco.cc | 39 +++++++--- offline/packages/bcolumicount/BcoLumiReco.h | 2 +- offline/packages/bcolumicount/Makefile.am | 3 + 8 files changed, 150 insertions(+), 26 deletions(-) create mode 100644 offline/packages/bcolumicount/BcoLumiCheck.cc create mode 100644 offline/packages/bcolumicount/BcoLumiCheck.h diff --git a/offline/packages/bcolumicount/BcoInfo.h b/offline/packages/bcolumicount/BcoInfo.h index be1b0bdbf3..f7abf37893 100644 --- a/offline/packages/bcolumicount/BcoInfo.h +++ b/offline/packages/bcolumicount/BcoInfo.h @@ -27,13 +27,13 @@ class BcoInfo : public PHObject /// isValid returns non zero if object contains valid data int isValid() const override; - uint64_t get_previous_bco() const {return 0;} - uint64_t get_current_bco() const {return 0;} - uint64_t get_future_bco() const {return 0;} + virtual uint64_t get_previous_bco() const {return 0;} + virtual uint64_t get_current_bco() const {return 0;} + virtual uint64_t get_future_bco() const {return 0;} - void set_previous_bco(uint64_t /*val*/) {return;} - void set_current_bco(uint64_t /*val*/) {return;} - void set_future_bco(uint64_t /*val*/) {return;} + virtual void set_previous_bco(uint64_t /*val*/) {return;} + virtual void set_current_bco(uint64_t /*val*/) {return;} + virtual void set_future_bco(uint64_t /*val*/) {return;} private: diff --git a/offline/packages/bcolumicount/BcoInfov1.cc b/offline/packages/bcolumicount/BcoInfov1.cc index 1d0516f375..2533d03155 100644 --- a/offline/packages/bcolumicount/BcoInfov1.cc +++ b/offline/packages/bcolumicount/BcoInfov1.cc @@ -10,9 +10,9 @@ void BcoInfov1::identify(std::ostream& out) const { out << "identify yourself: I am an BcoInfov1 Object\n"; out << std::hex; - out << "bco prev event: 0x" << get_previous_bco() << "\n" - << "bco curr event: 0x" << get_current_bco() << "\n" - << "bco futu event: 0x" << get_future_bco() + out << "bco previous event: 0x" << get_previous_bco() << "\n" + << "bco current event: 0x" << get_current_bco() << "\n" + << "bco future event: 0x" << get_future_bco() << std::dec << std::endl; @@ -23,3 +23,5 @@ int BcoInfov1::isValid() const { return (bco[2] ? 1 : 0); // return 1 if future bco is not zero } + + diff --git a/offline/packages/bcolumicount/BcoInfov1.h b/offline/packages/bcolumicount/BcoInfov1.h index 03308d0b38..645461c279 100644 --- a/offline/packages/bcolumicount/BcoInfov1.h +++ b/offline/packages/bcolumicount/BcoInfov1.h @@ -30,13 +30,13 @@ class BcoInfov1 : public BcoInfo /// isValid returns non zero if object contains valid data int isValid() const override; - uint64_t get_previous_bco() const {return bco[0];} - uint64_t get_current_bco() const {return bco[1];} - uint64_t get_future_bco() const {return bco[2];} + uint64_t get_previous_bco() const override {return bco[0];} + uint64_t get_current_bco() const override {return bco[1];} + uint64_t get_future_bco() const override {return bco[2];} - void set_previous_bco(uint64_t val) {bco[0] = val;} - void set_current_bco(uint64_t val) {bco[1] = val;} - void set_future_bco(uint64_t val) {bco[2] = val;} + void set_previous_bco(uint64_t val) override {bco[0] = val;} + void set_current_bco(uint64_t val) override {bco[1] = val;} + void set_future_bco(uint64_t val) override {bco[2] = val;} private: diff --git a/offline/packages/bcolumicount/BcoLumiCheck.cc b/offline/packages/bcolumicount/BcoLumiCheck.cc new file mode 100644 index 0000000000..c0a632b266 --- /dev/null +++ b/offline/packages/bcolumicount/BcoLumiCheck.cc @@ -0,0 +1,76 @@ +#include "BcoLumiCheck.h" + +#include "BcoInfov1.h" + +#include +#include + +#include + +#include +#include +#include // for SubsysReco + +#include +#include +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include // for PHWHERE +#include + +#include +#include + +#include + +BcoLumiCheck::BcoLumiCheck(const std::string &name) + : SubsysReco(name) +{ + return; +} + +int BcoLumiCheck::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + return iret; +} + +int BcoLumiCheck::InitRun(PHCompositeNode */*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +int BcoLumiCheck::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int BcoLumiCheck::process_event(PHCompositeNode *topNode) +{ + BcoInfo *bcoinfo = findNode::getClass(topNode,"BCOINFO"); + SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); + Gl1Packet *gl1packet = findNode::getClass(topNode, 14001); + if (gl1packet) + { + std::cout << "Event No: " << syncobject->EventNumber() << std::endl; +std::cout << std::hex << "gl1: bco 0x" << gl1packet->lValue(0, "BCO") << std::endl; + if (bcoinfo) + { + std::cout << "prev bco: 0x" << bcoinfo->get_previous_bco() << std::endl; + std::cout << "curr bco: 0x" << bcoinfo->get_current_bco() << std::endl; + std::cout << "futu bco: 0x" << bcoinfo->get_future_bco() << std::endl; + } + std::cout << std::dec; + } + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/bcolumicount/BcoLumiCheck.h b/offline/packages/bcolumicount/BcoLumiCheck.h new file mode 100644 index 0000000000..07a08cb4cc --- /dev/null +++ b/offline/packages/bcolumicount/BcoLumiCheck.h @@ -0,0 +1,24 @@ +#ifndef BCOLUMICOUNT_BCOLUMICHECK_H +#define BCOLUMICOUNT_BCOLUMICHECK_H + +#include + +#include +#include + +class SyncObject; + +class BcoLumiCheck : public SubsysReco +{ + public: + BcoLumiCheck(const std::string &name = "BCOLUMICHECK"); + ~BcoLumiCheck() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + private: + static int CreateNodeTree(PHCompositeNode *topNode); +}; + +#endif // BCOLUMICOUNT_BCOLUMICHECK_H diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc index fd9625bfd9..a5d3db7dd4 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.cc +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -1,5 +1,7 @@ #include "BcoLumiReco.h" +#include "BcoInfov1.h" + #include #include @@ -48,13 +50,34 @@ int BcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + BcoInfo *bcoinfo = findNode::getClass(topNode,"BCOINFO"); + if (!bcoinfo) + { + bcoinfo = new BcoInfov1(); + PHIODataNode *newnode = new PHIODataNode(bcoinfo,"BCOINFO","PHObject"); + dstNode->addNode(newnode); + } return Fun4AllReturnCodes::EVENT_OK; } int BcoLumiReco::process_event(PHCompositeNode *topNode) { static bool ifirst = true; + Event* evt = findNode::getClass(topNode,"PRDF"); + if (evt) + { + evt->identify(); + if (evt->getEvtType() != DATAEVENT) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + Packet *packet = evt->getPacket(14001); + uint64_t gtm_bco = packet->lValue(0, "BCO"); + std::cout << std::hex << "packet ival: 0x" << packet->lValue(0, "BCO") + << " uint64_t: 0x" << gtm_bco << std::dec << std::endl; + push(gtm_bco); + delete packet; + } if (ifirst) // abort first event { ifirst = false; @@ -68,15 +91,8 @@ int BcoLumiReco::process_event(PHCompositeNode *topNode) tmpsync = dynamic_cast (synccopy->CloneMe()); // just to create this object return Fun4AllReturnCodes::ABORTEVENT; // and abort } - Event* evt = findNode::getClass(topNode,"PRDF"); - if (evt) - { - evt->identify(); - Packet *packet = evt->getPacket(14001); -uint64_t gtm_bco = packet->lValue(0, "BCO"); -push(gtm_bco); -delete packet; - } + BcoInfo *bcoinfo = findNode::getClass(topNode,"BCOINFO"); + std::cout << "current event is: " << syncobject->EventNumber() << "\n"; std::cout << "saving as event: " << synccopy->EventNumber() << "\n"; *tmpsync = *syncobject; // save current version @@ -94,6 +110,9 @@ delete packet; std::cout << "current bco: " << get_current_bco() << "\n"; std::cout << "future bco: " << get_future_bco() << std::endl; std::cout << std::dec; + bcoinfo->set_previous_bco(get_previous_bco()); + bcoinfo->set_current_bco(get_current_bco()); + bcoinfo->set_future_bco(get_future_bco()); return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/bcolumicount/BcoLumiReco.h b/offline/packages/bcolumicount/BcoLumiReco.h index 20763cc94f..1a21df9a1c 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.h +++ b/offline/packages/bcolumicount/BcoLumiReco.h @@ -25,7 +25,7 @@ class BcoLumiReco : public SubsysReco static int CreateNodeTree(PHCompositeNode *topNode); SyncObject *synccopy {nullptr}; SyncObject *tmpsync {nullptr}; - std::array bco; + std::array bco {0}; }; #endif // BCOLUMICOUNT_BCOLUMIRECO_H diff --git a/offline/packages/bcolumicount/Makefile.am b/offline/packages/bcolumicount/Makefile.am index a4d0391cdd..3833324d98 100644 --- a/offline/packages/bcolumicount/Makefile.am +++ b/offline/packages/bcolumicount/Makefile.am @@ -21,6 +21,7 @@ libbcolumicount_la_LIBADD = \ libbcolumicount_io.la \ -lfun4all \ -lffaobjects \ + -lffarawobjects \ -lSubsysReco ROOTDICTS = \ @@ -34,6 +35,7 @@ nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) pkginclude_HEADERS = \ BcoInfo.h \ BcoInfov1.h \ + BcoLumiCheck.h \ BcoLumiReco.h @@ -43,6 +45,7 @@ libbcolumicount_io_la_SOURCES = \ BcoInfov1.cc libbcolumicount_la_SOURCES = \ + BcoLumiCheck.cc \ BcoLumiReco.cc BUILT_SOURCES = testexternals.cc From ac9de81b3227ce081239dc062d0353839e800e93 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 10 Mar 2026 14:54:48 -0400 Subject: [PATCH 369/866] add event number to bco info --- offline/packages/bcolumicount/BcoInfo.cc | 1 - offline/packages/bcolumicount/BcoInfo.h | 20 +++-- offline/packages/bcolumicount/BcoInfov1.cc | 14 +-- offline/packages/bcolumicount/BcoInfov1.h | 22 +++-- offline/packages/bcolumicount/BcoLumiCheck.cc | 18 ++-- offline/packages/bcolumicount/BcoLumiCheck.h | 3 +- offline/packages/bcolumicount/BcoLumiReco.cc | 89 ++++++++++--------- offline/packages/bcolumicount/BcoLumiReco.h | 25 ++++-- 8 files changed, 113 insertions(+), 79 deletions(-) diff --git a/offline/packages/bcolumicount/BcoInfo.cc b/offline/packages/bcolumicount/BcoInfo.cc index f816401b49..d775db903f 100644 --- a/offline/packages/bcolumicount/BcoInfo.cc +++ b/offline/packages/bcolumicount/BcoInfo.cc @@ -23,4 +23,3 @@ int BcoInfo::isValid() const std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; return 0; } - diff --git a/offline/packages/bcolumicount/BcoInfo.h b/offline/packages/bcolumicount/BcoInfo.h index f7abf37893..46548d48f4 100644 --- a/offline/packages/bcolumicount/BcoInfo.h +++ b/offline/packages/bcolumicount/BcoInfo.h @@ -27,17 +27,23 @@ class BcoInfo : public PHObject /// isValid returns non zero if object contains valid data int isValid() const override; - virtual uint64_t get_previous_bco() const {return 0;} - virtual uint64_t get_current_bco() const {return 0;} - virtual uint64_t get_future_bco() const {return 0;} + virtual uint64_t get_previous_bco() const { return 0; } + virtual uint64_t get_current_bco() const { return 0; } + virtual uint64_t get_future_bco() const { return 0; } - virtual void set_previous_bco(uint64_t /*val*/) {return;} - virtual void set_current_bco(uint64_t /*val*/) {return;} - virtual void set_future_bco(uint64_t /*val*/) {return;} + virtual void set_previous_bco(uint64_t /*val*/) { return; } + virtual void set_current_bco(uint64_t /*val*/) { return; } + virtual void set_future_bco(uint64_t /*val*/) { return; } + virtual int get_previous_evtno() const { return 0; } + virtual int get_current_evtno() const { return 0; } + virtual int get_future_evtno() const { return 0; } - private: + virtual void set_previous_evtno(int /*val*/) { return; } + virtual void set_current_evtno(int /*val*/) { return; } + virtual void set_future_evtno(int /*val*/) { return; } + private: ClassDefOverride(BcoInfo, 1) }; diff --git a/offline/packages/bcolumicount/BcoInfov1.cc b/offline/packages/bcolumicount/BcoInfov1.cc index 2533d03155..d8e5bbf656 100644 --- a/offline/packages/bcolumicount/BcoInfov1.cc +++ b/offline/packages/bcolumicount/BcoInfov1.cc @@ -10,11 +10,15 @@ void BcoInfov1::identify(std::ostream& out) const { out << "identify yourself: I am an BcoInfov1 Object\n"; out << std::hex; - out << "bco previous event: 0x" << get_previous_bco() << "\n" - << "bco current event: 0x" << get_current_bco() << "\n" - << "bco future event: 0x" << get_future_bco() + out << "previous event: " << get_previous_evtno() << std::hex + << " bco: 0x" << get_previous_bco() << "\n" << std::dec - << std::endl; + << "current event: " << get_current_evtno() << std::hex + << " bco: 0x" << get_current_bco() << "\n" + << std::dec + << "future event: " << get_future_evtno() << std::hex + << " bco: 0x" << get_future_bco() << std::dec + << std::endl; return; } @@ -23,5 +27,3 @@ int BcoInfov1::isValid() const { return (bco[2] ? 1 : 0); // return 1 if future bco is not zero } - - diff --git a/offline/packages/bcolumicount/BcoInfov1.h b/offline/packages/bcolumicount/BcoInfov1.h index 645461c279..5f5a9a7252 100644 --- a/offline/packages/bcolumicount/BcoInfov1.h +++ b/offline/packages/bcolumicount/BcoInfov1.h @@ -30,17 +30,25 @@ class BcoInfov1 : public BcoInfo /// isValid returns non zero if object contains valid data int isValid() const override; - uint64_t get_previous_bco() const override {return bco[0];} - uint64_t get_current_bco() const override {return bco[1];} - uint64_t get_future_bco() const override {return bco[2];} + uint64_t get_previous_bco() const override { return bco[0]; } + uint64_t get_current_bco() const override { return bco[1]; } + uint64_t get_future_bco() const override { return bco[2]; } - void set_previous_bco(uint64_t val) override {bco[0] = val;} - void set_current_bco(uint64_t val) override {bco[1] = val;} - void set_future_bco(uint64_t val) override {bco[2] = val;} + void set_previous_bco(uint64_t val) override { bco[0] = val; } + void set_current_bco(uint64_t val) override { bco[1] = val; } + void set_future_bco(uint64_t val) override { bco[2] = val; } + int get_previous_evtno() const override { return evtno[0]; } + int get_current_evtno() const override { return evtno[1]; } + int get_future_evtno() const override { return evtno[2]; } + + void set_previous_evtno(int val) override { evtno[0] = val; } + void set_current_evtno(int val) override { evtno[1] = val; } + void set_future_evtno(int val) override { evtno[2] = val; } private: - std::array bco{0}; + std::array bco{0}; + std::array evtno{0}; ClassDefOverride(BcoInfov1, 1) }; diff --git a/offline/packages/bcolumicount/BcoLumiCheck.cc b/offline/packages/bcolumicount/BcoLumiCheck.cc index c0a632b266..f2b4a9d9b6 100644 --- a/offline/packages/bcolumicount/BcoLumiCheck.cc +++ b/offline/packages/bcolumicount/BcoLumiCheck.cc @@ -37,7 +37,7 @@ int BcoLumiCheck::Init(PHCompositeNode *topNode) return iret; } -int BcoLumiCheck::InitRun(PHCompositeNode */*topNode*/) +int BcoLumiCheck::InitRun(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; } @@ -57,20 +57,22 @@ int BcoLumiCheck::CreateNodeTree(PHCompositeNode *topNode) int BcoLumiCheck::process_event(PHCompositeNode *topNode) { - BcoInfo *bcoinfo = findNode::getClass(topNode,"BCOINFO"); + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); Gl1Packet *gl1packet = findNode::getClass(topNode, 14001); if (gl1packet) { - std::cout << "Event No: " << syncobject->EventNumber() << std::endl; -std::cout << std::hex << "gl1: bco 0x" << gl1packet->lValue(0, "BCO") << std::endl; + std::cout << "Event No: " << syncobject->EventNumber() << std::hex + << " gl1: bco 0x" << gl1packet->lValue(0, "BCO") << std::dec << std::endl; if (bcoinfo) { - std::cout << "prev bco: 0x" << bcoinfo->get_previous_bco() << std::endl; - std::cout << "curr bco: 0x" << bcoinfo->get_current_bco() << std::endl; - std::cout << "futu bco: 0x" << bcoinfo->get_future_bco() << std::endl; + std::cout << "prev event: " << bcoinfo->get_previous_evtno() << std::hex + << " bco: 0x" << bcoinfo->get_previous_bco() << std::dec << std::endl; + std::cout << "curr event: " << bcoinfo->get_current_evtno() << std::hex + << " bco: 0x" << bcoinfo->get_current_bco() << std::dec << std::endl; + std::cout << "futu event: " << bcoinfo->get_future_evtno() << std::hex + << " bco: 0x" << bcoinfo->get_future_bco() << std::dec << std::endl; } - std::cout << std::dec; } return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/bcolumicount/BcoLumiCheck.h b/offline/packages/bcolumicount/BcoLumiCheck.h index 07a08cb4cc..89fd0ae306 100644 --- a/offline/packages/bcolumicount/BcoLumiCheck.h +++ b/offline/packages/bcolumicount/BcoLumiCheck.h @@ -17,8 +17,9 @@ class BcoLumiCheck : public SubsysReco int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; + private: static int CreateNodeTree(PHCompositeNode *topNode); }; -#endif // BCOLUMICOUNT_BCOLUMICHECK_H +#endif // BCOLUMICOUNT_BCOLUMICHECK_H diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc index a5d3db7dd4..5d6cfc2d65 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.cc +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -35,11 +35,6 @@ int BcoLumiReco::Init(PHCompositeNode *topNode) return iret; } -int BcoLumiReco::InitRun(PHCompositeNode */*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - int BcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); @@ -50,11 +45,11 @@ int BcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - BcoInfo *bcoinfo = findNode::getClass(topNode,"BCOINFO"); + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); if (!bcoinfo) { bcoinfo = new BcoInfov1(); - PHIODataNode *newnode = new PHIODataNode(bcoinfo,"BCOINFO","PHObject"); + PHIODataNode *newnode = new PHIODataNode(bcoinfo, "BCOINFO", "PHObject"); dstNode->addNode(newnode); } return Fun4AllReturnCodes::EVENT_OK; @@ -63,7 +58,8 @@ int BcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) int BcoLumiReco::process_event(PHCompositeNode *topNode) { static bool ifirst = true; - Event* evt = findNode::getClass(topNode,"PRDF"); + SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); + Event *evt = findNode::getClass(topNode, "PRDF"); if (evt) { evt->identify(); @@ -73,54 +69,67 @@ int BcoLumiReco::process_event(PHCompositeNode *topNode) } Packet *packet = evt->getPacket(14001); uint64_t gtm_bco = packet->lValue(0, "BCO"); - std::cout << std::hex << "packet ival: 0x" << packet->lValue(0, "BCO") - << " uint64_t: 0x" << gtm_bco << std::dec << std::endl; - push(gtm_bco); + if (Verbosity() > 1) + { + std::cout << std::hex << "packet ival: 0x" << packet->lValue(0, "BCO") + << " uint64_t: 0x" << gtm_bco << std::dec << std::endl; + } + push_bco(gtm_bco); delete packet; } - if (ifirst) // abort first event + if (syncobject) + { + push_evtno(syncobject->EventNumber()); + } + if (ifirst) // abort first event since it does not have a previous bco { ifirst = false; return Fun4AllReturnCodes::ABORTEVENT; - } -// Fun4AllServer *se = Fun4AllServer::instance(); - SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); - if (!synccopy) + } + if (!m_synccopy) { - synccopy = dynamic_cast (syncobject->CloneMe()); // clone for second event - tmpsync = dynamic_cast (synccopy->CloneMe()); // just to create this object - return Fun4AllReturnCodes::ABORTEVENT; // and abort + m_synccopy = dynamic_cast(syncobject->CloneMe()); // clone for second event + m_tmpsync = dynamic_cast(m_synccopy->CloneMe()); // just to create this object + return Fun4AllReturnCodes::ABORTEVENT; // and abort } - BcoInfo *bcoinfo = findNode::getClass(topNode,"BCOINFO"); + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); - std::cout << "current event is: " << syncobject->EventNumber() << "\n"; - std::cout << "saving as event: " << synccopy->EventNumber() << "\n"; - *tmpsync = *syncobject; // save current version - *syncobject = *synccopy; - *synccopy = *tmpsync; - if (Verbosity() > 100) + if (Verbosity() > 0) { - std::cout << "current sync object\n"; - syncobject->identify(); - std::cout << "next sync object\n"; - synccopy->identify(); + std::cout << "current event is: " << syncobject->EventNumber() << "\n"; + std::cout << "saving as event: " << m_synccopy->EventNumber() << "\n"; + } + // here we store the current sync object and overwrite its content with the cached copy + *m_tmpsync = *syncobject; // save current version in tmp + *syncobject = *m_synccopy; // copy previously cached version + *m_synccopy = *m_tmpsync; // cache current version + if (Verbosity() > 0) + { + std::cout << std::hex; + std::cout << "previous bco: " << get_previous_bco() << "\n"; + std::cout << "current bco: " << get_current_bco() << "\n"; + std::cout << "future bco: " << get_future_bco() << std::endl; + std::cout << std::dec; } - std::cout << std::hex; - std::cout << "previous bco: " << get_previous_bco() << "\n"; - std::cout << "current bco: " << get_current_bco() << "\n"; - std::cout << "future bco: " << get_future_bco() << std::endl; - std::cout << std::dec; bcoinfo->set_previous_bco(get_previous_bco()); bcoinfo->set_current_bco(get_current_bco()); bcoinfo->set_future_bco(get_future_bco()); + bcoinfo->set_previous_evtno(get_previous_evtno()); + bcoinfo->set_current_evtno(get_current_evtno()); + bcoinfo->set_future_evtno(get_future_evtno()); return Fun4AllReturnCodes::EVENT_OK; } -void BcoLumiReco::push(uint64_t value) +void BcoLumiReco::push_bco(uint64_t value) { - bco[0] = bco[1]; - bco[1] = bco[2]; - bco[2] = value; + m_bco[0] = m_bco[1]; + m_bco[1] = m_bco[2]; + m_bco[2] = value; } - +void BcoLumiReco::push_evtno(int value) +{ + m_evtno[0] = m_evtno[1]; + m_evtno[1] = m_evtno[2]; + m_evtno[2] = value; +} diff --git a/offline/packages/bcolumicount/BcoLumiReco.h b/offline/packages/bcolumicount/BcoLumiReco.h index 1a21df9a1c..6db4ea5fbc 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.h +++ b/offline/packages/bcolumicount/BcoLumiReco.h @@ -15,17 +15,24 @@ class BcoLumiReco : public SubsysReco ~BcoLumiReco() override = default; int Init(PHCompositeNode *topNode) override; - int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; - void push(uint64_t value); - uint64_t get_previous_bco() {return bco[0];} - uint64_t get_current_bco() const {return bco[1];} - uint64_t get_future_bco() const {return bco[2];} + + void push_bco(uint64_t value); + uint64_t get_previous_bco() { return m_bco[0]; } + uint64_t get_current_bco() const { return m_bco[1]; } + uint64_t get_future_bco() const { return m_bco[2]; } + + void push_evtno(int value); + int get_previous_evtno() { return m_evtno[0]; } + int get_current_evtno() const { return m_evtno[1]; } + int get_future_evtno() const { return m_evtno[2]; } + private: static int CreateNodeTree(PHCompositeNode *topNode); - SyncObject *synccopy {nullptr}; - SyncObject *tmpsync {nullptr}; - std::array bco {0}; + SyncObject *m_synccopy{nullptr}; + SyncObject *m_tmpsync{nullptr}; + std::array m_bco{0}; + std::array m_evtno{0}; }; -#endif // BCOLUMICOUNT_BCOLUMIRECO_H +#endif // BCOLUMICOUNT_BCOLUMIRECO_H From 20be46141935944e320121788619e6934a8aa281 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 10 Mar 2026 15:06:39 -0400 Subject: [PATCH 370/866] cleanup --- offline/packages/bcolumicount/BcoLumiReco.cc | 5 ++++- offline/packages/bcolumicount/Makefile.am | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc index 5d6cfc2d65..6dfc57cc95 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.cc +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -62,7 +62,10 @@ int BcoLumiReco::process_event(PHCompositeNode *topNode) Event *evt = findNode::getClass(topNode, "PRDF"); if (evt) { - evt->identify(); + if (Verbosity() > 1) + { + evt->identify(); + } if (evt->getEvtType() != DATAEVENT) { return Fun4AllReturnCodes::ABORTEVENT; diff --git a/offline/packages/bcolumicount/Makefile.am b/offline/packages/bcolumicount/Makefile.am index 3833324d98..70afc9b224 100644 --- a/offline/packages/bcolumicount/Makefile.am +++ b/offline/packages/bcolumicount/Makefile.am @@ -19,7 +19,6 @@ libbcolumicount_io_la_LIBADD = \ libbcolumicount_la_LIBADD = \ libbcolumicount_io.la \ - -lfun4all \ -lffaobjects \ -lffarawobjects \ -lSubsysReco From a95c3e8e05ac4efd4610c9a8fb88637fc2c58019 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 10 Mar 2026 15:15:18 -0400 Subject: [PATCH 371/866] include what you use --- offline/packages/bcolumicount/BcoInfo.cc | 2 -- offline/packages/bcolumicount/BcoInfov1.h | 2 -- offline/packages/bcolumicount/BcoLumiCheck.cc | 9 +-------- offline/packages/bcolumicount/BcoLumiCheck.h | 3 --- offline/packages/bcolumicount/BcoLumiReco.cc | 6 +++--- offline/packages/bcolumicount/BcoLumiReco.h | 2 ++ 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/offline/packages/bcolumicount/BcoInfo.cc b/offline/packages/bcolumicount/BcoInfo.cc index d775db903f..3fc672a599 100644 --- a/offline/packages/bcolumicount/BcoInfo.cc +++ b/offline/packages/bcolumicount/BcoInfo.cc @@ -4,8 +4,6 @@ #include -class PHObject; - void BcoInfo::Reset() { std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; diff --git a/offline/packages/bcolumicount/BcoInfov1.h b/offline/packages/bcolumicount/BcoInfov1.h index 5f5a9a7252..78b2a3f348 100644 --- a/offline/packages/bcolumicount/BcoInfov1.h +++ b/offline/packages/bcolumicount/BcoInfov1.h @@ -8,8 +8,6 @@ #include #include -class PHObject; - class BcoInfov1 : public BcoInfo { public: diff --git a/offline/packages/bcolumicount/BcoLumiCheck.cc b/offline/packages/bcolumicount/BcoLumiCheck.cc index f2b4a9d9b6..3ba12f1776 100644 --- a/offline/packages/bcolumicount/BcoLumiCheck.cc +++ b/offline/packages/bcolumicount/BcoLumiCheck.cc @@ -1,6 +1,6 @@ #include "BcoLumiCheck.h" -#include "BcoInfov1.h" +#include "BcoInfo.h" #include #include @@ -8,20 +8,13 @@ #include #include -#include #include // for SubsysReco #include -#include #include // for PHNode #include // for PHNodeIterator -#include // for PHObject #include #include // for PHWHERE -#include - -#include -#include #include diff --git a/offline/packages/bcolumicount/BcoLumiCheck.h b/offline/packages/bcolumicount/BcoLumiCheck.h index 89fd0ae306..75477dea98 100644 --- a/offline/packages/bcolumicount/BcoLumiCheck.h +++ b/offline/packages/bcolumicount/BcoLumiCheck.h @@ -3,11 +3,8 @@ #include -#include #include -class SyncObject; - class BcoLumiCheck : public SubsysReco { public: diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc index 6dfc57cc95..5947eea3ca 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.cc +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -1,12 +1,12 @@ #include "BcoLumiReco.h" +#include "BcoInfo.h" #include "BcoInfov1.h" #include #include #include -#include #include // for SubsysReco #include @@ -16,11 +16,11 @@ #include // for PHObject #include #include // for PHWHERE -#include #include #include - +#include // for Packet +# #include BcoLumiReco::BcoLumiReco(const std::string &name) diff --git a/offline/packages/bcolumicount/BcoLumiReco.h b/offline/packages/bcolumicount/BcoLumiReco.h index 6db4ea5fbc..c2657d20c4 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.h +++ b/offline/packages/bcolumicount/BcoLumiReco.h @@ -4,8 +4,10 @@ #include #include +#include #include +class PHCompositeNode; class SyncObject; class BcoLumiReco : public SubsysReco From dbd254b4c4f0416e42b29df4782209ade3a83c23 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 10 Mar 2026 15:28:12 -0400 Subject: [PATCH 372/866] add bcolumicount_io to lib dep of g4dst --- simulation/g4simulation/g4dst/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/simulation/g4simulation/g4dst/Makefile.am b/simulation/g4simulation/g4dst/Makefile.am index 7ea76582d4..3bb3eb1a17 100644 --- a/simulation/g4simulation/g4dst/Makefile.am +++ b/simulation/g4simulation/g4dst/Makefile.am @@ -11,6 +11,7 @@ lib_LTLIBRARIES = \ libg4dst_la_LDFLAGS = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ + -lbcolumicount_io \ -lcalo_io \ -lcalotrigger_io \ -lcentrality_io \ From 56be16346d622149b4042ade3bcc64f4ebb16971 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 10 Mar 2026 15:54:54 -0400 Subject: [PATCH 373/866] fix Reset and hex output --- offline/packages/bcolumicount/BcoInfov1.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/offline/packages/bcolumicount/BcoInfov1.cc b/offline/packages/bcolumicount/BcoInfov1.cc index d8e5bbf656..28e206413f 100644 --- a/offline/packages/bcolumicount/BcoInfov1.cc +++ b/offline/packages/bcolumicount/BcoInfov1.cc @@ -3,13 +3,13 @@ void BcoInfov1::Reset() { bco.fill(0); + evtno.fill(0); return; } void BcoInfov1::identify(std::ostream& out) const { out << "identify yourself: I am an BcoInfov1 Object\n"; - out << std::hex; out << "previous event: " << get_previous_evtno() << std::hex << " bco: 0x" << get_previous_bco() << "\n" << std::dec @@ -19,7 +19,6 @@ void BcoInfov1::identify(std::ostream& out) const << "future event: " << get_future_evtno() << std::hex << " bco: 0x" << get_future_bco() << std::dec << std::endl; - return; } From ecbd7812f80b31abc540f36c81a2eceef4dd93a8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 10 Mar 2026 16:12:18 -0400 Subject: [PATCH 374/866] delete cloned objects --- offline/packages/bcolumicount/BcoLumiReco.cc | 6 ++++++ offline/packages/bcolumicount/BcoLumiReco.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc index 5947eea3ca..bf8ea87224 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.cc +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -29,6 +29,12 @@ BcoLumiReco::BcoLumiReco(const std::string &name) return; } +BcoLumiReco::~BcoLumiReco() +{ + delete m_synccopy; + delete m_tmpsync; +} + int BcoLumiReco::Init(PHCompositeNode *topNode) { int iret = CreateNodeTree(topNode); diff --git a/offline/packages/bcolumicount/BcoLumiReco.h b/offline/packages/bcolumicount/BcoLumiReco.h index c2657d20c4..c0c0ab6a3a 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.h +++ b/offline/packages/bcolumicount/BcoLumiReco.h @@ -14,7 +14,7 @@ class BcoLumiReco : public SubsysReco { public: BcoLumiReco(const std::string &name = "BCOLUMIRECO"); - ~BcoLumiReco() override = default; + ~BcoLumiReco() override; int Init(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; From 21724b056f311fdb1b6c780cb9a1f3b8624ea8b3 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Wed, 11 Mar 2026 01:02:54 -0400 Subject: [PATCH 375/866] Update the way how we load the INTT DAC values, it was from CDB. Now we read the values from PSQL. --- .../intt/InttCombinedRawDataDecoder.cc | 46 ++++++++++--- .../intt/InttCombinedRawDataDecoder.h | 20 ++++-- offline/packages/intt/InttOdbcQuery.cc | 69 +++++++++++++++++++ offline/packages/intt/InttOdbcQuery.h | 9 +++ 4 files changed, 128 insertions(+), 16 deletions(-) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 18db00ef01..657a670fdc 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -35,8 +35,9 @@ InttCombinedRawDataDecoder::InttCombinedRawDataDecoder(std::string const& name) : SubsysReco(name) - , m_calibinfoDAC({"INTT_DACMAP", CDB}) + // , m_calibinfoDAC({"INTT_DACMAP", CDB}) , m_calibinfoBCO({"INTT_BCOMAP", CDB}) + , m_DACValues(0) { // Do nothing // Consider calling LoadHotChannelMapRemote() @@ -128,17 +129,29 @@ int InttCombinedRawDataDecoder::InitRun(PHCompositeNode* topNode) } /////////////////////////////////////// - std::cout << "calibinfo DAC : " << m_calibinfoDAC.first << " " << (m_calibinfoDAC.second == CDB ? "CDB" : "FILE") << std::endl; - m_dacmap.Verbosity(Verbosity()); - if (m_calibinfoDAC.second == CDB) + if ( DACValue_set_count == 1 && (m_DACValues.size() != 8 || std::find(m_DACValues.begin(), m_DACValues.end(), -1) != m_DACValues.end()) ) { - m_dacmap.LoadFromCDB(m_calibinfoDAC.first); + std::cout << PHWHERE << ", " << "INTT DAC values retrieved from intt_setting table not properly set, exiting." << std::endl; + gSystem->Exit(1); + exit(1); } - else - { - m_dacmap.LoadFromFile(m_calibinfoDAC.first); + + if (DACValue_set_count == 0){ + std::cout << PHWHERE << ", " << "INTT DAC values not set, used the default setting {30, 45, 60, 90, 120, 150, 180, 210} " << std::endl; + m_DACValues = default_DACValues; } + // std::cout << "calibinfo DAC : " << m_calibinfoDAC.first << " " << (m_calibinfoDAC.second == CDB ? "CDB" : "FILE") << std::endl; + // m_dacmap.Verbosity(Verbosity()); + // if (m_calibinfoDAC.second == CDB) + // { + // m_dacmap.LoadFromCDB(m_calibinfoDAC.first); + // } + // else + // { + // m_dacmap.LoadFromFile(m_calibinfoDAC.first); + // } + /////////////////////////////////////// std::cout << "calibinfo BCO : " << m_calibinfoBCO.first << " " << (m_calibinfoBCO.second == CDB ? "CDB" : "FILE") << std::endl; m_bcomap.Verbosity(Verbosity()); @@ -429,7 +442,9 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) //////////////////////// // dac conversion - int dac = m_dacmap.GetDAC(raw, adc); + // int dac = m_dacmap.GetDAC(raw, adc); + int dac = (adc >= 0 && adc <= 7) ? m_DACValues[adc] : -1; + // std::cout<< PHWHERE << "\n" << "ADC value: " << adc << ", converted DAC value: " << dac << std::endl; hit = new TrkrHitv2; //--hit->setAdc(adc); @@ -441,3 +456,16 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } + + +void InttCombinedRawDataDecoder::set_DACValues(std::vector input_dac_vec) +{ + m_DACValues = input_dac_vec; + DACValue_set_count = 1; + std::cout< #include #include +#include #include #include #include @@ -40,10 +41,10 @@ class InttCombinedRawDataDecoder : public SubsysReco /// Depreciated; use LoadHotChannelMap(const std::string&); int LoadHotChannelMapRemote(std::string const& s = "INTT_HotChannelMap") {return LoadBadChannelMap(s);} - void SetCalibDAC(std::string const& calibname = "INTT_DACMAP", const CalibRef& calibref = CDB) - { - m_calibinfoDAC = std::pair(calibname, calibref); - } + // void SetCalibDAC(std::string const& calibname = "INTT_DACMAP", const CalibRef& calibref = CDB) + // { + // m_calibinfoDAC = std::pair(calibname, calibref); + // } void SetCalibBCO(std::string const& calibname = "INTT_BCOMAP", const CalibRef& calibref = CDB) { @@ -60,6 +61,7 @@ class InttCombinedRawDataDecoder : public SubsysReco void set_bcoFilter(bool flag) {m_bcoFilter = flag; } void set_SaturatedChipRejection(bool flag){m_SaturatedChipRejection = flag;} // note : this is for removing a fraction of the saturated chips void set_HighChipMultiplicityCut(int cut){HighChipMultiplicityCut = cut;} + void set_DACValues(std::vector input_dac_vec); private: InttEventInfo* intt_event_header = nullptr; @@ -68,13 +70,17 @@ class InttCombinedRawDataDecoder : public SubsysReco bool m_writeInttEventHeader = false; bool m_bcoFilter = false; bool m_SaturatedChipRejection = true; // note : true as default - std::pair m_calibinfoDAC; + // std::pair m_calibinfoDAC; std::pair m_calibinfoBCO; InttBadChannelMap m_badmap; - InttDacMap m_dacmap; + // InttDacMap m_dacmap; InttBCOMap m_bcomap; + std::vector m_DACValues; + const std::vector default_DACValues = {30, 45, 60, 90, 120, 150, 180, 210}; // note : this is the setting used by most of the physics runs + int DACValue_set_count = 0; + int m_inttFeeOffset = 23; //23 is the offset for INTT in streaming mode bool m_outputBcoDiff = false; bool m_triggeredMode = false; diff --git a/offline/packages/intt/InttOdbcQuery.cc b/offline/packages/intt/InttOdbcQuery.cc index 51587c00a2..c43881b729 100644 --- a/offline/packages/intt/InttOdbcQuery.cc +++ b/offline/packages/intt/InttOdbcQuery.cc @@ -19,8 +19,11 @@ int InttOdbcQuery::Query(int runnumber) // statement will be deleted by DBInterface odbc::Statement* statement = DBInterface::instance()->getStatement("daq"); + m_intt_dac_values.clear(); + int iret = 0; iret += (QueryStreaming(statement, runnumber) != 0); + iret += (QueryAllDACValues(statement, runnumber) != 0); //... m_query_successful = (iret == 0); @@ -104,3 +107,69 @@ int InttOdbcQuery::QueryType(odbc::Statement *statement, int runnumber) return 0; } + +int InttOdbcQuery::QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value) // adc_value should be from 0 to 7 +{ + std::unique_ptr result_set; + std::string column_name = "dac" + std::to_string(adc_value); + DAC_value = -1; + + + try + { + std::string sql = "SELECT " + column_name + " From intt_setting WHERE runnumber = " + std::to_string(runnumber) + ";"; + result_set = std::unique_ptr(statement->executeQuery(sql)); + if (result_set && result_set->next()) + { + DAC_value = result_set->getInt(column_name.c_str()); + } + } + catch (odbc::SQLException& e) + { + std::cerr << PHWHERE << "\n" + << "\tSQL Exception:\n" + << "\t" << e.getMessage() << std::endl; + return 1; + } + + if (m_verbosity) + { + std::cout << column_name << " of run " << runnumber <<" is " << DAC_value << std::endl; + } + + return 0; +} + +int InttOdbcQuery::QueryAllDACValues(odbc::Statement *statement, int runnumber) +{ + int error_count = 0; + + for (int i = 0; i < 8; ++i) + { + int DAC_value = -1; + + error_count += QuerySingleDACValue(statement, runnumber, i, DAC_value); + + m_intt_dac_values.push_back(DAC_value); + } + + if (error_count != 0 || m_intt_dac_values.size() != 8 || std::find(m_intt_dac_values.begin(), m_intt_dac_values.end(), -1) != m_intt_dac_values.end()) + { + std::cerr << PHWHERE << "\n" + << "\tError retrieving DAC values. error_count: " << error_count + << ", size of m_intt_dac_values: " << m_intt_dac_values.size() << std::endl; + std:: cout << "In the dac map: "; + for (size_t i = 0; i < m_intt_dac_values.size(); ++i) + { + std::cout << "dac" << i << ": " << m_intt_dac_values[i] << ", "; + } + std::cout << std::endl; + + std::cout << "We then use the default mapping of intt_dac_values: {30, 45, 60, 90, 120, 150, 180, 210} for this run, runnumber : "<< runnumber << std::endl; + m_intt_dac_values = default_intt_dac_values; + + return error_count; + } + + return 0; +} \ No newline at end of file diff --git a/offline/packages/intt/InttOdbcQuery.h b/offline/packages/intt/InttOdbcQuery.h index 775e2e0ca4..dd03066cc0 100644 --- a/offline/packages/intt/InttOdbcQuery.h +++ b/offline/packages/intt/InttOdbcQuery.h @@ -1,9 +1,11 @@ #ifndef INTT_ODBC_QUERY_H #define INTT_ODBC_QUERY_H +#include #include #include #include +#include namespace odbc { @@ -22,12 +24,16 @@ class InttOdbcQuery int Query(int); bool IsStreaming() {return m_is_streaming;} + std::vector GetInttDACValues() {return m_intt_dac_values;} const std::string &Type() {return m_type;} private: int QueryStreaming(odbc::Statement *, int); int QueryType(odbc::Statement *, int); + int QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value); + int QueryAllDACValues(odbc::Statement *statement, int runnumber); + static const int m_MAX_NUM_RETRIES = 3000; static const int m_MIN_SLEEP_DUR = 200; // milliseconds static const int m_MAX_SLEEP_DUR = 3000; // milliseconds @@ -38,6 +44,9 @@ class InttOdbcQuery bool m_is_streaming{false}; std::string m_type; std::array, 8> m_file_set; + + std::vector m_intt_dac_values; + const std::vector default_intt_dac_values{30, 45, 60, 90, 120, 150, 180, 210}; // note : most of physics runs have this setting. }; #endif//INTT_ODBC_QUERY_H From 42ed1e514d564a5fec291a4a8f8db865b30b5c79 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Wed, 11 Mar 2026 11:43:30 -0400 Subject: [PATCH 376/866] Update the way how we load the INTT DAC values, for mass production, the new method. --- .../intt/InttCombinedRawDataDecoder.cc | 124 +++++++++++++++--- .../intt/InttCombinedRawDataDecoder.h | 11 +- 2 files changed, 117 insertions(+), 18 deletions(-) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 657a670fdc..ae05b62251 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -18,7 +18,12 @@ #include #include +#include +#include +#include + +#include #include #include // for PHIODataNode #include @@ -37,7 +42,7 @@ InttCombinedRawDataDecoder::InttCombinedRawDataDecoder(std::string const& name) : SubsysReco(name) // , m_calibinfoDAC({"INTT_DACMAP", CDB}) , m_calibinfoBCO({"INTT_BCOMAP", CDB}) - , m_DACValues(0) + , m_intt_dac_values(0) { // Do nothing // Consider calling LoadHotChannelMapRemote() @@ -129,17 +134,14 @@ int InttCombinedRawDataDecoder::InitRun(PHCompositeNode* topNode) } /////////////////////////////////////// - if ( DACValue_set_count == 1 && (m_DACValues.size() != 8 || std::find(m_DACValues.begin(), m_DACValues.end(), -1) != m_DACValues.end()) ) - { - std::cout << PHWHERE << ", " << "INTT DAC values retrieved from intt_setting table not properly set, exiting." << std::endl; - gSystem->Exit(1); - exit(1); - } - + recoConsts *rc = recoConsts::instance(); + int run_number = rc->get_IntFlag("RUNNUMBER"); + + odbc::Statement* statement = DBInterface::instance()->getStatement("daq"); if (DACValue_set_count == 0){ - std::cout << PHWHERE << ", " << "INTT DAC values not set, used the default setting {30, 45, 60, 90, 120, 150, 180, 210} " << std::endl; - m_DACValues = default_DACValues; - } + std::cout<< PHWHERE << ", " << "No manual setting for DAC values. Querying INTT DAC values from intt_setting table for run number " << run_number << std::endl; + InttCombinedRawDataDecoder::QueryAllDACValues(statement, run_number); + } // std::cout << "calibinfo DAC : " << m_calibinfoDAC.first << " " << (m_calibinfoDAC.second == CDB ? "CDB" : "FILE") << std::endl; // m_dacmap.Verbosity(Verbosity()); @@ -443,8 +445,12 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) //////////////////////// // dac conversion // int dac = m_dacmap.GetDAC(raw, adc); - int dac = (adc >= 0 && adc <= 7) ? m_DACValues[adc] : -1; - // std::cout<< PHWHERE << "\n" << "ADC value: " << adc << ", converted DAC value: " << dac << std::endl; + int dac = (adc >= 0 && adc <= 7) ? m_intt_dac_values[adc] : -1; + + if (Verbosity() > 100000){ + std::cout<< PHWHERE << "\n" << "ADC value: " << adc << ", converted DAC value: " << dac << std::endl; + } + hit = new TrkrHitv2; //--hit->setAdc(adc); @@ -460,12 +466,98 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) void InttCombinedRawDataDecoder::set_DACValues(std::vector input_dac_vec) { - m_DACValues = input_dac_vec; + m_intt_dac_values = input_dac_vec; DACValue_set_count = 1; + int count_minus = 0; std::cout<Exit(1); + } +} + + +int InttCombinedRawDataDecoder::QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value) // adc_value should be from 0 to 7 +{ + std::unique_ptr result_set; + std::string column_name = "dac" + std::to_string(adc_value); + DAC_value = -1; + + + try + { + std::string sql = "SELECT " + column_name + " From intt_setting WHERE runnumber = " + std::to_string(runnumber) + ";"; + result_set = std::unique_ptr(statement->executeQuery(sql)); + if (result_set && result_set->next()) + { + DAC_value = result_set->getInt(column_name.c_str()); + } + } + catch (odbc::SQLException& e) + { + std::cerr << PHWHERE << "\n" + << "\tSQL Exception:\n" + << "\t" << e.getMessage() << std::endl; + return 1; + } + + if (Verbosity()) + { + std::cout << column_name << " of run " << runnumber <<" is " << DAC_value << std::endl; + } + + return 0; +} + +int InttCombinedRawDataDecoder::QueryAllDACValues(odbc::Statement *statement, int runnumber) +{ + int error_count = 0; + + for (int i = 0; i < 8; ++i) + { + int DAC_value = -1; + + error_count += QuerySingleDACValue(statement, runnumber, i, DAC_value); + + m_intt_dac_values.push_back(DAC_value); + } + + if (error_count != 0 || m_intt_dac_values.size() != 8 || std::find(m_intt_dac_values.begin(), m_intt_dac_values.end(), -1) != m_intt_dac_values.end()) + { + std::cerr << PHWHERE << "\n" + << "\tError retrieving DAC values. error_count: " << error_count + << ", size of m_intt_dac_values: " << m_intt_dac_values.size() << std::endl; + std:: cout << "In the dac map: "; + for (size_t i = 0; i < m_intt_dac_values.size(); ++i) + { + std::cout << "dac" << i << ": " << m_intt_dac_values[i] << ", "; + } + std::cout << std::endl; + std::cout<< " The DAC values should be 8 integers and all should be positive. Exiting."<< std::endl; + std::cout<< " Please contact the INTT group if the run you analyzed doesn't appear in the intt_setting table."<< std::endl; + + exit(1); + gSystem->Exit(1); + + return error_count; + } + + return 0; } \ No newline at end of file diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.h b/offline/packages/intt/InttCombinedRawDataDecoder.h index 6c71b42880..0b2f5904ee 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.h +++ b/offline/packages/intt/InttCombinedRawDataDecoder.h @@ -18,6 +18,11 @@ class PHCompositeNode; class InttEventInfo; +namespace odbc +{ + class Statement; +} // namespace odbc + class InttCombinedRawDataDecoder : public SubsysReco { public: @@ -64,6 +69,9 @@ class InttCombinedRawDataDecoder : public SubsysReco void set_DACValues(std::vector input_dac_vec); private: + int QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value); + int QueryAllDACValues(odbc::Statement *statement, int runnumber); + InttEventInfo* intt_event_header = nullptr; std::string m_InttRawNodeName = "INTTRAWHIT"; bool m_runStandAlone = false; @@ -77,8 +85,7 @@ class InttCombinedRawDataDecoder : public SubsysReco // InttDacMap m_dacmap; InttBCOMap m_bcomap; - std::vector m_DACValues; - const std::vector default_DACValues = {30, 45, 60, 90, 120, 150, 180, 210}; // note : this is the setting used by most of the physics runs + std::vector m_intt_dac_values; int DACValue_set_count = 0; int m_inttFeeOffset = 23; //23 is the offset for INTT in streaming mode From 9f3e5f0e3003501bf980188bae7842227864c6a1 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Wed, 11 Mar 2026 11:59:59 -0400 Subject: [PATCH 377/866] revert the modification on the InttOdbcQuery --- offline/packages/intt/InttOdbcQuery.cc | 69 -------------------------- offline/packages/intt/InttOdbcQuery.h | 9 ---- 2 files changed, 78 deletions(-) diff --git a/offline/packages/intt/InttOdbcQuery.cc b/offline/packages/intt/InttOdbcQuery.cc index c43881b729..51587c00a2 100644 --- a/offline/packages/intt/InttOdbcQuery.cc +++ b/offline/packages/intt/InttOdbcQuery.cc @@ -19,11 +19,8 @@ int InttOdbcQuery::Query(int runnumber) // statement will be deleted by DBInterface odbc::Statement* statement = DBInterface::instance()->getStatement("daq"); - m_intt_dac_values.clear(); - int iret = 0; iret += (QueryStreaming(statement, runnumber) != 0); - iret += (QueryAllDACValues(statement, runnumber) != 0); //... m_query_successful = (iret == 0); @@ -107,69 +104,3 @@ int InttOdbcQuery::QueryType(odbc::Statement *statement, int runnumber) return 0; } - -int InttOdbcQuery::QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value) // adc_value should be from 0 to 7 -{ - std::unique_ptr result_set; - std::string column_name = "dac" + std::to_string(adc_value); - DAC_value = -1; - - - try - { - std::string sql = "SELECT " + column_name + " From intt_setting WHERE runnumber = " + std::to_string(runnumber) + ";"; - result_set = std::unique_ptr(statement->executeQuery(sql)); - if (result_set && result_set->next()) - { - DAC_value = result_set->getInt(column_name.c_str()); - } - } - catch (odbc::SQLException& e) - { - std::cerr << PHWHERE << "\n" - << "\tSQL Exception:\n" - << "\t" << e.getMessage() << std::endl; - return 1; - } - - if (m_verbosity) - { - std::cout << column_name << " of run " << runnumber <<" is " << DAC_value << std::endl; - } - - return 0; -} - -int InttOdbcQuery::QueryAllDACValues(odbc::Statement *statement, int runnumber) -{ - int error_count = 0; - - for (int i = 0; i < 8; ++i) - { - int DAC_value = -1; - - error_count += QuerySingleDACValue(statement, runnumber, i, DAC_value); - - m_intt_dac_values.push_back(DAC_value); - } - - if (error_count != 0 || m_intt_dac_values.size() != 8 || std::find(m_intt_dac_values.begin(), m_intt_dac_values.end(), -1) != m_intt_dac_values.end()) - { - std::cerr << PHWHERE << "\n" - << "\tError retrieving DAC values. error_count: " << error_count - << ", size of m_intt_dac_values: " << m_intt_dac_values.size() << std::endl; - std:: cout << "In the dac map: "; - for (size_t i = 0; i < m_intt_dac_values.size(); ++i) - { - std::cout << "dac" << i << ": " << m_intt_dac_values[i] << ", "; - } - std::cout << std::endl; - - std::cout << "We then use the default mapping of intt_dac_values: {30, 45, 60, 90, 120, 150, 180, 210} for this run, runnumber : "<< runnumber << std::endl; - m_intt_dac_values = default_intt_dac_values; - - return error_count; - } - - return 0; -} \ No newline at end of file diff --git a/offline/packages/intt/InttOdbcQuery.h b/offline/packages/intt/InttOdbcQuery.h index dd03066cc0..775e2e0ca4 100644 --- a/offline/packages/intt/InttOdbcQuery.h +++ b/offline/packages/intt/InttOdbcQuery.h @@ -1,11 +1,9 @@ #ifndef INTT_ODBC_QUERY_H #define INTT_ODBC_QUERY_H -#include #include #include #include -#include namespace odbc { @@ -24,16 +22,12 @@ class InttOdbcQuery int Query(int); bool IsStreaming() {return m_is_streaming;} - std::vector GetInttDACValues() {return m_intt_dac_values;} const std::string &Type() {return m_type;} private: int QueryStreaming(odbc::Statement *, int); int QueryType(odbc::Statement *, int); - int QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value); - int QueryAllDACValues(odbc::Statement *statement, int runnumber); - static const int m_MAX_NUM_RETRIES = 3000; static const int m_MIN_SLEEP_DUR = 200; // milliseconds static const int m_MAX_SLEEP_DUR = 3000; // milliseconds @@ -44,9 +38,6 @@ class InttOdbcQuery bool m_is_streaming{false}; std::string m_type; std::array, 8> m_file_set; - - std::vector m_intt_dac_values; - const std::vector default_intt_dac_values{30, 45, 60, 90, 120, 150, 180, 210}; // note : most of physics runs have this setting. }; #endif//INTT_ODBC_QUERY_H From ea2074408a35cf5a68653dd33dad6487878287bb Mon Sep 17 00:00:00 2001 From: devloom Date: Wed, 11 Mar 2026 12:38:23 -0400 Subject: [PATCH 378/866] add laser cluster alignment --- offline/packages/tpc/LaserClusterizer.cc | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index cdf18687df..12b65747f1 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -818,6 +819,35 @@ namespace clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); } + + // Get surface of max ADC hit + alignmentTransformationContainer::use_alignment = false; + Acts::Vector3 ideal(clusX, clusY, clusZ); + TrkrDefs::subsurfkey subsurfkey = 0; + + Surface surface = my_data.tGeometry->get_tpc_surface_from_coords( + maxKey, + ideal, + subsurfkey); + + if (!surface) + { + return; + } + + // Convert from ideal TPC coordinates to surface coordinates + Acts::Vector3 local = surface->transform(my_data.tGeometry->geometry().getGeoContext()).inverse() * (ideal * Acts::UnitConstants::cm); + local /= Acts::UnitConstants::cm; + + // Convert back to TPC coordinates with alignment applied + alignmentTransformationContainer::use_alignment = true; + Acts::Vector3 global = surface->transform(my_data.tGeometry->geometry().getGeoContext()) * (local * Acts::UnitConstants::cm); + global /= Acts::UnitConstants::cm; + clus->setX(global(0)); + clus->setY(global(1)); + clus->setZ(global(2)); + + 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); @@ -995,6 +1025,7 @@ int LaserClusterizer::InitRun(PHCompositeNode *topNode) // get the first layer to get the clock freq AdcClockPeriod = m_geom_container->GetFirstLayerCellGeom()->get_zstep(); m_tdriftmax = AdcClockPeriod * NZBinsSide; + return Fun4AllReturnCodes::EVENT_OK; } @@ -1146,6 +1177,9 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.peakTimeBin = m_laserEventInfo->getPeakSample(s); thread_pair.data.layerMin = 3; thread_pair.data.layerMax = 3; + // ******************** // + // m_tdriftmax = m_tGeometry->get_max_driftlength() / m_tGeometry->get_drift_velocity(); + // ******************** // thread_pair.data.tdriftmax = m_tdriftmax; thread_pair.data.eventNum = m_event; thread_pair.data.Verbosity = Verbosity(); From e4e8392f8e3351083374537bbe7ea1296d3187f3 Mon Sep 17 00:00:00 2001 From: devloom Date: Wed, 11 Mar 2026 12:42:39 -0400 Subject: [PATCH 379/866] clean up --- offline/packages/tpc/LaserClusterizer.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 12b65747f1..a7e74672ec 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -1177,9 +1177,6 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.peakTimeBin = m_laserEventInfo->getPeakSample(s); thread_pair.data.layerMin = 3; thread_pair.data.layerMax = 3; - // ******************** // - // m_tdriftmax = m_tGeometry->get_max_driftlength() / m_tGeometry->get_drift_velocity(); - // ******************** // thread_pair.data.tdriftmax = m_tdriftmax; thread_pair.data.eventNum = m_event; thread_pair.data.Verbosity = Verbosity(); From d106696e01fd8899ac922f90d91026475045bfa3 Mon Sep 17 00:00:00 2001 From: devloom Date: Wed, 11 Mar 2026 16:37:35 -0400 Subject: [PATCH 380/866] rabbit suggestions --- offline/packages/tpc/LaserClusterizer.cc | 30 ++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index a7e74672ec..9a2b265f57 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -444,6 +444,7 @@ namespace double maxAdc = 0.0; TrkrDefs::hitsetkey maxKey = 0; + TrkrDefs::hitsetkey secondmaxKey = 0; unsigned int nHits = clusHits.size(); @@ -556,6 +557,7 @@ namespace if (adc > maxAdc) { maxAdc = adc; + secondmaxKey = maxKey; maxKey = spechitkey.second; } } @@ -820,9 +822,10 @@ namespace } + pthread_mutex_lock(&mythreadlock); // Get surface of max ADC hit alignmentTransformationContainer::use_alignment = false; - Acts::Vector3 ideal(clusX, clusY, clusZ); + Acts::Vector3 ideal(clus->getX(), clus->getY(), clus->getZ()); TrkrDefs::subsurfkey subsurfkey = 0; Surface surface = my_data.tGeometry->get_tpc_surface_from_coords( @@ -832,7 +835,29 @@ namespace if (!surface) { - return; + // try second maximum ADC hit + if (secondmaxKey != 0) + { + surface = my_data.tGeometry->get_tpc_surface_from_coords( + secondmaxKey, + ideal, + subsurfkey); + } + + // if still no surface, skip this cluster + if (!surface) + { + // clean up + alignmentTransformationContainer::use_alignment = true; + delete fit3D; + if (my_data.hitHist) + { + delete my_data.hitHist; + my_data.hitHist = nullptr; + } + pthread_mutex_unlock(&mythreadlock); + return; + } } // Convert from ideal TPC coordinates to surface coordinates @@ -846,6 +871,7 @@ namespace clus->setX(global(0)); clus->setY(global(1)); clus->setZ(global(2)); + pthread_mutex_unlock(&mythreadlock); const auto ckey = TrkrDefs::genClusKey(maxKey, my_data.cluster_vector.size()); From 65e3ae26766581484c60aaaf272c0ff82be5b1f9 Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Wed, 11 Mar 2026 17:43:44 -0400 Subject: [PATCH 381/866] Implement BCO matching and move cout statements under verbosity --- .../KFParticle_sPHENIX/KFParticle_nTuple.cc | 17 +++++- .../KFParticle_sPHENIX/KFParticle_nTuple.h | 9 +++ .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 56 +++++++++++++++++++ .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 6 ++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index b4659e1b8d..44ffbbedda 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -303,7 +303,9 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch("runNumber", &m_runNumber, "runNumber/I"); m_tree->Branch("eventNumber", &m_evtNumber, "eventNumber/I"); - m_tree->Branch("BCO", &m_bco, "BCO/L"); + m_tree->Branch("event_bco", &m_event_bco, "event_bco/L"); //adding for the current event BCO, not shifted + m_tree->Branch("BCO", &m_bco, "BCO/L"); //already there, this is shifted BCO + m_tree->Branch("last_event_bco", &m_last_event_bco, "last_event_bco/L"); //BCO for the last event if (m_get_trigger_info) { @@ -674,10 +676,23 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, } m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; //m_bco = m_trigger_info_available ? gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0] : 0; + + //moving this logic to KFParticle_sPHENIX.cc in process_event, will be removed later + /* + //BCO for the last event try + if (m_runNumber != m_prev_runNumber || m_evtNumber != m_prev_evtNumber) + { + m_last_event_bco = m_prev_event_bco; + m_prev_event_bco = m_bco; + m_prev_runNumber = m_runNumber; + m_prev_evtNumber = m_evtNumber; + } //end BCO for last event + */ } else { m_runNumber = m_evtNumber = m_bco = -1; + // m_last_event_bco = -1; //add for last event BCO } if (m_trigger_info_available) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h index 4798e24942..7c3f4088fe 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h @@ -35,6 +35,13 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ std::vector daughters, std::vector intermediates); + // pass event-level BCO values from KFParticle_sPHENIX + void set_event_bcos(const int64_t this_bco, const int64_t last_bco) + { + m_event_bco = this_bco; + m_last_event_bco = last_bco; + } + float calc_secondary_vertex_mass_noPID(std::vector kfp_daughters); bool fillConditionMet() const; @@ -219,6 +226,8 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ int m_runNumber{-1}; int m_evtNumber{-1}; int64_t m_bco{-1}; + int64_t m_event_bco{-1};//current event BCO + int64_t m_last_event_bco{-1}; //only keeping this, BCO for the last event bool m_trigger_info_available{false}; }; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 8c049f30d6..93ee223686 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -29,6 +29,8 @@ #include #include +#include +#include #include #include @@ -150,7 +152,60 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; } + + // Adding BCO Matching + auto* evtHeader = findNode::getClass(topNode, "EventHeader"); // event header node + auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); // gl1 packet node + if (!gl1packet) + { + gl1packet = findNode::getClass(topNode, "GL1Packet"); + } + + if (evtHeader && gl1packet) + { + const int64_t run = evtHeader->get_RunNumber(); + const int64_t evn = evtHeader->get_EvtSequence(); + m_this_event_bco = static_cast(gl1packet->lValue(0, "BCO")); + + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "Event start | run: " << run << " event: " << evn << " this_event_bco: " << m_this_event_bco << std::endl; + } + + if (run != m_prev_runNumber || evn != m_prev_eventNumber) + { + + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "New event detected" << std::endl; + std::cout << "Previous event BCO: " << m_prev_event_bco << std::endl; + } + m_last_event_bco = m_prev_event_bco; + m_prev_event_bco = m_this_event_bco; + + m_prev_runNumber = run; + m_prev_eventNumber = evn; + + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "Updated values | last_event_bco: " << m_last_event_bco + << " stored_prev_event_bco: " << m_prev_event_bco + << std::endl; + } + } + } + else + { + + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "EventHeader or GL1 packet not found" << std::endl; + } + m_this_event_bco = -1; + m_last_event_bco = -1; + } +// End BCO matching here if (!m_use_fake_pv) { if (m_use_mbd_vertex) @@ -205,6 +260,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) if (m_save_output) { + set_event_bcos(m_this_event_bco, m_last_event_bco); //filling nTuple for BCO Matching fillBranch(topNode, mother[i], vertex_kfparticle[i], daughters[i], intermediates[i]); } if (m_save_dst) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index d5905d443c..5b0ceca785 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -422,6 +422,12 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K bool m_save_dst; bool m_save_output; int candidateCounter = 0; + //Adding member variables for BCO matching + int64_t m_this_event_bco{-1}; + int64_t m_last_event_bco{-1}; + int64_t m_prev_event_bco{-1}; + int64_t m_prev_runNumber{-1}; + int64_t m_prev_eventNumber{-1}; //till here std::string m_outfile_name; TFile *m_outfile; std::string m_decayDescriptor; From 960d444b2a3a6eefc2b624a417b5d551c26b96cd Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Wed, 11 Mar 2026 17:49:20 -0400 Subject: [PATCH 382/866] Implement BCO matching and move cout statements under verbosity --- .../packages/KFParticle_sPHENIX/KFParticle_nTuple.cc | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index 44ffbbedda..f6ae689aa9 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -677,22 +677,10 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; //m_bco = m_trigger_info_available ? gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0] : 0; - //moving this logic to KFParticle_sPHENIX.cc in process_event, will be removed later - /* - //BCO for the last event try - if (m_runNumber != m_prev_runNumber || m_evtNumber != m_prev_evtNumber) - { - m_last_event_bco = m_prev_event_bco; - m_prev_event_bco = m_bco; - m_prev_runNumber = m_runNumber; - m_prev_evtNumber = m_evtNumber; - } //end BCO for last event - */ } else { m_runNumber = m_evtNumber = m_bco = -1; - // m_last_event_bco = -1; //add for last event BCO } if (m_trigger_info_available) From 1bda69061a2b6b1a7020f41386871ec5c2b9682f Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Wed, 11 Mar 2026 18:16:41 -0400 Subject: [PATCH 383/866] Reset cached previous-event state on run change or invalid event to avoid propagating stale BCO history. --- offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 93ee223686..15a0a5f33e 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -181,7 +181,8 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) std::cout << "New event detected" << std::endl; std::cout << "Previous event BCO: " << m_prev_event_bco << std::endl; } - m_last_event_bco = m_prev_event_bco; + // m_last_event_bco = m_prev_event_bco; + m_last_event_bco = (run == m_prev_runNumber) ? m_prev_event_bco : -1; m_prev_event_bco = m_this_event_bco; m_prev_runNumber = run; @@ -204,6 +205,10 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) } m_this_event_bco = -1; m_last_event_bco = -1; + m_prev_event_bco = -1; + m_prev_runNumber = -1; + m_prev_eventNumber = -1; + } // End BCO matching here if (!m_use_fake_pv) From 5e6433bf8929cdae63c442fa6ec2f6e91083dbb2 Mon Sep 17 00:00:00 2001 From: devloom Date: Wed, 11 Mar 2026 18:25:02 -0400 Subject: [PATCH 384/866] fix max logic --- offline/packages/tpc/LaserClusterizer.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 9a2b265f57..fbb09a1fa2 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -444,6 +444,7 @@ namespace double maxAdc = 0.0; TrkrDefs::hitsetkey maxKey = 0; + double secondmaxAdc = 0.0; TrkrDefs::hitsetkey secondmaxKey = 0; unsigned int nHits = clusHits.size(); @@ -556,10 +557,18 @@ namespace if (adc > maxAdc) { - maxAdc = adc; + secondmaxAdc = maxAdc; secondmaxKey = maxKey; + maxAdc = adc; maxKey = spechitkey.second; } + else if (adc > secondmaxAdc) + { + secondmaxAdc = adc; + secondmaxKey = spechitkey.second; + } + + } if (nHits == 0) @@ -824,6 +833,7 @@ namespace pthread_mutex_lock(&mythreadlock); // Get surface of max ADC hit + bool alignmentflag = alignmentTransformationContainer::use_alignment; alignmentTransformationContainer::use_alignment = false; Acts::Vector3 ideal(clus->getX(), clus->getY(), clus->getZ()); TrkrDefs::subsurfkey subsurfkey = 0; @@ -848,7 +858,7 @@ namespace if (!surface) { // clean up - alignmentTransformationContainer::use_alignment = true; + alignmentTransformationContainer::use_alignment = alignmentflag; delete fit3D; if (my_data.hitHist) { @@ -871,6 +881,8 @@ namespace clus->setX(global(0)); clus->setY(global(1)); clus->setZ(global(2)); + + alignmentTransformationContainer::use_alignment = alignmentflag; pthread_mutex_unlock(&mythreadlock); @@ -878,6 +890,7 @@ namespace my_data.cluster_vector.push_back(clus); my_data.cluster_key_vector.push_back(ckey); + delete fit3D; if (my_data.hitHist) From de9a1074fb3d37fdb7d411a1138e55c89e864404 Mon Sep 17 00:00:00 2001 From: devloom Date: Wed, 11 Mar 2026 18:35:45 -0400 Subject: [PATCH 385/866] free memory --- offline/packages/tpc/LaserClusterizer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index fbb09a1fa2..8ecd28688e 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -859,6 +859,7 @@ namespace { // clean up alignmentTransformationContainer::use_alignment = alignmentflag; + delete clus; delete fit3D; if (my_data.hitHist) { @@ -881,7 +882,7 @@ namespace clus->setX(global(0)); clus->setY(global(1)); clus->setZ(global(2)); - + alignmentTransformationContainer::use_alignment = alignmentflag; pthread_mutex_unlock(&mythreadlock); From 0d1b523a7101ac51afd933972ebfd408353f7bfa Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Wed, 11 Mar 2026 22:29:35 -0400 Subject: [PATCH 386/866] Update the way how we load the INTT DAC values, for mass production, the new method2 --- .../intt/InttCombinedRawDataDecoder.cc | 83 ++++++++----------- .../intt/InttCombinedRawDataDecoder.h | 1 - 2 files changed, 34 insertions(+), 50 deletions(-) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index ae05b62251..8757bf3727 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -140,7 +140,25 @@ int InttCombinedRawDataDecoder::InitRun(PHCompositeNode* topNode) odbc::Statement* statement = DBInterface::instance()->getStatement("daq"); if (DACValue_set_count == 0){ std::cout<< PHWHERE << ", " << "No manual setting for DAC values. Querying INTT DAC values from intt_setting table for run number " << run_number << std::endl; - InttCombinedRawDataDecoder::QueryAllDACValues(statement, run_number); + int error_count = InttCombinedRawDataDecoder::QueryAllDACValues(statement, run_number); + + if (error_count != 0 || m_intt_dac_values.size() != 8 || std::find(m_intt_dac_values.begin(), m_intt_dac_values.end(), -1) != m_intt_dac_values.end()) + { + std::cerr << PHWHERE << "\n" + << "\tError retrieving DAC values. error_count: " << error_count + << ", size of m_intt_dac_values: " << m_intt_dac_values.size() << std::endl; + std:: cout << "In the dac map: "; + for (size_t i = 0; i < m_intt_dac_values.size(); ++i) + { + std::cout << "dac" << i << ": " << m_intt_dac_values[i] << ", "; + } + std::cout << std::endl; + std::cout<< " The DAC values should be 8 integers and all should be positive. Exiting."<< std::endl; + std::cout<< " Please contact the INTT group if the run you analyzed doesn't appear in the intt_setting table."<< std::endl; + + exit(1); + gSystem->Exit(1); + } } // std::cout << "calibinfo DAC : " << m_calibinfoDAC.first << " " << (m_calibinfoDAC.second == CDB ? "CDB" : "FILE") << std::endl; @@ -493,21 +511,29 @@ void InttCombinedRawDataDecoder::set_DACValues(std::vector input_dac_vec) } } - -int InttCombinedRawDataDecoder::QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value) // adc_value should be from 0 to 7 +int InttCombinedRawDataDecoder::QueryAllDACValues(odbc::Statement *statement, int runnumber) { + std::unique_ptr result_set; - std::string column_name = "dac" + std::to_string(adc_value); - DAC_value = -1; - + m_intt_dac_values.clear(); try { - std::string sql = "SELECT " + column_name + " From intt_setting WHERE runnumber = " + std::to_string(runnumber) + ";"; + std::string sql = "SELECT dac0, dac1, dac2, dac3, dac4, dac5, dac6, dac7 From intt_setting WHERE runnumber = " + std::to_string(runnumber) + ";"; result_set = std::unique_ptr(statement->executeQuery(sql)); if (result_set && result_set->next()) { - DAC_value = result_set->getInt(column_name.c_str()); + for (int i = 0; i < 8; i++) + { + std::string column_name = "dac" + std::to_string(i); + int DAC_value = -1; + + DAC_value = result_set->getInt(column_name.c_str()); + + m_intt_dac_values.push_back(DAC_value); + + std::cout<< PHWHERE << ", retrieved DAC value for " << column_name << ": " << DAC_value << std::endl; + } } } catch (odbc::SQLException& e) @@ -518,46 +544,5 @@ int InttCombinedRawDataDecoder::QuerySingleDACValue(odbc::Statement *statement, return 1; } - if (Verbosity()) - { - std::cout << column_name << " of run " << runnumber <<" is " << DAC_value << std::endl; - } - - return 0; -} - -int InttCombinedRawDataDecoder::QueryAllDACValues(odbc::Statement *statement, int runnumber) -{ - int error_count = 0; - - for (int i = 0; i < 8; ++i) - { - int DAC_value = -1; - - error_count += QuerySingleDACValue(statement, runnumber, i, DAC_value); - - m_intt_dac_values.push_back(DAC_value); - } - - if (error_count != 0 || m_intt_dac_values.size() != 8 || std::find(m_intt_dac_values.begin(), m_intt_dac_values.end(), -1) != m_intt_dac_values.end()) - { - std::cerr << PHWHERE << "\n" - << "\tError retrieving DAC values. error_count: " << error_count - << ", size of m_intt_dac_values: " << m_intt_dac_values.size() << std::endl; - std:: cout << "In the dac map: "; - for (size_t i = 0; i < m_intt_dac_values.size(); ++i) - { - std::cout << "dac" << i << ": " << m_intt_dac_values[i] << ", "; - } - std::cout << std::endl; - std::cout<< " The DAC values should be 8 integers and all should be positive. Exiting."<< std::endl; - std::cout<< " Please contact the INTT group if the run you analyzed doesn't appear in the intt_setting table."<< std::endl; - - exit(1); - gSystem->Exit(1); - - return error_count; - } - return 0; } \ No newline at end of file diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.h b/offline/packages/intt/InttCombinedRawDataDecoder.h index 0b2f5904ee..c38badefeb 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.h +++ b/offline/packages/intt/InttCombinedRawDataDecoder.h @@ -69,7 +69,6 @@ class InttCombinedRawDataDecoder : public SubsysReco void set_DACValues(std::vector input_dac_vec); private: - int QuerySingleDACValue(odbc::Statement *statement, int runnumber, int adc_value, int &DAC_value); int QueryAllDACValues(odbc::Statement *statement, int runnumber); InttEventInfo* intt_event_header = nullptr; From bd8068e579a4ef9044af889e6c6dc076ab266853 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Thu, 12 Mar 2026 06:07:00 -0400 Subject: [PATCH 387/866] CD: Jenkins requests --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 15 ++++++++------- .../TrackingDiagnostics/KshortReconstruction.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 1f503dcc01..e87d8c500b 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -219,13 +219,14 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_primary_vtx_x = thisVtx->point3d().x(); m_primary_vtx_y = thisVtx->point3d().y(); m_primary_vtx_z = thisVtx->point3d().z(); - constexpr float epsilon = 1e-6f; - if (std::abs(m_primary_vtx_x) < epsilon && - std::abs(m_primary_vtx_y) < epsilon && - std::abs(m_primary_vtx_z) < epsilon) - { - m_is_primary = true; - } + + constexpr float epsilon = 1e-6F; + if (std::abs(m_primary_vtx_x) < epsilon && + std::abs(m_primary_vtx_y) < epsilon && + std::abs(m_primary_vtx_z) < epsilon) + { + m_is_primary = true; + } } for (unsigned int i = 1; i < decay.size(); ++i) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.h b/offline/packages/TrackingDiagnostics/KshortReconstruction.h index 16ce14aca3..95eba65b02 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.h +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.h @@ -46,7 +46,7 @@ class KshortReconstruction : public SubsysReco //Truth matching code void truthMatch(bool match = true) { m_truth_match = match; } - void setMotherID(const std::string id = "K_S0") { m_mother_name = id; m_used_string = true; } + void setMotherID(const std::string &id = "K_S0") { m_mother_name = id; m_used_string = true; } void setMotherID(int id = 310) { m_mother_id = id; m_used_string = false; } private: From 8ed52b3cfc21bf23d919a358d4b307ed74a969a8 Mon Sep 17 00:00:00 2001 From: Usman <94740481+Mughal789@users.noreply.github.com> Date: Thu, 12 Mar 2026 09:47:22 -0400 Subject: [PATCH 388/866] Update offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 5b0ceca785..46aa1e4cef 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -424,7 +424,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K int candidateCounter = 0; //Adding member variables for BCO matching int64_t m_this_event_bco{-1}; - int64_t m_last_event_bco{-1}; + int64_t m_last_event_bco_sPHENIX{-1}; int64_t m_prev_event_bco{-1}; int64_t m_prev_runNumber{-1}; int64_t m_prev_eventNumber{-1}; //till here From b26fd44f55ab85578be70c46cc2948bbe5ba6d00 Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Thu, 12 Mar 2026 12:50:13 -0400 Subject: [PATCH 389/866] fix missing GL1 fallback in KFParticle_nTuple fillBranch --- .../KFParticle_sPHENIX/KFParticle_nTuple.cc | 36 +++++++++++++------ .../KFParticle_sPHENIX/KFParticle_nTuple.h | 1 - .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 9 +++-- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 3 +- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index f6ae689aa9..88216d356d 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -663,25 +663,41 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, PHNode* evtNode = nodeIter.findFirst("EventHeader"); - if (evtNode) + if (evtNode) + { + EventHeader* evtHeader = findNode::getClass(topNode, "EventHeader"); + if (evtHeader) { - EventHeader* evtHeader = findNode::getClass(topNode, "EventHeader"); m_runNumber = evtHeader->get_RunNumber(); m_evtNumber = evtHeader->get_EvtSequence(); + } + else + { + m_runNumber = -1; + m_evtNumber = -1; + } - auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); - if (!gl1packet) - { - gl1packet = findNode::getClass(topNode, "GL1Packet"); - } - m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; - //m_bco = m_trigger_info_available ? gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0] : 0; + auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); + if (!gl1packet) + { + gl1packet = findNode::getClass(topNode, "GL1Packet"); + } + if (gl1packet) + { + m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; } else { - m_runNumber = m_evtNumber = m_bco = -1; + m_bco = -1; } +} + else + { + m_runNumber = -1; + m_evtNumber = -1; + m_bco = -1; + } if (m_trigger_info_available) { diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h index 7c3f4088fe..f63e60a021 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h @@ -9,7 +9,6 @@ #include #include // for string #include - class PHCompositeNode; class TTree; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 15a0a5f33e..151a97f494 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -166,7 +166,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) { const int64_t run = evtHeader->get_RunNumber(); const int64_t evn = evtHeader->get_EvtSequence(); - m_this_event_bco = static_cast(gl1packet->lValue(0, "BCO")); + m_this_event_bco = static_cast(gl1packet->lValue(0, "BCO")); if (Verbosity() >= VERBOSITY_SOME) { @@ -181,9 +181,9 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) std::cout << "New event detected" << std::endl; std::cout << "Previous event BCO: " << m_prev_event_bco << std::endl; } - // m_last_event_bco = m_prev_event_bco; - m_last_event_bco = (run == m_prev_runNumber) ? m_prev_event_bco : -1; - m_prev_event_bco = m_this_event_bco; + //m_last_event_bco = m_prev_event_bco; + m_last_event_bco = (run == m_prev_runNumber) ? m_prev_event_bco : -1; + m_prev_event_bco = m_this_event_bco; m_prev_runNumber = run; m_prev_eventNumber = evn; @@ -208,7 +208,6 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) m_prev_event_bco = -1; m_prev_runNumber = -1; m_prev_eventNumber = -1; - } // End BCO matching here if (!m_use_fake_pv) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 46aa1e4cef..175d5143f2 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -44,6 +44,7 @@ #include #include // for pair #include // for vector +#include //include for new member added class PHCompositeNode; class TFile; @@ -424,7 +425,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K int candidateCounter = 0; //Adding member variables for BCO matching int64_t m_this_event_bco{-1}; - int64_t m_last_event_bco_sPHENIX{-1}; + int64_t m_last_event_bco{-1}; int64_t m_prev_event_bco{-1}; int64_t m_prev_runNumber{-1}; int64_t m_prev_eventNumber{-1}; //till here From 58657424ae3201f439fb2c6cb842290c5692ff8c Mon Sep 17 00:00:00 2001 From: devloom Date: Thu, 12 Mar 2026 19:22:21 -0400 Subject: [PATCH 390/866] empty commit From 00bd415c70c0426dd28119501288368c7b66cb41 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Thu, 12 Mar 2026 21:54:56 -0400 Subject: [PATCH 391/866] Add null check for DBInterface::instance()->getStatement() --- offline/packages/intt/InttCombinedRawDataDecoder.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 8757bf3727..c90e24433f 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -138,6 +138,16 @@ int InttCombinedRawDataDecoder::InitRun(PHCompositeNode* topNode) int run_number = rc->get_IntFlag("RUNNUMBER"); odbc::Statement* statement = DBInterface::instance()->getStatement("daq"); + if (!statement) + { + std::cerr << PHWHERE << "\n" + << "\tCould not get ODBC statement for 'daq' database\n" + << "\tExiting\n" + << std::flush; + exit(1); + gSystem->Exit(1); + } + if (DACValue_set_count == 0){ std::cout<< PHWHERE << ", " << "No manual setting for DAC values. Querying INTT DAC values from intt_setting table for run number " << run_number << std::endl; int error_count = InttCombinedRawDataDecoder::QueryAllDACValues(statement, run_number); From be7309c08fe17ebe0854c8733a4d069f09e2ca54 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Thu, 12 Mar 2026 22:23:05 -0400 Subject: [PATCH 392/866] Have an universal way to check the DAC-value vector. --- offline/packages/intt/InttCombinedRawDataDecoder.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index c90e24433f..4049db7bfa 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -152,7 +152,13 @@ int InttCombinedRawDataDecoder::InitRun(PHCompositeNode* topNode) std::cout<< PHWHERE << ", " << "No manual setting for DAC values. Querying INTT DAC values from intt_setting table for run number " << run_number << std::endl; int error_count = InttCombinedRawDataDecoder::QueryAllDACValues(statement, run_number); - if (error_count != 0 || m_intt_dac_values.size() != 8 || std::find(m_intt_dac_values.begin(), m_intt_dac_values.end(), -1) != m_intt_dac_values.end()) + int count_minus = 0; + for (const auto& dac_value : m_intt_dac_values) + { + if (dac_value <= 0) {count_minus++;} + } + + if (error_count != 0 || m_intt_dac_values.size() != 8 || count_minus != 0) { std::cerr << PHWHERE << "\n" << "\tError retrieving DAC values. error_count: " << error_count @@ -506,7 +512,7 @@ void InttCombinedRawDataDecoder::set_DACValues(std::vector input_dac_vec) } std::cout << std::endl; - if ( m_intt_dac_values.size() != 8 || count_minus != 0){ + if (m_intt_dac_values.size() != 8 || count_minus != 0){ std::cerr << PHWHERE << "\n" << "\tError: DAC values were set by user, but it should be 8 integers and all should be positive. Please check your input. Exiting. \n" << "\tThe current input DAC values are: "; From 3745b3f89a402fb1eec593d83f708f32cbf1ea69 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Thu, 12 Mar 2026 22:59:37 -0400 Subject: [PATCH 393/866] To check if the row is not found in the table --- .../intt/InttCombinedRawDataDecoder.cc | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 4049db7bfa..72c7e931dd 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -537,19 +537,20 @@ int InttCombinedRawDataDecoder::QueryAllDACValues(odbc::Statement *statement, in { std::string sql = "SELECT dac0, dac1, dac2, dac3, dac4, dac5, dac6, dac7 From intt_setting WHERE runnumber = " + std::to_string(runnumber) + ";"; result_set = std::unique_ptr(statement->executeQuery(sql)); - if (result_set && result_set->next()) + + if (!(result_set && result_set->next())) { - for (int i = 0; i < 8; i++) - { - std::string column_name = "dac" + std::to_string(i); - int DAC_value = -1; - - DAC_value = result_set->getInt(column_name.c_str()); - - m_intt_dac_values.push_back(DAC_value); - - std::cout<< PHWHERE << ", retrieved DAC value for " << column_name << ": " << DAC_value << std::endl; - } + std::cerr << PHWHERE << "\n" + << "\tNo DAC row found in intt_setting for run " << runnumber << std::endl; + return 1; + } + for (int i = 0; i < 8; i++) + { + std::string column_name = "dac" + std::to_string(i); + int DAC_value = -1; + DAC_value = result_set->getInt(column_name.c_str()); + m_intt_dac_values.push_back(DAC_value); + std::cout << PHWHERE << ", retrieved DAC value for " << column_name << ": " << DAC_value << std::endl; } } catch (odbc::SQLException& e) From 92ff610bec299e9b02f86f28dba8bd71b49dc022 Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Fri, 13 Mar 2026 11:39:51 -0400 Subject: [PATCH 394/866] Fix uint64_t initialization --- .../KFParticle_sPHENIX/KFParticle_nTuple.cc | 62 +++++++++---------- .../KFParticle_sPHENIX/KFParticle_nTuple.h | 6 +- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 7 ++- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index 88216d356d..b3b119e4f6 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -663,41 +663,41 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, PHNode* evtNode = nodeIter.findFirst("EventHeader"); - if (evtNode) - { - EventHeader* evtHeader = findNode::getClass(topNode, "EventHeader"); - if (evtHeader) - { - m_runNumber = evtHeader->get_RunNumber(); - m_evtNumber = evtHeader->get_EvtSequence(); - } - else - { - m_runNumber = -1; - m_evtNumber = -1; - } - - auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); - if (!gl1packet) - { - gl1packet = findNode::getClass(topNode, "GL1Packet"); - } - - if (gl1packet) - { - m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; + if (evtNode) + { + EventHeader* evtHeader = findNode::getClass(topNode, "EventHeader"); + if (evtHeader) + { + m_runNumber = evtHeader->get_RunNumber(); + m_evtNumber = evtHeader->get_EvtSequence(); + } + else + { + m_runNumber = -1; + m_evtNumber = -1; + } + + auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); + if (!gl1packet) + { + gl1packet = findNode::getClass(topNode, "GL1Packet"); + } + + if (gl1packet) + { + m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; + } + else + { + m_bco = -1; + } } else { - m_bco = -1; + m_runNumber = -1; + m_evtNumber = -1; + m_bco = -1; } -} - else - { - m_runNumber = -1; - m_evtNumber = -1; - m_bco = -1; - } if (m_trigger_info_available) { diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h index f63e60a021..45256fc1cc 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h @@ -9,6 +9,8 @@ #include #include // for string #include +#include // fixed width integer types used for BCO counters + class PHCompositeNode; class TTree; @@ -225,8 +227,8 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ int m_runNumber{-1}; int m_evtNumber{-1}; int64_t m_bco{-1}; - int64_t m_event_bco{-1};//current event BCO - int64_t m_last_event_bco{-1}; //only keeping this, BCO for the last event + uint64_t m_event_bco{0};//current event BCO + uint64_t m_last_event_bco{0}; //only keeping this, BCO for the last event bool m_trigger_info_available{false}; }; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 175d5143f2..0812ed8f14 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -45,6 +45,7 @@ #include // for pair #include // for vector #include //include for new member added +#include // fixed width integer types used for BCO counters class PHCompositeNode; class TFile; @@ -424,9 +425,9 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K bool m_save_output; int candidateCounter = 0; //Adding member variables for BCO matching - int64_t m_this_event_bco{-1}; - int64_t m_last_event_bco{-1}; - int64_t m_prev_event_bco{-1}; + uint64_t m_this_event_bco{0}; + uint64_t m_last_event_bco{0}; + uint64_t m_prev_event_bco{0}; int64_t m_prev_runNumber{-1}; int64_t m_prev_eventNumber{-1}; //till here std::string m_outfile_name; From ef8b389830cfe352b575c09549ee141cd7ffa112 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 13 Mar 2026 17:18:00 -0400 Subject: [PATCH 395/866] fix clang-tidy --- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 151a97f494..db46bffafe 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -137,14 +137,17 @@ int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) { - std::vector mother, vertex_kfparticle; - std::vector> daughters, intermediates; - int nPVs, multiplicity; + std::vector mother; + std::vector vertex_kfparticle; + std::vector> daughters; + std::vector> intermediates; + int nPVs; + int multiplicity; SvtxTrackMap *check_trackmap = findNode::getClass(topNode, m_trk_map_node_name); multiplicity = check_trackmap->size(); - if (check_trackmap->size() == 0) + if (check_trackmap->empty()) { if (Verbosity() >= VERBOSITY_SOME) { @@ -215,7 +218,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) if (m_use_mbd_vertex) { MbdVertexMap* check_vertexmap = findNode::getClass(topNode, "MbdVertexMap"); - if (check_vertexmap->size() == 0) + if (check_vertexmap->empty()) { if (Verbosity() >= VERBOSITY_SOME) { @@ -227,7 +230,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) else { SvtxVertexMap* check_vertexmap = findNode::getClass(topNode, m_vtx_map_node_name); - if (check_vertexmap->size() == 0) + if (check_vertexmap->empty()) { if (Verbosity() >= VERBOSITY_SOME) { @@ -248,7 +251,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) vertex_kfparticle = mother; } - if (mother.size() != 0) + if (!mother.empty()) { for (unsigned int i = 0; i < mother.size(); ++i) { @@ -538,7 +541,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() setNumberOfTracks(nTracks); setDaughters(daughter_list); - if (intermediates_name.size() > 0) + if (!intermediates_name.empty()) { hasIntermediateStates(); setIntermediateStates(intermediate_list); @@ -554,15 +557,14 @@ int KFParticle_sPHENIX::parseDecayDescriptor() } return 0; } - else + + if (Verbosity() >= VERBOSITY_SOME) { - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "KFParticle: Your decay descriptor, " << Name() << " cannot be parsed" - << "\nExiting!" << std::endl; - } - return Fun4AllReturnCodes::ABORTRUN; + std::cout << "KFParticle: Your decay descriptor, " << Name() << " cannot be parsed" + << "\nExiting!" << std::endl; } + return Fun4AllReturnCodes::ABORTRUN; + } void KFParticle_sPHENIX::getField() From 5a9c3c96c5819cb0586e2b51e4449634580bb5ce Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Sat, 14 Mar 2026 04:42:55 -0400 Subject: [PATCH 396/866] cosmetics update --- offline/packages/intt/InttCombinedRawDataDecoder.cc | 4 ++-- offline/packages/intt/InttCombinedRawDataDecoder.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 72c7e931dd..401a20629b 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -498,7 +498,7 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) } -void InttCombinedRawDataDecoder::set_DACValues(std::vector input_dac_vec) +void InttCombinedRawDataDecoder::set_DACValues(const std::vector& input_dac_vec) { m_intt_dac_values = input_dac_vec; DACValue_set_count = 1; @@ -548,7 +548,7 @@ int InttCombinedRawDataDecoder::QueryAllDACValues(odbc::Statement *statement, in { std::string column_name = "dac" + std::to_string(i); int DAC_value = -1; - DAC_value = result_set->getInt(column_name.c_str()); + DAC_value = result_set->getInt(column_name); m_intt_dac_values.push_back(DAC_value); std::cout << PHWHERE << ", retrieved DAC value for " << column_name << ": " << DAC_value << std::endl; } diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.h b/offline/packages/intt/InttCombinedRawDataDecoder.h index c38badefeb..3bbdfe502d 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.h +++ b/offline/packages/intt/InttCombinedRawDataDecoder.h @@ -66,7 +66,7 @@ class InttCombinedRawDataDecoder : public SubsysReco void set_bcoFilter(bool flag) {m_bcoFilter = flag; } void set_SaturatedChipRejection(bool flag){m_SaturatedChipRejection = flag;} // note : this is for removing a fraction of the saturated chips void set_HighChipMultiplicityCut(int cut){HighChipMultiplicityCut = cut;} - void set_DACValues(std::vector input_dac_vec); + void set_DACValues(const std::vector& input_dac_vec); private: int QueryAllDACValues(odbc::Statement *statement, int runnumber); From 2cec1df2b8f48113244281a7c380446d739a0072 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 16 Mar 2026 12:36:41 -0400 Subject: [PATCH 397/866] fix clang-tidy --- offline/packages/TrackingDiagnostics/KshortReconstruction.cc | 2 +- offline/packages/TrackingDiagnostics/KshortReconstruction.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index cb344e7851..6efbebf100 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -473,7 +473,7 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float m float cos_theta_reco = pathLength_proj.dot(projected_momentum) / (projected_momentum.norm() * pathLength_proj.norm()); - float reco_info[] = {(float) track1->get_id(), (float) mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), (float) mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; + float reco_info[] = {(float) track1->get_id(), mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; ntp_reco_info->Fill(reco_info); } diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.h b/offline/packages/TrackingDiagnostics/KshortReconstruction.h index 95eba65b02..27d6e3f601 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.h +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.h @@ -54,7 +54,7 @@ class KshortReconstruction : public SubsysReco // void fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); - void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymass1, float& decaymass2); + void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymassa, float& decaymassb); // void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity); From c7440ec0cb80778b043b335ae12fff5d9ab29a11 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 16 Mar 2026 16:09:35 -0400 Subject: [PATCH 398/866] make listPayloadIOVs useful --- offline/database/sphenixnpc/CDBUtils.cc | 30 +++++++++++++++++++++---- offline/database/sphenixnpc/CDBUtils.h | 12 +++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 080812b419..1c01b501d3 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -75,23 +75,45 @@ int CDBUtils::createPayloadType(const std::string &pt) return cdbclient->createDomain(pt); } -void CDBUtils::listPayloadIOVs(uint64_t iov) +auto CDBUtils::PayloadIOVsCommon(uint64_t iov, const std::string ptype) { + std::map> iovs; nlohmann::json resp = cdbclient->getPayloadIOVs(iov); if (resp["code"] != 0) { std::cout << resp["msg"] << std::endl; - return; + return iovs; } nlohmann::json payload_iovs = resp["msg"]; - std::map> iovs; for (auto &[pt, val] : payload_iovs.items()) { std::string url = val["payload_url"]; uint64_t bts = val["minor_iov_start"]; uint64_t ets = val["minor_iov_end"]; - iovs.insert(std::make_pair(pt, std::make_tuple(url, bts, ets))); + if (ets >= iov) + { + if (!ptype.empty()) + { + if (ptype != pt) + { + continue; + } + } + iovs.insert(std::make_pair(pt, std::make_tuple(url, bts, ets))); + } } + return iovs; +} + +auto CDBUtils::returnPayloadIOVs(uint64_t iov, const std::string ptype) +{ + auto iovs = PayloadIOVsCommon(iov,ptype); + return iovs; +} + +void CDBUtils::listPayloadIOVs(uint64_t iov, const std::string ptype) +{ + auto iovs = PayloadIOVsCommon(iov,ptype); for (const auto &it : iovs) { std::cout << it.first << ": " << std::get<0>(it.second) diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 393036236c..133fbc34fb 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -27,11 +27,9 @@ class CDBUtils int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); int cloneGlobalTag(const std::string &source, const std::string &target); - int deleteGlobalTag(const std::string &); void listGlobalTags(); void listPayloadTypes(); - void listPayloadIOVs(uint64_t iov); void clearCache(); bool isGlobalTagSet(); void Verbosity(int i); @@ -39,9 +37,13 @@ class CDBUtils int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start); int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start, uint64_t iov_end); - private: - int m_Verbosity = 0; - SphenixClient *cdbclient = nullptr; + auto returnPayloadIOVs(uint64_t iov, const std::string ptype = ""); + auto PayloadIOVsCommon(uint64_t iov, const std::string ptype = ""); + void listPayloadIOVs(uint64_t iov, const std::string ptype = ""); + +private: + int m_Verbosity {0}; + SphenixClient *cdbclient {nullptr}; std::string m_CachedGlobalTag; std::set m_PayloadTypeCache; }; From 193a51c1763400515054aa28ed7d5e1d0eb23e0d Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Mon, 16 Mar 2026 16:13:26 -0400 Subject: [PATCH 399/866] Add subtracted iso --- .../packages/CaloReco/PhotonClusterBuilder.cc | 52 ++++++++++++++++++- .../packages/CaloReco/PhotonClusterBuilder.h | 5 ++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.cc b/offline/packages/CaloReco/PhotonClusterBuilder.cc index edcf5f4418..8171c2cbce 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.cc +++ b/offline/packages/CaloReco/PhotonClusterBuilder.cc @@ -117,6 +117,19 @@ int PhotonClusterBuilder::InitRun(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTRUN; } + if (m_do_subtracted_iso) + { + m_emc_sub1_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC_RETOWER_SUB1"); + m_ihcal_sub1_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALIN_SUB1"); + m_ohcal_sub1_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALOUT_SUB1"); + + if (!m_emc_sub1_tower_container || !m_ihcal_sub1_tower_container || !m_ohcal_sub1_tower_container) + { + std::cout << Name() << ": subtracted isolation enabled but one or more SUB1 tower nodes are missing; " + << "iso_sub_* values will remain at " << m_subtracted_iso_defval << std::endl; + } + } + CreateNodes(topNode); return Fun4AllReturnCodes::EVENT_OK; } @@ -323,7 +336,7 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster nsaturated++; } } - + int totalphibins = 256; auto dphiwrap = [totalphibins](int towerphi, int maxiphi_arg) { @@ -435,7 +448,7 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster float e72 = 0; float detacog = std::abs(maxieta - avg_eta); float dphicog = std::abs(maxiphi - avg_phi); - float drad = std::sqrt(dphicog*dphicog + detacog*detacog); + float drad = std::sqrt(dphicog * dphicog + detacog * detacog); int signphi = (avg_phi - std::floor(avg_phi)) > 0.5 ? 1 : -1; @@ -767,6 +780,41 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster photon->set_shower_shape_parameter("iso_02_emcal", emcal_et_02 - ET); photon->set_shower_shape_parameter("iso_01_emcal", emcal_et_01 - ET); photon->set_shower_shape_parameter("iso_005_emcal", emcal_et_005 - ET); + + photon->set_shower_shape_parameter("iso_sub_04_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_04_hcalin", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_04_hcalout", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_03_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_03_hcalin", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_03_hcalout", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_02_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_01_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_005_emcal", m_subtracted_iso_defval); + + if (m_do_subtracted_iso && m_emc_sub1_tower_container && m_ihcal_sub1_tower_container && m_ohcal_sub1_tower_container) + { + const float sub_emcal_et_04 = calculate_layer_et(cluster_eta, cluster_phi, 0.4, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ihcal_et_04 = calculate_layer_et(cluster_eta, cluster_phi, 0.4, m_ihcal_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ohcal_et_04 = calculate_layer_et(cluster_eta, cluster_phi, 0.4, m_ohcal_sub1_tower_container, m_geomOH, RawTowerDefs::CalorimeterId::HCALOUT, m_vertex); + + const float sub_emcal_et_03 = calculate_layer_et(cluster_eta, cluster_phi, 0.3, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ihcal_et_03 = calculate_layer_et(cluster_eta, cluster_phi, 0.3, m_ihcal_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ohcal_et_03 = calculate_layer_et(cluster_eta, cluster_phi, 0.3, m_ohcal_sub1_tower_container, m_geomOH, RawTowerDefs::CalorimeterId::HCALOUT, m_vertex); + + const float sub_emcal_et_02 = calculate_layer_et(cluster_eta, cluster_phi, 0.2, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_emcal_et_01 = calculate_layer_et(cluster_eta, cluster_phi, 0.1, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_emcal_et_005 = calculate_layer_et(cluster_eta, cluster_phi, 0.05, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + + photon->set_shower_shape_parameter("iso_sub_04_emcal", sub_emcal_et_04 - ET); + photon->set_shower_shape_parameter("iso_sub_04_hcalin", sub_ihcal_et_04); + photon->set_shower_shape_parameter("iso_sub_04_hcalout", sub_ohcal_et_04); + photon->set_shower_shape_parameter("iso_sub_03_emcal", sub_emcal_et_03 - ET); + photon->set_shower_shape_parameter("iso_sub_03_hcalin", sub_ihcal_et_03); + photon->set_shower_shape_parameter("iso_sub_03_hcalout", sub_ohcal_et_03); + photon->set_shower_shape_parameter("iso_sub_02_emcal", sub_emcal_et_02 - ET); + photon->set_shower_shape_parameter("iso_sub_01_emcal", sub_emcal_et_01 - ET); + photon->set_shower_shape_parameter("iso_sub_005_emcal", sub_emcal_et_005 - ET); + } } double PhotonClusterBuilder::getTowerEta(RawTowerGeom* tower_geom, double vx, double vy, double vz) diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.h b/offline/packages/CaloReco/PhotonClusterBuilder.h index 1c987f9849..c788220871 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.h +++ b/offline/packages/CaloReco/PhotonClusterBuilder.h @@ -53,6 +53,7 @@ class PhotonClusterBuilder : public SubsysReco double deltaR(double eta1, double phi1, double eta2, double phi2); float calculate_layer_et(float seed_eta, float seed_phi, float radius, TowerInfoContainer* towerContainer, RawTowerGeomContainer* geomContainer, RawTowerDefs::CalorimeterId calo_id, float vertex_z); bool m_do_bdt{false}; + bool m_do_subtracted_iso{false}; std::string m_input_cluster_node{"CLUSTERINFO_CEMC"}; std::string m_output_photon_node{"PHOTONCLUSTER_CEMC"}; @@ -61,6 +62,7 @@ class PhotonClusterBuilder : public SubsysReco std::string m_bdt_model_file{"myBDT_5.root"}; std::vector m_bdt_feature_list; float m_vertex{std::numeric_limits::quiet_NaN()}; + float m_subtracted_iso_defval{-999}; RawClusterContainer* m_rawclusters{nullptr}; RawClusterContainer* m_photon_container{nullptr}; @@ -70,6 +72,9 @@ class PhotonClusterBuilder : public SubsysReco RawTowerGeomContainer* m_geomIH{nullptr}; TowerInfoContainer* m_ohcal_tower_container{nullptr}; RawTowerGeomContainer* m_geomOH{nullptr}; + TowerInfoContainer* m_emc_sub1_tower_container{nullptr}; + TowerInfoContainer* m_ihcal_sub1_tower_container{nullptr}; + TowerInfoContainer* m_ohcal_sub1_tower_container{nullptr}; std::unique_ptr m_bdt; }; From 8cfb34773daf361ba5e31612b717a502e604f624 Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Mon, 16 Mar 2026 16:16:02 -0400 Subject: [PATCH 400/866] Add subtracted iso --- offline/packages/CaloReco/PhotonClusterBuilder.h | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.h b/offline/packages/CaloReco/PhotonClusterBuilder.h index c788220871..b9a9baed50 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.h +++ b/offline/packages/CaloReco/PhotonClusterBuilder.h @@ -42,6 +42,7 @@ class PhotonClusterBuilder : public SubsysReco void set_bdt_model_file(const std::string& path) { m_bdt_model_file = path; } void set_bdt_feature_list(const std::vector& features) { m_bdt_feature_list = features; } void set_do_bdt(bool do_bdt) { m_do_bdt = do_bdt; } + void set_do_subtracted_iso(bool do_subtracted_iso) { m_do_subtracted_iso = do_subtracted_iso; } const std::vector& get_bdt_feature_list() const { return m_bdt_feature_list; } private: From 7cb76f940471f85e7580395acea3f885c8825d22 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 17 Mar 2026 09:28:33 -0400 Subject: [PATCH 401/866] fix cppcheck --- offline/database/sphenixnpc/CDBUtils.cc | 6 +++--- offline/database/sphenixnpc/CDBUtils.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 1c01b501d3..4a2865545a 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -75,7 +75,7 @@ int CDBUtils::createPayloadType(const std::string &pt) return cdbclient->createDomain(pt); } -auto CDBUtils::PayloadIOVsCommon(uint64_t iov, const std::string ptype) +auto CDBUtils::PayloadIOVsCommon(uint64_t iov, const std::string &ptype) { std::map> iovs; nlohmann::json resp = cdbclient->getPayloadIOVs(iov); @@ -105,13 +105,13 @@ auto CDBUtils::PayloadIOVsCommon(uint64_t iov, const std::string ptype) return iovs; } -auto CDBUtils::returnPayloadIOVs(uint64_t iov, const std::string ptype) +auto CDBUtils::returnPayloadIOVs(uint64_t iov, const std::string &ptype) { auto iovs = PayloadIOVsCommon(iov,ptype); return iovs; } -void CDBUtils::listPayloadIOVs(uint64_t iov, const std::string ptype) +void CDBUtils::listPayloadIOVs(uint64_t iov, const std::string &ptype) { auto iovs = PayloadIOVsCommon(iov,ptype); for (const auto &it : iovs) diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 133fbc34fb..616e115c54 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -37,9 +37,9 @@ class CDBUtils int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start); int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start, uint64_t iov_end); - auto returnPayloadIOVs(uint64_t iov, const std::string ptype = ""); - auto PayloadIOVsCommon(uint64_t iov, const std::string ptype = ""); - void listPayloadIOVs(uint64_t iov, const std::string ptype = ""); + auto returnPayloadIOVs(uint64_t iov, const std::string &ptype = ""); + auto PayloadIOVsCommon(uint64_t iov, const std::string &ptype = ""); + void listPayloadIOVs(uint64_t iov, const std::string &ptype = ""); private: int m_Verbosity {0}; From b6159de46060b3b67af32cedf235652a5f439805 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 17 Mar 2026 10:38:13 -0400 Subject: [PATCH 402/866] add new herwig and double interactions --- offline/framework/frog/CreateFileList.pl | 214 ++++++++++++++++++++++- 1 file changed, 212 insertions(+), 2 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index e0eaa402f3..47dd8f7990 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -41,7 +41,7 @@ my %proddesc = ( # "1" => "hijing (0-12fm) pileup 0-12fm DELETED", # "2" => "hijing (0-4.88fm) pileup 0-12fm DELETED", - "3" => "pythia8 pp MB", +# "3" => "pythia8 pp MB", "4" => "hijing (0-20fm) pileup 0-20fm", # "5" => "hijing (0-12fm) pileup 0-20fm DELETED", "6" => "hijing (0-4.88fm) pileup 0-20fm", @@ -77,7 +77,14 @@ "36" => "JS pythia8 Jet ptmin = 5GeV", "37" => "hijing O+O (0-15fm)", "38" => "JS pythia8 Jet ptmin = 60GeV", - "39" => "JS pythia8 Jet ptmin = 12GeV" + "39" => "JS pythia8 Jet ptmin = 12GeV", + "40" => "Herwig Jet ptmin = 5 GeV", + "41" => "Herwig Jet ptmin = 12 GeV", + "42" => "Herwig Jet ptmin = 20 GeV", + "43" => "Herwig Jet ptmin = 40 GeV", + "44" => "Herwig Jet ptmin = 50 GeV", + "45" => "JS pythia8 ptmin = 12GeV + Detroit", + "46" => "JS pythia8 Photonjet ptmin = 10GeV + Detroit" ); my %pileupdesc = ( @@ -1005,6 +1012,209 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 40) + { + $embedok = 1; + $filenamestring = "Herwig_Jet5"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 41) + { + $embedok = 1; + $filenamestring = "Herwig_Jet12"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 42) + { + $embedok = 1; + $filenamestring = "Herwig_Jet20"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 43) + { + $embedok = 1; + $filenamestring = "Herwig_Jet40"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 44) + { + $embedok = 1; + $filenamestring = "Herwig_Jet50"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 45) + { + $embedok = 1; + $filenamestring = "pythia8_Jet12_pythia8_Detroit"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 46) + { + $embedok = 1; + $filenamestring = "pythia8_PhotonJet10_pythia8_Detroit"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { From 63192a838a9a3c87eb89b2d4f9703f9e5d6414a0 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Tue, 17 Mar 2026 12:45:19 -0400 Subject: [PATCH 403/866] Update GlobalVertexv3.cc --- offline/packages/globalvertex/GlobalVertexv3.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/offline/packages/globalvertex/GlobalVertexv3.cc b/offline/packages/globalvertex/GlobalVertexv3.cc index 1504a7cd3d..4eca34c62c 100644 --- a/offline/packages/globalvertex/GlobalVertexv3.cc +++ b/offline/packages/globalvertex/GlobalVertexv3.cc @@ -128,7 +128,12 @@ float GlobalVertexv3::get_position(unsigned int coor) const auto caloit = _vtxs.find(GlobalVertex::VTXTYPE::CALO); if (caloit == _vtxs.end()) { - return std::numeric_limits::quiet_NaN(); + auto truthit = _vtxs.find(GlobalVertex::VTXTYPE::TRUTH); + if (truthit == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + return truthit->second[0]->get_position(coor); } return caloit->second[0]->get_position(coor); } From 1643e870621d982ab43b97fb111caed5b57cae1a Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 17 Mar 2026 12:51:09 -0400 Subject: [PATCH 404/866] fix memory leak at exit, use uniq_ptr --- offline/database/sphenixnpc/CDBUtils.cc | 4 ++-- offline/database/sphenixnpc/CDBUtils.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 4a2865545a..997b00e5c2 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -12,12 +12,12 @@ #include // for pair, make_pair CDBUtils::CDBUtils() - : cdbclient(new SphenixClient()) + : cdbclient(std::make_unique()) { } CDBUtils::CDBUtils(const std::string &globaltag) - : cdbclient(new SphenixClient(globaltag)) + : cdbclient(std::make_unique(globaltag)) { } diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 616e115c54..3c4f877c9d 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -2,6 +2,7 @@ #define SPHENIXNPC_CDBUTILS_H #include // for uint64_t +#include #include #include @@ -43,7 +44,7 @@ class CDBUtils private: int m_Verbosity {0}; - SphenixClient *cdbclient {nullptr}; + std::unique_ptr cdbclient; std::string m_CachedGlobalTag; std::set m_PayloadTypeCache; }; From 31baa72e67b5122c70d44e892803a84f96763a70 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 17 Mar 2026 14:26:10 -0400 Subject: [PATCH 405/866] change first OO run from 82374 to 82388 after trigger was finalized --- offline/framework/phool/RunnumberRange.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index 0a447f259b..d582a4e935 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -29,7 +29,7 @@ namespace RunnumberRange static const int RUN3AUAU_LAST = 78954; static const int RUN3PP_FIRST = 79146; // first beam data static const int RUN3PP_LAST = 81668; - static const int RUN3OO_FIRST = 82374; + static const int RUN3OO_FIRST = 82388; // after trigger settled down (run 82374 excluded); static const int RUN3OO_LAST = 82703; } From fbdf9c6dea0d2698600252ab07b1cea368a85d78 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 17 Mar 2026 15:07:55 -0400 Subject: [PATCH 406/866] use constexpr instead of static const --- offline/framework/phool/RunnumberRange.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index d582a4e935..ab6593bff5 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -20,17 +20,17 @@ */ namespace RunnumberRange { - static const int RUN2PP_FIRST = 47286; - static const int RUN2PP_LAST = 53880; - static const int RUN2AUAU_FIRST = 54128; - static const int RUN2AUAU_LAST = 54974; - static const int RUN3_TPCFW_CLOCK_CHANGE = 58667; - static const int RUN3AUAU_FIRST = 66457; - static const int RUN3AUAU_LAST = 78954; - static const int RUN3PP_FIRST = 79146; // first beam data - static const int RUN3PP_LAST = 81668; - static const int RUN3OO_FIRST = 82388; // after trigger settled down (run 82374 excluded); - static const int RUN3OO_LAST = 82703; + constexpr int RUN2PP_FIRST = 47286; + constexpr int RUN2PP_LAST = 53880; + constexpr int RUN2AUAU_FIRST = 54128; + constexpr int RUN2AUAU_LAST = 54974; + constexpr int RUN3_TPCFW_CLOCK_CHANGE = 58667; + constexpr int RUN3AUAU_FIRST = 66457; + constexpr int RUN3AUAU_LAST = 78954; + constexpr int RUN3PP_FIRST = 79146; // first beam data + constexpr int RUN3PP_LAST = 81668; + constexpr int RUN3OO_FIRST = 82388; // after trigger settled down (run 82374 excluded); + constexpr int RUN3OO_LAST = 82703; } #endif From 6a8cc05188a4aaa3a2ff3caa6a70b3f154651819 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 17 Mar 2026 15:21:57 -0400 Subject: [PATCH 407/866] fixes --- offline/database/sphenixnpc/CDBUtils.cc | 14 ++++---------- offline/database/sphenixnpc/CDBUtils.h | 4 ++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 997b00e5c2..4608605e7c 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -75,7 +75,7 @@ int CDBUtils::createPayloadType(const std::string &pt) return cdbclient->createDomain(pt); } -auto CDBUtils::PayloadIOVsCommon(uint64_t iov, const std::string &ptype) +std::map> CDBUtils::PayloadIOVs(uint64_t iov, const std::string &ptype) { std::map> iovs; nlohmann::json resp = cdbclient->getPayloadIOVs(iov); @@ -90,11 +90,11 @@ auto CDBUtils::PayloadIOVsCommon(uint64_t iov, const std::string &ptype) std::string url = val["payload_url"]; uint64_t bts = val["minor_iov_start"]; uint64_t ets = val["minor_iov_end"]; - if (ets >= iov) + if (ets > iov) { if (!ptype.empty()) { - if (ptype != pt) + if (pt.find(ptype) == std::string::npos) { continue; } @@ -105,15 +105,9 @@ auto CDBUtils::PayloadIOVsCommon(uint64_t iov, const std::string &ptype) return iovs; } -auto CDBUtils::returnPayloadIOVs(uint64_t iov, const std::string &ptype) -{ - auto iovs = PayloadIOVsCommon(iov,ptype); - return iovs; -} - void CDBUtils::listPayloadIOVs(uint64_t iov, const std::string &ptype) { - auto iovs = PayloadIOVsCommon(iov,ptype); + auto iovs = PayloadIOVs(iov,ptype); for (const auto &it : iovs) { std::cout << it.first << ": " << std::get<0>(it.second) diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 3c4f877c9d..0e6272fab1 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -2,6 +2,7 @@ #define SPHENIXNPC_CDBUTILS_H #include // for uint64_t +#include #include #include #include @@ -38,8 +39,7 @@ class CDBUtils int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start); int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start, uint64_t iov_end); - auto returnPayloadIOVs(uint64_t iov, const std::string &ptype = ""); - auto PayloadIOVsCommon(uint64_t iov, const std::string &ptype = ""); + std::map> PayloadIOVs(uint64_t iov, const std::string &ptype = ""); void listPayloadIOVs(uint64_t iov, const std::string &ptype = ""); private: From 54589d3163e44d4f5ed574bed5989546b28a1989 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Wed, 18 Mar 2026 05:22:21 -0400 Subject: [PATCH 408/866] Add a function to universally mask the INTT chip --- offline/packages/intt/InttCombinedRawDataDecoder.cc | 13 +++++++++++++ offline/packages/intt/InttCombinedRawDataDecoder.h | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 401a20629b..4ffd06f8e1 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -351,6 +351,19 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) continue; } + if (std::find(permanant_mask_chip.begin(), permanant_mask_chip.end(), std::format("{}_{}_{}", raw.felix_server, raw.felix_channel, raw.chip)) != permanant_mask_chip.end()) + { + if (1 < Verbosity()) + { + std::cout + << PHWHERE << "\n" + << "\tMasking permanant bad chip due to timing issues:\n" + << "\t" << raw.felix_server << " " << raw.felix_channel << " " << raw.chip << " " << raw.channel << "\n" + << std::endl; + } + continue; + } + //////////////////////// // bco filter if (m_bcomap.IsBad(raw, bco_full, bco) && m_bcoFilter) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.h b/offline/packages/intt/InttCombinedRawDataDecoder.h index 3bbdfe502d..642f2edafa 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.h +++ b/offline/packages/intt/InttCombinedRawDataDecoder.h @@ -95,6 +95,10 @@ class InttCombinedRawDataDecoder : public SubsysReco std::map evt_ChipHit_count_map; int HighChipMultiplicityCut = 71; + std::vector permanant_mask_chip = { + "2_9_15" // note : FELIX 2, FELIX channel 9, chip 15 (chip ID range: 0 to 25) + }; + }; #endif // INTT_COMBINEDRAWDATADECODER_H From 190096403d27d3945a10b6bace28d4220fb1d320 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 18 Mar 2026 09:53:31 -0400 Subject: [PATCH 409/866] empty commit to trigger jenkins From ce2fb5e92715feace19bd7d6012e75b950c5dcfe Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Wed, 18 Mar 2026 14:15:48 -0400 Subject: [PATCH 410/866] CaloCDB: Migrate FilterDatasets from CDBUtils to CDBInterface - Removed CDBUtils dependency: Deleted the std::unique_ptr member and removed its associated header from filter-datasets - Integrated CDBInterface: Updated getCalibration to utilize the CDBInterface::instance()->getUrl() method. - Managed Global State via recoConsts: - Updated getCalibration to dynamically set the TIMESTAMP flag in recoConsts for each IOV to ensure the correct calibration version is retrieved. - Initialized the CDB_GLOBALTAG flag within the main function of CaloCDB-FilterDatasets.cc. - Resolved Header Conflicts: Eliminated the destructor requirement that triggered the incomplete type error in the unique_ptr cleanup. --- .../calo_cdb/CaloCDB-FilterDatasets.cc | 5 ++++ calibrations/calorimeter/calo_cdb/Makefile.am | 1 + .../calorimeter/calo_cdb/filter-datasets.cc | 29 +++++-------------- .../calorimeter/calo_cdb/filter-datasets.h | 9 +----- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc b/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc index 8528cd26ae..31c3ba7798 100644 --- a/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc +++ b/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc @@ -1,5 +1,7 @@ #include "filter-datasets.h" +#include + #include int main(int argc, const char* const argv[]) @@ -28,6 +30,9 @@ int main(int argc, const char* const argv[]) debug = std::stoi(args[3]); } + recoConsts* rc = recoConsts::instance(); + rc->set_StringFlag("CDB_GLOBALTAG", "newcdbtag"); + FilterDatasets filter(debug); filter.process(input_csv, output_dir_path); diff --git a/calibrations/calorimeter/calo_cdb/Makefile.am b/calibrations/calorimeter/calo_cdb/Makefile.am index 9fbea67179..23e990440f 100644 --- a/calibrations/calorimeter/calo_cdb/Makefile.am +++ b/calibrations/calorimeter/calo_cdb/Makefile.am @@ -35,6 +35,7 @@ libcalo_cdb_la_LIBADD = \ -lcalo_io \ -lcdbobjects \ -lsphenixnpc \ + -lffamodules \ -lemcNoisyTowerFinder CaloCDB_GenStatus_SOURCES = CaloCDB-GenStatus.cc diff --git a/calibrations/calorimeter/calo_cdb/filter-datasets.cc b/calibrations/calorimeter/calo_cdb/filter-datasets.cc index 38ce957c4e..9dfbf442e3 100644 --- a/calibrations/calorimeter/calo_cdb/filter-datasets.cc +++ b/calibrations/calorimeter/calo_cdb/filter-datasets.cc @@ -4,11 +4,9 @@ // -- My Utils -- #include "myUtils.h" -// c++ includes -- -#include -#include -#include -#include +// sPHENIX includes -- +#include +#include FilterDatasets::FilterDatasets(Bool_t debug) : m_debug(debug) @@ -30,21 +28,12 @@ void FilterDatasets::readRunInfo(const std::string &line) std::string FilterDatasets::getCalibration(const std::string &pl_type, uint64_t iov) { - if (!uti) - { - uti = std::make_unique(); - } - return uti->getUrl(pl_type, iov); -} + recoConsts *rc = recoConsts::instance(); + // Update the global timestamp flag for the current run in the loop + rc->set_uint64Flag("TIMESTAMP", iov); -int FilterDatasets::setGlobalTag(const std::string &tagname) -{ - if (!uti) - { - uti = std::make_unique(); - } - int iret = uti->setGlobalTag(tagname); - return iret; + // Fetch the calibration URL via CDBInterface + return CDBInterface::instance()->getUrl(pl_type); } void FilterDatasets::analyze(const std::string &input, const std::string &outputDir) @@ -142,8 +131,6 @@ void FilterDatasets::process(const std::string &input, const std::string &output std::cout << "Debug: " << ((m_debug) ? "True" : "False") << std::endl; std::cout << "#############################" << std::endl; - setGlobalTag("newcdbtag"); - std::filesystem::path input_filepath_obj(input); if (!myUtils::readCSV(input_filepath_obj, [this](const std::string &line) { this->readRunInfo(line); })) diff --git a/calibrations/calorimeter/calo_cdb/filter-datasets.h b/calibrations/calorimeter/calo_cdb/filter-datasets.h index c3af89f1de..c4d9fa21f4 100644 --- a/calibrations/calorimeter/calo_cdb/filter-datasets.h +++ b/calibrations/calorimeter/calo_cdb/filter-datasets.h @@ -1,17 +1,13 @@ #ifndef CALOCDB_FILTERDATASETS_H #define CALOCDB_FILTERDATASETS_H -// -- sPHENIX includes -- -#include - // -- ROOT includes -- #include // -- c++ includes -- #include -#include +#include #include -#include #include class FilterDatasets @@ -26,7 +22,6 @@ class FilterDatasets void readRunInfo(const std::string &line); std::string getCalibration(const std::string &pl_type, uint64_t iov); - int setGlobalTag(const std::string &tagname); std::vector> m_runInfo; std::map m_ctr; @@ -37,8 +32,6 @@ class FilterDatasets , "CEMC_ZSCrossCalib", "HCALIN_ZSCrossCalib", "HCALOUT_ZSCrossCalib"}; Bool_t m_debug; - - std::unique_ptr uti{nullptr}; }; #endif From 265c26e9e0cb9eabf26ce52636ed0118253ad750 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Mar 2026 14:31:31 -0400 Subject: [PATCH 411/866] add fee masking to tpc time builder --- offline/framework/fun4allraw/Makefile.am | 4 +- .../fun4allraw/SingleTpcTimeFrameInput.cc | 37 +++++++++++++++++++ .../fun4allraw/SingleTpcTimeFrameInput.h | 4 +- .../fun4allraw/TpcTimeFrameBuilder.cc | 6 +++ .../fun4allraw/TpcTimeFrameBuilder.h | 16 ++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/offline/framework/fun4allraw/Makefile.am b/offline/framework/fun4allraw/Makefile.am index ef0c1b54a2..7f852ce989 100644 --- a/offline/framework/fun4allraw/Makefile.am +++ b/offline/framework/fun4allraw/Makefile.am @@ -100,7 +100,9 @@ libfun4allraw_la_LIBADD = \ -lfun4all \ -lEvent \ -lphoolraw \ - -lqautils + -lqautils \ + -lffamodules \ + -lcdbobjects BUILT_SOURCES = testexternals.cc diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index 03e83f4cd0..85ebd6f6b2 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -13,6 +13,8 @@ #include #include +#include +#include #include // for PHTimer #include @@ -64,6 +66,9 @@ SingleTpcTimeFrameInput::SingleTpcTimeFrameInput(const std::string &name) assert(i <= 20); m_hNorm->GetXaxis()->LabelsOption("v"); hm->registerHisto(m_hNorm); + + + fillBadFeeMap(); } SingleTpcTimeFrameInput::~SingleTpcTimeFrameInput() @@ -293,6 +298,7 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) m_TpcTimeFrameBuilderMap[packet_id] = new TpcTimeFrameBuilder(packet_id); m_TpcTimeFrameBuilderMap[packet_id]->setVerbosity(Verbosity()); + fillBadFeeMap(); if (!m_digitalCurrentDebugTTreeName.empty()) { m_TpcTimeFrameBuilderMap[packet_id]->SaveDigitalCurrentDebugTTree(m_digitalCurrentDebugTTreeName); @@ -396,3 +402,34 @@ void SingleTpcTimeFrameInput::ConfigureStreamingInputManager() } return; } + +void SingleTpcTimeFrameInput::fillBadFeeMap() +{ +const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); + +// map of ebdc to std::set to mask +std::map> maskedFEEs; + +if (filename.empty()) +{ + if (Verbosity() > 0) + { + std::cout << "SingleTpcTimeFrameInput::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; + } + return; + } + + CDBTTree cdbtree(filename); + cdbtree.LoadCalibrations(); + + const int nentries = cdbtree.GetSingleIntValue("N_MASKED_FEES"); + + for(int i=0; isetMaskedFEEs(maskedFEEs); + } +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index e1f9ded3dd..bb78722a09 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -41,10 +41,12 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput { m_digitalCurrentDebugTTreeName = name; } + private: const int NTPCPACKETS = 3; + void fillBadFeeMap(); Packet **plist{nullptr}; unsigned int m_NumSpecialEvents{0}; unsigned int m_BcoRange{0}; @@ -53,7 +55,7 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput //! packet ID -> TimeFrame builder std::map m_TpcTimeFrameBuilderMap; std::set m_SelectedPacketIDs; - + TH1 *m_hNorm = nullptr; PHTimer *m_FillPoolTimer = nullptr; diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index 309e7bf391..9f8721b0a7 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -595,6 +595,12 @@ int TpcTimeFrameBuilder::ProcessPacket(Packet* packet) if ((dma_word_data.dma_header & 0xFF00U) == FEE_MAGIC_KEY) { unsigned int fee_id = dma_word_data.dma_header & 0xffU; + + // for packet id 4XYZ ebdc is XY, endpoint is Z + if (m_maskedFEEs[((m_packet_id / 10) % 100)].contains(fee_id)) + { + continue; + } if (fee_id < MAX_FEECOUNT) { diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index 553052b851..79902e9932 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -40,6 +40,20 @@ class TpcTimeFrameBuilder { m_fastBCOSkip = fastBCOSkip; } + void setMaskedFEEs(const std::map> &maskedFEEs) + { + m_maskedFEEs = maskedFEEs; + + + for(const auto& [ebdc, feeset]: m_maskedFEEs) + { + std::cout << "checking ebdc " << ebdc << std::endl; + for(const auto& feeid : feeset) + { + std::cout << "fee id in set: " << feeid << std::endl; + } + } + } // enable saving of digital current debug TTree with file name `name` void SaveDigitalCurrentDebugTTree(const std::string &name); @@ -371,6 +385,8 @@ class TpcTimeFrameBuilder private: std::vector> m_feeData; + std::map> m_maskedFEEs; + int m_verbosity = 0; int m_packet_id = 0; From 6f1a2fc91dc430145192073be7955df18515c3f4 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Mar 2026 14:33:24 -0400 Subject: [PATCH 412/866] remove debug statements --- .../framework/fun4allraw/SingleTpcTimeFrameInput.cc | 2 -- offline/framework/fun4allraw/TpcTimeFrameBuilder.h | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index 85ebd6f6b2..ea131cd4bc 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -67,8 +67,6 @@ SingleTpcTimeFrameInput::SingleTpcTimeFrameInput(const std::string &name) m_hNorm->GetXaxis()->LabelsOption("v"); hm->registerHisto(m_hNorm); - - fillBadFeeMap(); } SingleTpcTimeFrameInput::~SingleTpcTimeFrameInput() diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index 79902e9932..a608687a96 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -43,16 +43,6 @@ class TpcTimeFrameBuilder void setMaskedFEEs(const std::map> &maskedFEEs) { m_maskedFEEs = maskedFEEs; - - - for(const auto& [ebdc, feeset]: m_maskedFEEs) - { - std::cout << "checking ebdc " << ebdc << std::endl; - for(const auto& feeid : feeset) - { - std::cout << "fee id in set: " << feeid << std::endl; - } - } } // enable saving of digital current debug TTree with file name `name` From 57e77e0ff3b81ffea3f0eebb8bbe5db19a53a724 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Mar 2026 14:33:50 -0400 Subject: [PATCH 413/866] clang-format --- .../fun4allraw/SingleTpcTimeFrameInput.cc | 21 +++++++------ .../fun4allraw/SingleTpcTimeFrameInput.h | 9 +++--- .../fun4allraw/TpcTimeFrameBuilder.cc | 2 +- .../fun4allraw/TpcTimeFrameBuilder.h | 30 +++++++++---------- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index ea131cd4bc..a4f9443c07 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -13,8 +13,8 @@ #include #include -#include #include +#include #include // for PHTimer #include @@ -66,7 +66,6 @@ SingleTpcTimeFrameInput::SingleTpcTimeFrameInput(const std::string &name) assert(i <= 20); m_hNorm->GetXaxis()->LabelsOption("v"); hm->registerHisto(m_hNorm); - } SingleTpcTimeFrameInput::~SingleTpcTimeFrameInput() @@ -403,16 +402,16 @@ void SingleTpcTimeFrameInput::ConfigureStreamingInputManager() void SingleTpcTimeFrameInput::fillBadFeeMap() { -const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); + const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); -// map of ebdc to std::set to mask -std::map> maskedFEEs; + // map of ebdc to std::set to mask + std::map> maskedFEEs; -if (filename.empty()) -{ - if (Verbosity() > 0) + if (filename.empty()) { - std::cout << "SingleTpcTimeFrameInput::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; + if (Verbosity() > 0) + { + std::cout << "SingleTpcTimeFrameInput::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; } return; } @@ -422,11 +421,11 @@ if (filename.empty()) const int nentries = cdbtree.GetSingleIntValue("N_MASKED_FEES"); - for(int i=0; isetMaskedFEEs(maskedFEEs); } diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index bb78722a09..a3c279584f 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -41,7 +41,6 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput { m_digitalCurrentDebugTTreeName = name; } - private: const int NTPCPACKETS = 3; @@ -65,14 +64,14 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput // NOLINTNEXTLINE(hicpp-special-member-functions) class TimeTracker - { + { public: - TimeTracker(PHTimer * timer, const std::string & name, TH1* hout) ; - virtual ~TimeTracker() ; + TimeTracker(PHTimer *timer, const std::string &name, TH1 *hout); + virtual ~TimeTracker(); void stop(); private: - PHTimer * m_timer = nullptr; + PHTimer *m_timer = nullptr; std::string m_name; TH1 *m_hNorm = nullptr; bool stopped = false; diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index 9f8721b0a7..1f76902cb7 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -595,7 +595,7 @@ int TpcTimeFrameBuilder::ProcessPacket(Packet* packet) if ((dma_word_data.dma_header & 0xFF00U) == FEE_MAGIC_KEY) { unsigned int fee_id = dma_word_data.dma_header & 0xffU; - + // for packet id 4XYZ ebdc is XY, endpoint is Z if (m_maskedFEEs[((m_packet_id / 10) % 100)].contains(fee_id)) { diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index a608687a96..751818eb97 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -54,7 +54,7 @@ class TpcTimeFrameBuilder static const uint16_t FEE_PACKET_MAGIC_KEY_1 = 0xfe; static const uint16_t FEE_PACKET_MAGIC_KEY_2 = 0xed; - static const uint16_t FEE_PACKET_MAGIC_KEY_3_DC = 0xdcdc; // Digital Current word[3] + static const uint16_t FEE_PACKET_MAGIC_KEY_3_DC = 0xdcdc; // Digital Current word[3] static const uint16_t FEE_MAGIC_KEY = 0xba00; static const uint16_t GTM_MAGIC_KEY = 0xbb00; @@ -85,8 +85,8 @@ class TpcTimeFrameBuilder int decode_gtm_data(const dma_word >m_word); int process_fee_data(unsigned int fee_id); - void process_fee_data_waveform(const unsigned int & fee_id, std::deque& data_buffer); - void process_fee_data_digital_current(const unsigned int & fee_id, std::deque& data_buffer); + void process_fee_data_waveform(const unsigned int &fee_id, std::deque &data_buffer); + void process_fee_data_digital_current(const unsigned int &fee_id, std::deque &data_buffer); struct gtm_payload { @@ -116,7 +116,7 @@ class TpcTimeFrameBuilder uint16_t data_crc = 0; uint16_t calc_crc = 0; - + uint16_t data_parity = 0; uint16_t calc_parity = 0; @@ -127,18 +127,18 @@ class TpcTimeFrameBuilder { static const int MAX_CHANNELS = 8; - uint64_t gtm_bco {std::numeric_limits::max()}; - uint32_t bx_timestamp_predicted {std::numeric_limits::max()}; + uint64_t gtm_bco{std::numeric_limits::max()}; + uint32_t bx_timestamp_predicted{std::numeric_limits::max()}; - uint16_t fee {std::numeric_limits::max()}; - uint16_t pkt_length {std::numeric_limits::max()}; - uint16_t channel {std::numeric_limits::max()}; + uint16_t fee{std::numeric_limits::max()}; + uint16_t pkt_length{std::numeric_limits::max()}; + uint16_t channel{std::numeric_limits::max()}; // uint16_t sampa_max_channel {std::numeric_limits::max()}; - uint16_t sampa_address {std::numeric_limits::max()}; - uint32_t bx_timestamp {0}; - uint32_t current[MAX_CHANNELS] {0}; - uint32_t nsamples[MAX_CHANNELS] {0}; - uint16_t data_crc {std::numeric_limits::max()}; + uint16_t sampa_address{std::numeric_limits::max()}; + uint32_t bx_timestamp{0}; + uint32_t current[MAX_CHANNELS]{0}; + uint32_t nsamples[MAX_CHANNELS]{0}; + uint16_t data_crc{std::numeric_limits::max()}; uint16_t calc_crc = {std::numeric_limits::max()}; // uint16_t type {std::numeric_limits::max()}; }; @@ -157,7 +157,7 @@ class TpcTimeFrameBuilder std::string m_name; TTree *m_tDigitalCurrent = nullptr; }; - DigitalCurrentDebugTTree * m_digitalCurrentDebugTTree = nullptr; + DigitalCurrentDebugTTree *m_digitalCurrentDebugTTree = nullptr; // ------------------------- // GTM Matcher From ef21e3fa2bdab2fd1baa12689ee1932192ed01cc Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Mar 2026 14:42:41 -0400 Subject: [PATCH 414/866] refactor everything into the time frame builder --- .../fun4allraw/SingleTpcTimeFrameInput.cc | 35 +------------------ .../fun4allraw/TpcTimeFrameBuilder.cc | 29 +++++++++++++++ .../fun4allraw/TpcTimeFrameBuilder.h | 6 ++-- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index a4f9443c07..dd9559b075 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -13,8 +13,6 @@ #include #include -#include -#include #include // for PHTimer #include @@ -295,7 +293,7 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) m_TpcTimeFrameBuilderMap[packet_id] = new TpcTimeFrameBuilder(packet_id); m_TpcTimeFrameBuilderMap[packet_id]->setVerbosity(Verbosity()); - fillBadFeeMap(); + m_TpcTimeFrameBuilderMap[packet_id]->fillBadFeeMap(); if (!m_digitalCurrentDebugTTreeName.empty()) { m_TpcTimeFrameBuilderMap[packet_id]->SaveDigitalCurrentDebugTTree(m_digitalCurrentDebugTTreeName); @@ -399,34 +397,3 @@ void SingleTpcTimeFrameInput::ConfigureStreamingInputManager() } return; } - -void SingleTpcTimeFrameInput::fillBadFeeMap() -{ - const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); - - // map of ebdc to std::set to mask - std::map> maskedFEEs; - - if (filename.empty()) - { - if (Verbosity() > 0) - { - std::cout << "SingleTpcTimeFrameInput::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; - } - return; - } - - CDBTTree cdbtree(filename); - cdbtree.LoadCalibrations(); - - const int nentries = cdbtree.GetSingleIntValue("N_MASKED_FEES"); - - for (int i = 0; i < nentries; i++) - { - maskedFEEs[cdbtree.GetIntValue(i, "EBDC")].insert(cdbtree.GetIntValue(i, "FEEID")); - } - for (const auto &[packet, tb] : m_TpcTimeFrameBuilderMap) - { - tb->setMaskedFEEs(maskedFEEs); - } -} \ No newline at end of file diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index 1f76902cb7..fc39fcace7 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -8,6 +8,9 @@ #include #include +#include +#include + #include // for PHTimer #include @@ -2062,3 +2065,29 @@ void TpcTimeFrameBuilder::BcoMatchingInformation::cleanup(uint64_t ref_bco) // clear orphans m_orphans.clear(); } + + +void TpcTimeFrameBuilder::fillBadFeeMap() +{ + const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); + + if (filename.empty()) + { + if (m_verbosity > 0) + { + std::cout << "TpcTimeFrameBuilder::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; + } + return; + } + + CDBTTree cdbtree(filename); + cdbtree.LoadCalibrations(); + + const int nentries = cdbtree.GetSingleIntValue("N_MASKED_FEES"); + + for (int i = 0; i < nentries; i++) + { + m_maskedFEEs[cdbtree.GetIntValue(i, "EBDC")].insert(cdbtree.GetIntValue(i, "FEEID")); + } + +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index 751818eb97..3da4ad4d19 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -40,11 +40,9 @@ class TpcTimeFrameBuilder { m_fastBCOSkip = fastBCOSkip; } - void setMaskedFEEs(const std::map> &maskedFEEs) - { - m_maskedFEEs = maskedFEEs; - } + void fillBadFeeMap(); + // enable saving of digital current debug TTree with file name `name` void SaveDigitalCurrentDebugTTree(const std::string &name); From 9b0ab1c0b8cba7d9dbc235654441a2eb7023421a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Mar 2026 14:44:04 -0400 Subject: [PATCH 415/866] remove unnecessary function --- offline/framework/fun4allraw/SingleTpcTimeFrameInput.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index a3c279584f..8460a6473b 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -44,8 +44,7 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput private: const int NTPCPACKETS = 3; - - void fillBadFeeMap(); + Packet **plist{nullptr}; unsigned int m_NumSpecialEvents{0}; unsigned int m_BcoRange{0}; From f947ccde161a826340a055b40dc4a39e8b5e5fd2 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Mar 2026 14:44:48 -0400 Subject: [PATCH 416/866] clang-format --- offline/framework/fun4allraw/SingleTpcTimeFrameInput.h | 2 +- offline/framework/fun4allraw/TpcTimeFrameBuilder.cc | 2 -- offline/framework/fun4allraw/TpcTimeFrameBuilder.h | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index 8460a6473b..e9e10cae59 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -44,7 +44,7 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput private: const int NTPCPACKETS = 3; - + Packet **plist{nullptr}; unsigned int m_NumSpecialEvents{0}; unsigned int m_BcoRange{0}; diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index fc39fcace7..e068899771 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -2066,7 +2066,6 @@ void TpcTimeFrameBuilder::BcoMatchingInformation::cleanup(uint64_t ref_bco) m_orphans.clear(); } - void TpcTimeFrameBuilder::fillBadFeeMap() { const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); @@ -2089,5 +2088,4 @@ void TpcTimeFrameBuilder::fillBadFeeMap() { m_maskedFEEs[cdbtree.GetIntValue(i, "EBDC")].insert(cdbtree.GetIntValue(i, "FEEID")); } - } \ No newline at end of file diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index 3da4ad4d19..07e2921310 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -42,7 +42,7 @@ class TpcTimeFrameBuilder } void fillBadFeeMap(); - + // enable saving of digital current debug TTree with file name `name` void SaveDigitalCurrentDebugTTree(const std::string &name); From ed2c67b8d5759ca1d532fd6f3fa581f169066a1d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 18 Mar 2026 15:50:01 -0400 Subject: [PATCH 417/866] cleanup --- .../calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc | 6 ++++-- calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc | 3 ++- .../calo_cdb/{filter-datasets.cc => FilterDatasets.cc} | 8 +++++++- .../calo_cdb/{filter-datasets.h => FilterDatasets.h} | 7 ++----- .../calorimeter/calo_cdb/{genStatus.cc => GenStatus.cc} | 3 +-- .../calorimeter/calo_cdb/{genStatus.h => GenStatus.h} | 0 calibrations/calorimeter/calo_cdb/Makefile.am | 8 ++++---- calibrations/calorimeter/calo_cdb/myUtils.cc | 3 +++ calibrations/calorimeter/calo_cdb/myUtils.h | 7 ++++--- 9 files changed, 27 insertions(+), 18 deletions(-) rename calibrations/calorimeter/calo_cdb/{filter-datasets.cc => FilterDatasets.cc} (96%) rename calibrations/calorimeter/calo_cdb/{filter-datasets.h => FilterDatasets.h} (89%) rename calibrations/calorimeter/calo_cdb/{genStatus.cc => GenStatus.cc} (99%) rename calibrations/calorimeter/calo_cdb/{genStatus.h => GenStatus.h} (100%) diff --git a/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc b/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc index 31c3ba7798..56df96e205 100644 --- a/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc +++ b/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc @@ -1,8 +1,10 @@ -#include "filter-datasets.h" +#include "FilterDatasets.h" #include #include +#include +#include int main(int argc, const char* const argv[]) { @@ -19,7 +21,7 @@ int main(int argc, const char* const argv[]) const std::string& input_csv = args[1]; std::string output_dir_path = "."; - Bool_t debug = false; + bool debug = false; if (args.size() >= 3) { diff --git a/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc b/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc index 335563c295..49bf3e3c4f 100644 --- a/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc +++ b/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc @@ -1,6 +1,7 @@ -#include "genStatus.h" +#include "GenStatus.h" #include +#include #include int main(int argc, const char* const argv[]) diff --git a/calibrations/calorimeter/calo_cdb/filter-datasets.cc b/calibrations/calorimeter/calo_cdb/FilterDatasets.cc similarity index 96% rename from calibrations/calorimeter/calo_cdb/filter-datasets.cc rename to calibrations/calorimeter/calo_cdb/FilterDatasets.cc index 9dfbf442e3..5ac745f0e8 100644 --- a/calibrations/calorimeter/calo_cdb/filter-datasets.cc +++ b/calibrations/calorimeter/calo_cdb/FilterDatasets.cc @@ -1,5 +1,5 @@ -#include "filter-datasets.h" +#include "FilterDatasets.h" // -- My Utils -- #include "myUtils.h" @@ -8,6 +8,12 @@ #include #include +#include +#include +#include +#include +#include + FilterDatasets::FilterDatasets(Bool_t debug) : m_debug(debug) { diff --git a/calibrations/calorimeter/calo_cdb/filter-datasets.h b/calibrations/calorimeter/calo_cdb/FilterDatasets.h similarity index 89% rename from calibrations/calorimeter/calo_cdb/filter-datasets.h rename to calibrations/calorimeter/calo_cdb/FilterDatasets.h index c4d9fa21f4..c92485e75e 100644 --- a/calibrations/calorimeter/calo_cdb/filter-datasets.h +++ b/calibrations/calorimeter/calo_cdb/FilterDatasets.h @@ -1,9 +1,6 @@ #ifndef CALOCDB_FILTERDATASETS_H #define CALOCDB_FILTERDATASETS_H -// -- ROOT includes -- -#include - // -- c++ includes -- #include #include @@ -13,7 +10,7 @@ class FilterDatasets { public: - explicit FilterDatasets(Bool_t debug = false); + explicit FilterDatasets(bool debug = false); void process(const std::string &input, const std::string &output = "."); @@ -31,7 +28,7 @@ class FilterDatasets , "CEMC_hotTowers_fracBadChi2", "HCALIN_hotTowers_fracBadChi2", "HCALOUT_hotTowers_fracBadChi2" , "CEMC_ZSCrossCalib", "HCALIN_ZSCrossCalib", "HCALOUT_ZSCrossCalib"}; - Bool_t m_debug; + bool m_debug; }; #endif diff --git a/calibrations/calorimeter/calo_cdb/genStatus.cc b/calibrations/calorimeter/calo_cdb/GenStatus.cc similarity index 99% rename from calibrations/calorimeter/calo_cdb/genStatus.cc rename to calibrations/calorimeter/calo_cdb/GenStatus.cc index a49703127a..a5cdf538f6 100644 --- a/calibrations/calorimeter/calo_cdb/genStatus.cc +++ b/calibrations/calorimeter/calo_cdb/GenStatus.cc @@ -1,4 +1,4 @@ -#include "genStatus.h" +#include "GenStatus.h" #include "geometry_constants.h" @@ -15,7 +15,6 @@ // c++ includes -- #include #include -#include #include #include diff --git a/calibrations/calorimeter/calo_cdb/genStatus.h b/calibrations/calorimeter/calo_cdb/GenStatus.h similarity index 100% rename from calibrations/calorimeter/calo_cdb/genStatus.h rename to calibrations/calorimeter/calo_cdb/GenStatus.h diff --git a/calibrations/calorimeter/calo_cdb/Makefile.am b/calibrations/calorimeter/calo_cdb/Makefile.am index 23e990440f..e54424f4ae 100644 --- a/calibrations/calorimeter/calo_cdb/Makefile.am +++ b/calibrations/calorimeter/calo_cdb/Makefile.am @@ -16,8 +16,8 @@ AM_LDFLAGS = \ `root-config --libs` pkginclude_HEADERS = \ - genStatus.h \ - filter-datasets.h \ + GenStatus.h \ + FilterDatasets.h \ geometry_constants.h \ myUtils.h @@ -25,8 +25,8 @@ lib_LTLIBRARIES = \ libcalo_cdb.la libcalo_cdb_la_SOURCES = \ - genStatus.cc \ - filter-datasets.cc \ + GenStatus.cc \ + FilterDatasets.cc \ myUtils.cc libcalo_cdb_la_LIBADD = \ diff --git a/calibrations/calorimeter/calo_cdb/myUtils.cc b/calibrations/calorimeter/calo_cdb/myUtils.cc index 21a37ed595..3f495a4e7d 100644 --- a/calibrations/calorimeter/calo_cdb/myUtils.cc +++ b/calibrations/calorimeter/calo_cdb/myUtils.cc @@ -4,9 +4,12 @@ // root includes -- #include #include +#include +#include // c++ includes -- #include +#include TFitResultPtr myUtils::doGausFit(TH1 *hist, Double_t start, Double_t end, const std::string &name) { diff --git a/calibrations/calorimeter/calo_cdb/myUtils.h b/calibrations/calorimeter/calo_cdb/myUtils.h index 2799ab808f..a44d61984e 100644 --- a/calibrations/calorimeter/calo_cdb/myUtils.h +++ b/calibrations/calorimeter/calo_cdb/myUtils.h @@ -2,18 +2,19 @@ #define CALOCDB_MYUTILS_H // ROOT includes -- +#include #include -#include // -- c++ includes -- #include #include #include -#include #include #include #include +class TH1; + template concept InvocableWithString = std::invocable; @@ -39,7 +40,7 @@ class myUtils * @return true if the file was successfully opened and read, false otherwise. */ template // Using the more general concept for wider applicability - static Bool_t readCSV(const std::filesystem::path& filePath, Callable lineHandler, Bool_t skipHeader = true) + static bool readCSV(const std::filesystem::path& filePath, Callable lineHandler, bool skipHeader = true) { std::ifstream file(filePath); From cea59d00c328005edb502f46033076e322a69f82 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 18 Mar 2026 21:43:34 -0400 Subject: [PATCH 418/866] trigger jenkins From d30a8d5dd4bb978a955a3840ade3f6ccc1cd0a4f Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:50:19 -0400 Subject: [PATCH 419/866] CaloCDB: Refactor header installation in Makefile.am - Public Headers (pkginclude_HEADERS): Retained GenStatus.h and geometry_constants.h because they are required for external macro execution in `runProd.C`. - Private Headers (noinst_HEADERS): Moved FilterDatasets.h and myUtils.h to noinst_HEADERS to prevent unnecessary global installation of internal utilities. --- calibrations/calorimeter/calo_cdb/Makefile.am | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/calibrations/calorimeter/calo_cdb/Makefile.am b/calibrations/calorimeter/calo_cdb/Makefile.am index e54424f4ae..0107211521 100644 --- a/calibrations/calorimeter/calo_cdb/Makefile.am +++ b/calibrations/calorimeter/calo_cdb/Makefile.am @@ -15,10 +15,14 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib64 \ `root-config --libs` +# Headers installed for use in macros and by other packages pkginclude_HEADERS = \ GenStatus.h \ + geometry_constants.h + +# Headers used only for building this library and its binaries +noinst_HEADERS = \ FilterDatasets.h \ - geometry_constants.h \ myUtils.h lib_LTLIBRARIES = \ From 8aedf7bbd2756209407cc60d0381bfb6d7885220 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Fri, 20 Mar 2026 00:23:16 -0400 Subject: [PATCH 420/866] Add get_position to truthvertex This was another reason using get_z on the global vertex returned NaN for type=truth. Now it works (tested privately) --- .../packages/globalvertex/TruthVertex_v1.cc | 18 ++++++++++++++++++ offline/packages/globalvertex/TruthVertex_v1.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/offline/packages/globalvertex/TruthVertex_v1.cc b/offline/packages/globalvertex/TruthVertex_v1.cc index 38e9b2a61b..1c1ad39f4d 100644 --- a/offline/packages/globalvertex/TruthVertex_v1.cc +++ b/offline/packages/globalvertex/TruthVertex_v1.cc @@ -15,3 +15,21 @@ int TruthVertex_v1::isValid() const { return std::isfinite(_z) && std::isfinite(_t); } + +float TruthVertex_v1::get_position(unsigned int coor) const +{ + if (coor == 0) + { + return get_x(); + } + if (coor == 1) + { + return get_y(); + } + if (coor == 2) + { + return get_z(); + } + + return std::numeric_limits::quiet_NaN(); +} \ No newline at end of file diff --git a/offline/packages/globalvertex/TruthVertex_v1.h b/offline/packages/globalvertex/TruthVertex_v1.h index 42b48d9903..ec18a8b053 100644 --- a/offline/packages/globalvertex/TruthVertex_v1.h +++ b/offline/packages/globalvertex/TruthVertex_v1.h @@ -46,6 +46,8 @@ class TruthVertex_v1 : public TruthVertex float get_y_err() const override { return _y_err; } void set_y_err(float y_err) override { _y_err = y_err; } + float get_position(unsigned int coor) const override; + private: unsigned int _id{std::numeric_limits::max()}; float _t{std::numeric_limits::quiet_NaN()}; From c996608763386c4f71bcb6b5a6c8c15cd1b33839 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar <137448289+nk7252@users.noreply.github.com> Date: Fri, 20 Mar 2026 00:30:57 -0400 Subject: [PATCH 421/866] Update offline/packages/globalvertex/TruthVertex_v1.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- offline/packages/globalvertex/TruthVertex_v1.h | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/globalvertex/TruthVertex_v1.h b/offline/packages/globalvertex/TruthVertex_v1.h index ec18a8b053..e5148387af 100644 --- a/offline/packages/globalvertex/TruthVertex_v1.h +++ b/offline/packages/globalvertex/TruthVertex_v1.h @@ -47,7 +47,6 @@ class TruthVertex_v1 : public TruthVertex void set_y_err(float y_err) override { _y_err = y_err; } float get_position(unsigned int coor) const override; - private: unsigned int _id{std::numeric_limits::max()}; float _t{std::numeric_limits::quiet_NaN()}; From 25804ae7ac8124b2122796f0bf82458312cfd2df Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 20 Mar 2026 15:06:34 -0400 Subject: [PATCH 422/866] add flag for double interaction samples --- offline/framework/frog/CreateFileList.pl | 83 ++++++------------------ 1 file changed, 20 insertions(+), 63 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 47dd8f7990..6d297598c1 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -82,9 +82,7 @@ "41" => "Herwig Jet ptmin = 12 GeV", "42" => "Herwig Jet ptmin = 20 GeV", "43" => "Herwig Jet ptmin = 40 GeV", - "44" => "Herwig Jet ptmin = 50 GeV", - "45" => "JS pythia8 ptmin = 12GeV + Detroit", - "46" => "JS pythia8 Photonjet ptmin = 10GeV + Detroit" + "44" => "Herwig Jet ptmin = 50 GeV" ); my %pileupdesc = ( @@ -112,6 +110,7 @@ my $pmax; my $production; my $momentum; +my $double; # that should teach me a lesson to not give a flag an optional string value # just using embed:s leads to the next ARGV to be used as argument, even if it # is the next option. Sadly getopt swallows the - so parsing this becomes @@ -149,7 +148,7 @@ $iarg++; } @ARGV=@newargs; -GetOptions('embed:s' => \$embed, 'l:i' => \$last_segment, 'momentum:s' => \$momentum, 'n:i' => \$nEvents, "nobkgpileup" => \$nobkgpileup, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); +GetOptions('double' => \$double, 'embed:s' => \$embed, 'l:i' => \$last_segment, 'momentum:s' => \$momentum, 'n:i' => \$nEvents, "nobkgpileup" => \$nobkgpileup, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); my $filenamestring; my %filetypes = (); my %notlike = (); @@ -215,6 +214,7 @@ } my $embedok = 0; +my $doubleok = 0; if (defined $prodtype) { @@ -683,6 +683,11 @@ { $embedok = 1; $filenamestring = "pythia8_PhotonJet10"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = "pythia8_PhotonJet10_pythia8_Detroit"; + } if (! defined $nopileup) { if (defined $embed) @@ -987,6 +992,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet12"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = "pythia8_Jet12_pythia8_Detroit"; + } if (! defined $nopileup) { if (defined $embed) @@ -1157,65 +1167,6 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } - elsif ($prodtype == 45) - { - $embedok = 1; - $filenamestring = "pythia8_Jet12_pythia8_Detroit"; - if (! defined $nopileup) - { - if (defined $embed) - { - if ($embed eq "pau") - { - $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); - } - elsif ($embed eq "central") - { - $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); - } - else - { - $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); - } - } - else - { - $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); - } - } - $pileupstring = $pp_pileupstring; - &commonfiletypes(); - } - elsif ($prodtype == 46) - { - $embedok = 1; - $filenamestring = "pythia8_PhotonJet10_pythia8_Detroit"; - if (! defined $nopileup) - { - if (defined $embed) - { - if ($embed eq "pau") - { - $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); - } - elsif ($embed eq "central") - { - $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); - } - else - { - $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); - } - } - else - { - $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); - } - } - $pileupstring = $pp_pileupstring; - &commonfiletypes(); - } - else { print "no production type $prodtype\n"; @@ -1229,6 +1180,11 @@ print "Embedding not implemented for type $prodtype\n"; exit(1); } +if (defined $double && ! $doubleok) +{ + print "Double interactions not implemented for type $prodtype\n"; + exit(1); +} my $filenamestring_with_runnumber = sprintf("%s\-%010d-",$filenamestring,$runnumber); if ($#ARGV < 0) @@ -1237,6 +1193,7 @@ { print "usage: CreateFileLists.pl -type \n"; print "parameters:\n"; + print "-double : double interactions, pp of your type and Detroit pp\n"; print "-embed : pp embedded into MB AuAu hijing (only for pp types)\n"; print " -embed pau : embedded into pAu (only for pp types)\n"; print " -embed central : embedded into central AuAu\n"; From e4802c58ebbb1eef94d12c654068e828c9ffc927 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 20 Mar 2026 15:22:08 -0400 Subject: [PATCH 423/866] add oo embedded files --- offline/framework/frog/CreateFileList.pl | 54 +++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 6d297598c1..08ea13e981 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -135,7 +135,7 @@ else { push(@newargs, $argument); - if ($ARGV[$iarg+1] ne "pau" && $ARGV[$iarg+1] ne "auau" && $ARGV[$iarg+1] ne "central") + if ($ARGV[$iarg+1] ne "pau" && $ARGV[$iarg+1] ne "auau" && $ARGV[$iarg+1] ne "central" && $ARGV[$iarg+1] ne "oo" ) { push(@newargs,"auau"); } @@ -328,6 +328,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -357,6 +361,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -523,6 +531,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -566,6 +578,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -666,6 +682,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -700,6 +720,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -729,6 +753,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -845,6 +873,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -874,6 +906,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -903,6 +939,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -932,6 +972,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -975,6 +1019,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -1009,6 +1057,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); From 2686fe3eecafbf45ab0e6fd5400d74e0b0a215ed Mon Sep 17 00:00:00 2001 From: Hao-Ren Jheng Date: Sun, 22 Mar 2026 22:33:21 -0400 Subject: [PATCH 424/866] DecayFinder search fix --- offline/packages/decayfinder/DecayFinder.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index 1593387592..e293b6c37e 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -361,6 +361,9 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) exit(1); } + // correct mother PID to search for match + const int mother_id_to_match = m_getChargeConjugate ? std::abs(m_mother_ID) : m_mother_ID; + if (m_truthinfo && !m_geneventmap) // This should use the truth info container if we have no HepMC record { if (Verbosity() >= VERBOSITY_SOME) @@ -374,7 +377,8 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) { PHG4Particle* g4particle = iter->second; int this_pid = m_getChargeConjugate ? abs(g4particle->get_pid()) : g4particle->get_pid(); - if (this_pid == m_mother_ID) + // if (this_pid == m_mother_ID) + if (this_pid == mother_id_to_match) { if (Verbosity() >= VERBOSITY_MAX) { @@ -455,7 +459,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) for (HepMC::GenEvent::particle_const_iterator p = theEvent->particles_begin(); p != theEvent->particles_end(); ++p) { int this_pid = m_getChargeConjugate ? abs((*p)->pdg_id()) : (*p)->pdg_id(); - if (this_pid == m_mother_ID) + if (this_pid == mother_id_to_match) { if (Verbosity() >= VERBOSITY_MAX) { From de78126e283bf6824684048c6259979c4e221da4 Mon Sep 17 00:00:00 2001 From: Hao-Ren Jheng Date: Sun, 22 Mar 2026 22:39:33 -0400 Subject: [PATCH 425/866] remove comment --- offline/packages/decayfinder/DecayFinder.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index e293b6c37e..a3521df780 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -377,7 +377,6 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) { PHG4Particle* g4particle = iter->second; int this_pid = m_getChargeConjugate ? abs(g4particle->get_pid()) : g4particle->get_pid(); - // if (this_pid == m_mother_ID) if (this_pid == mother_id_to_match) { if (Verbosity() >= VERBOSITY_MAX) From e4ba985f52d1a2d05173420736a81a080d32f6c8 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Mon, 23 Mar 2026 15:38:00 -0400 Subject: [PATCH 426/866] CD: Added new brnanches to HFTrackEfficiency and patched bug --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 50 ++++++++++++------- .../HFTrackEfficiency/HFTrackEfficiency.h | 4 ++ 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index e87d8c500b..09de461fe9 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -214,6 +214,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_true_mother_pT = mother->momentum().perp(); m_true_mother_p = std::sqrt(std::pow(mother->momentum().px(), 2) + std::pow(mother->momentum().py(), 2) + std::pow(mother->momentum().pz(), 2)); // Must have an old HepMC build, no mag function m_true_mother_eta = mother->momentum().eta(); + m_true_mother_phi = mother->momentum().phi(); HepMC::GenVertex *thisVtx = mother->production_vertex(); m_primary_vtx_x = thisVtx->point3d().x(); @@ -229,13 +230,17 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) } } + int index = -1; + for (unsigned int i = 1; i < decay.size(); ++i) { m_dst_track = nullptr; int truth_ID = -1; + if (std::find(std::begin(trackableParticles), std::end(trackableParticles), std::abs(decay[i].second)) != std::end(trackableParticles)) { + ++index; if (theEvent && decay[i].first.second > -1) { HepMC::GenParticle *daughterHepMC = theEvent->barcode_to_particle(decay[i].first.second); @@ -247,7 +252,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterHepMC->momentum().px(), daughterHepMC->momentum().py(), daughterHepMC->momentum().pz()), getParticleMass(decay[i].second)); daughterSumTrueLV += *daughterTrueLV; - m_true_track_PID[i - 1] = daughterHepMC->pdg_id(); + m_true_track_PID[index] = daughterHepMC->pdg_id(); // Now get the decay vertex position HepMC::GenVertex *thisVtx = daughterHepMC->production_vertex(); @@ -306,6 +311,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_true_mother_pT = motherTrueLV->perp(); m_true_mother_p = mother3Vector->mag(); m_true_mother_eta = motherTrueLV->pseudoRapidity(); + m_true_mother_phi = motherTrueLV->phi(); PHG4VtxPoint *thisVtx = m_truthInfo->GetVtx(motherG4->get_vtx_id()); m_primary_vtx_x = thisVtx->get_x(); @@ -321,7 +327,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_y = thisVtx->get_y(); m_secondary_vtx_z = thisVtx->get_z(); - m_true_track_PID[i - 1] = daughterG4->get_pid(); + m_true_track_PID[index] = daughterG4->get_pid(); truth_ID = daughterG4->get_track_id(); delete mother3Vector; @@ -329,10 +335,11 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) } } - m_true_track_pT[i - 1] = (float) daughterTrueLV->perp(); - m_true_track_eta[i - 1] = (float) daughterTrueLV->pseudoRapidity(); - m_min_true_track_pT = std::min(m_true_track_pT[i - 1], m_min_true_track_pT); - m_max_true_track_pT = std::max(m_true_track_pT[i - 1], m_max_true_track_pT); + m_true_track_pT[index] = (float) daughterTrueLV->perp(); + m_true_track_eta[index] = (float) daughterTrueLV->pseudoRapidity(); + m_true_track_phi[index] = (float) daughterTrueLV->phi(); + m_min_true_track_pT = std::min(m_true_track_pT[index], m_min_true_track_pT); + m_max_true_track_pT = std::max(m_true_track_pT[index], m_max_true_track_pT); if (m_dst_truth_reco_map && truth_ID >= 0) { @@ -350,7 +357,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_dst_track = m_input_trackMap->get(best_reco_id); if (m_dst_track) { - m_used_truth_reco_map[i - 1] = true; + m_used_truth_reco_map[index] = true; recoTrackFound = true; } } @@ -378,24 +385,25 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) { m_dst_track->identify(); } - m_reco_track_exists[i - 1] = true; - m_reco_track_pT[i - 1] = m_dst_track->get_pt(); - m_reco_track_eta[i - 1] = m_dst_track->get_eta(); - m_reco_track_chi2nDoF[i - 1] = m_dst_track->get_chisq() / m_dst_track->get_ndf(); + m_reco_track_exists[index] = true; + m_reco_track_pT[index] = m_dst_track->get_pt(); + m_reco_track_eta[index] = m_dst_track->get_eta(); + m_reco_track_phi[index] = m_dst_track->get_phi(); + m_reco_track_chi2nDoF[index] = m_dst_track->get_chisq() / m_dst_track->get_ndf(); if (m_dst_track->get_silicon_seed()) { - m_reco_track_silicon_seeds[i - 1] = static_cast(m_dst_track->get_silicon_seed()->size_cluster_keys()); + m_reco_track_silicon_seeds[index] = static_cast(m_dst_track->get_silicon_seed()->size_cluster_keys()); } else { - m_reco_track_silicon_seeds[i - 1] = 0; + m_reco_track_silicon_seeds[index] = 0; } - m_reco_track_tpc_seeds[i - 1] = static_cast(m_dst_track->get_tpc_seed()->size_cluster_keys()); - m_min_reco_track_pT = std::min(m_reco_track_pT[i - 1], m_min_reco_track_pT); - m_max_reco_track_pT = std::max(m_reco_track_pT[i - 1], m_max_reco_track_pT); + m_reco_track_tpc_seeds[index] = static_cast(m_dst_track->get_tpc_seed()->size_cluster_keys()); + m_min_reco_track_pT = std::min(m_reco_track_pT[index], m_min_reco_track_pT); + m_max_reco_track_pT = std::max(m_reco_track_pT[index], m_max_reco_track_pT); CLHEP::HepLorentzVector *daughterRecoLV = new CLHEP::HepLorentzVector(); - daughterRecoLV->setVectM(CLHEP::Hep3Vector(m_dst_track->get_px(), m_dst_track->get_py(), m_dst_track->get_pz()), getParticleMass(m_true_track_PID[i - 1])); + daughterRecoLV->setVectM(CLHEP::Hep3Vector(m_dst_track->get_px(), m_dst_track->get_py(), m_dst_track->get_pz()), getParticleMass(m_true_track_PID[index])); motherRecoLV += *daughterRecoLV; delete daughterRecoLV; @@ -410,6 +418,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) if (selectedTracks.size() == m_nDaughters) { m_reco_mother_mass = motherRecoLV.m(); + m_reco_mother_pT = motherRecoLV.perp(); if (m_write_track_map) { m_output_trackMap = findNode::getClass(topNode, outputNodeName); @@ -444,8 +453,10 @@ void HFTrackEfficiency::initializeBranches() m_tree->Branch("true_mother_mass", &m_true_mother_mass, "true_mother_mass/F"); m_tree->Branch("reco_mother_mass", &m_reco_mother_mass, "reco_mother_mass/F"); m_tree->Branch("true_mother_pT", &m_true_mother_pT, "true_mother_pT/F"); + m_tree->Branch("reco_mother_pT", &m_reco_mother_pT, "reco_mother_pT/F"); m_tree->Branch("true_mother_p", &m_true_mother_p, "true_mother_p/F"); m_tree->Branch("true_mother_eta", &m_true_mother_eta, "true_mother_eta/F"); + m_tree->Branch("true_mother_phi", &m_true_mother_phi, "true_mother_phi/F"); m_tree->Branch("min_true_track_pT", &m_min_true_track_pT, "min_true_track_pT/F"); m_tree->Branch("min_reco_track_pT", &m_min_reco_track_pT, "min_reco_track_pT/F"); m_tree->Branch("max_true_track_pT", &m_max_true_track_pT, "max_true_track_pT/F"); @@ -460,6 +471,8 @@ void HFTrackEfficiency::initializeBranches() m_tree->Branch("reco_" + TString(daughter_number) + "_pT", &m_reco_track_pT[iTrack], "reco_" + TString(daughter_number) + "_pT/F"); m_tree->Branch("true_" + TString(daughter_number) + "_eta", &m_true_track_eta[iTrack], "true_" + TString(daughter_number) + "_eta/F"); m_tree->Branch("reco_" + TString(daughter_number) + "_eta", &m_reco_track_eta[iTrack], "reco_" + TString(daughter_number) + "_eta/F"); + m_tree->Branch("true_" + TString(daughter_number) + "_phi", &m_true_track_phi[iTrack], "true_" + TString(daughter_number) + "_phi/F"); + m_tree->Branch("reco_" + TString(daughter_number) + "_phi", &m_reco_track_phi[iTrack], "reco_" + TString(daughter_number) + "_phi/F"); m_tree->Branch("true_" + TString(daughter_number) + "_PID", &m_true_track_PID[iTrack], "true_" + TString(daughter_number) + "_PID/F"); m_tree->Branch("reco_" + TString(daughter_number) + "_chi2nDoF", &m_reco_track_chi2nDoF[iTrack], "reco_" + TString(daughter_number) + "_chi2nDoF/F"); m_tree->Branch("reco_" + TString(daughter_number) + "_silicon_seeds", &m_reco_track_silicon_seeds[iTrack], "reco_" + TString(daughter_number) + "_silicon_seeds/I"); @@ -481,6 +494,7 @@ void HFTrackEfficiency::resetBranches() m_true_mother_mass = std::numeric_limits::quiet_NaN(); m_reco_mother_mass = std::numeric_limits::quiet_NaN(); m_true_mother_pT = std::numeric_limits::quiet_NaN(); + m_reco_mother_pT = std::numeric_limits::quiet_NaN(); m_true_mother_p = std::numeric_limits::quiet_NaN(); m_true_mother_eta = std::numeric_limits::quiet_NaN(); m_min_true_track_pT = std::numeric_limits::max(); @@ -495,6 +509,8 @@ void HFTrackEfficiency::resetBranches() m_reco_track_pT[iTrack] = std::numeric_limits::quiet_NaN(); m_true_track_eta[iTrack] = std::numeric_limits::quiet_NaN(); m_reco_track_eta[iTrack] = std::numeric_limits::quiet_NaN(); + m_true_track_phi[iTrack] = std::numeric_limits::quiet_NaN(); + m_reco_track_phi[iTrack] = std::numeric_limits::quiet_NaN(); m_true_track_PID[iTrack] = std::numeric_limits::quiet_NaN(); m_reco_track_chi2nDoF[iTrack] = std::numeric_limits::quiet_NaN(); m_reco_track_silicon_seeds[iTrack] = 0; diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h index ce1ac40be3..f667c3bc27 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h @@ -93,8 +93,10 @@ class HFTrackEfficiency : public SubsysReco float m_true_mother_mass{std::numeric_limits::quiet_NaN()}; float m_reco_mother_mass{std::numeric_limits::quiet_NaN()}; float m_true_mother_pT{std::numeric_limits::quiet_NaN()}; + float m_reco_mother_pT{std::numeric_limits::quiet_NaN()}; float m_true_mother_p{std::numeric_limits::quiet_NaN()}; float m_true_mother_eta{std::numeric_limits::quiet_NaN()}; + float m_true_mother_phi{std::numeric_limits::quiet_NaN()}; float m_min_true_track_pT{std::numeric_limits::max()}; float m_min_reco_track_pT{std::numeric_limits::max()}; float m_max_true_track_pT{std::numeric_limits::min()}; // Apparently min() is still a +ve value @@ -105,6 +107,8 @@ class HFTrackEfficiency : public SubsysReco float m_reco_track_pT[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_true_track_eta[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_reco_track_eta[m_maxTracks]{std::numeric_limits::quiet_NaN()}; + float m_true_track_phi[m_maxTracks]{std::numeric_limits::quiet_NaN()}; + float m_reco_track_phi[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_true_track_PID[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_reco_track_chi2nDoF[m_maxTracks]{std::numeric_limits::quiet_NaN()}; int m_reco_track_silicon_seeds[m_maxTracks]{0}; From 02337fe77040b69946d21cf6d2275c89138a310b Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Wed, 25 Mar 2026 13:21:54 -0400 Subject: [PATCH 427/866] safeguard of calling ZDC tower nodes when not using zdc info --- offline/packages/trigger/MinimumBiasClassifier.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index db3acba38e..35a5cf9e54 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -277,7 +277,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - if (!m_issim) + if (!m_issim && m_useZDC) { m_zdcinfo = findNode::getClass(topNode, "Zdcinfo"); if (Verbosity()) From 38c1e4b3bf2fb7ce5e6a6dcdadaaeb85c39a68f3 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 25 Mar 2026 12:28:26 -0400 Subject: [PATCH 428/866] also fill TrackState local x and local y. --- offline/packages/trackreco/WeightedFitter.cc | 39 +++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/offline/packages/trackreco/WeightedFitter.cc b/offline/packages/trackreco/WeightedFitter.cc index e35919c479..090775a0da 100644 --- a/offline/packages/trackreco/WeightedFitter.cc +++ b/offline/packages/trackreco/WeightedFitter.cc @@ -139,21 +139,21 @@ WeightedFitter::make_nodes ( m_track_map = findNode::getClass(top_node, m_track_map_node_name); if (!m_track_map) { m_track_map = new SvtxTrackMap_v2; - PHIODataNode* track_map_node = new PHIODataNode(m_track_map, m_track_map_node_name, "PHObject"); + auto* track_map_node = new PHIODataNode(m_track_map, m_track_map_node_name, "PHObject"); svtx_node->addNode(track_map_node); } m_alignment_map = findNode::getClass(top_node, m_alignment_map_node_name); if (!m_alignment_map) { m_alignment_map = new SvtxAlignmentStateMap_v1; - PHIODataNode* alignment_map_node = new PHIODataNode(m_alignment_map, m_alignment_map_node_name, "PHObject"); + auto* alignment_map_node = new PHIODataNode(m_alignment_map, m_alignment_map_node_name, "PHObject"); svtx_node->addNode(alignment_map_node); } m_weighted_track_map = findNode::getClass(top_node, m_weighted_track_map_node_name); if (!m_weighted_track_map) { m_weighted_track_map = new WeightedTrackMap; - PHIODataNode* weighted_track_map_node = new PHIODataNode(m_weighted_track_map, m_weighted_track_map_node_name, "PHObject"); + auto* weighted_track_map_node = new PHIODataNode(m_weighted_track_map, m_weighted_track_map_node_name, "PHObject"); svtx_node->addNode(weighted_track_map_node); } } @@ -350,12 +350,17 @@ WeightedFitter::get_cluster_keys ( m_silicon_seed = m_silicon_track_seed_container->get(track_seed->get_silicon_seed_index()); m_tpc_seed = m_tpc_track_seed_container->get(track_seed->get_tpc_seed_index()); } - m_crossing = m_silicon_seed ? m_silicon_seed->get_crossing() : SHRT_MAX; + + /* + * for TPC only tracks (no associated silicon seed), use nominal crossing as default + * this is consistent with what is done in PHActsTrkFitter + */ + m_crossing = m_silicon_seed ? m_silicon_seed->get_crossing() : 0; m_cluster_keys.clear(); for (auto const* seed : {m_silicon_seed, m_tpc_seed}) { if (!seed) { continue; } - std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(m_cluster_keys)); + std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(m_cluster_keys)); } return false; @@ -384,7 +389,7 @@ WeightedFitter::get_points ( Surface const surf = m_geometry->maps().getSurface(cluster_key, cluster); if (!surf) { continue; } - + auto local_to_global_transform = surf->transform(m_geometry->geometry().getGeoContext()); // in mm local_to_global_transform.translation() /= Acts::UnitConstants::cm; // converted to cm Eigen::Vector3d local_pos = Eigen::Vector3d { cluster->getLocalX(), cluster->getLocalY(), 0.0 }; // in cm @@ -580,20 +585,26 @@ WeightedFitter::add_track ( fitted_track.set_pz(slope(2)); SvtxAlignmentStateMap::StateVec alignment_states; - for (auto const& point : m_output_cluster_fit_points) { - Acts::Vector3 intersection = m_weighted_track->get_intersection(point.sensor_local_to_global_transform); + for (auto const& point : m_output_cluster_fit_points) + { + const auto intersection = m_weighted_track->get_intersection(point.sensor_local_to_global_transform); double path_length = m_weighted_track->get_path_length_of_intersection(point.sensor_local_to_global_transform); SvtxTrackState_v3 svtx_track_state(path_length); - svtx_track_state.set_x(intersection(0)); - svtx_track_state.set_y(intersection(1)); - svtx_track_state.set_z(intersection(2)); - svtx_track_state.set_px(slope(0)); - svtx_track_state.set_py(slope(1)); - svtx_track_state.set_pz(slope(2)); + svtx_track_state.set_x(intersection.x()); + svtx_track_state.set_y(intersection.y()); + svtx_track_state.set_z(intersection.z()); + svtx_track_state.set_px(slope.x()); + svtx_track_state.set_py(slope.y()); + svtx_track_state.set_pz(slope.z()); svtx_track_state.set_name(std::to_string(point.cluster_key)); svtx_track_state.set_cluskey(point.cluster_key); + // calculate corresponding local coordinate (in cluster surface reference frame) + const auto local = point.sensor_local_to_global_transform.inverse()*intersection; + svtx_track_state.set_localX(local.x() ); + svtx_track_state.set_localY(local.y() ); + Eigen::Matrix Jacobian_fitpars_globpos; for (int i = 0; i < 4; ++i) { Jacobian_fitpars_globpos.col(i) = m_weighted_track->get_partial_derivative(i, path_length); } Eigen::Matrix3d globpos_cov = Jacobian_fitpars_globpos * param_cov * Jacobian_fitpars_globpos.transpose(); From 32f97248b704c5181d05c158a975cc168bff55f7 Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Thu, 26 Mar 2026 17:13:57 -0400 Subject: [PATCH 429/866] fixed m_useZDC option --- offline/packages/trigger/MinimumBiasClassifier.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index 35a5cf9e54..c36a9430e1 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -155,7 +155,7 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() { std::cout << "Getting ZDC" << std::endl; } - if (!m_issim && !m_useZDC) + if (!m_issim && m_useZDC) { if (!m_zdcinfo) { From 194974edfe2958aa912bf37e9682f04f8e5d29ee Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Mon, 23 Mar 2026 23:40:51 -0400 Subject: [PATCH 430/866] Add optional QA Histograms to CaloStatusSkimmer Adding histograms, and method to toggle QA output --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 111 ++++++++++++++++-- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 36 +++++- .../Skimmers/CaloStatusSkimmer/Makefile.am | 3 +- 3 files changed, 138 insertions(+), 12 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 73dce5e912..645e6a00fa 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -1,17 +1,23 @@ #include "CaloStatusSkimmer.h" #include +#include #include #include #include +#include + #include #include +#include #include #include +#include + //____________________________________________________________________________.. CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) : SubsysReco(name) @@ -19,6 +25,60 @@ CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; } + +//____________________________________________________________________________.. +int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) +{ + std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) This is Init..." << std::endl; + + if (b_produce_QA_histograms) + { + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + h_EMC_nTowers_notinstr = new TH1F("h_EMC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in EMCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); + h_EMC_nTowers_notinstr->SetDirectory(nullptr); + h_HCal_nTowers_notinstr = new TH1F("h_HCal_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in HCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); + h_HCal_nTowers_notinstr->SetDirectory(nullptr); + h_sEPD_nTowers_notinstr = new TH1F("h_sEPD_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in sEPD; nNotInstrTowers; Counts", 17, -0.5, 16.5); + h_sEPD_nTowers_notinstr->SetDirectory(nullptr); + h_ZDC_nTowers_notinstr = new TH1F("h_ZDC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in ZDC; nNotInstrTowers; Counts", 5, -0.5, 4.5); + h_ZDC_nTowers_notinstr->SetDirectory(nullptr); + + h_EMC_nEvents = new TH1F("h_EMC_nEvents", "Number of events", 2, 0.5, 2.5); + h_EMC_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); + h_EMC_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); + h_EMC_nEvents->SetDirectory(nullptr); + + h_HCal_nEvents = new TH1F("h_HCal_nEvents", "Number of events", 2, 0.5, 2.5); + h_HCal_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); + h_HCal_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); + h_HCal_nEvents->SetDirectory(nullptr); + + h_sEPD_nEvents = new TH1F("h_sEPD_nEvents", "Number of events", 2, 0.5, 2.5); + h_sEPD_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); + h_sEPD_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); + h_sEPD_nEvents->SetDirectory(nullptr); + + h_ZDC_nEvents = new TH1F("h_ZDC_nEvents", "Number of events", 2, 0.5, 2.5); + h_ZDC_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); + h_ZDC_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); + h_ZDC_nEvents->SetDirectory(nullptr); + + hm->registerHisto(h_EMC_nTowers_notinstr); + hm->registerHisto(h_HCal_nTowers_notinstr); + hm->registerHisto(h_sEPD_nTowers_notinstr); + hm->registerHisto(h_ZDC_nTowers_notinstr); + + hm->registerHisto(h_EMC_nEvents); + hm->registerHisto(h_HCal_nEvents); + hm->registerHisto(h_sEPD_nEvents); + hm->registerHisto(h_ZDC_nEvents); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + //____________________________________________________________________________.. int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { @@ -32,7 +92,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) n_notowernodecounter++; if (Verbosity() > 0) { - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_CEMC" << std::endl; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_CEMC" << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } @@ -51,6 +111,11 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in EMCal = " << ntowers << ", not-instrumented(empty/missing pckt) towers in EMCal = " << notinstr_count << std::endl; } + if (b_produce_QA_histograms) + { + h_EMC_nTowers_notinstr->Fill(notinstr_count); + } + if (notinstr_count >= m_EMC_skim_threshold) { n_skimcounter++; @@ -67,7 +132,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) n_notowernodecounter++; if (Verbosity() > 0) { - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT" << std::endl; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT" << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } @@ -99,6 +164,12 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in HCalIn = " << ntowers_hcalin << ", not-instrumented(empty/missing pckt) towers in HCalIn = " << notinstr_count_hcalin << ", ntowers in HCalOut = " << ntowers_hcalout << ", not-instrumented(empty/missing pckt) towers in HCalOut = " << notinstr_count_hcalout << std::endl; } + if (b_produce_QA_histograms) + { + h_HCal_nTowers_notinstr->Fill(notinstr_count_hcalin); + h_HCal_nTowers_notinstr->Fill(notinstr_count_hcalout); + } + if (notinstr_count_hcalin >= m_HCal_skim_threshold || notinstr_count_hcalout >= m_HCal_skim_threshold) { @@ -116,7 +187,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) n_notowernodecounter++; if (Verbosity() > 0) { - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_SEPD" << std::endl; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_SEPD" << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } @@ -136,6 +207,11 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_count << std::endl; } + if(b_produce_QA_histograms) + { + h_sEPD_nTowers_notinstr->Fill(notinstr_count); + } + if (notinstr_count >= m_sEPD_skim_threshold) { n_skimcounter++; @@ -152,7 +228,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) n_notowernodecounter++; if (Verbosity() > 0) { - std::cout << PHWHERE << "calostatuscheck::process_event: missing TOWERS_ZDC" << std::endl; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_ZDC" << std::endl; } return Fun4AllReturnCodes::ABORTEVENT; } @@ -172,6 +248,11 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_count << std::endl; } + if(b_produce_QA_histograms) + { + h_ZDC_nTowers_notinstr->Fill(notinstr_count); + } + if (notinstr_count >= m_ZDC_skim_threshold) { n_skimcounter++; @@ -186,9 +267,25 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) int CaloStatusSkimmer::End([[maybe_unused]] PHCompositeNode *topNode) { std::cout << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." << std::endl; - std::cout << "Total events processed: " << n_eventcounter << std::endl; - std::cout << "Total events skimmed: " << n_skimcounter << std::endl; - std::cout << "Total events with missing tower nodes: " << n_notowernodecounter << std::endl; + std::cout << "CaloStatusSkimmer::End Total events processed: " << n_eventcounter << std::endl; + std::cout << "CaloStatusSkimmer::End Total events skimmed: " << n_skimcounter << std::endl; + std::cout << "CaloStatusSkimmer::End Total events with missing tower nodes: " << n_notowernodecounter << std::endl; + + if (b_produce_QA_histograms) + { + h_EMC_nEvents->SetBinContent(1, n_eventcounter); + h_EMC_nEvents->SetBinContent(2, n_skimcounter); + + h_HCal_nEvents->SetBinContent(1, n_eventcounter); + h_HCal_nEvents->SetBinContent(2, n_skimcounter); + + h_sEPD_nEvents->SetBinContent(1, n_eventcounter); + h_sEPD_nEvents->SetBinContent(2, n_skimcounter); + + h_ZDC_nEvents->SetBinContent(1, n_eventcounter); + h_ZDC_nEvents->SetBinContent(2, n_skimcounter); + + } return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 433b8d08c0..2c29d07459 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -10,7 +10,10 @@ #include #include +#include + class PHCompositeNode; +class TH1F; class CaloStatusSkimmer : public SubsysReco { public: @@ -18,6 +21,8 @@ class CaloStatusSkimmer : public SubsysReco { ~CaloStatusSkimmer() override = default; + int Init(PHCompositeNode* topNode) override; + /** Called for each event. This is where you do the real work. */ @@ -26,27 +31,38 @@ class CaloStatusSkimmer : public SubsysReco { /// Called at the end of all processing. int End(PHCompositeNode *topNode) override; - void do_skim_EMCal( uint16_t threshold) { + void do_skim_EMCal( uint16_t threshold) + { m_EMC_skim_threshold = threshold; } - void do_skim_HCal( uint16_t threshold) { + void do_skim_HCal( uint16_t threshold) + { m_HCal_skim_threshold = threshold; } - void do_skim_sEPD( uint16_t threshold) { + void do_skim_sEPD( uint16_t threshold) + { m_sEPD_skim_threshold = threshold; } - void do_skim_ZDC( uint16_t threshold) { + void do_skim_ZDC( uint16_t threshold) + { m_ZDC_skim_threshold = threshold; } + void produce_QA_histograms(bool produce) + { + b_produce_QA_histograms = produce; + } + private: uint32_t n_eventcounter{0}; uint32_t n_skimcounter{0}; uint32_t n_notowernodecounter{0}; + bool b_produce_QA_histograms{false}; + // If the threshold is set to 0, then the skimming for that subsystem is disabled. If threshold is > 0, then the event is skimmed if nchannels >= threshold not-instrumented (empty/missing packet) channels in that subsystem. uint16_t m_EMC_skim_threshold{192}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in EMCal @@ -59,6 +75,18 @@ class CaloStatusSkimmer : public SubsysReco { uint16_t m_ZDC_skim_threshold{1}; // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in ZDC + + //histograms + TH1F* h_EMC_nTowers_notinstr = nullptr; + TH1F* h_HCal_nTowers_notinstr = nullptr; + TH1F* h_sEPD_nTowers_notinstr = nullptr; + TH1F* h_ZDC_nTowers_notinstr = nullptr; + + TH1F* h_EMC_nEvents = nullptr; + TH1F* h_HCal_nEvents = nullptr; + TH1F* h_sEPD_nEvents = nullptr; + TH1F* h_ZDC_nEvents = nullptr; + }; #endif // CALOSTATUSSKIMMER_H diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am b/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am index 9f496c8587..6ec5fc7af2 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am +++ b/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am @@ -22,7 +22,8 @@ libCaloStatusSkimmer_la_SOURCES = \ libCaloStatusSkimmer_la_LIBADD = \ -lphool \ -lSubsysReco \ - -lcalo_io + -lcalo_io \ + -lqautils BUILT_SOURCES = testexternals.cc From 2e47119bbab500af01ac513a7cea2a3ce0a40977 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 29 Mar 2026 20:21:19 -0400 Subject: [PATCH 431/866] exclude double pythia8 in filename if not chosen double --- offline/framework/frog/CreateFileList.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 08ea13e981..ff58f73eb2 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -1369,6 +1369,10 @@ } print "This Can Take a While (10 minutes depending on the amount of events and the number of file types you want)\n"; my $conds = sprintf("dsttype = ? and filename like \'\%%%s\%\'",$filenamestring_with_runnumber); +if (! defined $double) +{ + $conds = sprintf("%s and filename not like '\%%pythia8_\%_pythia8\%'",$conds); +} if (exists $notlike{$filenamestring}) { From 7bba30274a7aa06027b4ccd52d2a5db0b9108bd9 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 30 Mar 2026 16:15:01 -0400 Subject: [PATCH 432/866] add herwig photon jets --- offline/framework/frog/CreateFileList.pl | 121 ++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index ff58f73eb2..9d7cd97e3c 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -82,7 +82,10 @@ "41" => "Herwig Jet ptmin = 12 GeV", "42" => "Herwig Jet ptmin = 20 GeV", "43" => "Herwig Jet ptmin = 40 GeV", - "44" => "Herwig Jet ptmin = 50 GeV" + "44" => "Herwig Jet ptmin = 50 GeV", + "45" => "Herwig Photonjet ptmin = 5 GeV", + "46" => "Herwig Photonjet ptmin = 10 GeV", + "47" => "Herwig Photonjet ptmin = 20 GeV" ); my %pileupdesc = ( @@ -1219,6 +1222,122 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 45) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet5"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 45) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet5"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 46) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet10"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 47) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet20"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { print "no production type $prodtype\n"; From b63099b4224fd902b2f2004c599ecc63a3c67792 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Tue, 31 Mar 2026 00:46:19 -0400 Subject: [PATCH 433/866] commit for associating the FPHXBCO and INTT_long_BCO information to TrkrHit --- offline/packages/intt/InttCombinedRawDataDecoder.cc | 2 ++ offline/packages/trackbase/TrkrHit.h | 8 ++++++++ offline/packages/trackbase/TrkrHitv1.cc | 2 ++ offline/packages/trackbase/TrkrHitv1.h | 12 ++++++++++-- offline/packages/trackbase/TrkrHitv2.cc | 2 ++ offline/packages/trackbase/TrkrHitv2.h | 12 ++++++++++-- 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 4ffd06f8e1..574d7bf783 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -502,6 +502,8 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) hit = new TrkrHitv2; //--hit->setAdc(adc); hit->setAdc(dac); + hit->setFPHXBCO(intthit->get_FPHX_BCO()); + hit->setBCO(intthit->get_bco()); hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } diff --git a/offline/packages/trackbase/TrkrHit.h b/offline/packages/trackbase/TrkrHit.h index 5a2180e162..963b321fa6 100644 --- a/offline/packages/trackbase/TrkrHit.h +++ b/offline/packages/trackbase/TrkrHit.h @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -55,6 +56,13 @@ class TrkrHit : public PHObject // after digitization, these are the adc values virtual void setAdc(const unsigned int) {} virtual unsigned int getAdc() const { return 0; } + + // optional per-hit timing payload used by detectors that need to retain + // the frontend bunch-counter value alongside the digitized hit. + virtual void setFPHXBCO(const uint16_t) {} + virtual uint16_t getFPHXBCO() const { return 0; } + virtual void setBCO(const uint64_t) {} + virtual uint64_t getBCO() const { return 0; } /* virtual void setCrossing(const short int) {} virtual short int getCrossing() { return 0;} diff --git a/offline/packages/trackbase/TrkrHitv1.cc b/offline/packages/trackbase/TrkrHitv1.cc index b0001fb30e..b96c56b42d 100644 --- a/offline/packages/trackbase/TrkrHitv1.cc +++ b/offline/packages/trackbase/TrkrHitv1.cc @@ -13,6 +13,8 @@ void TrkrHitv1::CopyFrom(const TrkrHit& source) // copy adc setAdc(source.getAdc()); + setFPHXBCO(source.getFPHXBCO()); + setBCO(source.getBCO()); } unsigned int TrkrHitv1::getAdc() const diff --git a/offline/packages/trackbase/TrkrHitv1.h b/offline/packages/trackbase/TrkrHitv1.h index 7ab629a1c3..6ac15306e2 100644 --- a/offline/packages/trackbase/TrkrHitv1.h +++ b/offline/packages/trackbase/TrkrHitv1.h @@ -28,7 +28,9 @@ class TrkrHitv1 : public TrkrHit // PHObject virtual overloads void identify(std::ostream& os = std::cout) const override { - os << "TrkrHitV1 class with adc = " << m_adc << std::endl; + os << "TrkrHitV1 class with adc = " << m_adc + << " and FPHX_BCO = " << m_fphx_bco + << " and BCO = " << m_bco << std::endl; } void Reset() override {} int isValid() const override { return 0; } @@ -49,11 +51,17 @@ class TrkrHitv1 : public TrkrHit double getEnergy() const override { return m_edep; } void setAdc(const unsigned int adc) override { m_adc = adc; } unsigned int getAdc() const override; + void setFPHXBCO(const uint16_t bco) override { m_fphx_bco = bco; } + uint16_t getFPHXBCO() const override { return m_fphx_bco; } + void setBCO(const uint64_t bco) override { m_bco = bco; } + uint64_t getBCO() const override { return m_bco; } protected: double m_edep = 0; unsigned int m_adc = 0; - ClassDefOverride(TrkrHitv1, 1); + uint16_t m_fphx_bco = 0; + uint64_t m_bco = 0; + ClassDefOverride(TrkrHitv1, 3); }; #endif // TRACKBASE_TRKRHITV1_H diff --git a/offline/packages/trackbase/TrkrHitv2.cc b/offline/packages/trackbase/TrkrHitv2.cc index 6ef48d6435..27a87085d3 100644 --- a/offline/packages/trackbase/TrkrHitv2.cc +++ b/offline/packages/trackbase/TrkrHitv2.cc @@ -14,6 +14,8 @@ void TrkrHitv2::CopyFrom(const TrkrHit& source) // copy adc setAdc(source.getAdc()); + setFPHXBCO(source.getFPHXBCO()); + setBCO(source.getBCO()); } // these set and get the energy before digitization diff --git a/offline/packages/trackbase/TrkrHitv2.h b/offline/packages/trackbase/TrkrHitv2.h index 8c83192019..c637ad8cc9 100644 --- a/offline/packages/trackbase/TrkrHitv2.h +++ b/offline/packages/trackbase/TrkrHitv2.h @@ -33,7 +33,9 @@ class TrkrHitv2 : public TrkrHit // PHObject virtual overloads void identify(std::ostream& os = std::cout) const override { - os << "TrkrHitv2 class with adc = " << m_adc << std::endl; + os << "TrkrHitv2 class with adc = " << m_adc + << " and FPHX_BCO = " << m_fphx_bco + << " and BCO = " << m_bco << std::endl; } void Reset() override {} int isValid() const override { return 0; } @@ -57,10 +59,16 @@ class TrkrHitv2 : public TrkrHit // after digitization, these are the adc values void setAdc(const unsigned int adc) override; unsigned int getAdc() const override; + void setFPHXBCO(const uint16_t bco) override { m_fphx_bco = bco; } + uint16_t getFPHXBCO() const override { return m_fphx_bco; } + void setBCO(const uint64_t bco) override { m_bco = bco; } + uint64_t getBCO() const override { return m_bco; } protected: unsigned short m_adc = 0; - ClassDefOverride(TrkrHitv2, 1); + uint16_t m_fphx_bco = 0; + uint64_t m_bco = 0; + ClassDefOverride(TrkrHitv2, 3); }; #endif // TRACKBASE_TRKRHITV2_H From 1c7135fa3c33d1b808f79f75f91930052f078aca Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Tue, 31 Mar 2026 12:45:41 -0400 Subject: [PATCH 434/866] Change the crossingOffset value from 512 to 200 This is to account for the cut-off --- offline/packages/trackbase/InttDefs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackbase/InttDefs.cc b/offline/packages/trackbase/InttDefs.cc index efe0425bec..42b7879a12 100644 --- a/offline/packages/trackbase/InttDefs.cc +++ b/offline/packages/trackbase/InttDefs.cc @@ -22,7 +22,7 @@ namespace static constexpr unsigned int kBitShiftLadderPhiIdWidth = 4; static constexpr unsigned int kBitShiftLadderZIdOffset = 14; static constexpr unsigned int kBitShiftLadderZIdWidth = 2; - static constexpr int crossingOffset = 512; + static constexpr int crossingOffset = 200; // bit shift for hitkey static const unsigned int kBitShiftCol __attribute__((unused)) = 16; From eac9a4795663cd3f2be8b68edd583477371e6341 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:42:40 -0400 Subject: [PATCH 435/866] sEPD TreeGen: Remove hardcoded sEPD input node name - Use default sEPD node: `TOWERINFO_CALIB_SEPD` - Allow for changing it if needed on macro side --- calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc | 4 ++-- calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc index 7f11a07255..b757561999 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -177,10 +177,10 @@ int sEPD_TreeGen::process_centrality(PHCompositeNode *topNode) //____________________________________________________________________________.. int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) { - TowerInfoContainer *towerinfosEPD = findNode::getClass(topNode, "TOWERINFO_CALIB_SEPD"); + TowerInfoContainer *towerinfosEPD = findNode::getClass(topNode, m_inputNode); if (!towerinfosEPD) { - std::cout << PHWHERE << "TOWERINFO_CALIB_SEPD Node missing, doing nothing." << std::endl; + std::cout << PHWHERE << m_inputNode << " Node missing, doing nothing." << std::endl; return Fun4AllReturnCodes::ABORTRUN; } diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h index 2d777f4011..c8d7222a32 100644 --- a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h @@ -85,6 +85,11 @@ class sEPD_TreeGen : public SubsysReco m_cuts.m_cent_max = cent_max; } + void set_inputNode(const std::string &inputNode) + { + m_inputNode = inputNode; + } + private: /** * @brief Validates event-level conditions (GlobalVertex, Minimum Bias). @@ -108,6 +113,8 @@ class sEPD_TreeGen : public SubsysReco */ int process_centrality(PHCompositeNode *topNode); + std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; + int m_event{0}; static constexpr int PROGRESS_PRINT_INTERVAL = 20; From 316fbf288ffad409932b68e657cf222fd41806e3 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:46:29 -0400 Subject: [PATCH 436/866] QVecCalib - Add EP Resolution QA Hist --- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 18 ++++++++++++++++++ .../sepd/sepd_eventplanecalib/QVecCalib.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index 46c99354e1..361b217f20 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -361,6 +361,11 @@ void QVecCalib::init_hists() m_hists2D[name_N] = new TH2F(name_N.c_str(), title_N.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); m_hists2D[name_NS] = new TH2F(name_NS.c_str(), title_NS.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + std::string name_EP_res = std::format("hEP_res_{}", n); + std::string title_EP_res = std::format("; Centrality [%]; #LTRe(Q^{{S}}_{{{0}}} Q^{{N*}}_{{{0}}}) / (|Q^{{S}}_{{{0}}}||Q^{{N}}_{{{0}}}|)#GT", n); + + m_profiles[name_EP_res] = new TProfile(name_EP_res.c_str(), title_EP_res.c_str(), m_cent_bins, m_cent_low, m_cent_high); + // South, North for (auto det : m_subdetectors) { @@ -723,6 +728,8 @@ void QVecCalib::prepare_flattening_hists() std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr2", n); std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr2", n); + std::string EP_res_name = std::format("hEP_res_{}", n); + FlatteningHists h; h.S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name); @@ -746,6 +753,8 @@ void QVecCalib::prepare_flattening_hists() h.Psi_N_corr2 = m_hists2D.at(psi_N_name); h.Psi_NS_corr2 = m_hists2D.at(psi_NS_name); + h.EP_res = m_profiles.at(EP_res_name); + se->registerHisto(h.S_x_corr2_avg); se->registerHisto(h.S_y_corr2_avg); se->registerHisto(h.N_x_corr2_avg); @@ -767,6 +776,8 @@ void QVecCalib::prepare_flattening_hists() se->registerHisto(h.Psi_N_corr2); se->registerHisto(h.Psi_NS_corr2); + se->registerHisto(h.EP_res); + m_flattening_hists.push_back(h); } } @@ -908,6 +919,11 @@ void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared:: double psi_N = std::atan2(q_N_corr2.y, q_N_corr2.x); double psi_NS = std::atan2(q_NS_corr2.y, q_NS_corr2.x); + double SP_QS_QN = q_S_corr2.x * q_N_corr2.x + q_S_corr2.y * q_N_corr2.y; + double norm_S = std::sqrt(q_S_corr2.x * q_S_corr2.x + q_S_corr2.y * q_S_corr2.y); + double norm_N = std::sqrt(q_N_corr2.x * q_N_corr2.x + q_N_corr2.y * q_N_corr2.y); + double EP_res = (norm_S && norm_N) ? SP_QS_QN / (norm_S * norm_N) : 0; + h.S_x_corr2_avg->Fill(cent, q_S_corr2.x); h.S_y_corr2_avg->Fill(cent, q_S_corr2.y); h.N_x_corr2_avg->Fill(cent, q_N_corr2.x); @@ -927,6 +943,8 @@ void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared:: h.Psi_S_corr2->Fill(cent, psi_S); h.Psi_N_corr2->Fill(cent, psi_N); h.Psi_NS_corr2->Fill(cent, psi_NS); + + h.EP_res->Fill(cent, EP_res); } bool QVecCalib::process_sEPD() diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index 7f834273b2..af9fa5253e 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -222,6 +222,8 @@ class QVecCalib : public SubsysReco TProfile* NS_yy_corr_avg{nullptr}; TProfile* NS_xy_corr_avg{nullptr}; + TProfile* EP_res{nullptr}; + TH2* Psi_S_corr2{nullptr}; TH2* Psi_N_corr2{nullptr}; TH2* Psi_NS_corr2{nullptr}; From 98638b7e2f53d907e11b4388aae8c6264e46546e Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Wed, 1 Apr 2026 00:18:27 -0400 Subject: [PATCH 437/866] Change histograms, move skim event to end, adjust skim to happen > threshold not >=, ZDC off by default Consolidate calo skim histograms in to one histogram. Now it counts how many times the threshold was exceeded. Remove TH1F pointers. Now all TH1. Move skimming to the end of process_event() ZDC is now off by default. (Blair's request) Switch skim condition to > threshold instead of >= threshold. --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 130 ++++++++---------- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 36 ++--- 2 files changed, 78 insertions(+), 88 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 645e6a00fa..4b55b01e9e 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -16,7 +16,7 @@ #include #include -#include +#include //____________________________________________________________________________.. CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) @@ -36,44 +36,31 @@ int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) auto* hm = QAHistManagerDef::getHistoManager(); assert(hm); - h_EMC_nTowers_notinstr = new TH1F("h_EMC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in EMCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); + h_EMC_nTowers_notinstr = new TH1("h_EMC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in EMCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); h_EMC_nTowers_notinstr->SetDirectory(nullptr); - h_HCal_nTowers_notinstr = new TH1F("h_HCal_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in HCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); + h_HCal_nTowers_notinstr = new TH1("h_HCal_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in HCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); h_HCal_nTowers_notinstr->SetDirectory(nullptr); - h_sEPD_nTowers_notinstr = new TH1F("h_sEPD_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in sEPD; nNotInstrTowers; Counts", 17, -0.5, 16.5); + h_sEPD_nTowers_notinstr = new TH1("h_sEPD_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in sEPD; nNotInstrTowers; Counts", 17, -0.5, 16.5); h_sEPD_nTowers_notinstr->SetDirectory(nullptr); - h_ZDC_nTowers_notinstr = new TH1F("h_ZDC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in ZDC; nNotInstrTowers; Counts", 5, -0.5, 4.5); + h_ZDC_nTowers_notinstr = new TH1("h_ZDC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in ZDC; nNotInstrTowers; Counts", 5, -0.5, 4.5); h_ZDC_nTowers_notinstr->SetDirectory(nullptr); - h_EMC_nEvents = new TH1F("h_EMC_nEvents", "Number of events", 2, 0.5, 2.5); - h_EMC_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); - h_EMC_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); - h_EMC_nEvents->SetDirectory(nullptr); + h_calo_nEvents = new TH1("h_calo_nEvents", "Number of events", 7, 0.5, 7.5); + h_calo_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); + h_calo_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); + h_calo_nEvents->GetXaxis()->SetBinLabel(3, "EMCal above not-instr threshold"); + h_calo_nEvents->GetXaxis()->SetBinLabel(4, "HCal above not-instr threshold"); + h_calo_nEvents->GetXaxis()->SetBinLabel(5, "sEPD above not-instr threshold"); + h_calo_nEvents->GetXaxis()->SetBinLabel(6, "ZDC above not-instr threshold"); + h_calo_nEvents->GetXaxis()->SetBinLabel(7, "No TowerInfo nodes found"); + h_calo_nEvents->SetDirectory(nullptr); - h_HCal_nEvents = new TH1F("h_HCal_nEvents", "Number of events", 2, 0.5, 2.5); - h_HCal_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); - h_HCal_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); - h_HCal_nEvents->SetDirectory(nullptr); - - h_sEPD_nEvents = new TH1F("h_sEPD_nEvents", "Number of events", 2, 0.5, 2.5); - h_sEPD_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); - h_sEPD_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); - h_sEPD_nEvents->SetDirectory(nullptr); - - h_ZDC_nEvents = new TH1F("h_ZDC_nEvents", "Number of events", 2, 0.5, 2.5); - h_ZDC_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); - h_ZDC_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); - h_ZDC_nEvents->SetDirectory(nullptr); + hm->registerHisto(h_calo_nEvents); hm->registerHisto(h_EMC_nTowers_notinstr); hm->registerHisto(h_HCal_nTowers_notinstr); hm->registerHisto(h_sEPD_nTowers_notinstr); hm->registerHisto(h_ZDC_nTowers_notinstr); - - hm->registerHisto(h_EMC_nEvents); - hm->registerHisto(h_HCal_nEvents); - hm->registerHisto(h_sEPD_nEvents); - hm->registerHisto(h_ZDC_nEvents); } return Fun4AllReturnCodes::EVENT_OK; @@ -83,6 +70,12 @@ int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { n_eventcounter++; + uint16_t notinstr_EMC = 0; + uint16_t notinstr_HCalin = 0; + uint16_t notinstr_HCalout = 0; + uint16_t notinstr_sEPD = 0; + uint16_t notinstr_ZDC = 0; + if (m_EMC_skim_threshold > 0) { TowerInfoContainer *towers = @@ -97,29 +90,27 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } const uint32_t ntowers = towers->size(); - uint16_t notinstr_count = 0; for (uint32_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = towers->get_tower_at_channel(ch); if (tower->get_isNotInstr()) { - ++notinstr_count; + ++notinstr_EMC; } } if (Verbosity() > 9) { - std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in EMCal = " << ntowers << ", not-instrumented(empty/missing pckt) towers in EMCal = " << notinstr_count << std::endl; + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in EMCal = " << ntowers << ", not-instrumented(empty/missing pckt) towers in EMCal = " << notinstr_EMC << std::endl; } if (b_produce_QA_histograms) { - h_EMC_nTowers_notinstr->Fill(notinstr_count); + h_EMC_nTowers_notinstr->Fill(notinstr_EMC); } - if (notinstr_count >= m_EMC_skim_threshold) + if (notinstr_EMC > m_EMC_skim_threshold) { - n_skimcounter++; - return Fun4AllReturnCodes::ABORTEVENT; + EMC_skim_count++; } } @@ -138,43 +129,40 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } const uint32_t ntowers_hcalin = hcalin_towers->size(); - uint16_t notinstr_count_hcalin = 0; for (uint32_t ch = 0; ch < ntowers_hcalin; ++ch) { TowerInfo *tower_in = hcalin_towers->get_tower_at_channel(ch); if (tower_in->get_isNotInstr()) { - ++notinstr_count_hcalin; + ++notinstr_HCalin; } } const uint32_t ntowers_hcalout = hcalout_towers->size(); - uint16_t notinstr_count_hcalout = 0; for (uint32_t ch = 0; ch < ntowers_hcalout; ++ch) { TowerInfo *tower_out = hcalout_towers->get_tower_at_channel(ch); if (tower_out->get_isNotInstr()) { - ++notinstr_count_hcalout; + ++notinstr_HCalout; } } if (Verbosity() > 9) { - std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in HCalIn = " << ntowers_hcalin << ", not-instrumented(empty/missing pckt) towers in HCalIn = " << notinstr_count_hcalin << ", ntowers in HCalOut = " << ntowers_hcalout << ", not-instrumented(empty/missing pckt) towers in HCalOut = " << notinstr_count_hcalout << std::endl; + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in HCalIn = " << ntowers_hcalin << ", not-instrumented(empty/missing pckt) towers in HCalIn = " << notinstr_HCalin << ", ntowers in HCalOut = " << ntowers_hcalout << ", not-instrumented(empty/missing pckt) towers in HCalOut = " << notinstr_HCalout << std::endl; } if (b_produce_QA_histograms) { - h_HCal_nTowers_notinstr->Fill(notinstr_count_hcalin); - h_HCal_nTowers_notinstr->Fill(notinstr_count_hcalout); + h_HCal_nTowers_notinstr->Fill(notinstr_HCalin); + h_HCal_nTowers_notinstr->Fill(notinstr_HCalout); } - if (notinstr_count_hcalin >= m_HCal_skim_threshold || - notinstr_count_hcalout >= m_HCal_skim_threshold) + if (notinstr_HCalin > m_HCal_skim_threshold || + notinstr_HCalout > m_HCal_skim_threshold) { - n_skimcounter++; - return Fun4AllReturnCodes::ABORTEVENT; + HCal_skim_count++; } } @@ -192,30 +180,28 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } const uint32_t ntowers = sepd_towers->size(); - uint16_t notinstr_count = 0; for (uint32_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); if (tower->get_isNotInstr()) { - ++notinstr_count; + ++notinstr_sEPD; } } if (Verbosity() > 9) { - std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_count << std::endl; + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_sEPD << std::endl; } if(b_produce_QA_histograms) { - h_sEPD_nTowers_notinstr->Fill(notinstr_count); + h_sEPD_nTowers_notinstr->Fill(notinstr_sEPD); } - if (notinstr_count >= m_sEPD_skim_threshold) + if (notinstr_sEPD > m_sEPD_skim_threshold) { - n_skimcounter++; - return Fun4AllReturnCodes::ABORTEVENT; + sEPD_skim_count++; } } @@ -233,33 +219,38 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } const uint32_t ntowers = zdc_towers->size(); - uint16_t notinstr_count = 0; for (uint32_t ch = 0; ch < ntowers; ++ch) { TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); if (tower->get_isNotInstr()) { - ++notinstr_count; + ++notinstr_ZDC; } } if (Verbosity() > 9) { - std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_count << std::endl; + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_ZDC << std::endl; } if(b_produce_QA_histograms) { - h_ZDC_nTowers_notinstr->Fill(notinstr_count); + h_ZDC_nTowers_notinstr->Fill(notinstr_ZDC); } - if (notinstr_count >= m_ZDC_skim_threshold) + if (notinstr_ZDC > m_ZDC_skim_threshold) { - n_skimcounter++; - return Fun4AllReturnCodes::ABORTEVENT; + ZDC_skim_count++; } } + // If any of the enabled skimming conditions are met, then increment the skim counter and return ABORTEVENT to skip the event + if ((m_EMC_skim_threshold > 0 && notinstr_EMC > m_EMC_skim_threshold) || (m_HCal_skim_threshold > 0 && (notinstr_HCalin > m_HCal_skim_threshold || notinstr_HCalout > m_HCal_skim_threshold)) || (m_sEPD_skim_threshold > 0 && notinstr_sEPD > m_sEPD_skim_threshold) || (m_ZDC_skim_threshold > 0 && notinstr_ZDC > m_ZDC_skim_threshold)) + { + n_skimcounter++; + return Fun4AllReturnCodes::ABORTEVENT; + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -273,18 +264,13 @@ int CaloStatusSkimmer::End([[maybe_unused]] PHCompositeNode *topNode) if (b_produce_QA_histograms) { - h_EMC_nEvents->SetBinContent(1, n_eventcounter); - h_EMC_nEvents->SetBinContent(2, n_skimcounter); - - h_HCal_nEvents->SetBinContent(1, n_eventcounter); - h_HCal_nEvents->SetBinContent(2, n_skimcounter); - - h_sEPD_nEvents->SetBinContent(1, n_eventcounter); - h_sEPD_nEvents->SetBinContent(2, n_skimcounter); - - h_ZDC_nEvents->SetBinContent(1, n_eventcounter); - h_ZDC_nEvents->SetBinContent(2, n_skimcounter); - + h_calo_nEvents->SetBinContent(1, n_eventcounter); + h_calo_nEvents->SetBinContent(2, n_skimcounter); + h_calo_nEvents->SetBinContent(3, EMC_skim_count); + h_calo_nEvents->SetBinContent(4, HCal_skim_count); + h_calo_nEvents->SetBinContent(5, sEPD_skim_count); + h_calo_nEvents->SetBinContent(6, ZDC_skim_count); + h_calo_nEvents->SetBinContent(7, n_notowernodecounter); } return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 2c29d07459..95f36ab33a 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -10,10 +10,10 @@ #include #include -#include +#include class PHCompositeNode; -class TH1F; +class TH1; class CaloStatusSkimmer : public SubsysReco { public: @@ -65,27 +65,31 @@ class CaloStatusSkimmer : public SubsysReco { // If the threshold is set to 0, then the skimming for that subsystem is disabled. If threshold is > 0, then the event is skimmed if nchannels >= threshold not-instrumented (empty/missing packet) channels in that subsystem. uint16_t m_EMC_skim_threshold{192}; - // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in EMCal + // skim if nchannels > this many not-instrumented (empty/missing packet) channels in EMCal uint16_t m_HCal_skim_threshold{192}; - // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in HCal + // skim if nchannels > this many not-instrumented (empty/missing packet) channels in HCal uint16_t m_sEPD_skim_threshold{1}; - // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in sEPD + // skim if nchannels > this many not-instrumented (empty/missing packet) channels in sEPD - uint16_t m_ZDC_skim_threshold{1}; - // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in ZDC + uint16_t m_ZDC_skim_threshold{0}; + // skim if nchannels > this many not-instrumented (empty/missing packet) channels in ZDC - //histograms - TH1F* h_EMC_nTowers_notinstr = nullptr; - TH1F* h_HCal_nTowers_notinstr = nullptr; - TH1F* h_sEPD_nTowers_notinstr = nullptr; - TH1F* h_ZDC_nTowers_notinstr = nullptr; + // Counters for number of events skimmed per subsystem + uint32_t EMC_skim_count = 0; + uint32_t HCal_skim_count = 0; + uint32_t sEPD_skim_count = 0; + uint32_t ZDC_skim_count = 0; - TH1F* h_EMC_nEvents = nullptr; - TH1F* h_HCal_nEvents = nullptr; - TH1F* h_sEPD_nEvents = nullptr; - TH1F* h_ZDC_nEvents = nullptr; + //Per-calo tower counter histograms + TH1* h_EMC_nTowers_notinstr = nullptr; + TH1* h_HCal_nTowers_notinstr = nullptr; + TH1* h_sEPD_nTowers_notinstr = nullptr; + TH1* h_ZDC_nTowers_notinstr = nullptr; + + //Event counter histograms + TH1* h_calo_nEvents = nullptr; }; From fbdd3d6ce50b64969541a0be2191903e88c9464b Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Wed, 1 Apr 2026 00:40:42 -0400 Subject: [PATCH 438/866] Fix histogram constructors Adjust the channel counting histograms range to reflect actual number of towers --- .../Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 4b55b01e9e..8941f15c0b 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -36,16 +36,16 @@ int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) auto* hm = QAHistManagerDef::getHistoManager(); assert(hm); - h_EMC_nTowers_notinstr = new TH1("h_EMC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in EMCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); + h_EMC_nTowers_notinstr = new TH1F("h_EMC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in EMCal; nNotInstrTowers; Counts", 24577, -0.5, 24576.5); h_EMC_nTowers_notinstr->SetDirectory(nullptr); - h_HCal_nTowers_notinstr = new TH1("h_HCal_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in HCal; nNotInstrTowers; Counts", 193, -0.5, 192.5); + h_HCal_nTowers_notinstr = new TH1F("h_HCal_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in HCal; nNotInstrTowers; Counts", 1537, -0.5, 1536.5); h_HCal_nTowers_notinstr->SetDirectory(nullptr); - h_sEPD_nTowers_notinstr = new TH1("h_sEPD_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in sEPD; nNotInstrTowers; Counts", 17, -0.5, 16.5); + h_sEPD_nTowers_notinstr = new TH1F("h_sEPD_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in sEPD; nNotInstrTowers; Counts", 745, -0.5, 744.5); h_sEPD_nTowers_notinstr->SetDirectory(nullptr); - h_ZDC_nTowers_notinstr = new TH1("h_ZDC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in ZDC; nNotInstrTowers; Counts", 5, -0.5, 4.5); + h_ZDC_nTowers_notinstr = new TH1F("h_ZDC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in ZDC; nNotInstrTowers; Counts", 53, -0.5, 52.5); h_ZDC_nTowers_notinstr->SetDirectory(nullptr); - h_calo_nEvents = new TH1("h_calo_nEvents", "Number of events", 7, 0.5, 7.5); + h_calo_nEvents = new TH1F("h_calo_nEvents", "Number of events", 7, 0.5, 7.5); h_calo_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); h_calo_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); h_calo_nEvents->GetXaxis()->SetBinLabel(3, "EMCal above not-instr threshold"); From 5db52297ed9715431e3590f3b4c0f7b5af85741e Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Wed, 1 Apr 2026 16:48:52 -0400 Subject: [PATCH 439/866] Add some parent and primary particle info to the truth tracks. --- .../g4simulation/g4eval/BaseTruthEval.cc | 41 +++++++++ .../g4simulation/g4eval/BaseTruthEval.h | 3 + .../g4simulation/g4eval/SvtxEvaluator.cc | 90 ++++++++++++------- .../g4simulation/g4eval/SvtxTruthEval.cc | 16 ++++ .../g4simulation/g4eval/SvtxTruthEval.h | 2 + 5 files changed, 118 insertions(+), 34 deletions(-) diff --git a/simulation/g4simulation/g4eval/BaseTruthEval.cc b/simulation/g4simulation/g4eval/BaseTruthEval.cc index 61aef260f7..f899fafcb7 100644 --- a/simulation/g4simulation/g4eval/BaseTruthEval.cc +++ b/simulation/g4simulation/g4eval/BaseTruthEval.cc @@ -147,6 +147,7 @@ bool BaseTruthEval::is_primary(PHG4Particle* particle) } bool is_primary = false; + //particle->identify(); if (particle->get_parent_id() == 0) { is_primary = true; @@ -274,6 +275,46 @@ PHG4Particle* BaseTruthEval::get_primary_particle(PHG4Particle* particle) return returnval; } +PHG4Particle* BaseTruthEval::get_parent_particle(PHG4Particle* particle) +{ + if (!has_reduced_node_pointers()) + { + ++m_Errors; + return nullptr; + } + + if (m_Strict) + { + assert(particle); + } + else if (!particle) + { + ++m_Errors; + return nullptr; + } + + PHG4Particle* returnval = m_TruthInfo->GetParticle(particle->get_parent_id()); + if(!returnval) + { + // std::cout << " did not get parent particle for particle with parent id " << particle->get_parent_id() << std::endl; + returnval = particle; + } + + //std::cout << " parent for particle " << particle->get_track_id() << " is " << particle->get_parent_id() + // << " with pid " << returnval->get_pid() << std::endl; + + if (m_Strict) + { + assert(returnval); + } + else if (!returnval) + { + ++m_Errors; + } + + return returnval; +} + PHG4Particle* BaseTruthEval::get_primary_particle(PHG4Shower* shower) { if (!has_reduced_node_pointers()) diff --git a/simulation/g4simulation/g4eval/BaseTruthEval.h b/simulation/g4simulation/g4eval/BaseTruthEval.h index 83a9e207a6..05b33ccb1d 100644 --- a/simulation/g4simulation/g4eval/BaseTruthEval.h +++ b/simulation/g4simulation/g4eval/BaseTruthEval.h @@ -57,6 +57,9 @@ class BaseTruthEval /// what was the primary particle that is associated with this shower? PHG4Particle* get_primary_particle(PHG4Shower* shower); + /// what was the parent particle of this particle? + PHG4Particle* get_parent_particle(PHG4Particle* particle); + /// which secondary showers are inside this shower? std::set all_secondary_showers(PHG4Shower* shower); diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 8996509105..041d111941 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -123,7 +123,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:" "gvx:gvy:gvz:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:nclusters:" + "gembed:gisprimary:nclusters:" "clusID:x:y:z:eta:phi:e:adc:layer:size:" "efromtruth:dphitru:detatru:dztru:drtru:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); @@ -138,7 +138,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gtrackID:gflavor:" "gpx:gpy:gpz:gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:efromtruth:" + "gembed:gisprimary:efromtruth:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -152,14 +152,14 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gy:gz:gr:gphi:geta:gt:gtrackID:gflavor:" "gpx:gpy:gpz:gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:efromtruth:nparticles:" + "gembed:gisprimary:efromtruth:nparticles:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } if (_do_g4cluster_eval) { _ntp_g4cluster = new TNtuple("ntp_g4cluster", "g4cluster => max truth", - "event:layer:gx:gy:gz:gt:gedep:gr:gphi:geta:gtrackID:gflavor:gembed:gprimary:gphisize:gzsize:gadc:nreco:x:y:z:r:phi:eta:ex:ey:ez:ephi:adc:phisize:zsize"); + "event:layer:gx:gy:gz:gt:gedep:gr:gphi:geta:gtrackID:gflavor:gembed:gisprimary:gphisize:gzsize:gadc:nreco:x:y:z:r:phi:eta:ex:ey:ez:ephi:adc:phisize:zsize"); } if (_do_gtrack_eval) @@ -172,7 +172,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:" + "gembed:gisprimary:gparentflavor:gprimaryflavor:gprimaryid:" "trackID:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:" "siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" "charge:quality:chisq:ndf:nhits:layers:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:nlmaps:nlintt:nltpc:nlmms:" @@ -192,7 +192,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" + "gembed:gisprimary:gparentflavor:gprimaryflavor:gprimaryid:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" "ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" "npedge:nredge:nbig:novlp:merr:msize:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); @@ -205,7 +205,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "glayer:" "gpx:gpy:gpz:gtpt:gtphi:gteta:" "gvx:gvy:gvz:" - "gembed:gprimary:gflav:" + "gembed:gisprimary:gflav:" "dphiprev:detaprev:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -1455,7 +1455,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gvz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gprimary = std::numeric_limits::quiet_NaN(); + float gisprimary = std::numeric_limits::quiet_NaN(); float gfpx = 0.; float gfpy = 0.; @@ -1504,7 +1504,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); + gisprimary = trutheval->is_primary(g4particle); } // if (g4particle) std::set clusters = clustereval->all_clusters_from(g4hit); @@ -1603,7 +1603,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gprimary, + gisprimary, nclusters, clusID, x, @@ -1727,7 +1727,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gprimary = std::numeric_limits::quiet_NaN(); + float gisprimary = std::numeric_limits::quiet_NaN(); float efromtruth = std::numeric_limits::quiet_NaN(); @@ -1781,7 +1781,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfz = outerhit->get_z(1); } gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); + gisprimary = trutheval->is_primary(g4particle); } // if (g4particle){ } @@ -1829,7 +1829,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gprimary, + gisprimary, efromtruth, nhit_tpc_all, nhit_tpc_in, @@ -2030,7 +2030,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gprimary = std::numeric_limits::quiet_NaN(); + float gisprimary = std::numeric_limits::quiet_NaN(); float efromtruth = std::numeric_limits::quiet_NaN(); @@ -2094,7 +2094,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); + gisprimary = trutheval->is_primary(g4particle); } // if (g4particle){ if (Verbosity() > 1) @@ -2162,7 +2162,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gprimary, + gisprimary, efromtruth, nparticles, nhit_tpc_all, @@ -2343,7 +2343,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gprimary = std::numeric_limits::quiet_NaN(); + float gisprimary = std::numeric_limits::quiet_NaN(); float efromtruth = std::numeric_limits::quiet_NaN(); @@ -2399,7 +2399,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); + gisprimary = trutheval->is_primary(g4particle); } // if (g4particle){ } // if (g4hit) { @@ -2459,7 +2459,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gprimary, + gisprimary, efromtruth, nparticles, nhit_tpc_all, @@ -2513,11 +2513,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gtrackID = g4particle->get_track_id(); float gflavor = g4particle->get_pid(); float gembed = trutheval->get_embed(g4particle); - float gprimary = trutheval->is_primary(g4particle); + float gisprimary = trutheval->is_primary(g4particle); if (Verbosity() > 1) { - std::cout << PHWHERE << " PHG4Particle ID " << gtrackID << " gflavor " << gflavor << " gprimary " << gprimary << std::endl; + std::cout << PHWHERE << " PHG4Particle ID " << gtrackID << " gflavor " << gflavor << " gisprimary " << gisprimary << std::endl; } // Get the truth clusters from this particle @@ -2620,7 +2620,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gtrackID, gflavor, gembed, - gprimary, + gisprimary, gphisize, gzsize, gadc, @@ -2712,7 +2712,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gtrackID = g4particle->get_track_id(); float gflavor = g4particle->get_pid(); - auto g4clustermap = trutheval->all_truth_clusters(g4particle); + auto g4clustermap = trutheval->all_truth_clusters(g4particle); std::set g4clusters; for(const auto& [key, cluster]: g4clustermap) { @@ -2879,8 +2879,13 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } float gembed = trutheval->get_embed(g4particle); - float gprimary = trutheval->is_primary(g4particle); + float gisprimary = trutheval->is_primary(g4particle); + float gparentflavor = trutheval->get_parent_particle_flavor(g4particle); + float gprimaryflavor = trutheval->get_primary_particle_flavor(g4particle); + PHG4Particle* g4primary = trutheval->get_primary_particle(g4particle); + float gprimaryid = g4primary->get_track_id(); + // matched track quantities float trackID = std::numeric_limits::quiet_NaN(); float charge = std::numeric_limits::quiet_NaN(); float quality = std::numeric_limits::quiet_NaN(); @@ -3322,7 +3327,10 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gprimary, + gisprimary, + gparentflavor, + gprimaryflavor, + gprimaryid, trackID, px, py, @@ -3758,7 +3766,12 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gtrackID = std::numeric_limits::quiet_NaN(); float gflavor = std::numeric_limits::quiet_NaN(); - float ng4hits = std::numeric_limits::quiet_NaN(); + float gparentflavor = std::numeric_limits::quiet_NaN(); + float gprimaryflavor = std::numeric_limits::quiet_NaN(); + float gprimaryid = std::numeric_limits::quiet_NaN(); + + + float ng4hits = std::numeric_limits::quiet_NaN(); unsigned int ngmaps = 0; unsigned int ngintt = 0; unsigned int ngmms = 0; @@ -3784,7 +3797,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gprimary = std::numeric_limits::quiet_NaN(); + float gisprimary = std::numeric_limits::quiet_NaN(); int ispure = 0; float nfromtruth = std::numeric_limits::quiet_NaN(); @@ -3830,6 +3843,12 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gtrackID = g4particle->get_track_id(); gflavor = g4particle->get_pid(); + gparentflavor = (float) trutheval->get_parent_particle_flavor(g4particle); + gprimaryflavor = (float) trutheval->get_primary_particle_flavor(g4particle); + PHG4Particle* g4primary = trutheval->get_primary_particle(g4particle); + gprimaryid = (float) g4primary->get_track_id(); + // std::cout << " gtrackID " << gtrackID << " gflavor " < g4clusters = clustereval->all_clusters_from(g4particle); ng4hits = g4clusters.size(); gpx = g4particle->get_px(); @@ -3922,7 +3941,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfz = outerhit->get_z(1); } gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); + gisprimary = trutheval->is_primary(g4particle); nfromtruth = trackeval->get_nclusters_contribution(track, g4particle); nwrong = trackeval->get_nwrongclusters_contribution(track, g4particle); @@ -4053,8 +4072,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfx, gfy, gfz, - gembed, - gprimary, + gembed, + gisprimary, + gparentflavor, + gprimaryflavor, + gprimaryid, nfromtruth, nwrong, ntrumaps, @@ -4094,7 +4116,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) << " py " << py << " pz " << pz << " gembed " << gembed - << " gprimary " << gprimary + << " gisprimary " << gisprimary << std::endl; } @@ -4139,7 +4161,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gvy = std::numeric_limits::quiet_NaN(); float gvz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gprimary = std::numeric_limits::quiet_NaN(); + float gisprimary = std::numeric_limits::quiet_NaN(); float gflav = std::numeric_limits::quiet_NaN(); float dphiprev = std::numeric_limits::quiet_NaN(); float detaprev = std::numeric_limits::quiet_NaN(); @@ -4212,7 +4234,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gprimary = trutheval->is_primary(g4particle); + gisprimary = trutheval->is_primary(g4particle); gflav = g4particle->get_pid(); if (i >= 1) { @@ -4245,7 +4267,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gvy, gvz, gembed, - gprimary, + gisprimary, gflav, dphiprev, detaprev, diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.cc b/simulation/g4simulation/g4eval/SvtxTruthEval.cc index 9500e7134a..f0dfb56426 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.cc @@ -1082,6 +1082,22 @@ bool SvtxTruthEval::is_primary(PHG4Particle* particle) return _basetrutheval.is_primary(particle); } +int SvtxTruthEval::get_parent_particle_flavor(PHG4Particle* particle) +{ + PHG4Particle* parent = _basetrutheval.get_parent_particle(particle); + int parent_pid = parent->get_pid(); + + return parent_pid; +} + +int SvtxTruthEval::get_primary_particle_flavor(PHG4Particle* particle) +{ + PHG4Particle* primary = _basetrutheval.get_primary_particle(particle); + int primary_pid = primary->get_pid(); + + return primary_pid; +} + PHG4Particle* SvtxTruthEval::get_primary_particle(PHG4Hit* g4hit) { if (!has_node_pointers()) diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.h b/simulation/g4simulation/g4eval/SvtxTruthEval.h index 24a86a5ace..b8a5efcff3 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.h +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.h @@ -46,6 +46,8 @@ class SvtxTruthEval std::set all_truth_hits(PHG4Particle* particle); PHG4Particle* get_particle(PHG4Hit* g4hit); int get_embed(PHG4Particle* particle); + int get_parent_particle_flavor(PHG4Particle* particle); + int get_primary_particle_flavor(PHG4Particle* particle); PHG4VtxPoint* get_vertex(PHG4Particle* particle); bool is_primary(PHG4Particle* particle); PHG4Particle* get_primary_particle(PHG4Hit* g4hit); From 04ab0217e3fd65fe5c4ea8b0172f36b3ca1269c4 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 2 Apr 2026 14:05:19 -0400 Subject: [PATCH 440/866] Use >= for skimming thresholds and bump EMCal threshold by 1 Change skimming comparisons from > to >= for EMC, HCal (in/out), sEPD, and ZDC so events are skimmed when not-instrumented channel counts meet or exceed the configured thresholds. Update the combined skimming condition accordingly. Bump default m_EMC_skim_threshold from 192 to 193 and clarify comments to explain the EMCal behavior (skim when at least one full packet +1 channel, i.e. >=193) and to document the >= semantics for other subsystems. --- .../Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc | 12 ++++++------ .../Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h | 11 ++++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 8941f15c0b..822dbdf9da 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -108,7 +108,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) h_EMC_nTowers_notinstr->Fill(notinstr_EMC); } - if (notinstr_EMC > m_EMC_skim_threshold) + if (notinstr_EMC >= m_EMC_skim_threshold) { EMC_skim_count++; } @@ -159,8 +159,8 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) h_HCal_nTowers_notinstr->Fill(notinstr_HCalout); } - if (notinstr_HCalin > m_HCal_skim_threshold || - notinstr_HCalout > m_HCal_skim_threshold) + if (notinstr_HCalin >= m_HCal_skim_threshold || + notinstr_HCalout >= m_HCal_skim_threshold) { HCal_skim_count++; } @@ -199,7 +199,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) h_sEPD_nTowers_notinstr->Fill(notinstr_sEPD); } - if (notinstr_sEPD > m_sEPD_skim_threshold) + if (notinstr_sEPD >= m_sEPD_skim_threshold) { sEPD_skim_count++; } @@ -238,14 +238,14 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) h_ZDC_nTowers_notinstr->Fill(notinstr_ZDC); } - if (notinstr_ZDC > m_ZDC_skim_threshold) + if (notinstr_ZDC >= m_ZDC_skim_threshold) { ZDC_skim_count++; } } // If any of the enabled skimming conditions are met, then increment the skim counter and return ABORTEVENT to skip the event - if ((m_EMC_skim_threshold > 0 && notinstr_EMC > m_EMC_skim_threshold) || (m_HCal_skim_threshold > 0 && (notinstr_HCalin > m_HCal_skim_threshold || notinstr_HCalout > m_HCal_skim_threshold)) || (m_sEPD_skim_threshold > 0 && notinstr_sEPD > m_sEPD_skim_threshold) || (m_ZDC_skim_threshold > 0 && notinstr_ZDC > m_ZDC_skim_threshold)) + if ((m_EMC_skim_threshold > 0 && notinstr_EMC >= m_EMC_skim_threshold) || (m_HCal_skim_threshold > 0 && (notinstr_HCalin >= m_HCal_skim_threshold || notinstr_HCalout >= m_HCal_skim_threshold)) || (m_sEPD_skim_threshold > 0 && notinstr_sEPD >= m_sEPD_skim_threshold) || (m_ZDC_skim_threshold > 0 && notinstr_ZDC >= m_ZDC_skim_threshold)) { n_skimcounter++; return Fun4AllReturnCodes::ABORTEVENT; diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 95f36ab33a..315cd578ac 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -64,17 +64,18 @@ class CaloStatusSkimmer : public SubsysReco { bool b_produce_QA_histograms{false}; // If the threshold is set to 0, then the skimming for that subsystem is disabled. If threshold is > 0, then the event is skimmed if nchannels >= threshold not-instrumented (empty/missing packet) channels in that subsystem. - uint16_t m_EMC_skim_threshold{192}; - // skim if nchannels > this many not-instrumented (empty/missing packet) channels in EMCal + + uint16_t m_EMC_skim_threshold{193}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in EMCal. For the EMCal in particular we want to skim if greater than 1 packet's worth of channels are not-instrumented, which corresponds to 193 channels (since each packet has 192 channels) uint16_t m_HCal_skim_threshold{192}; - // skim if nchannels > this many not-instrumented (empty/missing packet) channels in HCal + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in HCal. Corresponds to 1 packet's worth of channels in HCal, which has 192 channels per packet uint16_t m_sEPD_skim_threshold{1}; - // skim if nchannels > this many not-instrumented (empty/missing packet) channels in sEPD + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in sEPD. uint16_t m_ZDC_skim_threshold{0}; - // skim if nchannels > this many not-instrumented (empty/missing packet) channels in ZDC + // skim if nchannels > this many not-instrumented (empty/missing packet) channels in ZDC. Some issue in the ZDC right now so skimming is turned off by now by default. // Counters for number of events skimmed per subsystem uint32_t EMC_skim_count = 0; From 3c9108904736bc14f1cbe1fe1a288158dabb86a3 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 4 Apr 2026 15:43:48 -0400 Subject: [PATCH 441/866] CaloTowerStatus - Allow HCal Bad Tower Masking - remove restriction on Bad Tower Masking which initallly was limited EMCal and sEPD --- offline/packages/CaloReco/CaloTowerStatus.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 81013f9790..d21ea08dc2 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -113,11 +113,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) } } - m_calibName_hotMap = m_detector + "nome"; - if (m_dettype == CaloTowerDefs::CEMC || m_dettype == CaloTowerDefs::SEPD) - { - m_calibName_hotMap = m_detector + "_BadTowerMap"; - } + m_calibName_hotMap = m_detector + "_BadTowerMap"; m_fieldname_hotMap = "status"; m_fieldname_z_score = m_detector + "_sigma"; From c833b3e4e89561456ce4b67353a5a225fc54604c Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 4 Apr 2026 15:58:27 -0400 Subject: [PATCH 442/866] emcNoisyTowerFinder - Flag only dead towers for HCal - HCal cold / hot towers should remain unflagged as they can be calibrated offline - Only identify dead towers so they can be masked --- .../calo_emc_noisy_tower/emcNoisyTowerFinder.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc b/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc index 19809fedbb..533089f431 100644 --- a/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc +++ b/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc @@ -270,6 +270,16 @@ void emcNoisyTowerFinder::FindHot(const std::string &infilename, const std::stri } int val = h_hot->GetBinContent(i + 1, j + 1); float sigma = h_heatSigma->GetBinContent(i + 1, j + 1); + // For HCal only flag DEAD towers + if (Neta == 24 && val > 1) + { + if (Verbosity() > 0) + { + std::cout << "WARNING: Skipping Flagging for " << m_caloName << " Tower (" << j << ", " << i << ") with status = " << val << " and sigma = " << sigma << std::endl; + } + val = 0; + sigma = 0; + } cdbttree_out->SetIntValue(key, m_fieldname_out, val); cdbttree_out->SetFloatValue(key, m_caloName + "_sigma", sigma); } From 49d7338b97db155131f6f42cd3cad59682bfd49c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 5 Apr 2026 09:51:28 -0400 Subject: [PATCH 443/866] Remove debug output from CaloStatusSkimmer Comment out debug output in constructor and Init method --- .../Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 822dbdf9da..1ba5b822e4 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -12,24 +12,24 @@ #include #include +#include + #include #include #include -#include - //____________________________________________________________________________.. CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) : SubsysReco(name) { - std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; + //std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; } //____________________________________________________________________________.. int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) { - std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) This is Init..." << std::endl; + // std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) This is Init..." << std::endl; if (b_produce_QA_histograms) { From b3cf749afcdcc5190f1cf9ecb81ef25c43055bf2 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 5 Apr 2026 09:52:38 -0400 Subject: [PATCH 444/866] Remove unused TH1.h include Removed unnecessary TH1.h include from CaloStatusSkimmer.h --- offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index 315cd578ac..bc684efc79 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -10,8 +10,6 @@ #include #include -#include - class PHCompositeNode; class TH1; From 18593c45dce47bc3a00c338c4e638765f460d30c Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Wed, 8 Apr 2026 11:52:31 -0400 Subject: [PATCH 445/866] Change name gisprimatry back to gprimary. Add parent track ID to ntuples. --- .../g4simulation/g4eval/SvtxEvaluator.cc | 74 ++++++++++--------- .../g4simulation/g4eval/SvtxTruthEval.cc | 6 ++ .../g4simulation/g4eval/SvtxTruthEval.h | 1 + 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 041d111941..0ac2c85287 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -123,7 +123,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:" "gvx:gvy:gvz:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gisprimary:nclusters:" + "gembed:gprimary:nclusters:" "clusID:x:y:z:eta:phi:e:adc:layer:size:" "efromtruth:dphitru:detatru:dztru:drtru:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); @@ -138,7 +138,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gtrackID:gflavor:" "gpx:gpy:gpz:gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gisprimary:efromtruth:" + "gembed:gprimary:efromtruth:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -152,14 +152,14 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gy:gz:gr:gphi:geta:gt:gtrackID:gflavor:" "gpx:gpy:gpz:gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gisprimary:efromtruth:nparticles:" + "gembed:gprimary:efromtruth:nparticles:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } if (_do_g4cluster_eval) { _ntp_g4cluster = new TNtuple("ntp_g4cluster", "g4cluster => max truth", - "event:layer:gx:gy:gz:gt:gedep:gr:gphi:geta:gtrackID:gflavor:gembed:gisprimary:gphisize:gzsize:gadc:nreco:x:y:z:r:phi:eta:ex:ey:ez:ephi:adc:phisize:zsize"); + "event:layer:gx:gy:gz:gt:gedep:gr:gphi:geta:gtrackID:gflavor:gembed:gprimary:gphisize:gzsize:gadc:nreco:x:y:z:r:phi:eta:ex:ey:ez:ephi:adc:phisize:zsize"); } if (_do_gtrack_eval) @@ -172,7 +172,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gisprimary:gparentflavor:gprimaryflavor:gprimaryid:" + "gembed:gprimary:gparentflavor:gparentid:gprimaryflavor:gprimaryid:" "trackID:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:" "siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" "charge:quality:chisq:ndf:nhits:layers:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:nlmaps:nlintt:nltpc:nlmms:" @@ -192,7 +192,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gisprimary:gparentflavor:gprimaryflavor:gprimaryid:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" + "gembed:gprimary:gparentflavor:gparentid:gprimaryflavor:gprimaryid:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" "ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" "npedge:nredge:nbig:novlp:merr:msize:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); @@ -205,7 +205,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "glayer:" "gpx:gpy:gpz:gtpt:gtphi:gteta:" "gvx:gvy:gvz:" - "gembed:gisprimary:gflav:" + "gembed:gprimary:gflav:" "dphiprev:detaprev:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -1455,7 +1455,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gvz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gisprimary = std::numeric_limits::quiet_NaN(); + float gprimary = std::numeric_limits::quiet_NaN(); float gfpx = 0.; float gfpy = 0.; @@ -1504,7 +1504,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gisprimary = trutheval->is_primary(g4particle); + gprimary = trutheval->is_primary(g4particle); } // if (g4particle) std::set clusters = clustereval->all_clusters_from(g4hit); @@ -1603,7 +1603,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gisprimary, + gprimary, nclusters, clusID, x, @@ -1727,7 +1727,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gisprimary = std::numeric_limits::quiet_NaN(); + float gprimary = std::numeric_limits::quiet_NaN(); float efromtruth = std::numeric_limits::quiet_NaN(); @@ -1781,7 +1781,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfz = outerhit->get_z(1); } gembed = trutheval->get_embed(g4particle); - gisprimary = trutheval->is_primary(g4particle); + gprimary = trutheval->is_primary(g4particle); } // if (g4particle){ } @@ -1829,7 +1829,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gisprimary, + gprimary, efromtruth, nhit_tpc_all, nhit_tpc_in, @@ -2030,7 +2030,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gisprimary = std::numeric_limits::quiet_NaN(); + float gprimary = std::numeric_limits::quiet_NaN(); float efromtruth = std::numeric_limits::quiet_NaN(); @@ -2094,7 +2094,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gisprimary = trutheval->is_primary(g4particle); + gprimary = trutheval->is_primary(g4particle); } // if (g4particle){ if (Verbosity() > 1) @@ -2162,7 +2162,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gisprimary, + gprimary, efromtruth, nparticles, nhit_tpc_all, @@ -2343,7 +2343,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gisprimary = std::numeric_limits::quiet_NaN(); + float gprimary = std::numeric_limits::quiet_NaN(); float efromtruth = std::numeric_limits::quiet_NaN(); @@ -2399,7 +2399,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gisprimary = trutheval->is_primary(g4particle); + gprimary = trutheval->is_primary(g4particle); } // if (g4particle){ } // if (g4hit) { @@ -2459,7 +2459,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gisprimary, + gprimary, efromtruth, nparticles, nhit_tpc_all, @@ -2513,11 +2513,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gtrackID = g4particle->get_track_id(); float gflavor = g4particle->get_pid(); float gembed = trutheval->get_embed(g4particle); - float gisprimary = trutheval->is_primary(g4particle); + float gprimary = trutheval->is_primary(g4particle); if (Verbosity() > 1) { - std::cout << PHWHERE << " PHG4Particle ID " << gtrackID << " gflavor " << gflavor << " gisprimary " << gisprimary << std::endl; + std::cout << PHWHERE << " PHG4Particle ID " << gtrackID << " gflavor " << gflavor << " gprimary " << gprimary << std::endl; } // Get the truth clusters from this particle @@ -2620,7 +2620,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gtrackID, gflavor, gembed, - gisprimary, + gprimary, gphisize, gzsize, gadc, @@ -2879,8 +2879,10 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } float gembed = trutheval->get_embed(g4particle); - float gisprimary = trutheval->is_primary(g4particle); - float gparentflavor = trutheval->get_parent_particle_flavor(g4particle); + float gprimary = trutheval->is_primary(g4particle); + float gparentflavor = trutheval->get_parent_particle_flavor(g4particle); + PHG4Particle* parent = trutheval->get_parent_particle(g4particle); + float gparentid = parent->get_track_id(); float gprimaryflavor = trutheval->get_primary_particle_flavor(g4particle); PHG4Particle* g4primary = trutheval->get_primary_particle(g4particle); float gprimaryid = g4primary->get_track_id(); @@ -3327,8 +3329,9 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gisprimary, + gprimary, gparentflavor, + gparentid, gprimaryflavor, gprimaryid, trackID, @@ -3767,9 +3770,9 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gtrackID = std::numeric_limits::quiet_NaN(); float gflavor = std::numeric_limits::quiet_NaN(); float gparentflavor = std::numeric_limits::quiet_NaN(); + float gparentid = std::numeric_limits::quiet_NaN(); float gprimaryflavor = std::numeric_limits::quiet_NaN(); - float gprimaryid = std::numeric_limits::quiet_NaN(); - + float gprimaryid = std::numeric_limits::quiet_NaN(); float ng4hits = std::numeric_limits::quiet_NaN(); unsigned int ngmaps = 0; @@ -3797,7 +3800,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfy = std::numeric_limits::quiet_NaN(); float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gisprimary = std::numeric_limits::quiet_NaN(); + float gprimary = std::numeric_limits::quiet_NaN(); int ispure = 0; float nfromtruth = std::numeric_limits::quiet_NaN(); @@ -3844,6 +3847,8 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gflavor = g4particle->get_pid(); gparentflavor = (float) trutheval->get_parent_particle_flavor(g4particle); + PHG4Particle* parent = trutheval->get_parent_particle(g4particle); + gparentid = (float) parent->get_track_id(); gprimaryflavor = (float) trutheval->get_primary_particle_flavor(g4particle); PHG4Particle* g4primary = trutheval->get_primary_particle(g4particle); gprimaryid = (float) g4primary->get_track_id(); @@ -3941,7 +3946,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfz = outerhit->get_z(1); } gembed = trutheval->get_embed(g4particle); - gisprimary = trutheval->is_primary(g4particle); + gprimary = trutheval->is_primary(g4particle); nfromtruth = trackeval->get_nclusters_contribution(track, g4particle); nwrong = trackeval->get_nwrongclusters_contribution(track, g4particle); @@ -4073,8 +4078,9 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfy, gfz, gembed, - gisprimary, + gprimary, gparentflavor, + gparentid, gprimaryflavor, gprimaryid, nfromtruth, @@ -4116,7 +4122,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) << " py " << py << " pz " << pz << " gembed " << gembed - << " gisprimary " << gisprimary + << " gprimary " << gprimary << std::endl; } @@ -4161,7 +4167,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gvy = std::numeric_limits::quiet_NaN(); float gvz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); - float gisprimary = std::numeric_limits::quiet_NaN(); + float gprimary = std::numeric_limits::quiet_NaN(); float gflav = std::numeric_limits::quiet_NaN(); float dphiprev = std::numeric_limits::quiet_NaN(); float detaprev = std::numeric_limits::quiet_NaN(); @@ -4234,7 +4240,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) } gembed = trutheval->get_embed(g4particle); - gisprimary = trutheval->is_primary(g4particle); + gprimary = trutheval->is_primary(g4particle); gflav = g4particle->get_pid(); if (i >= 1) { @@ -4267,7 +4273,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gvy, gvz, gembed, - gisprimary, + gprimary, gflav, dphiprev, detaprev, diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.cc b/simulation/g4simulation/g4eval/SvtxTruthEval.cc index f0dfb56426..2ecaccf41c 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.cc @@ -1082,6 +1082,12 @@ bool SvtxTruthEval::is_primary(PHG4Particle* particle) return _basetrutheval.is_primary(particle); } +PHG4Particle* SvtxTruthEval::get_parent_particle(PHG4Particle* particle) +{ + PHG4Particle* parent = _basetrutheval.get_parent_particle(particle); + return parent; +} + int SvtxTruthEval::get_parent_particle_flavor(PHG4Particle* particle) { PHG4Particle* parent = _basetrutheval.get_parent_particle(particle); diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.h b/simulation/g4simulation/g4eval/SvtxTruthEval.h index b8a5efcff3..12b0b04ab0 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.h +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.h @@ -46,6 +46,7 @@ class SvtxTruthEval std::set all_truth_hits(PHG4Particle* particle); PHG4Particle* get_particle(PHG4Hit* g4hit); int get_embed(PHG4Particle* particle); + PHG4Particle* get_parent_particle(PHG4Particle* particle); int get_parent_particle_flavor(PHG4Particle* particle); int get_primary_particle_flavor(PHG4Particle* particle); PHG4VtxPoint* get_vertex(PHG4Particle* particle); From 108c24b3a0b58a5f8424b37f21a0d78a34ddec0c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 10 Apr 2026 09:00:29 -0400 Subject: [PATCH 446/866] make sure detector does not leave scope --- offline/packages/trackreco/MakeActsGeometry.cc | 11 +++++------ offline/packages/trackreco/MakeActsGeometry.h | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 5abeaa6397..64e1c16f48 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -299,19 +299,18 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) m_actsGeometry->set_tpc_tzero(m_tpc_tzero); m_actsGeometry->set_sampa_tzero_bias(m_sampa_tzero_bias); // alignment_transformation.useInttSurveyGeometry(m_inttSurvey); + if (Verbosity() > 1) { alignment_transformation.verbosity(); } alignment_transformation.createMap(topNode); - for (auto &[layer, factor] : m_misalignmentFactor) { alignment_transformation.misalignmentFactor(layer, factor); } - // print - if (Verbosity()) + if (Verbosity() > 3) { for (const auto &id : surfMaps.m_tpcVolumeIds) { @@ -742,13 +741,13 @@ void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& r config.materialDecorator = matDeco; // this does the building now. The TGeoDetector owns the // tracking geometry - ActsExamples::TGeoDetectorWithOptions detector(config); + m_TGeoDetector = std::make_unique(config); // Add specific options for this geometry - detector.addOptions(desc); + m_TGeoDetector->addOptions(desc); auto vm = ActsExamples::Options::parse(desc, argc, argv); - m_tGeometry = detector.m_detector.trackingGeometry(); + m_tGeometry = m_TGeoDetector->m_detector.trackingGeometry(); if (m_useField) { m_magneticField = ActsExamples::Options::readMagneticField(vm); diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index db53aa4337..dfd20f1d9f 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -216,6 +216,7 @@ class MakeActsGeometry : public SubsysReco // void makeTGeoNodeMap(PHCompositeNode *topNode); void unpackVolumes(); + std::unique_ptr m_TGeoDetector = nullptr; /// Subdetector geometry containers for getting layer information PHG4CylinderGeomContainer *m_geomContainerMvtx = nullptr; From 4e3b25837f0cdc1ebf498be23c10ee0f8ce00174 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Fri, 10 Apr 2026 13:23:56 -0400 Subject: [PATCH 447/866] CD: DecayFinder triggering bug fix --- offline/packages/decayfinder/DecayFinder.cc | 24 +++++++++++++++------ offline/packages/decayfinder/DecayFinder.h | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index a3521df780..6d622cd302 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -93,14 +93,14 @@ int DecayFinder::Init(PHCompositeNode* topNode) int DecayFinder::process_event(PHCompositeNode* topNode) { - bool decayFound = findDecay(topNode); + int decayFound = findDecay(topNode); - if (decayFound && m_save_dst && Verbosity() >= VERBOSITY_MORE) + if (decayFound > 0 && m_save_dst && Verbosity() >= VERBOSITY_MORE) { printNode(topNode); } - if (m_triggerOnDecay && !decayFound) + if (m_triggerOnDecay && decayFound < 1) { if (Verbosity() >= VERBOSITY_MORE) { @@ -317,10 +317,10 @@ int DecayFinder::parseDecayDescriptor() * as decays wont enter the HepMC record * need a switch to go to Geant4 record */ -bool DecayFinder::findDecay(PHCompositeNode* topNode) +int DecayFinder::findDecay(PHCompositeNode* topNode) { bool decayWasFound = false; - bool reconstructableDecayWasFound = false; + int reconstructableDecayWasFound = 0; bool aTrackFailedPT = false; bool aTrackFailedETA = false; bool aMotherHasPhoton = false; @@ -384,6 +384,11 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) std::cout << "parent->pdg_id(): " << g4particle->get_pid() << std::endl; } + aTrackFailedPT = false; + aTrackFailedETA = false; + aMotherHasPhoton = false; + aMotherHasPi0 = false; + bool breakOut = false; correctMotherProducts.clear(); decayChain.clear(); @@ -416,7 +421,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) else { m_nCandReconstructable += 1; - reconstructableDecayWasFound = true; + ++reconstructableDecayWasFound; if (m_save_dst) { fillDecayNode(topNode, decayChain); @@ -465,6 +470,11 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) std::cout << "parent->pdg_id(): " << (*p)->pdg_id() << std::endl; } + aTrackFailedPT = false; + aTrackFailedETA = false; + aMotherHasPhoton = false; + aMotherHasPi0 = false; + bool breakOut = false; correctMotherProducts.clear(); decayChain.clear(); @@ -505,7 +515,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) else { m_nCandReconstructable += 1; - reconstructableDecayWasFound = true; + ++reconstructableDecayWasFound; if (m_save_dst) { fillDecayNode(topNode, decayChain); diff --git a/offline/packages/decayfinder/DecayFinder.h b/offline/packages/decayfinder/DecayFinder.h index bd893546a1..3605733e9f 100644 --- a/offline/packages/decayfinder/DecayFinder.h +++ b/offline/packages/decayfinder/DecayFinder.h @@ -42,7 +42,7 @@ class DecayFinder : public SubsysReco int parseDecayDescriptor(); - bool findDecay(PHCompositeNode *topNode); + int findDecay(PHCompositeNode *topNode); bool findParticle(const std::string &particle); From a1aae44a959933bdc41b47c0b60a77b99d107080 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 10 Apr 2026 15:15:36 -0400 Subject: [PATCH 448/866] clean up --- offline/packages/trackreco/MakeActsGeometry.cc | 1 + offline/packages/trackreco/PHActsSiliconSeeding.cc | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 64e1c16f48..a76c822287 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -721,6 +721,7 @@ void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& r config.surfaceLogLevel = Acts::Logging::FATAL; config.layerLogLevel = Acts::Logging::FATAL; config.volumeLogLevel = Acts::Logging::FATAL; + config.logLevel = Acts::Logging::FATAL; config.detectorElementFactory = sPHENIXElementFactory; config.readJson(responseFile); diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index 1a9e27d5d2..ab0126913c 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -442,7 +442,6 @@ void PHActsSiliconSeeding::makeSvtxTracks(const std::vector& seedVect int numGoodSeeds = 0; m_seedid = -1; - int strobe = m_lowStrobeIndex; for (const auto& seed : seedVector) { if (m_seedAnalysis) @@ -601,11 +600,6 @@ void PHActsSiliconSeeding::makeSvtxTracks(const std::vector& seedVect << svtxtracktime << std::endl; } - strobe++; - if (strobe > m_highStrobeIndex) - { - std::cout << PHWHERE << "Error: some how grid seed vector is not the same as the number of strobes" << std::endl; - } } if (m_seedAnalysis) From bd1e06bac9e5d99b5cbf9a1b539829aeb20d158c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 10 Apr 2026 15:22:39 -0400 Subject: [PATCH 449/866] remove deadweight --- .../packages/trackreco/MakeActsGeometry.cc | 34 ------------------- offline/packages/trackreco/MakeActsGeometry.h | 9 ----- 2 files changed, 43 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index a76c822287..b4e03ca909 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -765,40 +765,6 @@ void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& r return; } -void MakeActsGeometry::readTGeoLayerBuilderConfigsFile(const std::string &path, - ActsExamples::TGeoDetector::Config &config) -{ - if (path.empty()) - { - std::cout << "There is no acts geometry response file loaded. Cannot build, exiting" - << std::endl; - exit(1); - } - - nlohmann::json djson; - std::ifstream infile(path, std::ifstream::in | std::ifstream::binary); - infile >> djson; - - config.unitScalor = djson["geo-tgeo-unit-scalor"]; - - config.buildBeamPipe = djson["geo-tgeo-build-beampipe"]; - if (config.buildBeamPipe) - { - const auto beamPipeParameters = - djson["geo-tgeo-beampipe-parameters"].get>(); - config.beamPipeRadius = beamPipeParameters[0]; - config.beamPipeHalflengthZ = beamPipeParameters[1]; - config.beamPipeLayerThickness = beamPipeParameters[2]; - } - - // Fill nested volume configs - for (const auto &volume : djson["Volumes"]) - { - auto &vol = config.volumes.emplace_back(); - vol = volume; - } -} - void MakeActsGeometry::unpackVolumes() { // m_tGeometry is a TrackingGeometry pointer diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index dfd20f1d9f..b7eb441b23 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -175,15 +175,6 @@ class MakeActsGeometry : public SubsysReco /// Function that mimics ActsExamples::GeometryExampleBase void makeGeometry(int argc, char *argv[], const std::string& responseFile, const std::string& materialFile); -#ifndef __CLING__ - std::pair, - std::vector>> - build(const boost::program_options::variables_map &vm, - ActsExamples::TGeoDetector::Config config, - ActsExamples::TGeoDetectorWithOptions &detector); -#endif - void readTGeoLayerBuilderConfigsFile(const std::string &path, - ActsExamples::TGeoDetector::Config &config); void setMaterialResponseFile(std::string &responseFile, std::string &materialFile); From 2d515ad605fea4d21699db65b98af8a8f414d943 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:45:15 -0400 Subject: [PATCH 450/866] EventPlaneReco: Update sEPD channel selection and charge handling Updated the sEPD event plane reconstruction strategy based on recent QA findings. Major changes include: - Removed isHot channel exclusion: QA determined no channels are consistently hot in sEPD; using all available channels instead. - Implemented charge clamping: Added a configurable threshold (default 50) to cap the maximum charge per channel, mitigating the impact of non-linearities or outliers. - Default Ring 0 exclusion: Added logic to skip the innermost ring (Ring 0) by default to avoid high-intensity beam background noise. - Updated noise floor: Increased default minimum channel charge from 0.2 to 0.5. - Added setters for the new charge threshold and ring-skipping toggle. --- .../packages/eventplaneinfo/EventPlaneReco.cc | 18 +++++++++++++++--- .../packages/eventplaneinfo/EventPlaneReco.h | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index 0179e08926..150f69f2fe 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -351,15 +351,27 @@ int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) TowerInfo* tower = towerinfosEPD->get_tower_at_channel(channel); unsigned int key = TowerInfoDefs::encode_epd(channel); + int rbin = TowerInfoDefs::get_epd_rbin(key); double charge = tower->get_energy(); - // skip bad channels - // skip channels with very low charge - if (tower->get_isHot() || charge < m_sepd_min_channel_charge) + // Skip Innermost Ring + if (m_skipRing0 && rbin == 0) { continue; } + // Skip Noise + if (charge <= m_sepd_min_channel_charge) + { + continue; + } + + // Clamp on high charge threshold + if (m_sEPD_charge_threshold && charge > m_sEPD_charge_threshold) + { + charge = m_sEPD_charge_threshold; + } + // arm = 0: South // arm = 1: North unsigned int arm = TowerInfoDefs::get_epd_arm(key); diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.h b/offline/packages/eventplaneinfo/EventPlaneReco.h index 231d30a8bb..7965366263 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.h +++ b/offline/packages/eventplaneinfo/EventPlaneReco.h @@ -65,6 +65,16 @@ class EventPlaneReco : public SubsysReco m_sepd_min_channel_charge = sepd_min_channel_charge; } + void set_charge_threshold(double threshold) + { + m_sEPD_charge_threshold = threshold; + } + + void set_skipRing0(bool skip) + { + m_skipRing0 = skip; + } + void set_EventPlaneInfoNodeName(const std::string &name) { m_EventPlaneInfoNodeName = name; @@ -91,9 +101,12 @@ class EventPlaneReco : public SubsysReco bool m_doNotCalib{false}; bool m_doNotCalibEvent{false}; + bool m_skipRing0{true}; + double m_cent{0.0}; double m_globalEvent{0}; - double m_sepd_min_channel_charge{0.2}; + double m_sepd_min_channel_charge{0.5}; + double m_sEPD_charge_threshold{50}; std::string m_calibName{"SEPD_EventPlaneCalib"}; std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; From cd1e1bf9d35c73815938b8399bd691bc28a76008 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:11:27 -0400 Subject: [PATCH 451/866] EventPlaneReco: Avoid negative thresholds - Ensure during the setting that the threshold is at minimum 0. - Thus, if user does not wish to use a channel threshold then it can be disabled by setting a threshold of zero. --- offline/packages/eventplaneinfo/EventPlaneReco.cc | 2 +- offline/packages/eventplaneinfo/EventPlaneReco.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index 150f69f2fe..bfd68cb4ca 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -367,7 +367,7 @@ int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) } // Clamp on high charge threshold - if (m_sEPD_charge_threshold && charge > m_sEPD_charge_threshold) + if (m_sEPD_charge_threshold > 0 && charge > m_sEPD_charge_threshold) { charge = m_sEPD_charge_threshold; } diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.h b/offline/packages/eventplaneinfo/EventPlaneReco.h index 7965366263..167e7b698a 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.h +++ b/offline/packages/eventplaneinfo/EventPlaneReco.h @@ -67,7 +67,7 @@ class EventPlaneReco : public SubsysReco void set_charge_threshold(double threshold) { - m_sEPD_charge_threshold = threshold; + m_sEPD_charge_threshold = std::max(0.0, threshold); } void set_skipRing0(bool skip) From 19956d803ad99b9dee39d643e8aa2414aa7cffdd Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 11 Apr 2026 15:16:58 -0400 Subject: [PATCH 452/866] QVecCalib: sEPD Q-vector Calibration and Channel Selection Updated the QVecCalib module to align with the new sEPD calibration strategy. Following QA analysis that indicated a lack of persistent hot channels, the per-channel status mapping has been deprecated. Key modifications: - Removed bad channel identification and `SEPD_HotMap` CDB generation. - Implemented mandatory Ring 0 exclusion to mitigate beam background interference. - Added charge clamping (default 50) to handle channel saturation or extreme outliers without discarding data. - Updated the noise floor to 0.5 and added setters for the new charge and noise thresholds. - Simplified `process_sEPD` to use global thresholds instead of individual channel status lookups. --- .../sepd/sepd_eventplanecalib/QVecCalib.cc | 197 ++---------------- .../sepd/sepd_eventplanecalib/QVecCalib.h | 41 ++-- 2 files changed, 28 insertions(+), 210 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index 361b217f20..a4cf72fd38 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -111,13 +111,6 @@ int QVecCalib::process_QA_hist() return ret; } - // Get List of Bad Channels - ret = process_bad_channels(file); - if (ret) - { - return ret; - } - // cleanup file->Close(); delete file; @@ -193,138 +186,6 @@ int QVecCalib::process_sEPD_event_thresholds(TFile* file) return Fun4AllReturnCodes::EVENT_OK; } -int QVecCalib::process_bad_channels(TFile* file) -{ - Fun4AllServer *se = Fun4AllServer::instance(); - - std::string sepd_charge_hist = "hSEPD_Charge"; - - TProfile *hSEPD_Charge{nullptr}; - file->GetObject(sepd_charge_hist.c_str(), hSEPD_Charge); - - // Check if the hist is stored in the file - if (hSEPD_Charge == nullptr) - { - std::cout << PHWHERE << "Error! Cannot find hist: " << sepd_charge_hist << ", in file: " << file->GetName() << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - int rbins = 16; - int bins_charge = 40; - - h2SEPD_South_Charge_rbin = new TH2F("h2SEPD_South_Charge_rbin", - "sEPD South; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); - - h2SEPD_North_Charge_rbin = new TH2F("h2SEPD_North_Charge_rbin", - "sEPD North; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); - - h2SEPD_South_Charge_rbinv2 = new TH2F("h2SEPD_South_Charge_rbinv2", - "sEPD South; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); - - h2SEPD_North_Charge_rbinv2 = new TH2F("h2SEPD_North_Charge_rbinv2", - "sEPD North; r_{bin}; Avg Charge", - rbins, -0.5, rbins - 0.5, - bins_charge, 0, bins_charge); - - hSEPD_Bad_Channels = new TProfile("h_sEPD_Bad_Channels", "sEPD Bad Channels; Channel; Status", QVecShared::SEPD_CHANNELS, -0.5, QVecShared::SEPD_CHANNELS-0.5); - - se->registerHisto(h2SEPD_South_Charge_rbin); - se->registerHisto(h2SEPD_North_Charge_rbin); - se->registerHisto(h2SEPD_South_Charge_rbinv2); - se->registerHisto(h2SEPD_North_Charge_rbinv2); - se->registerHisto(hSEPD_Bad_Channels); - - for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) - { - unsigned int key = TowerInfoDefs::encode_epd(channel); - int rbin = TowerInfoDefs::get_epd_rbin(key); - unsigned int arm = TowerInfoDefs::get_epd_arm(key); - - double avg_charge = hSEPD_Charge->GetBinContent(channel + 1); - - auto* h2 = (arm == 0) ? h2SEPD_South_Charge_rbin : h2SEPD_North_Charge_rbin; - - h2->Fill(rbin, avg_charge); - } - - auto* hSpx = h2SEPD_South_Charge_rbin->ProfileX("hSpx", 2, -1, "s"); - auto* hNpx = h2SEPD_North_Charge_rbin->ProfileX("hNpx", 2, -1, "s"); - - int ctr_dead = 0; - int ctr_hot = 0; - int ctr_cold = 0; - - for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) - { - unsigned int key = TowerInfoDefs::encode_epd(channel); - int rbin = TowerInfoDefs::get_epd_rbin(key); - unsigned int arm = TowerInfoDefs::get_epd_arm(key); - - auto* h2 = (arm == 0) ? h2SEPD_South_Charge_rbinv2 : h2SEPD_North_Charge_rbinv2; - auto* hprof = (arm == 0) ? hSpx : hNpx; - - double charge = hSEPD_Charge->GetBinContent(channel + 1); - double mean_charge = hprof->GetBinContent(rbin + 1); - double sigma = hprof->GetBinError(rbin + 1); - double zscore = 0.0; - - if (sigma > 0) - { - zscore = (charge - mean_charge) / sigma; - } - - if (charge < m_sEPD_min_avg_charge_threshold || std::abs(zscore) > m_sEPD_sigma_threshold) - { - m_bad_channels.insert(channel); - - std::string type; - QVecShared::ChannelStatus status_fill; - - // dead channel - if (charge == 0) - { - type = "Dead"; - status_fill = QVecShared::ChannelStatus::Dead; - ++ctr_dead; - } - // hot channel - else if (zscore > m_sEPD_sigma_threshold) - { - type = "Hot"; - status_fill = QVecShared::ChannelStatus::Hot; - ++ctr_hot; - } - // cold channel - else - { - type = "Cold"; - status_fill = QVecShared::ChannelStatus::Cold; - ++ctr_cold; - } - - hSEPD_Bad_Channels->Fill(channel, static_cast(status_fill)); - std::cout << std::format("{:4} Channel: {:3d}, arm: {}, rbin: {:2d}, Mean: {:5.2f}, Charge: {:5.2f}, Z-Score: {:5.2f}", - type, channel, arm, rbin, mean_charge, charge, zscore) << std::endl; - } - else - { - h2->Fill(rbin, charge); - } - } - - std::cout << "Total Bad Channels: " << m_bad_channels.size() << ", Dead: " - << ctr_dead << ", Hot: " << ctr_hot << ", Cold: " << ctr_cold << std::endl; - - std::cout << "Finished processing Hot sEPD channels" << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - void QVecCalib::init_hists() { unsigned int bins_psi = 126; @@ -957,14 +818,27 @@ bool QVecCalib::process_sEPD() { double charge = m_evtdata->get_sepd_charge(channel); - // Skip Bad Channels - if (m_bad_channels.contains(channel) || charge <= 0) + // Skip Noise + if (charge <= m_sEPD_noise_threshold) { continue; } + // Clamp on high charge threshold + if (m_sEPD_charge_threshold > 0 && charge > m_sEPD_charge_threshold) + { + charge = m_sEPD_charge_threshold; + } + unsigned int key = TowerInfoDefs::encode_epd(channel); unsigned int arm = TowerInfoDefs::get_epd_arm(key); + int rbin = TowerInfoDefs::get_epd_rbin(key); + + // Skip Innermost Ring + if (rbin == 0) + { + continue; + } // arm = 0: South // arm = 1: North @@ -1291,50 +1165,9 @@ void QVecCalib::write_cdb() std::cout << "Info: Directory " << m_cdb_output_dir << " already exists." << std::endl; } - write_cdb_BadTowers(); write_cdb_EventPlane(); } -void QVecCalib::write_cdb_BadTowers() -{ - std::cout << "Writing Bad Towers CDB" << std::endl; - - std::string payload = "SEPD_HotMap"; - std::string fieldname_status = "status"; - std::string fieldname_sigma = "SEPD_sigma"; - std::string output_file = std::format("{}/{}-{}-{}.root", m_cdb_output_dir, payload, m_dst_tag, m_runnumber); - - CDBTTree cdbttree(output_file); - - for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) - { - unsigned int key = TowerInfoDefs::encode_epd(channel); - int status = hSEPD_Bad_Channels->GetBinContent(channel+1); - - float sigma = 0; - - // Hot - if (status == static_cast(QVecShared::ChannelStatus::Hot)) - { - sigma = SIGMA_HOT; - } - - // Cold - else if (status == static_cast(QVecShared::ChannelStatus::Cold)) - { - sigma = SIGMA_COLD; - } - - cdbttree.SetIntValue(key, fieldname_status, status); - cdbttree.SetFloatValue(key, fieldname_sigma, sigma); - } - - std::cout << "Saving CDB: " << payload << " to " << output_file << std::endl; - - cdbttree.Commit(); - cdbttree.WriteCDBTTree(); -} - void QVecCalib::write_cdb_EventPlane() { std::cout << "Writing Event Plane CDB" << std::endl; diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index af9fa5253e..951250683d 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -96,6 +96,16 @@ class QVecCalib : public SubsysReco m_cdb_output_dir = cdb_dir; } + void set_charge_threshold(double threshold) + { + m_sEPD_charge_threshold = std::max(0.0, threshold); + } + + void set_noise_threshold(double threshold) + { + m_sEPD_noise_threshold = threshold; + } + private: static Pass validate_pass(int pass) { @@ -229,29 +239,20 @@ class QVecCalib : public SubsysReco TH2* Psi_NS_corr2{nullptr}; }; - // sEPD Bad Channels - std::unordered_set m_bad_channels; - - double m_sEPD_min_avg_charge_threshold{1}; double m_sEPD_sigma_threshold{3}; + double m_sEPD_charge_threshold{50}; + double m_sEPD_noise_threshold{0.5}; + // Hists TH1* hCentrality{nullptr}; TH2* h2SEPD_Charge{nullptr}; TH2* h2SEPD_Chargev2{nullptr}; - TH2* h2SEPD_South_Charge_rbin{nullptr}; - TH2* h2SEPD_North_Charge_rbin{nullptr}; - - TH2* h2SEPD_South_Charge_rbinv2{nullptr}; - TH2* h2SEPD_North_Charge_rbinv2{nullptr}; - TProfile* hSEPD_Charge_Min{nullptr}; TProfile* hSEPD_Charge_Max{nullptr}; - TProfile* hSEPD_Bad_Channels{nullptr}; - std::map m_hists2D; std::map m_profiles; @@ -399,14 +400,6 @@ class QVecCalib : public SubsysReco */ int process_QA_hist(); - /** - * @brief Identifies and catalogs "Bad" (Hot, Cold, or Dead) sEPD channels. - * * Uses a reference charge histogram to compute Z-scores based on mean charge - * per radial bin. Channels exceeding the sigma threshold are added to the internal exclusion set. - * * @param file Pointer to the open TFile containing QA histograms. - */ - int process_bad_channels(TFile* file); - /** * @brief Establishes sEPD charge-cut thresholds for event selection. * * Uses the 2D total charge vs. centrality distribution to derive mean and @@ -424,14 +417,6 @@ class QVecCalib : public SubsysReco * * @param output_dir The filesystem directory where the .root payload will be saved. */ void write_cdb_EventPlane(); - - /** - * @brief Writes the Hot/Cold tower status map to a CDB-formatted TTree. - * * Encodes sEPD channel indices into TowerInfo keys and maps status codes (1=Dead, - * 2=Hot, 3=Cold) to the final database payload. - * * @param output_dir The filesystem directory where the .root payload will be saved. - */ - void write_cdb_BadTowers(); }; #endif // SEPDEVENTPLANECALIB_QVECCALIB_H From 169c06b61ed2537a2766eb213db8a5e0fb1c43e2 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Sat, 11 Apr 2026 15:40:28 -0400 Subject: [PATCH 453/866] QVecCalib: Code Review Fixes - Add to header for use of std::max so QVecCalib.h is self-contained. - hEP_res_{n} histograms are only used during m_pass == Pass::ApplyFlattening --- calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc | 9 ++++++--- calibrations/sepd/sepd_eventplanecalib/QVecCalib.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc index a4cf72fd38..747524bfb2 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -222,10 +222,13 @@ void QVecCalib::init_hists() m_hists2D[name_N] = new TH2F(name_N.c_str(), title_N.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); m_hists2D[name_NS] = new TH2F(name_NS.c_str(), title_NS.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); - std::string name_EP_res = std::format("hEP_res_{}", n); - std::string title_EP_res = std::format("; Centrality [%]; #LTRe(Q^{{S}}_{{{0}}} Q^{{N*}}_{{{0}}}) / (|Q^{{S}}_{{{0}}}||Q^{{N}}_{{{0}}}|)#GT", n); + if (m_pass == Pass::ApplyFlattening) + { + std::string name_EP_res = std::format("hEP_res_{}", n); + std::string title_EP_res = std::format("; Centrality [%]; #LTRe(Q^{{S}}_{{{0}}} Q^{{N*}}_{{{0}}}) / (|Q^{{S}}_{{{0}}}||Q^{{N}}_{{{0}}}|)#GT", n); - m_profiles[name_EP_res] = new TProfile(name_EP_res.c_str(), title_EP_res.c_str(), m_cent_bins, m_cent_low, m_cent_high); + m_profiles[name_EP_res] = new TProfile(name_EP_res.c_str(), title_EP_res.c_str(), m_cent_bins, m_cent_low, m_cent_high); + } // South, North for (auto det : m_subdetectors) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h index 951250683d..0613505794 100644 --- a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -5,6 +5,7 @@ #include +#include #include #include #include From 4fc7b3c77d892b356fb61dc49881145cc7290894 Mon Sep 17 00:00:00 2001 From: Jinglin-liu Date: Mon, 13 Apr 2026 00:49:13 -0400 Subject: [PATCH 454/866] Add EMCalShowerShapes QA module --- offline/QA/Jet/EMCalShowerShapes.cc | 672 ++++++++++++++++++++++++++++ offline/QA/Jet/EMCalShowerShapes.h | 130 ++++++ offline/QA/Jet/Makefile.am | 2 + 3 files changed, 804 insertions(+) create mode 100644 offline/QA/Jet/EMCalShowerShapes.cc create mode 100644 offline/QA/Jet/EMCalShowerShapes.h diff --git a/offline/QA/Jet/EMCalShowerShapes.cc b/offline/QA/Jet/EMCalShowerShapes.cc new file mode 100644 index 0000000000..b24f36be9b --- /dev/null +++ b/offline/QA/Jet/EMCalShowerShapes.cc @@ -0,0 +1,672 @@ +/////////////////////// +//EMCal Shower Shape QA +// +/////////////////////// +#include "EMCalShowerShapes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + void shift_tower_index(int& ieta, int& iphi, int etadiv, int phidiv) + { + while (iphi < 0) + { + iphi += phidiv; + } + while (iphi >= phidiv) + { + iphi -= phidiv; + } + if (ieta < 0 || ieta >= etadiv) + { + ieta = -1; + } + } +} + +EMCalShowerShapes::EMCalShowerShapes(const std::string &modulename, const std::string &inputnode, const std::string &histtag) + : SubsysReco(modulename) + , m_modulename(modulename) + , m_inputnode(inputnode) + , m_histtag(histtag) + , m_trgToSelect(JetQADefs::GL1::MBDNSPhoton1) + , m_doTrgSelect(false) +{ +} + +EMCalShowerShapes::~EMCalShowerShapes() +{ + delete m_analyzer; +} + +int EMCalShowerShapes::Init(PHCompositeNode* /*topNode*/) +{ + delete m_analyzer; + m_analyzer = new TriggerAnalyzer(); + + gStyle->SetOptTitle(0); + m_manager = QAHistManagerDef::getHistoManager(); + if (!m_manager) + { + std::cerr << PHWHERE << "PANIC: couldn't grab histogram manager!" << std::endl; + assert(m_manager); + } + + std::string smallModuleName = m_modulename; + std::transform(smallModuleName.begin(), smallModuleName.end(), smallModuleName.begin(), ::tolower); + + std::vector vecHistNames = { + "cluster_et", + "e11_to_e33", + "e33_to_e55", + "e55_to_e77", + "e32_to_e35", + "weta", + "wphi", + "weta_cogx", + "wphi_cogx", + "detamax", + "dphimax", + "mean_time", + "iso04_emcal", + "weta_vs_et", + "wphi_vs_et"}; + + for (auto &histName : vecHistNames) + { + histName.insert(0, "h_" + smallModuleName + "_"); + if (!m_histtag.empty()) + { + histName.append("_" + m_histtag); + } + } + + h_cluster_et = new TH1F(vecHistNames[0].data(), "", 120, 0, 30); + h_cluster_et->GetXaxis()->SetTitle("E_{T} [GeV]"); + + h_e11oe33 = new TH1F(vecHistNames[1].data(), "", 25, 0, 1); + h_e11oe33->GetXaxis()->SetTitle("e11/e33"); + + h_e33oe55 = new TH1F(vecHistNames[2].data(), "", 25, 0, 1); + h_e33oe55->GetXaxis()->SetTitle("e33/e55"); + + h_e55oe77 = new TH1F(vecHistNames[3].data(), "", 25, 0, 1); + h_e55oe77->GetXaxis()->SetTitle("e55/e77"); + + h_e32oe35 = new TH1F(vecHistNames[4].data(), "", 25, 0, 1); + h_e32oe35->GetXaxis()->SetTitle("e32/e35"); + + h_weta = new TH1F(vecHistNames[5].data(), "", 120, 0, 2); + h_weta->GetXaxis()->SetTitle("w_{#eta}"); + + h_wphi = new TH1F(vecHistNames[6].data(), "", 120, 0, 2); + h_wphi->GetXaxis()->SetTitle("w_{#phi}"); + + h_weta_cogx = new TH1F(vecHistNames[7].data(), "", 50, 0, 2); + h_weta_cogx->GetXaxis()->SetTitle("w_{#eta}^{cogx}"); + + h_wphi_cogx = new TH1F(vecHistNames[8].data(), "", 50, 0, 2); + h_wphi_cogx->GetXaxis()->SetTitle("w_{#phi}^{cogx}"); + + h_detamax = new TH1F(vecHistNames[9].data(), "", 10, -0.5, 9.5); + h_detamax->GetXaxis()->SetTitle("detamax"); + + h_dphimax = new TH1F(vecHistNames[10].data(), "", 20, -0.5, 19.5); + h_dphimax->GetXaxis()->SetTitle("dphimax"); + + h_mean_time = new TH1F(vecHistNames[11].data(), "", 200, -20, 20); + h_mean_time->GetXaxis()->SetTitle("cluster mean time"); + + h_iso04_emcal = new TH1F(vecHistNames[12].data(), "", 200, -10, 40); + h_iso04_emcal->GetXaxis()->SetTitle("iso_{0.4}^{EMCal} [GeV]"); + + h_weta_vs_et = new TH2F(vecHistNames[13].data(), "", 120, 0, 30, 120, 0, 6); + h_weta_vs_et->GetXaxis()->SetTitle("E_{T} [GeV]"); + h_weta_vs_et->GetYaxis()->SetTitle("w_{#eta}"); + + h_wphi_vs_et = new TH2F(vecHistNames[14].data(), "", 120, 0, 30, 120, 0, 6); + h_wphi_vs_et->GetXaxis()->SetTitle("E_{T} [GeV]"); + h_wphi_vs_et->GetYaxis()->SetTitle("w_{#phi}"); + + return Fun4AllReturnCodes::EVENT_OK; +} + +int EMCalShowerShapes::InitRun(PHCompositeNode* topNode) +{ + LoadEMCalNodes(topNode); + return Fun4AllReturnCodes::EVENT_OK; +} + +bool EMCalShowerShapes::LoadEMCalNodes(PHCompositeNode *topNode) +{ + if (!m_emc_tower_container) + { + m_emc_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC"); + } + if (!m_geomEM) + { + m_geomEM = findNode::getClass(topNode, "TOWERGEOM_CEMC"); + } + + const bool have_nodes = (m_emc_tower_container && m_geomEM); + if (!have_nodes && !m_reportedMissingCaloNodes) + { + std::cout << PHWHERE << "EMCalShowerShapes::LoadEMCalNodes - missing TOWERINFO_CALIB_CEMC or TOWERGEOM_CEMC" << std::endl; + m_reportedMissingCaloNodes = true; + } + return have_nodes; +} + +float EMCalShowerShapes::GetVertexZ(PHCompositeNode *topNode) const +{ + MbdVertexMap* vertexmap = findNode::getClass(topNode, "MbdVertexMap"); + if (!vertexmap || vertexmap->empty()) + { + return 0.0F; + } + + MbdVertex* vtx = vertexmap->begin()->second; + if (!vtx) + { + return 0.0F; + } + + return vtx->get_z(); +} + +int EMCalShowerShapes::process_event(PHCompositeNode *topNode) +{ + RawClusterContainer* clusterContainer = findNode::getClass(topNode, m_inputnode); + if (!clusterContainer) + { + if (!m_reportedMissingClusterNode) + { + std::cout << PHWHERE << "EMCalShowerShapes::process_event - missing node " << m_inputnode << std::endl; + m_reportedMissingClusterNode = true; + } + return Fun4AllReturnCodes::EVENT_OK; + } + + if (!LoadEMCalNodes(topNode)) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + if (m_doTrgSelect) + { + m_analyzer->decodeTriggers(topNode); + if (!JetQADefs::DidTriggerFire(m_trgToSelect, m_analyzer)) + { + return Fun4AllReturnCodes::EVENT_OK; + } + } + + const float vertex_z = GetVertexZ(topNode); + if (m_doMbdZvtxCut && std::abs(vertex_z) > m_mbdZvtxMax) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + const CLHEP::Hep3Vector vertex_vec(0, 0, vertex_z); + + RawClusterContainer::ConstRange clusters = clusterContainer->getClusters(); + for (auto iter = clusters.first; iter != clusters.second; ++iter) + { + RawCluster* cluster = iter->second; + if (!cluster) + { + continue; + } + + const float eta = RawClusterUtility::GetPseudorapidity(*cluster, vertex_vec); + if (m_doClusterEtaCut && std::abs(eta) > m_clusterEtaMax) + { + continue; + } + + const float phi = RawClusterUtility::GetAzimuthAngle(*cluster, vertex_vec); + const float et = cluster->get_energy() / std::cosh(eta); + + ShowerShapeData data; + if (!CalculateShowerShapes(cluster, eta, phi, et, vertex_z, data)) + { + continue; + } + + h_cluster_et->Fill(et); + h_e11oe33->Fill(data.e11 / data.e33); + h_e33oe55->Fill(data.e33 / data.e55); + h_e55oe77->Fill(data.e55 / data.e77); + h_e32oe35->Fill(data.e32 / data.e35); + h_weta->Fill(data.weta); + h_wphi->Fill(data.wphi); + h_weta_cogx->Fill(data.weta_cogx); + h_wphi_cogx->Fill(data.wphi_cogx); + h_detamax->Fill(data.detamax); + h_dphimax->Fill(data.dphimax); + h_mean_time->Fill(data.mean_time); + h_iso04_emcal->Fill(data.iso04_emcal); + h_weta_vs_et->Fill(et, data.weta); + h_wphi_vs_et->Fill(et, data.wphi); + + /* + if (std::isfinite(et)) + { + h_cluster_et->Fill(et); + } + if (data.e33 > 0) + { + h_e11oe33->Fill(data.e11 / data.e33); + } + if (data.e55 > 0) + { + h_e33oe55->Fill(data.e33 / data.e55); + } + if (data.e77 > 0) + { + h_e55oe77->Fill(data.e55 / data.e77); + } + if (std::isfinite(data.weta)) + { + h_weta->Fill(data.weta); + } + if (std::isfinite(data.wphi)) + { + h_wphi->Fill(data.wphi); + } + if (std::isfinite(data.weta_cogx)) + { + h_weta_cogx->Fill(data.weta_cogx); + } + if (std::isfinite(data.wphi_cogx)) + { + h_wphi_cogx->Fill(data.wphi_cogx); + } + if (std::isfinite(data.detamax)) + { + h_detamax->Fill(data.detamax); + } + if (std::isfinite(data.dphimax)) + { + h_dphimax->Fill(data.dphimax); + } + if (std::isfinite(data.mean_time)) + { + h_mean_time->Fill(data.mean_time); + } + if (std::isfinite(data.iso04_emcal)) + { + h_iso04_emcal->Fill(data.iso04_emcal); + } + if (std::isfinite(data.e32_to_e35)) + { + h_e32_to_e35->Fill(data.e32_to_e35); + } + if (std::isfinite(et) && std::isfinite(data.weta)) + { + h_weta_vs_et->Fill(et, data.weta); + } + if (std::isfinite(et) && std::isfinite(data.wphi)) + { + h_wphi_vs_et->Fill(et, data.wphi); + } + */ + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +bool EMCalShowerShapes::CalculateShowerShapes(RawCluster* cluster, float cluster_eta, float cluster_phi, float cluster_et, float vertex_z, ShowerShapeData& data) const +{ + std::vector showershape = cluster->get_shower_shapes(m_shape_min_tower_E); + if (showershape.empty()) + { + return false; + } + + const std::pair leadtowerindex = cluster->get_lead_tower(); + const int lead_ieta = leadtowerindex.first; + const int lead_iphi = leadtowerindex.second; + + const float avg_eta = showershape[4] + 0.5F; + const float avg_phi = showershape[5] + 0.5F; + const int maxieta = std::floor(avg_eta); + const int maxiphi = std::floor(avg_phi); + + int detamax = 0; + int dphimax = 0; + float clusteravgtime = 0.0F; + float cluster_total_e = 0.0F; + const RawCluster::TowerMap& tower_map = cluster->get_towermap(); + std::set towers_in_cluster; + for (auto tower_iter : tower_map) + { + RawTowerDefs::keytype tower_key = tower_iter.first; + const int ieta = RawTowerDefs::decode_index1(tower_key); + const int iphi = RawTowerDefs::decode_index2(tower_key); + + const unsigned int towerinfokey = TowerInfoDefs::encode_emcal(ieta, iphi); + towers_in_cluster.insert(towerinfokey); + TowerInfo* towerinfo = m_emc_tower_container->get_tower_at_key(towerinfokey); + if (towerinfo) + { + clusteravgtime += towerinfo->get_time() * towerinfo->get_energy(); + cluster_total_e += towerinfo->get_energy(); + } + + constexpr int totalphibins = 256; + auto dphiwrap = [totalphibins](int towerphi, int maxiphi_arg) + { + int idphi = towerphi - maxiphi_arg; + if (idphi > totalphibins / 2) + { + idphi -= totalphibins; + } + if (idphi < -totalphibins / 2) + { + idphi += totalphibins; + } + return idphi; + }; + + const int deta = ieta - lead_ieta; + const int dphi_val = dphiwrap(iphi, lead_iphi); + detamax = std::max(std::abs(deta), detamax); + dphimax = std::max(std::abs(dphi_val), dphimax); + } + + if (cluster_total_e > 0) + { + clusteravgtime /= cluster_total_e; + } + else + { + std::cout << "cluster_total_e is 0(this should not happen!!!), setting clusteravgtime to NaN" << std::endl; + clusteravgtime = std::numeric_limits::quiet_NaN(); + } + + float E77[7][7] = {{0.0F}}; + int E77_ownership[7][7] = {{0}}; + + for (int ieta = maxieta - 3; ieta < maxieta + 4; ++ieta) + { + for (int iphi = maxiphi - 3; iphi < maxiphi + 4; ++iphi) + { + if (ieta < 0 || ieta > 95) + { + E77[ieta - maxieta + 3][iphi - maxiphi + 3] = 0.0F; + E77_ownership[ieta - maxieta + 3][iphi - maxiphi + 3] = 0; + continue; + } + + int temp_ieta = ieta; + int temp_iphi = iphi; + shift_tower_index(temp_ieta, temp_iphi, 96, 256); + if (temp_ieta < 0) + { + continue; + } + + const unsigned int towerinfokey = TowerInfoDefs::encode_emcal(temp_ieta, temp_iphi); + //if (towers_in_cluster.find(towerinfokey) != towers_in_cluster.end()) + if (towers_in_cluster.contains(towerinfokey)) + { + E77_ownership[ieta - maxieta + 3][iphi - maxiphi + 3] = 1; + } + + TowerInfo* towerinfo = m_emc_tower_container->get_tower_at_key(towerinfokey); + if (towerinfo && towerinfo->get_isGood()) + { + const float energy = towerinfo->get_energy(); + if (energy > m_shape_min_tower_E) + { + E77[ieta - maxieta + 3][iphi - maxiphi + 3] = energy; + } + } + } + } + + float e11 = E77[3][3]; + float e32 = 0.0F; + float e33 = 0.0F; + float e35 = 0.0F; + float e55 = 0.0F; + float e77 = 0.0F; + float weta = 0.0F; + float wphi = 0.0F; + float weta_cogx = 0.0F; + float wphi_cogx = 0.0F; + float Eetaphi = 0.0F; + + const float shift_eta = avg_eta - std::floor(avg_eta) - 0.5F; + const float shift_phi = avg_phi - std::floor(avg_phi) - 0.5F; + const float cog_eta = 3 + shift_eta; + const float cog_phi = 3 + shift_phi; + const int signphi = (avg_phi - std::floor(avg_phi)) > 0.5 ? 1 : -1; + + for (int i = 0; i < 7; ++i) + { + for (int j = 0; j < 7; ++j) + { + const int di = std::abs(i - 3); + const int dj = std::abs(j - 3); + const float di_float = i - cog_eta; + const float dj_float = j - cog_phi; + + if (E77_ownership[i][j] == 1) + { + weta += E77[i][j] * di * di; + wphi += E77[i][j] * dj * dj; + Eetaphi += E77[i][j]; + if (i != 3 || j != 3) + { + weta_cogx += E77[i][j] * di_float * di_float; + wphi_cogx += E77[i][j] * dj_float * dj_float; + } + } + + e77 += E77[i][j]; + if (di <= 1 && (dj == 0 || j == (3 + signphi))) + { + e32 += E77[i][j]; + } + if (di <= 1 && dj <= 1) + { + e33 += E77[i][j]; + } + if (di <= 1 && dj <= 2) + { + e35 += E77[i][j]; + } + if (di <= 2 && dj <= 2) + { + e55 += E77[i][j]; + } + } + } + + if (Eetaphi > 0) + { + weta /= Eetaphi; + wphi /= Eetaphi; + weta_cogx /= Eetaphi; + wphi_cogx /= Eetaphi; + } + /*else + { + weta = std::numeric_limits::quiet_NaN(); + wphi = std::numeric_limits::quiet_NaN(); + weta_cogx = std::numeric_limits::quiet_NaN(); + wphi_cogx = std::numeric_limits::quiet_NaN(); + }*/ + + data.e11 = e11; + data.e33 = e33; + data.e32 = e32; + data.e35 = e35; + data.e55 = e55; + data.e77 = e77; + data.weta = weta; + data.wphi = wphi; + data.weta_cogx = weta_cogx; + data.wphi_cogx = wphi_cogx; + data.detamax = detamax; + data.dphimax = dphimax; + data.mean_time = clusteravgtime; + data.iso04_emcal = CalculateLayerET(cluster_eta, cluster_phi, 0.4F, m_emc_tower_container, m_geomEM, vertex_z) - cluster_et; + //data.e32_to_e35 = (e35 > 0) ? (e32 / e35) : std::numeric_limits::quiet_NaN(); + + return true; +} + +double EMCalShowerShapes::GetTowerEta(RawTowerGeom* tower_geom, double vx, double vy, double vz) const +{ + if (!tower_geom) + { + return -9999; + } + if (vx == 0 && vy == 0 && vz == 0) + { + return tower_geom->get_eta(); + } + + const double radius = std::sqrt((tower_geom->get_center_x() - vx) * (tower_geom->get_center_x() - vx) + + (tower_geom->get_center_y() - vy) * (tower_geom->get_center_y() - vy)); + const double theta = std::atan2(radius, tower_geom->get_center_z() - vz); + return -std::log(std::tan(theta / 2.)); +} + +double EMCalShowerShapes::DeltaR(double eta1, double phi1, double eta2, double phi2) const +{ + double dphi = phi1 - phi2; + while (dphi > M_PI) + { + dphi -= 2 * M_PI; + } + while (dphi <= -M_PI) + { + dphi += 2 * M_PI; + } + return std::sqrt(std::pow(eta1 - eta2, 2) + std::pow(dphi, 2)); +} + +float EMCalShowerShapes::CalculateLayerET(float seed_eta, float seed_phi, float radius, TowerInfoContainer* towerContainer, RawTowerGeomContainer* geomContainer, float vertex_z) const +{ + if (!towerContainer || !geomContainer) + { + return std::numeric_limits::quiet_NaN(); + } + + float layer_et = 0.0F; + const unsigned int ntowers = towerContainer->size(); + for (unsigned int channel = 0; channel < ntowers; ++channel) + { + TowerInfo* tower = towerContainer->get_tower_at_channel(channel); + if (!tower || !tower->get_isGood()) + { + continue; + } + + const unsigned int towerkey = towerContainer->encode_key(channel); + const int ieta = towerContainer->getTowerEtaBin(towerkey); + const int iphi = towerContainer->getTowerPhiBin(towerkey); + + const RawTowerDefs::keytype geom_key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::CEMC, ieta, iphi); + RawTowerGeom* tower_geom = geomContainer->get_tower_geometry(geom_key); + if (!tower_geom) + { + continue; + } + + const double tower_eta = GetTowerEta(tower_geom, 0, 0, vertex_z); + const double tower_phi = tower_geom->get_phi(); + if (DeltaR(seed_eta, seed_phi, tower_eta, tower_phi) >= radius) + { + continue; + } + + const float energy = tower->get_energy(); + if (energy <= m_shape_min_tower_E) + { + continue; + } + + layer_et += energy / std::cosh(tower_eta); + } + + return layer_et; +} + +int EMCalShowerShapes::ResetEvent(PHCompositeNode* /*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +int EMCalShowerShapes::EndRun(const int /*runnumber*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +int EMCalShowerShapes::End(PHCompositeNode* /*topNode*/) +{ + m_manager->registerHisto(h_cluster_et); + m_manager->registerHisto(h_e11oe33); + m_manager->registerHisto(h_e33oe55); + m_manager->registerHisto(h_e55oe77); + m_manager->registerHisto(h_e32oe35); + m_manager->registerHisto(h_weta); + m_manager->registerHisto(h_wphi); + m_manager->registerHisto(h_weta_cogx); + m_manager->registerHisto(h_wphi_cogx); + m_manager->registerHisto(h_detamax); + m_manager->registerHisto(h_dphimax); + m_manager->registerHisto(h_mean_time); + m_manager->registerHisto(h_iso04_emcal); + m_manager->registerHisto(h_weta_vs_et); + m_manager->registerHisto(h_wphi_vs_et); + + return Fun4AllReturnCodes::EVENT_OK; +} + +int EMCalShowerShapes::Reset(PHCompositeNode* /*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +void EMCalShowerShapes::Print(const std::string &what) const +{ + std::cout << "EMCalShowerShapes::Print(" << what << ")" << std::endl; +} diff --git a/offline/QA/Jet/EMCalShowerShapes.h b/offline/QA/Jet/EMCalShowerShapes.h new file mode 100644 index 0000000000..2d076fd25f --- /dev/null +++ b/offline/QA/Jet/EMCalShowerShapes.h @@ -0,0 +1,130 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef EMCALSHOWERSHAPES_H +#define EMCALSHOWERSHAPES_H + +#include "JetQADefs.h" + +#include + +#include +#include + +class Fun4AllHistoManager; +class PHCompositeNode; +class RawCluster; +class RawTowerGeom; +class RawTowerGeomContainer; +class TH1; +class TH2; +class TowerInfoContainer; +class TriggerAnalyzer; + +class EMCalShowerShapes : public SubsysReco +{ + public: + EMCalShowerShapes(const std::string &modulename = "EMCalShowerShapes", const std::string &inputnode = "CLUSTERINFO_CEMC", const std::string &histtag = ""); + ~EMCalShowerShapes() override; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + int ResetEvent(PHCompositeNode *topNode) override; + int EndRun(const int runnumber) override; + int End(PHCompositeNode *topNode) override; + int Reset(PHCompositeNode *topNode) override; + void Print(const std::string &what = "ALL") const override; + + void SetTrgToSelect(const uint32_t trig = JetQADefs::GL1::MBDNSPhoton1) + { + m_doTrgSelect = true; + m_trgToSelect = trig; + } + + void SetHistTag(const std::string& tag) + { + m_histtag = tag; + } + + void SetApplyMbdZvtxCut(const bool apply) + { + m_doMbdZvtxCut = apply; + } + + void SetMbdZvtxMax(const float maxz) + { + m_mbdZvtxMax = maxz; + } + + void SetApplyClusterEtaCut(const bool apply) + { + m_doClusterEtaCut = apply; + } + + void SetClusterEtaMax(const float maxeta) + { + m_clusterEtaMax = maxeta; + } + + private: + struct ShowerShapeData + { + float e11 {std::numeric_limits::quiet_NaN()}; + float e33 {std::numeric_limits::quiet_NaN()}; + float e55 {std::numeric_limits::quiet_NaN()}; + float e77 {std::numeric_limits::quiet_NaN()}; + float e32 {std::numeric_limits::quiet_NaN()}; + float e35 {std::numeric_limits::quiet_NaN()}; + float weta {std::numeric_limits::quiet_NaN()}; + float wphi {std::numeric_limits::quiet_NaN()}; + float weta_cogx {std::numeric_limits::quiet_NaN()}; + float wphi_cogx {std::numeric_limits::quiet_NaN()}; + float detamax {std::numeric_limits::quiet_NaN()}; + float dphimax {std::numeric_limits::quiet_NaN()}; + float mean_time {std::numeric_limits::quiet_NaN()}; + float iso04_emcal {std::numeric_limits::quiet_NaN()}; + //float e32_to_e35 {std::numeric_limits::quiet_NaN()}; + }; + + bool LoadEMCalNodes(PHCompositeNode *topNode); + float GetVertexZ(PHCompositeNode *topNode) const; + bool CalculateShowerShapes(RawCluster* cluster, float cluster_eta, float cluster_phi, float cluster_et, float vertex_z, ShowerShapeData& data) const; + double GetTowerEta(RawTowerGeom* tower_geom, double vx, double vy, double vz) const; + double DeltaR(double eta1, double phi1, double eta2, double phi2) const; + float CalculateLayerET(float seed_eta, float seed_phi, float radius, TowerInfoContainer* towerContainer, RawTowerGeomContainer* geomContainer, float vertex_z) const; + + TriggerAnalyzer* m_analyzer {nullptr}; + Fun4AllHistoManager* m_manager {nullptr}; + TowerInfoContainer* m_emc_tower_container {nullptr}; + RawTowerGeomContainer* m_geomEM {nullptr}; + std::string m_modulename; + std::string m_inputnode; + std::string m_histtag; + uint32_t m_trgToSelect; + bool m_doTrgSelect; + bool m_reportedMissingClusterNode {false}; + bool m_reportedMissingCaloNodes {false}; + float m_shape_min_tower_E {0.070F}; + bool m_doMbdZvtxCut {true}; + float m_mbdZvtxMax {60.0F}; + bool m_doClusterEtaCut {true}; + float m_clusterEtaMax {0.7F}; + + TH1* h_cluster_et {nullptr}; + TH1* h_e11oe33 {nullptr}; + TH1* h_e33oe55 {nullptr}; + TH1* h_e55oe77 {nullptr}; + TH1* h_e32oe35 {nullptr}; + TH1* h_weta {nullptr}; + TH1* h_wphi {nullptr}; + TH1* h_weta_cogx {nullptr}; + TH1* h_wphi_cogx {nullptr}; + TH1* h_detamax {nullptr}; + TH1* h_dphimax {nullptr}; + TH1* h_mean_time {nullptr}; + TH1* h_iso04_emcal {nullptr}; + TH2* h_weta_vs_et {nullptr}; + TH2* h_wphi_vs_et {nullptr}; +}; + +#endif diff --git a/offline/QA/Jet/Makefile.am b/offline/QA/Jet/Makefile.am index 91b4292ad4..497c22458b 100644 --- a/offline/QA/Jet/Makefile.am +++ b/offline/QA/Jet/Makefile.am @@ -18,6 +18,7 @@ pkginclude_HEADERS = \ CaloStatusMapperDefs.h \ ConstituentsinJets.h \ DijetQA.h \ + EMCalShowerShapes.h \ EMClusterKinematics.h \ JetKinematicCheck.h \ JetQADefs.h \ @@ -43,6 +44,7 @@ libjetqa_la_SOURCES = \ CaloStatusMapper.cc \ ConstituentsinJets.cc \ DijetQA.cc \ + EMCalShowerShapes.cc \ EMClusterKinematics.cc \ JetKinematicCheck.cc \ JetSeedCount.cc \ From 7b00e98fa1692e903bea5f0da74fa684063e5fd2 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 13 Apr 2026 15:13:53 -0400 Subject: [PATCH 455/866] moved filling guarding bins to dedicated method. This is the correct way: - 2pi invariance is used for phi axis - identical content is used for r and z axis. --- .../TpcSpaceChargeReconstructionHelper.cc | 51 +++++++++++-------- .../TpcSpaceChargeReconstructionHelper.h | 11 ++-- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc index ffbefedc6b..a37cf33210 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc @@ -602,53 +602,64 @@ TH3* TpcSpaceChargeReconstructionHelper::add_guarding_bins(const TH3* source, co } } + // fill guarding phi bins + fill_guarding_bins( hout ); + + return hout; +} + +//_____________________________________________________________________________________________________________________- +void TpcSpaceChargeReconstructionHelper::fill_guarding_bins(TH3* source ) +{ + const auto nbinsx = source->GetNbinsX(); + const auto nbinsy = source->GetNbinsY(); + const auto nbinsz = source->GetNbinsZ(); + // fill guarding phi bins /* * we use 2pi periodicity to do that: * - last valid bin is copied to first guarding bin; * - first valid bin is copied to last guarding bin */ - for (int ir = 0; ir < rbins + 2; ++ir) + for (int ir = 0; ir < nbinsy; ++ir) { - for (int iz = 0; iz < zbins + 2; ++iz) + for (int iz = 0; iz < nbinsz; ++iz) { // copy last bin to first guarding bin - hout->SetBinContent(1, ir + 1, iz + 1, hout->GetBinContent(phibins + 1, ir + 1, iz + 1)); - hout->SetBinError(1, ir + 1, iz + 1, hout->GetBinError(phibins + 1, ir + 1, iz + 1)); + source ->SetBinContent(1, ir + 1, iz + 1, source ->GetBinContent(nbinsx-1, ir + 1, iz + 1)); + source ->SetBinError(1, ir + 1, iz + 1, source ->GetBinError(nbinsx-1, ir + 1, iz + 1)); // copy first bin to last guarding bin - hout->SetBinContent(phibins + 2, ir + 1, iz + 1, hout->GetBinContent(2, ir + 1, iz + 1)); - hout->SetBinError(phibins + 2, ir + 1, iz + 1, hout->GetBinError(2, ir + 1, iz + 1)); + source ->SetBinContent(nbinsx, ir + 1, iz + 1, source ->GetBinContent(2, ir + 1, iz + 1)); + source ->SetBinError(nbinsx, ir + 1, iz + 1, source ->GetBinError(2, ir + 1, iz + 1)); } } // fill guarding r bins - for (int iphi = 0; iphi < phibins + 2; ++iphi) + for (int iphi = 0; iphi < nbinsx; ++iphi) { - for (int iz = 0; iz < zbins + 2; ++iz) + for (int iz = 0; iz < nbinsz; ++iz) { - hout->SetBinContent(iphi + 1, 1, iz + 1, hout->GetBinContent(iphi + 1, 2, iz + 1)); - hout->SetBinError(iphi + 1, 1, iz + 1, hout->GetBinError(iphi + 1, 2, iz + 1)); + source ->SetBinContent(iphi + 1, 1, iz + 1, source ->GetBinContent(iphi + 1, 2, iz + 1)); + source ->SetBinError(iphi + 1, 1, iz + 1, source ->GetBinError(iphi + 1, 2, iz + 1)); - hout->SetBinContent(iphi + 1, rbins + 2, iz + 1, hout->GetBinContent(iphi + 1, rbins + 1, iz + 1)); - hout->SetBinError(iphi + 1, rbins + 2, iz + 1, hout->GetBinError(iphi + 1, rbins + 1, iz + 1)); + source ->SetBinContent(iphi + 1, nbinsy, iz + 1, source ->GetBinContent(iphi + 1, nbinsy-1, iz + 1)); + source ->SetBinError(iphi + 1, nbinsy, iz + 1, source ->GetBinError(iphi + 1, nbinsy-1, iz + 1)); } } // fill guarding z bins - for (int iphi = 0; iphi < phibins + 2; ++iphi) + for (int iphi = 0; iphi < nbinsx; ++iphi) { - for (int ir = 0; ir < rbins + 2; ++ir) + for (int ir = 0; ir < nbinsy; ++ir) { - hout->SetBinContent(iphi + 1, ir + 1, 1, hout->GetBinContent(iphi + 1, ir + 1, 2)); - hout->SetBinError(iphi + 1, ir + 1, 1, hout->GetBinError(iphi + 1, ir + 1, 2)); + source ->SetBinContent(iphi + 1, ir + 1, 1, source ->GetBinContent(iphi + 1, ir + 1, 2)); + source ->SetBinError(iphi + 1, ir + 1, 1, source ->GetBinError(iphi + 1, ir + 1, 2)); - hout->SetBinContent(iphi + 1, ir + 1, zbins + 2, hout->GetBinContent(iphi + 1, ir + 1, zbins + 1)); - hout->SetBinError(iphi + 1, ir + 1, zbins + 2, hout->GetBinError(iphi + 1, ir + 1, zbins + 1)); + source ->SetBinContent(iphi + 1, ir + 1, nbinsz, source ->GetBinContent(iphi + 1, ir + 1, nbinsz-1)); + source ->SetBinError(iphi + 1, ir + 1, nbinsz, source ->GetBinError(iphi + 1, ir + 1, nbinsz-1)); } } - - return hout; } //___________________________________________________________________________________________________ diff --git a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h index 12e9e4823c..065bf3ad15 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h +++ b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h @@ -71,12 +71,17 @@ class TpcSpaceChargeReconstructionHelper /** * copy input histogram into output, with new name, while adding two "guarding bins" on - * each axis, with identical content and error as the first and last bin of the original histogram - * this is necessary for being able to call TH3->Interpolate() when using these histograms - * to correct for the space charge distortions. + * each axis. Uses fill_guarding_bins to set guarding bin content */ static TH3* add_guarding_bins(const TH3* /*source*/, const TString& /*name*/); + /** + * fill first and last bins (along all axis) of provided histogram with + * either copy of the previous/next (physical) bin, (for r and z) + * or using 2pi invariance for the phi axis. + */ + static void fill_guarding_bins(TH3* /*source*/); + /// shortcut to angular window, needed to define TPOT acceptance using range_t = std::pair; From 9029c588ee68240e24e2d09b4ad132f4aa8b6c80 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 13 Apr 2026 15:40:20 -0400 Subject: [PATCH 456/866] Moved loading and saving distortion correction from root file to the DistortionCorrectionContainer, to avoid future code duplication. --- offline/packages/tpc/Makefile.am | 1 + .../tpc/TpcDistortionCorrectionContainer.h | 7 ++++++ .../tpc/TpcLoadDistortionCorrection.cc | 22 +++---------------- .../tpccalib/TpcSpaceChargeMatrixInversion.cc | 18 +-------------- 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/offline/packages/tpc/Makefile.am b/offline/packages/tpc/Makefile.am index a2bd71c1cf..637fa61489 100644 --- a/offline/packages/tpc/Makefile.am +++ b/offline/packages/tpc/Makefile.am @@ -86,6 +86,7 @@ libtpc_la_SOURCES = \ TpcClusterizer.cc \ TpcCombinedRawDataUnpacker.cc \ TpcCombinedRawDataUnpackerDebug.cc \ + TpcDistortionCorrectionContainer.cc \ TpcGlobalPositionWrapper.cc \ TpcLoadDistortionCorrection.cc \ TpcMap.cc \ diff --git a/offline/packages/tpc/TpcDistortionCorrectionContainer.h b/offline/packages/tpc/TpcDistortionCorrectionContainer.h index 2d65ca79dd..5d8dfa7988 100644 --- a/offline/packages/tpc/TpcDistortionCorrectionContainer.h +++ b/offline/packages/tpc/TpcDistortionCorrectionContainer.h @@ -8,6 +8,7 @@ */ #include +#include class TH1; @@ -17,6 +18,12 @@ class TpcDistortionCorrectionContainer //! constructor TpcDistortionCorrectionContainer() = default; + //! load histograms from input file + void load_histograms( const std::string& /*source*/ ); + + //! save histograms to out file + void save_histograms( const std::string& /*destination*/ ) const; + //! flag to tell us whether to read z data or just 2d data int m_dimensions = 3; diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.cc b/offline/packages/tpc/TpcLoadDistortionCorrection.cc index 65bf156a7a..09ca916e42 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.cc +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.cc @@ -56,7 +56,7 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) { std::cout << "("<< i <<", "<(iter.findFirst("PHCompositeNode", "RUN")); if (!runNode) @@ -83,24 +83,8 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) 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()); - if (!distortion_tfile) - { - std::cout << "TpcLoadDistortionCorrection::InitRun - cannot open " << m_correction_filename[i] << std::endl; - exit(1); - } - - const std::array extension = {{"_negz", "_posz"}}; - for (int j = 0; j < 2; ++j) - { - distortion_correction_object->m_hDPint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionP")+extension[j]).c_str())); - assert(distortion_correction_object->m_hDPint[j]); - distortion_correction_object->m_hDRint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionR")+extension[j]).c_str())); - assert(distortion_correction_object->m_hDRint[j]); - distortion_correction_object->m_hDZint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionZ")+extension[j]).c_str())); - assert(distortion_correction_object->m_hDZint[j]); - } + // load histograms from file + distortion_correction_object->load_histograms(m_correction_filename[i]); // assign correction object dimension from histograms dimention, assuming all histograms have the same distortion_correction_object->m_dimensions = distortion_correction_object->m_hDPint[0]->GetDimension(); diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc index 07f08c733c..9c787730aa 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc @@ -457,22 +457,6 @@ void TpcSpaceChargeMatrixInversion::save_distortion_corrections(const std::strin return; } - // save everything to root file - std::cout << "TpcSpaceChargeMatrixInversion::save_distortions - writing histograms to " << filename << std::endl; - std::unique_ptr outputfile(TFile::Open(filename.c_str(), "RECREATE")); - outputfile->cd(); + m_dcc_average->save_histograms(filename); - for (const auto& h_list : {m_dcc_average->m_hentries, m_dcc_average->m_hDRint, m_dcc_average->m_hDPint, m_dcc_average->m_hDZint}) - { - for (const auto& h : h_list) - { - if (h) - { - h->Write(h->GetName()); - } - } - } - - // close TFile - outputfile->Close(); } From da0b57625ac101fc8b541d00fe4a249234c737d8 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 13 Apr 2026 14:48:37 -0600 Subject: [PATCH 457/866] Update offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc index a37cf33210..d6e605ceb4 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc @@ -611,6 +611,12 @@ TH3* TpcSpaceChargeReconstructionHelper::add_guarding_bins(const TH3* source, co //_____________________________________________________________________________________________________________________- void TpcSpaceChargeReconstructionHelper::fill_guarding_bins(TH3* source ) { + if (!source) + { + std::cout << "TpcSpaceChargeReconstructionHelper::fill_guarding_bins - invalid source histogram" << std::endl; + return; + } + const auto nbinsx = source->GetNbinsX(); const auto nbinsy = source->GetNbinsY(); const auto nbinsz = source->GetNbinsZ(); From f879f900878a9eb927d176185e58d64e76e25e99 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 14 Apr 2026 15:44:39 -0400 Subject: [PATCH 458/866] added missing file --- .../tpc/TpcDistortionCorrectionContainer.cc | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 offline/packages/tpc/TpcDistortionCorrectionContainer.cc diff --git a/offline/packages/tpc/TpcDistortionCorrectionContainer.cc b/offline/packages/tpc/TpcDistortionCorrectionContainer.cc new file mode 100644 index 0000000000..0202dd8ade --- /dev/null +++ b/offline/packages/tpc/TpcDistortionCorrectionContainer.cc @@ -0,0 +1,61 @@ + +/*! + * \file TpcDistortionCorrectionContainer.cc + * \brief stores distortion correction histograms on the node tree + * \author Hugo Pereira Da Costa + */ + +#include "TpcDistortionCorrectionContainer.h" + +#include +#include +#include + +#include +#include + +//_______________________________________________________________ +void TpcDistortionCorrectionContainer::load_histograms( const std::string& source ) +{ + std::cout << "TpcDistortionCorrectionContainer::load_histograms - reading corrections from " << source << std::endl; + auto *distortion_tfile = TFile::Open(source.c_str()); + if (!distortion_tfile) + { + std::cout << "TpcDistortionCorrectionContainer::load_histograms - cannot open " << source << std::endl; + exit(1); + } + + const std::array extension = {{"_negz", "_posz"}}; + for (int j = 0; j < 2; ++j) + { + m_hDPint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionP")+extension[j]).c_str())); + assert(m_hDPint[j]); + m_hDRint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionR")+extension[j]).c_str())); + assert(m_hDRint[j]); + m_hDZint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionZ")+extension[j]).c_str())); + assert(m_hDZint[j]); + } +} + +//_______________________________________________________________ +void TpcDistortionCorrectionContainer::save_histograms( const std::string& destination ) const +{ + // save everything to root file + std::cout << "TpcDistortionCorrectionContainer::save_histograms - writing histograms to " << destination << std::endl; + std::unique_ptr outputfile(TFile::Open(destination.c_str(), "RECREATE")); + outputfile->cd(); + + for (const auto& h_list : {m_hentries, m_hDRint, m_hDPint, m_hDZint}) + { + for (const auto& h : h_list) + { + if (h) + { + h->Write(h->GetName()); + } + } + } + + // close TFile + outputfile->Close(); +} From 39415dc553fb06c86c7a13b59404943775a5c388 Mon Sep 17 00:00:00 2001 From: Daniel J Lis Date: Tue, 14 Apr 2026 16:22:12 -0400 Subject: [PATCH 459/866] djl -- custom nodes --- offline/packages/centrality/CentralityReco.cc | 35 +++++++--------- offline/packages/centrality/CentralityReco.h | 32 +++++++++++++++ .../packages/trigger/MinimumBiasClassifier.cc | 41 ++++++++++++------- .../packages/trigger/MinimumBiasClassifier.h | 27 +++++++++++- 4 files changed, 99 insertions(+), 36 deletions(-) diff --git a/offline/packages/centrality/CentralityReco.cc b/offline/packages/centrality/CentralityReco.cc index 0a45ecb2c1..bc478366a5 100644 --- a/offline/packages/centrality/CentralityReco.cc +++ b/offline/packages/centrality/CentralityReco.cc @@ -13,6 +13,9 @@ #include #include +#include + +#include #include @@ -62,18 +65,17 @@ int CentralityReco::InitRun(PHCompositeNode *topNode) { return Fun4AllReturnCodes::ABORTRUN; } - std::string vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); if (m_overwrite_vtx) { vertexscale_url = m_overwrite_url_vtx; std::cout << " Overwriting Vtx to " << m_overwrite_url_vtx << std::endl; } - + if (Download_centralityVertexScales(vertexscale_url)) - { - return Fun4AllReturnCodes::ABORTRUN; - } + { + return Fun4AllReturnCodes::ABORTRUN; + } CreateNodes(topNode); return Fun4AllReturnCodes::EVENT_OK; @@ -149,7 +151,7 @@ int CentralityReco::Download_centralityVertexScales(const std::string &dbfile) { cdbttree->Print(); } - + int nvertexbins = cdbttree->GetIntValue(0, "nvertexbins"); @@ -291,7 +293,7 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) std::cout << __FILE__ << " :: " << __FUNCTION__ << " :: " << __LINE__ << std::endl; } - m_mb_info = findNode::getClass(topNode, "MinimumBiasInfo"); + m_mb_info = findNode::getClass(topNode, m_mb_info_nodename); if (!m_mb_info) { @@ -299,15 +301,7 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_global_vertex_map = findNode::getClass(topNode, "GlobalVertexMap"); - - if (!m_global_vertex_map) - { - std::cout << "no vertex map node " << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - - m_central = findNode::getClass(topNode, "CentralityInfo"); + m_central = findNode::getClass(topNode, m_centrality_nodename); if (!m_central) { @@ -315,7 +309,7 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_mbd_container = findNode::getClass(topNode, "MbdPmtContainer"); + m_mbd_container = findNode::getClass(topNode, m_mbd_pmt_nodename); if (!m_mbd_container) { @@ -324,7 +318,7 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) } - m_mbd_out = findNode::getClass(topNode, "MbdOut"); + m_mbd_out = findNode::getClass(topNode, m_mbd_out_nodename); if (Verbosity()) { std::cout << "Getting MBD Out" << std::endl; @@ -365,7 +359,7 @@ void CentralityReco::CreateNodes(PHCompositeNode *topNode) CentralityInfo *central = new CentralityInfov2(); - PHIODataNode *centralityNode = new PHIODataNode(central, "CentralityInfo", "PHObject"); + PHIODataNode *centralityNode = new PHIODataNode(central, m_centrality_nodename, "PHObject"); detNode->addNode(centralityNode); return; @@ -376,7 +370,6 @@ float CentralityReco::getVertexScale() float mbd_vertex = m_mbd_out->get_zvtx(); - for (auto v_range_scale : m_vertex_scales) { auto v_range = v_range_scale.first; @@ -384,7 +377,7 @@ float CentralityReco::getVertexScale() { std::cout << "vertexrange : "< v_range.first && mbd_vertex <= v_range.second) { return v_range_scale.second; diff --git a/offline/packages/centrality/CentralityReco.h b/offline/packages/centrality/CentralityReco.h index bc0483d57d..37f97082ef 100644 --- a/offline/packages/centrality/CentralityReco.h +++ b/offline/packages/centrality/CentralityReco.h @@ -8,6 +8,7 @@ #include // for string, allocator // Forward declarations +class TF1; class CentralityInfo; class MinimumBiasInfo; class PHCompositeNode; @@ -51,11 +52,31 @@ class CentralityReco : public SubsysReco m_overwrite_url_scale = url; m_overwrite_scale = true; } + void setOverwriteVtx(const std::string &url) { m_overwrite_url_vtx = url; m_overwrite_vtx = true; } + + void set_minbiasNodeName(const std::string &name) + { + m_mb_info_nodename = name; + } + void set_mbdOutNodeName(const std::string &name) + { + m_mbd_out_nodename = name; + } + void set_centralityNodeName(const std::string &name) + { + m_centrality_nodename = name; + } + void set_mbdPmtNodeName(const std::string &name) + { + m_mbd_pmt_nodename = name; + } + + private: @@ -63,9 +84,20 @@ class CentralityReco : public SubsysReco std::string m_dbfilename; + std::string m_mb_info_nodename{"MinimumBiasInfo"}; + + std::string m_mbd_out_nodename{"MbdOut"}; + + std::string m_centrality_nodename{"CentralityInfo"}; + + std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; + + + bool m_use_vtx_function{true}; bool m_overwrite_divs{false}; bool m_overwrite_scale{false}; bool m_overwrite_vtx{false}; + std::string m_overwrite_url_divs{""}; std::string m_overwrite_url_scale{""}; std::string m_overwrite_url_vtx{""}; diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index c36a9430e1..f702fe9754 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -125,28 +125,31 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() // return Fun4AllReturnCodes::EVENT_OK; // } + if (m_global_vertex_map->empty()) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) return 1; + return 0; } GlobalVertex *vtx = m_global_vertex_map->begin()->second; if (!vtx) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) return 1; + return 0; } if (!vtx->isValid()) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) return 1; + return 0; } bool minbiascheck = true; - ; - + m_vertex = vtx->get_z(); m_vertex_scale = getVertexScale(); @@ -160,7 +163,8 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() if (!m_zdcinfo) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) return 1; + return 0; } } // Z vertex is within range @@ -226,9 +230,13 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() } m_mb_info->setIsAuAuMinimumBias(minbiascheck); - - return Fun4AllReturnCodes::EVENT_OK; + if (!minbiascheck && m_abortEvents) + { + return 1; + } + return 0; } + int MinimumBiasClassifier::process_event(PHCompositeNode *topNode) { if (Verbosity()) @@ -244,7 +252,11 @@ int MinimumBiasClassifier::process_event(PHCompositeNode *topNode) if (FillMinimumBiasInfo()) { - return Fun4AllReturnCodes::EVENT_OK; + if (Verbosity()) + { + std::cout << "MinimumBiasClassifier::process_event Aborting Event - not minbias" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; } return Fun4AllReturnCodes::EVENT_OK; @@ -257,7 +269,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) std::cout << __FILE__ << " :: " << __FUNCTION__ << " :: " << __LINE__ << std::endl; } - m_mb_info = findNode::getClass(topNode, "MinimumBiasInfo"); + m_mb_info = findNode::getClass(topNode, m_mb_info_nodename); if (!m_mb_info) { @@ -265,7 +277,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_mbd_container = findNode::getClass(topNode, "MbdPmtContainer"); + m_mbd_container = findNode::getClass(topNode, m_mbd_pmt_nodename); if (Verbosity()) { std::cout << "Getting MBD Tubes" << std::endl; @@ -279,7 +291,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) if (!m_issim && m_useZDC) { - m_zdcinfo = findNode::getClass(topNode, "Zdcinfo"); + m_zdcinfo = findNode::getClass(topNode, m_zdc_info_nodename); if (Verbosity()) { std::cout << "Getting ZDC Info" << std::endl; @@ -296,7 +308,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) std::cout << "Getting Vertex Map" << std::endl; } - m_global_vertex_map = findNode::getClass(topNode, "GlobalVertexMap"); + m_global_vertex_map = findNode::getClass(topNode, m_global_vertex_nodename); if (!m_global_vertex_map) { @@ -325,9 +337,10 @@ void MinimumBiasClassifier::CreateNodes(PHCompositeNode *topNode) dstNode->addNode(detNode); } + std::string nodename = m_mb_info_nodename; MinimumBiasInfo *mb = new MinimumBiasInfov1(); - PHIODataNode *mbNode = new PHIODataNode(mb, "MinimumBiasInfo", "PHObject"); + PHIODataNode *mbNode = new PHIODataNode(mb, nodename, "PHObject"); detNode->addNode(mbNode); return; diff --git a/offline/packages/trigger/MinimumBiasClassifier.h b/offline/packages/trigger/MinimumBiasClassifier.h index 5f32c10a62..ea235fbc1e 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.h +++ b/offline/packages/trigger/MinimumBiasClassifier.h @@ -31,7 +31,7 @@ class MinimumBiasClassifier : public SubsysReco ~MinimumBiasClassifier() override = default; int InitRun(PHCompositeNode *) override; - static void CreateNodes(PHCompositeNode *); + void CreateNodes(PHCompositeNode *); int GetNodes(PHCompositeNode *); //! event processing method @@ -60,8 +60,28 @@ class MinimumBiasClassifier : public SubsysReco void setIsSim(const bool sim) { m_issim = sim; } void setSpecies(MinimumBiasInfo::SPECIES spec) { m_species = spec; }; + + void abortEvents(const bool abort) { m_abortEvents = abort; }; + + void set_minbiasNodeName(const std::string &name) + { + m_mb_info_nodename = name; + } + void set_mbdPmtNodeName(const std::string &name) + { + m_mbd_pmt_nodename = name; + } + void set_zdcInfoNodeName(const std::string &name) + { + m_zdc_info_nodename = name; + } + void set_globalvertexNodeName(const std::string &name) + { + m_global_vertex_nodename = name; + } private: + bool m_abortEvents{false}; bool m_issim{false}; bool m_useZDC{true}; bool m_box_cut{true}; @@ -73,6 +93,11 @@ class MinimumBiasClassifier : public SubsysReco float getVertexScale(); std::string m_dbfilename; + std::string m_mb_info_nodename{"MinimumBiasInfo"}; + std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; + std::string m_zdc_info_nodename{"Zdcinfo"}; + std::string m_global_vertex_nodename{"GlobalVertexMap"}; + bool m_overwrite_scale{false}; bool m_overwrite_vtx{false}; std::string m_overwrite_url_scale{""}; From 5a29f035df4f3cc6c65db7e16ee999f06ec9ba33 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Wed, 15 Apr 2026 11:32:06 -0400 Subject: [PATCH 460/866] CD: PHSimpleVtx update to require INTT clusters --- .../KFParticle_sPHENIX/KFParticle_nTuple.cc | 6 +- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 116 ++++++------- .../trackreco/PHSimpleVertexFinder.cc | 155 +++++++++--------- .../packages/trackreco/PHSimpleVertexFinder.h | 5 + 4 files changed, 141 insertions(+), 141 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index b3b119e4f6..bc9f0b4c3a 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -303,9 +303,9 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch("runNumber", &m_runNumber, "runNumber/I"); m_tree->Branch("eventNumber", &m_evtNumber, "eventNumber/I"); - m_tree->Branch("event_bco", &m_event_bco, "event_bco/L"); //adding for the current event BCO, not shifted - m_tree->Branch("BCO", &m_bco, "BCO/L"); //already there, this is shifted BCO - m_tree->Branch("last_event_bco", &m_last_event_bco, "last_event_bco/L"); //BCO for the last event + m_tree->Branch("Collision_BCO", &m_bco, "Collision_BCO/L"); //already there, this is shifted BCO + m_tree->Branch("GL1_BCO", &m_event_bco, "GL1_BCO/L"); //adding for the current event BCO, not shifted + m_tree->Branch("last_GL1_BCO", &m_last_event_bco, "last_GL1_BCO/L"); //BCO for the last event if (m_get_trigger_info) { diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index db46bffafe..100c649145 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -155,64 +155,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; } - - // Adding BCO Matching - auto* evtHeader = findNode::getClass(topNode, "EventHeader"); // event header node - auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); // gl1 packet node - - if (!gl1packet) - { - gl1packet = findNode::getClass(topNode, "GL1Packet"); - } - - if (evtHeader && gl1packet) - { - const int64_t run = evtHeader->get_RunNumber(); - const int64_t evn = evtHeader->get_EvtSequence(); - m_this_event_bco = static_cast(gl1packet->lValue(0, "BCO")); - - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "Event start | run: " << run << " event: " << evn << " this_event_bco: " << m_this_event_bco << std::endl; - } - - if (run != m_prev_runNumber || evn != m_prev_eventNumber) - { - - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "New event detected" << std::endl; - std::cout << "Previous event BCO: " << m_prev_event_bco << std::endl; - } - //m_last_event_bco = m_prev_event_bco; - m_last_event_bco = (run == m_prev_runNumber) ? m_prev_event_bco : -1; - m_prev_event_bco = m_this_event_bco; - m_prev_runNumber = run; - m_prev_eventNumber = evn; - - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "Updated values | last_event_bco: " << m_last_event_bco - << " stored_prev_event_bco: " << m_prev_event_bco - << std::endl; - } - } - } - else - { - - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "EventHeader or GL1 packet not found" << std::endl; - } - m_this_event_bco = -1; - m_last_event_bco = -1; - m_prev_event_bco = -1; - m_prev_runNumber = -1; - m_prev_eventNumber = -1; - } -// End BCO matching here if (!m_use_fake_pv) { if (m_use_mbd_vertex) @@ -241,6 +184,65 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) } } + + // Adding BCO Matching + auto* evtHeader = findNode::getClass(topNode, "EventHeader"); // event header node + auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); // gl1 packet node + + if (!gl1packet) + { + gl1packet = findNode::getClass(topNode, "GL1Packet"); + } + + if (evtHeader && gl1packet) + { + const int64_t run = evtHeader->get_RunNumber(); + const int64_t evn = evtHeader->get_EvtSequence(); + m_this_event_bco = static_cast(gl1packet->lValue(0, "BCO")); + + if (Verbosity() >= VERBOSITY_A_LOT) + { + std::cout << "Event start | run: " << run << " event: " << evn << " this_event_bco: " << m_this_event_bco << std::endl; + } + + if (run != m_prev_runNumber || evn != m_prev_eventNumber) + { + + if (Verbosity() >= VERBOSITY_A_LOT) + { + std::cout << "New event detected" << std::endl; + std::cout << "Previous event BCO: " << m_prev_event_bco << std::endl; + } + + m_last_event_bco = (run == m_prev_runNumber) ? m_prev_event_bco : -1; + m_prev_event_bco = m_this_event_bco; + + m_prev_runNumber = run; + m_prev_eventNumber = evn; + + if (Verbosity() >= VERBOSITY_A_LOT) + { + std::cout << "Updated values | last_event_bco: " << m_last_event_bco + << " stored_prev_event_bco: " << m_prev_event_bco + << std::endl; + } + } + } + else + { + + if (Verbosity() >= VERBOSITY_MORE) + { + std::cout << "KFParticle: EventHeader or GL1 packet not found" << std::endl; + } + m_this_event_bco = -1; + m_last_event_bco = -1; + m_prev_event_bco = -1; + m_prev_runNumber = -1; + m_prev_eventNumber = -1; + } + // End BCO matching here + createDecay(topNode, mother, vertex_kfparticle, daughters, intermediates, nPVs); if (!m_has_intermediates_sPHENIX) { diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index 5f9340d8f6..99b83dc013 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -517,32 +517,19 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) } if (_require_mvtx) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (!siliconseed) + bool passed = passClusterRequirement(tr1); + if (!passed) { continue; } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) + } + if (_require_intt) + { + bool passed = passClusterRequirement(tr1, "INTT"); + if (!passed) { continue; } - if (Verbosity() > 3) - { - std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; - } } // look for close DCA matches with all other such tracks @@ -556,32 +543,19 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) } if (_require_mvtx) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr2->get_silicon_seed(); - if (!siliconseed) + bool passed = passClusterRequirement(tr2); + if (!passed) { continue; } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) + } + if (_require_intt) + { + bool passed = passClusterRequirement(tr2, "INTT"); + if (!passed) { continue; } - if (Verbosity() > 3) - { - std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; - } } // find DCA of these two tracks @@ -799,32 +773,19 @@ void PHSimpleVertexFinder::checkDCAs() } if (_require_mvtx) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (!siliconseed) + bool passed = passClusterRequirement(tr1); + if (!passed) { continue; } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) + } + if (_require_intt) + { + bool passed = passClusterRequirement(tr1, "INTT"); + if (!passed) { continue; } - if (Verbosity() > 3) - { - std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; - } } // look for close DCA matches with all other such tracks @@ -838,34 +799,20 @@ void PHSimpleVertexFinder::checkDCAs() } if (_require_mvtx) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr2->get_silicon_seed(); - if (!siliconseed) + bool passed = passClusterRequirement(tr2); + if (!passed) { continue; } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) + } + if (_require_intt) + { + bool passed = passClusterRequirement(tr2, "INTT"); + if (!passed) { continue; } - if (Verbosity() > 3) - { - std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; - } } - // find DCA of these two tracks if (Verbosity() > 3) { @@ -1324,3 +1271,49 @@ double PHSimpleVertexFinder::getAverage(std::vector &v) return avge; } + +bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, std::string type) +{ + bool pass = false; + + std::vector acceptable_types = {"MVTX", "INTT"}; + bool accept_this_type = std::find(acceptable_types.begin(), acceptable_types.end(), type) != acceptable_types.end(); + + if (!accept_this_type) + { + if (Verbosity() > 3) + { + std::cout << "type " << type << " was not recognised" << std::endl; + } + return pass; + } + + unsigned int nclus = 0; + unsigned int _nclus_required = type == "MVTX" ? _nmvtx_required : _nintt_required; + + TrackSeed *siliconseed = track->get_silicon_seed(); + if (!siliconseed) + { + return pass; + } + + for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) + { + uint8_t trkrId = type == "MVTX" ? TrkrDefs::mvtxId : TrkrDefs::inttId; + if (TrkrDefs::getTrkrId(*clusit) == trkrId) + { + nclus++; + } + if (nclus >= _nclus_required) + { + pass = true; + } + } + + if (Verbosity() > 3) + { + std::cout << " track id " << track->get_id() << " has " << nclus << " clusters for " << type << std::endl; + } + + return pass; +} diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index de5cff940b..41bd2bf4c5 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -48,6 +48,8 @@ class PHSimpleVertexFinder : public SubsysReco void setTrackQualityCut(double cut) { _qual_cut = cut; } void setRequireMVTX(bool set) { _require_mvtx = set; } void setNmvtxRequired(unsigned int n) { _nmvtx_required = n; } + void setRequireINTT(bool set) { _require_intt = set; } + void setNinttRequired(unsigned int n) { _nintt_required = n; } 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; } @@ -75,6 +77,7 @@ class PHSimpleVertexFinder : public SubsysReco void removeOutlierTrackPairs(); double getMedian(std::vector &v); double getAverage(std::vector &v); + bool passClusterRequirement(SvtxTrack *track, std::string type = "MVTX"); SvtxTrackMap *_track_map{nullptr}; TrkrClusterContainer* _cluster_map{nullptr}; @@ -91,7 +94,9 @@ class PHSimpleVertexFinder : public SubsysReco double _beamline_y_cut_hi = 0.2; double _qual_cut = 10.0; bool _require_mvtx = true; + bool _require_intt = false; unsigned int _nmvtx_required = 2; + unsigned int _nintt_required = 1; double _track_pt_cut = 0.0; double _outlier_cut = 0.015; From b5d1a81961b544004733a3f8377a1a649fa6bdf1 Mon Sep 17 00:00:00 2001 From: Jinglin-liu Date: Wed, 15 Apr 2026 17:57:18 -0400 Subject: [PATCH 461/866] Edit axis label and range --- offline/QA/Jet/EMCalShowerShapes.cc | 97 +++++++---------------------- offline/QA/Jet/EMCalShowerShapes.h | 1 - 2 files changed, 22 insertions(+), 76 deletions(-) diff --git a/offline/QA/Jet/EMCalShowerShapes.cc b/offline/QA/Jet/EMCalShowerShapes.cc index b24f36be9b..940abf89e0 100644 --- a/offline/QA/Jet/EMCalShowerShapes.cc +++ b/offline/QA/Jet/EMCalShowerShapes.cc @@ -117,29 +117,29 @@ int EMCalShowerShapes::Init(PHCompositeNode* /*topNode*/) h_cluster_et = new TH1F(vecHistNames[0].data(), "", 120, 0, 30); h_cluster_et->GetXaxis()->SetTitle("E_{T} [GeV]"); - h_e11oe33 = new TH1F(vecHistNames[1].data(), "", 25, 0, 1); + h_e11oe33 = new TH1F(vecHistNames[1].data(), "", 26, -0.02, 1.02); h_e11oe33->GetXaxis()->SetTitle("e11/e33"); - h_e33oe55 = new TH1F(vecHistNames[2].data(), "", 25, 0, 1); + h_e33oe55 = new TH1F(vecHistNames[2].data(), "", 26, -0.02, 1.02); h_e33oe55->GetXaxis()->SetTitle("e33/e55"); - h_e55oe77 = new TH1F(vecHistNames[3].data(), "", 25, 0, 1); + h_e55oe77 = new TH1F(vecHistNames[3].data(), "", 26, -0.02, 1.02); h_e55oe77->GetXaxis()->SetTitle("e55/e77"); - h_e32oe35 = new TH1F(vecHistNames[4].data(), "", 25, 0, 1); + h_e32oe35 = new TH1F(vecHistNames[4].data(), "", 26, -0.02, 1.02); h_e32oe35->GetXaxis()->SetTitle("e32/e35"); h_weta = new TH1F(vecHistNames[5].data(), "", 120, 0, 2); - h_weta->GetXaxis()->SetTitle("w_{#eta}"); + h_weta->GetXaxis()->SetTitle("w#eta"); h_wphi = new TH1F(vecHistNames[6].data(), "", 120, 0, 2); - h_wphi->GetXaxis()->SetTitle("w_{#phi}"); + h_wphi->GetXaxis()->SetTitle("w#phi"); h_weta_cogx = new TH1F(vecHistNames[7].data(), "", 50, 0, 2); - h_weta_cogx->GetXaxis()->SetTitle("w_{#eta}^{cogx}"); + h_weta_cogx->GetXaxis()->SetTitle("w#eta_cogx"); h_wphi_cogx = new TH1F(vecHistNames[8].data(), "", 50, 0, 2); - h_wphi_cogx->GetXaxis()->SetTitle("w_{#phi}^{cogx}"); + h_wphi_cogx->GetXaxis()->SetTitle("w#phi_cogx"); h_detamax = new TH1F(vecHistNames[9].data(), "", 10, -0.5, 9.5); h_detamax->GetXaxis()->SetTitle("detamax"); @@ -155,11 +155,11 @@ int EMCalShowerShapes::Init(PHCompositeNode* /*topNode*/) h_weta_vs_et = new TH2F(vecHistNames[13].data(), "", 120, 0, 30, 120, 0, 6); h_weta_vs_et->GetXaxis()->SetTitle("E_{T} [GeV]"); - h_weta_vs_et->GetYaxis()->SetTitle("w_{#eta}"); + h_weta_vs_et->GetYaxis()->SetTitle("w#eta"); h_wphi_vs_et = new TH2F(vecHistNames[14].data(), "", 120, 0, 30, 120, 0, 6); h_wphi_vs_et->GetXaxis()->SetTitle("E_{T} [GeV]"); - h_wphi_vs_et->GetYaxis()->SetTitle("w_{#phi}"); + h_wphi_vs_et->GetYaxis()->SetTitle("w#phi"); return Fun4AllReturnCodes::EVENT_OK; } @@ -235,7 +235,7 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) } const float vertex_z = GetVertexZ(topNode); - if (m_doMbdZvtxCut && std::abs(vertex_z) > m_mbdZvtxMax) + if (m_doMbdZvtxCut && std::abs(vertex_z) >= m_mbdZvtxMax) { return Fun4AllReturnCodes::EVENT_OK; } @@ -252,7 +252,7 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) } const float eta = RawClusterUtility::GetPseudorapidity(*cluster, vertex_vec); - if (m_doClusterEtaCut && std::abs(eta) > m_clusterEtaMax) + if (m_doClusterEtaCut && std::abs(eta) >= m_clusterEtaMax) { continue; } @@ -266,6 +266,16 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) continue; } + /* + if ( (data.e32 / data.e35) > 1 ) + { + std::cout << "e32/e35 > 1!!! e32 = "<< data.e32 << " e35 = " << data.e35 << std::endl; + } + if ( (data.e32 / data.e35) == 1 ) + { + std::cout << "e32/e35 = 1~~~ e32 = "<< data.e32 << " e35 = " << data.e35 << std::endl; + }*/ + h_cluster_et->Fill(et); h_e11oe33->Fill(data.e11 / data.e33); h_e33oe55->Fill(data.e33 / data.e55); @@ -282,68 +292,6 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) h_weta_vs_et->Fill(et, data.weta); h_wphi_vs_et->Fill(et, data.wphi); - /* - if (std::isfinite(et)) - { - h_cluster_et->Fill(et); - } - if (data.e33 > 0) - { - h_e11oe33->Fill(data.e11 / data.e33); - } - if (data.e55 > 0) - { - h_e33oe55->Fill(data.e33 / data.e55); - } - if (data.e77 > 0) - { - h_e55oe77->Fill(data.e55 / data.e77); - } - if (std::isfinite(data.weta)) - { - h_weta->Fill(data.weta); - } - if (std::isfinite(data.wphi)) - { - h_wphi->Fill(data.wphi); - } - if (std::isfinite(data.weta_cogx)) - { - h_weta_cogx->Fill(data.weta_cogx); - } - if (std::isfinite(data.wphi_cogx)) - { - h_wphi_cogx->Fill(data.wphi_cogx); - } - if (std::isfinite(data.detamax)) - { - h_detamax->Fill(data.detamax); - } - if (std::isfinite(data.dphimax)) - { - h_dphimax->Fill(data.dphimax); - } - if (std::isfinite(data.mean_time)) - { - h_mean_time->Fill(data.mean_time); - } - if (std::isfinite(data.iso04_emcal)) - { - h_iso04_emcal->Fill(data.iso04_emcal); - } - if (std::isfinite(data.e32_to_e35)) - { - h_e32_to_e35->Fill(data.e32_to_e35); - } - if (std::isfinite(et) && std::isfinite(data.weta)) - { - h_weta_vs_et->Fill(et, data.weta); - } - if (std::isfinite(et) && std::isfinite(data.wphi)) - { - h_wphi_vs_et->Fill(et, data.wphi); - } - */ } return Fun4AllReturnCodes::EVENT_OK; @@ -547,7 +495,6 @@ bool EMCalShowerShapes::CalculateShowerShapes(RawCluster* cluster, float cluster data.dphimax = dphimax; data.mean_time = clusteravgtime; data.iso04_emcal = CalculateLayerET(cluster_eta, cluster_phi, 0.4F, m_emc_tower_container, m_geomEM, vertex_z) - cluster_et; - //data.e32_to_e35 = (e35 > 0) ? (e32 / e35) : std::numeric_limits::quiet_NaN(); return true; } diff --git a/offline/QA/Jet/EMCalShowerShapes.h b/offline/QA/Jet/EMCalShowerShapes.h index 2d076fd25f..e478be8f45 100644 --- a/offline/QA/Jet/EMCalShowerShapes.h +++ b/offline/QA/Jet/EMCalShowerShapes.h @@ -83,7 +83,6 @@ class EMCalShowerShapes : public SubsysReco float dphimax {std::numeric_limits::quiet_NaN()}; float mean_time {std::numeric_limits::quiet_NaN()}; float iso04_emcal {std::numeric_limits::quiet_NaN()}; - //float e32_to_e35 {std::numeric_limits::quiet_NaN()}; }; bool LoadEMCalNodes(PHCompositeNode *topNode); From 7fcb80b95c5f5ef10ad6c4af46fead811e7a80f5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 15 Apr 2026 18:46:09 -0400 Subject: [PATCH 462/866] add 8,80GeV pythia8 jets and update double interactions --- offline/framework/frog/CreateFileList.pl | 137 ++++++++++++++++++++--- 1 file changed, 120 insertions(+), 17 deletions(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 9d7cd97e3c..01aafd3118 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -49,35 +49,35 @@ "8" => "HF pythia8 Bottom", "9" => "HF pythia8 Charm D0", "10" => "HF pythia8 Bottom D0", - "11" => "JS pythia8 Jet ptmin = 30GeV", - "12" => "JS pythia8 Jet ptmin = 10GeV", + "11" => "JS pythia8 Jet ptmin = 30 GeV", + "12" => "JS pythia8 Jet ptmin = 10 GeV", "13" => "JS pythia8 Photon Jet", "14" => "Single Particles", "15" => "Special Productions", "16" => "HF pythia8 D0 Jets", - "17" => "HF pythia8 D0 pi-k Jets ptmin = 5GeV ", - "18" => "HF pythia8 D0 pi-k Jets ptmin = 12GeV", - "19" => "JS pythia8 Jet ptmin = 40GeV", + "17" => "HF pythia8 D0 pi-k Jets ptmin = 5 GeV ", + "18" => "HF pythia8 D0 pi-k Jets ptmin = 12 GeV", + "19" => "JS pythia8 Jet ptmin = 40 GeV", "20" => "hijing pAu (0-10fm) pileup 0-10fm", - "21" => "JS pythia8 Jet ptmin = 20GeV", + "21" => "JS pythia8 Jet ptmin = 20 GeV", "22" => "cosmic field on", "23" => "cosmic field off", "24" => "AMPT", "25" => "EPOS", "26" => "JS pythia8 Detroit (MB)", - "27" => "JS pythia8 Photonjet ptmin = 5GeV", - "28" => "JS pythia8 Photonjet ptmin = 10GeV", - "29" => "JS pythia8 Photonjet ptmin = 20GeV", + "27" => "JS pythia8 Photonjet ptmin = 5 GeV", + "28" => "JS pythia8 Photonjet ptmin = 10 GeV", + "29" => "JS pythia8 Photonjet ptmin = 20 GeV", "30" => "Herwig MB", "31" => "Herwig Jet ptmin = 10 GeV", "32" => "Herwig Jet ptmin = 30 GeV", - "33" => "JS pythia8 Jet ptmin = 15GeV", - "34" => "JS pythia8 Jet ptmin = 50GeV", - "35" => "JS pythia8 Jet ptmin = 70GeV", - "36" => "JS pythia8 Jet ptmin = 5GeV", + "33" => "JS pythia8 Jet ptmin = 15 GeV", + "34" => "JS pythia8 Jet ptmin = 50 GeV", + "35" => "JS pythia8 Jet ptmin = 70 GeV", + "36" => "JS pythia8 Jet ptmin = 5 GeV", "37" => "hijing O+O (0-15fm)", - "38" => "JS pythia8 Jet ptmin = 60GeV", - "39" => "JS pythia8 Jet ptmin = 12GeV", + "38" => "JS pythia8 Jet ptmin = 60 GeV", + "39" => "JS pythia8 Jet ptmin = 12 GeV", "40" => "Herwig Jet ptmin = 5 GeV", "41" => "Herwig Jet ptmin = 12 GeV", "42" => "Herwig Jet ptmin = 20 GeV", @@ -85,7 +85,9 @@ "44" => "Herwig Jet ptmin = 50 GeV", "45" => "Herwig Photonjet ptmin = 5 GeV", "46" => "Herwig Photonjet ptmin = 10 GeV", - "47" => "Herwig Photonjet ptmin = 20 GeV" + "47" => "Herwig Photonjet ptmin = 20 GeV", + "48" => "JS pythia8 Jet ptmin = 8 GeV", + "49" => "JS pythia8 Jet ptmin = 80 GeV", ); my %pileupdesc = ( @@ -319,6 +321,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet30"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -522,6 +529,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet40"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -569,6 +581,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet20"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -673,6 +690,11 @@ { $embedok = 1; $filenamestring = "pythia8_PhotonJet5"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -744,6 +766,11 @@ { $embedok = 1; $filenamestring = "pythia8_PhotonJet20"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -897,6 +924,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet50"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -1046,7 +1078,7 @@ if (defined $double) { $doubleok = 1; - $filenamestring = "pythia8_Jet12_pythia8_Detroit"; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); } if (! defined $nopileup) { @@ -1338,6 +1370,77 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 48) + { + $embedok = 1; + $filenamestring = "pythia8_Jet8"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 49) + { + $embedok = 1; + $filenamestring = "pythia8_Jet80"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { print "no production type $prodtype\n"; From d66d44e080cb1a1098e3b387875c95713ac33cd6 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 15 Apr 2026 18:50:28 -0400 Subject: [PATCH 463/866] fix typo --- offline/framework/frog/CreateFileList.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 01aafd3118..ce6e662ae3 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -87,7 +87,7 @@ "46" => "Herwig Photonjet ptmin = 10 GeV", "47" => "Herwig Photonjet ptmin = 20 GeV", "48" => "JS pythia8 Jet ptmin = 8 GeV", - "49" => "JS pythia8 Jet ptmin = 80 GeV", + "49" => "JS pythia8 Jet ptmin = 80 GeV" ); my %pileupdesc = ( From da20ba5d6080f3734fd3f8cb25ff61680587f023 Mon Sep 17 00:00:00 2001 From: Jinglin-liu Date: Wed, 15 Apr 2026 22:52:54 -0400 Subject: [PATCH 464/866] Fix issues and add Et cut --- offline/QA/Jet/EMCalShowerShapes.cc | 22 ++++++++++------------ offline/QA/Jet/EMCalShowerShapes.h | 7 +++++++ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/offline/QA/Jet/EMCalShowerShapes.cc b/offline/QA/Jet/EMCalShowerShapes.cc index 940abf89e0..8e7e77c160 100644 --- a/offline/QA/Jet/EMCalShowerShapes.cc +++ b/offline/QA/Jet/EMCalShowerShapes.cc @@ -172,14 +172,8 @@ int EMCalShowerShapes::InitRun(PHCompositeNode* topNode) bool EMCalShowerShapes::LoadEMCalNodes(PHCompositeNode *topNode) { - if (!m_emc_tower_container) - { - m_emc_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC"); - } - if (!m_geomEM) - { - m_geomEM = findNode::getClass(topNode, "TOWERGEOM_CEMC"); - } + m_emc_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC"); + m_geomEM = findNode::getClass(topNode, "TOWERGEOM_CEMC"); const bool have_nodes = (m_emc_tower_container && m_geomEM); if (!have_nodes && !m_reportedMissingCaloNodes) @@ -259,6 +253,10 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) const float phi = RawClusterUtility::GetAzimuthAngle(*cluster, vertex_vec); const float et = cluster->get_energy() / std::cosh(eta); + if (m_doClusterETCut && et < m_clusterETMin) + { + continue; + } ShowerShapeData data; if (!CalculateShowerShapes(cluster, eta, phi, et, vertex_z, data)) @@ -277,10 +275,10 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) }*/ h_cluster_et->Fill(et); - h_e11oe33->Fill(data.e11 / data.e33); - h_e33oe55->Fill(data.e33 / data.e55); - h_e55oe77->Fill(data.e55 / data.e77); - h_e32oe35->Fill(data.e32 / data.e35); + if (data.e33 > 0) h_e11oe33->Fill(data.e11 / data.e33); + if (data.e55 > 0) h_e33oe55->Fill(data.e33 / data.e55); + if (data.e77 > 0) h_e55oe77->Fill(data.e55 / data.e77); + if (data.e35 > 0) h_e32oe35->Fill(data.e32 / data.e35); h_weta->Fill(data.weta); h_wphi->Fill(data.wphi); h_weta_cogx->Fill(data.weta_cogx); diff --git a/offline/QA/Jet/EMCalShowerShapes.h b/offline/QA/Jet/EMCalShowerShapes.h index e478be8f45..deccc3852d 100644 --- a/offline/QA/Jet/EMCalShowerShapes.h +++ b/offline/QA/Jet/EMCalShowerShapes.h @@ -61,6 +61,11 @@ class EMCalShowerShapes : public SubsysReco m_doClusterEtaCut = apply; } + void SetApplyClusterETCut(const bool apply) + { + m_doClusterETCut = apply; + } + void SetClusterEtaMax(const float maxeta) { m_clusterEtaMax = maxeta; @@ -108,6 +113,8 @@ class EMCalShowerShapes : public SubsysReco float m_mbdZvtxMax {60.0F}; bool m_doClusterEtaCut {true}; float m_clusterEtaMax {0.7F}; + bool m_doClusterETCut {true}; + float m_clusterETMin {5.0F}; TH1* h_cluster_et {nullptr}; TH1* h_e11oe33 {nullptr}; From ce03df27c0acf8e596f77aa98a7c294ba62a8d64 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Thu, 16 Apr 2026 11:09:35 -0400 Subject: [PATCH 465/866] CD: KFP: new verbosity for debugging --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 157 +++++++++++++++++- .../KFParticle_sPHENIX/KFParticle_Tools.h | 6 +- .../KFParticle_eventReconstruction.cc | 33 ++++ .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 1 + .../trackreco/PHSimpleVertexFinder.cc | 66 ++------ .../packages/trackreco/PHSimpleVertexFinder.h | 2 +- 6 files changed, 211 insertions(+), 54 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 9bb76608ee..0b1214dc26 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -327,6 +327,14 @@ std::vector KFParticle_Tools::makeAllDaughterParticles(PHCompositeNo } } + if (m_verbosity > 100) + { + printSelectionCheck("MVTX states", m_nMVTXStates, MVTX_states, 5); + printSelectionCheck("INTT states", m_nINTTStates, INTT_states, 5); + printSelectionCheck("TPC states", m_nTPCStates, TPC_states, 100); + printSelectionCheck("TPOT states", m_nTPOTStates, TPOT_states, 5); + } + if (MVTX_states < m_nMVTXStates) { continue; @@ -460,6 +468,25 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart { goodTrack = true; } + + + if (m_verbosity >= 10) + { + std::string decision = goodTrack ? "\033[1;32mThis track passed the selection\033[0m" + : "\033[1;31mThis track failed the selection\033[0m"; + std::cout << decision << std::endl; + if (m_verbosity >= 11) + { + printSelectionCheck("Track pT", m_track_min_pt, pt, m_track_max_pt); + printSelectionCheck("Track pT chi^2", 0, ptchi2, m_track_ptchi2); + printSelectionCheck("IP", m_track_ip, min_ip, FLT_MAX); + printSelectionCheck("IP chi^2", m_track_ipchi2, min_ipchi2, FLT_MAX); + printSelectionCheck("IP xy", m_track_ip_xy, min_ip_xy, FLT_MAX); + printSelectionCheck("IP xy chi^2", m_track_ipchi2_xy, min_ipchi2_xy, FLT_MAX); + printSelectionCheck("Track chi^2/nDoF", 0, trackchi2ndof, m_track_chi2ndof); + } + } + return goodTrack; } @@ -513,7 +540,7 @@ std::vector KFParticle_Tools::findAllGoodTracks(const std::vector> KFParticle_Tools::findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks) const +std::vector> KFParticle_Tools::findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks) { std::vector> goodTracksThatMeet; @@ -526,6 +553,19 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector= 10) + { + std::string decision = (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy) ? + "\033[1;32mThis track pair passed the DCA selection\033[0m" + : "\033[1;31mThis track pair failed the DCA selection\033[0m"; + std::cout << decision << std::endl; + if (m_verbosity >= 11) + { + printSelectionCheck("Pair DCA", 0., dca, m_comb_DCA); + printSelectionCheck("Pair DCA xy", 0., dca_xy, m_comb_DCA_xy); + } + } + if (dca <= m_comb_DCA && dca_xy <= m_comb_DCA_xy) { KFVertex twoParticleVertex; @@ -535,6 +575,19 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector combination = {*i_it, *j_it}; + if (nTracks == 2 && m_verbosity >= 10) + { + std::string decision = (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV) ? + "\033[1;32mThis track pair passed the quality and radius selection\033[0m" + : "\033[1;31mThis track pair failed the quality and radius selection\033[0m"; + std::cout << decision << std::endl; + if (m_verbosity >= 11) + { + printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); + printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, FLT_MAX); + } + } + if (nTracks == 2 && vertexchi2ndof > m_vertex_chi2ndof) { continue; @@ -581,6 +634,19 @@ std::vector> KFParticle_Tools::findNProngs(std::vector= 10) + { + std::string decision = (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy) ? + "\033[1;32mThis track combined with a SV set\033[0m" + : "\033[1;31mThis track did not combine with a SV set\033[0m"; + std::cout << decision << std::endl; + if (m_verbosity >= 11) + { + printSelectionCheck("Pair DCA", 0., dca, m_comb_DCA); + printSelectionCheck("Pair DCA xy", 0., dca_xy, m_comb_DCA_xy); + } + } + if (dca > m_comb_DCA || dca_xy > m_comb_DCA_xy) { dcaMet = false; @@ -601,6 +667,19 @@ std::vector> KFParticle_Tools::findNProngs(std::vector= 10) + { + std::string decision = (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV) ? + "\033[1;32mThis SV combination passed the quality and radius selection\033[0m" + : "\033[1;31mThis SV combination failed the quality and radius selection\033[0m"; + std::cout << decision << std::endl; + if (m_verbosity >= 11) + { + printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); + printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, FLT_MAX); + } + } + if ((unsigned int) nRequiredTracks == nProngs && vertexchi2ndof > m_vertex_chi2ndof) { continue; @@ -825,6 +904,12 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters float calculated_dEdx_value = get_dEdx(topNode, vDaughters[i]); double expected_dEdx_value = get_dEdx_fitValue((Int_t) vDaughters[i].GetQ() * vDaughters[i].GetP(), track_PDG_ID); bool accept_dEdx = isInRange((1 - m_dEdx_band_width) * expected_dEdx_value, calculated_dEdx_value, (1 + m_dEdx_band_width) * expected_dEdx_value); + + if (m_verbosity >= 11) + { + printSelectionCheck("dE/dx check", (1 - m_dEdx_band_width) * expected_dEdx_value, calculated_dEdx_value, (1 + m_dEdx_band_width) * expected_dEdx_value); + } + if (!accept_dEdx) { delete[] inputTracks; @@ -875,7 +960,9 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters float calculated_mass; float calculated_mass_err; mother.GetMass(calculated_mass, calculated_mass_err); - float calculated_pt = mother.GetPt(); + float calculated_pt; + float calculated_pt_err; + mother.GetPt(calculated_pt, calculated_pt_err); float min_mass = isIntermediate ? m_intermediate_mass_range[intermediateNumber].first : m_min_mass; float max_mass = isIntermediate ? m_intermediate_mass_range[intermediateNumber].second : m_max_mass; @@ -909,6 +996,12 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters { goodCandidate = false; } + + if (m_verbosity >= 11) + { + std::string decision = crossings.size() == 1 ? "\033[1;32mAll tracks are from the same BC\033[0m" : "\033[1;31mTracks are from different BC\033[0m"; + std::cout << decision << std::endl; + } } // Check the requirements of an intermediate states against this mother and re-do goodCandidate @@ -923,6 +1016,33 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters { goodCandidate = false; } + + if (m_verbosity >= 10) + { + std::string decision = goodCandidate ? "\033[1;32mAccepted the intermediate selection\033[0m" : "\033[1;31mRejected the intermediate selection\033[0m"; + std::cout << decision << std::endl; + + if (m_verbosity >= 11) + { + printSelectionCheck("Intermediate DIRA", m_intermediate_min_dira[k], intermediate_DIRA, FLT_MAX); + printSelectionCheck("Intermediate FD chi^2", m_intermediate_min_fdchi2[k], intermediate_FDchi2, FLT_MAX); + } + } + } + } + + if (m_verbosity >= 10) + { + std::string decision = goodCandidate ? "\033[1;32mAccepted the mother selection\033[0m" : "\033[1;31mRejected the mother selection\033[0m"; + std::cout << decision << std::endl; + + if (m_verbosity >= 11) + { + decision = chargeCheck ? "\033[1;32mVertex charge is right\033[0m" : "\033[1;31mVertex charge is wrong\033[0m"; + std::cout << decision << std::endl; + printSelectionCheck("Invariant Mass", min_mass, calculated_mass, max_mass); + printSelectionCheck("Mother pT", min_pt, calculated_pt, FLT_MAX); + printSelectionCheck("Mother SV volume", 0., calculateEllipsoidVolume(mother), max_vertex_volume); } } delete[] inputTracks; @@ -970,6 +1090,30 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida { goodCandidate = true; } + + if (m_verbosity >= 10) + { + std::string decision = goodCandidate ? "\033[1;32mPassed the PV constraint\033[0m" : "\033[1;31mFailed the PV constraint\033[0m"; + std::cout << decision << std::endl; + + if (m_verbosity >= 11) + { + printSelectionCheck("Mother DIRA", m_dira_min, calculated_dira, m_dira_max); + printSelectionCheck("Mother DIRA xy", m_dira_xy_min, calculated_dira_xy, m_dira_xy_max); + printSelectionCheck("Mother FD chi^2", m_fdchi2, calculated_fdchi2, FLT_MAX); + printSelectionCheck("Mother IP", 0, calculated_ip, m_mother_ip); + printSelectionCheck("Mother IP chi^2", 0., calculated_ipchi2, m_mother_ipchi2); + printSelectionCheck("Mother IP xy", 0., calculated_ip_xy, m_mother_ip_xy); + printSelectionCheck("Mother IP xy chi^2", 0., calculated_ipchi2_xy, m_mother_ipchi2_xy); + printSelectionCheck("Mother Decay Time", m_min_decayTime, calculated_decayTime, m_max_decayTime); + printSelectionCheck("Mother Decay Time Significance", m_mother_min_decay_time_significance, calculated_decay_time_significance, FLT_MAX); + printSelectionCheck("Mother Decay Time xy", m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy); + printSelectionCheck("Mother Decay Length", m_min_decayLength, calculated_decayLength, m_max_decayLength); + printSelectionCheck("Mother Decay Length Significance", m_mother_min_decay_length_significance, calculated_decay_length_significance, FLT_MAX); + printSelectionCheck("Mother Decay Length xy", m_min_decayLength_xy, calculated_decayLength_xy, m_max_decayLength_xy); + printSelectionCheck("Mother Decay Length xy Significance", m_mother_min_decay_length_xy_significance, calculated_decay_length_xy_significance, FLT_MAX); + } + } } std::tuple KFParticle_Tools::getCombination(KFParticle vDaughters[], int daughterOrder[], KFParticle vertex, bool constrain_to_vertex, bool isIntermediate, int intermediateNumber, int nTracks, bool constrainMass, float required_vertexID, PHCompositeNode *topNode) @@ -1210,7 +1354,7 @@ void KFParticle_Tools::init_dEdx_fits() if (m_use_local_PID_file) { - std::cout << PHWHERE << " using local file " << m_local_PID_filename << std::endl; + if (m_verbosity > 4) std::cout << PHWHERE << " using local file " << m_local_PID_filename << std::endl; // new method is independent of charge filefit->GetObject("pi_band",f_pion_plus); filefit->GetObject("K_band",f_kaon_plus); @@ -1299,3 +1443,10 @@ bool KFParticle_Tools::checkTrackAndVertexMatch(KFParticle vDaughters[], int nTr return vertexAndTrackMatch; } + +void KFParticle_Tools::printSelectionCheck(std::string parameter, float min, float val, float max) +{ + std::string passOrFail = isInRange(min, val, max) ? "\033[1;32mPassed the " + parameter + " requirement\033[0m" + : "\033[1;31mFailed the " + parameter + " requirement\033[0m"; + std::cout << passOrFail << ". Lower bound = " << min << ", measured value = " << val << ", upper bound = " << max << std::endl; +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index feabd4aafc..90640cbff6 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -75,7 +75,7 @@ class KFParticle_Tools : protected KFParticle_MVA std::vector findAllGoodTracks(const std::vector &daughterParticles, const std::vector &primaryVertices); - std::vector> findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks) const; + std::vector> findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks); std::vector> findNProngs(std::vector daughterParticles, const std::vector &goodTrackIndex, @@ -126,6 +126,8 @@ class KFParticle_Tools : protected KFParticle_MVA void set_dont_use_global_vertex(bool set_variable) { m_dont_use_global_vertex = set_variable; } protected: + int m_verbosity = 0; + std::string m_mother_name_Tools; int m_num_intermediate_states{-1}; std::vector m_num_tracks_from_intermediate; @@ -281,6 +283,8 @@ class KFParticle_Tools : protected KFParticle_MVA void removeDuplicates(std::vector &v); void removeDuplicates(std::vector> &v); void removeDuplicates(std::vector> &v); + + void printSelectionCheck(std::string parameter, float min, float val, float max); }; #endif // KFPARTICLESPHENIX_KFPARTICLETOOLS_H diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index 64d6b932fa..207b46879e 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -76,6 +76,24 @@ void KFParticle_eventReconstruction::createDecay(PHCompositeNode* topNode, std:: std::vector goodTrackIndex = findAllGoodTracks(daughterParticles, primaryVertices); + if (m_verbosity >= 10) + { + unsigned int i_number = daughterParticles.size(); + std::string s_number = i_number > 0 ? "\033[1;32m" + std::to_string(i_number) + "\033[0m" + : "\033[1;31m" + std::to_string(i_number) + "\033[0m"; + std::cout << "Number of daughters passing state selection = " << s_number << std::endl; + + i_number = goodTrackIndex.size(); + s_number = i_number > 0 ? "\033[1;32m" + std::to_string(i_number) + "\033[0m" + : "\033[1;31m" + std::to_string(i_number) + "\033[0m"; + std::cout << "Number of daughters passing track selection = " << s_number<< std::endl; + + i_number = primaryVertices.size(); + s_number = i_number > 0 ? "\033[1;32m" + std::to_string(i_number) + "\033[0m" + : "\033[1;31m" + std::to_string(i_number) + "\033[0m"; + std::cout << "Number of PVs passing selection = " << s_number << std::endl; + } + if (!m_has_intermediates) { buildBasicChain(selectedMother, selectedVertex, selectedDaughters, daughterParticles, goodTrackIndex, primaryVertices, topNode); @@ -102,6 +120,13 @@ void KFParticle_eventReconstruction::buildBasicChain(std::vector& se goodTracksThatMeet = findNProngs(daughterParticlesBasic, goodTrackIndexBasic, goodTracksThatMeet, m_num_tracks, p); } + if (m_verbosity >= 10) + { + std::string number = goodTracksThatMeet.size() > 0 ? "\033[1;32m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m" + : "\033[1;31m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m"; + std::cout << "Number of SVs passing selection = " << number << std::endl; + } + getCandidateDecay(selectedMotherBasic, selectedVertexBasic, selectedDaughtersBasic, daughterParticlesBasic, goodTracksThatMeet, primaryVerticesBasic, 0, m_num_tracks, false, 0, true, topNode); } @@ -136,6 +161,14 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte goodTracksThatMeet, m_num_tracks_from_intermediate[i], p); } + + if (m_verbosity >= 10) + { + std::string number = goodTracksThatMeet.size() > 0 ? "\033[1;32m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m" + : "\033[1;31m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m"; + std::cout << "Number of SVs passing selection = " << number << std::endl; + } + getCandidateDecay(potentialIntermediates[i], vertices, potentialDaughters[i], daughterParticlesAdv, goodTracksThatMeet, primaryVerticesAdv, track_start, track_stop, true, i, m_constrain_int_mass, topNode); track_start += track_stop; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 100c649145..6249fcc01e 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -88,6 +88,7 @@ KFParticle_sPHENIX::KFParticle_sPHENIX(const std::string &name) int KFParticle_sPHENIX::Init(PHCompositeNode *topNode) { + m_verbosity = Verbosity(); if (m_save_output && Verbosity() >= VERBOSITY_SOME) { diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index 99b83dc013..d58de911ee 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -515,21 +515,13 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr1)) { - bool passed = passClusterRequirement(tr1); - if (!passed) - { - continue; - } + continue; } - if (_require_intt) + if (_require_intt && !passClusterRequirement(tr1, "INTT")) { - bool passed = passClusterRequirement(tr1, "INTT"); - if (!passed) - { - continue; - } + continue; } // look for close DCA matches with all other such tracks @@ -541,21 +533,13 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr2)) { - bool passed = passClusterRequirement(tr2); - if (!passed) - { - continue; - } + continue; } - if (_require_intt) + if (_require_intt && !passClusterRequirement(tr2, "INTT")) { - bool passed = passClusterRequirement(tr2, "INTT"); - if (!passed) - { - continue; - } + continue; } // find DCA of these two tracks @@ -771,21 +755,13 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr1)) { - bool passed = passClusterRequirement(tr1); - if (!passed) - { - continue; - } + continue; } - if (_require_intt) + if (_require_intt && !passClusterRequirement(tr1, "INTT")) { - bool passed = passClusterRequirement(tr1, "INTT"); - if (!passed) - { - continue; - } + continue; } // look for close DCA matches with all other such tracks @@ -797,21 +773,13 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr2)) { - bool passed = passClusterRequirement(tr2); - if (!passed) - { - continue; - } + continue; } - if (_require_intt) + if (_require_intt && !passClusterRequirement(tr2, "INTT")) { - bool passed = passClusterRequirement(tr2, "INTT"); - if (!passed) - { - continue; - } + continue; } // find DCA of these two tracks if (Verbosity() > 3) @@ -1272,7 +1240,7 @@ double PHSimpleVertexFinder::getAverage(std::vector &v) return avge; } -bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, std::string type) +bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, const std::string &type) { bool pass = false; diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index 41bd2bf4c5..e31d77aa8a 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -77,7 +77,7 @@ class PHSimpleVertexFinder : public SubsysReco void removeOutlierTrackPairs(); double getMedian(std::vector &v); double getAverage(std::vector &v); - bool passClusterRequirement(SvtxTrack *track, std::string type = "MVTX"); + bool passClusterRequirement(SvtxTrack *track, const std::string &type = "MVTX"); SvtxTrackMap *_track_map{nullptr}; TrkrClusterContainer* _cluster_map{nullptr}; From 0e1365daf53223ae687f6c71dbbc4ad4d03c1bd7 Mon Sep 17 00:00:00 2001 From: Jinglin-liu Date: Thu, 16 Apr 2026 14:36:27 -0400 Subject: [PATCH 466/866] Fix issues --- offline/QA/Jet/EMCalShowerShapes.cc | 94 ++++++++++++++--------------- offline/QA/Jet/EMCalShowerShapes.h | 8 +-- 2 files changed, 48 insertions(+), 54 deletions(-) diff --git a/offline/QA/Jet/EMCalShowerShapes.cc b/offline/QA/Jet/EMCalShowerShapes.cc index 8e7e77c160..c5d6ffb9c7 100644 --- a/offline/QA/Jet/EMCalShowerShapes.cc +++ b/offline/QA/Jet/EMCalShowerShapes.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -77,12 +78,11 @@ int EMCalShowerShapes::Init(PHCompositeNode* /*topNode*/) delete m_analyzer; m_analyzer = new TriggerAnalyzer(); - gStyle->SetOptTitle(0); m_manager = QAHistManagerDef::getHistoManager(); if (!m_manager) { std::cerr << PHWHERE << "PANIC: couldn't grab histogram manager!" << std::endl; - assert(m_manager); + gSystem->Exit(1); } std::string smallModuleName = m_modulename; @@ -161,12 +161,32 @@ int EMCalShowerShapes::Init(PHCompositeNode* /*topNode*/) h_wphi_vs_et->GetXaxis()->SetTitle("E_{T} [GeV]"); h_wphi_vs_et->GetYaxis()->SetTitle("w#phi"); + // Register histograms here to preserve them even if files are closedß + m_manager->registerHisto(h_cluster_et); + m_manager->registerHisto(h_e11oe33); + m_manager->registerHisto(h_e33oe55); + m_manager->registerHisto(h_e55oe77); + m_manager->registerHisto(h_e32oe35); + m_manager->registerHisto(h_weta); + m_manager->registerHisto(h_wphi); + m_manager->registerHisto(h_weta_cogx); + m_manager->registerHisto(h_wphi_cogx); + m_manager->registerHisto(h_detamax); + m_manager->registerHisto(h_dphimax); + m_manager->registerHisto(h_mean_time); + m_manager->registerHisto(h_iso04_emcal); + m_manager->registerHisto(h_weta_vs_et); + m_manager->registerHisto(h_wphi_vs_et); + return Fun4AllReturnCodes::EVENT_OK; } int EMCalShowerShapes::InitRun(PHCompositeNode* topNode) { - LoadEMCalNodes(topNode); + if (!LoadEMCalNodes(topNode)) + { + return Fun4AllReturnCodes::ABORTRUN; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -211,12 +231,12 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << "EMCalShowerShapes::process_event - missing node " << m_inputnode << std::endl; m_reportedMissingClusterNode = true; } - return Fun4AllReturnCodes::EVENT_OK; + return Fun4AllReturnCodes::ABORTRUN; } if (!LoadEMCalNodes(topNode)) { - return Fun4AllReturnCodes::EVENT_OK; + return Fun4AllReturnCodes::ABORTRUN; } if (m_doTrgSelect) @@ -264,16 +284,6 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) continue; } - /* - if ( (data.e32 / data.e35) > 1 ) - { - std::cout << "e32/e35 > 1!!! e32 = "<< data.e32 << " e35 = " << data.e35 << std::endl; - } - if ( (data.e32 / data.e35) == 1 ) - { - std::cout << "e32/e35 = 1~~~ e32 = "<< data.e32 << " e35 = " << data.e35 << std::endl; - }*/ - h_cluster_et->Fill(et); if (data.e33 > 0) h_e11oe33->Fill(data.e11 / data.e33); if (data.e55 > 0) h_e33oe55->Fill(data.e33 / data.e55); @@ -575,41 +585,25 @@ float EMCalShowerShapes::CalculateLayerET(float seed_eta, float seed_phi, float return layer_et; } -int EMCalShowerShapes::ResetEvent(PHCompositeNode* /*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - -int EMCalShowerShapes::EndRun(const int /*runnumber*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - -int EMCalShowerShapes::End(PHCompositeNode* /*topNode*/) -{ - m_manager->registerHisto(h_cluster_et); - m_manager->registerHisto(h_e11oe33); - m_manager->registerHisto(h_e33oe55); - m_manager->registerHisto(h_e55oe77); - m_manager->registerHisto(h_e32oe35); - m_manager->registerHisto(h_weta); - m_manager->registerHisto(h_wphi); - m_manager->registerHisto(h_weta_cogx); - m_manager->registerHisto(h_wphi_cogx); - m_manager->registerHisto(h_detamax); - m_manager->registerHisto(h_dphimax); - m_manager->registerHisto(h_mean_time); - m_manager->registerHisto(h_iso04_emcal); - m_manager->registerHisto(h_weta_vs_et); - m_manager->registerHisto(h_wphi_vs_et); - - return Fun4AllReturnCodes::EVENT_OK; -} - -int EMCalShowerShapes::Reset(PHCompositeNode* /*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} +//int EMCalShowerShapes::ResetEvent(PHCompositeNode* /*topNode*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//int EMCalShowerShapes::EndRun(const int /*runnumber*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//int EMCalShowerShapes::End(PHCompositeNode* /*topNode*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//int EMCalShowerShapes::Reset(PHCompositeNode* /*topNode*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} void EMCalShowerShapes::Print(const std::string &what) const { diff --git a/offline/QA/Jet/EMCalShowerShapes.h b/offline/QA/Jet/EMCalShowerShapes.h index deccc3852d..b60d1153e8 100644 --- a/offline/QA/Jet/EMCalShowerShapes.h +++ b/offline/QA/Jet/EMCalShowerShapes.h @@ -29,10 +29,10 @@ class EMCalShowerShapes : public SubsysReco int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; - int ResetEvent(PHCompositeNode *topNode) override; - int EndRun(const int runnumber) override; - int End(PHCompositeNode *topNode) override; - int Reset(PHCompositeNode *topNode) override; + //int ResetEvent(PHCompositeNode *topNode) override; + //int EndRun(const int runnumber) override; + //int End(PHCompositeNode *topNode) override; + //int Reset(PHCompositeNode *topNode) override; void Print(const std::string &what = "ALL") const override; void SetTrgToSelect(const uint32_t trig = JetQADefs::GL1::MBDNSPhoton1) From 7698c6131d98d34e7522d09592ed7ab4b77eea5d Mon Sep 17 00:00:00 2001 From: Jinglin-liu Date: Thu, 16 Apr 2026 19:24:30 -0400 Subject: [PATCH 467/866] Resolve clang-tidy complains --- offline/QA/Jet/EMCalShowerShapes.cc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/offline/QA/Jet/EMCalShowerShapes.cc b/offline/QA/Jet/EMCalShowerShapes.cc index c5d6ffb9c7..88506fc4ce 100644 --- a/offline/QA/Jet/EMCalShowerShapes.cc +++ b/offline/QA/Jet/EMCalShowerShapes.cc @@ -285,10 +285,18 @@ int EMCalShowerShapes::process_event(PHCompositeNode *topNode) } h_cluster_et->Fill(et); - if (data.e33 > 0) h_e11oe33->Fill(data.e11 / data.e33); - if (data.e55 > 0) h_e33oe55->Fill(data.e33 / data.e55); - if (data.e77 > 0) h_e55oe77->Fill(data.e55 / data.e77); - if (data.e35 > 0) h_e32oe35->Fill(data.e32 / data.e35); + if (data.e33 > 0) { + h_e11oe33->Fill(data.e11 / data.e33); + } + if (data.e55 > 0) { + h_e33oe55->Fill(data.e33 / data.e55); + } + if (data.e77 > 0) { + h_e55oe77->Fill(data.e55 / data.e77); + } + if (data.e35 > 0) { + h_e32oe35->Fill(data.e32 / data.e35); + } h_weta->Fill(data.weta); h_wphi->Fill(data.wphi); h_weta_cogx->Fill(data.weta_cogx); @@ -343,7 +351,7 @@ bool EMCalShowerShapes::CalculateShowerShapes(RawCluster* cluster, float cluster cluster_total_e += towerinfo->get_energy(); } - constexpr int totalphibins = 256; + int totalphibins = 256; auto dphiwrap = [totalphibins](int towerphi, int maxiphi_arg) { int idphi = towerphi - maxiphi_arg; From 11a9d5c35e4332b28eff3ba262e6e46eec9db3d7 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Fri, 17 Apr 2026 11:30:56 -0400 Subject: [PATCH 468/866] CD: Cleaned up verbosity in KFP --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 62 +++++++++---------- .../KFParticle_sPHENIX/KFParticle_Tools.h | 4 ++ .../KFParticle_eventReconstruction.cc | 25 ++------ .../packages/trackreco/PHSimpleVertexFinder.h | 8 +-- 4 files changed, 41 insertions(+), 58 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 0b1214dc26..c527dddd30 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -472,9 +472,7 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart if (m_verbosity >= 10) { - std::string decision = goodTrack ? "\033[1;32mThis track passed the selection\033[0m" - : "\033[1;31mThis track failed the selection\033[0m"; - std::cout << decision << std::endl; + printSelectionCheck("This track", "passed", "failed", "the selection", goodTrack); if (m_verbosity >= 11) { printSelectionCheck("Track pT", m_track_min_pt, pt, m_track_max_pt); @@ -555,10 +553,7 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector= 10) { - std::string decision = (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy) ? - "\033[1;32mThis track pair passed the DCA selection\033[0m" - : "\033[1;31mThis track pair failed the DCA selection\033[0m"; - std::cout << decision << std::endl; + printSelectionCheck("This track pair", "passed", "failed", "the DCA selection", (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy)); if (m_verbosity >= 11) { printSelectionCheck("Pair DCA", 0., dca, m_comb_DCA); @@ -577,10 +572,7 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector= 10) { - std::string decision = (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV) ? - "\033[1;32mThis track pair passed the quality and radius selection\033[0m" - : "\033[1;31mThis track pair failed the quality and radius selection\033[0m"; - std::cout << decision << std::endl; + printSelectionCheck("This track pair", "passed", "failed", "the quality and radius selection", (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV)); if (m_verbosity >= 11) { printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); @@ -636,10 +628,7 @@ std::vector> KFParticle_Tools::findNProngs(std::vector= 10) { - std::string decision = (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy) ? - "\033[1;32mThis track combined with a SV set\033[0m" - : "\033[1;31mThis track did not combine with a SV set\033[0m"; - std::cout << decision << std::endl; + printSelectionCheck("This track", "combined", "did not combine", "with a SV set", (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy)); if (m_verbosity >= 11) { printSelectionCheck("Pair DCA", 0., dca, m_comb_DCA); @@ -669,10 +658,7 @@ std::vector> KFParticle_Tools::findNProngs(std::vector= 10) { - std::string decision = (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV) ? - "\033[1;32mThis SV combination passed the quality and radius selection\033[0m" - : "\033[1;31mThis SV combination failed the quality and radius selection\033[0m"; - std::cout << decision << std::endl; + printSelectionCheck("This SV combination", "passed", "failed", "the quality and radius selection", (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV)); if (m_verbosity >= 11) { printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); @@ -999,8 +985,8 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters if (m_verbosity >= 11) { - std::string decision = crossings.size() == 1 ? "\033[1;32mAll tracks are from the same BC\033[0m" : "\033[1;31mTracks are from different BC\033[0m"; - std::cout << decision << std::endl; + bool accept = crossings.size() == 1; + printSelectionCheck("", "All tracks are from the same BC", "Tracks are from different BC", "", accept); } } @@ -1019,9 +1005,7 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters if (m_verbosity >= 10) { - std::string decision = goodCandidate ? "\033[1;32mAccepted the intermediate selection\033[0m" : "\033[1;31mRejected the intermediate selection\033[0m"; - std::cout << decision << std::endl; - + printSelectionCheck("", "Accepted", "Rejected", "the intermediate selection", goodCandidate); if (m_verbosity >= 11) { printSelectionCheck("Intermediate DIRA", m_intermediate_min_dira[k], intermediate_DIRA, FLT_MAX); @@ -1033,13 +1017,10 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters if (m_verbosity >= 10) { - std::string decision = goodCandidate ? "\033[1;32mAccepted the mother selection\033[0m" : "\033[1;31mRejected the mother selection\033[0m"; - std::cout << decision << std::endl; - + printSelectionCheck("", "Accepted", "Rejected", "the mother selection", goodCandidate); if (m_verbosity >= 11) { - decision = chargeCheck ? "\033[1;32mVertex charge is right\033[0m" : "\033[1;31mVertex charge is wrong\033[0m"; - std::cout << decision << std::endl; + printSelectionCheck("Vertex charge is", "right", "wrong", "", chargeCheck); printSelectionCheck("Invariant Mass", min_mass, calculated_mass, max_mass); printSelectionCheck("Mother pT", min_pt, calculated_pt, FLT_MAX); printSelectionCheck("Mother SV volume", 0., calculateEllipsoidVolume(mother), max_vertex_volume); @@ -1093,9 +1074,7 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida if (m_verbosity >= 10) { - std::string decision = goodCandidate ? "\033[1;32mPassed the PV constraint\033[0m" : "\033[1;31mFailed the PV constraint\033[0m"; - std::cout << decision << std::endl; - + printSelectionCheck("", "Passed", "Failed", "the PV constraint", goodCandidate); if (m_verbosity >= 11) { printSelectionCheck("Mother DIRA", m_dira_min, calculated_dira, m_dira_max); @@ -1446,7 +1425,22 @@ bool KFParticle_Tools::checkTrackAndVertexMatch(KFParticle vDaughters[], int nTr void KFParticle_Tools::printSelectionCheck(std::string parameter, float min, float val, float max) { - std::string passOrFail = isInRange(min, val, max) ? "\033[1;32mPassed the " + parameter + " requirement\033[0m" - : "\033[1;31mFailed the " + parameter + " requirement\033[0m"; + std::string trailer = "the " + parameter + " requirement\033[0m"; + std::string passOrFail = isInRange(min, val, max) ? "\033[1;" + accept_colour + "mPassed " + trailer + : "\033[1;" + reject_colour + "mFailed " + trailer; std::cout << passOrFail << ". Lower bound = " << min << ", measured value = " << val << ", upper bound = " << max << std::endl; } + +void KFParticle_Tools::printSelectionCheck(std::string start, std::string accept, std::string reject, std::string end, bool equality) +{ + std::string decision = equality ? accept : reject; + std::string colour = equality ? accept_colour : reject_colour; + std::string spacing = start.empty() ? "" : " "; + std::cout << "\033[1;" << colour << "m" << start << spacing << decision << " " << end << "\033[0m" << std::endl; +} + +void KFParticle_Tools::printSelectionCheck(std::string info, unsigned int value) +{ + std::string colour = value > 0 ? accept_colour : reject_colour; + std::cout << info << " = \033[1;" + colour + "m" + value + "\033[0m" << std::endl; +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 90640cbff6..9a9bdbfb0e 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -285,6 +285,10 @@ class KFParticle_Tools : protected KFParticle_MVA void removeDuplicates(std::vector> &v); void printSelectionCheck(std::string parameter, float min, float val, float max); + void printSelectionCheck(std::string start, std::string accept, std::string reject, std::string end, bool equality); + void printSelectionCheck(std::string info, unsigned int value); + std::string accept_colour = "32"; + std::string reject_colour = "31"; }; #endif // KFPARTICLESPHENIX_KFPARTICLETOOLS_H diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index 207b46879e..3c40fd4e58 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -78,20 +78,9 @@ void KFParticle_eventReconstruction::createDecay(PHCompositeNode* topNode, std:: if (m_verbosity >= 10) { - unsigned int i_number = daughterParticles.size(); - std::string s_number = i_number > 0 ? "\033[1;32m" + std::to_string(i_number) + "\033[0m" - : "\033[1;31m" + std::to_string(i_number) + "\033[0m"; - std::cout << "Number of daughters passing state selection = " << s_number << std::endl; - - i_number = goodTrackIndex.size(); - s_number = i_number > 0 ? "\033[1;32m" + std::to_string(i_number) + "\033[0m" - : "\033[1;31m" + std::to_string(i_number) + "\033[0m"; - std::cout << "Number of daughters passing track selection = " << s_number<< std::endl; - - i_number = primaryVertices.size(); - s_number = i_number > 0 ? "\033[1;32m" + std::to_string(i_number) + "\033[0m" - : "\033[1;31m" + std::to_string(i_number) + "\033[0m"; - std::cout << "Number of PVs passing selection = " << s_number << std::endl; + printSelectionCheck("Number of daughters passing state selection", daughterParticles.size()); + printSelectionCheck("Number of daughters passing track selection", goodTrackIndex.size()); + printSelectionCheck("Number of PVs passing selection", primaryVertices.size()); } if (!m_has_intermediates) @@ -122,9 +111,7 @@ void KFParticle_eventReconstruction::buildBasicChain(std::vector& se if (m_verbosity >= 10) { - std::string number = goodTracksThatMeet.size() > 0 ? "\033[1;32m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m" - : "\033[1;31m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m"; - std::cout << "Number of SVs passing selection = " << number << std::endl; + printSelectionCheck("Number of SVs passing selection", goodTracksThatMeet.size()); } getCandidateDecay(selectedMotherBasic, selectedVertexBasic, selectedDaughtersBasic, daughterParticlesBasic, @@ -164,9 +151,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte if (m_verbosity >= 10) { - std::string number = goodTracksThatMeet.size() > 0 ? "\033[1;32m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m" - : "\033[1;31m" + std::to_string(goodTracksThatMeet.size()) + "\033[0m"; - std::cout << "Number of SVs passing selection = " << number << std::endl; + printSelectionCheck("Number of SVs passing selection", goodTracksThatMeet.size()); } getCandidateDecay(potentialIntermediates[i], vertices, potentialDaughters[i], daughterParticlesAdv, diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index e31d77aa8a..6520174937 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -46,18 +46,18 @@ class PHSimpleVertexFinder : public SubsysReco void setBeamSpotCutY(const double cutlo, const double cuthi) { _beamline_y_cut_lo = cutlo; _beamline_y_cut_hi = cuthi; } void setDcaCut(const double cut) { _base_dcacut = cut; } void setTrackQualityCut(double cut) { _qual_cut = cut; } - void setRequireMVTX(bool set) { _require_mvtx = set; } + void setRequireMVTX(bool set = true) { _require_mvtx = set; } void setNmvtxRequired(unsigned int n) { _nmvtx_required = n; } - void setRequireINTT(bool set) { _require_intt = set; } + void setRequireINTT(bool set = true) { _require_intt = set; } void setNinttRequired(unsigned int n) { _nintt_required = n; } 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 zeroField(const bool flag = true) { _zero_field = flag; } void setTrkrClusterContainerName(const std::string &name){ m_clusterContainerName = name; } - void set_pp_mode(bool mode) { _pp_mode = mode; } + void set_pp_mode(bool mode = true) { _pp_mode = mode; } private: int GetNodes(PHCompositeNode *topNode); From 43335a541ecaf08de52458928255436ddd5adb53 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Fri, 17 Apr 2026 11:34:00 -0400 Subject: [PATCH 469/866] CD: KFP CPP check --- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc | 6 +++--- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index c527dddd30..f1054a78f1 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1423,7 +1423,7 @@ bool KFParticle_Tools::checkTrackAndVertexMatch(KFParticle vDaughters[], int nTr return vertexAndTrackMatch; } -void KFParticle_Tools::printSelectionCheck(std::string parameter, float min, float val, float max) +void KFParticle_Tools::printSelectionCheck(const std::string ¶meter, float min, float val, float max) { std::string trailer = "the " + parameter + " requirement\033[0m"; std::string passOrFail = isInRange(min, val, max) ? "\033[1;" + accept_colour + "mPassed " + trailer @@ -1431,7 +1431,7 @@ void KFParticle_Tools::printSelectionCheck(std::string parameter, float min, flo std::cout << passOrFail << ". Lower bound = " << min << ", measured value = " << val << ", upper bound = " << max << std::endl; } -void KFParticle_Tools::printSelectionCheck(std::string start, std::string accept, std::string reject, std::string end, bool equality) +void KFParticle_Tools::printSelectionCheck(const std::string &start, const std::string &accept, const std::string &reject, const std::string &end, bool equality) { std::string decision = equality ? accept : reject; std::string colour = equality ? accept_colour : reject_colour; @@ -1439,7 +1439,7 @@ void KFParticle_Tools::printSelectionCheck(std::string start, std::string accept std::cout << "\033[1;" << colour << "m" << start << spacing << decision << " " << end << "\033[0m" << std::endl; } -void KFParticle_Tools::printSelectionCheck(std::string info, unsigned int value) +void KFParticle_Tools::printSelectionCheck(const std::string &info, unsigned int value) { std::string colour = value > 0 ? accept_colour : reject_colour; std::cout << info << " = \033[1;" + colour + "m" + value + "\033[0m" << std::endl; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 9a9bdbfb0e..c6782d1f36 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -284,9 +284,9 @@ class KFParticle_Tools : protected KFParticle_MVA void removeDuplicates(std::vector> &v); void removeDuplicates(std::vector> &v); - void printSelectionCheck(std::string parameter, float min, float val, float max); - void printSelectionCheck(std::string start, std::string accept, std::string reject, std::string end, bool equality); - void printSelectionCheck(std::string info, unsigned int value); + void printSelectionCheck(const std::string ¶meter, float min, float val, float max); + void printSelectionCheck(const std::string &start, const std::string a&ccept, const std::string &reject, const std::string &end, bool equality); + void printSelectionCheck(const std::string &info, unsigned int value); std::string accept_colour = "32"; std::string reject_colour = "31"; }; From 51dd7c7c9e7aaefeb046e35310f7bc2c422aa9e9 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Sat, 18 Apr 2026 10:12:59 -0400 Subject: [PATCH 470/866] CD: KFP CPP check --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 37 ++++++++++++++----- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 5 ++- .../KFParticle_sPHENIX/KFParticle_Tools.h | 2 +- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 09de461fe9..340e3f6c14 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -390,15 +390,34 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_reco_track_eta[index] = m_dst_track->get_eta(); m_reco_track_phi[index] = m_dst_track->get_phi(); m_reco_track_chi2nDoF[index] = m_dst_track->get_chisq() / m_dst_track->get_ndf(); - if (m_dst_track->get_silicon_seed()) - { - m_reco_track_silicon_seeds[index] = static_cast(m_dst_track->get_silicon_seed()->size_cluster_keys()); - } - else + + for (auto state_iter = m_dst_track->begin_states(); + state_iter != m_dst_track->end_states(); + ++state_iter) { - m_reco_track_silicon_seeds[index] = 0; + SvtxTrackState *tstate = state_iter->second; + if (tstate->get_pathlength() != 0) // The first track state is an extrapolation so has no cluster + { + auto stateckey = tstate->get_cluskey(); + uint8_t id = TrkrDefs::getTrkrId(stateckey); + + switch (id) + { + case TrkrDefs::mvtxId: + ++m_reco_track_silicon_seeds[index]; + break; + case TrkrDefs::inttId: + ++m_reco_track_silicon_seeds[index]; + break; + case TrkrDefs::tpcId: + ++m_reco_track_tpc_seeds[index]; + break; + default: + break; + } + } } - m_reco_track_tpc_seeds[index] = static_cast(m_dst_track->get_tpc_seed()->size_cluster_keys()); + m_min_reco_track_pT = std::min(m_reco_track_pT[index], m_min_reco_track_pT); m_max_reco_track_pT = std::max(m_reco_track_pT[index], m_max_reco_track_pT); @@ -513,8 +532,8 @@ void HFTrackEfficiency::resetBranches() m_reco_track_phi[iTrack] = std::numeric_limits::quiet_NaN(); m_true_track_PID[iTrack] = std::numeric_limits::quiet_NaN(); m_reco_track_chi2nDoF[iTrack] = std::numeric_limits::quiet_NaN(); - m_reco_track_silicon_seeds[iTrack] = 0; - m_reco_track_tpc_seeds[iTrack] = 0; + m_reco_track_silicon_seeds[iTrack] = std::numeric_limits::quiet_NaN(); + m_reco_track_tpc_seeds[iTrack] = std::numeric_limits::quiet_NaN(); } m_primary_vtx_x = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index f1054a78f1..a2e690b767 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1333,7 +1333,10 @@ void KFParticle_Tools::init_dEdx_fits() if (m_use_local_PID_file) { - if (m_verbosity > 4) std::cout << PHWHERE << " using local file " << m_local_PID_filename << std::endl; + if (m_verbosity > 4) + { + std::cout << PHWHERE << " using local file " << m_local_PID_filename << std::endl; + } // new method is independent of charge filefit->GetObject("pi_band",f_pion_plus); filefit->GetObject("K_band",f_kaon_plus); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index c6782d1f36..434a64cf4d 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -285,7 +285,7 @@ class KFParticle_Tools : protected KFParticle_MVA void removeDuplicates(std::vector> &v); void printSelectionCheck(const std::string ¶meter, float min, float val, float max); - void printSelectionCheck(const std::string &start, const std::string a&ccept, const std::string &reject, const std::string &end, bool equality); + void printSelectionCheck(const std::string &start, const std::string &accept, const std::string &reject, const std::string &end, bool equality); void printSelectionCheck(const std::string &info, unsigned int value); std::string accept_colour = "32"; std::string reject_colour = "31"; From 8921a077a2c1350a53c4f66dbcdf8bb2942efd7c Mon Sep 17 00:00:00 2001 From: Cameron Dean <59485912+cdean-github@users.noreply.github.com> Date: Sat, 18 Apr 2026 10:23:36 -0400 Subject: [PATCH 471/866] Update offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 340e3f6c14..57fd9bd505 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -532,8 +532,8 @@ void HFTrackEfficiency::resetBranches() m_reco_track_phi[iTrack] = std::numeric_limits::quiet_NaN(); m_true_track_PID[iTrack] = std::numeric_limits::quiet_NaN(); m_reco_track_chi2nDoF[iTrack] = std::numeric_limits::quiet_NaN(); - m_reco_track_silicon_seeds[iTrack] = std::numeric_limits::quiet_NaN(); - m_reco_track_tpc_seeds[iTrack] = std::numeric_limits::quiet_NaN(); + m_reco_track_silicon_seeds[iTrack] = -1; + m_reco_track_tpc_seeds[iTrack] = -1; } m_primary_vtx_x = std::numeric_limits::quiet_NaN(); From 04bbc4787c16b6adbd93fe0c91dba43cc3c895a7 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Sat, 18 Apr 2026 10:35:40 -0400 Subject: [PATCH 472/866] CD: Code rabbit suggestions --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 2 +- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 85 +++++++++---------- offline/packages/decayfinder/DecayFinder.cc | 2 +- .../trackreco/PHSimpleVertexFinder.cc | 19 +++-- 4 files changed, 56 insertions(+), 52 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index a2e690b767..8877c5be00 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -1445,5 +1445,5 @@ void KFParticle_Tools::printSelectionCheck(const std::string &start, const std:: void KFParticle_Tools::printSelectionCheck(const std::string &info, unsigned int value) { std::string colour = value > 0 ? accept_colour : reject_colour; - std::cout << info << " = \033[1;" + colour + "m" + value + "\033[0m" << std::endl; + std::cout << info << " = \033[1;" << colour << "m" << value << "\033[0m" << std::endl; } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 6249fcc01e..526def19a5 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -136,55 +136,13 @@ int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) } int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) -{ - +{ std::vector mother; std::vector vertex_kfparticle; std::vector> daughters; std::vector> intermediates; int nPVs; int multiplicity; - - SvtxTrackMap *check_trackmap = findNode::getClass(topNode, m_trk_map_node_name); - multiplicity = check_trackmap->size(); - - if (check_trackmap->empty()) - { - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "KFParticle: Event skipped as there are no tracks" << std::endl; - } - return Fun4AllReturnCodes::EVENT_OK; - } - - if (!m_use_fake_pv) - { - if (m_use_mbd_vertex) - { - MbdVertexMap* check_vertexmap = findNode::getClass(topNode, "MbdVertexMap"); - if (check_vertexmap->empty()) - { - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; - } - return Fun4AllReturnCodes::EVENT_OK; - } - } - else - { - SvtxVertexMap* check_vertexmap = findNode::getClass(topNode, m_vtx_map_node_name); - if (check_vertexmap->empty()) - { - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; - } - return Fun4AllReturnCodes::EVENT_OK; - } - } - } - // Adding BCO Matching auto* evtHeader = findNode::getClass(topNode, "EventHeader"); // event header node @@ -244,6 +202,47 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) } // End BCO matching here + SvtxTrackMap *check_trackmap = findNode::getClass(topNode, m_trk_map_node_name); + multiplicity = check_trackmap->size(); + + if (check_trackmap->empty()) + { + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "KFParticle: Event skipped as there are no tracks" << std::endl; + } + return Fun4AllReturnCodes::EVENT_OK; + } + + if (!m_use_fake_pv) + { + if (m_use_mbd_vertex) + { + MbdVertexMap* check_vertexmap = findNode::getClass(topNode, "MbdVertexMap"); + if (check_vertexmap->empty()) + { + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; + } + return Fun4AllReturnCodes::EVENT_OK; + } + } + else + { + SvtxVertexMap* check_vertexmap = findNode::getClass(topNode, m_vtx_map_node_name); + if (check_vertexmap->empty()) + { + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; + } + return Fun4AllReturnCodes::EVENT_OK; + } + } + } + + createDecay(topNode, mother, vertex_kfparticle, daughters, intermediates, nPVs); if (!m_has_intermediates_sPHENIX) { diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index 6d622cd302..596cce9c63 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -455,7 +455,7 @@ int DecayFinder::findDecay(PHCompositeNode* topNode) if (!m_genevt) { std::cout << "DecayFinder: Missing node PHHepMCGenEvent" << std::endl; - return false; + continue; } HepMC::GenEvent* theEvent = m_genevt->getEvent(); diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index d58de911ee..ccd2bde57d 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -574,13 +574,18 @@ void PHSimpleVertexFinder::checkDCAsZF(SvtxTrackMap *track_map) // tr1->identify(); TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (_require_mvtx) - { - if (!siliconseed) - { - continue; - } - } + if ((_require_mvtx || _require_intt) && !siliconseed) + { + continue; + } + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) + { + continue; + } + if (_require_intt && !passClusterRequirement(tr1, "INTT")) + { + continue; + } TrackSeed *tpcseed = tr1->get_tpc_seed(); std::vector global_vec; From 5fd977d86e0a8488a83e67ea5357b20acb3039ba Mon Sep 17 00:00:00 2001 From: cdean-github Date: Sun, 19 Apr 2026 12:50:08 -0400 Subject: [PATCH 473/866] CD: Clang tidy request --- offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 57fd9bd505..83b2e9fed8 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -404,8 +404,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) switch (id) { case TrkrDefs::mvtxId: - ++m_reco_track_silicon_seeds[index]; - break; + [[fallthrough]]; case TrkrDefs::inttId: ++m_reco_track_silicon_seeds[index]; break; From d1507d23a3a30c46251e7c5d668120b02eddaf0e Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Mon, 20 Apr 2026 14:06:58 -0400 Subject: [PATCH 474/866] Update TrkrNtuplizer: refine ntuple filling and fix variable handling --- .../TrackingDiagnostics/TrkrNtuplizer.cc | 77 ++++++++++++++++++- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index abc91cbf52..60f82b10e5 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -1388,7 +1388,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) //----------------------- // fill the Vertex NTuple //----------------------- - bool doit = true; + /* bool doit = true; if (_ntp_vertex && doit) { if (Verbosity() > 1) @@ -1402,11 +1402,8 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) { i = 0; } - // SvtxVertexMap* vertexmap = nullptr; - // vertexmap = findNode::getClass(topNode, "SvtxVertexMapActs"); // Acts vertices - float vx = std::numeric_limits::quiet_NaN(); float vy = std::numeric_limits::quiet_NaN(); float vz = std::numeric_limits::quiet_NaN(); @@ -1425,12 +1422,84 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) std::copy(fx_info, fx_info + ((int) (n_info::infosize)), vertex_data + n_event::evsize + n_vertex::vtxsize); _ntp_vertex->Fill(vertex_data); delete[] vertex_data; + } if (Verbosity() > 1) { _timer->stop(); std::cout << "vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; + }*/ + + //----------------------- + // Fix Nan placeholders for vertex variables + // //----------------------- + bool doit = true; + if (_ntp_vertex && doit) + { + if (Verbosity() > 1) + { + std::cout << "Filling ntp_vertex " << std::endl; + std::cout << "start vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; + _timer->restart(); + } + + SvtxVertexMap* vertexmap = findNode::getClass(topNode, "SvtxVertexMapActs"); + + if (!vertexmap) + { + std::cout << PHWHERE << " WARNING: SvtxVertexMapActs not found. Writing no vertex entries for this event." << std::endl; + } + else + { + for (auto & iter : *vertexmap) + { + SvtxVertex* vertex = iter.second; + if (!vertex) { continue; +} + + float fx_vertex[n_vertex::vtxsize]; + for (float& i : fx_vertex) + { + i = std::numeric_limits::quiet_NaN(); + } + + fx_vertex[vtxnvertexID] = static_cast(vertex->get_id()); + fx_vertex[vtxnvx] = vertex->get_x(); + fx_vertex[vtxnvy] = vertex->get_y(); + fx_vertex[vtxnvz] = vertex->get_z(); + fx_vertex[vtxnntracks] = static_cast(vertex->size_tracks()); + fx_vertex[vtxnchi2] = vertex->get_chisq(); + fx_vertex[vtxnndof] = vertex->get_ndof(); + + if (Verbosity() > 1) + { + std::cout << " adding vertex data " + << " id = " << vertex->get_id() + << " vx = " << vertex->get_x() + << " vy = " << vertex->get_y() + << " vz = " << vertex->get_z() + << " ntracks = " << vertex->size_tracks() + << std::endl; + } + + float* vertex_data = new float[((int) (n_info::infosize)) + n_event::evsize + n_vertex::vtxsize]; + std::copy(fx_event, fx_event + n_event::evsize, vertex_data); + std::copy(fx_vertex, fx_vertex + n_vertex::vtxsize, vertex_data + n_event::evsize); + std::copy(fx_info, fx_info + ((int) (n_info::infosize)), vertex_data + n_event::evsize + n_vertex::vtxsize); + + _ntp_vertex->Fill(vertex_data); + delete[] vertex_data; + } + } } + + if (Verbosity() > 1) + { + _timer->stop(); + std::cout << "vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; + } + + //-------------------- // fill the Hit NTuple //-------------------- From 6ffe19a5f9f80ab03a7e0ad8c39458a60ecf6b67 Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Tue, 21 Apr 2026 10:31:46 -0400 Subject: [PATCH 475/866] Cleanup TrkrNtuplizer: improve readability and apply minor fixes --- .../TrackingDiagnostics/TrkrNtuplizer.cc | 47 +------------------ 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index 60f82b10e5..d5fddf6538 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -1386,53 +1386,8 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } //----------------------- - // fill the Vertex NTuple + // fill the Vertex NTuple and fixed NaN placeholders //----------------------- - /* bool doit = true; - if (_ntp_vertex && doit) - { - if (Verbosity() > 1) - { - std::cout << "Filling ntp_vertex " << std::endl; - std::cout << "start vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; - _timer->restart(); - } - float fx_vertex[n_vertex::vtxsize]; - for (float& i : fx_vertex) - { - i = 0; - } - // SvtxVertexMap* vertexmap = nullptr; - // vertexmap = findNode::getClass(topNode, "SvtxVertexMapActs"); // Acts vertices - float vx = std::numeric_limits::quiet_NaN(); - float vy = std::numeric_limits::quiet_NaN(); - float vz = std::numeric_limits::quiet_NaN(); - float ntracks = std::numeric_limits::quiet_NaN(); - fx_vertex[vtxnvx] = vx; - fx_vertex[vtxnvy] = vy; - fx_vertex[vtxnvz] = vz; - fx_vertex[vtxnntracks] = ntracks; - if (Verbosity() > 1) - { - std::cout << " adding vertex data " << std::endl; - } - float* vertex_data = new float[((int) (n_info::infosize)) + n_event::evsize + n_vertex::vtxsize]; - std::copy(fx_event, fx_event + n_event::evsize, vertex_data); - std::copy(fx_vertex, fx_vertex + n_vertex::vtxsize, vertex_data + n_event::evsize); - std::copy(fx_info, fx_info + ((int) (n_info::infosize)), vertex_data + n_event::evsize + n_vertex::vtxsize); - _ntp_vertex->Fill(vertex_data); - delete[] vertex_data; - - } - if (Verbosity() > 1) - { - _timer->stop(); - std::cout << "vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; - }*/ - - //----------------------- - // Fix Nan placeholders for vertex variables - // //----------------------- bool doit = true; if (_ntp_vertex && doit) { From 6fe5c7409744964004a0bcd4e19bb774eab3cfcf Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 21 Apr 2026 13:51:21 -0400 Subject: [PATCH 476/866] Migrating the coderabbit setting from webUI to code --- .coderabbit.yaml | 142 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000000..bc24682a97 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,142 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +tone_instructions: >- + Be respectful, concise, and educational. Assume physicist contributors. Prioritize correctness and + safety. Ignore purely stylistic issues and Minor/Trivial/Info items. +reviews: + high_level_summary_instructions: >- + Write a concise PR summary for a scientific collaboration. + + Include: + + - Motivation / context + + - Key changes (bullets) + + - Potential risk areas (IO format changes, reconstruction behavior changes, thread-safety, + performance) + + - Possible future improvements + + + Add an emphasis that AI can make mistakes and use best judgment when reading + estimate_code_review_effort: false + suggested_labels: false + suggested_reviewers: false + in_progress_fortune: false + poem: false + enable_prompt_for_ai_agents: false + path_filters: + - '!**/build/**' + - '!**/install/**' + - '!**/*.root' + - '!**/*.pdf' + - '!**/*.png' + - '!**/*.jpg' + - '!**/*.gif' + - '!**/*.zip' + - '!**/*.tar.gz' + - '!**/*.so' + - '!**/*.dylib' + - '!**/*.a' + - '!**/*.o' + path_instructions: + - path: '**/*.{h,hpp,hxx,hh}' + instructions: >- + Focus on API clarity/stability, ownership semantics (RAII), and avoiding raw new/delete. + + If interfaces change, ask for compatibility notes and any needed downstream updates. + + + Only raise Critical or Major findings. Do not post minor style, formatting, naming, or + “nice-to-have” refactors. + - path: '**/*.{cc,cpp,cxx,c}' + instructions: >- + Prioritize correctness, memory safety, error handling, and thread-safety. + + Flag hidden global state, non-const singletons, and unclear lifetime assumptions. + + + Only raise Critical or Major findings. Do not post minor style, formatting, naming, or + “nice-to-have” refactors. + - path: '**/*.C' + instructions: Do NOT review these files + - path: '**/CMakeLists.txt' + instructions: | + Check for modern CMake target usage, correct scoping, and avoiding global flags. + auto_review: + ignore_title_keywords: + - WIP + - DRAFT + - DO NOT MERGE + - RFC + finishing_touches: + unit_tests: + enabled: false + pre_merge_checks: + docstrings: + mode: 'off' + title: + mode: 'off' + description: + mode: 'off' + issue_assessment: + mode: 'off' + custom_checks: + - mode: 'off' + name: Test plan present + instructions: > + Check that the PR description includes a "Testing" or "Test Plan" section with at least + one bullet. + + Accept: unit test, integration test, or example macro/validation command. + - mode: 'off' + name: Physics/reco impact noted (if applicable) + instructions: > + If the PR changes reconstruction outputs, calibration constants, or simulation behavior, + + ensure the description states expected analysis impact and whether reprocessing is + required. + tools: + swiftlint: + enabled: false + phpstan: + enabled: false + phpmd: + enabled: false + golangci-lint: + enabled: false + detekt: + enabled: false + pmd: + enabled: false +chat: + art: false + integrations: + jira: + usage: disabled + linear: + usage: disabled +knowledge_base: + code_guidelines: + filePatterns: + - CONTRIBUTING.md + - docs/** + - .github/*.md + learnings: + scope: global + jira: + usage: disabled +code_generation: + docstrings: + path_instructions: + - path: '**/*.{h,hpp,hh,hxx,cc,cpp,cxx,C}' + instructions: >- + Use Doxygen-style documentation, Link to example caller function if available. ONLY add + docstrings where none exist. Do NOT modify, rewrite, or reformat any existing + docstrings/comments. If a function already has a docstring (even if incomplete), leave it + unchanged. +issue_enrichment: + planning: + enabled: false + auto_planning: + enabled: false From ad8c400b45eb060180c344239ba733c2e7209adf Mon Sep 17 00:00:00 2001 From: cdean-github Date: Wed, 22 Apr 2026 09:22:17 -0400 Subject: [PATCH 477/866] CD: CR sugggestions --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 2 ++ .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 14 +++++++------- .../packages/trackreco/PHSimpleVertexFinder.cc | 15 +++++++++------ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 83b2e9fed8..9e957ad7f0 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -390,6 +390,8 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_reco_track_eta[index] = m_dst_track->get_eta(); m_reco_track_phi[index] = m_dst_track->get_phi(); m_reco_track_chi2nDoF[index] = m_dst_track->get_chisq() / m_dst_track->get_ndf(); + m_reco_track_silicon_seeds[index] = 0; + m_reco_track_tpc_seeds[index] = 0; for (auto state_iter = m_dst_track->begin_states(); state_iter != m_dst_track->end_states(); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 526def19a5..1b597afcef 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -194,18 +194,17 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) { std::cout << "KFParticle: EventHeader or GL1 packet not found" << std::endl; } - m_this_event_bco = -1; - m_last_event_bco = -1; - m_prev_event_bco = -1; - m_prev_runNumber = -1; - m_prev_eventNumber = -1; + m_this_event_bco = 0; + m_last_event_bco = 0; + m_prev_event_bco = 0; + m_prev_runNumber = 0; + m_prev_eventNumber = 0; } // End BCO matching here SvtxTrackMap *check_trackmap = findNode::getClass(topNode, m_trk_map_node_name); - multiplicity = check_trackmap->size(); - if (check_trackmap->empty()) + if (!check_trackmap || check_trackmap->empty()) { if (Verbosity() >= VERBOSITY_SOME) { @@ -213,6 +212,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; } + multiplicity = check_trackmap->size(); if (!m_use_fake_pv) { diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index ccd2bde57d..c93f3c198c 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -515,7 +515,7 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx && !passClusterRequirement(tr1)) + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) { continue; } @@ -533,7 +533,7 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx && !passClusterRequirement(tr2)) + if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) { continue; } @@ -574,7 +574,9 @@ void PHSimpleVertexFinder::checkDCAsZF(SvtxTrackMap *track_map) // tr1->identify(); TrackSeed *siliconseed = tr1->get_silicon_seed(); - if ((_require_mvtx || _require_intt) && !siliconseed) + const bool needs_mvtx_seed = _require_mvtx && _nmvtx_required > 0; + const bool needs_intt_seed = _require_intt && _nintt_required > 0; + if ((needs_mvtx_seed || needs_intt_seed) && !siliconseed) { continue; } @@ -760,7 +762,7 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx && !passClusterRequirement(tr1)) + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) { continue; } @@ -778,7 +780,7 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx && !passClusterRequirement(tr2)) + if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) { continue; } @@ -1265,7 +1267,8 @@ bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, const std::s unsigned int _nclus_required = type == "MVTX" ? _nmvtx_required : _nintt_required; TrackSeed *siliconseed = track->get_silicon_seed(); - if (!siliconseed) + bool needs_clus = _nclus_required > 0; + if (needs_clus && !siliconseed) { return pass; } From 14324c07b823bca16b246db17a8ac8521caf25c7 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Wed, 22 Apr 2026 09:43:21 -0400 Subject: [PATCH 478/866] CD: Clang tidy request --- .../packages/HFTrackEfficiency/HFTrackEfficiency.cc | 1 + offline/packages/trackreco/PHSimpleVertexFinder.cc | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 9e957ad7f0..c5f4c4e33b 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -401,6 +401,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) if (tstate->get_pathlength() != 0) // The first track state is an extrapolation so has no cluster { auto stateckey = tstate->get_cluskey(); + if (stateckey == TrkrDefs::CLUSKEYMAX) continue; uint8_t id = TrkrDefs::getTrkrId(stateckey); switch (id) diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index c93f3c198c..954e790ba6 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -1260,19 +1260,22 @@ bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, const std::s { std::cout << "type " << type << " was not recognised" << std::endl; } - return pass; + return false; } - unsigned int nclus = 0; unsigned int _nclus_required = type == "MVTX" ? _nmvtx_required : _nintt_required; + if (_nclus_required == 0) + { + return true; + } TrackSeed *siliconseed = track->get_silicon_seed(); - bool needs_clus = _nclus_required > 0; - if (needs_clus && !siliconseed) + if (!siliconseed) { - return pass; + return false; } + unsigned int nclus = 0; for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) { uint8_t trkrId = type == "MVTX" ? TrkrDefs::mvtxId : TrkrDefs::inttId; From 091502604916ed95144b085068b4ff2186689157 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Thu, 23 Apr 2026 09:31:44 -0400 Subject: [PATCH 479/866] CD: Jenkins corrected codeRabbit --- offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index c5f4c4e33b..4797d957ec 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -401,7 +401,10 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) if (tstate->get_pathlength() != 0) // The first track state is an extrapolation so has no cluster { auto stateckey = tstate->get_cluskey(); - if (stateckey == TrkrDefs::CLUSKEYMAX) continue; + if (stateckey == TrkrDefs::CLUSKEYMAX) + { + continue; + } uint8_t id = TrkrDefs::getTrkrId(stateckey); switch (id) From d822763bc0f64b6e282d5751b4ff476113b5c9ed Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 23 Apr 2026 09:59:40 -0400 Subject: [PATCH 480/866] add double interaction for pythia8 5GeV jets --- offline/framework/frog/CreateFileList.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index ce6e662ae3..6e7e0a463a 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -995,6 +995,10 @@ { $embedok = 1; $filenamestring = "pythia8_Jet5"; + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) From 9f9b593e69b2b1f762ca0d6f452de43e512f92fb Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 25 Apr 2026 18:33:00 -0400 Subject: [PATCH 481/866] add 60,80 and Detroit to double --- offline/framework/frog/CreateFileList.pl | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 6e7e0a463a..d169471a62 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -91,7 +91,7 @@ ); my %pileupdesc = ( - "1" => "50kHz for Au+Au, 3MHz for p+p (default)", + "1" => "50kHz for Au+Au, 3MHz for p+p, 220kHz for O+O (default)", "2" => "25kHz for Au+Au", "3" => "10kHz for Au+Au", "4" => "1MHz for pp 100us streaming", @@ -188,6 +188,7 @@ $AuAu_pileupstring = sprintf("_50kHz%s",$AuAu_bkgpileup); $pp_pileupstring = sprintf("_3MHz"); $pAu_pileupstring = sprintf("_500kHz%s",$pAu_bkgpileup); + $OO_pileupstring = sprintf("_220kHz%s",$OO_bkgpileup); } elsif ($pileup == 2) { @@ -661,6 +662,11 @@ { $embedok = 1; $filenamestring = "pythia8_Detroit"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -1046,6 +1052,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet60"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -1416,6 +1427,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet80"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) From 540af5ecac7e490462779dc891baa1ccf0abcae7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 27 Apr 2026 11:40:43 -0400 Subject: [PATCH 482/866] fix 5GeV selection --- offline/framework/frog/CreateFileList.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index d169471a62..316bfb0fa8 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -1001,6 +1001,7 @@ { $embedok = 1; $filenamestring = "pythia8_Jet5"; + if (defined $double) { $doubleok = 1; $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); @@ -1423,7 +1424,7 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } - elsif ($prodtype == 49) + elsif ($prodtype == 49) { $embedok = 1; $filenamestring = "pythia8_Jet80"; From e92fee96d740df96473bd538c87a4d81856fd32b Mon Sep 17 00:00:00 2001 From: rosstom Date: Wed, 29 Apr 2026 16:56:25 -0400 Subject: [PATCH 483/866] Merge with local changes --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 79 ++++++++++++++++- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 6 +- .../KFParticle_eventReconstruction.cc | 86 +++++++++++++++++-- .../KFParticle_sPHENIX/KFParticle_nTuple.cc | 16 +++- .../KFParticle_sPHENIX/KFParticle_sPHENIX.cc | 10 ++- offline/packages/decayfinder/DecayFinder.cc | 49 +++++++++-- offline/packages/decayfinder/DecayFinder.h | 2 +- 7 files changed, 226 insertions(+), 22 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 09de461fe9..7e5283ffe1 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -232,6 +232,13 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) int index = -1; + std::cout << "Particle truth barcodes and PIDs" << std::endl; + std::cout << "decay[0].first.second: " << decay[0].first.second << ", decay[0].second: " << decay[0].second << std::endl; + std::cout << "decay[1].first.second: " << decay[1].first.second << ", decay[1].second: " << decay[1].second << std::endl; + std::cout << "decay[2].first.second: " << decay[2].first.second << ", decay[2].second: " << decay[2].second << std::endl; + std::cout << "decay[3].first.second: " << decay[3].first.second << ", decay[3].second: " << decay[3].second << std::endl; + std::cout << "decay[4].first.second: " << decay[4].first.second << ", decay[4].second: " << decay[4].second << std::endl; + for (unsigned int i = 1; i < decay.size(); ++i) { m_dst_track = nullptr; @@ -241,6 +248,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) std::abs(decay[i].second)) != std::end(trackableParticles)) { ++index; + if (theEvent && decay[i].first.second > -1) { HepMC::GenParticle *daughterHepMC = theEvent->barcode_to_particle(decay[i].first.second); @@ -297,8 +305,74 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) continue; } - if (motherG4->get_pid() == decay[0].second && motherG4->get_barcode() == decay[0].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second) + if (motherG4->get_pid() == decay[0].second && motherG4->get_barcode() == decay[0].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second && m_nDaughters == 2) + { + if (Verbosity() >= VERBOSITY_MORE || true) // fix later + { + daughterG4->identify(); + } + + m_is_primary = m_truthInfo->is_sPHENIX_primary(motherG4); + + CLHEP::Hep3Vector *mother3Vector = new CLHEP::Hep3Vector(motherG4->get_px(), motherG4->get_py(), motherG4->get_pz()); + motherTrueLV->setVectM((*mother3Vector), getParticleMass(decay[0].second)); + m_true_mother_pT = motherTrueLV->perp(); + m_true_mother_p = mother3Vector->mag(); + m_true_mother_eta = motherTrueLV->pseudoRapidity(); + m_true_mother_phi = motherTrueLV->phi(); + + PHG4VtxPoint *thisVtx = m_truthInfo->GetVtx(motherG4->get_vtx_id()); + m_primary_vtx_x = thisVtx->get_x(); + m_primary_vtx_y = thisVtx->get_y(); + m_primary_vtx_z = thisVtx->get_z(); + + daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterG4->get_px(), daughterG4->get_py(), daughterG4->get_pz()), getParticleMass(decay[i].second)); + daughterSumTrueLV += *daughterTrueLV; + + // Now get the decay vertex position + thisVtx = m_truthInfo->GetVtx(daughterG4->get_vtx_id()); + m_secondary_vtx_x = thisVtx->get_x(); + m_secondary_vtx_y = thisVtx->get_y(); + m_secondary_vtx_z = thisVtx->get_z(); + + m_true_track_PID[index] = daughterG4->get_pid(); + truth_ID = daughterG4->get_track_id(); + + delete mother3Vector; + } + else if (m_nDaughters == 3) { + if (i != 4 && motherG4->get_pid() == decay[3].second && motherG4->get_barcode() == decay[3].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second) + { + PHG4Particle *motherG4_temp = nullptr; + if (motherG4->get_parent_id() != 0) + { + motherG4_temp = m_truthInfo->GetParticle(motherG4->get_parent_id()); + } + else + { + continue; + } + + if (motherG4_temp->get_pid() == decay[0].second && motherG4_temp->get_barcode() == decay[0].first.second) + { + motherG4 = motherG4_temp; + } + else + { + continue; + } + } + else if (i != 4) + { + continue; + } + + if (i==4 && !(motherG4->get_pid() == decay[0].second && motherG4->get_barcode() == decay[0].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second)) + { + continue; + } + if (Verbosity() >= VERBOSITY_MORE) { daughterG4->identify(); @@ -327,10 +401,11 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_y = thisVtx->get_y(); m_secondary_vtx_z = thisVtx->get_z(); - m_true_track_PID[index] = daughterG4->get_pid(); + m_true_track_PID[index] = daughterG4->get_pid(); truth_ID = daughterG4->get_track_id(); delete mother3Vector; + break; } } } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 9bb76608ee..15312138a1 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -986,7 +986,7 @@ std::tuple KFParticle_Tools::getCombination(KFParticle vDaught isGoodCandidate = checkTrackAndVertexMatch(vDaughters, nTracks, vertex); } - if (isGoodCandidate) + if (isGoodCandidate || m_use_truth_pv) { constrainToVertex(candidate, isGoodCandidate, vertex); } @@ -1257,6 +1257,10 @@ bool KFParticle_Tools::checkTrackAndVertexMatch(KFParticle vDaughters[], int nTr m_dst_mbdvertex = m_dst_mbdvertexmap->get(vertex.Id()); vertexCrossing = m_dst_mbdvertex->get_beam_crossing(); } + else if (m_use_truth_pv) + { + vertexCrossing = ; + } else { m_dst_vertex = m_dst_vertexmap->get(vertex.Id()); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index 64d6b932fa..c09cbc88d3 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -31,10 +31,17 @@ //sPHENIX stuff #include +#include +#include +#include +#include // KFParticle stuff #include +#include +#include + #include #include #include // for begin, distance, end @@ -52,6 +59,7 @@ KFParticle_eventReconstruction::KFParticle_eventReconstruction() : m_constrain_to_vertex(false) , m_constrain_int_mass(false) , m_use_fake_pv(false) + , m_use_truth_pv(false) { } @@ -65,6 +73,14 @@ void KFParticle_eventReconstruction::createDecay(PHCompositeNode* topNode, std:: { primaryVertices.push_back(createFakePV()); } + else if (m_use_truth_pv) + { + std::vector KFP_PVs = createTruthPV(topNode); + for (const auto& pv: KFP_PVs) + { + primaryVertices.push_back(pv); + } + } else { primaryVertices = makeAllPrimaryVertices(topNode, m_vtx_map_node_name); @@ -74,15 +90,19 @@ void KFParticle_eventReconstruction::createDecay(PHCompositeNode* topNode, std:: nPVs = primaryVertices.size(); - std::vector goodTrackIndex = findAllGoodTracks(daughterParticles, primaryVertices); - - if (!m_has_intermediates) + if (!m_use_truth_pv || nPVs != 0) { - buildBasicChain(selectedMother, selectedVertex, selectedDaughters, daughterParticles, goodTrackIndex, primaryVertices, topNode); - } - else - { - buildChain(selectedMother, selectedVertex, selectedDaughters, selectedIntermediates, daughterParticles, goodTrackIndex, primaryVertices, topNode); + std::vector goodTrackIndex = findAllGoodTracks(daughterParticles, primaryVertices); + + if (!m_has_intermediates) + { + buildBasicChain(selectedMother, selectedVertex, selectedDaughters, daughterParticles, goodTrackIndex, primaryVertices, topNode); + } + else + { + std::cout << "Gets to buildChain" << std::endl; + buildChain(selectedMother, selectedVertex, selectedDaughters, selectedIntermediates, daughterParticles, goodTrackIndex, primaryVertices, topNode); + } } } @@ -590,3 +610,53 @@ KFParticle KFParticle_eventReconstruction::createFakePV() kfp_vertex.SetId(0); return kfp_vertex; } + +std::vector KFParticle_eventReconstruction::createTruthPV(PHCompositeNode* topNode) +{ + std::vector kfp_vertex = {}; + + PHG4InEvent *ineve = findNode::getClass(topNode, "PHG4INEVENT"); + if (!ineve) + { + std::cout << PHWHERE << "no PHG4INEVENT node" << std::endl; + return kfp_vertex; + } + + auto vtxRange = ineve->GetVertices(); + // find the PV + std::vector primaryVtx = {}; + for (auto it = vtxRange.first; it != vtxRange.second; ++it) + { + if (it->first == 1) + { + primaryVtx.push_back(it->second); + } + } + + if (primaryVtx.size() == 0) + { + std::cerr << "getPrimaryVertex: No primary vertex found!" << std::endl; + return kfp_vertex; // return default empty vertex + } + + for (const auto& v : primaryVtx) + { + float pos[3] = { + static_cast(v->get_x()), + static_cast(v->get_y()), + static_cast(v->get_z()) + }; + float f_vertexParameters[6] = {pos[0], pos[1], pos[2], 0, 0, 0}; + + float f_vertexCovariance[21] = {0}; + + KFParticle kfp_v; + kfp_v.Create(f_vertexParameters, f_vertexCovariance, 0, -1); + kfp_v.NDF() = 0; + kfp_v.Chi2() = 0; + kfp_v.SetId(0); + kfp_vertex.push_back(kfp_v); + } + + return kfp_vertex; +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index b3b119e4f6..304b155674 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -270,6 +270,14 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) std::string dca_branch_name_xy = dca_branch_name + "_xy"; std::string dca_leaf_name_xy = dca_branch_name_xy + "/F"; m_tree->Branch(dca_branch_name_xy.c_str(), &m_daughter_dca_xy[iter], dca_leaf_name_xy.c_str()); + + std::string dca_sig_branch_name = "track_" + std::to_string(i + 1) + "_track_" + std::to_string(j + 1) + "_DCA_sig"; + std::string dca_sig_leaf_name = dca_sig_branch_name + "/F"; + m_tree->Branch(dca_sig_branch_name.c_str(), &m_daughter_dca_sig[iter], dca_sig_leaf_name.c_str()); + + std::string dca_sig_branch_name_xy = dca_sig_branch_name + "_xy"; + std::string dca_sig_leaf_name_xy = dca_sig_branch_name_xy + "/F"; + m_tree->Branch(dca_sig_branch_name_xy.c_str(), &m_daughter_dca_sig_xy[iter], dca_sig_leaf_name_xy.c_str()); ++iter; } @@ -496,6 +504,8 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_calculated_daughter_ipchi2[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); m_calculated_daughter_ip_err[i] = m_calculated_daughter_ip[i] / std::sqrt(m_calculated_daughter_ipchi2[i]); m_calculated_daughter_ip_xy[i] = daughterArray[i].GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_daughter_PV_dca_sig[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); + m_calculated_daughter_PV_dca_xy_sig[i] = daughterArray[i].GetDeviationFromVertexXY(vertex_fillbranch); } m_calculated_daughter_x[i] = daughterArray[i].GetX(); m_calculated_daughter_y[i] = daughterArray[i].GetY(); @@ -596,6 +606,8 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, { m_daughter_dca[iter] = daughterArray[i].GetDistanceFromParticle(daughterArray[j]); m_daughter_dca_xy[iter] = daughterArray[i].GetDistanceFromParticleXY(daughterArray[j]); + m_daughter_dca_sig[iter] = daughterArray[i].GetDeviationFromParticle(daughterArray[j]); + m_daughter_dca_sig_xy[iter] = daughterArray[i].GetDeviationFromParticleXY(daughterArray[j]); ++iter; } } @@ -631,7 +643,7 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, // it only makes sense to calculate PVID for non-fake vertex // (this otherwise crashes if m_use_fake_pv_nTuple is true in an event with no real vertices) - if (m_use_fake_pv_nTuple) + if (m_use_fake_pv_nTuple || m_use_truth_pv_nTuple) { m_calculated_vertex_ID = -100; // error value returned by getPVID } @@ -650,7 +662,7 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, kfpTupleTools.getTracksFromBC(topNode, m_calculated_daughter_bunch_crossing[0], m_vtx_map_node_name_nTuple, m_multiplicity, m_nPVs); // cannot retrieve vertex map info from fake PV, hence the second condition - if (m_constrain_to_vertex_nTuple && !m_use_fake_pv_nTuple) + if (m_constrain_to_vertex_nTuple && !m_use_fake_pv_nTuple && !m_use_truth_pv_nTuple) { m_nTracksOfVertex = kfpTupleTools.getTracksFromVertex(topNode, vertex_fillbranch, m_vtx_map_node_name_nTuple); } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index db46bffafe..cd9e18de8d 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -213,7 +213,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) m_prev_eventNumber = -1; } // End BCO matching here - if (!m_use_fake_pv) + if (!m_use_fake_pv && !m_use_truth_pv) { if (m_use_mbd_vertex) { @@ -242,6 +242,14 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) } createDecay(topNode, mother, vertex_kfparticle, daughters, intermediates, nPVs); + if (m_use_truth_pv && nPVs == 0) + { + if (Verbosity() >= VERBOSITY_SOME) + { + std::cout << "No Truth Vertices Found For This Event, Skipping" << std::endl; + } + return Fun4AllReturnCodes::EVENT_OK; + } if (!m_has_intermediates_sPHENIX) { intermediates = daughters; diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index a3521df780..000b1c4861 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -93,14 +93,14 @@ int DecayFinder::Init(PHCompositeNode* topNode) int DecayFinder::process_event(PHCompositeNode* topNode) { - bool decayFound = findDecay(topNode); + int decayFound = findDecay(topNode); - if (decayFound && m_save_dst && Verbosity() >= VERBOSITY_MORE) + if (decayFound > 0 && m_save_dst && Verbosity() >= VERBOSITY_MORE) { printNode(topNode); } - if (m_triggerOnDecay && !decayFound) + if (m_triggerOnDecay && decayFound < 1) { if (Verbosity() >= VERBOSITY_MORE) { @@ -317,10 +317,10 @@ int DecayFinder::parseDecayDescriptor() * as decays wont enter the HepMC record * need a switch to go to Geant4 record */ -bool DecayFinder::findDecay(PHCompositeNode* topNode) +int DecayFinder::findDecay(PHCompositeNode* topNode) { bool decayWasFound = false; - bool reconstructableDecayWasFound = false; + int reconstructableDecayWasFound = 0; bool aTrackFailedPT = false; bool aTrackFailedETA = false; bool aMotherHasPhoton = false; @@ -384,9 +384,16 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) std::cout << "parent->pdg_id(): " << g4particle->get_pid() << std::endl; } + aTrackFailedPT = false; + aTrackFailedETA = false; + aMotherHasPhoton = false; + aMotherHasPi0 = false; + bool breakOut = false; correctMotherProducts.clear(); decayChain.clear(); + std::cout << __LINE__ << std::endl; + std::cout << "g4particle->get_barcode()" << g4particle->get_barcode() << std::endl; decayChain.emplace_back(std::make_pair(g4particle->get_primary_id(), g4particle->get_barcode()), g4particle->get_pid()); searchGeant4Record(g4particle->get_barcode(), g4particle->get_pid(), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts); @@ -416,7 +423,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) else { m_nCandReconstructable += 1; - reconstructableDecayWasFound = true; + ++reconstructableDecayWasFound; if (m_save_dst) { fillDecayNode(topNode, decayChain); @@ -465,18 +472,27 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) std::cout << "parent->pdg_id(): " << (*p)->pdg_id() << std::endl; } + aTrackFailedPT = false; + aTrackFailedETA = false; + aMotherHasPhoton = false; + aMotherHasPi0 = false; + bool breakOut = false; correctMotherProducts.clear(); decayChain.clear(); + std::cout << __LINE__ << std::endl; + std::cout << "(*p)->barcode()" << (*p)->barcode() << std::endl; decayChain.emplace_back(std::make_pair(m_genevt->get_embedding_id(), (*p)->barcode()), (*p)->pdg_id()); // Make sure that the mother has a decay in our record if (!(*p)->end_vertex()) // Mother has no end vertex, decay volume was limited { + std::cout << "Searching G4 Record" << std::endl; searchGeant4Record((*p)->barcode(), (*p)->pdg_id(), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts); } else { + std::cout << "Searching HepMC Record" << std::endl; searchHepMCRecord((*p), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts); } @@ -505,7 +521,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) else { m_nCandReconstructable += 1; - reconstructableDecayWasFound = true; + ++reconstructableDecayWasFound; if (m_save_dst) { fillDecayNode(topNode, decayChain); @@ -611,6 +627,8 @@ void DecayFinder::searchHepMCRecord(HepMC::GenParticle* particle, std::vectorbarcode()" << (*children)->barcode() << std::endl; searchGeant4Record((*children)->barcode(), (*children)->pdg_id(), positive_requiredIntermediateDecayProducts, breakLoop, hasPhoton, hasPi0, failedPT, failedETA, actualIntermediateDecayProducts); @@ -647,6 +665,8 @@ void DecayFinder::searchHepMCRecord(HepMC::GenParticle* particle, std::vectorend_vertex()) { + std::cout << __LINE__ << std::endl; + std::cout << "(*children)->barcode()" << (*children)->barcode() << std::endl; searchGeant4Record((*children)->barcode(), (*children)->pdg_id(), decayProducts, breakLoop, hasPhoton, hasPi0, failedPT, failedETA, actualDecayProducts); } @@ -659,6 +679,8 @@ void DecayFinder::searchHepMCRecord(HepMC::GenParticle* particle, std::vectorpdg_id()); + std::cout << __LINE__ << std::endl; + std::cout << "(*grandchildren)->barcode()" << (*grandchildren)->barcode() << std::endl; decayChain.emplace_back(std::make_pair(m_genevt->get_embedding_id(), (*grandchildren)->barcode()), (*grandchildren)->pdg_id()); } } @@ -678,6 +700,7 @@ void DecayFinder::searchHepMCRecord(HepMC::GenParticle* particle, std::vector decayProducts, bool& breakLoop, bool& hasPhoton, bool& hasPi0, bool& failedPT, bool& failedETA, std::vector& actualDecayProducts) { + std::cout << "searchGeant4Record barcode: " << barcode << std::endl; PHG4TruthInfoContainer::ConstRange range = m_truthinfo->GetParticleRange(); for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { @@ -699,6 +722,8 @@ void DecayFinder::searchGeant4Record(int barcode, int pid, std::vector deca } if (mother->get_barcode() == barcode && abs(mother->get_pid()) == abs(pid)) { + std::cout << __LINE__ << std::endl; + std::cout << "mother->get_barcode()" << mother->get_barcode() << std::endl; int particleID = g4particle->get_pid(); if (Verbosity() >= VERBOSITY_MAX) { @@ -731,6 +756,8 @@ void DecayFinder::searchGeant4Record(int barcode, int pid, std::vector deca } actualDecayProducts.push_back(particleID); int embedding_id = m_geneventmap ? m_genevt->get_embedding_id() : g4particle->get_primary_id(); + std::cout << __LINE__ << std::endl; + std::cout << "g4particle->get_barcode()" << g4particle->get_barcode() << std::endl; decayChain.emplace_back(std::make_pair(embedding_id, g4particle->get_barcode()), particleID); } } // Now check if it's part of the other resonance list @@ -745,6 +772,8 @@ void DecayFinder::searchGeant4Record(int barcode, int pid, std::vector deca { std::cout << "This is a resonance to investigate further" << std::endl; } + std::cout << __LINE__ << std::endl; + std::cout << "g4particle->get_barcode()" << g4particle->get_barcode() << std::endl; searchGeant4Record(g4particle->get_barcode(), g4particle->get_pid(), decayProducts, breakLoop, hasPhoton, hasPi0, failedPT, failedETA, actualDecayProducts); } @@ -830,6 +859,8 @@ bool DecayFinder::checkIfCorrectHepMCParticle(HepMC::GenParticle* particle, bool } actualIntermediateDecayProducts.push_back((*greatgrandchildren)->pdg_id()); + std::cout << __LINE__ << std::endl; + std::cout << "(*greatgrandchildren)->barcode()" << (*greatgrandchildren)->barcode() << std::endl; decayChain.emplace_back(std::make_pair(m_genevt->get_embedding_id(), (*greatgrandchildren)->barcode()), (*greatgrandchildren)->pdg_id()); ++m_intermediate_product_counter; @@ -870,6 +901,8 @@ bool DecayFinder::checkIfCorrectHepMCParticle(HepMC::GenParticle* particle, bool else { actualIntermediateDecayProducts.push_back((*grandchildren)->pdg_id()); + std::cout << __LINE__ << std::endl; + std::cout << "(*grandchildren)->barcode()" << (*grandchildren)->barcode() << std::endl; decayChain.emplace_back(std::make_pair(m_genevt->get_embedding_id(), (*grandchildren)->barcode()), (*grandchildren)->pdg_id()); ++m_intermediate_product_counter; @@ -988,6 +1021,8 @@ bool DecayFinder::checkIfCorrectGeant4Particle(PHG4Particle* particle, bool& has } bool fakeBreak = false; + std::cout << __LINE__ << std::endl; + std::cout << "particle->get_barcode()" << particle->get_barcode() << std::endl; searchGeant4Record(particle->get_barcode(), particle->get_pid(), positive_intermediateDecayProducts, fakeBreak, hasPhoton, hasPi0, trackFailedPT, trackFailedETA, actualIntermediateDecayProducts); diff --git a/offline/packages/decayfinder/DecayFinder.h b/offline/packages/decayfinder/DecayFinder.h index bd893546a1..3605733e9f 100644 --- a/offline/packages/decayfinder/DecayFinder.h +++ b/offline/packages/decayfinder/DecayFinder.h @@ -42,7 +42,7 @@ class DecayFinder : public SubsysReco int parseDecayDescriptor(); - bool findDecay(PHCompositeNode *topNode); + int findDecay(PHCompositeNode *topNode); bool findParticle(const std::string &particle); From 18df402dd212560e1a8b94d92ceac40735553cb7 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 30 Apr 2026 15:34:18 -0400 Subject: [PATCH 484/866] handle missing gl1 packet --- offline/packages/bcolumicount/BcoLumiReco.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc index bf8ea87224..eb5b3dd8b7 100644 --- a/offline/packages/bcolumicount/BcoLumiReco.cc +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -77,6 +77,15 @@ int BcoLumiReco::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } Packet *packet = evt->getPacket(14001); + if (!packet) + { + if (Verbosity() > 0) + { + std::cout << "no gl1 packet 14001" << std::endl; + evt->identify(); + } + return Fun4AllReturnCodes::ABORTEVENT; + } uint64_t gtm_bco = packet->lValue(0, "BCO"); if (Verbosity() > 1) { From 80d3dea675e2b0b1994482c397e00582124a1de4 Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 30 Apr 2026 20:12:55 -0400 Subject: [PATCH 485/866] Minor fixes --- .../KFParticle_eventReconstruction.cc | 57 ------------------- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 3 +- offline/packages/decayfinder/DecayFinder.cc | 3 - 3 files changed, 1 insertion(+), 62 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index 9db00ec4d1..3c40fd4e58 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -31,17 +31,10 @@ //sPHENIX stuff #include -#include -#include -#include -#include // KFParticle stuff #include -#include -#include - #include #include #include // for begin, distance, end @@ -615,53 +608,3 @@ KFParticle KFParticle_eventReconstruction::createFakePV() kfp_vertex.SetId(0); return kfp_vertex; } - -std::vector KFParticle_eventReconstruction::createTruthPV(PHCompositeNode* topNode) -{ - std::vector kfp_vertex = {}; - - PHG4InEvent *ineve = findNode::getClass(topNode, "PHG4INEVENT"); - if (!ineve) - { - std::cout << PHWHERE << "no PHG4INEVENT node" << std::endl; - return kfp_vertex; - } - - auto vtxRange = ineve->GetVertices(); - // find the PV - std::vector primaryVtx = {}; - for (auto it = vtxRange.first; it != vtxRange.second; ++it) - { - if (it->first == 1) - { - primaryVtx.push_back(it->second); - } - } - - if (primaryVtx.size() == 0) - { - std::cerr << "getPrimaryVertex: No primary vertex found!" << std::endl; - return kfp_vertex; // return default empty vertex - } - - for (const auto& v : primaryVtx) - { - float pos[3] = { - static_cast(v->get_x()), - static_cast(v->get_y()), - static_cast(v->get_z()) - }; - float f_vertexParameters[6] = {pos[0], pos[1], pos[2], 0, 0, 0}; - - float f_vertexCovariance[21] = {0}; - - KFParticle kfp_v; - kfp_v.Create(f_vertexParameters, f_vertexCovariance, 0, -1); - kfp_v.NDF() = 0; - kfp_v.Chi2() = 0; - kfp_v.SetId(0); - kfp_vertex.push_back(kfp_v); - } - - return kfp_vertex; -} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 46ca9fea8a..a732d59ece 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -253,8 +253,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K { m_use_fake_pv = use_fake; m_use_fake_pv_nTuple = use_fake; - } - + } void allowZeroMassTracks(bool allow = true) { m_allowZeroMassTracks = allow; } void extraolateTracksToSV(bool extrapolate = true) diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index ed66e3bc73..596cce9c63 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -483,12 +483,10 @@ int DecayFinder::findDecay(PHCompositeNode* topNode) // Make sure that the mother has a decay in our record if (!(*p)->end_vertex()) // Mother has no end vertex, decay volume was limited { - std::cout << "Searching G4 Record" << std::endl; searchGeant4Record((*p)->barcode(), (*p)->pdg_id(), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts); } else { - std::cout << "Searching HepMC Record" << std::endl; searchHepMCRecord((*p), positive_motherDecayProducts, breakOut, aMotherHasPhoton, aMotherHasPi0, aTrackFailedPT, aTrackFailedETA, correctMotherProducts); } @@ -690,7 +688,6 @@ void DecayFinder::searchHepMCRecord(HepMC::GenParticle* particle, std::vector decayProducts, bool& breakLoop, bool& hasPhoton, bool& hasPi0, bool& failedPT, bool& failedETA, std::vector& actualDecayProducts) { - std::cout << "searchGeant4Record barcode: " << barcode << std::endl; PHG4TruthInfoContainer::ConstRange range = m_truthinfo->GetParticleRange(); for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { From 55d4b1abf61d12720a0ef7bff3921270c00d6cf4 Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 30 Apr 2026 20:14:16 -0400 Subject: [PATCH 486/866] Last fix --- .../packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h index 2493388bc2..9cbba08a70 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.h @@ -83,7 +83,6 @@ class KFParticle_eventReconstruction : public KFParticle_Tools std::vector possibleVertex); KFParticle createFakePV(); - std::vector createTruthPV(PHCompositeNode* topNode); protected: bool m_constrain_to_vertex; From fd05ef936db2705d1b3bb4afaaa5091f81d3eed7 Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 30 Apr 2026 20:15:47 -0400 Subject: [PATCH 487/866] Last last fix --- offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index a732d59ece..14c282e165 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -253,7 +253,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K { m_use_fake_pv = use_fake; m_use_fake_pv_nTuple = use_fake; - } + } void allowZeroMassTracks(bool allow = true) { m_allowZeroMassTracks = allow; } void extraolateTracksToSV(bool extrapolate = true) From dd98db258886298d85a63a02faedbb2e0eeafe31 Mon Sep 17 00:00:00 2001 From: rosstom Date: Thu, 30 Apr 2026 20:16:35 -0400 Subject: [PATCH 488/866] Last last fix --- offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 14c282e165..0812ed8f14 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -254,6 +254,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K m_use_fake_pv = use_fake; m_use_fake_pv_nTuple = use_fake; } + void allowZeroMassTracks(bool allow = true) { m_allowZeroMassTracks = allow; } void extraolateTracksToSV(bool extrapolate = true) From 6ccc13236ccc3cfc4641c163212d9a3f7876a5b8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 4 May 2026 16:57:52 -0400 Subject: [PATCH 489/866] check if Sumw2() has been called already for histo registration --- offline/framework/fun4all/Fun4AllHistoManager.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4all/Fun4AllHistoManager.cc b/offline/framework/fun4all/Fun4AllHistoManager.cc index f88a59c3b9..dde8c7367a 100644 --- a/offline/framework/fun4all/Fun4AllHistoManager.cc +++ b/offline/framework/fun4all/Fun4AllHistoManager.cc @@ -237,7 +237,11 @@ bool Fun4AllHistoManager::registerHisto(const std::string &hname, TNamed *h1d, c // For histograms, enforce error calculation and propagation if (h1d->InheritsFrom("TH1")) { - static_cast(h1d)->Sumw2();// NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + TH1 *h = static_cast(h1d); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + if (h->GetSumw2N() == 0) + { + h->Sumw2(); + } } return true; From c82520970897772f0200ff6e9246940aaf5d2d1e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 6 May 2026 09:48:34 -0400 Subject: [PATCH 490/866] add eta pt>3GeV --- offline/framework/frog/CreateFileList.pl | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 316bfb0fa8..089e83e6c4 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -87,7 +87,8 @@ "46" => "Herwig Photonjet ptmin = 10 GeV", "47" => "Herwig Photonjet ptmin = 20 GeV", "48" => "JS pythia8 Jet ptmin = 8 GeV", - "49" => "JS pythia8 Jet ptmin = 80 GeV" + "49" => "JS pythia8 Jet ptmin = 80 GeV", + "50" => "JS pythia8 Detroit eta ptmin = 3 GeV" ); my %pileupdesc = ( @@ -1462,6 +1463,39 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 50) + { + $embedok = 1; + $filenamestring = "pythia8_Eta3"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { print "no production type $prodtype\n"; From 157bed5a43cd6ef8ce18239de8f4a06c78b147c9 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 7 May 2026 13:53:21 -0400 Subject: [PATCH 491/866] mods for mbd calib passes to work with waveform fit dsts --- offline/packages/mbd/Makefile.am | 2 + offline/packages/mbd/MbdCalibReco.cc | 800 +++++++++++++++++++++++++++ offline/packages/mbd/MbdCalibReco.h | 77 +++ offline/packages/mbd/MbdEvent.cc | 73 ++- 4 files changed, 942 insertions(+), 10 deletions(-) create mode 100644 offline/packages/mbd/MbdCalibReco.cc create mode 100644 offline/packages/mbd/MbdCalibReco.h diff --git a/offline/packages/mbd/Makefile.am b/offline/packages/mbd/Makefile.am index be588c0adb..af9a9d2598 100644 --- a/offline/packages/mbd/Makefile.am +++ b/offline/packages/mbd/Makefile.am @@ -70,6 +70,7 @@ pkginclude_HEADERS = \ MbdPmtHit.h \ MbdPmtHitV1.h \ MbdPmtSimHitV1.h \ + MbdCalibReco.h \ MbdRawContainer.h \ MbdRawContainerV1.h \ MbdRawContainerV2.h \ @@ -178,6 +179,7 @@ libmbd_io_la_SOURCES = \ MbdSig.cc libmbd_la_SOURCES = \ + MbdCalibReco.cc \ MbdEvent.cc \ MbdCalib.cc \ MbdReco.cc \ diff --git a/offline/packages/mbd/MbdCalibReco.cc b/offline/packages/mbd/MbdCalibReco.cc new file mode 100644 index 0000000000..0d97a0a9d9 --- /dev/null +++ b/offline/packages/mbd/MbdCalibReco.cc @@ -0,0 +1,800 @@ +#include "MbdCalibReco.h" +#include "MbdCalib.h" +#include "MbdDefs.h" +//#include "MbdRawContainer.h" +//#include "MbdRawHit.h" +#include "MbdPmtContainer.h" +#include "MbdPmtHit.h" +#include "MbdOut.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MbdCalibReco::MbdCalibReco(const std::string &name) + : SubsysReco(name) +{ +} + +int MbdCalibReco::Init(PHCompositeNode * /*topNode*/) +{ + _mbdcal = new MbdCalib(); + _mbdcal->Verbosity( Verbosity() ); + return Fun4AllReturnCodes::EVENT_OK; +} + +int MbdCalibReco::InitRun(PHCompositeNode *topNode) +{ + _runheader = findNode::getClass(topNode, "RunHeader"); + if (!_runheader) + { + std::cout << PHWHERE << " RunHeader node not found, will use run number 0" << std::endl; + } + + _runnumber = _runheader ? _runheader->get_RunNumber() : 0; + + // Build run directory path and create it + std::ostringstream oss; + oss << _caldir << "/" << _runnumber; + _rundir = oss.str(); + gSystem->Exec(("mkdir -p " + _rundir).c_str()); + + if (!_cdbtag.empty()) + { + // Download baseline calibrations from CDB + recoConsts::instance()->set_StringFlag("CDB_GLOBALTAG", _cdbtag); + CDBInterface* cdb = CDBInterface::instance(); + std::string url; + + url = cdb->getUrl("MBD_SAMPMAX"); + if (!url.empty()) { _mbdcal->Download_SampMax(url); } + + url = cdb->getUrl("MBD_PED"); + if (!url.empty()) { _mbdcal->Download_Ped(url); } + + url = cdb->getUrl("MBD_TIMECORR"); + if (!url.empty()) { _mbdcal->Download_TimeCorr(url); } + + url = cdb->getUrl("MBD_SLEWCORR"); + if (!url.empty()) { _mbdcal->Download_SlewCorr(url); } + + std::cout << Name() << ": loaded calibrations from CDB tag " << _cdbtag << std::endl; + } + else + { + // Load baseline calibrations from local files if they exist + std::string calfile = _rundir + "/mbd_sampmax.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_SampMax(calfile); + } + calfile = _rundir + "/mbd_ped.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_Ped(calfile); + } + + // Load slew correction for subpass >= 2 + if (_subpass >= 2) + { + calfile = _rundir + "/mbd_slewcorr.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_SlewCorr(calfile); + std::cout << Name() << ": loaded " << calfile << std::endl; + } + else + { + std::cout << Name() << ": WARNING: " << calfile << " not found" << std::endl; + } + } + } + + // Load t0 offsets for subpass >= 1 (always from local files — outputs of previous subpass) + if (_subpass >= 1) + { + std::string prevpass = "pass" + std::to_string(_subpass - 1) + "_"; + + std::string calfile = _rundir + "/" + prevpass + "mbd_tq_t0.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_TQT0(calfile); + std::cout << Name() << ": loaded " << calfile << std::endl; + } + else + { + std::cout << Name() << ": WARNING: " << calfile << " not found" << std::endl; + } + + calfile = _rundir + "/" + prevpass + "mbd_tt_t0.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_TTT0(calfile); + std::cout << Name() << ": loaded " << calfile << std::endl; + } + else + { + std::cout << Name() << ": WARNING: " << calfile << " not found" << std::endl; + } + } + + // Build bitmask of scaled triggers whose names begin with "MBD N&S" + _mbias_trigger_mask = 0xfc00; + + InitHistos(); + + // Open output ROOT file + std::string outfname = _rundir + "/calmbdpass2." + std::to_string(_subpass); + if (_subpass == 0) + { + outfname += "_time-" + std::to_string(_runnumber) + ".root"; + } + else if (_subpass == 1 || _subpass == 2) + { + outfname += "_slew-" + std::to_string(_runnumber) + ".root"; + } + else + { + outfname += "_q-" + std::to_string(_runnumber) + ".root"; + } + _outfile = std::make_unique(outfname.c_str(), "RECREATE"); + std::cout << Name() << ": output file " << outfname << std::endl; + + return Fun4AllReturnCodes::EVENT_OK; +} + +int MbdCalibReco::getNodes(PHCompositeNode *topNode) +{ + _evtheader = findNode::getClass(topNode, "EventHeader"); + if (!_evtheader) + { + std::cout << PHWHERE << " EvtHeader not found, will use run number 0" << std::endl; + } + + _gl1packet = findNode::getClass(topNode,14001); + if (!_gl1packet) + { + _gl1packet = findNode::getClass(topNode, "GL1Packet"); + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " GL1Packet not found" << std::endl; + } + } + + /* + _mbdraws = findNode::getClass(topNode, "MbdRawContainer"); + if (!_mbdraws) + { + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " MbdRawContainer not found" << std::endl; + } + } + */ + + _mbdpmts = findNode::getClass(topNode, "MbdPmtContainer"); + if (!_mbdpmts) + { + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " MbdPmtContainer not found" << std::endl; + } + } + + _mbdout = findNode::getClass(topNode, "MbdOut"); + if (!_mbdout) + { + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " MbdOut not found" << std::endl; + } + } + + _mbdgeom = findNode::getClass(topNode, "MbdGeom"); + if (!_mbdgeom) + { + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " MbdGeom not found" << std::endl; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void MbdCalibReco::InitHistos() +{ + // Histograms must not be associated with the output TFile at creation + // time (InitRun happens before _outfile is opened above, but we call + // InitHistos before opening the file, so ROOT's current directory is + // gROOT or whichever file is current from the framework). + gROOT->cd(); + + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + std::string sn = std::to_string(ipmt); + + h_tt[ipmt] = new TH1F(("h_tt" + sn).c_str(), ("tt" + sn).c_str(), 7000, -30., 30.); + h_tt[ipmt]->SetXTitle("ns"); + + h_tq[ipmt] = new TH1F(("h_tq" + sn).c_str(), ("tq" + sn).c_str(), 7000, -150., 31. * 17.7623); + h_tq[ipmt]->SetXTitle("ns"); + + h_qp[ipmt] = new TH1F(("h_q" + sn).c_str(), ("q" + sn).c_str(), 3000, -100., 14900.); + h_qp[ipmt]->SetXTitle("ADC"); + + if (_subpass >= 1) + { + h2_slew[ipmt] = new TH2F(("h2_slew" + sn).c_str(), ("slew curve, ch " + sn).c_str(), 4000, -0.5, 16000. - 0.5, 1100, -5., 6.); + h2_slew[ipmt]->SetXTitle("ADC"); + h2_slew[ipmt]->SetYTitle("#Delta T (ns)"); + } + else + { + h2_slew[ipmt] = nullptr; + } + } + + h2_tt = new TH2F("h2_tt", "ch vs tt", 900, -150., 150., MbdDefs::MBD_N_PMT, -0.5, MbdDefs::MBD_N_PMT - 0.5); + h2_tt->SetXTitle("tt [ns]"); + h2_tt->SetYTitle("pmt ch"); + + h2_tq = new TH2F("h2_tq", "ch vs tq", 900, -150., 150., MbdDefs::MBD_N_PMT, -0.5, MbdDefs::MBD_N_PMT - 0.5); + h2_tq->SetXTitle("tq [ns]"); + h2_tq->SetYTitle("pmt ch"); +} + +int MbdCalibReco::process_event(PHCompositeNode *topNode) +{ + getNodes(topNode); + + // Require a scaled "MBD N&S" trigger + if (_mbias_trigger_mask != 0) + { + uint64_t strig = _gl1packet->getScaledVector(); // scaled trigger only + if ( (strig&_mbias_trigger_mask)==0 ) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + } + + // Per-event arrays for corrected times + /* + std::array ttcorr{}; + std::array tqcorr{}; + std::array adc_arr{}; + ttcorr.fill(std::numeric_limits::quiet_NaN()); + tqcorr.fill(std::numeric_limits::quiet_NaN()); + adc_arr.fill(0); + */ + + std::array armtime{}; + armtime.fill(0); + std::array nhit{}; + nhit.fill(0); + + Float_t zvtx = _mbdout->get_zvtx(); + // Vertex cut for subpass >= 1 + if ( _subpass >= 1 ) + { + if (std::abs(zvtx) > 60.) + { + return Fun4AllReturnCodes::EVENT_OK; + } + } + + for (int iarm=0; iarm<2; iarm++) + { + armtime[iarm] = _mbdout->get_time(iarm); + nhit[iarm] = _mbdout->get_npmt(iarm); + } + + for (int ipmt=0; ipmt < _mbdpmts->get_npmt(); ipmt++) + { + MbdPmtHit *pmt = _mbdpmts->get_pmt(ipmt); + if ( !pmt ) + { + continue; + } + + Short_t pmtno = pmt->get_pmt(); + Float_t q = pmt->get_q(); + Float_t tt = pmt->get_tt(); + Float_t tq = pmt->get_tq(); + + h_tt[pmtno]->Fill( tt ); + h2_tt->Fill( tt, pmtno ); + h_tq[pmtno]->Fill( tq ); + h2_tq->Fill( tq, pmtno ); + + // Fill charge histogram for in-time hits + if ( std::abs(tt)<26.0 && q > 0.) + { + h_qp[pmtno]->Fill( q ); + } + + int arm = _mbdgeom->get_arm( pmtno ); + + // Fill slew histogram for subpass >= 1 + if (_subpass >= 1 && h2_slew[pmtno]) + { + if (nhit[arm] >= 2. && q > 0.) + { + float dt = tt - armtime[arm]; + h2_slew[pmtno]->Fill(q, dt); + } + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int MbdCalibReco::End(PHCompositeNode * /*topNode*/) +{ + if (!_outfile) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + // Write histograms to output file + _outfile->cd(); + h2_tt->Write(); + h2_tq->Write(); + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + h_tt[ipmt]->Write(); + h_tq[ipmt]->Write(); + h_qp[ipmt]->Write(); + if (h2_slew[ipmt]) + { + h2_slew[ipmt]->Write(); + } + } + + // Always fit and write t0 (done at every subpass from the accumulated histograms) + //FitAndWriteT0(); + + /* + if (_subpass == 1 || _subpass == 2) + { + FitAndWriteSlew(); + } + */ + + _outfile->Close(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +int MbdCalibReco::getRunType() const +{ + // Run number → collision system (mirrors get_runtype() from get_runstr.h) + if (_runnumber <= 30000) + { + return 3; // SIMAUAU200 + } + if (_runnumber <= 53880) + { + return 1; // PP200 (Run24) + } + if (_runnumber <= 54962) + { + return 0; // AUAU200 (Run24) + } + if (_runnumber <= 78954) + { + return 0; // AUAU200 (Run25) + } + if (_runnumber <= 81667) + { + return 1; // PP200 (Run25) + } + if (_runnumber <= 82703) + { + return 2; // OO200 (Run25) + } + return -1; +} + +// --------------------------------------------------------------------------- +// FitAndWriteT0 — Gaussian fit to h_tt and h_tq, write *_t0.calib files +// --------------------------------------------------------------------------- +void MbdCalibReco::FitAndWriteT0() +{ + std::string passprefix = "pass" + std::to_string(_subpass) + "_"; + std::string tt_fname = _rundir + "/" + passprefix + "mbd_tt_t0.calib"; + std::string tq_fname = _rundir + "/" + passprefix + "mbd_tq_t0.calib"; + + std::ofstream tt_file(tt_fname); + std::ofstream tq_file(tq_fname); + if (!tt_file.is_open() || !tq_file.is_open()) + { + std::cout << Name() << "::FitAndWriteT0 ERROR cannot open calib files" << std::endl; + return; + } + + TF1 gaussian("mbdcal_gaus", "gaus", -25., 25.); + gaussian.SetLineColor(2); + + double min_twindow = -25.; + double max_twindow = 25.; + + // --- tt_t0 --- + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + if (ipmt == 0 || ipmt == 64) + { + h_tt[ipmt]->SetAxisRange(-25., 25.); + } + else + { + h_tt[ipmt]->SetAxisRange(min_twindow, max_twindow); + } + + int peakbin = h_tt[ipmt]->GetMaximumBin(); + double mean = h_tt[ipmt]->GetBinCenter(peakbin); + double peak = h_tt[ipmt]->GetMaximum(); + + gaussian.SetParameters(peak, mean, 5.); + gaussian.SetRange(mean - 3., mean + 3.); + h_tt[ipmt]->Fit(&gaussian, "RQ"); + + mean = gaussian.GetParameter(1); + double meanerr = gaussian.GetParError(1); + double sigma = gaussian.GetParameter(2); + double sigmaerr = gaussian.GetParError(2); + + if (ipmt == 0 || ipmt == 64) + { + min_twindow = mean - 3. * sigma; + max_twindow = mean + 3. * sigma; + } + + tt_file << ipmt << "\t" << mean << "\t" << meanerr << "\t" + << sigma << "\t" << sigmaerr << "\n"; + + // Normalise h2_tt row by fit peak amplitude + double fitpeak = gaussian.GetParameter(0); + if (fitpeak != 0.) + { + int nbinsx = h2_tt->GetNbinsX(); + for (int ibinx = 1; ibinx <= nbinsx; ibinx++) + { + float bc = h2_tt->GetBinContent(ibinx, ipmt + 1); + h2_tt->SetBinContent(ibinx, ipmt + 1, bc / fitpeak); + } + } + } + tt_file.close(); + + // Write canonical CDB ROOT file + { + MbdCalib tmpcal; + tmpcal.Download_TTT0(tt_fname); + std::string cdb_fname = tt_fname; + cdb_fname.replace(cdb_fname.rfind(".calib"), 6, ".root"); + tmpcal.Write_CDB_TTT0(cdb_fname); + } + + // --- tq_t0 --- + min_twindow = -25.; + max_twindow = 25.; + + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + if (ipmt == 0 || ipmt == 64) + { + h_tq[ipmt]->SetAxisRange(-25., 25.); + } + else + { + h_tq[ipmt]->SetAxisRange(min_twindow, max_twindow); + } + + int peakbin = h_tq[ipmt]->GetMaximumBin(); + double mean = h_tq[ipmt]->GetBinCenter(peakbin); + double peak = h_tq[ipmt]->GetMaximum(); + + gaussian.SetParameters(peak, mean, 5.); + gaussian.SetRange(mean - 3., mean + 3.); + h_tq[ipmt]->Fit(&gaussian, "RQ"); + + mean = gaussian.GetParameter(1); + double meanerr = gaussian.GetParError(1); + double sigma = gaussian.GetParameter(2); + double sigmaerr = gaussian.GetParError(2); + + if (ipmt == 0 || ipmt == 64) + { + min_twindow = mean - 3. * sigma; + max_twindow = mean + 3. * sigma; + } + + tq_file << ipmt << "\t" << mean << "\t" << meanerr << "\t" + << sigma << "\t" << sigmaerr << "\n"; + + // Normalise h2_tq row + double fitpeak = gaussian.GetParameter(0); + if (fitpeak != 0.) + { + int nbinsx = h2_tq->GetNbinsX(); + for (int ibinx = 1; ibinx <= nbinsx; ibinx++) + { + float bc = h2_tq->GetBinContent(ibinx, ipmt + 1); + h2_tq->SetBinContent(ibinx, ipmt + 1, bc / fitpeak); + } + } + } + tq_file.close(); + + { + MbdCalib tmpcal; + tmpcal.Download_TQT0(tq_fname); + std::string cdb_fname = tq_fname; + cdb_fname.replace(cdb_fname.rfind(".calib"), 6, ".root"); + tmpcal.Write_CDB_TQT0(cdb_fname); + } + + std::cout << Name() << ": wrote " << tt_fname << " and " << tq_fname << std::endl; +} + +// --------------------------------------------------------------------------- +// FindTH2Ridge — column-by-column Gaussian fits to find slew-correction ridge +// --------------------------------------------------------------------------- +void MbdCalibReco::FindTH2Ridge(const TH2 *h2, TGraphErrors *&gridge, + TGraphErrors *&grms) const +{ + int nbinsx = h2->GetNbinsX(); + double min_yrange = h2->GetYaxis()->GetBinLowEdge(1); + double max_yrange = h2->GetYaxis()->GetBinLowEdge(h2->GetNbinsY() + 1); + + gridge = new TGraphErrors(); + gridge->SetName("gridge"); + gridge->SetTitle("ridge"); + grms = new TGraphErrors(); + grms->SetName("grms"); + grms->SetTitle("rms of ridge"); + + TH1 *h_projx = h2->ProjectionX("_projx_tmp"); + TF1 gaussian("_slew_gaus", "gaus", min_yrange, max_yrange); + gaussian.SetLineColor(4); + + TH1 *h_projy = nullptr; + double adcmean = 0.; + double adcnum = 0.; + + for (int ibin = 1; ibin <= nbinsx; ibin++) + { + std::string projname = "_hproj_" + std::to_string(ibin); + if (!h_projy) + { + h_projy = h2->ProjectionY(projname.c_str(), ibin, ibin); + adcmean = h_projx->GetBinCenter(ibin); + adcnum = 1.; + } + else + { + TH1 *hadd = h2->ProjectionY(projname.c_str(), ibin, ibin); + h_projy->Add(hadd); + delete hadd; + adcmean += h_projx->GetBinCenter(ibin); + adcnum += 1.; + } + + if (h_projy->Integral() > 2000. || ibin == nbinsx) + { + adcmean /= adcnum; + + int maxbin = h_projy->GetMaximumBin(); + double xmax_g = h_projy->GetBinCenter(maxbin); + double ymax_g = h_projy->GetBinContent(maxbin); + gaussian.SetParameter(0, ymax_g); + gaussian.SetParameter(1, xmax_g); + gaussian.SetRange(xmax_g - 0.6, xmax_g + 0.6); + h_projy->Fit(&gaussian, "RWWQ"); + + double mean = gaussian.GetParameter(1); + double meanerr = gaussian.GetParError(1); + double rms = gaussian.GetParameter(2); + double rmserr = gaussian.GetParError(2); + + if (meanerr < 1.0) + { + int n = gridge->GetN(); + gridge->SetPoint(n, adcmean, mean); + gridge->SetPointError(n, 0., meanerr); + } + if (rmserr < 0.01) + { + int n = grms->GetN(); + grms->SetPoint(n, adcmean, rms); + grms->SetPointError(n, 0., rmserr); + } + + delete h_projy; + h_projy = nullptr; + adcmean = 0.; + adcnum = 0.; + } + } + + gridge->SetBit(TGraph::kIsSortedX); + grms->SetBit(TGraph::kIsSortedX); + delete h_projx; +} + +// --------------------------------------------------------------------------- +// FitAndWriteSlew — build slew-correction LUT from h2_slew ridge +// --------------------------------------------------------------------------- +void MbdCalibReco::FitAndWriteSlew() +{ + const int NPOINTS = 16000; + const int MINADC = 0; + const int MAXADC = 15999; + + std::string scorr_fname = _rundir + "/mbd_slewcorr.calib"; + std::ofstream scorr_file(scorr_fname); + if (!scorr_file.is_open()) + { + std::cout << Name() << "::FitAndWriteSlew ERROR cannot open " << scorr_fname << std::endl; + return; + } + + std::string trms_fname = _rundir + "/mbd_timerms.calib"; + std::ofstream trms_file(trms_fname); + + // Arrays of slew/trms graph pointers, indexed by feech (only T-channels used) + std::array g_slew{}; + std::array g_trms{}; + g_slew.fill(nullptr); + g_trms.fill(nullptr); + + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + if (!h2_slew[ipmt]) + { + continue; + } + + int feech_t = (ipmt / 8) * 16 + ipmt % 8; + + TGraphErrors *gr = nullptr; + TGraphErrors *grms_tmp = nullptr; + FindTH2Ridge(h2_slew[ipmt], gr, grms_tmp); + + g_slew[feech_t] = gr; + g_trms[feech_t] = grms_tmp; + + if (gr) + { + gr->SetName(("g_slew" + std::to_string(ipmt)).c_str()); + gr->SetMarkerStyle(20); + gr->SetMarkerSize(0.25); + } + if (grms_tmp) + { + grms_tmp->SetName(("g_trms" + std::to_string(ipmt)).c_str()); + grms_tmp->SetMarkerStyle(20); + grms_tmp->SetMarkerSize(0.25); + } + } + + // Write slew correction LUT (one T-channel feech at a time) + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + // Only T-channels: type = (feech/8) % 2 == 0 + if ((ifeech / 8) % 2 == 1) + { + continue; + } + + if (!g_slew[ifeech]) + { + continue; + } + + scorr_file << ifeech << "\t" << NPOINTS << "\t" << MINADC << "\t" << MAXADC << "\n"; + int step = (MAXADC - MINADC) / (NPOINTS - 1); + for (int iadc = MINADC; iadc <= MAXADC; iadc += step) + { + scorr_file << g_slew[ifeech]->Eval(iadc) << " "; + if (iadc % 10 == 9) + { + scorr_file << "\n"; + } + } + } + scorr_file.close(); + + // Write time-RMS LUT + if (trms_file.is_open()) + { + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + if ((ifeech / 8) % 2 == 1) + { + continue; + } + if (!g_trms[ifeech]) + { + continue; + } + + trms_file << ifeech << "\t" << NPOINTS << "\t" << MINADC << "\t" << MAXADC << "\n"; + int step = (MAXADC - MINADC) / (NPOINTS - 1); + for (int iadc = MINADC; iadc <= MAXADC; iadc += step) + { + trms_file << g_trms[ifeech]->Eval(iadc) << " "; + if (iadc % 10 == 9) + { + trms_file << "\n"; + } + } + } + trms_file.close(); + } + + // Write graphs to ROOT file and create CDB ROOT file + _outfile->cd(); + for (auto *g : g_slew) + { + if (g) + { + g->Write(); + } + } + for (auto *g : g_trms) + { + if (g) + { + g->Write(); + } + } + + { + MbdCalib tmpcal; + tmpcal.Download_SlewCorr(scorr_fname); + std::string cdb_fname = scorr_fname; + cdb_fname.replace(cdb_fname.rfind(".calib"), 6, ".root"); + tmpcal.Write_CDB_SlewCorr(cdb_fname); + } + + // Clean up + for (auto *g : g_slew) + { + delete g; + } + for (auto *g : g_trms) + { + delete g; + } + + std::cout << Name() << ": wrote " << scorr_fname << std::endl; +} + diff --git a/offline/packages/mbd/MbdCalibReco.h b/offline/packages/mbd/MbdCalibReco.h new file mode 100644 index 0000000000..f6d6448932 --- /dev/null +++ b/offline/packages/mbd/MbdCalibReco.h @@ -0,0 +1,77 @@ +#ifndef MBD_MBDCALIBRECO_H +#define MBD_MBDCALIBRECO_H + +#include "MbdDefs.h" + +#include + +#include +#include +#include +#include + +class PHCompositeNode; +class MbdCalib; +class MbdPmtContainer; +class MbdOut; +class MbdGeom; +class Gl1Packet; +class EventHeader; +class RunHeader; +class TH1; +class TH2; +class TFile; +class TGraphErrors; + +class MbdCalibReco : public SubsysReco +{ + public: + MbdCalibReco(const std::string& name = "MbdCalibReco"); + ~MbdCalibReco() override = default; + + int Init(PHCompositeNode* topNode) override; + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + int End(PHCompositeNode* topNode) override; + + void SetSubPass(const int s) { _subpass = s; } + void SetCalDir(const std::string& d) { _caldir = d; } + void SetCDBTag(const std::string& t) { _cdbtag = t; } + + private: + int getNodes(PHCompositeNode* topNode); + void InitHistos(); + int getRunType() const; + + void FitAndWriteT0(); + void FitAndWriteSlew(); + + void FindTH2Ridge(const TH2* h2, TGraphErrors*& gridge, TGraphErrors*& grms) const; + + uint64_t _mbias_trigger_mask{0}; + + int _subpass{0}; + int _runnumber{0}; + std::string _caldir{"results"}; + std::string _rundir; // _caldir// + std::string _cdbtag{}; // non-empty → download from CDB instead of local files + + MbdCalib* _mbdcal{nullptr}; + MbdPmtContainer* _mbdpmts{nullptr}; + MbdOut* _mbdout{nullptr}; + MbdGeom* _mbdgeom{nullptr}; + EventHeader* _evtheader{nullptr}; + RunHeader* _runheader{nullptr}; + Gl1Packet* _gl1packet{nullptr}; + + std::array h_tt{}; + std::array h_tq{}; + std::array h_qp{}; + std::array h2_slew{}; + TH2* h2_tt{nullptr}; + TH2* h2_tq{nullptr}; + + std::unique_ptr _outfile{nullptr}; +}; + +#endif // MBD_MBDCALIBRECO_H diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index b97d750f29..5c1e9ed087 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -165,18 +166,32 @@ int MbdEvent::InitRun() if ( _calpass>1 ) { std::string calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_sampmax.calib"; - std::cout << "Loading local sampmax, " << calfname << std::endl; - _mbdcal->Download_SampMax( calfname ); + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local sampmax, " << calfname << std::endl; + _mbdcal->Download_SampMax( calfname ); + } + else + { + std::cout << PHWHERE << "local sampmax not found, skipping: " << calfname << std::endl; + } calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_ped.calib"; - std::cout << "Loading local ped, " << calfname << std::endl; - _mbdcal->Download_Ped( calfname ); + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local ped, " << calfname << std::endl; + _mbdcal->Download_Ped( calfname ); + } + else + { + std::cout << PHWHERE << "local ped not found, skipping: " << calfname << std::endl; + } } // check if sampmax and ped calibs exist int scheck = _mbdcal->get_sampmax(0); - if ( (scheck<0 || _is_online) && _calpass!=1 ) + if ( (scheck<0 || _is_online) && _calpass==0 ) { _no_sampmax = 1000; // num events for on the fly calculation _calib_done = 0; @@ -281,11 +296,49 @@ int MbdEvent::InitRun() if ( _calpass == 2 ) { - // zero out the tt_t0, tq_t0, and gains to produce uncalibrated time and charge std::cout << "MBD Cal Pass 2" << std::endl; - _mbdcal->Reset_TTT0(); - _mbdcal->Reset_TQT0(); - _mbdcal->Reset_Gains(); + + // zero out the tt_t0, tq_t0, and gains to produce uncalibrated time and charge + // or load pass2 calibs from local file for calpass2+, if local files exist + if ( _calpass>1 ) + { + std::string calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tt_t0.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_tt_t0, " << calfname << std::endl; + _mbdcal->Download_TTT0( calfname ); + } + else + { + _mbdcal->Reset_TTT0(); + std::cout << PHWHERE << "local mbd_tt_t0 not found, reset to 0: " << calfname << std::endl; + } + + calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tq_t0.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_tq_t0, " << calfname << std::endl; + _mbdcal->Download_TQT0( calfname ); + } + else + { + _mbdcal->Reset_TQT0(); + std::cout << PHWHERE << "local mbd_tq_t0 not found, reset to 0: " << calfname << std::endl; + } + + calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_qfit.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_qfit, " << calfname << std::endl; + _mbdcal->Download_Gains( calfname ); + } + else + { + _mbdcal->Reset_Gains(); + std::cout << PHWHERE << "local mbd_gains not found, reset to 1: " << calfname << std::endl; + } + + } TDirectory *orig_dir = gDirectory; @@ -1381,7 +1434,7 @@ int MbdEvent::FillSampMaxCalib() // _no_sampmax keeps track of how many events to use for on-the-fly calibration _no_sampmax--; - if ( _no_sampmax==0 && _calpass != 1 ) + if ( _no_sampmax==0 && _calpass==0 ) { CalcSampMaxCalib(); _calib_done = 1; From 3a6becdf82fb2b9aa2bdcacf780d8479081c082b Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 7 May 2026 15:43:33 -0400 Subject: [PATCH 492/866] rabbit fixes --- offline/packages/mbd/MbdCalibReco.cc | 488 ++------------------------- offline/packages/mbd/MbdCalibReco.h | 13 +- 2 files changed, 35 insertions(+), 466 deletions(-) diff --git a/offline/packages/mbd/MbdCalibReco.cc b/offline/packages/mbd/MbdCalibReco.cc index 0d97a0a9d9..10ed14b559 100644 --- a/offline/packages/mbd/MbdCalibReco.cc +++ b/offline/packages/mbd/MbdCalibReco.cc @@ -1,8 +1,6 @@ #include "MbdCalibReco.h" #include "MbdCalib.h" #include "MbdDefs.h" -//#include "MbdRawContainer.h" -//#include "MbdRawHit.h" #include "MbdPmtContainer.h" #include "MbdPmtHit.h" #include "MbdOut.h" @@ -24,6 +22,7 @@ #include #include #include +#include #include #include @@ -39,7 +38,7 @@ MbdCalibReco::MbdCalibReco(const std::string &name) int MbdCalibReco::Init(PHCompositeNode * /*topNode*/) { - _mbdcal = new MbdCalib(); + _mbdcal = std::make_unique(); _mbdcal->Verbosity( Verbosity() ); return Fun4AllReturnCodes::EVENT_OK; } @@ -54,6 +53,8 @@ int MbdCalibReco::InitRun(PHCompositeNode *topNode) _runnumber = _runheader ? _runheader->get_RunNumber() : 0; + getNodes(topNode); + // Build run directory path and create it std::ostringstream oss; oss << _caldir << "/" << _runnumber; @@ -142,9 +143,9 @@ int MbdCalibReco::InitRun(PHCompositeNode *topNode) // Build bitmask of scaled triggers whose names begin with "MBD N&S" _mbias_trigger_mask = 0xfc00; - InitHistos(); - // Open output ROOT file + TDirectory *origdir = gDirectory; + std::string outfname = _rundir + "/calmbdpass2." + std::to_string(_subpass); if (_subpass == 0) { @@ -159,8 +160,18 @@ int MbdCalibReco::InitRun(PHCompositeNode *topNode) outfname += "_q-" + std::to_string(_runnumber) + ".root"; } _outfile = std::make_unique(outfname.c_str(), "RECREATE"); + if (!_outfile || _outfile->IsZombie()) + { + std::cerr << PHWHERE << " ERROR: cannot open output file " << outfname << std::endl; + _outfile.reset(); + return Fun4AllReturnCodes::ABORTRUN; + } std::cout << Name() << ": output file " << outfname << std::endl; + InitHistos(); + + origdir->cd(); + return Fun4AllReturnCodes::EVENT_OK; } @@ -183,18 +194,6 @@ int MbdCalibReco::getNodes(PHCompositeNode *topNode) } } - /* - _mbdraws = findNode::getClass(topNode, "MbdRawContainer"); - if (!_mbdraws) - { - static int counter = 0; - if ( counter<4 ) - { - std::cout << PHWHERE << " MbdRawContainer not found" << std::endl; - } - } - */ - _mbdpmts = findNode::getClass(topNode, "MbdPmtContainer"); if (!_mbdpmts) { @@ -225,17 +224,16 @@ int MbdCalibReco::getNodes(PHCompositeNode *topNode) } } + if ( !_mbdgeom || !_mbdout || !_mbdpmts || !_gl1packet || !_evtheader ) + { + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; } void MbdCalibReco::InitHistos() { - // Histograms must not be associated with the output TFile at creation - // time (InitRun happens before _outfile is opened above, but we call - // InitHistos before opening the file, so ROOT's current directory is - // gROOT or whichever file is current from the framework). - gROOT->cd(); - for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) { std::string sn = std::to_string(ipmt); @@ -251,9 +249,12 @@ void MbdCalibReco::InitHistos() if (_subpass >= 1) { - h2_slew[ipmt] = new TH2F(("h2_slew" + sn).c_str(), ("slew curve, ch " + sn).c_str(), 4000, -0.5, 16000. - 0.5, 1100, -5., 6.); - h2_slew[ipmt]->SetXTitle("ADC"); - h2_slew[ipmt]->SetYTitle("#Delta T (ns)"); + const int nbins[2] = {4000, 1100}; + const double xmin[2] = {-0.5, -5.}; + const double xmax[2] = {16000. - 0.5, 6.}; + h2_slew[ipmt] = new THnSparseF(("h2_slew" + sn).c_str(), ("slew curve, ch " + sn).c_str(), 2, nbins, xmin, xmax); + h2_slew[ipmt]->GetAxis(0)->SetTitle("ADC"); + h2_slew[ipmt]->GetAxis(1)->SetTitle("#Delta T (ns)"); } else { @@ -270,10 +271,8 @@ void MbdCalibReco::InitHistos() h2_tq->SetYTitle("pmt ch"); } -int MbdCalibReco::process_event(PHCompositeNode *topNode) +int MbdCalibReco::process_event(PHCompositeNode * /*topNode*/) { - getNodes(topNode); - // Require a scaled "MBD N&S" trigger if (_mbias_trigger_mask != 0) { @@ -284,16 +283,6 @@ int MbdCalibReco::process_event(PHCompositeNode *topNode) } } - // Per-event arrays for corrected times - /* - std::array ttcorr{}; - std::array tqcorr{}; - std::array adc_arr{}; - ttcorr.fill(std::numeric_limits::quiet_NaN()); - tqcorr.fill(std::numeric_limits::quiet_NaN()); - adc_arr.fill(0); - */ - std::array armtime{}; armtime.fill(0); std::array nhit{}; @@ -347,7 +336,8 @@ int MbdCalibReco::process_event(PHCompositeNode *topNode) if (nhit[arm] >= 2. && q > 0.) { float dt = tt - armtime[arm]; - h2_slew[pmtno]->Fill(q, dt); + const double coords[2] = {q, dt}; + h2_slew[pmtno]->Fill(coords); } } } @@ -355,7 +345,7 @@ int MbdCalibReco::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -int MbdCalibReco::End(PHCompositeNode * /*topNode*/) +int MbdCalibReco::EndRun(const int /*runnumber*/) { if (!_outfile) { @@ -377,424 +367,8 @@ int MbdCalibReco::End(PHCompositeNode * /*topNode*/) } } - // Always fit and write t0 (done at every subpass from the accumulated histograms) - //FitAndWriteT0(); - - /* - if (_subpass == 1 || _subpass == 2) - { - FitAndWriteSlew(); - } - */ - _outfile->Close(); return Fun4AllReturnCodes::EVENT_OK; } -int MbdCalibReco::getRunType() const -{ - // Run number → collision system (mirrors get_runtype() from get_runstr.h) - if (_runnumber <= 30000) - { - return 3; // SIMAUAU200 - } - if (_runnumber <= 53880) - { - return 1; // PP200 (Run24) - } - if (_runnumber <= 54962) - { - return 0; // AUAU200 (Run24) - } - if (_runnumber <= 78954) - { - return 0; // AUAU200 (Run25) - } - if (_runnumber <= 81667) - { - return 1; // PP200 (Run25) - } - if (_runnumber <= 82703) - { - return 2; // OO200 (Run25) - } - return -1; -} - -// --------------------------------------------------------------------------- -// FitAndWriteT0 — Gaussian fit to h_tt and h_tq, write *_t0.calib files -// --------------------------------------------------------------------------- -void MbdCalibReco::FitAndWriteT0() -{ - std::string passprefix = "pass" + std::to_string(_subpass) + "_"; - std::string tt_fname = _rundir + "/" + passprefix + "mbd_tt_t0.calib"; - std::string tq_fname = _rundir + "/" + passprefix + "mbd_tq_t0.calib"; - - std::ofstream tt_file(tt_fname); - std::ofstream tq_file(tq_fname); - if (!tt_file.is_open() || !tq_file.is_open()) - { - std::cout << Name() << "::FitAndWriteT0 ERROR cannot open calib files" << std::endl; - return; - } - - TF1 gaussian("mbdcal_gaus", "gaus", -25., 25.); - gaussian.SetLineColor(2); - - double min_twindow = -25.; - double max_twindow = 25.; - - // --- tt_t0 --- - for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) - { - if (ipmt == 0 || ipmt == 64) - { - h_tt[ipmt]->SetAxisRange(-25., 25.); - } - else - { - h_tt[ipmt]->SetAxisRange(min_twindow, max_twindow); - } - - int peakbin = h_tt[ipmt]->GetMaximumBin(); - double mean = h_tt[ipmt]->GetBinCenter(peakbin); - double peak = h_tt[ipmt]->GetMaximum(); - - gaussian.SetParameters(peak, mean, 5.); - gaussian.SetRange(mean - 3., mean + 3.); - h_tt[ipmt]->Fit(&gaussian, "RQ"); - - mean = gaussian.GetParameter(1); - double meanerr = gaussian.GetParError(1); - double sigma = gaussian.GetParameter(2); - double sigmaerr = gaussian.GetParError(2); - - if (ipmt == 0 || ipmt == 64) - { - min_twindow = mean - 3. * sigma; - max_twindow = mean + 3. * sigma; - } - - tt_file << ipmt << "\t" << mean << "\t" << meanerr << "\t" - << sigma << "\t" << sigmaerr << "\n"; - - // Normalise h2_tt row by fit peak amplitude - double fitpeak = gaussian.GetParameter(0); - if (fitpeak != 0.) - { - int nbinsx = h2_tt->GetNbinsX(); - for (int ibinx = 1; ibinx <= nbinsx; ibinx++) - { - float bc = h2_tt->GetBinContent(ibinx, ipmt + 1); - h2_tt->SetBinContent(ibinx, ipmt + 1, bc / fitpeak); - } - } - } - tt_file.close(); - - // Write canonical CDB ROOT file - { - MbdCalib tmpcal; - tmpcal.Download_TTT0(tt_fname); - std::string cdb_fname = tt_fname; - cdb_fname.replace(cdb_fname.rfind(".calib"), 6, ".root"); - tmpcal.Write_CDB_TTT0(cdb_fname); - } - - // --- tq_t0 --- - min_twindow = -25.; - max_twindow = 25.; - - for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) - { - if (ipmt == 0 || ipmt == 64) - { - h_tq[ipmt]->SetAxisRange(-25., 25.); - } - else - { - h_tq[ipmt]->SetAxisRange(min_twindow, max_twindow); - } - - int peakbin = h_tq[ipmt]->GetMaximumBin(); - double mean = h_tq[ipmt]->GetBinCenter(peakbin); - double peak = h_tq[ipmt]->GetMaximum(); - - gaussian.SetParameters(peak, mean, 5.); - gaussian.SetRange(mean - 3., mean + 3.); - h_tq[ipmt]->Fit(&gaussian, "RQ"); - - mean = gaussian.GetParameter(1); - double meanerr = gaussian.GetParError(1); - double sigma = gaussian.GetParameter(2); - double sigmaerr = gaussian.GetParError(2); - - if (ipmt == 0 || ipmt == 64) - { - min_twindow = mean - 3. * sigma; - max_twindow = mean + 3. * sigma; - } - - tq_file << ipmt << "\t" << mean << "\t" << meanerr << "\t" - << sigma << "\t" << sigmaerr << "\n"; - - // Normalise h2_tq row - double fitpeak = gaussian.GetParameter(0); - if (fitpeak != 0.) - { - int nbinsx = h2_tq->GetNbinsX(); - for (int ibinx = 1; ibinx <= nbinsx; ibinx++) - { - float bc = h2_tq->GetBinContent(ibinx, ipmt + 1); - h2_tq->SetBinContent(ibinx, ipmt + 1, bc / fitpeak); - } - } - } - tq_file.close(); - - { - MbdCalib tmpcal; - tmpcal.Download_TQT0(tq_fname); - std::string cdb_fname = tq_fname; - cdb_fname.replace(cdb_fname.rfind(".calib"), 6, ".root"); - tmpcal.Write_CDB_TQT0(cdb_fname); - } - - std::cout << Name() << ": wrote " << tt_fname << " and " << tq_fname << std::endl; -} - -// --------------------------------------------------------------------------- -// FindTH2Ridge — column-by-column Gaussian fits to find slew-correction ridge -// --------------------------------------------------------------------------- -void MbdCalibReco::FindTH2Ridge(const TH2 *h2, TGraphErrors *&gridge, - TGraphErrors *&grms) const -{ - int nbinsx = h2->GetNbinsX(); - double min_yrange = h2->GetYaxis()->GetBinLowEdge(1); - double max_yrange = h2->GetYaxis()->GetBinLowEdge(h2->GetNbinsY() + 1); - - gridge = new TGraphErrors(); - gridge->SetName("gridge"); - gridge->SetTitle("ridge"); - grms = new TGraphErrors(); - grms->SetName("grms"); - grms->SetTitle("rms of ridge"); - - TH1 *h_projx = h2->ProjectionX("_projx_tmp"); - TF1 gaussian("_slew_gaus", "gaus", min_yrange, max_yrange); - gaussian.SetLineColor(4); - - TH1 *h_projy = nullptr; - double adcmean = 0.; - double adcnum = 0.; - - for (int ibin = 1; ibin <= nbinsx; ibin++) - { - std::string projname = "_hproj_" + std::to_string(ibin); - if (!h_projy) - { - h_projy = h2->ProjectionY(projname.c_str(), ibin, ibin); - adcmean = h_projx->GetBinCenter(ibin); - adcnum = 1.; - } - else - { - TH1 *hadd = h2->ProjectionY(projname.c_str(), ibin, ibin); - h_projy->Add(hadd); - delete hadd; - adcmean += h_projx->GetBinCenter(ibin); - adcnum += 1.; - } - - if (h_projy->Integral() > 2000. || ibin == nbinsx) - { - adcmean /= adcnum; - - int maxbin = h_projy->GetMaximumBin(); - double xmax_g = h_projy->GetBinCenter(maxbin); - double ymax_g = h_projy->GetBinContent(maxbin); - gaussian.SetParameter(0, ymax_g); - gaussian.SetParameter(1, xmax_g); - gaussian.SetRange(xmax_g - 0.6, xmax_g + 0.6); - h_projy->Fit(&gaussian, "RWWQ"); - - double mean = gaussian.GetParameter(1); - double meanerr = gaussian.GetParError(1); - double rms = gaussian.GetParameter(2); - double rmserr = gaussian.GetParError(2); - - if (meanerr < 1.0) - { - int n = gridge->GetN(); - gridge->SetPoint(n, adcmean, mean); - gridge->SetPointError(n, 0., meanerr); - } - if (rmserr < 0.01) - { - int n = grms->GetN(); - grms->SetPoint(n, adcmean, rms); - grms->SetPointError(n, 0., rmserr); - } - - delete h_projy; - h_projy = nullptr; - adcmean = 0.; - adcnum = 0.; - } - } - - gridge->SetBit(TGraph::kIsSortedX); - grms->SetBit(TGraph::kIsSortedX); - delete h_projx; -} - -// --------------------------------------------------------------------------- -// FitAndWriteSlew — build slew-correction LUT from h2_slew ridge -// --------------------------------------------------------------------------- -void MbdCalibReco::FitAndWriteSlew() -{ - const int NPOINTS = 16000; - const int MINADC = 0; - const int MAXADC = 15999; - - std::string scorr_fname = _rundir + "/mbd_slewcorr.calib"; - std::ofstream scorr_file(scorr_fname); - if (!scorr_file.is_open()) - { - std::cout << Name() << "::FitAndWriteSlew ERROR cannot open " << scorr_fname << std::endl; - return; - } - - std::string trms_fname = _rundir + "/mbd_timerms.calib"; - std::ofstream trms_file(trms_fname); - - // Arrays of slew/trms graph pointers, indexed by feech (only T-channels used) - std::array g_slew{}; - std::array g_trms{}; - g_slew.fill(nullptr); - g_trms.fill(nullptr); - - for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) - { - if (!h2_slew[ipmt]) - { - continue; - } - - int feech_t = (ipmt / 8) * 16 + ipmt % 8; - - TGraphErrors *gr = nullptr; - TGraphErrors *grms_tmp = nullptr; - FindTH2Ridge(h2_slew[ipmt], gr, grms_tmp); - - g_slew[feech_t] = gr; - g_trms[feech_t] = grms_tmp; - - if (gr) - { - gr->SetName(("g_slew" + std::to_string(ipmt)).c_str()); - gr->SetMarkerStyle(20); - gr->SetMarkerSize(0.25); - } - if (grms_tmp) - { - grms_tmp->SetName(("g_trms" + std::to_string(ipmt)).c_str()); - grms_tmp->SetMarkerStyle(20); - grms_tmp->SetMarkerSize(0.25); - } - } - - // Write slew correction LUT (one T-channel feech at a time) - for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) - { - // Only T-channels: type = (feech/8) % 2 == 0 - if ((ifeech / 8) % 2 == 1) - { - continue; - } - - if (!g_slew[ifeech]) - { - continue; - } - - scorr_file << ifeech << "\t" << NPOINTS << "\t" << MINADC << "\t" << MAXADC << "\n"; - int step = (MAXADC - MINADC) / (NPOINTS - 1); - for (int iadc = MINADC; iadc <= MAXADC; iadc += step) - { - scorr_file << g_slew[ifeech]->Eval(iadc) << " "; - if (iadc % 10 == 9) - { - scorr_file << "\n"; - } - } - } - scorr_file.close(); - - // Write time-RMS LUT - if (trms_file.is_open()) - { - for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) - { - if ((ifeech / 8) % 2 == 1) - { - continue; - } - if (!g_trms[ifeech]) - { - continue; - } - - trms_file << ifeech << "\t" << NPOINTS << "\t" << MINADC << "\t" << MAXADC << "\n"; - int step = (MAXADC - MINADC) / (NPOINTS - 1); - for (int iadc = MINADC; iadc <= MAXADC; iadc += step) - { - trms_file << g_trms[ifeech]->Eval(iadc) << " "; - if (iadc % 10 == 9) - { - trms_file << "\n"; - } - } - } - trms_file.close(); - } - - // Write graphs to ROOT file and create CDB ROOT file - _outfile->cd(); - for (auto *g : g_slew) - { - if (g) - { - g->Write(); - } - } - for (auto *g : g_trms) - { - if (g) - { - g->Write(); - } - } - - { - MbdCalib tmpcal; - tmpcal.Download_SlewCorr(scorr_fname); - std::string cdb_fname = scorr_fname; - cdb_fname.replace(cdb_fname.rfind(".calib"), 6, ".root"); - tmpcal.Write_CDB_SlewCorr(cdb_fname); - } - - // Clean up - for (auto *g : g_slew) - { - delete g; - } - for (auto *g : g_trms) - { - delete g; - } - - std::cout << Name() << ": wrote " << scorr_fname << std::endl; -} - diff --git a/offline/packages/mbd/MbdCalibReco.h b/offline/packages/mbd/MbdCalibReco.h index f6d6448932..6a2c49c027 100644 --- a/offline/packages/mbd/MbdCalibReco.h +++ b/offline/packages/mbd/MbdCalibReco.h @@ -9,6 +9,7 @@ #include #include #include +#include class PHCompositeNode; class MbdCalib; @@ -32,7 +33,7 @@ class MbdCalibReco : public SubsysReco int Init(PHCompositeNode* topNode) override; int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode* topNode) override; - int End(PHCompositeNode* topNode) override; + int EndRun(const int runnumber) override; void SetSubPass(const int s) { _subpass = s; } void SetCalDir(const std::string& d) { _caldir = d; } @@ -41,12 +42,6 @@ class MbdCalibReco : public SubsysReco private: int getNodes(PHCompositeNode* topNode); void InitHistos(); - int getRunType() const; - - void FitAndWriteT0(); - void FitAndWriteSlew(); - - void FindTH2Ridge(const TH2* h2, TGraphErrors*& gridge, TGraphErrors*& grms) const; uint64_t _mbias_trigger_mask{0}; @@ -56,7 +51,7 @@ class MbdCalibReco : public SubsysReco std::string _rundir; // _caldir// std::string _cdbtag{}; // non-empty → download from CDB instead of local files - MbdCalib* _mbdcal{nullptr}; + std::unique_ptr _mbdcal; MbdPmtContainer* _mbdpmts{nullptr}; MbdOut* _mbdout{nullptr}; MbdGeom* _mbdgeom{nullptr}; @@ -67,7 +62,7 @@ class MbdCalibReco : public SubsysReco std::array h_tt{}; std::array h_tq{}; std::array h_qp{}; - std::array h2_slew{}; + std::array h2_slew{}; TH2* h2_tt{nullptr}; TH2* h2_tq{nullptr}; From 94ccd3502c6acd8184d8bdd5b7f095becd5e5867 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 7 May 2026 16:20:37 -0400 Subject: [PATCH 493/866] rabbit fixes 2 --- offline/packages/mbd/MbdCalibReco.cc | 29 +++++++++++- offline/packages/mbd/MbdCalibReco.h | 3 +- offline/packages/mbd/MbdEvent.cc | 67 +++++++++++++--------------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/offline/packages/mbd/MbdCalibReco.cc b/offline/packages/mbd/MbdCalibReco.cc index 10ed14b559..e102649332 100644 --- a/offline/packages/mbd/MbdCalibReco.cc +++ b/offline/packages/mbd/MbdCalibReco.cc @@ -168,7 +168,7 @@ int MbdCalibReco::InitRun(PHCompositeNode *topNode) } std::cout << Name() << ": output file " << outfname << std::endl; - InitHistos(); + BookHistograms(); origdir->cd(); @@ -232,8 +232,15 @@ int MbdCalibReco::getNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -void MbdCalibReco::InitHistos() +void MbdCalibReco::BookHistograms() { + // Delete histograms if they have already have been booked. + if ( h2_tt ) + { + DeleteHistograms(); + return; + } + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) { std::string sn = std::to_string(ipmt); @@ -271,6 +278,24 @@ void MbdCalibReco::InitHistos() h2_tq->SetYTitle("pmt ch"); } +void MbdCalibReco::DeleteHistograms() +{ + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + if ( h_tt[ipmt] ) delete h_tt[ipmt]; + if ( h_tq[ipmt] ) delete h_tq[ipmt]; + if ( h_qp[ipmt] ) delete h_qp[ipmt]; + + if ( h2_slew[ipmt] ) + { + delete h2_slew[ipmt]; + } + } + + if ( h2_tt ) delete h2_tt; + if ( h2_tq ) delete h2_tq; +} + int MbdCalibReco::process_event(PHCompositeNode * /*topNode*/) { // Require a scaled "MBD N&S" trigger diff --git a/offline/packages/mbd/MbdCalibReco.h b/offline/packages/mbd/MbdCalibReco.h index 6a2c49c027..eed96688cd 100644 --- a/offline/packages/mbd/MbdCalibReco.h +++ b/offline/packages/mbd/MbdCalibReco.h @@ -41,7 +41,8 @@ class MbdCalibReco : public SubsysReco private: int getNodes(PHCompositeNode* topNode); - void InitHistos(); + void BookHistograms(); + void DeleteHistograms(); uint64_t _mbias_trigger_mask{0}; diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index 5c1e9ed087..f768dfa16d 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -300,45 +300,42 @@ int MbdEvent::InitRun() // zero out the tt_t0, tq_t0, and gains to produce uncalibrated time and charge // or load pass2 calibs from local file for calpass2+, if local files exist - if ( _calpass>1 ) + std::string calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tt_t0.calib"; + if ( std::filesystem::exists(calfname) ) { - std::string calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tt_t0.calib"; - if ( std::filesystem::exists(calfname) ) - { - std::cout << "Loading local mbd_tt_t0, " << calfname << std::endl; - _mbdcal->Download_TTT0( calfname ); - } - else - { - _mbdcal->Reset_TTT0(); - std::cout << PHWHERE << "local mbd_tt_t0 not found, reset to 0: " << calfname << std::endl; - } - - calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tq_t0.calib"; - if ( std::filesystem::exists(calfname) ) - { - std::cout << "Loading local mbd_tq_t0, " << calfname << std::endl; - _mbdcal->Download_TQT0( calfname ); - } - else - { - _mbdcal->Reset_TQT0(); - std::cout << PHWHERE << "local mbd_tq_t0 not found, reset to 0: " << calfname << std::endl; - } + std::cout << "Loading local mbd_tt_t0, " << calfname << std::endl; + _mbdcal->Download_TTT0( calfname ); + } + else + { + _mbdcal->Reset_TTT0(); + std::cout << PHWHERE << "local mbd_tt_t0 not found, reset to 0: " << calfname << std::endl; + } - calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_qfit.calib"; - if ( std::filesystem::exists(calfname) ) - { - std::cout << "Loading local mbd_qfit, " << calfname << std::endl; - _mbdcal->Download_Gains( calfname ); - } - else - { - _mbdcal->Reset_Gains(); - std::cout << PHWHERE << "local mbd_gains not found, reset to 1: " << calfname << std::endl; - } + calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tq_t0.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_tq_t0, " << calfname << std::endl; + _mbdcal->Download_TQT0( calfname ); + } + else + { + _mbdcal->Reset_TQT0(); + std::cout << PHWHERE << "local mbd_tq_t0 not found, reset to 0: " << calfname << std::endl; + } + calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_qfit.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_qfit, " << calfname << std::endl; + _mbdcal->Download_Gains( calfname ); } + else + { + _mbdcal->Reset_Gains(); + std::cout << PHWHERE << "local mbd_gains not found, reset to 1: " << calfname << std::endl; + } + TDirectory *orig_dir = gDirectory; From 5bbb0c2aeab8a1aeffc98ef9699109adcbccc1bd Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 7 May 2026 16:47:50 -0400 Subject: [PATCH 494/866] clang-tidy fixes --- offline/packages/mbd/MbdCalibReco.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/offline/packages/mbd/MbdCalibReco.cc b/offline/packages/mbd/MbdCalibReco.cc index e102649332..d2acec905d 100644 --- a/offline/packages/mbd/MbdCalibReco.cc +++ b/offline/packages/mbd/MbdCalibReco.cc @@ -282,18 +282,26 @@ void MbdCalibReco::DeleteHistograms() { for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) { - if ( h_tt[ipmt] ) delete h_tt[ipmt]; - if ( h_tq[ipmt] ) delete h_tq[ipmt]; - if ( h_qp[ipmt] ) delete h_qp[ipmt]; - + if ( h_tt[ipmt] ) + { + delete h_tt[ipmt]; + } + if ( h_tq[ipmt] ) + { + delete h_tq[ipmt]; + } + if ( h_qp[ipmt] ) + { + delete h_qp[ipmt]; + } if ( h2_slew[ipmt] ) { delete h2_slew[ipmt]; } } - if ( h2_tt ) delete h2_tt; - if ( h2_tq ) delete h2_tq; + delete h2_tt; + delete h2_tq; } int MbdCalibReco::process_event(PHCompositeNode * /*topNode*/) From 4134ac0bf46aaf1f7c7ce15fb4a455c3e865d121 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 7 May 2026 17:06:28 -0400 Subject: [PATCH 495/866] code rabbit fix 3 --- offline/packages/mbd/MbdCalibReco.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/offline/packages/mbd/MbdCalibReco.cc b/offline/packages/mbd/MbdCalibReco.cc index d2acec905d..f131a0d6c2 100644 --- a/offline/packages/mbd/MbdCalibReco.cc +++ b/offline/packages/mbd/MbdCalibReco.cc @@ -346,6 +346,17 @@ int MbdCalibReco::process_event(PHCompositeNode * /*topNode*/) } Short_t pmtno = pmt->get_pmt(); + if ( pmtno<0 || pmtno>128 ) + { + static int counter = 0; + if ( counter<10 ) + { + std::cerr << PHWHERE << " invalide pmt no " << pmtno << std::endl; + counter++; + } + continue; + } + Float_t q = pmt->get_q(); Float_t tt = pmt->get_tt(); Float_t tq = pmt->get_tq(); From c7e5387d425f592730b11c385a61624a9ad46d2d Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 7 May 2026 17:09:08 -0400 Subject: [PATCH 496/866] code rabbit fix 3.1 --- offline/packages/mbd/MbdCalibReco.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/mbd/MbdCalibReco.cc b/offline/packages/mbd/MbdCalibReco.cc index f131a0d6c2..3b64e0f63e 100644 --- a/offline/packages/mbd/MbdCalibReco.cc +++ b/offline/packages/mbd/MbdCalibReco.cc @@ -346,7 +346,7 @@ int MbdCalibReco::process_event(PHCompositeNode * /*topNode*/) } Short_t pmtno = pmt->get_pmt(); - if ( pmtno<0 || pmtno>128 ) + if ( pmtno<0 || pmtno>=MbdDefs::MBD_N_PMT ) { static int counter = 0; if ( counter<10 ) From 91da54406caacad9b07ac43f68b4bc4d3142ffa4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 8 May 2026 14:47:02 -0400 Subject: [PATCH 497/866] 47287 was the first run2pp physics run passing our 5minute cut --- offline/framework/phool/RunnumberRange.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index ab6593bff5..7aadfd7d72 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -6,7 +6,7 @@ * * Each constant names the first or last run number (or a special marker) for a given data-taking period. * - * @var RUN2PP_FIRST First Run 2 proton-proton physics run. + * @var RUN2PP_FIRST First Run 2 proton-proton physics run passing >=5m, >=100k evts. * @var RUN2PP_LAST Last Run 2 proton-proton physics run. * @var RUN2AUAU_FIRST First Run 2 Au+Au (heavy-ion) physics run. * @var RUN2AUAU_LAST Last Run 2 Au+Au (heavy-ion) physics run. @@ -20,7 +20,7 @@ */ namespace RunnumberRange { - constexpr int RUN2PP_FIRST = 47286; + constexpr int RUN2PP_FIRST = 47287; constexpr int RUN2PP_LAST = 53880; constexpr int RUN2AUAU_FIRST = 54128; constexpr int RUN2AUAU_LAST = 54974; From fc639485cbc998b358cfe059fa45dd58b8657ebe Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 9 May 2026 16:23:07 -0400 Subject: [PATCH 498/866] add type 51: ets meson pt > 8GeV --- offline/framework/frog/CreateFileList.pl | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index 089e83e6c4..903fa28236 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -88,7 +88,8 @@ "47" => "Herwig Photonjet ptmin = 20 GeV", "48" => "JS pythia8 Jet ptmin = 8 GeV", "49" => "JS pythia8 Jet ptmin = 80 GeV", - "50" => "JS pythia8 Detroit eta ptmin = 3 GeV" + "50" => "JS pythia8 Detroit eta ptmin = 3 GeV", + "51" => "JS pythia8 Detroit eta ptmin = 8 GeV" ); my %pileupdesc = ( @@ -1496,6 +1497,39 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } + elsif ($prodtype == 51) + { + $embedok = 1; + $filenamestring = "pythia8_Eta8"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } else { print "no production type $prodtype\n"; From 38915389da4d31507198b1862f68a204248aa807 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 10 May 2026 05:41:52 -0400 Subject: [PATCH 499/866] call directed fitter constructor with proper logger --- offline/packages/trackreco/PHActsTrkFitter.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index a342ea104b..9082feda63 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -128,7 +128,7 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) m_fitCfg.dFit = ActsTrackFittingAlgorithm::makeDirectedKalmanFitterFunction( m_tGeometry->geometry().tGeometry, - m_tGeometry->geometry().magField); + m_tGeometry->geometry().magField, true, true, 0.0, Acts::FreeToBoundCorrection(), *Acts::getDefaultLogger("DirectedKalman", level)); MaterialSurfaceSelector selector; if (m_fitSiliconMMs || m_directNavigation) @@ -735,6 +735,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (Verbosity() > 1) { std::cout << "Calling fitTrack for track with siid " << siid << " tpcid " << tpcid << " crossing " << crossing << std::endl; + std::cout << "surfaces size " << surfaces.size() << " and source links size " << sourceLinks.size() << std::endl; } auto result = fitTrack(sourceLinks, seed, kfOptions, surfaces, calibrator, tracks); From ecb697166f7676109c18a5efacd163e015409ed2 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Mon, 11 May 2026 22:07:32 -0400 Subject: [PATCH 500/866] CaloTowerStatus: Prioritize direct URL overrides Updated the logic in InitRun to ensure that URLs provided via set_directURL_hotMap and set_directURL_chi2 take precedence over the default CDBInterface lookups. Previously, the code checked the CDB first, which caused user-specified URLs to act only as fallbacks rather than overrides. This made it difficult to test local calibration files when a CDB map already existed for the current run. The logic now: 1. Checks for a user-specified direct URL. 2. Falls back to the CDBInterface if no direct URL is provided. 3. Aborts or disables the masking if neither is found. --- offline/packages/CaloReco/CaloTowerStatus.cc | 56 ++++++++++---------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index d21ea08dc2..c3a621b826 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -81,22 +81,23 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_calibName_chi2 = m_detector + "_hotTowers_fracBadChi2"; m_fieldname_chi2 = "fraction"; - std::string calibdir = CDBInterface::instance()->getUrl(m_calibName_chi2); - if (!calibdir.empty()) + std::string calibdir_chi2; + if (use_directURL_chi2) { - m_cdbttree_chi2 = new CDBTTree(calibdir); - if (Verbosity() > 0) - { - std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_chi2 << " Doing isHot for frac bad chi2" << std::endl; - } + calibdir_chi2 = m_directURL_chi2; + std::cout << "CaloTowerStatus::InitRun: Using direct URL override for chi2: " << calibdir_chi2 << std::endl; + m_cdbttree_chi2 = new CDBTTree(calibdir_chi2); } else { - if (use_directURL_chi2) + calibdir_chi2 = CDBInterface::instance()->getUrl(m_calibName_chi2); + if (!calibdir_chi2.empty()) { - calibdir = m_directURL_chi2; - std::cout << "CaloTowerStatus::InitRun: Using default hotBadChi2" << calibdir << std::endl; - m_cdbttree_chi2 = new CDBTTree(calibdir); + m_cdbttree_chi2 = new CDBTTree(calibdir_chi2); + if (Verbosity() > 0) + { + std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_chi2 << " Doing isHot for frac bad chi2" << std::endl; + } } else { @@ -117,30 +118,31 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_fieldname_hotMap = "status"; m_fieldname_z_score = m_detector + "_sigma"; - calibdir = CDBInterface::instance()->getUrl(m_calibName_hotMap); - if (!calibdir.empty()) + std::string calibdir_hotMap; + if (use_directURL_hotMap) { - m_cdbttree_hotMap = new CDBTTree(calibdir); - if (Verbosity() > 1) - { - std::cout << "CaloTowerStatus::Init " << m_detector << " hot map found " << m_calibName_hotMap << " Ddoing isHot" << std::endl; - } + calibdir_hotMap = m_directURL_hotMap; + std::cout << "CaloTowerStatus::InitRun: Using direct URL override for hot map: " << calibdir_hotMap << std::endl; + m_cdbttree_hotMap = new CDBTTree(calibdir_hotMap); } else { - if (m_doAbortNoHotMap) + calibdir_hotMap = CDBInterface::instance()->getUrl(m_calibName_hotMap); + if (!calibdir_hotMap.empty()) { - std::cout << "CaloTowerStatus::InitRun: No hot map found for " << m_calibName_hotMap << " and abort mode is set. Exiting." << std::endl; - gSystem->Exit(1); - } - if (use_directURL_hotMap) - { - calibdir = m_directURL_hotMap; - std::cout << "CaloTowerStatus::InitRun: Using default map " << calibdir << std::endl; - m_cdbttree_hotMap = new CDBTTree(calibdir); + m_cdbttree_hotMap = new CDBTTree(calibdir_hotMap); + if (Verbosity() > 1) + { + std::cout << "CaloTowerStatus::Init " << m_detector << " hot map found " << m_calibName_hotMap << " Ddoing isHot" << std::endl; + } } else { + if (m_doAbortNoHotMap) + { + std::cout << "CaloTowerStatus::InitRun: No hot map found for " << m_calibName_hotMap << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_doHotMap = false; if (Verbosity() > 1) { From b3467b76fb6610d0a571711955b2c56be083b27d Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Mon, 11 May 2026 21:22:03 -0500 Subject: [PATCH 501/866] Fix Typo in Log Message "Ddoing" - > "Doing" Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- offline/packages/CaloReco/CaloTowerStatus.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index c3a621b826..2d0be5a892 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -133,7 +133,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_cdbttree_hotMap = new CDBTTree(calibdir_hotMap); if (Verbosity() > 1) { - std::cout << "CaloTowerStatus::Init " << m_detector << " hot map found " << m_calibName_hotMap << " Ddoing isHot" << std::endl; + std::cout << "CaloTowerStatus::Init " << m_detector << " hot map found " << m_calibName_hotMap << " Doing isHot" << std::endl; } } else From ad25fc22e314edbeb0dbdaf01d7d2b9f0b6ee135 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Tue, 12 May 2026 11:28:11 -0400 Subject: [PATCH 502/866] CaloTowerStatus: Remove redundant flags - Removed 'use_directURL_hotMap' and 'use_directURL_chi2' boolean flags. - Updated InitRun to check if URL strings are non-empty to determine if a direct override should be used. - Ensured that a non-empty direct URL string takes precedence over the default CDBInterface lookup. This change prevents potential bugs where a flag could be set to true without a valid filename, and streamlines the code by relying on the string's presence as the single source of truth for the override. --- offline/packages/CaloReco/CaloTowerStatus.cc | 4 ++-- offline/packages/CaloReco/CaloTowerStatus.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 2d0be5a892..f9e63348b6 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -82,7 +82,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_fieldname_chi2 = "fraction"; std::string calibdir_chi2; - if (use_directURL_chi2) + if (!m_directURL_chi2.empty()) { calibdir_chi2 = m_directURL_chi2; std::cout << "CaloTowerStatus::InitRun: Using direct URL override for chi2: " << calibdir_chi2 << std::endl; @@ -119,7 +119,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_fieldname_z_score = m_detector + "_sigma"; std::string calibdir_hotMap; - if (use_directURL_hotMap) + if (!m_directURL_hotMap.empty()) { calibdir_hotMap = m_directURL_hotMap; std::cout << "CaloTowerStatus::InitRun: Using direct URL override for hot map: " << calibdir_hotMap << std::endl; diff --git a/offline/packages/CaloReco/CaloTowerStatus.h b/offline/packages/CaloReco/CaloTowerStatus.h index 1c50486281..9c261155c4 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.h +++ b/offline/packages/CaloReco/CaloTowerStatus.h @@ -71,13 +71,11 @@ class CaloTowerStatus : public SubsysReco void set_directURL_hotMap(const std::string &str) { m_directURL_hotMap = str; - use_directURL_hotMap = true; return; } void set_directURL_chi2(const std::string &str) { m_directURL_chi2 = str; - use_directURL_chi2 = true; return; } void set_doAbortNoHotMap(bool status = true) @@ -121,8 +119,6 @@ class CaloTowerStatus : public SubsysReco std::string m_directURL_hotMap; std::string m_directURL_chi2; - bool use_directURL_hotMap{false}; - bool use_directURL_chi2{false}; float badChi2_treshold_const = {1e4}; float badChi2_treshold_quadratic = {1./100}; From 5ec8930ff78cbd0f472c359926f8cc240ded1eb2 Mon Sep 17 00:00:00 2001 From: Christopher W Platte Date: Tue, 12 May 2026 15:08:27 -0400 Subject: [PATCH 503/866] New TPCLamFit# --- .../packages/tpccalib/TpcLaminationFitting.cc | 9 +++++---- offline/packages/tpccalib/tpccalib-1.00.tar.gz | Bin 0 -> 406222 bytes 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 offline/packages/tpccalib/tpccalib-1.00.tar.gz diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 9e1eda849d..1c5cf71f9f 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -241,8 +241,8 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) //______________________________________ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) { - //m_correctedCMcluster_map = findNode::getClass(topNode, "LAMINATION_CLUSTER"); - m_correctedCMcluster_map = findNode::getClass(topNode, "LASER_CLUSTER"); + m_correctedCMcluster_map = findNode::getClass(topNode, "LAMINATION_CLUSTER"); + // m_correctedCMcluster_map = findNode::getClass(topNode, "LASER_CLUSTER"); if (!m_correctedCMcluster_map) { std::cout << PHWHERE << "CORRECTED_CM_CLUSTER Node missing, abort." << std::endl; @@ -407,8 +407,8 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) } TVector3 tmp_pos(pos[0], pos[1], pos[2]); - - if(cmclus->getNLayers() > m_nLayerCut && cmclus->getSDWeightedLayer() > 0.5) + if(cmclus->getNLayers() > m_nLayerCut) + // if(cmclus->getNLayers() > m_nLayerCut && cmclus->getSDWeightedLayer() > 0.5) { for (int l = 0; l < 18; l++) { @@ -714,6 +714,7 @@ int TpcLaminationFitting::fitLaminations() return Fun4AllReturnCodes::EVENT_OK; } + int TpcLaminationFitting::InterpolatePhiDistortions() { diff --git a/offline/packages/tpccalib/tpccalib-1.00.tar.gz b/offline/packages/tpccalib/tpccalib-1.00.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..605cabd32088e84d9eed575392cc19992174d054 GIT binary patch literal 406222 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 A!L+4uAbv`FUWCTeG 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

-De3-W3X>BRrnOz#mo-Ew$~n z$I0Wp(6H*6jI0qB2{;et7PvSoQ4MbB)Jb zoVH|_dC&MQ|7%E)S@DuoOa!{sgnsUL2Gaw)#{y2wIwtOb*rSmgikV39XMh_1qxwBu<0=o!HcY+$N###>GINLv=AxQT)e6SDE!PMJTQ{Sn~6VCFPjS zUXS$O+uQjBQTiXC_UZdKQ5Ze>1GV(C_viN}67wOH_eUY25dGRWgg|{nR~V^$ya<3a zUnMR#)l049Mvvlpw^NJ4N%!fQq{kVT*ZFRux{3c4`8P9e@HgqM>z{=}eG(@&b46Jw z>XoE%Ok|e5d88i^ z+$)*bexcm)pu~@2_h9#Q_u%BTaj>~9PPdQu)x)GfbkOAAatpG2WqOQ`Le0EN)67qd z7U!1GIBkgimwTtXM|<1i;PBw&MdNsTYvuyj{QYEla=&*A+rX?(X&+e6lb^tDKNy|* z!(P7LnW1Lf0sltR$m+k_!x8!(1H?(e6evMyl?DNVk%X&id_mximDblb+ow0Pyd{qC1gE$uIt>#Mo3dZd> zjx3do`{?BUU$lg6+t!^FBU-EQSh??I!5>@bI^xY)?>wfk@uTJP(cF^fDcB`2-N;&v z`x3>F#D~qL;vAQ^bikXxvLrj}J~m-2QwH+)8O1+~$my>tc(FFu8s356?_-Kt??t@f zOt=cK!=NUpbgK4%LJA8m>rcNQ=M?Z#|Ng|vrUzOuf00d2v+>uGE~8>CK&9@R6u#mO z0>g7Sh)a?GA`)Lj&1OHJ)EMTQg@9Qy#70NoQbKfpYUQPj`RX-6C*`fA3CGiklK_h( z=tJMtBB>EqAKw{?shW9GB-{D0lR=Oksv%xrSs>o3|3&iwE$^E|usMR@|7Y({z#PlcgFv*}3npan24)+~ z+)}Dbp(sfaiZwH$B0H3d$js=9jaaI(IwDJXL%I=hJ0)F}t`tiy#by{_z+fI@z~8e? zH`t8LYG!Qk=P@v2_~5Y^7`EZT2OhvYFlGz`24f8K{^gu=&$)}Fh+L}No!MQPSNERt zpZ!1o{v+bZUfFsTnj@_%Wi!OzSGN1Qa>{pk4iX4^6&@^_(OuR|%GciigbkR8b@PZ_ zd1^wNKVq!M(ZAmbGV+d$rKRq|w`PhHX||COtDPM}L`6d8cm#44$@8%C!H;}#EvxU) zgJrnFG=!GXFkdnb;!py_XIh=B%5Ogo>(g)WmtLQ~2d$6o)bmy-_0w*|CZtqX11H&@ zxqqKL{>@j#G0p9rRi3-#TPW>QJFv{cRTo|!qFo5yrya-Zpn0n>?qO3VUs7A*@d7!2B8gRx;SL>0=EcDDjTsaiVDQLiC0exS({rHP})$(U(J1=IIk46U%k z1GFZKv({+SzBt4**)zq`r((=V^n31-Aw&ft$K(L$Z&~X`qKJwT!c0$;iq`=2Zw??O zG{e`p2|g(w@fEb?q144HIG^)D43KH=L*Y9eKlE9{pWX zFCCY|nZu!6)lueoD^NZ%H&Oq>Kb?*VoX5L}XcNEX=7yy}o&&LwG$+R956U@u)yO?fT(w!=2 zlY*r3DPRyIj=aKQJ;_IcYuT*}74DxRC{sj#7?zRWkYie+TSXul$2{C_?L_1XClY|8 z{dnSLQugUZ;RI&E3AzOD#oQL37luhzFK|6hZ1Qq&(`6I4Z_Z8k94)6B58o&Pq7z!+IY)R&ff*A<1fhze&%T1Dfgqd1R6o*8gAn&G& zlN$AhOn{{OPylzyqfTjpp#*G+ST_J#WBBWSE>*5n*LUtzw^w%d)^%CZFym=E4Lz;58X*{(F(>{k;a@vuHuxy4qVL5+6OuIhF=N>evl^)< zqBkN*2OPUh^IdmHKMbeBh1wZb&E*C;b*(iaqRkq)kZm?kDmgX4QN6* zD4YqMvROl$3IwLf7DbbMZ_RZL?I21{h0dA6E%W{`>y5=x?NReuN4Vf)sSy#08-VyY zQ;v)bQN{07#K)-kkrj#=yN1@TDH6d$$9K2itFF9LUK@q?qGryTys64NosO0%))T3U z`6Ir9a}fTGH_oEbAZFe=r_bUZT4XiaV#W+^VMew%YtWdp;4f z9HeO*!aoOr3z;aD(=$QSs9+!N-yfE|H*(orsibL$!#@A6_vLBf#+8##c7%Gm6$MAmPOp*Mhi^`NDfwAR4bD z^>GqSQGRlSi>zrlz9Wp?=m5{D>;Rt6SPNj;>R?;p0iDDo(b%NcF_G&#$S4hOFpUQT z4tJQTfq05c5E|UJG^`+-NSYsNx8oc&oO2{)>J9WX^Wz#wPzCmfuhRX7at=zvCNue9 zT(b&s;ez{B24FP$Zrm+dgK>zf5w9{_cAy!<&BryE7`NG=ttu2k6r<-t`GViQXgG=< zOd_KOHxBp!6e^EDMs6sN==O01D7~Q;2qox{aA@cX(gF%B!Ln@R=E>~hNtn3 z3^t~0lXOfm<4tNF^+4pn%Qf*XsJll;4radLiI>Nm(_w}BTkO+`Vfw2v2(f!mWZO}w zhBlxOh4F!pov|1sZh*f{#|hgd)f}T_Rkh>Gxa6~$m(5iz`h-(ztCE7?F z;6%PTrU6ey9FjJRoTk*a4&4^+^m?x&1YaSxNI^=+B4ka0QeICLYVfg(ubcvzOY zyt<8ky_i=_^Uw;-i<(82%waNAnnpy69mhvD1Pbw#4$&>;$oo^n zN})~LL~s|OTnv4Br7FM%qUch+LunNhAWQrhq}>*Apje?`AKQ3+T5jyoHKKmR4F!b_ zFc2A7stz}pq~Wj%#afg*SnCnNK=U!JEQw^|IuVx0$5NMqdSw(zRDmtCN2oF4{9wLc z?MNlk#C%P~WJT+{piVd&HC~P#SPwuk^*&Urp0cQ~NQ=Z);a1`S8_AUnB)=msOG@U= z0t!ld;1GPy*^Zm5&2}jLTM{`N2Dd~@6KLh+DB@sZ!!jpPJe|~X;Cl9P=Oe2lkFQv9 z-x`%`t`;~aT&94Y#6;GyLosq84bv`~zxgLR0+Bt418=6zGbc(UKEWa+!Ut9rBPSq8 zb^swGJb+qnHKYsGTUcFk6ws0T zxodhXQ$npfsZ>h5rNC>|%I3!H)jOm6&>g69%_=1Pfln(fA9HxnR$trRIvi3_ zhPv}PHl9@pSRdjOdoJR(3xFf2wIb3?j_+tSxuC?4oadg>?_!6!r#S92z<5sTTA07m zdjqAi0^?+hspd4GrlVeKbU!k3nBRT)EKmR!z;&svpmc_%+)}hrsVrtHm6VKHx3#x( zceH}SXlsX3I&l^rAT)qs#ZKTvRD>dg3i!noOZOIQSZkA(Dz26oRXtLj1$B#_t~KCy zLJlG%c>ukF^edCwG>vFDN*hr^XS=RcAHn2e8e{9B@U|)!$y&4~7SjFU6Lt>+r(+vH z&LU(??lhWv%<=k0Cvpo$ASKy0)^7)5{q|fBc>~=8=4P0iYP6u}f z%q7b!u#$)O4{jH9#Uf_NAp*!jOv)Av+H3}(_wVO8N7TmVRxzd6{^gb1<-N6C+6n*_ zcZPLlcMuc!EnA4yVmFIc34 zsj*}dSjk+bNa~L|Jd*jZZrq_L&XNidZf$;?=uOpB+P|>g4mD6Q@RfE%N(W+r>*~TV zVA2vA;yY3iQi$x9RbIW9k22b%#Zmbq#Y-7Wm4cO0N-<1wM4O$U;W0pJi{^^O6tG2* zla29@u-$WMd}-J|n7S*y>(m{oA2zlyCtWs`z`DF=F`dzWet00$G#^mn50xz3%%q5k zN`h?8*_5WSXMHvdVSj(Ra6?)B$xdNFWzG&L11`rYsEv_|fc*fn%KDak2A^TdrF>P= z8cL;&YCkB0sz3B085tS5W(pwDW(YlHL_#~uYr$0+)b&q0)A_N1Ri)gGv)YG&K>hIg zAiyv_VZqb+%wj)X!h!l1!gh|8`A~To`MHg&trI1tz$cBIv(@BpIDR%GP(8SnP z$T3RL_Hic2)cE5_GQ5%Yc30PSqo6o`gRP{s(rH_;ETekrK|GDk2D8cjcclU3TQ4DB!GrZw6(oS(^1*lN{O_~Ra9@; zz2lQE&6CsVcx+Y;+b%?pzWHV@HLQYgI0ff$X~;w1l1#NyF{GBENr{8j-?%3=g!9GF z@c|Rc##>vZhBswQ4RjYuXgS7KOApExS4GLD;sD3Qi8Tvo8jxt$qne3mnRo-uUh84Y zJ8Pu|<_XP&U#FtJIhx*Cdz0$t#FNq9qz2pLriS%7OkE*J6Vh~jnMS}4@oZzeJuKrG z0dWb|al^BG0E$6=Q36Op4x|>lbUm;;5GR|J);V>j>vWo=gux3*+y#KEG&3QxnMUOZ z>P##cepA0{VB5e2Z_FTGfp`PedYukmKOE+t^lx^%-MA1MW7UX{#zy3YhAbFNNHdQx zfI=oN;m{!?@m{;jx0n>bLtmQ~MmDZveH$}26hucA=weDY{UzKThm`~Bad-}#?Nu(% zgZFPk{{8zwAbn)at*2RTPh@09(vq`PqMaD-Jm9X6p?%}l z_c19#QxR@h6w@g<-C|%q7x4K6|8nefh;P+7XM_JVSZXrtBQpc`yG4^eC5k559&68p z#*AplkO)Y7A;R$UzuJejWz4*wy|{yQ?@(oaymwFgs_Ah}tIwbaT>=PJWEtY0sStzp zSj$1gAZq95Z^E2E)ft;eAqCZ_ml7646e_^>0aF5?Xk}?W6WbB)CLEBYPQ(tYLbH?H zxEee)tfKj59&1e@b8&OsuN->u(KzxH+@m)t)FrL{hjGEl?3eGv^|3I8hLM*O_$cU-{yXpz4#MBjg65#Xy!3-&>yFt&_V!8-6?Os&iz;bxaO!Ryaij`I zRv@ChAZ1iQQUD=XRP|BSdulf@JTAHhQP{TvBB27=3ODKx00d@?C-xj}3N%h-gWN12 zH3N9ox@m=zJH+P9>B}c%Xq?$l$Bh^zSyd*|1=XO2VK39Vs$#|}S8JeAA6lpaUK)K> z%B*yBIa1uIgAO80lu0}svXiKxogiZ30ETouK&nyVUZNmTdW7Ouxb!--bqFKlYuJG> zC=G_h#+qdzZxr_Zl=e1xW(Fjk&j&yQgZiQlMF2!Xu#1$cT|b3;*gke-k~nT#T2P1- z_Q+^xa7Y&~I1cQ%f##uT@e&C9h2X(xz}4U$)T|eXR#zMwoR@kJ_9aZxp$F^2#`k=m zp_bfNFi0(v7O@lq(QRJJlsP~REqX(0;b>~k^c!7@&BMkva`uGrzvxa?8Ulp;9V;TQ z*{SAJ!K^Kvb(Plv3Z&n!2x~Wv!NHr}M%(izbPzGvU^>gmF9X!@~=S)rj6c6NI_}P5D=O==I(uQxinHu6`R) zw__AU`Uowww?VRlom3*RLMXM3SA{FFbHPQD?u6vFjGmK2myqJ19-%{IuE@g}nG3QN zMh`#(MtSv~#U|g<78bE@;jq(f5U1}o9f8bSGGiSOBTjS%1HS@pj^#i?J1+uY;T@qF z$rTMKx8Y-WZ(~ye(m1*_py(vjkO70u&SYsFqUM}2v-^Q*ycxs+TKcM-`4L-3yX6vk}l}q^CS|4WW z!x$P7!E|wde{$;n{U_RUaqJ0U(HVh7$vupW^hDrCs4CNgV%%hzo|54Qh2;A&I`0xt z9}FbC%J|PA9H586PmGGCDVXUQLpJl1@+ZgH)zdT&R>Esh3x&LegnRC};0qTCCSnRc z($Z*`)-L3%;gj4mAHdRX1;%5%Si0Mk^nt|WKNvv<} zZdQm}IBIxjY4+l40%z>PjacY2-5i{jxre)G+7bV-J8v=po33topvYS-5S z?NDeNj^v5^!aW!EzBJZ6cYs#&&^_k%<$4!WLoyrLz9NnIpof>t`8|ZpBr)X6rGmZ~ zg-tVFO@?xm4}dc^yR;<_9Xw%*gF;tw?&vUwql)k)fT{D?;^!KZFfk>G5QBwXMlB5~m?&YOY_{KJG*OxiZX^0p9LpKg@h)3Gu{fM5 zYr=jW8NgZ7#YrLx;T)m>fKC!hat#xxl>X?j4l(8sVaYHji#!Ab_pHzO`NU-#bF8xYrW)cc#;yw7JzjOAsUnWgHjs zVh{!ns1p`~ny`h0gn`^i&^b%^0CwatO&(q(Fzd+GM2cmC=51mY6%)z^VV5wIKtiupL>1=JQ~9pM?5@kV8KEVdrqN(CSQY1B7(HxAqF?+PXCD5Sbdcfk-$4& z(*nl9ZLNJ7C}W_3yyN;X*fLNyl{eqaTknXB9W%ulnnXlkGi&s?S}vdv;+E63tto5U zX*f2Y-D`l)yoW?<@)dulNLR#>hdOJaigGC8HwV0%4-FW`dPgVE0;F(-9TkEcY$F|R zOrgW|`JL^RtVw4^mMl^-x^AKMGR~4tR$fkbPQ%B-$L!EoJ3M-nk6OX!Zfv^iB6 zK`=H*%SkhqX;}7xQ~)!MSwUwn`9>};Ttd6;@jV+8Eu>l6Dc9k!88uz$l!B0@*2p+NA0d*iSu0`pb75xD?hzwJK?6cEFe4t(<$JF6GenGCCJ@-Lcf$5M=1B-6 z4$KI_sck>ZtiO#x9g<6AgH4P|B>U)yW`TkhN~=~%kV1?i1`*`VuE;c$4Y!Z{5FtaFF{XcjMro^vUD&gKSi4 z%@)HULM*beDToXz&fKQku!&YY@y>{C(0DI&b3|7upMoXuehFYG)~d)X9*SdeDsdX} zMp#Ipr)ve0!;#?$fOKYvQt9l66h|@>qWoj;mtYh0CnJ=6*~(@T7L@VrN;n8`?Dg|u zrVJahyj^8kZ9-aRbRR$tEhceuwBMnVrjg{sY=aj&`?whgPd`_XfZ3mr@Ji8pNsB`6 zzj)lP+RqP1!&Kt6*JS|a(Y`fvupsK}o^+~$#!Ie}K$TvzW~U_u8u>IenMR^?!HUcD zmWxSfKjgUGW_!SnmS^kA>wo2r#ome1rLa(Mv^x$)`(qZFy&A=gypXf8{*E;i5;BSm zzD2Lzp+VPYvKT}Y+KcBy$HPRYC=a0cjEay` z?G;7DwYuXw9n{QH?ZEUDE=nju#z;e^fJAdU8ydN43i=??aZK8}sAZGPJ}3RmPrOdg z*Hj^_K&jQL=$AwdxVmJ9)$Nxsw;I@=sKzI{scIL;XKo8MTflN1pW#FMY>MKu*Bn?b z>=k$X&b@p2aPLR*wFVY#dH5g(u)*e)>pSmM_(dWsMZq{^oCi!0LV@pm7y?`CqnVMA zC%4c$0vDRK4#*iSudVsTq?A|*T$`1>>ZZShz;3YWaw*HB+I5hjV+Sm0tXV_@Q8KS& zYj2=W=$8zQj4prhPagnvc&7spAqadSWLE*=7qO(V>7=#>X>y7&VTnaRj?%8fO4c40 zhdg~lh#SJEQ03A_Avr8>zOcHE0Ym1~8H$r@z>{fizRSa*}VZDwo zq_%CD?3KvO({2gm5b8rXz=~+TcGC3fK-ErL=%p=%lUiLPK%1!4=!&^Uw6d69+T7dS z+S^?UPjR=ZEsH3M0UE0D<%Knx4%@sT>6U~o;5->CuH0M6nO06liW8$3S_e$<2rI5a zxZ9cNyV$Cs{@|5s4v~0-!PVTsptsV8?FADnOe08XMqi*5?GIq)O99- zG@*5%Sty7B*vC!*NnWdPPh1ZLJO%~Ik#ZQk%>;@aa^DLw;K$Nx;3B&alSUGU!`tTiwjkfF--`zXKV(}7U+-IP2B3ZW*Nt}Vy2$4LZ|H(u~1dUq+>R>qDGyg56Lr?TUcJ%scf%q?XGTaSO;lY z>L8tt+uunr%DZK2eQ#}db!%j(#e}E*LiV;)PcJZXi)lMl_8<+6@WE(t>>!sJ zuO5`fk6{)+l$ngex6BjEsQ-ntr**dUb_`pp!3}|YEMPvZB4=$6-{hsZ+Tcd1ANS6O zm!dkgH{X4Bqic?L27ePRDUt)?K&JU}s+$+xw+-<)w@`L4te)13&cZ zlSRX67@Ld)w(U4lH9;|&j%>GsauqgJ;WU3}E9t}DsF9Zp#}B@oSFzcxg3~w(5i-N) zQI3I!1X8_YAA7B%#)au74FzuPEL&6T%z!2eMAXZG2>4cJtVV}5*!wLYy6VOtF_r?F zcTlXYA%?E|%LIKrvE7Hg!K04LE&Qyik}G-oXgzQD&Tqu`dyr6y)#BrihWS7Kk*Z z>7dN20d!3WSSTYb#de?&9p-p^BM~vWe6`6H2`yisj3Tc&sunbqGQDWd4ldY{uzmE6o_NCmJyA7RB6nmEb;|{0xo4zjN1hKM zJMvs8*pWEWb>v0RtRHidHCZIrhe#c{1l^K!8;?Y<<6LUw62xyTg3ppAdpLT2XmXfpEl;%F%79GF*!c z*cXJ4;ogGjJv(u0Cu{}dV`v|WJlu4eUWed7LBH3e`xLL;j(v=o8$`NS%m<6^0-j}` zdTyPrNg6bq3(P{?fjV9@k8mbuX05l~TLrt}9%JwTt@DRY_Y8G56X!E>4A|Dh`Rwi6 z75>S2jS&v&r=ZDokHW(D+I(|r!?zp0Cu0?0Ol-?P>^vNu%vqGDuQ<@+Ko`OX$9pJo zJnSLemL#wr$v=R7)Uh&;x62#Lo9l&4=Bf2bYkK0wtTk>;S_fm+@t*uw0UpEdG5E#B+c%%i*xd7Bxf~6?}*2 zKMI$l6@?k=wd;TtsvYMTs3$n~p=I*Ds$_BXaQ$Lp$})1JmaiEv5QFZe#Mg(83hGM! z_7XxG=gaP-^CDIs{Kn9&MA@!xuii6K>q)mHS8)qLKI*QX3y1DoKvC45%6U!bQCMhvW{>EM?#KYKVDYI#*k@qBZ(fFfK<$pgw-$bunV^u4q-3QRaWHPXb6-`y(g-QyTp9qxXN zyrAn*oC87qQ>jscDE1dnk4Ie*@E${u4|543#zoh-2V`Ze8Q^Jg9@q^EgFL)Hnwu!x zC>K6s7al!+djI}GZu|iMl*W&-(1QiW;O?P>hsRJ47%_g35iK4Ri(}(36XPhE-~>3& ze&>cST{vI|LdbErfJz^GIp+e2Mm3Y%m&2xxP*V;9_)gAg*-NYz;X$1V5o<>HIHrM3!W?e6`sKGw;PDvbtP&r5_#t0RmkuI!I z#6!hCaEgz5J%T|IXc%YaG2jp!_>MJKEMW{_q$SrxGGAp1_^R2@3n z#vDcY9gzcDOBs-skx}Q0=}W4W6y^J(bJ>lI3?B&bMR)2d8S6$ybk!Y2r`2{8CUkMm zq{T7*={DO{7tZ2hUk$>Dl(+}wvsS^C2R(~zj_8uzODt+OosmE>e&90);<)qzKA#Re z+hPTCH>~;b#{_$iysVgdhQOkI3_K3TAvvzK+Yvj{Eew4|w$vT3*ETSI6io#fY7C(s zSo`~>!VE^J$58&%fc7rVu%^wS$PEIz-GCWh+!Z38BK-I;>4mD~bBm^tN+cq3ML2}WN7UXx4nr~6XzmspQ2Nb)#2wRrjhOP#@gyF zBb>qz-0Md)Z-Z|);|PbYx`Zx7<@p1f8G6E>od&o>MC4bi@`6|8O82U%b{@-VWYDZe zR->l#%&{L15pZs>9`41Hrk4%W{qp+w92SW!5U)bj#7J^K4wTIUWcBe761T6N#)I@h znwWl)tfOfCAWh#7NUly^mO<%7_!xSX7p3DF{Al?Dp|0qYVK`Wc+PUVjh>~IZgR3YR zU(#{-_%LgM^~}&`LCQWly_Pf-SzKGLZtrbSsCd{YvLAiFIM%46kNm-?g^%!821Wm+@sF4N<-LsR`#s;O8=|^%3QY-n zfgcW!&l>^qTfMbz-CJY1Nz2;Ws^nRx#U8p>XTV?hO_hY2KWIMmPdYG>&q2x(XD%S~ zO;_y}kgGzH8O<#;6wc<@hmWn}hIeQ;=KICLfQF*gCwqQM7xIB#Kv?BOc%yfZsi^o_Y=sgLop=KI65*UI+NKNs130Zl_GTrgZU zXNyP6jXGQ_LE&dpMh0-sydK=ehmOcRrqVkkQV+)5WVP-;t3pnxbVIBC&h1Vgm0z60kr6sg+WK6y&OP6Z1~Rmrdw&b}ppoYF>kqHi#85uDdP}F5 z2wQHjlrO+xaO4F?w}~uf%ju%Qmf=@SG(okxvUa;#MOqWL&Wcq~RJQzdb3lasm|ckR zGjGv>r~KB>bbWAGK<#QfYe18WmknaNJ;>oX>_cw#9{KXap1swufOa1v#rD>y`D!tGU2IC z);_aZR899IEBzq(WFL2&w*2xSJs@oDOBT`&Vbqo^OB>R+=rROhh7e7*pZYhe%EXdk z%&H`vbc2k!S~?ETKbpd02melse`j8q-G0o?Zqp);$;a66_C?rg3@yujcC)%ZmUDrr zkY?va$0+watm=#~1j7RC2gjh%gQL5xAKh)66YkM?CyUd?(o2bTp%KY_W;NcvYCy(K zz~*>c_gWa0zj4a>&=1D4S1{I!mux&|rOLBs)Yxgl*xIz>C zBtI@5fFqYmXN}jQi{gO?G2-F}B!Fr|ce+Pb`jfu(N&n!Wm9~WV9j1^ATIqv~%kp37 z0wus9sZ&(sD+R{|p%&As#1;PNRu8wb+d}d}Y-Q}CmAt4Tdi3*M%-AWxIBcRnS39K< z9qGvB3=m%FOke3th0av{fYR`L{&^@-Kc+g=a15J~SfAm%@Cv3hfXS}G&yjM8rIezy z(iKCfybN0BW9FDVVg_ru>LkW`D8I<*Y|3B_KNsdzyJ?=61;JJBtmkrTJ*RtXh?}bq zGQScEN38vR1&X-GJ*54(}{T`g)=_>{(5emNP;`vMA zp&OixmRnlu)!h0Qd};+5DBv>dgT@@aR{TOu=B=6HIUUxDgYlx^lsRMoIz&V=<)mc9 zYq+!t$j8zEw#emAfvnaE(`z~rlcDReyWO3FSZQ2*W zpiLHMiltBGOkcwRG5|lyjQHn$#Zi6zpAy# zM;*1PznzJhR%rOFLNDE7|0LF4RFgUwi=ft%=s}ovq4m1zEN0f01^FimTs8#OHIR6@)Yv1eGaT|;#G)~_{hpUK5INR%px(9D*1^?21O%ev+qwH6z39?sD5n1OP%y{ zZ2Gx$$0obXX>%62Ym=tnMP0eijmLX#T;5Q8-bcgf#Rg@goYHXL&It)AO=8FSpy$Hq zvV}WYYh!a49z-MobQC~gsSW_IizBboEMDp?-g$NS1|PmVuTI;GKW%qj&_O$LuPOuE zj+1{yiT;sG(EF4^e&mwo?c$bBpsUS$+@!Cg;=oIZf&2^qbb73JHc6~J{FvEnJFUHq z)qCp2Udugy7uI_YM_Ph`?(df-?%&7nJ@|BnpQv!nn<`G8&J-uG;N&y~y&jrap)uxh zVA<4FvL{|Pr;F|>nblk+vr-(=SNI_%9z&sDGkmZ@9fRC-vIz|&xr$Ibw-{^AM-r(& zLmzN|4Lw|WqrQ|eYmL32fk%#xCNIOop>KTgJadXcm`BKI!|&?3}?B?AC>hJHVKml%VM2 z0aphCu^VUhg-^_p(tpXI=uO9N`POHVd9n`ye`7#iDPyEY5CBE=qOR1u4jSw>E`aG> z#n50`xGpfF7qQPO=cpq`izk{wnxA;R;}h8^DvQyv4j$Pa+g5SMNW|f?D%rPA9Q*X5 za00`2s3Y)7OraU%d>FJcTq<`_h4MA{*~Ccd(I`qUE_DBPzJJpCc;!rX-YniH7VhQj zb;VHw=zWmr$k4+57mhCJ99dW#e`go)Q|Ix`4lI?^&`NwDifG%5-XZa54v z9jDuWIXB10=rcTe#yw1ay ztE_xEjhPAa%9ZN+&YkM^%Ff=}?&y9d5z2k;oE|?vu`C%V)a+LEu;@W-`f@ojCHD_#TswEWIWdDmK5-`d^Wo|kXg8qD>vW5B)GZNJyx1cFG# z2(k8&hxacM3{AV%@t~(7E@%y|`eR4J!lH1;ko=x?A|Cu79bnH~I5JI)yoAPImhkQB zwSblNtqZSbJ#2YrmUC_+sUpDfP1l<&}-<+Ul+4m93po z7_s_X*<9aRU0d0%Zmm}0KUAul@gHu(-_^Cv%G)NywbhNc;p@&_XwLkCU0Hr_qrARa z5vAfP-Ysu0S2mYdu)BEcQW>rFjoYhtM7<*yt?!lfio{oGEMBQBW*UI>Y`~S33ces7 zU3*Et;ltW;<=#Eo0{9#hpci*^IClt;9+*~r(q2Llcw0NI5)mPw8*joT0x*#R9q(9x zt(~7MFu~inlJUI?CJVz+yiTVJtJ*-ocB|0Is?+IsIC*ej*UB4rs#}{|sr$KWyg2v* z3-JP^QYn6advBvs-Pzq<-GX&psa7^_!-qobANW9uEwXOJ`=DBD9ia*3k$VoP<_Q16 z*HDfPAh)(x07VgVu(Nj?AHAa^4E2jm6`@$P0BK7&XA`N&NDg<%2hHj@#}2dvWS?s{ zpgNpN6gM~>jPGmvCn!Av6j(!xPTxIl!B3>xC20FXLA9-hW7ko!b`4Hk*BXU)%mUD* zN32W}`2d({@>R02SPuG}y2eU1oC!i7s9>vOTBe%aK#>?C2cY{~g?l@zITh^~25rt= zK83cWHK#3%PrVkUt5TYx!wai9Z6O^kdvk%`&?mCj*B)Uuyw1dniKbd|&w-&|&eg=?XaC8Mewc@tDI#)60M;@&h%)Jly7M6pFN;+lc zfxAr$i~`KCtn|XL24>z`2srU*NSUmV!J^Q#kE9fiqTTUXD;cher&9>_=(|!PLoF3v zTT7MJ3OxCU?hNm}=(OC=r}m+Y&^m}63YXK~?&=!cI4ifyKzQuj&&6%fn4L`Ju35|a z^q{SG!>(b_h$Bo)Mj;Z((Ju)14c~BfNC8@(PniL5jbP$Pav0yk(Z(YM2tabpm@kTW zhsmsRw&ZG%ZzYw2L5dW2*)B;n=+wi#;WpbG;g%xZ;)PKqG=c3-hY$Nx|-b5oPt+ck2& zeCsWo&XvvEDHxY!FQh0>-jU~7qxh7w9z%x~t%(KeX-bwva10pk%AsJ_8aB{&w>=M# zT)TJJaBE0&-i~dh-EmLtu7d?cm!2-fG<|z+Zm6cE{o)~znO&S;7@N$#)?~K@ShAL* zrG7kiI%Ct8E#BCR6H@N%bbB4i-N7D+>s93icIs+fx>Nb|P<`Tcv3RL)1K@om7DKKC zyx>x_OAhUhT0iOnuOU1>jbF1no5S_Qu06!$i#REGtKh>ZwxMl7pq7!aL-8442A$Yl z6pE@8-KA+gqD~r3bFPi1#ty8)QKRd@zi=ChYH6k5I%;_Z_?kv8kBXk1ca^?Q(hZ|l@P7ugy9GU zQolkMu-%^J@PO7jt8?3tK;DK#lj;sfS)-Sh)2te zrg5D}7cqMb*)%!@a$ZN24CmdC_%6l|*CT(G?@>`6Qk zEPmwNHy!k;S9nC?0^IGsB#df!TqND;2|Ju?D7rg!k?z9X26%!^Hyuk-hnC&w0Ka-+ z)|a)h0*U$>F4OcryB7umFX@*k(gu@oip?X84LmIMY1;e^O|uHDLe(@Qq@nAlGmnQY z`&6PZmih~`1Csr-iDtUcNb{Pq#-|pg&1L{%|jCVS*QtYFuFiT zQh6o=6n>cI;+4g*ysO?f^1wQ*D=~BL5&t*PP+I}o6GK8_HWe+SMiUT<})*sz5qAJU?gH{ay&Oo6bHV4WZ_j6SMDVd8f4 zC_~5!1CVY9|4tvj`DPk#vE|+EU0jIdJxmgkz8fjAg!&{|6=cVl-Leu9HgR96u{6cZ zOPi5=`dMeFMh0DiK!HjTkvfB@F&X|sRD|i!Es5w;)@2&e177*B1CjK)_4;vE{CwYf z{q^hv-0A`#3YSM&f|Jk_{03W-4(0xCh!p2?EDJXSIFPiH94+F+ov@;j4wxIrX!g=_ zMBfl3qOB8=xbe}>Vmo7QR_;w=r~7;tdo-~?(rQMgT`82Q4AHdA&$@!{g#%Bk;Di=I zh@6E8B{Fm=MUTpal@y&6SGVWpq~;Js=mW&(@NuO@o=u9bkh&69`AShEVwfRhcRuI=t1pF>FdKooGevRd&N^;4By2Fd z1!c10`pAZ*=AmgoJgwAxdpmbWgCXQn#x)IfD5kVdrQkcosN%g+cYPcTHb5i~UPr@P zmrG__&i!Is&g43_A^=;Yi zb-gAAmy0VElcn7((DdrPhLbR@;$z>bk2l@xwb00+l^SSQmI=R3Ma{Q@9hA}Dr21Ko zWwbY`!M2#GVJ+f~P1mC1A|gGKmY$>hRXaUk6`D@4pHnC#>viDDAbtiYI;TY{VMIMg zfN|(x`c%X(rdVRUc!c#fH9p9!ClE+I1^`oyi^fXxJ2~r2R;JKs3lMtCCq_!zvmh1L zB@BmPeVJ!h$RFxJ+jW|hj~7vEip7(+b-c+ovS=BFhAb9K2m@>ho8}>mMxQ@K=7>aV zy-tTQD6@qmvas8j1Q;J04NcG}+>n&-5vsuPE+(&K^q%!PonBig%6+FRWqC~%m>!i; zUaKHFs>OZOlYS^G3k^Z0HTiLc^z)w5+QUS${!PN;S!5%RB+cAn`XH(`=_YAG(y0M0 zlRb2_SyS5GrE|@!%F#+rl2$}g z5=hQ%Wc{ZF>#qW}W4dg{k1~qI7mWa+@=AX2N`5d%eo!f-k8aGE;)6m`_xw9 zQ5BsasN;{9Kq8nAA(2pCebTiQoqMFqA640bgV~=oqVdNvN1uf+L-Ip0KrX=%4NKAY zrROzArKjosP&H~jkyg(d{!hx8C7L^0FSh5>8w?9p9Hu zPq?xA6Ytjm1%BG9!OyZ+*WaDdEUoEaFZIq ztr$CIW3#%wySplGl7y=;;UesR4JKWJL)>wp8xBRP68ixO1oQ}OqaP}aAp#`+475Rd7f)!mhKEByuxx}DBj zrHP5WMKZ0GWpQIX+m)2*)16oM(XjUsUq;(-7oEWwg!32NMwh&W60aLwyBvg4Q)0hb z)zcF93_#TL@u)C@`NFvI3Yc))5EN-r4-@xcQ_Cy2_clz)2!~8^j{tX!B8~_?SmsX{ zkY4is{<>M#e8Db10Dw+Xb$4@fZ4^G_E#P7EQX9dD!0D1C_p#(>--I_$Nt7$!ET#*` zR$+5eDh&Ya&fcw^-BDQ}cOU+@e;-j9lMS2biVZt(K2_eUme*FxJ2dLh_zVdVg#@u{ zlv|-tDo$I6KuN;Usk1*AoW4W1;dU?Psh}~LA+Xp5eI+)Hg@{{+O@W~G$=a;oWC7Wg z&!s{Tw=07n0%DIq+y;Q+>OdL_^?Qwm5s4i9XCiGba0etIDwWNDHe(r zfU!h8_7WroiwR@J1k$orwpT<%!cL^{?NE!bkWR;LSe)5atA=a4;k61dsSZXzEI4&w zxoo)>GFLW|Ib9l_h;)EH!=(QJnkA)9F%MMjay8?dw?4hRxBi?r1!kY^HJ{_Y5WS3^ zH}N4ao6K8BcEfja+7=K+Xcvg*McF}fX;dr0N(wz6+pt+!ht?*TR#`_LcGczOwKeQv z3~d~c#G;HMTosuSGXBkW7u40#SsfKs+ys(xE9(t%xar-@-Q+XiRY~ zjPc6~k@4@WEQiL9MBa&0dnimXk9v*9ML~w<#1jB?m}nv|xP=aU#q@S5irRk!yDtbM zif?2%J758}I?fSL?9y*ybBQrBc^(OKU{{05f?qUI@b4l(O5KCM7SqyG zy5x_)e{Xy|9hx_SsLr%D5*`TUDnR~Pj!1;Rh+qe74F63Zgd3FC{f;okf-~M|qd5bd zG1LXvwHk#sCHG#yB|z2^LP5vy(Na#PfV9XWtI*Q?dDU`pfPt1lrHFx{`Pk;}$~;E` zA%!VMafRdVv=9X~-ELQeBBU&Y#FMx!zzvp#VOVKh6v}{#8hlv1chUWrV;v}rfw)0b zwt*LHIAqGD#b{OFf>?$f8J-FN$;#YWv;`4i6wwUAv5{@;`{!Cp+d9T{(9SWn^1P*e zxi)>)8xL<8DpoPjnHHEBAOm2aKRmAuKstnEHQY#U+!O-~cPh4rt>KGfcqme+TbRV2 zjEIXloQMH&>RCD~fON?vUey%^~aSaAZCxlg(Ng z@rq+zRuv2Et9qQB(DwCWZPk(SOwepb10S}u;Zi@BUkPna~!0_eEJmSV$bhj}poOkWS-7JZl!`{C?_1Sy@Kqs8*;>N8?I2Se>P zIj&MuOMV9LLURew+VQ}EI3^n;oZOo?!>@xba}g?Z2lYMsHLI>157kwL4_ zlR}`hrUH6ZqwqD90!>WNjZO&4ZDA}&-@)iNO%C*fVQq=r42+UW6IP+oRqI9@hIU#2 zS>H+zobz_a(hFN}TBQdmGv<^5t8g5=g5zl7h2WIxm4c6bb^xt>fB@hwkcG5L8fm2> zc^gJm{1)zRoqBh2zb2DcqO1&k@ zTn5z%s6P1}pC|CI=-~B)-DxVEW?nZXte;kHRhCyPI1A;S%IYeILE^AL_nvfN!mR8; zX`+;UKvt{e9NJ1_L17}#VW-5wJZQ1;T$e+}v^!3hWTYZ(7Yfp42IA{{C-iEE3L*ew^w61hpqXsOJELtj0hXAcK%J zckIECr-rDm%I3y9E89D(n;R51eHR{f2F0PLK> zvTngM8sq}wauzr- zfaYV9TQ#dhP?P;LjKN#n*b-i+?zS*q9ARgIhl!m##xjvwF$PZ33cU>UHmD@x&VL8YlOlJtp7)@|MVe zytUe@73t->9h51ykk+_^+w+~G^$w=bvRedqT1)TbvgrH>0s8{*0{g1!ZE5XT$FQ|g zI?`)3+@_1+RTLuH= z82IRSB79a@2E>VFfOWQ*W&--JXlN`qw`lRJVmsiz647K!sMb}a=X!bL&e}?qivtf- z+1@Om5DOyB%93B9}CW|@DW+t4bZ{u0t^&dgNKdH zUHozXa{DjdCXG|G3Gldn+^W#PQM;nKfQpJNf$G0u;n8;i@SiFAF>P$&y^Xb%ogGnO zCvHC0R(E#wem%o1m=hq!DLmKE^;Ig1+?L)t9e|)`(i|^PSgMIJMgn|evLN3m%+gTI7+j6;pqVsAl76B-9O$8m| zT~SN?Zf!d6lR_*&#(wIGyNGr}=%R>h99&W@!a52zS2tF7;R(gIBq2x1=MKt2 zD9Qwj8lmep<}Nw48$FD8;TF;E?^*)zHy8kLZc~$mdZVGipmzYNp@9iT3fraSS)^8XFoVOHjhbJ! z(nN~|uZLPm7vpmr!4TV?Pd>73K?Mnks7QU+>9M7UoUSHixf6R%TK*!mB9en0bel!P z$vjSDi~W}cuq^u_XQ6W)D=Yjw3-Tp)vJK||@7gmNdW3lx>fMp>;1g0@@UU9AiQt?kwdWairP3he;S zyQ{ztYz+tE$o9Jh5iCG;OMiJ^AX&YKx63;S0Xn+2HcTV7dtTr;0E_TwX+JSdi~bv( z`HdE7EalaE)tyZ?FonYRIia;4raV9-sW5%ZbjhEbU6V=6MZVGtl1 z3ghII_hdKF+;{aBS|wGN*EY9SXdS}XKMI-TCd;ekI~$uj(6on$sin*9+ zP`WvF8R#2?vEXS?Cj89K=7` zXH%2%x#k?#Y7}$DG>0qiAXBW2;KH91t>wZ66D6=jNvo+qoAt@4Xse%V<~7Di+$_JZbrs~q8X6n z6-G(A7NxqxOi1Dn1$d%M$iRs3Gg&zBSrnXQTV9sg5s&Q#^C-g-W=P9T2A;@>{RcrtZh-wY81$arfcb~`K86J zx9{vM&EH%?5@kO=!j**u#rPKQCw6t8z~p4(?ZwRFt#ak<@|~4}sQgruopVnxRj81k zQ=lX>NEU`f5hCxFmy1NulHXM5sz`_}nZj+&^BzjKQ0Z%g^!2faGOTw=e=LIu;^uC8 zE#^{HBuu{;7|D>$n|tKzriSoW$lOp$peQlwLoyKz22FNTBUDoZ7(}N^-^)N9N+ows z&o>&KAT35yJxFyNfgI5v$YnACCaVH%BVPQu1FAyvM?oXc$W`;)hTOL!gfrXMkpE3|%1Fdd-N}FZY^ZmOJ^Hq3>6{W(1Qz=$fHoiPuaxwqfEmV|4X- zUNb5HT--IIMb0y>nS}UF%5Fqb4-7*X?d2thN8INxo_H`av50hEd1+$~TORYnXh)4ADk-Sbc670nLhxqVEl(*D_x|zZ*ui(f5YY zONDP3U3@tFJu~RGF(jD@caB~rD*{VrQAo1e|3=aahwmk- ziF4C*A2}TU-1fUN;VcU!lCG$@aXiP13OiC29Z9&Zj3UXrQK;A#?%frhvgdSz8DIzP zfLuzGNa;1Tdo28#ZZj+9I_tkPP4lUkJ`K3v%u|%88oA_MH#F4vdv7m#?}gFIRc}9| zXD?0&XSI9XR1{BNP7Y_xgS?K0pNRO?co}1kzlL6t3^I1Z^uOX`%F25_qO^PFJ01-b z3W1(5;eLN$DjMYt{~)Ar%tqd#+A(_N%L^a-qpp0cmd#ra7!Y8W2UNNLlx6t6uM8@Sx9op7jwRyR<@t8~@EJB3nrc&J=Bb?eT30Sf6A9QdfFH%_KiLOTQ3 z{Rz&+6CAp-u-#AYz^MJuw$ePo>743x&@XhcrKAH9dM06ch?Xe^#0<|Xc2uKSjDF_K zt5ne;Vq#aew>P%~Ydb}9Kp!I$a6gxdH-Bauf>R-1(QZo3VqDB!G|!mUDA3%W%INp;-g7CPB(-um=PWw*M% zxx4}lf0rD$tZbnPQ#1?skC3W>BxfeDJjZ-G7z6?k9NR-1;Lt{DR2uwDP3DS**X`^y zhosVK6s9Jhn(nrJP!rDv?`L+i99$vr!==CAIMA^Q?>U>CWR#lMREj3IAgND|(-F5r zXm3#N3noHgC1^_tPsc=j#Ms6pQA4L_0C{R+L&GX4&XQ(WSd35;fYHaxKx0dv1Zeaz z7p5pM2}RjKQzu-jr2LN(+U=EADlSJtBId{SWM(4 zYbj6jcPSFcMVo?E%IzR!zcC1BYoMT49-gq};gFnfyxC$LgF7E@WdfxMAM|JGR4-qK z{YZdMUb6X!nhU{-nW$!Yt*U*ETNNk~tV^ro)Ov6wojPodxt|ElD4QD$duYIyg6j7U zfm+8MJqWB;QksFA1$W=u8giPXNC_CFq*f&`z333bAwR&Di>BCvAnQfNp@BQ6cWifx z&1ty*RMNNRG?5-w!@h7j$pNu|!;@Zr(&=xY%ir~WE`Ko&e_u52ezV$IyclP{oxMBd z?HE_TiDKaF2Y1Y8Jof$v)#uik@EVpY04sVYCgiV@9& zxN`q~5Sv&cPM0EiD_@o1y2gF5L4hMI%m_!0129^Q{&s;hFpL8`%{lp$AL?Xrb~11I zF8U}SMt1B@!=-59f`TSLrsgzFx^-gL;c`3n4Z2IrhH~SAoAjEpdJJ50#oI~z3+ zFS6Ps*Wmx~XZ3zAGa+tf^inx-kI3qqA2Lh19JwSJI47<<40$rtp@e2j*ty}_6`P@E zcSfbF68@|QKSL|OZnxZakK$Vc`apWi7t!a`P8AVAYL4&YQPvI!Wo-4k_%|_{7#@Ww zZ;Wy#am-|K=0@IPfzby&4?~o}i6cLhZsQ`na?o`#>igzA@;JhaI>86x$Ohy)N_RYL zF;o#8@{KNBpD+fI+PR7jR-2#{S%*6H)STk*%2J>oDtDj4T+7+F+ij;+H;nn2w5QOL zf;7FP-y;;>cDP~94UEu?hfeoha{F#_#QQFi*6l{mx3a3eY?k|wrDN%JMPNbUjbo{D z`=y_)ghmtj&q70OBnxMCW*F2)vh8RHNZ6T3wftC+uaLnMIveT{Y4Dl z2S>%Cr5Kciq9uWn;2!GQ4;^IAK#AOwuBRKfQR2C?cN_l2{m)OsT^YmPCpL~8mO)~X6P~l6%OcN-rtI>hbr+Rn=JIl<9m6EiKN<^n{v zFs~M3IoR?-XqTCdE}z@zIvp|0$OsL5#gp*t*KOjmQ&)6)c_v^hQhZ>EX@t)K!dJ3K z65a3Tt^3O7K8V;PsNT_dKYi_XK?DzHATN26eR*%RMyG*fUZQ=aB0NNPi}dOjK!W8U zc_O{FXuA>nqh~W|bOmW9L?kj;VylOW8-HYEWa!{WiIR_jfsS@+Ubky~nqqrxJI$8e z>VBa}KbB;;N2f}GewQ?n$aHD$hOq$Q!M5!VQD~^a6hSXiAx~wYnb5@^lf~)ctjU0B z1-Dn;Sq+yo#3(X!mVyZ90y%)H=;vaVs%2CB78wlVwUWH&Eu$W@pzjiQE8^PY*n~_D zw;wVrs4xDM9z;w+k?jDOoZ7n|O1ZVzy;6we!!r3t7oq7T{LUJkd4DSw_oYj^H zm*IEyZF53=F4?Elr6lImwUuhX8pY_qLT8f0n8_?+q2w+o(CKhKhZ=Cg$1I#tM~BDE z>^zDe<%xuM00&4=uY+@4-dd&Dfv7Yg019DZ)9_4b)y_CS4T3v#a7N{tV@!0f$C*&_ zYC0$e&Y_FS6u0&em8#t=ijf?VO{P&-Lquh7i$fBVHho;c7}ur=iRF$X6!N(4M0%fz z6chjz4fc+|sM`&a z_&5%Mf}5^&L0NXx#0z^hSrV;%IIK=EwNmKTMJ~CRqq*GikR_GYN?m!H@@mN`u8>PP z1Edv#k0Hr0Sw!Q^zVK-(YmFXmCi@6ChXV-gqD#?&kj;b}s~29ON(3qDMF zKDaR3hcK1U(KCT+XkU|pf%V1eFkm5d8dUy7rBxGo^_2Q;miK5GI)!Ob&p7d3y<@|2 zv^1yz%zUuR;2;2fFEcY?Z{Bl!k>sZ7*e##umbaCM5+f1_@qnbD6rdr;NN0zH4tRha zLU>lM9oKs$Y&vw1zOqV1K;3p%?146ra$SZYn|SCrZMG8NndT^?TpY8kkl>aR?R353 z3kp?uYiDz9Wp^bxR-u`uM(R36?nD`oZDc=IBWjis;@NQ08B z|HjV%eTnI{*s}hzEXDSFA|On4XJzen>}bMelKVzWU#Vc$ zb|Ml`6v^e~o8IANm zu1plt^2!$G&=wJV)>n4#ZZ1ba#TFX0w?mo0`!8IibpKVmv$lDwjF0QL$XbWZHxidG zrueYE-wJ#{2lRX^c9Fx|lT()WKk`AbKJYeoc41i%{VuO0Z{AR`5Ip@>jk&rbpOdRo z3Y(jG3Z_Y8do_c6?7CO$CiqL7R?_Wg%wjK3`w0jp8fEs!k_!>@s-`Z ztz^W@pX0A7KBLQPw<{a*m!@8z|0!F34`zS0B1Ya9L57MZ5;HR8djdTpKF6S`SVyTa znu;rwKvQ6H>dL))33P@0+NbjExw$@-@oS&Tl#DsCGNpV@Tp8|MRn24qy>681Hwm$j zVoMC_)4hAc^(rXWe{lx)ED=(;O<0ei`lglZzxD(BmJBJ}CM@?*ebdVI-&zCvmJBJ} z=Js$KZF`uVwmo>OZ4a^6Vo^x+dwfT31M(&c6w1YR!zd5~L&V-&t}d6i-(B5cY`PN# zl~Aq^{|lSBvb7bD7W4wKTqbI}R`8;&{_4F=lmV2tV>*>kE{Sg)#E}olj&qjrSahjA zC045>)~X~{ipT5fld$ZKNa`mGlM|B@12s?2AY_NCBxb*YkX;5Q55(+O6|$GttL44j z&GquzN>nr|{v9Gbm6Ao@E53(bd6@F88yI=P7#z;gEd*LpzK#NN9KO?XI2JqEqT*yh z0nW{0*GLrCBCU(w4$A#Tg~-%BB?C%oOk`m*Z4hB*d_#0w%%u#U>+s-FKV>(oRlDs5 z8mdyUG@B*=fE^50j=6+=md(XLAVIS*Mnh2@CpAVt$gW2)I?e|@7eoFdtft#?o4uwK zGGYpD6e!|cG&wZ9WAVPEQ5I81JOS)j(X?j8eSW*Vi@v4H9?b?hSY#&hEVx}KIhX1+ zTce;$Z7$H_R>iOod0uu`;I@$B%h(+uWtxHHU5;H7gxaCS?Rp+e%^v9z0&R*<+4PQF zQdN=NnRo2gP%R*OAO-bkROWNYdEu~0eF}7VrvF&X@TKzyofvdesqAfUuWal_mVdBK z0b(0mlBB&8_ultd(Srjyba-OxYQkg+BAmG(A}nSijI4Lj-2VMWLauW$=t1tfAPb7R zm7}wkVp}LgWn_gAqhOA!C$?kkMpSk$u@!S_mCAeffC<>HuH4%yZ!BBG{)reU#N7_1 zFOJ&*J-LNXk1sTNWl5CD`Ng#D9vbSXN%Ng99!SjNZTHS8(K$M5X8cYKQ+-2m^66}e z1hcY%yhtpK4$pupuc;c@d{DVq%#xBydx7tGt~ZZhR(c)G)TeHYX3y_hCtizOy8${y zAwb*Noj-nC(#|s(Z|TB z!`dQ!7SMFxX*6>37z-P48*OWCR?|tQ?tzX--L3#x9a*+xuBqB%}h+gO8U|>+LvgdeUH` zOR4QPeAax5JDyg{)|GL~|?ZY0B*3~ve3c#ktUf?Yl42$j&0}we7P)-Q82&O!>a@X={w9%uo zAl90@*%iC1=TiznGU@I#DZ!CcCd-WvrLuT756N8^rc$zAV^Fe_(s!=1;NUgBOr^$izxMWrGMG%9n1 zmIjnU*~RNm>lIEEuYQ17aS&|H03%A%mQEW>CoB!PY1&nEGgAWyB`-AYY^Wg(z(co| zjXhDD61S|l0MKRuU5VB46NWCbC}KHwm_fe?TOSXM0xx|=er)3-?`c37dOqi3D$K3u zBu!ib0OM*_QH_Y0!gOWvLo|C`OlkZ3L9HIz%x}D5wa@AgQi{%kHkVh?5TLwfUEv%$_Y{aT6RvO)(EY1kx z-V9!cM&g)+L*p>f@6TIl*$5Uufu$W+p8Jyd3xwlxNK-dJ9e8{+=tlCWII$b!H#S}o!tswh6N0|1aiJWsjd zlQc=Vuex2eQ_x@%dgj+K#sDym{wc*M+pI%8l89nM;kkm4MZRFBoL23^s+~Bshc4O6TGAah zU8$t=@b|rY_|N98Pgmr>{AOH2 zr#8B;opZl?(IBUg48e&uf|CB)DctQ-Y$X$ZQX(Mi&{?_yb$v$3GKV!~eid%e=)~G<6BGb}NZ`;r?)fr#J@KUycW4&v z*Z^Pg9SXa|xj+dF10g@a4s49=Wv$00D%EkTK00s$X>dlXDDlau-`15l)4b%Y+dK#g{We zWkyiU1C$mNTGoEnAAkSa*um(&U3kP0SyU==V3=7Ii{3pLQ~^c)%F&WLhH z7r~2agL0)HF$W+iA2CMy3(q5k{Ns3pJ5IOP#xuZzMk2wRC{NZ`QVF71ORD0n3K%3k zf<1iJvD-idb&idbLD6&&o7KEVui3J$PgtYW%t4N*8UX|afq~ArcH*J0hOKZ5jfKf? z*Qeu7lA}Xrltf%u0qR{x^Dm*)k&bZNU|fyUgO0hh5%ax_Jsf>eQw0KS>W4b zf*4*ePme=%Sq9`FVb>atVJOr20v0CH$T@5pZ8dxgoH(NYOXRVvDK(ULg%1s;1 z`rV8R)j0R2Blu43YpHm`f^!LE$Ah(pp_V4B@k6&Y?w=Hmj*X9rOKNO98*M0MM2(~x zz*FOP7vp(q@lSHPergP4%hNxl0XTkY9;Jc}L0kq;dbUs#K~M``Rz(^1kt`4*{dC>- zPnv$W4p=!YVBiKMH$AJ{>$E5;Pe6(9^jcfMo>$&{GuTEdG)BAQ0TbMin~D>J<9%#F z`%Ktt?n>gGpW~YOCus1PtW_g^|Ccdm-;c5iCe5eZ(%r*#S(xXiOW&DZaN` z@SdtdO}Ewasc5?35$3=jX)PvdfLQ1yP$oIG1$J4F&jko$_$2lcQ-XSO?3zMgJgcI5 za4iHF4(|lQ)Yg+H6ki0o=a>ORTOMAId^-j`DU){}aY0>-hud_}1Jw1KB9Ir_rCiX( zTHvaAsntg(M+t@Y{Gr2AYC877XTk07cHuo*jyR|(lLJs!+qn!YAE3c18VMk&h9f$^ zaC{j-H8d!aQjHwKnR_Uswz}qcoBnBS&U(WCHvJ2qpIww2)!J?G1wVw=MJ)ppV#git zA)W=^g-Ax&wAo17guB4w(VW=6f`ikB+~tMSWx>1e$mQmFr4VXPi-Hmf0^*oLLrX+Y zPA;VG-zY{!1ug>R~IhJ?)l2_p#vSgedOxDY-MAXwH- zsC+u!LSNmVG~OC1Bp5k~3Z4&StNKyQ@#RG+;H4g%Q*G;NF& zKk860dPKg3cVT|LP7cln>qvQqx^eZ$S1nBD>Kb}Mj?F$sRO~BPduSMYbiFvyzh$1td9A&ztU2TWzmC$3WsD73?iq0h|poywV1?oi`IwctpG4b zepcF;<&`ZN4p_?ZVI7&QXYC8}Rv0~0>t6RMbkt7=wx2v~B?k@1Ej7~>DQRgCV_#;&3&vlNOGA4C zJ7z}RM*~5X7caINmZ-BSYsbOM&+<{DqD`@Lj-@eDJ#M5p_%a1lVgr7g43c{2xbGAw zIDrV>4j_jlvv}*N8z7J$E$SL{dBq}yOR_{|F29&P$O@@J3rXq=xCENP)Bcm}GIAjk?nb=3hhNrKyYZ-EtxER8M1c!)rm+bxI z954`A?KKA@rvM27jFNri5M4nW5$|t~Yzx3yR!X*9ihFgaOQhB#3So13bDkn(oQWKU zG@pbjNHZ&qFj+`m=YSz(9ApURm~k-efYZYdU_F#nF}S421-lJA-!kA#&V zapiCxJGI3LA+Lj9%_E`=q-2iF;?{37yCh`(f!K({s<6D`NTo(1D2oqZ9?9BgzOH?RaVAIK0EOmJS1_Iqqzf1QjSp+HBS;VBI`Kf4-%0|5(yXpXJv9? z`nqIlah2;?H1=h^4Cz@hU~&h=^z}d_H$5>i!Cew!=B%H8-)!SS|uO_I1^B?P!D7|Y*H1J{?^fwfH1cAHmYlzcSiTw zJWMr_R^0&NORoMn9C{d&Sc3x6-VR)YVoRyo8T2kEkXX{lJxu38CM=I9}+ONo6izeHIjYWbRg2SQI zY7c?Yv_|d5q2qQHewUi3fs==hNK$zMTX1g!NLwN!#P;HZb@~Und!k>ON6~kk8ofi_ zCt!VW+0%{iKx@T}Fih8Ip+LbAsa6Xcr=&Tp=fy zEHYoWeP@{xZPA4qxDZL1J83Dh#Vt<=tczO>c#IqdseR7M$XaBv>vifJrb`_qQ#W|Q zqG;ZYbtlB*^d~~1rgFq(Fjf%PCzHeHrj8!T-*g($#z0C(IMAueizXyKi@Gc*EiK=c zJ(WU>oguV9eZ^-tgPr~2AZoR90qh)GC6ZF3>v>kQS34mwS5xR#SpG|!U!)RnF?9U} zh5(e9h-%lIPM3vJC{Y6#x7bGkX$}<3!Pdu?FgoHfY*sXtB}Yw__(8M1LOdwX7S+-$ zt+WVDhCg9Y9rl>+y(Zu0Qv0F$fpxX%tts5+@|N&-qp<4*&U8fajHCXY9HedMD$$OG z_X#`9QOJh!%rZ`-Jm-_E5|( znh_on$_G+P>CX^TwryX~zc7)MPEbUoBw`-j8iY@%%r6%8gd{bcyqm~sg340geWj)Y zGzOP;mz{G-$s+)_fR_m9RS|<$bA!W+m_Cutl{-m}IC8#FAZbf~s=yPZMj13HguREx zA{fY00%boc3U*7DB^|G==A1jv!wI2QW8e{U@7WpV&nW?#>^+5eQE(z*2| zAWoDD_99HRSxADO4ARX<_%P7rkbXdqn#mS0R#ss(Gb+7Z2*uE~8oYywMWMj6*~2dD z8^%pS6YDk5uYy@!WY8R9OwxtbVw$bBHDQViz>)RK>aAz*=Mp3I7P$2bhKxpNr2)^tTH>B8 z%J3N~QGrF5lAigovPcTX_p`DE63njNj#Ig}C1>Gcv(+`q?m zzpvX`RTOatsHV6wlgja( z%jIx5muTYdN_lx@TUI^+T3%8@D$p$}cqGwvL3rU!O4ja;$3d{Nyqm5su@lh4LH1r$W^U!sd%G!jy?!zLW*1jQeelPR~JUEP4rqp z$j2RITgcf2{c+zq>2}-x{P;L$(K~MSieBebE@4S>=_N!vs*lI>QzVRs457h{*M{O;R*))jFn zpyou9ETU`-p%@rNp@(vGd5I8MKxCu){5q#{V)6G--L`!mt%)zGp2%Ag`g}Sk@>s>8 zyFlqHksefhXLT8_jN2<~J1Zd`4O@t~r;MVdZcctpV((<{V%fYTn1Q!rVzqC~ z#;Q-pMCGKOVf93?gZsv=DoLHAul;(bswZ@h0VG2nu7myNPkbNL$^Nq_f%JnP1X&6n zs?{}QaklqJ%Oi=PUFjl1(K`6_qpffdXg+ZISh=^da&MP75{!|L(p?0R#hZq|Wp&q0 zB%RsARfI(4G9<1Bv??Qu5DaCqaN-HsBxdU-d7N1p^D|x$T4txmVv>I=<;+8tkaHf8 zlT}P_STi4I7$Uz5iC+OYjtsv`2h)sc3^#XH?}>D&wg|&<)a#-UTvBAjzeyQ+nk2(% zL1P96NGW3IHs4;5wzJ3`%jhLS6fRhObcgi)UQ?zhr;HR*g+=Up&21A8z2m8%7stmP z$M-2XO2<1SaBM!TdEOx@DO+}Zin1j{WXjCQN(&1}7;!xyy_>8Z1VFhGT4sM)xje%Q-~c~u4#8`Cp2B`TFBDF1(5@TTn{OZ7o|@?L-~%1?1oau`}@~LwqjjU)H1)~R?k9G5nN$ah*vT$CrsZFo#zn)6Hhn+CG3VXVVvQfF%$mB|4 zCrMk;;2QP@oF3>pxnZWfmbCI$mS=g3P4~#0AE%>m6lAj(($H2{3+scLypG+uNQqEz zhYm2vE_M$ypL*zH*_54>7UGVKm_cq09)|H~O22^=?IpB7!8d$7NGA!z+C0-hKmx%M zBbN$fR-2MMx18?ysq35-+b8W$x%I`F>B*a^)E3L3x(+!#9T((&S`xIAz)U2MWl|+C z^srLp1*~SzNx?{{Oojr&kbV^Q9@#YpG?1_|7b!S|t2&uAN>qh=gOX?Td^F(&)Z)mq zu6DY#VlSpru-=*|1a$_L%E}f-3ckIvy}G$w-Cmc>0~t`KFC1TY6=DyAiXN>)xHDlg z7D|45ab{o0+_f-5mTgdUs}m=S`%VLt+`NXkNCI!VeE zo7D}3*l0I9zVcU?52*07vol45OAW@j0zQ5d`m##5mlz9KQ?2 z_$lh2TrN(+#Fi$lQ@7)_NZ+LvA$g%va((hb6pgA^Jur^gb784k6x%Q@kC%C;b5Ya; zW{N84*e0_1bmenudLCwhJf1 zl1En@!X-qBs01xRnYuKQudf|2(LhSrl)FLebrB|snvo%0(G7+~KTN(7K2*uWg>E6G zrLY%q`EZ7q3PehhWg^wPo11T2qjZysNG3VaV@&1ed2Nv&&72&m=Efm#-~GHWcS5u# zdyl$oytTB>vzK>`4!7B+IA*0RPG#LWC&x(cPF1vBOjR+~Qs;OvQ=&&| zv0C$bt?pteh0+0h%cW!Lqscg#Z?U74QI;@GM!-jl8u2(kW=S_4!zm?r9qtH+G|Plu zTW?yW2V9x_S;!KHz39+WTLDjsEaGh#gb(9wICcP= z>k0fbGR9jhfTKsW%jzNRM3I7jl1=j_>svRzYFh41Lv<5CNDTfx^~JHd!d95VNU=dN zw{cJfAz~C9rmwOb`mz(Y3ZYo{x}j(U*7{Cid2>fHcrh*wx*!p@qwq;7c45D1n!6Nx z{zqOb^4x{ZkHcb7b8Im_RB>Z;nz6u5)vQ)aZ5n3KS>uY4hq9yv#@K!~8be5n z(~(!fg%eSm9+77>)<7k)ONoReGhARS#3W}0eS!iMB1A||APhTfN+HUcS=Vd&%JmuV zCcNeQ+seflsu^*F7>gn~Pl_mXIoX$eHQWZ(8KSNTk9pN^*i*!~F}(uo+k6NdoW(30 z?!da|cIQ(gOLW6ZgK3IUEIvxz!A%JPlkXO{?rv_pH?Im23!=HWFQ%`hQ_7Kj5hm)^ z&N9z2nNGP~5o>`$9x$s~G~E5UuW2-SVE4hSa)vJgER4z=teeRM`qn70jCswCKaZBy zISh{z*RX6?o1(Z@0VdH>u-STz?qbU$I*RC7E2n)_$WZamC8&#tPxj% z)WzXoDY6RN$z0RLAKC;X&ufjsOc8&WW6yo*hKNin5{7}vEzZ%HoZqpOI6T`cJ9}&B zLijj<{M7JS()vSvHNVg>Bx=4bt*$7kt!SrieDtH69e%}l1B2CJVb1rh&4 zPzF%SDj@O^NlFD5iQM3k&0)IeB*15mOOM{HotB6-fGqQ>_>$)se?~8Hkx;me37J() zDiX9|Kw|Pzik%-h0mBjJK@s|lUP7b$q8Cx}U9|CRw0le_>VtGlFzSP}Nw*If!dhb} z0d=q~9{Ek7h*E?vrs_B{`jA$^vI_;*FEsF^o;mn;TBiuLwOI_Rq&3n|FA+pieYd;~ zE0h%-C{p|u&0|4-_vAJ6yJC@6tzEh-hr-qxEq2V3C@I`(SYDPd0(0h2y zs&it*?h#b&vrZYxLE$mAXT|9WRhRi`=TZ84;`%=aN34G1S1Ls|oYjb3^ zpcdtO3Hfudy8v+==4u)_y03mai=Y##1Z6th+S|E1x?fQ*^@yfu1ECm7jFPPUNPP^? zgEwLU6J#Az5w@A&co#_UR%^9tt?CI=3YjT$bK~~z3Izg?9bl?%bYHLm*T`hSB9$OI z@_86{hFm0Qjj`i+avR)K<~sEzXf}yu1iHNui)9TNdeKML0fSLW(N3i8eEf7vxGT9HM2c zI~C&&PQJk=!oXqDgHTX*t%`0S1y8-3q?Z_`=^QvkJwTEcEjF&O5jqIX6jCZYmmUvB z?|aKjg`>U%!CnGCN1+D62FKuauO;YJSC4IxiGU{>F$f$+{?2Qj&r%UyBvPIzTMXqY z&O}m?tK43_x4truaqKWP3Ax%*oJ3wwj0sJ}&?!r}^i#Aj=?;T34N?utsB>`Jc$oYR zg*z1Ch!C)VQYIARbP8QSTQC{tDs_v}I4MOWS>FKf2x}_!r$_|n8Is|WLomdwL3yNN zjkGUfJ}h`$sW1zSrF05c7Qw*LLLkjYZ*z-|zF=LwMC)0FkE)v+70p^#;v{Q7&X}`O zNtAMb@yHqF`4v`Z3G@KG-3HE06oRd7pDHmz*Af~;N-kLCAFSwac*oG;AT6a#aB10f zyRDL2N{T+q`b^Oyk<~Gjlu~@8*c&o1rR`Un&U|KVbz@~?6LVywt($KEv$(#pvx8>; zYnTO<%nOhuj{AmT0%9wu@vuvMLW>8PPg#qUJBAAq88AWa?RTH;I1I>ckZw`gxl}FTve`fmwjc!iYq$I0EW+xcc+J`dHh?d%bauGF-7PF~riUbtotS3Yh z`}+q62kC=r2bqI64zdRiGF0~deIao$t!zZcllw+JyPsQFNRjk`#UV1eS)cX}tb>vM zZ3-Y{?KU4|H4NHf2l6c3FIg2IoUKdPG=VR~TEja$6nZ)tR+~yu+79Je1e3dtwjLP% zp|Hk2ca&2E2V`UrR0gCrITJJ+ZtLL!yAQD5PlVz*b6mKLFsh~>T=B4ZEeewb*RiOJ z-57O_>GYr)q2qAi+Hi5A5V%T~O&o1vfKyt)?;II(QeXFqFxhu(N7ekv!Qc2_#p|pQ3tKmyyRx;0|kkkmlJ<4-zX`w34Tf&Zp zXNOJqEKvetjj$h>!h6?=ADyHG&Li6 zvs$^V0MR09Wl%jo;>YhbNG}YOgSIOfKZ>^7MmezUA~`7T-{09 zN#+7Qc@jjtp`-46U`-kkbuui`DzF=qTS+!V9o04CiW=A7?1=l?egT${_82G9yD`e#E7+rEOZU2kuES) z5R2#$fAX25appP3mn#F81g5Wqo(O69oby089OJaETEcQ=(T4q`kWnxuabZzI)wWw- zL?p)XKm{6VdD+lH-b@G}J1W=3%2{tP=NiDxyxuQ;7_<83El-42T>q)tJn8DN^IlZ; z6)oltRr5y5glpDa;{8OxT4D9waVUcI*6Ol|xdjDW-mMCZVQ--}X=o*J?-2)M2JPWZ zm%!NE_~Ic1HOC>0^eNIk_LX;{c#|C&D3L2L?}zAV&Ey}2Oj`)9dFj8wNtrFt0$%iF z>MWvn=z#K8y5*&Dcuuq3y$~hD$6VM5NOydSh7tAA+^AciP7M=3)GUvmVumPO2}WTp zy?GI;;GM-%IyWeIXcYP|fG5&{+ZPj+B3LJbt8$P!z{pFVoL{m=N3l_u+8hUBrRheW z?pvEXK*ldlu(f8(OZZ-r)|?67jg(dwJgXD;SxF$tQ56e>Qkx00rikf=Q#>x_tqrfW z)Aicc<_=xf8_s!mr|YzH1VBV>m6kXyid`R=(kl~gpMxVrti*5Jn7mG4*+Xe^YL3t= zeqYoLHX=!&l)O}w4vcR?eGv8)LSTwTtDpa_R(U%!`c5vF zf`Os zB0{+*^5oJG+D=`#lV$05HgM|1?x3S@FMjN>;xa$FtlFd#DVR@kt;H9lo%9;YlE~Z$ z?Ac~+g&?`BRL9GVu)Koga!QktjdyMnsx~A^_&kZtD}ooXUIwoQ^6Q}PRD*pw698jX^Nb)r zxVsq;U4!(bMf5^dGm@{TbJ@I=rSLUbN(7y4+vi!H(H%4(bGto)u8?VF6bXAMpHtqE zwu}ZK(tW$E3+KFV@ReIH$PNagapuJ}HA)7`z;Em_MPH_0i-9uZjW_i6Z(3|oUF>3( z=K($LwSqp2%o@Ny)lTq|S96DP|M-wY=lST8zo8D{Ewj}aa~fDg_LeL&^&sP|uEPhq zV-f>Nz2{KgB%*fkfvT5t z4g)x49>XK9%G0cHyQRR#boK6^5+^hTH{bq?cQgC*lyR@muriL9rDcsp& z_PEueD%80)%V7sP`UIP$5s5&WP=k&RS}{ z%#!C&4t)qjz`Gz}DW?$?-4YR#IZP}^lPKM|eqEjudAwX-SyvMpIC9UOdcg<64<4OH z-7o5ios`(zKBTC;lO>?TfOY3k`!ZtI-s-Y6(Xj5UE@RkrIL@$F^ID!Ohfk@6K?Bgc zos|%n#i@nCeve`40M0nnM}jgWeYid~J*8kNDa6#w_3Jq;HC)p^ulC&f;^f4QxzbDt zicY={JuXOjx-4^yQrn=sk;y6}2a~~`1iZD(8;G2@Mr~`kM$rf+7%v-F(K-}3xGV-m zu8)>-at2_URxq%J^6t*Mn4AjTtQ8oF-6NtyQWODX33@G=@10`|aeM$l?fTLU4wIEC zIHLmV0dha}+`7z4)^UW>lh@Mc5$Es$lq&R4wLw}uktgjzQ0Q0|I!-E-sNKdXCJ)md zju!F{vQs=20I5e9)4qNwtiO ziNm`ihj)CX;T?yDcYO8X^&4Hn-~^tbuy2fC0?Z>qZSIMjdHOgw^>AcL!q+hzTGHarRWYWaN@4FgAr3 zz<`6Yd9;Z8*YZBYT&!`ID09@9{zytea$7VLy()?TYl^WaPpMHVaek;2(F&oNvCnhiW|3?u ztieR$i7cG;Z9G~wxeHXb6Y2ocN0A;72^chM71|wGKkEroQw8|{U21PF+96T(QZ+^Y zxQHu@)Uz@9VM9HYsp5@3gkLgv{jHu}R^%sIJ<<>wM)zZ62A4Q$Z2+Y*TBFRP7)eQs z%pw|21q6_46)_!e#6UqD#aU0&0ZtH5;KMjWutjQa#j>zWkh&#;#mUHNf>NfOIWbu) zDI6n32#CBU3ITIHtvkBK4;r>8s~;V&2{uYEh(jPhvy5B_D@blj^myNnDIL0R>9vf@ z)xfO59KRLQOep!1a62{zrAm_Bff#(GR2;rYHX;v?OvvX*<@SyU%4n{=a8ov4E~?vz zU8qB@zfmA`#hZ@4JQwD>9y3NMK^JQxmh36O-_JZhCrVlHS9g z$*H-i*GkiKb2F23bF;G(uT4x&%+5`}X8oL+NHG}o@6VAx9nb5&_S%2==kQp6?X@ra z&+y;xhUa7W?-TIfw|*J?<*3r1NPqqB|GIzni@x?Jf5Tt;KG84%^J%eGLI! zod5U#&Hv}M`vkd;ufKfvHsG&?VsRY)FSp|5cHuKse(lS#N7Sp=KJg}wSN80+*S^#p zINSpo)i0;|6&%$k=CS_B?&jfV%bkvWk*ZdAFWQ)T$p1xU%oqUg$mfL;zxzwCz4rC5 zeJM>x?MNzEhg-*s8&~6z2;>Bf8r4W{*rGXz;_7nPnv+gs#@LZcwMj3z_dKE z@ISNm^T$5%+Bba3Yv-T1|Em`_e|X|+o&r}h_9fe2_CHoWdGz4$_Fwv%-}zgA|7XAU z_kH(2{7Z%MKdXH2H~-%Ee(!(!=El!{#lQLc?%(<6zwr1||M=Vf@qhY#zu~9;#3#P` z%|G#tzv2J<>(;M&_cs`&)nB_xyjCf9b#Yi_ZVO`&*Z9kAMDK z|H|k7#@^3-?brXnFL8@+{;hA^eEc^n-!onM?WdK${wr_(gWvV=bN}pC>OVes`75{WX96 zUo2k#lBrVTo0h-Z|5d;2_`#F*zxh|aAAJAsz2zVO%Adad;6Hr(-+%hv5B)cv`wLq~ zJO96L{F15P_h)|le}2>Z?Drl2yM^ADf64cKZT@pV`qe-FwWq(a_$Q}-;5Yx#JK5j! zxqteL{$ln!|Jb*F{onqPU-u1jfBT*P<=;1d$K?0@)*t+#@B8WB{cpax^Nqje^Z)+j zZQ5YCq(2fI0@z|O^UvWB;C6iu`|(+~-E-PqgnzIbsbH!ID?OK~LSX;-Z02{ry8ADA z|DTqwNC6DE|EDG=OX~igo|}dHzf_toy}JKj{{8>+z8U_TAxy&e|2Ky2fB(Bb_p5&K z|Ma#0<`3NZ&P(0@e~!*`>*8zv%a6ad9lrl3ikIDZm#^{Kmt))1{%fDWo%M~uP5J=teNM1(-Uk)xxeuU#8~oBl8Cz3u(2 zrLXy~e{yyI&dT5TmOFptbKi5Lo%_Uhf6wpy^ml*$H*W7{zUO~V|N5`|T|f4xH)_B6 zUqAT4um2ryf78#Viof!&eB#gl@gKeSTNbh(e#Kw?BY*FcBiH}n_k7K@fBjeg%s>C$ zfBYjq^6B6GOShIkvAFxs{>-2M>3{gupZ}TDU;M`Z`RE^fQ|;T|EZ_an`P`rQ%h!*7 z?QeYa7cc(y_kP3K4>@-p|6kwoZOi}Yul&@+-NtzP5B!EtZvXICI6wZmUz&aE(SP^7 zAO4On|JEme`1}9i_tob7-}Ln7f96kr_fOCK>#tk;ca{6!Q~0`jU-rhI{p$zc_3gjq z|Ni-7w?@~$=}&ZirT0gF;A?;4KR-GBtGB-9JATzK`1ap(^Dj?+?&trqzx{i^Yx~!I z#*`~Uvk-+bd=ea|~q@mK%s zZ<_pTzwGPUf5-jFzyDi)=*NEM7tZ~YU-Yk+zUI$<{-+yX{U5&bPkO!2y#K>rdHCbWaOEy#A9v{y%=l_nfc)h4G)d-Tdiye)Jpd|M@H5_<8@Y)nE9Vf6EW7PyOqu zU*Tkb!9V%)Kk={r?e~1ySAE}i{Kv1E{?>PY_Q@arj?zE=?4SCX2Xo*2W8Y~1i+}ig z7u(;K`E7sqCr1Bd^^eZ{gU@~2Zfoza{rKK(|gcJ zec!M3PrvSGzWslC=iUF|gYTXHwr~2Q-A3t-|95_W_0alX-#q=n zZoNhwSW4(AN=gKe|Y;pb^q>{{T?U1+WRB_{jXo|{H6cr!N2%_e%+t? z9e?=kfB7%J`Rn(7^Yl-A&+q=rwg2NQ@4R>T&;GZY|HD`O;HQ60=Rf`N2h~6J&;Q(y zeADJH_|Kz%_rHGWPkibVU-cXQ*GGgRh*k>_79a^lfLsCn7zEmt(a5u6i|2$C)JRgn z{Lr;=_4z>v-~5Uy`{?PvWs>2p*}l`+cF=jQ+v$;lw|Md_q){^cSDKocnn3z*a&}^F zc50^d+C*u#G(Gc*{(BjJuDM4oz&6(IR;5y2TfJ3Y6a?8Mb_Cd~7UbjadgIsP4bNsN7-4h3>SS4kxxG3tFQb;vr~MC>yK>LgEmw zJ^`?M-4m~4-R&KF)|S(8+>UK6+g8Q%ySDY#3A`@0`E{Xg7i#!=spi~8VoruMykf}yjTPS@#-Z{6LJ&#Nu?>j;paS(^HI2;Hro zxPI5`xV7;zAk$sUNzD2~a-V@ZS|u`+@pUjwr|ESrpim7Fw6$~EJ>Nyh3*i^*c3Zyd zi;Y#G&cn`Kx4YwXBcHbJ-kAm%m5T;Ozwg{}yrx!0)+gRv{}TWz-V3>GObU&XCS>TybZo=;iU`1rV`zDSmO{XpZF`FS*n zY#m!~pj&vqI_ca(N;Gub@D4Fumo$}UOH2%d-nCZY<>=O3%rxNnZr9oHV6De;Djtsl z!YL~fAZ+(qLjhp}Uy(`$z4aM{cu}R#!vSj5ML1Ry(n_m7RDE@R&}4}$i(vaLv!9|` zJAX8$rf|>`sz1UqnD;;r%F6+z$Ow&NQ`Bhtqn|tMe`%442^P@u(Bp*4hyp}ce5YIG zW)M=`;>!@~r~!M-%1f;VYzPsrZ&ke=Fe|}VeO^>;IVaGs zpk!o%j$yR{$2T4JD%AUdpQ^#9QQEpE?xBmu$M~ZYJU+rlK7y(~8bv+oU}(9~qlRb0 z9pbc(yC-^QgCfvN{;Yavz^T{lzChr61VX#xp4weU;vdSr)PfV@i^GF2s`Mh}45*;4Ecp=?oTnbQw`&wP{0o|KgTY2 z#h{^F6+c%gzlzva@@BB!$T6BWz>>M>$~u~#_tZ&;TaqmP1ITNbx=1c{CvWisY#90Y zhzW%E<)4G8toD? zz(hYg?r}@B3H)G57KZ1^Tml-^kFkNt9;ahS2w3_e$`8{|wE-Jv=W%JGIPr7=o3d(6 z(dH5zejoM(-{8g_0G}VzKb*R#2lr*IM=2O^0DwS$zv*D0XsAWD40>~T${thaVRR1k ztjcuLTU6-g{QL(!7xveNy)l}58eFB9X`zE(o=+Q(;#+uhN$|2ViVM&`%6dFEU7QxP ztzP13gR@|jca|%{n34Ooq|j~nK9n1w*K$ATIn{Qz^HyI1@+OS{UsY=wRj4gCCI2xN z7!M|zk3bgzJ;BsGhJB*mi%2vvUpNCMd=lqeebxrVZAy$v4Z^?uXjp5kSv`gqLI17C zXift|50(;%bqh;5-OdG?yuj}};wJ*=svpt1HrDMLl)iuvBL8txF~Tbm+TtD@+oz`H-==8HO1% z%ZLU}eP9VMV6>c_45#Amq&0SeIHJm5Vk$ZfU=HbsC)dX^ScIWeeL#;VI;_N!Ew5vi zG+KQ$pvgzEy*8Sv#*K-AA$1PKJUPCiuMA$XRDBAo%P;0AnEk@?|ZfW+w_oJD|xrlE-VdSbaMEjQ^OaXjybJIT!R2+EG+(c$=+ z5OSdfIk_3OJ-7^+IqbG;K#DhjWWZbAH!%a!iTFUIO9Gv}=gi_>R(e5T8gb=_?XoVA`fGxp2{59p&uW9R~=( zn)IYYFzXB^7aVMO>*L;uJ@s@mL_P<@0>+Du*?_~Tit!u_S(q=l_=7CUo?pa*IDZuX z`l8xKLO!-e;wQY<+jhcL{HT-gIvL!f>Z5)bC!jl{Bosbgb6R!xDD`tz|C3DSUs(Y( z!2V}?2HusXrzhuT;74ha^gpwcuk=43mHuaEt6W*B+%0bd?kVqXuimR{ZtRv$Lx2>VSmIE9yr;;#) z!AdI=QZt2hLG2UZf5x}&ZjuT-q@^JR`ORRcq7yT5pVxdH&cqv_Y?Hz+(x?pK9M2!g0K$*zI7LSZ?SzMq-S@gg315F(EY`8_&x( zozU+`{M!<}h%`t8+ z_?pm^-i?pBJS;H^e9L^eZHjF2eH-lzY_xw%A<+uQN^v5`1S6w#MaT(xMz-;t zcJz$h7q28?Mc4t!RHafRM2yla5i-Djb)x0$?E%B6lTQu@!q{{M;`zySJxwlpyf z^#3d}0CRJ*ME_6E%)X-kKYsN8JEco=0954*g9k_t=x_SPvjnH5fGOx(a0oM}eywPV z|4VQQSns9q32#`Q-;YOF7{DJS@dZTm>!u`cXtpG82xF3gZ3#vokpbvawLj?}L-OM* zLGSbBOtiju#Qyeevk!G2rs`cmD{;Ghp++cqlY%!PiLUZLpY01bO0AnzdMw}sh|iHK zU-;NjgQsQO~`)jkfMrqF5otG$TW-^qPJCg6^}bq z*DqV&JlM|)#zZ^|flW+X+Ql$V#=JlcSOB`$HT;M#bzB?|kFkt?I~aB_5-luRQ?r4s zOGmsbY40A1ch@IOqnFn;oKW*fNd-&flQjkA!{zQc=k1OF)S^<@qPACoG-(0fB?jJc z+MMWGS%OF_+a1`}PC!>t>YNL-eQ|4f3W!NDh>+a!0}EGf(H|QX4{w%o1AgWI)t~=gl{@rB>HntYW-||-WG&jlo|K!vw{oluj|6kpB zXJvaQ*#WF?g|GuyzYV5&fZ4~#9p@N%dxKRE`GN&#mBLqJCI+~_KI+Q_dWqfii|jwkGj)o(WjzF7UaKJv(@;T4I*kkdTu z*ezp9YHCp={Z2j`wPrOaR1FIGah)9>la{e#1x^y(Uy8}NO#68nu*|@XW5{2!OI55{jdxly=Ou5&7GS{?7ZGlM$%E7U z{@{YG^%{uEf@ShClry0uvgl*?GlkAX{7j78seET*yn7_vq~#B~K(YVZUbqtylJ+e`$7lGUESVntDb5eGKToq5S{*mG49S4decQHJaqv$-5U81Axi9JLCzz zg?^pT{dYT1qJxpC|ORw-gih+*Zq}Q~Z|!CD%MmwZVmAh|u5-%NuA&DDj*zdM)PF zCBqf;rKPvSO2X&1ZR-wnvSICddP$KlD4-nbor%0f4v7;)C)6KJp!Ps2aD+R6!zo_# z>-Q&5y!<57v=AM8MhM)M@~Do7XK99)<- zX8W$2`YZm5z^H?q?gg48a14V?)`3Ojxs|;Y8W`+BzQaD6DlN?;`3CJ)$hQd^Yh0u# z=SwhmoFEyV>m8E10?3%v!fZ#Bzvj>hmHmwaB{2JBzEV>urP zfA7YLzwh2J?rVhBeOSE?z0QlS_k1f{fa{HojTTC|BA4cIzz3=Y?@Zw?U~f#J2)*cc z66WU(e{hCr*MyOvB06TLT`)IktVwYS!|)x;7AMRD%L~&^dvUIfW^)UZf1Tue)h4=-aI9+(Y!9A)U*XSN^XfZpuI|Jf+#CGeWirDgo zb(M%Mfv5asBltXz06xzve$O+8?|E*~d#)b+|hw(MZXmSCH(VpBM30-newYka+Q! ziWs5=HsBfUca=3!nS984%^(m#;l;%?=`!_-&5-^-8jVEn!6gEXbcq;Vv`Sbx5`#nl z{dh$P5gP;g7840X{}`&LoHgTXhCla-gJI$qwW8zJCZ7k~)n=Laco~br99_<=`V_gf zhlr>VIb?AmHHMF9`6B3wFzz;MX$m5qW&D;XG<-~%MV>e|a15pMVx{;f9M==^Vs-d{o7a95#cAjg&HG>5)MX6iEPpZuo*Y zXbY*1b;e>H<{DxpJ^=PO?)}2cv#uCk{(IMHw6Ep_JV5_HGdDRM(*Ms*&b*5M|M8Rm z-d$PS8pa7Yq1Mo{V7b*|MQd&oJ@Es)*|b}3TM}1nI_~p87j>_|>b96mFxj_YHEPo7qJ%UE8K80YaSG{0OkSuZ21E4UdO*$zre3PX ze4<0GQCu5-_N^PlKu?x(B%%t4ImHqR%SW9V=(ar!faO0Ng;^YfQTSf3Q!`ZIM{Wnm z%}1I}G-UipW|BgeDg+29Up#Xh?sNCdGpJV)83ecm7$VZ5ZKo~?#cJR7-_fdG{QrRtDV@LGq@NpB>pJhHU@h%WILZCWo zcg2tz7?%+TVam6079KerFQ;U$P}%7;;aEkd^#x5J6(qY&fM{dNa)ytB9pt4v36;ut zoZ?cW^6+Qdt`}&?Btli|;i9BO;yW!K>i&q4GAA%~KuRkz>{0DI@gxegVF<(?+M+nQ46%9vag=5(A`f!Q zagR?9p)wX1tD?=cKg>ucFO7OA2$o~1ZBG(YxwjvMcrrOezujxc+MH9O)Mn1#Yk zZMH{qD3DgV+7rij%zcNzJxM>R*k1{RC#OEv7lvjXt<&V}RB?9VmqeYH9c4qM4Ee6e zF`E3})?J_=x1}KL>J~qjv;Uc#nMM1biP^b1Gy?+uZ>sbv|LaTU|F+AOw~=qF!XDVF zY_IIBF7K7sc64ShxyU8#Wd>Qm#N^8u*CXvFl|i}9vUB7=hnyQ^@v?#ldD-sT<0M21 z)ENWpW41|SKZJdZ*T%N(hRWm-(snF-ye(wJ<8H@s0&^L%S>P{S`yqy$?Kl|5xV zBOek)wsn^m;o)t!+vOV&a3%uqVHyF)S#MhF>xu~{M6c`s{E%6Q;1pp;A^?I<45!f1 zxZNVzArR--MQY;2_Jsn#Ifv`7=5`xsO@%xL48M+0SOZB;ZU~!oAso7R!#;I^Zb1Ex zham;Lu663dn#oRZBfjR)Zz9z=lLV6~H_OK*SdhYBvt*haXg>^9Pjtvn&N|Zd+W4TW z?FOV6Nvts-qex=C*!&?erFCKbCLJh_?%;GuloM+}Z|HY8$a)~smulp7o6lGoh0h|2 zeiPo&?@*ElehJg7o+G&;B)D5a9sn$iKf}Oov35p2CW4Ynyo^Hf0H*Oe1l#z=Z5Xcx zxAiEdp+`xrJPI}Oh~b;6r37n|b+@(E*Op`}-jw7{V%iY=vK*Ln@Uaqx9k%!(0^1>KOOX$!V+pd(GW^AVqnJL7P5B%rC==*6wA_;>7g=2 zO=z|hz|&Y1$ddw1VZG7tYPmqU$pZdzWp^hsex4f~uQD*{)AuIObiq5{Ncdxztz52AUZyKIoewBt zT0SdcL-VZJH)!v=Eme+|r!0Wh9+I?2=Kf%hf1+aFTwgaXxg$zR6q~_g-P9`gODDDh7$6*N=;Lq4MOMxIk4%TaUiQ z>~knKSp-gCy}Gr!&=+inflf|ngXmM3K+j$8+hdUg$8F)#R?spAXJJC^$6Z{yAQ4TZ zeh+Az;})4UQK*kK3KNgD7Om;)eMkR@M^h+G%oxkkrvi;gmNzmzy-2$uYj<;bbDpmc zG$7;HZpy}o<*Cvp=y}o*f%)0`M`V4r6*4}1&Ng`;H-oHKkw#vo{ZEAz3hP3ju#Reb z*h$YK3+^xfot&DTn+VB&XJ#f}#s7RMe-M#Ue6^-s6P6lMRbpF}H{Y~a_kh+ZR$;6_ zui)QeD$a1Iva+$eU0z#XS--Vi-oWS!mAk7OcM=SSl1oP{g%UTVW+B7|CK`_lh_#{# z5drJM&$eAh#$NNtKN7lTc+Gsgut-1?bU@e+YaMIA$Mm}WocWq|+b|c}^;#F!?T&rc z0B+%}BYs#q@_Vgbt=K-f@ZFkUgr7yH-n*H9F4jeTf`>eFlo3%e=bPzBUT6PbL+0# z^;cUJX|T<-xM;~_ja(|Lw<9YXby1GZMWd}9x#v44?on54F7;Cfs$P zEeVKzm|*A?0imZTh`M*%Zq+UX2z)dqk-w4?0{k0S{VvAtq1q?#WLCy+P!~T$s}jRi z^?}<#bV(kQ@Iwb+mOyEx^TC4gjU#O$GdVFPKAMdT=a(6XzAo!)m#kxY{YpM}ec>6t zcbC?CX%cAdwz0;X;D?!^48h+SLh2hZo5xOf>%`smIR0nVZ+d8eS0Cl%b1vbxJg1@~ zDvN(}{%Kdjio~9*dn{PmRyP1;Uh7mTBRAECj%g{|k1>VzG4w#|%xI_;DG}u}&!DCD zNKk;=yhDOIQV15WBTTr8C_ zY~^Gkh9ERCcCCL>MH1K#XR~{qr2q*ER0&7-g&G@Ub4j-)%)~USD4h-$R&q+r0VqEZ zevoC!i<| zxXNMb&N?otE@G=+a-INaG~p;(UpI#9o@POZW{#R&Y!IZe2~->UWxz@k1`;7F5K*Go z%5Do=@h%zRd0iRtEW&IZ!tjwGWB72-*WDT=&LrAGSUn2dNroW3mS$3SwE$T#K~*)B zdYo8|V$HGbZ%}Z^5P>2-vUFEZ63;zOSJwN)Kzq7y8PCL6=fg|n>h4R_YvMvqnt6Uf z35;XXX~GwvG`lA;pX!}DVEmX5oq8wsZM1ZWz$Cm+DqgDcri}eK+3(|2zmKIVUpEP0 z`+S^A{)lXC2sJ0Tavs4(>i1ovprh+=5ZAa5X{CXy*LEJQ0J$w8lHjk)a@vxYxTeFB!^PE6o{jH`?lvHb^4ZJVV2X5EfB`g{KzOk_^O2mBHj(Mjq zGEv76a0uMT*Wg1m?NZfw{CIM5t~haHVsh^K4NT$D%v+OF z*Nf97Oa(qA-%Q^q&Q0Ec|If-dv#@^CH>PK1D4$?DX}C>k91T_2P}$x$6^i zvNKcD6UE8vb2IQozL_Z%XD8++XM$R@lf@g8vp23!$x%+tO&2GpXXhs5)J$EUDMDYT zr=}I)8?(jh*Jn#JH|DN7g2~5^rzcCrxrrI*o&Y;NJy|T3ZcM7Vn}*K8=Ns2$!_(KH zx6rrQ30Y)jVhWaEVpeu`W^$@HH#a?9lEayqo-UTIU!N$+MVpzOhB+u*pS^z7zE3@V zJaYqqOkano6kumdv&ETdm{_@gW^qSdpPieVl6{?>ohVLE&dtH>$~V_>13{q~Il{S# z>EhJHjoHarIV*FMv&G4oiJ7@M`C|Hdv2>#}GdUN`esFQr&S8h|Ye?Y!K6m{7V;X5t zY?wlmTA|6LLQ`6yDWi~9>SDNVT@2H$i($HT(YITGMJi;sBb=zYpom%3^iBglnKuE& zlaV{1b;tASK`*PwtUeBy+QBt0S$^`8<)=jXz!XTLOky|&>~{k&=K4XGnsTdNJ_0i6 z@#9k7n#fz>zn^N&+2_yH++M5eHmZ!Mr{T=Qk(Gao{|`R1i9q4#5{%i<-&Y3-m~0LX zW!}0j{}%thI!Hh;B}{RIb6X1iH;Ml~)fn-(-5_?tYKy0_|JKn94_|b0_@Yz86}?4L z*-P|TRk&R7$;%a=dfbod5rwy$&X&`)8;>VTQ~f9!ECb|gKZ0x5>k6Qc!_YC<0E2iM z=q4)CkOW0#80%1&{VNhGZ}sVSpq(_n_4>zSe1p{0x#3wrA?}Q5@`Y7&QP-=V2 zu^$58H3_8A4J1p8*QZNJj23UqO(6+dECC6Mq-SvwNKd3Vk%GX78^xIktTQ!HoCT5( z9)P|A5)nzm;`JM|_%IF358x6A@kZd-4Ogm^;Q10VON?mvE9xN!rfH2C{z-ip3^s(bJgg+xx)aW--kOY4Q% zf3Df+u8aLg=iFzs{2VU+8$Oq&=jLXB?w*~Vd2OOJJv}w^%Kr1CivPA&USHiPW9YWq ztGm0&2Apx_e(qQ!4zx2&Fd_WHun>$K^Py}5Bee!t1xCsXAN5#JeGLIWG8?yr7ir~$ z5f9?*oQ_+<6b$BU4 zzhA-J>dJOiA0HDcED9?S>~abxE@wkU7uq^;1GML}C6w zsn>)%=oO5Z23sJ#2m_>#*aYZVjBBoL-x02>o#4mmw4p^m2{zV#>H2*nSXD20^tVe` z?r2asMY%RqL1txDaa4)uBzjN~*-=2=sw7kGCfGp3sh3nRh4vAnD;VFOYNKuIhd~>U zVLBkn`asM&w{5)c*6nu0x*%3#4G8OTi9kGO+W~zZq&c#0RB934@nvag*PzYuu4&zn zq`nt=X}hUgBIs)yXy4V_a`?rq@QX_L1+Jz!09-lQ{TS`#3sPQ2)R8Yr8~FwAduZ~1 z>-IwjaaGZ6J!jS^k^d`A%udaf1phZTH8(K@{NLo{^sD&aFNgoLv^AHJvpJZm-RpW7 zcEKtYOS8pEj@qC~+s$I?nzbY|RykEN`dxzKVpY8MMF&l1tkFu&D&4p-U4Uhuux=xE z+wqRNXJ`<48^b&hj>`i@R4ZaliXWzT$i-k0P|Fv!7KqkQ0t65+zljfcp5i(=lmWcy z`jmK#?2+3Pp0#8Bd z%+P_nbL!NCF#z?-0Wy89ow|%wcH*@i_O*1oY{A0WO^$jE>!1 zfLOk@y0*Ie9u68f_>GmF9qabywpE7uTjlND)ym#ldE46B+uqvTS%JYV?X2up*UN9O z;4)w84?qO&6i7+R^o&75i4%3$Oc+B&96B8HlVYN#@XtG2<=wl$N-X)ETHWm|rR-+4 z>iX5=RhtGS<7WepD#a%v}@mF@?8o&$Mf>{N=iioZ|c zYN)3b9Qh~BEnA{j*=S#~7UoFAIt=F=wtY$T&++XVKb_b<)?aLS{M)x% z4)qqegkyg(lfg;9y;i=nvmlo}GaA|xIb+VF5VY#rGKdLP@b#G-J2==suntD|6AMl0)BboSbLiuL`}miIe?gPu`lBK6KmF7NCP*(oi*n5g6PC%%wHToqjC$TjMyUYw$L$ccfGt%VfsKp=GM} zRJ7?Kopg+IlgXIFT>uJEZgV^a@LhHcw(JF*ayTH5L%l^G1Ghzq>lVy)5Ur>cSR8v& zC~#08uAxtSVQe)Q9(8sV&R)>D6+SfZwRlei zn6BQrKu5hrYt(3Fv9%x$coNFW^g-}%Z!TW-1yQ~ zx$<`T4%~Q9LP(5dq2Onz9MIFU3_nJ{JLgVKDsw^tY@m<3+d#2ler1cJ9hs z=gs2N%qV`S?ySINUEbZ?&ZY63)#@o=i@J8BQT0!%%jMm&=&XE~vkEn<(6oRg*Gq0~ zZ{FE1ug4VDOYKy)SGRWK3axJJ?3UNos&`k)%PZSdLcYRI`P%fWl9|ekuH0K$xwo53`8}}{im7sCZLk|R?MI3$n!9M%c$+99T$PW3lY`e4)YaVCgQ;0w*;?6H zUfHOuuI%6?F_IY#dYDTsufkkaHrLlTHwd0=TciJzdd0w^{lfNJ9tC4Ynz-7oHF;-n zh2VUNEwqypF;Xyv znDwCLnKi}BRP&+O<8`;=NB4X^B|2hs!hA_Ytoo$w9GnYdH}TL;F_>W0u79@bJLvba zXz~2g1+e&l$vCwf^4iY&Pm1urWCNeWRWCWoO zV00k4g~4rFM!Pg_UK1KH2eGMVj5F}r_%;417F=77Te1ye_5a{?;7 zlThLDzV$Rqi=r=yoJinSUf)>g|Cc|0&>FX3*Juln?OTwV>$T+AsVh~Kn26)>IG}@o zO+}&`OGsYe$rC6*A72Nwf}f#QTCtVz@+j_QN4{K8^F)w%D_NsJ3t+dQ1hJ@a^A?V9 z0jX^(ol6^RnZVigoZb}GkyR9_{!~A_0y)A_TwdAPMb1}|J!$hTV0?ZH2;cmm(^k23 zYHfFI_11QIdv#?;Qb<+pT`mPL*xgW-&0C*d!QiBetm#2z z45_+8DKs0%*o^eeQ6F1o2r#iZ@1S5P35TkhA|m&7H7FQT89S8kX0)^^Qe6Btdh;G=VCH+YLi*eP?FqU%V-MU*J2(Kl9P zb=j?T`>dBLcv_N0!`p&85t^l-2e~0Yhi5$&WMToDw|JUTgJBdXW=8P~5}N}nQsezg zB|=F)VtBr2%WP>|Vk@*^wyKej(e1KDyM=^e>P?C0bb^0pWkUl3zd~)`o0tO8cJK?f zv?LIvg^)?GWo4EYv_iB^scl<74tDrB*v4_Nla7PU$6+b>Ne#$?s~eTIy=9u-!fJ7e zMO&TPQVOVNj6X+B?A%>hTg!!LZ&5&S!xx9ZwDR7n1ya%6B*97lw_ zh4?s}255^9m0qF`I*KoyjA7%;N6}e)xk32gvbEp@U%twvnhNfXffa_DsX;eNOf3_E zYeP|=lnZ^~>sx)KVJF<6vJlHwUQSa)(c3K)dP;H~yAA zO4)92Rslr>vVzu=miJ_1GbdD4ng~G3LJ9=1P!L!xXWfMB=yV)yR;O zkeo(|KA4#&#@tN{y`vC$!TgbWk$)<28-0+vJ0aiUPMC|Idyrbe4Gg_?pnHC*B7W8Q z*G^?~3-8F9U-Q}yV$bcB%HHN_jdT};4E)V}x{lAy**b1_%9xFdxm^tcBrh)70C zMtg^rq(kM&_fM=ww+Td05uV7*qIFEzP0C~8cGYCJ@~3`GSMDLsp=aP>w#(GjTnZ6` zRF4RaNUo3>l^XXH62E#G@ysZKeTcR1hLHe@S5*15X(HgZ%&%6Vd(n2RItp9R+QKSK zPE1$@)Ye$F6SxJf-kWFE|c>Pl~jO*hf2cz{y}m42`Y|Y%bw@PpP+E= zxC7HzI7O=qyoQ(=ayyw!mik<4ICg8;{tER6k_+My2@{wOdV>!{s3(@FNcqw`@eFUbw&=yy7Ci^G#Pd>$$=D_Mhn{5xdZIUa2h=b6 z5s}uSYNFX(@GEmblF&P5lQbc$!tu5n|S~Bqn?^bVZ z-ug7Z<41ZYU+^!vHsTTAZEf<4txfo~QRVXR?-C1m70lfLD%=k5?NnLP`(9OAfW^FC zO5vHn%L5C@XMDS{dV2-&nCOr30=~Zun~6kKOX6`UwLw#}v5rqG%d5Nm3!j!!&@bFW z_)0v|JFyG+3Es%oHn|o0XLee>nVnuriF*v+DJ8#nsNUMc{j#~et9=b#2IV%&>pB4X z9el+_-MFKF=QlwKKw@DK;#E*)Z+lJu4nKo$;sVyci&t1iH%8zh`kSTHc6kGq5Wn!# zQfg;~HXi(g&um=CFQlO%$-C$kKEQ9>xbzzzmQq@eR8QBmy)5bjZ)0e)IydkW2tg6%7S zC#4)oOWIHQt=8@ZU*Ly)?`ai0Rr=Iv)xA#eg@22$vM*|-0*js{@yPGc;YNEee!@3T zt|&jjn^RZ5p{J!3(tcH@K}fI={A8<ZCNYv1SU*d}xxO^6Gy`ZosO9q41e!{nI zvmrVs9+y&vh0;>+3%?L~#INabNwe$W*Yej=N?9;1@e{oXY?hXSU+@KuOk|Vlhj>q^ z{q%40#Zszi%iY6I@a7@>Q*F~Leq2gql=6dP;LCHse5_u@d;=vE_K;Y^zwnXQl5f?orIavdQ+rAOy_8be zN!ym;cUma{-^6JqKGSiTq&};gTj=SH7dA%yaF1IlO)@H&tiq~c702&f7)sY^W=1z} z-(FkYSOLVox{(`~$jdCVy}7vySH1e2N(F*L*~psGFRS0G8hlVM&G!0!nVn9d?f#mS zZLk(WXHo8lBtj`T1gZ_D(CQ9)RM($1_4fad0CFE(LV9KMk=hgH44SIRA}4= zT24F$$#rzF;yG~d7B7ycG5I;V%=rLNydclY$b_t%Q?sNuM3^+Ce1`g;;R>uAjQKx4O0)nmtpQ zi0$-ON<<78ph`lGwPi+oAv6j^$~3N~!4;?Caf+pG6h zcILH53ug_jMvD0V!_NY(TPVPl*>U`ndF6_h8d;i8#fnYmtpwv(E7k-S0FeOOVe7w7 z35oKE(8Xk9D`i<7Ga_v9;T`#+j0kTUlrd+~)Jt^)#fmTs;^sz$ow%||ygd>&_ZnOe zYmLB1^4yuwfM~8fBZ2Avh_w74(L1LZEF?E1r;vN9_c2tR8te}vB_HM!MBWTkQbE#$ zSr`GsQi(PBRImVJMv-6{#5k3CM$v>7%zIJ^IfW6BYU)%sdGg}HSeYf|>kwlGk_$TW zeBpBU*%CO_cUtEY&Bmp5dUa>Fyt}t!TBze*Naz}#SCa9{mLs6&6HjB`LxA1Mr3|}x z1u1M>-wza5&jpXw^184RhzB;0fqERfRbUfwX(2ujTT*JS!p7t1Y$!Ys)2ysYqozSS zutEi{j6hkT1s|k|Cn@%1oebh8_!t0{J`G{G)T0NNu%gcT;|du1nPndg-@laPSqpF% zXjJ%ooRR3rQfAb2C&_6u7%pziU|_%sgQXg3tdsB9E)hTcp$fwZ;=MM= z=`nGxo}u5w3TkuI^!#q)f{}!9URk);sZN?xN=?lum~LMQh6Q5THW2=TUjzx zDY|N;zlF3`(7I+J7b##Ans(=*)46;b{cWsYNPB&)v|mVzv3A}sq@^J&#b0u}Y-|3~ z8-2;cHSFDAbdxV>*A8KG|NPqxTkQ{QL2#ELUymFUt%@DUj4mxBb;R<9YgWD2Y+huo zo0+9Tml;_04uF#QCbN_x8JUDSZ^gHgN)>ChqBozSZXVfw7fPUoIt^I6BKU$3hW~J% zuJ59-p|HLT|82p4x2<3bGGoQvwny;`JQ7K~)gQdw&1u~agE3xgdC?Woz}_ye?U>zW z`&FPP-^yC7ZGq>dED0+;ud&$jECzV1TzPwEt-N!0X_ywcON**+Y+)}UE!py}$ zAJpe1c1niNOW|49W|SB1@Ut&==^j8`Y5Rq|>s#3euh#PUu4UX5)8aOUJC?df&PRAK z8_#<+F(A>$dpSchuOCjG@D&5n30jz}RP4vjkyV6OzJhKZ?Sbu>44w4AT}xK)a7ggNvb{6TuH4`_~b-))4+4{Y&%DskfEf# zF|mu{50N=#gU?cGby;#xh7+1R+euDraKf7pUFg)&>N50{oz+t48a8j?-)QZC4rBZ) zl@jmfrCVfJ1{l);z$Df=4fDk5IExS3XY~gf*6GtTDC1)`DD!}lyq;l2cttbgV@wTtDHKm&uU-A|{?%Fi%$|bImFolV(!ayosiB@HeYC6 z46Z5Y#8O&Kw63#zKJY`3B`R@KHD1%2TvYZ06faV>E3E4<%creaMPD(w5Y)*hh=3|` z)Rpk4%@>uJQLBBMx8JTeyoBEpYLcLfYrp7(kb?j zoELtQMGlTJB4aE0#(RCxguZM>gqp4Z|POk zUHuX2k0Fwud258OE}Eh=@K}@d2WYJZAj;9kc=WTSy(X@SJx-B0vroh>P$Z0=Y)uBl zoSvOk&&wbse`)cbC592xZN01(+d|*q(?sm~sYnSefJCmN?(^%Yn~zU)l@m_lrxL08 zD%VtOjb29Ee`jyrq{D;sQPB)2nx$&&=%_9TX5u;a;gJ97eA$J6={yrn-o!}bnQ`&c z9qLabUw_i7h8Ddf2u^?yKSaM<;z%w(C@;lB@+j#-*1=hv3>2gvdkYKni<9(eIr_N# z@kg0Bv^hQ(9?8;C2W9jVDchO~5Se31Edam7w|%2LfTtQ|;>Z(k|W$O$Nb#7=b9 zRE!7|RX8Q+g^B`iNS={26zZ<2^j*ainzE}M(uS(4F<3!a6dnWo; z#>3UPeXWKrc??|DlR6FlI&~U+e0PuM!OzxJ-Kul(?j@{pmDUgX&3@F*=qDRzkATjj z!!!b|!3mSKzWyKRn`)ODw>es*3*|_xryD1V0611Nno>zd@mOt|cvpcWWGYZp4JOCN zXcbf|d5S`SpCco{>*ZydLn&HSuKd4`1;x;TM{W2qjbLeMi5VDY9k6bs*VK`6h{%cn6@8_xhD_&prk_I4v z==^VBMPth3Pg^^Ne55AT*PhbU0Khrg10{dc+QWA^KW`lFZSQ?(v3zGT8sVCEsb2Ww&#dSsEJ{LOH9Z-rUY6>l|nC~j2Ly#8ZSMtaxdJ5a2tWOSJy#y;QUQB5X zLkCYx;`K%nlVTC5D{#C^!xrHvbafF7C>}AghCU86V1icA5e;r*VQ4=my-<;bPOq}t zr~@)(u~^7M6f+s2Z>MwOX!)3ELanbWtRVj-TCql?5kQ$47(CT3F7(sz-mC`PD{vIi zY2f==z`se@$xs&&NeM9pgP0}XK~@3D(04}@RbT|Ls73K9LNi8dI>>ril&=@*u7AaY z3mGk^oO272?qb} zwIBC~#j6qyv6%Jq`|0m3bi;6GOr;7&kn)EC>b}DT1KuTaw2PbAMl~Fao~qUW$O;Q@ zp-{~$0IK+|&%M8yZnrFo$a1DxHO=^~5ZqUaxsveahL2mD|LjH=QbdU(d9mlq7zQ_i z+Ef)h^0V&Py962YTI;h#>T}=wx9+oLNK!ppN`}JES#Cb0QH1@o9Z4tL5*(3DGyY#1 zN>vn_Ub9HQsBIauMZ3>A1iwrMR&c{=uV3SXbSf1he$8vn@>zWodok@eaGc`bi6cSa z@5GW&ie`?50!o+C?D;3Y7q61Y>5%Kn{C$cTJhS9nT$4nRT!rUC5@lqI7>F)B5W*(f zUf^w?slF`yx+tB4O8rwxDDHtiq?CJ5G6nT?_n@Xq@Bj@r+Z`z4CQ1osVEvl@4XS3f zUA>~;Bl`EA#B!l9DvBTX#f)5fxY?;)ADGP*pyVV@gA}(85BCpSpqxF>32mR@En0-jdekgk za_!pckbU$VZRx6au>+^+>)zsLPBXqs1SY>BDcZk$WYZ99SH{giub0Z@FbOk1-(w^@ zAadW6p9gGz%(aGY7`*Iv2qJ*god}##T}?o3SAZZE`;O;8YlR#p&(6St<-qx40#cY? z^=o+ygN6xy?2wE$^KtUUr9`Z22?4?dxrlY35C-u}z7ySJS*L_qEUZ~RVS)wPWX(vd zz;yPIJLIAb5l^5nQGUPa*ASL)FNhbLePS?|Rc!X5ziA*d&+SbE$~<~Et?(SD=UxuV z55Rp7+{-JC9YdP~YJNJ-aTqKUG<6G$ETr<+=)4!r29`R}%2I-h2Ph^Y{8>C?C5PE9 zTj<%~JWqc?3Su(J7Q=t(z4+0}Q3^?12QPiGJkpO=E|*w2qXj!7BAQK&`PA@WyR?Vc z+OFD}Sid8PxHyOk@{Z|GF~oXDqnj-v0IlP(7a9NvSM6!kzl@;aAqLE!_0oY>IEa@G zVnvm5nwI-5mRbqs7h8rh>|>YH;+D%&=(KMFRS4~@-u408aZyx@D43Pi7t%!B)(Oi_hguRL04= z5&mZBmyGIWG1CM<4nFSheQ7a%iwKWPq<;`hfaphhnU(`Da%xMd!`Goi9P0B*nNq#7 z^s-E)OyEX9J%E)*KdYc<7TYvsQ6z|50x39!spt%*_PLn~5?~^Fg2|m;1xq_lY8NtM z&x|!Vw&F@sJhukNprSg^#LsZK<0b@O{%Coo@O-{#(W)$$=29hP^5x0LX&uCKZtsxw6svYO0K(} z$k2nWlj-ZK)pEHE$oMr_mh7X$Ph*+vozKV_4tBU3R?zc?k51nW^Xv`gRuFiwU&uL& zU?#uOKYU9(GcdNp$#}?W>xnN<@;Ue7q^~33uE1edzmHd>fpoTlfJY-+-ssxuIiZVE zn{G5y$Bj{tw^X*iq(zUBCJr#4&{G0-+BBEfDot~xS;CClANGzJ1@?r3B=;0(g#4;* z|1tr|K8A?gx!5|!bA~g|1zNI2WU0b4{^UAp@Zam@dlo} zv;MkSU#k63tJjwsD?hORSA^u9sj0vJPyT!LBdhk@VKumh$@O_`jXwH!!j9)soieW>Z?YrY1CeuwdOi|#g30QasF@mqlYnF z^tZTKV)eDPH3PVz#@>$|hjskR@Xi`L?7a_Fkl|Kg+e6!=W`POk3^7#f$RDtyu|IGg z*v}#T{ndWB8csk6`-3-7SVpwTuuK>4a&+*vL5_c&J@^ya(Hc8yU)aIeHRw_mU7>#8 zy?o%|Y}8p=8bH(!0&&+P$*K<|*gbYI>3Og!@3^)zM4<#Vu^l&VC1f?~J9rrywEz9~(cV_4!`|;7vJG~yad@=7dAzf6$PSJV5B57-CSx6kE|UcK8N?*d zv_Hm$88j#_;C=oA;}<~7ygs|OZZS~Qc3g@S1)d!}JU>WCP7m*wqJl1djp;H9ON}rMqX?aZdI2^Tiplsq)RYdGF&Ht6r7FbuxFX7nHzb1#CZ$U` zW5Jr7>8VnLorod9!efVDltCXQ^;9@1KQ0tRx^G{P-K|LdV(j1=PfU14`vyP555p40 zeiamdgDe#|c6C^OCXoU0OT*TtEp~Tevxh1x<@!OXQOd$=Lqz*;(f_evpvVk0l z9xs-1-*Sw4)h^W4&BWr^8C{%NWsj_S`Xik%g$djXd=F;~7OC(d^^rcudzweM@t5oC_;>TmhtJ!4cv5z^^QDspfMx8CW0Vl-GEl&YN>FsG3?vahBDxVowNhwQ zsG;Rb^tQq=BMxe2l|K{pFYG~|RjZrwj4VH6rN@|7^Jj}@`K$zQ%Z2J$y;{7G*mxhR z*vSDX=W)CbSClB#7znKVG+0ziUZKHm#$fRU2flj_SOjxKq@j28{G_Iu?REQBaJ@sf zTVOoDxZ~LNnCJU9B;}&Je}LC9ed)XH!(1F%a&4TK^M!gom*70iV2T}(jK|Y~^LOon z;8)yykAH~(*Lg2}3HKPJva7;DZ7RQc>0C@?2UON|?0wjky_9x;8uGrT%Gwzbv+wixT&3DW?kh&8@4 zP1MUb`s6{0E{^8G1t2|x39LaH=SXP5JE%4VlL6ZBwlyN(4=BvANNBu|>_lVVZY3CA zuoE;RVxCxpo@0e^YQl?lPG-o8Ny<72N5dy!6RA`3Msg4^e&EQ^O4(7+&5Ekil$-6+ zr~geGtf2*7UtL}5QfM$K*vqC5vaxKQ`updny|?G5|N6&yNgd5i%8^Ds$}=9adwBC} zo*D0bA@bBmOt&H*_|g$A9`mDho=3~iQ}8EayAUT0N=`j#0?`B&Kim zSH||!i_v)*4OCK0l0id7(l!f^)+`MkTjf2?i)3edV|G+yc*%5iJEFRsr>GcSe&X6C zUK7oeOAEPMe*f%=Wgg~9o1o#%6BS3f;9la&0n!0x3W@1Tk!r=m{+@M3f*K$(IFR!I zDX;|zo0nHwOk0Nvh=oe= zCntO|+MDNp|9dv;)sy3E9F3+i9AM`7MS4aQNH;XD zf%*Vn<~7-10sj2++1CF1+%cMNEhY9(c_rugLzp(_OkS;his^jLbGh$yp&io626*-v zp2;x%A~!7&YlRjcS&?vB&;eO)bLL>4!eTlM18xX`wTC7OmH}II1m-9#SkC>(vGL?> zF1JmN2ZpYw=;#19D=lcL4_yVz^#=N`HZri;=&s@JJK<*Ft71!9^Ux!(mwFF$@Pe>j zbMuT9Mc5{~3J=NVf5zfBb4Y$QT!mk9(P-V$Xx)m@;%p&Ds1S2R=Cd(?1_QJ0w0d@S zPCsqW1m4u%iATKK&eaO@-)^F~eCEwb>N~{m^dBnQPB1KnV!sA8DA6REgE^l}ot(}8 zPiPURf6Fw^i%hx(one6Ui|D7u0m~})Dhg(D zCh`(Uo(a)d`c+|K@Qq@&0ko+w+;*oAB+`BEh?lY)F!6cDDTGBT4A9xq;g1Us#cCs) z1mav6`jsuub388dO}wZ3M$4*Hu>Dk4rAOJ>$L`}*@xtuqc%IR4JfZYhTt>;0n*w2; zy{Yz{+v;%Qd93l~Z*@&-NwbwtCC_n2paRfjdd1#vpX_e6*ciR1Ahr4~aU~HMDgkiXwdGoU zWvQ|91H4;?Vt?)b|EKr=H(;F@aLt}rfc$eqe@M|jBH9L58C(gOwx3^LTWc7&?f=|f zeh%j;P1AOfhY742jkRKGG=sc;uX{2V|HZ~gEZkge+h1zgW}p$V#uH5^*kigV!QoztuS zGHT0p(hb+GcF*&BT?znLzijI(D7E82ct_#^4D4rKFe`W=H;4?GT0FU_S*~JU(_D_C z3flQI>7y#t*y;Yk(f0n{c`moly*^yA)wydZ3@Tz4F3!&`3Im5y)}b2!iI>}_fe%{b z8>B^qjE{6!R!qa}qh9%PBSVEQj2xj~iPosCB9Y^mvXh&D{4ag-5~;Ppox;kgNO> zBjHCJJ#a%@7()S1x;Cb@a&JE;<@q`fokekvaNi@?figI(pq-;@mAK;>=PEAV2i7=< zHUKfOMjD8e(pDtpXTnrWxTs=%d|bTb#Cn{U{+cH+k`x(eGI9_ z2m_d}rUZ(YE~i>FaPXiY*kf*A)?BC;up>MpVl1JB#G|3n@RLI;?!$t?`mrr9P{_q9 z4SgRZFz7ML;T)?~IP$sgW^=O(Jl4f1@OMZr<+Paud{xt=uSsr|$nS*96t0@II!3-8 z%O#aa2ri7+vE>Q{i=GYh1xBh*^bF1)U8Y`a$58mt4)&!5qfG+z75j(_(HPZc@1epjbYc`a z1$ZM+AotnD$NkPxcXP97Vz^om@^C4ng8G8G2EVnTPdcAyo0d_NrlD+0I2dUOQmCs$ zsbMg3$CCbz(ky^P6ut*wZLhek5MjHs*{Hv6aL-CH@@s}T5#=%dv3ODB4wfeR zSU3Q3hK(128i zq1IfZ@86I@?Tf`k;xXhDo+F&2tlC#6^k2Tj8j&;WA__+t%5JDPefegca&zStzG+24 zF@Lwe%S%H8qG}2SLwux6X_*Pp2&>kNl3qm&n^7pd1Py%Tv;4C)#to&G;24a31eMJu zr>3K`6is=pdQC{kbWhxiYH71CVo2Ov=8ctzRO+B78XvlYw2e)z(obz?Y_DV0jOlmv!~__s2BjDHg&!1QgBCuP**{vn;eL7_(p z)hE)MZLxy~usT4n?|1HT2V+QTs4#rrcHZF`G+evM<*;~lZGClr9s0I8o`hHM+I0F8 zRJoSOk+4+KUA9%z3PW^l@Y*C;u@sg9_&CtIa3i!jVovn?I20xw#FH6SZJ6}3STe}f>kN}V1Maek$r>(;d zSOgLL?X>D;NeQ15_r2)IF{e&$#~n`YA3^a((i^+f7P{eI|V{89?VphMB z#_`XWAb~)11?Ke|e61GH#cua_6OnhjB~i=7#zsLYa?wZS`mPh=m#CzCLuE1CMzs=N zfO>wJTfn{R1NkGA!NL=WJ)W$&@Mlh{1koTC#9N$K2Gs!B^4C4>>J7UW%@HvB% zn)=CKqPS4|)^bmbqUI^TvwJlp^A3+@aw8O(3DZ50U53^WKj8=C6u|5@6YM7DQY*%N z@<~h-`6w7SFKvl(YtIQmZnVlR&Yb*_Ee?A@za;Wp2h#hr$oEXG(a3}Lf{uVk2EkOs zeN%MfExh9Pjxd?S$%w9CDjQ{E=!AgL@h;01?b-4tVYz~ES{d8FyeyMx8oexo1@|63 zF`_}F`=TEV1N9L;01eZ=<}!0@=e=G@ncY$A1INQ*r#KIs67k(YZlOtk4$QDyw-40s zfys*Bz+~+6uz&$r$8OK{-0*=KiBoqNV38oI%Nr+lXxMQq2E3gI=;otQ#U zzb`@`&>!a76VDpMT(^-C_;CsB0vN4*PI8pQ%0|%gNpe8%w;PYL{0=5YAj-38NDY~5CqE@1*y76|~oQs1T;tuGZ zAGDR^(t3-ZAKm8a%Hv>V_2zLHG#fXMzzpTb0OqXycx&Awbb1-ag@(qY+l5wlyO@SO zx#StKnLyV~MeB@!gO{3?{EF?PbC;48geaNt7zP^WU@~uQ?!SKz@;s8QC3I|AbWPe~ zB!)|-LUzbc$n$R`$oL)(%HZvjUqm@Y8e}(G+T*V|#c=Ig(1WZObU2+E-l-!+Fiez& z;e}%bI_bDw46467YEo1U$LhJ&^`PqX3e{>6XIRgjZ-V6uh!79TETnk01N=sQYToc3 z%nJ13SB3l*Ga=yHH5OQMmzNG6Dx+u&kGoKYoPDn+pqo(ekwtqE!2TiL9|21ztVSRG zJLgs?g%2_y5=$fOjWZrPDn)?qWvsBk$H^ji0C)$Fk@ZDH3$2$ESGYc`tBRZ}LHOWt zw==4(2D*O}L!j#qM19_QqQ4+XyNH0r}2XxK;1D@Ht`#WgIeJTP@YK-twK@uNnE4l7fpl_&^iFbd!N0A#431N;I`G%!G2 z_mq}fZ(SJtE1{2NEx;&?qwD;5akEON%BHim6u(A~$|uR6Yy=49VWbs4-wIKF{$}_9 z03zVIcI>!4XB-l&tdXDEO<#?_xgC=}GXNR$962YO< z_veEjW61<{+)>cl@4TGA1AF?6|FC-v-TJXu*1ei1Uk`V(92T-VpumNASr z3h&^O99KU|@}vOAli`pzr*Az-gAQHeY~+p{eq9p?b6R~L_=~YWxw@uZ3p9l4w0zz< zJWgA93&^0wL*1}E0yL|Egx}aX__)!P3xiHS*=wR8*R#dq_B(Aw^5JIUWU$x>^T#GX zAw0sBPqij8dgAp(i*SDH(-K>3)N3nCrF=B5(#gi_lB+QmHkaowzO%U@kgrtn-_^OQ zpbF|UDsXO>W97{i0kJU)WF;HsU~?+a$hMMDujhk$twT{wjhX$4)w05CY0U1=O1utp zb@Q!&+METontK zUW?h28|+|c4kLv)py+Mx7gAAVRPIx%oY2dX1&^i|ymTF}&-5r60dtas!N?y4hSBI_ z7q^2gkK)xm(C|G1t(y&09s`z#UwN{;q$Av%wjhZ`B|nE={rl;`r=yc|u2_d-u(LMb zZN2~Sar+ z90c?AcHledI+kj+EUk@d3E*QK0<7rP;dW=U+^UM~Wh-)SX~Dy@r3$I)~S8^6@*t&iKr@kw>}-~eHPzdMJk zHRx{awM2P68d-I-Zd`*648|G!o!k#bqc~o%(}r}rFAJo*+nw}tXZN7{Zqtyj$&GH^ zIL@zkBQWS|P4jMKUG_}t(j2%RTimk7p!>Wx*~X1iB2!exuL3sGgZ8#}w#?{)jQqu7 zmG8^(t-biB6mDW#VHj;=@}cF8H{@TO49%SM(_|JQj|{qNbRu9=s8_8%5dL0qP7?j? zI5E}U9d>?M!2y6)-_tBziP#id#_)b+3K*Z|IKLa^)@!7-`s4;~Am2+pnX6vW z?xiuhP}&hyS7NEEUq?Yow1UVs;4Hdtbtc0&AEu@>P8+bBEMUsUJmUBCck>**8W)Lq z5KM+kA4Pqjm$wphy0*OMs(GBRlCoY2E&*15T>-msV>0%~*71pI z0KC3;hKcu)09;)$Kss6Ub@Gfb;WfnjC(y@xr;xN?+9A$pZeVfEz87&=vr&?>O14^2 zEyAAHTwy-o+@co`L2@41+y3?u6oFb!Zapf}!w2->18L43nH zyn|@H4LOn}a~i)j{~TV|Z0UR?B*iuNs2hVrisCF~^-7KdC7imQi?wQjF zilDFu=}Mj%eZGju3~WRF4_0+TyE^d0e!@cl+!lo6#lmu>UTKz|it)ut+)9_fPtG|E z#QEFb62TqKXyD|aX(NWcRg>tsKB|d_yrH0yWX}dm&pm4rT#wR(=IG$#$hn_~*nBe~ zaKi}?H>4P3ckhVX8J-)49*;<;Gp{^`S?(?Hqp=)|@bcffW59%A*SKZy5aK-%Y*G8o zvnufP1OhZ~g*e&5Jnjj}2Pdy`0>{psSdpVbfWJY)!?#)-sH){)#=_jBXGWX!G29o`BUr^Zq3Q!mib8q|4UZQlc zT*WYF=BZcw6`N3tMjgLCQ6iy*L`aGX-PQxQVK^vT89rjlwAseg5LxqVk%BVH7^=j# zIW7bizIWb5(Dp^LGQggf1(~|)wxGd?Ll77ZugL<9Dzm5CE-?5Qtd7=?BQl{_ams&G}pD(pg-$j2m<8cxi-#Q z0io%lm*qJu=)g&cr&U-_HczTxvA@;@@G32M1Zm$-?q6p>0ck*pEyZCJT{B#^0t)P! z!{!XA#2T^j$#wVlTK%iZy>iLD`v46V*`xwdf+xnrTb=M0blm5|0BC9S931X%Zgo2Q zhwTja68Yy&6~n8tXv+-j)zx~f#?EmH&ni=gGJ4RkKzX!r_+jg)`*wS8k{wP8WsRY=6_Um1urJx^2?(2UYOJIDqgFQQ1U zC^o>|<<*txwItn+yQ{0^);r%Df!!kb97j;T07?1juo>fqKL3`*41|pMM{u7rNhdMlfS#@|+J=nxo(metuKs$agd6mz8`|U0e^^+!NM4=1ivzJ8@k$7hIT$<{zwovyJxKcIC*DbYs|Katb+k4 z+wb&n7cYQzFk=%>`Y9g~GdfzZ4_5^1e<**U$W&0MGm0sK?&|ogFa!i!m^e79GOy14 zu!H^2TZhG|1V9*y4&;4|%_4d)_=5L1HATI^8;xd9P+r8?`NPH$GRL8ViEC~4h=Yq> z80e(&zNK}v2^|$=2&!BYE>vsP|Jf9m9h!4?YXU4j`Uw%%8;nEHVwcDZ{3zwGdQ(aY zW-`>5vXGP$C^&pv9*Zb0F848jnu4QKHKdFSgauWbhc$BvZuR-W$!WqrxfJj_Ra&YZ zsvdm~A{uwUlSQ;1Fq{Fyo*>)1gOh6Gms+j$*4#HcX3Ez>U>Pg@8sMy+HkZy}rG&bn ztF5}3awUz@>-O~sR(~}r^abW$!;89G~zRFxRe(d0KnR z_hzzV_#-zy)!D575@U&v2Yi-t@3M*u()w1)DtnVCiT#Kas1ld&@tJ<*gmj|+Ja+6j zu)FqX(v>++E>guinR5Ac!BmwW0g0| z8b1((A6J%AAMe!1VlnlR&+S)?xRljvW`mj_ck+1$_}&dag(8eAfrb)A=9A-|R$ch( z=hPR}U%0P^b!n>biyY%>P1wi#BJgyr_7==*_#m{L$YqAi`i%-|=WF9EQxdJC%w9-n z=nqSnBSImnw8_8nBL@{WEHSxk^u|%n- z=z(0L}#ERL((^=NWmrr2`}MjcPT$Wv4D z=&s0@6J4$=(KH)WoI({DAq506lq!c@CQ6A%yS7)fK%m4lS_ty-fX=2zhs1{dzya|< zr}0|?jl@=nr;@O3X2!CR%5v>DDLT~aW}`U;PaY8c{oMx5gxMG)B5-`larNKqU3*vC z$daFb<4>U_xtHLBzHWS~S zbI;lA-T_+O)$i`AuBu-Nx5jsaofi2u7B4By#c_*x=ET8~Q%F5j>GwkFT}u79(@I{T z6fRjVCfRgM;rz@-j_kfBzK1^(C<9hlYqQp_mAR>+sP-?YcXIC(yis_NZMstapjaXD z=wEp9KcZ6#mHHg1K!9Rz8<)(sX5w7#58<}^a(J+__lv=Tz;l^53nz2=$|@cv5%rp0 zTGN*WYym+-q{WZ3wih7ujVK>)ga1bynJ0aF{Xs|5 z3b$9vKJ<D+}UO3jN>?u@o zYR;6P2UDd$O6=keW*`L%GoR#{MFH(AFrP>Fx#>+tyRa~S_EpPA(-#}vOCz$}$Q_0W zeoU7;sFynwTJ)YPCD1>a{!CIaOQQU*SNQkr93M26lWN3+hnOexklUS(LA10cR`A8L zZO#wzF|dJQN!5nil7C5m&`0B-*;?Kf%#-x1*(&Z>b8iJ|dnsyr#ne`4TB>CW8g|ls zUw&UX9CT7MKA-v(JFw=kWSksLampI_qe++ild5@vSOOX9A23J;cjH)KH@>L0kEKUy zg-8{VIRxR4TNFPu(fC2Gd9~P$r&{dBQ%wL$xS3(mm+L)yO9VF8OP~~j1tOQN;SFq4G$PzlP(wFy6k=Y>p) zPwjH28`{hreKdO0ONNj1)g|sVzKv(Nv&3E<8(mhaO50+`s258K<r#1dCK8hzHT7$3nK31Flhg#ny$xrO3NifpJ&aJ(o!gvIx(o&bi|!@bZXpx zC)PZmT|izoG=NcFxl#)(sjgs57Ck#8W1?@%j)KZl&hH2kvEh$S;Hg{UN zg;y!sY-EaJu=gb;ffdelb+D{HKc})j8s$3os*g~Sn(Cgmv;0+42=L%d8jL z9LaK{6Q6fQO_VgXPUbB@AI`5_zeJ(8PeAn6;2T-)yg53H?F3~!4sL-Whand-Od-Dg zp;G;X2z=X{U*o1>!1jY>&DyStVtK8qCN9Muh0&29C#3SmW|GkXJ|jzLvHXdP+mvpO zgsP1JR6l?CT>V5*GdP#A@u4$A1NP3R4g8&)bl~@|4>*_jFyx^BxGQ4yOr4Ags)Yud zu(}9ecO@bm(rhEIErQsWOO~RiAx^}ZzNaPv`B5w3PNmXDy80R4WiiOyq)Jd$9RU#| zP+@*Fs%TzQg^DC?4P_u zT~kdwMi~;P821-~k{6rRtupU{oy;yxmhW_?yW1&T@NvmVwY0_j%X1PYhBmWP2HQWhtjm!2-dVFr*Jl} zi4yv_sfQ#cXk+)6)S?)5Z7dMq`0rB06wUiq_<>DyBz$r_d-vr_$~#LYrxSD1L{jMy zwB|)_W&8xnsdGQS&i$M^_p^2G7t|Toh#xcFVc&(!4-|=~l^*}__XdVaB1ivNX9ua; z;^1pT(cdZSW2eO?>sf7xsw9;_8aXeh->gI;P!Cb)I2K&fX7H_1z_O&$uUZSsW9QV} zL&`rt_b?J>9V?T~5KWQ9xXIp))b|_Y#vu7zu{3~v{qWhU{LiOyXEV*wYD1#bryj~X} zUzZ{%WnDuVIfw+c7E-s?DpP=N_6vxJ=cDgszwRUEhE{ov4B@NyNBxVcAKiCa^1y>X zjFwrWxE<0nEw*C9h<5Z^6BiV4>j5LsM`i^RCkb=R1HMdIh@8#L=OH>p%n#QaF`^Cx zFfa)Lxz9uH_yGCjcT@FI3)$~8=0*xGuOGNK%5-E(i@M%YtN$y zxaj>J2i3c#@PVO$p&djIu(*Ib3JF!opn&#{j6d8kP3m~xu%?7(?|Y#WIkzIBA%Ew> zN|MJe52K;*P%{X;vdxQAj3h#)i9CV@HYwC(Fb#=5g^a{bn~m8W)X8C6tcWL;IX#BW zHy5m}n1T+0pKI|_ZN#@=e~b{qcN8#3fX7fUFRu966mgzA*4sq!lJ{o*Wm3 za57P0<+CmI!bXKn?{nI9aXPFt3Hxz)dOTQ;jU9P@4iyU;%%K{WBW6<892((#LhfM8 zcC^fwCy>ouH2Y|nimFkhH4%~WQ#QQ?=_#N}+8FVMhfK>L0*G4q)pC{PG#q*1=(j6B zZv@M+COJW&Td3kDweaEK3D*oukH8}jSgJ|dBM?rl8{Hu={{8u~M-kY3+%YK)J-6^V zMC^@p3H|v)bi3UlU!3G<`4x|rUGsh$Mo>wvGMtk z17U3>Fns0K-cEUoTeYNL3!Tr6oulX8Bwg-&N^Z zIgi5EMKcdfoW4}hfipEzDl4!2n%A0s1Q6!!$!S<>IjdH)g62+YdG|?CY-UEmhZ)Mwi_}*{kcnpL1 zlIX17u`%4xcm?vf+{zV4F;!x-Byy1rDc7riy%`K-?6OVY-i&z-kqKA^g0rJoXi{Sr zdmT&cet%-kjnEo14Bl&n;cQCrSz)%!B;FdLS)xg~#K)u<#)oIaQ$%x%-8+EAA=t|V zP?MOxq{*0bgAV--0|AS+5z>I{FWNRe)8eGZVYs73sa3ioDepj^N8fe$2DWBej6b_-5m$lBT3esqsP0b&8 zPkh>`{N;9 zS(}^6Kp+;X888em52r7Thsb0qSMG<;#;3Bu|0{s7;<$Z@b~m8}mt4w3DesXrb=h%+ zT{0PX(^XtM5E4vt;|Xt-`n0;J2JWnk)rgyBK~?Q#RjHGo%zZg$l5vHtv*Vd2937kp zh+7WfJ~-(P;{;`b&1UfwBb~o>n*UEH`e9SOYGrBF`ky)?~Vw&^Paymrv{ZtbR9`#pf4o9KLB_;qW9zuJ?fsJp8cV`!tN7qcX^zBbIv~Yv7=V7{qJhSZ;)bDmjo=ZtetO!D0VFMf3u|4dpKS zV%aAXFWuMSvJ3ccwM7b_PH{-%k6ET<&^tQqpB?g(R)DI3G!B`KuLmG)1p_O(Hr^f% z43Nj+LalAmJ6shK*ccey2t|v>z!XD)A5R-e*6A6m}DJYa4(3(Ysj z=Rc`j?2PKkA4hFll{>FbFF3#S8quTQu)vy(jJNELLA}@b<7d?0O|9UDMJ9+9KM_y= z7Wq30kR1C`JKXX5l0|nIdkopeXcng7{$3iD(Qi}D0Zin~Z!i8|x``pP-0{!h-N-gY zNo^4AL}l4yS(KQ0NH18X)h-vrR^pL1wt*My*dn~g5>K+^gcWGLcsSnhPIXBP!< z!b`(7xa=-0caD0$4l7Cg0%gZ}?!1C|yif}ea)Rsv9)4xHUZlP0Nh@*Oct4c>F(+j; znuzL+IO5WZ%WMS%BxwSq7o9gM93p02Braq(;Xd2Scoi7bg+?~4RmfnLnqk#dkDtO0+Mh+)q;t_VIz zV0wQD+kU@)O28l@ZIjzQZEhKasw-i2AA)3}mLoAIRgc08rX#qk!CvFx6u4RBQDiJ| zJ9_j;jQdv6gvg9KBo+paN9e3p1^%-Ghb!DUh!HJ8Z0L1UaQnusV;NVrZB!_Fj*ruv zH_U|0I5*q7_2VR@7Ug53OA!v)J+o)TWWvzE?F4rq zp^-h?Hb^yYgxA0$h{)@}fa2q^j9X$w95(~i{00RFz(7of1q&KqyI~GwG)18RmPJQs zR7FvoBF~$IreSp5xsC#ice`xOE?oAq@WjHn=1=(%V$^x;T}s@-hv=sc8IJPejp;GGdvX{@ae*XWRjS`zJnnd~OK1dQFp`oSI_3azGyizu zYd#0!R&k)?=je!PTy~0LPu$2W$3Ck6eRR>mpoUF^JKcNsX}Rm>!bJn^)g(T}AFxRZ znY17%kItgbWo`{=M6h1i zwBm+0i>o~v_7>9$*#l^uETI)VfY$jETDK3Nb+Lrj{mQg}j^_>|&)3)&k}-(a{k`IP zE?Q^Iv}xNPHc-qN91k@V@5>NBR6>VMK`hTv47?gv%enXg`CN+TH&$8Jqrt>-pT)B0 zhSc|M$V0=1{$Ru@HzK_q;z~WS;Y`GEBY5U9Yh)Uo_8QIMI>J^@@UsJ?G~v zR{`DgVt7pQR{&v7L~jM*HJeQAYi8e|8VJvx7sG=_z1>o`v}g%#qZzj2<%Ed+0A;}i&pAL(QIFTM( zw%4b}9{727k$$0I4*qYp^yqy>`qtNz`AUXUBg#FV%)i6&8|pbf9OgPP7C$sD_I~b4 z3u$s%ly@#Bx^)KWS+ zKJ9h1^0B$8;DCYgJxBmT(R_0@A#6k2yK*sFsuFk*`)e8lvRIPLdb&I^*-*yVc*fkDk-dWm zBMIXODS@m2s`4hIZ3@nK7dR0!%Fy_7$@YA--39htMFXXNB!)2jzNPSu7G0XL6*ITx7^GDDn7?_aZ)Lo-6JehcRII!@=;&89- zyre8N8fvsox)E~pB{N_)U^38bC638k@ww^o&!WkQR}ZqtEw>9|z-6O=Wd(C}5p#LW z9l>tn(?^qQ!s1bCuVR zV%n#?3h7g(iSehR%49T}oXW(fypkMbud3h@#w9bK^Z;EzqQ3!6-2{ljuH9Uv)NQO} zh*>Q4@-UPP;yNj%>}ZwmvFSdYvUH`@OC@wz!)KRUD{$~K3pUbu-`A+dAR607-?ia(R}K-( zU#aa?8qYTI)FLi%jIZ?g6Ul^v%yZ&HFf4e$MrbSRT+V>6gX0ePhpHDK!i+Np?jkCo z4fcp}6Xu8o(@;L)BDT;Qg07z!gW2W8v5j|*&D@aep?ypVuYvu%oR_!-c2P$_wsYt` zMl!NZS%sj7*3v-ZDe%C=*l<6DE#$4lTeT<&gDATV+|pHGO({@!+`*A>tRr7A{>%(r zCZp?1dTRy-o{Y(X%CG&?x5sCvM)&Bw@oV?wqni9;f6?{fPsFp-+M3 zMssL76h7>o9K3}R-TnT%{^@&Eq`&T;9`%Mp7yNoMgwIjE z=6d-42JQP%a@KcucQHdf;WWbPPrNl`Y7vW)4ukp^>(51&Id2#L|lF#pA#|CV_Ks@J|>8kN~DmNNb;O zwvgGBa~H@gow{vh<2>DXGkAB~+}MJH0m=$_lLQnYQs6B7m@j3B*-IZ<%1IS@@(APJ zq;P(CE-Iu@u(Y&cCxI8J4QIX&LNN^{u81-2mTXp>TO5?&YBmK?2up(4<&gC0xK!;n zd2LXrG{}k31Ojq{wXR6k4Wc-J=3($*6@?|Cnd9!q7OD{8yyW9thO@ZLQSrn9k7M4m zP!G(j=9J2}-Fn*{Dbf(-_OKuFCHv(3shvz4?AoEQ;H2g1nZ~D;2mGleWujpTRzjTB$ z4MYn9Z^5I?5R4t}*v1!dl6fo#H&O#Vmed-x#1iBCx4*TXrMo4-N#E$HlyJ%Jf!{N-=EWDvk{hq)$4rAlny6&k|>rKKJ z1W9m)o4Zr(R^H;5EmXt2+kbNeBHDXgv5i;HvA56;3K9EqZ~L%P*;z!D*!jJ(&z_81 zl^|%G*MmmmJRXdVSggbW`h?HL5gUmLrk`SZD}|Z#L>8f&g9yk0@lVp#T>cBpujIn1 zPam;oyql?VK>Gw3lQZ6scOm7~N=2j7!T90Mbd+){j;;_!>!ACgh6)>++|V*k zuHLswr(}d`m|i*@lA#0a$O_OSBqd1MYs*37Y)ZI){j{Q%IBiu)du!oFe&WSdV;Zbh zWJSp`H-lbvE;P6ho&6hBbLI1y$bR`;v~01`bE@&Ykdro0HJ>e5l>mKsnJnzIT5Vu} zD=8y8Pfn*28pdP}Ruws6+6R(?CM=`z3=V9`N2(?z>0Pi4 zzT_F8_GQf!v>ZH7CNMGM2-TVAz@40(vn)Vb8YQZ9el>HoxBW^?6}Fj9`$_fQPhmOm z9R;ieob>fow=cxFp|h!QF5DHm*|2@V;@YcJ>YA5(n&OEux;ELfdHMMs0HzG&4WQIX zJm@>RcbAo_>^(p1R2$U*b=9byrNnLi*x-*%{&*l43bi(CyrB3P9Y9eQ#8YUHo(XF- zgo8U)ch=L{gatMu&{mvXv9#8Z{~5^Py;0d|+x>tO(hawGUjlP6qQl6o4#z>Th%x3Q zUI03UpF~;GJC+&m)VQM!{=|G~CJ#5|;RCmfRWfkf9-csx@R+_lkEvTb`>)=h*hex@ zoRRGT^g8>PjK?Ta0g=$N@Q_aZ%alsOGc==6)Ym8Rv8j7Q>fWqK*ua`55c@r`(ZMau z*fK!G?GLDKk|uropr6E30`(;8y}DU{X-id({B=%_GW?y{M5NB>kTMc z9I@VXeMJ_H$X>`H!E?Ek%|>gmIJjAhmVq;Jgx|)!hnt)9_KcP``k%uPtmCt@Wm_}5#csx_q+34NI z=7aZ6c8dQpBv6`@A@8oMDM9Dqql{{d#yDd5WiZ7(VlrE|Zpzu4Z~>PYHe`dE^GKT2 z#!r(`BAwBueAnLCd~bs%NjvfPq>lxqLtyTyOJ`2A2Y8Ks6TreGpg-W_5=`7r2V0O% z8g{>dd^?#oaBHv#%-h21!YKC;CL?h&`9gFvM=NAQZa#Sg1iOqhhzX5S28xws3F^kT zAAvP2%ZINT(Xg)>XZ^&@*iTR5M^8SM5+jB=pd^|brgS!S^AE^zvn>1R)f33f?@Qr3B43Nfof6C&3CTTYwU!i+n}kXE803~Y z+f&(Gv#SNQjR$7NBQ&=)*-oNCH0s4=S;haBPZ-VJza}#^n|~1XKAt9{vI0)vc`2Xb zbBs}1H*eN{LIbvcxC>)W0!wVZ@bkG76i<>~mZfG7rdjM1eMa0(S>`FQU=4mf zhfJQO<@+Z`<}jI)>--6@tLMYg37~fx6Ib&?+I;q_IlG`V|CMeFE#TpT`XAm}Ke3&2 z*B-x~xAM-%o9pwp()l=_bkPAMsS6Z>GGch|JLEhcd!!s4?bEE3)3SkR?K(R3vz9NT zVn#?958S-CUNHIGwS+&+=F;z+_W}sW9o8Twb8F0CtFy2(ca-4WoOO?{N9k}lyDN8+ zKQf2W*=UAh#Bg(CbH1#Mf95qIo(#&5Y(Dd6)A-}OtQ;e)EU%baJCsc0srk9*Y@X|U38fqTf&MG~LSa{3ea9TezNZtK-GG}>RJQy@4@ku>o9nmb?_E4D%?*zcM_|rQADwTmFFJ0#qpEl1kHz`B z2M^!R%l_on>@X46-##i|1m7yUqvz_Mp7y zN+z6rLusA7#G|d#sv$0I!Ndcvv6wqcv-#=^UkgAfot%QJSvrPK@?+>9qHDPF9d%Hm}1 z3WaxOPoqP?MWfd}B)7&*E@8=x` z*=)42VCTT=vN|CXEP}h`%TOBLEaZN0kKDNiZ_Ym<<~4V7ese$G*4WMYjs19AQ%f^4 z_TSvLKA6+iLbkHTKA6+k^33_xX6az#Zn-7?YHp;SJmO0R_=39nNgDMLn4+9p;GI-H z3KylyDtNqD|B_t~hw*fBeb5%h_g$n7O#}>9?iZcY2%BXbPiL+Fj!fty$H( z*=8M=%8?Wh$2~qFos$blPi98)kSGGb|;?0nq8FZA99&4Jk7(!)nz*Qm@VRrE+>YXO6p?%1xoR|WM4Er3-e#i z5t?ol8?T3@N;i1Cc=48BoVSa6+Fp*S)yuP(EqR?AF0^h%->Y6g1*+XoCZ;G}Ep*?t z9Q=SrXLP?#UXplQ-H%TrSgUA+WA25?tR|kILAkYyZ3bfI$VFLGN-73%@w_tXXm3gO zkBk|gaJpfNhD*TQ0!eIEmM)+0OO$x!mNX_yvJS(79kwbvhNy50aSU?w)Hx!;uxFx;p_8DG+^Zm$8~G_P=Ml2NZu zFw>ZGjdK|+3R5u;&cK1|(`-y_b;8lm)3aU{6XR@35wMrpI@(Mxr)0oDw8lcCZv#jcAH@_3*bLPscs^l0~P`EK>3(SL2>D6zl8GfJ0Upip>)< zCzl}Ce=JLLGML5a%&<0hpm+k2Gah}EOsLo=v+lMSCiLKoDFDw7o1N*M93k|=D`7)R z*tlB>8@7bOG!p9w$0nkY|IO(H>p74N<_Pc#ttlxACvldS()@||97JYkleHsq5> z?)os-+L-bTQ7z^)Wt2&x^Ud{#>tqRX4${inTzX(N>!^H&q?hrA7BSxZ_^rh!Cvz0% zw_l{wTGA_X0pEVy$QST&v+ZTi?*%XS=DUr2b^hFWsUPL)dUW5$K8Cc9-4fgf^M}wY z;)#>{iOIMeJm35I)$SIWWFka_#+jtNx0m|l-J{3v+f=CY6`rrZ+jzj0IbSjT<0tRG zmGtH-JpXo+AAY;}yR?eNx4rr3vGmw`vU;CF%%DBF&!izx$_48eFyRMdY)-x(kpi-_#F!natt-LXOcJI@O9pb1e?nFG?m?N6lnIM6k8oHs zI5n#pqE`i4i;bqVo(RG3Rr2~sKl$k#1_gooE6MI1>ZF9tooxMv& zd@e`YAZuOZIU8%YaGmZ=Bk_HaUhIC!@iaa$%Z@Y-Hq&&Pm^3HlBkUyUJ+uTQcbd{W zO=o!T@u++_hz;|2vNDz$_#w-66To93$z=HM!K3$<8OW_GM(WeF({Yb%q{q(qBQ9uJ z!C60c%S^I}x~B#AV|Tm5Jn3G~l3|vjEa?sSAeqLFutJiiCud^TDUJi0h~j6%j&yFp z(*+c!zZj3#ZZ59i|F%1)o9oV!IGz0?nPxLdfBDD=C-Bv2PG46tidYMlrWLaC%M;ZK zW?`_3L7U6JFwr1RM>qKA-KKM5C)%#!`3D{5 z+Xfw`!l=3@9(UyEJcjZnvq8*3bNjRL0G;w+;K zP6&_~{Wf=`HRy=f6on16rcsk6`rFktSbHxTsc$z`^am(#kVzU{=r!8vZQRpvtTeUv ztwEJU>ve|_yA%6G=FY`heMu3|fs#b_Ko|~_tC9p{b#M4CwY7JeYahmglKfZ6AVJ(< zZiE+asI(cVWG%jDB?6t9{c*d!Fa;?~%ErTJO?ub;NmMpZ@Elfxax_9ad6C zUJG_*Lw+FDLM4hf0JNd$sZ$1=Dc6_rU|@X4|A^`npcnfH;?p1{BV8!;$3^gId!cT4f~&F)r|0XWfP3E%{7~r zktg+K)^^_LdNU?zjl6)7>)G(ztiADTL*kL0_slQnD}OQk0sJy7cswFG#Jo%=mSv6n zSIGMm>mPGWH>zj+kUl=j$D@Y$B7syzUoVoVw`mKM$hJ-?K;pR|&iV-En!W%NF-S-H z6@g}so#B+wvrail!o~2f4fjXlzuR0?jI-*J$Mz+hz|M`sgU2c(Ty1{qw-lc^FY_JYXO>x-LtCygIQe;C`D^^{WN>?DIc*Et=Wx||Hp^ix zkO&?T5hSi~kPHhjS_rzjwCwR$TTM_Xt-cPCMAmYH8@=Mcze zeDUr<vb^Wh`={Sm65y=+_of6HaX2R1YQDrO(|qKBvkx2en%O*Y)zJl<&9E>2KO z0)OKZ`)C-@vmuhen7$(+%S)_;XlksoJ8guu%Q8dKnL~FDY@8i zm<4_4xZ7@`D)C+KAJg}wk?lRWGKrq7KWvl3JYBkq7wqT)zhob;@dJ5UP2O*>X}&sfcIkf z@hyKuZF=bBPR7*7M_wsx5k$(Bh27kfkTu>h_A3ZchJ$lk^E61nb+8gG{hQkfwM2;@TQ*zh>84$Sq zu_@;XltVQ>p^Apl)j#p$1pmkd<}e=9-)VGavKjd;C(PLd<4j!QPh$BJpXir?d~t>b ze!*Ngzi5l|7r)p?57OQ=PDg?Nvyf<#xM}cLKFQ?aw>%B@S3U{tT>V;n`Jn9-z&}e8 zZTg8e%Mv|Y_Y&dHl0@J7i3$xSjcnk2FL^!j5==^yJo1t}DkL$JL*GkYyOrRtvLuhZ zBxRLkWGdmap2b9y$L)_n{(+y+9l4TWLw+!@U!9l3#1OyXsJ$-x7rt#;>Ok%w=Eu~0 z%f>L(2HK>b(ag{%Ar#OzdpM3x&88eBWHpT+8~RC`hrgNDp&A*Vj@tx;(0=rhJ~uba zX^i6C6Z2!z{_|DzcaV%t z36q)mdOeATNnd}W?0F&AWEV7c^v#mp$>8x5vil_92i8U47c*lS5itFMFc8@}9-MT| z4PQ4NypQZRJ-YGdCY|Tmx$}(9cvBV^qp$VB!}rPxNFf9MPNRY!mf(?&K9Em-&)-h$ z*9-mn^{NBBu#681VVv zia#HkFAwF*Bl)yPI?8PZ80ZACN$hI7fMY)3k61t3`X$pZ8|KT!rpXzZsl7-tj3Y0< zE`go06_74Ze_T0=fBe#GQ){oz5TZ(TYbG&)2wf9Xa5arbS!4$2dT6%iuXIxW`b3O2 ziTgITiFZS*5*sso;%Kem9pQ5raLsnG#-FiJ}xi?$SPj+PFGUBdgHUqS>WeWkX>cy+&z6OJZqNC_3jAUSxmO39f?o z6^fGO-EJ$S8^axuYTiL1H8qjw!*MeZepN1v=yHjKAf7fCzm!9H2?P}Z@5(KOlc?@s z9wSLMfW?qGnoZJ);6M=21OF^D#q;d#q)OVR^0ld{Snp7yL&6wu+-R~JHnzX9>J@&m zT589EhJ}c{sAZD@N^@g&sm5ZXS&M|t#g&_6H%2nG4OkAu-JS3-8Adgt(3U4L&NNLL z<0{86$SaYJt{&_kV$>kYt}S4PDlYgCXW9q8%z{x2g}DHlux!uM$t)A}Cmd+`t!jJr zjzas9thdqB!GQzhk&a6*eR%Q6K7VMRZ#FkB9@;k#{5KEm8~E7-SyfC%=8a`bQp)Fr zqbK7BTtqD^nuE|BVI+Ru<9Cz^k{1M*)IS zBTWm|EW%loTLrvtVKJ|1AV6Aqdg+`@r7nVhuLsd7qQGPN$%7`X`ZW@|2{jMNH3NLX zX2CCHK}lG6gXx67kxi1ZIlT$iE`|gK7H9lE;t$y10*%F!j-MEBe$D1Y5B@d5^(8!-1q3~0z%cfon@#|G)*P%K>S`um*!GCqgZGD&Fg^8( zkf#&=H28efu*uXP7jg`xtAML48S)ph_n^T-lnlDM;K3VSczpt9hXMT%s!Q869?UYC z0RGH+4Ejeic*Qei%TO3Xn$C%Q(`Po>Ndgml#->T}NRq)gCVlxnNMMmouXEYrj~`P> zU;q$F^(N!}^$)Mh6ugbCw4l#dGTpFKX@~~28d8Nml&m1#Gx*vmy^i(E zWinz|w|+W=R)nkng|Psovk21J=) zr2K*JU7uZY1JIeBFJKtiF5_QhI>S>J54|ctC`iUUXyQv^zCLNOa)MniyBME zjeE1V-+lN?w!Eir7=lwDvFUv>^@bN@N?I43a~utZvbh-1ld6R8@ywqT#!+BuMltUd zYg5);KgqldB>N2`O4gSyjjkTi-^X+S()u&;DZSodEJcP0Og_>qPx_{#PuCTAEk#CBYIKJC7K z7VNza*6It7Cps+=wRN?qWtT{dqPLu5>WZkZHTI9nTVEQR{esn_LdCAy--|grNN^*W z9F~$G6A^}o*3Y9SH0c*lo=nWZ@ft`kG`)#1~_MRk6rS)dzLV= z=1`baT6c&JKsy%CCeslg+IH2sr#27Wl#4q(mz71Lz1DvGM9U`{4!_;k551QU-B;cl z>+<9`ri#V`UUMMH4GoTM2$G7pZ&+gbl`yZ%?-9ema?A{9KvRc&#lzcb810hu5}5=JWoFRxj5%@itEMe+Q6^kyweK74`=uouBJDMf~@`GXV6DDo{&_t{-QA1AAo=K3tlOEat2B&d^dJz?V zX5%`DOcWty8V%%1)`eoFtJ{ChQ15p-8}&E>P_z6Di6%pHTp)v2evk-uSHXlo>J7|T zCk$`o+BGu-H5R+-YJcve0TXc$9{}x`tM_tY+o@#~0ll)&va_H;(g07enncOtd3s_1 zERsf{#k1H62BX%2!;|yZ~bHypV)F`#d#0kp+&&L!2h~t=CM%VR% z4Je#}fkbBQ+gP_!0tJhColZ5@7zMWqCm1{?;ZP|U@Yiq|RWII3l||l_4621!t|LxtDEp&Dm%@B)A09{+rjVcX?n&fB5Lhn&9^;p(c6PSmiSKhaNbj zAZ@O@*#!y4O|j_~PVnHx=^Mu5lF=n3crQ!-T`><{$dwK5T4Op*RtcaxqiD}ExO{;` z1B-M9zeAvpy#hA4hIBQ@V$mhM} zMRuk$hALJ2n7!6YSVovCf&VWInph+?#N|sYlk}(d{Az5QY;nW#yKoJJ*RtmXDxsqi z^_)>856}`ub4@+r3eIjt>PJk^X)=f9p=0gxTwb7^KD(l1d@8zO`D~;Ov?X2kZsg#c z{wYS&ppP7oP-6CYNs8Bmu0Mk3Xu2diPQDOTvrs%ceE=sDi$nbfXKn)2l;1R>d^w6U zBuM9RzL1mHgRq_DvU`BMtje4J-e^%u+(`{gQK1_Ka$6v#&+>)z&z#q!*7si1CU-HJ z<59kqBM%0AP#7b_68M;*s?HX@!JIL*nu9qBP}l5FoP%>^prRI)P^SA=jiHxK;fD;I zer{1241JlfVRqYm8P!rRKX3WM?jcAPoW4y*3v1i~$Sb|aw;J30`DlH!{dlweVEuosx7!alHvb*}{a+scU8X;1 zkX=57ur_h4B_K75%#aMWAn;TPIx1%%S@+{ce0m!9rdg%Jp@cPuPI~9uBtU)|ic2+Tv=eG@58tb<^NQDEM=VAAjxldQG(AfD^lUGWpKv#UvDM7;+3#4XL~pyiPT!Ek@j( zTnAxo{g!aJthsdpkJ5LFhT1rnNV8l`54!T_KX(x~LV`0Zv3ti=yvHxH``!m{4)$Lh zY`+TLZ6CZid|#;?%trd`Fu-Sw0HH(@XSF_$L{@Sn5=LTobddnxO?ppO2A_JcPPP&u_=U~0do?1jSVqNdh!pbowMxocgg}(0M*9j znV#*wdA4`JnfeLr#%T%@bE$T9Xa^8`oo#X_sN`HH=ow_<3NhhyI5ugI;^8=*L=&5C z#^UBkG8D!YO90Mgnx+G)>L-bZs?R9!BkYrvYuM1EbhYV6rp9R0@TC#K9vVg;V;hT_ z&_&Fms{O@TR2Q_UF4o+&s|%^-oqW}@64X%jg(%PLkUBu2OyVf$I)=_XXYm^OYcj7J z328kWq$e(O4%-Ea3t{hA6+V%ivP$r%!1E#2BML@;N~%2=-bBe~6ojoX=$%Kf{H7$i zYaH!x@a;2h@m1ZqSt!rR8Lbnsy8Fn`FM!LMF#@WH&M|I%D*-Q0v? zP1$X}`=tpzA&47lFP%Ad-OBR51e$=#4x*(!*tJ5?NzcM$1@#^msl;T*OANd$!4qCD zQaBq-QhzoaUhA%_TYFc!=g7=84<6^R&Z+*Yo)bE3%{POz3TMoDjE;XfqRV_`umf06CDkKkL!(`g2#O zBHRwavO-z}XFf$>Z=7Q6bknx#Q@R7Ia4c}LF&z-buVFaxKnudtG;O9^PHoNeuqnBo zr5LrDLWsv%oy@+WiT|K0kn?DCM(kFG4<$no)R^A;1keBZT@Sd-b!vn5X% zkTzk1XC5P7W_%qwh+!JxB#n@#9;1t1Jmlto(%n+c>abg2i`38)c=CR2tFEoASA#$M zqb5XPZq|3TX>=02U#mk_+I#g{eXAap7W3I(sQ3s*JU>sky79snUl%t3JU&f$jc*4~ z^=!awnWc^uc-jeJ>Q-WLr>s2{e zd@Ps88Qni8qlB;Mk$q`aW_Ur@+5Ud#+3xcfKkWVQzrB3*djHM;IXFCe`{PeP|NTEI zG;*Ejqz8G=&Xa$991KV4_@9$(I=i^My8g97t{7Q|Ttpu}di>Yil>B@H9KjYM3ZJ3xIa$*5uBwQHy)ogq5O>Ayh)oCnRMv7d}|ovBkn?QQwaov z;pW{h-7XzpVeJz$ObsgSbJ+UR&C~3r+w88;vCv(u-8A2H+xYMe6jX!1aN>Qg*i{HM z+8?G;U7{BE!7a1ZJnFVvSWcyES>t-7jY^tY@^t9o$lw8oiz~LwXtQ$G>zxjwvrf>D zvhyK*#RACl0f#?BJhYEYdIkxikP-VpuUPAkY@79{z!EZ2`B%se1&$iDR{b?5a{cv9e%4VoLAapGe#fVV)rV357{+-3&3C_o6T`vbeys^j244r`*uV@tmFA!g0 z9O`IthU8JlyYb3${~Zi+ifg&F8l0G)huO3b1j4CMIWs#mG=rQ@**QBeQ2mVi5;#-c zxN@7}6hO`CU7sO8bv)}-$lA;Q>!D`z12(uy2Ck@6q*FOlr3Hm_Zr|Jb4CO zfy$um<^w7QEsC&zSVBUkRgG8A;J-IwhsTD8IIGYhpfn)dKn*_(frVN|b3Z75IvWA~ z8C=&%-}wFEv!M6nTXB8D0M5uw619~Mp>bb2!tBE9qGp9zPu=`*9s;-a6j~lceP-mi z1QGDh<7>UrpFriaqoEms=ngmSC_FjE&wznDuz)@%mqHq(K0kfa<;J$72?!&qzL)i1QzlBK~;-`rFT@_Nej+AM*jKe;6n?)dp?S$0u0}Bbz zu#x-+fy?YCs6_c8x)6KH39BqX@JBlf(pa4huA7{1<)>IA19U-zQu=I$iH(j%*U)z& z<6`T}e3+fDRqg?rn!>Kyef@0r_0Hbz;qm_4qc?AlT&B;8)VLipB9K7y484Ng_3Blf ztT}**Spnv3jOM_`V6~t2GPI^#g|2PG>LC14ZaC&SkwT=QR?m@Zu?U#Vje$T1%?OpS zH@P!!Np}E^V3igM>@l2@0S4mYp>c%z>16^$afL28fM?C583YYX;|@7iJ-Hnv6j^qz z&~90@XLa3sOksW+*G-PxhW-7wyQXx-RaYblwt{ZAnwNCh*f@)Er=gr2U%~dy=r)Q? zd$Qo!{$V4VUJpct%y4hSF!m?OMNEZ&bU!635IC;Gzr6cp3ncNN6|};jD+0T|3Tq@h zhVQq!EjL|GJ`cY08oVqF65-B|lbDY+a?N3F18aq?Z;T(&It0zeWc40q(rDlZ*q*Dozo9Xo!&6@@Y zG9Ad4ox~@zWWdCc8?(wrQL0aYdSQ>ikxaJ7%T~eX%eCYW=JW>jvuO%kV4wD|l6g2Y zi3vzJ*DN#JhepbEYA2Nx<|RXNwEFCM_O;;_>X-LfG((q{$u*a)OaNuzO-TWX5aP9t z^cMLGEl}>ygi1$DmgB(yiasA3IiC(1$R?9VS?l%)f@OS~T#1(O$2Z$YKTu1gXxb4t z9ymX}h;J*{>K~?hY8C0`Hll1K`1E@FbI@LIZmiSF2c9*gOEFUX(V$v2Ef&&CCo;G} z@I7#Y#7?p%r$C*Q;nF~Z}4@bak+y{=SK2LEd ztfwR^j2uz&f5F*st2!FT>l*oP+P0)^BZ9~?29qeqGjZqcMeU-)1`FL8Bx9I6-aMqD z#Jh8rwSpCwicXR0F^467B`2{I(i_m^B2NSxc0fb}XP-_b+J-UfX7cd+*}J-MWU z_)L>h288QQd4^2Eq7hxzUO{^6?q*c9S+Me8{o6+>Q!I1gkD41;K|OfV{&oYYhCF?! zL>sBmBp$*VBPk2}Ni{!}Qn1gI2l*(wb4|rQ1f|E< zAJ{V`a$63kl5hX5%Kt^=5QLup=JYVaFl{=AJCtx67VS=%7LyOntRVMLe&(WP%988> zDH-&wX%o>LV+k`L5pDo{rmB3Y4Do)mch^R?z$&p_hR>&lgnE$_%9!y0OvTD3)?2ry zdM{?UBf3qsSL8XR({k{m*ls=I0q}3_p~WXaCpj2rF-feWspKns0CX^04z)2x84C>I_)qm&8=Dyo3ypvP$w;zD*s`qol|G8Oy zK8gm(u{MEuyJxAQcq%a`=(*lc1IA@OBVK2y*5Wr5m5i-xEW{%SkkrBYH(Q zBWyg>MqR2UPs+g}NF%r^ml!;5lL(`BoCRSwBt9S+;XU=TR7-d1$fIa8@IlZ2dCot* zHnG^_7S0BeDa#6jDC4tT{6J}Vf&N05NmL`6gK|pd1tOBycx#-I^(PL|)R1Rp2w=&s zZ+`or7o9$)a;m%dNJ_&IhJ{cieTA}^MP25#hL%vI?Kw+D*5;bu+$AL$Zho z5xoa#^$owkR>mss=A5okd>s-n+6e7pX+@H$&@$qY!ty3RY79=KdV5~=$ivYH^5C)Y zDC}NyZ%b{!V(?m5?Um)!$Fm% zDc~~s+JsLSW)&uBIt?7NG$s*_!6s8@u3QY=iQ>TS6@yMR0?AwrvM@x3S4$mZPO6IT ztx(y)H!su>*EBA~wkpTH9N>VEhJ&Zpm;xC}nQoDV1k+Icc3x3SB8QqIz20MojMZjD+zw@2XlwS-=wOJOT`&T9KxD=9iNZnQvZybY zeLODIxjx=_q|FjGPOMx!TUKGi`V~HyQz8KWperysPp$Hgtg_wJz&dME71^tL?gten zcV(EDS{IF>XxWB5;^YO-MXt#TGD{HeTS-I7)6P_hmKGXj33-kn(jX zIg-U^*Ott|?t~?a$MdM7LN0a3AxmVS3nicxr;JGhf0Kp_mWv}xhG+l|ZNp0g25P9I z5+LHZdSh4vAcl&m_hbkKLJlc9bnL(JbPU?TM$q02+7ICuNcqzV2qqnjUIk}jr>0Nf z*X22lIUSNo&^Vjo3E5W@x*-~Z6)nMbh7O-2b(QGhq zPFy1#s`4=Ek)2~-++cejo03iscr}4DM>-dBz${iF8;^@^hdfr!)M4=*8%Ruyon&lO zAo)acT}u&ZE}V%`GBw#}gg`?8022Ms7(-^n1Pe?6y6vU2skYG>@_?(h;P&fs)Pz)b=>Ui|{ zyfF(aKpqyjqO59GtSy4XaNQKn8g|m^LT16`kLTjbc()HZW7KK$JY<~$%&POU4b&Pw zHi)ky=cW(%dy^kOaM-rYkT|CDt7PerAF`!&HAsQ5RmMyPr|t|BQK{Ti_X$+8(_ z5y-;X&Q7qh^UXJ_G*dskfddu8oye#d_Kk1dh`~mi#4|PlA5UT#)pU}Pek<0Y6z+{r z8u1JftM-f*?>8u}_Meg$9NGY8h3ojpGDs|(l6=w+wKW4`_~_ozyF?P-9%Ah-Sfb;z z_#AHyM;Ys_d6B=GDM!pUUa&?J1YME>L1KRNfH?4{4^7LPEq}g4TJdpq2RL|kxL#G!ESj#a6;gyNw1QM0*TnpQbjk@a#nEw5#jB>t(qN> zWw+7zp>+`Vk>h{VY}ZM>7yUEX0TTJ+qvl5A;raul0z;x8DskoNP$C6iL5hz0D)}-S z!Ty@4p=03$&Mzw_MV(bQ>EMy>USujU-jEVfs~0LX3B{-r z@}@ZwD{iBmBlA&Cg@I`IORi}7q! zn7an?38tUakt&%XQ-^w0Y9rSckvlMz$OAG4VXN0%K-RIX=HIeo;`;E`gG938GWi%I zKwtCLJBq&6Q?hUJ*B8%zk29(K{-R&WNo0JG{LjC^0AhmTeBN=7u?8|AD1U2JqA)zbKndU}s2*L``cE}Sz7Rb(}hE;TW ztcKk-tbx`TUNq(Y0LyO!llDWUCRI1rOmb|(3$3`omlaGoQ1^wGf1+21$(clFbX%a; zbn!^TxY{MNP?9u`F#pYMB$h`hvW?6!x_uG59~O)icmNe?0xn>HZyg|rO3u2+f;_~i z5=pY5IO%01As|nJ*b$Cb7PnweFK|#8XTJ)wUDP_9MrFuGQj)*`qaJ6{LdlpU5c$kzVjnrIA-rN|-g9_^^$u5d-p77o%RZg*aw==*|7*>Bq z-}|pRLHKi{LGC`%k;PnWu@H&+{)Sc$hdvidzbGx)QkFx$4|UhrHwJ_eutXHJRpCn%G@y5vTaC zF~(OWLWg&`at$hXebb1-KoN|9g@_=4l(8skd>eB*efVC;bFa@(e*(f;*xSOZAoRu! zp%A$h1Yv1}Z>74h7qX3_@{@eTn;w#fuBroXeo=q%cfV}$H`J`Lc1>U17^UM)wS+q; zIhhGn<_}UT`bxszO|kg9*cShecEqkbYyNbgV?mCHGLJ<*706xS!hvz1Qjo&aYEjBZ z3OUAdf>IsycUi?i@S@?#ph)z^-7rR=;3AoGC<>x@sT_>d?mvUVVRL>CY?CYYEy{Yp zv3Jk~8Ti~$I-k@@QYCkz)FoKe>Qj%XX}Qp?f|H!#iqYsk-}At>gUU%q(_}RB?r_AB zlN|7r_C8y?Y3wZ~q0&HY4(vgMiJ=J+TLX^GXoiWfvrw09Z~tL&@w_^6w6NeXk#$RZ z++x^@D4KB4H`X)R`(2iL8%Ro5oe^*bu3?DK>V1xkTz}oefPkNl87-$%05MQF0a8V_ znuuBhBqBvRoZqaqPp`KBw#&X`4cq0qCHeP%HBU(QfaJC}9{(rtwg2W~ z|BG?4tajV=*V#xG<8nZd$O4vJML3iy!l6__@(r>8ML@d0t*wBhKpKU5R(XL96wY?r>`K<=%{#gJ|*Z{de2` zyKS50SeDq2ZR@*K+HH5Y%IaFIhWj6&h2xN5_%QD2D#z!vfO(|fa<~ZNOl+ZGe8eyZm6M*V zTh#j>UDSKbyTvBa4el1kggS2|bp1~J*H*CcJHg}o2-#s0YkofJ< z&Uz_|zCd#S8%zJ+`2XwcEi^NTaEYJ)>+t_KA3fN7_`lkl4>vd48;>48Z2zzI_D1{h z#=r6Z|26pk7XDvmKWLb52A#Yv#GGtA`_VL_+rBwi|Lryix(?PqU&=9d_*9Vxe{Q!A z9tJDJWZIfdlR=A%%5(`fv-4Fo&AUX12*Jl!|1#u8v4}^(%2lt$-YHy=Q-BM7dy3)O zF7c@9na~3ah((a?&B}6FRDuTqdcck-vixjFY2KhG0VAlO-XNaDC)dFlV&21O$f zr}8ra;~iZG7&RJw>Q4|-kj_hL1{7xwON}3Zjf%1??IjG1oAzer&Qk74$&J3M5eF#B zVoKo~qJe5NO*jGt`bSXrNz!8%6MJu|uLlXtL?o&)94{J%Osp;I)Y`g4Pk_&uIw!FZ z>JG|%9sM{43WLu<7x1WLU!rkhJ-oDq59xAH&@?4ZZrZ)(x5}eK^BM!lU zei9%(q*SY@=EUH|&bB~I;W;j`H~E^*t^<&7(C>l)tI$HQy%yU&8^_96VP)=ks~ zjo1+EKc@%|f7^TgtRC$C{N?~-Fzg>7!t|>*FZXug>E7#|mv5i#y?zmV4>@1&9|bS> zUhN%0u}Awqm;{~B8lB_AEY&pLGO;K*eDY432i9&8`%9pX4VKiG!~ za2z4WJ{E)dUhnQSa1yX29A|$zAQ}FCd$?;`^lW$gC6srF1-OZMHg_p91ZsN)Gt}{S zkt1U=HupxT`uUL3rk=Frp6@DffB^YYdHGkFP5@g+!W=H>oRujM5? zg_lE9=qo95hy|Lb@(`YpFP1!h^|xnx2lR%X!pjSN^CLgL_*|I`<=Me2dNvt;u5e5N zetdXzu*b#IQy9W=nk84qRAh(YrZX~xBRLaxw=4$HZZ#{UV?zE{#-}&zcX%-HTg?m$ zj{&_MUeGIUFEkN2)goYzlvp$uTe;^oze#@Q6E3N5{NRJEsvE z%q7_|U!fmI$Htws1KrACWnWh+GmMYYsdhC`N^L!OxBmvI<$LtZeAhU79~>U+Jl_LS z{_OAwKT+qCP6|mS)ggX|x!BzSQvLTiX&Y0U#LYM_dEX@8<8+lhraA450-q0=XE7~> zts{+XYRZif84U-UlfERzO{{fO4sDUi^8n*XNaO{#0hP-BShx&UGE-0)iJOv*2Z;Q3 zo-kHB+udCy>J?|=&e*j20O3fSzZkx~% zLJ29;FaY|n8<XjXE!AzO>j3p$!aG4GaklgklCvBLhPd z1EztHp9x=J2wepZAlEZ?S&dmqznu&0g1Eb=dZX_kGUW&kVuYC2eTwHol*xO32HBJ_ zR-F}6+sLV$O%B>ytEyBbdR2X@R|Y24aFu9sr?z2=;nuS?$jG@BS_^}a0&cR3R=&bn zOy9yaei{BnKHr6ouH1L`ji&J85`GI9NG*fiT;5;2(qQEhnxSF zC#+iPPc4Rg7EX&WE3j+o8m1-Hka<+x!wia8pjKRZ3IC^5cTPIe4 zp^m6_K}=_#D);;|ftZ?3Ia6B>lkIGZx-ZcgMFTX9zh-N+(}Z2KmViA(G>u!0k+`%}57Mt)s)mka7 z#jAKePn?0#LcU@Qh|(o#2T$K`1$%;OQ%VV(F_clvk%aON_0wa_*9ljc#!uqus?vM- z9vZ9?_|a)^eESsI!&$0Sm-BLS-F>;?zkJa4a&G3{ZhCJYve^SF0cOJ}`$z#Axbrsd z8-h$|aJMvVkmDs{;#2q>UJpM2CB48SAS5;*RIja!Js&ApBq8{abq0o#$XJ(yMK>#D z{1T8UIBJF%z(+#68SFziydFJx0PM>6m|6`ZvZrJ?v+Q_s+0l8ouqN)?@ate>eLa*nLVN<-2nGiUSHj@&|ZlUZS1> zXeE5uCKOKlA`wK*1ZL77garhjjxVCn00UXW-;dELZkDk-9*vx=zn>xkD->tqL;x5F z;;H9E7r?0Y%qU}@u!8AuTvf?QF@8w>&knJjr+{dw0r@Nfj!;E>Hjg4=JqCS)j5ih#!b)Mm-a>FGT%~1L%8sid zv6Y#YqIItJP7Az`CEj(y-4|RnxSxnRO9AWX41mK5k6YG>j^`|(Y%v5~jL#Z#Bx z(yv~ii&CO9+v6LMFLzR~#7Ena--hQii+ zAXv4NhM|?l9p22F749Z623#Eh!(rQFliqfqy2DKBt;Ud81ltFf%kWZ~r+O+7j*D}h z!JE!sk0q;c?Ol6g^C2!Wod1$V0G!DFAz}j1PHc=(ScDz+&E-{ag0_Ud`zX%@AF{b( z2wN+E>sH)pB?WKc3l1UudQ7`tJj24`D%6vL{MNvgt z@Zd8VxJVltwOYl`fFebRB1P>lPYoa-7t@MbCspT{{hmWCw89UXL;4;2Ua(54I<-|X zwaAzcA+X5n;UF1(WO#wgn8+hyYNnHqxzbD+r-VW@4f+j|L}-+;uXWE6T}(_vX?0jy z7@@Lf=t+vg%<0UHug&lX;?asRX*BFJZn#`&p>{9~P9gVflA9XXrn2DNZ469Y9w$lO zGb?I0qciv=dC0PLPDa>HjfOv~tAS%!z46_j+Ww;ONk@?#6e5GNd;u&VtOnmMjK1CXMj>zf=P=SzIuy=%M_7PH=rOj%#TyoTG z!9>BIM)`44SBc&abT_@Rs=zL?{WCB7FK+gdM+)l8H1SHsH!gzF_%E|w`D~v z2hLZd0zyPe`blp#NM{)t$#NTwl#Ujvh^z`HKatS7DFknYr;07BRv1Bl7Bgz)1cM(L z)on9S2}T11`A45dV#QE%^&p$ZW1M9Ctg~Z7_ssP~U{UC@bGnw129>ANh?xTh28@t+itsZm2c!c(<5Dx;>6UZmPSyCc)-ST~NPhTjk%PA_nX`RS zq2w(0r^R!8MKy#A7?69f{8bkV%q1iosSDRBb?`Ff+c}CQPe6kbgcAlzqW27P2W4SU zjH92+uoS46$o7<_c;2mbLs((|l*v#BcT<5lbGKmCcI96fw$7>_3Wt?bie%3v@vfS^ zDb)I63`8V_gf4A%2%q!SudU_6SXWAfL9HXdmVWEh+{VYEOH)woIxDH`E+x~fRhZ67 z*=)}a_avss{DF+Yq^(l6|>Agm0jnsJhWt$hSDIqH)BZ^FXk9U zZfwBOL{)?a$(Ro9@9I>FdyBwQG*yLd#jV?fM7~@G)30lL2^zT-d}qhR1G|7j>?2wD z1|ea0gjg0Wi6uP(45)_`0B#TvXiUqk<U9RcPr1y~|wt zql&{}!dgI^^*r6CmU&+PH@@^V;ksD*siWi7c{I)pB=Yb=uyQ1wi7D;3cuFqn@!*ss zuaZK@zs|_IjA1)9!kH;YQ7sy$+PO~^S4DiOab8irBdHqU9GScf1kECvdRLwULFaMr z0)C1);4NKVUs71`OkCh$a=62@5$aH-TXoW0ZB}At;9Nt_O@s}sFsosJ(MX_BILtt~%LE{qRC}Qmx ze9H5QUzwFt^|?q{UE~Adq{*!*oBmVzdUTiwH)~E>`czU~G1t>z>#3*X`J8Wp6YnJ& zF{&8NCd%Eskhx8HyI{6KYO4W~D;3%LERl7W<-N9SZqw#>Y{jkeG;tWsil??=u3XJh z88zX;MNRlO7{Y%u|Np_19QA%*_kVJUfAru%ssDew{kXmU=<)w*KX~-`@%rZG`sQQw z|6gxE__zQ6zsCPRFaQ9{!LxmG8{U1kcN8?(zJch8Ms?^jOWbTxoVZ3byV50t?$FCQ zJ@^S;>>;pEL%{nka9$hh?Z*0MbG?m3LxTvcpoO{oSPeFs51NlEWY2bi2P{`VAhb@7 z9C6*C7SMI09NH*bBt0~SfD=|+TA>9m(g{!~5Q?Y2CTAaGAY*?%gGYZo8_k+g(j0;a z8uw@4)zMJnQKbw6;86pb{gCd8tPAaPMA(ynjeDbBvtrFb2m(Oe`8m>$3t&hV_Ty{c zH=QBY*$egcK02mG6ND7Fe#$mp7!ne5=6tsCM7hmpyNR8`;ZLxCLDbU$qMQL zx1m+MR8Ro|6u>aLTZsgI7+e$zQ(0N~h37#5TbXufj z%ZDD>=)xgu7+M6GzhvnK!J+IPXg~I%e2JaXBAt*CC@`rRclqxyIKq>XGc&roBp1*w z#@@Jn=@P(0Dj*qx3?XAmst4Gab=uy4KA%pi`VKZ=1s&@S zwqJFG#8uvG@BD51#jg4NkbOeJ31Igm=9oGCIKnwaK}n)$Tmm*h3wZvNLdDg z{e#2MAT*VJpU)$;6=ReD2h#x+Qr0C4Mtm!%ecFC|w7;|e`gx~{kpyrYs-MjZ#N*`` zsLg^Gw@i|Z{2?Di@fD03N_kE!rrV}QW<}%NA^jbsmyH1imp20!k>41Ov>H~4qw~)Cu{&)sl2F3YW@iLCg|~Qk42=<5hFw?AVCDQ(3TfVpYuLSr2D8XxbVqR{ z`!pS6cWJW-wWPWbOh!G&WK-HB6e+01GJx}zz>$zdF&bA8Gy}b}U&rhE+NZFk(FAsy!3|fX}99tA) zQXrY=vH_PS-{tot82q)w`;@?Zbci)8$1l(jVRDQY5repczq9BxHotKq;TdcPEbHa= z>lgIrEl4K;-<09U&e7lB(C?l7moK-E=<6$B7ZA9Oy${(+MAriLs}ppq-P)%bmrjeJ zTeO41P8~~{PPZoC+#3LSw}Y42vJf>DJjwO1TQy~MyEQ7jD^H#V^vy}#tx5^*h}aT# zB!}}BbDSnsqx9Z+hEXb-m6h2DyUafeOB}a=n}B#|vlaKAABrTC0lB9wEd;BQjXPoB z!-Unc@sgs1F|S9Ukz=-j9$d5hGl4T~f-r@8PegkiRR!VGkmHh2cnt~Bnoho|Sbw@t z`0Ds@7mm{Hqx}Qf#$R=CR?YnRX=sdWFsQu1Wq~Xk>$jUOw^CZ0Rd#q z%UMz5dYT{u3^WRC5$G;6!!Y7}{1hu#S*?7^#rAAlf6~Sk{jPkr%_IDDWJ5AUo_uk5 z{BrN`DA@U7cjs@%&)>e@3Etr_zOURWrRTeHNMXY0a1i#}a<$Y!j7FS}STMA(SHv4} zWJgjwj1(oc3XD~iE_IQv;;P2Ok3@B+wW;;3V!2>KVi6y4d9*5C_f%sXX}ESc>e=o& zV|K7`oln7YdQ z-B{#OW~a=8rmEKgm_UrG+!3xVu00CyNPcYogXlK5Tk zNZqZPTT4yKaE(9<8@K9BD%se0L9iVA*AMx$cK09w{E#<{U4xy2ei{C{kTuuw$|{@4 ztsrOoidNim7~7@eFUrc&lJ>Hs#`4wAdAz!EX129r>x_kRuxU}MG){-})qE*kJ$CJs zH`#MGVG(7N%DyMEOp%-v6M!2A3#Q9kr`%QkvryrmjL{l#^(TB~uR*}A_@v0KB#DVo zVw9m!4zdmWqmMMhsv#jUy1FH!$OMA_7$Y<(>)D2JG$MT{3bhq7pvf%hCe%;hkF$7i z0ht@3@GxMh0S^!tYru?R!Bb`5y6hubHlAzb$e6|Hx1)hZyqY;$Vgw|)RxvC%L@Z-z zj-jv4k-}0ufh&o=B4efQ94bm+N{C<7tk^k+O3Vb~%82{NEYxhLZO$l$2Ibpt{~3IT3kEyhgeQgG zQfTqq*2J7E==$=hQY3b5b0)yrA5G;f7*CSX^fXv+Z)`qz_~`MIZ=GrrHwMpE#q+el zut!cp@4GEwIvh)SGzfE^2Kh=5IHkP6(ZJoxA%#sTzARAL)4(0R;LlDLr-8Wle3K;4 zg#ta>0xz*wOo5m6GMkYWcY6IDd=s=k6tFP#ZI$quss*m0=sfT}Df>ob%X}J5>MUj^ zQ&QD^jN`G1@j}RAdfj5_ZE*pWoidfOvy-?9)8;(L#&XbJUt8JurMp^4SkBH~kVh#tkhb&z)-U=HHyeTBHqEa~Tf+{YPGx$?2 z-B)xvY_(?Dq;)kudw@btrO*c6s6e7RbIv9?M(#vTUmWbdxdT1Li1&t|;*a}MRIJC4 z)O^>ezDJ5qxKb60W`bMhL;duptR{U8ObTy2E^ra%9tKey2z+G=O`w_3gp z%SjL}yT#<@Kjr=(7UgU_jwd7p8AuNHV?y?mZtjVgm7yo|eJI_+*jos^p_Hrn;j2+&Rc?nPwC6%*sT%;NN-E zsRDs%=!O68&JX*Yst~`gv+hWr)5J0P4H~=h^tt!+xjcRO`uMO@9gKoTCQsOeK+Ff| z0RlvK7~Vr4{RqD=Y)cMab*i*z<@ezayDwitU7yfUVeiE;{cea=;patW33kDp&IZJ= zW}^gVdz#&PVS+5IfLnFK?51UIis+4EaN(<8nrkh5PU@*X2Wd&BGaCgOZ$Qul1n&|i z=?QuV{d1O1#lr~bP}KWKPHu?ogYjpE@iel^7cKpbGf$~J_u2#hF^ak4=&#d}aR_s3@7 z+B%kJ$CMX4`|f@7-7nDDwQlP@^!86Ti`oHX4+Ei4bmPqp$ICC}pcHiL7&(Bo(5A}> zFNJW{$W{oOj%SRQ4zK??LUe!C&N5MrZMLc0;`Ohc4hr2FEH$<0|h9i-m?vrIV5B76r5l zs>NEgk#y~Kl6AsvH{`Dy9rFK{Uk^Ig8yuhXp@wJz4{M>jcg*x+G>jm~NW}-aTYu_y zE3Gqn^b0@RsF`9U)t_4QzKd~8`N{ikceR)rcA@j|By(PI4c$?zbyl52MTJhj7^Ekz z_r+ZLsTcjM(NTksvs`wZPYS9txDHT5ien$c9Mt{bT5_M@=&E2z{z5!N$Y=C8>S=&4 zdMCG&?rZOCPDTla&q^|DP!b-*V)FziWpqXxF@$9*q0HzVx5cW;ILs)4b`2=X4OuNn zFHOyS3!qozxQYiE>>IjO3n?0q!Th?6=+Zdrp>>PfT)mH{n|o>lGJ<3xXyB#P{a&0} z&4^Je$)znJyw(AahHBS@-g-{+sibk&4BzUe7iq_G_jx;>|K(d{*rrvR3hGx|-n zpNNR*nb1j0h8)pFn)Ho{D4Ljy}PF;+cl^ z!b*dwYzEsS)aM~1jEcv)u_Z$jvjGLl1Bxs_#n!UJ4koPRazhj0=1(Us7l}U@oMpzwN#0Jbt`nN_zabw4{hss$+Z_vp=;O zel~?s2J$LAEtFml;xh~*I2-c(iJcd3U12>(7)T3SM|WO8sYzcD*81_u?CiKV?1viG zmz=T4NDWpj&9@nNJ5y(*0S4BKdI{5hX;Mkp?ul+XHU0@qRh^Iw2t={@39s5-Z@=1o zxBmWfP+KE)ddOvC^%8@(fh)3N%cy-a-y78};5ZN3TJSKt9hoRS~&0Tw81 zRA_+Wv^9f$^W(uc^?<{LX2C}ozmu7BGr-2Q1lxF#Vie~HHDc#ga|8(f2%E3)!o$bM zKfifVD#Dqt1pkB)z(H&WD;WNnPa?6%#MPT-ifwN>tJ->9`S8eJi**gC;Kbx}PP1kO z#b4wtJGFJOv~ZF-MtqczM2!zM6wwH$g|k+J8@y&f7koz~sebUSKjabyIW-fLO-o>; zrr0cqt%_pd$a|99-*thBUb}g>-T05F@$367U_n>;N^Ol_3Dza%BEY%D4HcSg zUSG24J?r?g@1)_ulJ~8e4ok&iZ)!W>0P+E!7TpZf5J;(XbDO&uHg|jWQrIzjC^RRh zgmJD73+1@LJJRW!8#^5L>pjC=E#lw~r?5qED+++dZ5-T@7v)srzeJ~}6a^KH#K!2d z$K*YCR?6{6(I$zjBNfEC-enS$2Z9TXCy0-XXk-)(UaaeYogsHx+Gq`yhfxk5!*PT6 zkiKR^+()2+$NkCmF=Q4i0ek|?U_5nx!|`Z1w}Uo6(=SE_1l@)NE5e(ZA6;Hp3)OH!V2Q3AmwIfo2|Nu;U-BlyfaQGePK94?5CD8y&lI|NN!FP(NdpdL&AWPZ-w{~56Gky zdZ49}uAUlv8cjj8=J;Z4f{O?=;-!Bz)%LI@HAk~SQJS(b(uwUB8HAW&IEK+aw!mlX ze}Rpnsled7(pA4uFXBgWbWF+@_E!kvQ&P!OOuyV>x707eRZCy)%fG*@D-rK|7k(JCfG#NtK-AUKlwwyR zbA@K}X9I}=-j9)^Ke6Qihf0^7)DKt@|D44J9#4iT?l(QNGBRg39k9misPoSCq*HCH zv7EgOYZGiwE@kol%N+ceDqwx2ZJyN)>JBa_mDYjkk#@#Z+28V@gTszixF z(d2x%Kp686r2ov$ChMNrd;$B{42aF}p#VQ<%A;*kC{G8^rupF4U+m+sb*9+ZzBE)g%;tpz@O=}x2F?oL6K7jvTzMX5ij%Sf3g=A2=Ts|1MbQ~@*sm9`(9MtS5 z0~9r7M;ssxaN@E9-bd(>6I}_${HFx=&SmC0SVsiYw;aqyj9?WZUUEiq3_513;h}Vr z!eGT2t0+i;1OxnQc5aF}iLtS$Z`*PJM%jS{4uJ2sa}G@bM>YGkAIKkN?+m#5u)0|&bL(gT)<}MBrwA+RlgdbEuu>lnmXjI+1VT54*T|Yh= zlsX4MWz&PxC?jM8|NfC;qH{Og9qU+E<(V_~&8oG(>2x`4@aIq+)s_P&&!P}`G=!OY zwE9sxlVozw5XlshUvfggV)twd`g*msIqaX~QJ`bFGQX7&S$gz;=t7*y5we>aUQFl` zTW4^)jVJ=e*VPM(H6qt4nKth*uV&{L=0n@RU??axU$O%2JC>1=xX#X;b%SoLB(2)1 zd-M4Rw18*o4vi?A#n~wN=N;$Jo+y}U7T@(?shfKa6nlYGs>Qq2EGV=GX?%?72Iq%5 znnCa!O^8@z)(e0_H&n@n&KJ>$Ly_<^dDT#5Qk9CJQ<-!Vb|u!d5LjEcmlIT3&+b|g z5sWUpLT-RhMO2F#1)!u_AudC1>*%ULG!1>@R}X_SfV6aJN0M)XqB4R>7^T>%cow;% zFjoYm^@7%Jtl~c=B|;|@b#pDOwZjjgT6WUhh)E%?I5>mC?n<+}8h)ra2b-p><;yj1 z>~XgS<(S7+|ETk*69p`Gk2A+L4(P)4JV1dD>1^3@6*ZVmt&Uszk&GfxE+W;QbFjv%`Rp5lrbisO?`ST=UN zZr$U4C*+OUb{)>vTDrsJ^2o{ib!+W&ZNqi(S_^_XsW%I;+HiY@mAf-587pz-cE;R& zwddW=X*bIn=;mH@XJ+l8f3B63LtN(1P)JS}R6ZtUdKQy@nfs&iu?Zp;0-J#GL7mh@~d?e_0#3M()*RbTr z=uJGK;6eWEMY+ij=$c!ofvO`!*Stj>jU?O(?lI~WAJud29F)#LF7urE@Ds6RfN}Ls zM(UxN+eDO22V=|hNJ9vl?#wOTFFi*ouz2DLfm9=Ec<-755s2w6uo&@~+@0hAZzxg# z+C(6Z8L(GSPJf2RbQ(X@he<;Qu53m6i|f{nI&Z0xJ|gJ|wO!TU^Npc_VxbjFN|w&NykUaJ*sqvFK*1@8LWE-vs|29%Ci83LsU1$k7(-G@2l|)zGHa<4Y=?~r2^azX+!5O zhFaN`k}ea<-Kn*oI#IjmaUXblvcRAe7QBFBB;{wB(rg9Qd5aIPRWP;+U-#rMRje!Z zY((rixmA!p0Eoxg^xR#Y(;ia^y>F=U_Y(@tKwnkCU)5Clg7oZ~9>|V-MO}B*cTTf6 zPE=#=vICw$7vQ<&KqT2s;BX;DQ+p@ip&etl41Q$G$!=<jXR5;6Fl@o;cG9(4xsBL;VTak;ful?n>YO_O&L9z;wx*!2EwI}a@~YeY`OU%Z zAt~UI?Lgzz+o-p}{?W^6r;MS%`4Jo?E@ok8u-v*a3}t5#>7Dx6&Y4$o1tZag^ey=) zF;0Jg1_p;m2Yaty6no$b*N`r!`(WycZRPw;`6Pf!jI^>Wro?>s1n1Xd5P-_{A}UXp z>F!%6t=?0YbUq|VhE}h~mp02+pKG74z9!idKKTQMSp2}xTQ&T8H?vTSQV{taJ`M-* zHl>FhK#-J|+ne1>+lOxLE%@_48R|tS!Ve ztJWOTM4d@vHu8oYoty}(?0QP8I8j*7un~IkQww#v$`XvNTb9a5XOj~|E3y;-^=V+sxZn;C6E0P|%4BHkXubN1?&Nj`#dTseoTMmqu zmP-q3$+ACAInJ1I%w+QV!B|srNQBRE;nHdj`C!*5r@#*&@T_AcwX9YJ5`{4x8B+@v z2F?qF8gTqnH@FsJ-6raN3hUr28#sv^q#eMq9D&^`j(K^n&2Ii4yNZW-Lct7I&^(PG z?1?3iF0N{TXxp`@7?0kDTrFEAH*(6E$#mJF>hpa0cwbZ1_^Y4Y^8wwS-O}8E)e&CdQy4(nmW%~ReHXtuCrpf)aAxgDL!RYAWYg7}0mMaR7NVOZ z7xAbbXoJ=J!zftT5i**(W18#jqLT^JAl@n*<43RFzyfKsro-{)R_#-}VFaYl{^_(8 z%sG5)96nTmx$`XIJ^O(Bu}0C=d~)4@V#q?sZg-B!PV`e-*{Ib@f|&!^f$q1{Ve~yjq)LHDrpZS2_avwl6)?nPuL(b4<`H>+Uf)@R6v?=+wK>f8Cg$d8#T10S+Y>c3Cr4H zhg>iY_HlHQ(dl^$FG>FK6k3s8u=|bKn0?14vH*-vf3;av9s*j6=II$Kt1)p8F_W37 zqWn~C7LytzP&P#cHisz7)t6AZ&#}l^n>beyZ}`*8CC_lSgy%O-ZG2bt+Da z=otX)XB>N`G3s8NjnT3MPg-KhVY36fI=HrxRe{SgMj|}>M)|-ut|Ph#={r_6c#gwb zvF*5&=r&RRA_8{*j94-pcf@wUv!%hl(I@eFbdjX9i4INWIx6eBYcO%k-wAvX@h%j8*o8ob#*-1|9@nAMpXg|O8MopR(< zRNJ9o=lbk288J+dT;p?a1l)ykJ;i~AT&5NMwu2pD3tNY;z9%!*OX6raUUpE?!?R$)Hm!xX_%I3uhix|}ZA3Z+|?c0+6aHY~M5)$s2Q zwHL_ej7%nhkDr~M(lTdAF>#1QfR~@pn-0f05*_WbhvkfI7sAYgO>>N-f+W{TMlSY{ z-$Ycfg>d*Clsr}lm|;Yg%<-z+_1!WMdYaBnVnnpAV`)#aUxC(F&GQ@uw=XQs7I9Iq z^Bhe8X+enX?$hyz5CHM?FF6*jMeOYSRu?!rj@=$*Js9iQSZUJPz?6lKZO5Vtb%<(I zj9@Z$T^WVXuXCCpce;h(0}H6G-6{qTF7R;i%;VBN8&2c5&ZsZ|MwtJ@mX7ccrXt|E zIp!Jz3rFl%mGZVork=uU@esJ$FZUFsGfLT>*c_;qORERT*$6M{P=jxCIkrU2reE9} zih_X5#ZxxfVl|Mm7=2r|up%_s&HR#3lZb_@>2B+&%yyx?FKd2Rwh8p1Fd}00lN1~6 z+5?rgC8)M;nW<`7%M2j5(P@x}>=Y-)KbRWkU_$DLo(l|%osNk4xW1LKtKD{jEtn5q z=$Mjg`K@>Qceqv}`c2*=B8PFwLvjcAYny-hVw~Mk5VQ6aCajE}W!o6n$vAnOM~DMN z2O8s(B#vrRZ-p$fg_MEPp!mB`c$t{-IPeHVFG^-EIK&Ve9~)o&X(~lrIv63y-Lh6| z%N^p09QdphJv`V!srT985q#Xi*vY*{@=7Wg(>iPgZ&|4dZxyJvW~HP(i*NVJYMd)n zaP*8hd8dQqgft2Z*5&+iH|Cdnf?zR=%he@ACn!5wQaC=nnxN6*_RT%n2^&;2j|4-) z8#a<{Kn}*#k|Mb;ZLmw~YxBp;r*u*$#ymkMbP@*g#4T40OZY(0J5ECPbk5P%1#MX? zZHxstM5L_GZpu1}Z8{U!s+1kE6G-_)HQ%0?Ju^EHMeNrBJ7*P@9znDv|}O_!e5eV6)`w zYAvYD&O^0$v0Pe(zqSf&S?N)yTv?$kPs@s<>_rsZQ__sbJFo1zD1(Bq8EV8N=lpEW z>BQ}HB0p$N9JM>l(3j3p;(|&nZl__W<`A$V=aTbxyMv`AdZs~B&f{s)BgbTh-i4eR z;TTJ@G55sF(;$xVtYoB3V`vq&$4*v*`7U*8x9lMZ*Dc~SqoET_4w^MisSTJZnN#d+ z#AW2lr_gicCUPG{W6dpICmu$!n!n}-dNEJ7xUrqN3ElUOi36jr*Os5U0RW1QEAP79 z?gtE0h$v|iO;Br&CTE=w0=OL_;&xc{8*w0Vs~_f`g85RR5k-PpwlfzGitf>+0-af$ zFR0SpyxXMeoxDtLD|TL~_EyUnRk+FA8CedVIqRLQtKEQb?9r45;KoyX5M4Wk_%T82 z7H8cBmv)2GS_I>Y%L|rlv8I#Y6<#m72(Sb=gmU6J6ppa)1HAJ&ftG%Zr`VGT-lq-R zrlQxSpcG{)oe>1W={2g`)TVrJ-E^1jyYBz(E_Z+F{;9jxUFoiNKXpHMZ@N#rf9`(Q z{Yy9O2HmCiYd34~pRaL&p?4Nyw=iYh>K(W`zmR+pxQ|LLmu_9(_gvQAYW|ID*^&i zh$gx|bgEBWGOEOK0P$+!r8zQO!s#qCsm;<#yOazS@rcLoKsxe-gKv||Xvad*@Y@N) z7m$T7CJHjpObdJxP#F2r_2kA|!Ts;-3d=LTIoL%x=+Yw)2H@qB-`-t89u({D} zKd@$_eN;*Q{B`Z`pY4i7vVD?H&jTL1zYA~<6;cAa%ZoM2a7Z}hLTYbTEk+?;`<4lR zIltFAFF%z&Uq+Jj`TqI7MonCa@%5dCl4;R~B|}a1g)UTY2mm%hU zRJke4xPjP?F0$z(KyhPYj#VMKgEh3#2)Dw|3+SO-xeog-j*5R%P+LSutInl?*ao7M zYhsZyE{j_QM|Bjy@BGayh(aT||o>7s#D)x5+xdl%8K^Iyk?1wfWabpIjBoEo;zQg?#n2cm+B@d$+Gc44fsM zWJd7z#c4BV(P=E1tN*%{JDnU8h`qN8k5G3;>@P*$kbp*cjf)Q;g|xUyW{VunJ7Z3S zT+3^=DgaeLs=wt!0t#tnc?nsz5}kvPw;R81H~wS2@$E6GU?wre1rc+U@HlJ+&u0_7 zwnHfZMhe<{5}%O|1skmNlQVQ|h%hl@tdT7agYjR+2)b$8b!S=N9kl2@g2}DD`^q-a zfXfGku9nFO7}PLp{nA~b(z>gy<8HeZ%HwyxIOVpETW6t~BFL$=7R;|q_D(Pl*GG`W z7i#M9E;+;?;gU)&YN0l&>vv{?J^ z<2Gs>MWrFPxQc3XceamqU+f?J{cdCMTZbU{iIWh(JtZ=s15c9ybQ3p}i|nq=s~fON zM+Z#Ng(x(uDU4H@P6^DHK$r_b$OUFXKY{HUu_%Sz0&*HpM%LIo83FZ9>>Nme*X(jq6gu%RktDj$Sr6kiuP`q8);Yyc zJ8LfJy*0&{M?tc5LVGv(ardB&e>N66EQgprX#5!J#Gb_?j*I8|K9V7-ER}wIkx-;v zl5BBWGGKE82NAt`&=_w< zqCpaPD#BwWSgKykr-b&|JS+ksfTO~7__H;4 zH@KR8N4rnX(P|%e6Ywm;x!w2}wCn8=es0t^=yS8aNuLku59sq@{ULomsz0L7$Mwhb z`K11YKEJJhJHi#EZr0quHwU{v20L#L4i+HoiYpK@w|L}J7MxtnMqGjkCrU!QAkw?k zDZh$cydH|SA*^kJ6zC(bNC8508;fuc@dbXZGV%)gH1zqmUc`BhB|xXE6}N=N2=dh{ zoP$nq^}(M-J2k>dwEy`*Hs?!Z9W8u3-mKxdyv2-~M2ey~WDSO7ARc`y!0n4{2ZA$Eqm-5vFz2VVseK2?KmL}u3sQ_2o&xOu7OX2oy8#(Mif zW4+y2f81Q(l*%bgm_eMb2jju)?2I9H8GI7$nqjQ5XjgTKyY{C^GM#dy+!v_G`LP-N z7|qVkBM_3HE{c(~la8+^$=UfdSlL;nrw#b?FnEquNr&m_^b%L%i?IU`@OQ6D| zj0o`Imcj# zdj1gD=}9bb=z2r()85e!`)`ke?bm+~e%d}bfEoDvQ{zEGvx6lmB&kjwhkf~yIm1vo zu|)G)Ftn#MIfM~AMI8Wj`R_29a_EpP9EP4qP|A;J;oUxC=zcax6&1jX6DFW)(>g8d zKc7#hWf^768IHkvil$ysZ_Wn``Is4;H_o+;4F=KK`W-v*OHO63#Qc5~f=1MBEmGu~xYZJ;FIpACoCdetdu z?Hwnxu+)xb6GO{j|D9ljB;gS3m>lOCtTk*jq&1;ZZi%T`w}Gx`aNse=mc!$ZwHVjJ zwoTaz-MoHi5!I<@NS?RMQ*W}7v7=3fw?3`n7+59IJA=*HqIrASEGTEx5JXg zlV=WFC{vrz)EVziVjdY$;5lOzBBh+r&Y=4i?HRkTBFjy%d`uSdEoV5iy9@&N;)wBA zDNvGyUCvSyZU=fsyiMqZXCMwP9hpe6Hq0Z&ULwIwPdsftx7zSY9IZ`)Cetoso_Mvc z11hS8(1cs`)Dp%X3AI}kN5~mMJY8%=Eu-O3Vbxl}Qy$d#k>wCe2MNb|vJK#o+9uyx z6B^cunxwlQc@XvLSGLBY(IHKc0Y+H%p{y?wjZC;8BQ1qHZagd#BG`{|XG7-Exif-8 zZI%mQyl=T7NEhPDmjEEAtauCh=_MVKd4^qxtk;h62qQv)ofAhwx5g5|$_w1cGrzY{~KtlmaklRe6TH)X`UFciSD>K%@1~xUw;EePm9VL6Wx#v8VgYTWUQF5}rv<48~&Bc#jF4Q)_{EMAC%P4jx`1ZkVOjT8rU*166g7Rng4pKhBuZl)}O#Hqe_|lfO!Wn1$S=;B9Q0#Je%{#yc!73Rw#k ztmGKK+qtRy2pN0W}@I2!a`I>1g(9n<(+dLjlUgN=VV ziCGQBR}fC%$&AM02X~lg94X#BL3DEBQlitWu%-bApi@0U{bARDtprMR45#nRWfQ8M z8w1j%Xu>qIGCbLXk*;5YS5` zdxSj@Nq~5bqKN^aO@w$sGUCIK-2F}5LKgi*>LY#ui=~~6QMiv6o9e)uXK`;3X)H&R zg$Xa#L|u@x23bQq64)HC->15qOh_6<3ltMU}(Q zaMbivhD%@S0GUoLzQTjS$PLb2boQPS5B2iaNQjRGUVLULH%s*PBnY{a1ai{nV_ps+ zRK0;<)viY&`mX<`dGZis?5r3TQTK)$9~9j?aJWsC#-Y$QXK~CE+bt9Aq}ru;C;Zfy zjAu7NSlbA1ZZOP%+w<8-hQ;>#-S)wY_jiGSmOjHq!`0%?3L3HDebR&v7N?6CPnE=e z44o7A4dZBrC|8gnUV;ZfG?g?`2x#NL_ce;~d=V>MBF$N1N-n*1VG&0u0Dfq;_WDjaP-pmOtT65$Yn8{ikH3>K4C?~5-uKi^c;Mqm zqxAAJcexYJz({TSUTGXrYMnZ!L{))Q6QAp)v0P`EHv zNyEz$_mjr@;T>Yi;b7W+i~|e~Dy7?SX4nR3D5Czen_f_W#;w7oKAQ&XL{go|ArmR!Wm>Te;AP8WZN5thQdK`zuo&HZ~i z3;8}GHa99j*SK$_j}H8kB(G!xK4}v9>NTd2cp*sF7UZo(axQWU0`7CF3i7%tbw3dRsA(FD*=SRXR*6Q!(E4waDo`^e+MR-o1l&Jr8NKpwvXyaeI#;jgn0}G; z5x~fgUaM+dxpnm=eYfa}SI=S{fOq8ie4v#<{e5K-u*4~(k?8{7$(K6$ur&sqyTxhnc4(dlcjaDh z-tHvu%KD_(hXxBF(^&9EYiO=2=|a!B)*vRsF}p+XX=H?ZqFDB&USVjmi~!tcXXmbj zT$$tl#8>^1Uz84~FymN+k$r)#WPI0wU{`QK>;7g_N|%h;zZcT?QR>Z3x4;k|&0~{MWuEwCbeNU-GTgEQ zK~CYo`& zrcCjl>w{q8sNA23u4);TI4l$`R-4DU~KSMDuZxZkLOyW{xGRlfbUWqd~!rL$1iV5P!; z7x3TJf4w1V{0qjc(OAtRG zn*x{#GPNeUM3_{xy~-`rsdG|g20QIRj}W5q7AQmG4~u{5hnN+^sFzOV}{X!!-Jj9 z$LsipwM@pRNw<*E*lwF|A(BlPo&oRBYKnRlyX> z^&r4@VKlf7 zMuQ7KEF7&b9VYeXE)sFYN1Ay4wehK^Bdf<{D(j69~|w!Il2R`Np7qA zTz`JMdz`&-y~^!*cgIUR0~Tuep795%kgvILg`3QFk<-DS$C#p%IV*bp+|FvSrsoTJ4YUsq z^WG7`P3_a0?H9WT4YcO{%+3;IcsN_cjrf(6?bv(u)9s$Iqxfx{Bh<~A33O_N(X4-2 z27+d2Tk99=0^0iI$nsZD$4_mrkI$8*^U9K!_@80$XNJBYr>dSL@gCUK7R?>#&f9=NQnEz=kj653Ef1SU@#8UMya^^h8n_+-j;K zYhikZiV&()p!Nw*KJ5NCTWk-A-#>3rxmZWl4+2+Ga0zDHEqHr6AD*uuAu@|@>Q{<+ zVP_!lFdV$9>?AN~#H2V2w?d@N!35);6+7WM2V}Q+2dK{I2l3$WjqIjQEYZMs7~oM6 zgMj{Q!d}QZ(1i9UYEM`0&HX^wur+KFZ2A`x@&`Fdfy<8vW`37@gxOX}@ z)V450FH6S~gO=$GCa9FzIG7>$=PW^Y^3jy%;U{v*wOQ2nsnMT}VFEe$Uodu9*j_0=P zRGoL0jc6Zal;Fvw_Rs^AE3+rV-(o#1Iy?wY&X(M-TBo zKu1}r(6Uzh!jz*>5;0S3jV*Hr)*Hmp$aCtaWl1~Fx@Ds5*B7vsbYg;|pu~(eXF=|F zWFWx^yNJPhg(nEolYc-dS_FHi*&-M_QA2K^vQyC!G?Y8AaY#)f)t**NK($c0Gt-fU9;7=Ynd^Xi9p+gKq4dNV~oJ<(* zl5&LnlJJ$$U})x~kRe5z*k*;i{0m~NR|BIoJK$c}B_BD6nq8?-vw4TJ76$eO!r~F| z7H7exvc88yHJ~{z)ZU-<6y~iW=nDQ0a0!gv4d-b#Z6JU@ESxReWB8zAj!HP*wj2Yw z!yk5EzRc}~i6*GMJlfgGzYIB9 z^vxx`P)U>C4tNRsUGcWo$5?ZHSgCElJ=%Y@{kL7$y2Vvw-xw%Irwlwaa%Jr7zkYsu z8I=PED-CAq&+w%oZB>A@@0t~-2QVRcGeR1KGDtSX`D;mfgl1FZH(GeC*TNDlBw$%V zXYmx%L;iU>l|j0Z2K(Rt@7;8Q*s0RVlf~A^O_4W_++=4U?Ne{a);>d#_f*qn z2woHfrSnx7=Ms>27Dr-qAZqpVwxTL5syXiLH{nC8DR=a_Y+!)ns{_5N3H1CFy z{yScV`_*Io0hHnv+>ZMh3~yGjd$g$3dM{HIC##_LW_#yv+b?#3QSZ&noxvQu8=L(( z0qXemGvK+Woa6-l5LT>pihy3ZoyKEVT*rX57dSNspw=nYc6bsWQ}BY`X(#+;83g3z z;QQSdd#`aj9qsSG3^f(-9Zs6v*UxNeSw(G5$tuMesW$#6+|CF9m z`TDHht@W#AYB&yc%dC812r`4vi2ZLG6%G8Ng@q~__>SH=j($eBoMIx^^k$dy|B{$thJhqm$WX+PFVw28HGJ6Ohud~H0j~`7} z&kvFUj)nT+XXXc?bsP;)89<0RhL4qV)rS1z)F8kwNG^dv${Uh$V-_|7_gwGpjVMj7 z!7)o_hO0RiN%>YFrXS-8Mu#KsF-ed2Y-A!Obchjxkxe9V!I*tu<$@0^eZwi&LZAW2 z<;ScxMMw+tCUwIU=<;^1SOWxSRvoDAj#(Sa!3#gc0qc`wJ);*(o=#ND=)|1eQ1!`2 zwMae|W<+Rn^5E@FA-B6h-JRGPD{=TyjM23DO^3&^RKUdR`>Jug-T05F@hjd!wB9>L zvPE|L#tbfQ&qGj)nErps|z;6#}QDrWEy71Aq-9U5Ji#T zY&Z-a$jrlN@{t*YxjhSlogIUg^eFIy}j%3v(R)NFVZ+!Qswubwm1%WH8 zQ`I%*^dH~Dq-vO^0%3-=`+cmqj<{qQ1d>=|sFkxD1WRdtImluKPPeq8Q7Yr4eUU- z*m`Y5T5xvHjY<2>tm*IptiRqQm6%;B#tB}f(I;WBRB~x$QQj(KlnW^~$WkOd4Pf|S zrcf=0dI-804ZgzTfm&c6ddGv!{NwJy;okmhFOOcZdRd&fxWC?(61UtG!{Y>h{`2w6 zqvPHE=M^KIZ{Y#Jcg9J^osvj4#uUZyjM}`qL;;E2V(hhv@jHgP_FnHDp{Bvn8Nm@5 zPjr}@ZV?W!?Ic!ZRga>4HDMCzs)lEh3oA6tElltbjdmc2&LXrF(Gl<#@qfjkvSoR* z`=38zX774K_qz|A?v4b)vKQm-kei^e~^yj zQOEw~V1l_+gyZTzBDJphrI%gD{n_{!FS~N7=@Ltx(L*?e(G^;ZUnDd7cNw>Ly8Aq5 zVDO3Rkx$dK&Vc94b48g0ETy*0W$G)s?YP0e_y_)5b$zg(dalTH|Hs!OdFLEIlAS1b zZ}^ix=r8_(|89D>)*|;Ni|diAk{kZy5BiIL;J=&rwtDokWpO=xk#a*H^cVlYe>bPM zl`mH?i;I_gj2r&s5BiIL;J=&XwrcdkWN|&HQon&e@ZZg?^Gw$_i_0??H8=WAzsM(l z&|mxm|J}@PtJmKC+%or$$neI)1T<*EOc|PYbn+@AD0g%7x((5;tYnW|ehC_fLo?G0 zv@%iT3nB}K%@p;y9gOli7kGE6`PY1^gi^ZnR;_eef0JXd8=5c=u({J4?NTiU>9O_j}=_}4cz z`@Qmc5%9nw*Uo(F3$_=F8&*8MwsHlk=4{o`0jM%9my#&qY6-%{B0`xf#B~#QPT;MQ zWN5>%>L&}g0(}$aa$p-)e{b*$haoV_cn(B{d!JN}bU}(5Ho-CeoQuF0i2%Y7ei*{L>WxiVTXu+xhE317%E*c1wpaDsg1ibtoKq2b-d4A`QU{h7wT@T| zlP;d4+fW}C04m&X^Nmu2u8H4?^;^9ET<-7=z$HGz7*uZ`$=?gG#)Iqlmo``|uogG0 zh}-oCH_XiQohNzgzg7pP(b;P7$IwGGyjwsH@6d^bI6Qf^ef9S`J6%kayKheqJ>`#^ zxuxY`+hUBRf`jJVcXZ`A}Xn?mLNNtPZ`6d-dWOu2W%wQgkOJw zU!C@&2M;%FP=S~)2Dh}3vtG{>0Lgz%27{=Dmf*+miwa5lorm8(e)2@G!g|+dm&s@? zxCz#VFmspmZG5@8L0@_?lt|w)X*>N$;d9jisNvfeias$Si)XQYR_yv3?4T*xNTa?7 z0~zCwiYGj%x%9D`)E#r!?rGc?p1o4wa-2rot&Cc!I57Vjuck~lPX8x6k>2vBHM-?G zHI`kwxW2%6-Tl>^i+A5!x-7Z59xrjMF0*l|l2?a3;&sPnzqpe>CNLv>O@r2~RST8) zESkW|2(lUU(L-IF_K&mkNqjZ!bgMP~hFc`-I+^!J1VPPODc0>|>~-q|#}uiOZ6}+# zdmIC;!ilP8G_+J25tU5x*EKG8Zs2@=HE=#bD0MsFWNHINFc(4lyFYDITqZpSYLV9| zgERqW)mdy1NL(YPh=!nHwHPA(SOhy?qq&&uuwX!U+qbaf) zFhISJ2--a-wCugY$`;&}#3c#-y~0}wnv3O_0E$E1oySifD$IrphIEA_vFgQSdb9H4qb$kW{iCe zB1LG{c&RwDkR+K>JYtSTjhhtLmSC}u`g%=epe@nJp`iwJatEYg9tZL1l>E++?<4DM z>POroNx8z|)NM>vii0gMKN=X4|M@sJ5?J;w5t>m2Sg=f%=(^I6GP&r0zrLbcrIrdK+@tP78T6>jn>3V7cf1gK_J_dUk%(8O=w(TQ(3I{Rb#t-q}jVFqjRo2X7bKN8sBEKw4jBROO zb4_pDs=;@GZzbXk!2mYu2^1zFi%r*`@4ehLQLagu8#V_~=(jIPmeE}eWN47U*LbAp6X&?0Xgn8`8AK}M@HNc8_*plXe5MN!Nl^({f-OMdAg{cFC}|OC;+qQES)#{HKT5DgpTVO4iI zPcJ7Z2ThK7{_eD-C5sJu{V&+z#dhAd*$30(=>+m3%W(oz_2=KP=}qm{IqY5|<@l8S zYe&m#uWusnCpu;qiB8#-{8|%IIL3&J@?+ARpNKh+YKHYegT;1jelZ0j#sy23*lC%H zZHmO0iBlt80F;ddhkOUdkkX-3w(ZF8^8}+ z=nw>tS`z!jR4VU3Ly6hBlvz3x_oo_o68@*}j`>@{P#N~5xmidDs<}wHBG-~AZT;ub zqlF_#1-l~nPC<5egMIGozk0R(`q^QVS$LFCk9S@@!%-l-(mFG=#3s+i)=LJ{o5biH zilaZ@iVfq zVr~dujuJq(T7!>n)k`Q9c;Hf~`4Zz>QsPx>pEep>pUdzxOnw&((K-^&JAkRouCqxB4SchG^aDjE9uF|I0#FuM|XMayQ5nBqr8zM&neT6C%j)vLn(&RyO>lRY}WC+-ScYGWxDyJFdx5YF6Q`HOR$A*@Psc zQ#ft#+Ax}&QCM6G5EPx^*7TLb&TFR6IY-aop4A&j!3gq>0NYLnVLj93(wB z2aYDm#_lT6X7jo-YW@gQ5G4^f_!;*iW>t!(cs7Rusl z$OSa{Vu|%X939YLVoZiXc-HGtX!}ZTVCE7dPycMj0`p{!%!mF0>W|^6o_BUw?b%oG zPvQV4gjrJC*`ecY$&J#&sck;2b#kUhTi?boffVu8I6@$j&IgPBL?(tiJ0J4(FG?&) zK6rL$e|4{_z8^%RkD1PnP6sjxq`4<87Om{Dh1S+cZj7;Mic&`=<0G=O6U3v7WRi|Z z?QB>I4hN_A6ok1Bl9(#WtJv_Mibq4$exu%KPwm^>qpn+qbl#@bakmBLMli^yb>BF_ z$<45d+LL18k;ytPZ@rXa=Cc>!wxcb9v<;S-DTJd@@tqp$Z^VIY$PQzJLDSxUk#gZz zT3!BP<(1~Te%aq) zrmY_&_KC9rm*(w1bH$a;V7MCWltvf10whoVX5_HR&{xBF8W|+otf?j3Wgjn@ZM<}s zUA%PvO>9*~RoKK7jcVz)@0g`OY{S^`Kf2{4a0n03|2VTbNtejrd*b$8INF*vH4FH1 z0A+J?;I_MrMpKj1_`?3GPuMQV#wBxmp!@7=7c)7TVQ2z!7A0Y#|Cm<9X zeVi!F8Mc*is>ex>zl_q6euvCE4z7~}XT?gP6%cC%=~+6<_&T@R97I)mwOX(65hwJT zOG&0o#Y2QbN*Us)55gXuXY-qBm=g0AUMQn?U#ER3154NSU4+%$1j zzQ(mCJn5Ug9cf*&f@_bzcWQPj@;T7-$>yrS&*Nf79@t97I=j_g{fNpAf9O#E;XYCO z0EXDS?>|*b5E{WYoYW-j!4a))c|YvFe6xEHJb(Lo2Qe@YgXJ%&#eqcua)EAcllU0t z;rJ3L-SIR%zTDhE+?h%thKvdPLVK9@JeNX#h86&n7*Af}IIU}=p@0uam)!HSs#Y=OhlHiLtBK!|c9QvO1dQA;$qcCB!*^&TH=*tfbBl`#?Fh$-mR8d1)yf^_Rj;N!A??o1V$$hJbZwV*EeCJWTxL2$tF^&( z-Hx|=Q8-lv5$?rb<4G#L>ZSdd5OObLDGkMED6hw3%)Gns$5XnOP017hPNOD>#>~Xf z0zxy_y2!>-mQlK9qL-Ut5)vzjB_$~WtuqLGFqu+wu!8o+W10=JbCAN;4CIJdC9N^G z5;x@#yTHtXl{ZMsXgi8wx4A4D0o?C696ZrnkOmk4UTy_{ zB^yL&NOWEOkUvE4-Yk2UOUw}>%k;PIkiSw+ZE*(fL2YTm?o4P!%k4f@j{a7l zM~PT8D|c96rDT6Om@S~z#C>z2G_;vGlAB{ND?K^pj8kXfxdHrE0UCbG+-2RNlGF0b zE-v@Z+r5 zb)oHQlFl+_{L=A%+W#z&iRAT=X9 zD4g3wu(cRWMh~b%34B1n(#XqlGn^BXBGRJ@j*NB%rX$}fx;1qVIIiGObVOt}bCRV4 zG;5%NBS~R%W7P;Qx`aj1XIC$6p5iS6l2l@tahMpyOQa-k`;;Cq9)YwqIoCd?{tJhw zl}r|Jhc+$hW^ZL*VKmo0Lb)7RbB#Lmm%zCuh6$iK^o|R^0hSLm1aW>c$78~2w$?(7 z82c}fWCW}~+8dCwGfX?`yh)xT=sbp-t!Pv7AsF z$Wmt$SH44DT&sVTJhyFgIFsn|BO1MKks%A8G+97Mbs0mK%kgxVCUicmP%*7mPhc!j z^2uRuS6mq)%v$e)_iMFQE4)Rd@MmOBJBm|8ryk3OF!*i!vyp?nq~|MQkz%!9b^hA<$$Ta9$YK5#jBE-nv_BwjLFtU9q=%DnYZTq{Ibcs!pU?7uoj zf^fL|COFzRU(IuUm|IKsJuE0C|My=@QuuwB6CTiaTTT(jI|4eG^a6DyLFg)6ljxjz z5)abL{DN}^==KHoAh+N)@3Y{@7Y!Gkh~#%!Z<~MAdUJs4B2=m;C#06gU?6r7t5$DN zCCz|1x}KZf0XI>F^po@=?pM)PD~=7C8alr<{d1LqNPa~jRyTYhWH2?BH6$;_<71T6 zvraX;skLuv8#l%Z!&?L12`}_{vs|+?uZlUkow6Egn`O$Jc{^^-ZiK^fG^L|J+kso` z^%3lj;QQ^Jzv1V>?wgmv{=ps|y|38wJ)7GsQu9nqOcKfqLypxg)|c)ZHe-3fW-PU~#wI8q)!MvwIisq4u^U>fD^8Y;5H5;>f!4gqD|YcquVjQu zDm`?rXq=mw-*_d1mk<}}N0I-+nnxXxbAe+vBt{>^9)irmF|50H6t^nBOa}_L6zXDF zq5&%*(@nc2+_yfDndQV6!(bLPabBB*$5ifa+3=X9?I^aPbQKpzQw+tOwc{r7`bSs6 z+P~oC_J91Hb)om`B$fhn$_S3lxy-a%rFJx6KT_|mEg7+uVMb2IBsIgM6=Peb+S0hc zO07m)WH28p}(z=_te_Dn^m5PO)I97n=_YAWQl}}>WNE+5fn4Kv==aaWkYtWbhwzsp08zI zEQtD6$fd>KMcAw;Z!t$CV*jGKYqq*zCEP)xB=yvtmxO4u$|e0TpFqDAzv~pD@{27! zt#(sywl3LXHmE}Cs;lQBebrN>fTNg2n^~r}!megUqP+A70es;~_@JdXhSb6jf8eZp zqdAXIC0BQzbW#fzr~IF@1i=}L%4cOaNeJQKw0uj{EH0G$kw)9-KX{v$-1B_FUY~zQ z@<&a*9idwe0C5(&b?%k+dunWV`kn0n5<4@Azh#bd4g60d=VrgoN-x=pWc+T+!&CeI z3n)Ji<6 zonipXBATXtYFuu7vx2v5Uq*v&S)dDVN&l;?Qg43lD{q&G+IjoOFP5_B3fQdZ`NIV4 zBWtm72O-;;B)-*qfz2sygRPP!`7@60 z-;q{e5%Zd2>>9R8R7q|T1ej817nspCdxOjHw|F2x`aVI-zC^+bhnzhWB{nZ6bjie+ zS|r)e9U2BT#JWcD<=k2_w5%lujLVb~+Cs~-1m~{aegxx)G2h$ zaMV5X5_5>7jBgsukXFZOGJ@Kw)*r37?F0{tL$4vD=|DcvfYr%;rLRGnc@WV7EU(mQ zR`P{+D)U=?hkJs2mICMDxC;pU2c1rqV6mYY-4p&`4) zhs~!URUAHThELTHebl$skrYiXmOSWLhyE-GcUVFjw%~u|(k6||bU1Ez7WlQ_CgYTs zIIp&Q>al{k_t4O%r%oW=dCe$&Q{Y^0yPK+RtwBj^TUDx526N%n-9kkfcVmH~%-@y2 zzmBY=0l)Ju!YkZ`qq6l!E!EOHT}N5g7|&lVAO1Tpxm&b!d`8UE()layz6v@q_%Bn? zeYy4~-{Ai-D|E4){O?Cm=NLi%cV6R*)REr&m8zghEDirfn#i)Y{m)#__hb$nrIRJh z_g9RT?1a3^Y0;YB`q!`ct$VQ%^R%w+rntkBzqi7b)U8a}e;<|W{n?cJs$Bm?%)S&r zEI-cDVqU*q!s|;3MUKDzUx?TLlH=+2Jw4B(=>MIKT~JgD9_V0j+>cL>$7JMH4x{-~ zGU}(7S@7)TOISCMIyB(Xe~Y0h7~tW0)MMQ$#><6-$Io`3AHTs@YF9aYP|4Lee`}dE z?7^$}KRmQ-tNzQorQrP<8mrrZvBXvw<=2MN$t!qzm%Snj}7meA=43h7|km8E>Emu#dfOa=1* zbt#BSc@C}L&CBn&o!h-$Jf4#FT;{Oh0PG+Vl<6zsE;UkuH?n7lAZ?%#w_qw2A#<+N z8HS_40a5gvu#tuw&;w&62kEF66W)&L0Cx}{*)B*7tp-d{a1%66_4Cc%?&=(GNS#f@ zaZrk6QHxht?VF7Xna;uh>uREG4&QR^A6ycVSg&Wm5bTry6y^Vwfty!ZkaLFCF59 z{L)YG;tYYqQ1?IK_W7|U73@;R0++ks)}PH7Z#S|)_6S@&J8NPOf9loO>~K0te0(En zdmU7YuRZ6)UJ3%;JT$sRINmzd;-IBraTYJl2gzNU1AiuUIE_;1vqJuShXU!16j61X zJf~Bb1omj3iK>Y&mZuxd{Brc*_^N?dWnq!=@EcO#0wbHyITEMbBkN0waHejf&e}PN zq4qc{EsS$|y_bA6ae6EeJ!1?qG!~^bW@u3kCrg%~PnK=uqHUm7=P~SSg3n|$ys6u8 z+qAj3cm9yt5mguHVA&iMmH9^m{PxUo3uKb+2o1#8$d9;c$U)UN*kxLIpMv%L5csk* ztj;k3w#WU*0c|pII|S;<3H?QvbeGaEXodf$9QPkTN3ND}@vz))87Z9L}Bt1BnhyVK|I z->rZ9{x9?nmj-_RBf8)!&r0lU_k^ig)eLSkC{wN+ zrp{=FSO6LV@^H(c7!u@Qh4tm4=ydXlGRp|nK5`ZI{ z`$pho!*}oh@A5BepFThR^LKx#hWNjw;7=>7Hy>*6-iK}xjCaUEm4m8m0Y39}0UFOi z!Cw`OD6z`V1fmvdnz8)c}|Ee@#WvR=7}kwK8WUva?LF^;rE z03F8D^R!>hK{_a;V~-ghpKjraD|Qhm0i}d7vY^FwgmtC8{t*^g+8f0I0 zo9}*UzF(_-{dM@Ei3n39-SzF-atuQw`by<;Cib{1Y)roJ9iDXiT7C^f4A5aP*NlrsyI~Fro`0!!i;q znZ4l&TDE0v!~Joc!C^2cK&1{w9$YtWNA9DCHR7Pov%~UFQ9^CO)7xYbb5Y*iKzx?6 z0V9aM}3L`EFyI@V&u57gbYQk(&SnK-ti=IsJw~|(d6LAvU**CWqZa8ox+|7 z;!-kIFP{p~^@+c;ygd~*dZM{U_0BW}5#yY70jB|Et)NGBB!Lo~^MIBSo{-rLWYD-@ zNB3(u6GuHkF2LjDJVMO@8cbGb#Zjp8!5|(mDb0cvTAGc2tQyZDVB@FAx{`qv1S+wNRtLJLIWJ9q6Y1P;!(Y;o0onbS!$ z28LvDiBC&H0f!XMul=x6DRujFd$QO^&eQtNb01y6^Le`8fBGerhvKa`!J3tewqU~& zhyZPS=_PI&-3jKfYJL$mHIPt=4M__Tj?m;xZVEj`0xU|#A4(89O4iaz);~T^`f)nT zj>sO;oF^^-NQq) z4WjWN&8-XuwL@t*wgnRyySQo0*+l!WJ)tY=r44kCLr6Hv2)sz(KeS7xLkRc!{j#ubT-h41S69}hS z@hnQPZ1coka`XmqG_q}B3fiqy-(r1R9KVeemGAc7pttno?ya7zxyMtE^ z=QRbPZ8j?vG0DW%WVS1OWE-4%O!rFtqFtS+!eT20O*PgJmj_a5+Dj;M5NSeb2FTQI zWqLi9+w!n=l8joDVYrIstJ+G2PZlGgUjni;d)NG8cT!9}4ub_o{Wx=mS z$6r@6lTNhFK+gvQqv&J*f^%=?{-`Kecb{&M?;Ee3}qphvuM2iM|fZAKE7hrfDwvnb=q+lrv< zfiZB@?IF}Y>PM4)=tTxIE^bC6_n93rr3BPD`$zp%vUO9ad882WzKA16ppkEXYeQ+5Ybk<#AK3# z>2;xY5kmn_1GXgAsv*mST{4XALq&%NZxbyxL&?zaS_jVD*-|q3eF6LDo>?QXtaQDd z!W3lZU%1>jbMWrv-uKV;4tSmIi1Pw9S;l~G$Jv@CuZFJd;_=KS2*$8kBP2nobXJ=A z$VNHNG`yxR85s|TH2)DbdY5jzHpQ!cd+;R@M!zxOXm!R#Vqe!H0N~U4N)$eGF0Bw z$PhN!X4a~cm>i14dlFZ~Y?ek!3J9^jus04pvf(4FNI?`wE#Dm8P%*Jt_jQvo96Z3yw&g$ zpE_ryzZQ(ZPp}ne9jD3(%dg_QiUdQY0Ck2K+Szrh^^bCkud`$MC>lH5LA+OlW9K?5 z=CENYKn)(Y(%lIVdA)Ga3qkVKd^976tlT zPJbX4<21`~NnqX+)CNt0@AqEQq797Qkb!x^qXFl}61^2-ysoopJj@sgs1lU?v(u{4 zf;sZA1YA+)ys30%f_4Z);wy@$Gaiz#^68uu5raf|HPnN1o3h}}Fhy}ml1&Svb(zRd zI`8_Zpvs^_!;^GCn`tmThFpU*g0t;do?~J06)LG3IuqzNgPL#6Nejef{MGCsO9vM! z>-7had}VXhDNpks{{58*0mXm9igOO;j7fHutPFmP{j!DRif>HdB)JL>c3@DG;PFv|jq7!ZKC^Uoc=iTZ;&r-5Zf@Dp=mF+g!< zgV-rXr3OvQ}GK#p@$$VM@GT^VQV8;89~oZPf71E zlK6}JhjF$lLTC?N0~%ESt&5g}W3zV76|BnED{N^BzkIO!a(DZ1*QIs6kEo;41Q_iB zeUkA|#(YEzoyE?&MJD1pdF-@Q(- zj-X6+?REndq;J}{Z~)|wi!$Dp3z*EGp?(S;yiUmvMxQ(f5Y(dDMUa?AS#FBay&7F!|FA z!~>p2z1UH8;8)|X7KrkLv>rGH@uVSCpm&QF1WO#)5;=2Vlqq*FkrPoNJ3D?crjT3_ zxwZs-kbU4|WoKu#QbF`YCKE>SX_;TbavU)P0QuB}tIREv!+Ia(Hz?^^3NUUxbj`(E zm{@Z)YXu48InfV^DFRzJY!0Fj%d9v#7Ovj9)Fvv_iL;Rmzk6ND@sQ#qgR zkY7|+CYe&BdWE)s&VoBwA#DyQ3Pdo z6qVoOj$&=qzm#&FE|SqjG)Q1?k7My5BK1yaZqGumMBft%?WQY^dFl~th0v~vMg!{z zS<9bJJmw^bPSDbkX$@c95#qpd@S2cLQT-E#7f4otPSLGgWTZb?VMr0{$f;e*9Ufjd zqagrNDEMJ+D2FVfCV-8kZzDj@4lDn8>M(Ns*h75@p|KEE<%aTR@Jd? z2+{4?9YU9SjzzlL0?*F;v$_j3fIPIJXB+ie*7}9_V+&ZI$yU%BhyT(R(=xcd-8MR7 z*w*Xo)-OMiYCJ~44VG}L-umT$ezZPSmVT%#^>Z$rwJXiJa51$^1+?(`=!cHSU32Z# z{1YCOQpL@(0Oq826LN zLC{GjdL=1F5|rHWd9>~hZ1UZ$Ecrf++@g?PhXw*QV3P!0O39?-`A|xoO5}jgSd~>M zYK!CSI-8`3s8JK&VaND8m&SU}F9$n>eIuG^tM^8~tiiQU)lq2x++I^E9sn&pIi8KO z=rktdWz*lh*QWLu835a1rp39!tJJ82IO^+7g?pet)qN6RJLDRTkB%v_dq?eM_!>>e z0Lwc3n2fnkhJl%*l7iAbTWhY$n3j-z2AY&v>y*69X|n+RVVhV$05J}cx)iWPY!Y$e zePxq)Pn_7FVlU?9gYS>#m_6Dk7^bW2U~u_Ko(y z`N}D+5ThMKVfIGReblXXYc(%vw`$gdIQ;RN+C^!%O6u^4Uy zTNhPg40OaiOU>luEIb}YXGyP9qYvY_Ni;a|u9L0cOf=YUUQ@9$vW|Bum4Pt%Cr4wA zFb)Qcg8&;~H83k|ZIz9l5&a_0%=Kg<7GL&Mut$Qq%RySgr@~a4ddy9=Cqs^y_KYMcx4l^+7%XZ_??7eKY(!ZE${H-}0RV*8o%*?J~6iT;f>=5ChR zy?Xm5x97VeUc;B%jxO2BOYF2NS01@?^Vag}J_t-9As87dQnc*MIT7EX@yo$3H-faT zJ^_@T-PTGong>u9GVF+n)GxI_$sFlrFvW66MZNv{1^s!u{bDzGxpTbz@+E%k9R2+b z{odJs`EvV+zP^HPLaIX}qG&6%uQ&mp2$iYEHGBgU?{l{bLL+?f=HLF4q%c=*&Zl}O zCBON&SMt4tPk~#E3-3>psw+Wx2M@*=CZ#J-rJktlabLS4LesH$qVN=5GxuuL48k_` zRwa@J7Q33nTI~ALjtGYZVMm_Nm30U?M8Cndmmg7on2aD%=D_J8+8<*1iLg_3+Tsy- zvtIk$ol;*Asf}E1A&D^$8+hEGo7+&*JcI8h%E7xq=S&TTA=_GzJkq9bVvm@t;#B5EE=q zpc$VIUVWZmL>)?5EqAlZ)C)Wbg z$5F&Y=_0ltLetbP&cf&^H;V=3iVZ?b(m=S-@0F0%G+{MlKBuf*)ZbjY=%9slHqho! zDryRyWK>btE22w`Sl)+4?qm5;|$F^r)5SgelI92BwKwOiMB3x`}M#m z3<g?^xuRqB}UhEY&E|ewj)9xDqTtx)f7Cy-w9 zXOuAIJy5Aw+Joe($!2~`$C7NyAoNK1AX8>7o41?-=hk}~wBl*6HRw09w26p&CG&Jk z&Hglox$?q7-L%`ioqz!6ach<`cyqF2nCKqeC8}2K$2{u z`R>uby~ zsoJ8(=xX1rDqQQ@{c0&IJn)MwXbgV;6F}yw+&_{Qj&KVLWGhKAPqfnOwt{S>FBV@U z!9a@51OjG{#hoNOry(>zy)3$0Yn1fVgjS$Rj!_#Eti;CZ*R^DLeYEOB4ODA~KkUAI zS!F+S5!ZmZpqF&TE+b;!RRSN7K@eAwroVXo7TSvkO_-V6$effb3tB+o;Urt*9BZq= z*3+i}e4IwWNW)jN96TLP8P;#&1N#<$g{1Mm69NrXr@8=M$S_lcVcgbx$n)fMT2Q^X zWxBbX`##Heu>n3(V*l#U_!ksRCOiuZqqV$!M9Rm*02{kJq_=(+4GU-0)i`tiC?&L6Zo#%?FOy)y>S<(UX%64oh?_f>%O4nQ3e<6I3GuXdapc(+Hrh;_{`pt zvl|qf#${8*)EmU2*??)2ZwMpZ@j8uAj`D=ADX2}1e}xd=LwPw$8Sijwexw0-u+b?y zIk8Qp3K6zNsRo<^24ve`mBu?G-8fw($);w#N{q6u_`lr3-0#jzD5>CHdK;ZbxSwP zX<@0%He)*DNM{@loK;&bk)X>L9)Xj|g39Xw7wp^enJBNqCphJk0UPEHD`TF*=vTSF znWxJ9wUh$7<2vHYZb(eYv*=l>UOw}*vq}LQJRqBI~io6>VbXxb(JWA#A}`Y zY&g8;3+L>q!{#Xfd2Jb1{n<2VizQ5ng%CF0xgs#F^F$CnjAbbFKn6aj^&T&`-)%Sk zBWnEmev6;17BTZ(6E0~iYNh<^@+HRRx8mBI){=pWI?f?IQiBX@D#5@vPN+f^}c5~^xx5*E@weF*Pt$MDkq3|_^gAFNvMrF zR(!homUJ3sN7TCLd+X1-1GOdizwTs$_%4ufGs=7B2O(}HVHlOdabHj}wf=Ztd%@s~;+Q^Mek9k*gu0B}b8G0+e57(+u6;&=V3`5MPbSa-MS|wjiDAC#{}9 z#7)TQFC!~Mq=gn-((!AD{mKQfAHQBBh$_{^%h}&1dh) zOVJ)R`vX+$%&UbUKx8ah%_eG(f)!cHgX_9R2%CJQPQ((Giopb-*eu0p1A4HAA%m#C#>mQ>iTjCfM9$7O>Ft_Z@oqhK8UvqW*_3Hv~M83JWUY7zR+5bMZ zN})sq@ zx4L9-9b5HVruw&nowUO+ddHJ8j!Wf%c$We?N}0iJQ#>?EE|Jmrxu)=~vGZdBOWox7 zq**>63H?z#lw#va9nX&I;&+ebI+x?_M3l*XY|1Qk8%DNenr)^FQ61UoBBZXU;-@BG z%#q}VLRnfE2}MJoELk2)tCh^i4FR2MMyuKgQ?EYYqe>4e`vk+R+*0)M7Z$C*y;Y&P zbNVKFibf^{t8;f|G*#&Yc;hY`(W?AKj#>9F_&8V_x-QslQ=I=X@CR`HSyMBS z7ujGGG%^azJIN3LpD|eZ!f-GO1@;Lh^Xz;o=N6QrML3HPaeE~=+gCww$X8o@4FPo+ z+yX>7n2=v*&^WDYIUIW@8o;Njfe~tAGQ`oPCQ7UMYJc=mw^(38M4CfJUo)_&zp|I~ zO30awm0sUUbQlybsJ(oBd`Px7W)YcE351hjP0b@z>QI)F^iPA&@c-4SHg*&{(>mAq zWt<}a>fOQc2*9H06c^1r+Zd-9HIT83OGu_mY{pqU>!%Il!B6Nz*86Kbn?Q-Qg7RSl zMNU~D{4Zfc_&v4#6Op{605jampXpvK&~XsxCyg1zFu_%E`t{dDW78)IfA0_v_J;zuWsFZm=R?(Y)A32 zRJd-)xw_yZ78=c{X{wx!WN{MR+~rd_w|ov1Dl6+*+@JM|*I{m#VNe^{^xF5WHgS!$ zM5`0A#`7GqP*YH=dD0w(oD;p!Tz{*B_i8?eZNAex|JJ-91`9iib6uEfGCnY+hQ1Oe zzwvTeVRli^9B1U3yyVaHsSWV9=+x)k!|3ido4;w?Cg8bYtB3hM8F(vgF|fUeZlx1G zZ<76~%uQoy49eR(+^w1H<~!>$eag2~VoQ*7srr9rpUUkV@3ah#`V4Iz>l!bfb+A#; zgu{ixR6tswk#)Wcp-JYEpK+FTE7!>|xxNfOH}n$7)%o=iD|p*71* zuQ5Aq`+YBmBQp}WIUV6YNzu90=SbLPBY@t0wEZf|2izT3?YGS*l-e2g#cp8o$Qcu$ z+$8==)Wi&K3SJ)C(2Tr;YF$b}hsvvYaF1mO}c80j*+8e&vE?HfR7Z)RyiN|>%1}0+9>Agu#2A!*1EsL$NWbdD~ z2mZj!cZXOil>%xmnXF=>g$I-yLX)Kf@o#XpxcZf_{xy%0t{_pW?bjUlRENQ0`YU4t z{q^fmgI&;R9n$);1v~ci?huyQYFv#uDow6V7!~m#sM@%gwbIP4d#56Fn6Jj+xqQxp zEw^pr3a64{sR~Zf0PdlDqaq7oKk_apOP*DX8Lq_rZbPkF>E1tH^4nDSZ@=}r4PhzGDzZysvWR#W(5_Oxua7>V3QUCo7BEmNP}+Ms#TTg5;#I) zs({@>{B@2{+?r(*(we9&OQ?bBE5cZ}SODIKN2BY@=vvtZml3WzOhmrKwYu^Zt5%DL zecJLRE@8E{T!w4ea53peS4So(C6&*061#8MB}wmh#tbA$ zz-bieXc$wNbB${}==+LliJxk#g&{w{$=gMh>LNCk7ljg|)QDvEqEU0S~*i>r`=j7VKAsL8iaW+U#Ko;YngN}_YvA3)=QaAMl)R|_Pt16jn0W#-4-NC`vG|cZPpZ(^g7s1Q1;cxcX>M6;3Xl%+FKE;A| zV}r?n1J^X-IA}Iz9GxKEm^4SjN(qt0s}(N1_K7|}ADVARYz_1#nq-cikrGRsCMR^0 zUQMdn)Mn;6)LM4>+rAtSyA z@o*-FXu(fep8xLj~{#Rju@St1W=~h8nSw_oTe8bNHYh45q^<8R6$Kd+0UKMQsTSA0wi` zka+$4Y47#s1~%LFeCO{k;3>4*J@Bzqd^LmK|joL?uB^a#`kfQTe~BT3|<}`KYMxj z_gBX|`>zj=U;qc+gr?c)@iDfZY&nhpqTIsvfPR3uL(&C^dT#Rwpb|Zq(aPo4I)RkU zdCR5P+oNfV}MtLrP{E2s=#VEdO5^t!2S)_9V#sf9G!38Ih^@1bih>7E-@6xiG>Q*RT z&Toxhm;br=+i`W}7=PAQ&J65Vk`?{D2>(^emE_yl_@@pZN|(bO&Zp#bX1(OwPd+dO z`(WlySh#~tun=E=ozN|tC|r0W0>zuj@MUy0SuRcQrdwYurU}P3)%9x9*YtLZoXk!n zvLN#<#yt+IDTJdnL%Ot{&Vv&S37d3!uDn~dn9u`|pj;be6Qsqo69|u>^;mpe--K`F+R ztdUhWC1G#FYM-POSw)03);S4gHAyqK8F#!i*4IYA77mXiRcN5#*KR9;9KmlgGWaQ* zO)L4uqhOt(CJVJ847L6s;W;(fQvr}suiNfovK3=Rm_ z_WwHg&H#^VH>0*}Gr@8zpxg~e{#bx~FhFpYfJhNx0i(b`?Zg|rgGMMGVe1_mh@_vS z7sK(jwO_OrEXV^~S48l@^d_6x23Gfw_NBC<)p`}?GOdaV)ZnVM_J zh!@RJfZ6d#+xHHkg6$>sH_3zKTf0Wia;-o4YE5UjU|vWG6T zHUc)HaKKLe7%P1mZ(eq%zuRDgwowKpyoFSY6313JT=56WGNYB{Je=!y#@v73qrj zi=DP`Zwgh<(nk~#qf9#+k0$LgCEH;EB?cT%mdVKio)M+E-0E}yab%mN4=5C-zHzvl zDg_T@lx~?4d?Bq3tE4_O_m6(g=Xm|~w@nr@I-t%hR6NMe2Nm&Cpz)I+8-v-6m+(7l z-lmK>Sr*uBC3B4)0fmg$(x$+;{)C-W?%(I{ELC`?ayZt#tu&Tb%$Z*z32w6F)~^8y z|LVA0t(sP49bjBbyfD?|_^YorSKRHiH^HC&?uwsRsal#ap!wm7RBFrQ4$G*dG$yO~XUOX=7#nhzzStoJbOqB!JpP9w2i zq`;mOTleMOj=E(f$#)a7|D$Ls9t&6uAjoQldQAeSbpz(eb89-zNfuYd?be|zJh4< zqQkF0&2LDJ{D94#4<}c1w^j}h^`e@1P^zDq)u-F(ag}D9qWo>KsF35|C5!tVHG$Xgr@ByI|oT1EIZk?HgM=O z@+|d`4!epT?d&Z2o!8qK6%1XgfIcS>Ek=RpS#ne>fjid@rV3QEKI2`W$zvDdW99}Y^Jl0P) zG0h|e1=;R(9H2g{j}2aUQ5Ari!1SSi`*LPq$)W|omnwi%JN$g7;hVeb)$%8wIO9KJ zKDjoTz;kY#J0A1hkJutNFEnP}wP(_Q(??5zY;uYOnz0t*Ls==u42K$-e&s1I%V_Fg)H%u$2 znW7s`{I^N3r*Z2&6e>EGk66ycLjOyX>*V9sG13$pdy2s(pc_Op&9nXlxnx#uY#;nk zlE7&I!VbElq(Z}GOfB4`qX9X$PO@a_=-?GxOF*yP!{tKj?d{e!snc2+f*&)MC*Y9k7^n`bM2G$==#*i|(Rc#uq~X`SWKKmmuuWlo*n)nOY08v4_jH=$(<}LuWR%9tNs1v-ZRuyH=phv?i}pBJbH03ZPmPS zxQoU*Q+UA%no9SSi*j;dBq&cp+YdC0rVH&M#oH1+?XzKbY)xQm96P0hami`>Jbsv*0A)ztO8Whes+klv4*g7%2n%A9m6w(K;E;kzWAQOQl$l@sCg~>7r2LH ziA|UT_g&y4WoV__Vz33b(bv2#fVN;shJy^~tNQi~?bCak*o&>dn5JE;t*x%UD=jRn zBzp;_P^YKad*Io5TJPo2Q2zc7e?=$t0lk%Di8I`jLnF4!!i~aqp6@ic;rHcddObc2 z<@~6`sen%wAV3La8*dHXy9d$6B%pJ6LfKLfKWYqFGzTo(Qe}$K(`b}JV0dT*8h&ey&kdWyxEyPfHE(8tuY?ny1FLY z3&HX2fFl8A-9Ra5DbUKYLAy(QyFof8pa_)r$p-8a?}NSm+rb-l6Tm%QQAwKy2vBnw zC_3H3qeQ7e(ViB`mA63Xlh{E#*5+$QtUIPbDth@$Z4Sr{0MF5j7yC)Q-o@CNz(Ca5 zmB4vIIN|lor2?L-*E?yo(PJ9+;NkAh(cX*a&F9^A9k@b<7vQ!dQs+DME zT#R1oSnR_~s56{*`Q63GOMTYzhl?*GZO}-)Ilz!5fmox9cKnNv@y3(SU)Lm%8^EP> zPeZ!ssM&)|Z0beSO8#UVa**N2UGBEe2U#xMPr)>xe9=T2rTLdCx^v)~Y@chsOUvY~ z&6gF^UexFnn5Dc_RK2{oUXI+j_hV~X+m`PVdDdhSo(vN+P z)Y?TwD-cAzLH|q>i9dXh*bL4!MAp&*BI#D|vUQ!IJ{~CsiiO0vP*yg6T}XagcIlO2 z`fK;M<9D^S;}7)}9?Z%=_xfgbzy5RMx8)6a1DmK%))oR1Vy&^vX0EDTFj0z(&P;?3EC4E2wX2#;T#%U(8lr$5}Jz*DZdHJJy%leN`+1@XG*g|wd=pL5IYr~DIxO;K%A=IOB z=Axd7$sV2+X=3&2!RosDV;~wNYRyXfuoYr|FKL>Dmo$o(G(o6Ln#VOH>_=0>5$FcD zK;Q(DM6|eokjz-}=*6iESU#;aMiCOUY{Y3P8ztY?@Sn$xmCh!fR{Z;WWqy)C#5|v! zh*Qy05p~gJmpAk*WFdjjL+F5~etjrL&}5PGDZPM$-vg)UpFxrGsjQU zsccGU3@lOkG+>AD%k|~X5RK4q^pqbZ96OTyWKk-A>XUY8ky>@T-iT&J@>FsXwUm%N zhH2<^+hpINSL#L*fOjP_EJux$J0E&8!+9SMhH^j>lZG@`ZdybRZX-Ayr~#%%F)oD$ zAh9pdw|GmxU*X{~Us@;58;b5{0u)JEvdXX>I5CQBuo9A-vdeQLj65N2lopD!DCs~< zan}5r=dXvCo!8|ReO-=br48M4w6MI^nNRZvlQPYT8Hoy<&heaXICHnzGiCMCj$J=v zKecFDL=!4w;tRJX5DiYvEQNctm)uV%>p=Ki#!R&w*BU$8-ZK<~s`RT1UY}*&}5M z%1Y53+5D?BU{m;OPFw<5g_PwcAW?yf0C!4uo}6C>Hy;@xbP^pm`K+^Lj#EWow54Nm zUbQD9udSRfnb$(usfmSb%Y|WpZG8$Vu)p{6MN-Gu?)k<;hYQk3Y&&{~%rEgC7{W>V zI%jwN5a|M4owU3e1)bYu z1I}~AbV0#QC;foGg(rQuL+Xo*E3uK(-BygtimVE5N3WZtF5xb3(P*?pIlhzVfOS4< z$VEh4nNf0l9lTB#y%SJ&9r8bUx;Ezm+(rJvc|Py=fX{r>x+W3CWm+NT{RCzvVU19U z%a>OzIU9_}C;%RhQ(|#0(A;jL>TOCSSSb3@Ys~kQ=qzAmQS*EXrvnf5@p5C3)R~j5 z5A4I9dFte;BJrhlPBgU5>s-fMxhL6HZZ}((Yk$Pn#^Ddeq` z+gcG5YfqEuxzWwvS&XQ0=(qBs{Q~EY7R=m7W_O7V<*bbtEMgFyGDegt7wC+_qjfL3 z%_n&xHWJYSd*6rGt{Y{#K7m(YZ}W#h_Y zSb1P_fq8C;wS=^58;iw-;CFyCm&+;HK8)8vPZ{lQ+{pn!)<;&fJ zCY#GNzuVn^@%)Fw=HBxrDl_&Dpt5n1Cn?^z^#*6KcbZgyJF7^dZL)ZP1)vZt1R1hF zLUCc1O)lJYwI;jTC8q>nvz0ML_3CCN&IKe9Z=GDW2@AEzz|94*5v!F@a(Lc)+Z~LQ z-*NW}@j45+=NQ9r4VjsGfA9glIhlqyF5UYg;nosVb% zm2VY%%_s}COO5m-A&O5@yKg0|XGdfQK@O18y&x%IxOv>XeU8{Ln3srv`zgljgWgGa zK&dQ5PRUusoTS5)2%^g(=&s0qap-W&==6x?b`Of8x)FEG6Q1>UVmV#~l6G-=y;_LNdJ-%I{GJ5L@ou1Hhz5dKQ=H*zY1c?^4S z{zwA|qd@i?hw``M@`oDomF;tCgQDT}$85mHc`qkf>kNa<(>4$#rzk6Ty6vxl3aT1faA%m@$O(P;AcVd?3s?fsqY z!`-blQ%WC6xo3YrM8L`s`|)M{)z8TrfGR@t<%`3;pT(}k>IKGtAJVadwJ?zZT_hz6 z%(C}22RG-m6clif zE?Vu;K)>U533Fyt!VD4>-8}b_pYVdgWG{G}DFO?5JPG!r0oF8lGcM#Y<8W3tOC}v$ z8_QO@;LzB}3XU(L@Q}#uSaJ2ZEaHUUu^-EJ;-A1!z(F2j0B-IVypAn2MA>QDCCURRzhtQcIRjs(ks7 zRtcydj^1I1nBE^XCC~$ye)s4{K5DN#zU0yhBp_;Xyb7(iaU}E-unemp1!G$&(SEThr0ROvcZ!8eub=4`S4{P@vwxRA0sg-5#|hd z-ys~B?nxJDxof4ci9sAyOOlj|*NtM&+k<7EHJ=0dW6u+MFPQUW)^0i^`spQ9d;6>1 zB;4?C8wovvZ?b8Ej*njh*)>YSdZ=%p-AGGJFxx?evB5nw))orN)P6w7E(Z&jOeTY- z;A6**uUyKD_JLGaCLu-Y3@w?)mj6Vq2yuI_MHd0x7A5vzCcY9~KjAZ`1E!CfblAJZ zbK%2g?Zl5*g;fGO&Kc9o#aaAvw|zmeijFe9NexM36(*RCm>hFW(a@7F3V0u+;v1|#3Y|qxlJNscU228j=vc`$el%* z1O(<HGU>@k$O?DB`DMF!K z9WP3Cp--+%RZLJJEjMIfMD>Y#E#*P(zft?sOAHS%*68EttE;seC1sgj_p+qk>qN$f zrmm=wt3OFrR)#!6)_}VxgzFfUxFivpYu?8)aWO&S{G=F>t%XuV3uu(&z~cAEBF$`{ zxB6$PI~A9AygJrQM#?T;*-?hxQ8+qV+U($85zXeU6vR%!tgTns-R*7(`MeS>>-yg~ zeC$-<`2=Ks6>W#J*V9sUuQE>6TImleHNbZ5l*RI{Fqg?Fw5#oOh|4FRa^@r3LYU!l z%#vD*0y`(@4P*ebnvv6SjhQ7pn>ylhVYAZ`lWTpW66})jh&6)UVbAaIvSUD9Qm=PT z>PCsf2~kUNpDnUIs6&(NAr+rj<7mRxbJF5)&0qg1yO58LZY0~F9eE=l;CY8}fIz?q zXRL%sS|^ma#6@fzvm?P*JhpZx7#9YA5wN(pfGhZD%6%Tq+Tdllbh4@0J6q8E7ThWo zhY+bO0`kW|AzUInZvvC!a;X#~5H2Dk-iv?cJNHnnb;iYXhx5GA@LmPR6}XCPzaPKe zOpcWbarjX=r(Xy!8tG~?`5>V2rCrC1b*Ge{5D4bl@o2}u7Vp{L;SBi&LL)iUy!w;p zp~@g6TZWOD>FFSyn3V$Ii27+e%`!D=4am??s2V0|^50986J%#liWXKUQ7%GSQe(P7 zD4jzVZ4(v&DZYimc`tYza*&A$qjSb;749G3zJ^2cMPP1sfmyoSb+jpNLQ|F#7t?s? zM$Vph@MfO4vIKv3w}um(r*N3KWSsixw0k81jymW_nxg(0jclSx0>-2o5lLzwwgz zA2^RtY;HR_Ui9B8&IGm$7mM>JWy%wB`lK#Fyf^6AS(!t+;z++N&{ZcOtibAUbkC89 zg5;z_vF(8E`!0QPm>fKW8lC94U6LRiwWSPJHa38eURg1Ow5ZmC0p?C*NDkdr;X;mL z6J}o7L&)gD31YZl4i_4vyKGuM+hw&3Qgu8NB<3EKMh6(Q4WZb3jZ&VOmpsRn2!5$p z_Zh10viGKuBZr-XPhu&mGDloK(_SOmz+uYvCn}i?l6{duH78eQH%fHWaT_xC3xMIY zi;)~d>l!7r0gTOTgmxA9nDr!_0DR`9|{6+KW?f_;$nZL_}-JR{D zUD&h|n)F_`Pa(~dZ;{;{G|r#+kI=J*o`pS_LOd5LWFNv}APE^fmG&h=op}rwGxQXc z#o_d|S&5#iX#vr7Eo?NA`GnKDfK?l`bMpdh=Ra#@SvneryTkdazC~Q!qlOdpk!> ztP0OjKh(se82z`&k{iUky6HgGPh{vUM7&XM0fks}_j~QuZ2Q=^>Dqk=_$W7?TH=3$ za?TI|KK>}lp`d9ZC^(rU8x6|k>7=*BOSmP9A}*DYSOr!N1++8=3Oj}0$N(b`>fGUj zIgr6eQ$9FvU>o2WZsG^~xP1=A@G*U`&w=}IU&4zff3PnEbh>=@#bI;r=U0aZNfSQo z{=B=BTR?YP{CUGI-c?fL$L)XY0{%MMef|&o@cS1pcb_+Z`YtJ7o|FsL-P$UItL?5C zlGn{=+dq5hGVviib6$GQ!xMb7zxzB|%YB{8#HoeWR@Wc81M1@u!ZmvVW zNX?e~;ozlT5+2x+w5PpI>+W!G15=An_YMHeFSif2k6t)C*n6B*Rx0)tLC1NwQHdw9 zjU;z{cKGzgVUXLk`Skz&@bV=;L~_@@cyYL%+Ywm*yKNw;n-~$YdHBoW(eAUN4T2~t zKgs4gULvu1HrIh7J+4^Xr}h0QdkuuIlFDW!yprO;re>s-y~C#W4p1W83G^E-0q<3n zcUOX$aD&0SxnZL%9+wuD3RUEb<877Gb!lQ%r62bI~@O|KSTeWGsPTugE`LM zC``kdMXX&j4c$f2eN_(6Wb;MyyS?Yz2fsMPmp*dNrQZ8LKil5lf3dTK#6%4VatR5x zL{CsFam9oSJfXMCN!Gnd2dDJDiff@QVFd9dBu>*RTKK-B^MmfV^6XuL!O8XOW*w;Aucsrvyn5;>*lC@32bMe=!n`Y|n<*hnE za&y>9%0h|Pg`x)56;?+h&N zDQn~aXtpi}Ch-ZUNYQ4qHHO1{g0ipX(o((z@J&v0gn%N=xFAb7Xedz2BrxSTudrNY zA6;O4H@c-L`TzI#E|lAHLJFHE zHKg#Sl}WgH7+v|q%+}pTBsWejlVn5)KYP-?Kz-K4VexZoi{HaN;FS9V02CX=JR_J2 z#2E_QDL^^eKKNl5co!DOHFZS2aorK$@r`{x7^bIywAp~V0jDQ%MOOLQ&)eB;d&24G z#bkzN+CNfjg%>X=KI6-S-S78)Hakge*JF20Z>&ZTVvHwQo3@Htjow&@Y{di_U48hc zu!*GXm|mCT4N}k%+t$nmu{<<|^hF5`(UK*+x8P1_t9*v61b-9rGrls|cJKyOn^;tIHxUj~A7{cAF*#7ABF z6cC##Xfkx=l0yQDWn{IAt;%enj*#nGx27~_l>mk|xmD^4cII33^2jJm80E(i=K!?1 zLS=|J!J?KNy(>^y!e;ug`7vBL-s8h-5>fZjphsoQ#xr7|!&18+sS8hF;NqT!>JSc- zjB2QlE1Gog-IYc^S3c@B@6Fd z33ViGx|<9}GQ>cwg?mH`i>`yhsg);v%re#^3V`&!8IHhtZHekX1J~DCZPF+ zAlG>w87w3@qKA90Qca0b4***DFbx2D?0D{WU_OiFq%I%y$KC!UozZRqmZ@6b0k<-I&w>iU(`A~!owuc#!&RIjKpY$Pu<;X+L;Y_sH|dv-37 zTRApYuM6<-+kslw;>yOpH&Afm_+5PzkQ$C>5XNw&TxOKe1r`5j5uXWw(3$~L%~yK8 zpe;!~Pe-5#W49>GRrhQ%O6$}QkJ@jE)QF~Bqt&j%0U6tz>5@seGAPAC)h&O1T!0W7=+XBi9ny>Q#F<^gO_BHW@WkdaHmU%=hd4 z`+~rJgX3k;xZmQ3QbBq20|sOrDAMpNb&acu8b@)IA=?mk6vS=04<0(4_$Y-Z|lk z+dbkwzdSEcwKQ{6CS}SYftM=9)%Y^I{nR2`RwsK(HXuk?E{O$_h;$MX@BmcD3IjSG z?kpG%F{%gP5z2>xig!5f)+vT`oj&Z?AZZjNSImtrGA$viqSREZacbQWQ^g9^qP-Xz zOAik9GS>Wd86UwZO|zh+jO;?0h7oMlK;kp4dW}dv1EzxE7D6kelY@b*>P#K#*PUp+ zP8XM$@`#s-8bEOJV7?IP4n}uE;Zg`fZlm#qi?Ct2b#q#|1xzEg0#G_7xIJ&Qa{+Fi z6NH;z&x|5u0i=uH_-uPaib=%mU9*arhw-JyGt@}8-%I-iha$PJ*-E5TS!`s=Rpc(< zUr}`$6mcNBKyBb3mh5n9#b+D~V=^1Ju$+}{!mYKfYy{q(rVO%4J!|MusIhzw`}l(rIeKS zE8zSJF--w353j`HE#fE|${bS#kXso;t-y)F4P@f0nB8E?YjhQ?v4+L9{IkQqC)qhy zfJd)L6A&?=ZX}^paLE^cR*9HpkewKVYMX@F2D`_3wSbjC`k@*MY?mBKa#dR^u)khb z8D?fpv5}{AO|h9xC^W`4kjiOLLOE$In7Fh*bBtjx8BWRv{-Hl z#?(gavdUr?m8In+FSi+q9>^~{zj*^8K|{@sN6U3Z)`bV?HW*_ehxL)fe`}0>H4g#j zJHQ}1fTPoV+5BmH@2Hme*uzti ziL7+l0LXA3+~!tNU-N;Er?1uRF=q~YbwmUf8Z}yebY42cqt8vF>?N#3$8i}}tDIXi ze@y zBD%Cv3>h2lt~DZ8XBE;f%)rqfRLNh8Y57Sc&F}FhSmKX>-=rv80`U5NF`SE+yhtz5 zn=ZXN2TTULv&=|9CJHwojEJ{VX_{>TjZ7*@Ae_G%n#@X`&76d&liEba;o2`Gi9Xtp z+x&xXK~b7!x4M{ z;BQ5e*llR$lq@kElw@$)KoC1Sm;v*F)gW`2SrBAlX(sJ4n?+{hTU-`l2UT<2^ZdNE zX|P-~&J{K^-Q}oq|AGg_)3g$6ElC4hVt)Fo3{d71G9~8rF@_#ouYlmm>Jz@H(dc_) zPxxMK5UYM41VQ8VVLSey>ZDm_Ed)kKX|uZdDPRry`(vRx1*m#;$fVdlR*E{HHc-t$ z8lYb-z}g?krt>i6aJF(WI|F@0l1}K9cx^`2*1((;|m6PDL~3r*$7<$*hB+4_ofUc zJm02NKveA^R#}${Mrn&KJ5MXes}+Bs zoPe`Z-Xs6V{77c z_q(Bc<+#gX*Vy^k?(f*rCYDWpM_4T^$R-Jl-j|kt$MuA&0wHOHnnb!(jRc^@dNQm! z1t{6z7Pg>A80f^`f!O<9j0qN;`Ezr0%`7Z%T4Ut52xX96Q_`M{P{Z$pg#cJD$c7aB zhf<@OCn|4D&A=q;837{5-r?%&n--gh8c*Fg%fW-f@!=1|n6h?h8ou zKq??H>q>e-1h~^C)izD!`}|ej{HBs7p~=H`pciKtwZuUOnp#>7pJeIgnAoRGYbezt zQ<`@|v!*i_mRl%5afOJQ({Nj}2tp)d(PshIf!lUdL!fhJ3dJZN_^vxh(c<$h-*rGz zdDZ!#h|nuB1i^d<_Hln&MSTaIIi8^O7xf+wga{&6$!bs z9jw$JiLNi)O1BmnTFDfxk@0gh@ha#t)aG-7shkc%F+-0zBwv^DRi=)te1DV86E6Ww zP+23A^{=;Df>Bg_Z}F?2PXDDF<10NKR2^ z9hB`b;hYzmrmW^p*;HV$g^Jum8u^d+G44vTSjmktKal_uLf>25H=oZBi>{dHg$+(U z6X}aq3grAwD`P0_P3Jijb)F*+>|Ipwmx^63k&SlHZZVu~ZQFUoXtXv_XoNElsBPPM;m+<{#V z1j3iu2L2DUL0~miOL!bO27^hVLsmMVxl{&4F2?4abn!OV2aOrayUifEv*bLaFqZ_}>= zg9*yQ6H~~HC%+C_@qXB=@`Va{on_3uz_BS)NJWMkEt%_>h7>XScH&sh?A&i5-m6T! zV5A>nV&Ob6t!cUG(IGROZQx+1k8!-sp2izJ-s#<>*U&rnD}YPOEx*N`?$UJ zgWd3vy&jyDysg`rgO;i_O^dQ>771CoAj)6G4f5AQErT26kDz_8Vx`P+yrv^E9VthL zub;pGa7GbXuc`Pe6s)iPR^W<{5e7Eeo6^5S_u7)vHdd1@mj z!eVsCS=u|LiX8A;!tKIRrz2P?_|3C2fGO|1cy{=5cc*L&E`c12ywn)IOYf2whvKQS z_x$@8$=l83ZKHDu4>>j2UjKA(2uBbPABQgS%DWi+hjc8JcCVJcdh5QzCSQt*d9Q;! zIJD7xxxan%{fmQV9A2pT{K(w@L`1ePI%HXnB&y830e{O3xji@zX{&?gy5y&MEt1C+ z@d)RRF|jafCfNxEC9EVBv1tatl4^a2lIOl;%P?4)B>5?28%D}k=C=m@_1h`hNIqB( zYnGUw;?>C#C;uYm$l{(W$Kwi{#lr7$C0Rm?D_rr)w-p*zQA!tPdyC@&7I4#Xub zT0J?WWEGSGtaTz`4Rt?s&^8Z~U|n>vS8{7(Z#nE>OoPQT3}{69)`WxxpiO)lai_Yl!ZtZXs%f1GaZGRyz(7=t3G$cf<+5($iBoAeiD*9Q#^h zKOv>GS4*B6Blf5|C?sSe^Cd{{1zZVv|faY%49V z9kinzTnHJ|pSRLdpIKEsn3x`<{v9pW#Ea3D7`dn54CdCw*^wzq#|{ z_Q7FNJ}w_0C&#O+Yw&L!{yl(y58>Y<`1ct8eSN&TwhI5?{TjSqgZFFjehuEQ!TU9M zzYg!$;r%+iUx)YW@O~ZMufzLwc>e(2KY;fS;Qa%5{{Y@UfcFpJ{e!Q|x$$l9?CR+L z>g=HM`ldf8B?7%@9JF!}Ad|q+gBwaQ6pOXzSxxTTJqabj4 z)>du5u?P_}AiUwi3#VcI!)aVG*Y}*q`^$+SyN-kDFx>&%NzQ-Ga-voM!KpRd?reezIb3I5dUYD%I5g=O(92jqGCv#p?+du~RKy-zTy za6kp$5r^)SU#?<9IqXhj@MU8 z=kWe`=~tjZe#587$7?HR@MsY}_E-4bKacyrL6yex3d-&$aIXO7UMtsNOq(mi(pl+g zrEo?({|_97b7M+Ob`98miDY@Ri?Pec%;_fE2R~ry*U^M-2lysYHMkIZE!B{0?gHD} zHi64g63-F&o4|;airSXMZU8b4B7$XYN+M2|60}8u^Vi}DYXIPDtG~ZC*^9WZWpp5r z)I!VXe1aF9n`-ETnSKVppqFgiX|_(f@brr>DA@cCAhqP^$GyV@IIiUI)$?R$C)xh~ zX!jslL|XwIp|Y1)2sY#|$?nfDx1T@Vefq^0l$QQ&I>HQ3TzZt8_F89{MzV)QJb-ii zyFHV87&s)83*IEl!z`CDFij}YNVaLea)M-%LSU4VQ;NO8Y)!KB^UvS!Z~t&8;q3j{ z%>aHmKQo&a3J7N&;nrDFUVguPoYbM!Eugc0U9JD+H~Mv)zzZlSI3A`*b>7oQ$BH-BUyOytlbN z^~><`!TR#F#GjN!j+Y#^YQ_=y&@GBaM`=`W`89HiDr9O-pqYEwBxBUP=)Ck~*8sNzB?<3v{b4Jkby$rt9Ho z01&#!Yz9e=qr(}_M|cWMTN+G;!AM8zyoFv_YDCN#2r=V8Um`})0s{|g+8_h}mfF*6 zDi=)1gSpdzhW{R>+#g)loU}c9B26Rp{-ADq9rV2{=Cslj;OSD*(zgM)nA{>A;iB2; z-~>>VCBtS}1B@#>?WUcY6D~%QD2Bt<6$s&ru5`y0n@busKPduk&Ep*c4XCz+U!aRPQ#t;33C1y|)Q&^Q$ z$lmS4nsl&^J9sJ^ zax3zzIZDscD}HmPnN7@e2Pgkh0F5mG0TEANvq&HPfktZ7C$<)#RDdIjss$t%S_!BG zC;^wM6oP5ByMsyAq{+Dh!U+S+_>?qh0MZ4#=?z+)Eg}{4$y-zFEo}2GvD)mVu*2nx zUCS%yGf-I;q8k?1gV|xPyD65}r zLOj1-L{cW4#c{Yy(bUp$YB77CY*u~xfkL>!BM(p%?C-Sej*w!?PVK$Z8w}HalQ6-e z^F=DyCL>1)FN+0^LlFZHO?{}H`jLJAurblC9gHem-9LGV4%p~+UC8er-oyU3rfT87 zHrKNz&84()De-ZfKab7|UOAKqn$taTzAf5c`leAb=|5@q*sZ*4qK2Z0ml2T3ytN}k zlfHjIap-6;IXe$EOeU_AWFo&%I_a_{go~5Nxx9D}7>Khm$|nq>L7cp}mP^7dM~KBD z&_R=U$}%2b)dl=cRU^fK^bvstM=^FAMDDrY@dzJenPRO-2xLp;a^7gVN$_UU_>_oz zJq;-G)hMw6#;##SymlF|0kiQKE8!zTON^pvKfB}2vvhxZ@#^U1tE0b_!=fPp7M3+z zG}kv18PvDX8whUM@NkVT*bt!FkkBIUEg3@97v&~Khffh>*(8%pVB?aH)6lA0jXDh z&SCOZA!qVx2q%NjPe7sTG1RoSj0Ty=O7M(1WEOiTl;x0-AfbZA!>p9$spnb-!(?}4 zNJ5X##1E$L3{kbe|Bq)XWvWS3I+QwyB}k{6wOgYO3KF@AN}U=^c=+`GJ} zb;_@W78{iAMb4YHLw9z!XObc?DbVfdcerizj<4fXMgvMY%Cl&cY_T2mA0z2cDke#^ zH_*AJcg<;aRpg_Ut@?*X)@z{zVA4lMusICCv0(XH^q2KHU10bzdiVhv^x#s!9YY5e zp0eDRladP2!>-&uh0E%n6xvUdt}UpdyHrlcSIC4T&R`Ic;z;znzNdVI1Z=vl6tXEzk#BuE~asxT1M|% zj#}ckS9qm4lQ%`>&@cE=-sOR)FC7}#KMyR>gzeA6K#}HHB%&&n5Gt$TcWAFpd5(AH zf~5ao6!_!r&fgOhEGMXAK}59&TndJ`qEp&PlKP7*YhAPgNEeeiLW;f=@|0G#*8!ID zx|iAmzA*io&%@9{(2jmPdAYaawHYuVC=iP^N4U({M)tfsAN1>fqxs!kd|*FvhX*)| zce(%2P8k@`eg`k1zBkm|^aGI}f*}~Vx1 zyr`jL%gct8Colk)n>n#4F-yGdhE*JK7>0wnEo79uG{^H^@&auOHO&A54pA{*^R1*a zx~`8Vec3UKKngVB5hic)_Q(AASjJq0k&|R9PL|re!TLaNwvRNJPswo$k*qb27& zceh;yRot6hl)n*$@|GMFEi~Qkb^-+Iucv+@(a(a*c;s6r(v1vEXVLlGDxC!-w5C&g zMnX^2o+GfINy8esy=5JuqWqZ+iHyF=8BJJTU!Pq|;%8h*jMoKMLXI*TH>Ol0#_|7p ze7y1-s(gRluK#zde)HP~KdA<+Wqv)#yw`L9hpSGW&u-d|a*X>^EH{#PLJ<~KSRyV_ zw%ijlorVokQwe7$YZX4Bo#DGZ~gA;bQ zV3wWcfo^w{VMy{JoleG>OsKRFxtqg=EA0D1TFEq_7{D4FobyOgFxm99MOp!Ggs8Hw zi^?9x=d18Zb{U+nc35#!q63#g+hLD%W6eyuyC&~($*@;|8nBjX*Jcj z<$d_1u4I6>QGH>eCFdhAnOtyoa(*Rg$Bxf2V;FD)GJv#Gw-z^I!mo6gxr=en>A-#t z=K>e;&w*@&|X*gp2Wt_b44ypQDQH z9qj!qIF~G`M#QLPNqv9&`41b*HTbZ1c(k!h-bVHP=Px#vO*5F-4}gT`YN_fx7$Kv% z6A(A2lO8)-4cI}66@lcVRNvQW>?1k#8~s||ST^c-Gze>+wc9IJEZiTgpj5a!>Rurk zX1~m#6)h}z(sG1$5gV76^Q&LDvcy@SeNC&hCQHvSPzCg=)J{w zWZ7si7#Gf|v|w4hppId_rjp*g0g#QxRi93F^V&lT*yrnZ2gP4q&MZvkRtv7|lZ(;I z<062Ftg@4`7j|k#XE|S$VOFp&hB1rrsr_L0#B>&DFS}1OERzkXC8dQg>Gpc;6nIWs zl}&MUAQZuj*T87peOiPhI$1h;n`%i8WZy??PP9huO*-h4D4_*)W?fdM`S3?D6|Dh0 z*(z4Bctn3;F$P3AV0{AC+%=@brm;o@&K6gEiXpG;8Buk=UfkXJ@rCXyF-)&y%PTOf z#pM+!wOn~^z_t-&XI5=-c?0WjSY~NsqZ$|uVgcnO10kbREa8^QKDcJ}ZRaz62)5jO zBeCVn5yfRO`s^)N-3zwYwwJ28^WpJD?5@oz3vaR3C+Q$_7h4{mx4Lg8%D>b7nAso= zoZrdh{@@It$qpXF3j~8&5ihl}B%8F)t5dYkvfXakQ$Y_g-~nnY>=>315R}gObd;vf z*UqSQHt3)Bt_`TVfY{IMP@fLyE?49MV`?XzNy_;~ajYm&#HV;L0P{CKYLFv9c-f$1 zM!_oJwZ^ZjYwN$6u^dP#fDPVs&N6hxaaqXxLpFkUNU59z-yk9`>uH3iuVmI9JZP-H zeWYWB?~mR-wh-Gv79k64+?&nz_RLzyx1C z-}~7akvgjYk(iFg8Ly(isy!ItHGskIft=uA{AkHa`I#;7ZZT#?0M=FnYc)raGaVl3 zPu;H3-3mSPMTag3$h_5uJV7E_dAoYEph@r?3=tH+nnip_5! zTXjz|ZQ-&ew7alw+Dp)P?l;OmX9yQk;_Sx=o% zB>y&=uaPYiJhz@6Pw6mnzu0=6qLLDS?e#3?#AH!827nW%ZKs;{-c!x@^{!AS@9TB> zRQ2JU7xXZ==OXs!BlT%nK*@BxB#x9+cd`{ zZz1m%C}^WUsGqigWfu1X1S@=Xy%7rQ*(!HHW*WPukmzK_oU#g>x7u&e?+QJc#3Pmc zSIIg_c)yO5n~v+_D#{@>E?$~d1@+qMG1ezzAR^~bghhs`R-|Xl(<{#0NmkqJB zY?FXc&R3#f<`gg~gm^`DrCcinzA`YbiwK%D%-9;PGZu>2^4@6idY<7DAp!fOsEVuo z;wt7zQI#r7fdnNwZ&dkJC;6KZhf!%?S60xp)q_zT`C3$1v|d~kzZ4Wa&_Y*JOGU&V zmHI)&6@OSMKqw-(L;iou5&k$s*^-ecpGafDa9DiH6b;Mep+8=Ymt+1t-Ptm;uLfZj z>dXvRJZ1A6&l|=a96~6=`@U|R0aBA?1%oJAEA`%BfVO=F?TYS=wgP`EDmufvCNeU0 zMwl@&+9V`y*SxyuAPLJ0Y>?~XlS|lyRXg2|Nz2rml(+YO zE&{bfCZGqE<2+U@To(;O9ev4kk;t)ZMtOES3u<^CX~liAT2*ZusDVpzPl=ZPsa=br z2zc%x33f0oIF96&w?Kvo-BT#G_x<5!0>8Fu(DHy??s4lZQUq%>4TaN(?-#X>6G$QM zHWF1#5j`{A_hY6)a%yEZ;_yeBgH;j&st`^t+TWfOsy-TpO0?qD>djVt77w@_tv#p!RimZuJ6($6;W#wG1xk3arh9o(Sb#=$>WFb?csgzox}HfqTbsB^&St%dpsZSVVgtM<@ZLmB3t&o z*|G2IL-_yfz1=wPoqhAZ{{8a%zhUtqc40y8wDU)Lh`v^$i=Qr7V0~M!5 zfvP2>J_U_>ZOjn;#L5;*fTlDY%AG8Nky}I`IJeJ#JM&dpFmTQ&2!5Sj4MmoaY$TP& z^6?V9Ij&Y-t900IsC&ta!of z&O2-_zcA0(y_C0RFY&TRT*Fid68MHq^_39g^6B1Twn(9SSfogSyUA3ei+V86Zp3?2NbE@HRvQoc(kvANvC)UC-^`Z-P~pXd#iGfwnEV z))nk_F7Gp)!DcyqM|?sYuWx4#fkRj%Bt_IS#dtBfPD7eBFya&D1|68;6!s~*dOo)> zoq3^OSO|rA9dAC#GtBWB4qe0S{d>h@;pwp+fyqGO{@H>kCEj1UQGPt zWPs+wAuH61uu*u`V>2x5YXOAM({Z;=M6*QOSI-KQegi3fjm6RUbg`oi;(_{d>rjIi z=B2g015}ocyW>fa?ZieUveAelft*~5{_gBD3=yP$pgaQ}*swLCw6&-^D+S@bOkAF0 zH{uoJoAa~>JP6LHvM7#5Y67ly23`y+@k$CwPTwyi2(IS8B)+?eC&g#+X(@3DkBe)V zd>`|RJmv;1Qe+YV)W%}Ghgosj6Wo2A`9Zi7@*$$^lp4>s3x~nnel|uU24RJMfv8#pWthvo;G3me4ySlksci*?*wfeSnKN7bytF3cmYh0 zUmvqAG`hF>6_3lw@%!YMY@?4W*~-RBvT}A@Ip%n$P9D5`t0iYsbH~?NGuJgtGXL1! z5?<9#ub{H`LaWO{KSf=1mo`3y?8YmWqo3~|HFsV-|9q%#?bnJeAH5(3qPL*~HK zll~beu;UD<(Y|5Tpw+`)4x9UX-yLip{6e|eWGn%RB>P6GB)ff@OyoqVB_V)pd*eZq z*g=wLYopS_3b#t{V@`kRiPQjCZIi*_8 z8@Imm7<2w&z&Iq$u90Is<4i3a@|*5O%?sQp`8f_G6O#!~tVqJ(s_)6NtJmWcSRDQl zF9)R&U@!9?)Ii|IXu9MEr5wVnBZfL!>f(11V zHqGQsSZHs7af`Suxzn-JP+J1o4qn&B<`j2^*VOF&;WaeP)hO)ItEu|`U~@$Pq@;uw zNW7n3>WOS$H@)Z4I}wRxK(@F8xB3GL>z@*hewkKAHY_F@a=IE-8;IUL+OWjr7^)-U zRj%hn?uEL zi`HoWOaUSHsy!}v$jrfi+BFe2u{%@43G>#$*uWHnAd&XvOmoy=4NzcS8Yv0B$Cj&! z2eT~s^6BnNAfgYyBpAE+wU{7q!DWxmwCw~Jc283Kkp2553axbrK&(m|J_^iu7nm)O z!&>)}Ju;~$@waO@OGeA#ZK0P{UW`VR%!0+UCoU2Uf<{i061hlC!i~zb^YfF**TiLr zE~2p`qvQJLl!3L~V`Jou0`Vj|!~79(C#*oqbJ8yDra%0QN)@ow3vMnXHz1Jf%i=UM zEwoVq@#%&)lG97S!`)o89|fC}tTDd*%x*Q}Rr1;ex!aDEpvqk zqp)Q=q{s`nP>Z&&&=i8=Pvat+gQRb8M7Wf;t{1$R5Z{Iy1JuKXq($Mx9Lai7Y)1Wy zTr$=6)uoC_T`M7P!lYMTWKTBNila$EaU?p{XwpaP%?uCLqT3`}9oDodCks$#Kyk2) zY=ERs8PVuW-l8Bt6)iC-|C~b#^yzx#=GcAb>J4!hFPLL5H4N7?QJ6I;Wf4c&l_VvU zh|q@KG^7uodfCntWqi@8LFdG_$eWaN=JvK0d-R!?){WQm^J1@8W}kMaEg2`kpIAxp zR1!a&r1iGd?V(Y(h7|U;SVRO&__z%JH#D+vuT`igmjZZZsMLx(upqAVT-WDM z4QfutZ7$J#Tcl>Xs6K6s2{|s@s zzg%^hQ!4~qP#NGn;2>C#;LET_`M@I|xwAq_aX(Kf7V_RjQP6TmL3zS#4$BXfGm22r z-4{MAg3LNIPp1zzJzLtgkqv!B+b)*)99YSih5qkfMNbgza5?+)ayeE$0~k+_QvT2( zI^2hocM!5=g8y=>TIkFFsj!L0kTDT8>34shc!ms(*&(W3 zSNo|Us+}NoVTkJK8$K5fm`&meq2)l7XtWu?;U=v~-#q7k)(Oqupfhmuy=32HVKdot zC9`YBMp0g(PSmI%Gs0033@?Jt_o}yIdowSkvD89YD4PEuf!y$=b|n3BhEOQL3)Wnb z3z<1|$?;NS`M8R?k9ghL+|8KbNZn)L4A!5lbkesg{YkHJa zf5$kNoC_>j-2LHT_a(F%8A~~Nl9=iq)$amq!xF-D`{TB2a#);&e93smEM$qDlBTb; zeU8kQ#9CZlUQT{u?6_fe9+{zg*b>Bn>)t;u+B(Nfb% z$@f4Ry!xKyd2Is zn(xweEp*UTQo)K9T(wD`v$l3Do~cNemGW)9Jp*5hoUiAM(aNX_+&-l7vbs|g$Oos0 z22sUMDi77dZ#hc$Ezjh1f#4|r!Z^Jcj@ZnK zR@d>RZHX^!L~6`BSRg#%sF!W9e&E#xW!xHN_z=X7^=!1`AaigGT6Yw{)r6ofXv9XP zUU5cty!7iolf~bFeq1?TbBDHa#sRA-3P@3}BpfdulhxoTX+Br9NG8#XJ1u)6)#cj= zrV1M^#})I4r9x4W0y<(zVnF<*16UWTUnVZ>*S;hm&u^BK%wd?LCEpclQjL~1uYlc5 zJ~*4r>`O)iRI$KmN=k&)1ZhNSdiRzoSK@4ivuFeHNhD^7cBsp6ItC9e4Ur=tJSR}b zX;H#~-siP8-mN#&QJvOR@g2LX^VQ+eSNAYvoOe~^Cw5KAds`jy%s_tP4oH>FS`gp91S#{Z)*lMr{T~XBKGNq>0aV#9l{j7 zQEXzjMS$eH?FVuGaov{8)hs!lg?VnUc^%vTcvqLZ z8#LU*J6|!3M;_3v=z#@eda)zO#Ih#DcD{IR(Olj>rqVI_I!xmTIkz5{Rie^X&%Xu& zbU}rtCKkFK8X&xP8~@c=)?i5osiDZVtoRi+T)2n2PbfjuJ zQk|}ma1Jg`5^@LZo2bjiSa5g_cqD?%{VP+^R8CJ7w=nbBF~txe59Z+q254!nFuZg# z%m~B_HJie8aB(j)kG$gKJoMR1&*SYiQ+$d|*zGd(P-~TPtRaL3e(2(ALu16viF+^8 zk2TmZ=-qjCj)g9|XXkL}TPD4HIB!=WtzmmZ(^X!eUTcc$C*`qIeihlIw=LL^p?e(} z>?k_H>JH*iwCv*4FwxW(!am!e$c#!>3`2-<+lMr?-(`8o|(D`a41 z5;)mT6k(s_A3F;4AgVJL_gjp<7K*|J)p={wX#>sDG@@0Sf50&kU#SBKA?edl9|grZ z;et%7O>oG%NDi+^)?2ZF6xNT2oSw}&i$T<#NWnP#*LOS~j%k4i%Zd)R5`ulGr=;yw z0nWWbD?m3@X|gHIpYHD~*Rky6H?YYKBz;oVN;da7x*Z8`BI*fM(F7VCfE$L7 zu+6B*9?54L!JO#x{unOtBcu_~Yp9l_ebN_SlJWop&^WC~szwuprh7rOgVSv*HeqVZ|rkGBn{6RGCTwohp+Wu7xWdi<4{gj2f#dD;N>AMT*o#Px#xg zt^9;q$eiR)Y+xHO?G_P1Mo}+TBPRlxreV*^+-H3% z{H5Z@9>ee$``c5KczHaKEM+Oj{|DkizS<<{PwwKK+e^d|MFndyP5Jq;CabwF<~Lr= zRh`?6)f2D*+-Q@t=f6s|aqMyawB#&Ao?vo>j0MW|*+zPnz$_9StH3GmmF)&kv_ej_ zelbw7YDw8fRs=P_RK#7@U?dw({L_yThUWbEG?Ve1mXpaxngAwuVMDnPvB$WVJWuVl zU`R|1fD!=VuU6daL-pg0Gi>L|I)(%#1xv8S2cwmi2xB``REk2mJPnBI*Q98?p|_?^nQ3uV^MsSd>4#bWV5&h55Pq>=jIdyhH( zTxR3BVtvlqH6uot6-toQ%@cCu>|T7++*?`ZD$>Emnf+SnY}Sp?`tb30Bt~$ zzqUfrW>YZzSOgmriuLeKcj!e$GXZ#n8soIQn4_u%IEWH{p?jNQrLCAFuu?6E_~qwJ zq88Lag#gv$Gnm#2%OT_0CX(BhLToZ;co^Mh< z9;qooXmAIk6vm?VqHqxd;~KGk7q(9u?5>Q+yyhlDu%E z7fWdOP3MIO87|LphJKPbL&OR29iT!E2@7UbEu{q@@>~SB6+wCyL35xLgg{U&AD}!Y zyAJz8n;uVrSB%hoWS;BYqumPeZ$9<-G~pP0a*};>h|y#?=u#Nbgd;m4FNnf6V-Rao z3Zjw&Zg|+Eov0a}AJNHG{^X-a#e7g4g0=|WpU~&E?ztEzX2SWh!?H&vpELX-p5hdx9D|i`^gEP0FS=E;~p%9AYo>GGKlOATu;I^5qrD$vH%fRZM zFNhwYcamh*5ZcH$@-u>7Jg$r99~@K>XW>xvAM_X2(n92V?n2gaHg|QlwyFHl@(kkw z)+%bQ%NFnR1^eM)&NAdruhRB}Z0}=6{G>LemokMs`Tgmh0tKDueswxf=|aqHKr0l= z0D=S=Iein#eDl2De+ZcW5HQ6AOex33;FTrj!A+FPH`A+Oc6|X9$wepJS*P7IB<2T_ z2{jvV{$h?KVqBWMYgFE{KNEgL+h^9Yt>xZ9O?vfOyp^oGlDv_?yXDt9BE0xSr2wDge=L6eZbMi`u^9rO3@OL?z!^UW+Q($r zwhWD@R`ck9nPh-osiQ81f|-m)Xm3)7t$mh~r`f*-YQ0TmY*+{MyqTPycCWVTi&U)8 z&5ENT^W=}cIUYxFsX|E?HOEX52iQWX1Z$8qf1s#`yv;@#{!C<=0p(O%boW?j5y553 zT49P|MATDNG{7CqFRn8!8)tAd_kw@ji(x%3qiVEDK{5};wHUb!Xd@0qP6`0YS<~j2 z$0)7nb26S;kZcG^|lUHVQl}V1Z9i8CQ1nZrnc--J}~~O#~_4D$;VL>@~ty zYs!m(q15whR8A`CRd<{${DjW+*r`LlZ5cGpX7U|NtP658wlHlDhpuMR7Z+)#i@W2!o64yg zs^f&CFwHQHV#8M87(BI&hO)3|75S9+J2r<;msx%ujqjf{TljO`>pZo+A5j5sS7QZn?R9EEHbqV zW;jSAD!Z?1Pz$p>OX%aQyhl}a_?i)mE!<3HkJ;&tYsBLq_R)|5hNy0hdR?@^V1hWa zv3^!2*=XgY+g~AH%lbZCHl0qg?s)ws@1gWUvdB)t8_BQ#+<@7iOwco`oIHtp2M279 z%X55@V{+mivn0`W=FLz=v)z5{YTS#2U(xCGmL`HDr~ZHiVH!5A=%8 zCXg$Wthpb=lyMFs9gj(Wkja*}=*4b(?rOn55pvM$y+wQXPa8=ziv>68_gU01LEFJ< z{Xwx)FJsbbQ3kybby+4Z)Zqmsn`(?Y72AcN$aR}r6$iA;0a2R0Be=qPg8?zUr`=KJ zm>st%ErnQ0v(14urW+3$PDDKMPs>PQ1k`2I)qlG|Wz`ax#xKUdcJsN3+HNG^;tI#rE+je`rKJQY@X#mKjh9l7L0GhaOS3%ub0{I+t`?kM>oa8A#6-n4bCf5@+YXKFnQw#-F=0= z&|X8ujTAND61ed(MaD9F3_;&vh1{l!;;4n9LW)tsQuCZ7*)v9N5p0?T+%J5p%|=-$ zl6knBMC*jX#Jo(Od4b1l0{KqpV=}_0L2I%vVpAyF8Cp353)4$CIMjqWp~f=mHaE(x z?i0yTiI+-Xupf#yX5K2MDZN@;1A6Ym!l8yyWsh%Z#A&L{FyPGfDjPo$$;RB> zhV`QT`a5EZL4>9!a3a7+(}xV}zy?h?>S6u8RdMp~}#h6Y3@rMXLs~b2V%# zP7oJWM4(#q|4nG)qt?Hrk{R-`z%%2@A~8U>Z`PM&18qfZ$Tc+_1@5v28LnE>x3+JD z8r*2uGIHDExyVhSQNv=<%OrG}wtKhH%luY9J%E|t-lxSdYn0=}od~`B3&3`YBW-2W z?3fptw!4va+5R;)1PPY1G5!{9Lpk59*_bLZBOpt3GYUfjo%RN}-7?2xi1y!*^R@vD zA`KImX zejHq4TB#bZ=p{{v7MW(%J+*LxnUM;AJWyqn49O1-he{Li1~b_eYvP|$>0eMBDD*PH zT*G}Ji8xTD#_53W{pO7Ge>Q>bV)Hd7$>Bf-Eh|e-Wg;J(WN8m5tsv?jbx$Mv;rXlN z1THgJc24Nm0>TD%0OzObkRKqXEsF)K3xsNnPUU`a0=ehW>=qByywf^XCtwKANaehw zBn*B&uiFDFQPd7iIya7>gaY{NuK4)vuO%Z&iVc%elxQhs<*fBSJXneouw&I8+W_vY= zy^7;VWbbM}SC)Hz-91tmFyHkhC&$M^*MNITqtPIgLRqTwd+MY7Nj}a=A@o8?yr22p zQIh=6t^86<9(euHP79+oCqWgvY3|6`Vv6?*Iz@NS^M|@vol^;sO%=E1gvNYLVF7`xsHYfz@t^)% zj^Dkwa=f-Otms$*==IH-d*=Qw963;iTDbm^z*j{Qs-=i`UoNI!9?j%t5;Lcq&jy>pF}1KDQ4*Vx21%mPJQ4T52M z4bIn^AWAm_l6%bLKu{^8gSJ6ng41YnIMJDrC_a&sf{&*hks{ak!gzubwRdLxT+_J0 zTSiYC?Z#&6FkPS|JrmOr3T=c&Tsa8kb4I!1W|P&xT--iQ;8DefP_Y~pr|mQT$J0n! z!$rAwF;1FYXq+hDK!2h_K~78Pl4-Jq<`U_~dmwQb}c3 z{lmFcUJOsG4G>%0!^g&oHOXMjha4A@C#rM#V+&&xIbjTS9Zy*iU#eB?;+T~0FVjw|Z-PONMg2qG%M`EjV6o1zwF9_g=3|0+Q0KznLysHafr@BKoQr4i&o*8ZOtAZLhHu1_F zr5wyKNp_(9)`;WYIY}N+YJN^}xR|*`u12B5>TncDb3*i%6IIJ@H0Vvo6k_BJ*0bYm zV4eNk5~$QnmWJN;HyYKdr*1->RYGRQCODY55tCYphUY_<;sIeN7!rvPtOx5}i*WYv z+R?ZY71q0KU1xmqShCJ*0i$qgr+o^uNoViU#C$@T`A8hwB;CSA3d6zZt-aQ@6YvcM z@sqxK=9wfM<59Q$CNm*I901t5tOlt6)T`CQxJR1mUSMVR4@|+%~-(UM8 z*<~2oak2xDxyPfte?NKD_)94#iOk?vyV=G}->nlfy_{}}C_OHVF8EqL&bGUYVPI29 z>Y9gS2Oc@!Mw5P}6ma0~S5JaV3+TNw-?Bju@NDJ*jE2(o+}3t>${|D-!(uAH^T_gfVAC>?IdJ*tZ1gvrsE*2{$Bq$qmXxJ4231eGcbEfSJJ z!T;5DSduM2-m`DgRuG@eMJ?U3!}>YQQeFiml}Z6)P9fFi zvP{!30~D%&xk>(9au#_GE88MHtG2Jv5VrhKrX?5m}FxA)p8C!2LhV1J;=+)a9+rJ>{za@u(Mu;C`(dakxzcCM|)h@ zeIT^7V?C$Hqrx8O<&@dvTDzLs+`(;{0^0U;P}GuG*VM7hiuu-`T%4q%+jJr+q6+8F zuW!>LJJX64N)~+8T$u6RxNKd@&h8YA)-K7R9*IutXi7HZXevNSPn}aI}3it z2P9K3)KVV54^IB2ezJz6_b)l;gt@YmONk~VUb=2nQ!$f5i%4>~e!l%|7h`TW+;bvB zk`Tisr9Do};V25*ZR^bl-MzqW?PLbhOs~e|+I~KQPvl06^p*;o)$`qtI8a(J=M6{Y zYTVUtks_=5Sv1h*hJp|iFJMF4^SCR(s9|KI^bBp-kn^i(=D6^>ruaB`r?5q`XW^)d z&@$1PT!8k9NwRB+LUWxs5G?>_l1v4tMhch)QY*zT0;3LD}Z7e|xQ>C!MRq>J&m4ZIJT0}B6p>Z*>=17Kb@CYq@)CltqV%Io*mxCsCDAapF z$QoZ7$tWYy;ktt8Qr<&FE?GP&n!_-6$0k@Lha-J>b{%Bt#2ukKN*_~D5oZW%aOYz8rWq&JN&&(xMHG;JxWrqUG=Haez|@Rj4K93$ z(nuvsGd6BDazM_i2xqMYG>6HfD{{?y1%ax?Ow`!yl8nk$ZpkRs<`>|4LE;xO#-vdx zWO5N9w;ilba?$Ez#3@u%jY$eONPO5zdepY0#WeODIt_-nNZ&*Sdxpz-PZOxJ zvIaLcOjb=awJt(lm=0@o`?qoP1CCy|+ zz-jWBh>wGvMJyaYYD(apHTO}skB`=!N2By@7bmy1_<&A`2D3x4I0vhzW5VLm%R%yn z0;bpN7+5Z2J9w_5vDP&JkT$Hw+B6&mr5r|zU!ctZ)po+hq5xEShfUJwOv)!T0d0hB z<|T-Y$+guTb+5QMHF~bnd1xBYZL8CPy-YrixS?U6m{|){x$WlodYFoo?w$s=XUP+; z*jazF!e2TQ6Rx6<$l;`W22($6p@NPiYGkeO{&bY4Ct0Ts*T{RS_Q9A%^R72;;=r2SetVQ6vI;^@s<;%t^#?R+GYUFy zwsAUZG=vA9V8zM9jN3GAwa=9;A#EN<@L_uo!8<00nI19Ro~!SFU911)H~#(Ws{b+i zz4#&hsyf-uIA9S|k~^;s4tAd(0nsSk8%6;mX$|`Q^bBy`TT1!@eCMbfCrB%dw~S2- z&oFXPlml?_)D2eotaCru{m0(n-izljc^$x?GJ8aZpLOEfKkUMsq1(?qT@!`}`z|N- zGyEv~F64LeLxtYX$jfNN%0Bm6!U2x}J*RT2oc(+UlaSPyJFQ-Of+>eQD#*x8;2`tm zTyjF-@#it#CR^r;4=*FSC`jk|5FaRreY{s#BWe7cblN%w69mZIZKhYD@H&!0 zka9P9@#E5#SU60J_m}WRztxDNV>@4t_}9Q%jYaqVxtBbpsU<+pt0Q6$=eMeH`q0{9 zh!D>(wspaP?k9wa39C1!-w{{6wuOBe4H!KNuBpI7TSl)vGIo^D#ii`@$_fJMs;D2o zlY9?_&0D<%=ABkRvclc4TRAn)&Q9KOq2D?KXh#h7y$SrGu*&xw@pG6yzCRGa#mXZ_ zWq=GE0;=ks3~ARt59YCd8oZW(daVBO2avi%`X_mx_@r6jm6s!v@_7IY2N@=Rjg`|g z%+4HzfkdYg?};-7yE8;$xn;ncrYA-0~Lc@*EAKX+>6n1tvp2C{(tl2`+36=>)*VV(RV#ofp#1 zZhf*9t0xj4mq$}jZ4R(dzZ>?o=X7%~`Hqb@iLItEmbHXyG94neE68pql}4rEZhOOu zibvV3R@phl#7y_4gcPHLKF}dEHB`YX&H~Uvce7mjd%=k~(xf{G$8>_({ zB~_CR{I15MC^H{SMj`3d2nE%a@G5T@n6H-2(gVwVi(A7~%i4pFs%Dt`kG`cunjs|V zs|=;pm1NYCwzEi9b-?9=%cdzAi89~@3X0SqKM@b;aotfaeuJa!H`<5X zh{fm@dSnx6c5w7`ie2;@G)4#}yiL!h1)UP>As62}RG?N=e;Vl-oiZ>81{}XZ-44C$ zq~MOkkIDqyasC#XTXdz8BnIiN#r`08#JeKYa?)(n`~fpXTwi2~QFoW!j~k_!6Q0qe zLQTZN@U`r!FQExBoT8Ev4T?T*g(~i;vA)fT!;6#EZy8H6Is_uItYcNMC{p+yL2QZj zDVPZE_>>E{4tnb&Lvhfy?5Ype7m#$oKI1tSu5_&sI0oIXbo{?~@{hw& z(tH`P)v|jFYW+YX2&nq9$yq!W-yJ;rFiMWy!Vz=kkF|N4fdI{|?P^rNn4x9&tfE*2 zO;!$5wbiWBJQ}t78JRmZdILE>aCJ1~GaLqJkd7^zp;*sAd$!RF@a6jReRT&cuN-S9 ziz}T?B(v8CRP6cw`r*sh5oqrAx)e8lVq*-ctWNj z9GNgN5zLaMR!077)h|584w@aEw}#oEbFJMl=edUYN!EWey&XuYWXCj#b{(w8JLIU2 z#@#$0=EtIKF6%m~m%|bD)A32xu`^|gT#{kHF@~1f3Ho!exU1E`EMvV+19;mm`Wj!Q zokrLu9!YFeCMm*uGv`t3Y|uaLUAvtUj|22?PJ@)4tm^XfrVYO*+wBit}V=T)6WSoAqjARb zk>yi4E8Pg9&jVVW(`?!G^ko6Y`?@VbMQME{?ky{~bZ^3$>8EXA$ZV+4=_ihDnA=m5 zgxdX7hjPV9K!q>2q?T4BO)AIqlqZD8{fMUkA7(5YY%|_O6Spl1*lY}x>6v^(28L*S zc`V-?owB?z-$m^#k463kR7B;1_8;M3fEIoqBLk(vZ)sTFp_bAy68j;#BGmfswq0< zssjMBVa#CvWEs1flM8@Y=~7lQ4lW9$7TRKVx@Q!@y*m~oKV%VrJqNPj8lad0cf>hj zGfJRHvER8Dm#1?L$5FoW zrP1L_f#e*W(RFh)=_6gac<>Afn^Oc`qs_PYIC=ldV@W30h3s&ChyR& zbTaBEtDDJ(lDwbRwr2a@Kib)$-{0?V|8SVp2d0GE<)R6GVlg1hpvipY)@%4|iodq; z>bg$&u1G-6t{af9N50*GI|U#H3WA6ZgVWt)3M7^;(bPo1YYJ>}z|3+V@CV;2o z2bm)(>_Jc;N4{IO+|c`e(w_p)$%We`6gAOknis7x?941)%LY*M>pI5Nelwez;WX%g z3>Y2J@9XqxI6{uk?1*x*k(3+DUVG)&q{Lgzhs&D=KND69hTtG4lKmV+nJ z!faH7R=b@J#}xm;bvx-c%1*m?8|C}X!+d{CobNrf9q$6lbR&Lai~066J$oy0@p#hd zb||0?MzGNc?F!v)hf@(`m{0>zK)zLq#wv^AMY|+a+!`C)pPZ#*jkzsRx&4US8m=vf zHfHfi@xGcCHq6TU?JZtsdik4B>q9p4A8-yyt z4JCXrj(Lh#+t^08M}$cxzJ3(@&y7c?Um6RyxHGygIxD^`7V_lxN8s+cuy-DR&xOGq z9B#0FejCc$LWZGe#bW}OGK~)ib4T@ zoORnQzsVsip8+>$D@klkRw`~Onu@wTBf?r-OE}(Y`L%{>YBl{x+Ob$oP8o^T)U$fh zg6mc57;WSXNA#HJ>DG7O%zF>-JTn`;`ihs)nFJaa$hWO9;B8Sh4$hXPZJ1Hs>IU@M za#kD@szjJ1e7yCV9X;R#kSn}nw;;;2ItDB9+j{LH61OocKjSmttq{s)n*9O7od!h7 z3e4B7*V#FcP)U90Jj9MHAs6Z$7qjcEnSXd5jmQ}xm%;&gcd?8nb4DX?hJ!H*d0JxY z^126mr)!kMSn$_I{kP?0-Ky=Cz*r0#bMEqwZdI{6>U61%rk+s0NiX{Mz2y4=nZ{&; zQ^vz6X|r1rdaw8PF_gP)v+VZm=KxRYPm*Zn?*-R7A&hlRzOW?lA+Z_U7HEhv)+nH4 z)|I4a1Ph1F?JtteYm z-Kk7{iDbFm8)ReygE#&qO4|vV)M3r3gV!O7W#MZ2tBs#M7*oW53tIEavE8koGxS5q z%Q`ObE9{XrOC61<_?ZnVywX_4rCC|Qpurl%-d1EhHznA=Gg7HSm~6qmGRk-zsp?Gye>Npa3+=o!vzF^=V|wGh&%`Bv@bddMtkLEj-xwKaMjxC@A`!8YCKG+ z1~rig{|ob>_5~NSFOc{&Sr2!&OvomQxdq106J|n|#mIOeED7@&8lH$?6jQT#ujpo( zcGLcX%u;to$=@jrf0xvIo^IbGdb}-;!l?&KldO~?fv}bIxHUr2e%ZZfZ|u%@ZVzXr zF4;<+u{fcFK1S*7L)U=zFqP^ES7_4jG?Jx8qd}hY*d6Ux>ZMwCuiL`5QAg329GJY0 zrW4e`kh!z&hYRFOQZ&m7n&kMVEoTS~j>1O|2v%ulLve`Gy2T05oq)g{96){F4N@_S z=grZDv6!0B_7C`Hd_JPEu#yf2+h{1=Oe{AN1Ay=QwDE?2}y#$)~i8^_`myvlk zB^;4Av=VlLsalQ(Erk|WR^WbykH798{PycVli!wCRwysZr(bNo>L_=+xk{va;>(4* z`e$5b;X`$&FLs65G~To;6_X%6I$h_fW6S)0vHSjg`E^Vt$V7uvO$`=*{o;7xIQdOC zflcXbUAy{eGFJj@S3GJkAo-@&O@06sQL7yan>?voljb1MOzDkCs`-!WgSQmtA+TB8 z14A;~^fqnJcCW=s$*IkA?ghCPw8`8p5szEMpB+DB-)u|`s}`-vn6Zn6?F98FgE=tg4H z=qYyK9&w?Yl3Lqt{Ky9LvNrRc1*DLjUJD+JZIp5@GrG5PFc$}Bb2iQ*2}gWGe;FHKn&(AfMOU#ne;WJ;Q|F7A!{^&mfL)C7htT7|L3o=-4_0QOM z5B+q@r-Om#TmfJN0wOtSv15AKNeT!>%cU@{iy;DRlG@wc*0;(=$hp_z84kDp$TWyH zo8UB-;g(HCgNfgx#GU4}dMT*IlpfA>x5F`6^aXRp*Xh`_ViFGf3GdiA{H)t2KYgFi z*3R(ylXh&XJL`Q_?9W-0_-VPUPLi6O)p5frEfnV*jaMwi3{$ngpnSQAXwIcJ$*1oQ z(z3Y8p)@g6!GsGELIpl&PNg81lRMfuE5#?}Vg}CBVsku6@E=+Hy11UU9S`XxKL9xe zL`X$@T5Z^53Qlfm$FWZ{_ZU|`VkPVVju0D@jX$M>Grs?DD`Ef++R?~x5e)+u2YSR( z_P$&D;F-V#ivu(Tv>6hfGKv1uAPY>EQOgmd+Rs>mKVUfh3r zjH`ax+sfr2%CR01KUOz1`;YS4JF#^9@x7_cOU0rNSpDY6WE162ftzkglMYK{2QRP# zT9-;KP0&eS7fsc`?RezpCG{ks!3YT-lTbV$WTsXUo7{nu(|wk6^MXdtpW?_iU9FRI&g_vieO~pzncX+N;{kR|@T|khNjC0|C$eW01|8itHl!;x-zY82ePoia zzLNe6OZ#k}o}93dfRr>k7RO9qv9gsV7OsRJ2Ft?G8x+~rsF$Jy^>7*yfwM(>ei~)l zs4HOg;+F8LVfN#VvM&nNIlF`2sxa0&UUZ*UHWN43N2bCLvUc(797rQM!4w=rrQ3k$LVcgh0Z)5?Gk;01xk-0}=1Jjko-RE+%TW zS`@knW`K&UoulXS@;P718@y=)a;0h6x+$HbD*HGLMsXkfIwA(Z$P4RH`nQ6vQx zwHN01yc>zBCpU0~jECzA5J^=VFs`;ygr`tx5-$X;&YTb-CS;V9W8Bq$qY2Y-l`tY8 z5>UYHbxc+tj$C%lo}t~ghVdcoS+~uR#oVw`bHt^|1)||L%Rk#Xu(^Luf^b#93u}xF ze|`L{Y5}Sdr+wH-LkzFwfH`!wX%8c96(*aRKuJzk<<;1lRz6$}oe(ZY(6Oxg00`4& z(1R!K;W zMyJD#+i8tk_5lXMX`Q*5!qbaHVq!E{W(#0HgK16J5;TAcqM?S9N!ojh-V_;SD$lxS z6l#t#IJ2YmaD+Fum!zC?U)x@+tgejfW(->;NwiZp*x5;MfTkI2lxp4HiDirIqF^ly z^%CwiF`l5D+F=_;_VvN{Ffd^?U-EpXPBXxU!4@f2)I^75!vjV3dSpA(4t<-BPB6($ zSwitqj6$lygGPi}F$cNVs;JC&zLPHpKkgD9T?X7>;R4aFYOagSW z6q)^f{8Z(Oxeoqk5tw9R_31gGHukl=vTE zcg9En&^((w59_#u7dmu?w>g6FxNObMdVo;M1W6+YQ5qQ%)-B zRTrqczrrS4$li2OuObI;>$K%6;C)ssx3U3i?_{?YCr6ah^C{}J1i(RVYa9XYV5JL` zX3*#2=&JcjwY{x)07vMi(ZA5~xZBPflj$rsqs3fBJI*4}8(uZ^i$3`mopBc!#<(v!8;lL=7z`DTye#H#$rBF-(c>|DyD0db#c=`Z4u9t6 zA~^y(d;o`YA&dm6RWW}Ysk2E5j3K|tW)Y`>xxX7ZU^DRoywsr8A?>jfyOiC*nWaJC zHyUJf7YuHL2J;;m5n|M-v^DBo*ErtMWfy5_uRKXXPk08z+zt|&9(q5vk{)HlAy1EU zydDXQoJACAhE z!Y-cuBU&NfawVcoyBqER?V)CqOipsxJdMSDMcRp!jWHw&Z$7T!P%U5e1i_o{2Z7^( zBfi=`Kw{HyMb$@!zUD%ip?m4zU^YLtq=K)oi!o+;HjpojYquyY@?@Bf5N#p4ux2!p?MjEkMl()Is^njT zZhvX5Y8{6A-F8aW4Q!<{!9-W%2}W<_2=2fk5Lwnruz`$h5eB_@;3M&Ss;vB))P6%K zuYA$j%xdg?aJ=+ua$NfjKi0DM|2$q>e1E)ly#BscNxlsUSUBp_mtuY%ct%6FVZMQb zES~o1tjzQ zNPUyefb@(iyrM*~nOZ6X_ImO3#fF&bVTQ7c?v0qxKuJnEs!b!|AWci{f*EcV2)~N} z;?AUikTue1eT80&8tlEO;p4IcyBVT1&%O$n-Z3Uz3C_Sf8{z!JReq;w)cOwYGj2j{ zo7fke;i%)xw2-&U^UXRT?W4`Ov5DuNYmP2392SMPY-X*~G`I$xH_^58lv&Zj$K{yp zRgF~~WtND@Davk(Y;z_U?tF~DOKv_M4`2ErF{YA9JQo9o%KLi8GCElrU z`NJ!E1|*r0H+yfZ6>5(uelwk?121K&Cce-cHj?E+3~&8);D;ppD8f8b={u>hLW9}^H zBTA_iSNLLjG;d>47=1TGKr%xtq5#}*vw_UwJJq2|nNALSnGCyWJ4J?2LV}KJxW3GP zA|cu9kVrb<7DZyVQR6Jzf<3s2tUc-u;Z_s1vbul4vP?)`Ek~M~H5Z4PdBPoO;<`F{ z!7rEv#fUYh<{mA$YtX1i;%`c*RBXh(%}|^!2B94CM#FVR+f&0)7%wsm&Pd5QMnZ;W z+2kU1-M!G5bVLfPtf*x#@~c`QF@wVCu_&vP27S;Z^qN%Ml4I7;4ud7xK%)p@#O;8x z)2lWRGm>aYV$bOaJPEf;O<8gE&8N}~OoK#aU~-OP;3u!H~JB9PnQ0AFY2vNare;mF(q3glu*YEH2HQHyN@ z8s+8D^Dg$(WfrtFMRJRkH^L=GVc=D4bxrVqgri>S{?Drl;`~$~$I~V-tbo}UULW3; z`GNy8ci z&u>XJts<6wbX7LI$YN_rJ^dX9_{NVV#yxWQTiX4qc9r}dLnLShlg#a*MS;%QYL52` zlMOO44F*b@9q0PZZ!JH}7+aWUlamZReEQ>}4bPrDHb|6X^MEet+_1*s__j0%*CvYW1GnD zprW1QBs^3CTlWDG*zP{@Hi=f9W7jz-c*?emV`T3(v5opy$sBt+vW>&Q4YMxNyeFn? zPD28SsmeQ_imH>U@&nl(#4o>F+RohGdgd1PGl>!ZdGrP$E)kSF$QvE!*v}B33j0ml z^$xby%pDW4@|k<*EPVQw`A~92?lIbW2CdU_(gem&{YJR`gs9MXAI@52j$E1J4iSSb z`h3ZbH>U{{TR>S@%ru0e?e+Vl3*A<0cAMw-*0eBHMujSgFA%EtC&4#JVm?G)*)N16fMiozT!#6LT^) zfK60(WWGoKTh`WFiEx=xeDb$)Qso;4cPq(=Wj+BYiYyv#W71H7wEm6F8H`)mJQ(>d ztR6J1%zVb8cWV7mcpN^>0>Zo2JP=Jcb+9D&r@9wJV@l-J289Uw(iLEL8<#s zH-F%k?!W{>45f?AAfiOY=QV|xMzr1D9O4#qm6${ngWwL$A}mg0aw9^W`S+U9WN?8- z$>E}0L&BUC*psb$IBy==`X8-yXBgZ|cA1QDy?xbJ*$_hHJ&i~JNC)1I<(-Kvn=0nHaof>t9ZZtN!Q1dz6N>R_fXKWW| zRyZNLLw1{V;fuyIMU8cZBe1N1_H%444=Au-|Jrc&6nJRJw0zo$tHHw2n-sgw_~$h& znaiwXhEa)=U3lT+ElTD(#_XqAz<+qWhr@I*Q9E4h_eyzB1I8jbo+QVQn7g8oA+dg} zx8X=W6dH(loCxvNE;Az8fam5%+#@;NS_OZmaV3T*E@Vt*GbJ8jm}5;osC`_>j@)L# zf4FJR(NxnM`_?t)F-3jDovBx86yeXSv5qiA?+%`Qz{uBf!gFlTg09H!&wEGB!&f^y zyN8DcVePQAhVmq+9GyIitq-yKz!FF}8nZaQ>WS28xVwVXhgvf4C+5sxsbFvNhBQsk zqy6X2L$4dB0IY%IEWsc!{=SsTnXW(ItmvOv)7rx>ljo#$pr26y9=WJ0dsil^gr1+m|=X z#~48!z0BYPMF$G|>Q(5}SL*u}21lgBcuc4;fxO_aumgHoJeOQ!S5sR%xJ65EyTDWx zH6-qRbu4p>HYGY~;bi&s%m&$gP;8y-YBhR;s=BH7Sr?csV$>qDvU-V7$EPj8-_4Yg zO_qVvMb4K46DdL$S!PALlF*EOn72l(vm+DFCd=BeCT6fcFxJd)=TZst#%N;94#7Pp z4M|~bt{|}3QvjI=um?TkysvSbqJneO(8`ExJ1<-sFiQDRC{k2%k~vmpYN9z?FV!7U zSobFlu6U^$9MeLldwL42e4o@i%+|cz+gU+4!(WX9npOZKsTo&i!l6lRBP_xv5)X!< z08q6I42rcp@?1z%8(Hl%aWps>djx3A{ihgWgz~D_I9Fb`gZxzeryjwnWS!9C)@_Iy z&H))|{%UOFL}ecn-u6V_I}zS6ndz|AP8;4{cL!%SyhNk=^*A|R{4I<~<-`t~dAr}z zex2J@0qe_xYlSt9!4b8- zFY(hUd(0ljIY?}xo+D&+xM${B@ppGM9eBINHxO~fRu@B zejyANZn5>leKc)@%-$YhYlYxdRsz?$S`flk!sArK>_-*A0}Ys6B{U`UF+ns764r}d zvv)x{YkJr+Su~SWn16?!Ufd%uvNK%Zlv>S|X|ERh5 zeD7%KSFZ6J@V}DFxYJ0sk)*_OaNH$iwshABXntK;A%EsbQ!r1Gf^JrjqCmr`?zpqL;KpAiz zChhS6Lk8ZXv_RdAmkZXiheGMA6a)4rYpaciD8Jwc2TRwj>o2N~cw*=0pV=3$brwin zc-ZfrZSTA|{JHsb_vQYJU!LtgKWZLrAN;U;RELIFKbQcH@D11c!Ee==T20qU#pq>> z7h6B+_B+kixQXYW9IIwlVrD(pv6drx-&IiVkJ^2=3RnGcTk%$11pD$o0kLz7_rD=9 zb}*!W^8nf5xp4wzm*&C{;qfZXhahriCQ1--wB;*52r98_q*tJzdMe!|^&AHbB`%dD zuYEEr7n`_Pu;xTsSBbZ{!O1NriTs%FtJ{FH5+v6TCG9P3E=X>$O1Y{*kX$GFK%QNF z4)@P_aX4&Y6*&Sdf60f(wtL$Fi5KNM3FgNjx^+zJTgJ1_ad=ZB^iB&$9crBC3`*^h z19ugdTB9d_a%gHd;&Ko@>m#F57YAhyoSEkeOI;96*ojKbF5GiOqb`m_Ja;Vnrv@CjJ`KWO|vX#7t{<7N|nBtDPV zFGB49|AjF810G-u-#sRD2lqwTxpZJa4v$*>jMAL7{De6+_&Mp}f{^G9%aRM#Z?DAQ z#azM9LmtAm7QUIMxsar$ji&mkW~WD?qE*@{_9%aQdGO+ggY9R3D|1LnOOB(FAt9on zi8w@|O`;NQF5(+c#^lFd!6^dd%Ml)s5o)-8pL9oQXKQ1cM2o2vBwUEHd9dD2m#aoc zdM|m}&B!%Ln`K8KtV9}GQz^lAvzlmblJ;njWpZ(m0;hj{*}86+hV!Fj80veg)OW}) zp}p+z=25!L-;-@ONR5Zez9xg;w*>lPdY&aK6Q4B*b8?fY5_&OLU(`uxS7(K?V${Le zyCr*7i#7VUJbWyx`rC_FM=xI;{q4(&5%gDBGQ~SlnhKlnxkge~{Uo7r0H87BKQ|+# z_=4~mmK0O{!DWMWMIRGk6ygkZ#qQ^Lqb$EUtSbV_ych4ZHF~iMc#gE-KYJ+(U(f0++*D;?K3_{d`->T0xc|dUEywe<7iMueb|hZ9^}^fO8}yVR=B~8J z80Q;N?h4G??a7$2*^p>(p3NlZ{38`hP&7|^BAc9OR%)WDiHX!5(w&^2o9MV4OHKqJ zD+eiN`f&>NPUaP9_m&g%mg-hBEK)b?CE6b}1wA_?-%nyVV60wDhFQ6nOl-A+ivdP3 z1l!Fa{v{g8+OW@aHzohMl;$_D z3HWw4RIDwYqL038Sl70XiM1L_;qE2hw}|GYVkRZKlb|{6u!G%4?p^KAR(20)4jYFV zCk@n$#-EHf^Xa5}-8a7T1RJDT{arcVl(oN=Y~C_fsMeW`u!swnvX_PzXyO_mhH4%- z-uy!7F@>z69cXE8Qiav}gX*8Twz=T|21SS3JBO*? zQ_R|VPW-B&Kt2u02Jw1`Wo8snXnk#mG{Xd&3l?`2zUqzZ&RdVgp9@9Dxb`TXF2>R^ zaFiDA6m1tl{9`fst?+nUCFul+2?>R%(NS#V6K(DPhmLp}NE2^f)f^*Tm7RBoL-O8@ z5v|@aafq6i=psC#U@6y5if6K*z@VqC(^Cr5DM11Oa{>q39gJ9Q3>Ao$GZmZY?bab* zLGIFVnKCixQ1Sq)KvchtuBGp=-hH4NKOB2v@8C?A-xb!P)6g3?Cw-(n@dZf)=+llMnQN2niD)l12vwo8%i!dX}f-bxL2kU&#V>3j)fDriVm;SOamwfgTie02pI-3ZIw0-CZl$0oH<-$ zDd$e5P8)5%YFNoBY2Z$mx!;%lE)gQ&3(R<0!A;l3`TOm?{Z|LOvg4^G7pVF?No|e~y06KE)DCVSQNPh$ASE3s zvOsD7ZFe;2W17rHJk_EJTDQ1=w6jCMzu({f;V`KWEZ}k=)H;Vp2YWBW75!i!3l<(pid={~Jb+1u*GKk9MFCv3~g7wVzmPWTezZCwz0|V($wp4PCJu}VO@HAGA}?(GRnDBY3d&yy%iaUu4 z#@GcGjv4xEowk579bh(FlM}}T`t5bpe3U=3*{CP%$m^9{35VkZN6>_3d`A@`NRvfL zEv)f4Tb&M@bp}p!`OYZqCWDEc;Jt3VUc81;Wjt5o0c#x0!f|6uLJv8biE+g+A!$%& z;Y?RUUZ_8Xh9~AO&{m)bHjybrd1{Z*klN-L&KJmK4u8lQ-jLF--;^`S>F$qtdQ@W{ zDTgHyWb-kQA}~O}8PCws;G&7f!q;wKD z_Wrm#O2^k+Q=KBUN%nB;Q?}7$sXZB?+aE@~yXT98(bHV&irdYS8=qYkB^vDCrPPZ8 z{RhN(*+%mORv<&>RsPf`K%}m8(zh%93D61aPrh2KM)T~Dw`I9K7+#aHN!o*>kaqmI z;%05l5CO2Ku$*HPWdF|gyq39mgQiMD>!WDXt>{hS08^i_5^vInJ+rl@>N77mzEjE5 zoJFAzpYZuK&Pd%d>~T}`KH##d_S(ZisAb*qugA&CZ`9EVRbMtg+Q-0MAiHP;6Ds%(Hk!cXzJQ?kOe?q zONe!aV>F0)eA){-Gw#yZ;Gt)U;>|DkzU5V2k&=Qv+4XG`wjEb<^L4wy(nAq!uP*^M z{8lMs^f3A=>VM{-%!1Np1*=6BiGa{zI({BIg`$f|dWn!LCsT8(mlmiBmz|cq#f?Sh z-GvhCy0j3aSVyWTo?zVuZTiH#Uipie!}JAapYn1P%@`BQCvAke2uMZM8j?{kQvv$* z4u4^ul{u1k3;HdNJ_>(fw$qid1(nJkX`4gIf{j2Z;?+T6FHF!)3V4EW{|PjV{UWJc`0Bl{+pf!CP|9Z zS>$kNn8d}CKFrDp!&r7BW~)!U1O=(r{c2+(qeHu7zC*d$Svt16*koRCZeq^H5=cfE zb#H0te=cu@Bf43gotsYx@kgdEi0>RBQ_M;66AL-U`?@6y<`DyrpW}xM59MIUO$p{upv|Sw7*1i8*#vsYfI(ocHWngnxzTH> zfv{M`BOkI=9R9`F&f_@UD&}^OusgR^hJLi>(mDgptG=9HdHH!&mmjaV{5Z9x9)WpO zmUphOjJvN`mH14B_%to&;g7rf`>;l2OGAc(WfHB?4ub=ImL+wJrViz`$n{jFM#clz{ej2MuWlFtF6)L*$0;lX!>jtv+_@Q%t;CsSB}?Kh83Zkf+nTI*U+FBYRu31l8=m8 zk&#r?;INhW(YoZ`DF;4(d3Ylw_O3V90d3sh`XB=U?v@qQj>{iMn^*``+x30aZoANt zxzZkSz!z0*&o##S{$i|6rwM0}2hl+u{PBZ4n17J@U>cEy@ndoLK9^SD5uTvMd}H>s zaVX!dl09bTjPa}d*@_-4<6#t>uXzsF?avN8{fIO2kq5-){Fwh>M3&PwGtU~zx-8n7 z&YGzZe=D|X`f|>N)7W*xR+gbU10#E>r;f(y8D{CEGpH+bjxuVhn7&Q>Xi#JlWEkWQ z^KLMu$brDS%O`?>O1^V1!2reK@*gmt!s7MEV7f zTJ15#l=E{qvF$;do}sM~*_BWXAZ&x&v&mwJ+mQhD5+kg|NpMGc%4IirpjH-mRGerFK;*d}$C+q48TwuX_NC2aRaWiSL zC)dRQ?V@VJRHv=J^~VqhGQiX1fQSWR zZMoO#qOV7-Kd3D?I?$i7NsPZ^zw!LLsulI^p$4|jQvtksHlaCF28Id2yi-f8OG1aE z35?Q4G>@mogHbu25O8SA24uQ8$_1R1t%i4m!Yp4?ZlDzhoQ?$)+`~975`&-Op`xIJ za8S?F$*7wF|JiVwZ!~c6!ltZf(GO_DOtDcqB<17My~K58s5?q*Jz=<|px6&a?|O2b zEJ`qfWC>HvExz2|`TO<{yVYdzAG-&KdoP}s?m>;06y-E|`XYJ$;s}$bvHwMv^YVQG zCHBZrxSzJuETgU@BZv{QYp#$In@C!fr9^4x2&797s*REWq_QZWsbHn&WHCTd1)(F; zoO~b)(QJ!uX#2h5^(GMseOrM>$rZ3w7M*WY8@=_?5yycu2oSITvjJIH`&4+N)a}EH zcLBCd@|7A%SoI1;!;8O^eoQ3Ab2{8GNz}P;2U#*1qKi$)2vkD8*#}jt)1jLIh@;E2 z^~T}ZhoiyUZijb(3(yjlYlcA8hur)>BlMN-qCoq69-kU3ZXzn09SEsLM9_93eQU>~9H8tMopcqxwH?&~_ zgA=_WZeYZg{k6nu1XxonqG`^s;qR4V=DoQ>w={k#@dE@u6DO6Dc}EZRHYa#JC5m@2 zx^|XUPb8ZEsfmp%8`>xd*;)xu6DM@GVJ2!haZ$~SI^oKM1ZQ|iBM^KYhhnzlvhVm1 zxYd)@S4&cB!l@#{U&Dq+#N>3;F^T11LKb4Cnf<5D{k`uFwhw-3;#IH89OfY?mNJD{ z)=4(v()&tb7ArTVK$t5CFs~n=#rx*v49Z({7MOklgmjVe$*7Fld`hM&HG|=}Jt#hX zw|2k0__y+h5{e~ZU)lFYK8KfOqtPhEUM*Ei?`X7uGfpOFs6F9TJa|T#1YiJcWy+*A zNn$Tx5!$H}a>S3MQBsq4SQDbXcz%2wAv7`z<*c+n> zhmU0%Qp0HTa;yAUPXxu(gaeCzO2$GKKp-k0&nOli+x=EQ^|^W698?6Luan-erknNU zqT+54m>|fMQvY5lvt>dB)eTuM=QUHzfS#wlVN$*xOxSFn9WOEU84g8&Bzm6F1;=kQ z@E|(_jvk?pt5M z=WzctDvcOiECO(JX?Dl^XAX5~+Pmx9dXaJ}T%;mYE7vE*FH?H^L=Ghy)hhQ%wk*k}Ej9xkBZ9 ziyB2kEF`Ka9K4-|D&Y1N{F}*#(3TJ|7>rX(p3f|4?X0C7LuA8j4nwkc!ZI$(S;KHF zec<9IsatbV&a4gD;+3)R8C?j^O_Z>QAC$ZCL}@_z4zjF!f{u3KRYnZsTcGFQAX4gS z7zkTVw4fweE_(AwJg<~RBlFSBvDT?MuVNuEL45aMqQvmdp!7Z!k_Zk_XqDY%bw>fz3R+OItkVWe+a0g7B)So3$Pc z&75M+(ezC1&dSa?V65^HgU(gE#lRQ5%&^&YGvrq&2DcA%vD#9l#D>7vhE`<{nH*z6Xt^bR4rsyMY zX)@o)+gt|D{DGjMIaQntqC8GXANR3i_5F2X;|)s8JLaI8V`1d3c-7jxPPxZ{5*ffo zW^%+AqY1HPU7Tln3NwMTppo@Kfm*dO2?=yWcL|e=7c%V<4gr8< zqw*BVVAMUsC^P5|BO4^+*h6^sHAN*He=g2aKiq5`_9((s>N4$lh?m@LY{LQimzj!2 z+*nURBKm?LA5)iQpls07 zB#j5bE!RS0Net3^?IyiPPjF_`Dw*E(9g$~|?GIU3qiYJ0ufq2l-qR$=AO^=N@R-Bei9Y9_);0iTGr(|QSO2){1%&)!Zn27 zN^`OJ$+H(vcgr{h+c=`JCZ&oOaY3#f&Fv>yqz4=W1as=jxGH4}6FLc|O*36u0DSDe zEhQ1hYMOf<>?(af+WsMf8wGP+VT9jKdfG*cfNat}H!1+mQj0+fB$r^;9ZzWFrF+gU zlbFIM1Gu!_bWt!4XvIx<`vY)hedC^n>b`qP`+U%CryOGVY`{VyRRb8WKpKc9YoTZh zBth<_wGw69ZKqbxh$1c=6gdNiq12$*$c(h3;T%f$Y@(S~_D0ggQKy5EiTOaZzZ<;` zdlTP6Zs9@`0%M%F)(ECB>9s~^PH{m4rgXl^_TJAm)2PYbcu$)`B_|TZ1V+_|^z%{S z62Lt)2@&RIcwgM3+>9J20-oz|Re!2!6?qYk6ULr zvol=9nq(hF)tRR2(siRIacR9q6H1K6wPZsLSpDnNA}Ygev~4;#T4OL3=k-*kHm?jC7(_xaO#TAhCsG?lQw*Hc{o@gl6Uqi27x zxk)i*@CzEBZqn89dfu^e->9z|v;jN(LnXNzrF(>7HZs6JJqa3t8}7W`B^^F3(8fAE z+U<8XO8@nrpZ^;_<6*mv%x-yG*s|5{yJdjzkOe=9)pWLC}Jf0LhkUnFF{QL30DE-zhQ55N2U(eRb`d`s#!F>er3c2b(~b zzB<||Q4hmwj_kg)Q%%lHNjTJU0#ffH>wSWGLb@b#UjcvsmIS&En(2-uwh|fgq-Y)_777R%w$bP%FDECc zSKS8!rjOo~&@(;(G>f`>p(=`I56HbsG>YlFQ939jvHOpXb}AUv&>?vXb-{OFfWBRN2e zQ}!OXAj=+9;=`&?90q9M+3vy4k5FU#yS@FrqhE0N-|rng-#t7`zJGC$Y$q?b503VB zUhQumBrjhbynJ!EYi*{`)}Y@*Ph^Q?2?nfA3dBfv$VdfZ61@`OgSjS>)I1&9=H zr?g-yRVyAu4H+z0;?g~5&8)!=Z6hEaIn;$Nu%rMLX1^6uR~mQf%(Wico{R@rsz%!$ zeaL`P?oB$W+1|26k#w|Up-H61A`a_LWJNesCyNW2z*NDH;a3*#CH3_8WYuyiNX@K0 z`D#5WBmY`iTuthAWP~bqksWIl!^Er+ODj;mnr_P3S;~#;~C?* zY00c%!We&z)6S+qp(;;62Geh0QxUf!7*86qVHJ^J8eurK!Q@P`1ktcoOE%GVy*`@s zbqwDD6vP6)IU9czzbw~@Eg8*x$0&by~$w}bQdb^e#quO9y% za-SR>~nZ?Qgp`7BrO3*wISBP>a~GeWH7*~L5DBsJY*X*kD4sH>aH_jO~ks1 z9-AQRQ1~qtR;;LwQ3g%AmQAKs>CnV@(UFns9`)X8_lO`)?B1YH=V=RP%wg@(Q>6M9eWk2Iw)-PJHS=A7WBXF`{U5C~}J`@c?GPT3! zA{D?ibyyAj3x8mCrOH`__;Sr(&hd3{KdbQ`TXmHVQA~9*Im3M300`>uTlikrDg8~* z*b}iJ5VIL~x4nh!MgLOzHR9iy{ORi7f%(vPH==HWMUPrw)5UEWM76N*Wv3~|7K^JJ znuQ&(##%*g#Bx|}UaVs9iuTGuzwRY?GAMBhi6;c5;h7NYgDyams8L`)~tAG?z4R>Eq(J`%J>h%Gsl__Dm{_PZC83rj$m>q-{p z@dI;VU1VolWq`&>>x95X_^e#AW)NCuZT)Lg3H`SjekeSbqtMXS41Vl0ZO2CY*e027 z`IXuHj!~ONjzm(8cZG=2lF6`P#C_SA?n=Pgz2>Wf{VkVx!G}b>ln`Zkug~C?nw&J? z&RV&Ic>!UAMM{7tno2R}np0Xx3qY?t^rjGMYRcwZ+<4vu2ftTrq)zvYI#3WvN8H_n zLIWu=r6>emwBNMO(v7m$#J7v#xL35VCw|F2j>Kd)h_=qO5`MdQNbr9Nu%q}YBVq*x zXaF}~x7gH^nI$hCuH*{oBAOSXM$lH@>t*%cUSS^xOu7hf1x&25G7mIA34ZfKg^=-b0nU(~WVi7PxgX{s7f~V~0*;ct?9yD6*3KCNQ zN7g$D;ZB63U#x7-T7D+x@X6XO`y0h!r%3in;ZD0_VNaMDMyAj2u;#B#(I~rPW2qQo zh>DJ_O- zmGHiRn|%2_-shh%{NAmHPbr!9fhs|MYrEg-UEjb87EMJdl5p(GMSb+pt>aDESZvcz znaD+G8pd>X+jaR-hBg1v=tOjNWPZw9e!|j>0mi&KwcKf?u(?Fpi^Y?1>*g3j$~m^k z>r%-A80Mtai-CmBXbdPvFbJ5&{O}lah46kyiX|IPM%}?AGr%F)iF8gB#z`sx@%kB{ z0SX&CIQ1Li_;xMigU{fiBs7^Uk;3)qt6H*mu=g`CQ9zNfuPEJ{*E&VNsc^nT)^;%oziP=Nh_^~uDabVQ4O4y0F4s-RqRhsYhmk_WrnPoM4T zzUc;2W=4!%L=YgVr-EwBn+H&fmukLkU7v>h?9xvq-_C1(33^$I84(wsIIS{k*oQ0ht>QDF5WEb>w}4nFH*iv53?Y+>sz8OX<~+L;3P81)QWPWMu3mj$BNv zU=3Ml@2$8_vy`ASA)+?quB(lbVGfN-_^qoFMiY{aWU1BZ)XxWlH%W!vy6PA+OrD@I z0qT`6hE*{w;BWYQG~P(czGA5C7h>rPl=^bxy8h+r`UU>#G~m~dK}q^}Gw7#K_|?(Q zYVaCxIlK@}Q~5t?>W|a^9u3>e|Cc zkN<1!;n$BIJ$&%!;p0dDwYv8B!TRcd^uM3uXJvW0lq@I5LZYfFphp@J zfplz6K_nKAUhasQAx2k4#(o4iIim)Enmz|i_2cAhfZTuD9kr6Dtz>5a2RZrn93G=U z3Ln=yt$G_D|E-<28mFTtP=5t5m8z)9Q^$K=4vHSay^!vlV_=MDt?{UPwKEX@;q97V z`rEUIEdLygvXz%V{_qfL?_BrL5@z&6I=E<@KbgO<=>=;!)d(c$2e-1_9%o1R4X!7w zk&Z{#eiybZPB}fz3SW=jjDGBn57Y7N65hb36n(o61>o{pp&LdX#ws-7nnkbI%yUZ9KzkzTR8(5 z!1fGZ9--g3KbE5(*TM(u;e!XkgXiPPFxSpMXrDX?dOR7xE??ohuyH;ddN123pC66k z8Mz?gCN8~0+0e?$7s;sA2STUSX${AuSVKyIy?9v~PVegoMK)OM4F+hpI!-Up?hji> z03=6GP((x@sYX*;gs0?lOg0Pc4bhOG=OmB~Udbgod&$vP{8&lZjpU+950;$A?8eM_ zce;IwTFte`*F*LjJ=)kf?T)f>6Q6tqlRE46m#WD-Q9^2?4Jx!btEmhTLr2;ILLt@? zm)R80_~EGg7Qn+3KGH%+BYxOa(7U-Qvfn4D&4H79KIjy|*Bu`K5ss47v#`6WD#Ues zSAa6FsAKIHZEQ!aPIn>+Pp(LgdVPytp@pWiU{|%oe7?>NARBi8g1?W(OETE2YI0u( zeqF6PV?%Zf%~{8kZUYFulrMynbbOg|2nSA;-R_RsJ=AJYHwwFxL#to1a-cHI_t2WL#zOQsUpx!{zmHV*#3q=e^j-a)b+beI?_ld z?ZF*u8u|_^J%moT;olCI$Al+b?Av73J+5X$z@N>M6GQ^mokDj2FTCchd%l0bh|v2| z{W~1I*;mvZOkgEhLP%`KMn3NJr6x|ZxDpJ88g3(7`t7$#nfff_NBqD~I(>NpAK(vF z0JPBC)P0}d2~fF)<#jK(u;7lD1$;}?(GynVQlC`Mhao&ya4+E~v^Wk3UutnvzSG|{ z(C!Z;avkN_84ftBpF6Djnn)B@?BQH72Ly9`rocZM+(2_3@YAovc4#blg6 zYj5d;Jz)y>B?d9SrhSf2Yu?lA=+hf{S}kw7bApC9-Pu@NLtCLaJntGrQy+E-&kVb_ zz>20Biy7gIof)1C?BvN-@~ruCFM2lceVxuT7TI*}IaK4CCcaJTQ=7P7*hE1MTTD?g zHba*dVOjDJu#-LQ4KTPFPWGaU2Wxe6R2OSo*-n z&`@Kgm6hgQ{FJ8gGaDPz-pZb3qzb%E|LiLoAa1dZ^;QVr!W=g^+of7n51S~*@UHjdYR1Nqgb=L*YBdSaQ7xPU1WHxeYiVN!9|ly2Nw=v z>E(|*g9{3WfAq>tux%PTz8i{^MhZdYi*BL{(|-abz|!P8b74LIR3Q05uV ziC>i%H(XF8ed1NfCfZ^Sjym47ua<;rGDkSiuxxDX{$uy~QS-&${{*ldO!~7S_iEUI zS=j~tsXIP@hW3;^I|SlYv(rX;0|`#P$l*4H@=Ik=H{bxYT-mKQLi{yXMJ(x6y_v7x zO}VPLg0%3mivOTA4Bau3R6f~=B!v<7;srGq9FL8xnk&I5*;o+;E*pIDxsRw&q>=#1 z)KK6~D~_P?D-c+xRk`uY-^2<#^pcV!B((3MpAh;yvZ@F%Lt>BzE46YsrT#=~Em=NW_VCf#l1_fVOsse#}u)A}xyM44M)t)IyU#MDL*OF;NxxiOSkN2V!yNn$NZ5$;YgDl3(;Bw(3c2*^}71C$WW3Vk@7-mOhECeKKS5;Um(G z`nQSd5&Y8XwB?WcsF_VJoR8tFCOPlq9sq`)r26!2)_l6N?LD#u?OuXceRwSW$w$+l z`A+>6X|?D037RSxR`h9Z9RBD}$a9c^N|fAM^yzx^>4WG~+6QZ0B}(&%LZ*)0j_fHeaIn;(LBT>>9@Ojckc`Lc%w1G)7 zt~f0Pjgvo<4pp}$)s@*OIlys$rv9qL*gf4kn<1(Zdx;o{V-5-BU9-okTY?g-+4^_;4q*Cm@Qtoo3og z;TV$w=|C-6Z9GZ{QQf+M8(aH!;E|r!8`SSDD&A~t^EKH6$! zONa$w8Yh4$(durTjO@o7{HQXtJkt|v&NL;>a1)=I`E3sY}6J^zQPQbZi)?qBL zv7x2|-%d05c%uA0@Q*vc?C(8)x_hv*yTAX#?u%#5!+#w8%v>Mq_m{%{%(-e|+9gMB z4hT=JMB-yYdlD_-j=_B%bZuHRy{g3yc84Efjfe5>ToVqrJNJ3mowjJYL$v{}iZc3Y z&)R`|dW;S$iI53MhK!2`6ESab$8>b?_k-q-dq;=6N5PP!)#{&dYs_;#BSK`_rnk9b zQJ?vvl@!!T(14IG5;d5M*CYMNt|GkZgE9^D4;{100HrHSkv59OD+O|jl6S>q$=fVp zN*Uv`S*{dz2KD>n`uBie^(m?uH(58nN%!kg`=SaDzXs-QmH#|iU8T?Kt2BxN7S?Y* zR>JFQ)VTK)3*Ey)?`Y@OQ24x$bW>7#-{5Q9B+5LDt17{pBszRnA;OYZPy z{@&K}kZ(r%f`@KD+|6kIZh#SdzDE4gA7??l&3d)lJyK zjcws3*TTbx_-$ZoQ6E#AsEK%+ zQ3fzL+Gq5X8snDWS9r2+MnQWww5l*LXlGOo$3iV&{coI^-THt51lay#O4?m3E2W@!6Sy$jc$y1L-rIy4X@R;R6VGLolQZF(`a32FmAn`x}UH1Hi19Hwv)0>_nPlM_62 z$aQQ#-Jv))@Ez@cxA*s%`^b`|XFEp+ua15cdteL*fqcX2;|DnVzce1OMKsU} zEz{4kPS|oidAa*^_wZ8sz|5qgu{+8NmTLw-yfX_ZF&=r8c&jTxHrhJ5d^dv?*H z=A*-n16W^tX-)dOwz~e%Tq~>V54`i?bn5{GJNfnE;X98B2V_AR50K#<`iDWRU@-GTY+3{JKrF9G3ps&&2?P~CWe91mTtq*7#MdmRpgQmk z)`9D|^Lo0O{jSgMcm4MLKA73>gW3H)xP8A5XZHJWcE1m&_N!`3t4j_0v~S9_a(J0= z=t+|A!ma_%w>=rd*5>}oswX*j&0M|4^*K~=T6La=4T-ijY)2kL1=UgMchi8jkXO-r zM?e1>8hP41JxxdCpVjRr!$G%CvQDl|*9OCylIiIR@LMB&G0;giBK`-qAJZ;Y-2G*wXZ7r!Q&od)=+$Veg%te_Br z%p25gK;+{5S~5RMFB;7JIDKjh^C0!O^++6KUJ(aixE3D^u8#ngH;j(}Rlfc_fC>z> za#CdH9f9Vl-AlE^ipmK9S&FJ!_GDbSBrle?gWlvK6)GJ7Xii;1Q7`xa(+T{>Kxgfn zY48dLji-zcn=0ZwrkFQ=#$T?x6ADlcDk8*3fuxTWCC-3XO+%2aSiH42_4khQ`C&LgUd? zXgs<*XgvC4Xgs<#G#=d+8jq(!wXeErGL`1;n+ z`1-cc_+~0JzPUSSeDlfB_~zEo_+}O~)R@_me!{~;e28;@ZbY50$TKH_m&vn1XMz@q zSkV`MLlsu!e4!>s}z@pzM@nBre$tPpA8I za}bGHK6Z|!sQODM)?(CubmKpYS&yFG!g`dKSb?I*-~k{5c}CVkh@Cb^WEHe|qsBp| zNezWiGtmxAHynYWCNT!2+nR(As7Y`D*%qJIA~1CJBy&Jqs4rX#OZ5k2>&DP~)OFs# z*igyft%=sgAvCxX#d_=}Mu%i0S#}LMO~c->mawP75IIiYI6GwN*lXblTPPAH$s}5gn7gvjb7-vp zjjyl?)WQPMCAMs%Lve-HlFs+*;QNiBsGuQZd*ik>3>zDUtqrxgd_(IW)l$g~lw;(= zejF6@xc=n(Zm;(-vu6}dh>HQ?t_W0k1KVcHt=LubQZCMMKbYdd!9ZaiQ{xDqEjb|O zqDT|@1z(yIG zgH?HupWqh9v7)d*up;s}Tn{HYMN*~5c@yxu`7yYdjOhv6aNMh4K%e5Z<>6NxI1Ufr za94a9IK+h6u=37)pD}=!(j?}9)J(L{6P+Dt$~mgb$r5ruu<03=9AN6DiG*QRDpGJ7 z6li|iBp-ij1|Ay)uI4<0C@ANRVP%C@UwDls5R%R9(dgH&*MEZz^KMmx5jt15cu7Ru zAT~C3aODmt9upQz#~hn!%hCt5DY#y?gl%A~(TxrKvcT zQ^X14!#Apd2^V>jUVoLCkETDUS%1RaIhAo4GjxO7N+gUcIj$VSqb1XZMwoME;x{X! zblUZ9H?`2WBZV%Ajqv)gwW%Yjg+4~K8+=D3;+d$09bh-mQD}*Z7qrrBr|34@lo*v; zwrxf^{CufuqsPE5qRd;JQTKFALA@IiQ;$*`WExw3JaD4EsUIQo@``j=uZ3KWZHmc& zFnVLBz0(`C-@Hsm-9aZm#+z)M4q=EK=qroCIy=Wi?9Y$BV`gT_e^Je~h-`x&*-;1s z8Y%}E3x>6<&Eo~WYT<>%BZZ6y>a*WLZ%7M{WVaM~ZJGSzO+tG)6dH94Hm&Ofjb03@bKa=S)tfRChPBf0F^}XByB_ z!tK}};(JJfi}6006LBD6f8Ld1p(U`U@I_a(>)K5XdNf0_KOf|Y;64UBg5`-`*?G|0 zyBvP!7Qm0V*>2g#LgE3McCC174tZx@nMYFl1amTCW?{J%@#7(!+a+FK3bcxlka z*t8lE*t~kyI&HN>&@pl6)WMV0$9M}rQYfI7eU5gS+9 zWF3qm;_fkbLyU+|l}x?u^n!D4(x^{33LKS?oB*8YWH5pY3u&JJoT&-=?#-6Q4U zfZPCRU{O|9CjHI;?>f^afI_^l9sa}_9cp)j}?6dVhaiit9UEFk6^{c^V zL4j*5a9zJHEO3JbZt6FtfL(|vAkY_m!nw=Gt+kv`WSMxG72;$zV^z@1LZA_?64ZeK ztOWv=A075lyGH?yY zr(=f4#0L)!s}zhZnKqnhJ$jd)0}k8=j%dm&!(+k{R_f#i4yPsp!IO_`oQ_2Pq)&24 zMnpu?tuJ88HA<0_138g<8TyR{;-+Y8^=NC(gbPGF(Z&J^4?m5eRe>bWc(p1ejnvHp zAy7-61Yxt}^_hP?g)R|tZ zp<*azwkdCmu7yQEl=2mCGlgk`H)H=gaR!g-bc|Ny&tYxmBxY7{C^zS#Ewaz7a~41f zoP+!u5tdy}j*XW+iyK;*V1fB)0XK&Jx8Ih5rA+po!r05-eoMgk_S-N5EK?9UlSHN< za9lYlGG9F!J>gXy)73+h+A2~ljOMtAf@kM z#&1@=2j3=tc_a@AEhTFYR-NzPCTou(+<|t6;6b9u?GB-(JNxTLHDO_)TVT8{hLi>Z zlOJ-jaR71M!5;y}2X_O;2cH3q5AFtx5B~@-KD-++KKu+|e0Vot zd^8)31p|0=Hv@S5(F1sVHv{hdUUyo5~v{XF@DdXH{@l12&sVyY<=Y@<-yldj0@e1V;>DvL=FIoU|J-yX4mg-d?- z>WF<-4b?X&r23MbAGZ(ocMp@b)y9Lh#`=SjBcXT0g-#b*T9?9V9tpUwWugh4`e_8N zWq2twUAyI^oi=WTMzx_lC^?kc>`_aUAq~@EEnUN>>uSKV!UlT4+=Ku82AjFr^m#)n zJdMqy0&_5#RBkGZNhPK-m{w^>ut~{iWuHDSVUS~Np$791NfHLb!yus}$ti5&Yr6Xv zX8lA{-@Jd1K=@Wo*m5IuHO^)P^#BAR}CArj{)2egA#p@GxTW3^=43Ir*s6p}l`{&FYT4OjJ#@(1I(U)r%r>v$Vv@ zmaS1&quZz8fI%&ZTkbY(H=Sqgr46|1(hp+8*&(Gp5#f&B{)0>{`aT_({3t$j&O8(n zhNUqjT-0Puh4M;_C(3$tnJ;x@ijPP@3xaS$YCmVtb5=an-Q_>`%|B4|WmE3*qbztai!$?yX9*rt3lHz`@D z%5}=0Cl?pj&6}JdngknK^$pAHQ}fs;Cg|m6$-VkTQp7Ow3nr??`yjY!lu@ekk%rpB zbeV&`Xzt&lesPqxI%sV(?6vx7jf_vT^T7ba6<@YS9kc>CV=2f@$%uFg`gXeRr&rOQ zZEJqdk&f*kOMxxq5=R>G`6vyuNDyPX+?705VJUM|g=A8ZlLC$&3QV7(3qUFH?Fg zFo@DVi(acRiH`%?EEM$pj7>~X=dX2&ib9#6fBEkvZn8G}Y-xMGy%;H@l6!3KCCiGg z4r~h7Z*|kRsTBf2dtwG_qQeJzp*P!+>GVT9Kptoe%j=fb88qp8_1{KvYa?7=U3+k9Si|Z1%NzQTay? zb0$RVOOfWP$(*=*{j=ll_0NgB*WMKRfb%_&JgH!#MJO^ohv((Vv36 zAN`5Q`_cT!`_X4Z-g9B?N4Lbz z&w;KVe|B{J_;aG`$8mK1^(Uh1um2Qu{q>)SuD_liU4Q+*3tfMG_vrfT&xEeO{^QW~ z*Z)4~`s;rWbp7?`K-XV?c69yq=S0_E$IYdGKHs#E+6%^Zk_K z0gP#42+GDw3gAPZuFWSCusDd{t2+w|MZ@<}fq7#1IxTrs3!?dQ@#!IbwaGB9uW{b^ z*x}SifB2|9Ze*U8z{qUw^fH0s>Q%K0iDqa9HkVN_bf6sVG1!)t)y*Y+*}&Y)fj>>ETZe6q{jq zxi*hDy&8_ZE7KiKT{egITuS++DO-XLrf?=8PEITrZ3n z3$La{jhzwzHg`U59RfDj!u&yC<6ATg1Z(zt7z)-_&+U8@4z{TB_0-A|6xL#gDPdvb zlW;@BLNgx|9F`h(cj)Z{#5UK%5V6>3JV-2dFn^fX=K2y0sfKW@VOmMI*c72YJvwvg|)?6^v=DMAFQJhP7RTSxx0d^NbRSBv{XLCSR+?#Gl z)p#&ft%T7-VNZQ@C{@h7kAAGNxEq>ejV z-5Ib9*Vs)FdDxVEX-+^LCvzS^&lY;3xQ_EgGF(>8>fUwk}i6lVh`pk_He#pkLD}(c)ns^&sXf5d@+_z{FK7}@AWXKCdH$Iqj!Qt z1I1RlJO^G9_T*{z$_;r0B}G&;D_0NHrK61@X(TNA2ru$UtEaI$4XxJd2s?|VE?UDH z#ymov#))_&;uL7s(uOoJOn-<8@-+5(7<1`_Z!62iaq5^2KZcRrsS<2`=epPJchV73 z_sf4y;+SY{1WZ^tXtEwQ37~Gj=>uk2sw&$YZ5zn5S#95+qwPpK(#Sb3nZR~wW|9PE z8H@^}w~o^u3e!h}$=Nw?6>9FU$=)fEmO^1pGTsG-*JqM?GVGu}6jm^8w!5QtF9o>a zu8{PAIliG5fq<+4;eBk7dHv*DiCV+Yn2Vu@K8NqiGm`*>KzqO8q(9z}xLGWLsS!_}q_QMfZ$+?p36|Bdh40+t0X)SCl$>jz#>aHFR6|mry%#bNM|<)~AAZ z8eDn1H~{4bZV4QWTL8c3f%d^*9_Jz<^y6+WCJnh^#(m^#MX;WT%s-O_rxBq?&+tR+sN@^6KMG1}Kp}OtB=%nZQ*Y%BRR828)kV17ubG`H>$ceVw&Bln6SpQ5vL-|4^V5@99*(5;%Q$C@jk*Qb+r z1y{*jwA`f-bC=^7ZHGIIvu7LiUvMcntHuUB_B*#{mrS#P>-X46kKJwl&0uaT|40T` znSUM&U*71;II5a!cn&4V5U?~!FfixMb>SN`B!yUP=j6*5b62AjS*uanOW(H8_J>R) z1>K+lR4YTv1wxUAnm&9xz9MU{LoD5VyT;X)?CQ#nrN@notl|8L=L%de`SZ^exLFFw zIb+kVC5Bf{a?4mB!)vENtdHT1Q@|$q6dO7Ypx)%Ueno#Atk~*h11Ir=B1aE!NL6}m zNvYC9rXK@>~oucOEfl$Tm+JDi@0c1sKH%=J8t zQOlpM;^uCI5b`#tonet|+ZAhDk#-`>|Gi}NSIAYus<>YOg&Psx^` zIpmy;osLF>QC7I6Q7uA6kSlGhu01N=W^TE!AK48i0&5Wwgw^S7e#`rKsFp+#SFRb{ z>OO)Bhe4{p{B#Eyj9^Kwj%>*cD$)~>Ql>1LT1_h}?|61~Msa71B&%$xMJXy1=gl>} z;QonFp#vVI$4gb$>7_ z>iWriT~iBlcYQMjgwA`Xy_=~sX%;sH@7!S(G?TK=Z@v}Hi5;WI{6tlegjc?WT~T6X zHzAzUTqNyPzP?75b2qAlOd+wx6u%h%0e z%!E|mC@AK`4dJK@+rF8v?c#AG@<2Yc2(jQhZQrn~(-6!}^i|8n4tZF|NZnix0ShV{rVPTES@oHx~R=8Gr zfDy!a#1ujvi0Sr|Y>BRDtK#V(R)z2WMOakz#;tkdRSO9o;aWt6(FrM+l*k`Pzu~ho zc~U36$(O$|h36$$(>tYh(mSAb(z~Q~(wmPWQpwvW?e#*KcZIaUcTKb(yYe@$BNp!F zwdaBSb(Sjcb~Ekv-?n<)4h=h@p_PjiZvS6<@7~`;k}C}FzmreVll=|H4vyotojb`c z6JX%k0rHsa&P+IY{cG$_+~C`G+d$08^VwfXb+4|zI5(I*WM{G6tx~CODoLf1;yq;n zq*;~)IF z-FR5Pn0(v_Kf-WqY`5Eu4MZA8@8;wtvC(d|nmZf8Y!>te=94OpXN;V^web-->Rfq>l)E8?SK5I2`u@r4?lF#K-$H6O+hDqI; zQ8vDy*9)iUc`tVO6_KG=ypemqejQ$zb7|qiRyn*ZY1v&-M%_tld8(sFiuUu7x82l! zKYVEO=8A6klyGOHfsr4(>Be5lkzF0#lN}SDtbAATr{4YvaV#=TvQ8XYlS|A@<&V!jk)DNX7tAf^>H|x$77NCRFI7| z#De6Q2#XcDu^=|qNnKb}qQuH+;wD>i4dJH`{4j!%v?xImqFV@(7F7L0k+cvbEhI@C zP1YpTR!c;hdITzZgxvG$9@i~D+2P|_Q?pup1)c57HG)=T2D8w#8~A%gwy0l&cj3@G z!YDywlAX$2g1SAT1Wi5+V58CP`1pMbe{8ZJEqvqS8v)wnpiKnb=Aiha)#RW}0ovlA zEd<@+p!lQJ;-D=7+Qzp&Ctw$UY;gkcjqhs&Y;sVnv)SOFM8GBol>}^YP^`1*b5J5+ zi-Sr6s3lESXOr5vt<|~1-%_0|{#I7A%imHpZT?nZ_KCz6$4tcUD9pak-xB66{#Ic2 zoBSfGgTWi^}pEj6vd-%89xBIh4lM54w&+S~js^x=8Cn;QXr)+ zhEaLzx9Hj)u!c1eamz<-$^2=(-86r0n?H9gR2DAZuFAsZTj+cXU(>>8l77W{0r(G{ ziF>s9Pq;q;UCX!SBD?^YylqoAv_LIuZ`ELUp;bE^R~v*Ngb_W?!Vr>=1&@l;56^@7 zkYeREgpjKM#5K1x5QQ~Ra2AkPVW&O_RW&Z##+v>T3+1IHzB9!|-MYoww!D=w*H|7r z@UV#S6ytNAnJN!&gnBP@mUnR&d|+*-uN2LWyTH;tXN(yDb>k)PbCST7y9tj30kT}2 zahDi6SZkpC^$12){j^(2qP9M>1t7JS$?uN0j#g{qE1+`QysH)YE{M(JbF zpV5z1h?tl9kI(X{CX7-rKuv9&31?l5nF0DRefytzfIKHCfh@URS**^Y6}!k^zKfb3 z4pfINwXj)m=ReQVUhpCdDiZaB@i)#5IN6fq<;u%J#ao>;RDz#e5zO_DBmlVnAB%s=88qA(BTN6*j{7i;lNqp>JYClj%TTbn5XqLp>AT4cY_ zEkJ>X)u!GdcbAccHU7>p+Z>)fE#mPEDvQgrw*`EjfQZvmtiF6kFC+J{ei_e4zF^Pr zy~%hp$6djW|N*b8m%qg-~Nl=-fH@7 zf4jK_&;6~|*7je#KUGJv#x&&TpX6_2ZEXdX-+!OuxlGaU6Xd%%3eUZ17=vy%O1uOM zcs(jX*FHfv$GZ$>kS=j25nV14LKA>|4a(v3`NhOL26Zrs1Mf-T9ZeGCHv@QFpR&j6 z{b0R^kN@5agZg=VxI#A@{u+&Y!+Ad>caI#h2df33N8&8wqn`(Ca+~KMgN8A}s{)T; z)4kYu)_MI)eQ>BfhBdZ9oJ({Lzs*VCc->e+D{}G-#>2#N^1Nw3Xj!G6Mi=3D1F(mO zsi#lEaS|HPqi{5dFX7P`BS~UIh46~v3thQeafCx=3{_s$;m4D?V01fMWAm(*lh;pP z@8OM?AztXeL=jkAA7=O97K{ic%b;v?!7rBb!pTw9ExVmEr!QNi(YktJdF1gImJ>UV6i2L=P_iR3HKOPQ$hAp?k zo_@K_^Z1W=hqQot=*oV#H|i?>((TDLl(@)8ekO=@xQAW8G7KUH0LabAX-ib(ijD70 zrXfh>xRzJAN4AD^Mm+a`z2Dn=4X_n~t={WGOSIGHAMJvgS?pFD*9*oNKa42PYaoj< z5X~xnRd+}kVdR};9*4@~0l^Y-B&CKx-Mt==pc){a)METHiAZ>wA#{MHyX^3Ye>MB5=Q$ zAi+zl6(GV}Wx5gah?aMEly^@ZU9W)8V^D_X z69tj1n61;?feu`gr*TFNdLqD>bBBXI9TDtkq>kJ_55}-N!9{qFj5xo>{{(Ja*ur~a z$(#84_x%;) zN{9qLptp4q2BBh9Uv+YCB4$30{yh)7(^<^)Jt|?1>V8jjE}?;CRfYzEE)-zZ6<+6gL-oKD zo&QB=c@#%&91PWVUlTEhV8q5DUVaM5h{892+oxCGQ0;f77?5X6tD2EMozC%$e&(x^ zc8Yhn#XB71Jx>kRGT!iP0#K->%u5`}5-81Cg-F8jEZ=n+$C(e|y^HfQ#&4D^U;UF^ zZQxU!9i*DOdWvU0ZykCAaW#kL^7Ga+kVyC=O!I*9r}bObFN~ixY2TDIF`HwJTNOEt zHEuAh3HSW!ekN5Iv_qpv6FntW>1X#s*}_fNse`W5`=l#&)75d%)wv70R`{*T86EU{ zLv)BvgvO%eod@2)+w;DNImPyt8V$JozL4Ky_U%f`+MdeMeiF?<(pmj0c^kw*zq%?? zt)~*Jb5JB`WPzQg!4?{r(jvuT{}_&=5Mz7xL)fK7n5T_3Jz|ygy-2*#96A6>_b}*H zAl)Ht=D~6>rL5@4EXITmxJ3&IVkb$QV_=v{I^WpaV;t@gncZu=jQBiM1$*cpF)l9X zAMQ(eOeA_DZ&ytfgQF|tLV`Pj z4`_F<*(GK@#In4FO|K8GagRr@2NPUl8csFd;!@<4b&_^1+cBI_Tn6EzcxQM*v+p98 z$Pu`+sg`#v5njvjMd5>W6pzw%yCamCH>!=O$jr%g9)X-1;{1`L@NAQ^jLSj8b4ETrG`OXdm?BAvg%}89@&|;~!L*fV!Ba1@ zU$OCvxQR2=`0dliTQ6b|80+PpNPwxg=l%EC6?TClAHe&2qa`k&CC;S9WDzQd253xp zb%AX^m>(mEL1h_!WVf)>OmFfL^Jol`I?b9StY{OS$BG8RgW<1p4#$5VM<0Kk>%baP zPQ!sJTSpSY3N**!?&o-)+z_AnrEM9I2?T|oBQp2GBibnNwg7Gx{ByxR^|_>1f+A0O zER6I@qpGz`$M6*6w&av&b}RJNgPx@%4ArVZ&0=X9<}mnMbn#qs*gB zVfdM)GC+z9FcjEF+58W@w`Ud54A;DYFk_#*u^e2!SfPp@C}vsg00te3&8?{D+b#`t z9A2=a4-jP@H4ZDRf@*G==_FBQe7%fr(If~w;OoxjQ&8RH_>>_Xt*;mJ05!D>y75*) zN`(qarqqWXKaH!_Zi*T+bJ(cqe2?{m%#RpMr^8FM|3=Ax`wWf~^fe6FOs917a*p6c z!tk0Dk3}~`-RZd|b^9y|9cNK|zkAy_t9jXP{j(|yUTjX-iftW`Ca6_q0CCsL4(!~u zvUizv#;P{^{IICfFWKPV8hQaxAAgEkr6g; zGB34_6xXQ5L(`mj6@Xe~_0`OS7Ts<%fE7AqnZFYT!%y2KR*qk-XLQ@ z=(vYkfxpPw_AV6u**sbzg`dZJw!ko{VrGy-_Ih&s`h-WH!h}6JI}(Tj(b zR{<$6M&rHhJ*Nt%ltox`GgVamNb z?W3BgrZ<^JFoW5-9!q9|@$=cY${4=lMU(LbS0>2ZTc&rXS-mTJ!QIW%>vuEkO}<&j zREjS1;SlJod9H!DcHax(xaMhO^qJ8al{os+oJMtl_sxu=zKy0c#ypT)(2*K-KdhZT z^1$gZKu*H0mQuFd(FBe0_8=}hBF&;9nPv=0^G0LRv?^&D)887Z^jP%69&ADw^n$U| zgnpg#I0TZrv%Fb--gz)~ARgB3@f6JZVvb1ojnG+Y+1z|Im|ijmv^!lE7z3{mM(8;N z%JJVyb>kb1d;n5ByM(+~z6{Ia@lgxOI}F~9`hj;oAG6IzX1cu2AQ=5gO&-%FACl|S*p$7RvASK;&zT?vM9p6fQr={yV)$6;uZ%qy@5ZCsJzcuYHhl*QQ>&WI3 zLe-bE0Z-f#g->J6TkSkO>O6gX@|0Vo zRKfMbUY{qIN;`FQhd?8Gc4S(6GEFj>W|K_A#+Bt#V7r$vYSO{eUAY<74}U|8YlXRi zyn?<+x$$IO=W4+_f2K9gr`Bsf8C* z&UP>yZt&aa9g;|nCjBt60H=e=WC(qFG#Qcp8omM`vt|K;Z(cxK0;t^u0rL70==DjN z;0(SqT7&lF-2^7_20O^A52jP&WshAJIxGs$z~bie3=8mM7LKOmWb&wognB23EBzc$cZ}SBLX_ zs6JO!CXLH#)fgFc^yDUkQP_`yF%Rl0Qz4UWN*H8>Hz=@rX1@ZkIZP?$j?3{h(5l6< zk&}f6+kAj&MKF5=bM%Dg%uGr7D+1!^*q3CfN)0zp5RaX}s-S_VvmW@JYCk?y@oKjW zRbv|VqVr2`-vnBj`ED}ixi3f+vHbm&+bQc=mR+0q_#PtF=m?ItO)dI%t5^Fa5G+LT z&H9y=TH$-pl)DL zLt!c3*_c2D+IMSWNeF8NG(w(uoaR_Gi~yvIuTa_4UcsKuA77;vH++$q?rM5T@7E9C zg%_G*Gc^lsCiD)}zSD-a6?N2UH-de@|*kebQYK%=N#^iDuGB)!r zB-TM}Nr-_O<3zrIz=!;P5cy`yj5n3^LQIdx1DX?V#>&t|=M@C0Q*U86&@bqpiss#t z`g?mOc(`39)mY6g`9;v6O2T;Kj~9KUq>5I2Z1ui(r5OC%x1-?lUD%zE@sQ!{jI{t{ z2jID*2YA1fb`r5+*6bzI{;wb+x!?uZ|3ik%LGeQ#KW3*{QNk;AgwS3U*N`g4yd))XXr{HLy}hUZdiv_5`}!YWVGug=v1=R{tJ8*ouE0;_%7BOeq_ab{ zSbmFUgO@=sp0GBvJfbplJ#MQ^0PPZ%$|~_8W~R_USGB?{eQBAp1gRID@zAU#szpen z)K8?m@O>>!*@X9_$0WZvn&g#X&;tvbUs zkyChtzJjRzx$cZ+>_ehV#mHUu4Y5LT8cJCk(+rVsOC~oQBgHHBr5?NigfXP(ZABDR z@tYIx$AjFKr{rZQBR3HvQ!d|KzP;Xj3Icqo&7BMdse8xKSi}tAXP0c#%?^sO+&QDp zT(i#_U8jv%K`Gd&UA{5fyt|#Ykhla3jCMUz(u5fu$9kdDm{Nb=vWuF7GZ3ty9Ak&e zok==1(c+30_fiYx7H2tc@1;=`vHcdRN{yjBxK&eyU60iSV9E1WRL1JU_2{jyYT!)a zXU3jn7WMEfANFCnALtUcUQ9^L63`O5b=Y%wLe(=^ztKR;Sz1otuqApd{gXzmxeeV$ z>xIdxp#4VT-@+b{N`&2dRXp7Xvd~6aPs#6xd*=G(RoFM->OoB=GhU)n(he|p__8JY3t8d4?!B7uktfEm(U7Zl z#1c~(YTL*WF4dPwnzFo;Gqy}VAs^2ubM&jBt{hwNG+(5w18$-={nlft3G<& zfj#@=>67kB=O3N!(Xan}bMlnmkc!UHflI4`_RZU<)vAlJY1wAIM$u}PCD>!GyXfm2 z2h%ARmD#&v{^~dOrjBFy%90uI5nueCa0`S`h!p2YMPx4qg%btIY6y#*#Pc?Co-N1#} zyhV277P4uJ!iFvKnpHX@xM&Ov?}sp)a`_I=eTG9GfvC@qms#K^In;&{@=eB3;vNK| zCy{4UAO$+CvF8q@T{l4&1Za&!=^#UQ6SK(*fkW0QAsQtsKY047h&SLdSu5nQvbV=P zRw}Ea0M~z}Kf!u~|1W-uR;%7mG;lw`X#50K*NLC$;RL891Hj5cwfWB~1C#YxKS6e_ zdFz@rt>!({ei^tk1EaT>-wh++|c zXi#+rAhJ5yj4ZrtA2<8A(ap_ex|vD5HP8HYD+4hL#(&l9?I!#mw>NN1DZiEBTij%U zEbeo4EYyfB$_)qW+(p@*UEINX&;yNFE+E`-NIzF;pcBY-meAsU){h{y=4oGVI7ql= z)L~KKl38|4$)>c_z^3m7+^_I&8>7|T8D0BhMoe8XvMt>EMqX{h@6)d)^zfl+McSACi_F%-9#@z@ktvd3QOhVLdf8|pFT8&@{q2ZCZTGj)l9ZDaTd=~; z!UVwSOyv1g&P~%9`ijUypVVABCPR6|FEJL#^yBh+EIWL>Axn<)L|)1_H5cE*wVF$ z^S7Zl3zJ#mP0`}eS2h8dB;o$oT>cKHy)T;m8Z7}ty|g=va~&(FnWj__3wYpRR(nkU z%Vse1t0M$>{Kek>C|{#%oq7rS#4NNF5QDu;gV_L7{)^dw-DeCjdBz$R+FwaW?86MR zwo@>bVhigtv_N?XYcDQU!VCi;)3I1C7E0@Fmf<8Rr>b_!ANk{)06xdhe|!G4^OTL= zd`z+6C~*jIe^E0w11VZO}_`3CSRcS7vn|hLQ!ZmqbBOF$;rxF=Gby$ z?$H!iEP~L-v}RL@E~eSIQcTNHI*syk9!he!vI;CJT1+9))gcDaWU30+Nn{IA*QD2g zO9(JR7oB}Gb%^AC#D!DI@uq!$z=04RGGN0+|IBlX64Q679c=|35gAewx_ll_L zM^?x_MXz|8M4+m=$);x~vC)SSnbk133`M9;GEP=aCh{x3H+YE2%A_im#VXL^E~AW@ zdx5ba7)b}($fFA{hR{$GQHyCIgnW6-Dni*v)?`<}6eqin*TB|lBL1}nywp*8V=)iJ<24mp5EN7JzlGw>sG7g}3nTJ*R_>M(< znKuI^^_(d|^2WMFvZ%L~rb=2}G%+R3dv!rY8)o&qk~MV~u5t@iND!gSe*ae!@7C3-c5DF)4aY*lF5J^7ag7(yaf_pct-9$9>Mw4SpvAT3j`WOT(}&v; z`gZ?^G>F{DV9zPd{*ac8(_FbAK~@phsY&l52Cmsqn$ci%9N(^;!%F%_L?FhSg9OG zOZKtrDwQJbi}UndSU1GkFgxY9vJ45eNrB~@`|FbS`r)%^I3ymGb=FdnFn;z~jyw*$ z9FgKk_=dzTO3=7iw*MA4qKF-al^}}&F4=ADI53Aq&B{ZpEVu|FBy<>!*tv$rA%b^_ zkc_-TiMU^5FXNkn_xB*Z|Aas~2zbHYPGik|f@Eu)azlOqo zXLfX6<(^kDjGsm-DP8{3r7j1^g5T+OS7z0r1WOkt?UftfJ@gK}6@4R25g9$B^hymt z=&8lMqAnH6vf_4LQAt}&PuG9LzDyluh-J*8@ybkSQqBrPZ!nuplf8`%V2Dv~Qhzrd z)-NU>H|V%$z+xqCJMNO3rh>PB78_Z zR2=H4}r0_pBDHJxHn{m=gZ zB5F}=w1<16toueou+CUCA|_H})qq%#AM3;~EV?t#2pMe)qHV!xTQJ%dC1^vurM>J| z@{`Bs`+k=V#all9E01}3jVQ4B@n759tx}fu zgL~=^TGj)WWzY%%8u4IVR#4BI#q>NW5zG^wU%+U@(IVubB1It22H8lP$1j$s7&#AZ zdR@W=6c~4OjNQvJ|B0>35q#6!y#z$M_`18e8LCr;sY_sz%zB^-VdS|nb%OT^IOgP2 zO*m|+oLlK!SS)Ta1vaFV@wB6(lk_9z*-_&j9)~hWAw`2n`OK&+v2Y=jLdav<@oE$< z>3zfxFHwdRq4gMEO8$dm`3WAqMFr;g#To7!oML&OtV>V0AjaQ5@PgFL`C<<)+Qs5z zhP!p@4YPBxkeQ;#|4x4SBDk>`ee&;OuFF`NY?tR#f#QGccUEhc8Rii-6)Y$+vm@+vGiJC3H<+rx3Y92n{+}hr3@6z)|%WpKB_#D5tn*L^+ zF1Bws+Wszk3`MtEsBZ(lT_1q2Zqg)e;EUVC2bvnQ)!N!^ZV}ObtF_f=G3xwwV{3bd z;s&&v+kX3I)M@jgm^wZU7O@8Sy{*Uev zWb2JoL{GdSOe)SU_TG6g0X_4Zhl<Jsu$!`>^=chn}lG^+7wR?P!eu;yho(~RGwcPi_)3WIcnZ_T4H z7+;F)Xg4L6&D96mFL#($sIogbuP88e|5Y z+eK7idGYNRmiL|lkb^FZY3jA}G6P3!VEDt0AhFcxlDcor}v?ZZQ{ zLP$4H2`p9QJQ9Xb)?C|X##tk8!5c>P1gIX*c-NsJfPXI7r+;sE`L4Z4%yfFRLXycm z?n!1skJOr>O9Tv}T*9mp)oNY_471W{OXS63nY@U=+oy*Th%Q5o!9XZ^gUv*AX26=8 z!3}IKqH`a+puv7LUu)tZT@e9(KbO1MICI#Gu@&KozF5|Uivo|A8}0?0akwwYj~4p{ zaU52(o6iyRz?sZ&S7qXbcO>L0j`LH%@{D>f&JnWaB_Duj@@0bd)8k7_Bt{nd)ThqXSnbT%+HCf=vX0ANU1l54D^D#V^E!iem3Jf1k|(CRxL}&*_p^@J z?(lN+zYsAXRsFYSH|3$$IcpX%n$^Y6R=d5YNVPdvf9W#b+6fPTQ+Ov3THJVTlIHQ?awEwVLpNYNY(S8 zPgn|XkrA9_BCjm8jh>wM@aY53NFJUR*~A4$W_=k0YL>_zNTN$&F`f9(kw43-j#~-7 zO^GR%FlmdEj=dR1$tNN6kh*1kJz8XL*HHDXNta~>mJAtlX-Njf!%WHL+Tx)xPvxL7 zKl@zy#T*y4QIwVUU1M`A($I49(C_fJl2iIxBGAo+pj!}w?obda5``KiKyO93xeM_o zN5E<1L*0$gaw}rXO#~O+yi~lOjKhn-*iR&rx3?1kd86%wfn@I|G;Z1ZN#iE$>Z@!e zT#vuIt%M8#UvVoDL&9jetxeq;!(FZy1&B;q~{w`f-REnKo2gh&gLC_<|@!dC!b54O)#tOcrqKH z1cKK7vBSsg-p?_L_GRpNeq2G+5~`XPPbiqkyGt0va7uYzo6~5+Z+evj%Eqkxma5(y zst}=xQpXgj<6NyzuXCQuz3ml}lE=!a*t0m;)xg||M2@?f=XXtikwlmjIpNI6luWJCd+a;oI>!q_C( z0_4=WdixoO;n3ZJ1ZHem=Jbbfmz98jEEa*&Gu@c$ax}&mJa`x_*tySnK;29l!_iB3 z*kV3fNiP_NG!-o3%yz=}nz9roy;0bvtQHGn_Q! zDBZwGLny1aWT;xw9!0S*17?z<9>#GYNi)^OZWoQ;@7_fNx7L(}DN8CXIyEO`wk;tW zS^k0fva)gsPYpreI^6?8i;?l9w8sX!aVkn=;klvbhUn~^9sYWjs?0_4O?qxD+YQAQ zt!3N)-E$*DC}WAh=F?$__X^i)Bv>7m64R3DFq%~~aZJcxnF5*aeoq-dQWaOm^Wkth zi)$YLqAn6pB&E-En&M(9`vT-L4f2NtvPgrRS|E5c9q&)$W2I~Iiz8Kvy}=VdlDEC7 zxA8t<*D~p9KtJH5i8%G7C)WS%nWRU2S{lt>R%6Cfu}sbEwaZK(X84T?O@s zoh+D7@Jv}0zDyUsOclP&C`>)Hj#F}xDx;o2ul;lSw0{v+1Uz3ntm)H9lGk*2Z8V+z z{_0I%*oC28s(n`Tf1P}i?XQ}h6|fi#d?HPzmuUso6wg0%i5O+ARP#yF`s@Eesy=mNh7ID-&$|GMA0>_>i25yS9WZJk}v1p5BRpa$j_S<&|RQ zPUJPwI5TOIRz8okY(?Ai!eJ7+iGu}Df;fFP=1{63%cL}os*HU=PYYK)cs;3 z(JjgwYY4mMeG0ufFuLY6!uUPWq>p#;FDVMjglubj3~rq{Un?_PggLyY5sR3@Jn3XT z@P1zuW3MvG5l+1rmD*Uz9d=@@rR>}b1ALM4Yo`T8G$3WpcC2L25r^(C*SH2I)@JU= zrRPQgb_P^{+iEFm9dD|$>oZ!as%e&Mb90%Nmd4J&GjV6nd)JM5H~*27C4&c*o?SUi zg$4V}>plh8EYpF7cx|wzW0K?(9BU&~itt#QmrFFDpq?!7CFa87*5*P1V=6lr#AGh) zQUTa3*OeJ~v%s3A=YlA)P-9h&a8bZtt^pbK6oIGb0$2GEN%@e7|EvDY_>afWK~?RD zj4s!S^|*Ze$Ia$u%m0ht-fnDdZ^H-1e{8|u_xO+Z@u#97T4O(0&5V%vl46k_iBO~; zeJecT`Fz|ChQp0#@cDQ+?9d`Sn)JiO43an(_T|5||`VU=NQ)l`;E`o_D_E`rhD-vvoX z1;cZzF70*vA?BG@OMn>FIbgeF6^NtWhD@y4N4tLP>T4v}p9!h;aXFE9GAUq$B;cEfafXv4n@F2><3>OG6XVSnQY zHQ``9`xWb5Mx4D|r;4bP)9h z^TZ*WD$UV(_7@yLjZ@0=1A@UI{MDfkK2(EMeQO+OUS}Ufcc6=fNc2hiLF(#K&p3eGRNHd#O4Yl3mWjJjS_>dnz^(OPN94B!) zmOma3Xim6!9YYtLR}e(SnWSGV!erK2gy+3I6I{)%l4`7Gm;54VaOI7s)KLcq)arfj z$_&`aHXE|36a9QcdLZMVK6+HKUd(5L}q-Bw9LR;{{Kc=J3eBMokN6HH(|q5si;$3OD{@ zIDZNMwb8TDiopI!$ay2n0W|8)CbMA3lA~!UZ)8>={e=cEd3Cyk`AV79()#`0-qU|Q zeRa}({g3_oUlyJDIK49Xx=xLJ111axN5>q+wZ5o zZ*NdUo<7POS1>gC88wmqFS-NAQIIgEx)9rpnXU-2J|kt(dv57d5EzP?ay}aX9KZ!W z#Sw)o5o!5QJmL%i3Qp%UO4Q=w1SFE%DYEeP2`h((BH@b2gKO_~mV`SWNB^FO-RUf5 zI`yHaDzDI!y}j4da9q);s)Niri&2PL?L0l|JbirfbXCZY3TpkZ*RSMcUHc6>AgttD z99MPGh;3~;3zYr5qVg>|dwX@o&KJqF5VUb%&jVkS>{#cjdNIKzC7{JK3-%`1MgqK_^Jp-wE zO<^<5I2!rhq442#=iM!8#xeVi43M=2R3a@IDiD;N(iArYebJ~iR@^2t<=Cq z&P2VeXKX*btowxVE6qTu*4&gKgYC1fnFmAHEIa#D4LJ3L$g0^drn9W6hP9>u zg|wRzea@k}Q0Mi`zRk@A-lu3b0H!tZ&OuWfL0fBRDPXSp>VUu-umsh*3%qXpNSS~5 zBoW#EOv8g_X22R>^bhsa&k44snb(d2oJjvQagMt4BvgkXm|P&6bP2X}Wopu6?vOj2 z+{|e4GhXbZxpo}HpsmxcU{6SN=TeYW2_2#+qjyt*z0{ z9_mdu%s}2~f+=O^BV#>&&NY1Lke8()7u+9KxOLXzsEfgE-=0b&MM?AMq}8S0=~`<2s9GBfIQq^6_MXRaaQA$t;{*t)_w^yk`jB3k2^ojq@TS zyBx!ic{J6$_spuQuwRwR<<9xB?ibDul7S>PGx!-R>zX&P%EJC5_QpJNKCH+*%$D~z zi15j?$vi%$dx84&Z_6^kC2MLe`1+3~{O}uDGnMiwOP-v~4Mhs23U43UYiHs#AN!Jh zt5oaIt?-;&(mu~}S(M{XYimtT)8$Zb?gpF#jqe|qE6hg*Lzec2;q%MsWHx}=jgm6< zr3_n8XIatiaA&fE#NvzWJj2!2KFa}wAp^$^s=Asg;3TsHjyZhw$ z$i8pZ4?!}A_PLJkIH6UgbTa4wTtK70A9e8AwD+QK?k;A;5w6Lm6%~?RdX@**`XL6I z;eK5f1saNkF?c2bDV8}3rU_%0dGQ7 zmz!DkrXzNoYMq2kC=phwZp@NNTdOE#5Qu43XFUxF^8D&4G zd7v^8f(l+l)F6u}6m2)MYQc#KWvY=1iKEl7m6K1n%FdO_DjxS~dzFCka#@c{4Hu(gXyEoaGWEpScAWNR->*yBE zZRu@Q?2tf@Hzb0DXfG*rmoT?t&$Xni1*L{Fg9f!_mO`s_a{+F*?GVOODbB(aAo*e5 zsA?QeU0IGrmop0${G5V>;VFJDiu?kTFBlH#)^QvT!;b;ovqlw_b4cg`flY18T+7m! zJnqf76EGot)Mb11G3Q&q!R$ttPLz#}7b%D2u%FrnYI1Kk_7<*;BTxsbWX^^f8Ke^E zzvb(-YvA5y-Y`LAryjt1Dt20NDi7GedGOzFv8PC>IrIleu&Sf)2E*4NrML8IoxGQYO3rXw$b<%6p zJo^d7Zphpi-4*kNSE52cRiU3>VY)`FfYATWS&$lAa;RH|dWq|gG_K3*;yO*^T2z*7 zBpXjxz&6!<&1YP-qw1UdM z5}Q56QEw6&)$h6`ou za&X<`5Q3$bcH%Thi*g6R59MKfE5WG?5TFR5dNaj4^* zbE?$R)0&EsN4l)JC^K-;6^oe{n2_u_5%OsQq zKPM0o=KcPdpf?OILm>;`F?H2ExA+xb%R>XF>GYNi4>KgAqHF@X6d*P&-GETDO#;;n zo6-pSlEL|Fckh8&tyj4~tTGi3Yi#SGcahawJ21lNEY+hjl?E39UN-H`XNk#XgLjF}(qUcbSCRhbe>@4rL>U2KTmUM${>%!AtIPVR zZ;k2}>ADu>M7w8riB^jMFWmhz-QqDk=xov*4id&wYF>l>V-sovW#JsBdS_|BMlrLO zD$}g#vrkmJ1P-4OzEr&|q>*38`WDNU6cp3waRf_XXllK@=4$&=sC)-8OCi8Oftr%R zR|L^w=^t$FmTYir3^G$GN;WVydK=V&a?Og3W@-JprdKb7Q0lKW4Z9U&6{N^G3KQ~O z2)XSxr*aO?2(Y8Tk^_Od!z?_*J>w#T;WMuM3hp#(Woh3W^E4~%Cz`so?9q7--Lt2| zt|33{(mftsURe+LF*Lt(%0nH%f3QtrfR$i4yz~MViV(UIPq})NeyBOLn6Y87rW4_# z$-JVS`-x0ua7CuOsxy#5v=S4^W;F)IsIG_uj-#uZJ%DMx0mU+3-xwk z#K3hs^|IC-WxDoagUPE`PKU}=9N8ARe_Db6GCVxL=uWxR2IbFLQ}i+aPW$4BD#Vge zP|}Y{m)%ycR8niSN|6PuKI88y!tsZ@Ua<%c+=2apaA>{@#^k&MB@{1b?1AB=C$FfZ z9(NG~2kS>L@OXO0y|3(Rj64K{3VKZEwD>5tA1w3-t~~%xs4iHL_y^P zPHHn}kG3Hj+Cyj5_{qsTv&bu}iY2F8E_1>=~}9UD}0*It%P&LS7_ z$AZ+D2#OV%u^=+mNnBX5sR0EN)s!?Xh^7UnX~Ae(l%@$0E(A>rs(+zqS_qmJI!!o_ zxq%>K_KHg<8S@c^mM&qS@Rk_b662fR=c3iGsuy2d{A$?v9b=yZ>M{pXvLr=3+f3x79-owX#?}b7AJU(0@qk|C=IjgJ8XviuI@6pR=u(b@H z$Zjw~C?A$9lMVVS{F9PY%7JG?X~Bo}2+!xigyJSA8&5F?&+{~Vhk?FM9Oz}k zE}uNJgTFcg#Qp*s+@LUMtpBVij4Vsam3nxYsxTdI_JnK47WwZcFabB1Ei4u5mdB{o zL)4Cfab$$sg&oWINfcV~YL|@YN)bE%146pqRb1XYymu9nS4M}V`>P%chuMM`Z{LoB z%XeWH*kBU&&(7{Aa-?U6j`YgLj%1N8@q!PCBny25NIc|5eYsyq^SoyH4+GefP?N5q z2RQB+ai861#3G~aK)~vW&r)4PlBFb}tC3JCir~KH^?NA7lWq!*}w%lO$@>C?&J zjdbuV%&DBJMl58bEA{)VlvY#F|D*%G4Aj?Ti=G^(o}98LSJ`w9it=0!3c3f+)L4%g zJ*8oGr@tQ9d0EO}y(&&p%JcVV(qB)mHLaij%gAK~5+%ke7!D_&JPZdZBk<$nPm}lq zTR+GN&gX!g9p3R%1ve8wDy)>8Uxx$S-ZZK?7SC0h1>~iX;}C0VOv|Q}6VTU6ET;-D zpI*)r*KizcMI9*&Oz!9cj?IYRG?&`Rf;B>%q?v zzgbz+sH|yL)=XE{#LDoW%Vut6EvT$zSJpBrYnhd`(v`KaGW_SVbqlA6%-)_iDP6{K z?a02S4(o-1UG2PrOVVSp$Fg0MQBDV}D7pn8NCg)m$s^?Dfg<6Yg2^PK2?k5*>ykKk z>d&JaFdq-14#(9MSSlya{WT06`5ds-Jo-h}P4=7OZlXXZmk}#SM9$(ld?Q09zdLLw z2OKGIDJsIVEeqWG;}sR7Ch$(4`RvYd033Dnt{;FLJ7zL5y67+<`3RMB?s3J)kt7gd z$sjtP;brJ|%s-1c1Yy>oXVB1dUt|G)=Ci_iY6nGr)E!o0gT$aV&O~3TvYSe zzifS-`?M1r2k|T9)Roo8Xo{ewuUY`ypRMB8(K)r=uwMU4>Dy5zTIb1f{GFO7zp7w+ zI3+Od<_L4uOvJ1LO0g9`9(e1!yStiykySrd;3`?wqkR6DQAgw2bu_d(RI^`AKUX#z z4c0bodOnM06*e7KU;N)yIZJhrCvotJO>2~#eEwiH0SZ=)Q$u|Bi$NUYRfXIJ!!3jt zK)kkgE7qczz-+AQXw)@%X-$rpB^s>xC!a)n2zMtC-lFenn%JoWF@ zej4_5zn=lBGc4YSJwbuuN=$RW8g1nP)dzfDs6nK4h>XE7HHr+N+tn|e8ivOjT%cxH zP)=RLf+qzyDUIiddzq;RHi$ zo+(Py;qE32&y`CA_%Ve;8!gB1I(VLDI1nX8r)%JBa%wPqw)Tc$5L-SKhHsT5SB|9C zd1uyaH~7t%t|d3>4eNQI^bqa2HpBPa)ucN|s7TMl=wdL--FM6DBVlT`X&r;jd3fNZ zU_dJ7R47<%BEVYDWmmeUw%%M+4WPCS#ABFWGCAIBb2B$4fgIujHfZi!e=aWg+DZGp zFhQf+80#`0m1BVpH0hT8FJyqP3#6&I`+%9pM>`Hk708JL3tqgCAR~B8^m$hEZh2&D>+j(VcHu&u6}; z5$NQiU?3TIG7PUB>Kg1Nns2`gSC%*7tP_kc!ha@VTxrzM8$~sw=XCV`DWnmtNi$0IdJ@C%9`#o>XH@ZXrSY&L;4f=@rXt9=LI7b#3mHud7*5*D|OUsh5QbgYTJu_iTl@@3}OmX?YNW8=>FV(G~REJ6PjyNH}&aKrGvh^x*mI(R-Qi zoUPOG3+&pK2yv{B*+cf4CphEs8!w>2?dz9UM#1O*1Mek1tsxKD%fo}b@zQEym@0X| z*pWQskVQ+DHIkbz4_R-7Nu`D3fQ_OsAr8eb7_ z3RA_bs_plc^vnYK{3?&$VyqObkroS%jkzWajUHwKs`Llc{SN(|Yz`NbN&h&YI7mzh z*7Vp>_dNRi1}|nLZsi>T!eRgQIQxVwqMHmp>g?~?*X&a(jTYlr&_0DSX!x-#5e-R0 zoJ#oM3){)GBI;Quurw#(Go7G4K(Kx zb>Y874O_Fxxp_k<0B71Zr&$Emb&%fV1x21*xQ>PaHnjR?)d2ZoB|}UdXzMH4eY~A8bI=kUBPiDU2SfPF$)%Yx1gr)sx0JUL z-%`%rzQ^4HFFNs=c*a=&OR+bKtJ(bZ!-uvC3H3|7rk#&J)Yru*1qYp=MB@zVFvZS% zv~TPgn4n4p(s6Gb%4}he*od(JnJoaceze>Thdf)8PL)1n+8yBngpD!?b#pGxhDSm~ zbC`6c?51^vr%7$1)9iP+M^iUuT_7%J*uwg~*<=Q*L0i!;4;i5HIMCFk6>;13sJy0J>ow_B{?{?dt?ddpifG4yB!y!COt#5VOE- z9IZ7r=~8EkV8&_+$XPFmGR0>yBRA_3Y`1XrXuCn-8Zx()8?GdS%n~cfs{EGLlhOQJ zT~+y>Wqfoj?=s#QTGrm);Md6~_R{PC1Lk>jG0=giJ^6lWDFPaK1T@MJ&~Os4;&je{ z=g4Uag3Ix=D9q`vB8~d&A&X_Hy#7p^KgI`V>Q-G?)l6eMce0?M!di?-vZZrKbeoc? zxhCh{G)NMafp{fX;>n3X_ue*h%1q{>X)N7hD%9J1{V)L==sZl|EnfoZzVkHV{k|O$ zUK>a*KtTr?9S8lf?qi!o57N`~AR0oyRg%GEKJ1VGYX*`lc5D*CfK^vCuL@qdG$a{` zINXuzv~p+8DQ{(&yt;!h!9`Q~#WVm?AFD^X9Y4s(6S;hxAfRtLM zJL9o6OuY0I5wq7zVP>fNG4BcuF?)t+p+7$+9{_=;!}G{PRrt(pq(L0xu2dy zGw5HaVATQmhXW94kW|Ms&>G3`K+ziuVjFd8Y`x(oUepYQv*=Ug37|i+8X>?^-KlyL zUlr5m?8e+))Tu1phX$cOjk}_AwZy>Y4XasG>~}GWGHhdJeeyZh8jZ)8CAE*aEcml# z&Y<<=NN8TL$&@+e;43<^9Lb?GZh z$egN56<`*JJ}bh1SzTzMZm{2XaZbaQF0X^<(5Iy*8)(9n*S&O zKUKh|d7!~3K?8it2UHZ$_Z(mp(ikX7>e+xnzsKOfzprU&66B>tW|)s?|Hx{67(b&kShL-ysN^#NsW41 zK$TtGe3naPs_03ng2TxtI-2I>@?SXx@ScoTLjKGtGF4H_St0E~PBF}gg&C_(CMR5~ zgre5NoZ_!uJ>jsdr23s(s3V{|xnOb*)7M;3jR*1{f-Q>!qwaV%p9-G-3ce2|SI0Ms ztG_zIcleuF_8w!AdxG`tDIU8=3~rBeF8Vy(L)Ned>wb@x^d4WUd$bJqaIsYlYlD8+ zV@QzZ+ipV=h&M^(bMNH%$a@2O^kAQ62&(qUC>Rb=VeNS5@nqz^dc}G`K@5ZV!T|tP zY{RzPs&C@Px@rE(BHPa;+s`5U)g-@t9ixKBdA+#R&Q97NlWcqv&F4V z3>Xam-(@Y->UwT@1xo&pNcRap3x+gcOwMhzrC>-!z=j`6Q3d zx?6ATQw;%W3&}JfL)v5v&p!4Kz9NILmrUkyPc!_o-*r&@PAlsoRw{o;TTTei?U1%3Rf&FZ&rtIV zXT}2MC*K?|Fi(`%#jh})R%Es?ot}po^w{L6GQUF`*7(ogE7j|f>z5|?O3c%Uv_BrI zHT*ma$COz%p<&+fm{5b`hbyAh@Oq;RBki~o^rHy#!M)EvK20Umdi(w?D>bBbbms3M zpyQI5oFx7EXmoizNh*|Wi=FrIoLl0Diik|-j=X>zq7N`(<+9TN9W%5d3L7pgNHc>Y zEvt*Sw?C|rlM@$<|`GQS3W#C*l`{_8b$C-skycO zp}G`tKcpI0*;y8cJfQo5EYUxF0jz1-+U@0OOA~jE7Robrv0@3G?n9)Ls@hWq+}H9E zT8;|dp-3f>eT8P#lZVChOP&$auMftd@MoX>l&j)*eu3D#wBP(uQPYJWfMLu6PhBku zKmc!6boiQq*D8(|n&3)7MsoDm7>{BKB;j@7mqB-AxrVcB34&<|8S>jbI4^1RnmQBFpy0C zn8_V2-l!%}0b^W-DzAV+E`!UN0_2ARPFb#k9|}0-b;w+fUoOcmbGYSqW_iEN@|Kui z^Ol)kQ!&5hH^BV-t?O_fIxJ9?s-%1C>#@M{WR+ln<&j;N1(vCy1PffA(C;kpe+LU>7X{Im z5(D>5`e9NL{(Ac>+^Y~i_P>ft;WVD~!X#lX5(SQh`lU$0R1evC1C-g%h6p~n0Ptcl zFOCKS`}KT`W_7g7;{8hkqhq}ia6!LU1{*sbECcz1$1N^|JF%h21Cqaf^Mq>52XR$p zK@?OX&c#bqCP0fTm5?XIVraT3XHsB4I8C^-b&w>Fo+^MtG2Lt4s`i*2#-g*ThAiXu z+VS(>oq1XK%uP&%<#KJ@*d|jBp8=Zni1hdLhk4i3cUmu5o|4 ztA9r4dETc<`~eSy@#q7q;TO^j3fz%$&~ZBfMh1ANfEryDpuf=u*qg*Li;Anxx;({I zg^0(F`S9%Pfj0=^IJoroyf33}zt`&m()GhpckrYG>j{(E8xN0N4^JHrkkmr>{=Bum53r+#3hcMk9^0V(ksT=`hBN6Wxp1%V?~J72z$^F20M| z5%kFxjA)_1<2iPTcl1(}NW{q}{*EyoF5dLW?mcyNBVqK?STYQwXod?+Vye?MA8I*! z_oMzYL5lkH_TfW%uO^5-H{SL}AHqve3r1MBJBgzUJVRfjBKyLr<>=)zU~&Ua8@}bf zlUgwb{A-YeF^608vf&sF`j+C+W+!2(GhX2%F+G6}S1F?gR;p+8p|djBG0j4c`#k|J zqhh1ni$AI;Q9KFH6XN%8;7x_Pttztii2w>xv=r_D#A=M`Lre*gv-@pSjkt*i-~SO_ zsu%D>-cgP*6f6A3>6Qee@NWz^3n~j7S-}5|+&V&vE=$aK)g=@H!IC$>9uF_OH1nIt z{8@*>WNKEmYo=66TOPPf1*RtxMisjZ@z4VSGY(*?JNadT{Dr&=B;WjmVQ(k%ai0)A z?#-Z|g$g@G?NyBu$)MWrKdj%UQYvM_E^^9f+#OB&^I_Nx`xjPJKtN9`QjvNjDXrr^ zq?W4Gcj1d*!WL>hZktg*>zdoHnq$qZm5;-1S1ZsOn})PG%tlizh-HBJ*04Tcwd}Jg zu1p!wAT2LH#A5EjB<398!1HnXMoH(FV49k`LTEPwKHw9Pf0xPZ)_Zs=-V3o^chOLu zxk_Bu-s_IGLQdCSD~DZOJl6npp2l9v>8-@{4EPu17Ggr5WWk=8kX&weL-Ut*iEL8X zyA=FMCUlA#L%`1}W&mYj$fHt+$t-_TSo%cGPjQb`O3YfcbW=njO`A_h;m{+03Xh(g zAfA?7vjn>0Am$=64lIy3zks3dj&zCbIAt%<0hBmuh0VqN3j4$}aidtE_IS_Q<3B~Sf%jQ}8vVtLNvT(Vh*yi$ zt5fkxw-AX@a<$8{ep!F(>+7E6{mPG#$M4YlpOrQq|KWb@BvB4@W+c{ZLzPrr_?1U% zs{gJ}^gk-j+yT0b|Hx|^sRJAuii*MPP*Sc|mQYY+071=yscRW5gi+WR&(fwNR*>J+ zspxKlA~YUJeAOJolPE0r!~Bvg6qsIZM+8=K*3YfJDHM9$C(@@qO~tyO&K08DWl(B4 znY?o}tAkFHuI_EYKf4W}+}bb=;9jRme&rgtn$9k|8aJQ|J<0t|pK2?l z%O|=t@O-+OH=wJvN^P%s?cLo%x>~Hi6u6+vMVPEuJr0*I?-vmcx*4iPe4p#GG)oYQI%mNi2I%dsT z^dXNSQ#GO{>D8I>6kUX7gib0~bbT2D9Y>2xkEOr-So${^OTX+``X$HGPj{8Cb(MeJ zvGlJ$mcB8TQMZUO|me{@Sc=a z8{kyFKCNgc{z8=Q2*bRV6_txFp9T@k3!EW5l@^;oGteu%XjYi8sW^zN6~9x&4w`kG zL1OK=ta|7-vne0;m&_Sz6xZWPJ3U#HT3Z~2c^ZcwMK~K@1mLw|0>6||;bath{4-4M zG#?{p@L+wG(Ive-X|Qv5w60IQRfx~6jj`H{vY;?wJ#g`Y9%fVa4O zD5vI+L?+BIVEczaC}phFo?)(rTdb1~S2=g=*T%~27QA1{F z+PHb~(`5@QJNX;w8DMVr`V{0ELSIs;7JpH|+m%d7(6wd>Oqv4ed2kU#6f}T>e~v?# zTp+oP@$l;%NOCC6&BtPr>cI$;m6e<%66K^o`$Vdgm{lZXWs6uZObIJXzH&%cUskdu zE8T6oNUCz+@eAid64FzNqy$SyO=%^lNM5?Bv}CKD8PzyWcb3zp z^)6Xbqb{LSXKU3zMCTQ+l=$UU(^vD6kNlvEHa{3LO@+>Mr;|^r0VrRIW!uD4UG?@4 z_4W^Xi*gV)zL~cTCi?j`0?{+IoL%$YT7E$I4!!-*hl!8!aNj zN};Uo2oaE$G)+V)0mV^_npSPn?$W$9t?GyS6v}SNG`7^%X4%F%A{QQQBXP$v zh{5|qjEH~x6<^aRM=_pnkr+NSDK2|MSyE%Ca%p7be$!Tt$uvFJs&U$d@u+FywD>` z;M}`L!RNhQwm zN+}86J{UOE@)G|E&jm^xs{Ejz9h5NCu4t=~jDIK`F=>)rOPt1(;At}Ace0XM)JyjA zuFtAv0pE)g|5%%hEM6c@B&l{ld08#D17wxj4wrT)8~PwB(yKWW16u| zEcO`-O+^rcL$3vj@0AFjYKU^B@AhjdFWz}VZCT`^OgY9n?B=&uE6Ci3twwLeYd1Ui zHY*k^LT{_(O?ZNQyGOHzyOq?=_gHRKWWzF(wD$ALfP-oeBGwL$1j|^Lq--@0J-&&+(Cx9ijEk0*GlySp?F>6U_x%$LmH-_b=r@s<6 zmo?8L<2AdxCjr<`6Xb=~1@yyueWG5T7_UTn4Dp^{&of|HP7DQ+!jG9SwAZd0RPqT0 zXk58V)tFbpK|wA!qiDqpWTPEQDakQh z1WI$2Q=g@vwa|->^^`4Mrm~rD1n(63SfrFJJ-G-r|?vb6W*KH2X zEUn!)&H2FbZJ>h?z6bDRfVtSMPP zgqqcqcry)q(fQ>+!plmJM_xfNEu;a)We8IVMKnE4%jesTb)hId8jLc%z|<7AQbVqy zXGriz_T_c?<{_|nZ;g_c7=4hYbCFf)!VJ=4#9rYg$>rd0>}C?P<%IiM{0D;mG2?Ke z>bOsm0A=2I!jBw&bS`cTHWLhc^C2criDfDwkrWsNXIfy@baVR!Lt<)(wxnvJvaLkf z!{)%MFJK+3NFbU=Val!zPyzM9T=BB~sg9R+*F6PhRhdAM4&H zJVyeN5ZEnqf}D(pmkcq+lu>ACkL-=4_ZhqnX5Ij_PMERsA(qZU9(e4^9x@HmeEV~Z z!81{{y^F>=-tola!MMCRhG&yraS5+t!+n(3@AZtRU|NK)Zg6n{(hBD7!PqR7>Xpsm zFak`s7bLSsC(oN}hZQKOqKdIh&s8p7h*ewToTKK+RGPV%j!R&QwY;sl$WF_UwJ3p! zcXd84Gs*?>TV_RDBA8rxi%0@fh=pgsxg~8)g`v`J%OaB~lZ=NZnWV@ZbEBI2a!1pe zYHfUX(Lz4%vQ9@VJi74wOE`PVesbU1T3!j?QNkGza6E}e!4TTzO~ZJdNe4wNjeN0* zYh28On4}P79e_|`)50+&6-gos0S5)UqF@&b8UQPqZsuPE-=#2hc(A4q8cS<8#&D99 zfHnX!J(woF4@$U2a4l+`HM+o%lvpEUt)(N@Ni15#IxS|MdacE*Goschen)tjB1CW3 z4|SA6BIgOxIfTIK4uT@3KKQbtMcrjVrFh5{7HPzcET;oAQ!Xljb^$5t3;%8;%>^iA zaR=Ux8*9hF*>Pg*xbU62@tqp@PM!Epb$luDSH%-G!l*bRerjB}RPdCq5h(cSxStLW zys^eZyRL1p5W%p#KE?1lBiP-F9+J)6(2XUk*op$U0bh~fJf4H@VJ@KpmXne=jJQ*I zyvS8jiqgP>ppPg)Hc`#`ECA9i$&V)0d>s9I9(Jd*_z@L3awe7)>;b&fIdICUfP3oECzJ%`G~+ zayy6)+$X$)^~2wAe02Y$D@UkrefozVgW)_#%kr+%9yCFoPniFsIQ7B(SQ{A?-^rjv zi%o7m?~?#(KaKlw`jG?9`7Cxm^t&k9<2A}{IUUz`?pFDj62)jqW{`1Yr(+-Qeo?V%0r0+j>9;~j=-|cJ}iQLNtHc?x>N^e zMf6=(aThBC6iOD!5p#qW#dp^_Wi?YlEb3Wi(a<}U$4$QT{(M9AIQmjWC%%_%WYt~2 z2YLKqy$eOe={xVk$E+epCu+f#@1+-ceHq<&{2Vd9m|@OukWPW`$65{+*3Z9ACX^Qe z#aCqGPu`r6J%EZ^`$az?5>cDK90wy|lC$9sD_Bz<2jLki=9N_o0f${^CmVQMg`uy~Bd%{| z_79S}T>p@9s8k1SY+Q*RFlH7INRvwt%CV9q=3E?x%H@;0vnykgg#YLt3e32@zwADP zjrV!?$%|*tpwX|6p1xr#@fNGoq>0SxXlT;asVQuA5=?RGBr(so`$fmR zc>N@p1&9<{&LqymwRB0Xw;0{7a+NeCS%VADMX^<-%M6ZC?8-{zIqGy?clNxaVEkV*7GJ_u$<4*zwPp7|Z>`+^=iPJz%pe60?%-TLihP_ z-kWh#o*{(t=87V8Yke{fJ@`PoaM;HTTey(UhnM&@pd+%Qm;99MU64f347C0R)9ElG z+bY3>RNSML*c(6%E5hS|h0mGA_(oVbaea1SZsB+r3hU2QOIG)#x`1oyrg}n(9G&rr zvpLPa&rBz}I7$6r9k-Q}C6^T?y_6)GapGx&C6)^mNm zi4GWWq7)4x&N=FTmb5c9tBo}${Jkwl3+%wHf3ngP)tl(!Z zum(N*m^!Ir&L;GL!bQ(ltvm`AQpvK-=92#~nP5PwDbHBt(fvXvC#iY!gn9AEg9~po zAI_#|WTEqZebMUYOO%$cQid$4?e<`W%<;_WGw`cnG(wMks5wHjIW*ijL93Am5RitV z!O8O`PJdW((+PQlK`BfrDESl%!Y~~~ENdJ&A>&ty#*5#B&*T`z9#_2$_8lwQcOVHq zOC<31VHqSAmRJxHOEO|nK9;3p7Xh)TK9-ed7ZtLU@GGMO!R~1Ec54@Jw|!~)+x4B+ zdb7s9)K)zAU$fc5*YLT^K3kjYv+eWGZT7jz;Wjzk7KhvBaN8Vihr{h~xLpRyV-uPIa9QMSLg#N`@m&VK)!3|W!tX7AtG)@Oee@j4Ocq$kKy$!#5vnH;v!zMr+r6(AwNF zA8c)JnGbe%H;o6IEx)ZEWDOPkHR{bR>^1n@ZEfRctBI2VK4F~cb7!}OpD^8;^ts7? z?!Xkq@In3-72j;{Q1Q(jTsn>Vmfxh}TkST%1Ibi;yRqZv6SUphCCuB~jIiyUO~SO} zZxbe{*r(4O`q=fG1issD6Zq~n&OTVdjh#*UY&Y8Uxs7YgultR*PoFrs;A3lhH;*2G z*xlVh$R_Xu`rK*}V&E!-xYgLDk2e3@ZW0(&OBJ+RTLj+T+9B}GMx#lettQa{%ZfgB zH>o%*kL`SVwl;SO@z$}H zZZ!ye7g=4i-e|UV=yMYnEqw0etaaqwu*i`4!6z^h`rK&|rY6gl0gIFnHMe&Nam#Pe z?^YY>g3rw@0&mfHHi-wozneZmw|80uz3Fcf^ky4oWiC0J+q*=@mhTg$t#*s>Zf)a) z1yrIeD3aS;b*heAk57z+7)1;wW&M}B=YQSDh>;i ziUYqOa9|Sz4&1@dC#bzk2sUZvBJ*z&BH-9m!B!JzEPQV65aO-f1|i;VHi>@Ta9EdA z9M&ZjhjmHCVH~OWuFvS&ZEok2v%9%Nh<0~zX0%}nVng9`6K5=Z?%)!E&B(_Y3!j@f zV{vn$pG_aP3;1krQgK*7R2*7I#anHkinq3DSA_oB%*RH&J6h6Z4vxdbCck= zHn$0WYljHfZZ_EGW|N9<@3gn`3EJ_u2=PvPhY;`VGzc;54TKo>2Kv}0fdrTA4t+Lp zX29nr3K;OYLxM@2RyusNcL?0yX%IMUfb_iCZs!geKy2fT75nd%ZfoHg#nJQ4l~r7x zkxtmf0!sPIlAEwR)Bm1_3HkC%YJ>_;P3CFxo)7DWS5di+zeTJ?TXLxDFh>*Thm+!t>Fh13l}g@ayaN@I03Nv-yGGTPr+w*8%(x4-ih+JBnS{?ldKe|q!wpWc7_l^?0y1L}?HgBR&O z;MXdy)%YdKUc1#QN^922&t3E0x3TD(sCjWU6!qsCS6e+fu8szFQVr}Z-N5@=)z@m^ zX{v#zOE>VomhE*Ks4dQdW$Asbb(z&HJKn)PInu6toPg|m84xEN=d?xsZFr5B#Jd1|;NIAk6 z<5FNhhcK35O|kdM*-;c?j_S; zjGn@QN)^jcV2@7YE?WGdrCn899Kez#xF;mIyAvdMaDuzLy99UF!67&qG`PDnFu?|Q zclY2r=yG@OKiG%vhyLnRS3gyCSJx>gJ7F5>9R_$%>^oB)#zY+qa)ZpQIE4>KR`MwN zLTnYo8$w325z-Hsh>KN%=oQkos-)4Q?C z6NPNd6LN%SbQRE3VaK^9J)MjA?SUV%!zdt?jUYZYj||fw(kHn)KvZe%$Px7v+l+6_2kx;<6>F!q_;wo*(XGa&t|5W` z3KWXtUSzBQTIqn?L88pWA%&-c1*e^oE51~lDAN-O^*3I_`39{ZMG*}zfiq#D2%q&X zVKbK0lX$_pow%*GV_)L{h1hS~sH%ez3_XV{pulxATuAht9o&vb)pc2Z`19*?nzWF3 z2Hau8y%nW8k7>Va#=0~d*ezHM{esiW0i8tDjRscirCjFGf2Qp{SS8Eu{yWLasFj;1dNZ7fg&f35O{q$M5i3MBi z2JOHhGxr9X6t`4nTv|+l(ARsbr%VOkTBaZ8^Ot>AaAEC6p(>okEZYRvvSs%^Je6=} zbB;|bfi{hVdSjAb0vuabG8KH*t?eBgdp*H%WO`#&cl$_fp$S_k^yTwAJmwTif*^UU5FX+xDS_6yIZf46 zo{VCBGWin72&n+)uOG=OZ1Kg91=Lvt!ck%`LsI4UwXuw#ZCyNH-|CXo#*IBV7rxL_ z=Lz5cWi!G@$nPNyXsi4BmCG3^coNA#V0Uu#nYz~Xi&0!ZBK0@evZCP!&rO?kjh;i# zP3MxLA{*QmdlF8Ul0n(w-lbMUCil3oBLUl$wXLZM%b5Br9=hTu= z7n2IpW;f(}r5c7CN`?1#jMq^2X@36xNV1QY5x5Kw0u?bi&@xhfa5$+hg2~;M-kUu} zdtUu(vv>1dTRY?6c!Ax^g#zz)OjGST^C4ZwO(=h3#Il3~$|2Vd&j>j*b(NM$*_0%P zp1IO$#7tx&8+gEzMlZH5&a0{+$Wce%gYND^A4&S18KeJmzXVlHe+5zE^aC=P++`&3 z*)R8}b<>Z_sh2BlzhAHVD+cIT4Z*|UoPgeyBi6Hj9*??}1fM`bM{6*STA||6+RV>Xzr~ITnTupKIE`WO{f08$av)>I=SoDpH&O*y2{C z(3krFTv$qLt=L~XvS_l8Lr=gxdjjgdD&D_@0KG*|pXSQ+u9s(ZL;*(TT{~2I#;Y}b zu?cqVLhTzb5pBZlPk)kUKEC~S_;nV*J9ZTDChsY2CA|1GQOEIZ)*(?fOw9wgF*t^M z>wdT#>d<5jC z57N7*US7)5)Ox~Zg!f_Jhie}$U@8!rCPc)NRr`F>bDSjgeWM}=nzSfR=ZHxC3==GK zhg%;ve>(Pk`=Bx(EkkUu38|Bm(DppCH1ZRjI{J9?nL{6^*S@dDvJ8!YjqB7IOqahw zh~jx6HMfH__WthkHxqTL#0pV0!?4aAz{`MXUfx>(t^6@vHPA^g+nu1yK9LxouBu`S zeya_r7*+93)0Oy8EFrkL#PhQs(UH~0Sx*8&BQLM#3M`1rI3&26T&V<_arr1^3Hmln zVUL(3zQ=6C`A_o)xntjOkRN@JVhJLcGu$Nj(-@34_px!%6%&6OBrDQ513%d9{z|yO zAKDrkFe*usV{l|OJZgaq28Wt$x@_9uM|XH9;tBQD)qZ!34<$|bmf$_P`Nq}_X!3*zl70T@S)uJtwMoC zQTd9eafdED*r@6PUfI+?+~iGxl^hI>?rQp3YJkRqSoJfoq-(~SOJ4AmTOS2~$E8I{ zE-ciy^V?WCbA)0lTk7sn1-6m?sF9wXE%%n7f{75rq0^9ihS{$c4~p2sf5F?lurTJc z_YA-6vNEi)d1eeQ))a2ca6@IKj;l!G7OlEk5G(#ENH3K!-ER`UPuALUKfJV-%u%CwYn&6x<>spuJ7nM*{i zohXaG=C*#yo2C%wQWF2yTdts6=c!%p@@MBZMl~nX>h++?n?q+lYAbl>S$t)ha_{rF zy zQ9UN{s%vvt#;_(dlp`Uil^Bt7Z)f+To3^@bfyV0L`xV0VouM*>;*X0o^?2Nu5$3k2 z3tP?~@i71-(`-Cf6Ct|dvZ{Fie$l<&c#t<0=`_wjzCT4^wu|g=9d^~WEh!$3(}@VV ztX?>EY#ObJU<7>Vf0Iu5&*;hJCtl)XxSE^&K2~bl6VbxcSt?IwTw}wj zwWmIbAc;=VL#AzPoz!8PpE=uFHEsZA zCOyX7Ey4Z>#CB*|9LIDMi%D}v()_0gSWU%!uGZvm`=v_6-OwpEhiJw%TOK^)SE0pR zODtPzuYQ71y68_uD}sGBZ()J8D{S&-4 z@OBi4l!mj>gCe!rhA@_H{c$kR(qdcX{cUB;mu z@So`}bqjBeqV;b1D$5ajq%uDkrRMTF2VawprIdmzBK ze^35+E^qsT&Qu3D8CG~oQZq|?6aPMY1lSzL+b@^Z#G<6b`D!bxRreznKRQBROqMDG zdIvReHjGOo8R7qJ6FcB0)Cls79{MI@I|5<4W1VP42f&MiFmP5XWYNHMn zz=1B_y9WRnHS`HOKvE8_>?GiZZ|WANevtajDSR{G!t7Gmjn(v#ba#xCvymii3$Vz# zG>vkOw|0?dSnJ@OYcVrDPunuZd7&s8&NA9`xzJRXp-vO3sD|K|m@iat1vW-Yx3)8NOsHv3GSp~&ifX$*UIw@nb$?m+ z{@7`;WHfLW-)c!Vu+LEKL$trxniCq;U$DM*6 zH4fO$j0ISRB<=bSQ=bF1P%DrBrAQi^(+T3POz)oMjIcUF1uzJNldqsUgm55cw!TB=>9F?8Wa4Ug zjq`B7YpPgzdrS?P<7F2uN(}Tf^Y3X(STSf$>Evj*ap*{t2vi)VnBipmX-+W=(DU=f z=8vkE6eRb!CMv$RMV2YxWre#9XNR{c(TD^$JnjIJRReyBqh&Uq4W zG+exP!}j-o$%0Dv?<#FMI;J-d9YP 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 WxBu^g=hOWgoKews4U9Gs%>Mww3R~L% From 7259aaa6b54d4f23abdb88fceb9c7d3da1a26adc Mon Sep 17 00:00:00 2001 From: Chris Platte <123033602+cplatte24@users.noreply.github.com> Date: Wed, 27 May 2026 11:17:16 -0500 Subject: [PATCH 549/866] Update offline/packages/tpccalib/TpcLaminationFitting.cc --- offline/packages/tpccalib/TpcLaminationFitting.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 78f4e4a3dd..d8a8c94291 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -396,7 +396,7 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) { const auto &[cmkey, cmclus_orig] = *cmitr; LaserCluster *cmclus = cmclus_orig; - const unsigned int adc = cmclus->getAdc(); + //const unsigned int adc = cmclus->getAdc(); bool side = (bool) TpcDefs::getSide(cmkey); if (cmclus->getNLayers() < m_nLayerCut) { From 67b32f93f88f58e8d7d02892a1020ade4e83a4a1 Mon Sep 17 00:00:00 2001 From: Christopher W Platte Date: Wed, 27 May 2026 12:30:50 -0400 Subject: [PATCH 550/866] Changed paramater seeds to be stored at TVectorD rather than in TTree --- .../packages/tpccalib/TpcLaminationFitting.cc | 17 +++++++++++------ .../packages/tpccalib/TpcLaminationFitting.h | 5 ++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index dcbb70b481..ea0413474c 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -350,9 +350,9 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) m_laminationTree->Branch("distanceToFit",&m_dist); m_laminationTree->Branch("nBinsFit",&m_nBins); m_laminationTree->Branch("RMSE",&m_rmse); - m_laminationTree->Branch("A_zdc",&m_A_zdc); - m_laminationTree->Branch("B_zdc",&m_B_zdc); - m_laminationTree->Branch("C_zdc",&m_C_zdc); + //m_laminationTree->Branch("A_zdc",&m_A_zdc); + //m_laminationTree->Branch("B_zdc",&m_B_zdc); + //m_laminationTree->Branch("C_zdc",&m_C_zdc); return Fun4AllReturnCodes::EVENT_OK; } @@ -580,9 +580,9 @@ int TpcLaminationFitting::fitLaminations() } else { - m_A_zdc = Af[s]->Eval(m_ZDC_coincidence); - m_B_zdc = Bf[s]->Eval(m_ZDC_coincidence); - m_C_zdc = Cseed[s]; + m_A_zdc[s] = Af[s]->Eval(m_ZDC_coincidence); + m_B_zdc[s] = Bf[s]->Eval(m_ZDC_coincidence); + m_C_zdc[s] = Cseed[s]; m_fLamination[l][s]->SetParameters(Af[s]->Eval(m_ZDC_coincidence), Bf[s]->Eval(m_ZDC_coincidence), Cseed[s], m_laminationIdeal[l][s] + m_laminationOffset[l][s]); m_fLamination[l][s]->FixParameter(3, m_laminationIdeal[l][s] + m_laminationOffset[l][s]); } @@ -1229,6 +1229,11 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } m_laminationTree->Write(); m_saveAllLaminationHistograms = true; + for(int s=0; s<2; s++) { + m_A_zdc[s]->Write(std::format("A_zdc_{}",s).c_str()); + m_B_zdc[s]->Write(std::format("B_zdc_{}",s).c_str()); + m_C_zdc[s]->Write(std::format("C_zdc_{}",s).c_str()); + } if(m_saveAllLaminationHistograms) { for(auto &i : m_hLamination) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index c952706773..55648462f4 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -152,13 +152,12 @@ class TpcLaminationFitting : public SubsysReco double m_A_err{0}; double m_B_err{0}; double m_C_err{0}; - double m_A_zdc{0}; - double m_B_zdc{0}; - double m_C_zdc{0}; double m_dist{0}; double m_rmse{}; int m_nBins{0}; + TVectorD m_A_zdc(2), m_B_zdc(2), m_C_zdc(2); + int m_lamPhiBins{200}; int m_lamRBins{200}; From ec021e1de45c0cc28fdf9bf0b25cd0067729366d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 27 May 2026 15:41:45 -0400 Subject: [PATCH 551/866] fix propagation machinery --- offline/packages/trackreco/ActsPropagator.cc | 47 +++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 6170edb2a6..946bd8e896 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -10,12 +10,14 @@ #include #include -#include + #include #include #include #include +#include #include +#include ActsPropagator::SurfacePtr ActsPropagator::makeVertexSurface(const SvtxVertex* vertex) @@ -146,11 +148,17 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - SphenixPropagator::Options> options(m_geometry->geometry().getGeoContext(), + SphenixPropagatorOptions options(m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); - - auto result = propagator.propagate(params, *surface, - options); + Acts::ForcedSurfaceReached aborter; + aborter.nearLimit = -10 * Acts::UnitConstants::mm; + aborter.surface = surface.get(); + options.actorList.append(aborter); + auto intersect = surface.get()->intersect(m_geometry->geometry().getGeoContext(), params.position(m_geometry->geometry().getGeoContext()), params.momentum(), + Acts::BoundaryTolerance::None(), 0.1 * Acts::UnitConstants::mm).closest(); + auto distance = intersect.pathLength(); + options.direction = Acts::Direction::fromScalarZeroAsPositive(intersect.pathLength()); + auto result = propagator.template propagate(params, *surface, options); if (result.ok()) { @@ -160,7 +168,21 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, return Acts::Result::success(pair); } + /* + // try it the other direction + options.direction = options.direction.invert(); + + auto result2 = propagator.propagate(params, *surface, options); + if (result2.ok()) + { + auto finalparams = *result2.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) + auto pathlength = result2.value().pathLength; + auto pair = std::make_pair(pathlength, finalparams); + return Acts::Result::success(pair); + } + */ + std::cout << "There was an error with both directions !" << options.direction << std::endl; return result.error(); } @@ -230,19 +252,22 @@ ActsPropagator::SphenixPropagator ActsPropagator::makePropagator() field = std::make_shared(fieldVec); } + Acts::Logging::Level logLevel = Acts::Logging::FATAL; + if (m_verbosity > 3) + { + logLevel = Acts::Logging::VERBOSE; + } auto trackingGeometry = m_geometry->geometry().tGeometry; Stepper stepper(field); + + std::shared_ptr navlogger = Acts::getDefaultLogger("ActsPropagator::NAVIGATION", logLevel); + Acts::Navigator::Config cfg{trackingGeometry}; cfg.resolvePassive = false; cfg.resolveMaterial = true; cfg.resolveSensitive = true; - Acts::Navigator navigator(cfg); + Acts::Navigator navigator(cfg, navlogger); - Acts::Logging::Level logLevel = Acts::Logging::FATAL; - if (m_verbosity > 3) - { - logLevel = Acts::Logging::VERBOSE; - } std::shared_ptr logger = Acts::getDefaultLogger("ActsPropagator", logLevel); return SphenixPropagator(stepper, navigator, logger); From 95e32b99ef2ebd4148a7e47ac36e568807a690ed Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 27 May 2026 16:16:47 -0400 Subject: [PATCH 552/866] clean up --- offline/packages/trackreco/ActsPropagator.cc | 22 ++------------------ 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 946bd8e896..1d403d8ae2 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -150,13 +150,9 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, SphenixPropagatorOptions options(m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); - Acts::ForcedSurfaceReached aborter; - aborter.nearLimit = -10 * Acts::UnitConstants::mm; - aborter.surface = surface.get(); - options.actorList.append(aborter); + auto intersect = surface.get()->intersect(m_geometry->geometry().getGeoContext(), params.position(m_geometry->geometry().getGeoContext()), params.momentum(), Acts::BoundaryTolerance::None(), 0.1 * Acts::UnitConstants::mm).closest(); - auto distance = intersect.pathLength(); options.direction = Acts::Direction::fromScalarZeroAsPositive(intersect.pathLength()); auto result = propagator.template propagate(params, *surface, options); @@ -168,21 +164,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, return Acts::Result::success(pair); } - /* - // try it the other direction - options.direction = options.direction.invert(); - - auto result2 = propagator.propagate(params, *surface, options); - if (result2.ok()) - { - auto finalparams = *result2.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) - auto pathlength = result2.value().pathLength; - auto pair = std::make_pair(pathlength, finalparams); - - return Acts::Result::success(pair); - } - */ - std::cout << "There was an error with both directions !" << options.direction << std::endl; + return result.error(); } From 369e42103fcd35b143807380785c9053f3ecb5dd Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Wed, 27 May 2026 23:19:27 -0400 Subject: [PATCH 553/866] get mbd zvtx and track vtx comparison --- calibrations/mbd/Makefile.am | 45 +++++++ calibrations/mbd/MbdTrackVertex.cc | 181 +++++++++++++++++++++++++++++ calibrations/mbd/MbdTrackVertex.h | 68 +++++++++++ calibrations/mbd/autogen.sh | 8 ++ calibrations/mbd/configure.ac | 19 +++ 5 files changed, 321 insertions(+) create mode 100644 calibrations/mbd/Makefile.am create mode 100644 calibrations/mbd/MbdTrackVertex.cc create mode 100644 calibrations/mbd/MbdTrackVertex.h create mode 100755 calibrations/mbd/autogen.sh create mode 100644 calibrations/mbd/configure.ac diff --git a/calibrations/mbd/Makefile.am b/calibrations/mbd/Makefile.am new file mode 100644 index 0000000000..850ee853d7 --- /dev/null +++ b/calibrations/mbd/Makefile.am @@ -0,0 +1,45 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + MbdTrackVertex.h + +lib_LTLIBRARIES = \ + libmbdcalib.la + +libmbdcalib_la_SOURCES = \ + MbdTrackVertex.cc + +libmbdcalib_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lglobalvertex_io \ + -lffarawobjects \ + -lffaobjects + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libmbdcalib.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/mbd/MbdTrackVertex.cc b/calibrations/mbd/MbdTrackVertex.cc new file mode 100644 index 0000000000..8d48427663 --- /dev/null +++ b/calibrations/mbd/MbdTrackVertex.cc @@ -0,0 +1,181 @@ +#include "MbdTrackVertex.h" + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +GlobalVertex::VTXTYPE trkType = GlobalVertex::SVTX; +GlobalVertex::VTXTYPE mbdType = GlobalVertex::MBD; +//____________________________________________________________________________.. +MbdTrackVertex::MbdTrackVertex(const std::string &name): + SubsysReco(name) +{ + std::cout << "MbdTrackVertex::MbdTrackVertex(const std::string &name) Calling ctor" << std::endl; +} + +//____________________________________________________________________________.. +MbdTrackVertex::~MbdTrackVertex() +{ + std::cout << "MbdTrackVertex::~MbdTrackVertex() Calling dtor" << std::endl; +} + +//____________________________________________________________________________.. +int MbdTrackVertex::Init(PHCompositeNode * /*topNode*/) +{ + outFile = new TFile(outFileName.c_str(), "RECREATE"); + if (_treeflag) + { + outTree = new TTree("mz", "MBD-TRK ZVTX"); + outTree->OptimizeBaskets(); + outTree->SetAutoSave(-5e6); + + outTree->Branch("evt", &_evt, "evt/I"); + outTree->Branch("mbdz", &_mbdVertex, "mbdz/F"); + outTree->Branch("trkz", &_trackerVertex, "trkz/F"); + outTree->Branch("ntrks", &_nTracks, "ntrks/i"); + outTree->Branch("nbz", &_nMBDVertex, "nbz/i"); + outTree->Branch("ntz", &_nTRKVertex, "ntz/i"); + } + + // h_mbdtrkz: dz = _mbdVertex - trackerVertex, range (-15,15) cm, 0.25 cm bins → 120 bins + h_mbdtrkz = new TH1F("h_mbdtrkz", "MBD - Tracker z-vertex;dz (cm);Counts", 120, -15., 15.); + h_bz = new TH1F("h_bz", "MBD z-vertex;z (cm);Counts", 400, -20., 20.); + h_trkz = new TH1F("h_trkz", "Tracker z-vertex;z (cm);Counts", 400, -20., 20.); + + // h2_mbdtrkz: THnSparseF, x = _trackerVertex, y = _mbdVertex, (-20,20) cm, 0.1 cm bins → 400 bins each + const int nbins2[2] = {400, 400}; + const double xmin2[2] = {-20., -20.}; + const double xmax2[2] = { 20., 20.}; + h2_mbdtrkz = new THnSparseF("h2_mbdtrkz", "MBD vs Tracker z-vertex", 2, nbins2, xmin2, xmax2); + h2_mbdtrkz->GetAxis(0)->SetTitle("Tracker z (cm)"); + h2_mbdtrkz->GetAxis(1)->SetTitle("MBD z (cm)"); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MbdTrackVertex::process_event(PHCompositeNode *topNode) +{ + EventHeader *eventheader = findNode::getClass(topNode, "EventHeader"); + _evt = eventheader ? eventheader->get_EvtSequence() : -1; + + if (_gl1_trigmask != 0) + { + Gl1Packet *gl1 = findNode::getClass(topNode, "GL1Packet"); + if (gl1) + { + if ((gl1->getScaledVector() & _gl1_trigmask) == 0) + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + } + else + { + std::cout << PHWHERE << " GL1Packet node not found, skipping trigger mask check" << std::endl; + } + } + + MbdVertexMap *m_dst_mbdvertexmap = findNode::getClass(topNode, "MbdVertexMap"); + SvtxVertexMap *m_dst_vertexmap = findNode::getClass(topNode, "SvtxVertexMap"); + + GlobalVertexMap *globalvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + + _mbdVertex = _trackerVertex = std::numeric_limits::quiet_NaN(); + _nTracks = _nMBDVertex = _nTRKVertex = std::numeric_limits::quiet_NaN(); + + _hasMBD = false; + _hasTRK = false; + + for (GlobalVertexMap::ConstIter iter = globalvertexmap->begin(); iter != globalvertexmap->end(); ++iter) + { + GlobalVertex *gvertex = iter->second; + + if (gvertex->count_vtxs(mbdType) != 0) + { + _hasMBD = true; + + auto mbditer = gvertex->find_vertexes(mbdType); + auto mbdvertexvector = mbditer->second; + + _nMBDVertex = mbdvertexvector.size(); + for (auto &vertex : mbdvertexvector) + { + MbdVertex *m_dst_vertex = m_dst_mbdvertexmap->find(vertex->get_id())->second; + _mbdVertex = m_dst_vertex->get_z(); + } + } + + if (gvertex->count_vtxs(trkType) != 0) + { + _hasTRK = true; + + auto trkiter = gvertex->find_vertexes(trkType); + auto trkvertexvector = trkiter->second; + + _nTRKVertex = trkvertexvector.size(); + for (auto &vertex : trkvertexvector) + { + SvtxVertex *m_dst_vertex = m_dst_vertexmap->find(vertex->get_id())->second; + if ( m_dst_vertex->get_beam_crossing() != 0 ) + { + continue; + } + if ( m_dst_vertex->size_tracks() > _nTracks) + { + _trackerVertex = m_dst_vertex->get_z(); + _nTracks = m_dst_vertex->size_tracks(); + } + if (_nTracks == 0) + { + _hasTRK = false; + } + } + } + } + + if (_hasMBD) + { + h_bz->Fill(_mbdVertex); + } + if (_hasTRK) + { + h_trkz->Fill(_trackerVertex); + } + + if (_hasMBD && _hasTRK) + { + h_mbdtrkz->Fill(_mbdVertex - _trackerVertex); + const double coords[2] = {_trackerVertex, _mbdVertex}; + h2_mbdtrkz->Fill(coords); + } + + if (_treeflag) outTree->Fill(); + + ++_counter; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MbdTrackVertex::End(PHCompositeNode * /*topNode*/) +{ + outFile->Write(); + outFile->Close(); + delete outFile; + + return Fun4AllReturnCodes::EVENT_OK; +} + diff --git a/calibrations/mbd/MbdTrackVertex.h b/calibrations/mbd/MbdTrackVertex.h new file mode 100644 index 0000000000..4a6b8a32be --- /dev/null +++ b/calibrations/mbd/MbdTrackVertex.h @@ -0,0 +1,68 @@ +#ifndef MBDTRACKVERTEX_H +#define MBDTRACKVERTEX_H + +#include + +#include +#include +#include +#include + +#include +#include + +class PHCompositeNode; + +class MbdTrackVertex : public SubsysReco +{ + public: + + MbdTrackVertex(const std::string &name = "MbdTrackVertex"); + + ~MbdTrackVertex() override; + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + void setOutputName(const std::string& name) { outFileName = name; }; + void SetTreeFlag(bool flag) { _treeflag = flag; } + void SetTriggerMask(uint64_t mask) { _gl1_trigmask = mask; } + + private: + + TFile* outFile {nullptr}; + TTree* outTree {nullptr}; + TH1F* h_mbdtrkz {nullptr}; + TH1F* h_bz {nullptr}; + TH1F* h_trkz {nullptr}; + THnSparseF* h2_mbdtrkz {nullptr}; + std::string outFileName = "mbdtrk_vertex.root"; + + Float_t _mbdVertex {std::numeric_limits::quiet_NaN()}; + Float_t _trackerVertex {std::numeric_limits::quiet_NaN()}; + UInt_t _nTracks {std::numeric_limits::quiet_NaN()}; + UInt_t _nMBDVertex {std::numeric_limits::quiet_NaN()}; + UInt_t _nTRKVertex {std::numeric_limits::quiet_NaN()}; + + bool _hasMBD {false}; + bool _hasTRK {false}; + + bool _treeflag {true}; + uint64_t _gl1_trigmask {0}; + int _counter{0}; + int _evt{0}; +}; + +#endif // MBDTRACKVERTEX_H diff --git a/calibrations/mbd/autogen.sh b/calibrations/mbd/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/mbd/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/mbd/configure.ac b/calibrations/mbd/configure.ac new file mode 100644 index 0000000000..350d9c3996 --- /dev/null +++ b/calibrations/mbd/configure.ac @@ -0,0 +1,19 @@ +AC_INIT(mbdcalib,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" +fi + +CINTDEFS=" -noIncludePaths -inlineInputHeader " +AC_SUBST(CINTDEFS) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT From 54afc9797987772bbfadc3969b94807b7049ea1a Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Wed, 27 May 2026 23:25:04 -0400 Subject: [PATCH 554/866] clang-tidy fix --- calibrations/mbd/MbdTrackVertex.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/calibrations/mbd/MbdTrackVertex.cc b/calibrations/mbd/MbdTrackVertex.cc index 8d48427663..31dc4327f0 100644 --- a/calibrations/mbd/MbdTrackVertex.cc +++ b/calibrations/mbd/MbdTrackVertex.cc @@ -162,7 +162,10 @@ int MbdTrackVertex::process_event(PHCompositeNode *topNode) h2_mbdtrkz->Fill(coords); } - if (_treeflag) outTree->Fill(); + if (_treeflag) + { + outTree->Fill(); + } ++_counter; From 72140e4ae8c9dda3f0ab546eeac2951e15e00d77 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 28 May 2026 09:30:15 -0400 Subject: [PATCH 555/866] empty commit to trigger jenkins From ceba2cae5bdeae43eaafbffda851a27a7b2fafd3 Mon Sep 17 00:00:00 2001 From: Mickey Chiu Date: Thu, 28 May 2026 10:16:58 -0400 Subject: [PATCH 556/866] make variables const Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- calibrations/mbd/MbdTrackVertex.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calibrations/mbd/MbdTrackVertex.cc b/calibrations/mbd/MbdTrackVertex.cc index 31dc4327f0..bf30305ed8 100644 --- a/calibrations/mbd/MbdTrackVertex.cc +++ b/calibrations/mbd/MbdTrackVertex.cc @@ -17,8 +17,8 @@ #include #include -GlobalVertex::VTXTYPE trkType = GlobalVertex::SVTX; -GlobalVertex::VTXTYPE mbdType = GlobalVertex::MBD; +constexpr GlobalVertex::VTXTYPE trkType = GlobalVertex::SVTX; +constexpr GlobalVertex::VTXTYPE mbdType = GlobalVertex::MBD; //____________________________________________________________________________.. MbdTrackVertex::MbdTrackVertex(const std::string &name): SubsysReco(name) From a6a388015bb3b31b642827a921d18f9234315327 Mon Sep 17 00:00:00 2001 From: Mickey Chiu Date: Thu, 28 May 2026 10:20:22 -0400 Subject: [PATCH 557/866] check for node existence Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- calibrations/mbd/MbdTrackVertex.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/calibrations/mbd/MbdTrackVertex.cc b/calibrations/mbd/MbdTrackVertex.cc index bf30305ed8..d4234bcf17 100644 --- a/calibrations/mbd/MbdTrackVertex.cc +++ b/calibrations/mbd/MbdTrackVertex.cc @@ -92,6 +92,11 @@ int MbdTrackVertex::process_event(PHCompositeNode *topNode) SvtxVertexMap *m_dst_vertexmap = findNode::getClass(topNode, "SvtxVertexMap"); GlobalVertexMap *globalvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + if (!m_dst_mbdvertexmap || !m_dst_vertexmap || !globalvertexmap) + { + std::cout << PHWHERE << " missing required vertex node(s)" << std::endl; + return Fun4AllReturnCodes::DISCARDEVENT; + } _mbdVertex = _trackerVertex = std::numeric_limits::quiet_NaN(); _nTracks = _nMBDVertex = _nTRKVertex = std::numeric_limits::quiet_NaN(); From ad44357834408728aa5648e5ed625bf9082c7492 Mon Sep 17 00:00:00 2001 From: Mickey Chiu Date: Thu, 28 May 2026 10:34:13 -0400 Subject: [PATCH 558/866] skip event if gl1 requested and not found Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- calibrations/mbd/MbdTrackVertex.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/calibrations/mbd/MbdTrackVertex.cc b/calibrations/mbd/MbdTrackVertex.cc index d4234bcf17..9c73c2ea7a 100644 --- a/calibrations/mbd/MbdTrackVertex.cc +++ b/calibrations/mbd/MbdTrackVertex.cc @@ -84,7 +84,8 @@ int MbdTrackVertex::process_event(PHCompositeNode *topNode) } else { - std::cout << PHWHERE << " GL1Packet node not found, skipping trigger mask check" << std::endl; + std::cout << PHWHERE << " GL1Packet node not found; discarding event because trigger masking was requested" << std::endl; + return Fun4AllReturnCodes::DISCARDEVENT; } } From 51c1669418f67587bf93df974dd09c9046f9935a Mon Sep 17 00:00:00 2001 From: Mughal789 Date: Fri, 29 May 2026 06:44:27 -0400 Subject: [PATCH 559/866] Preserve decay history in PHG4TruthTrackingAction --- .../g4main/PHG4TruthTrackingAction.cc | 52 +++++++++++++++++-- .../g4main/PHG4TruthTrackingAction.h | 3 ++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc index 614712d4d3..7243e519de 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc @@ -76,8 +76,8 @@ void PHG4TruthTrackingAction::PreUserTrackingAction(const G4Track* track) int vtxindex = ti->get_vtx_id(); // maybe we should do the sPHENIX primary tracking here as here is the place where the parent id etc. are finally set - - if (issPHENIXPrimary(*m_TruthInfoList, ti)) +// Old-- for only keeping sPHENIX primary +/* if (issPHENIXPrimary(*m_TruthInfoList, ti)) { // we also want to set keep this track PHG4TrackUserInfoV1* userinfo = dynamic_cast(track->GetUserInformation()); @@ -89,8 +89,31 @@ void PHG4TruthTrackingAction::PreUserTrackingAction(const G4Track* track) PHG4Particle* newparticle = dynamic_cast(ti->CloneMe()); m_TruthInfoList->AddsPHENIXPrimaryParticle(trackid, newparticle); + }*/ + + +// Now keeping sPHENIX primary as well as decay history + const bool keep_as_sphenix_primary = issPHENIXPrimary(*m_TruthInfoList, ti); + const bool keep_as_decay_history = keepDecayHistory(*m_TruthInfoList, ti); + + if (keep_as_sphenix_primary || keep_as_decay_history) + { + PHG4TrackUserInfoV1* userinfo = + dynamic_cast(track->GetUserInformation()); + + if (userinfo) + { + userinfo->SetKeep(true); + } } + if (keep_as_sphenix_primary) + { + PHG4Particle* newparticle = dynamic_cast(ti->CloneMe()); + + m_TruthInfoList->AddsPHENIXPrimaryParticle(trackid, newparticle); + }//end keeping sPHENIX primary & decay History + m_CurrG4Particle = {track_id_g4, trackid, vtxindex}; // create or add to a new shower object -------------------------------------- @@ -232,10 +255,11 @@ int PHG4TruthTrackingAction::ResetEvent(PHCompositeNode* /*unused*/) } return 0; -} +} PHG4Particle* PHG4TruthTrackingAction::AddParticle(PHG4TruthInfoContainer& truth, G4Track& track) { + int trackid = 0; if (track.GetParentID()) { @@ -357,6 +381,28 @@ PHG4VtxPoint* PHG4TruthTrackingAction::AddVertex(PHG4TruthInfoContainer& truth, * @return true if the particle is classified as an sPHENIX primary, `false` otherwise. * */ + +//For keeping all decay truth info +bool PHG4TruthTrackingAction::keepDecayHistory( + PHG4TruthInfoContainer& truth, + PHG4Particle* particle) const +{ + if (!particle) + { + return false; + } + + PHG4VtxPoint* vtx = truth.GetVtx(particle->get_vtx_id()); + if (!vtx) + { + return false; + } + + const bool from_decay = (vtx->get_process() == PHG4MCProcess::kPDecay); + + return from_decay; +}//End keep decay History + bool PHG4TruthTrackingAction::issPHENIXPrimary(PHG4TruthInfoContainer& truth, PHG4Particle* particle) const { PHG4VtxPoint* vtx = truth.GetVtx(particle->get_vtx_id()); diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h index 99e0c4669e..734436115f 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h @@ -116,6 +116,9 @@ class PHG4TruthTrackingAction : public PHG4TrackingAction // check if track is long-lived bool isLongLived(int pid) const; + // check if track should be kept because it is produced by a decay process + bool keepDecayHistory(PHG4TruthInfoContainer& truth, PHG4Particle* particle) const; + // check if track is sPHENIX primary bool issPHENIXPrimary(PHG4TruthInfoContainer& truth, PHG4Particle* particle) const; From 6867b5db208aed4fec80e6d7f09a9367310ff6a2 Mon Sep 17 00:00:00 2001 From: Christopher W Platte Date: Fri, 29 May 2026 10:48:22 -0400 Subject: [PATCH 560/866] Changed ZDC evaluated parameter values from branch to vector storage --- offline/packages/tpccalib/TpcLaminationFitting.cc | 9 ++++++--- offline/packages/tpccalib/TpcLaminationFitting.h | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 173b4e7df4..28e718d69b 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -32,7 +32,7 @@ #include #include #include - +#include #include #include @@ -1228,11 +1228,14 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) m_parameterScan[s]->Write(); } m_laminationTree->Write(); - for(int s=0; s<2; s++) { + m_A_zdc.Write("A_zdc"); + m_B_zdc.Write("B_zdc"); + m_C_zdc.Write("C_zdc"); + /* for(int s=0; s<2; s++) { m_A_zdc[s]->Write(std::format("A_zdc_{}",s).c_str()); m_B_zdc[s]->Write(std::format("B_zdc_{}",s).c_str()); m_C_zdc[s]->Write(std::format("C_zdc_{}",s).c_str()); - } + }*/ if(m_saveAllLaminationHistograms) { for(auto &i : m_hLamination) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 55648462f4..b42fe76416 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -8,7 +8,7 @@ #include #include - +#include class PHCompositeNode; class LaserClusterContainer; @@ -156,7 +156,9 @@ class TpcLaminationFitting : public SubsysReco double m_rmse{}; int m_nBins{0}; - TVectorD m_A_zdc(2), m_B_zdc(2), m_C_zdc(2); + TVectorD m_A_zdc{2}; + TVectorD m_B_zdc{2}; + TVectorD m_C_zdc{2}; int m_lamPhiBins{200}; int m_lamRBins{200}; From 996eb322f88119c7074d68a145ba5c14d0eff77d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 29 May 2026 13:54:32 -0400 Subject: [PATCH 561/866] fix clangtidy warning --- offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 449f16d732..4161dcc35d 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -215,7 +215,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_true_mother_p = std::sqrt(std::pow(mother->momentum().px(), 2) + std::pow(mother->momentum().py(), 2) + std::pow(mother->momentum().pz(), 2)); // Must have an old HepMC build, no mag function m_true_mother_eta = mother->momentum().eta(); m_true_mother_phi = mother->momentum().phi(); - if (mother->momentum().e() > abs(mother->momentum().pz())) + if (mother->momentum().e() > std::fabs(mother->momentum().pz())) { m_true_mother_rapidity = 0.5 * log((mother->momentum().e() + mother->momentum().pz())/(mother->momentum().e() - mother->momentum().pz())); } From dbbbccf41f80cdfc9cfd9695d158c0910109708f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 31 May 2026 20:19:14 -0400 Subject: [PATCH 562/866] pass3 speed up --- .../g4simulation/g4tpc/PHG4TpcDigitizer.cc | 222 ++++++++++++------ .../g4simulation/g4tpc/PHG4TpcDigitizer.h | 16 +- 2 files changed, 166 insertions(+), 72 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index 8062bd709e..f7a1642049 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -25,6 +25,7 @@ #include // for gsl_rng_alloc #include +#include #include // for exit #include #include @@ -273,10 +274,17 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } // for this layer and side, use a vector of a vector of cells for each phibin - phi_sorted_hits.clear(); - for (int iphi = 0; iphi < nphibins; iphi++) + if (phi_sorted_hits.size() != static_cast(nphibins)) { - phi_sorted_hits.emplace_back(); + phi_sorted_hits.clear(); + phi_sorted_hits.resize(nphibins); + } + else + { + for (auto &hits : phi_sorted_hits) + { + hits.clear(); + } } // Loop over all hitsets containing signals for this layer and add them to phi_sorted_hits for their phibin @@ -326,31 +334,24 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) for (unsigned int iphi = 0; iphi < phi_sorted_hits.size(); iphi++) { - // Make a fixed length vector to indicate whether each time bin is signal or noise int ntbins = layergeom->get_zbins(); - is_populated.clear(); - is_populated.assign(ntbins, 2); // mark all as noise only, for now - - // add an empty vector of hits for each t bin - t_sorted_hits.clear(); - for (int it = 0; it < ntbins; it++) - { - t_sorted_hits.emplace_back(); - } + signal_hit_by_tbin.assign(ntbins, nullptr); // add a signal hit from phi_sorted_hits for each t bin that has one for (unsigned int it = 0; it < phi_sorted_hits[iphi].size(); it++) { int tbin = TpcDefs::getTBin(phi_sorted_hits[iphi][it]->first); - is_populated[tbin] = 1; // this bin is a associated with a hit - t_sorted_hits[tbin].push_back(phi_sorted_hits[iphi][it]); + if (!signal_hit_by_tbin[tbin]) + { + signal_hit_by_tbin[tbin] = phi_sorted_hits[iphi][it]->second; + } if (Verbosity() > 2) { if (layer == print_layer) { TrkrDefs::hitkey hitkey = phi_sorted_hits[iphi][it]->first; - std::cout << "iphi " << iphi << " adding existing signal hit to t vector for layer " << layer + std::cout << "iphi " << iphi << " adding existing signal hit for layer " << layer << " side " << side << " tbin " << tbin << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) @@ -361,11 +362,8 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } } - adc_input.clear(); - adc_hitid.clear(); // initialize entries to zero for each t bin adc_input.assign(ntbins, 0.0); - adc_hitid.assign(ntbins, 0); // Now for this phibin we process all bins ordered by t into hits with noise //====================================================== @@ -374,33 +372,32 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) for (int it = 0; it < ntbins; it++) { - if (is_populated[it] == 1) + TrkrHit *signal_hit = signal_hit_by_tbin[it]; + if (signal_hit) { // This tbin has a hit, add noise - float signal_with_noise = add_noise_to_bin((t_sorted_hits[it][0]->second)->getEnergy()); + float signal_with_noise = add_noise_to_bin(signal_hit->getEnergy()); adc_input[it] = signal_with_noise; - adc_hitid[it] = t_sorted_hits[it][0]->first; if (Verbosity() > 2) { if (layer == print_layer) { std::cout << "existing signal hit: layer " << layer << " iphi " << iphi << " it " << it - << " edep " << (t_sorted_hits[it][0]->second)->getEnergy() + << " edep " << signal_hit->getEnergy() << " adc gain " << ADCSignalConversionGain << " signal with noise " << signal_with_noise << " adc_input " << adc_input[it] << std::endl; } } } - else if (is_populated[it] == 2) + else { if (!skip_noise) { // This t bin does not have a filled cell, add noise float noise = add_noise_to_bin(0.0); adc_input[it] = noise; - adc_hitid[it] = 0; // there is no hit, just add a placeholder in the vector for now, replace it later if (Verbosity() > 2) { @@ -414,13 +411,6 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } } } - else - { - // Cannot happen - std::cout << "Impossible value of is_populated, it = " << it - << " is_populated = " << is_populated[it] << std::endl; - exit(-1); - } } // Now we can digitize the entire stream of t bins for this phi bin @@ -438,7 +428,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } // optionally do not trigger on bins with no signal - if ((is_populated[it] == 2) && skip_noise) + if (!signal_hit_by_tbin[it] && skip_noise) { binpointer++; continue; @@ -466,7 +456,8 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) if (it + itup < ntbins && it + itup >= 0) // stay within the bin limits { float input = 0; - if ((is_populated[it + itup] == 2) && skip_noise) + TrkrHit *signal_hit = signal_hit_by_tbin[it + itup]; + if (!signal_hit && skip_noise) { input = add_noise_to_bin(0.0); // no noise added to this bin previously because skip_noise is true } @@ -492,8 +483,8 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) if (layer == print_layer) { std::cout << " Digitizing: iphi " << iphi << " it+itup " << it + itup - << " adc_hitid " << adc_hitid[it + itup] - << " is_populated " << is_populated[it + itup] + << " adc_hitid " << (signal_hit ? hitkey : 0) + << " is_populated " << (signal_hit ? 1 : 2) << " adc_input " << adc_input[it + itup] << " ADCThreshold " << ADCThreshold * ADCNoiseConversionGain << " adc_output " << adc_output @@ -504,10 +495,10 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } } - if (is_populated[it + itup] == 1) + if (signal_hit) { // this is a signal hit, it already exists - hit = t_sorted_hits[it + itup][0]->second; // pointer valid only for signal hits + hit = signal_hit; } else { @@ -545,20 +536,10 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) else { // set adc value to zero if there is a hit - // we need the hitset key, requires (layer, sector, side) - unsigned int sector = 12 * iphi / nphibins; - TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); - auto *hitset = trkrhitsetcontainer->findHitSet(hitsetkey); - if (hitset) + TrkrHit *hit = signal_hit_by_tbin[it]; + if (hit) { - // Get the hitkey - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it); - TrkrHit *hit = nullptr; - hit = hitset->getHit(hitkey); - if (hit) - { - hit->setAdc(0); - } + hit->setAdc(0); } // bin below threshold, move on binpointer++; @@ -573,7 +554,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) { std::cout << "From PHG4TpcDigitizer: hitsetcontainer dump at end before cleaning:" << std::endl; } - std::vector> delete_hitkey_list; + std::vector delete_hitkey_list; // Clean up undigitized hits - we want all hitsets for the Tpc // This loop is pretty efficient because the remove methods all take a specified hitset as input @@ -594,6 +575,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) // get all of the hits from this hitset TrkrHitSet *hitset = hitset_iter->second; + delete_hitkey_list.clear(); TrkrHitSet::ConstRange hit_range = hitset->getHits(); for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; hit_iter != hit_range.second; @@ -616,28 +598,26 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) std::cout << " -- this hit not digitized - delete it" << std::endl; } // screws up the iterator to delete it here, store the hitkey for later deletion - delete_hitkey_list.emplace_back(hitsetkey, hitkey); + delete_hitkey_list.push_back(hitkey); } } - } - // delete all undigitized hits - for (auto &i : delete_hitkey_list) - { - TrkrHitSet *hitset = trkrhitsetcontainer->findHitSet(i.first); - const unsigned int layer = TrkrDefs::getLayer(i.first); - hitset->removeHit(i.second); - if (Verbosity() > 20) + // delete all undigitized hits + for (auto &hitkey : delete_hitkey_list) { - if (layer == print_layer) + hitset->removeHit(hitkey); + if (Verbosity() > 20) { - std::cout << "removed hit with hitsetkey " << i.first - << " and hitkey " << i.second << std::endl; + if (layer == print_layer) + { + std::cout << "removed hit with hitsetkey " << hitsetkey + << " and hitkey " << hitkey << std::endl; + } } - } - // should also delete all entries with this hitkey from the TrkrHitTruthAssoc map - // hittruthassoc->removeAssoc(delete_hitkey_list[i].first, delete_hitkey_list[i].second); // Slow! Commented out by ADF 9/6/2022 + // should also delete all entries with this hitkey from the TrkrHitTruthAssoc map + // hittruthassoc->removeAssoc(hitsetkey, hitkey); // Slow! Commented out by ADF 9/6/2022 + } } // Final hitset dump @@ -648,7 +628,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) // We want all hitsets for the Tpc TrkrHitSetContainer::ConstRange hitset_range_final = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range_final.first; - hitset_iter != hitset_range_now.second; + hitset_iter != hitset_range_final.second; ++hitset_iter) { // we have an itrator to one TrkrHitSet for the Tpc from the trkrHitSetContainer @@ -708,3 +688,109 @@ float PHG4TpcDigitizer::added_noise() return noise; } +n; // mV - from definition of noise charge and pedestal charge + adc_input_voltage += noise_voltage; + + return adc_input_voltage; +} + +float PHG4TpcDigitizer::added_noise() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +ise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +n; // mV - from definition of noise charge and pedestal charge + adc_input_voltage += noise_voltage; + + return adc_input_voltage; +} + +float PHG4TpcDigitizer::added_noise() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +se() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} + gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +se() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +mV - from definition of noise charge and pedestal charge + adc_input_voltage += noise_voltage; + + return adc_input_voltage; +} + +float PHG4TpcDigitizer::added_noise() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +se() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} + gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +se() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +se() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} + gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +se() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +or, TpcEnc); + + return noise; +} +se() +{ + float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); + + return noise; +} +pcEnc); + + return noise; +} diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index db7f6eff0f..0d9cc655c0 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -16,6 +16,7 @@ #include class PHCompositeNode; +class TrkrHit; class PHG4TpcDigitizer : public SubsysReco { @@ -65,11 +66,8 @@ class PHG4TpcDigitizer : public SubsysReco bool skip_noise = false; std::vector > phi_sorted_hits; - std::vector > t_sorted_hits; - std::vector adc_input; - std::vector adc_hitid; - std::vector is_populated; + std::vector signal_hit_by_tbin; // settings std::map _max_adc; @@ -80,3 +78,13 @@ class PHG4TpcDigitizer : public SubsysReco }; #endif +th sPHENIX standard + gsl_rng *RandomGenerator; +}; + +#endif +ard + gsl_rng *RandomGenerator; +}; + +#endif From 6f44a753868f0ef38abcc5da46e4dd0062dba10c Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 1 Jun 2026 12:15:42 -0400 Subject: [PATCH 563/866] codex checkpoint --- .../Fun4AllStreamingInputManager.cc | 5 + offline/framework/fun4allraw/Makefile.am | 7 +- .../fun4allraw/SingleStreamingInput.h | 1 + .../fun4allraw/SingleTpcTimeFrameInput.cc | 70 +- .../fun4allraw/SingleTpcTimeFrameInput.h | 7 +- .../fun4allraw/TpcTimeFrameBuilder.h | 20 +- .../fun4allraw/TpcTimeFrameBuilderBase.h | 26 + .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 2165 +++++++++++++++++ .../fun4allraw/TpcTimeFrameBuilderRun3.h | 442 ++++ 9 files changed, 2726 insertions(+), 17 deletions(-) create mode 100644 offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h create mode 100644 offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc create mode 100644 offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 0bea81197b..025f6683a1 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -1299,6 +1299,11 @@ int Fun4AllStreamingInputManager::FillTpcPool() std::cout << "Fun4AllStreamingInputManager::FillTpcPool - fill pool for " << iter->Name() << std::endl; } iter->FillPool(ref_bco_minus_range); + const int fill_pool_status = iter->FillPoolStatus(); + if (fill_pool_status < 0) + { + return fill_pool_status; + } if (m_RunNumber == 0) { m_RunNumber = iter->RunNumber(); diff --git a/offline/framework/fun4allraw/Makefile.am b/offline/framework/fun4allraw/Makefile.am index 7f852ce989..1cd5a80afa 100644 --- a/offline/framework/fun4allraw/Makefile.am +++ b/offline/framework/fun4allraw/Makefile.am @@ -37,7 +37,9 @@ pkginclude_HEADERS = \ SingleTpcPoolInput.h \ SingleTriggeredInput.h \ SingleTpcTimeFrameInput.h \ - TpcTimeFrameBuilder.h + TpcTimeFrameBuilder.h \ + TpcTimeFrameBuilderBase.h \ + TpcTimeFrameBuilderRun3.h decoderincludedir = $(includedir)/mvtx_decoder decoderinclude_HEADERS = \ @@ -92,7 +94,8 @@ libfun4allraw_la_SOURCES = \ SingleTpcPoolInput.cc \ SingleTriggeredInput.cc \ SingleTpcTimeFrameInput.cc \ - TpcTimeFrameBuilder.cc + TpcTimeFrameBuilder.cc \ + TpcTimeFrameBuilderRun3.cc libfun4allraw_la_LIBADD = \ libmvtx_decoder.la \ diff --git a/offline/framework/fun4allraw/SingleStreamingInput.h b/offline/framework/fun4allraw/SingleStreamingInput.h index 082c1a079e..65220ec9fb 100644 --- a/offline/framework/fun4allraw/SingleStreamingInput.h +++ b/offline/framework/fun4allraw/SingleStreamingInput.h @@ -22,6 +22,7 @@ class SingleStreamingInput : public Fun4AllBase, public InputFileHandler virtual Eventiterator *GetEventIterator() { return m_EventIterator; } virtual void FillPool(const uint64_t) { return; } virtual void FillPool(const unsigned int = 1) { return; } + virtual int FillPoolStatus() const { return 0; } virtual void RunNumber(const int runno) { m_RunNumber = runno; } virtual int RunNumber() const { return m_RunNumber; } virtual int fileopen(const std::string &filename) override; diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index dd9559b075..6017e67ca7 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -1,5 +1,6 @@ #include "SingleTpcTimeFrameInput.h" #include "TpcTimeFrameBuilder.h" +#include "TpcTimeFrameBuilderRun3.h" #include "Fun4AllStreamingInputManager.h" #include "InputManagerType.h" @@ -25,6 +26,8 @@ #include #include +#include +#include #include #include #include @@ -113,6 +116,7 @@ SingleTpcTimeFrameInput::TimeTracker::~TimeTracker() void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) { + m_FillPoolStatus = Fun4AllReturnCodes::EVENT_OK; { static bool first = true; if (first) @@ -269,6 +273,18 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) auto &packet = plist[i]; assert(packet); + auto cleanup_remaining_packets = [&](const int first_index) + { + for (int j = first_index; j < npackets; ++j) + { + if (plist[j]) + { + delete plist[j]; + plist[j] = nullptr; + } + } + }; + // get packet id const auto packet_id = packet->getIdentifier(); @@ -284,14 +300,52 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) continue; } + const int hit_format = packet->getHitFormat(); + const auto builder_hit_format_iter = m_TpcTimeFrameBuilderHitFormatMap.find(packet_id); + if (builder_hit_format_iter != m_TpcTimeFrameBuilderHitFormatMap.end() && builder_hit_format_iter->second != hit_format) + { + std::cout << __PRETTY_FUNCTION__ << ": Error : packet id " << packet_id + << " changed TPC hit format from " << builder_hit_format_iter->second + << " to " << hit_format << ". Aborting run." << std::endl; + packet->identify(); + m_FillPoolStatus = Fun4AllReturnCodes::ABORTRUN; + cleanup_remaining_packets(i); + return; + } + if (!m_TpcTimeFrameBuilderMap.contains(packet_id)) { - if (Verbosity() >= 1) + TpcTimeFrameBuilderBase *builder = nullptr; + if (hit_format == IDTPCFEEV4) + { + if (Verbosity() >= 1) + { + std::cout << __PRETTY_FUNCTION__ << ": Creating TpcTimeFrameBuilder for packet id: " << packet_id + << " hit format " << hit_format << std::endl; + } + builder = new TpcTimeFrameBuilder(packet_id); + } + else if (hit_format == IDTPCFEEV5 || hit_format == IDTPCFEEV6) + { + if (Verbosity() >= 1) + { + std::cout << __PRETTY_FUNCTION__ << ": Creating TpcTimeFrameBuilderRun3 for packet id: " << packet_id + << " hit format " << hit_format << std::endl; + } + builder = new TpcTimeFrameBuilderRun3(packet_id); + } + else { - std::cout << __PRETTY_FUNCTION__ << ": Creating TpcTimeFrameBuilder for packet id: " << packet_id << std::endl; + std::cout << __PRETTY_FUNCTION__ << ": Error : unsupported TPC hit format " << hit_format + << " for packet id " << packet_id << ". Aborting run." << std::endl; + packet->identify(); + m_FillPoolStatus = Fun4AllReturnCodes::ABORTRUN; + cleanup_remaining_packets(i); + return; } - m_TpcTimeFrameBuilderMap[packet_id] = new TpcTimeFrameBuilder(packet_id); + m_TpcTimeFrameBuilderMap[packet_id] = builder; + m_TpcTimeFrameBuilderHitFormatMap[packet_id] = hit_format; m_TpcTimeFrameBuilderMap[packet_id]->setVerbosity(Verbosity()); m_TpcTimeFrameBuilderMap[packet_id]->fillBadFeeMap(); if (!m_digitalCurrentDebugTTreeName.empty()) @@ -306,7 +360,15 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) } assert(m_TpcTimeFrameBuilderMap[packet_id]); - m_TpcTimeFrameBuilderMap[packet_id]->ProcessPacket(packet); + const int process_packet_status = m_TpcTimeFrameBuilderMap[packet_id]->ProcessPacket(packet); + if (process_packet_status < 0) + { + std::cout << __PRETTY_FUNCTION__ << ": Error : TPC packet builder returned " << process_packet_status + << " for packet id " << packet_id << ". Aborting run." << std::endl; + m_FillPoolStatus = process_packet_status; + cleanup_remaining_packets(i); + return; + } // require_more_data = require_more_data or m_TpcTimeFrameBuilderMap[packet_id]->isMoreDataRequired(targetBCO); delete packet; diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index e9e10cae59..b83cd99a6d 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -12,7 +12,7 @@ class TpcRawHit; class Packet; -class TpcTimeFrameBuilder; +class TpcTimeFrameBuilderBase; class PHTimer; class TH1; class TH2; @@ -25,6 +25,7 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput explicit SingleTpcTimeFrameInput(const std::string &name); ~SingleTpcTimeFrameInput() override; void FillPool(const uint64_t targetBCO) override; + int FillPoolStatus() const override { return m_FillPoolStatus; } void CleanupUsedPackets(const uint64_t bclk) override; // bool CheckPoolDepth(const uint64_t bclk) override; void ClearCurrentEvent() override; @@ -51,7 +52,8 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput unsigned int m_NegativeBco{0}; //! packet ID -> TimeFrame builder - std::map m_TpcTimeFrameBuilderMap; + std::map m_TpcTimeFrameBuilderMap; + std::map m_TpcTimeFrameBuilderHitFormatMap; std::set m_SelectedPacketIDs; TH1 *m_hNorm = nullptr; @@ -76,6 +78,7 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput bool stopped = false; }; + int m_FillPoolStatus{0}; std::string m_digitalCurrentDebugTTreeName; }; diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index 07e2921310..b5b9a5e293 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -1,6 +1,8 @@ #ifndef Fun4All_TpcTimeFrameBuilder_H #define Fun4All_TpcTimeFrameBuilder_H +#include "TpcTimeFrameBuilderBase.h" + #include #include #include @@ -24,27 +26,27 @@ class TH2; class TTree; // NOLINTNEXTLINE(hicpp-special-member-functions) -class TpcTimeFrameBuilder +class TpcTimeFrameBuilder : public TpcTimeFrameBuilderBase { public: explicit TpcTimeFrameBuilder(const int packet_id); - virtual ~TpcTimeFrameBuilder(); + ~TpcTimeFrameBuilder() override; - int ProcessPacket(Packet *); - bool isMoreDataRequired(const uint64_t >m_bco) const; - void CleanupUsedPackets(const uint64_t &bclk); - std::vector &getTimeFrame(const uint64_t >m_bco); + int ProcessPacket(Packet *) override; + bool isMoreDataRequired(const uint64_t >m_bco) const override; + void CleanupUsedPackets(const uint64_t &bclk) override; + std::vector &getTimeFrame(const uint64_t >m_bco) override; - void setVerbosity(const int i); + void setVerbosity(int i) override; void setFastBCOSkip(bool fastBCOSkip = true) { m_fastBCOSkip = fastBCOSkip; } - void fillBadFeeMap(); + void fillBadFeeMap() override; // enable saving of digital current debug TTree with file name `name` - void SaveDigitalCurrentDebugTTree(const std::string &name); + void SaveDigitalCurrentDebugTTree(const std::string &name) override; protected: // Length for the 256-bit wide Round Robin Multiplexer for the data stream diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h new file mode 100644 index 0000000000..f137572c6a --- /dev/null +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h @@ -0,0 +1,26 @@ +#ifndef FUN4ALLRAW_TPCTIMEFRAMEBUILDERBASE_H +#define FUN4ALLRAW_TPCTIMEFRAMEBUILDERBASE_H + +#include +#include +#include + +class Packet; +class TpcRawHit; + +class TpcTimeFrameBuilderBase +{ + public: + virtual ~TpcTimeFrameBuilderBase() = default; + + virtual int ProcessPacket(Packet *) = 0; + virtual bool isMoreDataRequired(const uint64_t >m_bco) const = 0; + virtual void CleanupUsedPackets(const uint64_t &bclk) = 0; + virtual std::vector &getTimeFrame(const uint64_t >m_bco) = 0; + + virtual void setVerbosity(int i) = 0; + virtual void fillBadFeeMap() = 0; + virtual void SaveDigitalCurrentDebugTTree(const std::string &name) = 0; +}; + +#endif diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc new file mode 100644 index 0000000000..45645861a4 --- /dev/null +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -0,0 +1,2165 @@ +#include "TpcTimeFrameBuilderRun3.h" + +#include +#include + +#include + +#include +#include + +#include +#include + +#include // for PHTimer + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include // For std::tie + +TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) + : m_packet_id(packet_id) + , m_HistoPrefix("TpcTimeFrameBuilderRun3_Packet" + std::to_string(packet_id)) +{ + for (int fee = 0; fee < MAX_FEECOUNT; ++fee) + { + m_bcoMatchingInformation_vec.emplace_back( + std::string("BcoMatchingInformation_Packet") + std::to_string(packet_id) + "_FEE" + std::to_string(fee)); + } + + m_feeData.resize(MAX_FEECOUNT); + + // cppcheck-suppress noCopyConstructor + // cppcheck-suppress noOperatorEq + m_packetTimer = new PHTimer("TpcTimeFrameBuilderRun3_Packet" + std::to_string(packet_id)); + + Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + m_hNorm = new TH1D(TString(m_HistoPrefix.c_str()) + "_Normalization", // + TString(m_HistoPrefix.c_str()) + " Normalization;Items;Count", + 24, .5, 24.5); + int i = 1; + m_hNorm->GetXaxis()->SetBinLabel(i++, "Packet"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Lv1-Taggers"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "EnDat-Taggers"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "ChannelPackets"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Waveforms"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_FEE"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_FEE_INVALID"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_INVALID"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM_HEARTBEAT"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM_DC_STOP_SEND"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "TimeFrameSizeLimitError"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Matched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Unmatched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Matched_Hit_Sum"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Dropped_Hit_Sum"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_Exact_Matched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_FuzzyFallback"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_FuzzyFallback_Hit_Sum"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_MatchFailed"); + + assert(i <= 24); + m_hNorm->GetXaxis()->LabelsOption("v"); + hm->registerHisto(m_hNorm); + + h_PacketLength = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength", // + TString(m_HistoPrefix.c_str()) + " PacketLength;PacketLength [32bit Words];Count", 1000, .5, 5e6); + hm->registerHisto(h_PacketLength); + + h_PacketLength_Residual = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength_Residual", // + TString(m_HistoPrefix.c_str()) + + " PacketLength that does not fit into DMA transfer;PacketLength [16bit Words];Count", + 16, -.5, 15.5); + hm->registerHisto(h_PacketLength_Residual); + + h_PacketLength_Padding = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength_Padding", // + TString(m_HistoPrefix.c_str()) + + " padding within PacketLength;PacketLength [32bit Words];Count", + 16, -.5, 15.5); + hm->registerHisto(h_PacketLength_Padding); + + m_hFEEDataStream = new TH2I(TString(m_HistoPrefix.c_str()) + "_FEE_DataStream_WordCount", // + TString(m_HistoPrefix.c_str()) + + " FEE Data Stream Word Count;FEE ID;Type;Count", + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5, 25, .5, 25.5); + i = 1; + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordValid"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordSkipped"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordDigitalCurrentKeyWord"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "InvalidLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "RawHit"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitFormatErrorOverLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitFormatErrorMismatchedLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitCRCError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrent"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrentFormatErrorMismatchedLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrentCRCError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "ParityError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitUnusedBeforeCleanup"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeat"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncUnavailable"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncOK"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncUnavailable"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncOK"); + assert(i <= 25); + hm->registerHisto(m_hFEEDataStream); + + m_hFEEChannelPacketCount = new TH1I(TString(m_HistoPrefix.c_str()) + "_FEEChannelPacketCount", // + TString(m_HistoPrefix.c_str()) + + " Count of waveform packet per channel;FEE*256 + Channel;Count", + MAX_FEECOUNT * MAX_CHANNELS, -.5, MAX_FEECOUNT * MAX_CHANNELS - .5); + hm->registerHisto(m_hFEEChannelPacketCount); + + m_hFEESAMPAADC = new TH2I(TString(m_HistoPrefix.c_str()) + "_FEE_SAMPA_ADC", // + TString(m_HistoPrefix.c_str()) + + " ADC distribution in 2D;ADC Time Bin [0...1023];FEE*8+SAMPA;Sum ADC", + MAX_PACKET_LENGTH, -.5, MAX_PACKET_LENGTH - .5, + MAX_FEECOUNT * MAX_SAMPA, -.5, MAX_FEECOUNT * MAX_SAMPA - .5); + hm->registerHisto(m_hFEESAMPAADC); + + m_hFEESAMPAHeartBeatSync = new TH1I(TString(m_HistoPrefix.c_str()) + "_FEE_SAMPA_HEARTBEAT_SYNC", // + TString(m_HistoPrefix.c_str()) + + " FEE/SAMPA Sync Heartbeat Count;FEE*8+SAMPA;Sync Heartbeat Count", + MAX_FEECOUNT * MAX_SAMPA, -.5, MAX_FEECOUNT * MAX_SAMPA - .5); + hm->registerHisto(m_hFEESAMPAHeartBeatSync); + + h_GTMClockDiff_Matched = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Matched", // + TString(m_HistoPrefix.c_str()) + + " GTM BCO Diff for Matched Time Frame;Trigger BCO Diff [BCO];Count", + 1024, -512 - .5, 512 - .5); + hm->registerHisto(h_GTMClockDiff_Matched); + h_GTMClockDiff_Unmatched = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Unmatched", // + TString(m_HistoPrefix.c_str()) + + " GTM BCO Diff for Unmatched Time Frame;Trigger BCO Diff [BCO];Count", + 1024, -512 - .5, 512 - .5); + hm->registerHisto(h_GTMClockDiff_Unmatched); + h_GTMClockDiff_Dropped = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Dropped", // + TString(m_HistoPrefix.c_str()) + + " GTM BCO Diff for Dropped Time Frame;Trigger BCO Diff [BCO];Count", + 16384, -16384 - .5, 0 - .5); + hm->registerHisto(h_GTMClockDiff_Dropped); + h_TimeFrame_Matched_Size = new TH1I(TString(m_HistoPrefix.c_str()) + "_TimeFrame_Matched_Size", // + TString(m_HistoPrefix.c_str()) + + " Time frame size for Matched Time Frame ;Size [TPC raw hits];Count", + 3328, -.5, 3328 - .5); + hm->registerHisto(h_TimeFrame_Matched_Size); + + h_Run3FEEClockDiff_FuzzyFallback = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3FEEClockDiff_FuzzyFallback", // + TString(m_HistoPrefix.c_str()) + + " Run3 fuzzy fallback FEE clock diff;Clock Difference [FEE Clock Cycle];Count", + 2048, -1024 - .5, 1024 - .5); + hm->registerHisto(h_Run3FEEClockDiff_FuzzyFallback); + + h_ProcessPacket_Time = new TH2I(TString(m_HistoPrefix.c_str()) + "_ProcessPacket_Time", // + TString(m_HistoPrefix.c_str()) + + " Time cost to run ProcessPacket();Call counts;Time elapsed per call [ms];Count", + 100, 0, 30e6, 100, 0, 10); + hm->registerHisto(h_ProcessPacket_Time); +} + +TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() +{ + for (auto& timeHitEntry : m_timeHitMap) + { + while (!timeHitEntry.second.empty()) + { + delete timeHitEntry.second.back(); + timeHitEntry.second.pop_back(); + } + } + + for (auto& timeFrameEntry : m_timeFrameMap) + { + while (!timeFrameEntry.second.empty()) + { + delete timeFrameEntry.second.back(); + timeFrameEntry.second.pop_back(); + } + } + + delete m_packetTimer; + + delete m_digitalCurrentDebugTTree; +} + +void TpcTimeFrameBuilderRun3::setVerbosity(const int i) +{ + m_verbosity = i; + + for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + bcoMatchingInformation.set_verbosity(i); + } +} + +int64_t TpcTimeFrameBuilderRun3::get_signed_fee_bco_diff(uint32_t first, uint32_t second) +{ + static constexpr int64_t fee_clock_range = 1LL << 20U; + static constexpr int64_t fee_clock_half_range = 1LL << 19U; + + int64_t diff = static_cast(first & kFEEClockMask) - static_cast(second & kFEEClockMask); + if (diff > fee_clock_half_range) + { + diff -= fee_clock_range; + } + else if (diff < -fee_clock_half_range) + { + diff += fee_clock_range; + } + return diff; +} + +uint32_t TpcTimeFrameBuilderRun3::get_fee_bco_diff(uint32_t first, uint32_t second) +{ + const int64_t diff = get_signed_fee_bco_diff(first, second); + return static_cast(diff < 0 ? -diff : diff); +} + +size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector& timeframe) +{ + auto it = m_timeHitMap.find(fee_bco & kFEEClockMask); + if (it == m_timeHitMap.end()) + { + return 0; + } + + size_t moved = 0; + auto& hits = it->second; + for (auto hit_it = hits.begin(); hit_it != hits.end();) + { + TpcRawHit* hit = *hit_it; + if (hit->get_fee() == fee) + { + timeframe.push_back(hit); + hit_it = hits.erase(hit_it); + ++moved; + } + else + { + ++hit_it; + } + } + + if (hits.empty()) + { + m_timeHitMap.erase(it); + } + return moved; +} + +std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const +{ + uint32_t best_fee_bco = 0; + uint32_t best_diff = std::numeric_limits::max(); + + for (const auto& [fee_bco, hits] : m_timeHitMap) + { + bool has_fee_hit = false; + for (const TpcRawHit* hit : hits) + { + if (hit->get_fee() == fee) + { + has_fee_hit = true; + break; + } + } + if (!has_fee_hit) + { + continue; + } + + const uint32_t diff = get_fee_bco_diff(fee_bco, predicted_fee_bco); + if (diff < best_diff) + { + best_diff = diff; + best_fee_bco = fee_bco; + } + } + + if (best_diff <= kRun3FeeMatchWindow) + { + return best_fee_bco; + } + return std::nullopt; +} + +void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window) +{ + assert(m_hFEEDataStream); + + for (auto map_it = m_timeHitMap.begin(); map_it != m_timeHitMap.end();) + { + auto& hits = map_it->second; + for (auto hit_it = hits.begin(); hit_it != hits.end();) + { + TpcRawHit* hit = *hit_it; + const uint16_t fee = hit->get_fee(); + if (fee >= m_bcoMatchingInformation_vec.size()) + { + ++hit_it; + continue; + } + + const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee].get_predicted_fee_bco(bclk_rollover_corrected); + if (!predicted_fee_bco) + { + ++hit_it; + continue; + } + + const int64_t diff = get_signed_fee_bco_diff(map_it->first, *predicted_fee_bco); + if ((fee_clock_window == 0 && diff <= 0) || (fee_clock_window > 0 && diff < -static_cast(fee_clock_window))) + { + m_hFEEDataStream->Fill(hit->get_fee(), "HitUnusedBeforeCleanup", 1); + delete hit; + hit_it = hits.erase(hit_it); + } + else + { + ++hit_it; + } + } + + if (hits.empty()) + { + map_it = m_timeHitMap.erase(map_it); + } + else + { + ++map_it; + } + } +} + +bool TpcTimeFrameBuilderRun3::isMoreDataRequired(const uint64_t& gtm_bco) const +{ + for (const BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + // if (not bcoMatchingInformation.is_verified()) + // { + // continue; + // } + + if (bcoMatchingInformation.isMoreDataRequired(gtm_bco)) + { + return true; + } + } + + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id + << ":PASS: All FEEs satisfied for gtm_bco: 0x" << std::hex << gtm_bco << std::dec << ". Return false." + << std::endl; + } + return false; +} + +std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& gtm_bco) +{ + assert(m_hNorm); + const uint64_t bclk_rollover_corrected = m_bcoMatchingInformation_vec[0].get_gtm_rollover_correction(gtm_bco); + + for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + bcoMatchingInformation.cleanup(bclk_rollover_corrected); + } + + cleanup_time_hit_map(bclk_rollover_corrected, kRun3FeeMatchWindow); + + if (auto cached = m_timeFrameMap.find(bclk_rollover_corrected); cached != m_timeFrameMap.end()) + { + return cached->second; + } + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": getTimeFrame for gtm_bco: 0x" << std::hex << gtm_bco << std::dec + << ": bclk_rollover_corrected: 0x" << std::hex << bclk_rollover_corrected << std::dec + << std::endl; + } + + auto inserted_frame = m_timeFrameMap.emplace(bclk_rollover_corrected, std::vector{}); + auto frame_it = inserted_frame.first; + std::vector& timeframe = frame_it->second; + + size_t exact_hit_count = 0; + size_t fallback_hit_count = 0; + + for (uint16_t fee = 0; fee < m_bcoMatchingInformation_vec.size(); ++fee) + { + const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee].get_predicted_fee_bco(bclk_rollover_corrected); + if (!predicted_fee_bco) + { + continue; + } + + const size_t exact_hits = move_time_hits(*predicted_fee_bco, fee, timeframe); + exact_hit_count += exact_hits; + if (exact_hits > 0) + { + continue; + } + + const std::optional fuzzy_fee_bco = find_fuzzy_fee_bco(*predicted_fee_bco, fee); + if (!fuzzy_fee_bco) + { + continue; + } + + const size_t fuzzy_hits = move_time_hits(*fuzzy_fee_bco, fee, timeframe); + if (fuzzy_hits == 0) + { + continue; + } + + fallback_hit_count += fuzzy_hits; + assert(h_Run3FEEClockDiff_FuzzyFallback); + h_Run3FEEClockDiff_FuzzyFallback->Fill(get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco)); + + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": Run3 fuzzy FEE-clock fallback for fee " << fee + << " predicted 0x" << std::hex << *predicted_fee_bco + << " matched 0x" << *fuzzy_fee_bco << std::dec + << " diff " << get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco) + << " hits " << fuzzy_hits << std::endl; + } + } + + if (timeframe.empty()) + { + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ":ERROR: Run3 FEE-clock match failed for gtm_bco: 0x" << std::hex << gtm_bco << std::dec + << " bclk_rollover_corrected 0x" << std::hex << bclk_rollover_corrected << std::dec + << ". m_timeHitMap size: " << m_timeHitMap.size() << std::endl; + } + + m_hNorm->Fill("Run3_TimeFrame_MatchFailed", 1); + m_hNorm->Fill("GTM_TimeFrame_Unmatched", 1); + m_timeFrameMap.erase(frame_it); + static std::vector empty; + return empty; + } + + if (exact_hit_count > 0) + { + m_hNorm->Fill("Run3_TimeFrame_Exact_Matched", 1); + } + if (fallback_hit_count > 0) + { + m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback", 1); + m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback_Hit_Sum", fallback_hit_count); + } + + m_hNorm->Fill("GTM_TimeFrame_Matched", 1); + assert(h_TimeFrame_Matched_Size); + h_TimeFrame_Matched_Size->Fill(timeframe.size()); + m_hNorm->Fill("GTM_TimeFrame_Matched_Hit_Sum", timeframe.size()); + m_UsedTimeFrameSet.push(bclk_rollover_corrected); + return timeframe; +} + +void TpcTimeFrameBuilderRun3::CleanupUsedPackets(const uint64_t& bclk) +{ + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": cleaning up bcos < 0x" << std::hex + << bclk << std::dec << std::endl; + } + + while (!m_UsedTimeFrameSet.empty()) + { + const uint64_t bco_completed = m_UsedTimeFrameSet.front(); + m_UsedTimeFrameSet.pop(); + + auto it = m_timeFrameMap.find(bco_completed); + if (it != m_timeFrameMap.end()) + { + while (!it->second.empty()) + { + delete it->second.back(); + it->second.pop_back(); + } + m_timeFrameMap.erase(it); + } + } + + const uint64_t bclk_rollover_corrected = m_bcoMatchingInformation_vec[0].get_gtm_rollover_correction(bclk); + cleanup_time_hit_map(bclk_rollover_corrected, 0); +} + +int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) +{ + static size_t call_count = 0; + ++call_count; + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3::ProcessPacket: " << m_packet_id + << "\t- Entry " << std::endl; + } + + if (!packet) + { + std::cout << __PRETTY_FUNCTION__ << "\t- Error : Invalid packet, doing nothing" << std::endl; + assert(packet); + return 0; + } + + const int packet_hit_format = packet->getHitFormat(); + if (packet_hit_format != IDTPCFEEV5 && packet_hit_format != IDTPCFEEV6) + { + std::cout << __PRETTY_FUNCTION__ + << "\t- Error : TpcTimeFrameBuilderRun3 only supports packet formats " << IDTPCFEEV5 + << " or " << IDTPCFEEV6 + << " but received packet format " << packet_hit_format + << ". Aborting run." << std::endl; + packet->identify(); + return Fun4AllReturnCodes::ABORTRUN; + } + + if (m_hitFormat < 0) + { + m_hitFormat = packet_hit_format; + + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << " set exact Run3 clock sync for hit format " << m_hitFormat + << " with clock ratio = 30/8" << std::endl; + } + for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + bcoMatchingInformation.set_gtm_clock_ratio(30, 8); + } + } + else if (packet_hit_format != m_hitFormat) + { + std::cout << __PRETTY_FUNCTION__ << "\t- Error : packet format changed for packet " << m_packet_id + << " from " << m_hitFormat << " to " << packet_hit_format + << ". Aborting run." << std::endl; + packet->identify(); + return Fun4AllReturnCodes::ABORTRUN; + } + assert((packet_hit_format == m_hitFormat)); + + + if (m_packet_id != packet->getIdentifier()) + { + std::cout << __PRETTY_FUNCTION__ << "\t- Error : mismatched packet with packet ID expectation of " << m_packet_id << ", but received"; + packet->identify(); + assert(m_packet_id == packet->getIdentifier()); + return 0; + } + + assert(m_packetTimer); + if ((m_verbosity == 1 && (call_count % 1000) == 0) || (m_verbosity > 1)) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : received packet "; + packet->identify(); + + m_packetTimer->print_stat(); + } + m_packetTimer->restart(); + + // //remove after testing + // ; + // std::cout <<"packet->lValue(0, N_TAGGER) = "<lValue(0, "N_TAGGER")<lValue(0, NR_WF) = "<iValue(0, "NR_WF")<Fill("Packet", 1); + + int data_length = packet->getDataLength(); // 32bit length + assert(h_PacketLength); + h_PacketLength->Fill(data_length); + + int data_padding = packet->getPadding(); // 32bit padding + assert(h_PacketLength_Padding); + h_PacketLength_Padding->Fill(data_padding); + if (data_padding != 0) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : suspecious padding " + << data_padding << "\t- in packet " << m_packet_id << ":" << std::endl; + packet->identify(); + // packet->dump(); + } + + size_t dma_words_buffer = static_cast(data_length) * 2 / DAM_DMA_WORD_LENGTH + 1; + std::vector buffer(dma_words_buffer); + + int l2 = 0; + packet->fillIntArray(reinterpret_cast(buffer.data()), data_length + DAM_DMA_WORD_LENGTH / 2, &l2, "DATA"); + + if (data_padding != 0) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : data_length = " << data_length + << "\t- data_padding = " << data_padding << "\t l2 = " << l2 << "\t- in packet " << m_packet_id << ":" << std::endl; + } + + assert(l2 <= data_length); + + if (l2 < data_padding) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : l2 from fillIntArray() is smaller than padding suggesting an invalid data: " << l2 + << "\t- in packet " << m_packet_id << ". Data length: " << data_length + << ", data padding: " << data_padding << ". Ignore this packet: " << std::endl; + packet->identify(); + return Fun4AllReturnCodes::DISCARDEVENT; + } + l2 -= data_padding; + + assert(l2 >= 0); + + size_t dma_words = static_cast(l2) * 2 / DAM_DMA_WORD_LENGTH; + size_t dma_residual = (static_cast(l2) * 2) % DAM_DMA_WORD_LENGTH; + assert(dma_words <= buffer.size()); + assert(h_PacketLength_Residual); + h_PacketLength_Residual->Fill(dma_residual); + if (dma_residual > 0) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : mismatch of RCDAQ data to DMA transfer. Dropping mismatched data: " + << dma_residual << "\t- in packet " << m_packet_id << ". Dropping residual data : " << std::endl; + + assert(dma_words + 1 < buffer.size()); + const dma_word& last_dma_word_data = buffer[dma_words + 1]; + const uint16_t* last_dma_word = reinterpret_cast(&last_dma_word_data); + + for (size_t i = 0; i < dma_residual; ++i) + { + std::cout << "\t- 0x" << std::hex << last_dma_word[i] << std::dec; + } + std::cout << std::endl; + } + + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : packet" << m_packet_id << std::endl + << "\t- data_length = " << data_length << std::endl + << "\t- data_padding = " << data_padding << std::endl + << "\t- dma_words_buffer = " << dma_words_buffer << std::endl + << "\t- l2 = " << l2 << std::endl + << "\t- dma_words = " << dma_words << std::endl; + } + + // demultiplexer + for (size_t index = 0; index < dma_words; ++index) + { + const dma_word& dma_word_data = buffer[index]; + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing DMA word " + << index << "/" << dma_words << "\t- with header 0x" + << std::hex << dma_word_data.dma_header << std::dec << std::endl; + } + + if ((dma_word_data.dma_header & 0xFF00U) == FEE_MAGIC_KEY) + { + unsigned int fee_id = dma_word_data.dma_header & 0xffU; + + // for packet id 4XYZ ebdc is XY, endpoint is Z + if (m_maskedFEEs[((m_packet_id / 10) % 100)].contains(fee_id)) + { + continue; + } + + if (fee_id < MAX_FEECOUNT) + { + for (const uint16_t& i : dma_word_data.data) + { + m_feeData[fee_id].push_back(i); + } + m_hNorm->Fill("DMA_WORD_FEE", 1); + + // immediate fee buffer processing to reduce memory consuption + process_fee_data(fee_id); + } + else + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE ID " << fee_id << "\t- at position " << index << std::endl; + index += DAM_DMA_WORD_LENGTH - 1; + m_hNorm->Fill("DMA_WORD_FEE_INVALID", 1); + } + } + + else if ((dma_word_data.dma_header & 0xFF00U) == GTM_MAGIC_KEY) + { + decode_gtm_data(dma_word_data); + m_hNorm->Fill("DMA_WORD_GTM", 1); + } + else + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Unknown data type at position " << index << ": " + << std::hex << buffer[index].dma_header << std::dec << std::endl; + // not FEE data, e.g. GTM data or other stream, to be decoded + m_hNorm->Fill("DMA_WORD_INVALID", 1); + } + } + + // sanity check for the cached FEE-clock hit size + for (auto& timehit : m_timeHitMap) + { + if (timehit.second.size() > kMaxRawHitLimit) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : impossible amount of hits at FEE BCO " + << timehit.first << "\t- : " << timehit.second.size() << ", limit is " << kMaxRawHitLimit + << ". Dropping this FEE-clock cache!" + << std::endl; + m_hNorm->Fill("TimeFrameSizeLimitError", 1); + + while (!timehit.second.empty()) + { + delete timehit.second.back(); + timehit.second.pop_back(); + } + } + } + + m_packetTimer->stop(); + assert(h_ProcessPacket_Time); + h_ProcessPacket_Time->Fill(call_count, m_packetTimer->elapsed()); + + return Fun4AllReturnCodes::EVENT_OK; +} + +int TpcTimeFrameBuilderRun3::process_fee_data(unsigned int fee) +{ + assert(m_hFEEDataStream); + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing FEE " << fee << "\t- with " << m_feeData[fee].size() << "\t- words" << std::endl; + } + + assert(fee < m_feeData.size()); + std::deque& data_buffer = m_feeData[fee]; + + while (HEADER_LENGTH <= data_buffer.size()) + { + // packet loop + + bool is_digital_current = false; + // test if digital current packet + if (data_buffer[3] == FEE_PACKET_MAGIC_KEY_3_DC) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ + << "\t- : processing FEE " << fee + << "\t- with digital packet" << std::endl; + } + + m_hFEEDataStream->Fill(fee, "WordDigitalCurrentKeyWord", 1); + is_digital_current = true; + } // if (data_buffer[3] == FEE_PACKET_MAGIC_KEY_3) + else + { + if (data_buffer[1] != FEE_PACKET_MAGIC_KEY_1) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE magic key at position 1 0x" << std::hex << data_buffer[1] << std::dec << std::endl; + } + m_hFEEDataStream->Fill(fee, "WordSkipped", 1); + data_buffer.pop_front(); + continue; + } + assert(data_buffer[1] == FEE_PACKET_MAGIC_KEY_1); + + if (data_buffer[2] != FEE_PACKET_MAGIC_KEY_2) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE magic key at position 2 0x" << std::hex << data_buffer[2] << std::dec << std::endl; + } + m_hFEEDataStream->Fill(fee, "WordSkipped", 1); + data_buffer.pop_front(); + continue; + } + assert(data_buffer[2] == FEE_PACKET_MAGIC_KEY_2); + } + + // valid packet + const uint16_t pkt_length = data_buffer[0]; // this is indeed the number of 10-bit words + 5 in this packet + if (pkt_length > MAX_PACKET_LENGTH) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE pkt_length " << pkt_length << std::endl; + } + m_hFEEDataStream->Fill(fee, "InvalidLength", 1); + data_buffer.pop_front(); + continue; + } + + if (pkt_length + 1U > data_buffer.size()) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : packet over buffer boundary for now, skip decoding and wait for more data: " + " pkt_length = " + << pkt_length + << "\t- data_buffer.size() = " << data_buffer.size() + << std::endl; + } + break; + } + + if (is_digital_current) + { + process_fee_data_digital_current(fee, data_buffer); + } + else + { + process_fee_data_waveform(fee, data_buffer); + } + data_buffer.erase(data_buffer.begin(), data_buffer.begin() + pkt_length + 1); + m_hFEEDataStream->Fill(fee, "WordValid", pkt_length + 1); + + } // while (HEADER_LENGTH < data_buffer.size()) + + return Fun4AllReturnCodes::EVENT_OK; +} + +void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, std::deque& data_buffer) +{ + const uint16_t& pkt_length = data_buffer[0]; + + fee_payload payload; + // continue the decoding + payload.fee_id = fee; + payload.adc_length = data_buffer[0] - HEADER_LENGTH; // this is indeed the number of 10-bit words in this packet + payload.data_parity = data_buffer[4] >> 9U; + payload.sampa_address = static_cast(data_buffer[4] >> 5U) & 0xfU; + payload.sampa_channel = data_buffer[4] & 0x1fU; + payload.channel = data_buffer[4] & 0x1ffU; + payload.type = static_cast(data_buffer[3] >> 7U) & 0x7U; + payload.user_word = data_buffer[3] & 0x7fU; + payload.bx_timestamp = static_cast(static_cast(data_buffer[6] & 0x3ffU) << 10U) | (data_buffer[5] & 0x3ffU); + payload.data_crc = data_buffer[pkt_length]; + + if (!m_fastBCOSkip) + { + auto crc_parity = crc16_parity(fee, pkt_length); + payload.calc_crc = crc_parity.first; + payload.calc_parity = crc_parity.second; + + if (payload.data_crc != payload.calc_crc) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : CRC error in FEE " + << fee << "\t- at position " << pkt_length - 1 + << ": data_crc = " << payload.data_crc + << "\t- calc_crc = " << payload.calc_crc << std::endl; + } + m_hFEEDataStream->Fill(fee, "HitCRCError", 1); + // continue; + } + + if (payload.data_parity != payload.calc_parity) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : parity error in FEE " + << fee << "\t- at position " << pkt_length - 1 + << ": data_parity = " << payload.data_parity + << "\t- calc_parity = " << payload.calc_parity << std::endl; + } + m_hFEEDataStream->Fill(fee, "ParityError", 1); + // continue; + } + } // if (not m_fastBCOSkip) + + assert(fee < m_bcoMatchingInformation_vec.size()); + BcoMatchingInformation& m_bcoMatchingInformation = m_bcoMatchingInformation_vec[fee]; + // gtm_bco matching + if (payload.type == TpcTimeFrameBuilderRun3::BcoMatchingInformation::HEARTBEAT_T) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ + << "\t- : received heartbeat packet from FEE " << fee << std::endl; + } + + // if bco matching information is still not verified, drop the packet + if (!m_bcoMatchingInformation.is_verified()) + { + m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncUnavailable", 1); + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3::process_fee_data - bco_matching not verified for heart beat, dropping packet" << std::endl; + m_bcoMatchingInformation.print_gtm_bco_information(); + } + } + else // if (not m_bcoMatchingInformation.is_verified()) + { + const std::optional result = m_bcoMatchingInformation.find_reference_heartbeat(payload); + m_hFEEDataStream->Fill(fee, "PacketHeartBeat", 1); + + if (result) + { + // assign gtm bco + payload.gtm_bco = result.value(); + payload.has_clock_sync = true; + m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncOK", 1); + + assert(m_hFEESAMPAHeartBeatSync); + m_hFEESAMPAHeartBeatSync->Fill(fee * MAX_SAMPA + payload.sampa_address, 1); + } + else + { + m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncError", 1); + + // skip the waverform + } + if (m_verbosity > 2) + { + m_bcoMatchingInformation.print_gtm_bco_information(); + } + } + } + else if (!m_fastBCOSkip) // if (payload.type == m_bcoMatchingInformation.HEARTBEAT_T) + { + m_hFEEChannelPacketCount->Fill(fee * MAX_CHANNELS + payload.channel, 1); + + // if bco matching information is still not verified, drop the packet + if (!m_bcoMatchingInformation.is_verified()) + { + m_hFEEDataStream->Fill(fee, "PacketClockSyncUnavailable", 1); + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3::process_fee_data - bco_matching not verified, dropping packet" << std::endl; + m_bcoMatchingInformation.print_gtm_bco_information(); + } + } + else + { + payload.has_clock_sync = true; + m_hFEEDataStream->Fill(fee, "PacketClockSyncOK", 1); + } + } + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : received data packet " + << "\t- from FEE " << fee << std::endl + << "\t- pkt_length = " << pkt_length << std::endl + << "\t- type = " << payload.type << std::endl + << "\t- adc_length = " << payload.adc_length << std::endl + << "\t- sampa_address = " << payload.sampa_address << std::endl + << "\t- sampa_channel = " << payload.sampa_channel << std::endl + << "\t- channel = " << payload.channel << std::endl + << "\t- bx_timestamp = 0x" << std::hex << payload.bx_timestamp << std::dec << std::endl + << "\t- bco = 0x" << std::hex << payload.gtm_bco << std::dec << std::endl + << "\t- data_crc = 0x" << std::hex << payload.data_crc << std::dec << std::endl + << "\t- calc_crc = 0x" << std::hex << payload.calc_crc << std::dec << std::endl + << "\t- data_parity = 0x" << std::hex << payload.data_parity << std::dec << std::endl + << "\t- calc_parity = 0x" << std::hex << payload.calc_parity << std::dec << std::endl; + } + + if ((!m_fastBCOSkip) && payload.has_clock_sync) + { + m_hFEEDataStream->Fill(fee, "RawHit", 1); + + // Format is (N sample) (start time), (1st sample)... (Nth sample) + size_t pos = HEADER_LENGTH; + std::deque::const_iterator data_buffer_iterator = data_buffer.cbegin(); + std::advance(data_buffer_iterator, pos); + while (pos + 2 < pkt_length) + { + const uint16_t& nsamp = *data_buffer_iterator; + ++pos; + ++data_buffer_iterator; + const uint16_t& start_t = *data_buffer_iterator; + ++pos; + ++data_buffer_iterator; + if (m_verbosity > 3) + { + std::cout << __PRETTY_FUNCTION__ << ": nsamp: " << nsamp + << "+ pos: " << pos + << " pkt_length: " << pkt_length << " start_t:" << start_t << std::endl; + } + + if (pos + nsamp > pkt_length) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << ": WARNING : nsamp: " << nsamp + << "+ pos: " << pos + << " > pkt_length: " << pkt_length << ", format error over length: " << std::endl; + + for (int print_pos = 0; print_pos <= pkt_length; ++print_pos) + { + std::cout << "\t[" << print_pos << "]=0x" << std::hex << data_buffer[print_pos] << std::dec << "(" << data_buffer[print_pos] << ")"; + } + std::cout << std::endl; + } + m_hFEEDataStream->Fill(fee, "HitFormatErrorOverLength", 1); + + break; + } + + const unsigned int fee_sampa_address = fee * MAX_SAMPA + payload.sampa_address; + std::vector adc(nsamp); + for (int j = 0; j < nsamp; j++) + { + const uint16_t& adc_value = *data_buffer_iterator; + + adc[j] = adc_value; + m_hFEESAMPAADC->Fill(start_t + j, fee_sampa_address, adc_value); + + ++pos; + ++data_buffer_iterator; // data_buffer[pos++]; + } + payload.waveforms.emplace_back(start_t, std::move(adc)); + + // // an exception to deal with the last sample that is missing in the current hit format + // if (pos + 1 == pkt_length) break; + } + + if (pos != pkt_length) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << ": WARNING : residual data at the end of decoding:" + << " pos: " << pos + << " Fill(fee, "HitFormatErrorMismatchedLength", 1); + } + + // valid packet in the buffer, create a new hit + if (payload.type != TpcTimeFrameBuilderRun3::BcoMatchingInformation::HEARTBEAT_T) + { + TpcRawHitv3* hit = new TpcRawHitv3(); + m_timeHitMap[payload.bx_timestamp & kFEEClockMask].push_back(hit); + + hit->set_bco(payload.bx_timestamp); + hit->set_packetid(m_packet_id); + hit->set_fee(fee); + hit->set_channel(payload.channel); + hit->set_type(payload.type); + // hit->set_checksum(payload.data_crc); + hit->set_checksumerror(payload.data_crc != payload.calc_crc); + // hit->set_parity(payload.data_parity); + hit->set_parityerror(payload.data_parity != payload.calc_parity); + + for (std::pair>& waveform : payload.waveforms) + { + hit->move_adc_waveform(waveform.first, std::move(waveform.second)); + } + } + } // if (not m_fastBCOSkip) + + return; +} + +void TpcTimeFrameBuilderRun3::process_fee_data_digital_current(const unsigned int& fee, std::deque& data_buffer) +{ + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing digital_current data " << std::endl; + } + m_hFEEDataStream->Fill(fee, "DigitalCurrent", 1); + const uint16_t& pkt_length = data_buffer[0]; + + if (pkt_length != HEADER_LENGTH + digital_current_payload::MAX_CHANNELS * 2 * 2) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE pkt_length " << pkt_length + << ", expected at least " << HEADER_LENGTH + digital_current_payload::MAX_CHANNELS * 2 * 2 + << std::endl; + } + m_hFEEDataStream->Fill(fee, "DigitalCurrentFormatErrorMismatchedLength", 1); + return; + } + + digital_current_payload payload; + + payload.fee = fee; + payload.pkt_length = pkt_length; + payload.sampa_address = (data_buffer[4] >> 5U) & 0xfU; // NOLINT(hicpp-signed-bitwise) + // payload.sampa_max_channel = data_buffer[4] & 0x1fU; + payload.channel = data_buffer[4] & 0x1ffU; + // payload.type = data_buffer[3]; + payload.bx_timestamp = ((data_buffer[6] & 0x3ffU) << 10U) | (data_buffer[5] & 0x3ff); // NOLINT(hicpp-signed-bitwise) + + uint16_t pos = HEADER_LENGTH; + for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++) + { + payload.current[ich] = ((unsigned int) data_buffer[pos]) << 16U | ((unsigned int) data_buffer[pos + 1U]); + pos++; + pos++; + payload.nsamples[ich] = ((unsigned int) data_buffer[pos]) << 16U | ((unsigned int) data_buffer[pos + 1U]); + pos++; + pos++; + } + + if (pos != pkt_length) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : residual data at the end of decoding:" + << " pos: " << pos + << " 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : CRC error in FEE " + << fee << "\t- at position " << pkt_length - 1 + << ": data_crc = " << payload.data_crc + << "\t- calc_crc = " << payload.calc_crc << std::endl; + } + m_hFEEDataStream->Fill(fee, "DigitalCurrentCRCError", 1); + // continue; + } + + assert(fee < m_bcoMatchingInformation_vec.size()); + BcoMatchingInformation& m_bcoMatchingInformation = m_bcoMatchingInformation_vec[fee]; + std::tie(payload.gtm_bco, payload.bx_timestamp_predicted) = m_bcoMatchingInformation.find_dc_read_bco(); + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : received digital current packet " + << "\t- from FEE " << fee << std::endl + << "\t- pkt_length = " << pkt_length << std::endl + << "\t- sampa_address = " << payload.sampa_address << std::endl + << "\t- channel = " << payload.channel << std::endl + << "\t- bx_timestamp = 0x" << std::hex << payload.bx_timestamp << std::dec << std::endl + << "\t- gtm_bco = 0x" << std::hex << payload.gtm_bco << std::dec << std::endl + << "\t- bx_timestamp_predicted = 0x" << std::hex << payload.bx_timestamp_predicted << std::dec << std::endl; + + std::cout << "\t- current:"; + for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++) + { + std::cout << "\t[" << ich << "] = " << payload.current[ich]; + } + std::cout << std::endl; + std::cout << "\t- nsamples:"; + for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++) + { + std::cout << "\t[" << ich << "] = " << payload.nsamples[ich]; + } + std::cout << std::endl; + std::cout << "\t- data_crc = 0x" << std::hex << payload.data_crc << std::dec << std::endl + << "\t- calc_crc = 0x" << std::hex << payload.calc_crc << std::dec << std::endl; + } + + if (m_digitalCurrentDebugTTree) + { + m_digitalCurrentDebugTTree->fill(payload); + } + + return; +} + +void TpcTimeFrameBuilderRun3::SaveDigitalCurrentDebugTTree(const std::string& name) +{ + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Saving digital current debug TTree to " << name << std::endl; + } + + m_digitalCurrentDebugTTree = new TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree(name); +} + +TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree::DigitalCurrentDebugTTree(const std::string& name) + : m_name(name) +{ + // open TFile + PHTFileServer::open(m_name, "RECREATE"); + + // cppcheck-suppress noCopyConstructor + // cppcheck-suppress noOperatorEq + m_tDigitalCurrent = new TTree("T_DigitalCurrent", "DigitalCurrent Debug TTree"); + assert(m_tDigitalCurrent); + + m_tDigitalCurrent->Branch("dc", &m_payload, + "gtm_bco/l:bx_timestamp_predicted/i:fee/s:pkt_length/s:channel/s:sampa_address/s:bx_timestamp/i:current[8]/i:nsamples[8]/i:data_crc/s:calc_crc/s"); +} + +TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree::~DigitalCurrentDebugTTree() +{ + // open TFile + PHTFileServer::write(m_name); +} + +void TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree::fill(const TpcTimeFrameBuilderRun3::digital_current_payload& payload) +{ + assert(m_tDigitalCurrent); + + m_payload = payload; + m_tDigitalCurrent->Fill(); +} + +int TpcTimeFrameBuilderRun3::decode_gtm_data(const TpcTimeFrameBuilderRun3::dma_word& gtm_word) +{ + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing GTM data " << std::endl; + } + + const uint8_t* gtm = reinterpret_cast(>m_word); + + gtm_payload payload; + + payload.pkt_type = gtm[0] | static_cast((unsigned short) gtm[1] << 8U); + // if (payload.pkt_type != GTM_LVL1_ACCEPT_MAGIC_KEY && payload.pkt_type != GTM_ENDAT_MAGIC_KEY) + if (payload.pkt_type != GTM_LVL1_ACCEPT_MAGIC_KEY && payload.pkt_type != GTM_ENDAT_MAGIC_KEY && payload.pkt_type != GTM_MODEBIT_MAGIC_KEY) + { + return -1; + } + + payload.is_lvl1 = payload.pkt_type == GTM_LVL1_ACCEPT_MAGIC_KEY; + payload.is_endat = payload.pkt_type == GTM_ENDAT_MAGIC_KEY; + payload.is_modebit = payload.pkt_type == GTM_MODEBIT_MAGIC_KEY; + + payload.bco = ((unsigned long long) gtm[2] << 0U) | ((unsigned long long) gtm[3] << 8U) | ((unsigned long long) gtm[4] << 16U) | ((unsigned long long) gtm[5] << 24U) | ((unsigned long long) gtm[6] << 32U) | (((unsigned long long) gtm[7]) << 40U); + payload.lvl1_count = ((unsigned int) gtm[8] << 0U) | ((unsigned int) gtm[9] << 8U) | ((unsigned int) gtm[10] << 16U) | ((unsigned int) gtm[11] << 24U); + payload.endat_count = ((unsigned int) gtm[12] << 0U) | ((unsigned int) gtm[13] << 8U) | ((unsigned int) gtm[14] << 16U) | ((unsigned int) gtm[15] << 24U); + payload.last_bco = ((unsigned long long) gtm[16] << 0U) | ((unsigned long long) gtm[17] << 8U) | ((unsigned long long) gtm[18] << 16U) | ((unsigned long long) gtm[19] << 24U) | ((unsigned long long) gtm[20] << 32U) | (((unsigned long long) gtm[21]) << 40U); + payload.modebits = gtm[22]; + payload.userbits = gtm[23]; + + if (m_verbosity >= 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- GTM data : " + << "\t- pkt_type = " << payload.pkt_type << std::endl + << "\t- is_lvl1 = " << payload.is_lvl1 << std::endl + << "\t- is_endat = " << payload.is_endat << std::endl + << "\t- is_modebit = " << payload.is_modebit << std::endl + << "\t- bco = 0x" << std::hex << payload.bco << std::dec << std::endl + << "\t- lvl1_count = " << payload.lvl1_count << std::endl + << "\t- endat_count = " << payload.endat_count << std::endl + << "\t- last_bco = 0x" << std::hex << payload.last_bco << std::dec << std::endl + << "\t- modebits = 0x" << std::hex << (int) payload.modebits << std::dec << std::endl + << "\t- userbits = 0x" << std::hex << (int) payload.userbits << std::dec << std::endl; + } + + if (payload.is_modebit) + { + if (payload.modebits == BcoMatchingInformation::ELINK_HEARTBEAT_T) + { + if (m_verbosity > 2) + { + std::cout << "\t- (Heartbeat modebit)" << std::endl; + } + assert(m_hNorm); + m_hNorm->Fill("DMA_WORD_GTM_HEARTBEAT", 1); + } + + if (payload.modebits == BcoMatchingInformation::DC_STOP_SEND_T) + { + if (m_verbosity > 2) + { + std::cout << "\t- (DC stop send modebit)" << std::endl; + } + assert(m_hNorm); + m_hNorm->Fill("DMA_WORD_GTM_DC_STOP_SEND", 1); + } + } + + if (!(m_fastBCOSkip && (payload.is_lvl1 || payload.is_endat))) + { + int fee = -1; + for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + ++fee; + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing GTM data for FEE " << fee << std::endl; + } + + bcoMatchingInformation.save_gtm_bco_information(payload); + + if (m_verbosity > 2) + { + bcoMatchingInformation.print_gtm_bco_information(); + } + } + } // if (not m_fastBCOSkip) + + return 0; +} + +uint16_t TpcTimeFrameBuilderRun3::reverseBits(const uint16_t x) const +{ + uint16_t n = x; + n = (static_cast(n >> 1U) & 0x55555555U) | (static_cast(n << 1U) & 0xaaaaaaaaU); + n = (static_cast(n >> 2U) & 0x33333333U) | (static_cast(n << 2U) & 0xccccccccU); + n = (static_cast(n >> 4U) & 0x0f0f0f0fU) | (static_cast(n << 4U) & 0xf0f0f0f0U); + n = (static_cast(n >> 8U) & 0x00ff00ffU) | (static_cast(n << 8U) & 0xff00ff00U); + // n = (n >> 16U) & 0x0000ffffU | (n << 16U) & 0xffff0000U; + return n; +} + +std::pair TpcTimeFrameBuilderRun3::crc16_parity(const uint32_t fee, const uint16_t l) const +{ + const std::deque& data_buffer = m_feeData[fee]; + assert(l < data_buffer.size()); + + std::deque::const_iterator it = data_buffer.begin(); + + uint16_t crc = 0xffffU; + uint16_t data_parity = 0U; + + for (int i = 0; i < l; ++i, ++it) + { + const uint16_t& x = *it; + + crc ^= reverseBits(x); + for (uint16_t k = 0; k < 16U; k++) + { + crc = crc & 1U ? static_cast(crc >> 1U) ^ 0xa001U : crc >> 1U; + } + + // parity on data payload only + if (i >= HEADER_LENGTH) + { + // fast parity + uint16_t word = x & uint16_t((1U << 10U) - 1U); + word = word ^ static_cast(word >> 1U); + word = word ^ static_cast(word >> 2U); + word = word ^ static_cast(word >> 4U); + word = word ^ static_cast(word >> 8U); + data_parity ^= word & 1U; + } + } + crc = reverseBits(crc); + return std::make_pair(crc, data_parity); +} + +namespace +{ + // streamer for lists + template + std::ostream& operator<<(std::ostream& o, const std::list& list) + { + if (list.empty()) + { + o << "{}"; + } + else + { + const bool is_hex = (o.flags() & std::ios_base::hex); + o << "{ "; + bool first = true; + for (const auto& value : list) + { + if (!first) + { + o << ", "; + } + if (is_hex) + { + o << "0x"; + } + o << value; + first = false; + } + o << "\t- }"; + } + return o; + } + + template + std::ostream& operator<<(std::ostream& o, const std::vector& list) + { + if (list.empty()) + { + o << "{}"; + } + else + { + const bool is_hex = (o.flags() & std::ios_base::hex); + o << "{ "; + bool first = true; + for (const auto& value : list) + { + if (!first) + { + o << ", "; + } + if (is_hex) + { + o << "0x"; + } + o << value; + first = false; + } + o << "\t- }"; + } + return o; + } + +} // namespace + +TpcTimeFrameBuilderRun3::BcoMatchingInformation::BcoMatchingInformation(const std::string& name) + : m_name(name) +{ + Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + // cppcheck-suppress noCopyConstructor + // cppcheck-suppress noOperatorEq + m_hNorm = new TH1D(TString(m_name.c_str()) + "_Normalization", // + TString(m_name.c_str()) + " Normalization;Items;Count", + 20, .5, 20.5); + int i = 1; + m_hNorm->GetXaxis()->SetBinLabel(i++, "SyncGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DC_STOP_SEND_GTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEE"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEMatchedReference"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEMatchedNew"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEUnMatched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "TriggerGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "EnDATGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "UnmatchedEnDATGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCO"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedExisting"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedNew"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedFailed"); + + assert(i <= 20); + m_hNorm->GetXaxis()->LabelsOption("v"); + hm->registerHisto(m_hNorm); + + m_hFEEClockAdjustment_MatchedReference = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_MatchedReference", // + TString(m_name.c_str()) + + " FEEClockAdjustment for Matched Reference;Clock Adjustment [FEE Clock Cycle];Count", + 512, -256 - .5, +256 - .5); + hm->registerHisto(m_hFEEClockAdjustment_MatchedReference); + m_hFEEClockAdjustment_MatchedNew = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_MatchedNew", // + TString(m_name.c_str()) + + " FEEClockAdjustment for Matched New;Clock Adjustment [FEE Clock Cycle];Count", + 512, -256 - .5, +256 - .5); + hm->registerHisto(m_hFEEClockAdjustment_MatchedNew); + + m_hFEEClockAdjustment_Unmatched = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_Unmatched", // + TString(m_name.c_str()) + + " FEEClock Diff for unmatched;Clock Adjustment [FEE Clock Cycle];Count", + 512, + -(1UL << m_FEE_CLOCK_BITS) - .5, + +(1UL << m_FEE_CLOCK_BITS) - .5); + hm->registerHisto(m_hFEEClockAdjustment_Unmatched); + + m_hGTMNewEventSpacing = new TH1I(TString(m_name.c_str()) + + "_GTM_NewEventSpacing", // + TString(m_name.c_str()) + + " Spacing between two events;Clock Diff [RHIC Clock Cycle];Count", + 1024, -.5, +1024 - .5); + hm->registerHisto(m_hGTMNewEventSpacing); + + m_hFindGTMBCO_MatchedExisting_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedExisting_BCODiff", // + TString(m_name.c_str()) + + " find_gtm_bco matched to existing event clock diff;Clock Difference [FEE Clock Cycle];Count", + 512, -256 - .5, +256 - .5); + hm->registerHisto(m_hFindGTMBCO_MatchedExisting_BCODiff); + m_hFindGTMBCO_MatchedNew_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedNew_BCODiff", // + TString(m_name.c_str()) + + " find_gtm_bco matched to new event clock diff;Clock Difference [FEE Clock Cycle];Count", + 512, -256 - .5, +256 - .5); + hm->registerHisto(m_hFindGTMBCO_MatchedNew_BCODiff); +} + +//! whether reference bco has moved pass the given gtm_bco +bool TpcTimeFrameBuilderRun3::BcoMatchingInformation::isMoreDataRequired(const uint64_t& gtm_bco) const +{ + const uint64_t bco_correction = get_gtm_rollover_correction(gtm_bco); + + if (m_verbosity >= 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired entry" + << " at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << std::endl; + } + + if (m_bco_reference) + { + if (m_bco_reference.value().first > bco_correction + m_max_fee_sync_time) + { + if (m_verbosity >= 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << " at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". m_bco_reference.value().first = 0x" << std::hex << m_bco_reference.value().first << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << ". satisified m_max_fee_sync_time = " << m_max_fee_sync_time + << std::endl; + } + + return false; + } + } + + if (!m_bco_reference_candidate_list.empty()) + { + if (m_bco_reference_candidate_list.back().first > bco_correction + m_max_fee_sync_time) + { + if (m_verbosity >= 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". m_bco_reference_candidate_list.back().first = 0x" << std::hex << m_bco_reference_candidate_list.back().first << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << ". satisified m_max_fee_sync_time = " << m_max_fee_sync_time + << std::endl; + } + + return false; + } + + if (m_verbosity > 4) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". m_bco_reference_candidate_list.back().first = 0x" << std::hex << m_bco_reference_candidate_list.back().first << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << ". not yet satisified m_max_fee_sync_time = " << m_max_fee_sync_time + << std::endl; + } + } + + if (m_verbosity > 3) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec << ": more data required" + << " as their is NO m_bco_reference nor m_bco_reference_candidate_list" + << std::endl; + + std::cout << " m_gtm_bco_trigger_map:" << std::endl; + for (const auto& trig : m_gtm_bco_trigger_map) + { + std::cout << " - 0x" << std::hex << trig.first << std::dec << "(Diff = " << trig.first - bco_correction << ") " << std::endl; + } + + std::cout << " m_bco_matching_list:" << std::endl; + for (const auto& trig : m_bco_matching_list) + { + std::cout << " - 0x" << std::hex << trig.second << std::dec << "(Diff = " << trig.second - bco_correction << ") " << std::endl; + } + } + return true; +} + +//___________________________________________________ +std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::get_predicted_fee_bco(uint64_t gtm_bco) const +{ + // check proper initialization + if (!is_verified()) + { + return std::nullopt; + } + + // get gtm bco difference with proper rollover accounting + const int64_t gtm_bco_difference = int64_t(gtm_bco) - int64_t(m_bco_reference.value().first); // NOLINT(bugprone-unchecked-optional-access) + + assert(m_clock_ratio_numerator > 0); + assert(m_clock_ratio_denominator > 0); + + // convert to fee bco with the exact Run3 30/8 ratio, and truncate to 20 bits + const int64_t fee_bco_predicted = int64_t(m_bco_reference.value().second) + + (gtm_bco_difference * m_clock_ratio_numerator) / m_clock_ratio_denominator; // NOLINT(bugprone-unchecked-optional-access) + return uint32_t(static_cast(fee_bco_predicted) & 0xFFFFFU); +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::print_gtm_bco_information() const +{ + if (!m_gtm_bco_trig_list.empty()) + { + std::cout + << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::print_gtm_bco_information -" + << "\t- m_gtm_bco_trig_list: " << std::hex << m_gtm_bco_trig_list << std::dec + << std::endl; + + // also print predicted fee bco + if (is_verified()) + { + std::list fee_bco_predicted_list; + std::transform( + m_gtm_bco_trig_list.begin(), + m_gtm_bco_trig_list.end(), + std::back_inserter(fee_bco_predicted_list), + [this](const uint64_t& gtm_bco) + { return get_predicted_fee_bco(gtm_bco).value(); }); + + std::cout + << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::print_gtm_bco_information -" + << "\t- m_gtm_bco_trig_list fee predicted: " << std::hex << fee_bco_predicted_list << std::dec + << std::endl; + } + } + + std::cout << "\t m_gtm_bco_dc_read = " << std::hex + << m_gtm_bco_dc_read.first << " -> 0x" << m_gtm_bco_dc_read.second + << std::dec << std::endl; +} + +uint64_t TpcTimeFrameBuilderRun3::BcoMatchingInformation:: + get_gtm_rollover_correction(const uint64_t& gtm_bco) const +{ + // start with 40bit clock, enforced + uint64_t gtm_bco_corrected = gtm_bco & ((uint64_t(1) << m_GTM_CLOCK_BITS) - 1); + + if (!m_bco_reference) + { + return gtm_bco_corrected; + } + + // get the last GTM clock roll over + const uint64_t& last_bco = m_bco_reference.value().first; + const uint64_t last_bco_rollover = last_bco & + (std::numeric_limits::max() << m_GTM_CLOCK_BITS); + + // use the roll over of the last GTM clock reading + gtm_bco_corrected += last_bco_rollover; + + // check if the rollover has advanced + if (gtm_bco_corrected + (uint64_t(1) << (m_GTM_CLOCK_BITS - 1)) < last_bco) + { + gtm_bco_corrected += uint64_t(1) << m_GTM_CLOCK_BITS; + } + + return gtm_bco_corrected; +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(const TpcTimeFrameBuilderRun3::gtm_payload& gtm_tagger) +{ + // append gtm_bco from taggers in this event to packet-specific list of available lv1_bco + + // save level1 trigger bco + const bool& is_lvl1 = gtm_tagger.is_lvl1; + const bool& is_endat = gtm_tagger.is_endat; + const bool& is_modebit = gtm_tagger.is_modebit; + const uint64_t gtm_bco = get_gtm_rollover_correction(gtm_tagger.bco); + + if (is_lvl1) + { + assert(m_hNorm); + m_hNorm->Fill("TriggerGTM", 1); + + assert(m_hGTMNewEventSpacing); + if (!m_gtm_bco_trig_list.empty()) + { + m_hGTMNewEventSpacing->Fill(gtm_bco - m_gtm_bco_trig_list.back()); + } + m_gtm_bco_trig_list.push_back(gtm_bco); + } + + // also save ENDDAT bco + else if (is_endat) + { + assert(m_hNorm); + m_hNorm->Fill("EnDATGTM", 1); + + // add to list if difference to last entry is big enough + if (m_gtm_bco_trig_list.empty() || (gtm_bco - m_gtm_bco_trig_list.back()) > m_max_lv1_endat_bco_diff) + { + assert(m_hNorm); + m_hNorm->Fill("UnmatchedEnDATGTM", 1); + + if (!m_gtm_bco_trig_list.empty()) + { + assert(m_hGTMNewEventSpacing); + m_hGTMNewEventSpacing->Fill(gtm_bco - m_gtm_bco_trig_list.back()); + } + m_gtm_bco_trig_list.push_back(gtm_bco); + } + } + + // also save hearbeat bco + else if (is_modebit) + { + // get modebits + const uint64_t& modebits = gtm_tagger.modebits; + if (modebits == ELINK_HEARTBEAT_T) + { + assert(m_hNorm); + m_hNorm->Fill("HeartBeatGTM", 1); + + auto predicted_fee_bco = get_predicted_fee_bco(gtm_bco); + if (predicted_fee_bco) + { + m_bco_reference_candidate_list.emplace_back(gtm_bco, predicted_fee_bco.value()); + } + else + { + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information" + << "\t- Warning: predicted_fee_bco is not available for gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". Skipping heartbeat candidate." << std::endl; + } + } + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information" + << "\t- found heartbeat candidate " + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". Current m_bco_reference_candidate_list:" + << std::endl; + + for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_reference_candidate_list) + { + std::cout << "\t- gtm_bco = 0x" << std::hex << bco.first << std::dec + << "\t- fee_bco = 0x" << std::hex << bco.second << std::dec + << std::endl; + } + } + + while (m_bco_reference_candidate_list.size() > m_max_bco_reference_candidate_list_size) + { + if (m_verbosity > 1) + { + uint64_t bco = m_bco_reference_candidate_list.begin()->first; + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits" + << "Warning: m_bco_reference_candidate_list is full" + << "\t- drop unprocessed heart beat in queue " + << "at gtm_bco = 0x" << std::hex << bco + << std::dec + << ". Unprocessed heartbeats in queue with size of " << m_bco_reference_candidate_list.size() + << std::endl; + } + + m_bco_reference_candidate_list.pop_front(); + } + + } // if (modebits & (1U << ELINK_HEARTBEAT_T)) + + if (modebits == BX_COUNTER_SYNC_T) // initiate synchronization of clock sync + { + assert(m_hNorm); + m_hNorm->Fill("SyncGTM", 1); + + // get BCO and assign + m_verified_from_modebits = true; + m_bco_reference = std::make_pair(gtm_bco, 0); + m_bco_reference_candidate_list.clear(); + + if (m_verbosity) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits" + << "\t- found reference from modebits BX_COUNTER_SYNC_T " + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << std::endl; + } + } // if (modebits == BX_COUNTER_SYNC_T) // initiate synchronization of clock sync + + if (modebits == DC_STOP_SEND_T) + { + assert(m_hNorm); + m_hNorm->Fill("DC_STOP_SEND_GTM", 1); + + // save the gtm_bco for the digital current readout + m_gtm_bco_dc_read.first = gtm_bco; + if (is_verified()) + { + m_gtm_bco_dc_read.second = get_predicted_fee_bco(gtm_bco).value(); // NOLINT(bugprone-unchecked-optional-access) + } + else + { + m_gtm_bco_dc_read.second = 0; // not verified, so no reference clock sync available + } + + if (m_verbosity > 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information" + << "\t- found DC stop send modebit " + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << std::endl; + } + } + } +} + +//___________________________________________________ +std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_reference_heartbeat(const TpcTimeFrameBuilderRun3::fee_payload& HeartBeatPacket) +{ + assert(m_hNorm); + m_hNorm->Fill("HeartBeatFEE", 1); + + // make sure the bco matching is properly initialized and historical valid + if (!is_verified()) + { + return std::nullopt; + } + + assert(HeartBeatPacket.type == HEARTBEAT_T); + const uint32_t& fee_bco = HeartBeatPacket.bx_timestamp; + + if (m_bco_reference) + { + const uint64_t& gtm_bco = m_bco_reference.value().first; + const uint32_t& fee_bco_predicted = m_bco_reference.value().second; + // check if the predicted fee bco matches the actual fee bco + if (get_fee_bco_diff(fee_bco_predicted, fee_bco) < m_max_fee_bco_diff) + { + // assign gtm bco + m_bco_reference.value().second = fee_bco; + + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found an updated reference heartbeat and updated reference clock sync: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << fee_bco_predicted + << "\t- gtm_bco: 0x" << gtm_bco + << std::dec + << std::endl; + } + + assert(m_hFEEClockAdjustment_MatchedReference); + m_hFEEClockAdjustment_MatchedReference->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1); + + m_hNorm->Fill("HeartBeatFEEMatchedReference", 1); + + return gtm_bco; + } + } + + for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_reference_candidate_list) + { + const uint64_t gtm_bco = bco.first; + const uint32_t fee_bco_predicted = bco.second; + + // check if the predicted fee bco matches the actual fee bco + if (get_fee_bco_diff(fee_bco_predicted, fee_bco) < m_max_fee_bco_diff) + { + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found a new reference canidate heartbeat and replaced reference clock sync: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << fee_bco_predicted + << "\t- gtm_bco: 0x" << gtm_bco + << "\t- previous reference gtm_bco: 0x" << m_bco_reference.value().first // NOLINT(bugprone-unchecked-optional-access) + << "\t- previous reference fee_bco: 0x" << m_bco_reference.value().second // NOLINT(bugprone-unchecked-optional-access) + << std::dec + << std::endl; + } + // assign gtm bco + m_bco_reference = std::make_pair(gtm_bco, fee_bco); + + if (m_verbosity > 1) + { + std::cout << "\t- trimming m_bco_reference_candidate_list from size " << m_bco_reference_candidate_list.size() << std::endl; + + for (const m_gtm_fee_bco_matching_pair_t& bco_tmp : m_bco_reference_candidate_list) + { + std::cout << "\t\t- gtm_bco = 0x" << std::hex << bco_tmp.first << std::dec + << "\t\t- fee_bco = 0x" << std::hex << bco_tmp.second << std::dec + << std::endl; + } + } + + // remove the older candidate from the list + while (m_bco_reference_candidate_list.begin()->first != gtm_bco) + { + m_bco_reference_candidate_list.pop_front(); + } + m_bco_reference_candidate_list.pop_front(); + + if (m_verbosity > 1) + { + std::cout << "\t- to size " << m_bco_reference_candidate_list.size() << std::endl; + + for (const m_gtm_fee_bco_matching_pair_t& bco_tmp : m_bco_reference_candidate_list) + { + std::cout << "\t\t- gtm_bco = 0x" << std::hex << bco_tmp.first << std::dec + << "\t\t- fee_bco = 0x" << std::hex << bco_tmp.second << std::dec + << std::endl; + } + } + + assert(m_hFEEClockAdjustment_MatchedNew); + m_hFEEClockAdjustment_MatchedNew->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1); + + m_hNorm->Fill("HeartBeatFEEMatchedNew", 1); + return gtm_bco; + } + + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - unmatched heartbeat: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << fee_bco_predicted + << "\t- gtm_bco: 0x" << gtm_bco + << std::dec + << std::endl; + } + + assert(m_hFEEClockAdjustment_Unmatched); + m_hFEEClockAdjustment_Unmatched->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1); + } // for (const auto& bco : m_bco_reference_candidate_list) + + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - WARNING: failed match for fee_bco = 0x" << std::hex << fee_bco << std::dec << std::endl; + } + m_hNorm->Fill("HeartBeatFEEUnMatched", 1); + return std::nullopt; +} + +//___________________________________________________ +std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_gtm_bco(uint32_t fee_bco) +{ + if (verbosity() > 5) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - entry: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << std::dec + << "\t- is_verified(): " << (is_verified() ? "true" : "false") + << std::endl; + } + + // make sure the bco matching is properly initialized + if (!is_verified()) + { + return std::nullopt; + } + + assert(m_hNorm); + m_hNorm->Fill("FindGTMBCO", 1); + + // find matching gtm bco in map + const auto bco_matching_iter = std::find_if( + m_bco_matching_list.begin(), + m_bco_matching_list.end(), + [fee_bco](const m_fee_gtm_bco_matching_pair_t& pair) + { return get_fee_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); + + if (bco_matching_iter != m_bco_matching_list.end()) + { + m_hNorm->Fill("FindGTMBCOMatchedExisting", 1); + assert(m_hFindGTMBCO_MatchedExisting_BCODiff); + m_hFindGTMBCO_MatchedExisting_BCODiff->Fill(int64_t(fee_bco) - int64_t(bco_matching_iter->first)); + + if (verbosity() > 3) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - found existing FEE BCO: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << bco_matching_iter->first + << "\t- gtm_bco: 0x" << bco_matching_iter->second + << std::dec + << std::endl; + } + + return bco_matching_iter->second; + } + // find element for which predicted fee_bco matches fee_bco, within limit + const auto iter = std::find_if( + m_gtm_bco_trig_list.begin(), + m_gtm_bco_trig_list.end(), + [this, fee_bco](const uint64_t& gtm_bco) + { return get_fee_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); + + // check + if (iter != m_gtm_bco_trig_list.end()) + { + const uint64_t gtm_bco = *iter; + + m_hNorm->Fill("FindGTMBCOMatchedNew", 1); + assert(m_hFindGTMBCO_MatchedNew_BCODiff); + m_hFindGTMBCO_MatchedNew_BCODiff->Fill(int64_t(fee_bco) - int64_t(gtm_bco)); + + if (verbosity() > 2) + { + if (auto opt_fee_bco = get_predicted_fee_bco(gtm_bco)) // check if optional exists + { + const uint32_t fee_bco_predicted = *opt_fee_bco; // get_predicted_fee_bco(gtm_bco).value(); + const uint32_t fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco); + + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - new GL1 match: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << fee_bco_predicted + << "\t- gtm_bco: 0x" << gtm_bco + << std::dec + << "\t- difference: " << fee_bco_diff + << std::endl; + } + } + // save fee_bco and gtm_bco matching in map + m_bco_matching_list.emplace_back(fee_bco, gtm_bco); + + // remove gtm bco from runing list + m_gtm_bco_trig_list.erase(iter); + + // // update clock adjustment not applied for non HEARTBEAT_T + // update_multiplier_adjustment(gtm_bco, fee_bco); + + return gtm_bco; + } + + m_hNorm->Fill("FindGTMBCOMatchedFailed", 1); + + bool new_orphan = m_orphans.insert(fee_bco).second; + + if ((new_orphan && verbosity()) || (verbosity() > 3)) + { + // find element for which predicted fee_bco is the closest to request + const auto iter2 = std::min_element( + m_gtm_bco_trig_list.begin(), + m_gtm_bco_trig_list.end(), + [this, fee_bco](const uint64_t& first, const uint64_t& second) + { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); + + // const int fee_bco_diff = (iter2 != m_gtm_bco_trig_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1; + // compared to the previous statement, this checks if the optional + int fee_bco_diff = -1; + + if (iter2 != m_gtm_bco_trig_list.end()) + { + auto predicted = get_predicted_fee_bco(*iter2); + + if (predicted) + { + fee_bco_diff = get_bco_diff(*predicted, fee_bco); + } + } + + if (m_verbosity >= 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - match failed!" + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << std::dec + << "\t- gtm_bco: 0x" << *iter2 + << "\t- difference: " << fee_bco_diff + << std::endl; + } + } // if ((new_orphan and verbosity()) or (verbosity()>3)) + + if (verbosity() > 3) + { + std::cout << "\t- m_gtm_bco_trig_list : " << std::endl; + for (const auto& gtm_bco : m_gtm_bco_trig_list) + { + std::cout << "\t\t- 0x" << std::hex << gtm_bco << " -> 0x" << get_predicted_fee_bco(gtm_bco).value() << std::dec << std::endl; // NOLINT(bugprone-unchecked-optional-access) + } + + std::cout << "\t- m_bco_matching_list : " << std::endl; + for (const auto& iter_m_bco_matching_list : m_bco_matching_list) + { + std::cout << "\t\t- 0x" << std::hex << iter_m_bco_matching_list.first << " -> 0x" << iter_m_bco_matching_list.second << std::dec << std::endl; + } + + } // if (verbosity()>3) + + return std::nullopt; +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup() +{ + // remove old gtm_bco and matching + while (m_gtm_bco_trig_list.size() > m_max_matching_data_size) + { + m_gtm_bco_trig_list.pop_front(); + } + while (m_bco_matching_list.size() > m_max_matching_data_size) + { + m_bco_matching_list.pop_front(); + } + + // clear orphans + m_orphans.clear(); +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup(uint64_t ref_bco) +{ + // erase all elements from bco_list that are less than or equal to ref_bco + m_gtm_bco_trig_list.erase(std::remove_if(m_gtm_bco_trig_list.begin(), m_gtm_bco_trig_list.end(), + [ref_bco](const uint64_t& bco) + { return bco <= ref_bco; }), + m_gtm_bco_trig_list.end()); + + // erase all elements from bco_list that are less than or equal to ref_bco + m_bco_matching_list.erase(std::remove_if(m_bco_matching_list.begin(), m_bco_matching_list.end(), + [ref_bco](const m_fee_gtm_bco_matching_pair_t& pair) + { + return pair.second <= ref_bco; + }), + m_bco_matching_list.end()); + + // clear orphans + m_orphans.clear(); +} + +void TpcTimeFrameBuilderRun3::fillBadFeeMap() +{ + const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); + + if (filename.empty()) + { + if (m_verbosity > 0) + { + std::cout << "TpcTimeFrameBuilderRun3::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; + } + return; + } + + CDBTTree cdbtree(filename); + cdbtree.LoadCalibrations(); + + const int nentries = cdbtree.GetSingleIntValue("N_MASKED_FEES"); + + for (int i = 0; i < nentries; i++) + { + m_maskedFEEs[cdbtree.GetIntValue(i, "EBDC")].insert(cdbtree.GetIntValue(i, "FEEID")); + } +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h new file mode 100644 index 0000000000..a17d9f9570 --- /dev/null +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -0,0 +1,442 @@ +#ifndef Fun4All_TpcTimeFrameBuilderRun3_H +#define Fun4All_TpcTimeFrameBuilderRun3_H + +#include "TpcTimeFrameBuilderBase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Packet; +class TpcRawHit; +class PHTimer; +class TH1; +class TH2; +class TTree; + +// NOLINTNEXTLINE(hicpp-special-member-functions) +class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase +{ + public: + explicit TpcTimeFrameBuilderRun3(const int packet_id); + ~TpcTimeFrameBuilderRun3() override; + + int ProcessPacket(Packet *) override; + bool isMoreDataRequired(const uint64_t >m_bco) const override; + void CleanupUsedPackets(const uint64_t &bclk) override; + std::vector &getTimeFrame(const uint64_t >m_bco) override; + + void setVerbosity(int i) override; + void setFastBCOSkip(bool fastBCOSkip = true) + { + m_fastBCOSkip = fastBCOSkip; + } + + void fillBadFeeMap() override; + + // enable saving of digital current debug TTree with file name `name` + void SaveDigitalCurrentDebugTTree(const std::string &name) override; + + protected: + // Length for the 256-bit wide Round Robin Multiplexer for the data stream + static const size_t DAM_DMA_WORD_LENGTH = 16; + + static const uint16_t FEE_PACKET_MAGIC_KEY_1 = 0xfe; + static const uint16_t FEE_PACKET_MAGIC_KEY_2 = 0xed; + static const uint16_t FEE_PACKET_MAGIC_KEY_3_DC = 0xdcdc; // Digital Current word[3] + + static const uint16_t FEE_MAGIC_KEY = 0xba00; + static const uint16_t GTM_MAGIC_KEY = 0xbb00; + static const uint16_t GTM_LVL1_ACCEPT_MAGIC_KEY = 0xbbf0; + static const uint16_t GTM_ENDAT_MAGIC_KEY = 0xbbf1; + static const uint16_t GTM_MODEBIT_MAGIC_KEY = 0xbbf2; + + static const uint16_t MAX_FEECOUNT = 26; // that many FEEs + static const uint16_t MAX_SAMPA = 8; // that many FEEs + static const uint16_t MAX_CHANNELS = MAX_SAMPA * 32; // that many channels per FEE + // static const uint16_t HEADER_LENGTH = 5; + static const uint16_t HEADER_LENGTH = 7; + static const uint16_t MAX_PACKET_LENGTH = 1025; + + static const uint16_t GL1_BCO_MATCH_WINDOW = 256; // BCOs + + int m_hitFormat = -1; + + uint16_t reverseBits(const uint16_t x) const; + std::pair crc16_parity(const uint32_t fee, const uint16_t l) const; + + //! DMA word structure + struct dma_word + { + uint16_t dma_header = 0; + uint16_t data[DAM_DMA_WORD_LENGTH - 1] = {0}; + }; + + int decode_gtm_data(const dma_word >m_word); + int process_fee_data(unsigned int fee_id); + void process_fee_data_waveform(const unsigned int &fee_id, std::deque &data_buffer); + void process_fee_data_digital_current(const unsigned int &fee_id, std::deque &data_buffer); + + struct gtm_payload + { + uint16_t pkt_type = 0; + bool is_endat = false; + bool is_lvl1 = false; + bool is_modebit = false; + uint64_t bco = 0; + uint32_t lvl1_count = 0; + uint32_t endat_count = 0; + uint64_t last_bco = 0; + uint8_t modebits = 0; + uint8_t userbits = 0; + }; + + struct fee_payload + { + uint16_t fee_id = 0; + uint16_t adc_length = 0; + uint16_t sampa_address = 0; + uint16_t sampa_channel = 0; + uint16_t channel = 0; + uint16_t type = 0; + uint16_t user_word = 0; + uint32_t bx_timestamp = 0; + uint64_t gtm_bco = 0; + bool has_clock_sync = false; + + uint16_t data_crc = 0; + uint16_t calc_crc = 0; + + uint16_t data_parity = 0; + uint16_t calc_parity = 0; + + std::vector>> waveforms; + }; + + struct digital_current_payload + { + static const int MAX_CHANNELS = 8; + + uint64_t gtm_bco{std::numeric_limits::max()}; + uint32_t bx_timestamp_predicted{std::numeric_limits::max()}; + + uint16_t fee{std::numeric_limits::max()}; + uint16_t pkt_length{std::numeric_limits::max()}; + uint16_t channel{std::numeric_limits::max()}; + // uint16_t sampa_max_channel {std::numeric_limits::max()}; + uint16_t sampa_address{std::numeric_limits::max()}; + uint32_t bx_timestamp{0}; + uint32_t current[MAX_CHANNELS]{0}; + uint32_t nsamples[MAX_CHANNELS]{0}; + uint16_t data_crc{std::numeric_limits::max()}; + uint16_t calc_crc = {std::numeric_limits::max()}; + // uint16_t type {std::numeric_limits::max()}; + }; + + class DigitalCurrentDebugTTree + { + public: + explicit DigitalCurrentDebugTTree(const std::string &name); + virtual ~DigitalCurrentDebugTTree(); + + void fill(const digital_current_payload &payload); + + private: + digital_current_payload m_payload; + + std::string m_name; + TTree *m_tDigitalCurrent = nullptr; + }; + DigitalCurrentDebugTTree *m_digitalCurrentDebugTTree = nullptr; + + // ------------------------- + // GTM Matcher + // Initially developped by Hugo Pereira Da Costa as `MicromegasBcoMatchingInformation` + // ------------------------- + class BcoMatchingInformation + { + public: + //! constructor + explicit BcoMatchingInformation(const std::string &name); + + //!@name accessor + //@{ + + //! verbosity + int verbosity() const + { + return m_verbosity; + } + + //! true if matching information is verified + /** + * matching information is verified if at least one match + * between gtm_bco and fee_bco is found + */ + bool is_verified() const + { + return m_verified_from_modebits || m_verified_from_data; + } + + //! matching between fee bco and lvl1 bco + using m_gtm_fee_bco_matching_pair_t = std::pair; + using m_fee_gtm_bco_matching_pair_t = std::pair; + + //! get reference bco + const std::optional &get_reference_bco() const + { + return m_bco_reference; + } + + //! whether FEE data has moved pass the given gtm_bco + bool isMoreDataRequired(const uint64_t >m_bco) const; + + //! get predicted fee_bco from gtm_bco + std::optional get_predicted_fee_bco(uint64_t) const; + + //! multiplier + double get_gtm_clock_multiplier() + { + return m_multiplier; + } + + //! print gtm bco information + void print_gtm_bco_information() const; + + //@} + + //!@name modifiers + //@{ + + //! verbosity + void set_verbosity(int value) + { + m_verbosity = value; + } + + /// set gtm clock multiplier + void set_gtm_clock_multiplier(double value) + { + m_multiplier = value; + } + + void set_gtm_clock_ratio(int64_t numerator, int64_t denominator) + { + m_clock_ratio_numerator = numerator; + m_clock_ratio_denominator = denominator; + m_multiplier = static_cast(numerator) / static_cast(denominator); + } + + /// set gtm clock with rollover correction + uint64_t get_gtm_rollover_correction(const uint64_t >m_bco) const; + + //! find reference from data + std::optional find_reference_heartbeat(const fee_payload &HeartBeatPacket); + + //! save all GTM BCO clocks from packet data + void save_gtm_bco_information(const gtm_payload >m_tagger); + + //! find gtm bco matching a given fee + std::optional find_gtm_bco(uint32_t /*fee_gtm*/); + + //! cleanup + void cleanup(); + + //! cleanup + void cleanup(uint64_t /*ref_bco*/); + + m_gtm_fee_bco_matching_pair_t find_dc_read_bco() const + { + return m_gtm_bco_dc_read; + } + //@} + + /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ + enum SampaDataType + { + HEARTBEAT_T = 0b000, + TRUNCATED_DATA_T = 0b001, + TRUNCATED_TRIG_EARLY_DATA_T = 0b011, + NORMAL_DATA_T = 0b100, + LARGE_DATA_T = 0b101, + TRIG_EARLY_DATA_T = 0b110, + TRIG_EARLY_LARGE_DATA_T = 0b111, + }; + + // Command | OLD Mode-Bit | New Mode-Number | Function + // ====================================================== + // NOP | 0b000 | 0x0 | No Operation + // BX_SYNC | 0b001 | 0x1 | SAMPA Beam-crossing sync + // H_BEAT | 0b010 | 0x2 | Generates Heartbeat frame + // TRIG | 0b100 | 0x3 | Trigger data when FEM user bit is 0b01, otherwise the level 1 accept is used when FEM user bit is 0b00 + // CLK_SYNC | N/A | 0x4 | Reset and align 40 MHz and 20 MHz clocks to SAMPA + // SAMPA_RST | N/A | 0x5 | Hard reset SAMPA + // DC_START | N/A | 0x6 | Start digital current reading + // DC_STOP | N/A | 0x7 | Stop and send digital current packet + enum ModeBitType + { + BX_COUNTER_SYNC_T = 0x1, + ELINK_HEARTBEAT_T = 0x2, + DC_STOP_SEND_T = 0x7 + // SAMPA_EVENT_TRIGGER_T = 2, + // CLEAR_LV1_LAST_T = 6, + // CLEAR_LV1_ENDAT_T = 7 + }; + + // get the difference between two BCO WITHOUT rollover corrections + template + inline static constexpr T get_bco_diff( + const T &first, const T &second) + { + return first < second ? (second - first) : (first - second); + } + + // get the difference between two BCO with rollover corrections + inline static constexpr uint32_t get_fee_bco_diff( + const uint32_t &first, const uint32_t &second) // NOLINT(misc-unused-parameters) + { + const uint32_t diff_raw = get_bco_diff(first, second); + + return (diff_raw < (1U << (m_FEE_CLOCK_BITS / 2))) ? diff_raw : (1U << m_FEE_CLOCK_BITS) - diff_raw; + } + + private: + std::string m_name; + + //! verbosity + unsigned int m_verbosity = 0; + + //! verified + bool m_verified_from_modebits = false; + + bool m_verified_from_data = false; + + //! list of available bco, sorted in time with rollover corrected + std::list m_gtm_bco_trig_list; + + //! last digital current readout GTM BCO + m_gtm_fee_bco_matching_pair_t m_gtm_bco_dc_read = {0, 0}; + + //! list of available GTM -> FEE bco mapping for synchronization + std::optional m_bco_reference = std::nullopt; + + // std::optional< std::pair< uint64_t, uint32_t > > m_bco_reference_candidate = std::nullopt; + //! not yet matched heart beats + std::list m_bco_reference_candidate_list; + static constexpr unsigned int m_max_bco_reference_candidate_list_size = 16; + + // //! list of heart beat GTM BCO that is still to be matched + // std::queue m_heartbeat_gtm_bco_queue; + // static constexpr unsigned int m_max_heartbeat_queue_size = 16; + + //! list of available GTM -> FEE bco mapping for trigger association + std::map m_gtm_bco_trigger_map; + + std::list m_bco_matching_list; + + //! keep track or fee_bco for which no gtm_bco is found + std::set m_orphans; + + // define limit for matching two lvl1 and EnDAT tagger BCOs + static constexpr int m_max_lv1_endat_bco_diff = 16; + + // define limit for matching two fee_bco + static constexpr unsigned int m_max_fee_bco_diff = 64; + + // define limit for matching gtm_bco from lvl1 to enddat + + // define limit for matching fee_bco to fee_bco_predicted + static constexpr unsigned int m_max_gtm_bco_diff = 256; + + // // needed to avoid memory leak. Assumes that we will not be assembling more than 50 events at the same time + static constexpr unsigned int m_max_matching_data_size = 10; + + //! max time in GTM BCO for FEE data to sync over to datastream + static constexpr unsigned int m_max_fee_sync_time = 1024 * 8; + + static constexpr unsigned int m_FEE_CLOCK_BITS = 20; + static constexpr unsigned int m_GTM_CLOCK_BITS = 40; + + double m_multiplier = 0; + int64_t m_clock_ratio_numerator = 0; + int64_t m_clock_ratio_denominator = 1; + + TH1 *m_hNorm = nullptr; + TH1 *m_hFEEClockAdjustment_MatchedReference = nullptr; + TH1 *m_hFEEClockAdjustment_MatchedNew = nullptr; + TH1 *m_hFEEClockAdjustment_Unmatched = nullptr; + TH1 *m_hGTMNewEventSpacing = nullptr; + TH1 *m_hFindGTMBCO_MatchedExisting_BCODiff = nullptr; + TH1 *m_hFindGTMBCO_MatchedNew_BCODiff = nullptr; + + }; // class BcoMatchingInformation + + private: + std::vector> m_feeData; + + std::map> m_maskedFEEs; + + int m_verbosity = 0; + int m_packet_id = 0; + + //! common prefix for QA histograms + std::string m_HistoPrefix; + + static constexpr uint32_t kFEEClockMask = (1U << 20U) - 1U; + static constexpr uint32_t kRun3FeeMatchWindow = (GL1_BCO_MATCH_WINDOW * 30U + 7U) / 8U; + + static int64_t get_signed_fee_bco_diff(uint32_t first, uint32_t second); + static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); + size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe); + std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; + void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); + + //! FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching + std::map> m_timeHitMap; + + //! rollover-corrected GTM BCO -> matched TpcRawHit returned to the input manager + std::map> m_timeFrameMap; + static const size_t kMaxRawHitLimit = 10000; // 10k hits per event > 256ch/fee * 26fee + std::queue m_UsedTimeFrameSet; + + //! fast skip mode when searching for particular GL1 BCO over long segment of files + bool m_fastBCOSkip = false; + + //! map bco_information_t to packet id + std::vector m_bcoMatchingInformation_vec; + + //! QA area + + PHTimer *m_packetTimer = nullptr; + + TH1 *m_hNorm = nullptr; + TH2 *m_hFEEDataStream = nullptr; + TH1 *m_hFEEChannelPacketCount = nullptr; + TH2 *m_hFEESAMPAADC = nullptr; + TH1 *m_hFEESAMPAHeartBeatSync = nullptr; + + TH1 *h_PacketLength = nullptr; + TH1 *h_PacketLength_Padding = nullptr; + TH1 *h_PacketLength_Residual = nullptr; + + TH1 *h_GTMClockDiff_Matched = nullptr; + TH1 *h_GTMClockDiff_Unmatched = nullptr; + TH1 *h_GTMClockDiff_Dropped = nullptr; + TH1 *h_TimeFrame_Matched_Size = nullptr; + TH1 *h_Run3FEEClockDiff_FuzzyFallback = nullptr; + + TH2 *h_ProcessPacket_Time = nullptr; +}; + +#endif From 3b0f07bd1d3885bdaef29e5e7774828530af3339 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 Jun 2026 15:01:01 -0400 Subject: [PATCH 564/866] add diagnostics --- offline/packages/trackreco/PHCosmicsTrkFitter.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index d4664415ad..511eaaa419 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -983,6 +983,7 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) } void PHCosmicsTrkFitter::clearVectors() { + m_locx.clear(); m_locy.clear(); m_x.clear(); @@ -1000,10 +1001,6 @@ void PHCosmicsTrkFitter::clearVectors() void PHCosmicsTrkFitter::getCharge( TrackSeed* track, - // TrkrClusterContainer* clusterContainer, - // ActsGeometry* tGeometry, - // alignmentTransformationContainer* transformMapTransient, - // float vertexRadius, int& charge, float& cosmicslope) { @@ -1105,7 +1102,10 @@ void PHCosmicsTrkFitter::getCharge( { charge = 1; } - + if(Verbosity() > 2) + { + std::cout << "charge is " << charge << std::endl; + } float r1 = std::sqrt(square(globalMostOuter.x()) + square(globalMostOuter.y())); float r2 = std::sqrt(square(globalSecondMostOuter.x()) + square(globalSecondMostOuter.y())); float z1 = globalMostOuter.z(); From 8ae751257853389bec5b293083bf06ccd4e8c55e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 1 Jun 2026 15:27:52 -0400 Subject: [PATCH 565/866] move material selector to base object --- .../trackbase/ActsTrackFittingAlgorithm.h | 17 +++++++++++++++++ offline/packages/trackreco/PHActsTrkFitter.h | 17 ----------------- .../packages/trackreco/PHCosmicsTrkFitter.cc | 19 ++++++++++++++++++- .../packages/trackreco/PHCosmicsTrkFitter.h | 6 +++++- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/offline/packages/trackbase/ActsTrackFittingAlgorithm.h b/offline/packages/trackbase/ActsTrackFittingAlgorithm.h index c68698b9d7..4d794adac8 100644 --- a/offline/packages/trackbase/ActsTrackFittingAlgorithm.h +++ b/offline/packages/trackbase/ActsTrackFittingAlgorithm.h @@ -27,6 +27,23 @@ namespace Acts { class TrackingGeometry; } +struct MaterialSurfaceSelector + { + std::vector surfaces = {}; + + /// @param surface is the test surface + void operator()(const Acts::Surface* surface) + { + if (surface->surfaceMaterial() != nullptr) + { + if (std::find(surfaces.begin(), surfaces.end(), surface) == + surfaces.end()) + { + surfaces.push_back(surface); + } + } + } + }; class ActsTrackFittingAlgorithm final { diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 3e0ee71132..6ce4d4e711 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -295,23 +295,6 @@ class PHActsTrkFitter : public SubsysReco std::vector m_materialSurfaces = {}; - struct MaterialSurfaceSelector - { - std::vector surfaces = {}; - - /// @param surface is the test surface - void operator()(const Acts::Surface* surface) - { - if (surface->surfaceMaterial() != nullptr) - { - if (std::find(surfaces.begin(), surfaces.end(), surface) == - surfaces.end()) - { - surfaces.push_back(surface); - } - } - } - }; }; #endif diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index f7f60fe119..cc40d377a9 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -113,10 +113,27 @@ int PHCosmicsTrkFitter::InitRun(PHCompositeNode* topNode) { m_ConstField = true; } + auto level = Acts::Logging::FATAL; + if (Verbosity() > 5) + { + level = Acts::Logging::VERBOSE; + } m_fitCfg.fit = ActsTrackFittingAlgorithm::makeKalmanFitterFunction( m_tGeometry->geometry().tGeometry, - m_tGeometry->geometry().magField); + m_tGeometry->geometry().magField, + true, true, 0.0, Acts::FreeToBoundCorrection(), *Acts::getDefaultLogger("Kalman", level)); + + m_fitCfg.dFit = ActsTrackFittingAlgorithm::makeDirectedKalmanFitterFunction( + m_tGeometry->geometry().tGeometry, + m_tGeometry->geometry().magField, true, true, 0.0, Acts::FreeToBoundCorrection(), *Acts::getDefaultLogger("DirectedKalman", level)); + + MaterialSurfaceSelector selector; + if (m_directNavigation) + { + m_tGeometry->geometry().tGeometry->visitSurfaces(selector, false); + m_materialSurfaces = selector.surfaces; + } m_outlierFinder.verbosity = Verbosity(); std::map chi2Cuts; diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index 79be4c14f8..9d54e13f44 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -66,7 +66,7 @@ class PHCosmicsTrkFitter : public SubsysReco { m_fillSvtxTrackStates = fillSvtxTrackStates; } - + void directNavigator() { m_directNavigation = true; } void useActsEvaluator(bool actsEvaluator) { m_actsEvaluator = actsEvaluator; @@ -162,6 +162,8 @@ class PHCosmicsTrkFitter : public SubsysReco /// A bool to update the SvtxTrackState information (or not) bool m_fillSvtxTrackStates = true; + bool m_directNavigation = false; + // do we have a constant field bool m_ConstField = false; double fieldstrength{std::numeric_limits::quiet_NaN()}; @@ -198,6 +200,8 @@ class PHCosmicsTrkFitter : public SubsysReco SvtxAlignmentStateMap* m_alignmentStateMap = nullptr; ActsAlignmentStates m_alignStates; + std::vector m_materialSurfaces = {}; + bool m_zeroField = false; PHG4TpcGeomContainer* _tpccellgeo = nullptr; From dadc1568bf7a5fc1135c87b413d5423885b11056 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 1 Jun 2026 22:28:46 -0400 Subject: [PATCH 566/866] clean up --- .../framework/fun4allraw/TpcTimeFrameBuilderRun3.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index a17d9f9570..d38b3c3a69 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -205,12 +205,6 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! get predicted fee_bco from gtm_bco std::optional get_predicted_fee_bco(uint64_t) const; - //! multiplier - double get_gtm_clock_multiplier() - { - return m_multiplier; - } - //! print gtm bco information void print_gtm_bco_information() const; @@ -225,17 +219,10 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase m_verbosity = value; } - /// set gtm clock multiplier - void set_gtm_clock_multiplier(double value) - { - m_multiplier = value; - } - void set_gtm_clock_ratio(int64_t numerator, int64_t denominator) { m_clock_ratio_numerator = numerator; m_clock_ratio_denominator = denominator; - m_multiplier = static_cast(numerator) / static_cast(denominator); } /// set gtm clock with rollover correction @@ -368,7 +355,6 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static constexpr unsigned int m_FEE_CLOCK_BITS = 20; static constexpr unsigned int m_GTM_CLOCK_BITS = 40; - double m_multiplier = 0; int64_t m_clock_ratio_numerator = 0; int64_t m_clock_ratio_denominator = 1; From a8d360182fa55867aa2be9721ecdda1b5a544c02 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 Jun 2026 09:01:40 -0400 Subject: [PATCH 567/866] Fix momentum sign --- offline/packages/trackreco/PHCosmicsTrkFitter.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index cc40d377a9..ec566c6eb1 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -453,8 +453,8 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (!m_zeroField) { - momentum.x() = charge < 0 ? tan.x() : tan.x() * -1; - momentum.y() = charge < 0 ? tan.y() : tan.y() * -1; + momentum.x() = tan.x() * -1; + momentum.y() = tan.y() * -1; } else { From 0d98195ac289fcb635b9707aa06cac5535ddd73b Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 2 Jun 2026 10:50:56 -0400 Subject: [PATCH 568/866] add QA --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 107 +++++++++++++++++- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 11 ++ 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 45645861a4..cd25944aac 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -173,6 +173,18 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) 2048, -1024 - .5, 1024 - .5); hm->registerHisto(h_Run3FEEClockDiff_FuzzyFallback); + h_Run3WaveformStart_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3WaveformStart_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 matched waveform start clock vs GL1 spacing;FEE ADC waveform start clock;Current - previous GL1 GTM BCO [BCO]", + 1024, -.5, 1023.5, 1001, -.5, 1000.5); + hm->registerHisto(h_Run3WaveformStart_GL1Spacing); + + h_Run3PreviousTimeFrameWaveformStart = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameWaveformStartCache", // + TString(m_HistoPrefix.c_str()) + + " Run3 previous matched waveform start cache;FEE ADC waveform start clock;Count", + 1024, -.5, 1023.5); + h_Run3PreviousTimeFrameWaveformStart->SetDirectory(nullptr); + h_ProcessPacket_Time = new TH2I(TString(m_HistoPrefix.c_str()) + "_ProcessPacket_Time", // TString(m_HistoPrefix.c_str()) + " Time cost to run ProcessPacket();Call counts;Time elapsed per call [ms];Count", @@ -186,7 +198,9 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() { while (!timeHitEntry.second.empty()) { - delete timeHitEntry.second.back(); + TpcRawHit* hit = timeHitEntry.second.back(); + erase_waveform_start_cache(hit); + delete hit; timeHitEntry.second.pop_back(); } } @@ -195,11 +209,17 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() { while (!timeFrameEntry.second.empty()) { - delete timeFrameEntry.second.back(); + TpcRawHit* hit = timeFrameEntry.second.back(); + erase_waveform_start_cache(hit); + delete hit; timeFrameEntry.second.pop_back(); } } + m_hitWaveformStartMap.clear(); + + delete h_Run3PreviousTimeFrameWaveformStart; + delete m_packetTimer; delete m_digitalCurrentDebugTTree; @@ -215,6 +235,69 @@ void TpcTimeFrameBuilderRun3::setVerbosity(const int i) } } +void TpcTimeFrameBuilderRun3::erase_waveform_start_cache(TpcRawHit* hit) +{ + if (hit) + { + m_hitWaveformStartMap.erase(hit); + } +} + +void TpcTimeFrameBuilderRun3::flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco) +{ + assert(h_Run3PreviousTimeFrameWaveformStart); + assert(h_Run3WaveformStart_GL1Spacing); + + if (!m_previousTimeFrameGtmBco) + { + return; + } + + const uint64_t previous_gtm_bco = *m_previousTimeFrameGtmBco; + static constexpr uint64_t gtm_clock_range = uint64_t(1) << 40U; + const uint64_t current_gtm_bco_rollover_corrected = current_gtm_bco >= previous_gtm_bco + ? current_gtm_bco + : current_gtm_bco + gtm_clock_range; + const uint64_t gtm_bco_spacing = current_gtm_bco_rollover_corrected - previous_gtm_bco; + + for (int bin = 1; bin <= h_Run3PreviousTimeFrameWaveformStart->GetNbinsX(); ++bin) + { + const double count = h_Run3PreviousTimeFrameWaveformStart->GetBinContent(bin); + if (count == 0) + { + continue; + } + + h_Run3WaveformStart_GL1Spacing->Fill(h_Run3PreviousTimeFrameWaveformStart->GetXaxis()->GetBinCenter(bin), + gtm_bco_spacing, count); + } + + h_Run3PreviousTimeFrameWaveformStart->Reset(); + m_previousTimeFrameGtmBco.reset(); +} + +void TpcTimeFrameBuilderRun3::cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector& timeframe) +{ + assert(h_Run3PreviousTimeFrameWaveformStart); + + h_Run3PreviousTimeFrameWaveformStart->Reset(); + for (TpcRawHit* hit : timeframe) + { + const auto waveform_start_iter = m_hitWaveformStartMap.find(hit); + if (waveform_start_iter == m_hitWaveformStartMap.end()) + { + continue; + } + + for (const uint16_t waveform_start : waveform_start_iter->second) + { + h_Run3PreviousTimeFrameWaveformStart->Fill(waveform_start); + } + } + + m_previousTimeFrameGtmBco = gtm_bco; +} + int64_t TpcTimeFrameBuilderRun3::get_signed_fee_bco_diff(uint32_t first, uint32_t second) { static constexpr int64_t fee_clock_range = 1LL << 20U; @@ -334,6 +417,7 @@ void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_correc if ((fee_clock_window == 0 && diff <= 0) || (fee_clock_window > 0 && diff < -static_cast(fee_clock_window))) { m_hFEEDataStream->Fill(hit->get_fee(), "HitUnusedBeforeCleanup", 1); + erase_waveform_start_cache(hit); delete hit; hit_it = hits.erase(hit_it); } @@ -395,6 +479,8 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g return cached->second; } + flush_previous_timeframe_waveform_start_cache(bclk_rollover_corrected); + if (m_verbosity > 2) { std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id @@ -483,6 +569,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g assert(h_TimeFrame_Matched_Size); h_TimeFrame_Matched_Size->Fill(timeframe.size()); m_hNorm->Fill("GTM_TimeFrame_Matched_Hit_Sum", timeframe.size()); + cache_timeframe_waveform_starts(bclk_rollover_corrected, timeframe); m_UsedTimeFrameSet.push(bclk_rollover_corrected); return timeframe; } @@ -505,7 +592,9 @@ void TpcTimeFrameBuilderRun3::CleanupUsedPackets(const uint64_t& bclk) { while (!it->second.empty()) { - delete it->second.back(); + TpcRawHit* hit = it->second.back(); + erase_waveform_start_cache(hit); + delete hit; it->second.pop_back(); } m_timeFrameMap.erase(it); @@ -739,7 +828,9 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) while (!timehit.second.empty()) { - delete timehit.second.back(); + TpcRawHit* hit = timehit.second.back(); + erase_waveform_start_cache(hit); + delete hit; timehit.second.pop_back(); } } @@ -1077,6 +1168,14 @@ void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, // hit->set_parity(payload.data_parity); hit->set_parityerror(payload.data_parity != payload.calc_parity); + std::vector waveform_start_clocks; + waveform_start_clocks.reserve(payload.waveforms.size()); + for (const std::pair>& waveform : payload.waveforms) + { + waveform_start_clocks.push_back(waveform.first); + } + m_hitWaveformStartMap[hit] = std::move(waveform_start_clocks); + for (std::pair>& waveform : payload.waveforms) { hit->move_adc_waveform(waveform.first, std::move(waveform.second)); diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index d38b3c3a69..4d34d43fe7 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -387,12 +387,21 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe); std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); + void flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco); + void cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector &timeframe); + void erase_waveform_start_cache(TpcRawHit *hit); //! FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching std::map> m_timeHitMap; //! rollover-corrected GTM BCO -> matched TpcRawHit returned to the input manager std::map> m_timeFrameMap; + + //! TpcRawHit -> waveform start clock values, cached because TpcRawHitv3 does not expose waveform rows + std::map> m_hitWaveformStartMap; + + //! previous matched timeframe GTM BCO, used to fill waveform-start row once the next GTM BCO is known + std::optional m_previousTimeFrameGtmBco; static const size_t kMaxRawHitLimit = 10000; // 10k hits per event > 256ch/fee * 26fee std::queue m_UsedTimeFrameSet; @@ -421,6 +430,8 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH1 *h_GTMClockDiff_Dropped = nullptr; TH1 *h_TimeFrame_Matched_Size = nullptr; TH1 *h_Run3FEEClockDiff_FuzzyFallback = nullptr; + TH1 *h_Run3PreviousTimeFrameWaveformStart = nullptr; + TH2 *h_Run3WaveformStart_GL1Spacing = nullptr; TH2 *h_ProcessPacket_Time = nullptr; }; From 8ab7647b30e3c6062256949528db1be301165f8f Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 2 Jun 2026 10:54:25 -0400 Subject: [PATCH 569/866] add QA --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 16 ++++++++++++++++ .../fun4allraw/TpcTimeFrameBuilderRun3.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index cd25944aac..c1f8c3f92e 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -173,6 +173,18 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) 2048, -1024 - .5, 1024 - .5); hm->registerHisto(h_Run3FEEClockDiff_FuzzyFallback); + h_Run3TimeFrameExactHit_FEE = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3TimeFrameExactHit_FEE", // + TString(m_HistoPrefix.c_str()) + + " Run3 exact matched hit sum by FEE;FEE;Exact matched hits", + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3TimeFrameExactHit_FEE); + + h_Run3TimeFrameFuzzyHit_FEE = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3TimeFrameFuzzyHit_FEE", // + TString(m_HistoPrefix.c_str()) + + " Run3 fuzzy fallback matched hit sum by FEE;FEE;Fuzzy fallback matched hits", + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3TimeFrameFuzzyHit_FEE); + h_Run3WaveformStart_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3WaveformStart_GL1Spacing", // TString(m_HistoPrefix.c_str()) + " Run3 matched waveform start clock vs GL1 spacing;FEE ADC waveform start clock;Current - previous GL1 GTM BCO [BCO]", @@ -508,6 +520,8 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g exact_hit_count += exact_hits; if (exact_hits > 0) { + assert(h_Run3TimeFrameExactHit_FEE); + h_Run3TimeFrameExactHit_FEE->Fill(fee, exact_hits); continue; } @@ -524,6 +538,8 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } fallback_hit_count += fuzzy_hits; + assert(h_Run3TimeFrameFuzzyHit_FEE); + h_Run3TimeFrameFuzzyHit_FEE->Fill(fee, fuzzy_hits); assert(h_Run3FEEClockDiff_FuzzyFallback); h_Run3FEEClockDiff_FuzzyFallback->Fill(get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco)); diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 4d34d43fe7..161ad0ba1b 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -430,6 +430,8 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH1 *h_GTMClockDiff_Dropped = nullptr; TH1 *h_TimeFrame_Matched_Size = nullptr; TH1 *h_Run3FEEClockDiff_FuzzyFallback = nullptr; + TH1 *h_Run3TimeFrameExactHit_FEE = nullptr; + TH1 *h_Run3TimeFrameFuzzyHit_FEE = nullptr; TH1 *h_Run3PreviousTimeFrameWaveformStart = nullptr; TH2 *h_Run3WaveformStart_GL1Spacing = nullptr; From 504adff09b2b2f25994141e489782833251e254a Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 2 Jun 2026 11:28:18 -0400 Subject: [PATCH 570/866] comment out unused variable --- offline/packages/trackreco/PHActsSiliconSeeding.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index 397610cd2a..277be758f5 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -328,13 +328,13 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const std::vector& const int& strobe) { - int numSeeds = 0; + // int numSeeds = 0; int numGoodSeeds = 0; m_seedid = -1; for (const auto& seed : seedVector) { - numSeeds++; + // numSeeds++; if (m_seedAnalysis) { clearTreeVariables(); From e1836ad511b17fb5f38b073a5899a74b8003da98 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 2 Jun 2026 17:00:26 -0400 Subject: [PATCH 571/866] 30% speedup of PHG4TpcDigitizer --- .../g4simulation/g4tpc/PHG4TpcDigitizer.cc | 114 ------------------ .../g4simulation/g4tpc/PHG4TpcDigitizer.h | 42 ++----- 2 files changed, 13 insertions(+), 143 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index f7a1642049..61ca56d4b6 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -33,14 +33,6 @@ PHG4TpcDigitizer::PHG4TpcDigitizer(const std::string &name) : SubsysReco(name) - , TpcMinLayer(7) - , TpcNLayers(48) - , ADCThreshold(2700) // electrons - , TpcEnc(670) // electrons - , Pedestal(50000) // electrons - , ChargeToPeakVolts(20) // mV/fC - , ADCSignalConversionGain(std::numeric_limits::quiet_NaN()) // will be assigned in PHG4TpcDigitizer::InitRun - , ADCNoiseConversionGain(std::numeric_limits::quiet_NaN()) , RandomGenerator(gsl_rng_alloc(gsl_rng_mt19937)) // will be assigned in PHG4TpcDigitizer::InitRun { unsigned int seed = PHRandomSeed(); // fixed seed is handled in this funtcion @@ -688,109 +680,3 @@ float PHG4TpcDigitizer::added_noise() return noise; } -n; // mV - from definition of noise charge and pedestal charge - adc_input_voltage += noise_voltage; - - return adc_input_voltage; -} - -float PHG4TpcDigitizer::added_noise() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -ise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -n; // mV - from definition of noise charge and pedestal charge - adc_input_voltage += noise_voltage; - - return adc_input_voltage; -} - -float PHG4TpcDigitizer::added_noise() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -se() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} - gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -se() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -mV - from definition of noise charge and pedestal charge - adc_input_voltage += noise_voltage; - - return adc_input_voltage; -} - -float PHG4TpcDigitizer::added_noise() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -se() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} - gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -se() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -se() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} - gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -se() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -or, TpcEnc); - - return noise; -} -se() -{ - float noise = gsl_ran_gaussian(RandomGenerator, TpcEnc); - - return noise; -} -pcEnc); - - return noise; -} diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index 0d9cc655c0..4481561821 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -8,13 +8,13 @@ #include #include +#include + #include #include // for string #include // for pair, make_pair #include -#include - class PHCompositeNode; class TrkrHit; @@ -24,18 +24,12 @@ class PHG4TpcDigitizer : public SubsysReco PHG4TpcDigitizer(const std::string &name = "PHG4TpcDigitizer"); ~PHG4TpcDigitizer() override; - //! module initialization - int Init(PHCompositeNode * /*topNode*/) override { return 0; } - //! run initialization int InitRun(PHCompositeNode *topNode) override; //! event processing int process_event(PHCompositeNode *topNode) override; - //! end of process - int End(PHCompositeNode * /*topNode*/) override { return 0; }; - void set_adc_scale(const int layer, const unsigned int max_adc, const float energy_per_adc) { _max_adc.insert(std::make_pair(layer, max_adc)); @@ -53,17 +47,17 @@ class PHG4TpcDigitizer : public SubsysReco float added_noise(); float add_noise_to_bin(float signal); - unsigned int TpcMinLayer; - unsigned int TpcNLayers; - float ADCThreshold; - float ADCThreshold_mV = 0; - float TpcEnc; - float Pedestal; - float ChargeToPeakVolts; - float ADCSignalConversionGain; - float ADCNoiseConversionGain; + unsigned int TpcMinLayer {7}; + unsigned int TpcNLayers {48}; + float ADCThreshold {2700}; + float ADCThreshold_mV {0}; + float TpcEnc {670}; + float Pedestal {50000}; + float ChargeToPeakVolts {50}; + float ADCSignalConversionGain {std::numeric_limits::quiet_NaN()}; + float ADCNoiseConversionGain {std::numeric_limits::quiet_NaN()}; - bool skip_noise = false; + bool skip_noise {false}; std::vector > phi_sorted_hits; std::vector adc_input; @@ -74,17 +68,7 @@ class PHG4TpcDigitizer : public SubsysReco std::map _energy_scale; //! random generator that conform with sPHENIX standard - gsl_rng *RandomGenerator; -}; - -#endif -th sPHENIX standard - gsl_rng *RandomGenerator; -}; - -#endif -ard - gsl_rng *RandomGenerator; + gsl_rng *RandomGenerator {nullptr}; }; #endif From 295065a81a5d6c438d5725078495e4a439fe8e62 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 2 Jun 2026 21:18:41 -0400 Subject: [PATCH 572/866] fix charge determination --- .../packages/trackreco/PHCosmicsTrkFitter.cc | 159 +++++++----------- .../packages/trackreco/PHCosmicsTrkFitter.h | 6 +- 2 files changed, 63 insertions(+), 102 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index ec566c6eb1..8b22e2ab25 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -336,10 +336,6 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { continue; } - int charge = 0; - float cosmicslope = 0; - - getCharge(tpcseed, charge, cosmicslope); Acts::GeometryContext geoContext{m_alignmentTransformationMapTransient}; // copy transient map for this track into transient geoContext @@ -377,6 +373,11 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) intx = std::get<2>(intersect); inty = std::get<3>(intersect); } + if(Verbosity() > 2) + { + std::cout << "XY intersection options " << std::get<0>(intersect) << ", " << std::get<1>(intersect) << " and " << std::get<2>(intersect) << ", " << std::get<3>(intersect) << std::endl; + } + std::vector keys; std::vector clusPos; std::copy(tpcseed->begin_cluster_keys(), tpcseed->end_cluster_keys(), std::back_inserter(keys)); @@ -407,6 +408,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) float slope = tpcseed->get_slope(); float intz = m_vertexRadius * slope + tpcseed->get_Z0(); + Acts::Vector3 inter(intx, inty, intz); std::vector tpcparams{tpcR, tpcx, tpcy, tpcseed->get_slope(), @@ -453,7 +455,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (!m_zeroField) { - momentum.x() = tan.x() * -1; + momentum.x() = tan.x() * -1; momentum.y() = tan.y() * -1; } else @@ -481,6 +483,8 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) continue; } + int charge = getCharge(clusPos, tpcparams); + auto pSurface = Acts::Surface::makeShared( position); auto actsFourPos = Acts::Vector4(position(0), position(1), @@ -511,6 +515,25 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) fillVectors(siseed, tpcseed); m_tree->Fill(); } + if(m_dumpSeeds) + { + SvtxTrack_v4 newTrack; + newTrack.set_tpc_seed(tpcseed); + newTrack.set_crossing(crossing); + newTrack.set_silicon_seed(siseed); + + unsigned int trid = m_trackMap->size(); + newTrack.set_id(trid); + newTrack.set_px(momentum.x()); + newTrack.set_py(momentum.y()); + newTrack.set_pz(momentum.z()); + newTrack.set_x(position.x()/Acts::UnitConstants::cm); + newTrack.set_y(position.y()/Acts::UnitConstants::cm); + newTrack.set_z(position.z()/Acts::UnitConstants::cm); + newTrack.set_charge(charge); + m_trackMap->insertWithKey(&newTrack, trid); + continue; + } //! Reset the track seed with the dummy covariance auto seed = ActsTrackFittingAlgorithm::TrackParameters::create( m_transient_geocontext, @@ -999,117 +1022,51 @@ void PHCosmicsTrkFitter::clearVectors() m_ez.clear(); } -void PHCosmicsTrkFitter::getCharge( - TrackSeed* track, - int& charge, - float& cosmicslope) +int PHCosmicsTrkFitter::getCharge( + const std::vector& positions, + const std::vector& tpccparams) { Acts::GeometryContext transient_geocontext{m_alignmentTransformationMapTransient}; - - std::vector global_vec; - - for (auto clusIter = track->begin_cluster_keys(); - clusIter != track->end_cluster_keys(); - ++clusIter) - { - auto key = *clusIter; - auto cluster = m_clusterContainer->findCluster(key); - if (!cluster) + std::vector sorted_positions = positions; + // sort the clusters in order of outermost radius to innermost radius + std::sort(sorted_positions.begin(), sorted_positions.end(), [](const Acts::Vector3& a, const Acts::Vector3& b) + { + float aradius = std::sqrt(a.x()*a.x()+a.y()*a.y()); + if(a.y() < 0) { - std::cout << "MakeSourceLinks::getCharge: Failed to get cluster with key " << key << " for track seed" << std::endl; - continue; + aradius *= -1; } - - auto surf = m_tGeometry->maps().getSurface(key, cluster); - if (!surf) + float bradius = std::sqrt(b.x()*b.x()+b.y()*b.y()); + if(b.y() < 0) { - continue; + bradius *= -1; } - - // get cluster global positions - Acts::Vector2 local = m_tGeometry->getLocalCoords(key, cluster); // converts TPC time to z - Acts::Vector3 glob = surf->localToGlobal(transient_geocontext, - local * Acts::UnitConstants::cm, - Acts::Vector3(1, 1, 1)); - glob /= Acts::UnitConstants::cm; - - global_vec.push_back(glob); - } - - Acts::Vector3 globalMostOuter(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); - Acts::Vector3 globalSecondMostOuter(0, 999999, 0); - float largestR = 0; - // loop over global positions - for (auto& i : global_vec) + return aradius > bradius; }); + + float phi0 = std::atan2(sorted_positions[0].y() - tpccparams[2], sorted_positions[0].x() - tpccparams[1]); + int posphi = 0; + int negphi = 0; + // just take the first 4 outermost clusters as a test to determine the bend angle + // from the outermost radial cluster + for (size_t i = 1; i < 5; i++) { - Acts::Vector3 global = i; - // float r = std::sqrt(square(global.x()) + square(global.y())); - float r = radius(global.x(), global.y()); - - /// use the top hemisphere to determine the charge - if (r > largestR && global.y() > 0) - { - globalMostOuter = i; - largestR = r; - } - } + auto cluspos = sorted_positions[i]; - //! find the closest cluster to the outermost cluster - float maxdr = std::numeric_limits::max(); - for (auto& i : global_vec) - { - if (i.y() < 0) + float phi = std::atan2(cluspos.y() - tpccparams[2], cluspos.x() - tpccparams[1]); + if(phi > phi0) { - continue; + posphi++; } - - float dr = std::sqrt(square(globalMostOuter.x()) + square(globalMostOuter.y())) - std::sqrt(square(i.x()) + square(i.y())); - //! Place a dr cut to get maximum bend due to TPC clusters having - //! larger fluctuations - if (dr < maxdr && dr > 10) + else { - maxdr = dr; - globalSecondMostOuter = i; + negphi++; } } - - //! we have to calculate phi WRT the vertex position outside the detector, - //! not at (0,0) - Acts::Vector3 vertex(0, m_vertexRadius, 0); - globalMostOuter -= vertex; - globalSecondMostOuter -= vertex; - - const auto firstphi = atan2(globalMostOuter.y(), globalMostOuter.x()); - const auto secondphi = atan2(globalSecondMostOuter.y(), - globalSecondMostOuter.x()); - auto dphi = secondphi - firstphi; - - if (dphi > M_PI) - { - dphi = 2. * M_PI - dphi; - } - if (dphi < -M_PI) - { - dphi = 2 * M_PI + dphi; - } - - if (dphi > 0) - { - charge = -1; - } - else - { - charge = 1; - } - if(Verbosity() > 2) + int charge = posphi > negphi ? -1 : 1; + if (Verbosity() > 2) { std::cout << "charge is " << charge << std::endl; } - float r1 = std::sqrt(square(globalMostOuter.x()) + square(globalMostOuter.y())); - float r2 = std::sqrt(square(globalSecondMostOuter.x()) + square(globalSecondMostOuter.y())); - float z1 = globalMostOuter.z(); - float z2 = globalSecondMostOuter.z(); - cosmicslope = (r2 - r1) / (z2 - z1); - return; + return charge; } diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index 9d54e13f44..1b23641a36 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -62,6 +62,8 @@ class PHCosmicsTrkFitter : public SubsysReco int ResetEvent(PHCompositeNode* topNode) override; + void convertSeeds() { m_dumpSeeds = true; } + void setUpdateSvtxTrackStates(bool fillSvtxTrackStates) { m_fillSvtxTrackStates = fillSvtxTrackStates; @@ -103,7 +105,7 @@ class PHCosmicsTrkFitter : public SubsysReco int createNodes(PHCompositeNode* topNode); void loopTracks(Acts::Logging::Level logLevel); - void getCharge(TrackSeed* track, int& charge, float& cosmicslope); + int getCharge(const std::vector& positions, const std::vector& tpcparams); /// Convert the acts track fit result to an svtx track void updateSvtxTrack(std::vector& tips, @@ -205,6 +207,8 @@ class PHCosmicsTrkFitter : public SubsysReco bool m_zeroField = false; PHG4TpcGeomContainer* _tpccellgeo = nullptr; + bool m_dumpSeeds = false; + //! for diagnosing seed param + clusters bool m_seedClusAnalysis = false; TFile* m_outfile = nullptr; From 99c002d845c81386f7e8e424da6dac914e179e34 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 3 Jun 2026 11:31:12 -0400 Subject: [PATCH 573/866] fix typo in ChargeToPeakVolts initializer --- simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index 4481561821..51048d39f2 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -53,7 +53,7 @@ class PHG4TpcDigitizer : public SubsysReco float ADCThreshold_mV {0}; float TpcEnc {670}; float Pedestal {50000}; - float ChargeToPeakVolts {50}; + float ChargeToPeakVolts {20}; float ADCSignalConversionGain {std::numeric_limits::quiet_NaN()}; float ADCNoiseConversionGain {std::numeric_limits::quiet_NaN()}; From de5c39f18e3f68e0c1a98c4fe6d08df8e0b087a5 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 Jun 2026 11:36:08 -0400 Subject: [PATCH 574/866] track fits succeed --- .../packages/trackreco/PHCosmicsTrkFitter.cc | 103 ++++++++++++------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index 8b22e2ab25..9b8ce7ae20 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -341,7 +341,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) // copy transient map for this track into transient geoContext m_transient_geocontext = geoContext; - { + std::vector pos, sorted_positions; // get positions from cluster keys // TODO: should implement distortions TrackSeedHelper::position_map_t positions; @@ -349,18 +349,63 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { const auto& key(*key_iter); positions.emplace(key, m_tGeometry->getGlobalPosition( key, m_clusterContainer->findCluster(key))); + pos.push_back(positions[key]); } + sorted_positions = pos; TrackSeedHelper::circleFitByTaubin(tpcseed, positions, 0, 58); + + float tpcR = fabs(1. / tpcseed->get_qOverR()); + float tpcx = tpcseed->get_X0(); + float tpcy = tpcseed->get_Y0(); + + float dx = -tpcx; + float dy = m_vertexRadius - tpcy; + + float dist = std::sqrt(dx * dx + dy * dy); + float pcaxclaude = tpcx + tpcR * (dx / dist); + float pcayclaude = tpcy + tpcR * (dy / dist); + + std::sort(sorted_positions.begin(), sorted_positions.end(), [](const Acts::Vector3& a, const Acts::Vector3& b) + { + float aradius = std::sqrt(a.x()*a.x()+a.y()*a.y()); + if(a.y() < 0) + { + aradius *= -1; } + float bradius = std::sqrt(b.x()*b.x()+b.y()*b.y()); + if(b.y() < 0) + { + bradius *= -1; + } + return aradius > bradius; }); + + + auto arcLength = [&](float x, float y) + { + float angle = std::atan2(y - tpcy, x - tpcx); + return tpcR * angle; + }; + float sum_s = 0, sum_z = 0, sum_ss = 0, sum_sz = 0; + int n = sorted_positions.size(); + for(auto& p : sorted_positions) + { + float s = arcLength(p.x(), p.y()); + sum_s += s; + sum_z += p.z(); + sum_ss += s*s; + sum_sz += s*p.z(); + } + float denom = n * sum_ss - sum_s * sum_s; + float b = (n * sum_sz - sum_s * sum_z) / denom; + float a = (sum_z - b * sum_s) / n; + + float s_ca = arcLength(pcaxclaude, pcayclaude); + float z_ca = a + b * s_ca; - float tpcR = fabs(1. / tpcseed->get_qOverR()); - float tpcx = tpcseed->get_X0(); - float tpcy = tpcseed->get_Y0(); + Acts::Vector3 claudepca(pcaxclaude, pcayclaude, z_ca); - const auto intersect = - TrackFitUtils::circle_circle_intersection(m_vertexRadius, - tpcR, tpcx, tpcy); + const auto intersect = TrackFitUtils::circle_circle_intersection(m_vertexRadius, tpcR, tpcx, tpcy); float intx, inty; if (std::get<1>(intersect) > std::get<3>(intersect)) @@ -384,10 +429,10 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) TrackFitUtils::getTrackletClusters(m_tGeometry, m_clusterContainer, clusPos, keys); TrackFitUtils::position_vector_t xypoints, rzpoints; - for (auto& pos : clusPos) + for (auto& p : clusPos) { - float clusr = radius(pos.x(), pos.y()); - if (pos.y() < 0) + float clusr = radius(p.x(), p.y()); + if (p.y() < 0) { clusr *= -1; } @@ -397,8 +442,8 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { continue; } - xypoints.push_back(std::make_pair(pos.x(), pos.y())); - rzpoints.push_back(std::make_pair(pos.z(), clusr)); + xypoints.push_back(std::make_pair(p.x(), p.y())); + rzpoints.push_back(std::make_pair(p.z(), clusr)); } auto rzparams = TrackFitUtils::line_fit(rzpoints); @@ -417,7 +462,6 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) inter); auto tan = tangent.second; - auto pca = tangent.first; float p; if (m_ConstField) @@ -474,8 +518,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } momentum.z() = pz; - Acts::Vector3 position(pca.x(), pca.y(), - (m_vertexRadius - fulllineintz) / fulllineslope); + Acts::Vector3 position = claudepca; position *= Acts::UnitConstants::cm; if (!is_valid(momentum)) @@ -513,6 +556,10 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_pz = momentum(2); m_charge = charge; fillVectors(siseed, tpcseed); + m_x.push_back(claudepca.x()); + m_y.push_back(claudepca.y()); + m_z.push_back(claudepca.z()); + m_r.push_back(radius(claudepca.x(), claudepca.y())); m_tree->Fill(); } if(m_dumpSeeds) @@ -527,9 +574,9 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) newTrack.set_px(momentum.x()); newTrack.set_py(momentum.y()); newTrack.set_pz(momentum.z()); - newTrack.set_x(position.x()/Acts::UnitConstants::cm); - newTrack.set_y(position.y()/Acts::UnitConstants::cm); - newTrack.set_z(position.z()/Acts::UnitConstants::cm); + newTrack.set_x(claudepca.x()); + newTrack.set_y(claudepca.y()); + newTrack.set_z(claudepca.z()); newTrack.set_charge(charge); m_trackMap->insertWithKey(&newTrack, trid); continue; @@ -970,26 +1017,16 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) auto key = *it; auto cluster = m_clusterContainer->findCluster(key); m_locx.push_back(cluster->getLocalX()); - float ly = cluster->getLocalY(); - if (TrkrDefs::getTrkrId(key) == TrkrDefs::TrkrId::tpcId) - { - double drift_velocity = m_tGeometry->get_drift_velocity(); - double zdriftlength = cluster->getLocalY() * drift_velocity; - double surfCenterZ = 52.89; // 52.89 is where G4 thinks the surface center is - double zloc = surfCenterZ - zdriftlength; // converts z drift length to local z position in the TPC in north - unsigned int side = TpcDefs::getSide(key); - if (side == 0) - { - zloc = -zloc; - } - ly = zloc * 10; - } - m_locy.push_back(ly); + m_locy.push_back(cluster->getLocalY()); auto glob = m_tGeometry->getGlobalPosition(key, cluster); m_x.push_back(glob.x()); m_y.push_back(glob.y()); m_z.push_back(glob.z()); float r = std::sqrt(glob.x() * glob.x() + glob.y() * glob.y()); + if(glob.y() < 0) + { + r *= -1; + } m_r.push_back(r); TVector3 globt(glob.x(), glob.y(), glob.z()); m_phi.push_back(globt.Phi()); From 0f482248b60b33de6c1c3bf9067a60e38fe4c3f6 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 Jun 2026 11:36:45 -0400 Subject: [PATCH 575/866] clang-format --- .../packages/trackreco/PHCosmicsTrkFitter.cc | 89 +++++++++---------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index 9b8ce7ae20..0e7a3b530e 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -45,8 +45,8 @@ #include #include -#include #include +#include #include #include @@ -309,7 +309,19 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { // silicon source links sourceLinks = makeSourceLinks.getSourceLinks( - siseed, + siseed, + measurements, + m_clusterContainer, + m_tGeometry, + m_globalPositionWrapper, + m_alignmentTransformationMapTransient, + m_transient_id_set, + crossing); + } + + // tpc source links + const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( + tpcseed, measurements, m_clusterContainer, m_tGeometry, @@ -317,18 +329,6 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_alignmentTransformationMapTransient, m_transient_id_set, crossing); - } - - // tpc source links - const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( - tpcseed, - measurements, - m_clusterContainer, - m_tGeometry, - m_globalPositionWrapper, - m_alignmentTransformationMapTransient, - m_transient_id_set, - crossing); sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end()); @@ -342,32 +342,32 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_transient_geocontext = geoContext; std::vector pos, sorted_positions; - // get positions from cluster keys - // TODO: should implement distortions - TrackSeedHelper::position_map_t positions; - for( auto key_iter = tpcseed->begin_cluster_keys(); key_iter != tpcseed->end_cluster_keys(); ++key_iter ) - { - const auto& key(*key_iter); - positions.emplace(key, m_tGeometry->getGlobalPosition( key, m_clusterContainer->findCluster(key))); - pos.push_back(positions[key]); - } - sorted_positions = pos; + // get positions from cluster keys + // TODO: should implement distortions + TrackSeedHelper::position_map_t positions; + for (auto key_iter = tpcseed->begin_cluster_keys(); key_iter != tpcseed->end_cluster_keys(); ++key_iter) + { + const auto& key(*key_iter); + positions.emplace(key, m_tGeometry->getGlobalPosition(key, m_clusterContainer->findCluster(key))); + pos.push_back(positions[key]); + } + sorted_positions = pos; - TrackSeedHelper::circleFitByTaubin(tpcseed, positions, 0, 58); + TrackSeedHelper::circleFitByTaubin(tpcseed, positions, 0, 58); - float tpcR = fabs(1. / tpcseed->get_qOverR()); - float tpcx = tpcseed->get_X0(); - float tpcy = tpcseed->get_Y0(); + float tpcR = fabs(1. / tpcseed->get_qOverR()); + float tpcx = tpcseed->get_X0(); + float tpcy = tpcseed->get_Y0(); - float dx = -tpcx; - float dy = m_vertexRadius - tpcy; + float dx = -tpcx; + float dy = m_vertexRadius - tpcy; - float dist = std::sqrt(dx * dx + dy * dy); - float pcaxclaude = tpcx + tpcR * (dx / dist); - float pcayclaude = tpcy + tpcR * (dy / dist); + float dist = std::sqrt(dx * dx + dy * dy); + float pcaxclaude = tpcx + tpcR * (dx / dist); + float pcayclaude = tpcy + tpcR * (dy / dist); - std::sort(sorted_positions.begin(), sorted_positions.end(), [](const Acts::Vector3& a, const Acts::Vector3& b) - { + std::sort(sorted_positions.begin(), sorted_positions.end(), [](const Acts::Vector3& a, const Acts::Vector3& b) + { float aradius = std::sqrt(a.x()*a.x()+a.y()*a.y()); if(a.y() < 0) { @@ -380,7 +380,6 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } return aradius > bradius; }); - auto arcLength = [&](float x, float y) { float angle = std::atan2(y - tpcy, x - tpcx); @@ -388,13 +387,13 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) }; float sum_s = 0, sum_z = 0, sum_ss = 0, sum_sz = 0; int n = sorted_positions.size(); - for(auto& p : sorted_positions) + for (auto& p : sorted_positions) { float s = arcLength(p.x(), p.y()); sum_s += s; sum_z += p.z(); - sum_ss += s*s; - sum_sz += s*p.z(); + sum_ss += s * s; + sum_sz += s * p.z(); } float denom = n * sum_ss - sum_s * sum_s; float b = (n * sum_sz - sum_s * sum_z) / denom; @@ -418,7 +417,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) intx = std::get<2>(intersect); inty = std::get<3>(intersect); } - if(Verbosity() > 2) + if (Verbosity() > 2) { std::cout << "XY intersection options " << std::get<0>(intersect) << ", " << std::get<1>(intersect) << " and " << std::get<2>(intersect) << ", " << std::get<3>(intersect) << std::endl; } @@ -453,7 +452,6 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) float slope = tpcseed->get_slope(); float intz = m_vertexRadius * slope + tpcseed->get_Z0(); - Acts::Vector3 inter(intx, inty, intz); std::vector tpcparams{tpcR, tpcx, tpcy, tpcseed->get_slope(), @@ -562,7 +560,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_r.push_back(radius(claudepca.x(), claudepca.y())); m_tree->Fill(); } - if(m_dumpSeeds) + if (m_dumpSeeds) { SvtxTrack_v4 newTrack; newTrack.set_tpc_seed(tpcseed); @@ -609,7 +607,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) auto magcontext = m_tGeometry->geometry().magFieldContext; auto calibcontext = m_tGeometry->geometry().calibContext; - auto ppPlainOptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); + auto ppPlainOptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); ActsTrackFittingAlgorithm::GeneralFitterOptions kfOptions{ @@ -1023,7 +1021,7 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) m_y.push_back(glob.y()); m_z.push_back(glob.z()); float r = std::sqrt(glob.x() * glob.x() + glob.y() * glob.y()); - if(glob.y() < 0) + if (glob.y() < 0) { r *= -1; } @@ -1043,7 +1041,6 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) } void PHCosmicsTrkFitter::clearVectors() { - m_locx.clear(); m_locy.clear(); m_x.clear(); @@ -1090,7 +1087,7 @@ int PHCosmicsTrkFitter::getCharge( auto cluspos = sorted_positions[i]; float phi = std::atan2(cluspos.y() - tpccparams[2], cluspos.x() - tpccparams[1]); - if(phi > phi0) + if (phi > phi0) { posphi++; } From e7ceb043a228fde0e91e53f75ad18b97e24df12f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 Jun 2026 12:04:28 -0400 Subject: [PATCH 576/866] refactor into function --- .../packages/trackreco/PHCosmicsTrkFitter.cc | 131 ++++++++++-------- .../packages/trackreco/PHCosmicsTrkFitter.h | 1 + 2 files changed, 74 insertions(+), 58 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index 0e7a3b530e..bf2490c15d 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -353,58 +353,27 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } sorted_positions = pos; - TrackSeedHelper::circleFitByTaubin(tpcseed, positions, 0, 58); - - float tpcR = fabs(1. / tpcseed->get_qOverR()); - float tpcx = tpcseed->get_X0(); - float tpcy = tpcseed->get_Y0(); - - float dx = -tpcx; - float dy = m_vertexRadius - tpcy; - - float dist = std::sqrt(dx * dx + dy * dy); - float pcaxclaude = tpcx + tpcR * (dx / dist); - float pcayclaude = tpcy + tpcR * (dy / dist); - std::sort(sorted_positions.begin(), sorted_positions.end(), [](const Acts::Vector3& a, const Acts::Vector3& b) { - float aradius = std::sqrt(a.x()*a.x()+a.y()*a.y()); - if(a.y() < 0) - { - aradius *= -1; - } - float bradius = std::sqrt(b.x()*b.x()+b.y()*b.y()); - if(b.y() < 0) - { - bradius *= -1; - } - return aradius > bradius; }); + float aradius = std::sqrt(a.x()*a.x()+a.y()*a.y()); + if(a.y() < 0) + { + aradius *= -1; + } + float bradius = std::sqrt(b.x()*b.x()+b.y()*b.y()); + if(b.y() < 0) + { + bradius *= -1; + } + return aradius > bradius; }); - auto arcLength = [&](float x, float y) - { - float angle = std::atan2(y - tpcy, x - tpcx); - return tpcR * angle; - }; - float sum_s = 0, sum_z = 0, sum_ss = 0, sum_sz = 0; - int n = sorted_positions.size(); - for (auto& p : sorted_positions) - { - float s = arcLength(p.x(), p.y()); - sum_s += s; - sum_z += p.z(); - sum_ss += s * s; - sum_sz += s * p.z(); - } - float denom = n * sum_ss - sum_s * sum_s; - float b = (n * sum_sz - sum_s * sum_z) / denom; - float a = (sum_z - b * sum_s) / n; + TrackSeedHelper::circleFitByTaubin(tpcseed, positions, 0, 58); - float s_ca = arcLength(pcaxclaude, pcayclaude); - float z_ca = a + b * s_ca; + Acts::Vector3 pca = calculatePCA(tpcseed, sorted_positions); - Acts::Vector3 claudepca(pcaxclaude, pcayclaude, z_ca); - const auto intersect = TrackFitUtils::circle_circle_intersection(m_vertexRadius, tpcR, tpcx, tpcy); + // now calculate the momentum vector + const auto intersect = TrackFitUtils::circle_circle_intersection(m_vertexRadius, std::abs(1./tpcseed->get_qOverR()), tpcseed->get_X0(), tpcseed->get_Y0()); float intx, inty; if (std::get<1>(intersect) > std::get<3>(intersect)) @@ -454,7 +423,10 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) Acts::Vector3 inter(intx, inty, intz); - std::vector tpcparams{tpcR, tpcx, tpcy, tpcseed->get_slope(), + std::vector tpcparams{(float) std::abs(1./tpcseed->get_qOverR()), + tpcseed->get_X0(), + tpcseed->get_Y0(), + tpcseed->get_slope(), tpcseed->get_Z0()}; auto tangent = TrackFitUtils::get_helix_tangent(tpcparams, inter); @@ -516,7 +488,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } momentum.z() = pz; - Acts::Vector3 position = claudepca; + Acts::Vector3 position = pca; position *= Acts::UnitConstants::cm; if (!is_valid(momentum)) @@ -541,9 +513,9 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { clearVectors(); m_seed = tpcid; - m_R = tpcR; - m_X0 = tpcx; - m_Y0 = tpcy; + m_R = std::abs(1./tpcseed->get_qOverR()); + m_X0 = tpcseed->get_X0(); + m_Y0 = tpcseed->get_Y0(); m_Z0 = fulllineintz; m_slope = fulllineslope; m_pcax = position(0); @@ -554,10 +526,10 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_pz = momentum(2); m_charge = charge; fillVectors(siseed, tpcseed); - m_x.push_back(claudepca.x()); - m_y.push_back(claudepca.y()); - m_z.push_back(claudepca.z()); - m_r.push_back(radius(claudepca.x(), claudepca.y())); + m_x.push_back(position.x()); + m_y.push_back(position.y()); + m_z.push_back(position.z()); + m_r.push_back(radius(position.x(), position.y())); m_tree->Fill(); } if (m_dumpSeeds) @@ -572,9 +544,9 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) newTrack.set_px(momentum.x()); newTrack.set_py(momentum.y()); newTrack.set_pz(momentum.z()); - newTrack.set_x(claudepca.x()); - newTrack.set_y(claudepca.y()); - newTrack.set_z(claudepca.z()); + newTrack.set_x(position.x()); + newTrack.set_y(position.y()); + newTrack.set_z(position.z()); newTrack.set_charge(charge); m_trackMap->insertWithKey(&newTrack, trid); continue; @@ -1104,3 +1076,46 @@ int PHCosmicsTrkFitter::getCharge( return charge; } + +Acts::Vector3 PHCosmicsTrkFitter::calculatePCA(TrackSeed* seed, const std::vector& sorted_positions) +{ + float tpcR = fabs(1. / seed->get_qOverR()); + float tpcx = seed->get_X0(); + float tpcy = seed->get_Y0(); + + // calculate the pcaxy for the seed wrt a line surface located at (0,m_vertexRadius) in x-y plane + float dx = -tpcx; + float dy = m_vertexRadius - tpcy; + float dist = std::sqrt(dx * dx + dy * dy); + float pcax = tpcx + tpcR * (dx / dist); + float pcay = tpcy + tpcR * (dy / dist); + + auto arcLength = [&](float x, float y) + { + float angle = std::atan2(y - tpcy, x - tpcx); + return tpcR * angle; + }; + + float sum_s = 0, sum_z = 0, sum_ss = 0, sum_sz = 0; + int n = sorted_positions.size(); + // Compute the arc-length parameter for each cluster, then fit to a line + // Fit z = a + b*s using simple linear regression + for (auto& p : sorted_positions) + { + float s = arcLength(p.x(), p.y()); + sum_s += s; + sum_z += p.z(); + sum_ss += s * s; + sum_sz += s * p.z(); + } + + float denom = n * sum_ss - sum_s * sum_s; + float b = (n * sum_sz - sum_s * sum_z) / denom; + float a = (sum_z - b * sum_s) / n; + + // Then evaluate at the arc length of the PCA to get the z position of the PCA + float s_ca = arcLength(pcax, pcay); + float z_ca = a + b * s_ca; + + return Acts::Vector3(pcax, pcay, z_ca); +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index 1b23641a36..e111ee1463 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -112,6 +112,7 @@ class PHCosmicsTrkFitter : public SubsysReco Trajectory::IndexedParameters& paramsMap, ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track); + Acts::Vector3 calculatePCA(TrackSeed* seed, const std::vector& sorted_positions); /// Helper function to call either the regular navigation or direct /// navigation, depending on m_fitSiliconMMs From fb23caeec07a308d271c0bcb67d08bbc72f10eaf Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 Jun 2026 12:50:13 -0400 Subject: [PATCH 577/866] refactor momentum determination into function --- .../packages/trackreco/PHCosmicsTrkFitter.cc | 273 +++++++++--------- .../packages/trackreco/PHCosmicsTrkFitter.h | 4 +- 2 files changed, 134 insertions(+), 143 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index bf2490c15d..a30b991e0c 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -371,132 +371,16 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) Acts::Vector3 pca = calculatePCA(tpcseed, sorted_positions); + Acts::Vector3 momentum = calculateMomentum(tpcseed, sorted_positions); - // now calculate the momentum vector - const auto intersect = TrackFitUtils::circle_circle_intersection(m_vertexRadius, std::abs(1./tpcseed->get_qOverR()), tpcseed->get_X0(), tpcseed->get_Y0()); - float intx, inty; + Acts::Vector3 position = pca * Acts::UnitConstants::cm; - if (std::get<1>(intersect) > std::get<3>(intersect)) - { - intx = std::get<0>(intersect); - inty = std::get<1>(intersect); - } - else - { - intx = std::get<2>(intersect); - inty = std::get<3>(intersect); - } - if (Verbosity() > 2) - { - std::cout << "XY intersection options " << std::get<0>(intersect) << ", " << std::get<1>(intersect) << " and " << std::get<2>(intersect) << ", " << std::get<3>(intersect) << std::endl; - } - - std::vector keys; - std::vector clusPos; - std::copy(tpcseed->begin_cluster_keys(), tpcseed->end_cluster_keys(), std::back_inserter(keys)); - TrackFitUtils::getTrackletClusters(m_tGeometry, m_clusterContainer, - clusPos, keys); - TrackFitUtils::position_vector_t xypoints, rzpoints; - for (auto& p : clusPos) - { - float clusr = radius(p.x(), p.y()); - if (p.y() < 0) - { - clusr *= -1; - } - - // exclude silicon and tpot clusters for now - if (std::abs(clusr) > 80 || std::abs(clusr) < 30) - { - continue; - } - xypoints.push_back(std::make_pair(p.x(), p.y())); - rzpoints.push_back(std::make_pair(p.z(), clusr)); - } - - auto rzparams = TrackFitUtils::line_fit(rzpoints); - float fulllineintz = std::get<1>(rzparams); - float fulllineslope = std::get<0>(rzparams); - - float slope = tpcseed->get_slope(); - float intz = m_vertexRadius * slope + tpcseed->get_Z0(); - - Acts::Vector3 inter(intx, inty, intz); - - std::vector tpcparams{(float) std::abs(1./tpcseed->get_qOverR()), - tpcseed->get_X0(), - tpcseed->get_Y0(), - tpcseed->get_slope(), - tpcseed->get_Z0()}; - auto tangent = TrackFitUtils::get_helix_tangent(tpcparams, - inter); - - auto tan = tangent.second; - - float p; - if (m_ConstField) - { - p = std::cosh(tpcseed->get_eta()) * fabs(1. / tpcseed->get_qOverR()) * (0.3 / 100) * fieldstrength; - } - else - { - p = tpcseed->get_p(); - } - - tan *= p; - - //! if we got the opposite seed then z will be backwards, so we take the - //! value of tan.z() multiplied by the sign of the slope determined for - //! the full cosmic track - //! same with px/py since a single cosmic produces two seeds that bend - //! in opposite directions - float theta = std::atan(fulllineslope); - /// Normalize to 0(xyparams); - if (fulllineslopexy < 0) - { - momentum.x() = fabs(tan.x()); - } - else - { - momentum.x() = fabs(tan.x()) * -1; - } - momentum.y() = fabs(tan.y()) * -1; - } - - momentum.z() = pz; - Acts::Vector3 position = pca; - - position *= Acts::UnitConstants::cm; if (!is_valid(momentum)) { continue; } - int charge = getCharge(clusPos, tpcparams); + int charge = getCharge(tpcseed, sorted_positions); auto pSurface = Acts::Surface::makeShared( position); @@ -516,8 +400,8 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_R = std::abs(1./tpcseed->get_qOverR()); m_X0 = tpcseed->get_X0(); m_Y0 = tpcseed->get_Y0(); - m_Z0 = fulllineintz; - m_slope = fulllineslope; + m_Z0 = tpcseed->get_Z0(); + m_slope = tpcseed->get_slope(); m_pcax = position(0); m_pcay = position(1); m_pcaz = position(2); @@ -1028,28 +912,18 @@ void PHCosmicsTrkFitter::clearVectors() m_ez.clear(); } -int PHCosmicsTrkFitter::getCharge( - const std::vector& positions, - const std::vector& tpccparams) +int PHCosmicsTrkFitter::getCharge(TrackSeed *tpcseed, + const std::vector& sorted_positions) { Acts::GeometryContext transient_geocontext{m_alignmentTransformationMapTransient}; - std::vector sorted_positions = positions; - // sort the clusters in order of outermost radius to innermost radius - std::sort(sorted_positions.begin(), sorted_positions.end(), [](const Acts::Vector3& a, const Acts::Vector3& b) - { - float aradius = std::sqrt(a.x()*a.x()+a.y()*a.y()); - if(a.y() < 0) - { - aradius *= -1; - } - float bradius = std::sqrt(b.x()*b.x()+b.y()*b.y()); - if(b.y() < 0) - { - bradius *= -1; - } - return aradius > bradius; }); - float phi0 = std::atan2(sorted_positions[0].y() - tpccparams[2], sorted_positions[0].x() - tpccparams[1]); + std::vector tpcparams{(float) std::abs(1. / tpcseed->get_qOverR()), + tpcseed->get_X0(), + tpcseed->get_Y0(), + tpcseed->get_slope(), + tpcseed->get_Z0()}; + + float phi0 = std::atan2(sorted_positions[0].y() - tpcparams[2], sorted_positions[0].x() - tpcparams[1]); int posphi = 0; int negphi = 0; // just take the first 4 outermost clusters as a test to determine the bend angle @@ -1058,7 +932,7 @@ int PHCosmicsTrkFitter::getCharge( { auto cluspos = sorted_positions[i]; - float phi = std::atan2(cluspos.y() - tpccparams[2], cluspos.x() - tpccparams[1]); + float phi = std::atan2(cluspos.y() - tpcparams[2], cluspos.x() - tpcparams[1]); if (phi > phi0) { posphi++; @@ -1118,4 +992,121 @@ Acts::Vector3 PHCosmicsTrkFitter::calculatePCA(TrackSeed* seed, const std::vecto float z_ca = a + b * s_ca; return Acts::Vector3(pcax, pcay, z_ca); +} + + +Acts::Vector3 PHCosmicsTrkFitter::calculateMomentum(TrackSeed* tpcseed, const std::vector& sorted_positions) +{ + // now calculate the momentum vector + const auto intersect = TrackFitUtils::circle_circle_intersection(m_vertexRadius, std::abs(1. / tpcseed->get_qOverR()), tpcseed->get_X0(), tpcseed->get_Y0()); + float intx, inty; + + if (std::get<1>(intersect) > std::get<3>(intersect)) + { + intx = std::get<0>(intersect); + inty = std::get<1>(intersect); + } + else + { + intx = std::get<2>(intersect); + inty = std::get<3>(intersect); + } + if (Verbosity() > 2) + { + std::cout << "XY intersection options " << std::get<0>(intersect) << ", " << std::get<1>(intersect) << " and " << std::get<2>(intersect) << ", " << std::get<3>(intersect) << std::endl; + } + + TrackFitUtils::position_vector_t xypoints, rzpoints; + for (auto& p : sorted_positions) + { + float clusr = radius(p.x(), p.y()); + if (p.y() < 0) + { + clusr *= -1; + } + + // exclude silicon and tpot clusters for now + if (std::abs(clusr) > 80 || std::abs(clusr) < 30) + { + continue; + } + xypoints.push_back(std::make_pair(p.x(), p.y())); + rzpoints.push_back(std::make_pair(p.z(), clusr)); + } + + auto rzparams = TrackFitUtils::line_fit(rzpoints); + float fulllineslope = std::get<0>(rzparams); + + float slope = tpcseed->get_slope(); + float intz = m_vertexRadius * slope + tpcseed->get_Z0(); + + Acts::Vector3 inter(intx, inty, intz); + + std::vector tpcparams{(float) std::abs(1. / tpcseed->get_qOverR()), + tpcseed->get_X0(), + tpcseed->get_Y0(), + tpcseed->get_slope(), + tpcseed->get_Z0()}; + auto tangent = TrackFitUtils::get_helix_tangent(tpcparams, + inter); + + auto tan = tangent.second; + + float p; + if (m_ConstField) + { + p = std::cosh(tpcseed->get_eta()) * fabs(1. / tpcseed->get_qOverR()) * (0.3 / 100) * fieldstrength; + } + else + { + p = tpcseed->get_p(); + } + + tan *= p; + + //! if we got the opposite seed then z will be backwards, so we take the + //! value of tan.z() multiplied by the sign of the slope determined for + //! the full cosmic track + //! same with px/py since a single cosmic produces two seeds that bend + //! in opposite directions + float theta = std::atan(fulllineslope); + /// Normalize to 0(xyparams); + if (fulllineslopexy < 0) + { + momentum.x() = fabs(tan.x()); + } + else + { + momentum.x() = fabs(tan.x()) * -1; + } + momentum.y() = fabs(tan.y()) * -1; + } + + momentum.z() = pz; + + return momentum; } \ No newline at end of file diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index e111ee1463..ca83fbf56a 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -105,7 +105,7 @@ class PHCosmicsTrkFitter : public SubsysReco int createNodes(PHCompositeNode* topNode); void loopTracks(Acts::Logging::Level logLevel); - int getCharge(const std::vector& positions, const std::vector& tpcparams); + int getCharge(TrackSeed *tpcseed, const std::vector& sorted_positions); /// Convert the acts track fit result to an svtx track void updateSvtxTrack(std::vector& tips, @@ -113,7 +113,7 @@ class PHCosmicsTrkFitter : public SubsysReco ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track); Acts::Vector3 calculatePCA(TrackSeed* seed, const std::vector& sorted_positions); - + Acts::Vector3 calculateMomentum(TrackSeed* tpcseed, const std::vector& sorted_positions); /// Helper function to call either the regular navigation or direct /// navigation, depending on m_fitSiliconMMs inline ActsTrackFittingAlgorithm::TrackFitterResult fitTrack( From 6cb0dd2f91a4d3c5c631aed6c00463b513d37a03 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 Jun 2026 13:02:54 -0400 Subject: [PATCH 578/866] clang-format --- offline/packages/trackreco/PHCosmicsTrkFitter.cc | 7 +++---- offline/packages/trackreco/PHCosmicsTrkFitter.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index a30b991e0c..611a2d2eb6 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -397,7 +397,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { clearVectors(); m_seed = tpcid; - m_R = std::abs(1./tpcseed->get_qOverR()); + m_R = std::abs(1. / tpcseed->get_qOverR()); m_X0 = tpcseed->get_X0(); m_Y0 = tpcseed->get_Y0(); m_Z0 = tpcseed->get_Z0(); @@ -912,8 +912,8 @@ void PHCosmicsTrkFitter::clearVectors() m_ez.clear(); } -int PHCosmicsTrkFitter::getCharge(TrackSeed *tpcseed, - const std::vector& sorted_positions) +int PHCosmicsTrkFitter::getCharge(TrackSeed* tpcseed, + const std::vector& sorted_positions) { Acts::GeometryContext transient_geocontext{m_alignmentTransformationMapTransient}; @@ -994,7 +994,6 @@ Acts::Vector3 PHCosmicsTrkFitter::calculatePCA(TrackSeed* seed, const std::vecto return Acts::Vector3(pcax, pcay, z_ca); } - Acts::Vector3 PHCosmicsTrkFitter::calculateMomentum(TrackSeed* tpcseed, const std::vector& sorted_positions) { // now calculate the momentum vector diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index ca83fbf56a..5f71534b2f 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -105,7 +105,7 @@ class PHCosmicsTrkFitter : public SubsysReco int createNodes(PHCompositeNode* topNode); void loopTracks(Acts::Logging::Level logLevel); - int getCharge(TrackSeed *tpcseed, const std::vector& sorted_positions); + int getCharge(TrackSeed* tpcseed, const std::vector& sorted_positions); /// Convert the acts track fit result to an svtx track void updateSvtxTrack(std::vector& tips, From b757137ffd592187370bead729aa9899a0a46ce0 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Wed, 3 Jun 2026 13:27:56 -0400 Subject: [PATCH 579/866] Address feedback from review --- .../bcolumicount/StreamingBcoInfov1.cc | 1 + .../bcolumicount/StreamingBcoLumiReco.cc | 45 +++++++++++++++---- .../bcolumicount/StreamingBcoLumiReco.h | 7 ++- .../bcolumicount/StreamingLumiInfo.cc | 6 --- .../packages/bcolumicount/StreamingLumiInfo.h | 2 - .../bcolumicount/StreamingLumiInfov1.cc | 10 ----- .../bcolumicount/StreamingLumiInfov1.h | 2 - 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1.cc b/offline/packages/bcolumicount/StreamingBcoInfov1.cc index 9b97dd855e..73eb9f56b3 100644 --- a/offline/packages/bcolumicount/StreamingBcoInfov1.cc +++ b/offline/packages/bcolumicount/StreamingBcoInfov1.cc @@ -7,6 +7,7 @@ void StreamingBcoInfov1::Reset() { set_bco(0); + set_evtno(0); set_usable_bco_tag(false); set_bco_streaming_window(std::make_pair(0, 0)); return; diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc index 29b6ae794b..f735844f49 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc @@ -128,6 +128,15 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) //uint64_t gl1_livevec = packet->lValue(0, "TriggerVector"); int bunchno = packet->lValue(0,"BunchNumber"); + if (bunchno < 0 || bunchno >= m_bunches) + { + if (Verbosity() > 0) + { + std::cout << PHWHERE << " invalid bunch number: " << bunchno << std::endl; + } + delete packet; + return Fun4AllReturnCodes::ABORTEVENT; + } // SYNTAX TAKEN FROM ZHIWANS CODE, why = and not +=? If this is correct it seems like a waste to call it for every event (would just need it for the last event in a particular crossing?) m_bunchnumber_MBDNS_raw[bunchno] = packet->lValue(0, "GL1PRAW"); @@ -144,6 +153,12 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) if (Verbosity() > 2) { + if (!syncobject) + { + std::cout << PHWHERE << " SyncObject missing" << std::endl; + delete packet; + return Fun4AllReturnCodes::ABORTEVENT; + } std::cout << "Event No: " << syncobject->EventNumber() /*<< std::hex*/ << " gl1 bco: " << gtm_bco <(topNode, "STREAMINGBCOINFO"); + if (!streaming_bco_info) + { + std::cout << PHWHERE << " STREAMINGBCOINFO node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } m_bco = bcoinfo->get_current_bco(); if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} uint64_t bco_prev = bcoinfo->get_previous_bco(); @@ -167,12 +187,8 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) uint64_t bco_diff_prev = m_bco - bco_prev; uint64_t bco_diff_futu = bco_futu - m_bco; - // TODO: Set BCO window length in the macro - // TODO: Set BCO Negative window length in the macro - // window length: 360, negative window length: 20 - // Therefore, should check if BCO is within 340 // special case if BCO is within 20 of previous BCO? - if (bco_diff_prev < 340) + if (bco_diff_prev < m_default_positive_window_length) { m_usable_bco_tag = true; } @@ -180,14 +196,14 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) { m_usable_bco_tag = false; } - if (bco_diff_futu < 340) + if (bco_diff_futu < m_default_positive_window_length) { // double check boundaries for overlap!! - m_bco_streaming_window = std::make_pair(get_bco() - 20, bco_futu - 21); + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); } else { - m_bco_streaming_window = std::make_pair(get_bco() - 20, get_bco() + 340); + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, get_bco() + m_default_positive_window_length); } if (Verbosity() > 2) { @@ -237,6 +253,10 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) streaming_bco_info->set_bco(get_bco()); streaming_bco_info->set_usable_bco_tag(get_usable_bco_tag()); streaming_bco_info->set_bco_streaming_window(get_bco_streaming_window()); + if (syncobject) + { + streaming_bco_info->set_evtno(syncobject->EventNumber()); + } } } return Fun4AllReturnCodes::EVENT_OK; @@ -260,6 +280,11 @@ int StreamingBcoLumiReco::EndRun(int /*runnumber*/) std::cout << "bunchno : " << i << " lumi_raw : " << m_bunchnumber_lumi_raw[i] << std::endl; } } + if (!m_streaming_lumi_info) + { + std::cout << PHWHERE << " STREAMINGLUMIINFO node missing in EndRun" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } m_streaming_lumi_info->set_lumi_raw(get_lumi_raw()); m_streaming_lumi_info->set_lumi_live(get_lumi_live()); m_streaming_lumi_info->set_lumi_scaled(get_lumi_scaled()); @@ -276,6 +301,10 @@ int StreamingBcoLumiReco::EndRun(int /*runnumber*/) m_bunchnumber_MBDNS_raw.fill(0); m_bunchnumber_MBDNS_live.fill(0); m_bunchnumber_MBDNS_scaled.fill(0); + m_lumi_raw = 0.; + m_lumi_live = 0.; + m_lumi_scaled = 0.; + m_rawgl1scaler = 0; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.h b/offline/packages/bcolumicount/StreamingBcoLumiReco.h index 51b6f349ef..a5066eb7c6 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.h +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.h @@ -15,7 +15,7 @@ class StreamingBcoLumiReco : public SubsysReco { public: - StreamingBcoLumiReco(const std::string &name = "BCOLUMICHECK"); + StreamingBcoLumiReco(const std::string &name = "STREAMINGBCOLUMIRECO"); ~StreamingBcoLumiReco() override = default; int Init(PHCompositeNode *topNode) override; @@ -35,7 +35,8 @@ class StreamingBcoLumiReco : public SubsysReco virtual double get_lumi_live() const { return m_lumi_live; } virtual double get_lumi_scaled() const { return m_lumi_scaled; } - + virtual void set_default_positive_window_length(int val) { m_default_positive_window_length = val; } + virtual void set_default_negative_window_length(int val) { m_default_negative_window_length = val; } @@ -52,6 +53,8 @@ class StreamingBcoLumiReco : public SubsysReco int m_evtno{0}; bool m_usable_bco_tag = false; std::pair m_bco_streaming_window; + unsigned int m_default_positive_window_length{340}; + unsigned int m_default_negative_window_length{20}; double m_xsec_MBDNS = 24.07*1e9; //convert to pb from Vernier scan DOUBLE CHECK VALUE! diff --git a/offline/packages/bcolumicount/StreamingLumiInfo.cc b/offline/packages/bcolumicount/StreamingLumiInfo.cc index 753f82a858..f7f2afebc2 100644 --- a/offline/packages/bcolumicount/StreamingLumiInfo.cc +++ b/offline/packages/bcolumicount/StreamingLumiInfo.cc @@ -4,12 +4,6 @@ #include -void StreamingLumiInfo::Reset() -{ - std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; - return; -} - void StreamingLumiInfo::identify(std::ostream& os) const { os << "identify yourself: virtual StreamingLumiInfo Object" << std::endl; diff --git a/offline/packages/bcolumicount/StreamingLumiInfo.h b/offline/packages/bcolumicount/StreamingLumiInfo.h index 8c68be22d9..1644b91d3b 100644 --- a/offline/packages/bcolumicount/StreamingLumiInfo.h +++ b/offline/packages/bcolumicount/StreamingLumiInfo.h @@ -18,8 +18,6 @@ class StreamingLumiInfo : public PHObject StreamingLumiInfo() = default; /// dtor ~StreamingLumiInfo() override = default; - /// Clear Sync - void Reset() override; /** identify Function from PHObject @param os Output Stream diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.cc b/offline/packages/bcolumicount/StreamingLumiInfov1.cc index 8b554564ce..691259d784 100644 --- a/offline/packages/bcolumicount/StreamingLumiInfov1.cc +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.cc @@ -4,16 +4,6 @@ #include -void StreamingLumiInfov1::Reset() -{ - // Double check that this is only called once per run!! Or... it should just be called in the InitRun hook? - set_lumi_raw(0.); - set_lumi_live(0.); - set_lumi_scaled(0.); - - return; -} - void StreamingLumiInfov1::identify(std::ostream& os) const { os << "identify yourself: I am a StreamingLumiInfov1 Object\n"; return; diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.h b/offline/packages/bcolumicount/StreamingLumiInfov1.h index b25f1af295..b18a8a8c89 100644 --- a/offline/packages/bcolumicount/StreamingLumiInfov1.h +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.h @@ -19,8 +19,6 @@ class StreamingLumiInfov1 : public StreamingLumiInfo StreamingLumiInfov1() = default; /// dtor ~StreamingLumiInfov1() override = default; - /// Clear Sync - void Reset() override; /** identify Function from PHObject @param os Output Stream From c4441c0c1294542ae4e5cacf2afc00e3039bfb18 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 Jun 2026 13:31:16 -0400 Subject: [PATCH 580/866] fix units in diagnostic tree --- offline/packages/trackreco/PHCosmicsTrkFitter.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index 611a2d2eb6..8bde0c47bb 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -402,18 +402,18 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_Y0 = tpcseed->get_Y0(); m_Z0 = tpcseed->get_Z0(); m_slope = tpcseed->get_slope(); - m_pcax = position(0); - m_pcay = position(1); - m_pcaz = position(2); + m_pcax = position(0) / Acts::UnitConstants::cm; + m_pcay = position(1) / Acts::UnitConstants::cm; + m_pcaz = position(2) / Acts::UnitConstants::cm; m_px = momentum(0); m_py = momentum(1); m_pz = momentum(2); m_charge = charge; fillVectors(siseed, tpcseed); - m_x.push_back(position.x()); - m_y.push_back(position.y()); - m_z.push_back(position.z()); - m_r.push_back(radius(position.x(), position.y())); + m_x.push_back(position.x() / Acts::UnitConstants::cm); + m_y.push_back(position.y() / Acts::UnitConstants::cm); + m_z.push_back(position.z() / Acts::UnitConstants::cm); + m_r.push_back(radius(position.x(), position.y()) / Acts::UnitConstants::cm); m_tree->Fill(); } if (m_dumpSeeds) From 2331b813495758bebc28b5544edd152431d70290 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Wed, 3 Jun 2026 13:39:15 -0400 Subject: [PATCH 581/866] Remove unnecessary delete packet --- offline/packages/bcolumicount/StreamingBcoLumiReco.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc index f735844f49..277e7dfaf7 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc @@ -156,7 +156,6 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) if (!syncobject) { std::cout << PHWHERE << " SyncObject missing" << std::endl; - delete packet; return Fun4AllReturnCodes::ABORTEVENT; } std::cout << "Event No: " << syncobject->EventNumber() /*<< std::hex*/ From 1fa5e0fd8ab1bd18308a6d401fb04e222b2a7ed0 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Wed, 3 Jun 2026 13:59:34 -0400 Subject: [PATCH 582/866] Add vernier scan xsec to sphenix_constants. Value needs to be verified. --- offline/framework/phool/sphenix_constants.h | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/framework/phool/sphenix_constants.h b/offline/framework/phool/sphenix_constants.h index b5e72a4699..e1d00ca4c9 100644 --- a/offline/framework/phool/sphenix_constants.h +++ b/offline/framework/phool/sphenix_constants.h @@ -12,5 +12,6 @@ namespace sphenix_constants //! time between RHIC crossings (ns) static constexpr double time_between_crossings = 106.65237; static constexpr double CF4_density = 3.86; // mg / cm3 Tom Hemmick + static constexpr double m_xsec_MBDNS = 24.07*1e9; //convert to pb from Vernier scan } // namespace sphenix_constants #endif From 727d732973ee35d1d373fc7d257681d3383a3883 Mon Sep 17 00:00:00 2001 From: Virginia Bailey Date: Wed, 3 Jun 2026 14:35:11 -0400 Subject: [PATCH 583/866] add option to not do rescaling in RetowerCEMC --- offline/packages/jetbackground/RetowerCEMC.cc | 9 +++++++-- offline/packages/jetbackground/RetowerCEMC.h | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/offline/packages/jetbackground/RetowerCEMC.cc b/offline/packages/jetbackground/RetowerCEMC.cc index f9afbad6dd..890ed2cd7a 100644 --- a/offline/packages/jetbackground/RetowerCEMC.cc +++ b/offline/packages/jetbackground/RetowerCEMC.cc @@ -145,8 +145,13 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) } else { - towerinfo->set_energy(retower_e_temp / (double) (1 - scalefactor)); - if (retower_e_temp == 0) + if(_do_rescale) + { + towerinfo->set_energy(retower_e_temp / (double) (1 - scalefactor)); + } + else towerinfo->set_energy(retower_e_temp); + + if (retower_e_temp == 0) { towerinfo->set_time(0); } diff --git a/offline/packages/jetbackground/RetowerCEMC.h b/offline/packages/jetbackground/RetowerCEMC.h index 3edb6fd112..20661d3518 100644 --- a/offline/packages/jetbackground/RetowerCEMC.h +++ b/offline/packages/jetbackground/RetowerCEMC.h @@ -18,6 +18,7 @@ class RetowerCEMC : public SubsysReco void SetEnergyDistribution(int val) { _weighted_energy_distribution = val; } void set_frac_cut(double frac_cut) { _frac_cut = frac_cut; } + void set_do_rescale(bool do_rescale) {_do_rescale = do_rescale;} void set_towerinfo(bool use_towerinfo) { m_use_towerinfo = use_towerinfo; } void set_towerNodePrefix(const std::string &prefix) { @@ -32,7 +33,8 @@ class RetowerCEMC : public SubsysReco void get_weighted_fraction(PHCompositeNode *topNode); int _weighted_energy_distribution{1}; - double _frac_cut{0.5}; + double _frac_cut{1}; + bool _do_rescale{false}; bool m_use_towerinfo{false}; std::string m_towerNodePrefix{"TOWERINFO_CALIB"}; From 3891ae7f5ffad4cfca208eee7f6f4ab9c8829728 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 3 Jun 2026 14:36:21 -0400 Subject: [PATCH 584/866] clangify cosmics trk fitter --- .../packages/trackreco/PHCosmicsTrkFitter.cc | 39 +++++++++++-------- .../packages/trackreco/PHCosmicsTrkFitter.h | 2 +- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index 8bde0c47bb..e2103a0858 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -258,7 +259,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) std::cout << " seed map size " << m_seedMap->size() << std::endl; } - for (auto track : *m_seedMap) + for (auto* track : *m_seedMap) { if (!track) { @@ -269,10 +270,10 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) unsigned int siid = track->get_silicon_seed_index(); // get the crossing number - auto siseed = m_siliconSeeds->get(siid); + auto* siseed = m_siliconSeeds->get(siid); short crossing = 0; - auto tpcseed = m_tpcSeeds->get(tpcid); + auto* tpcseed = m_tpcSeeds->get(tpcid); if (Verbosity() > 1) { std::cout << "TPC id " << tpcid << std::endl; @@ -341,7 +342,8 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) // copy transient map for this track into transient geoContext m_transient_geocontext = geoContext; - std::vector pos, sorted_positions; + std::vector pos; + std::vector sorted_positions; // get positions from cluster keys // TODO: should implement distortions TrackSeedHelper::position_map_t positions; @@ -739,7 +741,7 @@ int PHCosmicsTrkFitter::createNodes(PHCompositeNode* topNode) if (!m_alignmentStateMap) { m_alignmentStateMap = new SvtxAlignmentStateMap_v1; - auto node = new PHDataNode(m_alignmentStateMap, "SvtxAlignmentStateMap", "PHObject"); + auto* node = new PHDataNode(m_alignmentStateMap, "SvtxAlignmentStateMap", "PHObject"); svtxNode->addNode(node); } @@ -858,7 +860,7 @@ void PHCosmicsTrkFitter::makeBranches() } void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) { - for (auto seed : {tpcseed, siseed}) + for (auto* seed : {tpcseed, siseed}) { if (!seed) { @@ -869,7 +871,7 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) ++it) { auto key = *it; - auto cluster = m_clusterContainer->findCluster(key); + auto* cluster = m_clusterContainer->findCluster(key); m_locx.push_back(cluster->getLocalX()); m_locy.push_back(cluster->getLocalY()); auto glob = m_tGeometry->getGlobalPosition(key, cluster); @@ -888,7 +890,7 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) m_phisize.push_back(cluster->getPhiSize()); m_zsize.push_back(cluster->getZSize()); auto para_errors = - m_clusErrPara.get_clusterv5_modified_error(cluster, r, key); + ClusterErrorPara::get_clusterv5_modified_error(cluster, r, key); m_ephi.push_back(std::sqrt(para_errors.first)); m_ez.push_back(std::sqrt(para_errors.second)); @@ -951,7 +953,7 @@ int PHCosmicsTrkFitter::getCharge(TrackSeed* tpcseed, return charge; } -Acts::Vector3 PHCosmicsTrkFitter::calculatePCA(TrackSeed* seed, const std::vector& sorted_positions) +Acts::Vector3 PHCosmicsTrkFitter::calculatePCA(TrackSeed* seed, const std::vector& sorted_positions) const { float tpcR = fabs(1. / seed->get_qOverR()); float tpcx = seed->get_X0(); @@ -970,11 +972,14 @@ Acts::Vector3 PHCosmicsTrkFitter::calculatePCA(TrackSeed* seed, const std::vecto return tpcR * angle; }; - float sum_s = 0, sum_z = 0, sum_ss = 0, sum_sz = 0; + float sum_s = 0; + float sum_z = 0; + float sum_ss = 0; + float sum_sz = 0; int n = sorted_positions.size(); // Compute the arc-length parameter for each cluster, then fit to a line // Fit z = a + b*s using simple linear regression - for (auto& p : sorted_positions) + for (const auto& p : sorted_positions) { float s = arcLength(p.x(), p.y()); sum_s += s; @@ -998,7 +1003,8 @@ Acts::Vector3 PHCosmicsTrkFitter::calculateMomentum(TrackSeed* tpcseed, const st { // now calculate the momentum vector const auto intersect = TrackFitUtils::circle_circle_intersection(m_vertexRadius, std::abs(1. / tpcseed->get_qOverR()), tpcseed->get_X0(), tpcseed->get_Y0()); - float intx, inty; + float intx; + float inty; if (std::get<1>(intersect) > std::get<3>(intersect)) { @@ -1015,8 +1021,9 @@ Acts::Vector3 PHCosmicsTrkFitter::calculateMomentum(TrackSeed* tpcseed, const st std::cout << "XY intersection options " << std::get<0>(intersect) << ", " << std::get<1>(intersect) << " and " << std::get<2>(intersect) << ", " << std::get<3>(intersect) << std::endl; } - TrackFitUtils::position_vector_t xypoints, rzpoints; - for (auto& p : sorted_positions) + TrackFitUtils::position_vector_t xypoints; + TrackFitUtils::position_vector_t rzpoints; + for (const auto& p : sorted_positions) { float clusr = radius(p.x(), p.y()); if (p.y() < 0) @@ -1029,8 +1036,8 @@ Acts::Vector3 PHCosmicsTrkFitter::calculateMomentum(TrackSeed* tpcseed, const st { continue; } - xypoints.push_back(std::make_pair(p.x(), p.y())); - rzpoints.push_back(std::make_pair(p.z(), clusr)); + xypoints.emplace_back(p.x(), p.y()); + rzpoints.emplace_back(p.z(), clusr); } auto rzparams = TrackFitUtils::line_fit(rzpoints); diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index 5f71534b2f..c3f95cb8a5 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -112,7 +112,7 @@ class PHCosmicsTrkFitter : public SubsysReco Trajectory::IndexedParameters& paramsMap, ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track); - Acts::Vector3 calculatePCA(TrackSeed* seed, const std::vector& sorted_positions); + Acts::Vector3 calculatePCA(TrackSeed* seed, const std::vector& sorted_positions) const; Acts::Vector3 calculateMomentum(TrackSeed* tpcseed, const std::vector& sorted_positions); /// Helper function to call either the regular navigation or direct /// navigation, depending on m_fitSiliconMMs From fabdc92cc5364602dcdc61378e645528cfd702a8 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 3 Jun 2026 15:01:12 -0400 Subject: [PATCH 585/866] fix histo name --- .../framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 11 ++++++----- .../framework/fun4allraw/TpcTimeFrameBuilderRun3.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index c1f8c3f92e..90199b7d8a 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -167,11 +167,11 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) 3328, -.5, 3328 - .5); hm->registerHisto(h_TimeFrame_Matched_Size); - h_Run3FEEClockDiff_FuzzyFallback = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3FEEClockDiff_FuzzyFallback", // + h_Run3_FEE_GTMMatching_ClockDiff = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3_FEE_GTMMatching_ClockDiff", // TString(m_HistoPrefix.c_str()) + - " Run3 fuzzy fallback FEE clock diff;Clock Difference [FEE Clock Cycle];Count", + " Run3 FEE GTM matching clock diff;Clock Difference [FEE Clock Cycle];Count", 2048, -1024 - .5, 1024 - .5); - hm->registerHisto(h_Run3FEEClockDiff_FuzzyFallback); + hm->registerHisto(h_Run3_FEE_GTMMatching_ClockDiff); h_Run3TimeFrameExactHit_FEE = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3TimeFrameExactHit_FEE", // TString(m_HistoPrefix.c_str()) + @@ -522,6 +522,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g { assert(h_Run3TimeFrameExactHit_FEE); h_Run3TimeFrameExactHit_FEE->Fill(fee, exact_hits); + h_Run3_FEE_GTMMatching_ClockDiff->Fill(0., static_cast(exact_hits)); continue; } @@ -540,8 +541,8 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g fallback_hit_count += fuzzy_hits; assert(h_Run3TimeFrameFuzzyHit_FEE); h_Run3TimeFrameFuzzyHit_FEE->Fill(fee, fuzzy_hits); - assert(h_Run3FEEClockDiff_FuzzyFallback); - h_Run3FEEClockDiff_FuzzyFallback->Fill(get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco)); + assert(h_Run3_FEE_GTMMatching_ClockDiff); + h_Run3_FEE_GTMMatching_ClockDiff->Fill(get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco), fuzzy_hits); if (m_verbosity >= 1) { diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 161ad0ba1b..89578149bf 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -429,7 +429,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH1 *h_GTMClockDiff_Unmatched = nullptr; TH1 *h_GTMClockDiff_Dropped = nullptr; TH1 *h_TimeFrame_Matched_Size = nullptr; - TH1 *h_Run3FEEClockDiff_FuzzyFallback = nullptr; + TH1 *h_Run3_FEE_GTMMatching_ClockDiff = nullptr; TH1 *h_Run3TimeFrameExactHit_FEE = nullptr; TH1 *h_Run3TimeFrameFuzzyHit_FEE = nullptr; TH1 *h_Run3PreviousTimeFrameWaveformStart = nullptr; From 953e3e968b39a38d2f6007e18a421a738b6ff690 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 3 Jun 2026 15:24:40 -0400 Subject: [PATCH 586/866] refactor: change h_Run3_FEE_GTMMatching_ClockDiff to a 2D histogram and update fill methods --- .../framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 13 ++++++++----- .../framework/fun4allraw/TpcTimeFrameBuilderRun3.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 90199b7d8a..82bedc93d7 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -167,10 +167,11 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) 3328, -.5, 3328 - .5); hm->registerHisto(h_TimeFrame_Matched_Size); - h_Run3_FEE_GTMMatching_ClockDiff = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3_FEE_GTMMatching_ClockDiff", // + h_Run3_FEE_GTMMatching_ClockDiff = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3_FEE_GTMMatching_ClockDiff", // TString(m_HistoPrefix.c_str()) + - " Run3 FEE GTM matching clock diff;Clock Difference [FEE Clock Cycle];Count", - 2048, -1024 - .5, 1024 - .5); + " Run3 FEE GTM matching clock diff by FEE;Clock Difference [FEE Clock Cycle];FEE;Matched hits", + 2048, -1024 - .5, 1024 - .5, + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); hm->registerHisto(h_Run3_FEE_GTMMatching_ClockDiff); h_Run3TimeFrameExactHit_FEE = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3TimeFrameExactHit_FEE", // @@ -522,7 +523,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g { assert(h_Run3TimeFrameExactHit_FEE); h_Run3TimeFrameExactHit_FEE->Fill(fee, exact_hits); - h_Run3_FEE_GTMMatching_ClockDiff->Fill(0., static_cast(exact_hits)); + h_Run3_FEE_GTMMatching_ClockDiff->Fill(0., static_cast(fee), static_cast(exact_hits)); continue; } @@ -542,7 +543,9 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g assert(h_Run3TimeFrameFuzzyHit_FEE); h_Run3TimeFrameFuzzyHit_FEE->Fill(fee, fuzzy_hits); assert(h_Run3_FEE_GTMMatching_ClockDiff); - h_Run3_FEE_GTMMatching_ClockDiff->Fill(get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco), fuzzy_hits); + h_Run3_FEE_GTMMatching_ClockDiff->Fill(static_cast(get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco)), + static_cast(fee), + static_cast(fuzzy_hits)); if (m_verbosity >= 1) { diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 89578149bf..0037e99695 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -429,7 +429,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH1 *h_GTMClockDiff_Unmatched = nullptr; TH1 *h_GTMClockDiff_Dropped = nullptr; TH1 *h_TimeFrame_Matched_Size = nullptr; - TH1 *h_Run3_FEE_GTMMatching_ClockDiff = nullptr; + TH2 *h_Run3_FEE_GTMMatching_ClockDiff = nullptr; TH1 *h_Run3TimeFrameExactHit_FEE = nullptr; TH1 *h_Run3TimeFrameFuzzyHit_FEE = nullptr; TH1 *h_Run3PreviousTimeFrameWaveformStart = nullptr; From c10378b68b78676352658e7e58b55c38e3f92c7d Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 3 Jun 2026 16:00:04 -0400 Subject: [PATCH 587/866] enhance exact hit matching logic and add GTM BCO offset constant --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 26 ++++++++++++++++--- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 4 +++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 82bedc93d7..eaa4b7ecc9 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -517,13 +517,28 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g continue; } - const size_t exact_hits = move_time_hits(*predicted_fee_bco, fee, timeframe); + size_t exact_hits = 0; + for (int32_t fee_clock_offset = -kRun3ExactMatchWindow; fee_clock_offset <= kRun3ExactMatchWindow; ++fee_clock_offset) + { + const uint32_t exact_fee_bco = static_cast(static_cast(static_cast(*predicted_fee_bco) + fee_clock_offset) & kFEEClockMask); + const size_t exact_hits_for_bco = move_time_hits(exact_fee_bco, fee, timeframe); + if (exact_hits_for_bco == 0) + { + continue; + } + + exact_hits += exact_hits_for_bco; + assert(h_Run3_FEE_GTMMatching_ClockDiff); + h_Run3_FEE_GTMMatching_ClockDiff->Fill(static_cast(get_signed_fee_bco_diff(exact_fee_bco, *predicted_fee_bco)), + static_cast(fee), + static_cast(exact_hits_for_bco)); + } + exact_hit_count += exact_hits; if (exact_hits > 0) { assert(h_Run3TimeFrameExactHit_FEE); h_Run3TimeFrameExactHit_FEE->Fill(fee, exact_hits); - h_Run3_FEE_GTMMatching_ClockDiff->Fill(0., static_cast(fee), static_cast(exact_hits)); continue; } @@ -1901,15 +1916,18 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c m_hNorm->Fill("SyncGTM", 1); // get BCO and assign + const uint64_t bco_reference_gtm_bco = gtm_bco + kBXCounterSyncGtmBcoOffset; m_verified_from_modebits = true; - m_bco_reference = std::make_pair(gtm_bco, 0); + m_bco_reference = std::make_pair(bco_reference_gtm_bco, 0); m_bco_reference_candidate_list.clear(); if (m_verbosity) { std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits" << "\t- found reference from modebits BX_COUNTER_SYNC_T " - << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << "at gtm_bco = 0x" << std::hex << gtm_bco + << " reference gtm_bco = 0x" << bco_reference_gtm_bco << std::dec + << " sync offset = " << kBXCounterSyncGtmBcoOffset << std::endl; } } // if (modebits == BX_COUNTER_SYNC_T) // initiate synchronization of clock sync diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 0037e99695..564492b3e5 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -352,6 +352,9 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! max time in GTM BCO for FEE data to sync over to datastream static constexpr unsigned int m_max_fee_sync_time = 1024 * 8; + //! fixed GTM BCO offset applied when BX_COUNTER_SYNC_T defines the reference clock + static constexpr uint64_t kBXCounterSyncGtmBcoOffset = 4; + static constexpr unsigned int m_FEE_CLOCK_BITS = 20; static constexpr unsigned int m_GTM_CLOCK_BITS = 40; @@ -381,6 +384,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static constexpr uint32_t kFEEClockMask = (1U << 20U) - 1U; static constexpr uint32_t kRun3FeeMatchWindow = (GL1_BCO_MATCH_WINDOW * 30U + 7U) / 8U; + static constexpr int32_t kRun3ExactMatchWindow = 2; static int64_t get_signed_fee_bco_diff(uint32_t first, uint32_t second); static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); From 84f82e4c4ba28c9bc574d2779846d2169692b2cb Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 3 Jun 2026 16:13:43 -0400 Subject: [PATCH 588/866] refactor: comment out unused GTM BCO matching methods and histograms --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 366 ++++++++---------- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 12 +- 2 files changed, 176 insertions(+), 202 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index eaa4b7ecc9..112e263885 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -1629,16 +1629,16 @@ TpcTimeFrameBuilderRun3::BcoMatchingInformation::BcoMatchingInformation(const st 1024, -.5, +1024 - .5); hm->registerHisto(m_hGTMNewEventSpacing); - m_hFindGTMBCO_MatchedExisting_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedExisting_BCODiff", // - TString(m_name.c_str()) + - " find_gtm_bco matched to existing event clock diff;Clock Difference [FEE Clock Cycle];Count", - 512, -256 - .5, +256 - .5); - hm->registerHisto(m_hFindGTMBCO_MatchedExisting_BCODiff); - m_hFindGTMBCO_MatchedNew_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedNew_BCODiff", // - TString(m_name.c_str()) + - " find_gtm_bco matched to new event clock diff;Clock Difference [FEE Clock Cycle];Count", - 512, -256 - .5, +256 - .5); - hm->registerHisto(m_hFindGTMBCO_MatchedNew_BCODiff); + // m_hFindGTMBCO_MatchedExisting_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedExisting_BCODiff", // + // TString(m_name.c_str()) + + // " find_gtm_bco matched to existing event clock diff;Clock Difference [FEE Clock Cycle];Count", + // 512, -256 - .5, +256 - .5); + // hm->registerHisto(m_hFindGTMBCO_MatchedExisting_BCODiff); + // m_hFindGTMBCO_MatchedNew_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedNew_BCODiff", // + // TString(m_name.c_str()) + + // " find_gtm_bco matched to new event clock diff;Clock Difference [FEE Clock Cycle];Count", + // 512, -256 - .5, +256 - .5); + // hm->registerHisto(m_hFindGTMBCO_MatchedNew_BCODiff); } //! whether reference bco has moved pass the given gtm_bco @@ -1918,7 +1918,7 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c // get BCO and assign const uint64_t bco_reference_gtm_bco = gtm_bco + kBXCounterSyncGtmBcoOffset; m_verified_from_modebits = true; - m_bco_reference = std::make_pair(bco_reference_gtm_bco, 0); + m_bco_reference = std::make_pair(bco_reference_gtm_bco, kBXCounterSyncFEEBcoOffset); m_bco_reference_candidate_list.clear(); if (m_verbosity) @@ -1927,7 +1927,8 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c << "\t- found reference from modebits BX_COUNTER_SYNC_T " << "at gtm_bco = 0x" << std::hex << gtm_bco << " reference gtm_bco = 0x" << bco_reference_gtm_bco << std::dec - << " sync offset = " << kBXCounterSyncGtmBcoOffset + << " GTM sync offset = " << kBXCounterSyncGtmBcoOffset + << " FEE sync offset = " << kBXCounterSyncFEEBcoOffset << std::endl; } } // if (modebits == BX_COUNTER_SYNC_T) // initiate synchronization of clock sync @@ -1981,12 +1982,10 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re // check if the predicted fee bco matches the actual fee bco if (get_fee_bco_diff(fee_bco_predicted, fee_bco) < m_max_fee_bco_diff) { - // assign gtm bco - m_bco_reference.value().second = fee_bco; - + // Keep QA for matched heartbeat, but do not update clock reference from heartbeat. if (verbosity() > 1) { - std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found an updated reference heartbeat and updated reference clock sync: " + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found a matched reference heartbeat; clock reference update disabled: " << std::hex << "\t- fee_bco: 0x" << fee_bco << "\t- predicted: 0x" << fee_bco_predicted @@ -2014,7 +2013,7 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re { if (verbosity() > 1) { - std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found a new reference canidate heartbeat and replaced reference clock sync: " + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found a new reference candidate heartbeat; clock reference update disabled: " << std::hex << "\t- fee_bco: 0x" << fee_bco << "\t- predicted: 0x" << fee_bco_predicted @@ -2024,38 +2023,11 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re << std::dec << std::endl; } - // assign gtm bco - m_bco_reference = std::make_pair(gtm_bco, fee_bco); - + // Keep QA for matched candidate heartbeat, but do not replace the clock reference or trim candidates. if (m_verbosity > 1) { - std::cout << "\t- trimming m_bco_reference_candidate_list from size " << m_bco_reference_candidate_list.size() << std::endl; - - for (const m_gtm_fee_bco_matching_pair_t& bco_tmp : m_bco_reference_candidate_list) - { - std::cout << "\t\t- gtm_bco = 0x" << std::hex << bco_tmp.first << std::dec - << "\t\t- fee_bco = 0x" << std::hex << bco_tmp.second << std::dec - << std::endl; - } - } - - // remove the older candidate from the list - while (m_bco_reference_candidate_list.begin()->first != gtm_bco) - { - m_bco_reference_candidate_list.pop_front(); - } - m_bco_reference_candidate_list.pop_front(); - - if (m_verbosity > 1) - { - std::cout << "\t- to size " << m_bco_reference_candidate_list.size() << std::endl; - - for (const m_gtm_fee_bco_matching_pair_t& bco_tmp : m_bco_reference_candidate_list) - { - std::cout << "\t\t- gtm_bco = 0x" << std::hex << bco_tmp.first << std::dec - << "\t\t- fee_bco = 0x" << std::hex << bco_tmp.second << std::dec - << std::endl; - } + std::cout << "\t- clock reference update from heartbeat is disabled; candidate list retained at size " + << m_bco_reference_candidate_list.size() << std::endl; } assert(m_hFEEClockAdjustment_MatchedNew); @@ -2088,156 +2060,156 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re return std::nullopt; } -//___________________________________________________ -std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_gtm_bco(uint32_t fee_bco) -{ - if (verbosity() > 5) - { - std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - entry: " - << std::hex - << "\t- fee_bco: 0x" << fee_bco - << std::dec - << "\t- is_verified(): " << (is_verified() ? "true" : "false") - << std::endl; - } - - // make sure the bco matching is properly initialized - if (!is_verified()) - { - return std::nullopt; - } - - assert(m_hNorm); - m_hNorm->Fill("FindGTMBCO", 1); - - // find matching gtm bco in map - const auto bco_matching_iter = std::find_if( - m_bco_matching_list.begin(), - m_bco_matching_list.end(), - [fee_bco](const m_fee_gtm_bco_matching_pair_t& pair) - { return get_fee_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); - - if (bco_matching_iter != m_bco_matching_list.end()) - { - m_hNorm->Fill("FindGTMBCOMatchedExisting", 1); - assert(m_hFindGTMBCO_MatchedExisting_BCODiff); - m_hFindGTMBCO_MatchedExisting_BCODiff->Fill(int64_t(fee_bco) - int64_t(bco_matching_iter->first)); - - if (verbosity() > 3) - { - std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - found existing FEE BCO: " - << std::hex - << "\t- fee_bco: 0x" << fee_bco - << "\t- predicted: 0x" << bco_matching_iter->first - << "\t- gtm_bco: 0x" << bco_matching_iter->second - << std::dec - << std::endl; - } - - return bco_matching_iter->second; - } - // find element for which predicted fee_bco matches fee_bco, within limit - const auto iter = std::find_if( - m_gtm_bco_trig_list.begin(), - m_gtm_bco_trig_list.end(), - [this, fee_bco](const uint64_t& gtm_bco) - { return get_fee_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); - - // check - if (iter != m_gtm_bco_trig_list.end()) - { - const uint64_t gtm_bco = *iter; - - m_hNorm->Fill("FindGTMBCOMatchedNew", 1); - assert(m_hFindGTMBCO_MatchedNew_BCODiff); - m_hFindGTMBCO_MatchedNew_BCODiff->Fill(int64_t(fee_bco) - int64_t(gtm_bco)); - - if (verbosity() > 2) - { - if (auto opt_fee_bco = get_predicted_fee_bco(gtm_bco)) // check if optional exists - { - const uint32_t fee_bco_predicted = *opt_fee_bco; // get_predicted_fee_bco(gtm_bco).value(); - const uint32_t fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco); - - std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - new GL1 match: " - << std::hex - << "\t- fee_bco: 0x" << fee_bco - << "\t- predicted: 0x" << fee_bco_predicted - << "\t- gtm_bco: 0x" << gtm_bco - << std::dec - << "\t- difference: " << fee_bco_diff - << std::endl; - } - } - // save fee_bco and gtm_bco matching in map - m_bco_matching_list.emplace_back(fee_bco, gtm_bco); - - // remove gtm bco from runing list - m_gtm_bco_trig_list.erase(iter); - - // // update clock adjustment not applied for non HEARTBEAT_T - // update_multiplier_adjustment(gtm_bco, fee_bco); - - return gtm_bco; - } - - m_hNorm->Fill("FindGTMBCOMatchedFailed", 1); - - bool new_orphan = m_orphans.insert(fee_bco).second; - - if ((new_orphan && verbosity()) || (verbosity() > 3)) - { - // find element for which predicted fee_bco is the closest to request - const auto iter2 = std::min_element( - m_gtm_bco_trig_list.begin(), - m_gtm_bco_trig_list.end(), - [this, fee_bco](const uint64_t& first, const uint64_t& second) - { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); - - // const int fee_bco_diff = (iter2 != m_gtm_bco_trig_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1; - // compared to the previous statement, this checks if the optional - int fee_bco_diff = -1; - - if (iter2 != m_gtm_bco_trig_list.end()) - { - auto predicted = get_predicted_fee_bco(*iter2); - - if (predicted) - { - fee_bco_diff = get_bco_diff(*predicted, fee_bco); - } - } - - if (m_verbosity >= 2) - { - std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - match failed!" - << std::hex - << "\t- fee_bco: 0x" << fee_bco - << std::dec - << "\t- gtm_bco: 0x" << *iter2 - << "\t- difference: " << fee_bco_diff - << std::endl; - } - } // if ((new_orphan and verbosity()) or (verbosity()>3)) - - if (verbosity() > 3) - { - std::cout << "\t- m_gtm_bco_trig_list : " << std::endl; - for (const auto& gtm_bco : m_gtm_bco_trig_list) - { - std::cout << "\t\t- 0x" << std::hex << gtm_bco << " -> 0x" << get_predicted_fee_bco(gtm_bco).value() << std::dec << std::endl; // NOLINT(bugprone-unchecked-optional-access) - } - - std::cout << "\t- m_bco_matching_list : " << std::endl; - for (const auto& iter_m_bco_matching_list : m_bco_matching_list) - { - std::cout << "\t\t- 0x" << std::hex << iter_m_bco_matching_list.first << " -> 0x" << iter_m_bco_matching_list.second << std::dec << std::endl; - } - - } // if (verbosity()>3) - - return std::nullopt; -} +// //___________________________________________________ +// std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_gtm_bco(uint32_t fee_bco) +// { +// if (verbosity() > 5) +// { +// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - entry: " +// << std::hex +// << "\t- fee_bco: 0x" << fee_bco +// << std::dec +// << "\t- is_verified(): " << (is_verified() ? "true" : "false") +// << std::endl; +// } + +// // make sure the bco matching is properly initialized +// if (!is_verified()) +// { +// return std::nullopt; +// } + +// assert(m_hNorm); +// m_hNorm->Fill("FindGTMBCO", 1); + +// // find matching gtm bco in map +// const auto bco_matching_iter = std::find_if( +// m_bco_matching_list.begin(), +// m_bco_matching_list.end(), +// [fee_bco](const m_fee_gtm_bco_matching_pair_t& pair) +// { return get_fee_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); + +// if (bco_matching_iter != m_bco_matching_list.end()) +// { +// m_hNorm->Fill("FindGTMBCOMatchedExisting", 1); +// assert(m_hFindGTMBCO_MatchedExisting_BCODiff); +// m_hFindGTMBCO_MatchedExisting_BCODiff->Fill(int64_t(fee_bco) - int64_t(bco_matching_iter->first)); + +// if (verbosity() > 3) +// { +// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - found existing FEE BCO: " +// << std::hex +// << "\t- fee_bco: 0x" << fee_bco +// << "\t- predicted: 0x" << bco_matching_iter->first +// << "\t- gtm_bco: 0x" << bco_matching_iter->second +// << std::dec +// << std::endl; +// } + +// return bco_matching_iter->second; +// } +// // find element for which predicted fee_bco matches fee_bco, within limit +// const auto iter = std::find_if( +// m_gtm_bco_trig_list.begin(), +// m_gtm_bco_trig_list.end(), +// [this, fee_bco](const uint64_t& gtm_bco) +// { return get_fee_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); + +// // check +// if (iter != m_gtm_bco_trig_list.end()) +// { +// const uint64_t gtm_bco = *iter; + +// m_hNorm->Fill("FindGTMBCOMatchedNew", 1); +// assert(m_hFindGTMBCO_MatchedNew_BCODiff); +// m_hFindGTMBCO_MatchedNew_BCODiff->Fill(int64_t(fee_bco) - int64_t(gtm_bco)); + +// if (verbosity() > 2) +// { +// if (auto opt_fee_bco = get_predicted_fee_bco(gtm_bco)) // check if optional exists +// { +// const uint32_t fee_bco_predicted = *opt_fee_bco; // get_predicted_fee_bco(gtm_bco).value(); +// const uint32_t fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco); + +// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - new GL1 match: " +// << std::hex +// << "\t- fee_bco: 0x" << fee_bco +// << "\t- predicted: 0x" << fee_bco_predicted +// << "\t- gtm_bco: 0x" << gtm_bco +// << std::dec +// << "\t- difference: " << fee_bco_diff +// << std::endl; +// } +// } +// // save fee_bco and gtm_bco matching in map +// m_bco_matching_list.emplace_back(fee_bco, gtm_bco); + +// // remove gtm bco from runing list +// m_gtm_bco_trig_list.erase(iter); + +// // // update clock adjustment not applied for non HEARTBEAT_T +// // update_multiplier_adjustment(gtm_bco, fee_bco); + +// return gtm_bco; +// } + +// m_hNorm->Fill("FindGTMBCOMatchedFailed", 1); + +// bool new_orphan = m_orphans.insert(fee_bco).second; + +// if ((new_orphan && verbosity()) || (verbosity() > 3)) +// { +// // find element for which predicted fee_bco is the closest to request +// const auto iter2 = std::min_element( +// m_gtm_bco_trig_list.begin(), +// m_gtm_bco_trig_list.end(), +// [this, fee_bco](const uint64_t& first, const uint64_t& second) +// { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); + +// // const int fee_bco_diff = (iter2 != m_gtm_bco_trig_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1; +// // compared to the previous statement, this checks if the optional +// int fee_bco_diff = -1; + +// if (iter2 != m_gtm_bco_trig_list.end()) +// { +// auto predicted = get_predicted_fee_bco(*iter2); + +// if (predicted) +// { +// fee_bco_diff = get_bco_diff(*predicted, fee_bco); +// } +// } + +// if (m_verbosity >= 2) +// { +// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - match failed!" +// << std::hex +// << "\t- fee_bco: 0x" << fee_bco +// << std::dec +// << "\t- gtm_bco: 0x" << *iter2 +// << "\t- difference: " << fee_bco_diff +// << std::endl; +// } +// } // if ((new_orphan and verbosity()) or (verbosity()>3)) + +// if (verbosity() > 3) +// { +// std::cout << "\t- m_gtm_bco_trig_list : " << std::endl; +// for (const auto& gtm_bco : m_gtm_bco_trig_list) +// { +// std::cout << "\t\t- 0x" << std::hex << gtm_bco << " -> 0x" << get_predicted_fee_bco(gtm_bco).value() << std::dec << std::endl; // NOLINT(bugprone-unchecked-optional-access) +// } + +// std::cout << "\t- m_bco_matching_list : " << std::endl; +// for (const auto& iter_m_bco_matching_list : m_bco_matching_list) +// { +// std::cout << "\t\t- 0x" << std::hex << iter_m_bco_matching_list.first << " -> 0x" << iter_m_bco_matching_list.second << std::dec << std::endl; +// } + +// } // if (verbosity()>3) + +// return std::nullopt; +// } //___________________________________________________ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup() diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 564492b3e5..509d881e9f 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -234,8 +234,8 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! save all GTM BCO clocks from packet data void save_gtm_bco_information(const gtm_payload >m_tagger); - //! find gtm bco matching a given fee - std::optional find_gtm_bco(uint32_t /*fee_gtm*/); + // //! find gtm bco matching a given fee + // std::optional find_gtm_bco(uint32_t /*fee_gtm*/); //! cleanup void cleanup(); @@ -353,7 +353,9 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static constexpr unsigned int m_max_fee_sync_time = 1024 * 8; //! fixed GTM BCO offset applied when BX_COUNTER_SYNC_T defines the reference clock - static constexpr uint64_t kBXCounterSyncGtmBcoOffset = 4; + static constexpr uint64_t kBXCounterSyncGtmBcoOffset = 0; + //! fixed FEE BCO offset applied when BX_COUNTER_SYNC_T defines the reference clock + static constexpr uint64_t kBXCounterSyncFEEBcoOffset = 15; static constexpr unsigned int m_FEE_CLOCK_BITS = 20; static constexpr unsigned int m_GTM_CLOCK_BITS = 40; @@ -366,8 +368,8 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH1 *m_hFEEClockAdjustment_MatchedNew = nullptr; TH1 *m_hFEEClockAdjustment_Unmatched = nullptr; TH1 *m_hGTMNewEventSpacing = nullptr; - TH1 *m_hFindGTMBCO_MatchedExisting_BCODiff = nullptr; - TH1 *m_hFindGTMBCO_MatchedNew_BCODiff = nullptr; + // TH1 *m_hFindGTMBCO_MatchedExisting_BCODiff = nullptr; + // TH1 *m_hFindGTMBCO_MatchedNew_BCODiff = nullptr; }; // class BcoMatchingInformation From 43961c24b187f27eada8196bf56a57d889f562e4 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 3 Jun 2026 16:29:49 -0400 Subject: [PATCH 589/866] feat: add count_time_hits method to improve hit counting logic --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 34 +++++++++++++++---- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 3 +- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 112e263885..a92ddb39fb 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -366,6 +366,25 @@ size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, s return moved; } +size_t TpcTimeFrameBuilderRun3::count_time_hits(uint32_t fee_bco, uint16_t fee) const +{ + auto it = m_timeHitMap.find(fee_bco & kFEEClockMask); + if (it == m_timeHitMap.end()) + { + return 0; + } + + size_t count = 0; + for (const TpcRawHit* hit : it->second) + { + if (hit->get_fee() == fee) + { + ++count; + } + } + return count; +} + std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const { uint32_t best_fee_bco = 0; @@ -548,7 +567,8 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g continue; } - const size_t fuzzy_hits = move_time_hits(*fuzzy_fee_bco, fee, timeframe); + + const size_t fuzzy_hits = count_time_hits(*fuzzy_fee_bco, fee); if (fuzzy_hits == 0) { continue; @@ -573,6 +593,12 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } } + if (fallback_hit_count > 0) + { + m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback", 1); + m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback_Hit_Sum", fallback_hit_count); + } + if (timeframe.empty()) { if (m_verbosity >= 1) @@ -594,12 +620,6 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g { m_hNorm->Fill("Run3_TimeFrame_Exact_Matched", 1); } - if (fallback_hit_count > 0) - { - m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback", 1); - m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback_Hit_Sum", fallback_hit_count); - } - m_hNorm->Fill("GTM_TimeFrame_Matched", 1); assert(h_TimeFrame_Matched_Size); h_TimeFrame_Matched_Size->Fill(timeframe.size()); diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 509d881e9f..bf8da5f5dd 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -355,7 +355,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! fixed GTM BCO offset applied when BX_COUNTER_SYNC_T defines the reference clock static constexpr uint64_t kBXCounterSyncGtmBcoOffset = 0; //! fixed FEE BCO offset applied when BX_COUNTER_SYNC_T defines the reference clock - static constexpr uint64_t kBXCounterSyncFEEBcoOffset = 15; + static constexpr uint64_t kBXCounterSyncFEEBcoOffset = 12; static constexpr unsigned int m_FEE_CLOCK_BITS = 20; static constexpr unsigned int m_GTM_CLOCK_BITS = 40; @@ -391,6 +391,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static int64_t get_signed_fee_bco_diff(uint32_t first, uint32_t second); static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe); + size_t count_time_hits(uint32_t fee_bco, uint16_t fee) const; std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); void flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco); From 7d93cb5d96875dbe87f870924c66912edaccd7e7 Mon Sep 17 00:00:00 2001 From: Virginia Bailey Date: Wed, 3 Jun 2026 16:41:11 -0400 Subject: [PATCH 590/866] store bad tower fraction even if tower is masked --- offline/packages/jetbackground/RetowerCEMC.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/jetbackground/RetowerCEMC.cc b/offline/packages/jetbackground/RetowerCEMC.cc index 890ed2cd7a..7ed0409f04 100644 --- a/offline/packages/jetbackground/RetowerCEMC.cc +++ b/offline/packages/jetbackground/RetowerCEMC.cc @@ -159,8 +159,8 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) { towerinfo->set_time((retower_time_temp / retower_e_temp)); } - towerinfo->set_chi2(scalefactor); } + towerinfo->set_chi2(scalefactor); //store the fraction of bad towers as the chi2 } } } From 4741a7b14be0c88cf59eb133db8f011c0c32d4a1 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Wed, 3 Jun 2026 17:34:26 -0400 Subject: [PATCH 591/866] CD: Better truth matching --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 69 +++++++++++-------- .../HFTrackEfficiency/HFTrackEfficiency.h | 6 +- .../packages/HFTrackEfficiency/Makefile.am | 3 +- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 4797d957ec..d8deb15af0 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -114,6 +114,13 @@ int HFTrackEfficiency::process_event(PHCompositeNode *topNode) } } + if (!m_svtx_evalstack) + { + m_svtx_evalstack = new SvtxEvalStack(topNode); + trackeval = m_svtx_evalstack->get_track_eval(); + } + m_svtx_evalstack->next_event(topNode); +/* m_dst_truth_reco_map = findNode::getClass(topNode, "PHG4ParticleSvtxMap"); if (m_dst_truth_reco_map) { @@ -129,7 +136,7 @@ int HFTrackEfficiency::process_event(PHCompositeNode *topNode) std::cout << __FILE__ << ": PHG4ParticleSvtxMap not found, reverting to true matching by momentum relations. Truth matching will be less accurate" << std::endl; } } - +*/ if (m_decay_descriptor.empty() && !m_decayMap->empty()) { getDecayDescriptor(); @@ -231,11 +238,12 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) } int index = -1; + PHG4Particle *daughterG4 {nullptr}; for (unsigned int i = 1; i < decay.size(); ++i) { m_dst_track = nullptr; - int truth_ID = -1; + //int truth_ID = -1; if (std::find(std::begin(trackableParticles), std::end(trackableParticles), std::abs(decay[i].second)) != std::end(trackableParticles)) @@ -261,23 +269,24 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_z = thisVtx->point3d().z(); // We need the G4 ID, not the HepMC ID to use the truth/reco map - if (m_dst_truth_reco_map) + //if (m_dst_truth_reco_map) + //{ + PHG4TruthInfoContainer::ConstRange range = m_truthInfo->GetParticleRange(); + + for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { - PHG4TruthInfoContainer::ConstRange range = m_truthInfo->GetParticleRange(); + //PHG4Particle *daughterG4 = iter->second; + daughterG4 = iter->second; - for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) + if (std::abs(daughterG4->get_px() - daughterTrueLV->x()) <= 5e-3 && + std::abs(daughterG4->get_py() - daughterTrueLV->y()) <= 5e-3 && + std::abs(daughterG4->get_pz() - daughterTrueLV->z()) <= 5e-3 && daughterG4->get_pid() == decay[i].second) { - PHG4Particle *daughterG4 = iter->second; - - if (std::abs(daughterG4->get_px() - daughterTrueLV->x()) <= 5e-3 && - std::abs(daughterG4->get_py() - daughterTrueLV->y()) <= 5e-3 && - std::abs(daughterG4->get_pz() - daughterTrueLV->z()) <= 5e-3 && daughterG4->get_pid() == decay[i].second) - { - truth_ID = daughterG4->get_track_id(); - break; - } + //truth_ID = daughterG4->get_track_id(); + break; } } + //} } else { @@ -285,7 +294,8 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { - PHG4Particle *daughterG4 = iter->second; + //PHG4Particle *daughterG4 = iter->second; + daughterG4 = iter->second; PHG4Particle *motherG4 = nullptr; if (daughterG4->get_parent_id() != 0) @@ -328,7 +338,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_z = thisVtx->get_z(); m_true_track_PID[index] = daughterG4->get_pid(); - truth_ID = daughterG4->get_track_id(); + //truth_ID = daughterG4->get_track_id(); delete mother3Vector; } @@ -341,20 +351,21 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_min_true_track_pT = std::min(m_true_track_pT[index], m_min_true_track_pT); m_max_true_track_pT = std::max(m_true_track_pT[index], m_max_true_track_pT); - if (m_dst_truth_reco_map && truth_ID >= 0) + //if (m_dst_truth_reco_map && truth_ID >= 0) + if (trackeval && daughterG4) { - std::map> reco_set = m_dst_truth_reco_map->get(truth_ID); - if (reco_set.empty()) - { - continue; - } - const auto &best_weight = reco_set.rbegin(); - if (best_weight->second.empty()) - { - continue; - } - unsigned int best_reco_id = *best_weight->second.rbegin(); - m_dst_track = m_input_trackMap->get(best_reco_id); + //std::map> reco_set = m_dst_truth_reco_map->get(truth_ID); + //if (reco_set.empty()) + //{ + // continue; + //} + //const auto &best_weight = reco_set.rbegin(); + //if (best_weight->second.empty()) + //{ + // continue; + //} + //unsigned int best_reco_id = *best_weight->second.rbegin(); + m_dst_track = trackeval->best_track_from(daughterG4);//m_input_trackMap->get(best_reco_id); if (m_dst_track) { m_used_truth_reco_map[index] = true; diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h index f667c3bc27..e68e51520c 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h @@ -4,6 +4,8 @@ #define HFTRACKEFFICIENCY_H #include +#include +#include #include #include @@ -54,7 +56,9 @@ class HFTrackEfficiency : public SubsysReco PHHepMCGenEventMap *m_geneventmap{nullptr}; PHHepMCGenEvent *m_genevt{nullptr}; - PHG4ParticleSvtxMap *m_dst_truth_reco_map{nullptr}; + SvtxEvalStack *m_svtx_evalstack{nullptr}; + SvtxTrackEval *trackeval{nullptr}; + //PHG4ParticleSvtxMap *m_dst_truth_reco_map{nullptr}; DecayFinderContainerBase *m_decayMap{nullptr}; std::string m_df_module_name; diff --git a/offline/packages/HFTrackEfficiency/Makefile.am b/offline/packages/HFTrackEfficiency/Makefile.am index ed47b011eb..7b53aed68f 100644 --- a/offline/packages/HFTrackEfficiency/Makefile.am +++ b/offline/packages/HFTrackEfficiency/Makefile.am @@ -24,7 +24,8 @@ libhftrackefficiency_la_LIBADD = \ -ldecayfinder_io \ -ltrackbase_historic_io \ -lphg4hit \ - -lphhepmc + -lphhepmc \ + -lg4eval ################################################ # linking tests From 8201aee906706af3d5bdb3e2027f824bf3cd319e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 4 Jun 2026 08:50:36 -0400 Subject: [PATCH 592/866] fix benign clang tidy warning and occasional surface param problem --- offline/packages/trackreco/PHCosmicsTrkFitter.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index e2103a0858..fc6de17328 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -377,13 +377,13 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) Acts::Vector3 position = pca * Acts::UnitConstants::cm; - if (!is_valid(momentum)) + if (!is_valid(momentum) || !is_valid(position)) { continue; } int charge = getCharge(tpcseed, sorted_positions); - + auto pSurface = Acts::Surface::makeShared( position); auto actsFourPos = Acts::Vector4(position(0), position(1), @@ -410,8 +410,9 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_px = momentum(0); m_py = momentum(1); m_pz = momentum(2); + m_charge = charge; - fillVectors(siseed, tpcseed); + fillVectors(tpcseed, siseed); m_x.push_back(position.x() / Acts::UnitConstants::cm); m_y.push_back(position.y() / Acts::UnitConstants::cm); m_z.push_back(position.z() / Acts::UnitConstants::cm); From 8d386e95729cf8c5a55840b1db142ed8ce4f6e98 Mon Sep 17 00:00:00 2001 From: Virginia Bailey Date: Thu, 4 Jun 2026 18:18:33 -0400 Subject: [PATCH 593/866] clang tidy --- offline/packages/jetbackground/RetowerCEMC.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/jetbackground/RetowerCEMC.cc b/offline/packages/jetbackground/RetowerCEMC.cc index 7ed0409f04..9b896a1c48 100644 --- a/offline/packages/jetbackground/RetowerCEMC.cc +++ b/offline/packages/jetbackground/RetowerCEMC.cc @@ -149,7 +149,8 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) { towerinfo->set_energy(retower_e_temp / (double) (1 - scalefactor)); } - else towerinfo->set_energy(retower_e_temp); + else { towerinfo->set_energy(retower_e_temp); +} if (retower_e_temp == 0) { From 435077bc2e01fd6f3cbd79ec27239ae4c2e333ea Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Thu, 4 Jun 2026 20:18:45 -0400 Subject: [PATCH 594/866] clang-tidy --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index a92ddb39fb..5219d54d16 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -313,8 +313,8 @@ void TpcTimeFrameBuilderRun3::cache_timeframe_waveform_starts(uint64_t gtm_bco, int64_t TpcTimeFrameBuilderRun3::get_signed_fee_bco_diff(uint32_t first, uint32_t second) { - static constexpr int64_t fee_clock_range = 1LL << 20U; - static constexpr int64_t fee_clock_half_range = 1LL << 19U; + static constexpr int64_t fee_clock_range = static_cast(uint64_t{1} << 20U); + static constexpr int64_t fee_clock_half_range = static_cast(uint64_t{1} << 19U); int64_t diff = static_cast(first & kFEEClockMask) - static_cast(second & kFEEClockMask); if (diff > fee_clock_half_range) @@ -528,9 +528,10 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g size_t exact_hit_count = 0; size_t fallback_hit_count = 0; - for (uint16_t fee = 0; fee < m_bcoMatchingInformation_vec.size(); ++fee) + for (size_t fee_index = 0; fee_index < m_bcoMatchingInformation_vec.size(); ++fee_index) { - const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee].get_predicted_fee_bco(bclk_rollover_corrected); + const uint16_t fee = static_cast(fee_index); + const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee_index].get_predicted_fee_bco(bclk_rollover_corrected); if (!predicted_fee_bco) { continue; @@ -1747,20 +1748,21 @@ bool TpcTimeFrameBuilderRun3::BcoMatchingInformation::isMoreDataRequired(const u std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::get_predicted_fee_bco(uint64_t gtm_bco) const { // check proper initialization - if (!is_verified()) + if (!is_verified() || !m_bco_reference) { return std::nullopt; } // get gtm bco difference with proper rollover accounting - const int64_t gtm_bco_difference = int64_t(gtm_bco) - int64_t(m_bco_reference.value().first); // NOLINT(bugprone-unchecked-optional-access) + const auto& bco_reference = *m_bco_reference; + const int64_t gtm_bco_difference = int64_t(gtm_bco) - int64_t(bco_reference.first); assert(m_clock_ratio_numerator > 0); assert(m_clock_ratio_denominator > 0); // convert to fee bco with the exact Run3 30/8 ratio, and truncate to 20 bits - const int64_t fee_bco_predicted = int64_t(m_bco_reference.value().second) + - (gtm_bco_difference * m_clock_ratio_numerator) / m_clock_ratio_denominator; // NOLINT(bugprone-unchecked-optional-access) + const int64_t fee_bco_predicted = int64_t(bco_reference.second) + + (gtm_bco_difference * m_clock_ratio_numerator) / m_clock_ratio_denominator; return uint32_t(static_cast(fee_bco_predicted) & 0xFFFFFU); } From 25eecda311902299ca488b54b7e02fe361266675 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 5 Jun 2026 00:43:47 -0400 Subject: [PATCH 595/866] fix clang-tidy, use consistent initializers --- offline/packages/jetbackground/RetowerCEMC.cc | 18 +++++++------ offline/packages/jetbackground/RetowerCEMC.h | 26 +++++++++---------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/offline/packages/jetbackground/RetowerCEMC.cc b/offline/packages/jetbackground/RetowerCEMC.cc index 9b896a1c48..9543f0e75b 100644 --- a/offline/packages/jetbackground/RetowerCEMC.cc +++ b/offline/packages/jetbackground/RetowerCEMC.cc @@ -145,14 +145,16 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) } else { - if(_do_rescale) - { - towerinfo->set_energy(retower_e_temp / (double) (1 - scalefactor)); - } - else { towerinfo->set_energy(retower_e_temp); -} + if (_do_rescale) + { + towerinfo->set_energy(retower_e_temp / (double) (1 - scalefactor)); + } + else + { + towerinfo->set_energy(retower_e_temp); + } - if (retower_e_temp == 0) + if (retower_e_temp == 0) { towerinfo->set_time(0); } @@ -161,7 +163,7 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) towerinfo->set_time((retower_time_temp / retower_e_temp)); } } - towerinfo->set_chi2(scalefactor); //store the fraction of bad towers as the chi2 + towerinfo->set_chi2(scalefactor); // store the fraction of bad towers as the chi2 } } } diff --git a/offline/packages/jetbackground/RetowerCEMC.h b/offline/packages/jetbackground/RetowerCEMC.h index 20661d3518..3c48a057ce 100644 --- a/offline/packages/jetbackground/RetowerCEMC.h +++ b/offline/packages/jetbackground/RetowerCEMC.h @@ -18,7 +18,7 @@ class RetowerCEMC : public SubsysReco void SetEnergyDistribution(int val) { _weighted_energy_distribution = val; } void set_frac_cut(double frac_cut) { _frac_cut = frac_cut; } - void set_do_rescale(bool do_rescale) {_do_rescale = do_rescale;} + void set_do_rescale(bool do_rescale) { _do_rescale = do_rescale; } void set_towerinfo(bool use_towerinfo) { m_use_towerinfo = use_towerinfo; } void set_towerNodePrefix(const std::string &prefix) { @@ -38,21 +38,21 @@ class RetowerCEMC : public SubsysReco bool m_use_towerinfo{false}; std::string m_towerNodePrefix{"TOWERINFO_CALIB"}; - static const int neta_ihcal = 24; - static const int neta_emcal = 96; - static const int nphi_ihcal = 64; - static const int nphi_emcal = 256; + static const int neta_ihcal{24}; + static const int neta_emcal{96}; + static const int nphi_ihcal{64}; + static const int nphi_emcal{256}; - int retower_lowerbound_originaltower_ieta[neta_ihcal] = {0}; - int retower_upperbound_originaltower_ieta[neta_ihcal] = {0}; - double retower_lowerbound_originaltower_fraction[neta_ihcal] = {0.0}; - double retower_upperbound_originaltower_fraction[neta_ihcal] = {0.0}; - double retower_totalarea[neta_ihcal] = {0.0}; + int retower_lowerbound_originaltower_ieta[neta_ihcal]{0}; + int retower_upperbound_originaltower_ieta[neta_ihcal]{0}; + double retower_lowerbound_originaltower_fraction[neta_ihcal]{0.0}; + double retower_upperbound_originaltower_fraction[neta_ihcal]{0.0}; + double retower_totalarea[neta_ihcal]{0.0}; int retower_first_lowerbound_originaltower_iphi{-1}; - double rawtower_e[neta_emcal][nphi_emcal] = {{0.0}}; - double rawtower_time[neta_emcal][nphi_emcal] = {{0.0}}; - int rawtower_status[neta_emcal][nphi_emcal] = {{0}}; + double rawtower_e[neta_emcal][nphi_emcal]{{0.0}}; + double rawtower_time[neta_emcal][nphi_emcal]{{0.0}}; + int rawtower_status[neta_emcal][nphi_emcal]{{0}}; std::string EMTowerName; std::string IHTowerName; From f2f4d86735c95100f6594f21079de60bec705041 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Fri, 5 Jun 2026 12:51:32 -0400 Subject: [PATCH 596/866] speed up --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 214 ++++++++++-------- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 5 +- 2 files changed, 127 insertions(+), 92 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 5219d54d16..224bc4a6a9 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -42,6 +42,7 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) } m_feeData.resize(MAX_FEECOUNT); + m_timeHitMap.resize(MAX_FEECOUNT); // cppcheck-suppress noCopyConstructor // cppcheck-suppress noOperatorEq @@ -207,14 +208,16 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() { - for (auto& timeHitEntry : m_timeHitMap) + for (auto& feeTimeHitMap : m_timeHitMap) { - while (!timeHitEntry.second.empty()) + for (auto& timeHitEntry : feeTimeHitMap) { - TpcRawHit* hit = timeHitEntry.second.back(); - erase_waveform_start_cache(hit); - delete hit; - timeHitEntry.second.pop_back(); + for (TpcRawHit* hit : timeHitEntry.second) + { + erase_waveform_start_cache(hit); + delete hit; + } + timeHitEntry.second.clear(); } } @@ -336,85 +339,114 @@ uint32_t TpcTimeFrameBuilderRun3::get_fee_bco_diff(uint32_t first, uint32_t seco size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector& timeframe) { - auto it = m_timeHitMap.find(fee_bco & kFEEClockMask); - if (it == m_timeHitMap.end()) + if (fee >= m_timeHitMap.size()) { return 0; } - size_t moved = 0; - auto& hits = it->second; - for (auto hit_it = hits.begin(); hit_it != hits.end();) + auto& fee_time_hits = m_timeHitMap[fee]; + auto it = fee_time_hits.find(fee_bco & kFEEClockMask); + if (it == fee_time_hits.end()) { - TpcRawHit* hit = *hit_it; - if (hit->get_fee() == fee) - { - timeframe.push_back(hit); - hit_it = hits.erase(hit_it); - ++moved; - } - else - { - ++hit_it; - } + return 0; } - if (hits.empty()) + std::vector& hits = it->second; + const size_t moved = hits.size(); + if (moved == 0) { - m_timeHitMap.erase(it); + fee_time_hits.erase(it); + return 0; } + + timeframe.reserve(timeframe.size() + moved); + timeframe.insert(timeframe.end(), hits.begin(), hits.end()); + fee_time_hits.erase(it); return moved; } size_t TpcTimeFrameBuilderRun3::count_time_hits(uint32_t fee_bco, uint16_t fee) const { - auto it = m_timeHitMap.find(fee_bco & kFEEClockMask); - if (it == m_timeHitMap.end()) + if (fee >= m_timeHitMap.size()) + { + return 0; + } + + const auto& fee_time_hits = m_timeHitMap[fee]; + auto it = fee_time_hits.find(fee_bco & kFEEClockMask); + if (it == fee_time_hits.end()) { return 0; } + return it->second.size(); +} + +size_t TpcTimeFrameBuilderRun3::time_hit_bucket_count() const +{ size_t count = 0; - for (const TpcRawHit* hit : it->second) + for (const auto& fee_time_hits : m_timeHitMap) { - if (hit->get_fee() == fee) - { - ++count; - } + count += fee_time_hits.size(); } return count; } std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const { + if (fee >= m_timeHitMap.size()) + { + return std::nullopt; + } + + const auto& fee_time_hits = m_timeHitMap[fee]; + if (fee_time_hits.empty()) + { + return std::nullopt; + } + + predicted_fee_bco &= kFEEClockMask; uint32_t best_fee_bco = 0; uint32_t best_diff = std::numeric_limits::max(); + bool found = false; - for (const auto& [fee_bco, hits] : m_timeHitMap) + auto consider_fee_bco = [&](uint32_t fee_bco, const std::vector& hits) { - bool has_fee_hit = false; - for (const TpcRawHit* hit : hits) - { - if (hit->get_fee() == fee) - { - has_fee_hit = true; - break; - } - } - if (!has_fee_hit) + if (hits.empty()) { - continue; + return; } const uint32_t diff = get_fee_bco_diff(fee_bco, predicted_fee_bco); - if (diff < best_diff) + if (diff <= kRun3FeeMatchWindow && (!found || diff < best_diff || (diff == best_diff && fee_bco < best_fee_bco))) { + found = true; best_diff = diff; best_fee_bco = fee_bco; } + }; + + auto scan_range = [&](uint32_t first_fee_bco, uint32_t last_fee_bco) + { + for (auto it = fee_time_hits.lower_bound(first_fee_bco); it != fee_time_hits.end() && it->first <= last_fee_bco; ++it) + { + consider_fee_bco(it->first, it->second); + } + }; + + const uint32_t lower_fee_bco = (predicted_fee_bco - kRun3FeeMatchWindow) & kFEEClockMask; + const uint32_t upper_fee_bco = (predicted_fee_bco + kRun3FeeMatchWindow) & kFEEClockMask; + if (lower_fee_bco <= upper_fee_bco) + { + scan_range(lower_fee_bco, upper_fee_bco); + } + else + { + scan_range(lower_fee_bco, kFEEClockMask); + scan_range(0, upper_fee_bco); } - if (best_diff <= kRun3FeeMatchWindow) + if (found) { return best_fee_bco; } @@ -425,48 +457,35 @@ void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_correc { assert(m_hFEEDataStream); - for (auto map_it = m_timeHitMap.begin(); map_it != m_timeHitMap.end();) + const size_t nfees = std::min(m_timeHitMap.size(), m_bcoMatchingInformation_vec.size()); + for (size_t fee_index = 0; fee_index < nfees; ++fee_index) { - auto& hits = map_it->second; - for (auto hit_it = hits.begin(); hit_it != hits.end();) + const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee_index].get_predicted_fee_bco(bclk_rollover_corrected); + if (!predicted_fee_bco) { - TpcRawHit* hit = *hit_it; - const uint16_t fee = hit->get_fee(); - if (fee >= m_bcoMatchingInformation_vec.size()) - { - ++hit_it; - continue; - } - - const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee].get_predicted_fee_bco(bclk_rollover_corrected); - if (!predicted_fee_bco) - { - ++hit_it; - continue; - } + continue; + } + const uint16_t fee = static_cast(fee_index); + auto& fee_time_hits = m_timeHitMap[fee_index]; + for (auto map_it = fee_time_hits.begin(); map_it != fee_time_hits.end();) + { const int64_t diff = get_signed_fee_bco_diff(map_it->first, *predicted_fee_bco); if ((fee_clock_window == 0 && diff <= 0) || (fee_clock_window > 0 && diff < -static_cast(fee_clock_window))) { - m_hFEEDataStream->Fill(hit->get_fee(), "HitUnusedBeforeCleanup", 1); - erase_waveform_start_cache(hit); - delete hit; - hit_it = hits.erase(hit_it); + for (TpcRawHit* hit : map_it->second) + { + m_hFEEDataStream->Fill(fee, "HitUnusedBeforeCleanup", 1); + erase_waveform_start_cache(hit); + delete hit; + } + map_it = fee_time_hits.erase(map_it); } else { - ++hit_it; + ++map_it; } } - - if (hits.empty()) - { - map_it = m_timeHitMap.erase(map_it); - } - else - { - ++map_it; - } } } @@ -607,7 +626,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ":ERROR: Run3 FEE-clock match failed for gtm_bco: 0x" << std::hex << gtm_bco << std::dec << " bclk_rollover_corrected 0x" << std::hex << bclk_rollover_corrected << std::dec - << ". m_timeHitMap size: " << m_timeHitMap.size() << std::endl; + << ". m_timeHitMap size: " << time_hit_bucket_count() << std::endl; } m_hNorm->Fill("Run3_TimeFrame_MatchFailed", 1); @@ -872,22 +891,30 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) } // sanity check for the cached FEE-clock hit size - for (auto& timehit : m_timeHitMap) + for (size_t fee = 0; fee < m_timeHitMap.size(); ++fee) { - if (timehit.second.size() > kMaxRawHitLimit) + auto& fee_time_hits = m_timeHitMap[fee]; + for (auto timehit = fee_time_hits.begin(); timehit != fee_time_hits.end();) { - std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : impossible amount of hits at FEE BCO " - << timehit.first << "\t- : " << timehit.second.size() << ", limit is " << kMaxRawHitLimit - << ". Dropping this FEE-clock cache!" - << std::endl; - m_hNorm->Fill("TimeFrameSizeLimitError", 1); + if (timehit->second.size() > kMaxRawHitLimit) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : impossible amount of hits for FEE " + << fee << " at FEE BCO " << timehit->first << "\t- : " << timehit->second.size() + << ", limit is " << kMaxRawHitLimit + << ". Dropping this FEE-clock cache!" + << std::endl; + m_hNorm->Fill("TimeFrameSizeLimitError", 1); - while (!timehit.second.empty()) + for (TpcRawHit* hit : timehit->second) + { + erase_waveform_start_cache(hit); + delete hit; + } + timehit = fee_time_hits.erase(timehit); + } + else { - TpcRawHit* hit = timehit.second.back(); - erase_waveform_start_cache(hit); - delete hit; - timehit.second.pop_back(); + ++timehit; } } } @@ -1211,8 +1238,15 @@ void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, // valid packet in the buffer, create a new hit if (payload.type != TpcTimeFrameBuilderRun3::BcoMatchingInformation::HEARTBEAT_T) { + if (fee >= m_timeHitMap.size()) + { + std::cout << __PRETTY_FUNCTION__ << ": ERROR : invalid FEE " << fee + << " for packet " << m_packet_id << ". Dropping waveform hit." << std::endl; + return; + } + TpcRawHitv3* hit = new TpcRawHitv3(); - m_timeHitMap[payload.bx_timestamp & kFEEClockMask].push_back(hit); + m_timeHitMap[fee][payload.bx_timestamp & kFEEClockMask].push_back(hit); hit->set_bco(payload.bx_timestamp); hit->set_packetid(m_packet_id); diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index bf8da5f5dd..dde620f7ce 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -392,14 +392,15 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe); size_t count_time_hits(uint32_t fee_bco, uint16_t fee) const; + size_t time_hit_bucket_count() const; std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); void flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco); void cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector &timeframe); void erase_waveform_start_cache(TpcRawHit *hit); - //! FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching - std::map> m_timeHitMap; + //! FEE -> FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching + std::vector>> m_timeHitMap; //! rollover-corrected GTM BCO -> matched TpcRawHit returned to the input manager std::map> m_timeFrameMap; From 708f7774f9da38341ea24861dfd4a552e9a52eb8 Mon Sep 17 00:00:00 2001 From: Tom Hemmick Date: Fri, 5 Jun 2026 13:54:19 -0400 Subject: [PATCH 597/866] Initial version. Requires later updates to remove reference to user directories. --- offline/packages/PHGarfield/GasModel.cc | 80 +++++ offline/packages/PHGarfield/Makefile.am | 90 +++++ offline/packages/PHGarfield/MergeGasFiles.cc | 223 ++++++++++++ offline/packages/PHGarfield/PHGarfield.cc | 339 ++++++++++++++++++ offline/packages/PHGarfield/PHGarfield.h | 67 ++++ .../packages/PHGarfield/PHGarfieldLinkDef.h | 5 + offline/packages/PHGarfield/autogen.sh | 9 + offline/packages/PHGarfield/configure.ac | 14 + .../PHGarfield/macros/GasModel_condor.job | 13 + .../packages/PHGarfield/macros/StartScript.sh | 31 ++ .../packages/PHGarfield/macros/TestFieldMap.C | 183 ++++++++++ 11 files changed, 1054 insertions(+) create mode 100644 offline/packages/PHGarfield/GasModel.cc create mode 100644 offline/packages/PHGarfield/Makefile.am create mode 100644 offline/packages/PHGarfield/MergeGasFiles.cc create mode 100644 offline/packages/PHGarfield/PHGarfield.cc create mode 100644 offline/packages/PHGarfield/PHGarfield.h create mode 100644 offline/packages/PHGarfield/PHGarfieldLinkDef.h create mode 100755 offline/packages/PHGarfield/autogen.sh create mode 100644 offline/packages/PHGarfield/configure.ac create mode 100644 offline/packages/PHGarfield/macros/GasModel_condor.job create mode 100755 offline/packages/PHGarfield/macros/StartScript.sh create mode 100644 offline/packages/PHGarfield/macros/TestFieldMap.C diff --git a/offline/packages/PHGarfield/GasModel.cc b/offline/packages/PHGarfield/GasModel.cc new file mode 100644 index 0000000000..34e52e1f94 --- /dev/null +++ b/offline/packages/PHGarfield/GasModel.cc @@ -0,0 +1,80 @@ +#include +#include + +#include "Garfield/MediumMagboltz.hh" +#include "Garfield/ComponentUser.hh" +#include "Garfield/Sensor.hh" +#include "Garfield/DriftLineRKF.hh" + +using namespace Garfield; +using namespace std; + +//------------------------------------------------------------ +// This standalone executable makes gas calculations for +// whatever mixture you specify and range of electric, +// magnetic, and angle between values that you select. +// TKH 5/27/2026 +// +// +//------------------------------------------------------------ + +int main(int argc, char* argv[]) { + + if (argc != 11) { + std::cerr + << "Usage:\n" + << argv[0] + << " Emin Emax nE Bmin Bmax nB Amin Amax nA output_file_name\n\n" + << "Units:\n" + << " E: V/cm\n" + << " B: Tesla\n" + << " angle: radians\n"; + return 1; + } + + const double Emin = std::atof(argv[1]); + const double Emax = std::atof(argv[2]); + const int nE = std::atoi(argv[3]); + + const double Bmin = std::atof(argv[4]); + const double Bmax = std::atof(argv[5]); + const int nB = std::atoi(argv[6]); + + const double Amin = std::atof(argv[7]); + const double Amax = std::atof(argv[8]); + const int nA = std::atoi(argv[9]); + + const string output_file(argv[10]); + + std::cout << "E grid: " + << Emin << " -> " << Emax + << " with " << nE << " points\n"; + + std::cout << "B grid: " + << Bmin << " -> " << Bmax + << " with " << nB << " points\n"; + + std::cout << "Angle grid: " + << Amin << " -> " << Amax + << " with " << nA << " points\n"; + + std::cout << "Output File: " << output_file << endl; + + + // ------------------------------------------------------------ + // Gas: Ar/CF4/isobutane = 75/20/5. + // ------------------------------------------------------------ + MediumMagboltz gas; + gas.SetComposition("ar", 75., "cf4", 20., "isobutane", 5.); + gas.SetTemperature(301.65); // K from Grafana + gas.SetPressure(762.); // Torr from Grafana + + // Try to load an existing gas table. + bool LogGrid = false; + gas.SetFieldGrid(Emin, Emax, nE, LogGrid, + Bmin, Bmax, nB, + Amin, Amax, nA); + + gas.GenerateGasTable(10); + gas.WriteGasFile(output_file.c_str()); +} diff --git a/offline/packages/PHGarfield/Makefile.am b/offline/packages/PHGarfield/Makefile.am new file mode 100644 index 0000000000..1c74a0a706 --- /dev/null +++ b/offline/packages/PHGarfield/Makefile.am @@ -0,0 +1,90 @@ +AUTOMAKE_OPTIONS = foreign + +ROOT_CFLAGS = $(shell root-config --cflags) +ROOT_LIBS = $(shell root-config --libs) + +AM_CPPFLAGS = \ + -I$(includedir) \ + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + PHGarfield.h + +lib_LTLIBRARIES = \ + libPHGarfield.la + +libPHGarfield_la_LIBADD = \ + -lffamodules \ + -lffarawobjects \ + -lcdbobjects \ + -ltpc \ + -lNoRootEvent \ + -lphool \ + -lphfield \ + -lGarfield \ + -lSubsysReco + +ROOTDICTS = \ + PHGarfield_Dict.cc + +pcmdir = $(libdir) +nobase_dist_pcm_DATA = \ + PHGarfield_Dict_rdict.pcm + +libPHGarfield_la_SOURCES = \ + $(ROOTDICTS) \ + PHGarfield.cc + +bin_PROGRAMS = \ + GasModel \ + MergeGasFiles + +MergeGasFiles_SOURCES = MergeGasFiles.cc + +MergeGasFiles_LDFLAGS = \ + -L$(OFFLINE_MAIN)/lib64 \ + $(ROOT_LIBS) + +MergeGasFiles_LDADD = \ + -lGarfield + +GasModel_SOURCES = GasModel.cc + +GasModel_LDFLAGS = \ + -L$(OFFLINE_MAIN)/lib64 \ + $(ROOT_LIBS) + +GasModel_LDADD = \ + -lGarfield + +# Rule for generating table CINT dictionaries. +%_Dict.cc: %.h %LinkDef.h + rootcint -f $@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ + +#just to get the dependency +%_Dict_rdict.pcm: %_Dict.cc ; + +################################################ +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libPHGarfield.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc new file mode 100644 index 0000000000..d515fc5462 --- /dev/null +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -0,0 +1,223 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "Garfield/MediumMagboltz.hh" + +using namespace std; + +int main() +{ + + // This is a utility to test whether the process of "merging" files is actually different from a single file. + // It may be of no further use afterthe development was complete. + // TKH 6/2/2026 + int nValid=10000; + TNtuple *Validity = new TNtuple("Validity", "Validity", "Valid:e:b:a:Vxerr:Vyerr:Vzerr"); + + // New version chooses to NOT write output to a file (which seems broken), + // but to instead just tries to merge the files and validate the copy in memory. + const std::string dir = "gasfiles"; + const std::string out = "Ar75_CF20_iso5.gas"; + + auto filename = [&](const int i) + { + return dir + "/PART_" + std::to_string(i) + ".gas"; + }; + + Garfield::MediumMagboltz gas; + Garfield::MediumMagboltz gas0; + + const std::string first = filename(0); + if (!std::filesystem::exists(first)) + { + std::cerr << "Missing first gas file: " << first << std::endl; + return 1; + } + + if (!gas.LoadGasFile(first)) + { + std::cerr << "Failed to load " << first << std::endl; + return 1; + } + + // Gas 0 only loads the FIRST file. This will test the memory validity of the merge... + if (!gas0.LoadGasFile(first)) + { + std::cerr << "Failed to load " << first << std::endl; + return 1; + } + + int nFiles = 1; + for (int i = 1; ; ++i) + { + const std::string file = filename(i); + + if (!std::filesystem::exists(file)) + { + std::cout << "Stopping at first missing file: " << file << std::endl; + break; + } + + std::cout << "Merging " << file << std::endl; + + if (!gas.MergeGasFile(file, true)) + { + std::cerr << "Failed to merge " << file << std::endl; + return 1; + } + + ++nFiles; + } + + // Don't write out since it crashes? + //gas.WriteGasFile("test.gas"); + + // Now perform the validation test... + double emin=400; + double emax=400; + //double ne=1; + + double bmin=1.15; + double bmax=1.45; + double nb=50; + + double amin=0.0; + double amax=0.2; + //double na=50; + + // Initialize using the current system time + TRandom3 Randy(time(0)); //new initialization each run + cout << endl << endl << "Valid Calls: "<< endl; + for (int i=0; iFill(1,sqrt(ex*ex + ey*ey + ez*ez),sqrt(bx*bx + by*by + bz*bz),a,DelVx, DelVy, DelVz); + } + + cout << endl << endl << "Invalid Calls: "<< endl; + for (int i=0; iFill(0,sqrt(ex*ex + ey*ey + ez*ez),sqrt(bx*bx + by*by + bz*bz),a,DelVx, DelVy, DelVz); + } + + + TFile *output= new TFile("GarfieldValidity.root","RECREATE"); + Validity->Write(); + output->Close(); + + return 0; +} diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc new file mode 100644 index 0000000000..1a9d15a4d2 --- /dev/null +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -0,0 +1,339 @@ +#include + +#include "PHGarfield.h" + +#include "Garfield/ComponentUser.hh" +#include "Garfield/MediumMagboltz.hh" +#include "Garfield/Sensor.hh" +#include "Garfield/DriftLineRKF.hh" + +#include +#include +#include +#include + +#include +#include // for PHIODataNode +#include // for PHNodeIterator +#include // for PHObject +#include + +#include +#include +#include + +#include + +#include +#include // for uint16_t +#include // for exit, size_t +#include // for basic_ostream, operat... +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace findNode; +using namespace Garfield; + +PHGarfield::PHGarfield(const std::string &name) : SubsysReco(name) +{ + PHI_MIN = -M_PI; // Local handling of Phi valued that wrap around. +} + +int PHGarfield::InitRun(PHCompositeNode *topNode) +{ + // Avoids the compiler error for having nore used the topNode. + (void) topNode; + + std::cout << "PHGarfield::InitRun(PHCompositeNode *topNode) Initializing" << std::endl; + m_cdb = CDBInterface::instance(); + + // Here we use the CDBInterface to set up the magnetic field map: + std::string url = m_cdb->getUrl("FIELDMAP_TRACKING"); + m_field = new PHField3DCartesian(url, 1.0); + + // Here we use the CDBInterface to set up the channel making of the TPC: + std::string geofile = m_cdb->getUrl("Tracking_Geometry"); + std::string text = m_cdb->getUrl("TPC_FEE_CHANNEL_MAP"); + m_cdbTPCMAPttree = new CDBTTree(text.c_str()); + m_cdbTPCMAPttree->LoadCalibrations(); + + // Make the Garfield Component and register the methods that will interface to our fields... + m_component = new Garfield::ComponentUser(); + m_component->SetMagneticField([this](double x, double y, double z,double& bx, double& by, double& bz) { GetMagneticFieldTesla(x, y, z, bx, by, bz); }); + m_component->SetElectricField([this](double x, double y, double z,double& ex, double& ey, double& ez) { GetElectricFieldVcm (x, y, z, ex, ey, ez); }); + InitializeGas("/direct/phenix+u/workarea/hemmick/code.sphenix/tkh/gas/gasfiles/"); + + // Diagnostic during code development... + FillRadii(); + // PrintMaps(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHGarfield::FillRadii() +{ + // Unload the pad map to get the radii in a handy location: + for (unsigned int side=0; side<2; side++) + { + for (unsigned int sector=0; sector<12; sector++) + { + for (unsigned int fee=0; fee<26; fee++) + { + for (unsigned int channel=0; channel<256; channel++) + { + unsigned int key = (256 * (fee)) + channel; + int layer = m_cdbTPCMAPttree->GetIntValue (key, "layer"); + double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R")/CLHEP::cm; + if (layer > 6) + { + radii[layer-7] = r; + } + } + } + } + } + +} + + void PHGarfield::PrintGarfield(double x, double y, double z) +{ + double ex, ey, ez, bx, by, bz, vx, vy, vz; + GetElectricFieldVcm ( x, y, z, ex, ey, ez); + GetMagneticFieldTesla( x, y, z, bx, by, bz); + m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); + cout << " x:" << x + << " y:" << y + << " z:" << z + << " ex:" << ex + << " ey:" << ey + << " ez:" << ez + << " bx:" << bx + << " by:" << by + << " bz:" << bz + << " vx:" << vx + << " vy:" << vy + << " vz:" << vz + << endl; +} + +void PHGarfield::PrintMaps() +{ + // Print out a few test points of the Garfield information + PrintGarfield(0.0, 0.0, 0.1); + PrintGarfield(0.0, 0.0, 100.0); + PrintGarfield(0.0, 40.0, 100.1); + PrintGarfield(0.0, 78.0, 010.1); + + // Print out the pad coordinate map: + int MAX = 10; + int prints = 0; + for (unsigned int side=0; side<2; side++) + { + for (unsigned int sector=0; sector<12; sector++) + { + for (unsigned int fee=0; fee<26; fee++) + { + for (unsigned int channel=0; channel<256; channel++) + { + unsigned int key = (256 * (fee)) + channel; + int layer = m_cdbTPCMAPttree->GetIntValue (key, "layer"); + double phi = ((side == 1 ? 1 : -1) * (m_cdbTPCMAPttree->GetDoubleValue(key, "phi") - M_PI / 2.)) + ((sector % 12) * M_PI / 6); + double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R")/CLHEP::cm; + + phi = bounder(phi, PHI_MIN); + + if (layer > 6) + { + if (prints < MAX) + { + prints++; + cout << " side: " << side; + cout << " sector: " << sector; + cout << " fee: " << fee; + cout << " channel: " << channel; + cout << " layer: " << layer; + cout << " phi: " << phi; + cout << " r: " << r; + cout << endl; + } + } + } + } + } + } + +} + +void PHGarfield::GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double& bx_t, double& by_t, double& bz_t) +{ + // NOTE: Garfield uses cm, V/cm, and Tesla. + // CLHEP uses mm, V/mm, and kiloTesla + // PHField3DCartesian follows the CLHEP conventions for magnetic fields. + + double point[4] = + { + x_cm * CLHEP::cm, + y_cm * CLHEP::cm, + z_cm * CLHEP::cm, + //(z_cm-20.0) * CLHEP::cm, + 0.0 + }; + + double bfield[3] = {0.0, 0.0, 0.0}; + + // Get the magnetic field via the PHField3DCartesian object constructed usinf the CDB url reference. + m_field->GetFieldValue(point, bfield); + + bx_t = bfield[0] / CLHEP::tesla; + by_t = bfield[1] / CLHEP::tesla; + bz_t = bfield[2] / CLHEP::tesla; +} + +void PHGarfield::GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double& ex_vcm, double& ey_vcm, double& ez_vcm) +{ + // NOTE: Garfield uses cm, V/cm, and Tesla. + (void) x_cm; + (void) y_cm; + + ex_vcm = 0.0; + ey_vcm = 0.0; + ez_vcm = z_cm > 0 ? -400.0 : 400.0; + +} + +void PHGarfield::InitializeGas(std::string dir) +{ + // Create and fill the gas object so that we can trace particles through the gas... + m_gas = new Garfield::MediumMagboltz(); + + auto filename = [&](const int i) { return dir + "/PART_" + std::to_string(i) + ".gas"; }; + + const std::string first = filename(0); + if (!std::filesystem::exists(first)) + { + std::cerr << "Missing first gas file: " << first << std::endl; + return; + } + + if (!m_gas->LoadGasFile(first)) + { + std::cerr << "Failed to load " << first << std::endl; + return; + } + + int nFiles = 1; + for (int i = 1; ; ++i) + { + const std::string file = filename(i); + + if (!std::filesystem::exists(file)) + { + std::cout << "Stopping at first missing file: " << file << std::endl; + break; + } + + std::cout << "Merging " << file << std::endl; + + if (!m_gas->MergeGasFile(file, true)) + { + std::cerr << "Failed to merge " << file << std::endl; + return; + } + + ++nFiles; + } +} + +int PHGarfield::process_event(PHCompositeNode *topNode) +{ + // Avoids the compiler error for having nore used the topNode. + (void) topNode; + + // Initial implementation doesn't do anything event-by-event. + // Nonetheless, a future user might want do do something here... + + return Fun4AllReturnCodes::EVENT_OK; +} + +double PHGarfield::bounder(double phi, double phi_min) +{ + + double phi_max = phi_min + 2.0*M_PI; + while (phi < phi_min) phi = phi + 2.0*M_PI; + while (phi >= phi_max) phi = phi - 2.0*M_PI; + + return phi; +} + + +TPolyLine3D *PHGarfield::ReverseDrift (double x, double y, double z, double step_ns) +{ + vector xlist; + vector ylist; + vector zlist; + + xlist.push_back(x); + ylist.push_back(y); + zlist.push_back(z); + + double ex, ey, ez, bx, by, bz, vx, vy, vz; + + double zPrevious = z; + while (!StopHere(x,y,z,zPrevious)) + { + zPrevious = z; + GetMagneticFieldTesla( x, y, z, bx, by, bz); + GetElectricFieldVcm ( x, y, z, ex, ey, ez); + m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); + + x = x - vx*step_ns; + y = y - vy*step_ns; + z = z - vz*step_ns; + + xlist.push_back(x); + ylist.push_back(y); + zlist.push_back(z); + } + + TPolyLine3D *poly = new TPolyLine3D(xlist.size() - 1); + for (unsigned int i=0; iSetPoint(i,xlist[i], ylist[i], zlist[i]); + } + + return poly; +} + +bool PHGarfield::StopHere(const double x, const double y, const double z, + const double zPrevious) +{ + const double r = std::hypot(x, y); + + if (r < 18.0) return true; + if (r > 82.0) return true; + if (z > 120.0) return true; + if (z < -120.0) return true; + + // z crossed the central membrane. + if (z * zPrevious < 0.0) return true; + + return false; +} + diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h new file mode 100644 index 0000000000..cf29805153 --- /dev/null +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -0,0 +1,67 @@ +#ifndef PHGARFIELD__H +#define PHGARFIELD__H + +#include +#include + +#include + +#include +#include + +class CdbUrlSave; +class CDBInterface; +class CDBTTree; +class PHCompositeNode; +class TpcMap; +class PHField3DCartesian; +class ComponentUser; +class TPolyLine3D; + +namespace Garfield +{ + class ComponentUser; + class MediumMagboltz; +} + + +class PHGarfield : public SubsysReco +{ + public: + PHGarfield(const std::string &name = "PHGarfield"); + ~PHGarfield() override = default; + + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + + bool StopHere(const double x, const double y, const double z, const double zPrevious); + + void PrintMaps(); + void PrintGarfield(double x, double y, double z); + + // These are left in public namespace for easy plotting macros... + // The user is encouraged to add more routine to fit their analysis goals... + TPolyLine3D *ReverseDrift (double x_cm, double y_cm, double z_cm, double step_ns=50.0); // Drifts electrons from some initial point until they hit a detector boundary... + double radii[48]; // Radius on each layer just for test purposes...need to be cm! + + private: + CDBInterface *m_cdb {nullptr}; // Access to all thiungs CDB... + CDBTTree *m_cdbTPCMAPttree {nullptr}; // Locations of the pads from CDB... + PHField3DCartesian *m_field {nullptr}; // The stanards sPHENIX field holding container. + Garfield::ComponentUser *m_component {nullptr}; // This handles the interface of the electric and magnetic fields as handed to Garfield + Garfield::MediumMagboltz *m_gas {nullptr}; // This is the pre-tabulated gas properties required by Garfield... + + void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double& bx_t, double& by_t, double& bz_t) ; // Feeds magnetic field to Garfield + void GetElectricFieldVcm (double x_cm, double y_cm, double z_cm, double& ex_vcm, double& ey_vcm, double& ez_vcm) ; // Feeds electric field to Garfield + void InitializeGas (std::string dir); + void FillRadii(); + + // These are utilities for a spot check of the overall routine: + //std::string calibdir; + //std::string m_DiodeContainerName; + double bounder(double phi, double phi_min); + double PHI_MIN; + +}; + +#endif diff --git a/offline/packages/PHGarfield/PHGarfieldLinkDef.h b/offline/packages/PHGarfield/PHGarfieldLinkDef.h new file mode 100644 index 0000000000..067f2f4576 --- /dev/null +++ b/offline/packages/PHGarfield/PHGarfieldLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class PHGarfield+ ; + +#endif /* __CINT__ */ diff --git a/offline/packages/PHGarfield/autogen.sh b/offline/packages/PHGarfield/autogen.sh new file mode 100755 index 0000000000..333dd3b499 --- /dev/null +++ b/offline/packages/PHGarfield/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" + diff --git a/offline/packages/PHGarfield/configure.ac b/offline/packages/PHGarfield/configure.ac new file mode 100644 index 0000000000..b2b598e585 --- /dev/null +++ b/offline/packages/PHGarfield/configure.ac @@ -0,0 +1,14 @@ +AC_INIT(PHGarfield, [1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE + +AC_PROG_CXX(CC g++) +LT_INIT([disable-static]) + +dnl leaving this here in case we want to play with different compiler +dnl specific flags +CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/offline/packages/PHGarfield/macros/GasModel_condor.job b/offline/packages/PHGarfield/macros/GasModel_condor.job new file mode 100644 index 0000000000..6f25606c19 --- /dev/null +++ b/offline/packages/PHGarfield/macros/GasModel_condor.job @@ -0,0 +1,13 @@ +Universe = vanilla +getenv = True +Initialdir = /direct/phenix+u/workarea/hemmick/code.sphenix/tkh/gas +Executable = $(Initialdir)/StartScript.sh +Output = $(Initialdir)/out/hitset_AuAu_$(process).out +Error = $(Initialdir)/err/hitset_AuAu_$(process).err +Log = $(Initialdir)/log/hitset_AuAu_$(process).log +PeriodicHold = (NumJobStarts>=1 && JobStatus == 1) +request_memory = 4GB +Priority = 20 +job_lease_duration = 3600 +Arguments = $(process) +Queue 50 diff --git a/offline/packages/PHGarfield/macros/StartScript.sh b/offline/packages/PHGarfield/macros/StartScript.sh new file mode 100755 index 0000000000..ac90ced0dc --- /dev/null +++ b/offline/packages/PHGarfield/macros/StartScript.sh @@ -0,0 +1,31 @@ +#! /bin/bash +emin=400 +emax=400 +ne=1 + +bmin=1.15 +bmax=1.45 +nb=50 + +amin=0.0 +amax=0.2 +na=50 + +bnow=$(awk -v bmin="$bmin" \ + -v bmax="$bmax" \ + -v nb="$nb" \ + -v i="$1" \ +'BEGIN { + print bmin + (bmax - bmin) * i / nb +}') + +echo $bnow + +output="/direct/phenix+u/workarea/hemmick/code.sphenix/tkh/gas/gasfiles/PART_"$1".gas" + +echo $output + +echo GasModel $emin $emax $ne $bnow $bnow 1 $amin $amax $na $output +GasModel $emin $emax $ne $bnow $bnow 1 $amin $amax $na $output + +echo all done diff --git a/offline/packages/PHGarfield/macros/TestFieldMap.C b/offline/packages/PHGarfield/macros/TestFieldMap.C new file mode 100644 index 0000000000..55021ca501 --- /dev/null +++ b/offline/packages/PHGarfield/macros/TestFieldMap.C @@ -0,0 +1,183 @@ +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +R__LOAD_LIBRARY(libfun4all.so) +R__LOAD_LIBRARY(libfun4allutils.so) +R__LOAD_LIBRARY(libffamodules.so) +R__LOAD_LIBRARY(libfun4allraw.so) +R__LOAD_LIBRARY(libffarawmodules.so) +R__LOAD_LIBRARY(libcdbobjects.so) +R__LOAD_LIBRARY(libffamodules.so) +R__LOAD_LIBRARY(libPHGarfield.so) + +#define Nebdc 24 +#define Nserver 2 + +// Global namespace to assist drawing... +TPolyLine3D *npoly3[48]; +TPolyLine3D *spoly3[48]; +TPolyLine *npoly2[48]; +TPolyLine *spoly2[48]; +TGeoTube *tubby; +TCanvas *canny; +TCanvas *canny2; + +TBox *boxer1; +TBox *boxer2; + +void TestFieldMap() +{ + recoConsts* rc = recoConsts::instance(); + + rc->set_StringFlag("CDB_GLOBALTAG","FieldMapTest"); + rc->set_uint64Flag("TIMESTAMP",1); + + auto cdb = CDBInterface::instance(); + std::string url = cdb->getUrl("FIELDMAP_TRACKING"); + std::cout << "Field map URL:\n" << url << std::endl; + + Fun4AllServer *se = Fun4AllServer::instance(); + + Enable::QA = false; + Enable::CDB = true; + + // Register a whole slew of input managers... + // NOTE: This depends upon the requested files being in frog. Ribbit. + char nextinput[500]; + char nextfile[500]; + Fun4AllInputManager* in[Nebdc]; + for (unsigned int ebdc=0; ebdc<24; ebdc++) + { + for (unsigned int server=0; server<2; server++) + { + sprintf(nextinput,"ebdc%02d_%01d",ebdc,server); + //sprintf(nextfile,"DST_STREAMING_EVENT_ebdc%02d_%01d_run3line_laser_ana540_nocdbtag_v001-00064890-00000.root",ebdc,server); // Line Laser + sprintf(nextfile,"DST_STREAMING_EVENT_ebdc%02d_%01d_run3auau_ana514_nocdbtag_v001-00075570-00000.root",ebdc,server); // AuAu Zero Field + std::cout << nextfile << " " << nextinput << endl; + in[ebdc] = new Fun4AllDstInputManager(nextinput); + in[ebdc]->fileopen(nextfile); + se->registerInputManager(in[ebdc]); + } + } + + // Now register a flag handler because MAAABE it will make the CDB work correctly? + //SubsysReco *fh = new FlagHandler(); + //se->registerSubsystem(fh); + + // Register my analysis module. + PHGarfield *phg = new PHGarfield(); + se->registerSubsystem(phg); + + se->run(4); + + canny = new TCanvas("canny","canny",3000,2500); + canny2 = new TCanvas("canny2","canny2",3000,2500); + tubby = new TGeoTube("tubby",20,80,110); + + canny->cd(); + tubby->Draw(); + + canny2->cd(); + //gPad->DrawFrame(-150., -10., 150., 10.); + gPad->DrawFrame(-150., -100., 150., 100.); + boxer1 = new TBox(-102,20,102,78); + boxer1->Draw(); + boxer2 = new TBox(-102,-78,102,-20); + boxer2->Draw("same"); + + for (int i=0; i<48; i++) + { + canny->cd(); + npoly3[i] = phg->ReverseDrift(0,phg->radii[i],102); + npoly3[i]->SetLineColor(kRed); + npoly3[i]->SetLineWidth(3); + npoly3[i]->Draw("same"); + + canny2->cd(); + int N = npoly3[i]->GetN(); + float *p = npoly3[i]->GetP(); + float x[500]; + float y[500]; + float z[500]; + for (int j=0; jSetLineColor(kRed); + npoly2[i]->SetLineWidth(3); + npoly2[i]->Draw("Lsame"); + } + + for (int i=0; i<48; i++) + { + canny->cd(); + spoly3[i] = phg->ReverseDrift(0,phg->radii[i],-102); + spoly3[i]->SetLineColor(kCyan); + spoly3[i]->SetLineWidth(3); + spoly3[i]->Draw("same"); + + canny2->cd(); + int N = spoly3[i]->GetN(); + float *p = spoly3[i]->GetP(); + float x[500]; + float y[500]; + float z[500]; + for (int j=0; jSetLineColor(kCyan); + spoly2[i]->SetLineWidth(3); + spoly2[i]->Draw("Lsame"); + } + //se->dumpHistos("Looker.root"); +} From 36cda703fe1169a1b1541855ab78177182b021ea Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 5 Jun 2026 15:09:49 -0400 Subject: [PATCH 598/866] speed up by x1000 --- .../g4eval/SvtxTruthRecoTableEval.cc | 177 +++++++++++------- .../g4eval/SvtxTruthRecoTableEval.h | 4 +- 2 files changed, 108 insertions(+), 73 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc index 6d3c7cd7a7..ec6e4cbedf 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc @@ -2,7 +2,8 @@ #include "SvtxTruthRecoTableEval.h" #include "SvtxEvalStack.h" #include "SvtxTrackEval.h" -#include "SvtxTruthEval.h" + +#include "SvtxClusterEval.h" #include #include @@ -19,10 +20,18 @@ #include #include #include +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include +#include +#include //____________________________________________________________________________.. SvtxTruthRecoTableEval::SvtxTruthRecoTableEval(const std::string &name) @@ -53,11 +62,13 @@ int SvtxTruthRecoTableEval::InitRun(PHCompositeNode *topNode) //____________________________________________________________________________.. int SvtxTruthRecoTableEval::process_event(PHCompositeNode *topNode) { + const int verbosity = Verbosity(); + if (!m_svtxevalstack) { m_svtxevalstack = std::make_unique(topNode); m_svtxevalstack->set_strict(false); - m_svtxevalstack->set_verbosity(Verbosity()); + m_svtxevalstack->set_verbosity(verbosity); m_svtxevalstack->set_use_initial_vertex(true); m_svtxevalstack->set_use_genfit_vertex(false); m_svtxevalstack->next_event(topNode); @@ -67,17 +78,15 @@ int SvtxTruthRecoTableEval::process_event(PHCompositeNode *topNode) m_svtxevalstack->next_event(topNode); } - if (Verbosity() > 1) - { - std::cout << "Fill truth map " << std::endl; - } - fillTruthMap(topNode); + SvtxTrackEval *trackeval = m_svtxevalstack->get_track_eval(); + assert(trackeval); + trackeval->set_verbosity(verbosity); - if (Verbosity() > 1) + if (verbosity > 1) { - std::cout << "Fill reco map " << std::endl; + std::cout << "Fill truth/reco maps " << std::endl; } - fillRecoMap(topNode); + fillTruthRecoMaps(topNode, trackeval, verbosity); return Fun4AllReturnCodes::EVENT_OK; } @@ -102,14 +111,13 @@ int SvtxTruthRecoTableEval::End(PHCompositeNode * /*unused*/) return Fun4AllReturnCodes::EVENT_OK; } -void SvtxTruthRecoTableEval::fillTruthMap(PHCompositeNode *topNode) +void SvtxTruthRecoTableEval::fillTruthRecoMaps(PHCompositeNode *topNode, SvtxTrackEval *trackeval, const int verbosity) { PHG4TruthInfoContainer *truthinfo = findNode::getClass(topNode, "G4TruthInfo"); assert(truthinfo); - SvtxTrackEval *trackeval = m_svtxevalstack->get_track_eval(); - trackeval->set_verbosity(Verbosity()); - assert(trackeval); + SvtxTrackMap *trackMap = findNode::getClass(topNode, "SvtxTrackMap"); + assert(trackMap); PHG4TruthInfoContainer::ConstRange range = truthinfo->GetParticleRange(); if (m_scanForPrimaries) @@ -117,96 +125,123 @@ void SvtxTruthRecoTableEval::fillTruthMap(PHCompositeNode *topNode) range = truthinfo->GetPrimaryParticleRange(); } + std::vector selectedTruthIds; + std::unordered_set selectedTruthIdSet; + const double minMomentumTruthMap2 = m_minMomentumTruthMap * m_minMomentumTruthMap; + for (auto iter = range.first; iter != range.second; ++iter) { PHG4Particle *g4particle = iter->second; - const double momentum = CLHEP:: - Hep3Vector(g4particle->get_px(), g4particle->get_py(), g4particle->get_pz()) - .mag(); + const double px = g4particle->get_px(); + const double py = g4particle->get_py(); + const double pz = g4particle->get_pz(); + const double momentum2 = px * px + py * py + pz * pz; // only record particle above minimal momentum requirement. - if (momentum < m_minMomentumTruthMap) + if (momentum2 < minMomentumTruthMap2) { continue; } - int gtrackID = g4particle->get_track_id(); - const std::set &alltracks = trackeval->all_tracks_from(g4particle); + const int gtrackID = g4particle->get_track_id(); + selectedTruthIds.push_back(gtrackID); + selectedTruthIdSet.insert(gtrackID); + } + + SvtxClusterEval *clustereval = trackeval->get_cluster_eval(); + std::map truthMaps; - // not to record zero associations - if (alltracks.empty()) + for (const auto &[key, track] : *trackMap) + { + TrackSeed *siliconSeed = track->get_silicon_seed(); + TrackSeed *tpcSeed = track->get_tpc_seed(); + + std::size_t nclusterKeys = 0; + if (siliconSeed) { - continue; + nclusterKeys += siliconSeed->size_cluster_keys(); + } + if (tpcSeed) + { + nclusterKeys += tpcSeed->size_cluster_keys(); } - PHG4ParticleSvtxMap::WeightedRecoTrackMap recomap; + std::unordered_map nclustersByTruthId; + nclustersByTruthId.reserve(nclusterKeys); - for (auto *track : alltracks) + const auto add_cluster_contributions = [&](TrackSeed *seed) { - /// We fill the map with a key corresponding to the ncluster contribution. - /// This weight could in principle be anything we choose - float clusCont = trackeval->get_nclusters_contribution(track, g4particle); + if (!seed) + { + return; + } + + for (auto clusterIter = seed->begin_cluster_keys(); + clusterIter != seed->end_cluster_keys(); + ++clusterIter) + { + const std::set particles = clustereval->all_truth_particles(*clusterIter); + for (PHG4Particle *g4particle : particles) + { + ++nclustersByTruthId[g4particle->get_track_id()]; + } + } + }; + + // Match SvtxTrackEval::get_track_ckeys ordering. + add_cluster_contributions(siliconSeed); + add_cluster_contributions(tpcSeed); + + SvtxPHG4ParticleMap::WeightedTruthTrackMap truthmap; + SvtxTrack_FastSim *fastsim_track = dynamic_cast(track); - auto iterator = recomap.find(clusCont); - if (iterator == recomap.end()) + const unsigned int trackID = track->get_id(); + for (const auto &[gtrackID, nclusters] : nclustersByTruthId) + { + const float clusCont = static_cast(nclusters); + if (selectedTruthIdSet.find(gtrackID) != selectedTruthIdSet.end()) { - std::set dumset; - dumset.insert(track->get_id()); - recomap.insert(std::make_pair(clusCont, dumset)); + truthMaps[gtrackID][clusCont].insert(trackID); } - else + if (!fastsim_track) { - iterator->second.insert(track->get_id()); + truthmap[clusCont].insert(gtrackID); } } - if (Verbosity() > 1) + if (fastsim_track) { - std::cout << " Inserting gtrack id " << gtrackID << " with map size " << recomap.size() << std::endl; + // Preserve SvtxTrackEval::all_truth_particles fast-sim special case for reco->truth maps only. + PHG4Particle *g4particle = truthinfo->GetParticle(fastsim_track->get_truth_track_id()); + const float clusCont = trackeval->get_nclusters_contribution(track, g4particle); + truthmap[clusCont].insert(g4particle->get_track_id()); } - m_truthMap->insert(gtrackID, recomap); + if (verbosity > 1) + { + std::cout << " Inserting track id " << key << " with truth map size " << truthmap.size() << std::endl; + } + m_recoMap->insert(key, std::move(truthmap)); } - m_truthMap->setProcessed(true); -} - -void SvtxTruthRecoTableEval::fillRecoMap(PHCompositeNode *topNode) -{ - SvtxTrackMap *trackMap = findNode::getClass(topNode, "SvtxTrackMap"); - - assert(trackMap); - - SvtxTrackEval *trackeval = m_svtxevalstack->get_track_eval(); - assert(trackeval); - - for (const auto &[key, track] : *trackMap) + for (const int gtrackID : selectedTruthIds) { - const std::set &allparticles = trackeval->all_truth_particles(track); - SvtxPHG4ParticleMap::WeightedTruthTrackMap truthmap; - for (PHG4Particle *g4particle : allparticles) + auto truthMapIter = truthMaps.find(gtrackID); + if (truthMapIter == truthMaps.end() || truthMapIter->second.empty()) { - float clusCont = trackeval->get_nclusters_contribution(track, g4particle); - auto iterator = truthmap.find(clusCont); - if (iterator == truthmap.end()) - { - std::set dumset; - dumset.insert(g4particle->get_track_id()); - truthmap.insert(std::make_pair(clusCont, dumset)); - } - else - { - iterator->second.insert(g4particle->get_track_id()); - } + continue; } - if (Verbosity() > 1) + + if (verbosity > 1) { - std::cout << " Inserting track id " << key << " with truth map size " << truthmap.size() << std::endl; + std::cout << " Inserting gtrack id " << gtrackID << " with map size " << truthMapIter->second.size() << std::endl; } - m_recoMap->insert(key, truthmap); + + m_truthMap->insert(gtrackID, std::move(truthMapIter->second)); } + m_truthMap->setProcessed(true); m_recoMap->setProcessed(true); } diff --git a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h index e09b16a9c3..8886385531 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h +++ b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h @@ -12,6 +12,7 @@ class PHCompositeNode; class PHG4TruthInfoContainer; class SvtxEvalStack; +class SvtxTrackEval; class SvtxTruthRecoTableEval : public SubsysReco { @@ -34,8 +35,7 @@ class SvtxTruthRecoTableEval : public SubsysReco private: int createNodes(PHCompositeNode *topNode); - void fillTruthMap(PHCompositeNode *topNode); - void fillRecoMap(PHCompositeNode *topNode); + void fillTruthRecoMaps(PHCompositeNode *topNode, SvtxTrackEval *trackeval, int verbosity); bool m_scanForPrimaries = false; From 79cd6b038f20639a43fe404c6204f2dac55545f3 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Fri, 5 Jun 2026 15:29:30 -0400 Subject: [PATCH 599/866] memory optimization --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 75 ++++++++----------- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 16 ++-- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 224bc4a6a9..c7aa92cfa5 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -212,10 +212,10 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() { for (auto& timeHitEntry : feeTimeHitMap) { - for (TpcRawHit* hit : timeHitEntry.second) + for (CachedTimeHit& cached_hit : timeHitEntry.second) { - erase_waveform_start_cache(hit); - delete hit; + delete cached_hit.hit; + cached_hit.hit = nullptr; } timeHitEntry.second.clear(); } @@ -226,14 +226,10 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() while (!timeFrameEntry.second.empty()) { TpcRawHit* hit = timeFrameEntry.second.back(); - erase_waveform_start_cache(hit); delete hit; timeFrameEntry.second.pop_back(); } } - - m_hitWaveformStartMap.clear(); - delete h_Run3PreviousTimeFrameWaveformStart; delete m_packetTimer; @@ -251,14 +247,6 @@ void TpcTimeFrameBuilderRun3::setVerbosity(const int i) } } -void TpcTimeFrameBuilderRun3::erase_waveform_start_cache(TpcRawHit* hit) -{ - if (hit) - { - m_hitWaveformStartMap.erase(hit); - } -} - void TpcTimeFrameBuilderRun3::flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco) { assert(h_Run3PreviousTimeFrameWaveformStart); @@ -292,23 +280,14 @@ void TpcTimeFrameBuilderRun3::flush_previous_timeframe_waveform_start_cache(uint m_previousTimeFrameGtmBco.reset(); } -void TpcTimeFrameBuilderRun3::cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector& timeframe) +void TpcTimeFrameBuilderRun3::cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector& waveform_start_clocks) { assert(h_Run3PreviousTimeFrameWaveformStart); h_Run3PreviousTimeFrameWaveformStart->Reset(); - for (TpcRawHit* hit : timeframe) + for (const uint16_t waveform_start : waveform_start_clocks) { - const auto waveform_start_iter = m_hitWaveformStartMap.find(hit); - if (waveform_start_iter == m_hitWaveformStartMap.end()) - { - continue; - } - - for (const uint16_t waveform_start : waveform_start_iter->second) - { - h_Run3PreviousTimeFrameWaveformStart->Fill(waveform_start); - } + h_Run3PreviousTimeFrameWaveformStart->Fill(waveform_start); } m_previousTimeFrameGtmBco = gtm_bco; @@ -337,7 +316,7 @@ uint32_t TpcTimeFrameBuilderRun3::get_fee_bco_diff(uint32_t first, uint32_t seco return static_cast(diff < 0 ? -diff : diff); } -size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector& timeframe) +size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector& timeframe, std::vector& waveform_start_clocks) { if (fee >= m_timeHitMap.size()) { @@ -351,7 +330,7 @@ size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, s return 0; } - std::vector& hits = it->second; + std::vector& hits = it->second; const size_t moved = hits.size(); if (moved == 0) { @@ -360,7 +339,18 @@ size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, s } timeframe.reserve(timeframe.size() + moved); - timeframe.insert(timeframe.end(), hits.begin(), hits.end()); + for (CachedTimeHit& cached_hit : hits) + { + if (cached_hit.hit) + { + timeframe.push_back(cached_hit.hit); + cached_hit.hit = nullptr; + } + + waveform_start_clocks.insert(waveform_start_clocks.end(), + cached_hit.waveform_start_clocks.begin(), + cached_hit.waveform_start_clocks.end()); + } fee_time_hits.erase(it); return moved; } @@ -410,7 +400,7 @@ std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t pre uint32_t best_diff = std::numeric_limits::max(); bool found = false; - auto consider_fee_bco = [&](uint32_t fee_bco, const std::vector& hits) + auto consider_fee_bco = [&](uint32_t fee_bco, const std::vector& hits) { if (hits.empty()) { @@ -473,11 +463,11 @@ void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_correc const int64_t diff = get_signed_fee_bco_diff(map_it->first, *predicted_fee_bco); if ((fee_clock_window == 0 && diff <= 0) || (fee_clock_window > 0 && diff < -static_cast(fee_clock_window))) { - for (TpcRawHit* hit : map_it->second) + for (CachedTimeHit& cached_hit : map_it->second) { m_hFEEDataStream->Fill(fee, "HitUnusedBeforeCleanup", 1); - erase_waveform_start_cache(hit); - delete hit; + delete cached_hit.hit; + cached_hit.hit = nullptr; } map_it = fee_time_hits.erase(map_it); } @@ -546,6 +536,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g size_t exact_hit_count = 0; size_t fallback_hit_count = 0; + std::vector matched_waveform_start_clocks; for (size_t fee_index = 0; fee_index < m_bcoMatchingInformation_vec.size(); ++fee_index) { @@ -560,7 +551,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g for (int32_t fee_clock_offset = -kRun3ExactMatchWindow; fee_clock_offset <= kRun3ExactMatchWindow; ++fee_clock_offset) { const uint32_t exact_fee_bco = static_cast(static_cast(static_cast(*predicted_fee_bco) + fee_clock_offset) & kFEEClockMask); - const size_t exact_hits_for_bco = move_time_hits(exact_fee_bco, fee, timeframe); + const size_t exact_hits_for_bco = move_time_hits(exact_fee_bco, fee, timeframe, matched_waveform_start_clocks); if (exact_hits_for_bco == 0) { continue; @@ -644,7 +635,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g assert(h_TimeFrame_Matched_Size); h_TimeFrame_Matched_Size->Fill(timeframe.size()); m_hNorm->Fill("GTM_TimeFrame_Matched_Hit_Sum", timeframe.size()); - cache_timeframe_waveform_starts(bclk_rollover_corrected, timeframe); + cache_timeframe_waveform_starts(bclk_rollover_corrected, matched_waveform_start_clocks); m_UsedTimeFrameSet.push(bclk_rollover_corrected); return timeframe; } @@ -668,7 +659,6 @@ void TpcTimeFrameBuilderRun3::CleanupUsedPackets(const uint64_t& bclk) while (!it->second.empty()) { TpcRawHit* hit = it->second.back(); - erase_waveform_start_cache(hit); delete hit; it->second.pop_back(); } @@ -905,10 +895,10 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) << std::endl; m_hNorm->Fill("TimeFrameSizeLimitError", 1); - for (TpcRawHit* hit : timehit->second) + for (CachedTimeHit& cached_hit : timehit->second) { - erase_waveform_start_cache(hit); - delete hit; + delete cached_hit.hit; + cached_hit.hit = nullptr; } timehit = fee_time_hits.erase(timehit); } @@ -1246,7 +1236,6 @@ void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, } TpcRawHitv3* hit = new TpcRawHitv3(); - m_timeHitMap[fee][payload.bx_timestamp & kFEEClockMask].push_back(hit); hit->set_bco(payload.bx_timestamp); hit->set_packetid(m_packet_id); @@ -1264,12 +1253,12 @@ void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, { waveform_start_clocks.push_back(waveform.first); } - m_hitWaveformStartMap[hit] = std::move(waveform_start_clocks); - for (std::pair>& waveform : payload.waveforms) { hit->move_adc_waveform(waveform.first, std::move(waveform.second)); } + + m_timeHitMap[fee][payload.bx_timestamp & kFEEClockMask].push_back(CachedTimeHit{hit, std::move(waveform_start_clocks)}); } } // if (not m_fastBCOSkip) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index dde620f7ce..ca68ab6e48 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -390,24 +390,26 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static int64_t get_signed_fee_bco_diff(uint32_t first, uint32_t second); static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); - size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe); + struct CachedTimeHit + { + TpcRawHit *hit = nullptr; + std::vector waveform_start_clocks; + }; + + size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe, std::vector &waveform_start_clocks); size_t count_time_hits(uint32_t fee_bco, uint16_t fee) const; size_t time_hit_bucket_count() const; std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); void flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco); - void cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector &timeframe); - void erase_waveform_start_cache(TpcRawHit *hit); + void cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector &waveform_start_clocks); //! FEE -> FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching - std::vector>> m_timeHitMap; + std::vector>> m_timeHitMap; //! rollover-corrected GTM BCO -> matched TpcRawHit returned to the input manager std::map> m_timeFrameMap; - //! TpcRawHit -> waveform start clock values, cached because TpcRawHitv3 does not expose waveform rows - std::map> m_hitWaveformStartMap; - //! previous matched timeframe GTM BCO, used to fill waveform-start row once the next GTM BCO is known std::optional m_previousTimeFrameGtmBco; static const size_t kMaxRawHitLimit = 10000; // 10k hits per event > 256ch/fee * 26fee From 4f61b7334c165724eb5bae2963166cb1e66a1039 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 5 Jun 2026 15:37:22 -0400 Subject: [PATCH 600/866] trigger jenkins From 98fd40f6e92d4cbec4827c337abab9892cb7d5bd Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Fri, 5 Jun 2026 22:53:19 -0400 Subject: [PATCH 601/866] FEE stat. QA --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 156 +++++++++++------- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 24 ++- 2 files changed, 108 insertions(+), 72 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index c7aa92cfa5..681613cdb2 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -187,17 +187,29 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); hm->registerHisto(h_Run3TimeFrameFuzzyHit_FEE); - h_Run3WaveformStart_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3WaveformStart_GL1Spacing", // + h_Run3Waveform_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3Waveform_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 matched waveform ADC sum vs GL1 spacing;ADC Time Bin [0...1023];Current - previous GL1 GTM BCO [BCO]", + 1024, -.5, 1023.5, 1001, -.5, 1000.5); + hm->registerHisto(h_Run3Waveform_GL1Spacing); + + h_Run3FEE_TimeFrameCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TimeFrameCount_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 exact timeframe count by FEE vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", + 1001, -.5, 1000.5, MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3FEE_TimeFrameCount_GL1Spacing); + + h_Run3FEE_TriggerCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TriggerCount_GL1Spacing", // TString(m_HistoPrefix.c_str()) + - " Run3 matched waveform start clock vs GL1 spacing;FEE ADC waveform start clock;Current - previous GL1 GTM BCO [BCO]", - 1024, -.5, 1023.5, 1001, -.5, 1000.5); - hm->registerHisto(h_Run3WaveformStart_GL1Spacing); + " Run3 GL1 trigger count by FEE vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", + 1001, -.5, 1000.5, MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3FEE_TriggerCount_GL1Spacing); - h_Run3PreviousTimeFrameWaveformStart = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameWaveformStartCache", // - TString(m_HistoPrefix.c_str()) + - " Run3 previous matched waveform start cache;FEE ADC waveform start clock;Count", - 1024, -.5, 1023.5); - h_Run3PreviousTimeFrameWaveformStart->SetDirectory(nullptr); + h_Run3PreviousTimeFrameWaveformADC = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameWaveformADCCache", // + TString(m_HistoPrefix.c_str()) + + " Run3 previous matched waveform ADC cache;ADC Time Bin [0...1023];Sum ADC", + 1024, -.5, 1023.5); + h_Run3PreviousTimeFrameWaveformADC->SetDirectory(nullptr); h_ProcessPacket_Time = new TH2I(TString(m_HistoPrefix.c_str()) + "_ProcessPacket_Time", // TString(m_HistoPrefix.c_str()) + @@ -212,10 +224,9 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() { for (auto& timeHitEntry : feeTimeHitMap) { - for (CachedTimeHit& cached_hit : timeHitEntry.second) + for (TpcRawHit* hit : timeHitEntry.second) { - delete cached_hit.hit; - cached_hit.hit = nullptr; + delete hit; } timeHitEntry.second.clear(); } @@ -230,7 +241,7 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() timeFrameEntry.second.pop_back(); } } - delete h_Run3PreviousTimeFrameWaveformStart; + delete h_Run3PreviousTimeFrameWaveformADC; delete m_packetTimer; @@ -247,10 +258,12 @@ void TpcTimeFrameBuilderRun3::setVerbosity(const int i) } } -void TpcTimeFrameBuilderRun3::flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco) +void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current_gtm_bco) { - assert(h_Run3PreviousTimeFrameWaveformStart); - assert(h_Run3WaveformStart_GL1Spacing); + assert(h_Run3PreviousTimeFrameWaveformADC); + assert(h_Run3Waveform_GL1Spacing); + assert(h_Run3FEE_TimeFrameCount_GL1Spacing); + assert(h_Run3FEE_TriggerCount_GL1Spacing); if (!m_previousTimeFrameGtmBco) { @@ -264,32 +277,74 @@ void TpcTimeFrameBuilderRun3::flush_previous_timeframe_waveform_start_cache(uint : current_gtm_bco + gtm_clock_range; const uint64_t gtm_bco_spacing = current_gtm_bco_rollover_corrected - previous_gtm_bco; - for (int bin = 1; bin <= h_Run3PreviousTimeFrameWaveformStart->GetNbinsX(); ++bin) + const int waveform_ybin = h_Run3Waveform_GL1Spacing->GetYaxis()->FindFixBin(static_cast(gtm_bco_spacing)); + double waveform_entries = 0; + for (int xbin = 1; xbin <= h_Run3PreviousTimeFrameWaveformADC->GetNbinsX(); ++xbin) { - const double count = h_Run3PreviousTimeFrameWaveformStart->GetBinContent(bin); - if (count == 0) + const double adc_sum = h_Run3PreviousTimeFrameWaveformADC->GetBinContent(xbin); + if (adc_sum == 0) { continue; } - h_Run3WaveformStart_GL1Spacing->Fill(h_Run3PreviousTimeFrameWaveformStart->GetXaxis()->GetBinCenter(bin), - gtm_bco_spacing, count); + h_Run3Waveform_GL1Spacing->AddBinContent(h_Run3Waveform_GL1Spacing->GetBin(xbin, waveform_ybin), adc_sum); + ++waveform_entries; + } + h_Run3Waveform_GL1Spacing->SetEntries(h_Run3Waveform_GL1Spacing->GetEntries() + waveform_entries); + + const int fee_xbin = h_Run3FEE_TriggerCount_GL1Spacing->GetXaxis()->FindFixBin(static_cast(gtm_bco_spacing)); + double timeframe_entries = 0; + for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) + { + const int fee_ybin = static_cast(fee) + 1; + h_Run3FEE_TriggerCount_GL1Spacing->AddBinContent(h_Run3FEE_TriggerCount_GL1Spacing->GetBin(fee_xbin, fee_ybin)); + + if (m_previousTimeFrameExactFees.test(fee)) + { + h_Run3FEE_TimeFrameCount_GL1Spacing->AddBinContent(h_Run3FEE_TimeFrameCount_GL1Spacing->GetBin(fee_xbin, fee_ybin)); + ++timeframe_entries; + } } + h_Run3FEE_TriggerCount_GL1Spacing->SetEntries(h_Run3FEE_TriggerCount_GL1Spacing->GetEntries() + MAX_FEECOUNT); + h_Run3FEE_TimeFrameCount_GL1Spacing->SetEntries(h_Run3FEE_TimeFrameCount_GL1Spacing->GetEntries() + timeframe_entries); - h_Run3PreviousTimeFrameWaveformStart->Reset(); + h_Run3PreviousTimeFrameWaveformADC->Reset(); + m_previousTimeFrameExactFees.reset(); m_previousTimeFrameGtmBco.reset(); } -void TpcTimeFrameBuilderRun3::cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector& waveform_start_clocks) +void TpcTimeFrameBuilderRun3::cache_timeframe_qa(uint64_t gtm_bco, const std::vector& timeframe, const std::bitset& exact_matched_fees) { - assert(h_Run3PreviousTimeFrameWaveformStart); + assert(h_Run3PreviousTimeFrameWaveformADC); - h_Run3PreviousTimeFrameWaveformStart->Reset(); - for (const uint16_t waveform_start : waveform_start_clocks) + h_Run3PreviousTimeFrameWaveformADC->Reset(); + for (const TpcRawHit* hit : timeframe) { - h_Run3PreviousTimeFrameWaveformStart->Fill(waveform_start); + if (!hit) + { + continue; + } + + std::unique_ptr adc_iter(hit->CreateAdcIterator()); + if (!adc_iter) + { + continue; + } + + for (adc_iter->First(); !adc_iter->IsDone(); adc_iter->Next()) + { + const uint16_t time_bin = adc_iter->CurrentTimeBin(); + const uint16_t adc = adc_iter->CurrentAdc(); + if (adc == 0 || time_bin >= 1024U) + { + continue; + } + + h_Run3PreviousTimeFrameWaveformADC->AddBinContent(static_cast(time_bin) + 1, adc); + } } + m_previousTimeFrameExactFees = exact_matched_fees; m_previousTimeFrameGtmBco = gtm_bco; } @@ -316,7 +371,7 @@ uint32_t TpcTimeFrameBuilderRun3::get_fee_bco_diff(uint32_t first, uint32_t seco return static_cast(diff < 0 ? -diff : diff); } -size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector& timeframe, std::vector& waveform_start_clocks) +size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector& timeframe) { if (fee >= m_timeHitMap.size()) { @@ -330,7 +385,7 @@ size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, s return 0; } - std::vector& hits = it->second; + std::vector& hits = it->second; const size_t moved = hits.size(); if (moved == 0) { @@ -339,18 +394,7 @@ size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, s } timeframe.reserve(timeframe.size() + moved); - for (CachedTimeHit& cached_hit : hits) - { - if (cached_hit.hit) - { - timeframe.push_back(cached_hit.hit); - cached_hit.hit = nullptr; - } - - waveform_start_clocks.insert(waveform_start_clocks.end(), - cached_hit.waveform_start_clocks.begin(), - cached_hit.waveform_start_clocks.end()); - } + timeframe.insert(timeframe.end(), hits.begin(), hits.end()); fee_time_hits.erase(it); return moved; } @@ -400,7 +444,7 @@ std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t pre uint32_t best_diff = std::numeric_limits::max(); bool found = false; - auto consider_fee_bco = [&](uint32_t fee_bco, const std::vector& hits) + auto consider_fee_bco = [&](uint32_t fee_bco, const std::vector& hits) { if (hits.empty()) { @@ -463,11 +507,10 @@ void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_correc const int64_t diff = get_signed_fee_bco_diff(map_it->first, *predicted_fee_bco); if ((fee_clock_window == 0 && diff <= 0) || (fee_clock_window > 0 && diff < -static_cast(fee_clock_window))) { - for (CachedTimeHit& cached_hit : map_it->second) + for (TpcRawHit* hit : map_it->second) { m_hFEEDataStream->Fill(fee, "HitUnusedBeforeCleanup", 1); - delete cached_hit.hit; - cached_hit.hit = nullptr; + delete hit; } map_it = fee_time_hits.erase(map_it); } @@ -520,7 +563,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g return cached->second; } - flush_previous_timeframe_waveform_start_cache(bclk_rollover_corrected); + flush_previous_timeframe_qa_cache(bclk_rollover_corrected); if (m_verbosity > 2) { @@ -536,7 +579,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g size_t exact_hit_count = 0; size_t fallback_hit_count = 0; - std::vector matched_waveform_start_clocks; + std::bitset exact_matched_fees; for (size_t fee_index = 0; fee_index < m_bcoMatchingInformation_vec.size(); ++fee_index) { @@ -551,7 +594,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g for (int32_t fee_clock_offset = -kRun3ExactMatchWindow; fee_clock_offset <= kRun3ExactMatchWindow; ++fee_clock_offset) { const uint32_t exact_fee_bco = static_cast(static_cast(static_cast(*predicted_fee_bco) + fee_clock_offset) & kFEEClockMask); - const size_t exact_hits_for_bco = move_time_hits(exact_fee_bco, fee, timeframe, matched_waveform_start_clocks); + const size_t exact_hits_for_bco = move_time_hits(exact_fee_bco, fee, timeframe); if (exact_hits_for_bco == 0) { continue; @@ -569,6 +612,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g { assert(h_Run3TimeFrameExactHit_FEE); h_Run3TimeFrameExactHit_FEE->Fill(fee, exact_hits); + exact_matched_fees.set(fee); continue; } @@ -622,6 +666,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g m_hNorm->Fill("Run3_TimeFrame_MatchFailed", 1); m_hNorm->Fill("GTM_TimeFrame_Unmatched", 1); + cache_timeframe_qa(bclk_rollover_corrected, timeframe, exact_matched_fees); m_timeFrameMap.erase(frame_it); static std::vector empty; return empty; @@ -635,7 +680,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g assert(h_TimeFrame_Matched_Size); h_TimeFrame_Matched_Size->Fill(timeframe.size()); m_hNorm->Fill("GTM_TimeFrame_Matched_Hit_Sum", timeframe.size()); - cache_timeframe_waveform_starts(bclk_rollover_corrected, matched_waveform_start_clocks); + cache_timeframe_qa(bclk_rollover_corrected, timeframe, exact_matched_fees); m_UsedTimeFrameSet.push(bclk_rollover_corrected); return timeframe; } @@ -895,10 +940,9 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) << std::endl; m_hNorm->Fill("TimeFrameSizeLimitError", 1); - for (CachedTimeHit& cached_hit : timehit->second) + for (TpcRawHit* hit : timehit->second) { - delete cached_hit.hit; - cached_hit.hit = nullptr; + delete hit; } timehit = fee_time_hits.erase(timehit); } @@ -1247,18 +1291,12 @@ void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, // hit->set_parity(payload.data_parity); hit->set_parityerror(payload.data_parity != payload.calc_parity); - std::vector waveform_start_clocks; - waveform_start_clocks.reserve(payload.waveforms.size()); - for (const std::pair>& waveform : payload.waveforms) - { - waveform_start_clocks.push_back(waveform.first); - } for (std::pair>& waveform : payload.waveforms) { hit->move_adc_waveform(waveform.first, std::move(waveform.second)); } - m_timeHitMap[fee][payload.bx_timestamp & kFEEClockMask].push_back(CachedTimeHit{hit, std::move(waveform_start_clocks)}); + m_timeHitMap[fee][payload.bx_timestamp & kFEEClockMask].push_back(hit); } } // if (not m_fastBCOSkip) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index ca68ab6e48..c967907562 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -4,6 +4,7 @@ #include "TpcTimeFrameBuilderBase.h" #include +#include #include #include #include @@ -390,28 +391,23 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static int64_t get_signed_fee_bco_diff(uint32_t first, uint32_t second); static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); - struct CachedTimeHit - { - TpcRawHit *hit = nullptr; - std::vector waveform_start_clocks; - }; - - size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe, std::vector &waveform_start_clocks); + size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe); size_t count_time_hits(uint32_t fee_bco, uint16_t fee) const; size_t time_hit_bucket_count() const; std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); - void flush_previous_timeframe_waveform_start_cache(uint64_t current_gtm_bco); - void cache_timeframe_waveform_starts(uint64_t gtm_bco, const std::vector &waveform_start_clocks); + void flush_previous_timeframe_qa_cache(uint64_t current_gtm_bco); + void cache_timeframe_qa(uint64_t gtm_bco, const std::vector &timeframe, const std::bitset &exact_matched_fees); //! FEE -> FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching - std::vector>> m_timeHitMap; + std::vector>> m_timeHitMap; //! rollover-corrected GTM BCO -> matched TpcRawHit returned to the input manager std::map> m_timeFrameMap; - //! previous matched timeframe GTM BCO, used to fill waveform-start row once the next GTM BCO is known + //! previous timeframe QA state, filled once the next GTM BCO defines the GL1 spacing std::optional m_previousTimeFrameGtmBco; + std::bitset m_previousTimeFrameExactFees; static const size_t kMaxRawHitLimit = 10000; // 10k hits per event > 256ch/fee * 26fee std::queue m_UsedTimeFrameSet; @@ -442,8 +438,10 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH2 *h_Run3_FEE_GTMMatching_ClockDiff = nullptr; TH1 *h_Run3TimeFrameExactHit_FEE = nullptr; TH1 *h_Run3TimeFrameFuzzyHit_FEE = nullptr; - TH1 *h_Run3PreviousTimeFrameWaveformStart = nullptr; - TH2 *h_Run3WaveformStart_GL1Spacing = nullptr; + TH1 *h_Run3PreviousTimeFrameWaveformADC = nullptr; + TH2 *h_Run3Waveform_GL1Spacing = nullptr; + TH2 *h_Run3FEE_TimeFrameCount_GL1Spacing = nullptr; + TH2 *h_Run3FEE_TriggerCount_GL1Spacing = nullptr; TH2 *h_ProcessPacket_Time = nullptr; }; From ac28c87aed6f0e1b88d883f9a111ab5809a7f7d7 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 6 Jun 2026 12:36:12 -0400 Subject: [PATCH 602/866] codex checkpoint --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 292 ++++++++++++++++-- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 12 + 2 files changed, 281 insertions(+), 23 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 681613cdb2..98aeb9f175 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -53,7 +53,7 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) m_hNorm = new TH1D(TString(m_HistoPrefix.c_str()) + "_Normalization", // TString(m_HistoPrefix.c_str()) + " Normalization;Items;Count", - 24, .5, 24.5); + kRun3NormalizationBinCount, .5, kRun3NormalizationBinCount + .5); int i = 1; m_hNorm->GetXaxis()->SetBinLabel(i++, "Packet"); m_hNorm->GetXaxis()->SetBinLabel(i++, "Lv1-Taggers"); @@ -80,7 +80,13 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_FuzzyFallback_Hit_Sum"); m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_MatchFailed"); - assert(i <= 24); + m_hNormTruncatedWaveformRecoveryFeeFirstBin = i; + for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) + { + m_hNorm->GetXaxis()->SetBinLabel(i++, ("Run3_TruncatedWaveformRecover_FEE" + std::to_string(fee)).c_str()); + } + + assert(i <= kRun3NormalizationBinCount + 1); m_hNorm->GetXaxis()->LabelsOption("v"); hm->registerHisto(m_hNorm); @@ -189,10 +195,16 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) h_Run3Waveform_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3Waveform_GL1Spacing", // TString(m_HistoPrefix.c_str()) + - " Run3 matched waveform ADC sum vs GL1 spacing;ADC Time Bin [0...1023];Current - previous GL1 GTM BCO [BCO]", + " Run3 matched waveform ADC sum before truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1023];Current - previous GL1 GTM BCO [BCO]", 1024, -.5, 1023.5, 1001, -.5, 1000.5); hm->registerHisto(h_Run3Waveform_GL1Spacing); + h_Run3WaveformRecovered_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3WaveformRecovered_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 matched waveform ADC sum after truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1023];Current - previous GL1 GTM BCO [BCO]", + 1024, -.5, 1023.5, 1001, -.5, 1000.5); + hm->registerHisto(h_Run3WaveformRecovered_GL1Spacing); + h_Run3FEE_TimeFrameCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TimeFrameCount_GL1Spacing", // TString(m_HistoPrefix.c_str()) + " Run3 exact timeframe count by FEE vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", @@ -211,6 +223,12 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) 1024, -.5, 1023.5); h_Run3PreviousTimeFrameWaveformADC->SetDirectory(nullptr); + h_Run3PreviousTimeFrameRecoveredWaveformADC = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameRecoveredWaveformADCCache", // + TString(m_HistoPrefix.c_str()) + + " Run3 previous matched waveform ADC cache after truncated waveform recovery;ADC Time Bin [0...1023];Sum ADC", + 1024, -.5, 1023.5); + h_Run3PreviousTimeFrameRecoveredWaveformADC->SetDirectory(nullptr); + h_ProcessPacket_Time = new TH2I(TString(m_HistoPrefix.c_str()) + "_ProcessPacket_Time", // TString(m_HistoPrefix.c_str()) + " Time cost to run ProcessPacket();Call counts;Time elapsed per call [ms];Count", @@ -242,6 +260,7 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() } } delete h_Run3PreviousTimeFrameWaveformADC; + delete h_Run3PreviousTimeFrameRecoveredWaveformADC; delete m_packetTimer; @@ -258,10 +277,33 @@ void TpcTimeFrameBuilderRun3::setVerbosity(const int i) } } +void TpcTimeFrameBuilderRun3::fill_waveform_gl1_spacing(TH1 *waveform_adc_cache, TH2 *waveform_gl1_spacing, uint64_t gtm_bco_spacing) const +{ + assert(waveform_adc_cache); + assert(waveform_gl1_spacing); + + const int waveform_ybin = waveform_gl1_spacing->GetYaxis()->FindFixBin(static_cast(gtm_bco_spacing)); + double waveform_entries = 0; + for (int xbin = 1; xbin <= waveform_adc_cache->GetNbinsX(); ++xbin) + { + const double adc_sum = waveform_adc_cache->GetBinContent(xbin); + if (adc_sum == 0) + { + continue; + } + + waveform_gl1_spacing->AddBinContent(waveform_gl1_spacing->GetBin(xbin, waveform_ybin), adc_sum); + ++waveform_entries; + } + waveform_gl1_spacing->SetEntries(waveform_gl1_spacing->GetEntries() + waveform_entries); +} + void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current_gtm_bco) { assert(h_Run3PreviousTimeFrameWaveformADC); + assert(h_Run3PreviousTimeFrameRecoveredWaveformADC); assert(h_Run3Waveform_GL1Spacing); + assert(h_Run3WaveformRecovered_GL1Spacing); assert(h_Run3FEE_TimeFrameCount_GL1Spacing); assert(h_Run3FEE_TriggerCount_GL1Spacing); @@ -277,20 +319,8 @@ void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current : current_gtm_bco + gtm_clock_range; const uint64_t gtm_bco_spacing = current_gtm_bco_rollover_corrected - previous_gtm_bco; - const int waveform_ybin = h_Run3Waveform_GL1Spacing->GetYaxis()->FindFixBin(static_cast(gtm_bco_spacing)); - double waveform_entries = 0; - for (int xbin = 1; xbin <= h_Run3PreviousTimeFrameWaveformADC->GetNbinsX(); ++xbin) - { - const double adc_sum = h_Run3PreviousTimeFrameWaveformADC->GetBinContent(xbin); - if (adc_sum == 0) - { - continue; - } - - h_Run3Waveform_GL1Spacing->AddBinContent(h_Run3Waveform_GL1Spacing->GetBin(xbin, waveform_ybin), adc_sum); - ++waveform_entries; - } - h_Run3Waveform_GL1Spacing->SetEntries(h_Run3Waveform_GL1Spacing->GetEntries() + waveform_entries); + fill_waveform_gl1_spacing(h_Run3PreviousTimeFrameWaveformADC, h_Run3Waveform_GL1Spacing, gtm_bco_spacing); + fill_waveform_gl1_spacing(h_Run3PreviousTimeFrameRecoveredWaveformADC, h_Run3WaveformRecovered_GL1Spacing, gtm_bco_spacing); const int fee_xbin = h_Run3FEE_TriggerCount_GL1Spacing->GetXaxis()->FindFixBin(static_cast(gtm_bco_spacing)); double timeframe_entries = 0; @@ -309,15 +339,16 @@ void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current h_Run3FEE_TimeFrameCount_GL1Spacing->SetEntries(h_Run3FEE_TimeFrameCount_GL1Spacing->GetEntries() + timeframe_entries); h_Run3PreviousTimeFrameWaveformADC->Reset(); + h_Run3PreviousTimeFrameRecoveredWaveformADC->Reset(); m_previousTimeFrameExactFees.reset(); m_previousTimeFrameGtmBco.reset(); } -void TpcTimeFrameBuilderRun3::cache_timeframe_qa(uint64_t gtm_bco, const std::vector& timeframe, const std::bitset& exact_matched_fees) +void TpcTimeFrameBuilderRun3::cache_waveform_adc(TH1 *waveform_adc_cache, const std::vector& timeframe) const { - assert(h_Run3PreviousTimeFrameWaveformADC); + assert(waveform_adc_cache); - h_Run3PreviousTimeFrameWaveformADC->Reset(); + waveform_adc_cache->Reset(); for (const TpcRawHit* hit : timeframe) { if (!hit) @@ -335,14 +366,19 @@ void TpcTimeFrameBuilderRun3::cache_timeframe_qa(uint64_t gtm_bco, const std::ve { const uint16_t time_bin = adc_iter->CurrentTimeBin(); const uint16_t adc = adc_iter->CurrentAdc(); - if (adc == 0 || time_bin >= 1024U) + if (adc == 0 || time_bin >= kRun3TruncatedWaveformRecoveryWindow) { continue; } - h_Run3PreviousTimeFrameWaveformADC->AddBinContent(static_cast(time_bin) + 1, adc); + waveform_adc_cache->AddBinContent(static_cast(time_bin) + 1, adc); } } +} + +void TpcTimeFrameBuilderRun3::cache_timeframe_qa(uint64_t gtm_bco, const std::vector& timeframe, const std::bitset& exact_matched_fees) +{ + cache_waveform_adc(h_Run3PreviousTimeFrameRecoveredWaveformADC, timeframe); m_previousTimeFrameExactFees = exact_matched_fees; m_previousTimeFrameGtmBco = gtm_bco; @@ -487,6 +523,182 @@ std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t pre return std::nullopt; } +size_t TpcTimeFrameBuilderRun3::append_shifted_waveforms(TpcRawHitv3 *target, const TpcRawHit &source, uint32_t fee_clock_shift) const +{ + if (!target || fee_clock_shift >= kRun3TruncatedWaveformRecoveryWindow) + { + return 0; + } + + std::unique_ptr adc_iter(source.CreateAdcIterator()); + if (!adc_iter) + { + return 0; + } + + size_t appended_waveforms = 0; + std::vector adc_values; + uint16_t waveform_start = 0; + uint32_t expected_time_bin = std::numeric_limits::max(); + + auto flush_waveform = [&]() + { + if (adc_values.empty()) + { + return; + } + + std::vector waveform_adc; + waveform_adc.swap(adc_values); + target->move_adc_waveform(waveform_start, std::move(waveform_adc)); + expected_time_bin = std::numeric_limits::max(); + ++appended_waveforms; + }; + + for (adc_iter->First(); !adc_iter->IsDone(); adc_iter->Next()) + { + const uint32_t shifted_time_bin = static_cast(adc_iter->CurrentTimeBin()) + fee_clock_shift; + if (shifted_time_bin >= kRun3TruncatedWaveformRecoveryWindow) + { + flush_waveform(); + continue; + } + + if (adc_values.empty() || shifted_time_bin != expected_time_bin) + { + flush_waveform(); + waveform_start = static_cast(shifted_time_bin); + } + + adc_values.push_back(adc_iter->CurrentAdc()); + expected_time_bin = shifted_time_bin + 1U; + } + flush_waveform(); + + return appended_waveforms; +} + +size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_fee_bco, uint16_t fee, std::vector& timeframe) +{ + if (fee >= m_timeHitMap.size()) + { + return 0; + } + + predicted_fee_bco &= kFEEClockMask; + std::array current_hits{}; + std::array current_hit_diff{}; + current_hit_diff.fill(std::numeric_limits::max()); + + for (TpcRawHit* hit : timeframe) + { + if (!hit || hit->get_fee() != fee || hit->get_channel() >= MAX_CHANNELS) + { + continue; + } + + TpcRawHitv3* hit_v3 = dynamic_cast(hit); + if (!hit_v3) + { + continue; + } + + const uint16_t channel = hit_v3->get_channel(); + const int64_t signed_diff = get_signed_fee_bco_diff(static_cast(hit_v3->get_bco()), predicted_fee_bco); + const int64_t abs_diff = signed_diff < 0 ? -signed_diff : signed_diff; + if (abs_diff < current_hit_diff[channel]) + { + current_hit_diff[channel] = abs_diff; + current_hits[channel] = hit_v3; + } + } + + size_t recovered_hits = 0; + auto& fee_time_hits = m_timeHitMap[fee]; + if (fee_time_hits.empty()) + { + return 0; + } + + auto recover_from_bucket = [&](const std::pair>& bucket) + { + for (const TpcRawHit* source_hit : bucket.second) + { + if (!source_hit || source_hit->get_channel() >= MAX_CHANNELS) + { + continue; + } + + const uint16_t channel = source_hit->get_channel(); + TpcRawHitv3* target_hit = current_hits[channel]; + const uint32_t target_fee_bco = target_hit ? static_cast(target_hit->get_bco()) & kFEEClockMask : predicted_fee_bco; + const int64_t fee_clock_shift = get_signed_fee_bco_diff(static_cast(source_hit->get_bco()), target_fee_bco); + if (fee_clock_shift <= 0 || fee_clock_shift >= static_cast(kRun3TruncatedWaveformRecoveryWindow)) + { + continue; + } + + bool created_target = false; + if (!target_hit) + { + target_hit = new TpcRawHitv3(); + target_hit->set_bco(predicted_fee_bco); + target_hit->set_packetid(m_packet_id); + target_hit->set_fee(fee); + target_hit->set_channel(channel); + target_hit->set_type(source_hit->get_type()); + target_hit->set_checksumerror(source_hit->get_checksumerror()); + target_hit->set_parityerror(source_hit->get_parityerror()); + timeframe.push_back(target_hit); + current_hits[channel] = target_hit; + current_hit_diff[channel] = 0; + created_target = true; + } + + const size_t appended_waveforms = append_shifted_waveforms(target_hit, *source_hit, static_cast(fee_clock_shift)); + if (appended_waveforms == 0) + { + if (created_target) + { + current_hits[channel] = nullptr; + current_hit_diff[channel] = std::numeric_limits::max(); + assert(!timeframe.empty() && timeframe.back() == target_hit); + timeframe.pop_back(); + delete target_hit; + } + continue; + } + + target_hit->set_checksumerror(target_hit->get_checksumerror() || source_hit->get_checksumerror()); + target_hit->set_parityerror(target_hit->get_parityerror() || source_hit->get_parityerror()); + ++recovered_hits; + } + }; + + const uint32_t lower_fee_bco = (predicted_fee_bco + 1U) & kFEEClockMask; + const uint32_t upper_fee_bco = (predicted_fee_bco + kRun3TruncatedWaveformRecoveryWindow - 1U) & kFEEClockMask; + auto scan_range = [&](uint32_t first_fee_bco, uint32_t last_fee_bco) + { + for (auto it = fee_time_hits.lower_bound(first_fee_bco); it != fee_time_hits.end() && it->first <= last_fee_bco; ++it) + { + recover_from_bucket(*it); + } + }; + + if (lower_fee_bco <= upper_fee_bco) + { + scan_range(lower_fee_bco, upper_fee_bco); + } + else + { + scan_range(lower_fee_bco, kFEEClockMask); + scan_range(0, upper_fee_bco); + } + + return recovered_hits; +} + + void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window) { assert(m_hFEEDataStream); @@ -580,8 +792,10 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g size_t exact_hit_count = 0; size_t fallback_hit_count = 0; std::bitset exact_matched_fees; + std::array predicted_fee_bcos{}; + std::bitset predicted_fee_bco_available; - for (size_t fee_index = 0; fee_index < m_bcoMatchingInformation_vec.size(); ++fee_index) + for (size_t fee_index = 0; fee_index < std::min(m_bcoMatchingInformation_vec.size(), static_cast(MAX_FEECOUNT)); ++fee_index) { const uint16_t fee = static_cast(fee_index); const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee_index].get_predicted_fee_bco(bclk_rollover_corrected); @@ -589,6 +803,8 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g { continue; } + predicted_fee_bcos[fee] = *predicted_fee_bco; + predicted_fee_bco_available.set(fee); size_t exact_hits = 0; for (int32_t fee_clock_offset = -kRun3ExactMatchWindow; fee_clock_offset <= kRun3ExactMatchWindow; ++fee_clock_offset) @@ -654,6 +870,36 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback_Hit_Sum", fallback_hit_count); } + cache_waveform_adc(h_Run3PreviousTimeFrameWaveformADC, timeframe); + + size_t recovered_hit_count = 0; + for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) + { + if (!predicted_fee_bco_available.test(fee)) + { + continue; + } + + const size_t recovered_hits = recover_truncated_waveforms(predicted_fee_bcos[fee], fee, timeframe); + if (recovered_hits == 0) + { + continue; + } + + recovered_hit_count += recovered_hits; + if (m_hNormTruncatedWaveformRecoveryFeeFirstBin > 0) + { + m_hNorm->Fill(static_cast(m_hNormTruncatedWaveformRecoveryFeeFirstBin + fee), static_cast(recovered_hits)); + } + } + + if (m_verbosity >= 1 && recovered_hit_count > 0) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": Run3 truncated waveform recovery appended " << recovered_hit_count + << " later hit segments for gtm_bco: 0x" << std::hex << gtm_bco << std::dec << std::endl; + } + if (timeframe.empty()) { if (m_verbosity >= 1) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index c967907562..13967abe84 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -4,6 +4,7 @@ #include "TpcTimeFrameBuilderBase.h" #include +#include #include #include #include @@ -21,6 +22,7 @@ class Packet; class TpcRawHit; +class TpcRawHitv3; class PHTimer; class TH1; class TH2; @@ -388,6 +390,9 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static constexpr uint32_t kFEEClockMask = (1U << 20U) - 1U; static constexpr uint32_t kRun3FeeMatchWindow = (GL1_BCO_MATCH_WINDOW * 30U + 7U) / 8U; static constexpr int32_t kRun3ExactMatchWindow = 2; + static constexpr uint32_t kRun3TruncatedWaveformRecoveryWindow = 1024U; + static constexpr int kRun3NormalizationBaseBinCount = 20; + static constexpr int kRun3NormalizationBinCount = kRun3NormalizationBaseBinCount + MAX_FEECOUNT; static int64_t get_signed_fee_bco_diff(uint32_t first, uint32_t second); static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); @@ -395,8 +400,12 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase size_t count_time_hits(uint32_t fee_bco, uint16_t fee) const; size_t time_hit_bucket_count() const; std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; + size_t recover_truncated_waveforms(uint32_t predicted_fee_bco, uint16_t fee, std::vector &timeframe); + size_t append_shifted_waveforms(TpcRawHitv3 *target, const TpcRawHit &source, uint32_t fee_clock_shift) const; void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); void flush_previous_timeframe_qa_cache(uint64_t current_gtm_bco); + void fill_waveform_gl1_spacing(TH1 *waveform_adc_cache, TH2 *waveform_gl1_spacing, uint64_t gtm_bco_spacing) const; + void cache_waveform_adc(TH1 *waveform_adc_cache, const std::vector &timeframe) const; void cache_timeframe_qa(uint64_t gtm_bco, const std::vector &timeframe, const std::bitset &exact_matched_fees); //! FEE -> FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching @@ -408,6 +417,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! previous timeframe QA state, filled once the next GTM BCO defines the GL1 spacing std::optional m_previousTimeFrameGtmBco; std::bitset m_previousTimeFrameExactFees; + int m_hNormTruncatedWaveformRecoveryFeeFirstBin = 0; static const size_t kMaxRawHitLimit = 10000; // 10k hits per event > 256ch/fee * 26fee std::queue m_UsedTimeFrameSet; @@ -439,7 +449,9 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH1 *h_Run3TimeFrameExactHit_FEE = nullptr; TH1 *h_Run3TimeFrameFuzzyHit_FEE = nullptr; TH1 *h_Run3PreviousTimeFrameWaveformADC = nullptr; + TH1 *h_Run3PreviousTimeFrameRecoveredWaveformADC = nullptr; TH2 *h_Run3Waveform_GL1Spacing = nullptr; + TH2 *h_Run3WaveformRecovered_GL1Spacing = nullptr; TH2 *h_Run3FEE_TimeFrameCount_GL1Spacing = nullptr; TH2 *h_Run3FEE_TriggerCount_GL1Spacing = nullptr; From 779e44d27fe333f62edb8d03703e8c42979233a6 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 6 Jun 2026 12:40:42 -0400 Subject: [PATCH 603/866] clean hit format type def --- .../framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 12 ++++++------ .../framework/fun4allraw/TpcTimeFrameBuilderRun3.h | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 98aeb9f175..2d2b0f4106 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -523,7 +523,7 @@ std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t pre return std::nullopt; } -size_t TpcTimeFrameBuilderRun3::append_shifted_waveforms(TpcRawHitv3 *target, const TpcRawHit &source, uint32_t fee_clock_shift) const +size_t TpcTimeFrameBuilderRun3::append_shifted_waveforms(TpcRawHitRun3_typ *target, const TpcRawHit &source, uint32_t fee_clock_shift) const { if (!target || fee_clock_shift >= kRun3TruncatedWaveformRecoveryWindow) { @@ -586,7 +586,7 @@ size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_f } predicted_fee_bco &= kFEEClockMask; - std::array current_hits{}; + std::array current_hits{}; std::array current_hit_diff{}; current_hit_diff.fill(std::numeric_limits::max()); @@ -597,7 +597,7 @@ size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_f continue; } - TpcRawHitv3* hit_v3 = dynamic_cast(hit); + TpcRawHitRun3_typ* hit_v3 = dynamic_cast(hit); if (!hit_v3) { continue; @@ -630,7 +630,7 @@ size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_f } const uint16_t channel = source_hit->get_channel(); - TpcRawHitv3* target_hit = current_hits[channel]; + TpcRawHitRun3_typ* target_hit = current_hits[channel]; const uint32_t target_fee_bco = target_hit ? static_cast(target_hit->get_bco()) & kFEEClockMask : predicted_fee_bco; const int64_t fee_clock_shift = get_signed_fee_bco_diff(static_cast(source_hit->get_bco()), target_fee_bco); if (fee_clock_shift <= 0 || fee_clock_shift >= static_cast(kRun3TruncatedWaveformRecoveryWindow)) @@ -641,7 +641,7 @@ size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_f bool created_target = false; if (!target_hit) { - target_hit = new TpcRawHitv3(); + target_hit = new TpcRawHitRun3_typ(); target_hit->set_bco(predicted_fee_bco); target_hit->set_packetid(m_packet_id); target_hit->set_fee(fee); @@ -1525,7 +1525,7 @@ void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, return; } - TpcRawHitv3* hit = new TpcRawHitv3(); + TpcRawHitRun3_typ* hit = new TpcRawHitRun3_typ(); hit->set_bco(payload.bx_timestamp); hit->set_packetid(m_packet_id); diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 13967abe84..5f82efd08d 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -23,6 +23,7 @@ class Packet; class TpcRawHit; class TpcRawHitv3; +using TpcRawHitRun3_typ = TpcRawHitv3; class PHTimer; class TH1; class TH2; @@ -401,7 +402,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase size_t time_hit_bucket_count() const; std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; size_t recover_truncated_waveforms(uint32_t predicted_fee_bco, uint16_t fee, std::vector &timeframe); - size_t append_shifted_waveforms(TpcRawHitv3 *target, const TpcRawHit &source, uint32_t fee_clock_shift) const; + size_t append_shifted_waveforms(TpcRawHitRun3_typ *target, const TpcRawHit &source, uint32_t fee_clock_shift) const; void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); void flush_previous_timeframe_qa_cache(uint64_t current_gtm_bco); void fill_waveform_gl1_spacing(TH1 *waveform_adc_cache, TH2 *waveform_gl1_spacing, uint64_t gtm_bco_spacing) const; From 1f53daa5b4994223cec26fe113e569bcf9fc518a Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 6 Jun 2026 13:13:16 -0400 Subject: [PATCH 604/866] fix clang-tidy --- simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc index ec6e4cbedf..5b7da8e23c 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc @@ -200,7 +200,7 @@ void SvtxTruthRecoTableEval::fillTruthRecoMaps(PHCompositeNode *topNode, SvtxTra for (const auto &[gtrackID, nclusters] : nclustersByTruthId) { const float clusCont = static_cast(nclusters); - if (selectedTruthIdSet.find(gtrackID) != selectedTruthIdSet.end()) + if (selectedTruthIdSet.contains(gtrackID)) { truthMaps[gtrackID][clusCont].insert(trackID); } From e706282266e3f30f881ece00796ccfedf8dcc6d1 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 6 Jun 2026 13:46:52 -0400 Subject: [PATCH 605/866] speed up and fix FEE clock and ADC clock difference --- offline/framework/ffarawobjects/TpcRawHitv3.h | 4 ++ .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 39 +++++++++++++------ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/offline/framework/ffarawobjects/TpcRawHitv3.h b/offline/framework/ffarawobjects/TpcRawHitv3.h index 755520c678..8d1994a8fc 100644 --- a/offline/framework/ffarawobjects/TpcRawHitv3.h +++ b/offline/framework/ffarawobjects/TpcRawHitv3.h @@ -73,7 +73,11 @@ class TpcRawHitv3 : public TpcRawHit // { // adcmap[sample] = val; // } + using AdcWaveform_t = std::pair >; + using AdcWaveformVector_t = std::vector; + void move_adc_waveform(const uint16_t start_time, std::vector &&adc); + const AdcWaveformVector_t &get_adc_waveforms() const { return m_adcData; } uint16_t get_type() const override { return type; } void set_type(const uint16_t i) override { type = i; } diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 2d2b0f4106..6833602e56 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -530,8 +530,9 @@ size_t TpcTimeFrameBuilderRun3::append_shifted_waveforms(TpcRawHitRun3_typ *targ return 0; } - std::unique_ptr adc_iter(source.CreateAdcIterator()); - if (!adc_iter) + const auto& source_run3 = static_cast(source); + const TpcRawHitRun3_typ::AdcWaveformVector_t& source_waveforms = source_run3.get_adc_waveforms(); + if (source_waveforms.empty()) { return 0; } @@ -555,23 +556,39 @@ size_t TpcTimeFrameBuilderRun3::append_shifted_waveforms(TpcRawHitRun3_typ *targ ++appended_waveforms; }; - for (adc_iter->First(); !adc_iter->IsDone(); adc_iter->Next()) + for (const TpcRawHitRun3_typ::AdcWaveform_t& source_waveform : source_waveforms) { - const uint32_t shifted_time_bin = static_cast(adc_iter->CurrentTimeBin()) + fee_clock_shift; - if (shifted_time_bin >= kRun3TruncatedWaveformRecoveryWindow) + const std::vector& source_adc_values = source_waveform.second; + if (source_adc_values.empty()) { - flush_waveform(); continue; } - if (adc_values.empty() || shifted_time_bin != expected_time_bin) + const uint32_t shifted_waveform_start = static_cast(source_waveform.first) + fee_clock_shift; + if (shifted_waveform_start >= kRun3TruncatedWaveformRecoveryWindow) { flush_waveform(); - waveform_start = static_cast(shifted_time_bin); + continue; } - adc_values.push_back(adc_iter->CurrentAdc()); - expected_time_bin = shifted_time_bin + 1U; + for (size_t adc_index = 0; adc_index < source_adc_values.size(); ++adc_index) + { + const uint32_t shifted_time_bin = shifted_waveform_start + static_cast(adc_index); + if (shifted_time_bin >= kRun3TruncatedWaveformRecoveryWindow) + { + flush_waveform(); + break; + } + + if (adc_values.empty() || shifted_time_bin != expected_time_bin) + { + flush_waveform(); + waveform_start = static_cast(shifted_time_bin); + } + + adc_values.push_back(source_adc_values[adc_index]); + expected_time_bin = shifted_time_bin + 1U; + } } flush_waveform(); @@ -632,7 +649,7 @@ size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_f const uint16_t channel = source_hit->get_channel(); TpcRawHitRun3_typ* target_hit = current_hits[channel]; const uint32_t target_fee_bco = target_hit ? static_cast(target_hit->get_bco()) & kFEEClockMask : predicted_fee_bco; - const int64_t fee_clock_shift = get_signed_fee_bco_diff(static_cast(source_hit->get_bco()), target_fee_bco); + const int64_t fee_clock_shift = get_signed_fee_bco_diff(static_cast(source_hit->get_bco()), target_fee_bco) /2; # FEE BCO is 2x ADC clock and therefore the shift is devided by /2 if (fee_clock_shift <= 0 || fee_clock_shift >= static_cast(kRun3TruncatedWaveformRecoveryWindow)) { continue; From ffcc5451e4d87ed1361f65736e61fcc91d53f3f2 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 6 Jun 2026 20:50:12 -0400 Subject: [PATCH 606/866] update matching time windows --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 32 ++++++++++++------- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 3 ++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 6833602e56..717eec436f 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -193,16 +193,17 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); hm->registerHisto(h_Run3TimeFrameFuzzyHit_FEE); + static constexpr uint32_t kRun3TruncatedWaveformRecoveryWindowPlotingRange = 1200U; h_Run3Waveform_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3Waveform_GL1Spacing", // TString(m_HistoPrefix.c_str()) + - " Run3 matched waveform ADC sum before truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1023];Current - previous GL1 GTM BCO [BCO]", - 1024, -.5, 1023.5, 1001, -.5, 1000.5); + " Run3 matched waveform ADC sum before truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1199];Current - previous GL1 GTM BCO [BCO]", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5, 1001, -.5, 1000.5); hm->registerHisto(h_Run3Waveform_GL1Spacing); h_Run3WaveformRecovered_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3WaveformRecovered_GL1Spacing", // TString(m_HistoPrefix.c_str()) + - " Run3 matched waveform ADC sum after truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1023];Current - previous GL1 GTM BCO [BCO]", - 1024, -.5, 1023.5, 1001, -.5, 1000.5); + " Run3 matched waveform ADC sum after truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1199];Current - previous GL1 GTM BCO [BCO]", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5, 1001, -.5, 1000.5); hm->registerHisto(h_Run3WaveformRecovered_GL1Spacing); h_Run3FEE_TimeFrameCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TimeFrameCount_GL1Spacing", // @@ -219,14 +220,14 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) h_Run3PreviousTimeFrameWaveformADC = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameWaveformADCCache", // TString(m_HistoPrefix.c_str()) + - " Run3 previous matched waveform ADC cache;ADC Time Bin [0...1023];Sum ADC", - 1024, -.5, 1023.5); + " Run3 previous matched waveform ADC cache;ADC Time Bin [0...1199];Sum ADC", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5); h_Run3PreviousTimeFrameWaveformADC->SetDirectory(nullptr); h_Run3PreviousTimeFrameRecoveredWaveformADC = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameRecoveredWaveformADCCache", // TString(m_HistoPrefix.c_str()) + - " Run3 previous matched waveform ADC cache after truncated waveform recovery;ADC Time Bin [0...1023];Sum ADC", - 1024, -.5, 1023.5); + " Run3 previous matched waveform ADC cache after truncated waveform recovery;ADC Time Bin [0...1199];Sum ADC", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5); h_Run3PreviousTimeFrameRecoveredWaveformADC->SetDirectory(nullptr); h_ProcessPacket_Time = new TH2I(TString(m_HistoPrefix.c_str()) + "_ProcessPacket_Time", // @@ -264,7 +265,7 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() delete m_packetTimer; - delete m_digitalCurrentDebugTTree; + // delete m_digitalCurrentDebugTTree; } void TpcTimeFrameBuilderRun3::setVerbosity(const int i) @@ -649,8 +650,15 @@ size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_f const uint16_t channel = source_hit->get_channel(); TpcRawHitRun3_typ* target_hit = current_hits[channel]; const uint32_t target_fee_bco = target_hit ? static_cast(target_hit->get_bco()) & kFEEClockMask : predicted_fee_bco; - const int64_t fee_clock_shift = get_signed_fee_bco_diff(static_cast(source_hit->get_bco()), target_fee_bco) /2; # FEE BCO is 2x ADC clock and therefore the shift is devided by /2 - if (fee_clock_shift <= 0 || fee_clock_shift >= static_cast(kRun3TruncatedWaveformRecoveryWindow)) + const int64_t fee_bco_diff = get_signed_fee_bco_diff(static_cast(source_hit->get_bco()), target_fee_bco); + if (fee_bco_diff <= 0 || fee_bco_diff >= static_cast(kRun3TruncatedWaveformRecoveryFEEWindow)) + { + continue; + } + + const int64_t fee_clock_shift = fee_bco_diff / static_cast(kRun3FEEClockPerADCClock); + // FEE BCO is 2x ADC clock, so the waveform shift is half the FEE BCO difference. + if (fee_clock_shift <= 0) { continue; } @@ -693,7 +701,7 @@ size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_f }; const uint32_t lower_fee_bco = (predicted_fee_bco + 1U) & kFEEClockMask; - const uint32_t upper_fee_bco = (predicted_fee_bco + kRun3TruncatedWaveformRecoveryWindow - 1U) & kFEEClockMask; + const uint32_t upper_fee_bco = (predicted_fee_bco + kRun3TruncatedWaveformRecoveryFEEWindow - 1U) & kFEEClockMask; auto scan_range = [&](uint32_t first_fee_bco, uint32_t last_fee_bco) { for (auto it = fee_time_hits.lower_bound(first_fee_bco); it != fee_time_hits.end() && it->first <= last_fee_bco; ++it) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 5f82efd08d..97fb100a1b 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -391,7 +391,10 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static constexpr uint32_t kFEEClockMask = (1U << 20U) - 1U; static constexpr uint32_t kRun3FeeMatchWindow = (GL1_BCO_MATCH_WINDOW * 30U + 7U) / 8U; static constexpr int32_t kRun3ExactMatchWindow = 2; + static constexpr uint32_t kRun3FEEClockPerADCClock = 2U; static constexpr uint32_t kRun3TruncatedWaveformRecoveryWindow = 1024U; + static constexpr uint32_t kRun3TruncatedWaveformRecoveryFEEWindow = + kRun3TruncatedWaveformRecoveryWindow * kRun3FEEClockPerADCClock; static constexpr int kRun3NormalizationBaseBinCount = 20; static constexpr int kRun3NormalizationBinCount = kRun3NormalizationBaseBinCount + MAX_FEECOUNT; From d6a5fe7c89175e7a460ce15703b19c776f5abec5 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 6 Jun 2026 21:16:43 -0400 Subject: [PATCH 607/866] add FEE recovery QA --- .../fun4allraw/TpcTimeFrameBuilder.cc | 2 +- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 25 +++++++++++++++++++ .../fun4allraw/TpcTimeFrameBuilderRun3.h | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index e068899771..0ae44cab32 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -183,7 +183,7 @@ TpcTimeFrameBuilder::~TpcTimeFrameBuilder() delete m_packetTimer; - delete m_digitalCurrentDebugTTree; + // delete m_digitalCurrentDebugTTree; } void TpcTimeFrameBuilder::setVerbosity(const int i) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 717eec436f..3df533bd06 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -212,6 +212,12 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) 1001, -.5, 1000.5, MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); hm->registerHisto(h_Run3FEE_TimeFrameCount_GL1Spacing); + h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TimeFrameRecoveredCount_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 timeframe count by FEE after truncated waveform recovery vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", + 1001, -.5, 1000.5, MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing); + h_Run3FEE_TriggerCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TriggerCount_GL1Spacing", // TString(m_HistoPrefix.c_str()) + " Run3 GL1 trigger count by FEE vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", @@ -306,6 +312,7 @@ void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current assert(h_Run3Waveform_GL1Spacing); assert(h_Run3WaveformRecovered_GL1Spacing); assert(h_Run3FEE_TimeFrameCount_GL1Spacing); + assert(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing); assert(h_Run3FEE_TriggerCount_GL1Spacing); if (!m_previousTimeFrameGtmBco) @@ -325,6 +332,7 @@ void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current const int fee_xbin = h_Run3FEE_TriggerCount_GL1Spacing->GetXaxis()->FindFixBin(static_cast(gtm_bco_spacing)); double timeframe_entries = 0; + double recovered_timeframe_entries = 0; for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) { const int fee_ybin = static_cast(fee) + 1; @@ -335,13 +343,21 @@ void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current h_Run3FEE_TimeFrameCount_GL1Spacing->AddBinContent(h_Run3FEE_TimeFrameCount_GL1Spacing->GetBin(fee_xbin, fee_ybin)); ++timeframe_entries; } + + if (m_previousTimeFrameRecoveredFees.test(fee)) + { + h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->AddBinContent(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->GetBin(fee_xbin, fee_ybin)); + ++recovered_timeframe_entries; + } } h_Run3FEE_TriggerCount_GL1Spacing->SetEntries(h_Run3FEE_TriggerCount_GL1Spacing->GetEntries() + MAX_FEECOUNT); h_Run3FEE_TimeFrameCount_GL1Spacing->SetEntries(h_Run3FEE_TimeFrameCount_GL1Spacing->GetEntries() + timeframe_entries); + h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->SetEntries(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->GetEntries() + recovered_timeframe_entries); h_Run3PreviousTimeFrameWaveformADC->Reset(); h_Run3PreviousTimeFrameRecoveredWaveformADC->Reset(); m_previousTimeFrameExactFees.reset(); + m_previousTimeFrameRecoveredFees.reset(); m_previousTimeFrameGtmBco.reset(); } @@ -382,6 +398,15 @@ void TpcTimeFrameBuilderRun3::cache_timeframe_qa(uint64_t gtm_bco, const std::ve cache_waveform_adc(h_Run3PreviousTimeFrameRecoveredWaveformADC, timeframe); m_previousTimeFrameExactFees = exact_matched_fees; + m_previousTimeFrameRecoveredFees.reset(); + for (const TpcRawHit* hit : timeframe) + { + if (!hit || hit->get_fee() >= MAX_FEECOUNT) + { + continue; + } + m_previousTimeFrameRecoveredFees.set(hit->get_fee()); + } m_previousTimeFrameGtmBco = gtm_bco; } diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 97fb100a1b..95ee3a472a 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -421,6 +421,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! previous timeframe QA state, filled once the next GTM BCO defines the GL1 spacing std::optional m_previousTimeFrameGtmBco; std::bitset m_previousTimeFrameExactFees; + std::bitset m_previousTimeFrameRecoveredFees; int m_hNormTruncatedWaveformRecoveryFeeFirstBin = 0; static const size_t kMaxRawHitLimit = 10000; // 10k hits per event > 256ch/fee * 26fee std::queue m_UsedTimeFrameSet; @@ -457,6 +458,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase TH2 *h_Run3Waveform_GL1Spacing = nullptr; TH2 *h_Run3WaveformRecovered_GL1Spacing = nullptr; TH2 *h_Run3FEE_TimeFrameCount_GL1Spacing = nullptr; + TH2 *h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing = nullptr; TH2 *h_Run3FEE_TriggerCount_GL1Spacing = nullptr; TH2 *h_ProcessPacket_Time = nullptr; From c2e3c3aef1b18971f2e40e52921c1889a2d2eff6 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 6 Jun 2026 22:45:23 -0400 Subject: [PATCH 608/866] recover tree deletion --- offline/framework/fun4allraw/TpcTimeFrameBuilder.cc | 2 +- offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index 0ae44cab32..e068899771 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -183,7 +183,7 @@ TpcTimeFrameBuilder::~TpcTimeFrameBuilder() delete m_packetTimer; - // delete m_digitalCurrentDebugTTree; + delete m_digitalCurrentDebugTTree; } void TpcTimeFrameBuilder::setVerbosity(const int i) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 3df533bd06..c9722bb69a 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -271,7 +271,7 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() delete m_packetTimer; - // delete m_digitalCurrentDebugTTree; + delete m_digitalCurrentDebugTTree; } void TpcTimeFrameBuilderRun3::setVerbosity(const int i) From 99e6726353940e635e0d3cd95fee174eda530457 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 Jun 2026 11:27:55 -0400 Subject: [PATCH 609/866] clang-tidy --- offline/packages/PHGarfield/GasModel.cc | 2 +- offline/packages/PHGarfield/MergeGasFiles.cc | 4 +- offline/packages/PHGarfield/PHGarfield.cc | 51 ++++++++++++++------ offline/packages/PHGarfield/PHGarfield.h | 2 +- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/offline/packages/PHGarfield/GasModel.cc b/offline/packages/PHGarfield/GasModel.cc index 34e52e1f94..5bf577be58 100644 --- a/offline/packages/PHGarfield/GasModel.cc +++ b/offline/packages/PHGarfield/GasModel.cc @@ -76,5 +76,5 @@ int main(int argc, char* argv[]) { Amin, Amax, nA); gas.GenerateGasTable(10); - gas.WriteGasFile(output_file.c_str()); + gas.WriteGasFile(output_file); } diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc index d515fc5462..1f86c9a54b 100644 --- a/offline/packages/PHGarfield/MergeGasFiles.cc +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -54,7 +54,6 @@ int main() return 1; } - int nFiles = 1; for (int i = 1; ; ++i) { const std::string file = filename(i); @@ -73,7 +72,6 @@ int main() return 1; } - ++nFiles; } // Don't write out since it crashes? @@ -93,7 +91,7 @@ int main() //double na=50; // Initialize using the current system time - TRandom3 Randy(time(0)); //new initialization each run + TRandom3 Randy(time(nullptr)); //new initialization each run cout << endl << endl << "Valid Calls: "<< endl; for (int i=0; i - #include "PHGarfield.h" #include "Garfield/ComponentUser.hh" @@ -51,9 +49,9 @@ using namespace std; using namespace findNode; using namespace Garfield; -PHGarfield::PHGarfield(const std::string &name) : SubsysReco(name) +PHGarfield::PHGarfield(const std::string &name) : SubsysReco(name), PHI_MIN(-M_PI) { - PHI_MIN = -M_PI; // Local handling of Phi valued that wrap around. + // Local handling of Phi valued that wrap around. } int PHGarfield::InitRun(PHCompositeNode *topNode) @@ -71,7 +69,7 @@ int PHGarfield::InitRun(PHCompositeNode *topNode) // Here we use the CDBInterface to set up the channel making of the TPC: std::string geofile = m_cdb->getUrl("Tracking_Geometry"); std::string text = m_cdb->getUrl("TPC_FEE_CHANNEL_MAP"); - m_cdbTPCMAPttree = new CDBTTree(text.c_str()); + m_cdbTPCMAPttree = new CDBTTree(text); m_cdbTPCMAPttree->LoadCalibrations(); // Make the Garfield Component and register the methods that will interface to our fields... @@ -114,7 +112,15 @@ void PHGarfield::FillRadii() void PHGarfield::PrintGarfield(double x, double y, double z) { - double ex, ey, ez, bx, by, bz, vx, vy, vz; + double ex; + double ey; + double ez; + double bx; + double by; + double bz; + double vx; + double vy; + double vz; GetElectricFieldVcm ( x, y, z, ex, ey, ez); GetMagneticFieldTesla( x, y, z, bx, by, bz); m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); @@ -238,7 +244,6 @@ void PHGarfield::InitializeGas(std::string dir) return; } - int nFiles = 1; for (int i = 1; ; ++i) { const std::string file = filename(i); @@ -257,7 +262,6 @@ void PHGarfield::InitializeGas(std::string dir) return; } - ++nFiles; } } @@ -276,8 +280,10 @@ double PHGarfield::bounder(double phi, double phi_min) { double phi_max = phi_min + 2.0*M_PI; - while (phi < phi_min) phi = phi + 2.0*M_PI; - while (phi >= phi_max) phi = phi - 2.0*M_PI; + while (phi < phi_min) { phi = phi + 2.0*M_PI; +} + while (phi >= phi_max) { phi = phi - 2.0*M_PI; +} return phi; } @@ -293,7 +299,15 @@ TPolyLine3D *PHGarfield::ReverseDrift (double x, double y, double z, double step ylist.push_back(y); zlist.push_back(z); - double ex, ey, ez, bx, by, bz, vx, vy, vz; + double ex; + double ey; + double ez; + double bx; + double by; + double bz; + double vx; + double vy; + double vz; double zPrevious = z; while (!StopHere(x,y,z,zPrevious)) @@ -326,13 +340,18 @@ bool PHGarfield::StopHere(const double x, const double y, const double z, { const double r = std::hypot(x, y); - if (r < 18.0) return true; - if (r > 82.0) return true; - if (z > 120.0) return true; - if (z < -120.0) return true; + if (r < 18.0) { return true; +} + if (r > 82.0) { return true; +} + if (z > 120.0) { return true; +} + if (z < -120.0) { return true; +} // z crossed the central membrane. - if (z * zPrevious < 0.0) return true; + if (z * zPrevious < 0.0) { return true; +} return false; } diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index cf29805153..25abbc0eec 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -42,7 +42,7 @@ class PHGarfield : public SubsysReco // These are left in public namespace for easy plotting macros... // The user is encouraged to add more routine to fit their analysis goals... TPolyLine3D *ReverseDrift (double x_cm, double y_cm, double z_cm, double step_ns=50.0); // Drifts electrons from some initial point until they hit a detector boundary... - double radii[48]; // Radius on each layer just for test purposes...need to be cm! + double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! private: CDBInterface *m_cdb {nullptr}; // Access to all thiungs CDB... From b2b274d3bc53a742b1dadea98191702448aeb200 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 Jun 2026 11:28:12 -0400 Subject: [PATCH 610/866] clang-format --- offline/packages/PHGarfield/GasModel.cc | 38 +- offline/packages/PHGarfield/MergeGasFiles.cc | 335 ++++++++--------- offline/packages/PHGarfield/PHGarfield.cc | 343 +++++++++--------- offline/packages/PHGarfield/PHGarfield.h | 30 +- .../packages/PHGarfield/PHGarfieldLinkDef.h | 2 +- 5 files changed, 379 insertions(+), 369 deletions(-) diff --git a/offline/packages/PHGarfield/GasModel.cc b/offline/packages/PHGarfield/GasModel.cc index 5bf577be58..266af322d4 100644 --- a/offline/packages/PHGarfield/GasModel.cc +++ b/offline/packages/PHGarfield/GasModel.cc @@ -1,16 +1,16 @@ #include #include -#include "Garfield/MediumMagboltz.hh" #include "Garfield/ComponentUser.hh" -#include "Garfield/Sensor.hh" #include "Garfield/DriftLineRKF.hh" +#include "Garfield/MediumMagboltz.hh" +#include "Garfield/Sensor.hh" using namespace Garfield; using namespace std; //------------------------------------------------------------ -// This standalone executable makes gas calculations for +// This standalone executable makes gas calculations for // whatever mixture you specify and range of electric, // magnetic, and angle between values that you select. // TKH 5/27/2026 @@ -18,34 +18,35 @@ using namespace std; // //------------------------------------------------------------ -int main(int argc, char* argv[]) { - - if (argc != 11) { +int main(int argc, char* argv[]) +{ + if (argc != 11) + { std::cerr - << "Usage:\n" - << argv[0] - << " Emin Emax nE Bmin Bmax nB Amin Amax nA output_file_name\n\n" - << "Units:\n" - << " E: V/cm\n" - << " B: Tesla\n" - << " angle: radians\n"; + << "Usage:\n" + << argv[0] + << " Emin Emax nE Bmin Bmax nB Amin Amax nA output_file_name\n\n" + << "Units:\n" + << " E: V/cm\n" + << " B: Tesla\n" + << " angle: radians\n"; return 1; } const double Emin = std::atof(argv[1]); const double Emax = std::atof(argv[2]); - const int nE = std::atoi(argv[3]); + const int nE = std::atoi(argv[3]); const double Bmin = std::atof(argv[4]); const double Bmax = std::atof(argv[5]); - const int nB = std::atoi(argv[6]); + const int nB = std::atoi(argv[6]); const double Amin = std::atof(argv[7]); const double Amax = std::atof(argv[8]); - const int nA = std::atoi(argv[9]); + const int nA = std::atoi(argv[9]); const string output_file(argv[10]); - + std::cout << "E grid: " << Emin << " -> " << Emax << " with " << nE << " points\n"; @@ -60,7 +61,6 @@ int main(int argc, char* argv[]) { std::cout << "Output File: " << output_file << endl; - // ------------------------------------------------------------ // Gas: Ar/CF4/isobutane = 75/20/5. // ------------------------------------------------------------ @@ -74,7 +74,7 @@ int main(int argc, char* argv[]) { gas.SetFieldGrid(Emin, Emax, nE, LogGrid, Bmin, Bmax, nB, Amin, Amax, nA); - + gas.GenerateGasTable(10); gas.WriteGasFile(output_file); } diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc index 1f86c9a54b..67638be809 100644 --- a/offline/packages/PHGarfield/MergeGasFiles.cc +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -1,12 +1,12 @@ +#include +#include +#include #include #include #include -#include -#include -#include -#include #include +#include #include "Garfield/MediumMagboltz.hh" @@ -14,11 +14,10 @@ using namespace std; int main() { - // This is a utility to test whether the process of "merging" files is actually different from a single file. // It may be of no further use afterthe development was complete. // TKH 6/2/2026 - int nValid=10000; + int nValid = 10000; TNtuple *Validity = new TNtuple("Validity", "Validity", "Valid:e:b:a:Vxerr:Vyerr:Vzerr"); // New version chooses to NOT write output to a file (which seems broken), @@ -36,186 +35,188 @@ int main() const std::string first = filename(0); if (!std::filesystem::exists(first)) - { - std::cerr << "Missing first gas file: " << first << std::endl; - return 1; - } + { + std::cerr << "Missing first gas file: " << first << std::endl; + return 1; + } if (!gas.LoadGasFile(first)) - { - std::cerr << "Failed to load " << first << std::endl; - return 1; - } + { + std::cerr << "Failed to load " << first << std::endl; + return 1; + } // Gas 0 only loads the FIRST file. This will test the memory validity of the merge... if (!gas0.LoadGasFile(first)) + { + std::cerr << "Failed to load " << first << std::endl; + return 1; + } + + for (int i = 1;; ++i) + { + const std::string file = filename(i); + + if (!std::filesystem::exists(file)) { - std::cerr << "Failed to load " << first << std::endl; - return 1; + std::cout << "Stopping at first missing file: " << file << std::endl; + break; } - for (int i = 1; ; ++i) + std::cout << "Merging " << file << std::endl; + + if (!gas.MergeGasFile(file, true)) { - const std::string file = filename(i); - - if (!std::filesystem::exists(file)) - { - std::cout << "Stopping at first missing file: " << file << std::endl; - break; - } - - std::cout << "Merging " << file << std::endl; - - if (!gas.MergeGasFile(file, true)) - { - std::cerr << "Failed to merge " << file << std::endl; - return 1; - } - + std::cerr << "Failed to merge " << file << std::endl; + return 1; } + } // Don't write out since it crashes? - //gas.WriteGasFile("test.gas"); + // gas.WriteGasFile("test.gas"); // Now perform the validation test... - double emin=400; - double emax=400; - //double ne=1; + double emin = 400; + double emax = 400; + // double ne=1; - double bmin=1.15; - double bmax=1.45; - double nb=50; + double bmin = 1.15; + double bmax = 1.45; + double nb = 50; - double amin=0.0; - double amax=0.2; - //double na=50; + double amin = 0.0; + double amax = 0.2; + // double na=50; // Initialize using the current system time - TRandom3 Randy(time(nullptr)); //new initialization each run - cout << endl << endl << "Valid Calls: "<< endl; - for (int i=0; iFill(1,sqrt(ex*ex + ey*ey + ez*ez),sqrt(bx*bx + by*by + bz*bz),a,DelVx, DelVy, DelVz); - } - - cout << endl << endl << "Invalid Calls: "<< endl; - for (int i=0; iFill(0,sqrt(ex*ex + ey*ey + ez*ez),sqrt(bx*bx + by*by + bz*bz),a,DelVx, DelVy, DelVz); - } - - - TFile *output= new TFile("GarfieldValidity.root","RECREATE"); + TRandom3 Randy(time(nullptr)); // new initialization each run + cout << endl + << endl + << "Valid Calls: " << endl; + for (int i = 0; i < nValid; i++) + { + double eMag = Randy.Uniform(emin, emax); + double bMag = Randy.Uniform(bmin, bmin + 0.2 * (bmax - bmin) / nb); // Comes from file0... + double a = Randy.Uniform(amin, amax); + double PHI = Randy.Uniform(0.0, 2.0 * TMath::Pi()); + + double ex = 0; + double ey = 0; + double ez = eMag; + + double bx = bMag * sin(a) * cos(PHI); + double by = bMag * sin(a) * sin(PHI); + double bz = bMag * cos(a); + + double vx; + double vy; + double vz; + + double vx0; + double vy0; + double vz0; + + gas.ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); + gas0.ElectronVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0); + + /* + cout << " i:" <Fill(1, sqrt(ex * ex + ey * ey + ez * ez), sqrt(bx * bx + by * by + bz * bz), a, DelVx, DelVy, DelVz); + } + + cout << endl + << endl + << "Invalid Calls: " << endl; + for (int i = 0; i < nValid; i++) + { + double eMag = Randy.Uniform(emin, emax); + double bMag = Randy.Uniform(bmin + 5.0 * (bmax - bmin) / nb, bmax); // Comes from beyond file0... + double a = Randy.Uniform(amin, amax); + double PHI = Randy.Uniform(0.0, 2.0 * TMath::Pi()); + + double ex = 0; + double ey = 0; + double ez = eMag; + + double bx = bMag * sin(a) * cos(PHI); + double by = bMag * sin(a) * sin(PHI); + double bz = bMag * cos(a); + + double vx; + double vy; + double vz; + double vx0; + double vy0; + double vz0; + gas.ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); + gas0.ElectronVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0); + /* + cout << " i:" <Fill(0, sqrt(ex * ex + ey * ey + ez * ez), sqrt(bx * bx + by * by + bz * bz), a, DelVx, DelVy, DelVz); + } + + TFile *output = new TFile("GarfieldValidity.root", "RECREATE"); Validity->Write(); output->Close(); - + return 0; } diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc index 70b3b71df1..30948adb9f 100644 --- a/offline/packages/PHGarfield/PHGarfield.cc +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -1,14 +1,14 @@ #include "PHGarfield.h" #include "Garfield/ComponentUser.hh" +#include "Garfield/DriftLineRKF.hh" #include "Garfield/MediumMagboltz.hh" #include "Garfield/Sensor.hh" -#include "Garfield/DriftLineRKF.hh" -#include #include -#include +#include #include +#include #include #include // for PHIODataNode @@ -23,22 +23,22 @@ #include #include -#include // for uint16_t -#include // for exit, size_t -#include // for basic_ostream, operat... +#include // for uint16_t +#include // for exit, size_t #include +#include // for basic_ostream, operat... -#include -#include -#include -#include +#include #include -#include #include -#include +#include +#include +#include +#include +#include -#include #include +#include #include #include @@ -49,23 +49,25 @@ using namespace std; using namespace findNode; using namespace Garfield; -PHGarfield::PHGarfield(const std::string &name) : SubsysReco(name), PHI_MIN(-M_PI) +PHGarfield::PHGarfield(const std::string& name) + : SubsysReco(name) + , PHI_MIN(-M_PI) { - // Local handling of Phi valued that wrap around. + // Local handling of Phi valued that wrap around. } -int PHGarfield::InitRun(PHCompositeNode *topNode) +int PHGarfield::InitRun(PHCompositeNode* topNode) { // Avoids the compiler error for having nore used the topNode. (void) topNode; - + std::cout << "PHGarfield::InitRun(PHCompositeNode *topNode) Initializing" << std::endl; m_cdb = CDBInterface::instance(); - + // Here we use the CDBInterface to set up the magnetic field map: std::string url = m_cdb->getUrl("FIELDMAP_TRACKING"); m_field = new PHField3DCartesian(url, 1.0); - + // Here we use the CDBInterface to set up the channel making of the TPC: std::string geofile = m_cdb->getUrl("Tracking_Geometry"); std::string text = m_cdb->getUrl("TPC_FEE_CHANNEL_MAP"); @@ -74,43 +76,44 @@ int PHGarfield::InitRun(PHCompositeNode *topNode) // Make the Garfield Component and register the methods that will interface to our fields... m_component = new Garfield::ComponentUser(); - m_component->SetMagneticField([this](double x, double y, double z,double& bx, double& by, double& bz) { GetMagneticFieldTesla(x, y, z, bx, by, bz); }); - m_component->SetElectricField([this](double x, double y, double z,double& ex, double& ey, double& ez) { GetElectricFieldVcm (x, y, z, ex, ey, ez); }); + m_component->SetMagneticField([this](double x, double y, double z, double& bx, double& by, double& bz) + { GetMagneticFieldTesla(x, y, z, bx, by, bz); }); + m_component->SetElectricField([this](double x, double y, double z, double& ex, double& ey, double& ez) + { GetElectricFieldVcm(x, y, z, ex, ey, ez); }); InitializeGas("/direct/phenix+u/workarea/hemmick/code.sphenix/tkh/gas/gasfiles/"); - + // Diagnostic during code development... FillRadii(); // PrintMaps(); - + return Fun4AllReturnCodes::EVENT_OK; } void PHGarfield::FillRadii() { // Unload the pad map to get the radii in a handy location: - for (unsigned int side=0; side<2; side++) + for (unsigned int side = 0; side < 2; side++) + { + for (unsigned int sector = 0; sector < 12; sector++) { - for (unsigned int sector=0; sector<12; sector++) - { - for (unsigned int fee=0; fee<26; fee++) - { - for (unsigned int channel=0; channel<256; channel++) - { - unsigned int key = (256 * (fee)) + channel; - int layer = m_cdbTPCMAPttree->GetIntValue (key, "layer"); - double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R")/CLHEP::cm; - if (layer > 6) - { - radii[layer-7] = r; - } - } - } - } + for (unsigned int fee = 0; fee < 26; fee++) + { + for (unsigned int channel = 0; channel < 256; channel++) + { + unsigned int key = (256 * (fee)) + channel; + int layer = m_cdbTPCMAPttree->GetIntValue(key, "layer"); + double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R") / CLHEP::cm; + if (layer > 6) + { + radii[layer - 7] = r; + } + } + } } - + } } - void PHGarfield::PrintGarfield(double x, double y, double z) +void PHGarfield::PrintGarfield(double x, double y, double z) { double ex; double ey; @@ -121,8 +124,8 @@ void PHGarfield::FillRadii() double vx; double vy; double vz; - GetElectricFieldVcm ( x, y, z, ex, ey, ez); - GetMagneticFieldTesla( x, y, z, bx, by, bz); + GetElectricFieldVcm(x, y, z, ex, ey, ez); + GetMagneticFieldTesla(x, y, z, bx, by, bz); m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); cout << " x:" << x << " y:" << y @@ -142,49 +145,48 @@ void PHGarfield::FillRadii() void PHGarfield::PrintMaps() { // Print out a few test points of the Garfield information - PrintGarfield(0.0, 0.0, 0.1); - PrintGarfield(0.0, 0.0, 100.0); + PrintGarfield(0.0, 0.0, 0.1); + PrintGarfield(0.0, 0.0, 100.0); PrintGarfield(0.0, 40.0, 100.1); PrintGarfield(0.0, 78.0, 010.1); - + // Print out the pad coordinate map: int MAX = 10; int prints = 0; - for (unsigned int side=0; side<2; side++) + for (unsigned int side = 0; side < 2; side++) + { + for (unsigned int sector = 0; sector < 12; sector++) { - for (unsigned int sector=0; sector<12; sector++) - { - for (unsigned int fee=0; fee<26; fee++) - { - for (unsigned int channel=0; channel<256; channel++) - { - unsigned int key = (256 * (fee)) + channel; - int layer = m_cdbTPCMAPttree->GetIntValue (key, "layer"); - double phi = ((side == 1 ? 1 : -1) * (m_cdbTPCMAPttree->GetDoubleValue(key, "phi") - M_PI / 2.)) + ((sector % 12) * M_PI / 6); - double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R")/CLHEP::cm; - - phi = bounder(phi, PHI_MIN); - - if (layer > 6) - { - if (prints < MAX) - { - prints++; - cout << " side: " << side; - cout << " sector: " << sector; - cout << " fee: " << fee; - cout << " channel: " << channel; - cout << " layer: " << layer; - cout << " phi: " << phi; - cout << " r: " << r; - cout << endl; - } - } - } - } - } + for (unsigned int fee = 0; fee < 26; fee++) + { + for (unsigned int channel = 0; channel < 256; channel++) + { + unsigned int key = (256 * (fee)) + channel; + int layer = m_cdbTPCMAPttree->GetIntValue(key, "layer"); + double phi = ((side == 1 ? 1 : -1) * (m_cdbTPCMAPttree->GetDoubleValue(key, "phi") - M_PI / 2.)) + ((sector % 12) * M_PI / 6); + double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R") / CLHEP::cm; + + phi = bounder(phi, PHI_MIN); + + if (layer > 6) + { + if (prints < MAX) + { + prints++; + cout << " side: " << side; + cout << " sector: " << sector; + cout << " fee: " << fee; + cout << " channel: " << channel; + cout << " layer: " << layer; + cout << " phi: " << phi; + cout << " r: " << r; + cout << endl; + } + } + } + } } - + } } void PHGarfield::GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double& bx_t, double& by_t, double& bz_t) @@ -192,15 +194,14 @@ void PHGarfield::GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, do // NOTE: Garfield uses cm, V/cm, and Tesla. // CLHEP uses mm, V/mm, and kiloTesla // PHField3DCartesian follows the CLHEP conventions for magnetic fields. - + double point[4] = - { - x_cm * CLHEP::cm, - y_cm * CLHEP::cm, - z_cm * CLHEP::cm, - //(z_cm-20.0) * CLHEP::cm, - 0.0 - }; + { + x_cm * CLHEP::cm, + y_cm * CLHEP::cm, + z_cm * CLHEP::cm, + //(z_cm-20.0) * CLHEP::cm, + 0.0}; double bfield[3] = {0.0, 0.0, 0.0}; @@ -221,75 +222,76 @@ void PHGarfield::GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, doub ex_vcm = 0.0; ey_vcm = 0.0; ez_vcm = z_cm > 0 ? -400.0 : 400.0; - } void PHGarfield::InitializeGas(std::string dir) { // Create and fill the gas object so that we can trace particles through the gas... m_gas = new Garfield::MediumMagboltz(); - - auto filename = [&](const int i) { return dir + "/PART_" + std::to_string(i) + ".gas"; }; - + + auto filename = [&](const int i) + { return dir + "/PART_" + std::to_string(i) + ".gas"; }; + const std::string first = filename(0); if (!std::filesystem::exists(first)) - { - std::cerr << "Missing first gas file: " << first << std::endl; - return; - } - + { + std::cerr << "Missing first gas file: " << first << std::endl; + return; + } + if (!m_gas->LoadGasFile(first)) + { + std::cerr << "Failed to load " << first << std::endl; + return; + } + + for (int i = 1;; ++i) + { + const std::string file = filename(i); + + if (!std::filesystem::exists(file)) { - std::cerr << "Failed to load " << first << std::endl; - return; + std::cout << "Stopping at first missing file: " << file << std::endl; + break; } - - for (int i = 1; ; ++i) + + std::cout << "Merging " << file << std::endl; + + if (!m_gas->MergeGasFile(file, true)) { - const std::string file = filename(i); - - if (!std::filesystem::exists(file)) - { - std::cout << "Stopping at first missing file: " << file << std::endl; - break; - } - - std::cout << "Merging " << file << std::endl; - - if (!m_gas->MergeGasFile(file, true)) - { - std::cerr << "Failed to merge " << file << std::endl; - return; - } - + std::cerr << "Failed to merge " << file << std::endl; + return; } + } } -int PHGarfield::process_event(PHCompositeNode *topNode) -{ +int PHGarfield::process_event(PHCompositeNode* topNode) +{ // Avoids the compiler error for having nore used the topNode. (void) topNode; // Initial implementation doesn't do anything event-by-event. // Nonetheless, a future user might want do do something here... - + return Fun4AllReturnCodes::EVENT_OK; } double PHGarfield::bounder(double phi, double phi_min) { - - double phi_max = phi_min + 2.0*M_PI; - while (phi < phi_min) { phi = phi + 2.0*M_PI; -} - while (phi >= phi_max) { phi = phi - 2.0*M_PI; -} + double phi_max = phi_min + 2.0 * M_PI; + while (phi < phi_min) + { + phi = phi + 2.0 * M_PI; + } + while (phi >= phi_max) + { + phi = phi - 2.0 * M_PI; + } return phi; } - -TPolyLine3D *PHGarfield::ReverseDrift (double x, double y, double z, double step_ns) +TPolyLine3D* PHGarfield::ReverseDrift(double x, double y, double z, double step_ns) { vector xlist; vector ylist; @@ -298,7 +300,7 @@ TPolyLine3D *PHGarfield::ReverseDrift (double x, double y, double z, double step xlist.push_back(x); ylist.push_back(y); zlist.push_back(z); - + double ex; double ey; double ez; @@ -308,51 +310,60 @@ TPolyLine3D *PHGarfield::ReverseDrift (double x, double y, double z, double step double vx; double vy; double vz; - - double zPrevious = z; - while (!StopHere(x,y,z,zPrevious)) - { - zPrevious = z; - GetMagneticFieldTesla( x, y, z, bx, by, bz); - GetElectricFieldVcm ( x, y, z, ex, ey, ez); - m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); - - x = x - vx*step_ns; - y = y - vy*step_ns; - z = z - vz*step_ns; - - xlist.push_back(x); - ylist.push_back(y); - zlist.push_back(z); - } - TPolyLine3D *poly = new TPolyLine3D(xlist.size() - 1); - for (unsigned int i=0; iSetPoint(i,xlist[i], ylist[i], zlist[i]); - } + double zPrevious = z; + while (!StopHere(x, y, z, zPrevious)) + { + zPrevious = z; + GetMagneticFieldTesla(x, y, z, bx, by, bz); + GetElectricFieldVcm(x, y, z, ex, ey, ez); + m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); + + x = x - vx * step_ns; + y = y - vy * step_ns; + z = z - vz * step_ns; + + xlist.push_back(x); + ylist.push_back(y); + zlist.push_back(z); + } + + TPolyLine3D* poly = new TPolyLine3D(xlist.size() - 1); + for (unsigned int i = 0; i < xlist.size() - 1; i++) + { + poly->SetPoint(i, xlist[i], ylist[i], zlist[i]); + } return poly; } bool PHGarfield::StopHere(const double x, const double y, const double z, - const double zPrevious) + const double zPrevious) { const double r = std::hypot(x, y); - - if (r < 18.0) { return true; -} - if (r > 82.0) { return true; -} - if (z > 120.0) { return true; -} - if (z < -120.0) { return true; -} - + + if (r < 18.0) + { + return true; + } + if (r > 82.0) + { + return true; + } + if (z > 120.0) + { + return true; + } + if (z < -120.0) + { + return true; + } + // z crossed the central membrane. - if (z * zPrevious < 0.0) { return true; -} - + if (z * zPrevious < 0.0) + { + return true; + } + return false; } - diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index 25abbc0eec..2b8409a402 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -22,8 +22,7 @@ namespace Garfield { class ComponentUser; class MediumMagboltz; -} - +} // namespace Garfield class PHGarfield : public SubsysReco { @@ -41,27 +40,26 @@ class PHGarfield : public SubsysReco // These are left in public namespace for easy plotting macros... // The user is encouraged to add more routine to fit their analysis goals... - TPolyLine3D *ReverseDrift (double x_cm, double y_cm, double z_cm, double step_ns=50.0); // Drifts electrons from some initial point until they hit a detector boundary... - double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! - + TPolyLine3D *ReverseDrift(double x_cm, double y_cm, double z_cm, double step_ns = 50.0); // Drifts electrons from some initial point until they hit a detector boundary... + double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! + private: - CDBInterface *m_cdb {nullptr}; // Access to all thiungs CDB... - CDBTTree *m_cdbTPCMAPttree {nullptr}; // Locations of the pads from CDB... - PHField3DCartesian *m_field {nullptr}; // The stanards sPHENIX field holding container. - Garfield::ComponentUser *m_component {nullptr}; // This handles the interface of the electric and magnetic fields as handed to Garfield - Garfield::MediumMagboltz *m_gas {nullptr}; // This is the pre-tabulated gas properties required by Garfield... + CDBInterface *m_cdb{nullptr}; // Access to all thiungs CDB... + CDBTTree *m_cdbTPCMAPttree{nullptr}; // Locations of the pads from CDB... + PHField3DCartesian *m_field{nullptr}; // The stanards sPHENIX field holding container. + Garfield::ComponentUser *m_component{nullptr}; // This handles the interface of the electric and magnetic fields as handed to Garfield + Garfield::MediumMagboltz *m_gas{nullptr}; // This is the pre-tabulated gas properties required by Garfield... - void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double& bx_t, double& by_t, double& bz_t) ; // Feeds magnetic field to Garfield - void GetElectricFieldVcm (double x_cm, double y_cm, double z_cm, double& ex_vcm, double& ey_vcm, double& ez_vcm) ; // Feeds electric field to Garfield - void InitializeGas (std::string dir); + void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double &bx_t, double &by_t, double &bz_t); // Feeds magnetic field to Garfield + void GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double &ex_vcm, double &ey_vcm, double &ez_vcm); // Feeds electric field to Garfield + void InitializeGas(std::string dir); void FillRadii(); // These are utilities for a spot check of the overall routine: - //std::string calibdir; - //std::string m_DiodeContainerName; + // std::string calibdir; + // std::string m_DiodeContainerName; double bounder(double phi, double phi_min); double PHI_MIN; - }; #endif diff --git a/offline/packages/PHGarfield/PHGarfieldLinkDef.h b/offline/packages/PHGarfield/PHGarfieldLinkDef.h index 067f2f4576..07eccee133 100644 --- a/offline/packages/PHGarfield/PHGarfieldLinkDef.h +++ b/offline/packages/PHGarfield/PHGarfieldLinkDef.h @@ -1,5 +1,5 @@ #ifdef __CINT__ -#pragma link C++ class PHGarfield+ ; +#pragma link C++ class PHGarfield + ; #endif /* __CINT__ */ From c215d0ae46cbf9f1992d57213e1e506e22032873 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 Jun 2026 12:41:30 -0400 Subject: [PATCH 611/866] formatting and clang problems --- offline/packages/PHGarfield/GasModel.cc | 17 ++- offline/packages/PHGarfield/MergeGasFiles.cc | 120 +++++++++---------- offline/packages/PHGarfield/PHGarfield.cc | 53 ++++---- offline/packages/PHGarfield/PHGarfield.h | 2 +- 4 files changed, 92 insertions(+), 100 deletions(-) diff --git a/offline/packages/PHGarfield/GasModel.cc b/offline/packages/PHGarfield/GasModel.cc index 266af322d4..36bf18ad07 100644 --- a/offline/packages/PHGarfield/GasModel.cc +++ b/offline/packages/PHGarfield/GasModel.cc @@ -1,13 +1,10 @@ #include #include -#include "Garfield/ComponentUser.hh" -#include "Garfield/DriftLineRKF.hh" -#include "Garfield/MediumMagboltz.hh" -#include "Garfield/Sensor.hh" - -using namespace Garfield; -using namespace std; +#include +#include +#include +#include //------------------------------------------------------------ // This standalone executable makes gas calculations for @@ -45,7 +42,7 @@ int main(int argc, char* argv[]) const double Amax = std::atof(argv[8]); const int nA = std::atoi(argv[9]); - const string output_file(argv[10]); + const std::string output_file(argv[10]); std::cout << "E grid: " << Emin << " -> " << Emax @@ -59,12 +56,12 @@ int main(int argc, char* argv[]) << Amin << " -> " << Amax << " with " << nA << " points\n"; - std::cout << "Output File: " << output_file << endl; + std::cout << "Output File: " << output_file << std::endl; // ------------------------------------------------------------ // Gas: Ar/CF4/isobutane = 75/20/5. // ------------------------------------------------------------ - MediumMagboltz gas; + Garfield::MediumMagboltz gas; gas.SetComposition("ar", 75., "cf4", 20., "isobutane", 5.); gas.SetTemperature(301.65); // K from Grafana gas.SetPressure(762.); // Torr from Grafana diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc index 67638be809..92d60a922a 100644 --- a/offline/packages/PHGarfield/MergeGasFiles.cc +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -8,9 +8,8 @@ #include #include -#include "Garfield/MediumMagboltz.hh" +#include -using namespace std; int main() { @@ -23,7 +22,6 @@ int main() // New version chooses to NOT write output to a file (which seems broken), // but to instead just tries to merge the files and validate the copy in memory. const std::string dir = "gasfiles"; - const std::string out = "Ar75_CF20_iso5.gas"; auto filename = [&](const int i) { @@ -90,9 +88,9 @@ int main() // Initialize using the current system time TRandom3 Randy(time(nullptr)); // new initialization each run - cout << endl - << endl - << "Valid Calls: " << endl; + std::cout << std::endl + << std::endl + << "Valid Calls: " << std::endl; for (int i = 0; i < nValid; i++) { double eMag = Randy.Uniform(emin, emax); @@ -120,32 +118,32 @@ int main() gas0.ElectronVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0); /* - cout << " i:" <Fill(1, sqrt(ex * ex + ey * ey + ez * ez), sqrt(bx * bx + by * by + bz * bz), a, DelVx, DelVy, DelVz); } - cout << endl - << endl - << "Invalid Calls: " << endl; + std::cout << std::endl + << std::endl + << "Invalid Calls: " << std::endl; for (int i = 0; i < nValid; i++) { double eMag = Randy.Uniform(emin, emax); @@ -181,32 +179,32 @@ int main() gas.ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); gas0.ElectronVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0); /* - cout << " i:" < +#include +#include +#include #include #include @@ -45,10 +45,6 @@ #include #include -using namespace std; -using namespace findNode; -using namespace Garfield; - PHGarfield::PHGarfield(const std::string& name) : SubsysReco(name) , PHI_MIN(-M_PI) @@ -56,12 +52,12 @@ PHGarfield::PHGarfield(const std::string& name) // Local handling of Phi valued that wrap around. } -int PHGarfield::InitRun(PHCompositeNode* topNode) +int PHGarfield::InitRun(PHCompositeNode*) { - // Avoids the compiler error for having nore used the topNode. - (void) topNode; - + if(Verbosity() > 1) + { std::cout << "PHGarfield::InitRun(PHCompositeNode *topNode) Initializing" << std::endl; + } m_cdb = CDBInterface::instance(); // Here we use the CDBInterface to set up the magnetic field map: @@ -69,7 +65,6 @@ int PHGarfield::InitRun(PHCompositeNode* topNode) m_field = new PHField3DCartesian(url, 1.0); // Here we use the CDBInterface to set up the channel making of the TPC: - std::string geofile = m_cdb->getUrl("Tracking_Geometry"); std::string text = m_cdb->getUrl("TPC_FEE_CHANNEL_MAP"); m_cdbTPCMAPttree = new CDBTTree(text); m_cdbTPCMAPttree->LoadCalibrations(); @@ -84,8 +79,10 @@ int PHGarfield::InitRun(PHCompositeNode* topNode) // Diagnostic during code development... FillRadii(); - // PrintMaps(); - + if(Verbosity() > 1) + { + PrintMaps(); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -127,7 +124,7 @@ void PHGarfield::PrintGarfield(double x, double y, double z) GetElectricFieldVcm(x, y, z, ex, ey, ez); GetMagneticFieldTesla(x, y, z, bx, by, bz); m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); - cout << " x:" << x + std::cout << " x:" << x << " y:" << y << " z:" << z << " ex:" << ex @@ -139,7 +136,7 @@ void PHGarfield::PrintGarfield(double x, double y, double z) << " vx:" << vx << " vy:" << vy << " vz:" << vz - << endl; + << std::endl; } void PHGarfield::PrintMaps() @@ -173,14 +170,14 @@ void PHGarfield::PrintMaps() if (prints < MAX) { prints++; - cout << " side: " << side; - cout << " sector: " << sector; - cout << " fee: " << fee; - cout << " channel: " << channel; - cout << " layer: " << layer; - cout << " phi: " << phi; - cout << " r: " << r; - cout << endl; + std::cout << " side: " << side; + std::cout << " sector: " << sector; + std::cout << " fee: " << fee; + std::cout << " channel: " << channel; + std::cout << " layer: " << layer; + std::cout << " phi: " << phi; + std::cout << " r: " << r; + std::cout << std::endl; } } } @@ -293,9 +290,9 @@ double PHGarfield::bounder(double phi, double phi_min) TPolyLine3D* PHGarfield::ReverseDrift(double x, double y, double z, double step_ns) { - vector xlist; - vector ylist; - vector zlist; + std::vector xlist; + std::vector ylist; + std::vector zlist; xlist.push_back(x); ylist.push_back(y); diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index 2b8409a402..f8fe19b2ee 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -30,7 +30,7 @@ class PHGarfield : public SubsysReco PHGarfield(const std::string &name = "PHGarfield"); ~PHGarfield() override = default; - int InitRun(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *) override; int process_event(PHCompositeNode *topNode) override; bool StopHere(const double x, const double y, const double z, const double zPrevious); From 391555cfaf7c57ff55bb2425370a5e43ad072f9b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 Jun 2026 12:43:59 -0400 Subject: [PATCH 612/866] remove macros files --- .../PHGarfield/macros/GasModel_condor.job | 13 -- .../packages/PHGarfield/macros/StartScript.sh | 31 --- .../packages/PHGarfield/macros/TestFieldMap.C | 183 ------------------ 3 files changed, 227 deletions(-) delete mode 100644 offline/packages/PHGarfield/macros/GasModel_condor.job delete mode 100755 offline/packages/PHGarfield/macros/StartScript.sh delete mode 100644 offline/packages/PHGarfield/macros/TestFieldMap.C diff --git a/offline/packages/PHGarfield/macros/GasModel_condor.job b/offline/packages/PHGarfield/macros/GasModel_condor.job deleted file mode 100644 index 6f25606c19..0000000000 --- a/offline/packages/PHGarfield/macros/GasModel_condor.job +++ /dev/null @@ -1,13 +0,0 @@ -Universe = vanilla -getenv = True -Initialdir = /direct/phenix+u/workarea/hemmick/code.sphenix/tkh/gas -Executable = $(Initialdir)/StartScript.sh -Output = $(Initialdir)/out/hitset_AuAu_$(process).out -Error = $(Initialdir)/err/hitset_AuAu_$(process).err -Log = $(Initialdir)/log/hitset_AuAu_$(process).log -PeriodicHold = (NumJobStarts>=1 && JobStatus == 1) -request_memory = 4GB -Priority = 20 -job_lease_duration = 3600 -Arguments = $(process) -Queue 50 diff --git a/offline/packages/PHGarfield/macros/StartScript.sh b/offline/packages/PHGarfield/macros/StartScript.sh deleted file mode 100755 index ac90ced0dc..0000000000 --- a/offline/packages/PHGarfield/macros/StartScript.sh +++ /dev/null @@ -1,31 +0,0 @@ -#! /bin/bash -emin=400 -emax=400 -ne=1 - -bmin=1.15 -bmax=1.45 -nb=50 - -amin=0.0 -amax=0.2 -na=50 - -bnow=$(awk -v bmin="$bmin" \ - -v bmax="$bmax" \ - -v nb="$nb" \ - -v i="$1" \ -'BEGIN { - print bmin + (bmax - bmin) * i / nb -}') - -echo $bnow - -output="/direct/phenix+u/workarea/hemmick/code.sphenix/tkh/gas/gasfiles/PART_"$1".gas" - -echo $output - -echo GasModel $emin $emax $ne $bnow $bnow 1 $amin $amax $na $output -GasModel $emin $emax $ne $bnow $bnow 1 $amin $amax $na $output - -echo all done diff --git a/offline/packages/PHGarfield/macros/TestFieldMap.C b/offline/packages/PHGarfield/macros/TestFieldMap.C deleted file mode 100644 index 55021ca501..0000000000 --- a/offline/packages/PHGarfield/macros/TestFieldMap.C +++ /dev/null @@ -1,183 +0,0 @@ -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -R__LOAD_LIBRARY(libfun4all.so) -R__LOAD_LIBRARY(libfun4allutils.so) -R__LOAD_LIBRARY(libffamodules.so) -R__LOAD_LIBRARY(libfun4allraw.so) -R__LOAD_LIBRARY(libffarawmodules.so) -R__LOAD_LIBRARY(libcdbobjects.so) -R__LOAD_LIBRARY(libffamodules.so) -R__LOAD_LIBRARY(libPHGarfield.so) - -#define Nebdc 24 -#define Nserver 2 - -// Global namespace to assist drawing... -TPolyLine3D *npoly3[48]; -TPolyLine3D *spoly3[48]; -TPolyLine *npoly2[48]; -TPolyLine *spoly2[48]; -TGeoTube *tubby; -TCanvas *canny; -TCanvas *canny2; - -TBox *boxer1; -TBox *boxer2; - -void TestFieldMap() -{ - recoConsts* rc = recoConsts::instance(); - - rc->set_StringFlag("CDB_GLOBALTAG","FieldMapTest"); - rc->set_uint64Flag("TIMESTAMP",1); - - auto cdb = CDBInterface::instance(); - std::string url = cdb->getUrl("FIELDMAP_TRACKING"); - std::cout << "Field map URL:\n" << url << std::endl; - - Fun4AllServer *se = Fun4AllServer::instance(); - - Enable::QA = false; - Enable::CDB = true; - - // Register a whole slew of input managers... - // NOTE: This depends upon the requested files being in frog. Ribbit. - char nextinput[500]; - char nextfile[500]; - Fun4AllInputManager* in[Nebdc]; - for (unsigned int ebdc=0; ebdc<24; ebdc++) - { - for (unsigned int server=0; server<2; server++) - { - sprintf(nextinput,"ebdc%02d_%01d",ebdc,server); - //sprintf(nextfile,"DST_STREAMING_EVENT_ebdc%02d_%01d_run3line_laser_ana540_nocdbtag_v001-00064890-00000.root",ebdc,server); // Line Laser - sprintf(nextfile,"DST_STREAMING_EVENT_ebdc%02d_%01d_run3auau_ana514_nocdbtag_v001-00075570-00000.root",ebdc,server); // AuAu Zero Field - std::cout << nextfile << " " << nextinput << endl; - in[ebdc] = new Fun4AllDstInputManager(nextinput); - in[ebdc]->fileopen(nextfile); - se->registerInputManager(in[ebdc]); - } - } - - // Now register a flag handler because MAAABE it will make the CDB work correctly? - //SubsysReco *fh = new FlagHandler(); - //se->registerSubsystem(fh); - - // Register my analysis module. - PHGarfield *phg = new PHGarfield(); - se->registerSubsystem(phg); - - se->run(4); - - canny = new TCanvas("canny","canny",3000,2500); - canny2 = new TCanvas("canny2","canny2",3000,2500); - tubby = new TGeoTube("tubby",20,80,110); - - canny->cd(); - tubby->Draw(); - - canny2->cd(); - //gPad->DrawFrame(-150., -10., 150., 10.); - gPad->DrawFrame(-150., -100., 150., 100.); - boxer1 = new TBox(-102,20,102,78); - boxer1->Draw(); - boxer2 = new TBox(-102,-78,102,-20); - boxer2->Draw("same"); - - for (int i=0; i<48; i++) - { - canny->cd(); - npoly3[i] = phg->ReverseDrift(0,phg->radii[i],102); - npoly3[i]->SetLineColor(kRed); - npoly3[i]->SetLineWidth(3); - npoly3[i]->Draw("same"); - - canny2->cd(); - int N = npoly3[i]->GetN(); - float *p = npoly3[i]->GetP(); - float x[500]; - float y[500]; - float z[500]; - for (int j=0; jSetLineColor(kRed); - npoly2[i]->SetLineWidth(3); - npoly2[i]->Draw("Lsame"); - } - - for (int i=0; i<48; i++) - { - canny->cd(); - spoly3[i] = phg->ReverseDrift(0,phg->radii[i],-102); - spoly3[i]->SetLineColor(kCyan); - spoly3[i]->SetLineWidth(3); - spoly3[i]->Draw("same"); - - canny2->cd(); - int N = spoly3[i]->GetN(); - float *p = spoly3[i]->GetP(); - float x[500]; - float y[500]; - float z[500]; - for (int j=0; jSetLineColor(kCyan); - spoly2[i]->SetLineWidth(3); - spoly2[i]->Draw("Lsame"); - } - //se->dumpHistos("Looker.root"); -} From 3f7025659ac13cb1162e67635483be3a2af3e0e5 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 8 Jun 2026 13:41:19 -0400 Subject: [PATCH 613/866] name arg --- offline/packages/PHGarfield/PHGarfield.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc index 8b4038fb8e..2a6752c240 100644 --- a/offline/packages/PHGarfield/PHGarfield.cc +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -52,7 +52,7 @@ PHGarfield::PHGarfield(const std::string& name) // Local handling of Phi valued that wrap around. } -int PHGarfield::InitRun(PHCompositeNode*) +int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) { if(Verbosity() > 1) { From 6f71eb405aa24369a8d075a22214b0d7741be0ee Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Mon, 8 Jun 2026 14:49:36 -0400 Subject: [PATCH 614/866] Back to original try. No change in previous classes. And new v6 class that I uses. --- offline/packages/trackbase/Makefile.am | 3 + offline/packages/trackbase/TrkrCluster.h | 24 ++ offline/packages/trackbase/TrkrClusterv6.cc | 141 +++++++++ offline/packages/trackbase/TrkrClusterv6.h | 277 ++++++++++++++++++ .../packages/trackbase/TrkrClusterv6LinkDef.h | 5 + 5 files changed, 450 insertions(+) create mode 100644 offline/packages/trackbase/TrkrClusterv6.cc create mode 100644 offline/packages/trackbase/TrkrClusterv6.h create mode 100644 offline/packages/trackbase/TrkrClusterv6LinkDef.h diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index bcb0b81d96..3e10b1f173 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -115,6 +115,7 @@ pkginclude_HEADERS = \ TrkrClusterv3.h \ TrkrClusterv4.h \ TrkrClusterv5.h \ + TrkrClusterv6.h \ TrkrDefs.h \ TrkrHit.h \ TrkrHitSet.h \ @@ -187,6 +188,7 @@ ROOTDICTS = \ TrkrClusterv3_Dict.cc \ TrkrClusterv4_Dict.cc \ TrkrClusterv5_Dict.cc \ + TrkrClusterv6_Dict.cc \ TrkrHitSetContMvtxHelper_Dict.cc \ TrkrHitSetContMvtxHelperv1_Dict.cc \ TrkrHitSetContainer_Dict.cc \ @@ -273,6 +275,7 @@ libtrack_io_la_SOURCES = \ TrkrClusterv3.cc \ TrkrClusterv4.cc \ TrkrClusterv5.cc \ + TrkrClusterv6.cc \ TrkrDefs.cc \ TrkrHitSet.cc \ TrkrHitSetContMvtxHelper.cc \ diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 7fd091a527..0fdb36b6eb 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -79,6 +79,30 @@ class TrkrCluster : public PHObject virtual float getPhiError() const { return NAN; } virtual float getRPhiError() const { return NAN; } virtual float getZError() const { return NAN; } + virtual unsigned int getCenAdc() const { return UINT_MAX; } + virtual float getPadCen() const { return NAN; } + virtual float getTBinCen() const { return NAN; } + virtual float getPadMax() const { return NAN; } + virtual float getTBinMax() const { return NAN; } + virtual char getSLEdge() const { return std::numeric_limits::max(); } + virtual char getSREdge() const { return std::numeric_limits::max(); } + virtual char getTLEdge() const { return std::numeric_limits::max(); } + virtual char getTREdge() const { return std::numeric_limits::max(); } + virtual char getDLEdge() const { return std::numeric_limits::max(); } + virtual char getDREdge() const { return std::numeric_limits::max(); } + virtual char getHLEdge() const { return std::numeric_limits::max(); } + virtual char getHREdge() const { return std::numeric_limits::max(); } + virtual int getSLMix() const { return std::numeric_limits::max(); } + virtual int getSRMix() const { return std::numeric_limits::max(); } + virtual int getTLMix() const { return std::numeric_limits::max(); } + virtual int getTRMix() const { return std::numeric_limits::max(); } + virtual float getPhiBinLo() const { return NAN; } + virtual float getPhiBinHi() const { return NAN; } + virtual float getTBinLo() const { return NAN; } + virtual float getTBinHi() const { return NAN; } + virtual float getPadPhase() const { return NAN; } + virtual float getTBinPhase() const { return NAN; } + virtual float getRSize() const { return NAN; } /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} diff --git a/offline/packages/trackbase/TrkrClusterv6.cc b/offline/packages/trackbase/TrkrClusterv6.cc new file mode 100644 index 0000000000..4481a9828a --- /dev/null +++ b/offline/packages/trackbase/TrkrClusterv6.cc @@ -0,0 +1,141 @@ +/** + * @file trackbase/TrkrClusterv6.cc + * @author Ishan Goel + * @date May 2026 + * @brief Implementation of TrkrClusterv6 + */ +#include "TrkrClusterv6.h" + +#include +#include // for swap + +namespace +{ + // square convenience function + template + constexpr T square(const T& x) + { + return x * x; + } +} // namespace + +TrkrClusterv6::TrkrClusterv6() + : m_subsurfkey(TrkrDefs::SUBSURFKEYMAX) + , m_phierr(0) + , m_zerr(0) + , m_adc(0) + , m_maxadc(0) + , m_cenadc(0) + , m_padcen(0) + , m_tbincen(0) + , m_padmax(0) + , m_tbinmax(0) + , m_rsize(0) + , m_phisize(0) + , m_zsize(0) + , m_overlap(0) + , m_edge(0) + , m_sledge(0) + , m_sredge(0) + , m_tledge(0) + , m_tredge(0) + , m_dledge(0) + , m_dredge(0) + , m_hledge(0) + , m_hredge(0) + , m_slmix(0) + , m_srmix(0) + , m_tlmix(0) + , m_trmix(0) + , m_phibinlo(0) + , m_phibinhi(0) + , m_tbinlo(0) + , m_tbinhi(0) + , m_padphase(0) + , m_tbinphase(0) +{ + for (float& i : m_local) + { + i = NAN; + } +} + +void TrkrClusterv6::identify(std::ostream& os) const +{ + os << "---TrkrClusterv6--------------------" << std::endl; + + os << " (rphi,z) = (" << getLocalX(); + os << ", " << getLocalY() << ") cm "; + + os << " valid = " << isValid() << std::endl; + + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int TrkrClusterv6::isValid() const +{ + for (int i = 0; i < 2; ++i) + { + if (std::isnan(getPosition(i))) + { + return 0; + } + } + if (m_adc == 0xFFFF) + { + return 0; + } + + return 1; +} + +void TrkrClusterv6::CopyFrom(const TrkrCluster& source) +{ + // do nothing if copying onto oneself + if (this == &source) + { + return; + } + + // parent class method + TrkrCluster::CopyFrom(source); + + setLocalX(source.getLocalX()); + setLocalY(source.getLocalY()); + setSubSurfKey(source.getSubSurfKey()); + setAdc(source.getAdc()); + setMaxAdc(source.getMaxAdc()); + setCenAdc(source.getCenAdc()); + setPadCen(source.getPadCen()); + setTBinCen(source.getTBinCen()); + setPadMax(source.getPadMax()); + setTBinMax(source.getTBinMax()); + setPhiError(source.getRPhiError()); + setZError(source.getZError()); + setRSize(source.getRSize()); + setPhiSize(source.getPhiSize()); + setZSize(source.getZSize()); + setOverlap(source.getOverlap()); + setEdge(source.getEdge()); + setSLEdge(source.getSLEdge()); + setSREdge(source.getSREdge()); + setTLEdge(source.getTLEdge()); + setTREdge(source.getTREdge()); + setDLEdge(source.getDLEdge()); + setDREdge(source.getDREdge()); + setHLEdge(source.getHLEdge()); + setHREdge(source.getHREdge()); + setSLMix(source.getSLMix()); + setSRMix(source.getSRMix()); + setTLMix(source.getTLMix()); + setTRMix(source.getTRMix()); + setPhiBinLo(source.getPhiBinLo()); + setPhiBinHi(source.getPhiBinHi()); + setTBinLo(source.getTBinLo()); + setTBinHi(source.getTBinHi()); + setPadPhase(source.getPadPhase()); + setTBinPhase(source.getTBinPhase()); +} diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h new file mode 100644 index 0000000000..7e34f31b71 --- /dev/null +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -0,0 +1,277 @@ +/** + * @file trackbase/TrkrClusterv6.h + * @author Ishan Goel + * @date May 2026 + * @brief Version 6 of TrkrCluster + */ +#ifndef TRACKBASE_TRKRCLUSTERV6_H +#define TRACKBASE_TRKRCLUSTERV6_H + +#include "TrkrCluster.h" +#include "TrkrDefs.h" + +#include +#include + +class PHObject; + +/** + * @brief Version 6 of TrkrCluster + * + * This version of TrkrCluster is blown up to contain a maximum of information + */ + +class TrkrClusterv6 : public TrkrCluster +{ + public: + //! ctor + TrkrClusterv6(); + + //! dtor + ~TrkrClusterv6() override = default; + + // PHObject virtual overloads + + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = TrkrClusterv6(); } + int isValid() const override; + PHObject* CloneMe() const override { return new TrkrClusterv6(*this); } + + //! import PHObject CopyFrom, in order to avoid clang warning + using PHObject::CopyFrom; + + //! copy content from base class + void CopyFrom(const TrkrCluster&) override; + + //! copy content from base class + void CopyFrom(TrkrCluster* source) override + { + if (!source) + { + return; + } + CopyFrom(*source); + } + + // + // cluster position + // + float getPosition(int coor) const override + { + return (coor >= 0 && coor < 2) ? m_local[coor] : NAN; + } + void setPosition(int coor, float xi) override + { + if (coor >= 0 && coor < 2) + { + m_local[coor] = xi; + } + } + float getLocalX() const override { return m_local[0]; } + void setLocalX(float loc0) override { m_local[0] = loc0; } + float getLocalY() const override { return m_local[1]; } + void setLocalY(float loc1) override { m_local[1] = loc1; } + + TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } + void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + + // + // cluster info + // + unsigned int getAdc() const override { return m_adc; } + void setAdc(unsigned int adc) override { m_adc = adc; } + + unsigned int getMaxAdc() const override { return m_maxadc; } + void setMaxAdc(uint16_t maxadc) override { m_maxadc = maxadc; } + + unsigned int getCenAdc() const override { return m_cenadc; } + void setCenAdc(uint16_t cenadc) { m_cenadc = cenadc; } + + float getPadCen() const override { return m_padcen; } + void setPadCen(float padcen) { m_padcen = padcen; } + + float getTBinCen() const override { return m_tbincen; } + void setTBinCen(float tbincen) { m_tbincen = tbincen; } + + float getPadMax() const override { return m_padmax; } + void setPadMax(float padmax) { m_padmax = padmax; } + + float getTBinMax() const override { return m_tbinmax; } + void setTBinMax(float tbinmax) { m_tbinmax = tbinmax; } + + // + // convenience interface + // + float getRPhiError() const override { return m_phierr; } + float getZError() const override { return m_zerr; } + + void setPhiError(float phierror) { m_phierr = phierror; } + void setZError(float zerror) { m_zerr = zerror; } + + /// deprecated global funtions with a warning + float getX() const override + { + std::cout << "Deprecated getx trkrcluster function!" << std::endl; + return NAN; + } + float getY() const override + { + std::cout << "Deprecated gety trkrcluster function!" << std::endl; + return NAN; + } + float getZ() const override + { + std::cout << "Deprecated getz trkrcluster function!" << std::endl; + return NAN; + } + void setX(float) override + { + std::cout << "Deprecated setx trkrcluster function!" << std::endl; + } + void setY(float) override + { + std::cout << "Deprecated sety trkrcluster function!" << std::endl; + } + void setZ(float) override + { + std::cout << "Deprecated setz trkrcluster function!" << std::endl; + } + float getSize(unsigned int, unsigned int) const override + { + std::cout << "Deprecated getsize trkrcluster function!" << std::endl; + return NAN; + } + void setSize(unsigned int, unsigned int, float) override + { + std::cout << "Deprecated setsize trkrcluster function!" << std::endl; + } + float getError(unsigned int, unsigned int) const override + { + std::cout << "Deprecated geterr trkrcluster function!" << std::endl; + return NAN; + } + void setError(unsigned int, unsigned int, float) override + { + std::cout << "Deprecated seterr trkrcluster function!" << std::endl; + } + + char getSize() const override { return m_phisize * m_zsize; } + // void setSize(char size) { m_size = size; } + + float getRSize() const override { return (float) m_rsize; } + void setRSize(unsigned char rsize) { m_rsize = rsize; } + + float getPhiSize() const override { return (float) m_phisize; } + void setPhiSize(char phisize) { m_phisize = phisize; } + + float getZSize() const override { return (float) m_zsize; } + void setZSize(char zsize) { m_zsize = zsize; } + + char getOverlap() const override { return m_overlap; } + void setOverlap(char overlap) override { m_overlap = overlap; } + + char getEdge() const override { return m_edge; } + void setEdge(char edge) override { m_edge = edge; } + + char getSLEdge() const override { return m_sledge; } + void setSLEdge(char sledge) { m_sledge = sledge; } + + char getSREdge() const override { return m_sredge; } + void setSREdge(char sredge) { m_sredge = sredge; } + + char getTLEdge() const override { return m_tledge; } + void setTLEdge(char tledge) { m_tledge = tledge; } + + char getTREdge() const override { return m_tredge; } + void setTREdge(char tredge) { m_tredge = tredge; } + + char getDLEdge() const override { return m_dledge; } + void setDLEdge(char dledge) { m_dledge = dledge; } + + char getDREdge() const override { return m_dredge; } + void setDREdge(char dredge) { m_dredge = dredge; } + + char getHLEdge() const override { return m_hledge; } + void setHLEdge(char hledge) { m_hledge = hledge; } + + char getHREdge() const override { return m_hredge; } + void setHREdge(char hredge) { m_hredge = hredge; } + + int getSLMix() const override { return m_slmix; } + void setSLMix(char slmix) { m_slmix = slmix; } + + int getSRMix() const override { return m_srmix; } + void setSRMix(char srmix) { m_srmix = srmix; } + + int getTLMix() const override { return m_tlmix; } + void setTLMix(char tlmix) { m_tlmix = tlmix; } + + int getTRMix() const override { return m_trmix; } + void setTRMix(char trmix) { m_trmix = trmix; } + + float getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(float phibinlo) { m_phibinlo = phibinlo; } + + float getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(float phibinhi) { m_phibinhi = phibinhi; } + + float getTBinLo() const override { return m_tbinlo; } + void setTBinLo(float tbinlo) { m_tbinlo = tbinlo; } + + float getTBinHi() const override { return m_tbinhi; } + void setTBinHi(float tbinhi) { m_tbinhi = tbinhi; } + + float getPadPhase() const override { return m_padphase; } + void setPadPhase(float padphase) { m_padphase = padphase; } + + float getTBinPhase() const override { return m_tbinphase; } + void setTBinPhase(float tbinphase){ m_tbinphase = tbinphase; } + + // float getPhiSize() const override + //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} + // float getZSize() const override + //{std::cout << "Deprecated size function" << std::endl; return NAN;} + // float getPhiError() const override + //{ std::cout << "Deprecated getPhiError function"<< std::endl; return NAN;} + + private: + float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + //< 2D local position [cm] 2 * 32 64bit - cumul 1*64 + TrkrDefs::subsurfkey m_subsurfkey; //< unique identifier for hitsetkey-surface maps 16 bit + float m_phierr; + float m_zerr; + unsigned short int m_adc; //< cluster sum adc 16 + unsigned short int m_maxadc; //< cluster max adc 16 + unsigned short int m_cenadc; //< cluster centroid adc 16 + float m_padcen; + float m_tbincen; + float m_padmax; + float m_tbinmax; + unsigned char m_rsize; // 8bit + char m_phisize; // 8bit + char m_zsize; // 8bit + char m_overlap; // 8bit + char m_edge; // 8bit - cumul 2*64 + char m_sledge; // 8bit + char m_sredge; // 8bit + char m_tledge; // 8bit + char m_tredge; // 8bit + char m_dledge; // 8bit + char m_dredge; // 8bit + char m_hledge; // 8bit + char m_hredge; // 8bit + char m_slmix; // 8bit + char m_srmix; // 8bit + char m_tlmix; // 8bit + char m_trmix; // 8bit + float m_phibinlo; + float m_phibinhi; + float m_tbinlo; + float m_tbinhi; + float m_padphase; + float m_tbinphase; + + ClassDefOverride(TrkrClusterv6, 1) +}; + +#endif // TRACKBASE_TRKRCLUSTERV6_H diff --git a/offline/packages/trackbase/TrkrClusterv6LinkDef.h b/offline/packages/trackbase/TrkrClusterv6LinkDef.h new file mode 100644 index 0000000000..936ec262cc --- /dev/null +++ b/offline/packages/trackbase/TrkrClusterv6LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TrkrClusterv6 + ; + +#endif From badf5c7fab8c9abd5f02f6ca80bef2620ab9759f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 8 Jun 2026 20:51:58 -0400 Subject: [PATCH 615/866] use initializers in class, remove depracted methods - the base class should take care of this --- offline/packages/trackbase/TrkrClusterv6.cc | 41 ------- offline/packages/trackbase/TrkrClusterv6.h | 124 ++++++-------------- 2 files changed, 35 insertions(+), 130 deletions(-) diff --git a/offline/packages/trackbase/TrkrClusterv6.cc b/offline/packages/trackbase/TrkrClusterv6.cc index 4481a9828a..e9ade93a08 100644 --- a/offline/packages/trackbase/TrkrClusterv6.cc +++ b/offline/packages/trackbase/TrkrClusterv6.cc @@ -19,47 +19,6 @@ namespace } } // namespace -TrkrClusterv6::TrkrClusterv6() - : m_subsurfkey(TrkrDefs::SUBSURFKEYMAX) - , m_phierr(0) - , m_zerr(0) - , m_adc(0) - , m_maxadc(0) - , m_cenadc(0) - , m_padcen(0) - , m_tbincen(0) - , m_padmax(0) - , m_tbinmax(0) - , m_rsize(0) - , m_phisize(0) - , m_zsize(0) - , m_overlap(0) - , m_edge(0) - , m_sledge(0) - , m_sredge(0) - , m_tledge(0) - , m_tredge(0) - , m_dledge(0) - , m_dredge(0) - , m_hledge(0) - , m_hredge(0) - , m_slmix(0) - , m_srmix(0) - , m_tlmix(0) - , m_trmix(0) - , m_phibinlo(0) - , m_phibinhi(0) - , m_tbinlo(0) - , m_tbinhi(0) - , m_padphase(0) - , m_tbinphase(0) -{ - for (float& i : m_local) - { - i = NAN; - } -} - void TrkrClusterv6::identify(std::ostream& os) const { os << "---TrkrClusterv6--------------------" << std::endl; diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 7e34f31b71..943addfdf8 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -25,7 +25,7 @@ class TrkrClusterv6 : public TrkrCluster { public: //! ctor - TrkrClusterv6(); + TrkrClusterv6() = default; //! dtor ~TrkrClusterv6() override = default; @@ -58,7 +58,7 @@ class TrkrClusterv6 : public TrkrCluster // float getPosition(int coor) const override { - return (coor >= 0 && coor < 2) ? m_local[coor] : NAN; + return (coor >= 0 && coor < 2) ? m_local[coor] : std::numeric_limits::quiet_NaN(); } void setPosition(int coor, float xi) override { @@ -108,53 +108,6 @@ class TrkrClusterv6 : public TrkrCluster void setPhiError(float phierror) { m_phierr = phierror; } void setZError(float zerror) { m_zerr = zerror; } - /// deprecated global funtions with a warning - float getX() const override - { - std::cout << "Deprecated getx trkrcluster function!" << std::endl; - return NAN; - } - float getY() const override - { - std::cout << "Deprecated gety trkrcluster function!" << std::endl; - return NAN; - } - float getZ() const override - { - std::cout << "Deprecated getz trkrcluster function!" << std::endl; - return NAN; - } - void setX(float) override - { - std::cout << "Deprecated setx trkrcluster function!" << std::endl; - } - void setY(float) override - { - std::cout << "Deprecated sety trkrcluster function!" << std::endl; - } - void setZ(float) override - { - std::cout << "Deprecated setz trkrcluster function!" << std::endl; - } - float getSize(unsigned int, unsigned int) const override - { - std::cout << "Deprecated getsize trkrcluster function!" << std::endl; - return NAN; - } - void setSize(unsigned int, unsigned int, float) override - { - std::cout << "Deprecated setsize trkrcluster function!" << std::endl; - } - float getError(unsigned int, unsigned int) const override - { - std::cout << "Deprecated geterr trkrcluster function!" << std::endl; - return NAN; - } - void setError(unsigned int, unsigned int, float) override - { - std::cout << "Deprecated seterr trkrcluster function!" << std::endl; - } - char getSize() const override { return m_phisize * m_zsize; } // void setSize(char size) { m_size = size; } @@ -227,49 +180,42 @@ class TrkrClusterv6 : public TrkrCluster float getTBinPhase() const override { return m_tbinphase; } void setTBinPhase(float tbinphase){ m_tbinphase = tbinphase; } - // float getPhiSize() const override - //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} - // float getZSize() const override - //{std::cout << "Deprecated size function" << std::endl; return NAN;} - // float getPhiError() const override - //{ std::cout << "Deprecated getPhiError function"<< std::endl; return NAN;} - private: float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; //< 2D local position [cm] 2 * 32 64bit - cumul 1*64 - TrkrDefs::subsurfkey m_subsurfkey; //< unique identifier for hitsetkey-surface maps 16 bit - float m_phierr; - float m_zerr; - unsigned short int m_adc; //< cluster sum adc 16 - unsigned short int m_maxadc; //< cluster max adc 16 - unsigned short int m_cenadc; //< cluster centroid adc 16 - float m_padcen; - float m_tbincen; - float m_padmax; - float m_tbinmax; - unsigned char m_rsize; // 8bit - char m_phisize; // 8bit - char m_zsize; // 8bit - char m_overlap; // 8bit - char m_edge; // 8bit - cumul 2*64 - char m_sledge; // 8bit - char m_sredge; // 8bit - char m_tledge; // 8bit - char m_tredge; // 8bit - char m_dledge; // 8bit - char m_dredge; // 8bit - char m_hledge; // 8bit - char m_hredge; // 8bit - char m_slmix; // 8bit - char m_srmix; // 8bit - char m_tlmix; // 8bit - char m_trmix; // 8bit - float m_phibinlo; - float m_phibinhi; - float m_tbinlo; - float m_tbinhi; - float m_padphase; - float m_tbinphase; + TrkrDefs::subsurfkey m_subsurfkey {TrkrDefs::SUBSURFKEYMAX}; //< unique identifier for hitsetkey-surface maps 16 bit + float m_phierr{0}; + float m_zerr{0}; + unsigned short int m_adc{0}; //< cluster sum adc 16 + unsigned short int m_maxadc{0}; //< cluster max adc 16 + unsigned short int m_cenadc{0}; //< cluster centroid adc 16 + float m_padcen{0}; + float m_tbincen{0}; + float m_padmax{0}; + float m_tbinmax{0}; + unsigned char m_rsize{0}; // 8bit + char m_phisize{0}; // 8bit + char m_zsize{0}; // 8bit + char m_overlap{0}; // 8bit + char m_edge{0}; // 8bit - cumul 2*64 + char m_sledge{0}; // 8bit + char m_sredge{0}; // 8bit + char m_tledge{0}; // 8bit + char m_tredge{0}; // 8bit + char m_dledge{0}; // 8bit + char m_dredge{0}; // 8bit + char m_hledge{0}; // 8bit + char m_hredge{0}; // 8bit + char m_slmix{0}; // 8bit + char m_srmix{0}; // 8bit + char m_tlmix{0}; // 8bit + char m_trmix{0}; // 8bit + float m_phibinlo{0}; + float m_phibinhi{0}; + float m_tbinlo{0}; + float m_tbinhi{0}; + float m_padphase{0}; + float m_tbinphase{0}; ClassDefOverride(TrkrClusterv6, 1) }; From c53fbbf0e43a56c7d184cc3e092d7e0163766bce Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Mon, 8 Jun 2026 21:08:33 -0400 Subject: [PATCH 616/866] handle coderabbitai complains --- offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 95ee3a472a..c941fcd046 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -36,6 +36,12 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase explicit TpcTimeFrameBuilderRun3(const int packet_id); ~TpcTimeFrameBuilderRun3() override; + // delete copy and move constructors and assignment operators to avoid unsafe copying + TpcTimeFrameBuilderRun3(const TpcTimeFrameBuilderRun3&) = delete; + TpcTimeFrameBuilderRun3& operator=(const TpcTimeFrameBuilderRun3&) = delete; + TpcTimeFrameBuilderRun3(TpcTimeFrameBuilderRun3&&) = delete; + TpcTimeFrameBuilderRun3& operator=(TpcTimeFrameBuilderRun3&&) = delete; + int ProcessPacket(Packet *) override; bool isMoreDataRequired(const uint64_t >m_bco) const override; void CleanupUsedPackets(const uint64_t &bclk) override; From 61086263d5c15673b4d043f9f505e2d0448ed619 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 9 Jun 2026 09:08:39 -0400 Subject: [PATCH 617/866] up verbosity --- offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index c9722bb69a..2bcb2d578c 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -903,7 +903,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g static_cast(fee), static_cast(fuzzy_hits)); - if (m_verbosity >= 1) + if (m_verbosity >= 2) { std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": Run3 fuzzy FEE-clock fallback for fee " << fee From 95f0073ffcaf5a2772ccd6ad67ec11fbe2787d19 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 9 Jun 2026 09:33:26 -0400 Subject: [PATCH 618/866] change NAN to numeric limits --- offline/packages/trackbase/TrkrCluster.h | 52 ++++++++++++------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 0fdb36b6eb..f37440646b 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -51,9 +51,9 @@ class TrkrCluster : public PHObject // // cluster position // - virtual float getLocalX() const { return NAN; } + virtual float getLocalX() const { return std::numeric_limits::quiet_NaN(); } virtual void setLocalX(float) {} - virtual float getLocalY() const { return NAN; } + virtual float getLocalY() const { return std::numeric_limits::quiet_NaN(); } virtual void setLocalY(float) {} // @@ -68,22 +68,22 @@ class TrkrCluster : public PHObject virtual char getEdge() const { return std::numeric_limits::max(); } virtual void setEdge(char) {} virtual void setTime(const float) {} - virtual float getTime() const { return NAN; } + virtual float getTime() const { return std::numeric_limits::quiet_NaN(); } virtual char getSize() const { return std::numeric_limits::max(); } // // convenience interface // - virtual float getPhiSize() const { return NAN; } - virtual float getZSize() const { return NAN; } - virtual float getPhiError() const { return NAN; } - virtual float getRPhiError() const { return NAN; } - virtual float getZError() const { return NAN; } + virtual float getPhiSize() const { return std::numeric_limits::quiet_NaN(); } + virtual float getZSize() const { return std::numeric_limits::quiet_NaN(); } + virtual float getPhiError() const { return std::numeric_limits::quiet_NaN(); } + virtual float getRPhiError() const { return std::numeric_limits::quiet_NaN(); } + virtual float getZError() const { return std::numeric_limits::quiet_NaN(); } virtual unsigned int getCenAdc() const { return UINT_MAX; } - virtual float getPadCen() const { return NAN; } - virtual float getTBinCen() const { return NAN; } - virtual float getPadMax() const { return NAN; } - virtual float getTBinMax() const { return NAN; } + virtual float getPadCen() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinCen() const { return std::numeric_limits::quiet_NaN(); } + virtual float getPadMax() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinMax() const { return std::numeric_limits::quiet_NaN(); } virtual char getSLEdge() const { return std::numeric_limits::max(); } virtual char getSREdge() const { return std::numeric_limits::max(); } virtual char getTLEdge() const { return std::numeric_limits::max(); } @@ -96,36 +96,36 @@ class TrkrCluster : public PHObject virtual int getSRMix() const { return std::numeric_limits::max(); } virtual int getTLMix() const { return std::numeric_limits::max(); } virtual int getTRMix() const { return std::numeric_limits::max(); } - virtual float getPhiBinLo() const { return NAN; } - virtual float getPhiBinHi() const { return NAN; } - virtual float getTBinLo() const { return NAN; } - virtual float getTBinHi() const { return NAN; } - virtual float getPadPhase() const { return NAN; } - virtual float getTBinPhase() const { return NAN; } - virtual float getRSize() const { return NAN; } + virtual float getPhiBinLo() const { return std::numeric_limits::quiet_NaN(); } + virtual float getPhiBinHi() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinLo() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinHi() const { return std::numeric_limits::quiet_NaN(); } + virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } + virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} - virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return NAN; } + virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual TrkrDefs::subsurfkey getSubSurfKey() const { return TrkrDefs::SUBSURFKEYMAX; } virtual void setSubSurfKey(TrkrDefs::subsurfkey /*id*/) {} // Global coordinate functions are deprecated, use local // coordinate functions only - virtual float getX() const { return NAN; } + virtual float getX() const { return std::numeric_limits::quiet_NaN(); } virtual void setX(float) {} - virtual float getY() const { return NAN; } + virtual float getY() const { return std::numeric_limits::quiet_NaN(); } virtual void setY(float) {} - virtual float getZ() const { return NAN; } + virtual float getZ() const { return std::numeric_limits::quiet_NaN(); } virtual void setZ(float) {} - virtual float getPosition(int /*coor*/) const { return NAN; } + virtual float getPosition(int /*coor*/) const { return std::numeric_limits::quiet_NaN(); } virtual void setPosition(int /*coor*/, float /*xi*/) {} virtual void setGlobal() {} virtual void setLocal() {} virtual bool isGlobal() const { return true; } - virtual float getError(unsigned int /*i*/, unsigned int /*j*/) const { return NAN; } + virtual float getError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual void setError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} - virtual float getSize(unsigned int /*i*/, unsigned int /*j*/) const { return NAN; } + virtual float getSize(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual void setSize(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} protected: From e4b34e056ea03f3c17027d7e8a4e966b50fedc01 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 9 Jun 2026 10:24:40 -0400 Subject: [PATCH 619/866] improve speed --- offline/packages/trackreco/PHSimpleKFProp.cc | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/offline/packages/trackreco/PHSimpleKFProp.cc b/offline/packages/trackreco/PHSimpleKFProp.cc index f0cc26ecff..17ee057a4c 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.cc +++ b/offline/packages/trackreco/PHSimpleKFProp.cc @@ -242,7 +242,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) // copy seed clusters position into local map std::map trackClusPositions; std::transform(track->begin_cluster_keys(), track->end_cluster_keys(), std::inserter(trackClusPositions, trackClusPositions.end()), - [globalPositions](const auto& key) + [&globalPositions](const auto& key) { return std::make_pair(key, globalPositions.at(key)); }); /// Can't circle fit a seed with less than 3 clusters, skip it @@ -317,7 +317,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) // copy seed clusters position into local map std::map pretrackClusPositions; std::transform(pretrack.begin_cluster_keys(), pretrack.end_cluster_keys(), std::inserter(pretrackClusPositions, pretrackClusPositions.end()), - [globalPositions](const auto& key) + [&globalPositions](const auto& key) { return std::make_pair(key, globalPositions.at(key)); }); // fit seed @@ -892,8 +892,8 @@ bool PHSimpleKFProp::PropagateStep( // search for closest available cluster within window double query_pt[3] = {new_tx, new_ty, new_tz}; - std::vector index_out(1); - std::vector distance_out(1); + std::array index_out; + std::array distance_out; int n_results = _kdtrees[next_layer]->knnSearch(&query_pt[0], 1, index_out.data(), distance_out.data()); // if no results, then no cluster to add, but propagation is not necessarily done @@ -1230,11 +1230,6 @@ std::vector PHSimpleKFProp::PropagateTrack(TrackSeed* track, std::cout << std::endl; } - // get layer for each cluster - std::vector layers; - std::transform(ckeys.begin(), ckeys.end(), std::back_inserter(layers), [](const TrkrDefs::cluskey& key) - { return TrkrDefs::getLayer(key); }); - double old_phi = track_phi; unsigned int old_layer = TrkrDefs::getLayer(ckeys[0]); if (Verbosity() > 1) @@ -1371,7 +1366,7 @@ void PHSimpleKFProp::rejectAndPublishSeeds(std::vector& seeds, con PositionMap local; std::transform(seed.begin_cluster_keys(), seed.end_cluster_keys(), std::inserter(local, local.end()), - [positions](const auto& key) + [&positions](const auto& key) { return std::make_pair(key, positions.at(key)); }); TrackSeedHelper::circleFitByTaubin(&seed,local, 7, 55); TrackSeedHelper::lineFit(&seed,local, 7, 55); From 80c4695c3aaefc7668d2b049eaa1575de520015b Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 9 Jun 2026 14:16:23 -0400 Subject: [PATCH 620/866] add debug prints --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 300 ++++++++++++++++++ .../fun4allraw/TpcTimeFrameBuilderRun3.h | 30 ++ 2 files changed, 330 insertions(+) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 2bcb2d578c..bba68a8974 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -835,6 +835,45 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << std::endl; } + // Track initial buffer usage + if (m_verbosity >= 2) + { + size_t total_time_hits = 0; + size_t time_hit_map_buckets = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits += bucket.second.size(); + } + } + size_t total_gtm_bco_trig = 0; + size_t total_bco_ref_cand = 0; + size_t total_gtm_bco_trigger = 0; + size_t total_bco_matching = 0; + size_t total_orphans = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand += bco_info.get_bco_reference_candidate_list_size(); + total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching += bco_info.get_bco_matching_list_size(); + total_orphans += bco_info.get_orphans_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [INITIAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << " frames, m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets << " FEE-BCO buckets, " + << total_time_hits << " total hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig + << ", bco_ref_cand: " << total_bco_ref_cand + << ", gtm_trigger_map: " << total_gtm_bco_trigger + << ", bco_matching: " << total_bco_matching + << ", orphans: " << total_orphans << "]" + << std::endl; + } + auto inserted_frame = m_timeFrameMap.emplace(bclk_rollover_corrected, std::vector{}); auto frame_it = inserted_frame.first; std::vector& timeframe = frame_it->second; @@ -922,6 +961,39 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g cache_waveform_adc(h_Run3PreviousTimeFrameWaveformADC, timeframe); + // Track buffer usage after exact and fuzzy hit processing + if (m_verbosity >= 2) + { + size_t total_time_hits_post_exact_fuzzy = 0; + size_t time_hit_map_buckets_post_exact_fuzzy = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_post_exact_fuzzy += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_post_exact_fuzzy += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_post = 0; + size_t total_bco_ref_cand_post = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_post += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand_post += bco_info.get_bco_reference_candidate_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [AFTER EXACT/FUZZY] STL buffer usage - exact_hits: " << exact_hit_count + << ", fuzzy_hits: " << fallback_hit_count + << ", timeframe size: " << timeframe.size() + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_post_exact_fuzzy << " buckets, " + << total_time_hits_post_exact_fuzzy << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_post + << ", bco_ref_cand: " << total_bco_ref_cand_post << "]" + << std::endl; + } + size_t recovered_hit_count = 0; for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) { @@ -950,6 +1022,38 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << " later hit segments for gtm_bco: 0x" << std::hex << gtm_bco << std::dec << std::endl; } + // Track buffer usage after recovery + if (m_verbosity >= 2) + { + size_t total_time_hits_post_recovery = 0; + size_t time_hit_map_buckets_post_recovery = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_post_recovery += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_post_recovery += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_recovery = 0; + size_t total_bco_ref_cand_recovery = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_recovery += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand_recovery += bco_info.get_bco_reference_candidate_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [AFTER RECOVERY] STL buffer usage - timeframe size: " << timeframe.size() + << ", recovered_hits: " << recovered_hit_count + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_post_recovery << " buckets, " + << total_time_hits_post_recovery << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_recovery + << ", bco_ref_cand: " << total_bco_ref_cand_recovery << "]" + << std::endl; + } + if (timeframe.empty()) { if (m_verbosity >= 1) @@ -960,6 +1064,35 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ". m_timeHitMap size: " << time_hit_bucket_count() << std::endl; } + if (m_verbosity >= 1) + { + size_t total_time_hits_empty = 0; + size_t time_hit_map_buckets_empty = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_empty += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_empty += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_empty = 0; + size_t total_bco_ref_cand_empty = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_empty += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand_empty += bco_info.get_bco_reference_candidate_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [EMPTY-FRAME ERROR] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_empty << " buckets, " + << total_time_hits_empty << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_empty + << ", bco_ref_cand: " << total_bco_ref_cand_empty << "]" + << std::endl; + } + m_hNorm->Fill("Run3_TimeFrame_MatchFailed", 1); m_hNorm->Fill("GTM_TimeFrame_Unmatched", 1); cache_timeframe_qa(bclk_rollover_corrected, timeframe, exact_matched_fees); @@ -978,6 +1111,50 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g m_hNorm->Fill("GTM_TimeFrame_Matched_Hit_Sum", timeframe.size()); cache_timeframe_qa(bclk_rollover_corrected, timeframe, exact_matched_fees); m_UsedTimeFrameSet.push(bclk_rollover_corrected); + + // Track final buffer usage + if (m_verbosity >= 1) + { + size_t total_time_hits_final = 0; + size_t time_hit_map_buckets_final = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_final += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_final += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_final = 0; + size_t total_bco_ref_cand_final = 0; + size_t total_gtm_bco_trigger_final = 0; + size_t total_bco_matching_final = 0; + size_t total_orphans_final = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand_final += bco_info.get_bco_reference_candidate_list_size(); + total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching_final += bco_info.get_bco_matching_list_size(); + total_orphans_final += bco_info.get_orphans_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [FINAL] STL buffer usage - timeframe size: " << timeframe.size() + << ", exact_hits: " << exact_hit_count + << ", fuzzy_hits: " << fallback_hit_count + << ", recovered_hits: " << recovered_hit_count + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_final << " buckets, " + << total_time_hits_final << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_final + << ", bco_ref_cand: " << total_bco_ref_cand_final + << ", gtm_trigger_map: " << total_gtm_bco_trigger_final + << ", bco_matching: " << total_bco_matching_final + << ", orphans: " << total_orphans_final << "]" + << std::endl; + } + return timeframe; } @@ -1084,6 +1261,50 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) } m_packetTimer->restart(); + // Track initial buffer usage at start of ProcessPacket + if (m_verbosity >= 1) + { + size_t total_time_hits = 0; + size_t time_hit_map_buckets = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits += bucket.second.size(); + } + } + size_t total_fee_data = 0; + for (const auto& fee_data_deque : m_feeData) + { + total_fee_data += fee_data_deque.size(); + } + size_t total_gtm_bco_trig = 0; + size_t total_bco_ref_cand = 0; + size_t total_gtm_bco_trigger = 0; + size_t total_bco_matching = 0; + size_t total_orphans = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand += bco_info.get_bco_reference_candidate_list_size(); + total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching += bco_info.get_bco_matching_list_size(); + total_orphans += bco_info.get_orphans_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [INITIAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_feeData total: " << total_fee_data + << ", m_timeHitMap: " << time_hit_map_buckets << " buckets, " << total_time_hits << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig + << ", bco_ref_cand: " << total_bco_ref_cand + << ", gtm_trigger_map: " << total_gtm_bco_trigger + << ", bco_matching: " << total_bco_matching + << ", orphans: " << total_orphans << "]" + << std::endl; + } + // //remove after testing // ; // std::cout <<"packet->lValue(0, N_TAGGER) = "<lValue(0, "N_TAGGER")<= 1) + { + size_t total_time_hits_post = 0; + size_t time_hit_map_buckets_post = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_post += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_post += bucket.second.size(); + } + } + size_t total_fee_data_post = 0; + for (const auto& fee_data_deque : m_feeData) + { + total_fee_data_post += fee_data_deque.size(); + } + size_t total_gtm_bco_trig_post = 0; + size_t total_bco_ref_cand_post = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_post += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand_post += bco_info.get_bco_reference_candidate_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [AFTER DMA PROCESSING] STL buffer usage - m_feeData total: " << total_fee_data_post + << ", m_timeHitMap: " << time_hit_map_buckets_post << " buckets, " << total_time_hits_post << " hits" + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_post + << ", bco_ref_cand: " << total_bco_ref_cand_post << "]" + << std::endl; + } + // sanity check for the cached FEE-clock hit size for (size_t fee = 0; fee < m_timeHitMap.size(); ++fee) { @@ -1253,6 +1509,50 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) assert(h_ProcessPacket_Time); h_ProcessPacket_Time->Fill(call_count, m_packetTimer->elapsed()); + // Track final buffer usage at end of ProcessPacket + if (m_verbosity >= 1) + { + size_t total_time_hits_final = 0; + size_t time_hit_map_buckets_final = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_final += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_final += bucket.second.size(); + } + } + size_t total_fee_data_final = 0; + for (const auto& fee_data_deque : m_feeData) + { + total_fee_data_final += fee_data_deque.size(); + } + size_t total_gtm_bco_trig_final = 0; + size_t total_bco_ref_cand_final = 0; + size_t total_gtm_bco_trigger_final = 0; + size_t total_bco_matching_final = 0; + size_t total_orphans_final = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); + total_bco_ref_cand_final += bco_info.get_bco_reference_candidate_list_size(); + total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching_final += bco_info.get_bco_matching_list_size(); + total_orphans_final += bco_info.get_orphans_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [FINAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_feeData total: " << total_fee_data_final + << ", m_timeHitMap: " << time_hit_map_buckets_final << " buckets, " << total_time_hits_final << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_final + << ", bco_ref_cand: " << total_bco_ref_cand_final + << ", gtm_trigger_map: " << total_gtm_bco_trigger_final + << ", bco_matching: " << total_bco_matching_final + << ", orphans: " << total_orphans_final << "]" + << std::endl; + } + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index c941fcd046..cb94f4bcb5 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -218,6 +218,36 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! print gtm bco information void print_gtm_bco_information() const; + //! get size of m_gtm_bco_trig_list + size_t get_gtm_bco_trig_list_size() const + { + return m_gtm_bco_trig_list.size(); + } + + //! get size of m_bco_reference_candidate_list + size_t get_bco_reference_candidate_list_size() const + { + return m_bco_reference_candidate_list.size(); + } + + //! get size of m_gtm_bco_trigger_map + size_t get_gtm_bco_trigger_map_size() const + { + return m_gtm_bco_trigger_map.size(); + } + + //! get size of m_bco_matching_list + size_t get_bco_matching_list_size() const + { + return m_bco_matching_list.size(); + } + + //! get size of m_orphans + size_t get_orphans_size() const + { + return m_orphans.size(); + } + //@} //!@name modifiers From cd749ece73a6523f96b6400c44a1d4acb89b65ae Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 9 Jun 2026 14:17:33 -0400 Subject: [PATCH 621/866] retire unused m_orphans --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 157 ------------------ .../fun4allraw/TpcTimeFrameBuilderRun3.h | 9 - 2 files changed, 166 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index bba68a8974..109518e025 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -2739,157 +2739,6 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re return std::nullopt; } -// //___________________________________________________ -// std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_gtm_bco(uint32_t fee_bco) -// { -// if (verbosity() > 5) -// { -// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - entry: " -// << std::hex -// << "\t- fee_bco: 0x" << fee_bco -// << std::dec -// << "\t- is_verified(): " << (is_verified() ? "true" : "false") -// << std::endl; -// } - -// // make sure the bco matching is properly initialized -// if (!is_verified()) -// { -// return std::nullopt; -// } - -// assert(m_hNorm); -// m_hNorm->Fill("FindGTMBCO", 1); - -// // find matching gtm bco in map -// const auto bco_matching_iter = std::find_if( -// m_bco_matching_list.begin(), -// m_bco_matching_list.end(), -// [fee_bco](const m_fee_gtm_bco_matching_pair_t& pair) -// { return get_fee_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); - -// if (bco_matching_iter != m_bco_matching_list.end()) -// { -// m_hNorm->Fill("FindGTMBCOMatchedExisting", 1); -// assert(m_hFindGTMBCO_MatchedExisting_BCODiff); -// m_hFindGTMBCO_MatchedExisting_BCODiff->Fill(int64_t(fee_bco) - int64_t(bco_matching_iter->first)); - -// if (verbosity() > 3) -// { -// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - found existing FEE BCO: " -// << std::hex -// << "\t- fee_bco: 0x" << fee_bco -// << "\t- predicted: 0x" << bco_matching_iter->first -// << "\t- gtm_bco: 0x" << bco_matching_iter->second -// << std::dec -// << std::endl; -// } - -// return bco_matching_iter->second; -// } -// // find element for which predicted fee_bco matches fee_bco, within limit -// const auto iter = std::find_if( -// m_gtm_bco_trig_list.begin(), -// m_gtm_bco_trig_list.end(), -// [this, fee_bco](const uint64_t& gtm_bco) -// { return get_fee_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); - -// // check -// if (iter != m_gtm_bco_trig_list.end()) -// { -// const uint64_t gtm_bco = *iter; - -// m_hNorm->Fill("FindGTMBCOMatchedNew", 1); -// assert(m_hFindGTMBCO_MatchedNew_BCODiff); -// m_hFindGTMBCO_MatchedNew_BCODiff->Fill(int64_t(fee_bco) - int64_t(gtm_bco)); - -// if (verbosity() > 2) -// { -// if (auto opt_fee_bco = get_predicted_fee_bco(gtm_bco)) // check if optional exists -// { -// const uint32_t fee_bco_predicted = *opt_fee_bco; // get_predicted_fee_bco(gtm_bco).value(); -// const uint32_t fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco); - -// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - new GL1 match: " -// << std::hex -// << "\t- fee_bco: 0x" << fee_bco -// << "\t- predicted: 0x" << fee_bco_predicted -// << "\t- gtm_bco: 0x" << gtm_bco -// << std::dec -// << "\t- difference: " << fee_bco_diff -// << std::endl; -// } -// } -// // save fee_bco and gtm_bco matching in map -// m_bco_matching_list.emplace_back(fee_bco, gtm_bco); - -// // remove gtm bco from runing list -// m_gtm_bco_trig_list.erase(iter); - -// // // update clock adjustment not applied for non HEARTBEAT_T -// // update_multiplier_adjustment(gtm_bco, fee_bco); - -// return gtm_bco; -// } - -// m_hNorm->Fill("FindGTMBCOMatchedFailed", 1); - -// bool new_orphan = m_orphans.insert(fee_bco).second; - -// if ((new_orphan && verbosity()) || (verbosity() > 3)) -// { -// // find element for which predicted fee_bco is the closest to request -// const auto iter2 = std::min_element( -// m_gtm_bco_trig_list.begin(), -// m_gtm_bco_trig_list.end(), -// [this, fee_bco](const uint64_t& first, const uint64_t& second) -// { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); - -// // const int fee_bco_diff = (iter2 != m_gtm_bco_trig_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1; -// // compared to the previous statement, this checks if the optional -// int fee_bco_diff = -1; - -// if (iter2 != m_gtm_bco_trig_list.end()) -// { -// auto predicted = get_predicted_fee_bco(*iter2); - -// if (predicted) -// { -// fee_bco_diff = get_bco_diff(*predicted, fee_bco); -// } -// } - -// if (m_verbosity >= 2) -// { -// std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_gtm_bco - match failed!" -// << std::hex -// << "\t- fee_bco: 0x" << fee_bco -// << std::dec -// << "\t- gtm_bco: 0x" << *iter2 -// << "\t- difference: " << fee_bco_diff -// << std::endl; -// } -// } // if ((new_orphan and verbosity()) or (verbosity()>3)) - -// if (verbosity() > 3) -// { -// std::cout << "\t- m_gtm_bco_trig_list : " << std::endl; -// for (const auto& gtm_bco : m_gtm_bco_trig_list) -// { -// std::cout << "\t\t- 0x" << std::hex << gtm_bco << " -> 0x" << get_predicted_fee_bco(gtm_bco).value() << std::dec << std::endl; // NOLINT(bugprone-unchecked-optional-access) -// } - -// std::cout << "\t- m_bco_matching_list : " << std::endl; -// for (const auto& iter_m_bco_matching_list : m_bco_matching_list) -// { -// std::cout << "\t\t- 0x" << std::hex << iter_m_bco_matching_list.first << " -> 0x" << iter_m_bco_matching_list.second << std::dec << std::endl; -// } - -// } // if (verbosity()>3) - -// return std::nullopt; -// } - //___________________________________________________ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup() { @@ -2902,9 +2751,6 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup() { m_bco_matching_list.pop_front(); } - - // clear orphans - m_orphans.clear(); } //___________________________________________________ @@ -2923,9 +2769,6 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup(uint64_t ref_bco) return pair.second <= ref_bco; }), m_bco_matching_list.end()); - - // clear orphans - m_orphans.clear(); } void TpcTimeFrameBuilderRun3::fillBadFeeMap() diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index cb94f4bcb5..453d5cb68d 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -242,12 +242,6 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase return m_bco_matching_list.size(); } - //! get size of m_orphans - size_t get_orphans_size() const - { - return m_orphans.size(); - } - //@} //!@name modifiers @@ -372,9 +366,6 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase std::list m_bco_matching_list; - //! keep track or fee_bco for which no gtm_bco is found - std::set m_orphans; - // define limit for matching two lvl1 and EnDAT tagger BCOs static constexpr int m_max_lv1_endat_bco_diff = 16; From 13bfad28312a3047b723e3a90e9c20aa7eea5928 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Tue, 9 Jun 2026 14:20:44 -0400 Subject: [PATCH 622/866] debug and tuning --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 109518e025..3accbc70e3 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -852,14 +852,12 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g size_t total_bco_ref_cand = 0; size_t total_gtm_bco_trigger = 0; size_t total_bco_matching = 0; - size_t total_orphans = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); total_bco_ref_cand += bco_info.get_bco_reference_candidate_list_size(); total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching += bco_info.get_bco_matching_list_size(); - total_orphans += bco_info.get_orphans_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [INITIAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() @@ -870,7 +868,6 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ", bco_ref_cand: " << total_bco_ref_cand << ", gtm_trigger_map: " << total_gtm_bco_trigger << ", bco_matching: " << total_bco_matching - << ", orphans: " << total_orphans << "]" << std::endl; } @@ -1129,14 +1126,12 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g size_t total_bco_ref_cand_final = 0; size_t total_gtm_bco_trigger_final = 0; size_t total_bco_matching_final = 0; - size_t total_orphans_final = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); total_bco_ref_cand_final += bco_info.get_bco_reference_candidate_list_size(); total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching_final += bco_info.get_bco_matching_list_size(); - total_orphans_final += bco_info.get_orphans_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [FINAL] STL buffer usage - timeframe size: " << timeframe.size() @@ -1151,7 +1146,6 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ", bco_ref_cand: " << total_bco_ref_cand_final << ", gtm_trigger_map: " << total_gtm_bco_trigger_final << ", bco_matching: " << total_bco_matching_final - << ", orphans: " << total_orphans_final << "]" << std::endl; } @@ -1262,7 +1256,7 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) m_packetTimer->restart(); // Track initial buffer usage at start of ProcessPacket - if (m_verbosity >= 1) + if (m_verbosity >= 2) { size_t total_time_hits = 0; size_t time_hit_map_buckets = 0; @@ -1283,14 +1277,12 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) size_t total_bco_ref_cand = 0; size_t total_gtm_bco_trigger = 0; size_t total_bco_matching = 0; - size_t total_orphans = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); total_bco_ref_cand += bco_info.get_bco_reference_candidate_list_size(); total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching += bco_info.get_bco_matching_list_size(); - total_orphans += bco_info.get_orphans_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [INITIAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() @@ -1301,7 +1293,6 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) << ", bco_ref_cand: " << total_bco_ref_cand << ", gtm_trigger_map: " << total_gtm_bco_trigger << ", bco_matching: " << total_bco_matching - << ", orphans: " << total_orphans << "]" << std::endl; } @@ -1443,7 +1434,7 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) } // Track buffer usage after DMA word processing - if (m_verbosity >= 1) + if (m_verbosity >= 2) { size_t total_time_hits_post = 0; size_t time_hit_map_buckets_post = 0; @@ -1531,14 +1522,12 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) size_t total_bco_ref_cand_final = 0; size_t total_gtm_bco_trigger_final = 0; size_t total_bco_matching_final = 0; - size_t total_orphans_final = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); total_bco_ref_cand_final += bco_info.get_bco_reference_candidate_list_size(); total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching_final += bco_info.get_bco_matching_list_size(); - total_orphans_final += bco_info.get_orphans_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [FINAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() @@ -1549,7 +1538,6 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) << ", bco_ref_cand: " << total_bco_ref_cand_final << ", gtm_trigger_map: " << total_gtm_bco_trigger_final << ", bco_matching: " << total_bco_matching_final - << ", orphans: " << total_orphans_final << "]" << std::endl; } @@ -2076,7 +2064,7 @@ int TpcTimeFrameBuilderRun3::decode_gtm_data(const TpcTimeFrameBuilderRun3::dma_ payload.modebits = gtm[22]; payload.userbits = gtm[23]; - if (m_verbosity >= 2) + if (m_verbosity >= 1) { std::cout << __PRETTY_FUNCTION__ << "\t- GTM data : " << "\t- pkt_type = " << payload.pkt_type << std::endl From 582a0ad5a02094e41dd1f24258b1967de087f37a Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 9 Jun 2026 14:34:00 -0400 Subject: [PATCH 623/866] clarify p square cut --- simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc index 5b7da8e23c..1e118363b7 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc @@ -138,7 +138,8 @@ void SvtxTruthRecoTableEval::fillTruthRecoMaps(PHCompositeNode *topNode, SvtxTra const double pz = g4particle->get_pz(); const double momentum2 = px * px + py * py + pz * pz; - // only record particle above minimal momentum requirement. + // only record particle above minimal momentum (square) requirement. + // doing this saves us a slow sqrt operation to calculate the momentum itself if (momentum2 < minMomentumTruthMap2) { continue; From 81eca27d6334bbffe614f02e704837ada865e6ab Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 9 Jun 2026 15:56:23 -0400 Subject: [PATCH 624/866] clang-tidy --- offline/packages/trackreco/PHSimpleKFProp.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHSimpleKFProp.cc b/offline/packages/trackreco/PHSimpleKFProp.cc index 17ee057a4c..3e4d80d869 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.cc +++ b/offline/packages/trackreco/PHSimpleKFProp.cc @@ -892,8 +892,8 @@ bool PHSimpleKFProp::PropagateStep( // search for closest available cluster within window double query_pt[3] = {new_tx, new_ty, new_tz}; - std::array index_out; - std::array distance_out; + std::array index_out{}; + std::array distance_out{}; int n_results = _kdtrees[next_layer]->knnSearch(&query_pt[0], 1, index_out.data(), distance_out.data()); // if no results, then no cluster to add, but propagation is not necessarily done From 5d974c7f4af486ec02d84f2aecec3f13a0f188f6 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 9 Jun 2026 22:53:52 -0400 Subject: [PATCH 625/866] empty commit to trigger jenkins From baa4af35cce69362222152892d7984e8d82b9330 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 10 Jun 2026 09:57:12 -0400 Subject: [PATCH 626/866] limit caching for 1s in case of large GL1 trigger spacing jump --- offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc | 3 +++ offline/framework/fun4allraw/SingleTpcTimeFrameInput.h | 3 +++ offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 6 +++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index 6017e67ca7..35ded04e35 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -181,6 +181,9 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) // std::set saved_beamclocks; while (true) { + // clean up cache to avoid memory over usage when trigger jumped by a long time + CleanupUsedPackets(targetBCO - kUsedPacketsCachingLimit); + if (m_TpcTimeFrameBuilderMap.empty()) { if (Verbosity() > 1) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index b83cd99a6d..45210fa74e 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -46,6 +46,9 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput private: const int NTPCPACKETS = 3; + // in BCO, limit caching to 1 second worth of packets, to avoid memory over usage when trigger jumped by a long time + static constexpr uint64_t kUsedPacketsCachingLimit = 10000000; + Packet **plist{nullptr}; unsigned int m_NumSpecialEvents{0}; unsigned int m_BcoRange{0}; diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 3accbc70e3..cbb94f8178 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -1012,7 +1012,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } } - if (m_verbosity >= 1 && recovered_hit_count > 0) + if (m_verbosity >= 2 && recovered_hit_count > 0) { std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": Run3 truncated waveform recovery appended " << recovered_hit_count @@ -1110,7 +1110,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g m_UsedTimeFrameSet.push(bclk_rollover_corrected); // Track final buffer usage - if (m_verbosity >= 1) + if (m_verbosity >= 2) { size_t total_time_hits_final = 0; size_t time_hit_map_buckets_final = 0; @@ -2064,7 +2064,7 @@ int TpcTimeFrameBuilderRun3::decode_gtm_data(const TpcTimeFrameBuilderRun3::dma_ payload.modebits = gtm[22]; payload.userbits = gtm[23]; - if (m_verbosity >= 1) + if (m_verbosity >= 2) { std::cout << __PRETTY_FUNCTION__ << "\t- GTM data : " << "\t- pkt_type = " << payload.pkt_type << std::endl From ec23756bb8caf0b72cd55028706e9f340172470d Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 10 Jun 2026 09:59:58 -0400 Subject: [PATCH 627/866] verbosity check --- offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index cbb94f8178..a736e71214 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -1501,7 +1501,7 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) h_ProcessPacket_Time->Fill(call_count, m_packetTimer->elapsed()); // Track final buffer usage at end of ProcessPacket - if (m_verbosity >= 1) + if (m_verbosity >= 2) { size_t total_time_hits_final = 0; size_t time_hit_map_buckets_final = 0; From b065161a3642e29e46d89bccaae4d0b030abb080 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 10 Jun 2026 10:19:32 -0400 Subject: [PATCH 628/866] tie max caching window to FEE rollover --- offline/framework/fun4allraw/SingleTpcTimeFrameInput.h | 4 ++-- offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index 45210fa74e..3a2250b10b 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -46,8 +46,8 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput private: const int NTPCPACKETS = 3; - // in BCO, limit caching to 1 second worth of packets, to avoid memory over usage when trigger jumped by a long time - static constexpr uint64_t kUsedPacketsCachingLimit = 10000000; + // in BCO, limit caching to a quarter of FEE clock rollover or 7ms, to avoid memory over usage when trigger jumped by a long time + static constexpr uint64_t kUsedPacketsCachingLimit = (1<<20)/4/4; Packet **plist{nullptr}; unsigned int m_NumSpecialEvents{0}; diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index a736e71214..426611b255 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -1061,7 +1061,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ". m_timeHitMap size: " << time_hit_bucket_count() << std::endl; } - if (m_verbosity >= 1) + if (m_verbosity >= 2) { size_t total_time_hits_empty = 0; size_t time_hit_map_buckets_empty = 0; @@ -1157,7 +1157,9 @@ void TpcTimeFrameBuilderRun3::CleanupUsedPackets(const uint64_t& bclk) if (m_verbosity > 2) { std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": cleaning up bcos < 0x" << std::hex - << bclk << std::dec << std::endl; + << bclk << std::dec + << " and m_UsedTimeFrameSet size: " << m_UsedTimeFrameSet.size() + << std::endl; } while (!m_UsedTimeFrameSet.empty()) From bd113267254a3754b7718efe222573c69b054c81 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 10 Jun 2026 10:46:08 -0400 Subject: [PATCH 629/866] add method to return map sizes --- offline/database/cdbobjects/CDBTTree.cc | 8 ++++---- offline/database/cdbobjects/CDBTTree.h | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/offline/database/cdbobjects/CDBTTree.cc b/offline/database/cdbobjects/CDBTTree.cc index 6889dfacb1..67f66c61a9 100644 --- a/offline/database/cdbobjects/CDBTTree.cc +++ b/offline/database/cdbobjects/CDBTTree.cc @@ -230,7 +230,7 @@ void CDBTTree::WriteMultipleCDBTTree() void CDBTTree::SetSingleFloatValue(const std::string &name, float value) { std::string fieldname = "F" + name; -// if (!m_SingleFloatEntryMap.contains(fieldname)) + // if (!m_SingleFloatEntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleFloatEntryMap.find(fieldname) == m_SingleFloatEntryMap.end()) { @@ -249,7 +249,7 @@ void CDBTTree::SetSingleFloatValue(const std::string &name, float value) void CDBTTree::SetSingleDoubleValue(const std::string &name, double value) { std::string fieldname = "D" + name; -// if (!m_SingleDoubleEntryMap.contains(fieldname)) + // if (!m_SingleDoubleEntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleDoubleEntryMap.find(fieldname) == m_SingleDoubleEntryMap.end()) { @@ -268,7 +268,7 @@ void CDBTTree::SetSingleDoubleValue(const std::string &name, double value) void CDBTTree::SetSingleIntValue(const std::string &name, int value) { std::string fieldname = "I" + name; -// if (!m_SingleIntEntryMap.contains(fieldname)) + // if (!m_SingleIntEntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleIntEntryMap.find(fieldname) == m_SingleIntEntryMap.end()) { @@ -287,7 +287,7 @@ void CDBTTree::SetSingleIntValue(const std::string &name, int value) void CDBTTree::SetSingleUInt64Value(const std::string &name, uint64_t value) { std::string fieldname = "g" + name; -// if (m_SingleUInt64EntryMap.contains(fieldname)) + // if (m_SingleUInt64EntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleUInt64EntryMap.find(fieldname) == m_SingleUInt64EntryMap.end()) { diff --git a/offline/database/cdbobjects/CDBTTree.h b/offline/database/cdbobjects/CDBTTree.h index 0db6719f71..bf04a83ea1 100644 --- a/offline/database/cdbobjects/CDBTTree.h +++ b/offline/database/cdbobjects/CDBTTree.h @@ -30,14 +30,22 @@ class CDBTTree void Print(); void SetFilename(const std::string &fname) { m_Filename = fname; } void LoadCalibrations(); + float GetSingleFloatValue(const std::string &name, int verbose = 0); float GetFloatValue(int channel, const std::string &name, int verbose = 0); + size_t GetFloatMapSize() const { return m_FloatEntryMap.size(); } + double GetSingleDoubleValue(const std::string &name, int verbose = 0); double GetDoubleValue(int channel, const std::string &name, int verbose = 0); + size_t GetDoubleMapSize() const { return m_DoubleEntryMap.size(); } + int GetSingleIntValue(const std::string &name, int verbose = 0); int GetIntValue(int channel, const std::string &name, int verbose = 0); + size_t GetIntMapSize() const { return m_IntEntryMap.size(); } + uint64_t GetSingleUInt64Value(const std::string &name, int verbose = 0); uint64_t GetUInt64Value(int channel, const std::string &name, int verbose = 0); + size_t GetUInt64MapSize() const { return m_UInt64EntryMap.size(); } const auto &GetFloatEntryMap() const { return m_FloatEntryMap; } const auto &GetDoubleEntryMap() const { return m_DoubleEntryMap; } From 10b4a8542ec1e56f412258b7dc990922a8e2ea5d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 10 Jun 2026 10:55:17 -0400 Subject: [PATCH 630/866] trigger jenkins From 2e711b521f84348508ef7d2e1b28e20d57435059 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 10 Jun 2026 11:35:29 -0400 Subject: [PATCH 631/866] cleanup --- offline/packages/PHGarfield/GasModel.cc | 6 +- offline/packages/PHGarfield/Makefile.am | 35 ++---------- offline/packages/PHGarfield/MergeGasFiles.cc | 20 ++++--- offline/packages/PHGarfield/PHGarfield.cc | 59 ++++++-------------- offline/packages/PHGarfield/PHGarfield.h | 27 +++------ 5 files changed, 44 insertions(+), 103 deletions(-) diff --git a/offline/packages/PHGarfield/GasModel.cc b/offline/packages/PHGarfield/GasModel.cc index 36bf18ad07..d64f9970ad 100644 --- a/offline/packages/PHGarfield/GasModel.cc +++ b/offline/packages/PHGarfield/GasModel.cc @@ -1,10 +1,8 @@ -#include +#include #include +#include -#include -#include #include -#include //------------------------------------------------------------ // This standalone executable makes gas calculations for diff --git a/offline/packages/PHGarfield/Makefile.am b/offline/packages/PHGarfield/Makefile.am index 1c74a0a706..6037ac8d1c 100644 --- a/offline/packages/PHGarfield/Makefile.am +++ b/offline/packages/PHGarfield/Makefile.am @@ -1,8 +1,5 @@ AUTOMAKE_OPTIONS = foreign -ROOT_CFLAGS = $(shell root-config --cflags) -ROOT_LIBS = $(shell root-config --libs) - AM_CPPFLAGS = \ -I$(includedir) \ -isystem$(OFFLINE_MAIN)/include \ @@ -11,7 +8,8 @@ AM_CPPFLAGS = \ AM_LDFLAGS = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 + -L$(OFFLINE_MAIN)/lib64 \ + `root-config --libs` pkginclude_HEADERS = \ PHGarfield.h @@ -23,22 +21,13 @@ libPHGarfield_la_LIBADD = \ -lffamodules \ -lffarawobjects \ -lcdbobjects \ - -ltpc \ - -lNoRootEvent \ + -lEvent \ -lphool \ -lphfield \ -lGarfield \ -lSubsysReco -ROOTDICTS = \ - PHGarfield_Dict.cc - -pcmdir = $(libdir) -nobase_dist_pcm_DATA = \ - PHGarfield_Dict_rdict.pcm - libPHGarfield_la_SOURCES = \ - $(ROOTDICTS) \ PHGarfield.cc bin_PROGRAMS = \ @@ -47,29 +36,15 @@ bin_PROGRAMS = \ MergeGasFiles_SOURCES = MergeGasFiles.cc -MergeGasFiles_LDFLAGS = \ - -L$(OFFLINE_MAIN)/lib64 \ - $(ROOT_LIBS) - MergeGasFiles_LDADD = \ - -lGarfield + -lGarfield \ + -lphool GasModel_SOURCES = GasModel.cc -GasModel_LDFLAGS = \ - -L$(OFFLINE_MAIN)/lib64 \ - $(ROOT_LIBS) - GasModel_LDADD = \ -lGarfield -# Rule for generating table CINT dictionaries. -%_Dict.cc: %.h %LinkDef.h - rootcint -f $@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ - -#just to get the dependency -%_Dict_rdict.pcm: %_Dict.cc ; - ################################################ BUILT_SOURCES = testexternals.cc diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc index 92d60a922a..6bbfd544d9 100644 --- a/offline/packages/PHGarfield/MergeGasFiles.cc +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -1,15 +1,16 @@ -#include -#include -#include -#include -#include -#include +#include #include #include +#include #include +#include +#include +#include +#include // for pi +#include int main() { @@ -87,7 +88,8 @@ int main() // double na=50; // Initialize using the current system time - TRandom3 Randy(time(nullptr)); // new initialization each run + TRandom3 Randy; + Randy.SetSeed(PHRandomSeed()); // new initialization each run std::cout << std::endl << std::endl << "Valid Calls: " << std::endl; @@ -96,7 +98,7 @@ int main() double eMag = Randy.Uniform(emin, emax); double bMag = Randy.Uniform(bmin, bmin + 0.2 * (bmax - bmin) / nb); // Comes from file0... double a = Randy.Uniform(amin, amax); - double PHI = Randy.Uniform(0.0, 2.0 * TMath::Pi()); + double PHI = Randy.Uniform(0.0, 2.0 * std::numbers::pi); double ex = 0; double ey = 0; @@ -160,7 +162,7 @@ int main() double eMag = Randy.Uniform(emin, emax); double bMag = Randy.Uniform(bmin + 5.0 * (bmax - bmin) / nb, bmax); // Comes from beyond file0... double a = Randy.Uniform(amin, amax); - double PHI = Randy.Uniform(0.0, 2.0 * TMath::Pi()); + double PHI = Randy.Uniform(0.0, 2.0 * std::numbers::pi); double ex = 0; double ey = 0; diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc index 2a6752c240..4f9e59a4b5 100644 --- a/offline/packages/PHGarfield/PHGarfield.cc +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -1,55 +1,30 @@ #include "PHGarfield.h" -#include -#include -#include -#include - #include -#include -#include -#include -#include -#include // for PHIODataNode -#include // for PHNodeIterator -#include // for PHObject -#include -#include -#include -#include +#include -#include +#include -#include -#include // for uint16_t -#include // for exit, size_t -#include -#include // for basic_ostream, operat... +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include +#include +#include + +#include +#include +#include +#include // for basic_ostream, operat... +#include PHGarfield::PHGarfield(const std::string& name) : SubsysReco(name) - , PHI_MIN(-M_PI) { - // Local handling of Phi valued that wrap around. } int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) @@ -58,7 +33,7 @@ int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) { std::cout << "PHGarfield::InitRun(PHCompositeNode *topNode) Initializing" << std::endl; } - m_cdb = CDBInterface::instance(); + CDBInterface *m_cdb = CDBInterface::instance(); // Here we use the CDBInterface to set up the magnetic field map: std::string url = m_cdb->getUrl("FIELDMAP_TRACKING"); @@ -160,7 +135,7 @@ void PHGarfield::PrintMaps() { unsigned int key = (256 * (fee)) + channel; int layer = m_cdbTPCMAPttree->GetIntValue(key, "layer"); - double phi = ((side == 1 ? 1 : -1) * (m_cdbTPCMAPttree->GetDoubleValue(key, "phi") - M_PI / 2.)) + ((sector % 12) * M_PI / 6); + double phi = ((side == 1 ? 1 : -1) * (m_cdbTPCMAPttree->GetDoubleValue(key, "phi") - std::numbers::pi / 2.)) + ((sector % 12) * std::numbers::pi / 6); double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R") / CLHEP::cm; phi = bounder(phi, PHI_MIN); @@ -275,14 +250,14 @@ int PHGarfield::process_event(PHCompositeNode* topNode) double PHGarfield::bounder(double phi, double phi_min) { - double phi_max = phi_min + 2.0 * M_PI; + double phi_max = phi_min + 2.0 * std::numbers::pi; while (phi < phi_min) { - phi = phi + 2.0 * M_PI; + phi = phi + 2.0 * std::numbers::pi; } while (phi >= phi_max) { - phi = phi - 2.0 * M_PI; + phi = phi - 2.0 * std::numbers::pi; } return phi; diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index f8fe19b2ee..2768416fa9 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -1,21 +1,13 @@ #ifndef PHGARFIELD__H #define PHGARFIELD__H -#include -#include - #include +#include #include -#include -class CdbUrlSave; -class CDBInterface; class CDBTTree; -class PHCompositeNode; -class TpcMap; class PHField3DCartesian; -class ComponentUser; class TPolyLine3D; namespace Garfield @@ -41,25 +33,24 @@ class PHGarfield : public SubsysReco // These are left in public namespace for easy plotting macros... // The user is encouraged to add more routine to fit their analysis goals... TPolyLine3D *ReverseDrift(double x_cm, double y_cm, double z_cm, double step_ns = 50.0); // Drifts electrons from some initial point until they hit a detector boundary... - double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! private: - CDBInterface *m_cdb{nullptr}; // Access to all thiungs CDB... - CDBTTree *m_cdbTPCMAPttree{nullptr}; // Locations of the pads from CDB... - PHField3DCartesian *m_field{nullptr}; // The stanards sPHENIX field holding container. - Garfield::ComponentUser *m_component{nullptr}; // This handles the interface of the electric and magnetic fields as handed to Garfield - Garfield::MediumMagboltz *m_gas{nullptr}; // This is the pre-tabulated gas properties required by Garfield... - void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double &bx_t, double &by_t, double &bz_t); // Feeds magnetic field to Garfield void GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double &ex_vcm, double &ey_vcm, double &ez_vcm); // Feeds electric field to Garfield void InitializeGas(std::string dir); void FillRadii(); + double bounder(double phi, double phi_min); + + CDBTTree *m_cdbTPCMAPttree{nullptr}; // Locations of the pads from CDB... + PHField3DCartesian *m_field{nullptr}; // The stanards sPHENIX field holding container. + Garfield::ComponentUser *m_component{nullptr}; // This handles the interface of the electric and magnetic fields as handed to Garfield + Garfield::MediumMagboltz *m_gas{nullptr}; // This is the pre-tabulated gas properties required by Garfield... // These are utilities for a spot check of the overall routine: // std::string calibdir; // std::string m_DiodeContainerName; - double bounder(double phi, double phi_min); - double PHI_MIN; + double PHI_MIN {-std::numbers::pi}; + double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! }; #endif From 70a675fd54bfe626ed55412f467d1f33d26a0336 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 10 Jun 2026 11:35:49 -0400 Subject: [PATCH 632/866] remove root 5 linkdef --- offline/packages/PHGarfield/PHGarfieldLinkDef.h | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 offline/packages/PHGarfield/PHGarfieldLinkDef.h diff --git a/offline/packages/PHGarfield/PHGarfieldLinkDef.h b/offline/packages/PHGarfield/PHGarfieldLinkDef.h deleted file mode 100644 index 07eccee133..0000000000 --- a/offline/packages/PHGarfield/PHGarfieldLinkDef.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef __CINT__ - -#pragma link C++ class PHGarfield + ; - -#endif /* __CINT__ */ From 7818c9c4ad3365967ed82ee17592c42548d1154f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 10 Jun 2026 11:36:46 -0400 Subject: [PATCH 633/866] clang-format --- offline/packages/PHGarfield/MergeGasFiles.cc | 10 +++--- offline/packages/PHGarfield/PHGarfield.cc | 35 ++++++++++---------- offline/packages/PHGarfield/PHGarfield.h | 4 +-- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc index 6bbfd544d9..7bbbc3d3bd 100644 --- a/offline/packages/PHGarfield/MergeGasFiles.cc +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -9,7 +9,7 @@ #include #include #include -#include // for pi +#include // for pi #include int main() @@ -91,8 +91,8 @@ int main() TRandom3 Randy; Randy.SetSeed(PHRandomSeed()); // new initialization each run std::cout << std::endl - << std::endl - << "Valid Calls: " << std::endl; + << std::endl + << "Valid Calls: " << std::endl; for (int i = 0; i < nValid; i++) { double eMag = Randy.Uniform(emin, emax); @@ -155,8 +155,8 @@ int main() } std::cout << std::endl - << std::endl - << "Invalid Calls: " << std::endl; + << std::endl + << "Invalid Calls: " << std::endl; for (int i = 0; i < nValid; i++) { double eMag = Randy.Uniform(emin, emax); diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc index 4f9e59a4b5..d04d7c4bb4 100644 --- a/offline/packages/PHGarfield/PHGarfield.cc +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -2,7 +2,6 @@ #include - #include #include @@ -29,11 +28,11 @@ PHGarfield::PHGarfield(const std::string& name) int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) { - if(Verbosity() > 1) + if (Verbosity() > 1) { - std::cout << "PHGarfield::InitRun(PHCompositeNode *topNode) Initializing" << std::endl; + std::cout << "PHGarfield::InitRun(PHCompositeNode *topNode) Initializing" << std::endl; } - CDBInterface *m_cdb = CDBInterface::instance(); + CDBInterface* m_cdb = CDBInterface::instance(); // Here we use the CDBInterface to set up the magnetic field map: std::string url = m_cdb->getUrl("FIELDMAP_TRACKING"); @@ -54,9 +53,9 @@ int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) // Diagnostic during code development... FillRadii(); - if(Verbosity() > 1) + if (Verbosity() > 1) { - PrintMaps(); + PrintMaps(); } return Fun4AllReturnCodes::EVENT_OK; } @@ -100,18 +99,18 @@ void PHGarfield::PrintGarfield(double x, double y, double z) GetMagneticFieldTesla(x, y, z, bx, by, bz); m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); std::cout << " x:" << x - << " y:" << y - << " z:" << z - << " ex:" << ex - << " ey:" << ey - << " ez:" << ez - << " bx:" << bx - << " by:" << by - << " bz:" << bz - << " vx:" << vx - << " vy:" << vy - << " vz:" << vz - << std::endl; + << " y:" << y + << " z:" << z + << " ex:" << ex + << " ey:" << ey + << " ez:" << ez + << " bx:" << bx + << " by:" << by + << " bz:" << bz + << " vx:" << vx + << " vy:" << vy + << " vz:" << vz + << std::endl; } void PHGarfield::PrintMaps() diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index 2768416fa9..a4e15fe129 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -49,8 +49,8 @@ class PHGarfield : public SubsysReco // These are utilities for a spot check of the overall routine: // std::string calibdir; // std::string m_DiodeContainerName; - double PHI_MIN {-std::numbers::pi}; - double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! + double PHI_MIN{-std::numbers::pi}; + double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! }; #endif From 62ad176e522d1e28ff682a8155538d4ffbf0eb66 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 10 Jun 2026 14:44:15 -0400 Subject: [PATCH 634/866] fix include file ordering --- offline/packages/trackbase/MvtxEventInfov1.h | 5 ++--- offline/packages/trackbase/MvtxEventInfov2.h | 5 ++--- offline/packages/trackbase/MvtxEventInfov3.h | 4 ++-- offline/packages/trackbase/ResidualOutlierFinder.h | 8 ++++++-- offline/packages/trackbase/SpacePoint.h | 7 ++++--- offline/packages/trackbase/TrkrClusterv2.h | 3 ++- offline/packages/trackbase/TrkrClusterv3.h | 3 ++- offline/packages/trackbase/TrkrClusterv4.h | 3 ++- offline/packages/trackbase/TrkrClusterv5.h | 3 ++- offline/packages/trackbase/TrkrClusterv6.h | 2 +- 10 files changed, 25 insertions(+), 18 deletions(-) diff --git a/offline/packages/trackbase/MvtxEventInfov1.h b/offline/packages/trackbase/MvtxEventInfov1.h index 5c6b382304..869f735925 100644 --- a/offline/packages/trackbase/MvtxEventInfov1.h +++ b/offline/packages/trackbase/MvtxEventInfov1.h @@ -10,12 +10,11 @@ /* 29/09/2023 */ /***************************/ -#include +#include "MvtxEventInfo.h" +#include #include -#include "MvtxEventInfo.h" - typedef std::pair strobe_L1_pair; /// diff --git a/offline/packages/trackbase/MvtxEventInfov2.h b/offline/packages/trackbase/MvtxEventInfov2.h index a4629c6441..9b0b8325a4 100644 --- a/offline/packages/trackbase/MvtxEventInfov2.h +++ b/offline/packages/trackbase/MvtxEventInfov2.h @@ -10,12 +10,11 @@ /* 09/11/2023 */ /***************************/ -#include +#include "MvtxEventInfo.h" +#include #include -#include "MvtxEventInfo.h" - typedef std::pair strobe_L1_pair; /// diff --git a/offline/packages/trackbase/MvtxEventInfov3.h b/offline/packages/trackbase/MvtxEventInfov3.h index d1e11fa129..e0f213780f 100644 --- a/offline/packages/trackbase/MvtxEventInfov3.h +++ b/offline/packages/trackbase/MvtxEventInfov3.h @@ -10,11 +10,11 @@ /* 29/09/2023 */ /***************************/ -#include +#include "MvtxEventInfo.h" +#include #include -#include "MvtxEventInfo.h" /// class MvtxEventInfov3 : public MvtxEventInfo diff --git a/offline/packages/trackbase/ResidualOutlierFinder.h b/offline/packages/trackbase/ResidualOutlierFinder.h index d0ace7fb12..7a587f56ec 100644 --- a/offline/packages/trackbase/ResidualOutlierFinder.h +++ b/offline/packages/trackbase/ResidualOutlierFinder.h @@ -1,19 +1,23 @@ #ifndef TRACKBASE_RESIDUALOUTLIERFINDER_H #define TRACKBASE_RESIDUALOUTLIERFINDER_H +#include + #include #include #include -#include + #include #include + #include #include +#include #include + #include -#include struct ResidualOutlierFinder { ActsGeometry* m_tGeometry = nullptr; diff --git a/offline/packages/trackbase/SpacePoint.h b/offline/packages/trackbase/SpacePoint.h index afede18a3b..354d2beeb9 100644 --- a/offline/packages/trackbase/SpacePoint.h +++ b/offline/packages/trackbase/SpacePoint.h @@ -1,14 +1,15 @@ #ifndef TRACKBASE_SPACEPOINT_H #define TRACKBASE_SPACEPOINT_H -#include -#include -#include "trackbase/TrkrDefs.h" +#include #include #include #include +#include +#include + /** * A struct for Acts to take cluster information for seeding */ diff --git a/offline/packages/trackbase/TrkrClusterv2.h b/offline/packages/trackbase/TrkrClusterv2.h index fb7e6eda31..9b4edafc74 100644 --- a/offline/packages/trackbase/TrkrClusterv2.h +++ b/offline/packages/trackbase/TrkrClusterv2.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV2_H #define TRACKBASE_TRKRCLUSTERV2_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** diff --git a/offline/packages/trackbase/TrkrClusterv3.h b/offline/packages/trackbase/TrkrClusterv3.h index ded341dd35..49cd6dd6e6 100644 --- a/offline/packages/trackbase/TrkrClusterv3.h +++ b/offline/packages/trackbase/TrkrClusterv3.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV3_H #define TRACKBASE_TRKRCLUSTERV3_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** diff --git a/offline/packages/trackbase/TrkrClusterv4.h b/offline/packages/trackbase/TrkrClusterv4.h index 15a17adf3a..ec0bc4703c 100644 --- a/offline/packages/trackbase/TrkrClusterv4.h +++ b/offline/packages/trackbase/TrkrClusterv4.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV4_H #define TRACKBASE_TRKRCLUSTERV4_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index 9e5e0fe7ff..ebb0bae961 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV5_H #define TRACKBASE_TRKRCLUSTERV5_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 943addfdf8..37ffdffbbf 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -10,7 +10,7 @@ #include "TrkrCluster.h" #include "TrkrDefs.h" -#include +#include #include class PHObject; From 4d0fa327ec79c2dd1f229324e4d2aa89aebe5c06 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 10 Jun 2026 19:13:31 -0400 Subject: [PATCH 635/866] Handle abnormal operation where trigger has long spacing while TPC kept taking streaming data --- .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 139 +++++++++++------- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 28 ++-- 2 files changed, 97 insertions(+), 70 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 426611b255..e08f28796f 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -756,14 +756,33 @@ void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_correc const size_t nfees = std::min(m_timeHitMap.size(), m_bcoMatchingInformation_vec.size()); for (size_t fee_index = 0; fee_index < nfees; ++fee_index) { + const uint16_t fee = static_cast(fee_index); + auto& fee_time_hits = m_timeHitMap[fee_index]; + const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee_index].get_predicted_fee_bco(bclk_rollover_corrected); if (!predicted_fee_bco) { + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": WARNING: No predicted FEE BCO for fee index " << fee_index + << " with bclk_rollover_corrected: 0x" << std::hex << bclk_rollover_corrected << std::dec + << ". Clearing time hit map for this fee." << std::endl; + } + + for (auto map_it = fee_time_hits.begin(); map_it != fee_time_hits.end();) + { + for (TpcRawHit* hit : map_it->second) + { + m_hFEEDataStream->Fill(fee, "HitUnusedBeforeCleanup", 1); + delete hit; + } + map_it = fee_time_hits.erase(map_it); + } + continue; } - const uint16_t fee = static_cast(fee_index); - auto& fee_time_hits = m_timeHitMap[fee_index]; for (auto map_it = fee_time_hits.begin(); map_it != fee_time_hits.end();) { const int64_t diff = get_signed_fee_bco_diff(map_it->first, *predicted_fee_bco); @@ -849,13 +868,13 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } } size_t total_gtm_bco_trig = 0; - size_t total_bco_ref_cand = 0; + size_t total_bco_heartbeat = 0; size_t total_gtm_bco_trigger = 0; size_t total_bco_matching = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat += bco_info.get_bco_heartbeat_list_size(); total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching += bco_info.get_bco_matching_list_size(); } @@ -865,7 +884,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ", m_timeHitMap: " << time_hit_map_buckets << " FEE-BCO buckets, " << total_time_hits << " total hits" << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig - << ", bco_ref_cand: " << total_bco_ref_cand + << ", bco_heartbeat: " << total_bco_heartbeat << ", gtm_trigger_map: " << total_gtm_bco_trigger << ", bco_matching: " << total_bco_matching << std::endl; @@ -972,11 +991,11 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } } size_t total_gtm_bco_trig_post = 0; - size_t total_bco_ref_cand_post = 0; + size_t total_bco_heartbeat_post = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_post += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand_post += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat_post += bco_info.get_bco_heartbeat_list_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [AFTER EXACT/FUZZY] STL buffer usage - exact_hits: " << exact_hit_count @@ -987,7 +1006,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ", m_timeHitMap: " << time_hit_map_buckets_post_exact_fuzzy << " buckets, " << total_time_hits_post_exact_fuzzy << " hits" << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_post - << ", bco_ref_cand: " << total_bco_ref_cand_post << "]" + << ", bco_heartbeat: " << total_bco_heartbeat_post << "]" << std::endl; } @@ -1033,11 +1052,11 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } } size_t total_gtm_bco_trig_recovery = 0; - size_t total_bco_ref_cand_recovery = 0; + size_t total_bco_heartbeat_recovery = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_recovery += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand_recovery += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat_recovery += bco_info.get_bco_heartbeat_list_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [AFTER RECOVERY] STL buffer usage - timeframe size: " << timeframe.size() @@ -1047,7 +1066,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ", m_timeHitMap: " << time_hit_map_buckets_post_recovery << " buckets, " << total_time_hits_post_recovery << " hits" << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_recovery - << ", bco_ref_cand: " << total_bco_ref_cand_recovery << "]" + << ", bco_heartbeat: " << total_bco_heartbeat_recovery << "]" << std::endl; } @@ -1074,11 +1093,11 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } } size_t total_gtm_bco_trig_empty = 0; - size_t total_bco_ref_cand_empty = 0; + size_t total_bco_heartbeat_empty = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_empty += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand_empty += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat_empty += bco_info.get_bco_heartbeat_list_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [EMPTY-FRAME ERROR] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() @@ -1086,7 +1105,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ", m_timeHitMap: " << time_hit_map_buckets_empty << " buckets, " << total_time_hits_empty << " hits" << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_empty - << ", bco_ref_cand: " << total_bco_ref_cand_empty << "]" + << ", bco_heartbeat: " << total_bco_heartbeat_empty << "]" << std::endl; } @@ -1123,13 +1142,13 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g } } size_t total_gtm_bco_trig_final = 0; - size_t total_bco_ref_cand_final = 0; + size_t total_bco_heartbeat_final = 0; size_t total_gtm_bco_trigger_final = 0; size_t total_bco_matching_final = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand_final += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat_final += bco_info.get_bco_heartbeat_list_size(); total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching_final += bco_info.get_bco_matching_list_size(); } @@ -1143,7 +1162,7 @@ std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& g << ", m_timeHitMap: " << time_hit_map_buckets_final << " buckets, " << total_time_hits_final << " hits" << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_final - << ", bco_ref_cand: " << total_bco_ref_cand_final + << ", bco_heartbeat: " << total_bco_heartbeat_final << ", gtm_trigger_map: " << total_gtm_bco_trigger_final << ", bco_matching: " << total_bco_matching_final << std::endl; @@ -1217,16 +1236,6 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) if (m_hitFormat < 0) { m_hitFormat = packet_hit_format; - - if (m_verbosity >= 1) - { - std::cout << __PRETTY_FUNCTION__ << " set exact Run3 clock sync for hit format " << m_hitFormat - << " with clock ratio = 30/8" << std::endl; - } - for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) - { - bcoMatchingInformation.set_gtm_clock_ratio(30, 8); - } } else if (packet_hit_format != m_hitFormat) { @@ -1276,13 +1285,13 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) total_fee_data += fee_data_deque.size(); } size_t total_gtm_bco_trig = 0; - size_t total_bco_ref_cand = 0; + size_t total_bco_heartbeat = 0; size_t total_gtm_bco_trigger = 0; size_t total_bco_matching = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat += bco_info.get_bco_heartbeat_list_size(); total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching += bco_info.get_bco_matching_list_size(); } @@ -1292,7 +1301,7 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) << ", m_feeData total: " << total_fee_data << ", m_timeHitMap: " << time_hit_map_buckets << " buckets, " << total_time_hits << " hits" << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig - << ", bco_ref_cand: " << total_bco_ref_cand + << ", bco_heartbeat: " << total_bco_heartbeat << ", gtm_trigger_map: " << total_gtm_bco_trigger << ", bco_matching: " << total_bco_matching << std::endl; @@ -1454,11 +1463,11 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) total_fee_data_post += fee_data_deque.size(); } size_t total_gtm_bco_trig_post = 0; - size_t total_bco_ref_cand_post = 0; + size_t total_bco_heartbeat_post = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_post += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand_post += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat_post += bco_info.get_bco_heartbeat_list_size(); } std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": [AFTER DMA PROCESSING] STL buffer usage - m_feeData total: " << total_fee_data_post @@ -1466,7 +1475,7 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) << ", m_timeFrameMap: " << m_timeFrameMap.size() << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_post - << ", bco_ref_cand: " << total_bco_ref_cand_post << "]" + << ", bco_heartbeat: " << total_bco_heartbeat_post << "]" << std::endl; } @@ -1503,7 +1512,7 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) h_ProcessPacket_Time->Fill(call_count, m_packetTimer->elapsed()); // Track final buffer usage at end of ProcessPacket - if (m_verbosity >= 2) + if (m_verbosity >= 1) { size_t total_time_hits_final = 0; size_t time_hit_map_buckets_final = 0; @@ -1521,13 +1530,13 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) total_fee_data_final += fee_data_deque.size(); } size_t total_gtm_bco_trig_final = 0; - size_t total_bco_ref_cand_final = 0; + size_t total_bco_heartbeat_final = 0; size_t total_gtm_bco_trigger_final = 0; size_t total_bco_matching_final = 0; for (const auto& bco_info : m_bcoMatchingInformation_vec) { total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); - total_bco_ref_cand_final += bco_info.get_bco_reference_candidate_list_size(); + total_bco_heartbeat_final += bco_info.get_bco_heartbeat_list_size(); total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); total_bco_matching_final += bco_info.get_bco_matching_list_size(); } @@ -1537,7 +1546,7 @@ int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) << ", m_feeData total: " << total_fee_data_final << ", m_timeHitMap: " << time_hit_map_buckets_final << " buckets, " << total_time_hits_final << " hits" << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_final - << ", bco_ref_cand: " << total_bco_ref_cand_final + << ", bco_heartbeat: " << total_bco_heartbeat_final << ", gtm_trigger_map: " << total_gtm_bco_trigger_final << ", bco_matching: " << total_bco_matching_final << std::endl; @@ -2340,15 +2349,15 @@ bool TpcTimeFrameBuilderRun3::BcoMatchingInformation::isMoreDataRequired(const u } } - if (!m_bco_reference_candidate_list.empty()) + if (!m_bco_heartbeat_list.empty()) { - if (m_bco_reference_candidate_list.back().first > bco_correction + m_max_fee_sync_time) + if (m_bco_heartbeat_list.back().first > bco_correction + m_max_fee_sync_time) { if (m_verbosity >= 2) { std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec - << ". m_bco_reference_candidate_list.back().first = 0x" << std::hex << m_bco_reference_candidate_list.back().first << std::dec + << ". m_bco_heartbeat_list.back().first = 0x" << std::hex << m_bco_heartbeat_list.back().first << std::dec << " bco_correction = 0x" << std::hex << bco_correction << std::dec << ". satisified m_max_fee_sync_time = " << m_max_fee_sync_time << std::endl; @@ -2361,7 +2370,7 @@ bool TpcTimeFrameBuilderRun3::BcoMatchingInformation::isMoreDataRequired(const u { std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec - << ". m_bco_reference_candidate_list.back().first = 0x" << std::hex << m_bco_reference_candidate_list.back().first << std::dec + << ". m_bco_heartbeat_list.back().first = 0x" << std::hex << m_bco_heartbeat_list.back().first << std::dec << " bco_correction = 0x" << std::hex << bco_correction << std::dec << ". not yet satisified m_max_fee_sync_time = " << m_max_fee_sync_time << std::endl; @@ -2373,7 +2382,7 @@ bool TpcTimeFrameBuilderRun3::BcoMatchingInformation::isMoreDataRequired(const u std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec << " bco_correction = 0x" << std::hex << bco_correction << std::dec << ": more data required" - << " as their is NO m_bco_reference nor m_bco_reference_candidate_list" + << " as their is NO m_bco_reference nor m_bco_heartbeat_list" << std::endl; std::cout << " m_gtm_bco_trigger_map:" << std::endl; @@ -2400,6 +2409,28 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::get_pre return std::nullopt; } + // check whether it is within the same FEE clock rollover window based on the reference candidate list + { + uint64_t latest_reference_bco = (*m_bco_reference).first; + if (not m_bco_heartbeat_list.empty()) + { + latest_reference_bco = m_bco_heartbeat_list.back().first; // get the latest heartbeat bco + } + + if (get_bco_diff(gtm_bco , latest_reference_bco)*m_clock_ratio_numerator + > ((1U << (m_FEE_CLOCK_BITS -1))) * m_clock_ratio_denominator) + { + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::get_predicted_fee_bco -" + << " GTM bco 0x" << std::hex << gtm_bco << std::dec + << " is too far from the latest heartbeat bco 0x" << std::hex << latest_reference_bco << std::dec + << ", cannot predict fee bco" << std::endl; + } + return std::nullopt; + } + } + // get gtm bco difference with proper rollover accounting const auto& bco_reference = *m_bco_reference; const int64_t gtm_bco_difference = int64_t(gtm_bco) - int64_t(bco_reference.first); @@ -2532,7 +2563,7 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c auto predicted_fee_bco = get_predicted_fee_bco(gtm_bco); if (predicted_fee_bco) { - m_bco_reference_candidate_list.emplace_back(gtm_bco, predicted_fee_bco.value()); + m_bco_heartbeat_list.emplace_back(gtm_bco, predicted_fee_bco.value()); } else { @@ -2549,10 +2580,10 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information" << "\t- found heartbeat candidate " << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec - << ". Current m_bco_reference_candidate_list:" + << ". Current m_bco_heartbeat_list:" << std::endl; - for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_reference_candidate_list) + for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_heartbeat_list) { std::cout << "\t- gtm_bco = 0x" << std::hex << bco.first << std::dec << "\t- fee_bco = 0x" << std::hex << bco.second << std::dec @@ -2560,21 +2591,21 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c } } - while (m_bco_reference_candidate_list.size() > m_max_bco_reference_candidate_list_size) + while (m_bco_heartbeat_list.size() > m_max_bco_heartbeat_list_size) { if (m_verbosity > 1) { - uint64_t bco = m_bco_reference_candidate_list.begin()->first; + uint64_t bco = m_bco_heartbeat_list.begin()->first; std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits" - << "Warning: m_bco_reference_candidate_list is full" + << "Warning: m_bco_heartbeat_list is full" << "\t- drop unprocessed heart beat in queue " << "at gtm_bco = 0x" << std::hex << bco << std::dec - << ". Unprocessed heartbeats in queue with size of " << m_bco_reference_candidate_list.size() + << ". Unprocessed heartbeats in queue with size of " << m_bco_heartbeat_list.size() << std::endl; } - m_bco_reference_candidate_list.pop_front(); + m_bco_heartbeat_list.pop_front(); } } // if (modebits & (1U << ELINK_HEARTBEAT_T)) @@ -2588,7 +2619,7 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c const uint64_t bco_reference_gtm_bco = gtm_bco + kBXCounterSyncGtmBcoOffset; m_verified_from_modebits = true; m_bco_reference = std::make_pair(bco_reference_gtm_bco, kBXCounterSyncFEEBcoOffset); - m_bco_reference_candidate_list.clear(); + m_bco_heartbeat_list.clear(); if (m_verbosity) { @@ -2672,7 +2703,7 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re } } - for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_reference_candidate_list) + for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_heartbeat_list) { const uint64_t gtm_bco = bco.first; const uint32_t fee_bco_predicted = bco.second; @@ -2696,7 +2727,7 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re if (m_verbosity > 1) { std::cout << "\t- clock reference update from heartbeat is disabled; candidate list retained at size " - << m_bco_reference_candidate_list.size() << std::endl; + << m_bco_heartbeat_list.size() << std::endl; } assert(m_hFEEClockAdjustment_MatchedNew); @@ -2719,7 +2750,7 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_re assert(m_hFEEClockAdjustment_Unmatched); m_hFEEClockAdjustment_Unmatched->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1); - } // for (const auto& bco : m_bco_reference_candidate_list) + } // for (const auto& bco : m_bco_heartbeat_list) if (verbosity() > 1) { diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index 453d5cb68d..f4dedef4da 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -224,10 +224,10 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase return m_gtm_bco_trig_list.size(); } - //! get size of m_bco_reference_candidate_list - size_t get_bco_reference_candidate_list_size() const + //! get size of m_bco_heartbeat_list + size_t get_bco_heartbeat_list_size() const { - return m_bco_reference_candidate_list.size(); + return m_bco_heartbeat_list.size(); } //! get size of m_gtm_bco_trigger_map @@ -253,12 +253,6 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase m_verbosity = value; } - void set_gtm_clock_ratio(int64_t numerator, int64_t denominator) - { - m_clock_ratio_numerator = numerator; - m_clock_ratio_denominator = denominator; - } - /// set gtm clock with rollover correction uint64_t get_gtm_rollover_correction(const uint64_t >m_bco) const; @@ -328,8 +322,9 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase const uint32_t &first, const uint32_t &second) // NOLINT(misc-unused-parameters) { const uint32_t diff_raw = get_bco_diff(first, second); - - return (diff_raw < (1U << (m_FEE_CLOCK_BITS / 2))) ? diff_raw : (1U << m_FEE_CLOCK_BITS) - diff_raw; + const uint32_t half_range = 1U << (m_FEE_CLOCK_BITS - 1); + const uint32_t full_range = 1U << m_FEE_CLOCK_BITS; + return (diff_raw <= half_range) ? diff_raw : full_range - diff_raw; } private: @@ -354,8 +349,8 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase // std::optional< std::pair< uint64_t, uint32_t > > m_bco_reference_candidate = std::nullopt; //! not yet matched heart beats - std::list m_bco_reference_candidate_list; - static constexpr unsigned int m_max_bco_reference_candidate_list_size = 16; + std::list m_bco_heartbeat_list; + static constexpr unsigned int m_max_bco_heartbeat_list_size = 16; // //! list of heart beat GTM BCO that is still to be matched // std::queue m_heartbeat_gtm_bco_queue; @@ -391,8 +386,9 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static constexpr unsigned int m_FEE_CLOCK_BITS = 20; static constexpr unsigned int m_GTM_CLOCK_BITS = 40; - int64_t m_clock_ratio_numerator = 0; - int64_t m_clock_ratio_denominator = 1; + //! Run3 FEE firmware + static constexpr int64_t m_clock_ratio_numerator = 30; + static constexpr int64_t m_clock_ratio_denominator = 8; TH1 *m_hNorm = nullptr; TH1 *m_hFEEClockAdjustment_MatchedReference = nullptr; @@ -417,7 +413,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase static constexpr uint32_t kFEEClockMask = (1U << 20U) - 1U; static constexpr uint32_t kRun3FeeMatchWindow = (GL1_BCO_MATCH_WINDOW * 30U + 7U) / 8U; - static constexpr int32_t kRun3ExactMatchWindow = 2; + static constexpr int32_t kRun3ExactMatchWindow = 6; // allow for 1BCO offset from different clock freq. + 1BCO for possible missing first sync static constexpr uint32_t kRun3FEEClockPerADCClock = 2U; static constexpr uint32_t kRun3TruncatedWaveformRecoveryWindow = 1024U; static constexpr uint32_t kRun3TruncatedWaveformRecoveryFEEWindow = From f57ffffae66eb256056101a3a7f561cb6378ce22 Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Wed, 10 Jun 2026 19:56:25 -0400 Subject: [PATCH 636/866] Increase verbosity levels for warning messages in BCO prediction and cleanup functions --- offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index e08f28796f..62478aa0bf 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -762,7 +762,7 @@ void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_correc const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee_index].get_predicted_fee_bco(bclk_rollover_corrected); if (!predicted_fee_bco) { - if (m_verbosity >= 1) + if (m_verbosity >= 2) { std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": WARNING: No predicted FEE BCO for fee index " << fee_index @@ -2420,11 +2420,13 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::get_pre if (get_bco_diff(gtm_bco , latest_reference_bco)*m_clock_ratio_numerator > ((1U << (m_FEE_CLOCK_BITS -1))) * m_clock_ratio_denominator) { - if (m_verbosity > 1) + if (m_verbosity >= 3) { std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::get_predicted_fee_bco -" << " GTM bco 0x" << std::hex << gtm_bco << std::dec << " is too far from the latest heartbeat bco 0x" << std::hex << latest_reference_bco << std::dec + << " get_bco_diff(gtm_bco , latest_reference_bco) =" << get_bco_diff(gtm_bco , latest_reference_bco) + << " > " << ((1U << (m_FEE_CLOCK_BITS -1))) * m_clock_ratio_denominator / m_clock_ratio_numerator << ", cannot predict fee bco" << std::endl; } return std::nullopt; From 204e425afa9e1a9ea15bb61d32613e6d60329c18 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 11 Jun 2026 09:57:58 -0400 Subject: [PATCH 637/866] clang-tidy --- offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index 62478aa0bf..c8d5859210 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -2412,7 +2412,7 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::get_pre // check whether it is within the same FEE clock rollover window based on the reference candidate list { uint64_t latest_reference_bco = (*m_bco_reference).first; - if (not m_bco_heartbeat_list.empty()) + if (! m_bco_heartbeat_list.empty()) { latest_reference_bco = m_bco_heartbeat_list.back().first; // get the latest heartbeat bco } @@ -2437,8 +2437,8 @@ std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::get_pre const auto& bco_reference = *m_bco_reference; const int64_t gtm_bco_difference = int64_t(gtm_bco) - int64_t(bco_reference.first); - assert(m_clock_ratio_numerator > 0); - assert(m_clock_ratio_denominator > 0); + static_assert(m_clock_ratio_numerator > 0); + static_assert(m_clock_ratio_denominator > 0); // convert to fee bco with the exact Run3 30/8 ratio, and truncate to 20 bits const int64_t fee_bco_predicted = int64_t(bco_reference.second) + From 92963146aaf84544a8945b34b6524556e3fab7da Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 8 Jun 2026 14:57:47 -0400 Subject: [PATCH 638/866] store reference as a pair, (as in the matching map) and update accessors accodringly --- .../MicromegasBcoMatchingInformation_v2.cc | 24 +++++++++---------- .../MicromegasBcoMatchingInformation_v2.h | 22 ++++++----------- .../SingleMicromegasPoolInput_v2.cc | 5 ++-- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 31524e97f4..78c2ee7d16 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -142,10 +142,10 @@ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_b } // get gtm bco difference with proper rollover accounting - const uint64_t gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first); + const uint64_t gtm_bco_difference = (gtm_bco >= m_bco_reference.second) ? (gtm_bco - m_bco_reference.second) : (gtm_bco + (1ULL << 40U) - m_bco_reference.second); // convert to fee bco, and truncate to 20 bits - const uint64_t fee_bco_predicted = m_fee_bco_first + get_adjusted_multiplier() * gtm_bco_difference; + const uint64_t fee_bco_predicted = m_bco_reference.first + get_adjusted_multiplier() * gtm_bco_difference; return uint32_t(fee_bco_predicted & 0xFFFFFU); } @@ -225,8 +225,7 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_modebits(const Mic // get BCO and assign const auto& gtm_bco = payload.bco; - m_gtm_bco_first = gtm_bco; - m_fee_bco_first = 0; + m_bco_reference = {0, gtm_bco}; m_verified_from_modebits = true; return true; } @@ -302,19 +301,18 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay if (get_bco_diff(sum, fee_bco_diff) < m_max_fee_bco_diff) { m_verified_from_data = true; - m_gtm_bco_first = gtm_bco_list[i]; - m_fee_bco_first = m_fee_bco_prev; + m_bco_reference = { m_fee_bco_prev, gtm_bco_list[i] }; if (verbosity()) { std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - matching is verified" << std::endl; std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data -" - << " m_gtm_bco_first: " << std::hex << m_gtm_bco_first << std::dec - << std::endl; - std::cout - << "MicromegasBcoMatchingInformation_v2::find_reference_from_data -" - << " m_fee_bco_first: " << std::hex << m_fee_bco_first << std::dec + << std::hex + << " m_bco_reference: ( 0x" + << m_bco_reference.first + << ", 0x" << m_bco_reference.second << ")" + << std::dec << std::endl; } return true; @@ -481,7 +479,7 @@ void MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment(uint64_t } // skip if trivial - if (gtm_bco == m_gtm_bco_first) + if (gtm_bco == m_bco_reference.second) { return; } @@ -496,7 +494,7 @@ void MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment(uint64_t } const uint32_t fee_bco_predicted = *predicted_opt; const double delta_fee_bco = double(fee_bco) - double(fee_bco_predicted); - const double gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first); + const double gtm_bco_difference = (gtm_bco >= m_bco_reference.second) ? (gtm_bco - m_bco_reference.second) : (gtm_bco + (1ULL << 40U) - m_bco_reference.second); m_multiplier_adjustment_numerator += gtm_bco_difference * delta_fee_bco; m_multiplier_adjustment_denominator += gtm_bco_difference * gtm_bco_difference; diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h index 1b25f8d8a8..f89caee5f9 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h @@ -97,13 +97,10 @@ class MicromegasBcoMatchingInformation_v2 //! print gtm bco information void print_gtm_bco_information() const; - //! get first gtm bco - unsigned int get_fee_bco_first() const - { return m_fee_bco_first; } - - //! get first gtm bco - uint64_t get_gtm_bco_first() const - { return m_gtm_bco_first; } + //! get BCO matching reference + using m_bco_matching_pair_t = std::pair; + const m_bco_matching_pair_t& get_bco_matching_reference() const + { return m_bco_reference; } //! get last gtm bco uint64_t get_gtm_bco_last() const @@ -178,15 +175,8 @@ class MicromegasBcoMatchingInformation_v2 //! verified bool m_verified_from_modebits = false; - bool m_verified_from_data = false; - //! first lvl1 bco (40 bits) - uint64_t m_gtm_bco_first = 0; - - //! first fee bco (20 bits) - uint32_t m_fee_bco_first = 0; - //! last found fee_bco /** used to try finding bco reference from data */ uint32_t m_fee_bco_prev = 0; @@ -195,8 +185,10 @@ class MicromegasBcoMatchingInformation_v2 //! list of available bco std::list m_gtm_bco_list; + //! reference matching + m_bco_matching_pair_t m_bco_reference; + //! matching between fee bco and lvl1 bco - using m_bco_matching_pair_t = std::pair; std::list m_bco_matching_list; //! keep track or fee_bco for which no gtm_bco is found diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 89c0caa9f3..a990a059a6 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -773,19 +773,18 @@ void SingleMicromegasPoolInput_v2::decode_gtm_data(int packet_id, const SingleMi if (m_do_evaluation) { m_waveform.packet_id = packet_id; - m_waveform.gtm_bco_first = bco_matching_information.get_gtm_bco_first(); + m_waveform.gtm_bco_first = bco_matching_information.get_bco_matching_reference().second; m_waveform.gtm_bco = bco_matching_information.get_gtm_bco_last(); { const auto predicted = bco_matching_information.get_predicted_fee_bco(m_waveform.gtm_bco); - ; if (predicted) { m_waveform.fee_bco_predicted = predicted.value(); } } - m_waveform.fee_bco_first = bco_matching_information.get_fee_bco_first(); + m_waveform.fee_bco_first = bco_matching_information.get_bco_matching_reference().first; } } From f79886fca9c59da48bbcbbfebd44fc56213558af Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 8 Jun 2026 16:34:31 -0400 Subject: [PATCH 639/866] Change the pool filling strategy so that it matches the TPC better: check the difference between the requested BCO and the last BCO found in the TPOT data stream, including some extra delay corresponding to how much time it takes for TPOT to send all the data for said trigger. --- .../Fun4AllStreamingInputManager.cc | 13 +++- .../MicromegasBcoMatchingInformation_v2.cc | 57 +++++++++++++-- .../MicromegasBcoMatchingInformation_v2.h | 17 +++++ .../SingleMicromegasPoolInput_v2.cc | 71 +++---------------- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 40 ++++++----- 5 files changed, 112 insertions(+), 86 deletions(-) diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 025f6683a1..dd5a777309 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -794,7 +794,7 @@ int Fun4AllStreamingInputManager::FillIntt() } inttcont->AddHit(intthititer); } - } + } return 0; } int Fun4AllStreamingInputManager::FillMvtx() @@ -987,7 +987,7 @@ int Fun4AllStreamingInputManager::FillMvtx() if (Verbosity() > 2) { - std::cout << "Adding 0x" << std::hex << bco + std::cout << "Adding 0x" << std::hex << bco << " ref: 0x" << select_crossings << std::dec << std::endl; } for (auto *mvtxFeeIdInfo : hitinfo.MvtxFeeIdInfoVector) @@ -1333,13 +1333,20 @@ int Fun4AllStreamingInputManager::FillTpcPool() int Fun4AllStreamingInputManager::FillMicromegasPool() { + + uint64_t ref_bco_minus_range = 0; + if (m_RefBCO > m_micromegas_negative_bco) + { + ref_bco_minus_range = m_RefBCO - m_micromegas_negative_bco; + } + for (auto *iter : m_MicromegasInputVector) { if (Verbosity() > 0) { std::cout << "Fun4AllStreamingInputManager::FillMicromegasPool - fill pool for " << iter->Name() << std::endl; } - iter->FillPool(); + iter->FillPool(ref_bco_minus_range); if (m_RunNumber == 0) { m_RunNumber = iter->RunNumber(); diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 78c2ee7d16..ee83878dec 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -98,6 +98,10 @@ namespace //! copied from micromegas/MicromegasDefs.h, not available here constexpr int m_nchannels_fee = 256; + // gtm clock bits + /* used for rollover calculation */ + static constexpr unsigned int m_GTM_CLOCK_BITS = 40; + /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ enum SampaDataType { @@ -132,6 +136,12 @@ unsigned int MicromegasBcoMatchingInformation_v2::m_max_multiplier_adjustment_co // define limit for matching fee_bco to fee_bco_predicted unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 100; +// +// unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 8; +// unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 16; +unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 32; + + //___________________________________________________ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_bco(uint64_t gtm_bco) const { @@ -142,7 +152,7 @@ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_b } // get gtm bco difference with proper rollover accounting - const uint64_t gtm_bco_difference = (gtm_bco >= m_bco_reference.second) ? (gtm_bco - m_bco_reference.second) : (gtm_bco + (1ULL << 40U) - m_bco_reference.second); + const uint64_t gtm_bco_difference = get_gtm_rollover_correction(gtm_bco) - m_bco_reference.second; // convert to fee bco, and truncate to 20 bits const uint64_t fee_bco_predicted = m_bco_reference.first + get_adjusted_multiplier() * gtm_bco_difference; @@ -178,6 +188,46 @@ void MicromegasBcoMatchingInformation_v2::print_gtm_bco_information() const } } +//___________________________________________________ +uint64_t MicromegasBcoMatchingInformation_v2::get_gtm_rollover_correction(uint64_t gtm_bco) const +{ + // check proper initialization + if (!is_verified()) { return gtm_bco; } + else if( gtm_bco >= m_bco_reference.second ) return gtm_bco; + else return gtm_bco+(1ULL << m_GTM_CLOCK_BITS); +} + +//___________________________________________________ +bool MicromegasBcoMatchingInformation_v2::is_more_data_required( uint64_t gtm_bco ) const +{ + // check proper initialization + if( !is_verified() ) return true; + + // get rollover corrected gtm + const auto gtm_bco_corrected = get_gtm_rollover_correction( gtm_bco ); + + // check against reference + if (m_bco_reference.second > gtm_bco_corrected + m_max_fee_sync_time) + { return false; } + + // check against stored bco + if( !m_gtm_bco_list.empty() ) + { + if (m_gtm_bco_list.back() > gtm_bco_corrected + m_max_fee_sync_time) + { return false; } + } + + // check against matched BCOs + if( !m_bco_matching_list.empty() ) + { + if (m_bco_matching_list.back().second > gtm_bco_corrected + m_max_fee_sync_time) + { return false; } + } + + return true; +} + + //___________________________________________________ void MicromegasBcoMatchingInformation_v2::save_gtm_bco_information(int /*packet_id*/, const MicromegasBcoMatchingInformation_v2::gtm_payload& payload) { @@ -245,8 +295,7 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay { // add difference to last // get gtm bco difference with proper rollover accounting - const uint64_t gtm_bco_difference = (gtm_bco >= gtm_bco_list.back()) ? (gtm_bco - gtm_bco_list.back()) : (gtm_bco + (1ULL << 40U) - gtm_bco_list.back()); - + const uint64_t gtm_bco_difference = get_gtm_rollover_correction( gtm_bco ) - gtm_bco_list.back(); gtm_bco_diff_list.push_back(get_adjusted_multiplier() * gtm_bco_difference); } @@ -494,7 +543,7 @@ void MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment(uint64_t } const uint32_t fee_bco_predicted = *predicted_opt; const double delta_fee_bco = double(fee_bco) - double(fee_bco_predicted); - const double gtm_bco_difference = (gtm_bco >= m_bco_reference.second) ? (gtm_bco - m_bco_reference.second) : (gtm_bco + (1ULL << 40U) - m_bco_reference.second); + const double gtm_bco_difference = (gtm_bco >= m_bco_reference.second) ? (gtm_bco - m_bco_reference.second) : (gtm_bco + (1ULL << m_GTM_CLOCK_BITS) - m_bco_reference.second); m_multiplier_adjustment_numerator += gtm_bco_difference * delta_fee_bco; m_multiplier_adjustment_denominator += gtm_bco_difference * gtm_bco_difference; diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h index f89caee5f9..a023c6504a 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h @@ -106,6 +106,14 @@ class MicromegasBcoMatchingInformation_v2 uint64_t get_gtm_bco_last() const { return m_gtm_bco_list.empty() ? 0:*m_gtm_bco_list.rbegin(); } + //! get rollover corrected GTM bco depending on reference + uint64_t get_gtm_rollover_correction(uint64_t /*gtm_bco*/) const; + + //! returns true if more data needs to be fetched. + /** it is based on the latest BCO read from the data stream, from either tagger or heartbeat */ + bool is_more_data_required(uint64_t /*gtm_bco*/) const; + + //@} //!@name modifiers @@ -141,6 +149,12 @@ class MicromegasBcoMatchingInformation_v2 m_max_gtm_bco_diff = value; } + //! max time in GTM BCO for FEE data to sync over to datastream + static void set_m_max_fee_sync_time( unsigned int value ) + { + m_max_fee_sync_time = value; + } + //! find reference from modebits bool find_reference_from_modebits(const gtm_payload&); @@ -210,6 +224,9 @@ class MicromegasBcoMatchingInformation_v2 // define limit for matching fee_bco to fee_bco_predicted static unsigned int m_max_gtm_bco_diff; + //! max time in GTM BCO for FEE data to sync over to datastream + static unsigned int m_max_fee_sync_time; + //! adjustment to multiplier double m_multiplier_adjustment = 0; diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index a990a059a6..5d89af8837 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -228,12 +228,11 @@ SingleMicromegasPoolInput_v2::~SingleMicromegasPoolInput_v2() } //______________________________________________________________ -void SingleMicromegasPoolInput_v2::FillPool(const unsigned int /*nbclks*/) +void SingleMicromegasPoolInput_v2::FillPool(const uint64_t target_bco) { + if (AllDone()) // no more files and all events read - { - return; - } + { return; } while (!GetEventiterator()) // at startup this is a null pointer { @@ -244,9 +243,8 @@ void SingleMicromegasPoolInput_v2::FillPool(const unsigned int /*nbclks*/) } } - while (GetSomeMoreEvents()) + while( is_more_data_required(target_bco) ) { - // std::cout << "SingleMicromegasPoolInput_v2::FillPool" << std::endl; std::unique_ptr evt(GetEventiterator()->getNextEvent()); while (!evt) { @@ -326,15 +324,6 @@ void SingleMicromegasPoolInput_v2::Print(const std::string& what) const } } - if (what == "ALL" || what == "FEEBCLK") - { - for (auto bcliter : m_FEEBclkMap) - { - std::cout << "FEE" << bcliter.first << " bclk: 0x" - << std::hex << bcliter.second << std::dec << std::endl; - } - } - if (what == "ALL" || what == "STORAGE") { for (const auto& bcliter : m_MicromegasRawHitMap) @@ -350,13 +339,6 @@ void SingleMicromegasPoolInput_v2::Print(const std::string& what) const } } - if (what == "ALL" || what == "STACK") - { - for (const auto& iter : m_BclkStack) - { - std::cout << "stacked bclk: 0x" << std::hex << iter << std::dec << std::endl; - } - } } //____________________________________________________________________________ @@ -380,8 +362,6 @@ void SingleMicromegasPoolInput_v2::CleanupUsedPackets(const uint64_t bclk, bool } // cleanup bco stacks - /* it erases all elements for which the bco is no greater than the provided one */ - m_BclkStack.erase(m_BclkStack.begin(), m_BclkStack.upper_bound(bclk)); m_BeamClockFEE.erase(m_BeamClockFEE.begin(), m_BeamClockFEE.upper_bound(bclk)); m_BeamClockPacket.erase(m_BeamClockPacket.begin(), m_BeamClockPacket.upper_bound(bclk)); @@ -395,51 +375,24 @@ void SingleMicromegasPoolInput_v2::CleanupUsedPackets(const uint64_t bclk, bool //_______________________________________________________ void SingleMicromegasPoolInput_v2::ClearCurrentEvent() { - std::cout << "SingleMicromegasPoolInput_v2::ClearCurrentEvent." << std::endl; - uint64_t currentbclk = *m_BclkStack.begin(); - CleanupUsedPackets(currentbclk); - return; + std::cout << "SingleTpcTimeFrameInput::ClearCurrentEvent() - deprecated " << std::endl; } //_______________________________________________________ -bool SingleMicromegasPoolInput_v2::GetSomeMoreEvents() +bool SingleMicromegasPoolInput_v2::is_more_data_required(const uint64_t target_bco) const { if (AllDone()) { return false; } - // check minimum pool size - if (m_MicromegasRawHitMap.size() < m_BcoPoolSize) - { - return true; - } + if( m_bco_matching_information_map.empty() ) + { return true; } - // make sure that the latest BCO received by each FEEs is past the current BCO - std::set toerase; - uint64_t lowest_bclk = m_MicromegasRawHitMap.begin()->first + m_BcoRange; - for (auto bcliter : m_FEEBclkMap) - { - if (bcliter.second <= lowest_bclk) - { - uint64_t highest_bclk = m_MicromegasRawHitMap.rbegin()->first; - if ((highest_bclk - m_MicromegasRawHitMap.begin()->first) < MaxBclkDiff()) - { - return true; - } - - std::cout << PHWHERE << Name() << ": erasing FEE " << bcliter.first - << " with stuck bclk: " << std::hex << bcliter.second - << " current bco range: 0x" << m_MicromegasRawHitMap.begin()->first - << ", to: 0x" << highest_bclk << ", delta: " << std::dec - << (highest_bclk - m_MicromegasRawHitMap.begin()->first) - << std::dec << std::endl; - toerase.insert(bcliter.first); - } - } - for (const auto& fee : toerase) + for( const auto& [packet, bco_matching_information]:m_bco_matching_information_map ) { - m_FEEBclkMap.erase(fee); + if( bco_matching_information.is_more_data_required( target_bco ) ) + { return true; } } return false; @@ -759,7 +712,6 @@ void SingleMicromegasPoolInput_v2::decode_gtm_data(int packet_id, const SingleMi { const auto& gtm_bco = payload.bco; m_BeamClockPacket[gtm_bco].insert(packet_id); - m_BclkStack.insert(gtm_bco); } // find reference from modebits, using BX_COUNTER_SYNC_T @@ -1021,7 +973,6 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int } m_BeamClockFEE[gtm_bco].insert(fee_id); - m_FEEBclkMap[fee_id] = gtm_bco; if (StreamingInputManager()) { diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index 3746b9eb41..064638e752 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -25,10 +25,17 @@ class TH1; class SingleMicromegasPoolInput_v2 : public SingleStreamingInput { public: + + //! constructor explicit SingleMicromegasPoolInput_v2(const std::string &name = "SingleMicromegasPoolInput_v2"); + + //! destructor ~SingleMicromegasPoolInput_v2() override; - void FillPool(const unsigned int nevents = 1) override; + //! pool filling + void FillPool(const uint64_t /*target_bco*/) override; + + //! cleanup void CleanupUsedPackets(const uint64_t bclk) override { CleanupUsedPackets(bclk, false); @@ -37,17 +44,23 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput //! specialized verion of cleaning up packets, with an extra flag about wheter the cleanup hits are dropped or not void CleanupUsedPackets(const uint64_t /* bclk */, bool /*dropped */) override; + //! current event cleaning void ClearCurrentEvent() override; - bool GetSomeMoreEvents(); + + //! print void Print(const std::string &what = "ALL") const override; + + //! void CreateDSTNode(PHCompositeNode *topNode) override; void SetBcoRange(const unsigned int value) { m_BcoRange = value; } + void ConfigureStreamingInputManager() override; + void SetNegativeBco(const unsigned int value) { m_NegativeBco = value; } //! define minimum pool size in terms of how many BCO are stored - void SetBcoPoolSize(const unsigned int value) { m_BcoPoolSize = value; } + void SetBcoPoolSize(const unsigned int /*value*/) {} //! save some statistics for BCO QA void FillBcoQA(uint64_t /*gtm_bco*/) override; @@ -61,7 +74,11 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// output file name for evaluation histograms void set_evaluation_outputfile(const std::string &outputfile) { m_evaluation_filename = outputfile; } - private: + private: + + //! true if more data is to be processed for collecting that of a given bco + bool is_more_data_required(const uint64_t /*target_bco*/) const; + //!@name decoding constants //@{ /// max number of FEE per OBDC @@ -97,9 +114,6 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// bco adjustment for matching across subsystems unsigned int m_NegativeBco{0}; - //! minimum number of BCO required in Micromegas Pools - unsigned int m_BcoPoolSize{1}; - //! store list of packets that have data for a given beam clock /** * all packets in taggers are stored, @@ -114,18 +128,6 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput //! store list of raw hits matching a given bco std::map> m_MicromegasRawHitMap; - //! store current list of BCO on a per fee basis. - /** only packets for which a given FEE have data are stored */ - std::map m_FEEBclkMap; - - //! store current list of BCO - /** - * all packets in taggers are stored, - * disregarding whether there is data associated to it or not - * this allows to keep track of dropped data, also in zero-suppression mode - */ - std::set m_BclkStack; - //! map bco_information_t to packet id using bco_matching_information_map_t = std::map; bco_matching_information_map_t m_bco_matching_information_map; From 5afdda325735af221ad13eb1d39de858b81936cd Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 8 Jun 2026 22:08:14 -0400 Subject: [PATCH 640/866] fixed error message --- offline/framework/ffarawobjects/MicromegasRawHitv3.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/ffarawobjects/MicromegasRawHitv3.cc b/offline/framework/ffarawobjects/MicromegasRawHitv3.cc index 15bdd93a50..3799bfa1ef 100644 --- a/offline/framework/ffarawobjects/MicromegasRawHitv3.cc +++ b/offline/framework/ffarawobjects/MicromegasRawHitv3.cc @@ -11,7 +11,7 @@ MicromegasRawHitv3::MicromegasRawHitv3(MicromegasRawHit *source) { once = false; std::cout << "MicromegasRawHitv3::MicromegasRawHitv3(MicromegasRawHit *tpchit) - " - << "WARNING: This moethod is slow and should be avoided as much as possible! Please use the move constructor." + << "WARNING: This method is slow and should be avoided as much as possible! Please use the move constructor." << std::endl; } From 22c5f1c3b20aa581c8fe0cb88f291a8993986ccd Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 9 Jun 2026 15:26:49 -0400 Subject: [PATCH 641/866] - implement per FEE local rawhit storage - also store per FEE packet id. --- .../SingleMicromegasPoolInput_v2.cc | 65 ++++++++++--------- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 14 +++- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 5d89af8837..a7e6558bca 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -307,6 +307,7 @@ void SingleMicromegasPoolInput_v2::FillPool(const uint64_t target_bco) m_timer.stop(); } + } //______________________________________________________________ @@ -323,41 +324,34 @@ void SingleMicromegasPoolInput_v2::Print(const std::string& what) const } } } - - if (what == "ALL" || what == "STORAGE") - { - for (const auto& bcliter : m_MicromegasRawHitMap) - { - std::cout << "Beam clock 0x" << std::hex << bcliter.first << std::dec << std::endl; - for (auto* feeiter : bcliter.second) - { - std::cout - << "fee: " << feeiter->get_fee() - << " at " << std::hex << feeiter << std::dec - << std::endl; - } - } - } - } //____________________________________________________________________________ void SingleMicromegasPoolInput_v2::CleanupUsedPackets(const uint64_t bclk, bool dropped) { // delete all raw hits associated to bco smaller than reference, and remove from map - for (auto iter = m_MicromegasRawHitMap.begin(); iter != m_MicromegasRawHitMap.end() && (iter->first <= bclk); iter = m_MicromegasRawHitMap.erase(iter)) + // loop over per-FEE maps + for( auto&& rawhitmap: m_MicromegasRawHitMap ) { - for (const auto& rawhit : iter->second) + // loop over rawhit lists for which gtm bco is below request + // delete hits in list and remove list from map + for (auto iter = rawhitmap.begin(); iter != rawhitmap.end() && (iter->first <= bclk); iter = rawhitmap.erase(iter)) { - if (dropped) + for (const auto& rawhit : iter->second) { - // increment dropped waveform counter and histogram - ++m_waveform_counters[rawhit->get_packetid()].dropped_pool; - ++m_fee_waveform_counters[rawhit->get_fee()].dropped_pool; - h_waveform_count_dropped_pool->Fill(std::to_string(rawhit->get_packetid()).c_str(), 1); - h_fee_waveform_count_dropped_pool->Fill(rawhit->get_fee(), 1); + // increment dropped waveform counters + if (dropped) + { + // increment dropped waveform counter and histogram + ++m_waveform_counters[rawhit->get_packetid()].dropped_pool; + ++m_fee_waveform_counters[rawhit->get_fee()].dropped_pool; + h_waveform_count_dropped_pool->Fill(std::to_string(rawhit->get_packetid()).c_str(), 1); + h_fee_waveform_count_dropped_pool->Fill(rawhit->get_fee(), 1); + } + + // delete raw hit + delete rawhit; } - delete rawhit; } } @@ -455,10 +449,12 @@ void SingleMicromegasPoolInput_v2::FillBcoQA(uint64_t gtm_bco) } // waveforms - const auto wf_iter = m_MicromegasRawHitMap.find(gtm_bco_loc); - if (wf_iter != m_MicromegasRawHitMap.end()) + // loop over FEEs, find gtm bco and increment by number of rawhits in corresponding list + for( const auto& rawhitmap:m_MicromegasRawHitMap ) { - n_waveforms += wf_iter->second.size(); + const auto wf_iter = rawhitmap.find(gtm_bco_loc); + if (wf_iter != rawhitmap.end()) + { n_waveforms += wf_iter->second.size(); } } } @@ -657,6 +653,10 @@ void SingleMicromegasPoolInput_v2::process_packet(Packet* packet) // populate fee buffer if (fee_id < MAX_FEECOUNT) { + + // update FEE packet ID + m_fee_packet[fee_id] = packet_id; + // NOLINTNEXTLINE(modernize-loop-convert) for (unsigned int i = 0; i < DAM_DMA_WORD_LENGTH - 1; i++) { @@ -665,6 +665,7 @@ void SingleMicromegasPoolInput_v2::process_packet(Packet* packet) // immediate fee buffer processing to reduce memory consuption process_fee_data(packet_id, fee_id); + } } } @@ -974,11 +975,11 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int m_BeamClockFEE[gtm_bco].insert(fee_id); + // add hit to streaming input manager if (StreamingInputManager()) - { - StreamingInputManager()->AddMicromegasRawHit(gtm_bco, newhit.get()); - } + { StreamingInputManager()->AddMicromegasRawHit(gtm_bco, newhit.get()); } - m_MicromegasRawHitMap[gtm_bco].push_back(newhit.release()); + // add to local map + m_MicromegasRawHitMap[fee_id][gtm_bco].push_back(newhit.release()); } } diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index 064638e752..984078d4c8 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -125,13 +125,23 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput //! store list of FEE that have data for a given beam clock std::map> m_BeamClockFEE; - //! store list of raw hits matching a given bco - std::map> m_MicromegasRawHitMap; + //! list of raw hits + using rawhit_list_t = std::vector; + + //! maps list of raw hits on GTM BCO values + using rawhit_map_t = std::map; + + //! store list of raw hits matching a given GTM bco on a per FEE basis + std::array m_MicromegasRawHitMap{}; //! map bco_information_t to packet id using bco_matching_information_map_t = std::map; bco_matching_information_map_t m_bco_matching_information_map; + //! map packet to FEE ID + /* it is filled on the fly. It allows to quickly retrieve BCO matching information from FEE index */ + std::array m_fee_packet; + class counter_t { public: From 316fd67566c58997ae48dc5b5953034507c0a461 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 10 Jun 2026 16:14:07 -0400 Subject: [PATCH 642/866] First shot at recovering overlaping trigger frames. --- .../ffarawobjects/MicromegasRawHitv3.h | 8 +- .../MicromegasBcoMatchingInformation_v2.cc | 8 +- .../SingleMicromegasPoolInput_v2.cc | 159 +++++++++++++++++- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 12 +- 4 files changed, 176 insertions(+), 11 deletions(-) diff --git a/offline/framework/ffarawobjects/MicromegasRawHitv3.h b/offline/framework/ffarawobjects/MicromegasRawHitv3.h index 3a369be542..929dc1f232 100644 --- a/offline/framework/ffarawobjects/MicromegasRawHitv3.h +++ b/offline/framework/ffarawobjects/MicromegasRawHitv3.h @@ -65,8 +65,13 @@ class MicromegasRawHitv3 : public MicromegasRawHit //! adc list using adc_list_t = std::vector; + using waveform_pair_t = std::pair; + + // get adc values + const std::vector& get_adc_waveforms() const + { return m_adcData; } - // set adc values + // set adc values (move operator) void move_adc_waveform(const uint16_t start_time, adc_list_t &&adc); private: @@ -83,7 +88,6 @@ class MicromegasRawHitv3 : public MicromegasRawHit //! list of waveforms /** each pair contains the start sample of the waveform and the constituting adc values */ - using waveform_pair_t = std::pair; std::vector m_adcData; ClassDefOverride(MicromegasRawHitv3, 1) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index ee83878dec..cc88ca2d1c 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -19,8 +19,6 @@ namespace { - // streamer for lists - // streamer for lists template std::ostream& operator<<(std::ostream& o, const std::list& list) @@ -102,6 +100,9 @@ namespace /* used for rollover calculation */ static constexpr unsigned int m_GTM_CLOCK_BITS = 40; + static constexpr uint64_t m_GTM_CLOCK_MASK = (1ULL << m_GTM_CLOCK_BITS)-1; + static constexpr uint64_t m_GTM_CLOCK_ROLLOVER = 1ULL << m_GTM_CLOCK_BITS; + /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ enum SampaDataType { @@ -141,7 +142,6 @@ unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 100; // unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 16; unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 32; - //___________________________________________________ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_bco(uint64_t gtm_bco) const { @@ -194,7 +194,7 @@ uint64_t MicromegasBcoMatchingInformation_v2::get_gtm_rollover_correction(uint64 // check proper initialization if (!is_verified()) { return gtm_bco; } else if( gtm_bco >= m_bco_reference.second ) return gtm_bco; - else return gtm_bco+(1ULL << m_GTM_CLOCK_BITS); + else return gtm_bco+m_GTM_CLOCK_ROLLOVER; } //___________________________________________________ diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index a7e6558bca..27bcc1888c 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -142,6 +142,8 @@ namespace } // namespace +using MicromegasRawHit_impl = MicromegasRawHitv3; + //______________________________________________________________ SingleMicromegasPoolInput_v2::SingleMicromegasPoolInput_v2(const std::string& name) : SingleStreamingInput(name) @@ -308,6 +310,9 @@ void SingleMicromegasPoolInput_v2::FillPool(const uint64_t target_bco) m_timer.stop(); } + // recover truncated FEEs for target bco + recover_truncated_waveforms( target_bco ); + } //______________________________________________________________ @@ -473,6 +478,7 @@ void SingleMicromegasPoolInput_v2::FillBcoQA(uint64_t gtm_bco) // how many waveforms found for this BCO h_waveform->Fill(n_waveforms); } + //_______________________________________________________ void SingleMicromegasPoolInput_v2::createQAHistos() { @@ -956,7 +962,7 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int } // create new hit - auto newhit = std::make_unique(); + auto newhit = std::make_unique(); newhit->set_bco(fee_bco); newhit->set_gtm_bco(gtm_bco); @@ -980,6 +986,155 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int { StreamingInputManager()->AddMicromegasRawHit(gtm_bco, newhit.get()); } // add to local map - m_MicromegasRawHitMap[fee_id][gtm_bco].push_back(newhit.release()); + m_MicromegasRawHitMap[fee_id][gtm_bco].emplace_back(newhit.release()); } } + +//____________________________________________________________________ +void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t target_bco ) +{ + + // TODO: consolidate everything (ahah) + + static constexpr uint32_t kTruncatedWaveformWindow = 1024U; + static constexpr uint32_t kFEEClockPerADCClock = 2U; + static constexpr uint32_t kTruncatedWaveformFEEWindow = kTruncatedWaveformWindow*kFEEClockPerADCClock; + + using rawhit_array_t = std::array; + + // keep track of exact BCO + uint64_t found_bco = target_bco; + + // loop over fees + for( size_t fee = 0; fee < MAX_FEECOUNT; ++fee ) + { + + // get local raw hitmap + auto&& rawhitmap = m_MicromegasRawHitMap[fee]; + if( rawhitmap.empty() ) continue; + + // get the relevant BCO matching information object + const auto& bco_matching = m_bco_matching_information_map.at( m_fee_packet[fee] ); + const double truncatedWaveformGTMWindow = kTruncatedWaveformFEEWindow/bco_matching.get_adjusted_multiplier(); + + // find matching bco if any and store raw hits + // list of raw hits (channel ordered) matching target BCO + rawhit_array_t current_rawhits{}; + for( auto&& [bco, rawhitlist]:rawhitmap ) + { + + // compare bco to target, within acceptable range + // TODO properly acount for rollover. introduce a get_signed_diff + if( bco >= target_bco-m_NegativeBco && bco < target_bco+m_BcoRange ) + { + found_bco = bco; + for( auto&& rawhit:rawhitlist ) + { + if( rawhit->get_channel() < MAX_FEECHANNELCOUNT ) + { current_rawhits[rawhit->get_channel()] = rawhit; } + } + + break; + } + } + + // keep track of newly created hits + [[maybe_unused]] rawhit_array_t new_rawhits{}; + + // find candidate overlapping bco if any + for( auto&& [bco, rawhitlist]:rawhitmap ) + { + if( bco > found_bco && bco <= found_bco + truncatedWaveformGTMWindow ) + { + +// std::cout << "SingleMicromegasPoolInput_v2::recover_truncated_waveforms -" +// << " fee: " << fee +// << " target_bco: " << target_bco +// << " found_bco: " << found_bco +// << " bco: " << bco +// << std::endl; + + // perform overlap restoration + for( auto* source:rawhitlist ) + { + + // cast to versioned raw hit + auto* source_impl = static_cast(source); + + // get channel and check + const auto channel = source->get_channel(); + if( channel >= MAX_FEECHANNELCOUNT ) { continue; } + + // keep track of target hit + MicromegasRawHit_impl* target = nullptr; + + // check if there is an existing raw hit in current BCO at the same channel + if( current_rawhits[channel] ) + { + + // cast to versioned raw hit + target = static_cast(current_rawhits[channel]); + + } else { + + // get FEE BCO from GTM + auto result = bco_matching.get_predicted_fee_bco( target_bco ); + // auto result = bco_matching.get_predicted_fee_bco( found_bco ); + if( !result ) { continue; } + + const auto target_fee_bco = result.value(); + + // create new hit with shifted waveform + target = new MicromegasRawHit_impl; + + // copy relevant members from source + target->set_bco(target_fee_bco); + target->set_gtm_bco(source->get_gtm_bco()); + target->set_packetid(source->get_packetid()); + target->set_fee(source->get_fee()); + target->set_channel(source->get_channel()); + target->set_sampaaddress(source->get_sampaaddress()); + + // store in new array + new_rawhits[target->get_channel()] = target; + target->set_sampachannel(source->get_sampachannel()); + + } + + // calculate waveform shift + const uint64_t fee_bco_diff = source->get_bco() - target->get_bco(); + const uint16_t fee_clock_shift = static_cast(fee_bco_diff/kFEEClockPerADCClock); + + // get waveforms (copy) + auto waveformlist = source_impl->get_adc_waveforms(); + + // move copy to target hit, with properly shifted start time + for( auto&& [start_time,adc_list]:waveformlist) + { target->move_adc_waveform( start_time+fee_clock_shift, std::move(adc_list) ); } + + } + + // found overlapping BCO. stop here + break; + } + } + + // copy new hits in internal storage and add to streaming manager + for( auto* rawhit:new_rawhits ) + { + if( rawhit ) + { + // add hit to streaming input manager + if (StreamingInputManager()) + { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit); } + + // add hit to insternal storage + m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit); + } + } + + // TODO: should mark target BCO as corrected + + } + +} diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index 984078d4c8..7a219b53ad 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -84,6 +84,9 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// max number of FEE per OBDC static constexpr uint16_t MAX_FEECOUNT = 26; + /// max number of channels per FEE + static constexpr uint16_t MAX_FEECHANNELCOUNT = 256; + // Length for the 256-bit wide Round Robin Multiplexer for the data stream static constexpr size_t DAM_DMA_WORD_LENGTH = 16; //@} @@ -99,8 +102,11 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput void decode_gtm_data(int /*packet_id*/, const dma_word &); void process_fee_data(int /*packet_id*/, unsigned int /*fee_id*/); + // recover truncated waveforms for a given gtm bco + void recover_truncated_waveforms( const uint64_t /*target_bco*/ ); + // fee data buffer - std::vector> m_feeData{MAX_FEECOUNT}; + std::array, MAX_FEECOUNT> m_feeData{}; // list of packets from data stream std::array plist{}; @@ -136,11 +142,11 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput //! map bco_information_t to packet id using bco_matching_information_map_t = std::map; - bco_matching_information_map_t m_bco_matching_information_map; + bco_matching_information_map_t m_bco_matching_information_map{}; //! map packet to FEE ID /* it is filled on the fly. It allows to quickly retrieve BCO matching information from FEE index */ - std::array m_fee_packet; + std::array m_fee_packet{}; class counter_t { From b169597fcfe44a91f3230cc0276bea323d261bd1 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 10 Jun 2026 16:57:49 -0400 Subject: [PATCH 643/866] make sure duplicated waveform don't extend beyond the 1024 limit. --- .../SingleMicromegasPoolInput_v2.cc | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 27bcc1888c..54175c7557 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -1047,13 +1047,6 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t if( bco > found_bco && bco <= found_bco + truncatedWaveformGTMWindow ) { -// std::cout << "SingleMicromegasPoolInput_v2::recover_truncated_waveforms -" -// << " fee: " << fee -// << " target_bco: " << target_bco -// << " found_bco: " << found_bco -// << " bco: " << bco -// << std::endl; - // perform overlap restoration for( auto* source:rawhitlist ) { @@ -1079,7 +1072,6 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // get FEE BCO from GTM auto result = bco_matching.get_predicted_fee_bco( target_bco ); - // auto result = bco_matching.get_predicted_fee_bco( found_bco ); if( !result ) { continue; } const auto target_fee_bco = result.value(); @@ -1094,14 +1086,15 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t target->set_fee(source->get_fee()); target->set_channel(source->get_channel()); target->set_sampaaddress(source->get_sampaaddress()); + target->set_sampachannel(source->get_sampachannel()); // store in new array new_rawhits[target->get_channel()] = target; - target->set_sampachannel(source->get_sampachannel()); } // calculate waveform shift + // TODO: get proper diff with proper rollover const uint64_t fee_bco_diff = source->get_bco() - target->get_bco(); const uint16_t fee_clock_shift = static_cast(fee_bco_diff/kFEEClockPerADCClock); @@ -1110,7 +1103,17 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // move copy to target hit, with properly shifted start time for( auto&& [start_time,adc_list]:waveformlist) - { target->move_adc_waveform( start_time+fee_clock_shift, std::move(adc_list) ); } + { + + // make sure shifted start time is in acceptable window + if( start_time+fee_clock_shift >= kTruncatedWaveformWindow ) continue; + + // make sure all samples are in acceptable range + if( start_time+fee_clock_shift + adc_list.size() >= kTruncatedWaveformWindow ) + { adc_list.resize( start_time+fee_clock_shift - kTruncatedWaveformWindow ); } + + target->move_adc_waveform( start_time+fee_clock_shift, std::move(adc_list) ); + } } From 36310d926f0625e4153fc2f334b35f6c8428c4d5 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 Jun 2026 10:20:00 -0400 Subject: [PATCH 644/866] - Fix truncating raw hits. - do not save hits for which there is no waveforms. --- .../SingleMicromegasPoolInput_v2.cc | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 54175c7557..873972c800 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -1000,8 +1000,6 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t static constexpr uint32_t kFEEClockPerADCClock = 2U; static constexpr uint32_t kTruncatedWaveformFEEWindow = kTruncatedWaveformWindow*kFEEClockPerADCClock; - using rawhit_array_t = std::array; - // keep track of exact BCO uint64_t found_bco = target_bco; @@ -1010,6 +1008,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t { // get local raw hitmap + using rawhit_array_t = std::array; auto&& rawhitmap = m_MicromegasRawHitMap[fee]; if( rawhitmap.empty() ) continue; @@ -1039,7 +1038,8 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t } // keep track of newly created hits - [[maybe_unused]] rawhit_array_t new_rawhits{}; + using rawhit_impl_array_t = std::array; + rawhit_impl_array_t new_rawhits{}; // find candidate overlapping bco if any for( auto&& [bco, rawhitlist]:rawhitmap ) @@ -1109,10 +1109,11 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t if( start_time+fee_clock_shift >= kTruncatedWaveformWindow ) continue; // make sure all samples are in acceptable range - if( start_time+fee_clock_shift + adc_list.size() >= kTruncatedWaveformWindow ) - { adc_list.resize( start_time+fee_clock_shift - kTruncatedWaveformWindow ); } + if( start_time+fee_clock_shift + adc_list.size() > kTruncatedWaveformWindow ) + { adc_list.resize( kTruncatedWaveformWindow - start_time - fee_clock_shift ); } target->move_adc_waveform( start_time+fee_clock_shift, std::move(adc_list) ); + } } @@ -1127,12 +1128,17 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t { if( rawhit ) { - // add hit to streaming input manager - if (StreamingInputManager()) - { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit); } - - // add hit to insternal storage - m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit); + if( !rawhit->get_adc_waveforms().empty() ) + { + // add hit to streaming input manager + if (StreamingInputManager()) + { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit); } + + // add hit to insternal storage + m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit); + } else { + delete rawhit; + } } } From 3a1f3f88b04c64a86ca1800d042842968cdde015 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 Jun 2026 12:34:02 -0400 Subject: [PATCH 645/866] sanitize BCO differences (GTM and FEE) to properly account for clock rollover. Based on Jin's code. --- .../MicromegasBcoMatchingInformation_v2.cc | 131 +++++++++++------- .../MicromegasBcoMatchingInformation_v2.h | 23 ++- .../SingleMicromegasPoolInput_v2.cc | 17 +-- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 1 + 4 files changed, 108 insertions(+), 64 deletions(-) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index cc88ca2d1c..397f172274 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -80,15 +80,8 @@ namespace return o; } - // get the difference between two BCO. - template - constexpr T get_bco_diff(const T& first, const T& second) - { - return first < second ? (second - first) : (first - second); - } - // define limit for matching two fee_bco - constexpr unsigned int m_max_fee_bco_diff = 10; + constexpr uint32_t m_max_fee_bco_diff = 10; // needed to avoid memory leak. Assumes that we will not be assembling more than 50 events at the same time constexpr unsigned int m_max_matching_data_size = 50; @@ -98,10 +91,16 @@ namespace // gtm clock bits /* used for rollover calculation */ - static constexpr unsigned int m_GTM_CLOCK_BITS = 40; - + static constexpr unsigned int m_GTM_CLOCK_BITS = 40U; static constexpr uint64_t m_GTM_CLOCK_MASK = (1ULL << m_GTM_CLOCK_BITS)-1; - static constexpr uint64_t m_GTM_CLOCK_ROLLOVER = 1ULL << m_GTM_CLOCK_BITS; + static constexpr int64_t m_GTM_CLOCK_RANGE = 1ULL << m_GTM_CLOCK_BITS; + static constexpr int64_t m_GTM_CLOCK_HALF_RANGE = 1ULL << (m_GTM_CLOCK_BITS-1); + + // Fee clock bits + static constexpr unsigned int m_FEE_CLOCK_BITS = 20U; + static constexpr uint32_t m_FEE_CLOCK_MASK = (1ULL << m_FEE_CLOCK_BITS)-1; + static constexpr int32_t m_FEE_CLOCK_RANGE = 1ULL << m_FEE_CLOCK_BITS; + static constexpr int32_t m_FEE_CLOCK_HALF_RANGE = 1ULL << (m_FEE_CLOCK_BITS-1); /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ enum SampaDataType @@ -121,6 +120,7 @@ namespace BX_COUNTER_SYNC_T = 0b001, ELINK_HEARTBEAT_T = 0b010 }; + } // namespace // this is the clock multiplier from lvl1 to fee clock @@ -142,6 +142,46 @@ unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 100; // unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 16; unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 32; +//___________________________________________________ +int64_t MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff(uint64_t first, uint64_t second) +{ + // calculate raw diff + int64_t diff = static_cast(first & m_GTM_CLOCK_MASK) - static_cast(second & m_GTM_CLOCK_MASK); + + // make sure result is within +/- m_GTM_CLOCK_HALF_RANGE + if (diff > m_GTM_CLOCK_HALF_RANGE) { diff -= m_GTM_CLOCK_RANGE; } + else if (diff < -m_GTM_CLOCK_HALF_RANGE) { diff += m_GTM_CLOCK_RANGE; } + + return diff; +} + +//___________________________________________________ +int32_t MicromegasBcoMatchingInformation_v2::get_signed_fee_bco_diff(uint32_t first, uint32_t second) +{ + // calculate raw diff + int32_t diff = static_cast(first & m_FEE_CLOCK_MASK) - static_cast(second & m_FEE_CLOCK_MASK); + + // make sure result is within +/- m_FEE_CLOCK_HALF_RANGE + if (diff > m_FEE_CLOCK_HALF_RANGE) { diff -= m_FEE_CLOCK_RANGE; } + else if (diff < -m_FEE_CLOCK_HALF_RANGE) { diff += m_FEE_CLOCK_RANGE; } + + return diff; +} + +//___________________________________________________ +uint64_t MicromegasBcoMatchingInformation_v2::get_unsigned_gtm_bco_diff(uint64_t first, uint64_t second) +{ + const auto diff = get_signed_gtm_bco_diff(first, second); + return uint64_t((diff<0) ? -diff:diff); +} + +//___________________________________________________ +uint32_t MicromegasBcoMatchingInformation_v2::get_unsigned_fee_bco_diff(uint32_t first, uint32_t second) +{ + const auto diff = get_signed_fee_bco_diff(first, second); + return uint32_t((diff<0) ? -diff:diff); +} + //___________________________________________________ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_bco(uint64_t gtm_bco) const { @@ -151,12 +191,12 @@ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_b return std::nullopt; } - // get gtm bco difference with proper rollover accounting - const uint64_t gtm_bco_difference = get_gtm_rollover_correction(gtm_bco) - m_bco_reference.second; + // get gtm bco difference + const int64_t gtm_bco_difference = get_signed_gtm_bco_diff(gtm_bco, m_bco_reference.second); // convert to fee bco, and truncate to 20 bits - const uint64_t fee_bco_predicted = m_bco_reference.first + get_adjusted_multiplier() * gtm_bco_difference; - return uint32_t(fee_bco_predicted & 0xFFFFFU); + const int64_t fee_bco_predicted = m_bco_reference.first + get_adjusted_multiplier() * gtm_bco_difference; + return uint32_t(fee_bco_predicted & m_FEE_CLOCK_MASK); } //___________________________________________________ @@ -188,39 +228,27 @@ void MicromegasBcoMatchingInformation_v2::print_gtm_bco_information() const } } -//___________________________________________________ -uint64_t MicromegasBcoMatchingInformation_v2::get_gtm_rollover_correction(uint64_t gtm_bco) const -{ - // check proper initialization - if (!is_verified()) { return gtm_bco; } - else if( gtm_bco >= m_bco_reference.second ) return gtm_bco; - else return gtm_bco+m_GTM_CLOCK_ROLLOVER; -} - //___________________________________________________ bool MicromegasBcoMatchingInformation_v2::is_more_data_required( uint64_t gtm_bco ) const { // check proper initialization if( !is_verified() ) return true; - // get rollover corrected gtm - const auto gtm_bco_corrected = get_gtm_rollover_correction( gtm_bco ); - - // check against reference - if (m_bco_reference.second > gtm_bco_corrected + m_max_fee_sync_time) + // compare to reference + if( get_signed_gtm_bco_diff( m_bco_reference.second, gtm_bco ) > m_max_fee_sync_time ) { return false; } // check against stored bco if( !m_gtm_bco_list.empty() ) { - if (m_gtm_bco_list.back() > gtm_bco_corrected + m_max_fee_sync_time) + if( get_signed_gtm_bco_diff( m_gtm_bco_list.back(), gtm_bco ) > m_max_fee_sync_time ) { return false; } } // check against matched BCOs if( !m_bco_matching_list.empty() ) { - if (m_bco_matching_list.back().second > gtm_bco_corrected + m_max_fee_sync_time) + if( get_signed_gtm_bco_diff( m_bco_matching_list.back().second, gtm_bco ) > m_max_fee_sync_time ) { return false; } } @@ -288,15 +316,15 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay { // store gtm bco and diff to previous in an array std::vector gtm_bco_list; - std::vector gtm_bco_diff_list; + std::vector fee_bco_diff_list; for (const auto& gtm_bco : m_gtm_bco_list) { if (!gtm_bco_list.empty()) { // add difference to last // get gtm bco difference with proper rollover accounting - const uint64_t gtm_bco_difference = get_gtm_rollover_correction( gtm_bco ) - gtm_bco_list.back(); - gtm_bco_diff_list.push_back(get_adjusted_multiplier() * gtm_bco_difference); + const int64_t gtm_bco_difference = get_signed_gtm_bco_diff( gtm_bco, gtm_bco_list.back() ); + fee_bco_diff_list.push_back(get_adjusted_multiplier() * gtm_bco_difference); } // append to list @@ -306,7 +334,7 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay // print all differences if (verbosity()) { - std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - gtm_bco_diff_list: " << gtm_bco_diff_list << std::endl; + std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - fee_bco_diff_list: " << fee_bco_diff_list << std::endl; } // skip hearbeat @@ -330,7 +358,7 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay } // calculate difference - const uint64_t fee_bco_diff = get_bco_diff(fee_bco, m_fee_bco_prev); + const uint32_t fee_bco_diff = get_unsigned_fee_bco_diff(fee_bco, m_fee_bco_prev); // discard identical fee_bco if (fee_bco_diff < m_max_fee_bco_diff) @@ -341,13 +369,13 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - fee_bco_diff: " << fee_bco_diff << std::endl; // look for matching diff in gtm_bco array - for (size_t i = 0; i < gtm_bco_diff_list.size(); ++i) + for (size_t i = 0; i < fee_bco_diff_list.size(); ++i) { - uint64_t sum = 0; - for (size_t j = i; j < gtm_bco_diff_list.size(); ++j) + uint32_t sum = 0; + for (size_t j = i; j < fee_bco_diff_list.size(); ++j) { - sum += gtm_bco_diff_list[j]; - if (get_bco_diff(sum, fee_bco_diff) < m_max_fee_bco_diff) + sum += fee_bco_diff_list[j]; + if (get_unsigned_fee_bco_diff(sum, fee_bco_diff) < m_max_fee_bco_diff) { m_verified_from_data = true; m_bco_reference = { m_fee_bco_prev, gtm_bco_list[i] }; @@ -388,7 +416,7 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa m_bco_matching_list.begin(), m_bco_matching_list.end(), [fee_bco](const m_bco_matching_pair_t& pair) - { return get_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); + { return get_unsigned_fee_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); if (bco_matching_iter != m_bco_matching_list.end()) { @@ -399,7 +427,7 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [this, fee_bco](const uint64_t& gtm_bco) - { return get_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); + { return get_unsigned_fee_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); // check if (iter != m_gtm_bco_list.end()) @@ -410,7 +438,7 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa if (auto opt_fee_bco = get_predicted_fee_bco(gtm_bco)) // check if optional exists { const auto fee_bco_predicted = *opt_fee_bco; // get_predicted_fee_bco(gtm_bco).value(); - const auto fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco); + const auto fee_bco_diff = get_unsigned_fee_bco_diff(fee_bco_predicted, fee_bco); std::cout << "MicromegasBcoMatchingInformation_v2::find_gtm_bco -" << " packet_id: " << packet_id @@ -448,9 +476,8 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [this, fee_bco](const uint64_t& first, const uint64_t& second) - { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); + { return get_unsigned_fee_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_unsigned_fee_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); - // const int fee_bco_diff = (iter2 != m_gtm_bco_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1; // compared to the previous statement, this checks if the optional int fee_bco_diff = -1; @@ -460,7 +487,7 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa if (predicted) { - fee_bco_diff = get_bco_diff(*predicted, fee_bco); + fee_bco_diff = get_unsigned_fee_bco_diff(*predicted, fee_bco); } } @@ -541,12 +568,12 @@ void MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment(uint64_t gSystem->Exit(1); exit(1); } - const uint32_t fee_bco_predicted = *predicted_opt; - const double delta_fee_bco = double(fee_bco) - double(fee_bco_predicted); - const double gtm_bco_difference = (gtm_bco >= m_bco_reference.second) ? (gtm_bco - m_bco_reference.second) : (gtm_bco + (1ULL << m_GTM_CLOCK_BITS) - m_bco_reference.second); + const uint32_t fee_bco_predicted = predicted_opt.value(); + const double delta_fee_bco = get_signed_fee_bco_diff(fee_bco,fee_bco_predicted); + const double gtm_bco_difference = get_signed_gtm_bco_diff(gtm_bco,m_bco_reference.second); - m_multiplier_adjustment_numerator += gtm_bco_difference * delta_fee_bco; - m_multiplier_adjustment_denominator += gtm_bco_difference * gtm_bco_difference; + m_multiplier_adjustment_numerator += gtm_bco_difference*delta_fee_bco; + m_multiplier_adjustment_denominator += gtm_bco_difference*gtm_bco_difference; ++m_multiplier_adjustment_count; if (verbosity()) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h index a023c6504a..643b56a7b9 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h @@ -106,14 +106,10 @@ class MicromegasBcoMatchingInformation_v2 uint64_t get_gtm_bco_last() const { return m_gtm_bco_list.empty() ? 0:*m_gtm_bco_list.rbegin(); } - //! get rollover corrected GTM bco depending on reference - uint64_t get_gtm_rollover_correction(uint64_t /*gtm_bco*/) const; - //! returns true if more data needs to be fetched. /** it is based on the latest BCO read from the data stream, from either tagger or heartbeat */ bool is_more_data_required(uint64_t /*gtm_bco*/) const; - //@} //!@name modifiers @@ -179,6 +175,25 @@ class MicromegasBcoMatchingInformation_v2 //@} + //!@name utilities + //@{ + + //! get difference between two GTM BCO, properly accounting for 40bits rollover + /** based on Jin's code in TpcTimeFrameBuilder */ + static int64_t get_signed_gtm_bco_diff(uint64_t /*first*/, uint64_t /*second*/); + + //! get difference between two FEE BCO, properly accounting for 20bits rollover + /** based on Jin's code in TpcTimeFrameBuilder */ + static int32_t get_signed_fee_bco_diff(uint32_t /*first*/, uint32_t /*second*/); + + //! get difference between two GTM BCO, properly accounting for 40bits rollover + static uint64_t get_unsigned_gtm_bco_diff(uint64_t /*first*/, uint64_t /*second*/); + + //! get difference between two FEE BCO, properly accounting for 20bits rollover + static uint32_t get_unsigned_fee_bco_diff(uint32_t /*first*/, uint32_t /*second*/); + + //@} + private: //! update multiplier adjustment diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 873972c800..c7a8d4a3f7 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -996,9 +996,9 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // TODO: consolidate everything (ahah) - static constexpr uint32_t kTruncatedWaveformWindow = 1024U; - static constexpr uint32_t kFEEClockPerADCClock = 2U; - static constexpr uint32_t kTruncatedWaveformFEEWindow = kTruncatedWaveformWindow*kFEEClockPerADCClock; + static constexpr int32_t kTruncatedWaveformWindow = 1024U; + static constexpr int32_t kFEEClockPerADCClock = 2U; + static constexpr int32_t kTruncatedWaveformFEEWindow = kTruncatedWaveformWindow*kFEEClockPerADCClock; // keep track of exact BCO uint64_t found_bco = target_bco; @@ -1023,8 +1023,8 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t { // compare bco to target, within acceptable range - // TODO properly acount for rollover. introduce a get_signed_diff - if( bco >= target_bco-m_NegativeBco && bco < target_bco+m_BcoRange ) + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, found_bco ); + if( bco_diff >= -m_NegativeBco && bco_diff < m_BcoRange ) { found_bco = bco; for( auto&& rawhit:rawhitlist ) @@ -1044,7 +1044,8 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // find candidate overlapping bco if any for( auto&& [bco, rawhitlist]:rawhitmap ) { - if( bco > found_bco && bco <= found_bco + truncatedWaveformGTMWindow ) + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, found_bco ); + if( bco_diff > 0 && bco_diff < truncatedWaveformGTMWindow ) { // perform overlap restoration @@ -1095,8 +1096,8 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // calculate waveform shift // TODO: get proper diff with proper rollover - const uint64_t fee_bco_diff = source->get_bco() - target->get_bco(); - const uint16_t fee_clock_shift = static_cast(fee_bco_diff/kFEEClockPerADCClock); + const int64_t fee_bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_fee_bco_diff( source->get_bco(), target->get_bco() ); + const int16_t fee_clock_shift = static_cast(fee_bco_diff/kFEEClockPerADCClock); // get waveforms (copy) auto waveformlist = source_impl->get_adc_waveforms(); diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index 7a219b53ad..031bd85805 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -60,6 +60,7 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput void SetNegativeBco(const unsigned int value) { m_NegativeBco = value; } //! define minimum pool size in terms of how many BCO are stored + /** obsolete */ void SetBcoPoolSize(const unsigned int /*value*/) {} //! save some statistics for BCO QA From 6dec602aa24738d4f05ce09d569cf67976c31c48 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 Jun 2026 15:12:24 -0400 Subject: [PATCH 646/866] fixed some integer type --- .../fun4allraw/MicromegasBcoMatchingInformation_v2.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 397f172274..0a97f4b7e7 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -98,9 +98,9 @@ namespace // Fee clock bits static constexpr unsigned int m_FEE_CLOCK_BITS = 20U; - static constexpr uint32_t m_FEE_CLOCK_MASK = (1ULL << m_FEE_CLOCK_BITS)-1; - static constexpr int32_t m_FEE_CLOCK_RANGE = 1ULL << m_FEE_CLOCK_BITS; - static constexpr int32_t m_FEE_CLOCK_HALF_RANGE = 1ULL << (m_FEE_CLOCK_BITS-1); + static constexpr uint32_t m_FEE_CLOCK_MASK = (1UL << m_FEE_CLOCK_BITS)-1ULL; + static constexpr int32_t m_FEE_CLOCK_RANGE = 1UL << m_FEE_CLOCK_BITS; + static constexpr int32_t m_FEE_CLOCK_HALF_RANGE = 1UL << (m_FEE_CLOCK_BITS-1UL); /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ enum SampaDataType From a2a8dfbcd55646e696c2446241acc63d192faa92 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 Jun 2026 15:14:04 -0400 Subject: [PATCH 647/866] removed comment --- offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index c7a8d4a3f7..436b3031ad 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -1142,9 +1142,6 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t } } } - - // TODO: should mark target BCO as corrected - } } From 04c646e8e74589738d4c46a2ef5b1e68b36bdb28 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 11 Jun 2026 19:38:29 -0400 Subject: [PATCH 648/866] fix include file ordering, use std::numeric_limits --- calibrations/tpc/dEdx/dEdxFitter.h | 44 ++++++++++--------- generators/flowAfterburner/flowAfterburner.h | 24 +++++----- generators/sHijing/xml_test.cc | 17 ++++--- offline/QA/KFParticle/QAKFParticle.h | 3 +- offline/database/cdbobjects/CDBTTree.cc | 2 +- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 42 +++++++++--------- .../packages/PHGenFitPkg/PHGenFit/Fitter.h | 2 +- .../TruthNeutralMesonv1.h | 3 +- .../bcolumicount/StreamingBcoLumiReco.cc | 2 + .../bcolumicount/StreamingBcoLumiReco.h | 12 ++--- .../packages/globalvertex/GlobalVertexMap.h | 8 ++-- .../packages/globalvertex/GlobalVertexReco.h | 3 +- .../mvtx/MvtxCombinedRawDataDecoder.cc | 11 ----- .../mvtx/MvtxCombinedRawDataDecoder.h | 37 +++++++--------- offline/packages/tpc/TrainingHitsContainer.h | 5 ++- offline/packages/trackbase/ActsGeometry.cc | 6 ++- .../trackbase_historic/SvtxTrackSeed_v2.h | 12 ++--- .../trackbase_historic/TrackAnalysisUtils.cc | 11 ++--- .../TrackInfoContainer_v3.h | 5 ++- offline/packages/trackreco/ALICEKF.h | 4 +- offline/packages/trackreco/PHActsGSF.cc | 22 +++++----- .../trackreco/PHActsTrackProjection.h | 15 +++---- offline/packages/uspin/SpinDBNode.cc | 16 +++---- .../g4eval/compressor_generator.h | 2 +- simulation/g4simulation/g4eval/g4evalfn.cc | 8 ++-- .../g4simulation/g4gdml/PHG4GDMLWrite.hh | 4 +- .../g4gdml/PHG4GDMLWriteDefine.hh | 4 +- .../g4gdml/PHG4GDMLWriteMaterials.hh | 5 ++- .../g4gdml/PHG4GDMLWriteSolids.hh | 4 +- .../g4gdml/PHG4GDMLWriteStructure.hh | 4 +- .../g4mvtx/PHG4MvtxDisplayAction.cc | 2 +- .../g4simulation/g4tpc/PHG4TpcPadPlane.h | 5 ++- 32 files changed, 175 insertions(+), 169 deletions(-) diff --git a/calibrations/tpc/dEdx/dEdxFitter.h b/calibrations/tpc/dEdx/dEdxFitter.h index 0dc4da0f0c..dcec9d96f0 100644 --- a/calibrations/tpc/dEdx/dEdxFitter.h +++ b/calibrations/tpc/dEdx/dEdxFitter.h @@ -1,15 +1,19 @@ #ifndef DEDXFITTER_H_ #define DEDXFITTER_H_ -#include -#include +#include "GlobaldEdxFitter.h" + #include #include #include + #include + #include -#include "GlobaldEdxFitter.h" +#include + +#include //Forward declerations class PHCompositeNode; @@ -59,29 +63,29 @@ class dEdxFitter: public SubsysReco { ntracks_to_fit = ntrk; } private: - //output filename - std::string _outfile = "dedx_outfile.root"; - TFile* outf = nullptr; - size_t _event = 0; - - SvtxTrackMap* _trackmap = nullptr; - TrkrClusterContainer* _clustermap = nullptr; - ActsGeometry* _geometry = nullptr; - PHG4TpcGeomContainer* _tpcgeom = nullptr; - SvtxVertexMap* _vertexmap = nullptr; - //Get all the nodes void GetNodes(PHCompositeNode * /*topNode*/); void process_tracks(); - int nmaps_cut = 1; - int nintt_cut = 1; - int ntpc_cut = 30; - float eta_cut = 1.; - float dcaxy_cut = 0.5; + //output filename + std::string _outfile {"dedx_outfile.root"}; + TFile* outf {nullptr}; + size_t _event {0}; + + SvtxTrackMap* _trackmap {nullptr}; + TrkrClusterContainer* _clustermap {nullptr}; + ActsGeometry* _geometry {nullptr}; + PHG4TpcGeomContainer* _tpcgeom {nullptr}; + SvtxVertexMap* _vertexmap {nullptr}; + + int nmaps_cut {1}; + int nintt_cut {1}; + int ntpc_cut {30}; + float eta_cut {1.}; + float dcaxy_cut {0.5}; - size_t ntracks_to_fit = 40000; + size_t ntracks_to_fit {40000}; std::vector minima; std::unique_ptr fitter; diff --git a/generators/flowAfterburner/flowAfterburner.h b/generators/flowAfterburner/flowAfterburner.h index 8cac630401..6c3c77706c 100644 --- a/generators/flowAfterburner/flowAfterburner.h +++ b/generators/flowAfterburner/flowAfterburner.h @@ -1,11 +1,11 @@ #ifndef FLOWAFTERBURNER_FLOWAFTERBURNER_H #define FLOWAFTERBURNER_FLOWAFTERBURNER_H +#include "AfterburnerAlgo.h" + #include #include -#include "AfterburnerAlgo.h" - namespace CLHEP { class HepRandomEngine; @@ -63,18 +63,18 @@ class Afterburner private: - AfterburnerAlgo * m_algo = nullptr; - CLHEP::HepRandomEngine * m_engine = nullptr; - bool m_ownAlgo = false; - bool m_ownEngine = false; - float m_mineta = -5.0f; - float m_maxeta = 5.0f; - float m_minpt = 0.0f; - float m_maxpt = 100.0f; - double m_phishift = 0.0; // shift of the reaction plane angle in phi, used to align with the impact parameter + AfterburnerAlgo * m_algo {nullptr}; + CLHEP::HepRandomEngine * m_engine {nullptr}; + bool m_ownAlgo {false}; + bool m_ownEngine {false}; + float m_mineta {-5.0}; + float m_maxeta {5.0}; + float m_minpt {0.0}; + float m_maxpt {100.0}; + double m_phishift {0.0}; // shift of the reaction plane angle in phi, used to align with the impact parameter void setPsiN(unsigned int n, float psi); - float m_psi_n[6] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; // reaction plane angles + float m_psi_n[6] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // reaction plane angles // Legacy arguments void readLegacyArguments( diff --git a/generators/sHijing/xml_test.cc b/generators/sHijing/xml_test.cc index 587fd0e957..a6c1ba75f2 100644 --- a/generators/sHijing/xml_test.cc +++ b/generators/sHijing/xml_test.cc @@ -3,6 +3,14 @@ // // Inspired by code from ATLAS. Thanks! // +#define f2cFortran +#define gFortran + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#include "cfortran.h" +#pragma GCC diagnostic pop + #include #include #include @@ -12,15 +20,6 @@ #include #include -#define f2cFortran -#define gFortran - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#include "cfortran.h" -#pragma GCC diagnostic pop - -//using namespace boost; float atl_ran(int * /*unused*/) { diff --git a/offline/QA/KFParticle/QAKFParticle.h b/offline/QA/KFParticle/QAKFParticle.h index 60d47c158c..1123ac92d4 100644 --- a/offline/QA/KFParticle/QAKFParticle.h +++ b/offline/QA/KFParticle/QAKFParticle.h @@ -3,6 +3,8 @@ #ifndef QA_KFPARTICLE_QAKFPARTICLE_H #define QA_KFPARTICLE_QAKFPARTICLE_H +#include "QAKFParticleTrackPtAsymmetry.h" + #include #include @@ -15,7 +17,6 @@ #include -#include "QAKFParticleTrackPtAsymmetry.h" class KFParticle_Container; class PHCompositeNode; diff --git a/offline/database/cdbobjects/CDBTTree.cc b/offline/database/cdbobjects/CDBTTree.cc index 67f66c61a9..f43635ce5f 100644 --- a/offline/database/cdbobjects/CDBTTree.cc +++ b/offline/database/cdbobjects/CDBTTree.cc @@ -287,7 +287,7 @@ void CDBTTree::SetSingleIntValue(const std::string &name, int value) void CDBTTree::SetSingleUInt64Value(const std::string &name, uint64_t value) { std::string fieldname = "g" + name; - // if (m_SingleUInt64EntryMap.contains(fieldname)) + // if (!m_SingleUInt64EntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleUInt64EntryMap.find(fieldname) == m_SingleUInt64EntryMap.end()) { diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 8877c5be00..d7067e4cef 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -26,6 +26,7 @@ /*****************/ #include "KFParticle_Tools.h" +#include "KFParticle_truthAndDetTools.h" #include #include @@ -55,8 +56,6 @@ #include #include #include -#include "KFParticle_truthAndDetTools.h" - #include #include // for TMatrixD #include // for TMatrixT, operator* @@ -68,6 +67,7 @@ #include // for abs, NULL #include // for operator<<, basic_ostream #include // for end +#include #include // for _Rb_tree_iterator, map #include // for allocator_traits<>::va... @@ -78,13 +78,13 @@ KFParticle_Tools::KFParticle_Tools() : m_has_intermediates(false) , m_min_mass(0) , m_max_mass(0) - , m_min_decayTime(-1 * FLT_MAX) - , m_max_decayTime(FLT_MAX) - , m_min_decayLength(-1 * FLT_MAX) - , m_max_decayLength(FLT_MAX) + , m_min_decayTime(-1 * std::numeric_limits::max()) + , m_max_decayTime(std::numeric_limits::max()) + , m_min_decayLength(-1 * std::numeric_limits::max()) + , m_max_decayLength(std::numeric_limits::max()) , m_track_min_pt(0.) , m_track_max_pt(5e3) - , m_track_ptchi2(FLT_MAX) + , m_track_ptchi2(std::numeric_limits::max()) , m_track_ip_xy(-100.) , m_track_ipchi2_xy(-1) , m_track_ip(-1.) @@ -101,7 +101,7 @@ KFParticle_Tools::KFParticle_Tools() , m_dira_min(-1.01) , m_dira_max(1.01) , m_mother_pt(0.) - , m_mother_ipchi2(FLT_MAX) + , m_mother_ipchi2(std::numeric_limits::max()) , m_get_charge_conjugate(false) , m_extrapolateTracksToSV(true) , m_vtx_map_node_name("SvtxVertexMap") @@ -477,10 +477,10 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart { printSelectionCheck("Track pT", m_track_min_pt, pt, m_track_max_pt); printSelectionCheck("Track pT chi^2", 0, ptchi2, m_track_ptchi2); - printSelectionCheck("IP", m_track_ip, min_ip, FLT_MAX); - printSelectionCheck("IP chi^2", m_track_ipchi2, min_ipchi2, FLT_MAX); - printSelectionCheck("IP xy", m_track_ip_xy, min_ip_xy, FLT_MAX); - printSelectionCheck("IP xy chi^2", m_track_ipchi2_xy, min_ipchi2_xy, FLT_MAX); + printSelectionCheck("IP", m_track_ip, min_ip, std::numeric_limits::max()); + printSelectionCheck("IP chi^2", m_track_ipchi2, min_ipchi2, std::numeric_limits::max()); + printSelectionCheck("IP xy", m_track_ip_xy, min_ip_xy, std::numeric_limits::max()); + printSelectionCheck("IP xy chi^2", m_track_ipchi2_xy, min_ipchi2_xy, std::numeric_limits::max()); printSelectionCheck("Track chi^2/nDoF", 0, trackchi2ndof, m_track_chi2ndof); } } @@ -576,7 +576,7 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector= 11) { printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); - printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, FLT_MAX); + printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, std::numeric_limits::max()); } } @@ -662,7 +662,7 @@ std::vector> KFParticle_Tools::findNProngs(std::vector= 11) { printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); - printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, FLT_MAX); + printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, std::numeric_limits::max()); } } @@ -1008,8 +1008,8 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters printSelectionCheck("", "Accepted", "Rejected", "the intermediate selection", goodCandidate); if (m_verbosity >= 11) { - printSelectionCheck("Intermediate DIRA", m_intermediate_min_dira[k], intermediate_DIRA, FLT_MAX); - printSelectionCheck("Intermediate FD chi^2", m_intermediate_min_fdchi2[k], intermediate_FDchi2, FLT_MAX); + printSelectionCheck("Intermediate DIRA", m_intermediate_min_dira[k], intermediate_DIRA, std::numeric_limits::max()); + printSelectionCheck("Intermediate FD chi^2", m_intermediate_min_fdchi2[k], intermediate_FDchi2, std::numeric_limits::max()); } } } @@ -1022,7 +1022,7 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters { printSelectionCheck("Vertex charge is", "right", "wrong", "", chargeCheck); printSelectionCheck("Invariant Mass", min_mass, calculated_mass, max_mass); - printSelectionCheck("Mother pT", min_pt, calculated_pt, FLT_MAX); + printSelectionCheck("Mother pT", min_pt, calculated_pt, std::numeric_limits::max()); printSelectionCheck("Mother SV volume", 0., calculateEllipsoidVolume(mother), max_vertex_volume); } } @@ -1079,18 +1079,18 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida { printSelectionCheck("Mother DIRA", m_dira_min, calculated_dira, m_dira_max); printSelectionCheck("Mother DIRA xy", m_dira_xy_min, calculated_dira_xy, m_dira_xy_max); - printSelectionCheck("Mother FD chi^2", m_fdchi2, calculated_fdchi2, FLT_MAX); + printSelectionCheck("Mother FD chi^2", m_fdchi2, calculated_fdchi2, std::numeric_limits::max()); printSelectionCheck("Mother IP", 0, calculated_ip, m_mother_ip); printSelectionCheck("Mother IP chi^2", 0., calculated_ipchi2, m_mother_ipchi2); printSelectionCheck("Mother IP xy", 0., calculated_ip_xy, m_mother_ip_xy); printSelectionCheck("Mother IP xy chi^2", 0., calculated_ipchi2_xy, m_mother_ipchi2_xy); printSelectionCheck("Mother Decay Time", m_min_decayTime, calculated_decayTime, m_max_decayTime); - printSelectionCheck("Mother Decay Time Significance", m_mother_min_decay_time_significance, calculated_decay_time_significance, FLT_MAX); + printSelectionCheck("Mother Decay Time Significance", m_mother_min_decay_time_significance, calculated_decay_time_significance, std::numeric_limits::max()); printSelectionCheck("Mother Decay Time xy", m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy); printSelectionCheck("Mother Decay Length", m_min_decayLength, calculated_decayLength, m_max_decayLength); - printSelectionCheck("Mother Decay Length Significance", m_mother_min_decay_length_significance, calculated_decay_length_significance, FLT_MAX); + printSelectionCheck("Mother Decay Length Significance", m_mother_min_decay_length_significance, calculated_decay_length_significance, std::numeric_limits::max()); printSelectionCheck("Mother Decay Length xy", m_min_decayLength_xy, calculated_decayLength_xy, m_max_decayLength_xy); - printSelectionCheck("Mother Decay Length xy Significance", m_mother_min_decay_length_xy_significance, calculated_decay_length_xy_significance, FLT_MAX); + printSelectionCheck("Mother Decay Length xy Significance", m_mother_min_decay_length_xy_significance, calculated_decay_length_xy_significance, std::numeric_limits::max()); } } } diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h index 7f2ec1f761..958baa62aa 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h +++ b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h @@ -13,7 +13,7 @@ #include #include -#include "GenFit/Exception.h" +#include #include diff --git a/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h b/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h index 6386ebea67..2203ac6e57 100644 --- a/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h +++ b/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h @@ -1,9 +1,10 @@ #ifndef TRUTHNEUTRALMESONV1_H #define TRUTHNEUTRALMESONV1_H -#include #include "TruthNeutralMeson.h" +#include + class TruthNeutralMesonv1 : public TruthNeutralMeson { public: diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc index 277e7dfaf7..1e3c66d47f 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc @@ -28,6 +28,8 @@ #include #include // for Packet +#include + #include StreamingBcoLumiReco::StreamingBcoLumiReco(const std::string &name) diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.h b/offline/packages/bcolumicount/StreamingBcoLumiReco.h index a5066eb7c6..77e4e27f0e 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.h +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.h @@ -1,16 +1,16 @@ #ifndef BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H #define BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H +#include "StreamingLumiInfo.h" + #include #include -#include "StreamingLumiInfo.h" #include #include #include -#include - +class TH1; class StreamingBcoLumiReco : public SubsysReco { @@ -44,9 +44,9 @@ class StreamingBcoLumiReco : public SubsysReco static int CreateNodeTree(PHCompositeNode *topNode); const int trigbits = 40; Fun4AllHistoManager *hm = nullptr; - TH1I *h_bco_diff = nullptr; - TH1I *h_bco_diff_trigbits[40] = {nullptr}; - TH1I *h_bco_tag = nullptr; + TH1 *h_bco_diff = nullptr; + TH1 *h_bco_diff_trigbits[40] = {nullptr}; + TH1 *h_bco_tag = nullptr; uint64_t m_bco{0}; int m_bunches = 120; diff --git a/offline/packages/globalvertex/GlobalVertexMap.h b/offline/packages/globalvertex/GlobalVertexMap.h index 7ee70fa284..2ba8f6b0c6 100644 --- a/offline/packages/globalvertex/GlobalVertexMap.h +++ b/offline/packages/globalvertex/GlobalVertexMap.h @@ -3,9 +3,11 @@ #ifndef GLOBALVERTEX_GLOBALVERTEXMAP_H #define GLOBALVERTEX_GLOBALVERTEXMAP_H -#include #include "Vertex.h" #include "GlobalVertex.h" + +#include + #include #include @@ -15,7 +17,7 @@ class GlobalVertexMap : public PHObject typedef std::map::const_iterator ConstIter; typedef std::map::iterator Iter; - ~GlobalVertexMap() override {} + ~GlobalVertexMap() override = default; void identify(std::ostream& os = std::cout) const override { os << "GlobalVertexMap base class" << std::endl; } int isValid() const override { return 0; } @@ -42,7 +44,7 @@ class GlobalVertexMap : public PHObject virtual Iter end(); protected: - GlobalVertexMap() {} + GlobalVertexMap() = default; private: ClassDefOverride(GlobalVertexMap, 1); diff --git a/offline/packages/globalvertex/GlobalVertexReco.h b/offline/packages/globalvertex/GlobalVertexReco.h index 1149a17220..34240cf32b 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.h +++ b/offline/packages/globalvertex/GlobalVertexReco.h @@ -10,9 +10,10 @@ /// \author Mike McCumber //=========================================================== -#include #include "GlobalVertex.h" +#include + #include // for string class PHCompositeNode; diff --git a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc index 2a851b56b6..cc3ba5bcb3 100644 --- a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc +++ b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc @@ -180,11 +180,6 @@ void MvtxCombinedRawDataDecoder::GetNodes(PHCompositeNode *topNode) } } -//_____________________________________________________________________ -int MvtxCombinedRawDataDecoder::Init(PHCompositeNode * /*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} //____________________________________________________________________________.. int MvtxCombinedRawDataDecoder::InitRun(PHCompositeNode *topNode) @@ -365,12 +360,6 @@ int MvtxCombinedRawDataDecoder::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -//_____________________________________________________________________ -int MvtxCombinedRawDataDecoder::End(PHCompositeNode * /*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - // void MvtxCombinedRawDataDecoder::removeDuplicates( // std::vector > &v) diff --git a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h index 0dfce2bcd7..852b6fe1df 100644 --- a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h +++ b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h @@ -7,6 +7,8 @@ * \author Jakub Kvapil */ +#include "MvtxPixelMask.h" + #include #include @@ -16,7 +18,6 @@ #include #include -#include "MvtxPixelMask.h" class MvtxEventInfo; class MvtxRawEvtHeader; @@ -33,17 +34,11 @@ class MvtxCombinedRawDataDecoder : public SubsysReco /// constructor explicit MvtxCombinedRawDataDecoder(const std::string& name = "MvtxCombinedRawDataDecoder"); - /// global initialization - int Init(PHCompositeNode* /*dummy*/) override; - /// run initialization - int InitRun(PHCompositeNode* /*dummy*/) override; + int InitRun(PHCompositeNode *topNode) override; /// event processing - int process_event(PHCompositeNode* /*dummy*/) override; - - /// end of processing - int End(PHCompositeNode* /*dummy*/) override; + int process_event(PHCompositeNode *topNode) override; void useRawHitNodeName(const std::string& name) { m_MvtxRawHitNodeName = name; } @@ -63,20 +58,20 @@ class MvtxCombinedRawDataDecoder : public SubsysReco void CreateNodes(PHCompositeNode*); void GetNodes(PHCompositeNode*); - uint64_t gl1rawhitbco = 0; + uint64_t gl1rawhitbco {0}; - TrkrHitSetContainer* hit_set_container = nullptr; - TrkrHitSetContMvtxHelper* mvtx_hit_set_helper = nullptr; - MvtxEventInfo* mvtx_event_header = nullptr; - MvtxRawEvtHeader* mvtx_raw_event_header = nullptr; - MvtxRawHitContainer* mvtx_raw_hit_container = nullptr; - MvtxRawHit* mvtx_rawhit = nullptr; + TrkrHitSetContainer* hit_set_container {nullptr}; + TrkrHitSetContMvtxHelper* mvtx_hit_set_helper {nullptr}; + MvtxEventInfo* mvtx_event_header {nullptr}; + MvtxRawEvtHeader* mvtx_raw_event_header {nullptr}; + MvtxRawHitContainer* mvtx_raw_hit_container {nullptr}; + MvtxRawHit* mvtx_rawhit {nullptr}; - std::string m_MvtxRawHitNodeName = "MVTXRAWHIT"; - std::string m_MvtxRawEvtHeaderNodeName = "MVTXRAWEVTHEADER"; + std::string m_MvtxRawHitNodeName {"MVTXRAWHIT"}; + std::string m_MvtxRawEvtHeaderNodeName {"MVTXRAWEVTHEADER"}; - bool m_readStrWidthFromDB = true; - float m_strobeWidth = 89.; //! microseconds + bool m_readStrWidthFromDB {true}; + float m_strobeWidth {89.}; //! microseconds // mask hot pixels bool m_doOfflineMasking{false}; @@ -85,4 +80,4 @@ class MvtxCombinedRawDataDecoder : public SubsysReco bool m_mvtx_is_triggered{false}; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/tpc/TrainingHitsContainer.h b/offline/packages/tpc/TrainingHitsContainer.h index 28345adf57..33f38fe36a 100644 --- a/offline/packages/tpc/TrainingHitsContainer.h +++ b/offline/packages/tpc/TrainingHitsContainer.h @@ -1,14 +1,15 @@ #ifndef TRAININGHITSCONTAINER_H #define TRAININGHITSCONTAINER_H -#include #include "TrainingHits.h" +#include + class TrainingHitsContainer : public PHObject { public: TrainingHitsContainer(); - ~TrainingHitsContainer() override {} + ~TrainingHitsContainer() override = default; void Reset() override; std::vector v_hits; diff --git a/offline/packages/trackbase/ActsGeometry.cc b/offline/packages/trackbase/ActsGeometry.cc index 7965193149..8096be1896 100644 --- a/offline/packages/trackbase/ActsGeometry.cc +++ b/offline/packages/trackbase/ActsGeometry.cc @@ -1,15 +1,17 @@ #include "ActsGeometry.h" -#include #include "TpcDefs.h" #include "TrkrCluster.h" #include "alignmentTransformationContainer.h" + #include +#include + namespace { /// square template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h b/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h index b699ca25ba..c67322ef73 100644 --- a/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h +++ b/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h @@ -1,13 +1,13 @@ #ifndef TRACKBASEHISTORIC_SVTXTRACKSEED_V2_H #define TRACKBASEHISTORIC_SVTXTRACKSEED_V2_H -#include - #include "TrackSeed.h" -#include +#include + #include #include +#include class SvtxTrackSeed_v2 : public TrackSeed { @@ -33,9 +33,9 @@ class SvtxTrackSeed_v2 : public TrackSeed void set_crossing_estimate(const short int cross) override { m_crossing_estimate = cross; } private: - unsigned int m_silicon_seed = std::numeric_limits::max(); - unsigned int m_tpc_seed = std::numeric_limits::max(); - short int m_crossing_estimate = SHRT_MAX; + unsigned int m_silicon_seed {std::numeric_limits::max()}; + unsigned int m_tpc_seed {std::numeric_limits::max()}; + short int m_crossing_estimate {std::numeric_limits::max()}; ClassDefOverride(SvtxTrackSeed_v2, 1); }; diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 0a04d41f26..f7dbbb2b80 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -1,9 +1,9 @@ #include "TrackAnalysisUtils.h" -#include +#include "SvtxTrack.h" +#include "TrackSeed.h" -#include -#include +#include #include #include @@ -11,8 +11,9 @@ #include #include -#include "SvtxTrack.h" -#include "TrackSeed.h" + +#include +#include #include diff --git a/offline/packages/trackbase_historic/TrackInfoContainer_v3.h b/offline/packages/trackbase_historic/TrackInfoContainer_v3.h index 41d32c3f4c..d1f31d06a5 100644 --- a/offline/packages/trackbase_historic/TrackInfoContainer_v3.h +++ b/offline/packages/trackbase_historic/TrackInfoContainer_v3.h @@ -1,11 +1,12 @@ #ifndef TRACKINFOCONTAINERV3_H #define TRACKINFOCONTAINERV3_H -#include #include "SvtxTrackInfo.h" #include "SvtxTrackInfo_v3.h" #include "TrackInfoContainer.h" +#include + #include class TrackInfoContainer_v3 : public TrackInfoContainer @@ -38,7 +39,7 @@ class TrackInfoContainer_v3 : public TrackInfoContainer } protected: - TClonesArray *_clones = nullptr; + TClonesArray *_clones {nullptr}; private: ClassDefOverride(TrackInfoContainer_v3, 1); diff --git a/offline/packages/trackreco/ALICEKF.h b/offline/packages/trackreco/ALICEKF.h index 570b0d7777..86fdfa9ac7 100644 --- a/offline/packages/trackreco/ALICEKF.h +++ b/offline/packages/trackreco/ALICEKF.h @@ -1,13 +1,15 @@ #ifndef ALICEKF_H #define ALICEKF_H +#include "GPUTPCTrackParam.h" + #include + #include #include #include #include #include -#include "GPUTPCTrackParam.h" #include diff --git a/offline/packages/trackreco/PHActsGSF.cc b/offline/packages/trackreco/PHActsGSF.cc index 6523e87beb..85b9a2b4ae 100644 --- a/offline/packages/trackreco/PHActsGSF.cc +++ b/offline/packages/trackreco/PHActsGSF.cc @@ -1,15 +1,7 @@ #include "PHActsGSF.h" #include "MakeSourceLinks.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "ActsEvaluator.h" #include #include @@ -29,6 +21,17 @@ #include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -40,7 +43,6 @@ #include #include -#include "ActsEvaluator.h" #include diff --git a/offline/packages/trackreco/PHActsTrackProjection.h b/offline/packages/trackreco/PHActsTrackProjection.h index 0b06ae1ef8..79c5c62f5e 100644 --- a/offline/packages/trackreco/PHActsTrackProjection.h +++ b/offline/packages/trackreco/PHActsTrackProjection.h @@ -1,13 +1,14 @@ #ifndef TRACKRECO_PHACTSTRACKPROJECTION_H #define TRACKRECO_PHACTSTRACKPROJECTION_H -#include -#include -#include +#include "ActsPropagator.h" #include +#include -#include "ActsPropagator.h" +#include + +#include #include #include @@ -17,6 +18,8 @@ #include #include +#include +#include class PHCompositeNode; class RawClusterContainer; @@ -26,10 +29,6 @@ class SvtxTrackMap; class SvtxTrack; class SvtxVertexMap; -#include -#include -#include - /** * This class takes final fitted tracks from the Acts track fitting * and projects them out to cylinders with radius at the same radius diff --git a/offline/packages/uspin/SpinDBNode.cc b/offline/packages/uspin/SpinDBNode.cc index 6bb03fc55d..5b7e480195 100644 --- a/offline/packages/uspin/SpinDBNode.cc +++ b/offline/packages/uspin/SpinDBNode.cc @@ -1,6 +1,14 @@ #include "SpinDBNode.h" +#include "SpinDBContent.h" +#include "SpinDBContentv1.h" +#include "SpinDBOutput.h" + +#include + +#include #include +#include #include #include @@ -9,14 +17,6 @@ #include #include -#include - -#include -#include - -#include "SpinDBContent.h" -#include "SpinDBContentv1.h" -#include "SpinDBOutput.h" SpinDBNode::SpinDBNode(const std::string &name) : SubsysReco(name) diff --git a/simulation/g4simulation/g4eval/compressor_generator.h b/simulation/g4simulation/g4eval/compressor_generator.h index cf1b293479..072dccb60b 100644 --- a/simulation/g4simulation/g4eval/compressor_generator.h +++ b/simulation/g4simulation/g4eval/compressor_generator.h @@ -11,7 +11,7 @@ #include #include -#include "RtypesCore.h" +#include //----------------------------------------------------------------------------- UShort_t residesIn(Float_t raw, std::vector* dict) diff --git a/simulation/g4simulation/g4eval/g4evalfn.cc b/simulation/g4simulation/g4eval/g4evalfn.cc index 47971d974b..5da402f6c7 100644 --- a/simulation/g4simulation/g4eval/g4evalfn.cc +++ b/simulation/g4simulation/g4eval/g4evalfn.cc @@ -1,12 +1,14 @@ +#include "g4evalfn.h" + +#include "TrkrClusLoc.h" +#include "TrkrClusterIsMatcher.h" + #include #include #include #include #include -#include "TrkrClusLoc.h" -#include "TrkrClusterIsMatcher.h" -#include "g4evalfn.h" #include #include diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh index 0c18c92fcc..f22f534a54 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh @@ -40,7 +40,7 @@ #ifndef _PHG4GDMLWRITE_INCLUDED_ #define _PHG4GDMLWRITE_INCLUDED_ -#include +#include "PHG4GDMLAuxStructType.hh" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" @@ -52,8 +52,8 @@ #include +#include -#include "PHG4GDMLAuxStructType.hh" class G4LogicalVolume; class G4VPhysicalVolume; diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh index b7dbf38b81..8619bb18ee 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh @@ -40,12 +40,12 @@ #ifndef _PHG4GDMLWRITEDEFINE_INCLUDED_ #define _PHG4GDMLWRITEDEFINE_INCLUDED_ +#include "PHG4GDMLWrite.hh" + #include #include #include -#include "PHG4GDMLWrite.hh" - class PHG4GDMLWriteDefine : public PHG4GDMLWrite { diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh index f448bef7b2..e5eb3ac45a 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh @@ -40,11 +40,12 @@ #ifndef _PHG4GDMLWRITEMATERIALS_INCLUDED_ #define _PHG4GDMLWRITEMATERIALS_INCLUDED_ +#include "PHG4GDMLWriteDefine.hh" + #include -#include #include -#include "PHG4GDMLWriteDefine.hh" +#include class G4Isotope; class G4Element; diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh index 03c67f44a4..c67d13c885 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh @@ -40,11 +40,11 @@ #ifndef _PHG4GDMLWRITESOLIDS_INCLUDED_ #define _PHG4GDMLWRITESOLIDS_INCLUDED_ +#include "PHG4GDMLWriteMaterials.hh" + #include #include -#include "PHG4GDMLWriteMaterials.hh" - class G4BooleanSolid; class G4Box; class G4Cons; diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh index 2bf2aea5fe..9887d0cdf4 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh @@ -40,11 +40,11 @@ #ifndef _PHG4GDMLWRITESTRUCTURE_INCLUDED_ #define _PHG4GDMLWRITESTRUCTURE_INCLUDED_ +#include "PHG4GDMLWriteParamvol.hh" + #include #include -#include "PHG4GDMLWriteParamvol.hh" - class G4LogicalVolume; class G4VPhysicalVolume; class G4PVDivision; diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc index e04230ab24..3e9a58023d 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc @@ -1,7 +1,7 @@ #include "PHG4MvtxDisplayAction.h" #include -#include "g4main/PHG4DisplayAction.h" // for PHG4DisplayAction +#include // for PHG4DisplayAction #include #include diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h index 8c9e1cc8f3..6c9ff571e6 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h @@ -1,13 +1,14 @@ #ifndef G4TPC_PHG4TPCPADPLANE_H #define G4TPC_PHG4TPCPADPLANE_H -#include +#include "TpcClusterBuilder.h" #include -#include "TpcClusterBuilder.h" #include +#include + #include // for string class TrkrHitSetContainer; From 606cd937576dc4b5d1797f42589f048c82b1ac34 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 Jun 2026 19:02:23 -0400 Subject: [PATCH 649/866] clang-tidy --- .../MicromegasBcoMatchingInformation_v2.cc | 20 +++++++++---------- .../SingleMicromegasPoolInput_v2.cc | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 0a97f4b7e7..4a9fe4f85d 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -91,16 +91,16 @@ namespace // gtm clock bits /* used for rollover calculation */ - static constexpr unsigned int m_GTM_CLOCK_BITS = 40U; - static constexpr uint64_t m_GTM_CLOCK_MASK = (1ULL << m_GTM_CLOCK_BITS)-1; - static constexpr int64_t m_GTM_CLOCK_RANGE = 1ULL << m_GTM_CLOCK_BITS; - static constexpr int64_t m_GTM_CLOCK_HALF_RANGE = 1ULL << (m_GTM_CLOCK_BITS-1); + constexpr unsigned int m_GTM_CLOCK_BITS = 40U; + constexpr uint64_t m_GTM_CLOCK_MASK = (1ULL << m_GTM_CLOCK_BITS)-1; + constexpr int64_t m_GTM_CLOCK_RANGE = 1ULL << m_GTM_CLOCK_BITS; + constexpr int64_t m_GTM_CLOCK_HALF_RANGE = 1ULL << (m_GTM_CLOCK_BITS-1); // Fee clock bits - static constexpr unsigned int m_FEE_CLOCK_BITS = 20U; - static constexpr uint32_t m_FEE_CLOCK_MASK = (1UL << m_FEE_CLOCK_BITS)-1ULL; - static constexpr int32_t m_FEE_CLOCK_RANGE = 1UL << m_FEE_CLOCK_BITS; - static constexpr int32_t m_FEE_CLOCK_HALF_RANGE = 1UL << (m_FEE_CLOCK_BITS-1UL); + constexpr unsigned int m_FEE_CLOCK_BITS = 20U; + constexpr uint32_t m_FEE_CLOCK_MASK = (1UL << m_FEE_CLOCK_BITS)-1ULL; + constexpr int32_t m_FEE_CLOCK_RANGE = 1UL << m_FEE_CLOCK_BITS; + constexpr int32_t m_FEE_CLOCK_HALF_RANGE = 1UL << (m_FEE_CLOCK_BITS-1UL); /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ enum SampaDataType @@ -196,7 +196,7 @@ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_b // convert to fee bco, and truncate to 20 bits const int64_t fee_bco_predicted = m_bco_reference.first + get_adjusted_multiplier() * gtm_bco_difference; - return uint32_t(fee_bco_predicted & m_FEE_CLOCK_MASK); + return static_cast(fee_bco_predicted) & m_FEE_CLOCK_MASK; } //___________________________________________________ @@ -232,7 +232,7 @@ void MicromegasBcoMatchingInformation_v2::print_gtm_bco_information() const bool MicromegasBcoMatchingInformation_v2::is_more_data_required( uint64_t gtm_bco ) const { // check proper initialization - if( !is_verified() ) return true; + if( !is_verified() ) { return true; } // compare to reference if( get_signed_gtm_bco_diff( m_bco_reference.second, gtm_bco ) > m_max_fee_sync_time ) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 436b3031ad..a03fe65e51 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -1010,7 +1010,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // get local raw hitmap using rawhit_array_t = std::array; auto&& rawhitmap = m_MicromegasRawHitMap[fee]; - if( rawhitmap.empty() ) continue; + if( rawhitmap.empty() ) { continue; } // get the relevant BCO matching information object const auto& bco_matching = m_bco_matching_information_map.at( m_fee_packet[fee] ); From ad81fd1d7703e94161f65b0c495008fade9bd1fe Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 Jun 2026 19:07:39 -0400 Subject: [PATCH 650/866] use unique_ptr for creating new hits during truncated waveform recovery. --- .../fun4allraw/SingleMicromegasPoolInput_v2.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index a03fe65e51..765a498f2b 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -1038,7 +1038,8 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t } // keep track of newly created hits - using rawhit_impl_array_t = std::array; + using rawhit_impl_pointer_t = std::unique_ptr; // unique_ptr to raw hit implementation object + using rawhit_impl_array_t = std::array; // fixed size array of the above rawhit_impl_array_t new_rawhits{}; // find candidate overlapping bco if any @@ -1090,7 +1091,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t target->set_sampachannel(source->get_sampachannel()); // store in new array - new_rawhits[target->get_channel()] = target; + new_rawhits[target->get_channel()].reset(target); } @@ -1125,7 +1126,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t } // copy new hits in internal storage and add to streaming manager - for( auto* rawhit:new_rawhits ) + for( auto&& rawhit:new_rawhits ) { if( rawhit ) { @@ -1133,12 +1134,10 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t { // add hit to streaming input manager if (StreamingInputManager()) - { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit); } + { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit.get()); } // add hit to insternal storage - m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit); - } else { - delete rawhit; + m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit.release()); } } } From 820ad8a3b0a3d82fc1023177660ee072d82270bd Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 11 Jun 2026 19:56:51 -0400 Subject: [PATCH 651/866] bettern handling of rollover when doing gtm bco comparisons. --- .../MicromegasBcoMatchingInformation_v2.cc | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 4a9fe4f85d..22e30f087a 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -271,7 +271,7 @@ void MicromegasBcoMatchingInformation_v2::save_gtm_bco_information(int /*packet_ const auto& gtm_bco = payload.bco; // add to list if difference to last entry is big enough - if (m_gtm_bco_list.empty() || (gtm_bco - m_gtm_bco_list.back()) > 10) + if (m_gtm_bco_list.empty() || get_signed_gtm_bco_diff(gtm_bco,m_gtm_bco_list.back()) > 10) { m_gtm_bco_list.push_back(gtm_bco); } @@ -441,15 +441,15 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa const auto fee_bco_diff = get_unsigned_fee_bco_diff(fee_bco_predicted, fee_bco); std::cout << "MicromegasBcoMatchingInformation_v2::find_gtm_bco -" - << " packet_id: " << packet_id - << " fee_id: " << fee_id - << std::hex - << " fee_bco: 0x" << fee_bco - << " predicted: 0x" << fee_bco_predicted - << " gtm_bco: 0x" << gtm_bco - << std::dec - << " difference: " << fee_bco_diff - << std::endl; + << " packet_id: " << packet_id + << " fee_id: " << fee_id + << std::hex + << " fee_bco: 0x" << fee_bco + << " predicted: 0x" << fee_bco_predicted + << " gtm_bco: 0x" << gtm_bco + << std::dec + << " difference: " << fee_bco_diff + << std::endl; } } // save fee_bco and gtm_bco matching in map @@ -526,14 +526,13 @@ void MicromegasBcoMatchingInformation_v2::cleanup() void MicromegasBcoMatchingInformation_v2::cleanup(uint64_t ref_bco) { // erase all elements from bco_list that are less than or equal to ref_bco - m_gtm_bco_list.erase(std::remove_if(m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [ref_bco](const uint64_t& bco) - { return bco <= ref_bco; }), - m_gtm_bco_list.end()); + m_gtm_bco_list.erase(std::remove_if(m_gtm_bco_list.begin(), m_gtm_bco_list.end(), + [ref_bco](const uint64_t& bco) { return get_signed_gtm_bco_diff( bco,ref_bco ) <= 0; }), m_gtm_bco_list.end()); // erase all elements from bco_list that are less than or equal to ref_bco - m_bco_matching_list.erase(std::remove_if(m_bco_matching_list.begin(), m_bco_matching_list.end(), [ref_bco](const m_bco_matching_pair_t& pair) - { return pair.second <= ref_bco; }), - m_bco_matching_list.end()); + m_bco_matching_list.erase(std::remove_if(m_bco_matching_list.begin(), m_bco_matching_list.end(), + [ref_bco](const m_bco_matching_pair_t& pair) { return get_signed_gtm_bco_diff( pair.second, ref_bco ) <= 0; }), + m_bco_matching_list.end()); // clear orphans m_orphans.clear(); From 0b9b8c162660ee3a7b271178e5c8574561406f14 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 11 Jun 2026 21:02:53 -0400 Subject: [PATCH 652/866] restore previous version of PHActsGSF.cc which is not part of our build --- offline/packages/trackreco/PHActsGSF.cc | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/offline/packages/trackreco/PHActsGSF.cc b/offline/packages/trackreco/PHActsGSF.cc index 85b9a2b4ae..6523e87beb 100644 --- a/offline/packages/trackreco/PHActsGSF.cc +++ b/offline/packages/trackreco/PHActsGSF.cc @@ -1,7 +1,15 @@ #include "PHActsGSF.h" #include "MakeSourceLinks.h" -#include "ActsEvaluator.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -21,17 +29,6 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include @@ -43,6 +40,7 @@ #include #include +#include "ActsEvaluator.h" #include From 0d58a9a8f895bab2ec0dd05e2fe6dbcbd66e5d54 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 11 Jun 2026 21:03:20 -0400 Subject: [PATCH 653/866] fix clang-tidy --- simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh b/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh index 120a335861..5545c16933 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh @@ -36,6 +36,8 @@ #ifndef _PHG4GDMLAUXSTRUCTTYPE_INCLUDED_ #define _PHG4GDMLAUXSTRUCTTYPE_INCLUDED_ +#include + #include struct PHG4GDMLAuxStructType From ac03253aeb9b091d5e4169a3df5808e4d4e7b3af Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 12 Jun 2026 09:51:04 -0400 Subject: [PATCH 654/866] - Fixed nasty bug when comparing bco diff to matching range - added some debug output. --- .../SingleMicromegasPoolInput_v2.cc | 58 ++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 765a498f2b..41c7969baf 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -941,12 +941,13 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int { if (Verbosity()) { - std::cout << "SingleMicromegasPoolInput_v2::process_fee_data -" - << " samples: " << samples - << " pos: " << pos - << " pkt_length: " << pkt_length - << " format error" - << std::endl; + std::cout + << "SingleMicromegasPoolInput_v2::process_fee_data -" + << " samples: " << samples + << " pos: " << pos + << " pkt_length: " << pkt_length + << " format error" + << std::endl; } break; } @@ -1023,10 +1024,19 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t { // compare bco to target, within acceptable range - const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, found_bco ); - if( bco_diff >= -m_NegativeBco && bco_diff < m_BcoRange ) + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco ); + if( bco_diff >= -(int64_t)m_NegativeBco && bco_diff < m_BcoRange ) { found_bco = bco; + if( Verbosity() ) + { + std::cout << "SingleMicromegasPoolInput_v2::recover_truncated_waveforms -" + << " fee: " << fee + << " target_bco: " << target_bco + << " found_bco: " << found_bco + << std::endl; + } + for( auto&& rawhit:rawhitlist ) { if( rawhit->get_channel() < MAX_FEECHANNELCOUNT ) @@ -1045,10 +1055,20 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // find candidate overlapping bco if any for( auto&& [bco, rawhitlist]:rawhitmap ) { - const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, found_bco ); - if( bco_diff > 0 && bco_diff < truncatedWaveformGTMWindow ) + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco ); + if( bco_diff >= m_BcoRange && bco_diff < truncatedWaveformGTMWindow ) { + if( Verbosity() ) + { + std::cout << "SingleMicromegasPoolInput_v2::recover_truncated_waveforms -" + << " fee: " << fee + << " target_bco: " << target_bco + << " found_bco: " << found_bco + << " overlaping bco: " << bco + << std::endl; + } + // perform overlap restoration for( auto* source:rawhitlist ) { @@ -1128,19 +1148,17 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // copy new hits in internal storage and add to streaming manager for( auto&& rawhit:new_rawhits ) { - if( rawhit ) + if( rawhit && !rawhit->get_adc_waveforms().empty() ) { - if( !rawhit->get_adc_waveforms().empty() ) - { - // add hit to streaming input manager - if (StreamingInputManager()) - { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit.get()); } + // add hit to streaming input manager + if (StreamingInputManager()) + { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit.get()); } - // add hit to insternal storage - m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit.release()); - } + // add hit to insternal storage + m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit.release()); } } - } + + } // FEE loop } From bece3f0bd1612bda0d655d3066bcd8b5ab53b537 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Fri, 12 Jun 2026 10:27:19 -0400 Subject: [PATCH 655/866] Trying again! --- .../TrackingDiagnostics/TrackResiduals.cc | 173 ++++++++++ .../TrackingDiagnostics/TrackResiduals.h | 53 ++- .../TrackingDiagnostics/TrkrNtuplizer.cc | 60 +++- offline/packages/tpc/TpcClusterizer.cc | 305 +++++++++++++++--- 4 files changed, 536 insertions(+), 55 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 1a5a69fae0..d123176d70 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -46,6 +46,8 @@ #include #include +#include + #include #include #include @@ -57,6 +59,7 @@ #include #include #include +#include #include @@ -126,6 +129,7 @@ int TrackResiduals::InitRun(PHCompositeNode* topNode) void TrackResiduals::clearClusterStateVectors() { m_cluskeys.clear(); + m_clussize.clear(); m_clusphisize.clear(); m_cluszsize.clear(); m_idealsurfcenterx.clear(); @@ -183,7 +187,23 @@ void TrackResiduals::clearClusterStateVectors() m_statelzlocderivqop.clear(); m_clusedge.clear(); + m_clussledge.clear(); + m_clussredge.clear(); + m_clustledge.clear(); + m_clustredge.clear(); + m_clusdledge.clear(); + m_clusdredge.clear(); + m_clushledge.clear(); + m_clushredge.clear(); + m_clusslmix.clear(); + m_clussrmix.clear(); + m_clustlmix.clear(); + m_clustrmix.clear(); m_clusoverlap.clear(); + m_clusPadCen.clear(); + m_clusTBinCen.clear(); + m_clusPadMax.clear(); + m_clusTBinMax.clear(); m_cluslx.clear(); m_cluslz.clear(); m_cluselx.clear(); @@ -197,7 +217,14 @@ void TrackResiduals::clearClusterStateVectors() m_clusgzunmoved.clear(); m_clusAdc.clear(); m_clusMaxAdc.clear(); + m_clusCenAdc.clear(); m_cluslayer.clear(); + m_clusphibinlo.clear(); + m_clusphibinhi.clear(); + m_clustbinlo.clear(); + m_clustbinhi.clear(); + m_cluspadphase.clear(); + m_clustbinphase.clear(); m_statelx.clear(); m_statelz.clear(); @@ -301,6 +328,21 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) } } + EventHeader* eventheader = findNode::getClass(topNode, "EventHeader"); + + if(eventheader) + { + m_evt_id = eventheader->get_EvtSequence(); + } + else + { + m_evt_id = -1; + } + + auto *rcs = recoConsts::instance(); + m_runnumber = rcs->get_IntFlag("RUNNUMBER"); + m_segment = rcs->get_IntFlag("RUNSEGMENT"); + m_ntpcclus = 0; if (Verbosity() > 1) { @@ -662,11 +704,37 @@ void TrackResiduals::fillClusterTree(TrkrClusterContainer* clusters, m_scluseta = acos(glob.z() / std::sqrt(square(glob.x()) + square(glob.y()) + square(glob.z()))); m_adc = cluster->getAdc(); m_clusmaxadc = cluster->getMaxAdc(); + m_cluscenadc = cluster->getCenAdc(); + m_padcen = cluster->getPadCen(); + m_tbincen = cluster->getTBinCen(); + m_padmax = cluster->getPadMax(); + m_tbinmax = cluster->getTBinMax(); m_scluslx = cluster->getLocalX(); m_scluslz = cluster->getLocalY(); + m_phibinlo = cluster->getPhiBinLo(); + m_phibinhi = cluster->getPhiBinHi(); + m_tbinlo = cluster->getTBinLo(); + m_tbinhi = cluster->getTBinHi(); + m_padphase = cluster->getPadPhase(); + m_tbinphase = cluster->getTBinPhase(); auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, m_sclusgr, key); + m_size = cluster->getRSize(); m_phisize = cluster->getPhiSize(); m_zsize = cluster->getZSize(); + m_overlap = cluster->getOverlap(); + m_nedge = cluster->getEdge(); + m_sledge = cluster->getSLEdge(); + m_sredge = cluster->getSREdge(); + m_tledge = cluster->getTLEdge(); + m_tredge = cluster->getTREdge(); + m_dledge = cluster->getDLEdge(); + m_dredge = cluster->getDREdge(); + m_hledge = cluster->getHLEdge(); + m_hredge = cluster->getHREdge(); + m_slmix = cluster->getSLMix(); + m_srmix = cluster->getSRMix(); + m_tlmix = cluster->getTLMix(); + m_trmix = cluster->getTRMix(); m_scluselx = std::sqrt(para_errors.first); m_scluselz = std::sqrt(para_errors.second); @@ -1087,7 +1155,19 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); + m_clussledge.push_back(cluster->getSLEdge()); + m_clussredge.push_back(cluster->getSREdge()); + m_clustledge.push_back(cluster->getTLEdge()); + m_clustredge.push_back(cluster->getTREdge()); + m_clusdledge.push_back(cluster->getDLEdge()); + m_clusdredge.push_back(cluster->getDREdge()); + m_clushledge.push_back(cluster->getHLEdge()); + m_clushredge.push_back(cluster->getHREdge()); m_clusoverlap.push_back(cluster->getOverlap()); + m_clusslmix.push_back(cluster->getSLMix()); + m_clussrmix.push_back(cluster->getSRMix()); + m_clustlmix.push_back(cluster->getTLMix()); + m_clustrmix.push_back(cluster->getTRMix()); // get new local coords from moved cluster Surface surf = geometry->maps().getSurface(ckey, cluster); @@ -1160,9 +1240,21 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); + m_clusCenAdc.push_back(cluster->getCenAdc()); + m_clusPadCen.push_back(cluster->getPadCen()); + m_clusTBinCen.push_back(cluster->getTBinCen()); + m_clusPadMax.push_back(cluster->getPadMax()); + m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); + m_clusphibinlo.push_back(cluster->getPhiBinLo()); + m_clusphibinhi.push_back(cluster->getPhiBinHi()); + m_clustbinlo.push_back(cluster->getTBinLo()); + m_clustbinhi.push_back(cluster->getTBinHi()); + m_cluspadphase.push_back(cluster->getPadPhase()); + m_clustbinphase.push_back(cluster->getTBinPhase()); auto misaligncenter = surf->center(geometry->geometry().getGeoContext()); auto misalignnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); @@ -1416,6 +1508,18 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); + m_clussledge.push_back(cluster->getSLEdge()); + m_clussredge.push_back(cluster->getSREdge()); + m_clustledge.push_back(cluster->getTLEdge()); + m_clustredge.push_back(cluster->getTREdge()); + m_clusdledge.push_back(cluster->getDLEdge()); + m_clusdredge.push_back(cluster->getDREdge()); + m_clushledge.push_back(cluster->getHLEdge()); + m_clushredge.push_back(cluster->getHREdge()); + m_clusslmix.push_back(cluster->getSLMix()); + m_clussrmix.push_back(cluster->getSRMix()); + m_clustlmix.push_back(cluster->getTLMix()); + m_clustrmix.push_back(cluster->getTRMix()); m_clusoverlap.push_back(cluster->getOverlap()); // This is the nominal position of the cluster in local coords, completely uncorrected - is that what we want? @@ -1438,9 +1542,21 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); + m_clusCenAdc.push_back(cluster->getCenAdc()); + m_clusPadCen.push_back(cluster->getPadCen()); + m_clusTBinCen.push_back(cluster->getTBinCen()); + m_clusPadMax.push_back(cluster->getPadMax()); + m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); + m_clusphibinlo.push_back(cluster->getPhiBinLo()); + m_clusphibinhi.push_back(cluster->getPhiBinHi()); + m_clustbinlo.push_back(cluster->getTBinLo()); + m_clustbinhi.push_back(cluster->getTBinHi()); + m_cluspadphase.push_back(cluster->getPadPhase()); + m_clustbinphase.push_back(cluster->getTBinPhase()); if (Verbosity() > 1) { @@ -1607,6 +1723,7 @@ void TrackResiduals::createBranches() m_eventtree->Branch("run", &m_runnumber, "m_runnumber/I"); m_eventtree->Branch("segment", &m_segment, "m_segment/I"); m_eventtree->Branch("event", &m_event, "m_event/I"); + m_eventtree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_eventtree->Branch("gl1bco", &m_bco, "m_bco/I"); m_eventtree->Branch("nmvtx", &m_nmvtx_all, "m_nmvtx_all/I"); m_eventtree->Branch("nintt", &m_nintt_all, "m_nintt_all/I"); @@ -1627,6 +1744,7 @@ void TrackResiduals::createBranches() m_failedfits->Branch("segment", &m_segment, "m_segment/I"); m_failedfits->Branch("trackid", &m_trackid, "m_trackid/I"); m_failedfits->Branch("event", &m_event, "m_event/I"); + m_failedfits->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_failedfits->Branch("silseedx", &m_silseedx, "m_silseedx/F"); m_failedfits->Branch("silseedy", &m_silseedy, "m_silseedy/F"); m_failedfits->Branch("silseedz", &m_silseedz, "m_silseedz/F"); @@ -1653,6 +1771,7 @@ void TrackResiduals::createBranches() m_vertextree->Branch("run", &m_runnumber, "m_runnumber/I"); m_vertextree->Branch("segment", &m_segment, "m_segment/I"); m_vertextree->Branch("event", &m_event, "m_event/I"); + m_vertextree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_vertextree->Branch("firedTriggers", &m_firedTriggers); m_vertextree->Branch("gl1BunchCrossing", &m_gl1BunchCrossing, "m_gl1BunchCrossing/l"); m_vertextree->Branch("gl1bco", &m_bco, "m_bco/l"); @@ -1675,6 +1794,7 @@ void TrackResiduals::createBranches() m_hittree->Branch("run", &m_runnumber, "m_runnumber/I"); m_hittree->Branch("segment", &m_segment, "m_segment/I"); m_hittree->Branch("event", &m_event, "m_event/I"); + m_hittree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_hittree->Branch("gl1bco", &m_bco, "m_bco/l"); m_hittree->Branch("hitsetkey", &m_hitsetkey, "m_hitsetkey/i"); m_hittree->Branch("gx", &m_hitgx, "m_hitgx/F"); @@ -1704,6 +1824,7 @@ void TrackResiduals::createBranches() m_clustree->Branch("run", &m_runnumber, "m_runnumber/I"); m_clustree->Branch("segment", &m_segment, "m_segment/I"); m_clustree->Branch("event", &m_event, "m_event/I"); + m_clustree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_clustree->Branch("gl1bco", &m_bco, "m_bco/l"); m_clustree->Branch("lx", &m_scluslx, "m_scluslx/F"); m_clustree->Branch("lz", &m_scluslz, "m_scluslz/F"); @@ -1713,11 +1834,37 @@ void TrackResiduals::createBranches() m_clustree->Branch("phi", &m_sclusphi, "m_sclusphi/F"); m_clustree->Branch("eta", &m_scluseta, "m_scluseta/F"); m_clustree->Branch("adc", &m_adc, "m_adc/F"); + m_clustree->Branch("size", &m_size, "m_size/I"); m_clustree->Branch("phisize", &m_phisize, "m_phisize/I"); m_clustree->Branch("zsize", &m_zsize, "m_zsize/I"); + m_clustree->Branch("phibinlo", &m_phibinlo, "m_phibinlo/F"); + m_clustree->Branch("phibinhi", &m_phibinhi, "m_phibinhi/F"); + m_clustree->Branch("tbinlo", &m_tbinlo, "m_tbinlo/F"); + m_clustree->Branch("tbinhi", &m_tbinhi, "m_tbinhi/F"); + m_clustree->Branch("padphase", &m_padphase, "m_padphase/F"); + m_clustree->Branch("tbinphase", &m_tbinphase, "m_tbinphase/F"); + m_clustree->Branch("overlap", &m_overlap, "m_overlap/I"); + m_clustree->Branch("nedge", &m_nedge, "m_nedge/I"); + m_clustree->Branch("sledge", &m_sledge, "m_sledge/I"); + m_clustree->Branch("sredge", &m_sredge, "m_sredge/I"); + m_clustree->Branch("tledge", &m_tledge, "m_tledge/I"); + m_clustree->Branch("tredge", &m_tredge, "m_tredge/I"); + m_clustree->Branch("dledge", &m_dledge, "m_dledge/I"); + m_clustree->Branch("dredge", &m_dredge, "m_dredge/I"); + m_clustree->Branch("hledge", &m_hledge, "m_hledge/I"); + m_clustree->Branch("hredge", &m_hredge, "m_hredge/I"); + m_clustree->Branch("slmix", &m_slmix, "m_slmix/I"); + m_clustree->Branch("srmix", &m_srmix, "m_srmix/I"); + m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/I"); + m_clustree->Branch("trmix", &m_trmix, "m_trmix/I"); m_clustree->Branch("erphi", &m_scluselx, "m_scluselx/F"); m_clustree->Branch("ez", &m_scluselz, "m_scluselz/F"); m_clustree->Branch("maxadc", &m_clusmaxadc, "m_clusmaxadc/F"); + m_clustree->Branch("cenadc", &m_cluscenadc, "m_cluscenadc/F"); + m_clustree->Branch("padcen", &m_padcen, "m_padcen/F"); + m_clustree->Branch("tbincen", &m_tbincen, "m_tbincen/F"); + m_clustree->Branch("padmax", &m_padmax, "m_padmax/F"); + m_clustree->Branch("tbinmax", &m_tbinmax, "m_tbinmax/F"); m_clustree->Branch("sector", &m_clussector, "m_clussector/I"); m_clustree->Branch("side", &m_side, "m_side/I"); m_clustree->Branch("stave", &m_staveid, "m_staveid/I"); @@ -1734,6 +1881,7 @@ void TrackResiduals::createBranches() m_tree->Branch("run", &m_runnumber, "m_runnumber/I"); m_tree->Branch("segment", &m_segment, "m_segment/I"); m_tree->Branch("event", &m_event, "m_event/I"); + m_tree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_tree->Branch("mbdcharge",&m_totalmbd, "m_totalmbd/F"); m_tree->Branch("mbdzvtx", &m_mbdvtxz, "m_mbdvtxz/F"); m_tree->Branch("firedTriggers", &m_firedTriggers); @@ -1815,7 +1963,27 @@ void TrackResiduals::createBranches() m_tree->Branch("clusside", &m_clside); m_tree->Branch("cluskeys", &m_cluskeys); m_tree->Branch("clusedge", &m_clusedge); + m_tree->Branch("clussledge", &m_clussledge); + m_tree->Branch("clussredge", &m_clussredge); + m_tree->Branch("clustledge", &m_clustledge); + m_tree->Branch("clustredge", &m_clustredge); + m_tree->Branch("clusdledge", &m_clusdledge); + m_tree->Branch("clusdredge", &m_clusdredge); + m_tree->Branch("clushledge", &m_clushledge); + m_tree->Branch("clushredge", &m_clushredge); + m_tree->Branch("clusslmix", &m_clusslmix); + m_tree->Branch("clussrmix", &m_clussrmix); + m_tree->Branch("clustlmix", &m_clustlmix); + m_tree->Branch("clustrmix", &m_clustrmix); m_tree->Branch("clusoverlap", &m_clusoverlap); + m_tree->Branch("clusphibinlo", &m_clusphibinlo); + m_tree->Branch("clusphibinhi", &m_clusphibinhi); + m_tree->Branch("clustbinlo", &m_clustbinlo); + m_tree->Branch("clustbinhi", &m_clustbinhi); + m_tree->Branch("clusPadCen", &m_clusPadCen); + m_tree->Branch("clusTBinCen", &m_clusTBinCen); + m_tree->Branch("clusPadMax", &m_clusPadMax); + m_tree->Branch("clusTBinMax", &m_clusTBinMax); m_tree->Branch("cluslx", &m_cluslx); m_tree->Branch("cluslz", &m_cluslz); m_tree->Branch("cluselx", &m_cluselx); @@ -1824,6 +1992,8 @@ void TrackResiduals::createBranches() m_tree->Branch("clusgy", &m_clusgy); m_tree->Branch("clusgz", &m_clusgz); m_tree->Branch("clusgr", &m_clusgr); + m_tree->Branch("cluspadphase", &m_cluspadphase); + m_tree->Branch("clustbinphase", &m_clustbinphase); if (m_doAlignment) { m_tree->Branch("clusgxunmoved", &m_clusgxunmoved); @@ -1832,6 +2002,8 @@ void TrackResiduals::createBranches() } m_tree->Branch("clusAdc", &m_clusAdc); m_tree->Branch("clusMaxAdc", &m_clusMaxAdc); + m_tree->Branch("clusCenAdc", &m_clusCenAdc); + m_tree->Branch("clussize", &m_clussize); m_tree->Branch("clusphisize", &m_clusphisize); m_tree->Branch("cluszsize", &m_cluszsize); @@ -2235,6 +2407,7 @@ void TrackResiduals::fillEventTree(PHCompositeNode* topNode) if (Verbosity() > 1) { std::cout << " m_event:" << m_event << std::endl; + std::cout << " m_evt_id:" << m_evt_id << std::endl; std::cout << " m_ntpc_clus0:" << m_ntpc_clus0 << std::endl; std::cout << " m_ntpc_clus1: " << m_ntpc_clus1 << std::endl; std::cout << " m_nmvtx_all:" << m_nmvtx_all << std::endl; diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 7e789faba5..6601fc47c9 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -128,6 +128,7 @@ class TrackResiduals : public SubsysReco bool m_doMicromegasOnly = false; int m_event = 0; + int m_evt_id = -1; int m_segment = std::numeric_limits::quiet_NaN(); int m_runnumber = std::numeric_limits::quiet_NaN(); int m_ntpcclus = std::numeric_limits::quiet_NaN(); @@ -246,8 +247,34 @@ class TrackResiduals : public SubsysReco float m_scluseta = std::numeric_limits::quiet_NaN(); float m_adc = std::numeric_limits::quiet_NaN(); float m_clusmaxadc = std::numeric_limits::quiet_NaN(); + float m_cluscenadc = std::numeric_limits::quiet_NaN(); + int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); + int m_overlap = std::numeric_limits::quiet_NaN(); + int m_nedge = std::numeric_limits::quiet_NaN(); + int m_sledge = std::numeric_limits::quiet_NaN(); + int m_sredge = std::numeric_limits::quiet_NaN(); + int m_tledge = std::numeric_limits::quiet_NaN(); + int m_tredge = std::numeric_limits::quiet_NaN(); + int m_dledge = std::numeric_limits::quiet_NaN(); + int m_dredge = std::numeric_limits::quiet_NaN(); + int m_hledge = std::numeric_limits::quiet_NaN(); + int m_hredge = std::numeric_limits::quiet_NaN(); + int m_slmix = std::numeric_limits::quiet_NaN(); + int m_srmix = std::numeric_limits::quiet_NaN(); + int m_tlmix = std::numeric_limits::quiet_NaN(); + int m_trmix = std::numeric_limits::quiet_NaN(); + float m_phibinlo = std::numeric_limits::quiet_NaN(); + float m_phibinhi = std::numeric_limits::quiet_NaN(); + float m_tbinlo = std::numeric_limits::quiet_NaN(); + float m_tbinhi = std::numeric_limits::quiet_NaN(); + float m_padphase = std::numeric_limits::quiet_NaN(); + float m_tbinphase = std::numeric_limits::quiet_NaN(); + float m_padcen = std::numeric_limits::quiet_NaN(); + float m_tbincen = std::numeric_limits::quiet_NaN(); + float m_padmax = std::numeric_limits::quiet_NaN(); + float m_tbinmax = std::numeric_limits::quiet_NaN(); float m_scluslx = std::numeric_limits::quiet_NaN(); float m_scluslz = std::numeric_limits::quiet_NaN(); float m_sclusgx = std::numeric_limits::quiet_NaN(); @@ -270,6 +297,11 @@ class TrackResiduals : public SubsysReco //! clusters on track information std::vector m_clusAdc; std::vector m_clusMaxAdc; + std::vector m_clusCenAdc; + std::vector m_clusPadCen; + std::vector m_clusTBinCen; + std::vector m_clusPadMax; + std::vector m_clusTBinMax; std::vector m_cluslx; std::vector m_cluslz; std::vector m_cluselx; @@ -288,10 +320,29 @@ class TrackResiduals : public SubsysReco std::vector m_clsector; std::vector m_clside; std::vector m_cluslayer; + std::vector m_clussize; std::vector m_clusphisize; std::vector m_cluszsize; - std::vector m_clusedge; std::vector m_clusoverlap; + std::vector m_clusedge; + std::vector m_clussledge; + std::vector m_clussredge; + std::vector m_clustledge; + std::vector m_clustredge; + std::vector m_clusdledge; + std::vector m_clusdredge; + std::vector m_clushledge; + std::vector m_clushredge; + std::vector m_clusslmix; + std::vector m_clussrmix; + std::vector m_clustlmix; + std::vector m_clustrmix; + std::vector m_clusphibinlo; + std::vector m_clusphibinhi; + std::vector m_clustbinlo; + std::vector m_clustbinhi; + std::vector m_cluspadphase; + std::vector m_clustbinphase; std::vector m_cluskeys; std::vector m_idealsurfcenterx; std::vector m_idealsurfcentery; diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index d5fddf6538..1c90c4688c 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -289,6 +289,11 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) nclue, ncluadc, nclumaxadc, + nclucenadc, + nclupadcen, + nclutbincen, + nclupadmax, + nclutbinmax, ncluthick, ncluafac, nclubfac, @@ -301,7 +306,25 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) ncluzsize, nclupedge, ncluredge, + nclusledge, + nclusredge, + nclutledge, + nclutredge, + ncludledge, + ncludredge, + ncluhledge, + ncluhredge, + ncluslmix, + nclusrmix, + nclutlmix, + nclutrmix, ncluovlp, + ncluphibinlo, + ncluphibinhi, + nclutbinlo, + nclutbinhi, + nclupadphase, + nclutbinphase, nclutrackID, ncluniter, clusize = ncluniter + 1 @@ -337,7 +360,7 @@ int TrkrNtuplizer::Init(PHCompositeNode* /*unused*/) std::string str_vertex = {"vertexID:vx:vy:vz:ntracks:chi2:ndof"}; std::string str_event = {"event:seed:run:seg:job"}; std::string str_hit = {"hitID:e:adc:layer:phielem:zelem:cellID:ecell:phibin:zbin:tbin:phi:r:x:y:z"}; - std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:ovlp:trackID:niter"}; + std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:cenadc:padcen:tbincen:padmax:tbinmax:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:sledge:sredge:tledge:tredge:dledge:dredge:hledge:hredge:slmix:srmix:tlmix:trmix:ovlp:phibinlo:phibinhi:tbinlo:tbinhi:padphase:tbinphase:trackID:niter"}; std::string str_seed = {"seedID:siter:spt:sptot:seta:sphi:syxint:srzint:sxyslope:srzslope:sX0:sY0:sdZ0:sR0:scharge:sdedx:spidedx:skdedx:sprdedx:sn1pix:snsil:sntpc:snhits"}; std::string str_residual = {"alpha:beta:resphio:resphi:resz"}; std::string str_track = {"trackID:crossing:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:charge:quality:chisq:ndf:nhits:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:dedx:pidedx:kdedx:prdedx:vertexID:vx:vy:vz:dca2d:dca2dsigma:dca3dxy:dca3dxysigma:dca3dz:dca3dzsigma:pcax:pcay:pcaz:hlxpt:hlxeta:hlxphi:hlxX0:hlxY0:hlxZ0:hlxcharge"}; @@ -1386,7 +1409,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } //----------------------- - // fill the Vertex NTuple and fixed NaN placeholders + // fill the Vertex NTuple and fixed NaN placeholders //----------------------- bool doit = true; if (_ntp_vertex && doit) @@ -1409,8 +1432,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) for (auto & iter : *vertexmap) { SvtxVertex* vertex = iter.second; - if (!vertex) { continue; -} + if (!vertex) { continue; } float fx_vertex[n_vertex::vtxsize]; for (float& i : fx_vertex) @@ -1453,8 +1475,6 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) _timer->stop(); std::cout << "vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; } - - //-------------------- // fill the Hit NTuple //-------------------- @@ -2284,6 +2304,11 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c fXcluster[n_cluster::nclue] = cluster->getAdc(); fXcluster[n_cluster::ncluadc] = cluster->getAdc(); fXcluster[n_cluster::nclumaxadc] = cluster->getMaxAdc(); + fXcluster[n_cluster::nclucenadc] = cluster->getCenAdc(); + fXcluster[n_cluster::nclupadcen] = cluster->getPadCen(); + fXcluster[n_cluster::nclutbincen] = cluster->getTBinCen(); + fXcluster[n_cluster::nclupadmax] = cluster->getPadMax(); + fXcluster[n_cluster::nclutbinmax] = cluster->getTBinMax(); fXcluster[n_cluster::nclulayer] = layer_local; if (layer_local < 3) @@ -2311,7 +2336,7 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c } } */ - fXcluster[n_cluster::nclusize] = cluster->getSize(); + fXcluster[n_cluster::nclusize] = cluster->getRSize(); fXcluster[n_cluster::ncluphisize] = cluster->getPhiSize(); fXcluster[n_cluster::ncluzsize] = cluster->getZSize(); fXcluster[n_cluster::nclupedge] = cluster->getEdge(); @@ -2321,8 +2346,25 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c { fXcluster[n_cluster::ncluredge] = 1; } - - fXcluster[n_cluster::ncluovlp] = 3; // cluster->getOvlp(); + fXcluster[n_cluster::nclusledge] = cluster->getSLEdge(); + fXcluster[n_cluster::nclusredge] = cluster->getSREdge(); + fXcluster[n_cluster::nclutledge] = cluster->getTLEdge(); + fXcluster[n_cluster::nclutredge] = cluster->getTREdge(); + fXcluster[n_cluster::ncludledge] = cluster->getDLEdge(); + fXcluster[n_cluster::ncludredge] = cluster->getDREdge(); + fXcluster[n_cluster::ncluhledge] = cluster->getHLEdge(); + fXcluster[n_cluster::ncluhredge] = cluster->getHREdge(); + fXcluster[n_cluster::ncluslmix] = cluster->getSLMix(); + fXcluster[n_cluster::nclusrmix] = cluster->getSRMix(); + fXcluster[n_cluster::nclutlmix] = cluster->getTLMix(); + fXcluster[n_cluster::nclutrmix] = cluster->getTRMix(); + fXcluster[n_cluster::ncluovlp] = cluster->getOverlap(); + fXcluster[n_cluster::ncluphibinlo] = cluster->getPhiBinLo(); + fXcluster[n_cluster::ncluphibinhi] = cluster->getPhiBinHi(); + fXcluster[n_cluster::nclutbinlo] = cluster->getTBinLo(); + fXcluster[n_cluster::nclutbinhi] = cluster->getTBinHi(); + fXcluster[n_cluster::nclupadphase] = cluster->getPadPhase(); + fXcluster[n_cluster::nclutbinphase] = cluster->getTBinPhase(); fXcluster[n_cluster::nclutrackID] = std::numeric_limits::quiet_NaN(); fXcluster[n_cluster::ncluniter] = 0; diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 687d5b58f9..5e0d58e112 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include // for hitkey, getLayer #include #include @@ -84,6 +85,36 @@ namespace unsigned short edge = 0; }; + struct ClusterCounters + { + int overlap = 0; + + int nedge = 0; // Total No. of Edges + + int sledge = 0; // Touching Left Sector Edge + int sredge = 0; // Touching Right Sector Edge + + int tledge = 0; // Touching Left Time Edge + int tredge = 0; // Touching Right Time Edge + + int dledge = 0; // Touching Left Dead Edge + int dredge = 0; // Touching Right Dead Edge + + int hledge = 0; // Touching Left Hot Edge + int hredge = 0; // Touching Right Hot Edge + + int slmix = 0; // Touching Cluster at Left in Phibin + int srmix = 0; // Touching Cluster at Right in Phibin + + int tlmix = 0; // Touching Cluster at Left in Timebin + int trmix = 0; // Touching Cluster at Right in Timebin + + void clear() + { + *this = ClusterCounters{}; + } + }; + using vec_dVerbose = std::vector>>; // Neural network parameters and modules @@ -176,13 +207,14 @@ namespace } } - void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, int &touch, int &edge) + void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, ClusterCounters &counts, bool &ttop_edge, bool &tbottom_edge) { const int FitRangeT = (int) my_data.maxHalfSizeT; const int NTBinsMax = (int) my_data.tbins; - const int FixedWindow = (int) my_data.FixedWindow; + // const int FixedWindow = (int) my_data.FixedWindow; tup = 0; tdown = 0; + /* if (FixedWindow != 0) { tup = FixedWindow; @@ -190,15 +222,16 @@ namespace if (tbin + tup >= NTBinsMax) { tup = NTBinsMax - tbin - 1; - edge++; + counts.nedge++; } if ((tbin - tdown) <= 0) { tdown = tbin; - edge++; + counts.edge++; } return; } + */ for (int it = 0; it < FitRangeT; it++) { int ct = tbin + it; @@ -206,7 +239,12 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tup = it; - edge++; + if (!ttop_edge) + { + counts.nedge++; + counts.tredge = 1; + ttop_edge = true; + } break; // truncate edge } @@ -216,7 +254,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -228,7 +266,7 @@ namespace adcval[phibin][ct + 2] + adcval[phibin][ct + 3]) { // rising again tup = it + 1; - touch++; + counts.overlap++; break; } } @@ -241,7 +279,12 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tdown = it; - edge++; + if (!tbottom_edge) + { + counts.nedge++; + counts.tledge = 1; + tbottom_edge = true; + } break; // truncate edge } if (adcval[phibin][ct] <= 0) @@ -250,7 +293,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -261,7 +304,7 @@ namespace adcval[phibin][ct - 2] + adcval[phibin][ct - 3]) { // rising again tdown = it + 1; - touch++; + counts.overlap++; break; } } @@ -271,13 +314,14 @@ namespace return; } - void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, int &touch, int &edge) + void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, ClusterCounters &counts, bool &phitop_edge, bool &phibottom_edge) { int FitRangePHI = (int) my_data.maxHalfSizePhi; int NPhiBinsMax = (int) my_data.phibins; - const int FixedWindow = (int) my_data.FixedWindow; + // const int FixedWindow = (int) my_data.FixedWindow; phidown = 0; phiup = 0; + /* if (FixedWindow != 0) { phiup = FixedWindow; @@ -294,13 +338,19 @@ namespace } return; } + */ for (int iphi = 0; iphi < FitRangePHI; iphi++) { int cphi = phibin + iphi; if (cphi < 0 || cphi >= NPhiBinsMax) { // phiup = iphi; - edge++; + if (!phitop_edge) + { + counts.nedge++; + counts.sredge = 1; + phitop_edge = true; + } break; // truncate edge } @@ -312,7 +362,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -323,7 +373,7 @@ namespace adcval[cphi + 2][tbin] + adcval[cphi + 3][tbin]) { // rising again phiup = iphi + 1; - touch++; + counts.overlap++; break; } } @@ -337,7 +387,12 @@ namespace if (cphi < 0 || cphi >= NPhiBinsMax) { // phidown = iphi; - edge++; + if (!phibottom_edge) + { + counts.nedge++; + counts.sledge = 1; + phibottom_edge = true; + } break; // truncate edge } @@ -348,7 +403,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -359,7 +414,7 @@ namespace adcval[cphi - 2][tbin] + adcval[cphi - 3][tbin]) { // rising again phidown = iphi + 1; - touch++; + counts.overlap++; break; } } @@ -369,6 +424,61 @@ namespace return; } + void check_cluster_touching(const std::vector& ihit_list, const std::vector>& adcval, int phibins, int tbins, ClusterCounters &counts) + { + // Encode (iphi, it) into single integer for fast lookup + std::unordered_set cluster_hits; + cluster_hits.reserve(ihit_list.size()); + + auto encode = [tbins](int phi, int t) + { + return phi * tbins + t; + }; + + for (const auto &hit : ihit_list) + { + cluster_hits.insert(encode(hit.iphi, hit.it)); + } + + for (const auto &hit : ihit_list) + { + int iphi = hit.iphi; + int it = hit.it; + + for (int dphi = -1; dphi <= 1; ++dphi) + { + for (int dt = -1; dt <= 1; ++dt) + { + if (dphi == 0 && dt == 0) { continue; } + + int nphi = iphi + dphi; + int nt = it + dt; + + if (nphi < 0 || nphi >= phibins || + nt < 0 || nt >= tbins) { + continue; + } + + // skip same cluster + if (cluster_hits.contains(encode(nphi, nt))) { continue; } + + // neighbor has signal → touching + if (adcval[nphi][nt] > 0 && + adcval[nphi][nt] != USHRT_MAX) + { + // Check Phi + if (dphi == -1) { counts.slmix = 1; } + if (dphi == 1) { counts.srmix = 1; } + + // Check Time + if (dt == -1) { counts.tlmix = 1; } + if (dt == 1) { counts.trmix = 1; } + } + } + } + } + } + int is_hit_isolated(int iphi, int it, int NPhiBinsMax, int NTBinsMax, const std::vector> &adcval) { // check isolated hits @@ -426,20 +536,25 @@ namespace return isiso; } - void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, int &touch, int &edge) + void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, ClusterCounters &counts) { + bool ttop_edge = false; + bool tbottom_edge = false; + bool phitop_edge = false; + bool phibottom_edge = false; + // search along phi at the peak in t // const int NPhiBinsMax = (int) my_data.phibins; // const int NTBinsMax = (int) my_data.tbins; int tup = 0; int tdown = 0; - find_t_range(phibin, tbin, my_data, adcval, tdown, tup, touch, edge); + find_t_range(phibin, tbin, my_data, adcval, tdown, tup, counts, ttop_edge, tbottom_edge); // now we have the t extent of the cluster, go find the phi edges for (int it = tbin - tdown; it <= (tbin + tup); it++) { int phiup = 0; int phidown = 0; - find_phi_range(phibin, it, my_data, adcval, phidown, phiup, touch, edge); + find_phi_range(phibin, it, my_data, adcval, phidown, phiup, counts, phitop_edge, phibottom_edge); for (int iphi = (phibin - phidown); iphi <= (phibin + phiup); iphi++) { if (adcval[iphi][it] > 0 && adcval[iphi][it] != USHRT_MAX) @@ -456,7 +571,7 @@ namespace hit.it = it; hit.adc = adcval[iphi][it]; - if (touch > 0) + if (counts.overlap > 0) { if ((iphi == (phibin - phidown)) || (iphi == (phibin + phiup))) @@ -472,7 +587,7 @@ namespace } 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) + const std::vector &ihit_list, thread_data &my_data, ClusterCounters counts) { // // get z range from layer geometry @@ -488,6 +603,8 @@ namespace double iphi_sum = 0.0; double iphi2_sum = 0.0; + double it_sum = 0.0; + double radius = my_data.layergeom->get_radius(); // returns center of layer int phibinhi = -1; @@ -497,6 +614,12 @@ namespace int clus_size = ihit_list.size(); int max_adc = 0; + int phibinmax = -1; + int tbinmax = -1; + double cen_adc = 0; + + int size = 0; + if (clus_size <= my_data.min_clus_size) { return; @@ -521,14 +644,16 @@ namespace training_hits->phistep = my_data.layergeom->get_phistep(); training_hits->zstep = my_data.layergeom->get_zstep() * my_data.tGeometry->get_drift_velocity(); training_hits->layer = my_data.layer; - training_hits->ntouch = ntouch; - training_hits->nedge = nedge; + training_hits->ntouch = counts.overlap; + training_hits->nedge = counts.nedge; training_hits->v_adc.fill(0); } // std::cout << "process list" << std::endl; std::vector hitkeyvec; + std::map, double> adc_map; + // keep track of the hit locations in a given cluster std::map m_phi{}; std::map m_z{}; @@ -544,7 +669,18 @@ namespace continue; } - max_adc = std::max(max_adc, static_cast(std::round(adc))); // preserves rounding (0.5 -> 1) + size++; + + int adc_int = static_cast(std::round(adc)); + + if (adc_int > max_adc) + { + max_adc = adc_int; + phibinmax = iphi; + tbinmax = 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); @@ -565,8 +701,12 @@ namespace t_sum += t * adc; t2_sum += square(t) * adc; + it_sum += it * adc; + adc_sum += adc; + adc_map[{iphi, it}] += adc; + if (my_data.fillClusHitsVerbose) { auto pnew = m_phi.try_emplace(iphi, adc); @@ -623,13 +763,15 @@ namespace left_pad >= my_data.phioffset && deadset.contains(TpcDefs::genHitKey(left_pad, 0))) { - nedge++; + counts.nedge++; + counts.dledge = 1; } if (right_pad < (my_data.phibins + my_data.phioffset) && deadset.contains(TpcDefs::genHitKey(right_pad, 0))) { - nedge++; + counts.nedge++; + counts.dredge = 1; } } } @@ -646,24 +788,62 @@ namespace left_pad >= my_data.phioffset && hotset.contains(TpcDefs::genHitKey(left_pad, 0))) { - nedge++; + counts.nedge++; + counts.hledge = 1; } if (right_pad < (my_data.phibins + my_data.phioffset) && hotset.contains(TpcDefs::genHitKey(right_pad, 0))) { - nedge++; + counts.nedge++; + counts.hredge = 1; } } } - // This is the global position + // This is local position double clusiphi = iphi_sum / adc_sum; + double clusit = it_sum / adc_sum; + + // This is the global position double clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); + double clust = t_sum / adc_sum; + + // ADC of centroid bin + int iphi_centroid = static_cast(std::floor(clusiphi)); + int it_centroid = static_cast(std::floor(clusit)); + + auto it_cent = adc_map.find({iphi_centroid, it_centroid}); + if (it_cent != adc_map.end()) + { + cen_adc = it_cent->second; + } + else + { + cen_adc = 0.0; // centroid may not land on a real hit + } + + // Max ADC position in global coordinates + double maxphi = my_data.layergeom->get_phi(phibinmax, my_data.side); + double maxt = my_data.layergeom->get_zcenter(tbinmax); + + // Phase relative to max ADC position + double padphase = 0.0; + double tbinphase = 0.0; + + if (my_data.layergeom->get_phistep() > 0) + { + padphase = (clusphi - maxphi) / my_data.layergeom->get_phistep(); + } + + if (my_data.layergeom->get_zstep() > 0) + { + tbinphase = (clust - maxt) / my_data.layergeom->get_zstep(); + } double clusx = radius * cos(clusphi); double clusy = radius * sin(clusphi); - double clust = t_sum / adc_sum; + // needed for surface identification double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); // convert z drift length to z position in the TPC @@ -702,6 +882,7 @@ namespace char tsize = tbinhi - tbinlo + 1; char phisize = phibinhi - phibinlo + 1; + char rsize = size; // std::cout << "phisize: " << (int) phisize << " phibinhi " << phibinhi << " phibinlo " << phibinlo << std::endl; // phi_cov = (weighted mean of dphi^2) - (weighted mean of dphi)^2, which is essentially the weighted mean of dphi^2. The error is then: // e_phi = sigma_dphi/sqrt(N) = sqrt( sigma_dphi^2 / N ) -- where N is the number of samples of the distribution with standard deviation sigma_dphi @@ -726,20 +907,45 @@ 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 TrkrClusterv6; + // auto *clus = new TrkrClusterv5; // auto clus = std::make_unique(); clus_base = clus; - clus->setAdc(adc_sum); - clus->setMaxAdc(max_adc); - clus->setEdge(nedge); - clus->setPhiSize(phisize); - clus->setZSize(tsize); - clus->setSubSurfKey(subsurfkey); - clus->setOverlap(ntouch); clus->setLocalX(local(0)); clus->setLocalY(clust); + clus->setSubSurfKey(subsurfkey); + clus->setAdc(adc_sum); + clus->setMaxAdc(max_adc); + clus->setCenAdc(cen_adc); + clus->setPadCen(clusiphi); + clus->setTBinCen(clusit); + clus->setPadMax(phibinmax); + clus->setTBinMax(tbinmax); clus->setPhiError(sqrt(phi_err_square)); clus->setZError(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(), 2))); + clus->setRSize(rsize); + clus->setPhiSize(phisize); + clus->setZSize(tsize); + clus->setOverlap(counts.overlap); + clus->setEdge(counts.nedge); + clus->setSLEdge(counts.sledge); + clus->setSREdge(counts.sredge); + clus->setTLEdge(counts.tledge); + clus->setTREdge(counts.tredge); + clus->setDLEdge(counts.dledge); + clus->setDREdge(counts.dredge); + clus->setHLEdge(counts.hledge); + clus->setHREdge(counts.hredge); + clus->setSLMix(counts.slmix); + clus->setSRMix(counts.srmix); + clus->setTLMix(counts.tlmix); + clus->setTRMix(counts.trmix); + clus->setPhiBinLo(phibinlo); + clus->setPhiBinHi(phibinhi); + clus->setTBinLo(tbinlo); + clus->setTBinHi(tbinhi); + clus->setPadPhase(padphase); + clus->setTBinPhase(tbinphase); my_data.cluster_vector.push_back(clus); b_made_cluster = true; } @@ -1037,6 +1243,9 @@ namespace } } */ + + std::vector> adcval_orig = adcval; + // std::cout << "done filling " << std::endl; while (!all_hit_map.empty()) { @@ -1064,9 +1273,10 @@ namespace // start with highest adc hit // -> cluster around it and get vector of hits std::vector ihit_list; - int ntouch = 0; - int nedge = 0; - get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); + // Setting all the counters + ClusterCounters counts; + + get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); if (my_data->FixedWindow > 0) { @@ -1102,11 +1312,16 @@ namespace my_data->FixedWindow = 0; // reset hit list and try again without fixed window ihit_list.clear(); - get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); + // resetting all the counters + counts.clear(); + get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); // std::cout << " stepdown size after " << ihit_list.size() << std::endl; my_data->FixedWindow = window_cache; } } + + check_cluster_touching(ihit_list, adcval_orig, my_data->phibins, my_data->tbins, counts); + if (ihit_list.size() <= 1) { remove_hits(ihit_list, all_hit_map, adcval); @@ -1117,7 +1332,7 @@ namespace // -> add hits to truth association // remove hits from all_hit_map // repeat untill all_hit_map empty - calc_cluster_parameter(iphi, it, ihit_list, *my_data, ntouch, nedge); + calc_cluster_parameter(iphi, it, ihit_list, *my_data, counts); remove_hits(ihit_list, all_hit_map, adcval); ihit_list.clear(); } From 9e896a990140853a219458512690eae55dbfe616 Mon Sep 17 00:00:00 2001 From: Gregory J Ottino Date: Thu, 7 May 2026 18:07:40 -0400 Subject: [PATCH 656/866] update to fit Si or TPC only tracks with track pruner --- offline/packages/trackbase/ActsSurfaceMaps.cc | 5 + offline/packages/trackbase/ActsSurfaceMaps.h | 7 + .../packages/trackreco/MakeActsGeometry.cc | 6 + offline/packages/trackreco/PHActsTrkFitter.cc | 37 +++- offline/packages/trackreco/PHActsTrkFitter.h | 6 + .../trackreco/PHSimpleVertexFinder.cc | 204 ++++++++++-------- .../packages/trackreco/PHSimpleVertexFinder.h | 11 +- 7 files changed, 172 insertions(+), 104 deletions(-) diff --git a/offline/packages/trackbase/ActsSurfaceMaps.cc b/offline/packages/trackbase/ActsSurfaceMaps.cc index d92e387ca0..69cd94ece6 100644 --- a/offline/packages/trackbase/ActsSurfaceMaps.cc +++ b/offline/packages/trackbase/ActsSurfaceMaps.cc @@ -34,6 +34,11 @@ bool ActsSurfaceMaps::isTpcSurface(const Acts::Surface* surface) const return m_tpcVolumeIds.find(surface->geometryId().volume()) != m_tpcVolumeIds.end(); } +bool ActsSurfaceMaps::isSiSurface(const Acts::Surface* surface) const +{ + return m_siVolumeIds.find(surface->geometryId().volume()) != m_siVolumeIds.end(); +} + bool ActsSurfaceMaps::isMicromegasSurface(const Acts::Surface* surface) const { return m_micromegasVolumeIds.find(surface->geometryId().volume()) != m_micromegasVolumeIds.end(); diff --git a/offline/packages/trackbase/ActsSurfaceMaps.h b/offline/packages/trackbase/ActsSurfaceMaps.h index 94c327be79..e90263c49a 100644 --- a/offline/packages/trackbase/ActsSurfaceMaps.h +++ b/offline/packages/trackbase/ActsSurfaceMaps.h @@ -37,6 +37,9 @@ struct ActsSurfaceMaps //! true if given surface corresponds to TPC bool isTpcSurface(const Acts::Surface* surface) const; + //! true if given surface corresponds to the silicon + bool isSiSurface(const Acts::Surface* surface) const; + //! true if given surface corresponds to Micromegas bool isMicromegasSurface(const Acts::Surface* surface) const; @@ -65,6 +68,10 @@ struct ActsSurfaceMaps /** it is used to quickly tell if a given Acts Surface belongs to the TPC */ std::set m_tpcVolumeIds; + //! stores all acts volume ids relevant to the Silicon + /** it is used to quickly tell if a given Acts Surface belongs to the Silicon */ + std::set m_siVolumeIds; + //! stores all acts volume ids relevant to the micromegas /** it is used to quickly tell if a given Acts Surface belongs to micromegas */ std::set m_micromegasVolumeIds; diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 0afea11b6c..7f2deec166 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -285,6 +285,12 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) } } + // fill Si volume ids + for (const auto &[hitsetid, surface] : m_clusterSurfaceMapSilicon) + { + surfMaps.m_siVolumeIds.insert(surface->geometryId().volume()); + } + // fill Micromegas volume ids for (const auto &[hitsetid, surface] : m_clusterSurfaceMapMmEdit) { diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 1cf72bdfdc..caf7183281 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -525,11 +525,11 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) // position comes from the silicon seed, unless there is no silicon seed Acts::Vector3 position(0, 0, 0); - if (siseed) + if (siseed && !m_ignoreSilicon) { position = TrackSeedHelper::get_xyz(siseed) * Acts::UnitConstants::cm; } - if (!siseed || !is_valid(position) || m_ignoreSilicon) + if (!siseed || !is_valid(position) || m_forceTpcOnlyFit) { position = TrackSeedHelper::get_xyz(tpcseed) * Acts::UnitConstants::cm; } @@ -573,6 +573,13 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) continue; } } + //else if (m_forceTpcOnlyFit) + //{ + // if (surface_apr->geometryId().volume() < 14) + // { + // continue; + // } + //} bool pop_flag = false; if (surface_apr->geometryId().approach() == 1) { @@ -642,7 +649,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) float seedphi = 0; float seedtheta = 0; float seedeta = 0; - if (siseed) + if (siseed && !m_forceTpcOnlyFit) { seedphi = siseed->get_phi(); seedtheta = siseed->get_theta(); @@ -980,6 +987,9 @@ SourceLinkVec PHActsTrkFitter::filterSourceLinks(const SourceLinkVec& sourceLink if (m_forceSiOnlyFit && (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isTpcSurface(surf)) ) { continue; } + if (m_forceTpcOnlyFit && (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isSiSurface(surf)) ) + { continue; } + // update vectors filtered.push_back(sl); } @@ -1066,7 +1076,7 @@ void PHActsTrkFitter::updateSvtxTrack( track->identify(); } - if (!m_fitSiliconMMs && !m_forceSiOnlyFit) + if (!m_fitSiliconMMs && !m_forceSiOnlyFit && !m_forceTpcOnlyFit) { track->clear_states(); } @@ -1093,9 +1103,20 @@ void PHActsTrkFitter::updateSvtxTrack( track->set_y(params.position(m_transient_geocontext)(1) / Acts::UnitConstants::cm); track->set_z(params.position(m_transient_geocontext)(2) / Acts::UnitConstants::cm); - track->set_px(params.momentum()(0)); - track->set_py(params.momentum()(1)); - track->set_pz(params.momentum()(2)); + auto* seed = track->get_tpc_seed(); + + if(!m_forceSiOnlyFit) + { + track->set_px(params.momentum()(0)); + track->set_py(params.momentum()(1)); + track->set_pz(params.momentum()(2)); + } + else + { + track->set_px(seed->get_px()); + track->set_py(seed->get_py()); + track->set_pz(seed->get_pz()); + } track->set_charge(params.charge()); track->set_chisq(trajState.chi2Sum); @@ -1130,7 +1151,7 @@ void PHActsTrkFitter::updateSvtxTrack( // 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) { // acts propagator diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 6ce4d4e711..2997ef6f5d 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -83,6 +83,11 @@ class PHActsTrkFitter : public SubsysReco m_forceSiOnlyFit = forceSiOnlyFit; } + void forceTpcOnlyFit(bool forceTpcOnlyFit) + { + m_forceTpcOnlyFit = forceTpcOnlyFit; + } + /// require micromegas in SiliconMM fits void setUseMicromegas(bool value) { @@ -216,6 +221,7 @@ class PHActsTrkFitter : public SubsysReco bool m_fitSiliconMMs = false; bool m_forceSiOnlyFit = false; + bool m_forceTpcOnlyFit = false; /// requires micromegas present when fitting silicon-MM surfaces bool m_useMicromegas = true; diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index 954e790ba6..5f9340d8f6 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -515,13 +515,34 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) + if (_require_mvtx) { - continue; - } - if (_require_intt && !passClusterRequirement(tr1, "INTT")) - { - continue; + unsigned int nmvtx = 0; + TrackSeed *siliconseed = tr1->get_silicon_seed(); + if (!siliconseed) + { + continue; + } + + for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) + { + if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) + { + nmvtx++; + } + if (nmvtx >= _nmvtx_required) + { + break; + } + } + if (nmvtx < _nmvtx_required) + { + continue; + } + if (Verbosity() > 3) + { + std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; + } } // look for close DCA matches with all other such tracks @@ -533,13 +554,34 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) + if (_require_mvtx) { - continue; - } - if (_require_intt && !passClusterRequirement(tr2, "INTT")) - { - continue; + unsigned int nmvtx = 0; + TrackSeed *siliconseed = tr2->get_silicon_seed(); + if (!siliconseed) + { + continue; + } + + for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) + { + if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) + { + nmvtx++; + } + if (nmvtx >= _nmvtx_required) + { + break; + } + } + if (nmvtx < _nmvtx_required) + { + continue; + } + if (Verbosity() > 3) + { + std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; + } } // find DCA of these two tracks @@ -574,20 +616,13 @@ void PHSimpleVertexFinder::checkDCAsZF(SvtxTrackMap *track_map) // tr1->identify(); TrackSeed *siliconseed = tr1->get_silicon_seed(); - const bool needs_mvtx_seed = _require_mvtx && _nmvtx_required > 0; - const bool needs_intt_seed = _require_intt && _nintt_required > 0; - if ((needs_mvtx_seed || needs_intt_seed) && !siliconseed) - { - continue; - } - if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) - { - continue; - } - if (_require_intt && !passClusterRequirement(tr1, "INTT")) - { - continue; - } + if (_require_mvtx) + { + if (!siliconseed) + { + continue; + } + } TrackSeed *tpcseed = tr1->get_tpc_seed(); std::vector global_vec; @@ -762,13 +797,34 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) + if (_require_mvtx) { - continue; - } - if (_require_intt && !passClusterRequirement(tr1, "INTT")) - { - continue; + unsigned int nmvtx = 0; + TrackSeed *siliconseed = tr1->get_silicon_seed(); + if (!siliconseed) + { + continue; + } + + for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) + { + if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) + { + nmvtx++; + } + if (nmvtx >= _nmvtx_required) + { + break; + } + } + if (nmvtx < _nmvtx_required) + { + continue; + } + if (Verbosity() > 3) + { + std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; + } } // look for close DCA matches with all other such tracks @@ -780,14 +836,36 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) - { - continue; - } - if (_require_intt && !passClusterRequirement(tr2, "INTT")) + if (_require_mvtx) { - continue; + unsigned int nmvtx = 0; + TrackSeed *siliconseed = tr2->get_silicon_seed(); + if (!siliconseed) + { + continue; + } + + for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) + { + if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) + { + nmvtx++; + } + if (nmvtx >= _nmvtx_required) + { + break; + } + } + if (nmvtx < _nmvtx_required) + { + continue; + } + if (Verbosity() > 3) + { + std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; + } } + // find DCA of these two tracks if (Verbosity() > 3) { @@ -1246,53 +1324,3 @@ double PHSimpleVertexFinder::getAverage(std::vector &v) return avge; } - -bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, const std::string &type) -{ - bool pass = false; - - std::vector acceptable_types = {"MVTX", "INTT"}; - bool accept_this_type = std::find(acceptable_types.begin(), acceptable_types.end(), type) != acceptable_types.end(); - - if (!accept_this_type) - { - if (Verbosity() > 3) - { - std::cout << "type " << type << " was not recognised" << std::endl; - } - return false; - } - - unsigned int _nclus_required = type == "MVTX" ? _nmvtx_required : _nintt_required; - if (_nclus_required == 0) - { - return true; - } - - TrackSeed *siliconseed = track->get_silicon_seed(); - if (!siliconseed) - { - return false; - } - - unsigned int nclus = 0; - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - uint8_t trkrId = type == "MVTX" ? TrkrDefs::mvtxId : TrkrDefs::inttId; - if (TrkrDefs::getTrkrId(*clusit) == trkrId) - { - nclus++; - } - if (nclus >= _nclus_required) - { - pass = true; - } - } - - if (Verbosity() > 3) - { - std::cout << " track id " << track->get_id() << " has " << nclus << " clusters for " << type << std::endl; - } - - return pass; -} diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index 6520174937..de5cff940b 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -46,18 +46,16 @@ class PHSimpleVertexFinder : public SubsysReco void setBeamSpotCutY(const double cutlo, const double cuthi) { _beamline_y_cut_lo = cutlo; _beamline_y_cut_hi = cuthi; } void setDcaCut(const double cut) { _base_dcacut = cut; } void setTrackQualityCut(double cut) { _qual_cut = cut; } - void setRequireMVTX(bool set = true) { _require_mvtx = set; } + void setRequireMVTX(bool set) { _require_mvtx = set; } void setNmvtxRequired(unsigned int n) { _nmvtx_required = n; } - void setRequireINTT(bool set = true) { _require_intt = set; } - void setNinttRequired(unsigned int n) { _nintt_required = n; } 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 = true) { _zero_field = flag; } + void zeroField(const bool flag) { _zero_field = flag; } void setTrkrClusterContainerName(const std::string &name){ m_clusterContainerName = name; } - void set_pp_mode(bool mode = true) { _pp_mode = mode; } + void set_pp_mode(bool mode) { _pp_mode = mode; } private: int GetNodes(PHCompositeNode *topNode); @@ -77,7 +75,6 @@ class PHSimpleVertexFinder : public SubsysReco void removeOutlierTrackPairs(); double getMedian(std::vector &v); double getAverage(std::vector &v); - bool passClusterRequirement(SvtxTrack *track, const std::string &type = "MVTX"); SvtxTrackMap *_track_map{nullptr}; TrkrClusterContainer* _cluster_map{nullptr}; @@ -94,9 +91,7 @@ class PHSimpleVertexFinder : public SubsysReco double _beamline_y_cut_hi = 0.2; double _qual_cut = 10.0; bool _require_mvtx = true; - bool _require_intt = false; unsigned int _nmvtx_required = 2; - unsigned int _nintt_required = 1; double _track_pt_cut = 0.0; double _outlier_cut = 0.015; From 6b53649dd9f81499ba7d79e745bb5f72e93de890 Mon Sep 17 00:00:00 2001 From: Gregory J Ottino Date: Thu, 7 May 2026 18:13:24 -0400 Subject: [PATCH 657/866] restoring vertex finder to current master --- .../trackreco/PHSimpleVertexFinder.cc | 204 ++++++++---------- .../packages/trackreco/PHSimpleVertexFinder.h | 11 +- 2 files changed, 96 insertions(+), 119 deletions(-) diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index 5f9340d8f6..954e790ba6 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -515,34 +515,13 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr1, "INTT")) + { + continue; } // look for close DCA matches with all other such tracks @@ -554,34 +533,13 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr2->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr2, "INTT")) + { + continue; } // find DCA of these two tracks @@ -616,13 +574,20 @@ void PHSimpleVertexFinder::checkDCAsZF(SvtxTrackMap *track_map) // tr1->identify(); TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (_require_mvtx) - { - if (!siliconseed) - { - continue; - } - } + const bool needs_mvtx_seed = _require_mvtx && _nmvtx_required > 0; + const bool needs_intt_seed = _require_intt && _nintt_required > 0; + if ((needs_mvtx_seed || needs_intt_seed) && !siliconseed) + { + continue; + } + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) + { + continue; + } + if (_require_intt && !passClusterRequirement(tr1, "INTT")) + { + continue; + } TrackSeed *tpcseed = tr1->get_tpc_seed(); std::vector global_vec; @@ -797,34 +762,13 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr1, "INTT")) + { + continue; } // look for close DCA matches with all other such tracks @@ -836,36 +780,14 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr2->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr2, "INTT")) + { + continue; } - // find DCA of these two tracks if (Verbosity() > 3) { @@ -1324,3 +1246,53 @@ double PHSimpleVertexFinder::getAverage(std::vector &v) return avge; } + +bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, const std::string &type) +{ + bool pass = false; + + std::vector acceptable_types = {"MVTX", "INTT"}; + bool accept_this_type = std::find(acceptable_types.begin(), acceptable_types.end(), type) != acceptable_types.end(); + + if (!accept_this_type) + { + if (Verbosity() > 3) + { + std::cout << "type " << type << " was not recognised" << std::endl; + } + return false; + } + + unsigned int _nclus_required = type == "MVTX" ? _nmvtx_required : _nintt_required; + if (_nclus_required == 0) + { + return true; + } + + TrackSeed *siliconseed = track->get_silicon_seed(); + if (!siliconseed) + { + return false; + } + + unsigned int nclus = 0; + for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) + { + uint8_t trkrId = type == "MVTX" ? TrkrDefs::mvtxId : TrkrDefs::inttId; + if (TrkrDefs::getTrkrId(*clusit) == trkrId) + { + nclus++; + } + if (nclus >= _nclus_required) + { + pass = true; + } + } + + if (Verbosity() > 3) + { + std::cout << " track id " << track->get_id() << " has " << nclus << " clusters for " << type << std::endl; + } + + return pass; +} diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index de5cff940b..6520174937 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -46,16 +46,18 @@ class PHSimpleVertexFinder : public SubsysReco void setBeamSpotCutY(const double cutlo, const double cuthi) { _beamline_y_cut_lo = cutlo; _beamline_y_cut_hi = cuthi; } void setDcaCut(const double cut) { _base_dcacut = cut; } void setTrackQualityCut(double cut) { _qual_cut = cut; } - void setRequireMVTX(bool set) { _require_mvtx = set; } + void setRequireMVTX(bool set = true) { _require_mvtx = set; } void setNmvtxRequired(unsigned int n) { _nmvtx_required = n; } + void setRequireINTT(bool set = true) { _require_intt = set; } + void setNinttRequired(unsigned int n) { _nintt_required = n; } 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 zeroField(const bool flag = true) { _zero_field = flag; } void setTrkrClusterContainerName(const std::string &name){ m_clusterContainerName = name; } - void set_pp_mode(bool mode) { _pp_mode = mode; } + void set_pp_mode(bool mode = true) { _pp_mode = mode; } private: int GetNodes(PHCompositeNode *topNode); @@ -75,6 +77,7 @@ class PHSimpleVertexFinder : public SubsysReco void removeOutlierTrackPairs(); double getMedian(std::vector &v); double getAverage(std::vector &v); + bool passClusterRequirement(SvtxTrack *track, const std::string &type = "MVTX"); SvtxTrackMap *_track_map{nullptr}; TrkrClusterContainer* _cluster_map{nullptr}; @@ -91,7 +94,9 @@ class PHSimpleVertexFinder : public SubsysReco double _beamline_y_cut_hi = 0.2; double _qual_cut = 10.0; bool _require_mvtx = true; + bool _require_intt = false; unsigned int _nmvtx_required = 2; + unsigned int _nintt_required = 1; double _track_pt_cut = 0.0; double _outlier_cut = 0.015; From f806ec163156e248e3b9a14161c72647cfda56c0 Mon Sep 17 00:00:00 2001 From: Gregory J Ottino Date: Fri, 12 Jun 2026 17:47:59 -0400 Subject: [PATCH 658/866] Added verbose comments to forceSiOnlyFit and forceTpcOnlyFit to clarify use case as alignment only --- offline/packages/trackreco/PHActsTrkFitter.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index 2997ef6f5d..47c7b6d055 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -77,12 +77,18 @@ class PHActsTrkFitter : public SubsysReco m_fitSiliconMMs = fitSiliconMMs; } - /// with direct navigation, force a fit with only silicon hits + /// FOR ALIGNMENT STUDIES ONLY, USE AT OWN RISK. With direct navigation, force a fit with only silicon hits and a full + /// matched (si+tpc track seed). This requires a standard track fit to be run first, followed by refit configured with + /// the option below. NOTE this uses the TPC track seed pT for the final pT value, to compensate for poor pt resolution + /// with the silicon seeds only. void forceSiOnlyFit(bool forceSiOnlyFit) { m_forceSiOnlyFit = forceSiOnlyFit; } + /// FOR ALIGNMENT STUDIES ONLY, USE AT OWN RISK. With direct navigation, force a fit with only tpc hits and a full + /// matched (si+tpc track seed). This requires a standard track fit to be run first, followed by refit configured with + /// the option below. NOTE this has poor pointing as the Si is not used for an initial guess of the track pointing void forceTpcOnlyFit(bool forceTpcOnlyFit) { m_forceTpcOnlyFit = forceTpcOnlyFit; From da627ac20bdbc5b0542d6d12503c1f00f6d0f3cd Mon Sep 17 00:00:00 2001 From: Jin Huang Date: Sat, 13 Jun 2026 20:48:56 -0400 Subject: [PATCH 659/866] Store abserved sync tagger to BXCounterSync CDB TTree for use in EBDC which failed BXSync --- .../fun4allraw/SingleTpcTimeFrameInput.cc | 4 + .../fun4allraw/SingleTpcTimeFrameInput.h | 6 ++ .../fun4allraw/TpcTimeFrameBuilder.cc | 4 + .../fun4allraw/TpcTimeFrameBuilder.h | 1 + .../fun4allraw/TpcTimeFrameBuilderBase.h | 1 + .../fun4allraw/TpcTimeFrameBuilderRun3.cc | 87 ++++++++++++++++++- .../fun4allraw/TpcTimeFrameBuilderRun3.h | 30 +++++++ 7 files changed, 132 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index 35ded04e35..f9cf309631 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -355,6 +355,10 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) { m_TpcTimeFrameBuilderMap[packet_id]->SaveDigitalCurrentDebugTTree(m_digitalCurrentDebugTTreeName); } + if (!m_bxCounterSyncCDBTTreeName.empty()) + { + m_TpcTimeFrameBuilderMap[packet_id]->SaveBXCounterSyncCDBTTree(m_bxCounterSyncCDBTTreeName); + } } if (Verbosity() > 1) diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index 3a2250b10b..af22167e61 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -43,6 +43,11 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput m_digitalCurrentDebugTTreeName = name; } + void setBXCounterSyncCDBTTreeName(const std::string &name) + { + m_bxCounterSyncCDBTTreeName = name; + } + private: const int NTPCPACKETS = 3; @@ -83,6 +88,7 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput int m_FillPoolStatus{0}; std::string m_digitalCurrentDebugTTreeName; + std::string m_bxCounterSyncCDBTTreeName; }; #endif diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index e068899771..21917c0cf3 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -1124,6 +1124,10 @@ void TpcTimeFrameBuilder::process_fee_data_digital_current(const unsigned int& f return; } +void TpcTimeFrameBuilder::SaveBXCounterSyncCDBTTree(const std::string& /*name*/) +{ +} + void TpcTimeFrameBuilder::SaveDigitalCurrentDebugTTree(const std::string& name) { if (m_verbosity >= 1) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index b5b9a5e293..9d65baba5b 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -47,6 +47,7 @@ class TpcTimeFrameBuilder : public TpcTimeFrameBuilderBase // enable saving of digital current debug TTree with file name `name` void SaveDigitalCurrentDebugTTree(const std::string &name) override; + void SaveBXCounterSyncCDBTTree(const std::string &name) override; protected: // Length for the 256-bit wide Round Robin Multiplexer for the data stream diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h index f137572c6a..e67c3b18a4 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h @@ -21,6 +21,7 @@ class TpcTimeFrameBuilderBase virtual void setVerbosity(int i) = 0; virtual void fillBadFeeMap() = 0; virtual void SaveDigitalCurrentDebugTTree(const std::string &name) = 0; + virtual void SaveBXCounterSyncCDBTTree(const std::string &name) = 0; }; #endif diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc index c8d5859210..cab8c787b5 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -34,6 +34,7 @@ TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) : m_packet_id(packet_id) , m_HistoPrefix("TpcTimeFrameBuilderRun3_Packet" + std::to_string(packet_id)) + , m_bxCounterSyncCDBTTreeName(m_HistoPrefix + "_BXCounterSyncCDBTTree.root") { for (int fee = 0; fee < MAX_FEECOUNT; ++fee) { @@ -266,6 +267,9 @@ TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() timeFrameEntry.second.pop_back(); } } + + write_bx_counter_sync_cdb_tree(); + delete h_Run3PreviousTimeFrameWaveformADC; delete h_Run3PreviousTimeFrameRecoveredWaveformADC; @@ -284,6 +288,57 @@ void TpcTimeFrameBuilderRun3::setVerbosity(const int i) } } +void TpcTimeFrameBuilderRun3::write_bx_counter_sync_cdb_tree() const +{ + if (m_bxCounterSyncCDBTTreeName.empty()) + { + return; + } + + CDBTTree cdbtree(m_bxCounterSyncCDBTTreeName); + + int entry_count = 0; + for (size_t fee = 0; fee < m_bcoMatchingInformation_vec.size(); ++fee) + { + const BcoMatchingInformation& bco_info = m_bcoMatchingInformation_vec[fee]; + const size_t observation_count = std::min(bco_info.get_bx_counter_sync_observation_count(), + BcoMatchingInformation::kMaxBXCounterSyncObservations); + const auto& observations = bco_info.get_bx_counter_sync_observations(); + for (size_t observation_index = 0; observation_index < observation_count; ++observation_index) + { + const BcoMatchingInformation::BXCounterSyncObservation& observation = observations[observation_index]; + const int channel = static_cast(fee * BcoMatchingInformation::kMaxBXCounterSyncObservations + observation_index); + cdbtree.SetIntValue(channel, "packet_id", m_packet_id); + cdbtree.SetIntValue(channel, "fee", static_cast(fee)); + cdbtree.SetIntValue(channel, "observation", static_cast(observation_index)); + cdbtree.SetUInt64Value(channel, "bx_counter_sync_gtm_bco", observation.bx_counter_sync_gtm_bco); + cdbtree.SetUInt64Value(channel, "bco_reference_gtm_bco", observation.bco_reference_gtm_bco); + cdbtree.SetUInt64Value(channel, "m_bco_reference_gtm_bco", observation.m_bco_reference.first); + cdbtree.SetIntValue(channel, "m_bco_reference_fee_bco", static_cast(observation.m_bco_reference.second)); + ++entry_count; + } + } + + if (entry_count == 0) + { + return; + } + + cdbtree.SetSingleIntValue("packet_id", m_packet_id); + cdbtree.SetSingleIntValue("n_bx_counter_sync_observations", entry_count); + cdbtree.SetSingleIntValue("max_fee_count", MAX_FEECOUNT); + cdbtree.SetSingleIntValue("max_observations_per_fee", static_cast(BcoMatchingInformation::kMaxBXCounterSyncObservations)); + cdbtree.CommitSingle(); + cdbtree.Commit(); + cdbtree.WriteCDBTTree(); + + if (m_verbosity >= 0) + { + std::cout << __PRETTY_FUNCTION__ << " - saved " << entry_count + << " BX_COUNTER_SYNC_T observations to " << m_bxCounterSyncCDBTTreeName << std::endl; + } +} + void TpcTimeFrameBuilderRun3::fill_waveform_gl1_spacing(TH1 *waveform_adc_cache, TH2 *waveform_gl1_spacing, uint64_t gtm_bco_spacing) const { assert(waveform_adc_cache); @@ -2007,6 +2062,16 @@ void TpcTimeFrameBuilderRun3::process_fee_data_digital_current(const unsigned in return; } +void TpcTimeFrameBuilderRun3::SaveBXCounterSyncCDBTTree(const std::string& name) +{ + m_bxCounterSyncCDBTTreeName = name; + + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Saving BX counter sync CDB TTree to " << m_bxCounterSyncCDBTTreeName << std::endl; + } +} + void TpcTimeFrameBuilderRun3::SaveDigitalCurrentDebugTTree(const std::string& name) { if (m_verbosity >= 1) @@ -2508,6 +2573,23 @@ uint64_t TpcTimeFrameBuilderRun3::BcoMatchingInformation:: } //___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_bx_counter_sync_observation( + uint64_t bx_counter_sync_gtm_bco, + uint64_t bco_reference_gtm_bco, + const TpcTimeFrameBuilderRun3::BcoMatchingInformation::m_gtm_fee_bco_matching_pair_t& bco_reference) +{ + if (m_bx_counter_sync_observation_count >= kMaxBXCounterSyncObservations) + { + return; + } + + BXCounterSyncObservation& observation = m_bx_counter_sync_observations[m_bx_counter_sync_observation_count]; + observation.bx_counter_sync_gtm_bco = bx_counter_sync_gtm_bco; + observation.bco_reference_gtm_bco = bco_reference_gtm_bco; + observation.m_bco_reference = bco_reference; + ++m_bx_counter_sync_observation_count; +} + void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(const TpcTimeFrameBuilderRun3::gtm_payload& gtm_tagger) { // append gtm_bco from taggers in this event to packet-specific list of available lv1_bco @@ -2619,8 +2701,11 @@ void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(c // get BCO and assign const uint64_t bco_reference_gtm_bco = gtm_bco + kBXCounterSyncGtmBcoOffset; + const m_gtm_fee_bco_matching_pair_t bx_counter_sync_reference = + std::make_pair(bco_reference_gtm_bco, static_cast(kBXCounterSyncFEEBcoOffset)); m_verified_from_modebits = true; - m_bco_reference = std::make_pair(bco_reference_gtm_bco, kBXCounterSyncFEEBcoOffset); + m_bco_reference = bx_counter_sync_reference; + save_bx_counter_sync_observation(gtm_bco, bco_reference_gtm_bco, bx_counter_sync_reference); m_bco_heartbeat_list.clear(); if (m_verbosity) diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h index f4dedef4da..ecbe213465 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -57,6 +57,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase // enable saving of digital current debug TTree with file name `name` void SaveDigitalCurrentDebugTTree(const std::string &name) override; + void SaveBXCounterSyncCDBTTree(const std::string &name) override; protected: // Length for the 256-bit wide Round Robin Multiplexer for the data stream @@ -202,6 +203,15 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! matching between fee bco and lvl1 bco using m_gtm_fee_bco_matching_pair_t = std::pair; using m_fee_gtm_bco_matching_pair_t = std::pair; + struct BXCounterSyncObservation + { + uint64_t bx_counter_sync_gtm_bco = 0; + uint64_t bco_reference_gtm_bco = 0; + m_gtm_fee_bco_matching_pair_t m_bco_reference = {0, 0}; + }; + + //! expect two but tollerate up to four BX_COUNTER_SYNC_T observations to define the reference clock, depending on data quality. The first few observations will be saved in the CDB for future reference. + static constexpr size_t kMaxBXCounterSyncObservations = 4; //! get reference bco const std::optional &get_reference_bco() const @@ -209,6 +219,16 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase return m_bco_reference; } + const std::array &get_bx_counter_sync_observations() const + { + return m_bx_counter_sync_observations; + } + + size_t get_bx_counter_sync_observation_count() const + { + return m_bx_counter_sync_observation_count; + } + //! whether FEE data has moved pass the given gtm_bco bool isMoreDataRequired(const uint64_t >m_bco) const; @@ -328,6 +348,10 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase } private: + void save_bx_counter_sync_observation(uint64_t bx_counter_sync_gtm_bco, + uint64_t bco_reference_gtm_bco, + const m_gtm_fee_bco_matching_pair_t &bco_reference); + std::string m_name; //! verbosity @@ -347,6 +371,10 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! list of available GTM -> FEE bco mapping for synchronization std::optional m_bco_reference = std::nullopt; + //! first BX_COUNTER_SYNC_T observations saved for future CDB reference studies + std::array m_bx_counter_sync_observations; + size_t m_bx_counter_sync_observation_count = 0; + // std::optional< std::pair< uint64_t, uint32_t > > m_bco_reference_candidate = std::nullopt; //! not yet matched heart beats std::list m_bco_heartbeat_list; @@ -410,6 +438,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase //! common prefix for QA histograms std::string m_HistoPrefix; + std::string m_bxCounterSyncCDBTTreeName; static constexpr uint32_t kFEEClockMask = (1U << 20U) - 1U; static constexpr uint32_t kRun3FeeMatchWindow = (GL1_BCO_MATCH_WINDOW * 30U + 7U) / 8U; @@ -434,6 +463,7 @@ class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase void fill_waveform_gl1_spacing(TH1 *waveform_adc_cache, TH2 *waveform_gl1_spacing, uint64_t gtm_bco_spacing) const; void cache_waveform_adc(TH1 *waveform_adc_cache, const std::vector &timeframe) const; void cache_timeframe_qa(uint64_t gtm_bco, const std::vector &timeframe, const std::bitset &exact_matched_fees); + void write_bx_counter_sync_cdb_tree() const; //! FEE -> FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching std::vector>> m_timeHitMap; From 2027ac55a099e8a2fe41ddacb49593cc026a14eb Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 12 Jun 2026 11:34:22 -0400 Subject: [PATCH 660/866] announce deprecation --- offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index 031bd85805..7e9fd804cd 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -60,8 +60,9 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput void SetNegativeBco(const unsigned int value) { m_NegativeBco = value; } //! define minimum pool size in terms of how many BCO are stored - /** obsolete */ - void SetBcoPoolSize(const unsigned int /*value*/) {} + /** deprecated */ + void SetBcoPoolSize(const unsigned int /*value*/) + { std::cout << "SingleMicromegasPoolInput_v2::SetBcoPoolSize is deprecated" << std::endl; } //! save some statistics for BCO QA void FillBcoQA(uint64_t /*gtm_bco*/) override; From 850d753a0cbd77973ac9c5a9a9540122f856a045 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Fri, 12 Jun 2026 11:34:40 -0400 Subject: [PATCH 661/866] adjust m_max_gtm_bco_diff so that FEEs are not incorrectly associated to the next GTM BCO. 60 FEE clocks corresponds to 16 GTM BCO which is the minimum distance between two consecutive triggers. --- .../MicromegasBcoMatchingInformation_v2.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 22e30f087a..83ceb7bf6a 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -123,23 +123,21 @@ namespace } // namespace -// this is the clock multiplier from lvl1 to fee clock +//! this is the clock multiplier from lvl1 to fee clock bool MicromegasBcoMatchingInformation_v2::m_multiplier_is_set = false; double MicromegasBcoMatchingInformation_v2::m_multiplier = 0; -// true if on-fly multiplier adjustment is enabled +//! true if on-fly multiplier adjustment is enabled bool MicromegasBcoMatchingInformation_v2::m_multiplier_adjustment_enabled = true; -// muliplier adjustment count +//! muliplier adjustment count /* controls how often the gtm multiplier is automatically adjusted */ unsigned int MicromegasBcoMatchingInformation_v2::m_max_multiplier_adjustment_count = 200; -// define limit for matching fee_bco to fee_bco_predicted -unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 100; +//! define limit for matching fee_bco to fee_bco_predicted +unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 60; -// -// unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 8; -// unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 16; +//! Max time forward to ensure that a given unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 32; //___________________________________________________ @@ -422,6 +420,7 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa { return bco_matching_iter->second; } + // find element for which predicted fee_bco matches fee_bco, within limit const auto iter = std::find_if( m_gtm_bco_list.begin(), From d06234147a0d8aa68b1a91bbf3c73b580d397069 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Jun 2026 11:22:59 -0400 Subject: [PATCH 662/866] update matching evaluation tree so that one can compare GL1 BCO and Tagger BCO --- .../SingleMicromegasPoolInput_v2.cc | 126 ++++++++++-------- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 26 ++-- 2 files changed, 80 insertions(+), 72 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 41c7969baf..427017fe65 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -310,6 +310,9 @@ void SingleMicromegasPoolInput_v2::FillPool(const uint64_t target_bco) m_timer.stop(); } + if( m_do_evaluation ) + { fill_evaluation_tree( target_bco ); } + // recover truncated FEEs for target bco recover_truncated_waveforms( target_bco ); @@ -561,20 +564,18 @@ 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); m_evaluation_tree->Branch("gtm_bco_first", &m_waveform.gtm_bco_first); - m_evaluation_tree->Branch("gtm_bco", &m_waveform.gtm_bco); - m_evaluation_tree->Branch("gtm_bco_matched", &m_waveform.gtm_bco_matched); + m_evaluation_tree->Branch("gtm_bco_tagger", &m_waveform.gtm_bco_tagger); + m_evaluation_tree->Branch("gtm_bco_gl1", &m_waveform.gtm_bco_gl1); m_evaluation_tree->Branch("fee_bco_first", &m_waveform.fee_bco_first); m_evaluation_tree->Branch("fee_bco", &m_waveform.fee_bco); - m_evaluation_tree->Branch("fee_bco_predicted", &m_waveform.fee_bco_predicted); - m_evaluation_tree->Branch("fee_bco_predicted_matched", &m_waveform.fee_bco_predicted_matched); + m_evaluation_tree->Branch("fee_bco_predicted_tagger", &m_waveform.fee_bco_predicted_tagger); + m_evaluation_tree->Branch("fee_bco_predicted_gl1", &m_waveform.fee_bco_predicted_gl1); } } @@ -727,24 +728,6 @@ void SingleMicromegasPoolInput_v2::decode_gtm_data(int packet_id, const SingleMi * because any BX_COUNTER_SYNC_T event will break past references */ bco_matching_information.find_reference_from_modebits(payload); - - // store in running waveform - if (m_do_evaluation) - { - m_waveform.packet_id = packet_id; - m_waveform.gtm_bco_first = bco_matching_information.get_bco_matching_reference().second; - m_waveform.gtm_bco = bco_matching_information.get_gtm_bco_last(); - - { - const auto predicted = bco_matching_information.get_predicted_fee_bco(m_waveform.gtm_bco); - if (predicted) - { - m_waveform.fee_bco_predicted = predicted.value(); - } - } - - m_waveform.fee_bco_first = bco_matching_information.get_bco_matching_reference().first; - } } //____________________________________________________________________ @@ -871,13 +854,6 @@ 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; @@ -886,20 +862,9 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int { // assign gtm bco gtm_bco = result.value(); - 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; @@ -912,14 +877,6 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int ++m_fee_heartbeat_counters[fee_id].dropped_bco; } - if( m_do_evaluation ) - { - m_waveform.matched = false; - m_waveform.gtm_bco_matched = 0; - m_waveform.fee_bco_predicted_matched = 0; - m_evaluation_tree->Fill(); - } - // skip the waverform continue; } @@ -991,6 +948,58 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int } } +//____________________________________________________________________ +void SingleMicromegasPoolInput_v2::fill_evaluation_tree( const uint64_t target_bco ) +{ + + // loop over fees + for( size_t fee = 0; fee < MAX_FEECOUNT; ++fee ) + { + + // get local raw hitmap + auto&& rawhitmap = m_MicromegasRawHitMap[fee]; + if( rawhitmap.empty() ) { continue; } + + // get the relevant BCO matching information object + const auto& bco_matching_information = m_bco_matching_information_map.at( m_fee_packet[fee] ); + if( !bco_matching_information.is_verified() ) + { continue; } + + m_waveform.packet_id = m_fee_packet[fee]; + m_waveform.fee_id = fee; + m_waveform.gtm_bco_first = bco_matching_information.get_bco_matching_reference().second; + m_waveform.fee_bco_first = bco_matching_information.get_bco_matching_reference().first; + + // assign target bco and prediction + m_waveform.gtm_bco_gl1 = target_bco; + m_waveform.fee_bco_predicted_gl1 = bco_matching_information.get_predicted_fee_bco(target_bco).value(); + + // find matching bco if any and store raw hits + // list of raw hits (channel ordered) matching target BCO + for( auto&& [bco, rawhitlist]:rawhitmap ) + { + + // compare bco to target, within acceptable range + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco ); + if( bco_diff >= -(int64_t)m_NegativeBco && bco_diff < m_BcoRange ) + { + + // assign found bco and prediction + m_waveform.gtm_bco_tagger = bco; + m_waveform.fee_bco_predicted_tagger = bco_matching_information.get_predicted_fee_bco(bco).value(); + for( auto&& rawhit:rawhitlist ) + { + m_waveform.channel = rawhit->get_channel(); + m_waveform.fee_bco = rawhit->get_bco(); + m_evaluation_tree->Fill(); + } + break; + } + } + + } // FEE loop +} + //____________________________________________________________________ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t target_bco ) { @@ -1014,8 +1023,12 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t if( rawhitmap.empty() ) { continue; } // get the relevant BCO matching information object - const auto& bco_matching = m_bco_matching_information_map.at( m_fee_packet[fee] ); - const double truncatedWaveformGTMWindow = kTruncatedWaveformFEEWindow/bco_matching.get_adjusted_multiplier(); + const auto& bco_matching_information = m_bco_matching_information_map.at( m_fee_packet[fee] ); + + // do nothing if bco_matching_information is not verified + if( !bco_matching_information.is_verified() ) { continue; } + + const double truncatedWaveformGTMWindow = kTruncatedWaveformFEEWindow/bco_matching_information.get_adjusted_multiplier(); // find matching bco if any and store raw hits // list of raw hits (channel ordered) matching target BCO @@ -1093,10 +1106,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t } else { // get FEE BCO from GTM - auto result = bco_matching.get_predicted_fee_bco( target_bco ); - if( !result ) { continue; } - - const auto target_fee_bco = result.value(); + const auto target_fee_bco = bco_matching_information.get_predicted_fee_bco( target_bco ).value(); // create new hit with shifted waveform target = new MicromegasRawHit_impl; diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index 7e9fd804cd..a46cc2f0f5 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -104,6 +104,9 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput void decode_gtm_data(int /*packet_id*/, const dma_word &); void process_fee_data(int /*packet_id*/, unsigned int /*fee_id*/); + // fill evaluation tree + void fill_evaluation_tree( const uint64_t /*target_bco*/ ); + // recover truncated waveforms for a given gtm bco void recover_truncated_waveforms( const uint64_t /*target_bco*/ ); @@ -247,20 +250,14 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// channel id unsigned short channel {0}; - /// true if measurement is hearbeat - bool is_heartbeat = false; - - /// true if matched - bool matched = false; - /// ll1 bco uint64_t gtm_bco_first {0}; - /// ll1 bco - uint64_t gtm_bco {0}; + /// bco + uint64_t gtm_bco_tagger {0}; - /// ll1 bco - uint64_t gtm_bco_matched {0}; + /// bco + uint64_t gtm_bco_gl1 {0}; /// fee bco unsigned int fee_bco_first {0}; @@ -268,11 +265,12 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// fee bco unsigned int fee_bco {0}; - /// fee bco predicted (from gtm) - unsigned int fee_bco_predicted {0}; + /// fee bco predicted (from gtm tagger) + unsigned int fee_bco_predicted_tagger {0}; + + /// fee bco predicted (from gtm gl1) + unsigned int fee_bco_predicted_gl1 {0}; - /// fee bco match (from gtm) - unsigned int fee_bco_predicted_matched {0}; }; Waveform m_waveform; From 27b93e66ae9a750319d0d78a832f256336416297 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Jun 2026 14:32:06 -0400 Subject: [PATCH 663/866] added offset between Tagger and GL1 --- .../SingleMicromegasPoolInput_v2.cc | 20 ++-- .../fun4allraw/SingleMicromegasPoolInput_v2.h | 100 ++++++++++-------- 2 files changed, 69 insertions(+), 51 deletions(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 427017fe65..9c1508deef 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -391,9 +391,11 @@ bool SingleMicromegasPoolInput_v2::is_more_data_required(const uint64_t target_b if( m_bco_matching_information_map.empty() ) { return true; } + // correct target_bco by negative BCO and Tagger offset + const uint64_t target_bco_corrected = target_bco + m_NegativeBco + m_TaggerBcoOffset; for( const auto& [packet, bco_matching_information]:m_bco_matching_information_map ) { - if( bco_matching_information.is_more_data_required( target_bco ) ) + if( bco_matching_information.is_more_data_required( target_bco_corrected ) ) { return true; } } @@ -972,7 +974,10 @@ void SingleMicromegasPoolInput_v2::fill_evaluation_tree( const uint64_t target_b // assign target bco and prediction m_waveform.gtm_bco_gl1 = target_bco; - m_waveform.fee_bco_predicted_gl1 = bco_matching_information.get_predicted_fee_bco(target_bco).value(); + + // get prediction + const uint64_t target_bco_corrected = target_bco + m_NegativeBco + m_TaggerBcoOffset; + m_waveform.fee_bco_predicted_gl1 = bco_matching_information.get_predicted_fee_bco(target_bco_corrected).value(); // find matching bco if any and store raw hits // list of raw hits (channel ordered) matching target BCO @@ -980,7 +985,7 @@ void SingleMicromegasPoolInput_v2::fill_evaluation_tree( const uint64_t target_b { // compare bco to target, within acceptable range - const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco ); + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco_corrected ); if( bco_diff >= -(int64_t)m_NegativeBco && bco_diff < m_BcoRange ) { @@ -1011,7 +1016,8 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t static constexpr int32_t kTruncatedWaveformFEEWindow = kTruncatedWaveformWindow*kFEEClockPerADCClock; // keep track of exact BCO - uint64_t found_bco = target_bco; + const uint64_t target_bco_corrected = target_bco + m_NegativeBco + m_TaggerBcoOffset; + uint64_t found_bco = target_bco_corrected; // loop over fees for( size_t fee = 0; fee < MAX_FEECOUNT; ++fee ) @@ -1037,7 +1043,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t { // compare bco to target, within acceptable range - const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco ); + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco_corrected ); if( bco_diff >= -(int64_t)m_NegativeBco && bco_diff < m_BcoRange ) { found_bco = bco; @@ -1068,7 +1074,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t // find candidate overlapping bco if any for( auto&& [bco, rawhitlist]:rawhitmap ) { - const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco ); + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco_corrected ); if( bco_diff >= m_BcoRange && bco_diff < truncatedWaveformGTMWindow ) { @@ -1106,7 +1112,7 @@ void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t t } else { // get FEE BCO from GTM - const auto target_fee_bco = bco_matching_information.get_predicted_fee_bco( target_bco ).value(); + const auto target_fee_bco = bco_matching_information.get_predicted_fee_bco( target_bco_corrected ).value(); // create new hit with shifted waveform target = new MicromegasRawHit_impl; diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index a46cc2f0f5..d635677c37 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -26,31 +26,31 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput { public: - //! constructor + /// constructor explicit SingleMicromegasPoolInput_v2(const std::string &name = "SingleMicromegasPoolInput_v2"); - //! destructor + /// destructor ~SingleMicromegasPoolInput_v2() override; - //! pool filling + /// pool filling void FillPool(const uint64_t /*target_bco*/) override; - //! cleanup + /// cleanup void CleanupUsedPackets(const uint64_t bclk) override { CleanupUsedPackets(bclk, false); } - //! specialized verion of cleaning up packets, with an extra flag about wheter the cleanup hits are dropped or not + /// specialized verion of cleaning up packets, with an extra flag about wheter the cleanup hits are dropped or not void CleanupUsedPackets(const uint64_t /* bclk */, bool /*dropped */) override; - //! current event cleaning + /// current event cleaning void ClearCurrentEvent() override; - //! print + /// print void Print(const std::string &what = "ALL") const override; - //! + /// void CreateDSTNode(PHCompositeNode *topNode) override; void SetBcoRange(const unsigned int value) { m_BcoRange = value; } @@ -59,12 +59,21 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput void SetNegativeBco(const unsigned int value) { m_NegativeBco = value; } - //! define minimum pool size in terms of how many BCO are stored + /// set the offset between FELIX tagger BCO (internal) and GL1 (external) BCO + /** + * explicitly taggerBCO = GL1 BCO + offset + * this is somewhat redundant with m_Negative BCO, unfortunately, but + * 1/ m_NegativeBco is also used upstream by Fun4AllStreamingInputManager + * 2/ m_NegativeBCO is unsigned int + */ + void SetTaggerBcoOffset( const int value ) { m_TaggerBcoOffset = value; } + + /// define minimum pool size in terms of how many BCO are stored /** deprecated */ void SetBcoPoolSize(const unsigned int /*value*/) { std::cout << "SingleMicromegasPoolInput_v2::SetBcoPoolSize is deprecated" << std::endl; } - //! save some statistics for BCO QA + /// save some statistics for BCO QA void FillBcoQA(uint64_t /*gtm_bco*/) override; // write the initial histograms for QA manager @@ -78,10 +87,10 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput private: - //! true if more data is to be processed for collecting that of a given bco + /// true if more data is to be processed for collecting that of a given bco bool is_more_data_required(const uint64_t /*target_bco*/) const; - //!@name decoding constants + ///@name decoding constants //@{ /// max number of FEE per OBDC static constexpr uint16_t MAX_FEECOUNT = 26; @@ -93,7 +102,7 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput static constexpr size_t DAM_DMA_WORD_LENGTH = 16; //@} - //! DMA word structure + /// DMA word structure struct dma_word { uint16_t dma_header; @@ -104,16 +113,16 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput void decode_gtm_data(int /*packet_id*/, const dma_word &); void process_fee_data(int /*packet_id*/, unsigned int /*fee_id*/); - // fill evaluation tree + /// fill evaluation tree void fill_evaluation_tree( const uint64_t /*target_bco*/ ); - // recover truncated waveforms for a given gtm bco + /// recover truncated waveforms for a given gtm bco void recover_truncated_waveforms( const uint64_t /*target_bco*/ ); - // fee data buffer + /// fee data buffer std::array, MAX_FEECOUNT> m_feeData{}; - // list of packets from data stream + /// list of packets from data stream std::array plist{}; /// keep track of number of non data events @@ -125,7 +134,10 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// bco adjustment for matching across subsystems unsigned int m_NegativeBco{0}; - //! store list of packets that have data for a given beam clock + /// offset between FELIX tagger BCO (internal) and GL1 (external) BCO + int m_TaggerBcoOffset{0}; + + /// store list of packets that have data for a given beam clock /** * all packets in taggers are stored, * disregarding whether there is data associated to it or not @@ -133,42 +145,42 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput */ std::map> m_BeamClockPacket; - //! store list of FEE that have data for a given beam clock + /// store list of FEE that have data for a given beam clock std::map> m_BeamClockFEE; - //! list of raw hits + /// list of raw hits using rawhit_list_t = std::vector; - //! maps list of raw hits on GTM BCO values + /// maps list of raw hits on GTM BCO values using rawhit_map_t = std::map; - //! store list of raw hits matching a given GTM bco on a per FEE basis + /// store list of raw hits matching a given GTM bco on a per FEE basis std::array m_MicromegasRawHitMap{}; - //! map bco_information_t to packet id + /// map bco_information_t to packet id using bco_matching_information_map_t = std::map; bco_matching_information_map_t m_bco_matching_information_map{}; - //! map packet to FEE ID + /// map packet to FEE ID /* it is filled on the fly. It allows to quickly retrieve BCO matching information from FEE index */ std::array m_fee_packet{}; class counter_t { public: - //! total count + /// total count uint64_t total {0}; - //! drop count due to unmatched bco + /// drop count due to unmatched bco uint64_t dropped_bco {0}; - //! drop count due to pools + /// drop count due to pools uint64_t dropped_pool {0}; - //! dropped fraction (bco) + /// dropped fraction (bco) double dropped_fraction_bco() const { return double(dropped_bco) / total; } - //! dropped fraction (pool) + /// dropped fraction (pool) double dropped_fraction_pool() const { return double(dropped_pool) / total; } }; @@ -187,50 +199,50 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput // timer PHTimer m_timer{"SingleMicromegasPoolInput_v2"}; - //!@name QA histograms + ///@name QA histograms //@{ - //! keeps track of how often a given (or all) packets are found for a given BCO + /// keeps track of how often a given (or all) packets are found for a given BCO TH1 *h_packet_stat{nullptr}; - //! keep track of how many heartbeats are found per FEE sampa + /// keep track of how many heartbeats are found per FEE sampa TH1 *h_heartbeat_stat{nullptr}; - //! keeps track of how many packets are found for a given BCO + /// keeps track of how many packets are found for a given BCO TH1 *h_packet{nullptr}; - //! keeps track of how many waveforms are found for a given BCO + /// keeps track of how many waveforms are found for a given BCO TH1 *h_waveform{nullptr}; - //! total number of waveforms per packet + /// total number of waveforms per packet TH1 *h_waveform_count_total{nullptr}; - //! total number of dropped waveforms per packet due to bco mismatch + /// total number of dropped waveforms per packet due to bco mismatch /*! waveforms are dropped when their FEE-BCO cannot be associated to any global BCO */ TH1 *h_waveform_count_dropped_bco{nullptr}; - //! total number of dropped waveforms per packet due to fun4all pool mismatch + /// total number of dropped waveforms per packet due to fun4all pool mismatch TH1 *h_waveform_count_dropped_pool{nullptr}; - //! total number of waveforms per packet + /// total number of waveforms per packet TH1 *h_fee_waveform_count_total{nullptr}; - //! total number of dropped waveforms per fee due to bco mismatch + /// total number of dropped waveforms per fee due to bco mismatch /*! waveforms are dropped when their FEE-BCO cannot be associated to any global BCO */ TH1 *h_fee_waveform_count_dropped_bco{nullptr}; - //! total number of dropped waveforms per fee due to fun4all pool mismatch + /// total number of dropped waveforms per fee due to fun4all pool mismatch TH1 *h_fee_waveform_count_dropped_pool{nullptr}; //@} - //!@name evaluation + ///@name evaluation //@{ - //! evaluation + /// evaluation bool m_do_evaluation = false; - //! evaluation output filename + /// evaluation output filename std::string m_evaluation_filename = "SingleMicromegasPoolInput.root"; std::unique_ptr m_evaluation_file; @@ -275,7 +287,7 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput Waveform m_waveform; - //! tree + /// tree TTree *m_evaluation_tree {nullptr}; //*} From 88706e2c5a9a521975c347d4257c118ab521c1ba Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Jun 2026 16:44:23 -0400 Subject: [PATCH 664/866] added flag to enable/disable truncated waveforms recovery --- offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc | 2 +- offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 9c1508deef..6248c1a506 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -314,7 +314,7 @@ void SingleMicromegasPoolInput_v2::FillPool(const uint64_t target_bco) { fill_evaluation_tree( target_bco ); } // recover truncated FEEs for target bco - recover_truncated_waveforms( target_bco ); + if( m_recover_truncated_waveforms ) { recover_truncated_waveforms( target_bco ); } } diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index d635677c37..cdb2275a8a 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -53,6 +53,8 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// void CreateDSTNode(PHCompositeNode *topNode) override; + void SetRecoverTruncatedWaveforms( bool value ) { m_recover_truncated_waveforms = value; } + void SetBcoRange(const unsigned int value) { m_BcoRange = value; } void ConfigureStreamingInputManager() override; @@ -119,6 +121,9 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// recover truncated waveforms for a given gtm bco void recover_truncated_waveforms( const uint64_t /*target_bco*/ ); + /// true to recover waveform truncated due to overlapping timeframes + bool m_recover_truncated_waveforms{true}; + /// fee data buffer std::array, MAX_FEECOUNT> m_feeData{}; From 11356307f848587a93691d6ee33b47acb38ebb66 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Jun 2026 17:18:53 -0400 Subject: [PATCH 665/866] increased time for pool filling. --- .../framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 83ceb7bf6a..954ab59f18 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -138,7 +138,7 @@ unsigned int MicromegasBcoMatchingInformation_v2::m_max_multiplier_adjustment_co unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 60; //! Max time forward to ensure that a given -unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 32; +unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 96; //___________________________________________________ int64_t MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff(uint64_t first, uint64_t second) From d55e4d36719f1e24eae377541e6e18e4a0496f9e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 15 Jun 2026 17:20:24 -0400 Subject: [PATCH 666/866] Set default offset value for GL1 vs tagger to 3, which (I think) works for all run3 pp --- offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index cdb2275a8a..ef7a63e00f 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -140,7 +140,7 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput unsigned int m_NegativeBco{0}; /// offset between FELIX tagger BCO (internal) and GL1 (external) BCO - int m_TaggerBcoOffset{0}; + int m_TaggerBcoOffset{3}; /// store list of packets that have data for a given beam clock /** From e8acadd3c6df18557a0cb6ec77d8dc9dbf7b9a7b Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 15 Jun 2026 17:56:23 -0400 Subject: [PATCH 667/866] use std::array, add access method for radii --- offline/packages/PHGarfield/PHGarfield.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index a4e15fe129..626afbd2e1 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -3,6 +3,7 @@ #include +#include #include #include @@ -34,6 +35,8 @@ class PHGarfield : public SubsysReco // The user is encouraged to add more routine to fit their analysis goals... TPolyLine3D *ReverseDrift(double x_cm, double y_cm, double z_cm, double step_ns = 50.0); // Drifts electrons from some initial point until they hit a detector boundary... + double GetRadius(size_t index) {return radii.at(index);} + private: void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double &bx_t, double &by_t, double &bz_t); // Feeds magnetic field to Garfield void GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double &ex_vcm, double &ey_vcm, double &ez_vcm); // Feeds electric field to Garfield @@ -50,7 +53,7 @@ class PHGarfield : public SubsysReco // std::string calibdir; // std::string m_DiodeContainerName; double PHI_MIN{-std::numbers::pi}; - double radii[48]{}; // Radius on each layer just for test purposes...need to be cm! + std::array radii{}; // Radius on each layer just for test purposes...need to be cm! }; #endif From 61b00a26aadd044c1bf6eee7d012856630519e48 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 15 Jun 2026 19:38:48 -0400 Subject: [PATCH 668/866] use const methods where possible --- offline/packages/PHGarfield/PHGarfield.cc | 10 +++++----- offline/packages/PHGarfield/PHGarfield.h | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc index d04d7c4bb4..e6fe4516ae 100644 --- a/offline/packages/PHGarfield/PHGarfield.cc +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -84,7 +84,7 @@ void PHGarfield::FillRadii() } } -void PHGarfield::PrintGarfield(double x, double y, double z) +void PHGarfield::PrintGarfield(double x, double y, double z) const { double ex; double ey; @@ -113,7 +113,7 @@ void PHGarfield::PrintGarfield(double x, double y, double z) << std::endl; } -void PHGarfield::PrintMaps() +void PHGarfield::PrintMaps() const { // Print out a few test points of the Garfield information PrintGarfield(0.0, 0.0, 0.1); @@ -160,7 +160,7 @@ void PHGarfield::PrintMaps() } } -void PHGarfield::GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double& bx_t, double& by_t, double& bz_t) +void PHGarfield::GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double& bx_t, double& by_t, double& bz_t) const { // NOTE: Garfield uses cm, V/cm, and Tesla. // CLHEP uses mm, V/mm, and kiloTesla @@ -184,7 +184,7 @@ void PHGarfield::GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, do bz_t = bfield[2] / CLHEP::tesla; } -void PHGarfield::GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double& ex_vcm, double& ey_vcm, double& ez_vcm) +void PHGarfield::GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double& ex_vcm, double& ey_vcm, double& ez_vcm) const { // NOTE: Garfield uses cm, V/cm, and Tesla. (void) x_cm; @@ -195,7 +195,7 @@ void PHGarfield::GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, doub ez_vcm = z_cm > 0 ? -400.0 : 400.0; } -void PHGarfield::InitializeGas(std::string dir) +void PHGarfield::InitializeGas(const std::string &dir) { // Create and fill the gas object so that we can trace particles through the gas... m_gas = new Garfield::MediumMagboltz(); diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index 626afbd2e1..47d3118898 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -24,25 +24,25 @@ class PHGarfield : public SubsysReco ~PHGarfield() override = default; int InitRun(PHCompositeNode *) override; - int process_event(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode * /*topNode*/) override; bool StopHere(const double x, const double y, const double z, const double zPrevious); - void PrintMaps(); - void PrintGarfield(double x, double y, double z); + void PrintMaps() const; + void PrintGarfield(double x, double y, double z) const; // These are left in public namespace for easy plotting macros... // The user is encouraged to add more routine to fit their analysis goals... TPolyLine3D *ReverseDrift(double x_cm, double y_cm, double z_cm, double step_ns = 50.0); // Drifts electrons from some initial point until they hit a detector boundary... - double GetRadius(size_t index) {return radii.at(index);} + double GetRadius(size_t index) const {return radii.at(index);} private: - void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double &bx_t, double &by_t, double &bz_t); // Feeds magnetic field to Garfield - void GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double &ex_vcm, double &ey_vcm, double &ez_vcm); // Feeds electric field to Garfield - void InitializeGas(std::string dir); + void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double &bx_t, double &by_t, double &bz_t) const; // Feeds magnetic field to Garfield + void GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double &ex_vcm, double &ey_vcm, double &ez_vcm) const; // Feeds electric field to Garfield + void InitializeGas(const std::string &dir); void FillRadii(); - double bounder(double phi, double phi_min); + static double bounder(double phi, double phi_min); CDBTTree *m_cdbTPCMAPttree{nullptr}; // Locations of the pads from CDB... PHField3DCartesian *m_field{nullptr}; // The stanards sPHENIX field holding container. From c4b774942b474ed466eeaf369f8fa6cca396b996 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 15 Jun 2026 19:50:41 -0400 Subject: [PATCH 669/866] clean up process_event --- offline/packages/PHGarfield/PHGarfield.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc index e6fe4516ae..157ffb893d 100644 --- a/offline/packages/PHGarfield/PHGarfield.cc +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -236,11 +236,8 @@ void PHGarfield::InitializeGas(const std::string &dir) } } -int PHGarfield::process_event(PHCompositeNode* topNode) +int PHGarfield::process_event(PHCompositeNode*) { - // Avoids the compiler error for having nore used the topNode. - (void) topNode; - // Initial implementation doesn't do anything event-by-event. // Nonetheless, a future user might want do do something here... From eb922e2799c914a7b4b36a04d2eb5a55292513fe Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 16 Jun 2026 08:12:23 -0400 Subject: [PATCH 670/866] retire obsolete rawbcolumi --- ...un4AllStreamingLumiCountingInputManager.cc | 593 ------------------ ...Fun4AllStreamingLumiCountingInputManager.h | 108 ---- offline/framework/rawbcolumi/Makefile.am | 50 -- .../rawbcolumi/SingleGl1PoolInputv2.cc | 362 ----------- .../rawbcolumi/SingleGl1PoolInputv2.h | 54 -- .../rawbcolumi/SingleStreamingInputv2.cc | 139 ---- .../rawbcolumi/SingleStreamingInputv2.h | 114 ---- offline/framework/rawbcolumi/autogen.sh | 8 - offline/framework/rawbcolumi/configure.ac | 17 - 9 files changed, 1445 deletions(-) delete mode 100644 offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.cc delete mode 100644 offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.h delete mode 100644 offline/framework/rawbcolumi/Makefile.am delete mode 100644 offline/framework/rawbcolumi/SingleGl1PoolInputv2.cc delete mode 100644 offline/framework/rawbcolumi/SingleGl1PoolInputv2.h delete mode 100644 offline/framework/rawbcolumi/SingleStreamingInputv2.cc delete mode 100644 offline/framework/rawbcolumi/SingleStreamingInputv2.h delete mode 100755 offline/framework/rawbcolumi/autogen.sh delete mode 100644 offline/framework/rawbcolumi/configure.ac diff --git a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.cc b/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.cc deleted file mode 100644 index 754718cfc6..0000000000 --- a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.cc +++ /dev/null @@ -1,593 +0,0 @@ -#include "Fun4AllStreamingLumiCountingInputManager.h" - -#include -#include "SingleStreamingInputv2.h" - -#include - -#include -#include // for Fun4AllInputManager -#include -#include -#include - -#include // for SyncObject -#include - -#include -#include -#include - -#include // for PHObject -#include -#include // for PHWHERE -#include - -#include -#include -#include -#include - -#include // for max -#include -#include // for uint64_t, uint16_t -#include -#include // for operator<<, basic_ostream, endl -#include // for pair - -Fun4AllStreamingLumiCountingInputManager::Fun4AllStreamingLumiCountingInputManager(const std::string &name, const std::string &dstnodename, const std::string &topnodename) - : Fun4AllInputManager(name, dstnodename, topnodename) - , m_SyncObject(new SyncObjectv1()) -{ - Fun4AllServer *se = Fun4AllServer::instance(); - m_topNode = se->topNode(TopNodeName()); - - createLuminosityHistos(); - return; -} - -Fun4AllStreamingLumiCountingInputManager::~Fun4AllStreamingLumiCountingInputManager() -{ - if (IsOpen()) - { - fileclose(); - } - // std::cout<<"----Write? files to output.root"<Write("", TObject::kOverwrite); - h_lumibco->Write("", TObject::kOverwrite); - h_bunchnumber->Write("", TObject::kOverwrite); - h_bunchnumber_occur->Write("", TObject::kOverwrite); - tfile->Close(); - delete tfile; - */ - return iret; -} - -void Fun4AllStreamingLumiCountingInputManager::SetOutputFileName(const std::string &fileName) -{ - m_outputFileName = fileName; // Update the filename -} - -int Fun4AllStreamingLumiCountingInputManager::fileclose() -{ - // std::cout<<"----fileclose()"<Name() << " reads run " - << iter->RunNumber() - << " from file " << iter->FileName() - << std::endl; - } - } - Fun4AllInputManager::Print(what); - return; -} - -int Fun4AllStreamingLumiCountingInputManager::ResetEvent() -{ - // zhiwan - // m_RefBCO = 0; - return 0; -} - -int Fun4AllStreamingLumiCountingInputManager::PushBackEvents(const int /*i*/) -{ - return 0; -} - -int Fun4AllStreamingLumiCountingInputManager::GetSyncObject(SyncObject **mastersync) -{ - // here we copy the sync object from the current file to the - // location pointed to by mastersync. If mastersync is a 0 pointer - // the syncobject is cloned. If mastersync allready exists the content - // of syncobject is copied - if (!(*mastersync)) - { - if (m_SyncObject) - { - *mastersync = dynamic_cast(m_SyncObject->CloneMe()); - assert(*mastersync); - } - } - else - { - *(*mastersync) = *m_SyncObject; // copy syncobject content - } - return Fun4AllReturnCodes::SYNC_OK; -} - -int Fun4AllStreamingLumiCountingInputManager::SyncIt(const SyncObject *mastersync) -{ - if (!mastersync) - { - std::cout << PHWHERE << Name() << " No MasterSync object, cannot perform synchronization" << std::endl; - std::cout << "Most likely your first file does not contain a SyncObject and the file" << std::endl; - std::cout << "opened by the Fun4AllDstInputManager with Name " << Name() << " has one" << std::endl; - std::cout << "Change your macro and use the file opened by this input manager as first input" << std::endl; - std::cout << "and you will be okay. Fun4All will not process the current configuration" << std::endl - << std::endl; - return Fun4AllReturnCodes::SYNC_FAIL; - } - int iret = m_SyncObject->Different(mastersync); - if (iret) - { - std::cout << "big problem" << std::endl; - exit(1); - } - return Fun4AllReturnCodes::SYNC_OK; -} - -std::string Fun4AllStreamingLumiCountingInputManager::GetString(const std::string &what) const -{ - std::cout << PHWHERE << " called with " << what << " , returning empty string" << std::endl; - return ""; -} - -void Fun4AllStreamingLumiCountingInputManager::registerStreamingInput(SingleStreamingInputv2 *evtin, InputManagerType::enu_subsystem system) -{ - evtin->StreamingLumiInputManager(this); - // if the streaming flag is set, we only want the first event from the GL1 to - // get the starting BCO of that run which enables us to dump all the junk which - // is taken before the run starts in the streaming systems. But we don't want the - // GL1 in the output, so we do not create its dst node if running in streaming - if (system == InputManagerType::GL1) - { - if (!m_StreamingFlag) - { - evtin->CreateDSTNode(m_topNode); - } - } - else - { - evtin->CreateDSTNode(m_topNode); - } - evtin->ConfigureStreamingInputManager(); - if (system == InputManagerType::GL1) - { - m_gl1_registered_flag = true; - m_Gl1InputVector.push_back(evtin); - } - else - { - std::cout << "invalid subsystem flag " << system << std::endl; - gSystem->Exit(1); - exit(1); - } - if (Verbosity() > 3) - { - std::cout << "registering " << evtin->Name() - << " number of registered inputs: " - << m_Gl1InputVector.size() - << std::endl; - } - std::cout << m_Gl1InputVector.size() << std::endl; -} - -void Fun4AllStreamingLumiCountingInputManager::AddGl1RawHit(uint64_t bclk, Gl1Packet *hit) -{ - m_Gl1RawHitMap[bclk].Gl1RawHitVector.push_back(hit); -} - -void Fun4AllStreamingLumiCountingInputManager::AddGl1Window(uint64_t bco_trim, int negative_window, int positive_window) -{ - m_BCOWindows[bco_trim] = std::make_pair(bco_trim - negative_window, bco_trim + positive_window); -} - -void Fun4AllStreamingLumiCountingInputManager::AddGl1BunchNumber(uint64_t bco_trim, int bunch_number) -{ - m_BCOBunchNumber[bco_trim] = bunch_number; -} - -int Fun4AllStreamingLumiCountingInputManager::FillGl1() -{ - // unsigned int alldone = 0; - for (auto *iter : m_Gl1InputVector) - { - if (Verbosity() > 0) - { - std::cout << "Fun4AllStreamingLumiCountingInputManager::FillGl1 - fill pool for " << iter->Name() << std::endl; - std::cout << "Run number " << iter->RunNumber() << std::endl; - } - iter->FillPool(); - - if (m_RunNumber == 0) - { - m_RunNumber = iter->RunNumber(); - SetRunNumber(m_RunNumber); - } - else - { - if (m_RunNumber != iter->RunNumber()) - { - std::cout << PHWHERE << " Run Number mismatch, run is " - << m_RunNumber << ", " << iter->Name() << " reads " - << iter->RunNumber() << std::endl; - std::cout << "You are likely reading files from different runs, do not do that" << std::endl; - Print("INPUTFILES"); - gSystem->Exit(1); - exit(1); - } - } - } - - if (Verbosity() > 0) - { - std::cout << "Here BCO " << m_BCOWindows.begin()->first << " left " << m_BCOWindows.begin()->second.first << " right " << m_BCOWindows.begin()->second.second << std::endl; - } - /* - for (const auto &entry : m_BCOWindows) { - uint64_t key = entry.first; - uint64_t valueFirst = entry.second.first; - uint64_t valueSecond = entry.second.second; - std::cout << "Key: " << key - << ", Value First: " << valueFirst - << ", Value Second: " << valueSecond - << std::endl; - } - - for (const auto& [bco_trim, bunch_number] : m_BCOBunchNumber) { - std::cout << "Here BCO " << bco_trim << " Bunch Number " << bunch_number << std::endl; - } - */ - // std::cout << "Here BCO " <first < 1) - { - auto first_element = m_BCOWindows.begin(); - auto second_element = std::next(m_BCOWindows.begin()); - // std::cout<<"Key 1: "<first<<" Value ( "<second.first<<" , "<second.second<first<<" Value ( "<second.first<<" , "<second.second<first - first_element->first<<" compared with window "<< m_negative_bco_window+m_positive_bco_window < 1099511000000, then switch them - m_diffBCO = second_element->first - first_element->first; - - if (second_element->first - first_element->first > 1099510000000) - { - flat_overflow = true; - // int temp_m_diffBCO=first_element->first+1099511627775+1-second_element->first; - bco_temp = first_element->first; - m_BCOWindows.erase(m_BCOWindows.begin()); - bco_temp += 1099511627775 + 1; - m_BCOWindows[bco_temp] = std::make_pair(bco_temp - m_negative_bco_window, bco_temp + m_positive_bco_window); - first_element = m_BCOWindows.begin(); - second_element = std::next(m_BCOWindows.begin()); - m_diffBCO = second_element->first - first_element->first; - std::cout << "overflow new diff " << m_diffBCO << " new first element " << first_element->first << " new second element " << second_element->first << std::endl; - } - h_diffbco->Fill(m_diffBCO); - if (m_diffBCO < static_cast(m_negative_bco_window + m_positive_bco_window)) - { - m_BCOWindows.begin()->second.second = second_element->second.first; - std::cout << "*** new Key 1 BCO " << m_BCOWindows.begin()->first << " left " << m_BCOWindows.begin()->second.first << " right " << m_BCOWindows.begin()->second.second << std::endl; - } - } - - m_bco_trim = m_BCOWindows.begin()->first; - m_lower_bound = m_BCOWindows.begin()->second.first; - m_upper_bound = m_BCOWindows.begin()->second.second; - m_bunch_number = m_BCOBunchNumber[m_BCOWindows.begin()->first]; - // ttree->Fill(); - h_bunchnumber->Fill(m_BCOBunchNumber[m_BCOWindows.begin()->first]); - h_lumibco->Fill(m_BCOWindows.begin()->second.second - m_BCOWindows.begin()->second.first); - - int lower = -1 * static_cast(m_bco_trim - m_lower_bound); - int upper = (m_upper_bound > m_bco_trim) ? static_cast(m_upper_bound - m_bco_trim) : -1 * static_cast(m_bco_trim - m_upper_bound); // it is possible that upper is <0 - // std::cout<<"lower="<first); - // m_BCOBunchNumber.erase(m_BCOBunchNumber.begin()); - } - if (!m_BCOWindows.empty()) - { - m_BCOWindows.erase(m_BCOWindows.begin()); - } - if (flat_overflow) - { - m_BCOWindows.erase(m_BCOWindows.begin()); - bco_temp -= 1099511627775 + 1; - m_BCOWindows[bco_temp] = std::make_pair(bco_temp - m_negative_bco_window, bco_temp + m_positive_bco_window); - std::cout << " Change back, new bco window map " << m_BCOBunchNumber.begin()->first << std::endl; - flat_overflow = false; - } - - // mow use new - - Gl1Packet *gl1packet = findNode::getClass(m_topNode, "GL1RAWHIT"); - for (auto *gl1hititer : m_Gl1RawHitMap.begin()->second.Gl1RawHitVector) - { - if (!m_StreamingFlag) // if streaming flag is set, the gl1packet is a nullptr - { - gl1packet->FillFrom(gl1hititer); - MySyncManager()->CurrentEvent(gl1packet->getEvtSequence()); - } - } - - // add for mbd p_gl1 - Gl1Packet *p_gl1 = findNode::getClass(m_topNode, "GL1RAWHIT"); //"GL1Packet"); - if (!p_gl1) - { - std::cout << "CAN not find this Gl1Packet" << std::endl; - } - else - { - int bunchnumber = p_gl1->getBunchNumber(); - // uint64_t evtBCO_gl1 = p_gl1->getBCO() & 0xFFFFFFFFFFU; - // for (int i = 0; i <9;i++)// int(GL1PScaler_raw_vec.size()); i++) - // { - if (p_gl1->lValue(0, "GL1PRAW")) // 0-8, 0 is MBDSN - { - // GL1PScaler_raw_vec[i][bunchnumber] = p_gl1->lValue(i, "GL1PRAW"); - // std::cout<<"evtBCO: "<lValue(0, "GL1PRAW"); - m_bunchnumber_MBDNS_live[bunchnumber] = p_gl1->lValue(0, "GL1PLIVE"); - m_bunchnumber_MBDNS_scaled[bunchnumber] = p_gl1->lValue(0, "GL1PSCALED"); - m_bunchnumber_ZDCCoin_raw[bunchnumber] = p_gl1->lValue(5, "GL1PRAW"); // zdc coincidence - // h_gl1p_MBDSN_bunchid->Fill(bunchnumber, p_gl1->lValue(0, "GL1PRAW")); - // std::cout<<" bunchnumber ="<lValue(0, 0)) - { - // m_bunchnumber_rawgl1scaler[bunchnumber] = p_gl1->lValue(0, 0); - // std::cout<<" bunchnumber ="< 0) - { - if (m_alldone_flag) - { - std::cout << "all done is true" << std::endl; - } - } - - if (m_alldone_flag) - { - std::cout << m_event_number << " Events -- Storing files to output.root" << std::endl; - std::string updatedFileName = m_outputFileName + "_" + std::to_string(m_event_number) + ".root"; - if (TFile::Open(updatedFileName.c_str(), "READ")) - { - updatedFileName = m_outputFileName + "_" + std::to_string(m_event_number + 1) + ".root"; - } - tfile = TFile::Open(updatedFileName.c_str(), "RECREATE", ""); - ttree->Write("", TObject::kOverwrite); - h_lumibco->Write("", TObject::kOverwrite); - h_bunchnumber->Write("", TObject::kOverwrite); - h_bunchnumber_occur->Write("", TObject::kOverwrite); - h_diffbco->Write("", TObject::kOverwrite); - h_gl1p_MBDSN_bunchid_raw->Write("", TObject::kOverwrite); - h_gl1p_MBDSN_bunchid_live->Write("", TObject::kOverwrite); - h_gl1p_MBDSN_bunchid_scaled->Write("", TObject::kOverwrite); - h_gl1p_rawgl1scaler->Write("", TObject::kOverwrite); - h_gl1p_ZDCCoin_bunchid_raw->Write("", TObject::kOverwrite); - tfile->Close(); - delete tfile; - - ttree->Reset(); - h_lumibco->Reset(); - h_bunchnumber->Reset(); - h_bunchnumber_occur->Reset(); - h_diffbco->Reset(); - h_gl1p_MBDSN_bunchid_raw->Reset(); - h_gl1p_MBDSN_bunchid_live->Reset(); - h_gl1p_MBDSN_bunchid_scaled->Reset(); - h_gl1p_rawgl1scaler->Reset(); - h_gl1p_ZDCCoin_bunchid_raw->Reset(); - } - - return 0; -} - -void Fun4AllStreamingLumiCountingInputManager::SetNegativeWindow(const unsigned int i) -{ - m_negative_bco_window = std::max(i, m_negative_bco_window); -} - -void Fun4AllStreamingLumiCountingInputManager::SetPositiveWindow(const unsigned int i) -{ - m_positive_bco_window = std::max(i, m_positive_bco_window); -} - -void Fun4AllStreamingLumiCountingInputManager::createLuminosityHistos() -{ - auto *hm = QAHistManagerDef::getHistoManager(); - assert(hm); - // zhiwan - { - auto *tr = new TTree("BCOWindowTree", "BCO Window Data"); - tr->Branch("bco_trim", &m_bco_trim); - tr->Branch("lower_bound", &m_lower_bound); - tr->Branch("upper_bound", &m_upper_bound); - tr->Branch("bunch_number", &m_bunch_number); - // tr->Branch("rawgl1scaler", &m_rawgl1scaler); - tr->SetAutoFlush(100000); - hm->registerHisto(tr); - } - - { - auto *h = new TH1I("h_LumiBCO", "Lumi BCO", 500, 0, 500); - h->GetXaxis()->SetTitle(" Lumi BCO per event"); - h->SetTitle("Number of BCO matched"); - hm->registerHisto(h); - } - { - auto *h = new TH1I("h_BunchNumber", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_BunchNumberOccurance", "Bunch Number Lumi BCO", 120, -0.5, 119.5); - h->GetXaxis()->SetTitle("Bunch Number per time window"); - h->SetTitle("Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1I("h_diffBCO", "gl1 bco 1-2", 3500, 0, 3500); - h->GetXaxis()->SetTitle("GL1 BCO difference"); - h->SetTitle("Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_MBDSNraw_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("MBDSN Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_MBDSNlive_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("MBDSN Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_MBDSNscaled_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("MBDSN Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_rawgl1scalerBunchID", "Bunch Number Lumi BCO", 10, -0.5, 9.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("raw GL1 scaler"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_gl1p_ZDCCoin_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("raw GL1 scaler"); - hm->registerHisto(h); - } - // Get the global pointers - h_lumibco = dynamic_cast(hm->getHisto("h_LumiBCO")); - h_bunchnumber = dynamic_cast(hm->getHisto("h_BunchNumber")); - h_bunchnumber_occur = dynamic_cast(hm->getHisto("h_BunchNumberOccurance")); - ttree = dynamic_cast(hm->getHisto("BCOWindowTree")); - h_diffbco = dynamic_cast(hm->getHisto("h_diffBCO")); - h_gl1p_MBDSN_bunchid_raw = dynamic_cast(hm->getHisto("h_MBDSNraw_BunchID")); - h_gl1p_MBDSN_bunchid_live = dynamic_cast(hm->getHisto("h_MBDSNlive_BunchID")); - h_gl1p_MBDSN_bunchid_scaled = dynamic_cast(hm->getHisto("h_MBDSNscaled_BunchID")); - h_gl1p_rawgl1scaler = dynamic_cast(hm->getHisto("h_rawgl1scalerBunchID")); - h_gl1p_ZDCCoin_bunchid_raw = dynamic_cast(hm->getHisto("h_gl1p_ZDCCoin_BunchID")); -} diff --git a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.h b/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.h deleted file mode 100644 index 3f1515bb23..0000000000 --- a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.h +++ /dev/null @@ -1,108 +0,0 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. -#ifndef RAWBCOLUMI_FUN4ALLSTREAMINGLUMICOUNTINGINPUTMANAGER_H -#define RAWBCOLUMI_FUN4ALLSTREAMINGLUMICOUNTINGINPUTMANAGER_H - -#include -// #include -#include - -#include -#include -#include -#include -class SingleStreamingInputv2; -class Gl1Packet; -class PHCompositeNode; -class SyncObject; -class TH1; -class TTree; -class Fun4AllStreamingLumiCountingInputManager : public Fun4AllInputManager -{ - public: - Fun4AllStreamingLumiCountingInputManager(const std::string &name = "DUMMY", const std::string &dstnodename = "DST", const std::string &topnodename = "TOP"); - ~Fun4AllStreamingLumiCountingInputManager() override; - int fileopen(const std::string & /*filenam*/) override { return 0; } - // cppcheck-suppress virtualCallInConstructor - int fileclose() override; - int run(const int nevents = 0) override; - - void Print(const std::string &what = "ALL") const override; - int ResetEvent() override; - int PushBackEvents(const int i) override; - int GetSyncObject(SyncObject **mastersync) override; - int SyncIt(const SyncObject *mastersync) override; - int HasSyncObject() const override { return 1; } - std::string GetString(const std::string &what) const override; - void registerStreamingInput(SingleStreamingInputv2 *evtin, InputManagerType::enu_subsystem); - int FillGl1(); - void AddGl1RawHit(uint64_t bclk, Gl1Packet *hit); - void AddGl1Window(uint64_t bco_trim, int negative_window, int positive_window); - void AddGl1BunchNumber(uint64_t bco_trim, int bunch_number); - void SetNegativeWindow(const unsigned int i); - void SetPositiveWindow(const unsigned int i); - void Streaming(bool b = true) { m_StreamingFlag = b; } - void SetOutputFileName(const std::string &fileName); - void SetEndofEvent(bool flag = false, bool flag2 = false) - { - m_alldone_flag = flag; - m_lastevent_flag = flag2; - } - void SetEventNumber(int num) { m_event_number = num; } - - private: - struct Gl1RawHitInfo - { - std::vector Gl1RawHitVector; - unsigned int EventFoundCounter{0}; - }; - - void createLuminosityHistos(); - - SyncObject *m_SyncObject{nullptr}; - PHCompositeNode *m_topNode{nullptr}; - - int m_RunNumber{0}; - unsigned int m_negative_bco_window{0}; - unsigned int m_positive_bco_window{0}; - uint64_t m_rawgl1scaler{0}; - // std::string m_output_file="output.root"; - bool m_alldone_flag = {false}; - bool m_lastevent_flag = {false}; - int m_event_number{0}; - int m_diffBCO{0}; - bool m_gl1_registered_flag{false}; - bool m_StreamingFlag{false}; - bool flat_overflow{false}; - uint64_t bco_temp = 0; - - std::vector m_Gl1InputVector; - std::map m_Gl1RawHitMap; - std::map> m_BCOWindows; - std::map m_BCOBunchNumber; - std::map m_bunchnumber_MBDNS_raw; - std::map m_bunchnumber_MBDNS_live; - std::map m_bunchnumber_MBDNS_scaled; - std::map m_bunchnumber_ZDCCoin_raw; - // std::map m_bunchnumber_rawgl1scaler; - - // QA histos - TH1 *h_lumibco{nullptr}; - TH1 *h_bunchnumber{nullptr}; - TH1 *h_bunchnumber_occur{nullptr}; - TH1 *h_diffbco{nullptr}; - TH1 *h_gl1p_MBDSN_bunchid_raw{nullptr}; - TH1 *h_gl1p_MBDSN_bunchid_live{nullptr}; - TH1 *h_gl1p_MBDSN_bunchid_scaled{nullptr}; - TH1 *h_gl1p_rawgl1scaler{nullptr}; - TH1 *h_gl1p_ZDCCoin_bunchid_raw{nullptr}; - uint64_t m_bco_trim{}; - uint64_t m_lower_bound{}; - uint64_t m_upper_bound{}; - int m_bunch_number{}; - TTree *ttree = nullptr; - TFile *tfile = nullptr; - std::string m_outputFileName = "/sphenix/user/xuzhiwan/luminosity/streaming-macro/macro/output.root"; // Default value -}; - -#endif /* RAWBCOLUMI_FUN4ALLSTREAMINGLUMICOUNTINGINPUTMANAGER_H */ diff --git a/offline/framework/rawbcolumi/Makefile.am b/offline/framework/rawbcolumi/Makefile.am deleted file mode 100644 index b95b96ad16..0000000000 --- a/offline/framework/rawbcolumi/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -AUTOMAKE_OPTIONS = foreign - -AM_CPPFLAGS = \ - -I$(includedir) \ - -isystem$(OFFLINE_MAIN)/include \ - -isystem$(ROOTSYS)/include \ - -isystem$(OPT_SPHENIX)/include - -AM_LDFLAGS = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib - -pkginclude_HEADERS = \ - SingleGl1PoolInputv2.h \ - SingleStreamingInputv2.h \ - Fun4AllStreamingLumiCountingInputManager.h - -lib_LTLIBRARIES = \ - librawbcolumi.la - -# source for mvtx decoder library -librawbcolumi_la_SOURCES = \ - SingleGl1PoolInputv2.cc \ - SingleStreamingInputv2.cc \ - Fun4AllStreamingLumiCountingInputManager.cc - -librawbcolumi_la_LIBADD = \ - -lffarawobjects \ - -lfun4all \ - -lEvent \ - -lphoolraw \ - -lqautils - -BUILT_SOURCES = testexternals.cc - -noinst_PROGRAMS = \ - testexternals - -testexternals_SOURCES = testexternals.cc -testexternals_LDADD = librawbcolumi.la - -testexternals.cc: - echo "//*** this is a generated file. Do not commit, do not edit" > $@ - echo "int main()" >> $@ - echo "{" >> $@ - echo " return 0;" >> $@ - echo "}" >> $@ - -clean-local: - rm -f $(BUILT_SOURCES) diff --git a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.cc b/offline/framework/rawbcolumi/SingleGl1PoolInputv2.cc deleted file mode 100644 index aa4193b7f9..0000000000 --- a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.cc +++ /dev/null @@ -1,362 +0,0 @@ -#include "SingleGl1PoolInputv2.h" - -#include -#include -#include "Fun4AllStreamingLumiCountingInputManager.h" - -#include - -#include -#include // for PHIODataNode -#include // for PHNode -#include // for PHNodeIterator -#include // for PHObject -#include -#include - -#include -#include -#include -#include // for Packet - -#include // for uint64_t -#include // for operator<<, basic_ostream<... -#include // for reverse_iterator -#include // for numeric_limits -#include -#include -#include // for pair - -SingleGl1PoolInputv2::SingleGl1PoolInputv2(const std::string &name) - : SingleStreamingInputv2(name) -{ - SubsystemEnum(InputManagerType::GL1); -} - -SingleGl1PoolInputv2::~SingleGl1PoolInputv2() -{ - CleanupUsedPackets(std::numeric_limits::max()); -} - -void SingleGl1PoolInputv2::FillPool(const unsigned int /*nbclks*/) -{ - if (AllDone()) // no more files and all events read - { - return; - } - while (GetEventiterator() == nullptr) // at startup this is a null pointer - { - if (!OpenNextFile()) - { - AllDone(1); - return; - } - } - // std::set saved_beamclocks; - while (GetSomeMoreEvents()) - { - std::unique_ptr evt(GetEventiterator()->getNextEvent()); - while (!evt) - { - fileclose(); - if (!OpenNextFile()) - { - AllDone(1); - return; - } - evt.reset(GetEventiterator()->getNextEvent()); - } - if (Verbosity() > 2) - { - std::cout << PHWHERE << "Fetching next Event" << evt->getEvtSequence() << std::endl; - } - if ((m_total_event == 0 && evt->getEvtType() == ENDRUNEVENT) || - (m_total_event != 0 && evt->getEvtSequence() - 2 == m_total_event)) - { - m_alldone_flag = true; - m_lastevent_flag = true; - } - if (evt->getEvtSequence() % 5000 == 0) - { - m_alldone_flag = true; - m_lastevent_flag = true; - } - if (Verbosity() > 2) - { - if (m_alldone_flag) - { - std::cout << "gl1 all done is true" << std::endl; - } - // else{std::cout<<"gl1 all done is false"<getRunNumber()); - if (GetVerbosity() > 1) - { - evt->identify(); - } - if (evt->getEvtType() != DATAEVENT) - { - m_NumSpecialEvents++; - if (evt->getEvtType() == ENDRUNEVENT) - { - AllDone(1); - std::unique_ptr nextevt(GetEventiterator()->getNextEvent()); - if (nextevt) - { - std::cout << PHWHERE << " Found event after End Run Event " << std::endl; - std::cout << "End Run Event identify: " << std::endl; - evt->identify(); - std::cout << "Next event identify: " << std::endl; - nextevt->identify(); - } - return; - } - continue; - } - int EventSequence = evt->getEvtSequence(); - Packet *packet = evt->getPacket(14001); - if (!packet) - { - std::cout << PHWHERE << "Packet 14001 is null ptr" << std::endl; - evt->identify(); - m_alldone_flag = true; - m_lastevent_flag = true; - if (StreamingLumiInputManager()) - { - StreamingLumiInputManager()->SetEndofEvent(m_alldone_flag, m_lastevent_flag); - StreamingLumiInputManager()->SetEventNumber(EventSequence); - } - m_alldone_flag = false; - m_lastevent_flag = false; - continue; - } - if (Verbosity() > 1) - { - packet->identify(); - } - - Gl1Packet *newhit = new Gl1Packetv3(); - uint64_t gtm_bco = packet->lValue(0, "BCO"); - uint64_t bco_trim = gtm_bco & 0xFFFFFFFFFFU; - // std::cout<first<<" left "<second.first<<" right "<< m_BCOWindows.begin()->second.second<lValue(0, "BunchNumber"); - // std::cout<<"BCO "<AddGl1Window(bco_trim, m_negative_bco_window, m_positive_bco_window); - StreamingLumiInputManager()->AddGl1BunchNumber(bco_trim, m_BCOBunchNumber[bco_trim]); - StreamingLumiInputManager()->SetEndofEvent(m_alldone_flag, m_lastevent_flag); - StreamingLumiInputManager()->SetEventNumber(EventSequence); - StreamingLumiInputManager()->SetNegativeWindow(m_negative_bco_window); - StreamingLumiInputManager()->SetPositiveWindow(m_positive_bco_window); - } - if (evt->getEvtSequence() % 5000 == 0) - { - m_alldone_flag = false; - m_lastevent_flag = false; - } - - m_FEEBclkMap.insert(gtm_bco); - newhit->setBCO(packet->lValue(0, "BCO")); - newhit->setHitFormat(packet->getHitFormat()); - newhit->setIdentifier(packet->getIdentifier()); - newhit->setEvtSequence(EventSequence); - newhit->setPacketNumber(packet->iValue(0)); - newhit->setBunchNumber(packet->lValue(0, "BunchNumber")); - newhit->setTriggerInput(packet->lValue(0, "TriggerInput")); - newhit->setLiveVector(packet->lValue(0, "LiveVector")); - newhit->setScaledVector(packet->lValue(0, "ScaledVector")); - newhit->setGTMBusyVector(packet->lValue(0, "GTMBusyVector")); - newhit->setGTMAllBusyVector(packet->lValue(0, "GTMAllBusyVector")); - for (int i = 0; i < 64; i++) - { - for (int j = 0; j < 3; j++) - { - newhit->setScaler(i, j, packet->lValue(i, j)); - } - } - for (int i = 0; i < 12; i++) - { - newhit->setGl1pScaler(i, 0, packet->lValue(i, "GL1PRAW")); - newhit->setGl1pScaler(i, 1, packet->lValue(i, "GL1PLIVE")); - newhit->setGl1pScaler(i, 2, packet->lValue(i, "GL1PSCALED")); - } - if (Verbosity() > 2) - { - std::cout << PHWHERE << " Packet: " << packet->getIdentifier() - << " evtno: " << EventSequence - << ", bco: 0x" << std::hex << gtm_bco << std::dec - << ", bunch no: " << packet->lValue(0, "BunchNumber") - << std::endl; - std::cout << PHWHERE << " RB Packet: " << newhit->getIdentifier() - << " evtno: " << newhit->getEvtSequence() - << ", bco: 0x" << std::hex << newhit->getBCO() << std::dec - << ", bunch no: " << +newhit->getBunchNumber() - << std::endl; - } - if (Verbosity() > 2) - { - std::cout << PHWHERE << "evtno: " << EventSequence - << ", bco: 0x" << std::hex << gtm_bco << std::dec - << std::endl; - } - if (StreamingLumiInputManager()) - { - StreamingLumiInputManager()->AddGl1RawHit(gtm_bco, newhit); - } - - m_Gl1RawHitMap[gtm_bco].push_back(newhit); - m_BclkStack.insert(gtm_bco); - - delete packet; - } -} - -void SingleGl1PoolInputv2::Print(const std::string &what) const -{ - if (what == "ALL" || what == "FEEBCLK") - { - for (auto bcliter : m_FEEBclkMap) - { - std::cout << PHWHERE << " bclk: 0x" - << std::hex << bcliter << std::dec << std::endl; - } - } - if (what == "ALL" || what == "STORAGE") - { - for (const auto &bcliter : m_Gl1RawHitMap) - { - std::cout << PHWHERE << "Beam clock 0x" << std::hex << bcliter.first << std::dec << std::endl; - for (auto *feeiter : bcliter.second) - { - std::cout << PHWHERE << "fee: " << feeiter->getBCO() - << " at " << std::hex << feeiter << std::dec << std::endl; - } - } - } - if (what == "ALL" || what == "STACK") - { - for (auto iter : m_BclkStack) - { - std::cout << PHWHERE << "stacked bclk: 0x" << std::hex << iter << std::dec << std::endl; - } - } -} - -void SingleGl1PoolInputv2::CleanupUsedPackets(const uint64_t bclk) -{ - std::vector toclearbclk; - for (const auto &iter : m_Gl1RawHitMap) - { - if (iter.first <= bclk) - { - for (auto *pktiter : iter.second) - { - delete pktiter; - } - toclearbclk.push_back(iter.first); - } - else - { - break; - } - } - - for (auto iter : toclearbclk) - { - m_FEEBclkMap.erase(iter); - m_BclkStack.erase(iter); - m_Gl1RawHitMap.erase(iter); - } -} - -bool SingleGl1PoolInputv2::CheckPoolDepth(const uint64_t bclk) -{ - // if (m_FEEBclkMap.size() < 10) - // { - // std::cout << PHWHERE << "not all FEEs in map: " << m_FEEBclkMap.size() << std::endl; - // return true; - // } - for (auto iter : m_FEEBclkMap) - { - if (Verbosity() > 2) - { - std::cout << PHWHERE << "my bclk 0x" << std::hex << iter - << " req: 0x" << bclk << std::dec << std::endl; - } - if (iter < bclk) - { - if (Verbosity() > 1) - { - std::cout << PHWHERE << "FEE " << iter << " beamclock 0x" << std::hex << iter - << " smaller than req bclk: 0x" << bclk << std::dec << std::endl; - } - return false; - } - } - return true; -} - -void SingleGl1PoolInputv2::ClearCurrentEvent() -{ - // called interactively, to get rid of the current event - uint64_t currentbclk = *m_BclkStack.begin(); - // std::cout << PHWHERE << "clearing bclk 0x" << std::hex << currentbclk << std::dec << std::endl; - CleanupUsedPackets(currentbclk); - // m_BclkStack.erase(currentbclk); - return; -} - -bool SingleGl1PoolInputv2::GetSomeMoreEvents() -{ - if (AllDone()) - { - return false; - } - if (m_Gl1RawHitMap.empty()) - { - return true; - } - - uint64_t lowest_bclk = m_Gl1RawHitMap.begin()->first; - lowest_bclk += m_BcoRange; - uint64_t last_bclk = m_Gl1RawHitMap.rbegin()->first; - if (Verbosity() > 1) - { - std::cout << PHWHERE << "first bclk 0x" << std::hex << lowest_bclk - << " last bco: 0x" << last_bclk - << std::dec << std::endl; - } - if (lowest_bclk >= last_bclk) - { - return true; - } - return false; -} - -void SingleGl1PoolInputv2::CreateDSTNode(PHCompositeNode *topNode) -{ - PHNodeIterator iter(topNode); - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - dstNode = new PHCompositeNode("DST"); - topNode->addNode(dstNode); - } - PHNodeIterator iterDst(dstNode); - PHCompositeNode *detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", "GL1")); - if (!detNode) - { - detNode = new PHCompositeNode("GL1"); - dstNode->addNode(detNode); - } - Gl1Packet *gl1hitcont = findNode::getClass(detNode, "GL1RAWHIT"); - if (!gl1hitcont) - { - gl1hitcont = new Gl1Packetv3(); - PHIODataNode *newNode = new PHIODataNode(gl1hitcont, "GL1RAWHIT", "PHObject"); - detNode->addNode(newNode); - } -} diff --git a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.h b/offline/framework/rawbcolumi/SingleGl1PoolInputv2.h deleted file mode 100644 index f2252571f4..0000000000 --- a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef RAWBCOLUMI_SINGLEGL1POOLINPUTV2_H -#define RAWBCOLUMI_SINGLEGL1POOLINPUTV2_H - -#include "SingleStreamingInputv2.h" - -#include -#include -#include -#include -#include -#include - -class Gl1Packet; -class PHCompositeNode; - -class SingleGl1PoolInputv2 : public SingleStreamingInputv2 -{ - public: - explicit SingleGl1PoolInputv2(const std::string &name); - ~SingleGl1PoolInputv2() override; - void FillPool(const unsigned int) override; - void CleanupUsedPackets(const uint64_t bclk) override; - bool CheckPoolDepth(const uint64_t bclk) override; - void ClearCurrentEvent() override; - bool GetSomeMoreEvents(); - void Print(const std::string &what = "ALL") const override; - void CreateDSTNode(PHCompositeNode *topNode) override; - void SetBcoRange(const unsigned int i) { m_BcoRange = i; } - // void ConfigureStreamingInputManager() override; - void SetNegativeWindow(const unsigned int value) { m_negative_bco_window = value; } - void SetPositiveWindow(const unsigned int value) { m_positive_bco_window = value; } - void SetTotalEvent(const int value) { m_total_event = value; } - - private: - unsigned int m_NumSpecialEvents{0}; - unsigned int m_BcoRange{0}; - - //! map bco to packet - std::map m_packet_bco; - - std::map> m_Gl1RawHitMap; - std::map> m_BCOWindows; - std::map m_BCOBunchNumber; - std::set m_FEEBclkMap; - std::set m_BclkStack; - - unsigned int m_negative_bco_window = 20; - unsigned int m_positive_bco_window = 325; - bool m_alldone_flag = {false}; - bool m_lastevent_flag = {false}; - int m_total_event = std::numeric_limits::max(); -}; - -#endif diff --git a/offline/framework/rawbcolumi/SingleStreamingInputv2.cc b/offline/framework/rawbcolumi/SingleStreamingInputv2.cc deleted file mode 100644 index c0c7aef409..0000000000 --- a/offline/framework/rawbcolumi/SingleStreamingInputv2.cc +++ /dev/null @@ -1,139 +0,0 @@ -#include "SingleStreamingInputv2.h" - -#include - -#include - -#include -#include - -#include // for uint64_t -#include // for operator<<, basic_ostream, endl -#include -#include // for pair - -SingleStreamingInputv2::SingleStreamingInputv2(const std::string &name) - : Fun4AllBase(name) -{ -} - -SingleStreamingInputv2::~SingleStreamingInputv2() -{ - delete m_EventIterator; -} - -int SingleStreamingInputv2::fileopen(const std::string &filenam) -{ - std::cout << PHWHERE << "trying to open " << filenam << std::endl; - if (IsOpen()) - { - std::cout << "Closing currently open file " - << FileName() - << " and opening " << filenam << std::endl; - fileclose(); - } - FileName(filenam); - FROG frog; - std::string fname = frog.location(FileName()); - if (Verbosity() > 0) - { - std::cout << Name() << ": opening file " << FileName() << std::endl; - } - int status = 0; - m_EventIterator = new fileEventiterator(fname.c_str(), status); - m_EventsThisFile = 0; - if (status) - { - delete m_EventIterator; - m_EventIterator = nullptr; - std::cout << PHWHERE << Name() << ": could not open file " << fname << std::endl; - return -1; - } - IsOpen(1); - AddToFileOpened(fname); // add file to the list of files which were opened - return 0; -} - -int SingleStreamingInputv2::fileclose() -{ - if (!IsOpen()) - { - std::cout << Name() << ": fileclose: No Input file open" << std::endl; - return -1; - } - delete m_EventIterator; - m_EventIterator = nullptr; - IsOpen(0); - // if we have a file list, move next entry to top of the list - // or repeat the same entry again - UpdateFileList(); - return 0; -} - -void SingleStreamingInputv2::Print(const std::string &what) const -{ - if (what == "ALL" || what == "FEE") - { - for (const auto &bcliter : m_BeamClockFEE) - { - std::cout << "Beam clock 0x" << std::hex << bcliter.first << std::dec << std::endl; - for (auto feeiter : bcliter.second) - { - std::cout << "FEM: " << feeiter << std::endl; - } - } - } - if (what == "ALL" || what == "FEEBCLK") - { - for (auto bcliter : m_FEEBclkMap) - { - std::cout << "FEE" << bcliter.first << " bclk: 0x" - << std::hex << bcliter.second << std::dec << std::endl; - } - } - if (what == "ALL" || what == "STACK") - { - for (auto iter : m_BclkStack) - { - std::cout << "stacked bclk: 0x" << std::hex << iter << std::dec << std::endl; - } - } -} - -bool SingleStreamingInputv2::CheckPoolDepth(const uint64_t bclk) -{ - // if (m_FEEBclkMap.size() < 10) - // { - // std::cout << "not all FEEs in map: " << m_FEEBclkMap.size() << std::endl; - // return true; - // } - for (auto iter : m_FEEBclkMap) - { - if (Verbosity() > 2) - { - std::cout << "my bclk 0x" << std::hex << iter.second - << " req: 0x" << bclk << std::dec << std::endl; - } - if (iter.second < bclk) - { - if (Verbosity() > 1) - { - std::cout << "FEE " << iter.first << " beamclock 0x" << std::hex << iter.second - << " smaller than req bclk: 0x" << bclk << std::dec << std::endl; - } - return true; - } - } - return false; -} - -void SingleStreamingInputv2::ClearCurrentEvent() -{ - // called interactively, to get rid of the current event - uint64_t currentbclk = *m_BclkStack.begin(); - std::cout << "clearing bclk 0x" << std::hex << currentbclk << std::dec << std::endl; - CleanupUsedPackets(currentbclk); - m_BclkStack.erase(currentbclk); - m_BeamClockFEE.erase(currentbclk); - return; -} diff --git a/offline/framework/rawbcolumi/SingleStreamingInputv2.h b/offline/framework/rawbcolumi/SingleStreamingInputv2.h deleted file mode 100644 index 184fe6923f..0000000000 --- a/offline/framework/rawbcolumi/SingleStreamingInputv2.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef RAWBCOLUMI_SINGLESTREAMINGINPUTV2_H -#define RAWBCOLUMI_SINGLESTREAMINGINPUTV2_H - -#include -#include - -#include // for uint64_t -#include -#include -#include - -class Eventiterator; -class Fun4AllEvtInputPoolManager; -class Fun4AllStreamingInputManager; -class Fun4AllStreamingLumiCountingInputManager; -class PHCompositeNode; - -class SingleStreamingInputv2 : public Fun4AllBase, public InputFileHandler -{ - public: - explicit SingleStreamingInputv2(const std::string &name); - ~SingleStreamingInputv2() override; - virtual Eventiterator *GetEventIterator() { return m_EventIterator; } - virtual void FillPool(const uint64_t) { return; } - virtual void FillPool(const unsigned int = 1) { return; } - virtual void RunNumber(const int runno) { m_RunNumber = runno; } - virtual int RunNumber() const { return m_RunNumber; } - virtual int fileopen(const std::string &filename) override; - virtual int fileclose() override; - virtual int AllDone() const { return m_AllDone; } - virtual void AllDone(const int i) { m_AllDone = i; } - virtual void EventNumberOffset(const int i) { m_EventNumberOffset = i; } - virtual void Print(const std::string &what = "ALL") const override; - virtual void CleanupUsedPackets(const uint64_t) { return; } - virtual bool CheckPoolDepth(const uint64_t bclk); - virtual void ClearCurrentEvent(); - virtual Eventiterator *GetEventiterator() const { return m_EventIterator; } - virtual Fun4AllStreamingInputManager *StreamingInputManager() { return m_StreamingInputMgr; } - virtual void StreamingInputManager(Fun4AllStreamingInputManager *in) { m_StreamingInputMgr = in; } - // virtual void StreamingInputManager(Fun4AllStreamingLumiCountingInputManager *in) { m_StreamingLumiInputMgr = in; } - virtual Fun4AllStreamingLumiCountingInputManager *StreamingLumiInputManager() { return m_StreamingLumiInputMgr; } - virtual void StreamingLumiInputManager(Fun4AllStreamingLumiCountingInputManager *in) { m_StreamingLumiInputMgr = in; } - virtual void CreateDSTNode(PHCompositeNode *) { return; } - virtual void ConfigureStreamingInputManager() { return; } - virtual void SubsystemEnum(const int id) { m_SubsystemEnum = id; } - virtual int SubsystemEnum() const { return m_SubsystemEnum; } - void MaxBclkDiff(uint64_t ui) { m_MaxBclkSpread = ui; } - uint64_t MaxBclkDiff() const { return m_MaxBclkSpread; } - virtual const std::map> &BclkStackMap() const { return m_BclkStackPacketMap; } - virtual const std::set &BclkStack() const { return m_BclkStack; } - virtual const std::map> &BeamClockFEE() const { return m_BeamClockFEE; } - void setHitContainerName(const std::string &name) { m_rawHitContainerName = name; } - const std::string &getHitContainerName() const { return m_rawHitContainerName; } - const std::map> &getFeeGTML1BCOMap() const { return m_FeeGTML1BCOMap; } - - void clearPacketBClkStackMap(const int &packetid, const uint64_t &bclk) - { - std::set to_erase; - auto set = m_BclkStackPacketMap.find(packetid)->second; - for (auto &bclk_to_erase : set) - { - if (bclk_to_erase <= bclk) - { - to_erase.insert(bclk_to_erase); - } - } - for (auto &bclk_to_erase : to_erase) - { - set.erase(bclk_to_erase); - } - } - - void clearFeeGTML1BCOMap(const uint64_t &bclk) - { - std::set toerase; - for (auto &[key, set] : m_FeeGTML1BCOMap) - { - for (auto &ll1bclk : set) - { - if (ll1bclk <= bclk) - { - // to avoid invalid reads - toerase.insert(ll1bclk); - } - } - for (auto &bclk_to_erase : toerase) - { - set.erase(bclk_to_erase); - } - } - } - - protected: - std::map> m_BclkStackPacketMap; - std::map> m_FeeGTML1BCOMap; - std::string m_rawHitContainerName = ""; - - private: - Eventiterator *m_EventIterator{nullptr}; - // Fun4AllEvtInputPoolManager *m_InputMgr {nullptr}; - Fun4AllStreamingInputManager *m_StreamingInputMgr{nullptr}; - Fun4AllStreamingLumiCountingInputManager *m_StreamingLumiInputMgr{nullptr}; - uint64_t m_MaxBclkSpread{1000000}; - unsigned int m_EventNumberOffset{1}; // packet event counters start at 0 but we start with event number 1 - int m_RunNumber{0}; - int m_EventsThisFile{0}; - int m_AllDone{0}; - int m_SubsystemEnum{0}; - std::map> m_BeamClockFEE; - std::map m_FEEBclkMap; - std::set m_BclkStack; -}; - -#endif diff --git a/offline/framework/rawbcolumi/autogen.sh b/offline/framework/rawbcolumi/autogen.sh deleted file mode 100755 index dea267bbfd..0000000000 --- a/offline/framework/rawbcolumi/autogen.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ -libtoolize --force; automake -a --add-missing; autoconf) - -$srcdir/configure "$@" diff --git a/offline/framework/rawbcolumi/configure.ac b/offline/framework/rawbcolumi/configure.ac deleted file mode 100644 index 301b8f12e5..0000000000 --- a/offline/framework/rawbcolumi/configure.ac +++ /dev/null @@ -1,17 +0,0 @@ -AC_INIT(rawbcolumi,[2.00]) -AC_CONFIG_SRCDIR([configure.ac]) - -AM_INIT_AUTOMAKE -AC_PROG_CXX(CC g++) - -LT_INIT([disable-static]) - -dnl no point in suppressing warnings people should -dnl at least see them, so here we go for g++: -Wall -if test $ac_cv_prog_gxx = yes; then - CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" -fi - - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT From 9f54bca88d43478ea7a833686bd9deb301799ccd Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 16 Jun 2026 14:06:51 -0400 Subject: [PATCH 671/866] add reading cdb calibrations from test file --- offline/database/sphenixnpc/CDBUtils.cc | 18 +++---- offline/database/sphenixnpc/CDBUtils.h | 4 +- offline/database/sphenixnpc/SphenixClient.cc | 49 ++++++++++++++++++-- offline/database/sphenixnpc/SphenixClient.h | 3 +- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 4608605e7c..46737fe89a 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -85,7 +85,7 @@ std::map> CDBUtils::Pay return iovs; } nlohmann::json payload_iovs = resp["msg"]; - for (auto &[pt, val] : payload_iovs.items()) + for (const auto &[pt, val] : payload_iovs.items()) { std::string url = val["payload_url"]; uint64_t bts = val["minor_iov_start"]; @@ -94,10 +94,10 @@ std::map> CDBUtils::Pay { if (!ptype.empty()) { - if (pt.find(ptype) == std::string::npos) - { - continue; - } + if (pt.find(ptype) == std::string::npos) + { + continue; + } } iovs.insert(std::make_pair(pt, std::make_tuple(url, bts, ets))); } @@ -107,7 +107,7 @@ std::map> CDBUtils::Pay void CDBUtils::listPayloadIOVs(uint64_t iov, const std::string &ptype) { - auto iovs = PayloadIOVs(iov,ptype); + auto iovs = PayloadIOVs(iov, ptype); for (const auto &it : iovs) { std::cout << it.first << ": " << std::get<0>(it.second) @@ -123,7 +123,7 @@ int CDBUtils::cloneGlobalTag(const std::string &source, const std::string &targe nlohmann::json resp = cdbclient->getGlobalTags(); nlohmann::json msgcont = resp["msg"]; std::set gtset; - for (auto &it : msgcont.items()) + for (const auto &it : msgcont.items()) { std::string exist_gt = it.value().at("name"); gtset.insert(exist_gt); @@ -149,7 +149,7 @@ void CDBUtils::listGlobalTags() nlohmann::json resp = cdbclient->getGlobalTags(); nlohmann::json msgcont = resp["msg"]; std::set globaltags; - for (auto &it : msgcont.items()) + for (const auto &it : msgcont.items()) { std::string exist_gt = it.value().at("name"); globaltags.insert(exist_gt); @@ -166,7 +166,7 @@ void CDBUtils::listPayloadTypes() nlohmann::json resp = cdbclient->getPayloadTypes(); nlohmann::json msgcont = resp["msg"]; std::set payloadtypes; - for (auto &it : msgcont.items()) + for (const auto &it : msgcont.items()) { std::string exist_pl = it.value().at("name"); payloadtypes.insert(exist_pl); diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 0e6272fab1..067ccf295b 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -42,8 +42,8 @@ class CDBUtils std::map> PayloadIOVs(uint64_t iov, const std::string &ptype = ""); void listPayloadIOVs(uint64_t iov, const std::string &ptype = ""); -private: - int m_Verbosity {0}; + private: + int m_Verbosity{0}; std::unique_ptr cdbclient; std::string m_CachedGlobalTag; std::set m_PayloadTypeCache; diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index 7de6ecd6ed..01f571ceca 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -5,6 +5,7 @@ #include +#include #include #include @@ -69,13 +70,53 @@ nlohmann::json SphenixClient::getUrlDict(long long iov) ++it; } } - for (auto& piov : resp["msg"].items()) + for (const auto& piov : resp["msg"].items()) { piov.value() = piov.value()["payload_url"]; } return resp; } +void SphenixClient::DumpCalibrations(long long iov, const std::string& filename) +{ + nlohmann::json resp = getPayloadIOVs(iov); + if (resp["code"] != 0) + { + std::cout << "not writing " << filename << std::endl; + return; + } + for (auto it = resp["msg"].begin(); it != resp["msg"].end();) + { + if (it.value()["minor_iov_end"] < iov) + { + it = resp["msg"].erase(it); + } + else + { + ++it; + } + } + std::ofstream dumpfile(filename); + if (dumpfile.is_open()) + { + for (const auto& piov : resp["msg"].items()) + { + std::string payload_url = piov.value()["payload_url"]; + if (!payload_url.empty() && payload_url.front() == '"' && payload_url.back() == '"') + { + payload_url = payload_url.substr(1, payload_url.size() - 2); + } + dumpfile << piov.key() << " " << payload_url << std::endl; + } + dumpfile.close(); + } + else + { + std::cout << "Could not open " << filename << std::endl; + } + return; +} + nlohmann::json SphenixClient::deletePayloadIOV(const std::string& pl_type, long long iov_start) { return nopayloadclient::NoPayloadClient::deletePayloadIOV(pl_type, 0, iov_start); @@ -162,7 +203,7 @@ int SphenixClient::cache_set_GlobalTag(const std::string& tagname) bool found_gt = false; nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; - for (auto& it : msgcont.items()) + for (const auto& it : msgcont.items()) { std::string exist_gt = it.value().at("name"); std::cout << "global tag: " << exist_gt << std::endl; @@ -196,7 +237,7 @@ int SphenixClient::createDomain(const std::string& domain) { resp = nopayloadclient::NoPayloadClient::getPayloadTypes(); nlohmann::json msgcont = resp["msg"]; - for (auto& it : msgcont.items()) + for (const auto& it : msgcont.items()) { std::string existent_domain = it.value().at("name"); m_DomainCache.insert(existent_domain); @@ -235,7 +276,7 @@ bool SphenixClient::existGlobalTag(const std::string& gt_name) } nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; - for (auto& it : msgcont.items()) + for (const auto& it : msgcont.items()) { std::string exist_gt = it.value().at("name"); m_GlobalTagCache.insert(gt_name); diff --git a/offline/database/sphenixnpc/SphenixClient.h b/offline/database/sphenixnpc/SphenixClient.h index 95b3729e95..0dd6d9ff1c 100644 --- a/offline/database/sphenixnpc/SphenixClient.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -39,9 +39,10 @@ class SphenixClient : public nopayloadclient::NoPayloadClient bool isGlobalTagSet(); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } + void DumpCalibrations(long long iov, const std::string& filename); private: - int m_Verbosity = 0; + int m_Verbosity{0}; std::string m_CachedGlobalTag; std::set m_DomainCache; std::set m_GlobalTagCache; From 02b37d8f3e082bf11940fb9cca3a722b67989713 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 16 Jun 2026 14:08:51 -0400 Subject: [PATCH 672/866] add reading cdb calibrations from test file --- offline/framework/ffamodules/CDBInterface.cc | 96 ++++++++++++++++++-- offline/framework/ffamodules/CDBInterface.h | 6 ++ 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index 2a0b3e1b3c..dfe464e5e6 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -20,10 +20,13 @@ #include -#include // for uint64_t +#include // for uint64_t +#include +#include #include // for operator<<, basic_ostream, endl -#include // for pair -#include // for vector +#include +#include // for pair +#include // for vector CDBInterface *CDBInterface::__instance{nullptr}; @@ -55,7 +58,8 @@ CDBInterface::~CDBInterface() //____________________________________________________________________________.. int CDBInterface::End(PHCompositeNode *topNode) { - int iret = UpdateRunNode(topNode);PHNodeIterator iter(topNode); + int iret = UpdateRunNode(topNode); + PHNodeIterator iter(topNode); return iret; } @@ -127,6 +131,15 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f return ""; } std::string domain_noconst = domain; + if (m_Read_From_File_Flag) + { + if (m_Payload_Url_Cache.contains(domain_noconst)) + { + return m_Payload_Url_Cache[domain_noconst]; + } + std::cout << "calibration " << domain << " not found in local cache" << std::endl; + return ""; + } recoConsts *rc = recoConsts::instance(); if (!rc->FlagExist("CDB_GLOBALTAG")) { @@ -185,14 +198,85 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f std::cout << "... reply: " << return_url << std::endl; } } - if (! return_url.empty()) + if (!return_url.empty()) { 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; + << ", time stamp: " << timestamp << std::endl; } } return return_url; } + +void CDBInterface::DumpCalibrations(const std::string &filename) +{ + recoConsts *rc = recoConsts::instance(); + if (!rc->FlagExist("CDB_GLOBALTAG")) + { + std::cout << PHWHERE << "CDB_GLOBALTAG flag needs to be set via" << std::endl; + std::cout << "rc->set_StringFlag(\"CDB_GLOBALTAG\",)" << std::endl; + gSystem->Exit(1); + } + if (!rc->FlagExist("TIMESTAMP")) + { + std::cout << PHWHERE << "TIMESTAMP flag needs to be set via" << std::endl; + std::cout << "rc->set_uint64Flag(\"TIMESTAMP\",<64 bit timestamp>)" << std::endl; + gSystem->Exit(1); + } + if (cdbclient == nullptr) + { + cdbclient = new SphenixClient(rc->get_StringFlag("CDB_GLOBALTAG")); + } + uint64_t timestamp = rc->get_uint64Flag("TIMESTAMP"); + cdbclient->DumpCalibrations(timestamp, filename); + return; +} + +void CDBInterface::ReadCalibrationsFromFile(const std::string &filename) +{ + std::filesystem::path filePath = filename; + if (!std::filesystem::exists(filePath)) + { + std::cout << PHWHERE << " cannot locate " << filename << std::endl; + gSystem->Exit(1); + } + if (!std::filesystem::is_regular_file(filePath)) + { + std::cout << PHWHERE << " not a regular file " << filename << std::endl; + gSystem->Exit(1); + } + std::ifstream calibsfile(filename); + if (calibsfile.is_open()) + { + std::string line; + while (std::getline(calibsfile, line)) + { + // Skip empty lines + if (line.empty()) + { + continue; + } + + // Skip comments + if (line[0] == '#') + { + continue; + } + std::istringstream iss(line); + std::string key; + std::string payload_url; + if (iss >> key >> payload_url) + { + m_Payload_Url_Cache.insert(std::make_pair(key, payload_url)); + } + } + m_Read_From_File_Flag = true; + } + else + { + std::cout << "could not open " << filename << std::endl; + } + return; +} diff --git a/offline/framework/ffamodules/CDBInterface.h b/offline/framework/ffamodules/CDBInterface.h index 4132b35a34..b4b0303239 100644 --- a/offline/framework/ffamodules/CDBInterface.h +++ b/offline/framework/ffamodules/CDBInterface.h @@ -6,6 +6,7 @@ #include #include // for uint64_t +#include #include #include #include // for tuple @@ -34,6 +35,9 @@ class CDBInterface : public SubsysReco std::string getUrl(const std::string &domain, const std::string &filename = ""); + void DumpCalibrations(const std::string &filename); + void ReadCalibrationsFromFile(const std::string &filename); + private: CDBInterface(const std::string &name = "CDBInterface"); @@ -41,6 +45,8 @@ class CDBInterface : public SubsysReco SphenixClient *cdbclient{nullptr}; bool disable{false}; bool disable_default{false}; + bool m_Read_From_File_Flag{false}; + std::map m_Payload_Url_Cache; std::set> m_UrlVector; }; From 2cf35256b5d539665477a86e97d8e2f1326ff973 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 16 Jun 2026 14:31:57 -0400 Subject: [PATCH 673/866] fix bug in time range found by the rabbit --- offline/database/sphenixnpc/SphenixClient.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index 01f571ceca..b20eea35e7 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -61,7 +61,7 @@ nlohmann::json SphenixClient::getUrlDict(long long iov) } for (auto it = resp["msg"].begin(); it != resp["msg"].end();) { - if (it.value()["minor_iov_end"] < iov) + if (it.value()["minor_iov_end"] <= iov) { it = resp["msg"].erase(it); } @@ -87,7 +87,7 @@ void SphenixClient::DumpCalibrations(long long iov, const std::string& filename) } for (auto it = resp["msg"].begin(); it != resp["msg"].end();) { - if (it.value()["minor_iov_end"] < iov) + if (it.value()["minor_iov_end"] <= iov) { it = resp["msg"].erase(it); } From f33067d2445823153c6edf828c912849182e0cbc Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 22:48:54 -0400 Subject: [PATCH 674/866] Moved ActsAborter to TrackReco. It is not used anywhere else --- offline/packages/trackbase/ActsAborter.h | 46 -------------------- offline/packages/trackbase/Makefile.am | 1 - offline/packages/trackreco/ActsPropagator.cc | 32 +++++++++++--- 3 files changed, 25 insertions(+), 54 deletions(-) delete mode 100644 offline/packages/trackbase/ActsAborter.h diff --git a/offline/packages/trackbase/ActsAborter.h b/offline/packages/trackbase/ActsAborter.h deleted file mode 100644 index b87aaa25c7..0000000000 --- a/offline/packages/trackbase/ActsAborter.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef TRACKBASE_ACTSABORTER_H -#define TRACKBASE_ACTSABORTER_H - -#include -#include -#include - -struct ActsAborter -{ - unsigned int abortlayer = std::numeric_limits::max(); - unsigned int abortvolume = std::numeric_limits::max(); - - template - bool operator()(propagator_state_t& state, const stepper_t& /*stepper*/, - const navigator_t& navigator, const Acts::Logger& /*logger*/) const - { - if (navigator.targetReached(state.navigation)) - { - return true; - } - - // if (!state.navigation.currentSurface) - if (!navigator.currentSurface(state.navigation)) - { - return false; - } - - auto volumeno = state.navigation.currentSurface->geometryId().volume(); - auto layerno = state.navigation.currentSurface->geometryId().layer(); - auto sensitive = state.navigation.currentSurface->geometryId().sensitive(); - - /// Check that we are in the proper layer and that we've also reached - /// a sensitive surface - if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) - { - navigator.targetReached(state.navigation, true); - return true; - } - - return false; - } -}; - -#endif diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 3e10b1f173..439d73256e 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -38,7 +38,6 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ - ActsAborter.h \ ActsGeometry.h \ ActsSourceLink.h \ ActsSurfaceMaps.h \ diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 1d403d8ae2..0064e7196c 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -1,7 +1,5 @@ #include "ActsPropagator.h" -#include - #include #include #include @@ -19,6 +17,8 @@ #include #include +#include "ActsAborter.h" + ActsPropagator::SurfacePtr ActsPropagator::makeVertexSurface(const SvtxVertex* vertex) { @@ -104,7 +104,18 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, unsigned int actslayer; if (!checkLayer(sphenixLayer, actsvolume, actslayer) || !m_geometry) { + + std::cout << "ActsPropagator::propagateTrack - checkLayer failed" << std::endl; return Acts::Result::failure(std::error_code(0, std::generic_category())); + + } else { + + std::cout << "ActsPropagator::propagateTrack -" + << " sphenixLayer: " << sphenixLayer + << " actsvolume: " << actsvolume + << " actslayer: " << actslayer + << std::endl; + } if (m_verbosity > 1) @@ -114,14 +125,19 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - SphenixPropagatorOptions options( + // using actor_list_t = Acts::ActorList<>; + using actor_list_t = Acts::ActorList; + using propagator_options_t = SphenixPropagator::Options; + + propagator_options_t options( m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); + ActsAborter aborter; aborter.abortlayer = actslayer; aborter.abortvolume = actsvolume; - options.actorList.append(aborter); - + options.actorList.get() = aborter; + // options.actorList.append(aborter); auto result = propagator.propagate(params, options); @@ -132,6 +148,8 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto pair = std::make_pair(pathlength, finalparams); return Acts::Result::success(pair); + } else { + std::cout << "ActsPropagator::propagateTrack - propagation failed" << std::endl; } return result.error(); @@ -164,7 +182,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, return Acts::Result::success(pair); } - + return result.error(); } @@ -235,7 +253,7 @@ ActsPropagator::SphenixPropagator ActsPropagator::makePropagator() } Acts::Logging::Level logLevel = Acts::Logging::FATAL; - if (m_verbosity > 3) +// if (m_verbosity > 3) { logLevel = Acts::Logging::VERBOSE; } From d44add19563d0db3e5a6bd2335cfaa846bfa2231 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 23:11:49 -0400 Subject: [PATCH 675/866] Moved aborter as a local class. Removed unnecessary typedefs --- offline/packages/trackreco/ActsPropagator.cc | 108 +++++++++++++------ offline/packages/trackreco/ActsPropagator.h | 10 +- 2 files changed, 78 insertions(+), 40 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 0064e7196c..92fd687611 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -17,8 +17,42 @@ #include #include -#include "ActsAborter.h" +/// local aborter class, used to tell acts to end track propagation when a given layer is used +/** the class is defined locally only because it has no usage outside of ActsPropagator */ +struct ActsAborter +{ + + /// (ACTS) layer id at which propagation should stop + unsigned int abortlayer = std::numeric_limits::max(); + + /// (ACTS) voulme id at which propagation should stop + unsigned int abortvolume = std::numeric_limits::max(); + + /// called at each extrapolation step, by acts, to verify whether to stop propagation or not + template + bool checkAbort( + propagator_state_t& state, const stepper_t& /*stepper*/, + const navigator_t& navigator, const Acts::Logger& /*logger*/) const + { + + if (!navigator.currentSurface(state.navigation)) + { return false; } + + const auto& volumeno = state.navigation.currentSurface->geometryId().volume(); + const auto& layerno = state.navigation.currentSurface->geometryId().layer(); + const auto& sensitive = state.navigation.currentSurface->geometryId().sensitive(); + + /// Check that we are in the proper layer and that we've also reached + /// a sensitive surface + if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) + { return true; } + return false; + } + +}; + +//____________________________________________________________________ ActsPropagator::SurfacePtr ActsPropagator::makeVertexSurface(const SvtxVertex* vertex) { @@ -27,12 +61,16 @@ ActsPropagator::makeVertexSurface(const SvtxVertex* vertex) vertex->get_y() * Acts::UnitConstants::cm, vertex->get_z() * Acts::UnitConstants::cm)); } + +//____________________________________________________________________ ActsPropagator::SurfacePtr ActsPropagator::makeVertexSurface(const Acts::Vector3& vertex) { return Acts::Surface::makeShared( vertex * Acts::UnitConstants::cm); } + +//____________________________________________________________________ ActsPropagator::BoundTrackParamResult ActsPropagator::makeTrackParams(SvtxTrackState* state, int trackCharge, @@ -57,6 +95,8 @@ ActsPropagator::makeTrackParams(SvtxTrackState* state, cov, Acts::ParticleHypothesis::pion()); } + +//____________________________________________________________________ ActsPropagator::BoundTrackParamResult ActsPropagator::makeTrackParams(SvtxTrack* track, SvtxVertexMap* vertexMap) @@ -96,6 +136,7 @@ ActsPropagator::makeTrackParams(SvtxTrack* track, 1 * Acts::UnitConstants::cm); } +//____________________________________________________________________ ActsPropagator::BTPPairResult ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const unsigned int sphenixLayer) @@ -125,19 +166,17 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - // using actor_list_t = Acts::ActorList<>; + // create propagator options with proper aborter using actor_list_t = Acts::ActorList; using propagator_options_t = SphenixPropagator::Options; propagator_options_t options( - m_geometry->geometry().getGeoContext(), - m_geometry->geometry().magFieldContext); + m_geometry->geometry().getGeoContext(), + m_geometry->geometry().magFieldContext); - ActsAborter aborter; - aborter.abortlayer = actslayer; - aborter.abortvolume = actsvolume; - options.actorList.get() = aborter; - // options.actorList.append(aborter); + // initialize aborter + options.actorList.get().abortlayer = actslayer; + options.actorList.get().abortvolume = actsvolume; auto result = propagator.propagate(params, options); @@ -155,9 +194,9 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, return result.error(); } +//____________________________________________________________________ ActsPropagator::BTPPairResult -ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, - const SurfacePtr& surface) +ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const SurfacePtr& surface) { if (m_verbosity > 1) { @@ -166,13 +205,13 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - SphenixPropagatorOptions options(m_geometry->geometry().getGeoContext(), + SphenixPropagator::Options options(m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); auto intersect = surface.get()->intersect(m_geometry->geometry().getGeoContext(), params.position(m_geometry->geometry().getGeoContext()), params.momentum(), Acts::BoundaryTolerance::None(), 0.1 * Acts::UnitConstants::mm).closest(); options.direction = Acts::Direction::fromScalarZeroAsPositive(intersect.pathLength()); - auto result = propagator.template propagate(params, *surface, options); + auto result = propagator.propagate(params, *surface, options); if (result.ok()) { @@ -186,6 +225,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, return result.error(); } +//____________________________________________________________________ ActsPropagator::BTPPairResult ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, const SurfacePtr& surface) @@ -200,14 +240,13 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, Propagator::Options> options(m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); - auto result = propagator.propagate(params, *surface, - options); + auto result = propagator.propagate(params, *surface, options); if (result.ok()) { - auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) - auto pathlength = result.value().pathLength; - auto pair = std::make_pair(pathlength, finalparams); + const auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) + const auto pathlength = result.value().pathLength; + const auto pair = std::make_pair(pathlength, finalparams); return Acts::Result::success(pair); } @@ -215,6 +254,7 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, return result.error(); } +//____________________________________________________________________ ActsPropagator::FastPropagator ActsPropagator::makeFastPropagator() { auto field = m_geometry->geometry().magField; @@ -225,23 +265,22 @@ ActsPropagator::FastPropagator ActsPropagator::makeFastPropagator() { std::cout << "Using const field of val " << m_fieldval << std::endl; } - Acts::Vector3 fieldVec(0, 0, m_fieldval); + const Acts::Vector3 fieldVec(0, 0, m_fieldval); field = std::make_shared(fieldVec); } + // create stepper with proper magnetic field ActsPropagator::Stepper stepper(field); - Acts::Logging::Level logLevel = Acts::Logging::FATAL; - if (m_verbosity > 3) - { - logLevel = Acts::Logging::VERBOSE; - } - + // create logger + const Acts::Logging::Level logLevel = (m_verbosity > 3) ? Acts::Logging::VERBOSE:Acts::Logging::FATAL; std::shared_ptr logger = Acts::getDefaultLogger("ActsPropagator", logLevel); - return ActsPropagator::FastPropagator(stepper, Acts::VoidNavigator(), - logger); + // create propagator and return + return ActsPropagator::FastPropagator(stepper, Acts::VoidNavigator(), logger); } + +//____________________________________________________________________ ActsPropagator::SphenixPropagator ActsPropagator::makePropagator() { auto field = m_geometry->geometry().magField; @@ -252,27 +291,27 @@ ActsPropagator::SphenixPropagator ActsPropagator::makePropagator() field = std::make_shared(fieldVec); } - Acts::Logging::Level logLevel = Acts::Logging::FATAL; -// if (m_verbosity > 3) - { - logLevel = Acts::Logging::VERBOSE; - } - auto trackingGeometry = m_geometry->geometry().tGeometry; + Stepper stepper(field); + // create mavigation logger + const Acts::Logging::Level logLevel = (m_verbosity > 3) ? Acts::Logging::VERBOSE:Acts::Logging::FATAL; std::shared_ptr navlogger = Acts::getDefaultLogger("ActsPropagator::NAVIGATION", logLevel); + // create navigator + const auto trackingGeometry = m_geometry->geometry().tGeometry; Acts::Navigator::Config cfg{trackingGeometry}; cfg.resolvePassive = false; cfg.resolveMaterial = true; cfg.resolveSensitive = true; Acts::Navigator navigator(cfg, navlogger); - + // create propagator with proper logger and return std::shared_ptr logger = Acts::getDefaultLogger("ActsPropagator", logLevel); return SphenixPropagator(stepper, navigator, logger); } +//____________________________________________________________________ bool ActsPropagator::checkLayer(const unsigned int& sphenixlayer, unsigned int& actsvolume, unsigned int& actslayer) @@ -343,6 +382,7 @@ bool ActsPropagator::checkLayer(const unsigned int& sphenixlayer, return true; } +//____________________________________________________________________ void ActsPropagator::printTrackParams(const Acts::BoundTrackParameters& params) { std::cout << "Propagating final track fit with momentum: " diff --git a/offline/packages/trackreco/ActsPropagator.h b/offline/packages/trackreco/ActsPropagator.h index 164145156b..8356a748c5 100644 --- a/offline/packages/trackreco/ActsPropagator.h +++ b/offline/packages/trackreco/ActsPropagator.h @@ -31,16 +31,14 @@ class ActsPropagator public: using BoundTrackParam = Acts::BoundTrackParameters; using BoundTrackParamResult = Acts::Result; - /// Return type of std::pair using BoundTrackParamPair = std::pair; using BTPPairResult = Acts::Result; using SurfacePtr = std::shared_ptr; using Stepper = Acts::EigenStepper<>; + using FastPropagator = Acts::Propagator; using SphenixPropagator = Acts::Propagator; - using Actors = Acts::ActorList<>; - using SphenixPropagatorOptions = SphenixPropagator::Options; - + ActsPropagator() {} ActsPropagator(ActsGeometry* geometry) : m_geometry(geometry) @@ -52,9 +50,9 @@ class ActsPropagator /// functions below SurfacePtr makeVertexSurface(const SvtxVertex* vertex); SurfacePtr makeVertexSurface(const Acts::Vector3& vertex); - BoundTrackParamResult makeTrackParams(SvtxTrack* track, + BoundTrackParamResult makeTrackParams(SvtxTrack* track, SvtxVertexMap* vertexMap); - BoundTrackParamResult makeTrackParams(SvtxTrackState* state, + BoundTrackParamResult makeTrackParams(SvtxTrackState* state, int trackCharge, SurfacePtr surf); From a39a167a10c901045e69c86e242d46b24ad49942 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 23:31:15 -0400 Subject: [PATCH 676/866] Removed obsolete include --- offline/packages/trackreco/PHActsTrackPropagator.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/trackreco/PHActsTrackPropagator.cc b/offline/packages/trackreco/PHActsTrackPropagator.cc index 449b55f44a..6cf4f8cfbf 100644 --- a/offline/packages/trackreco/PHActsTrackPropagator.cc +++ b/offline/packages/trackreco/PHActsTrackPropagator.cc @@ -11,7 +11,6 @@ #include #include -#include #include #include From f76b6ee753fb3fb44a2cd034d3af14a02bc941c7 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 23:33:47 -0400 Subject: [PATCH 677/866] removed printouts initialize variables --- offline/packages/trackreco/ActsPropagator.cc | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 92fd687611..bb24495aee 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -141,23 +141,10 @@ ActsPropagator::BTPPairResult ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const unsigned int sphenixLayer) { - unsigned int actsvolume; - unsigned int actslayer; + unsigned int actsvolume = 0; + unsigned int actslayer = 0; if (!checkLayer(sphenixLayer, actsvolume, actslayer) || !m_geometry) - { - - std::cout << "ActsPropagator::propagateTrack - checkLayer failed" << std::endl; - return Acts::Result::failure(std::error_code(0, std::generic_category())); - - } else { - - std::cout << "ActsPropagator::propagateTrack -" - << " sphenixLayer: " << sphenixLayer - << " actsvolume: " << actsvolume - << " actslayer: " << actslayer - << std::endl; - - } + { return Acts::Result::failure(std::error_code(0, std::generic_category())); } if (m_verbosity > 1) { From d3cc8c10ed171192bc40110c0a4846e4eb22b3d1 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 23:37:55 -0400 Subject: [PATCH 678/866] fixed compilation. --- .../MakeMilleFiles.cc | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index 939de889a7..cb50fd55f0 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -297,23 +297,22 @@ bool MakeMilleFiles::getLocalVtxDerivativesXY(SvtxTrack* track, const Acts::Vector3& vertex, float lclvtx_derivative[SvtxAlignmentState::NRES][SvtxAlignmentState::NLOC]) { + //! Get the first track state beyond the vertex, which will be the //! innermost track state and propagate it to the vertex surface to //! get the jacobian at the vertex - SvtxTrackState* firststate = (*std::next(track->begin_states(), 1)).second; + auto* firststate = (*std::next(track->begin_states(), 1)).second; - TrkrDefs::cluskey ckey = firststate->get_cluskey(); - auto cluster = _cluster_map->findCluster(ckey); - auto surf = _tGeometry->maps().getSurface(ckey, cluster); + const auto ckey = firststate->get_cluskey(); + const auto cluster = _cluster_map->findCluster(ckey); + const auto surf = _tGeometry->maps().getSurface(ckey, cluster); - auto param = propagator.makeTrackParams(firststate, track->get_charge(), surf).value(); - auto perigee = propagator.makeVertexSurface(vertex); - auto actspropagator = propagator.makePropagator(); - ActsPropagator::SphenixPropagatorOptions - options(_tGeometry->geometry().getGeoContext(), - _tGeometry->geometry().magFieldContext); + const auto param = propagator.makeTrackParams(firststate, track->get_charge(), surf).value(); + const auto perigee = propagator.makeVertexSurface(vertex); + const auto actspropagator = propagator.makePropagator(); + const ActsPropagator::SphenixPropagator::Options options(_tGeometry->geometry().getGeoContext(), _tGeometry->geometry().magFieldContext); - auto result = actspropagator.propagate(param, *perigee, options); + const auto result = actspropagator.propagate(param, *perigee, options); if (result.ok()) { From 4d58b6b3909c26df83944818251befc6f55898a6 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 23:42:10 -0400 Subject: [PATCH 679/866] fixed error code. --- offline/packages/trackreco/ActsPropagator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index bb24495aee..e73bf46c24 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -144,7 +144,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, unsigned int actsvolume = 0; unsigned int actslayer = 0; if (!checkLayer(sphenixLayer, actsvolume, actslayer) || !m_geometry) - { return Acts::Result::failure(std::error_code(0, std::generic_category())); } + { return Acts::Result::failure(std::make_error_code(std::errc::invalid_argument)); } if (m_verbosity > 1) { From 89f9db0da2f1dbf9a425ca72568c6925939e093b Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 17 Jun 2026 09:25:34 -0400 Subject: [PATCH 680/866] Put struct in the header for other classes --- offline/packages/trackreco/ActsPropagator.cc | 34 ------------------ offline/packages/trackreco/ActsPropagator.h | 36 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index e73bf46c24..63a018f56b 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -17,40 +17,6 @@ #include #include -/// local aborter class, used to tell acts to end track propagation when a given layer is used -/** the class is defined locally only because it has no usage outside of ActsPropagator */ -struct ActsAborter -{ - - /// (ACTS) layer id at which propagation should stop - unsigned int abortlayer = std::numeric_limits::max(); - - /// (ACTS) voulme id at which propagation should stop - unsigned int abortvolume = std::numeric_limits::max(); - - /// called at each extrapolation step, by acts, to verify whether to stop propagation or not - template - bool checkAbort( - propagator_state_t& state, const stepper_t& /*stepper*/, - const navigator_t& navigator, const Acts::Logger& /*logger*/) const - { - - if (!navigator.currentSurface(state.navigation)) - { return false; } - - const auto& volumeno = state.navigation.currentSurface->geometryId().volume(); - const auto& layerno = state.navigation.currentSurface->geometryId().layer(); - const auto& sensitive = state.navigation.currentSurface->geometryId().sensitive(); - - /// Check that we are in the proper layer and that we've also reached - /// a sensitive surface - if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) - { return true; } - - return false; - } - -}; //____________________________________________________________________ ActsPropagator::SurfacePtr diff --git a/offline/packages/trackreco/ActsPropagator.h b/offline/packages/trackreco/ActsPropagator.h index 8356a748c5..d9dfd5c904 100644 --- a/offline/packages/trackreco/ActsPropagator.h +++ b/offline/packages/trackreco/ActsPropagator.h @@ -97,4 +97,40 @@ class ActsPropagator float m_overstepLimit = 0.01 * Acts::UnitConstants::cm; // sphenix units cm }; +/// local aborter class, used to tell acts to end track propagation when a given layer is used +/** the class is defined locally only because it has no usage outside of ActsPropagator */ +struct ActsAborter +{ + + /// (ACTS) layer id at which propagation should stop + unsigned int abortlayer = std::numeric_limits::max(); + + /// (ACTS) voulme id at which propagation should stop + unsigned int abortvolume = std::numeric_limits::max(); + + /// called at each extrapolation step, by acts, to verify whether to stop propagation or not + template + bool checkAbort( + propagator_state_t& state, const stepper_t& /*stepper*/, + const navigator_t& navigator, const Acts::Logger& /*logger*/) const + { + + if (!navigator.currentSurface(state.navigation)) + { return false; } + + const auto& volumeno = state.navigation.currentSurface->geometryId().volume(); + const auto& layerno = state.navigation.currentSurface->geometryId().layer(); + const auto& sensitive = state.navigation.currentSurface->geometryId().sensitive(); + + /// Check that we are in the proper layer and that we've also reached + /// a sensitive surface + if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) + { return true; } + + return false; + } + +}; + + #endif From 8336d13d222d18494e4e4eb242f8fdaab62ca2d1 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 17 Jun 2026 09:33:36 -0400 Subject: [PATCH 681/866] Switch propagator call back to template with forced surface reached --- offline/packages/trackreco/ActsPropagator.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 63a018f56b..5a5f8422c2 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -164,8 +164,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const S auto intersect = surface.get()->intersect(m_geometry->geometry().getGeoContext(), params.position(m_geometry->geometry().getGeoContext()), params.momentum(), Acts::BoundaryTolerance::None(), 0.1 * Acts::UnitConstants::mm).closest(); options.direction = Acts::Direction::fromScalarZeroAsPositive(intersect.pathLength()); - auto result = propagator.propagate(params, *surface, options); - + auto result = propagator.template propagate(params, *surface, options); if (result.ok()) { auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) @@ -226,7 +225,7 @@ ActsPropagator::FastPropagator ActsPropagator::makeFastPropagator() ActsPropagator::Stepper stepper(field); // create logger - const Acts::Logging::Level logLevel = (m_verbosity > 3) ? Acts::Logging::VERBOSE:Acts::Logging::FATAL; + const Acts::Logging::Level logLevel = (m_verbosity > 3) ? Acts::Logging::VERBOSE : Acts::Logging::FATAL; std::shared_ptr logger = Acts::getDefaultLogger("ActsPropagator", logLevel); // create propagator and return From 4d307f8dcb0019ddc3571a8d4c3a629a30e023e8 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 10:27:11 -0400 Subject: [PATCH 682/866] Fixed compilation: typename alias has been removed from header. use SphenixPropagator::Options<> instead. --- offline/packages/trackreco/ActsPropagator.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 5a5f8422c2..8c0f14554b 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -158,13 +158,11 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const S auto propagator = makePropagator(); - SphenixPropagator::Options options(m_geometry->geometry().getGeoContext(), - m_geometry->geometry().magFieldContext); + SphenixPropagator::Options options(m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); - auto intersect = surface.get()->intersect(m_geometry->geometry().getGeoContext(), params.position(m_geometry->geometry().getGeoContext()), params.momentum(), - Acts::BoundaryTolerance::None(), 0.1 * Acts::UnitConstants::mm).closest(); + auto intersect = surface.get()->intersect(m_geometry->geometry().getGeoContext(), params.position(m_geometry->geometry().getGeoContext()), params.momentum(), Acts::BoundaryTolerance::None(), 0.1 * Acts::UnitConstants::mm).closest(); options.direction = Acts::Direction::fromScalarZeroAsPositive(intersect.pathLength()); - auto result = propagator.template propagate(params, *surface, options); + auto result = propagator.template propagate, Acts::ForcedSurfaceReached, Acts::PathLimitReached>(params, *surface, options); if (result.ok()) { auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) From e0f8445852864a18c29d23617d83202374733ebb Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 10:33:43 -0400 Subject: [PATCH 683/866] move Aborter back to local definition. On agreement with Joe --- offline/packages/trackreco/ActsPropagator.cc | 34 ++++++++++++++++++ offline/packages/trackreco/ActsPropagator.h | 36 -------------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 8c0f14554b..153ddbd609 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -17,6 +17,40 @@ #include #include +/// local aborter class, used to tell acts to end track propagation when a given layer is used +/** for the time being, the class is defined locally only, because it has no usage outside of ActsPropagator */ +struct ActsAborter +{ + + /// (ACTS) layer id at which propagation should stop + unsigned int abortlayer = std::numeric_limits::max(); + + /// (ACTS) voulme id at which propagation should stop + unsigned int abortvolume = std::numeric_limits::max(); + + /// called at each extrapolation step, by acts, to verify whether to stop propagation or not + template + bool checkAbort( + propagator_state_t& state, const stepper_t& /*stepper*/, + const navigator_t& navigator, const Acts::Logger& /*logger*/) const + { + + if (!navigator.currentSurface(state.navigation)) + { return false; } + + const auto& volumeno = state.navigation.currentSurface->geometryId().volume(); + const auto& layerno = state.navigation.currentSurface->geometryId().layer(); + const auto& sensitive = state.navigation.currentSurface->geometryId().sensitive(); + + /// Check that we are in the proper layer and that we've also reached + /// a sensitive surface + if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) + { return true; } + + return false; + } + +}; //____________________________________________________________________ ActsPropagator::SurfacePtr diff --git a/offline/packages/trackreco/ActsPropagator.h b/offline/packages/trackreco/ActsPropagator.h index d9dfd5c904..8356a748c5 100644 --- a/offline/packages/trackreco/ActsPropagator.h +++ b/offline/packages/trackreco/ActsPropagator.h @@ -97,40 +97,4 @@ class ActsPropagator float m_overstepLimit = 0.01 * Acts::UnitConstants::cm; // sphenix units cm }; -/// local aborter class, used to tell acts to end track propagation when a given layer is used -/** the class is defined locally only because it has no usage outside of ActsPropagator */ -struct ActsAborter -{ - - /// (ACTS) layer id at which propagation should stop - unsigned int abortlayer = std::numeric_limits::max(); - - /// (ACTS) voulme id at which propagation should stop - unsigned int abortvolume = std::numeric_limits::max(); - - /// called at each extrapolation step, by acts, to verify whether to stop propagation or not - template - bool checkAbort( - propagator_state_t& state, const stepper_t& /*stepper*/, - const navigator_t& navigator, const Acts::Logger& /*logger*/) const - { - - if (!navigator.currentSurface(state.navigation)) - { return false; } - - const auto& volumeno = state.navigation.currentSurface->geometryId().volume(); - const auto& layerno = state.navigation.currentSurface->geometryId().layer(); - const auto& sensitive = state.navigation.currentSurface->geometryId().sensitive(); - - /// Check that we are in the proper layer and that we've also reached - /// a sensitive surface - if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) - { return true; } - - return false; - } - -}; - - #endif From 2bd713ac4ff052f64363b43ce24ab04522a6abcc Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 10:42:09 -0400 Subject: [PATCH 684/866] removed error message. --- offline/packages/trackreco/ActsPropagator.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 153ddbd609..27952c6e96 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -174,8 +174,6 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto pair = std::make_pair(pathlength, finalparams); return Acts::Result::success(pair); - } else { - std::cout << "ActsPropagator::propagateTrack - propagation failed" << std::endl; } return result.error(); From 35be54cbf9fd6e5203ecd229eaa8c893960aebc3 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 11:29:07 -0400 Subject: [PATCH 685/866] Allow to specify cluster map name. This allows to run on TRKR_CLUSTER_SEED so directly from track DSTs without the need to load the corresponding Cluster DST. --- offline/packages/tpccalib/PHTpcResiduals.cc | 8 ++++---- offline/packages/tpccalib/PHTpcResiduals.h | 16 ++++++++++++++-- offline/packages/trackreco/PHTrackPruner.cc | 4 ++-- offline/packages/trackreco/PHTrackPruner.h | 16 +++++++++++++++- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 4360bc7d1b..788e4ae06d 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -744,10 +744,10 @@ int PHTpcResiduals::createNodes(PHCompositeNode* /*topNode*/) int PHTpcResiduals::getNodes(PHCompositeNode* topNode) { // clusters - m_clusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); + m_clusterContainer = findNode::getClass(topNode, m_clustermapname); if (!m_clusterContainer) { - std::cout << PHWHERE << "No TRKR_CLUSTER node on node tree. Exiting." << std::endl; + std::cout << "PHTpcResiduals::getNodes - cluster map named " << m_clustermapname << " not found." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -755,7 +755,7 @@ int PHTpcResiduals::getNodes(PHCompositeNode* topNode) m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); if (!m_tGeometry) { - std::cout << "ActsTrackingGeometry not on node tree. Exiting." << std::endl; + std::cout << "PHTpcResiduals::getNodes - ActsGeometry not found." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -763,7 +763,7 @@ int PHTpcResiduals::getNodes(PHCompositeNode* topNode) m_trackMap = findNode::getClass(topNode, m_trackmapname); if (!m_trackMap) { - std::cout << PHWHERE << " " << m_trackmapname << " not on node tree. Exiting." << std::endl; + std::cout << "PHTpcResiduals::getNodes - track map named " << m_trackmapname << " not found." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index 62609e9400..1e750aad3a 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -130,6 +130,10 @@ class PHTpcResiduals : public SubsysReco void setTrackMapName( const std::string& value ) { m_trackmapname = value; } + /// modify track map name + void setClusterMapName( const std::string& value ) + { m_clustermapname = value; } + private: int getNodes(PHCompositeNode *topNode); @@ -144,11 +148,19 @@ class PHTpcResiduals : public SubsysReco /// Gets distortion cell for identifying bins in TPC int getCell(const Acts::Vector3 &loc); - /// Node information for Acts tracking geometry and silicon+MM - /// track fit + //! track map name std::string m_trackmapname = "SvtxSiliconMMTrackMap"; + + //! track map SvtxTrackMap *m_trackMap = nullptr; + + //! acts geometry ActsGeometry *m_tGeometry = nullptr; + + //! cluster map name + std::string m_clustermapname = "TRKR_CLUSTER"; + + //! cluster map TrkrClusterContainer *m_clusterContainer = nullptr; //! tpc global position wrapper diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index 57eb6df854..de84fa9bf9 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -320,10 +320,10 @@ int PHTrackPruner::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; } diff --git a/offline/packages/trackreco/PHTrackPruner.h b/offline/packages/trackreco/PHTrackPruner.h index ef59a64178..6bfc086e1d 100644 --- a/offline/packages/trackreco/PHTrackPruner.h +++ b/offline/packages/trackreco/PHTrackPruner.h @@ -34,12 +34,25 @@ class PHTrackPruner : public SubsysReco int End(PHCompositeNode *) override; - void set_pruned_svtx_seed_map_name(const std::string &map_name) { _pruned_svtx_seed_map_name = map_name; } + //! input cluster map name. Default is TRKR_CLUSTER + void set_cluster_map_name(const std::string &map_name) { _cluster_map_name = map_name; } + + //! input seeds map name void set_svtx_seed_map_name(const std::string &map_name) { _svtx_seed_map_name = map_name; } + + //! input silicon seeds map name void set_si_seed_map_name(const std::string &map_name) { _si_seed_map_name = map_name; } + + //! input tpc seeds map name void set_tpc_seed_map_name(const std::string &map_name) { _tpc_seed_map_name = map_name; } + + //! input track map name void set_svtx_track_map_name(const std::string &map_name) { _svtx_track_map_name = map_name; } + //! output pruned track map name + void set_pruned_svtx_seed_map_name(const std::string &map_name) { _pruned_svtx_seed_map_name = map_name; } + + /// low pt cut void set_track_pt_low_cut(const double val) { m_track_pt_low_cut = val; } void set_track_quality_high_cut(const double val) { m_track_quality_high_cut = val; } @@ -72,6 +85,7 @@ class PHTrackPruner : public SubsysReco ActsGeometry *_tGeometry{nullptr}; int m_event = 0; + std::string _cluster_map_name = "TRKR_CLUSTER"; std::string _tpc_seed_map_name = "TpcTrackSeedContainer"; std::string _si_seed_map_name = "SiliconTrackSeedContainer"; std::string _svtx_seed_map_name = "SvtxTrackSeedContainer"; From ee62be6776c50cd3f4138b2aa12336fe370bd9ab Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 15:28:26 -0400 Subject: [PATCH 686/866] removed unneeded svtx_seed_map and seed_map_name --- offline/packages/trackreco/PHTrackPruner.cc | 9 --------- offline/packages/trackreco/PHTrackPruner.h | 8 +++----- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index de84fa9bf9..e1e2cb24ad 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -103,14 +103,12 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) { // _tpc_seed_map contains the TPC seed track stubs // _si_seed_map contains the silicon seed track stubs - // _svtx_seed_map contains the combined silicon and tpc track seeds // _svtx_track_map contains the fitted acts track stubs if (Verbosity() > 0) { cout << PHWHERE << " TPC seed map size " << _tpc_seed_map->size() << " Silicon seed map size " << _si_seed_map->size() - << " Svtx seed map size " << _svtx_seed_map->size() << " Svtx track map size " << _svtx_track_map->size() << endl; } @@ -282,13 +280,6 @@ int PHTrackPruner::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - _svtx_seed_map = findNode::getClass(topNode, _svtx_seed_map_name); - if (!_svtx_seed_map) - { - cerr << PHWHERE << " ERROR: Can't find " << _svtx_seed_map_name.c_str() << endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - _pruned_svtx_seed_map = findNode::getClass(topNode, _pruned_svtx_seed_map_name); if (!_pruned_svtx_seed_map) { diff --git a/offline/packages/trackreco/PHTrackPruner.h b/offline/packages/trackreco/PHTrackPruner.h index 6bfc086e1d..4ed10888a6 100644 --- a/offline/packages/trackreco/PHTrackPruner.h +++ b/offline/packages/trackreco/PHTrackPruner.h @@ -37,9 +37,6 @@ class PHTrackPruner : public SubsysReco //! input cluster map name. Default is TRKR_CLUSTER void set_cluster_map_name(const std::string &map_name) { _cluster_map_name = map_name; } - //! input seeds map name - void set_svtx_seed_map_name(const std::string &map_name) { _svtx_seed_map_name = map_name; } - //! input silicon seeds map name void set_si_seed_map_name(const std::string &map_name) { _si_seed_map_name = map_name; } @@ -74,11 +71,13 @@ class PHTrackPruner : public SubsysReco double getBunchCrossing(unsigned int trid, double z_mismatch); TrackSeedContainer *_pruned_svtx_seed_map{nullptr}; - TrackSeedContainer *_svtx_seed_map{nullptr}; TrackSeedContainer *_tpc_seed_map{nullptr}; TrackSeedContainer *_si_seed_map{nullptr}; + + // should remove TrackSeed *_tpc_seed{nullptr}; TrackSeed *_si_seed{nullptr}; + SvtxTrackMap *_svtx_track_map{nullptr}; SvtxTrack *_svtx_track{nullptr}; TrkrClusterContainer *_cluster_map{nullptr}; @@ -88,7 +87,6 @@ class PHTrackPruner : public SubsysReco std::string _cluster_map_name = "TRKR_CLUSTER"; std::string _tpc_seed_map_name = "TpcTrackSeedContainer"; std::string _si_seed_map_name = "SiliconTrackSeedContainer"; - std::string _svtx_seed_map_name = "SvtxTrackSeedContainer"; std::string _pruned_svtx_seed_map_name = "PrunedSvtxTrackSeedContainer"; std::string _svtx_track_map_name = "SvtxTrackMap"; From c905662b6a11c0087e66d43cc70214313e00ac32 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 15:36:04 -0400 Subject: [PATCH 687/866] removed _tpc_seed and _si_seed members. They are not necessary --- offline/packages/trackreco/PHTrackPruner.cc | 10 +++++----- offline/packages/trackreco/PHTrackPruner.h | 4 ---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index e1e2cb24ad..ed5e673bb3 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -130,13 +130,13 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) } if (Verbosity() > 1) { std::cout<<"Pass track selection"<get_tpc_seed(); - _si_seed = _svtx_track->get_silicon_seed(); - if (_tpc_seed && _si_seed) + auto* tpc_seed = _svtx_track->get_tpc_seed(); + auto* si_seed = _svtx_track->get_silicon_seed(); + if (tpc_seed && si_seed) { if (Verbosity() > 1) { std::cout<<"Insert tpcid and siid into good_matches"<find(_tpc_seed); - int siid = _si_seed_map->find(_si_seed); + int tpcid = _tpc_seed_map->find(tpc_seed); + int siid = _si_seed_map->find(si_seed); good_matches.insert(std::make_pair(tpcid, siid)); } } diff --git a/offline/packages/trackreco/PHTrackPruner.h b/offline/packages/trackreco/PHTrackPruner.h index 4ed10888a6..aa746141c7 100644 --- a/offline/packages/trackreco/PHTrackPruner.h +++ b/offline/packages/trackreco/PHTrackPruner.h @@ -74,10 +74,6 @@ class PHTrackPruner : public SubsysReco TrackSeedContainer *_tpc_seed_map{nullptr}; TrackSeedContainer *_si_seed_map{nullptr}; - // should remove - TrackSeed *_tpc_seed{nullptr}; - TrackSeed *_si_seed{nullptr}; - SvtxTrackMap *_svtx_track_map{nullptr}; SvtxTrack *_svtx_track{nullptr}; TrkrClusterContainer *_cluster_map{nullptr}; From 4a72ab9cb802565fc1688587acf98ddd7ca274cb Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 15:38:10 -0400 Subject: [PATCH 688/866] removed _svtx_track and m_event. --- offline/packages/trackreco/PHTrackPruner.cc | 9 ++++----- offline/packages/trackreco/PHTrackPruner.h | 2 -- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index ed5e673bb3..fb50061e5d 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -122,16 +122,16 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) for (auto &iter : *_svtx_track_map) { - _svtx_track = iter.second; + auto* svtx_track = iter.second; - if(!checkTrack(_svtx_track)) + if(!checkTrack(svtx_track)) { continue; } if (Verbosity() > 1) { std::cout<<"Pass track selection"<get_tpc_seed(); - auto* si_seed = _svtx_track->get_silicon_seed(); + auto* tpc_seed = svtx_track->get_tpc_seed(); + auto* si_seed = svtx_track->get_silicon_seed(); if (tpc_seed && si_seed) { if (Verbosity() > 1) { std::cout<<"Insert tpcid and siid into good_matches"< Date: Wed, 17 Jun 2026 16:12:15 -0400 Subject: [PATCH 689/866] removed trivial destructor --- offline/packages/trackreco/PHTrackPruner.cc | 3 --- offline/packages/trackreco/PHTrackPruner.h | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index fb50061e5d..e54298372f 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -83,9 +83,6 @@ PHTrackPruner::PHTrackPruner(const std::string &name) { } -//____________________________________________________________________________.. -PHTrackPruner::~PHTrackPruner() = default; - //____________________________________________________________________________.. int PHTrackPruner::InitRun(PHCompositeNode *topNode) { diff --git a/offline/packages/trackreco/PHTrackPruner.h b/offline/packages/trackreco/PHTrackPruner.h index aabfff0606..ffe4007d60 100644 --- a/offline/packages/trackreco/PHTrackPruner.h +++ b/offline/packages/trackreco/PHTrackPruner.h @@ -24,9 +24,10 @@ class TNtuple; class PHTrackPruner : public SubsysReco { public: - PHTrackPruner(const std::string &name = "PHTrackPruner"); - ~PHTrackPruner() override; + + //! constructor + PHTrackPruner(const std::string &name = "PHTrackPruner"); int InitRun(PHCompositeNode *topNode) override; From 400a237a33059b36d731ec4e34a8f54f9f84cba1 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 16:12:17 -0400 Subject: [PATCH 690/866] Added PHTrackTrackSeed module, which resynchronize seed from TrackSeedContainer and pointers from track objects. --- offline/packages/trackreco/Makefile.am | 2 + .../PHTrackTrackSeedSynchronization.cc | 168 ++++++++++++++++++ .../PHTrackTrackSeedSynchronization.h | 61 +++++++ 3 files changed, 231 insertions(+) create mode 100644 offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc create mode 100644 offline/packages/trackreco/PHTrackTrackSeedSynchronization.h diff --git a/offline/packages/trackreco/Makefile.am b/offline/packages/trackreco/Makefile.am index 74626f2c60..e4f9f448cc 100644 --- a/offline/packages/trackreco/Makefile.am +++ b/offline/packages/trackreco/Makefile.am @@ -60,6 +60,7 @@ pkginclude_HEADERS = \ PHTrackPruner.h \ PHTrackCleaner.h \ PHTrackSelector.h \ + PHTrackTrackSeedSynchronization.h \ PHRaveVertexing.h \ PHSiliconHelicalPropagator.h \ PHSiliconSeedMerger.h \ @@ -155,6 +156,7 @@ libtrack_reco_la_SOURCES = \ PHTrackClusterAssociator.cc \ PHTrackSeeding.cc \ PHTrackSelector.cc \ + PHTrackTrackSeedSynchronization.cc \ PHTrackSetMerging.cc \ PHTrackPropagating.cc \ PHTrackFitting.cc \ diff --git a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc new file mode 100644 index 0000000000..901e249f78 --- /dev/null +++ b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc @@ -0,0 +1,168 @@ +#include "PHTrackTrackSeedSynchronization.h" + +/// Tracking includes +#include +#include +#include +#include +#include +#include // for cluskey, getTrkrId, tpcId + +#include +#include +#include +#include + +#include // for SvtxTrack +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include // for UINT_MAX +#include // for fabs, sqrt +#include // for operator<<, basic_ostream +#include +#include // for _Rb_tree_const_iterator +#include // for pair + +using namespace std; + +namespace +{ + + /// find index of seed in container that matches argument seed + size_t find_seed_id( TrackSeedContainer* container, TrackSeed* source ) + { + // perform quick search + const size_t index = container->find( source ); + if( index < container->size() ) return index; + + // perform deep search based on cluster keys + using cluster_keyset_t=std::set; + + // get cluster key set from seed + auto get_cluster_keyset = []( TrackSeed* seed ) + { + cluster_keyset_t ckeys; + std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::inserter(ckeys, ckeys.end() ) ); + return ckeys; + }; + + const auto source_ckeys = get_cluster_keyset( source ); + + for( size_t i = 0; i < container->size(); ++i ) + { + auto* seed = container->get(i); + if( !seed ) continue; + + const auto ckeys = get_cluster_keyset( seed ); + if( ckeys == source_ckeys ) + { return i; } + } + + // error + std::cout << "find_seed_id - could not find seed " << source << " in container " << container << std::endl; + return container->size(); + } + +} + +//____________________________________________________________________________.. +PHTrackTrackSeedSynchronization::PHTrackTrackSeedSynchronization(const std::string &name) + : SubsysReco(name) +{} + +//____________________________________________________________________________.. +int PHTrackTrackSeedSynchronization::InitRun(PHCompositeNode *topNode) +{ + int ret = GetNodes(topNode); + if (ret != Fun4AllReturnCodes::EVENT_OK) + { + return ret; + } + + return ret; +} + +//____________________________________________________________________________.. +int PHTrackTrackSeedSynchronization::process_event(PHCompositeNode * /*unused*/) +{ + // loop over tracks and synchronize + for( auto &&[key,track]:*_svtx_track_map ) + { synchronize_track(track); } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________ +bool PHTrackTrackSeedSynchronization::synchronize_track( SvtxTrack* track ) const +{ + { + // silicon seed + auto* seed = track->get_silicon_seed(); + if( seed ) + { + auto index = find_seed_id( _si_seed_map, seed ); + if( index < _si_seed_map->size() ) + { track->set_silicon_seed( _si_seed_map->get(index)); } + } + } + + { + // tpc seed + auto* seed = track->get_tpc_seed(); + if( seed ) + { + auto index = find_seed_id( _tpc_seed_map, seed ); + if( index < _tpc_seed_map->size() ) + { track->set_tpc_seed( _tpc_seed_map->get(index)); } + } + } + + return true; +} + +//__________________________________________________________________________________ +int PHTrackTrackSeedSynchronization::End(PHCompositeNode * /*unused*/) +{ return Fun4AllReturnCodes::EVENT_OK; } + +//__________________________________________________________________________________ +int PHTrackTrackSeedSynchronization::GetNodes(PHCompositeNode *topNode) +{ + + // tracks + _svtx_track_map = findNode::getClass(topNode, _svtx_track_map_name); + if (!_svtx_track_map) + { + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name.c_str() << " not found on the node tree." << endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + // silicon seeds + _si_seed_map = findNode::getClass(topNode, _si_seed_map_name); + if (!_si_seed_map) + { + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name.c_str() << " not found on the node tree." << endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + // tpc seeds + _tpc_seed_map = findNode::getClass(topNode, _tpc_seed_map_name); + if (!_tpc_seed_map) + { + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name.c_str() << " not found on the node tree." << endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + diff --git a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h new file mode 100644 index 0000000000..56ecef6f56 --- /dev/null +++ b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h @@ -0,0 +1,61 @@ +#ifndef PHTRACKTRACKSEEDSYNCHRONIZATION_H +#define PHTRACKTRACKSEEDSYNCHRONIZATION_H + +#include +#include +#include + +#include +#include + +class PHCompositeNode; +class TrackSeedContainer; +class TrackSeed; +class SvtxTrackSeed; +class SvtxTrackMap; +class SvtxTrack; +class TrkrClusterContainer; +class TF1; +class TFile; +class TNtuple; + +class PHTrackTrackSeedSynchronization : public SubsysReco +{ + public: + + //! constructor + PHTrackTrackSeedSynchronization(const std::string& = "PHTrackTrackSeedSynchronization"); + + int InitRun(PHCompositeNode *topNode) override; + + int process_event(PHCompositeNode *) override; + + int End(PHCompositeNode *) override; + + //! input silicon seeds map name + void set_si_seed_map_name(const std::string &map_name) { _si_seed_map_name = map_name; } + + //! input tpc seeds map name + void set_tpc_seed_map_name(const std::string &map_name) { _tpc_seed_map_name = map_name; } + + //! input track map name + void set_svtx_track_map_name(const std::string &map_name) { _svtx_track_map_name = map_name; } + + private: + + int GetNodes(PHCompositeNode*); + + /// make sure that the track seed pointers stored in track correspond to those store in the seed containers + bool synchronize_track(SvtxTrack*) const; + + TrackSeedContainer *_tpc_seed_map{nullptr}; + TrackSeedContainer *_si_seed_map{nullptr}; + SvtxTrackMap *_svtx_track_map{nullptr}; + + std::string _tpc_seed_map_name = "TpcTrackSeedContainer"; + std::string _si_seed_map_name = "SiliconTrackSeedContainer"; + std::string _svtx_track_map_name = "SvtxTrackMap"; + +}; + +#endif // PHTrackTrackSeedSynchronization_H From 3dd346001ddd9f149402ffc1cb5e3766ed1afd25 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 16:26:42 -0400 Subject: [PATCH 691/866] added the possibility to ignore micromegas clusters when comparing track seeds. --- .../PHTrackTrackSeedSynchronization.cc | 84 ++++++++++--------- .../PHTrackTrackSeedSynchronization.h | 8 ++ 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc index 901e249f78..c55846ad5e 100644 --- a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc +++ b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc @@ -36,46 +36,6 @@ using namespace std; -namespace -{ - - /// find index of seed in container that matches argument seed - size_t find_seed_id( TrackSeedContainer* container, TrackSeed* source ) - { - // perform quick search - const size_t index = container->find( source ); - if( index < container->size() ) return index; - - // perform deep search based on cluster keys - using cluster_keyset_t=std::set; - - // get cluster key set from seed - auto get_cluster_keyset = []( TrackSeed* seed ) - { - cluster_keyset_t ckeys; - std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::inserter(ckeys, ckeys.end() ) ); - return ckeys; - }; - - const auto source_ckeys = get_cluster_keyset( source ); - - for( size_t i = 0; i < container->size(); ++i ) - { - auto* seed = container->get(i); - if( !seed ) continue; - - const auto ckeys = get_cluster_keyset( seed ); - if( ckeys == source_ckeys ) - { return i; } - } - - // error - std::cout << "find_seed_id - could not find seed " << source << " in container " << container << std::endl; - return container->size(); - } - -} - //____________________________________________________________________________.. PHTrackTrackSeedSynchronization::PHTrackTrackSeedSynchronization(const std::string &name) : SubsysReco(name) @@ -166,3 +126,47 @@ int PHTrackTrackSeedSynchronization::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } + +//__________________________________________________________________________________ +size_t PHTrackTrackSeedSynchronization::find_seed_id( TrackSeedContainer* container, TrackSeed* source ) const +{ + // perform quick search + const size_t index = container->find( source ); + if( index < container->size() ) return index; + + // perform deep search based on cluster keys + if( Verbosity() ) + { std::cout << "PHTrackTrackSeedSynchronization::find_seed_id - performing deep search for seed " << source << " in container " << container << std::endl; } + + using cluster_keyset_t=std::set; + + // get cluster key set from seed + auto get_cluster_keyset = [this]( TrackSeed* seed ) + { + cluster_keyset_t ckeys; + if( m_ignore_micromegas ) + { + std::copy_if( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::inserter(ckeys, ckeys.end() ), + []( const TrkrDefs::cluskey& ckey ) { return TrkrDefs::getTrkrId(ckey) != TrkrDefs::micromegasId; } ); + } else { + std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::inserter(ckeys, ckeys.end() ) ); + } + return ckeys; + + }; + + const auto source_ckeys = get_cluster_keyset( source ); + for( size_t i = 0; i < container->size(); ++i ) + { + auto* seed = container->get(i); + if( !seed ) continue; + + const auto ckeys = get_cluster_keyset( seed ); + if( ckeys == source_ckeys ) + { return i; } + } + + // error + std::cout << "PHTrackTrackSeedSynchronization::find_seed_id - could not find seed " << source << " in container " << container << std::endl; + return container->size(); +} diff --git a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h index 56ecef6f56..8e02a60b09 100644 --- a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h +++ b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h @@ -41,6 +41,9 @@ class PHTrackTrackSeedSynchronization : public SubsysReco //! input track map name void set_svtx_track_map_name(const std::string &map_name) { _svtx_track_map_name = map_name; } + //! ignore micromegas + void set_ignore_micromegas( bool value ) { m_ignore_micromegas = value; } + private: int GetNodes(PHCompositeNode*); @@ -48,6 +51,9 @@ class PHTrackTrackSeedSynchronization : public SubsysReco /// make sure that the track seed pointers stored in track correspond to those store in the seed containers bool synchronize_track(SvtxTrack*) const; + /// find index of seed in container that matches argument seed + size_t find_seed_id( TrackSeedContainer*, TrackSeed* ) const; + TrackSeedContainer *_tpc_seed_map{nullptr}; TrackSeedContainer *_si_seed_map{nullptr}; SvtxTrackMap *_svtx_track_map{nullptr}; @@ -56,6 +62,8 @@ class PHTrackTrackSeedSynchronization : public SubsysReco std::string _si_seed_map_name = "SiliconTrackSeedContainer"; std::string _svtx_track_map_name = "SvtxTrackMap"; + bool m_ignore_micromegas = false; + }; #endif // PHTrackTrackSeedSynchronization_H From 82a21d54f2e42f0230e55b546fab325efab550cc Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 16:43:51 -0400 Subject: [PATCH 692/866] Fixed typo Removed unnecessary c_str --- offline/packages/trackreco/PHTrackPruner.cc | 6 +++--- .../packages/trackreco/PHTrackTrackSeedSynchronization.cc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index e54298372f..fd5eb19e44 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -258,21 +258,21 @@ int PHTrackPruner::GetNodes(PHCompositeNode *topNode) _svtx_track_map = findNode::getClass(topNode, _svtx_track_map_name); if (!_svtx_track_map) { - cerr << PHWHERE << " ERROR: Can't find " << _svtx_track_map_name.c_str() << endl; + cerr << PHWHERE << " ERROR: Can't find " << _svtx_track_map_name << endl; return Fun4AllReturnCodes::ABORTEVENT; } _si_seed_map = findNode::getClass(topNode, _si_seed_map_name); if (!_si_seed_map) { - cerr << PHWHERE << " ERROR: Can't find " << _si_seed_map_name.c_str() << endl; + cerr << PHWHERE << " ERROR: Can't find " << _si_seed_map_name << endl; return Fun4AllReturnCodes::ABORTEVENT; } _tpc_seed_map = findNode::getClass(topNode, _tpc_seed_map_name); if (!_tpc_seed_map) { - cerr << PHWHERE << " ERROR: Can't find " << _tpc_seed_map_name.c_str() << endl; + cerr << PHWHERE << " ERROR: Can't find " << _tpc_seed_map_name << endl; return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc index c55846ad5e..4559c90619 100644 --- a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc +++ b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc @@ -103,7 +103,7 @@ int PHTrackTrackSeedSynchronization::GetNodes(PHCompositeNode *topNode) _svtx_track_map = findNode::getClass(topNode, _svtx_track_map_name); if (!_svtx_track_map) { - cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name.c_str() << " not found on the node tree." << endl; + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name << " not found on the node tree." << endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -111,7 +111,7 @@ int PHTrackTrackSeedSynchronization::GetNodes(PHCompositeNode *topNode) _si_seed_map = findNode::getClass(topNode, _si_seed_map_name); if (!_si_seed_map) { - cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name.c_str() << " not found on the node tree." << endl; + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _si_seed_map_name << " not found on the node tree." << endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -119,7 +119,7 @@ int PHTrackTrackSeedSynchronization::GetNodes(PHCompositeNode *topNode) _tpc_seed_map = findNode::getClass(topNode, _tpc_seed_map_name); if (!_tpc_seed_map) { - cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name.c_str() << " not found on the node tree." << endl; + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _tpc_seed_map_name << " not found on the node tree." << endl; return Fun4AllReturnCodes::ABORTEVENT; } From c00aec6f672bcbc6c027275c6d6f945fe03fb5c9 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 17 Jun 2026 16:47:33 -0400 Subject: [PATCH 693/866] check seed index validity before inserting as a good match. This prevents crash when seed pointers and maps are not synchronized --- offline/packages/trackreco/PHTrackPruner.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index fd5eb19e44..c4982f03e0 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -115,7 +115,7 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) return Fun4AllReturnCodes::EVENT_OK; } - std::multimap good_matches; + std::multimap good_matches; for (auto &iter : *_svtx_track_map) { @@ -132,13 +132,16 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) if (tpc_seed && si_seed) { if (Verbosity() > 1) { std::cout<<"Insert tpcid and siid into good_matches"<find(tpc_seed); - int siid = _si_seed_map->find(si_seed); - good_matches.insert(std::make_pair(tpcid, siid)); + const size_t tpcid = _tpc_seed_map->find(tpc_seed); + const size_t siid = _si_seed_map->find(si_seed); + + // check index validity + if( tpcid < _tpc_seed_map->size() && siid < _si_seed_map->size() ) + { good_matches.emplace(tpcid, siid); } } } - for (auto [tpcid, siid] : good_matches) + for (const auto& [tpcid, siid] : good_matches) { if (Verbosity() > 1) { std::cout<<"Insert pruned svtx seed map"<(); From ea9058b0671230c0aebd13ce1543f65217c70292 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 22 Sep 2025 10:52:39 -0400 Subject: [PATCH 694/866] added printing seed statistics for PHSeedPruner --- offline/packages/trackreco/PHTrackPruner.cc | 7 +++++++ offline/packages/trackreco/PHTrackPruner.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index c4982f03e0..e5f3c3bf33 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -117,6 +117,9 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) std::multimap good_matches; + // increment number of processed tracks + m_total_tracks += _svtx_track_map->size(); + for (auto &iter : *_svtx_track_map) { auto* svtx_track = iter.second; @@ -125,7 +128,9 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) { continue; } + if (Verbosity() > 1) { std::cout<<"Pass track selection"<get_tpc_seed(); auto* si_seed = svtx_track->get_silicon_seed(); @@ -249,6 +254,8 @@ bool PHTrackPruner::checkTrack(SvtxTrack *track) int PHTrackPruner::End(PHCompositeNode * /*unused*/) { + std::cout << "PHTrackPruner::End - m_total_tracks: " << m_total_tracks << std::endl; + std::cout << "PHTrackPruner::End - m_accepted_tracks: " << m_accepted_tracks << " fraction: " << double(m_accepted_tracks)/m_total_tracks << std::endl; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/trackreco/PHTrackPruner.h b/offline/packages/trackreco/PHTrackPruner.h index ffe4007d60..5ed234b39d 100644 --- a/offline/packages/trackreco/PHTrackPruner.h +++ b/offline/packages/trackreco/PHTrackPruner.h @@ -97,6 +97,10 @@ class PHTrackPruner : public SubsysReco int m_ntpc_states_low_cut = 35; int m_ntpot_states_low_cut = 2; + //! keep track of track/seed statistics + unsigned long m_total_tracks = 0; + unsigned long m_accepted_tracks = 0; + }; #endif // PHTRACKPRUNER_H From bc5af2c638dea12aa7b3a5a2578695ce6c1a7a60 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 14:40:30 -0400 Subject: [PATCH 695/866] added high pt cut, disabled by default. --- offline/packages/trackreco/PHTrackPruner.cc | 9 ++++++++- offline/packages/trackreco/PHTrackPruner.h | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index e5f3c3bf33..a7b2fecc47 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -189,13 +189,20 @@ bool PHTrackPruner::checkTrack(SvtxTrack *track) return false; } - //pt cut + // low pt cut if(track->get_pt() < m_track_pt_low_cut) { if (Verbosity() > 1) { std::cout<<"Track pt "<get_pt()<<" , pt cut "<0 && track->get_pt() < m_track_pt_high_cut) + { + if (Verbosity() > 1) { std::cout<<"Track pt "<get_pt()<<" , pt cut "<get_quality() > m_track_quality_high_cut) { diff --git a/offline/packages/trackreco/PHTrackPruner.h b/offline/packages/trackreco/PHTrackPruner.h index 5ed234b39d..ad71782ca5 100644 --- a/offline/packages/trackreco/PHTrackPruner.h +++ b/offline/packages/trackreco/PHTrackPruner.h @@ -52,6 +52,11 @@ class PHTrackPruner : public SubsysReco /// low pt cut void set_track_pt_low_cut(const double val) { m_track_pt_low_cut = val; } + + /// high pt cut. + /** enforced only if >0 */ + void set_track_pt_high_cut(const double val) { m_track_pt_high_cut = val; } + void set_track_quality_high_cut(const double val) { m_track_quality_high_cut = val; } void set_nmvtx_clus_low_cut(const int n) { m_nmvtx_clus_low_cut = n; } @@ -85,7 +90,13 @@ class PHTrackPruner : public SubsysReco std::string _pruned_svtx_seed_map_name = "PrunedSvtxTrackSeedContainer"; std::string _svtx_track_map_name = "SvtxTrackMap"; + /// low pt cut double m_track_pt_low_cut = 0.5; + + /// high pt cut. + /** enforced only if >0 */ + double m_track_pt_high_cut = 0.; + double m_track_quality_high_cut = 100; int m_nmvtx_clus_low_cut = 3; int m_nintt_clus_low_cut = 2; From c872f84fd0c540b2d32e4c081b9265b559fa129a Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 18 Jun 2026 10:18:15 -0400 Subject: [PATCH 696/866] removed using namespace std --- offline/packages/trackreco/PHTrackPruner.cc | 74 ++++++++++----------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index a7b2fecc47..12816dc596 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -34,8 +34,6 @@ #include // for _Rb_tree_const_iterator #include // for pair -using namespace std; - namespace { //! get cluster keys from a given track @@ -104,10 +102,10 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) if (Verbosity() > 0) { - cout << PHWHERE << " TPC seed map size " << _tpc_seed_map->size() - << " Silicon seed map size " << _si_seed_map->size() - << " Svtx track map size " << _svtx_track_map->size() - << endl; + std::cout << PHWHERE << " TPC seed map size " << _tpc_seed_map->size() + << " Silicon seed map size " << _si_seed_map->size() + << " Svtx track map size " << _svtx_track_map->size() + << std::endl; } if (_svtx_track_map->size() == 0) @@ -129,26 +127,28 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) continue; } - if (Verbosity() > 1) { std::cout<<"Pass track selection"< 1) { std::cout <<"Pass track selection"<get_tpc_seed(); auto* si_seed = svtx_track->get_silicon_seed(); if (tpc_seed && si_seed) { - if (Verbosity() > 1) { std::cout<<"Insert tpcid and siid into good_matches"< 1) { std::cout <<"Insert tpcid and siid into good_matches"<find(tpc_seed); const size_t siid = _si_seed_map->find(si_seed); // check index validity if( tpcid < _tpc_seed_map->size() && siid < _si_seed_map->size() ) - { good_matches.emplace(tpcid, siid); } + { + good_matches.emplace(tpcid, siid); + ++m_accepted_tracks; + } } } for (const auto& [tpcid, siid] : good_matches) { - if (Verbosity() > 1) { std::cout<<"Insert pruned svtx seed map"< 1) { std::cout <<"Insert pruned svtx seed map"<(); _svtx_seed->set_silicon_seed_index(siid); _svtx_seed->set_tpc_seed_index(tpcid); @@ -160,13 +160,13 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) if (Verbosity() > 1) { - std::cout << " combined seed id " << _pruned_svtx_seed_map->size() - 1 << " si id " << siid << " tpc id " << tpcid << " crossing estimate " << crossing_estimate << std::endl; + std::cout << " combined seed id " << _pruned_svtx_seed_map->size() - 1 << " si id " << siid << " tpc id " << tpcid << " crossing estimate " << crossing_estimate << std::endl; } } if (Verbosity() > 0) { - std::cout << "final svtx seed map size " << _pruned_svtx_seed_map->size() << std::endl; + std::cout << "final svtx seed map size " << _pruned_svtx_seed_map->size() << std::endl; } if (Verbosity() > 1) @@ -176,7 +176,7 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) seed->identify(); } - cout << "PHTrackPruner::process_event(PHCompositeNode *topNode) Leaving process_event" << endl; + std::cout << "PHTrackPruner::process_event(PHCompositeNode *topNode) Leaving process_event" << std::endl; } return Fun4AllReturnCodes::EVENT_OK; } @@ -185,28 +185,28 @@ bool PHTrackPruner::checkTrack(SvtxTrack *track) { if(!track) { - if (Verbosity() > 1) { std::cout<<"invalid track"< 1) { std::cout <<"invalid track"<get_pt() < m_track_pt_low_cut) { - if (Verbosity() > 1) { std::cout<<"Track pt "<get_pt()<<" , pt cut "< 1) { std::cout <<"Track pt "<get_pt()<<" , pt cut "<0 && track->get_pt() < m_track_pt_high_cut) { - if (Verbosity() > 1) { std::cout<<"Track pt "<get_pt()<<" , pt cut "< 1) { std::cout <<"Track pt "<get_pt()<<" , pt cut "<get_quality() > m_track_quality_high_cut) { - if (Verbosity() > 1) { std::cout<<"Track quality "<get_quality()<<" , quality cut "< 1) { std::cout <<"Track quality "<get_quality()<<" , quality cut "<(cluster_keys) < m_nmvtx_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmvtx "<(cluster_keys)<<" , nmvtx cut "< 1) { std::cout <<"nmvtx "<(cluster_keys)<<" , nmvtx cut "<(cluster_keys) < m_nintt_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"nintt "<(cluster_keys)<<" , nintt cut "< 1) { std::cout <<"nintt "<(cluster_keys)<<" , nintt cut "<(cluster_keys) < m_ntpc_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"ntpc "<(cluster_keys)<<" , ntpc cut "< 1) { std::cout <<"ntpc "<(cluster_keys)<<" , ntpc cut "<(cluster_keys) < m_ntpot_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmicromegas "<(cluster_keys)<<" , nmicromegas cut "< 1) { std::cout <<"nmicromegas "<(cluster_keys)<<" , nmicromegas cut "<(state_keys) < m_nmvtx_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmvtxstates "<(state_keys)<<" , nmvtxstates cut "< 1) { std::cout <<"nmvtxstates "<(state_keys)<<" , nmvtxstates cut "<(state_keys) < m_nintt_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"ninttstates "<(state_keys)<<" , ninttstates cut "< 1) { std::cout <<"ninttstates "<(state_keys)<<" , ninttstates cut "<(state_keys) < m_ntpc_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"ntpcstates "<(state_keys)<<" , ntpcstates cut "< 1) { std::cout <<"ntpcstates "<(state_keys)<<" , ntpcstates cut "<(state_keys) < m_ntpot_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmicromegasstates "<(state_keys)<<" , nmicromegasstates cut "< 1) { std::cout <<"nmicromegasstates "<(state_keys)<<" , nmicromegasstates cut "<(topNode, _svtx_track_map_name); if (!_svtx_track_map) { - cerr << PHWHERE << " ERROR: Can't find " << _svtx_track_map_name << endl; + std::cout << PHWHERE << " ERROR: Can't find " << _svtx_track_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _si_seed_map = findNode::getClass(topNode, _si_seed_map_name); if (!_si_seed_map) { - cerr << PHWHERE << " ERROR: Can't find " << _si_seed_map_name << endl; + std::cout << PHWHERE << " ERROR: Can't find " << _si_seed_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _tpc_seed_map = findNode::getClass(topNode, _tpc_seed_map_name); if (!_tpc_seed_map) { - cerr << PHWHERE << " ERROR: Can't find " << _tpc_seed_map_name << endl; + std::cout << PHWHERE << " ERROR: Can't find " << _tpc_seed_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _pruned_svtx_seed_map = findNode::getClass(topNode, _pruned_svtx_seed_map_name); if (!_pruned_svtx_seed_map) { - std::cout << "Creating node " << _pruned_svtx_seed_map_name << std::endl; + std::cout << "Creating node " << _pruned_svtx_seed_map_name << std::endl; /// Get the DST Node PHNodeIterator iter(topNode); PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); @@ -327,14 +327,14 @@ int PHTrackPruner::GetNodes(PHCompositeNode *topNode) _cluster_map = findNode::getClass(topNode, _cluster_map_name); if (!_cluster_map) { - std::cout << PHWHERE << " ERROR: Can't find node " << _cluster_map_name << std::endl; + std::cout << PHWHERE << " ERROR: Can't find node " << _cluster_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _tGeometry = findNode::getClass(topNode, "ActsGeometry"); if (!_tGeometry) { - std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl; + std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -356,7 +356,7 @@ short int PHTrackPruner::findCrossingGeometrically(unsigned int tpcid, unsigned if (Verbosity() > 1) { - std::cout << "findCrossing: " + std::cout << "findCrossing: " << " tpcid " << tpcid << " si_id " << si_id << " tpc_z " << tpc_z << " si_z " << si_z << " dz " << tpc_z - si_z << " INTT crossing " << crossing << " crossing_estimate " << crossing_estimate << std::endl; } @@ -398,7 +398,7 @@ double PHTrackPruner::getBunchCrossing(unsigned int trid, double z_mismatch) if (side_set.size() == 2 && Verbosity() > 1) { - std::cout << " WARNING: tpc seed " << trid << " changed TPC sides, " + std::cout << " WARNING: tpc seed " << trid << " changed TPC sides, " << " final side " << side << std::endl; } @@ -411,7 +411,7 @@ double PHTrackPruner::getBunchCrossing(unsigned int trid, double z_mismatch) if (Verbosity() > 1) { - std::cout << " gettrackid " << trid << " side " << side << " z_mismatch " << z_mismatch << " crossings " << crossings << std::endl; + std::cout << " gettrackid " << trid << " side " << side << " z_mismatch " << z_mismatch << " crossings " << crossings << std::endl; } return crossings; From 8550c30745f72cda52892d1dc1f3dc96ac4aa0eb Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Fri, 19 Jun 2026 13:26:04 -0400 Subject: [PATCH 697/866] Option for v5 vs v6. --- offline/packages/tpc/TpcClusterizer.cc | 13 ++++++++++++- offline/packages/tpc/TpcClusterizer.h | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 5e0d58e112..28a6ea7a9a 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -907,7 +907,18 @@ 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 TrkrClusterv6; + TrkrCluster* clus = nullptr; + + if (m_debug) + { + clus = new TrkrClusterv6; + } + else + { + clus = new TrkrClusterv5; + } + + // auto *clus = new TrkrClusterv6; // auto *clus = new TrkrClusterv5; // auto clus = std::make_unique(); clus_base = clus; diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index 801207654e..c566f5b4f8 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -91,6 +91,11 @@ class TpcClusterizer : public SubsysReco m_hotChannelMapName = hmap; } + void DetailedClusterAnalysis() + { + m_debug = true; + } + private: bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; @@ -135,6 +140,7 @@ class TpcClusterizer : public SubsysReco bool m_maskDeadChannels {false}; bool m_maskHotChannels {false}; bool m_maskFromFile {false}; + bool m_debug{false}; std::string m_deadChannelMapName; std::string m_hotChannelMapName; }; From d8866f95015265f7247127de1b7cd5ab12a2393e Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Sat, 20 Jun 2026 01:15:46 -0400 Subject: [PATCH 698/866] Implements the ability to tilt the TPC envelope in sPHENIX, and attempts to handle the fallout in the simulation and reconstruction code. --- .../TrackingDiagnostics/TrackResiduals.cc | 4 +- offline/packages/tpc/TpcClusterMover.cc | 19 +- offline/packages/tpc/TpcClusterMover.h | 4 +- offline/packages/tpc/TpcClusterizer.cc | 42 +- offline/packages/trackbase/ActsGeometry.cc | 104 ++- offline/packages/trackbase/ActsGeometry.h | 6 + .../trackbase/AlignmentTransformation.cc | 41 +- .../trackbase_historic/TrackAnalysisUtils.cc | 7 +- .../packages/trackreco/MakeActsGeometry.cc | 82 ++- offline/packages/trackreco/MakeActsGeometry.h | 4 + offline/packages/trackreco/MakeSourceLinks.cc | 6 +- offline/packages/trackreco/MakeSourceLinks.h | 2 +- offline/packages/trackreco/PHActsTrkFitter.cc | 2 +- .../packages/trackreco/PHCosmicsTrkFitter.cc | 4 +- .../g4simulation/g4detectors/Makefile.am | 3 + .../g4simulation/g4detectors/PHG4TpcGeom.h | 53 +- .../g4simulation/g4detectors/PHG4TpcGeomv2.cc | 593 ++++++++++++++++++ .../g4simulation/g4detectors/PHG4TpcGeomv2.h | 158 +++++ .../g4detectors/PHG4TpcGeomv2LinkDef.h | 5 + .../g4simulation/g4eval/SvtxTruthEval.cc | 44 +- .../g4simulation/g4tpc/PHG4TpcDetector.cc | 39 +- .../g4tpc/PHG4TpcElectronDrift.cc | 25 +- .../g4simulation/g4tpc/PHG4TpcElectronDrift.h | 1 + .../g4simulation/g4tpc/TpcClusterBuilder.cc | 4 +- 24 files changed, 1130 insertions(+), 122 deletions(-) create mode 100644 simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc create mode 100644 simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h create mode 100644 simulation/g4simulation/g4detectors/PHG4TpcGeomv2LinkDef.h diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 1a5a69fae0..9c9a09f651 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -115,7 +115,9 @@ int TrackResiduals::InitRun(PHCompositeNode* topNode) m_globalPositionWrapper.set_suppressCrossing(m_convertSeeds); // clusterMover needs the correct radii of the TPC layers auto *tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); - m_clusterMover.initialize_geometry(tpccellgeo); + + auto *geometry = findNode::getClass(topNode, "ActsGeometry"); + m_clusterMover.initialize_geometry(tpccellgeo, geometry); m_clusterMover.set_verbosity(0); auto *se = Fun4AllServer::instance(); diff --git a/offline/packages/tpc/TpcClusterMover.cc b/offline/packages/tpc/TpcClusterMover.cc index 39c5e156d4..d1f391b9ea 100644 --- a/offline/packages/tpc/TpcClusterMover.cc +++ b/offline/packages/tpc/TpcClusterMover.cc @@ -45,13 +45,16 @@ TpcClusterMover::TpcClusterMover() } } -void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer* cellgeo) +void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer* cellgeo, ActsGeometry *tGeometry) { if (_verbosity > 0) { std::cout << "TpcClusterMover: Initializing layer radii for Tpc from cell geometry object" << std::endl; } + + _tGeometry = tGeometry; + int layer = 0; PHG4TpcGeomContainer::ConstRange layerrange = cellgeo->get_begin_end(); for (PHG4TpcGeomContainer::ConstIterator layeriter = layerrange.first; @@ -67,8 +70,9 @@ void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer* cellgeo) 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 - + // The input object contains all clusters for the track in world coordinates + // The surface radii are in envelope coordinates, we transform the positions to envelope coordinates + std::vector> global_moved; std::vector tpc_global_vec; @@ -80,7 +84,8 @@ std::vector> TpcClusterMover::proces if (trkrid == TrkrDefs::tpcId) { tpc_cluskey_vec.push_back(ckey); - tpc_global_vec.push_back(global); + Acts::Vector3 env_global = _tGeometry->transformTpcWorldToEnvelope(global); + tpc_global_vec.push_back(env_global); } else { @@ -140,9 +145,9 @@ std::vector> TpcClusterMover::proces // now move the cluster to the surface radius // we keep the cluster key fixed, change the surface if necessary - Acts::Vector3 global_new(xnew, ynew, znew); - - // add the new position and surface to the return object + Acts::Vector3 env_global_new(xnew, ynew, znew); + // now we transform back to global coordinates and add the new position and surface to the return object + Acts::Vector3 global_new = _tGeometry->transformTpcEnvelopeToWorld(env_global_new); global_moved.emplace_back(cluskey, global_new); if (_verbosity > 2) diff --git a/offline/packages/tpc/TpcClusterMover.h b/offline/packages/tpc/TpcClusterMover.h index 92a053e990..7eaa0b3495 100644 --- a/offline/packages/tpc/TpcClusterMover.h +++ b/offline/packages/tpc/TpcClusterMover.h @@ -24,7 +24,7 @@ class TpcClusterMover //! Updates the assumed default geometry below to that contained in the //! cell geo - void initialize_geometry(PHG4TpcGeomContainer *cellgeo); + void initialize_geometry(PHG4TpcGeomContainer *cellgeo, ActsGeometry *tGeometry); private: int get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y) const; @@ -48,6 +48,8 @@ class TpcClusterMover double outer_tpc_spacing = 0.0; int _verbosity = 0; + + ActsGeometry *_tGeometry = nullptr; }; #endif diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 687d5b58f9..a9ec66a219 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -29,7 +29,8 @@ #include #include // for SubsysReco -#include +//#include +#include #include #include @@ -657,30 +658,29 @@ namespace } } - // This is the global position + // This is the phi position in the tpc_envelope double clusiphi = iphi_sum / adc_sum; - double clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); + double env_clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); - double clusx = radius * cos(clusphi); - double clusy = radius * sin(clusphi); + // these positions are in the tpc_envelope + double env_clusx = radius * cos(env_clusphi); + double env_clusy = radius * sin(env_clusphi); double clust = t_sum / adc_sum; // needed for surface identification double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); // convert z drift length to z position in the TPC - double clusz = my_data.m_tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; + double env_clusz = my_data.m_tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; if (my_data.side == 0) { - clusz = -clusz; + env_clusz = -env_clusz; } - // std::cout << " side " << my_data.side << " clusz " << clusz << " clust " << clust << " driftmax " << my_data.m_tdriftmax << std::endl; const double phi_cov = (iphi2_sum / adc_sum - square(clusiphi)) * pow(my_data.layergeom->get_phistep(), 2); const double t_cov = t2_sum / adc_sum - square(clust); - // Get the surface key to find the surface from the - // TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); - Acts::Vector3 global(clusx, clusy, clusz); + // get_tpc_surface_from_coords expects a world global position + Acts::Vector3 env_global(env_clusx, env_clusy, env_clusz); + Acts::Vector3 global = my_data.tGeometry->transformTpcEnvelopeToWorld(env_global); TrkrDefs::subsurfkey subsurfkey = 0; - Surface surface = my_data.tGeometry->get_tpc_surface_from_coords( tpcHitSetKey, global, @@ -693,6 +693,8 @@ namespace hitkeyvec.clear(); return; } + // Acts::Vector3 surfcent = surface->center(my_data.tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm; + // std::cout << " surf center = " << surfcent.x() << " " << surfcent.y() << " " << surfcent.z() << std::endl; // Estimate the errors // Blow up error on single pixel clusters by a factor 3 to compensate for threshold effects @@ -744,6 +746,7 @@ namespace b_made_cluster = true; } + // This code needs to be reviewed in case of a non-zero TPC tilt - ADF 6/16/26 if (use_nn && clus_base && training_hits) { try @@ -1298,16 +1301,11 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) AdcClockPeriod = geom->GetFirstLayerCellGeom()->get_zstep(); - std::cout << "FirstLayerCellGeomv1 streamer: " << std::endl; - 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 = 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 = static_cast (geom->GetLayerCellGeom(40)); // cast because << not in the base class - std::cout << *g3 << std::endl; - + // the identify now contains all information from the streamer for v2 + geom->GetFirstLayerCellGeom()->identify(); + geom->GetLayerCellGeom(24)->identify(); + geom->GetLayerCellGeom(40)->identify(); + if (m_maskDeadChannels) { m_deadChannelMap.clear(); diff --git a/offline/packages/trackbase/ActsGeometry.cc b/offline/packages/trackbase/ActsGeometry.cc index 8096be1896..bac8fdf558 100644 --- a/offline/packages/trackbase/ActsGeometry.cc +++ b/offline/packages/trackbase/ActsGeometry.cc @@ -7,6 +7,10 @@ #include +#include +#include +#include + namespace { /// square @@ -149,9 +153,16 @@ Surface ActsGeometry::get_tpc_surface_from_coords( Acts::Vector3 world, TrkrDefs::subsurfkey& subsurfkey) const { + // Assume that the world coordinates are in the sPHENIX frame, where the TPC is tilted + // We convert the position to tpc envelope coordinates, where we know where everything is + Acts::Vector3 world_envelope = transformTpcWorldToEnvelope(world); + double world_phi = atan2(world_envelope[1], world_envelope[0]); + unsigned int layer = TrkrDefs::getLayer(hitsetkey); unsigned int side = TpcDefs::getSide(hitsetkey); - + unsigned int sector = TpcDefs::getSectorId(hitsetkey); + + // returns an iterator to all of the surfaces for this layer auto mapIter = m_surfMaps.m_tpcSurfaceMap.find(layer); if (mapIter == m_surfMaps.m_tpcSurfaceMap.end()) @@ -160,11 +171,42 @@ Surface ActsGeometry::get_tpc_surface_from_coords( << hitsetkey << std::endl; return nullptr; } - double world_phi = atan2(world[1], world[0]); const auto& surf_vec = mapIter->second; unsigned int surf_index = 999; + // Apparently, tilting the TPC leads to the surfaces not being sorted in phi in the outer layers + // just test all surfaces in each layer for now + for(unsigned int isurf = 0; isurf < surf_vec.size(); ++isurf) + { + Surface this_surf = surf_vec[isurf]; + auto surf_center = this_surf->center(m_tGeometry.getGeoContext()); + surf_center /= 10.0; // convert from mm to cm + //this surface center includes the TPC tilt used in PHG4TpcDetector construction, transform it to tpc envelope coordinates + Acts::Vector3 surf_center_envelope = transformTpcWorldToEnvelope(surf_center); + double surf_phi = atan2(surf_center_envelope[1], surf_center_envelope[0]); + double surfStepPhi = m_tGeometry.tpcSurfStepPhi; + + if ((world_phi > surf_phi - surfStepPhi / 2.0) && (world_phi < surf_phi + surfStepPhi / 2.0)) + { + if(surf_center.z() < 0 && side != 0) { continue; } + if(surf_center.z() > 0 && side != 1) { continue; } + surf_index = isurf; + subsurfkey = isurf; + break; + } + } + + if(surf_index == 999) + { + std::cout << "Error: surface not found in ActsGeometry::get_tpc_surface_from_coords " + << " layer " << layer << " side " << side << " sector " << sector << " world_phi " << world_phi << " world[0] " << world[0] << " world[1] " << world[1] << " hitsetkey " << hitsetkey << std::endl; + return nullptr; + } + + return surf_vec[surf_index]; + + /* // Predict which surface index this phi and side will correspond to // assumes that the vector elements are ordered positive z, -pi to pi, then negative z, -pi to pi // we use TPC side from the hitsetkey, since z can be either sign in north and south, depending on crossing @@ -172,33 +214,38 @@ Surface ActsGeometry::get_tpc_surface_from_coords( double rounded_nsurf = std::round((double) (surf_vec.size() / 2) * fraction - 0.5); // NOLINT unsigned int nsurfm = (unsigned int) rounded_nsurf; - + std::cout << " surf_vec.size " << surf_vec.size() << " rounded_nsurf " << rounded_nsurf << " initial nsurfm " << nsurfm << std::endl; + if (side == 0) { nsurfm += surf_vec.size() / 2; } unsigned int nsurf = nsurfm % surf_vec.size(); Surface this_surf = surf_vec[nsurf]; - //std::cout << " world_phi " << world_phi << " fraction " << fraction << " rounded_nsurf " << rounded_nsurf << " nsurfm " << nsurfm << " nsurf " << nsurf << std::endl; - - auto vec3d = this_surf->center(m_tGeometry.getGeoContext()); - std::vector surf_center = {vec3d(0) / 10.0, vec3d(1) / 10.0, vec3d(2) / 10.0}; // convert from mm to cm - double surf_phi = atan2(surf_center[1], surf_center[0]); + auto surf_center = this_surf->center(m_tGeometry.getGeoContext()); + surf_center /= 10.0; // convert from mm to cm + //this surface center is from the default geometry, which includes the TPC tilt used in PHG4TpcDetector construction + // transform it to tpc envelope coordinates + Acts::Vector3 surf_center_envelope = m_tpc_world_envelope_transform * surf_center; + + double surf_phi = atan2(surf_center_envelope[1], surf_center_envelope[0]); double surfStepPhi = m_tGeometry.tpcSurfStepPhi; - // std::cout << " surf_phi " << surf_phi << " surfStepPhi " << surfStepPhi << " nsurf " << nsurf << std::endl; - if ((world_phi > surf_phi - surfStepPhi / 2.0 && world_phi < surf_phi + surfStepPhi / 2.0)) + if ((world_phi > surf_phi - surfStepPhi / 2.0) && (world_phi < surf_phi + surfStepPhi / 2.0)) { surf_index = nsurf; subsurfkey = nsurf; + std::cout << "success, found nsurf = " << nsurf << std::endl; } else { // check for the periodic boundary condition auto firstsurf = *surf_vec.begin(); - auto firstsurfcenter = firstsurf->center(geometry().getGeoContext()); - float firstsurf_phi = atan2(firstsurfcenter[1], firstsurfcenter[0]); - if (world_phi < firstsurf_phi - surfStepPhi / 2.0) + auto firstsurfcenter = firstsurf->center(m_tGeometry.getGeoContext()); + firstsurfcenter /= 10.0; + auto firstsurfcenter_envelope = m_tpc_world_envelope_transform * firstsurfcenter; + double firstsurf_phi = atan2(firstsurfcenter_envelope[1], firstsurfcenter_envelope[0]); + if (world_phi < -M_PI) { world_phi += 2.0 * M_PI; } @@ -211,12 +258,16 @@ Surface ActsGeometry::get_tpc_surface_from_coords( } unsigned int new_nsurf = (nsurf+i) % surf_vec.size(); this_surf = surf_vec[new_nsurf]; - vec3d = this_surf->center(geometry().getGeoContext()); - surf_center = {vec3d(0) / 10.0, vec3d(1) / 10.0, vec3d(2) / 10.0}; // convert from mm to cm - surf_phi = atan2(surf_center[1], surf_center[0]); - //std::cout << " new world_phi " << world_phi << " new surf_phi " << surf_phi << " new_nsurf " << new_nsurf << std::endl; - if ((world_phi > surf_phi - surfStepPhi / 2.0 && world_phi < surf_phi + surfStepPhi / 2.0)) + surf_center = this_surf->center(m_tGeometry.getGeoContext()); + surf_center /= 10.0; + surf_center_envelope = m_tpc_world_envelope_transform * surf_center; + surf_phi = atan2(surf_center_envelope[1], surf_center_envelope[0]); + double this_philow = surf_phi - surfStepPhi / 2.0; + double this_phihigh = surf_phi + surfStepPhi / 2.0; + + if ((world_phi > this_philow) && (world_phi < this_phihigh)) { + std::cout << "success, found nsurf = " << new_nsurf << std::endl; surf_index = new_nsurf; subsurfkey = new_nsurf; return surf_vec[surf_index]; @@ -224,8 +275,9 @@ Surface ActsGeometry::get_tpc_surface_from_coords( } return nullptr; } + */ + - return surf_vec[surf_index]; } //________________________________________________________________________________________________ @@ -291,3 +343,17 @@ Acts::Vector2 ActsGeometry::getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* c return local; } + + Acts::Vector3 ActsGeometry::transformTpcWorldToEnvelope(Acts::Vector3 world) const + { + Acts::Vector3 envelope = m_tpc_world_envelope_transform * world; + + return envelope; + } + + Acts::Vector3 ActsGeometry::transformTpcEnvelopeToWorld(Acts::Vector3 envelope) const + { + Acts::Vector3 world = m_tpc_world_envelope_transform.inverse() * envelope; + + return world; + } diff --git a/offline/packages/trackbase/ActsGeometry.h b/offline/packages/trackbase/ActsGeometry.h index df391d98bb..d92bf4af38 100644 --- a/offline/packages/trackbase/ActsGeometry.h +++ b/offline/packages/trackbase/ActsGeometry.h @@ -51,6 +51,7 @@ class ActsGeometry void set_CM_halfwidth(double val) { _CM_halfwidth = val; } void set_tpc_tzero(double tz) { _tpc_tzero = tz; } void set_sampa_tzero_bias(double tzb) { _sampa_tzero_bias = tzb; } + void set_tpc_world_envelope_transform(Acts::Transform3 transf) { m_tpc_world_envelope_transform = transf; } double get_tpc_tzero() const { return _tpc_tzero; } double get_sampa_tzero_bias() const { return _sampa_tzero_bias; } @@ -77,12 +78,17 @@ class ActsGeometry Acts::Transform3 makeAffineTransform(Acts::Vector3 rotation, Acts::Vector3 translation) const; + Acts::Vector3 transformTpcWorldToEnvelope(Acts::Vector3 vin) const ; + Acts::Vector3 transformTpcEnvelopeToWorld(Acts::Vector3 vin) const ; + Acts::Vector2 getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* cluster) const; Acts::Vector2 getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* cluster, short int crossing) const; private: ActsTrackingGeometry m_tGeometry; ActsSurfaceMaps m_surfMaps; + Acts::Transform3 m_tpc_world_envelope_transform; + Acts::Transform3 m_tpc_envelope_world_transform; double _drift_velocity = 8.0e-3; // cm/ns double _max_driftlength = 102.235; // cm double _CM_halfwidth = 0.28; // cm diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 171d9684ac..78078b0fbc 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -254,14 +254,14 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) unsigned int side = TpcDefs::getSide(hitsetkey); unsigned int sector = TpcDefs::getSectorId(hitsetkey); - // std::cout << "New module hitsetkey " << hitsetkey << "test_layer " << test_layer << " side " << side << " sector " << sector << " nlayers " << nlayers << " layer_begin " << layer_begin << std::endl; + // std::cout << "New module hitsetkey " << hitsetkey << "test_layer " << test_layer << " side " << side << " sector " << sector << " nlayers " << nlayers << " layer_begin " << layer_begin << std::endl; // loop over layers in module for (unsigned int this_layer = layer_begin; this_layer < layer_begin + nlayers; ++this_layer) { TrkrDefs::hitsetkey this_hitsetkey = TpcDefs::genHitSetKey(this_layer, sector, side); - // std::cout << " *** module hitsetkey " << hitsetkey << " this_hitsetkey " << this_hitsetkey << " this layer " << this_layer << " side " << side << " sector " << sector << std::endl; + // std::cout << " *** module hitsetkey " << hitsetkey << " this_hitsetkey " << this_hitsetkey << " this layer " << this_layer << " side " << side << " sector " << sector << std::endl; // is this correct?????? int subsurfkey_min = (1 - side) * 144 + (144 - sector * 12) - 12 - 6; @@ -643,26 +643,24 @@ void AlignmentTransformation::extractModuleCenterPositions() for (int isector = 0; isector < 12; ++isector) { - double sectorphi = sectorPhi[iside][iregion]; + double sectorphi = sectorPhi[iside][isector]; TrkrDefs::hitsetkey hitsetkey_in = TpcDefs::genHitSetKey(lin, isector, iside); - if (localVerbosity) - { - std::cout << " hitsetkey_in " << hitsetkey_in << " lin " << lin << " sector " << isector << " side " << iside << " region " << iregion << std::endl; - } - double surf_rad_in = extractModuleCenter(hitsetkey_in, sectorphi); + double surf_rad_in = extractModuleCenter(hitsetkey_in, sectorphi); TrkrDefs::hitsetkey hitsetkey_out = TpcDefs::genHitSetKey(lout, isector, iside); - double surf_rad_out = extractModuleCenter(hitsetkey_out, sectorphi); + double surf_rad_out = extractModuleCenter(hitsetkey_out, sectorphi); + double mod_radius = (surf_rad_in + surf_rad_out) / 2.0; - TpcModuleRadii[iside][isector][iregion] = mod_radius; - if (localVerbosity) - { - std::cout << " hitsetkey_out " << hitsetkey_out << " lout " << lout << " sector " << isector << " side " << iside - << " region " << iregion << " module radius " << mod_radius << std::endl; - } + if (localVerbosity) + { + std::cout << " hitsetkey_in " << hitsetkey_in << " lin " << lin << " sector " << isector << " side " << iside << " region " << iregion << std::endl; + std::cout << " hitsetkey_out " << hitsetkey_out << " lout " << lout << " sector " << isector << " side " << iside << " region " << iregion << std::endl; + std::cout << " module radius " << mod_radius << std::endl; + } + } } } @@ -670,7 +668,7 @@ void AlignmentTransformation::extractModuleCenterPositions() double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetkey, double sectorphi) { - // We want the module center position from the ideal geometry + // We want the module center position from the ideal geometry in the tpc envelope frame // the radius and z are not used, only the phi value double x = std::cos(sectorphi + 0.01) * 10.0; @@ -680,7 +678,12 @@ double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetke Acts::Vector3 world(x, y, z); TrkrDefs::subsurfkey subsurfkey = 0; - Surface surface = m_tGeometry->get_tpc_surface_from_coords(hitsetkey, world, subsurfkey); + // std::cout << "extractModuleCenter: sectorphi " << sectorphi << " world " << world(0) << " " << world(1) << " " << world(2) << std::endl; + + // Note: the "world" position here is in pre-tilt tpc envelope coordinates, not global coordinates + // But, get_tpc_surface_from_coords() expects a global position as input, so we convert to world coordinates + Acts::Vector3 world_envelope = m_tGeometry->transformTpcEnvelopeToWorld(world); + Surface surface = m_tGeometry->get_tpc_surface_from_coords(hitsetkey, world_envelope, subsurfkey); if (!surface) { std::cout << PHWHERE << "Failed to find surface, quit " << std::endl; @@ -689,7 +692,9 @@ double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetke Eigen::Vector3d surf_center = surface->center(m_tGeometry->geometry().getGeoContext()); surf_center /= 10.0; // convert from mm to cm - double surf_radius = std::sqrt(surf_center[0] * surf_center[0] + surf_center[1] * surf_center[1]); + // convert to tpc envelope coords + Acts::Vector3 surf_center_envelope = m_tGeometry->transformTpcWorldToEnvelope(surf_center); + double surf_radius = std::sqrt(surf_center_envelope[0] * surf_center_envelope[0] + surf_center_envelope[1] * surf_center_envelope[1]); return surf_radius; } diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index f7dbbb2b80..49bbd418bb 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -308,13 +308,14 @@ namespace TrackAnalysisUtils TpcGlobalPositionWrapper globalWrapper; globalWrapper.loadNodes(topNode); globalWrapper.set_suppressCrossing(true); + + auto* geometry = findNode::getClass(topNode, "ActsGeometry"); + TpcClusterMover mover; auto* tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); - mover.initialize_geometry(tpccellgeo); + mover.initialize_geometry(tpccellgeo, geometry); mover.set_verbosity(0); - auto* geometry = findNode::getClass(topNode, "ActsGeometry"); - std::vector> global_raw; for (const auto& key : get_cluster_keys(track)) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 0afea11b6c..7e3976aa68 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -180,10 +180,47 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) PHG4TpcGeom *layergeom = m_geomContainerTpc->GetLayerCellGeom(20); // z geometry is the same for all layers m_max_driftlength = layergeom->get_max_driftlength(); - m_CM_halfwidth = layergeom->get_CM_halfwidth(); - + m_CM_halfwidth = layergeom->get_CM_halfwidth(); m_maxSurfZ = m_max_driftlength - 0.0001; // add clearance from physical TPC gas volume length to avoid overlaps - + + // This transform will eventually be built using the tilt and placement variables that will be in layergeom + // TPC envelope to global transformation + + double rot_x = layergeom->get_rot_x(); + double rot_y = layergeom->get_rot_y(); + double rot_z = layergeom->get_rot_z(); + double place_x = layergeom->get_place_x(); + double place_y = layergeom->get_place_y(); + double place_z = layergeom->get_place_z(); + Eigen::Vector3d rot(rot_x, rot_y, rot_z); + Eigen::Vector3d trans(place_x, place_y, place_z); + + Eigen::AngleAxisd alpha(rot(0), Eigen::Vector3d::UnitX()); + Eigen::AngleAxisd beta(rot(1), Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd gamma(rot(2), Eigen::Vector3d::UnitZ()); + Eigen::Quaternion q = gamma * beta * alpha; + m_tpc_envelope_world_transform.linear() = q.matrix(); + m_tpc_envelope_world_transform.translation() = trans; + // and the inverse + m_tpc_world_envelope_transform = m_tpc_envelope_world_transform.inverse(); + + // test + Acts::Vector3 test_env(10.0, 40.0, 80.0); + std::cout << "MakeActsGeometry::InitRun transform tests north" << std::endl; + std::cout << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + Acts::Vector3 test_glob = m_tpc_envelope_world_transform * test_env; + std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; + Acts::Vector3 test_env_check = m_tpc_world_envelope_transform * test_glob; + std::cout << " test_env_check " << test_env_check.x() << " " << test_env_check.y() << " " << test_env_check.z() << std::endl; + + Acts::Vector3 test_envs(10.0, 40.0, -80.0); + std::cout << "MakeActsGeometry::InitRun transform tests south" << std::endl; + std::cout << " test_env " << test_envs.x() << " " << test_envs.y() << " " << test_envs.z() << std::endl; + Acts::Vector3 test_globs = m_tpc_envelope_world_transform * test_envs; + std::cout << " test_glob " << test_globs.x() << " " << test_globs.y() << " " << test_globs.z() << std::endl; + Acts::Vector3 test_env_checks = m_tpc_world_envelope_transform * test_globs; + std::cout << " test_env_check " << test_env_checks.x() << " " << test_env_checks.y() << " " << test_env_checks.z() << std::endl; + // Alignment Transformation declaration of instance - must be here to set initial alignment flag AlignmentTransformation alignment_transformation; alignment_transformation.createAlignmentTransformContainer(topNode); @@ -298,6 +335,7 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) m_actsGeometry->set_CM_halfwidth(m_CM_halfwidth); m_actsGeometry->set_tpc_tzero(m_tpc_tzero); m_actsGeometry->set_sampa_tzero_bias(m_sampa_tzero_bias); + m_actsGeometry->set_tpc_world_envelope_transform(m_tpc_world_envelope_transform); // transform world position to TPC envelope position // alignment_transformation.useInttSurveyGeometry(m_inttSurvey); if (Verbosity() > 1) @@ -846,11 +884,12 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) { auto surf = j->getSharedPtr(); auto vec3d = surf->center(m_geoCtxt); - - // convert to cm - std::vector world_center = {vec3d(0) / 10.0, - vec3d(1) / 10.0, - vec3d(2) / 10.0}; + vec3d /= 10.0; + auto vec3d_envelope = m_tpc_world_envelope_transform * vec3d; // needs to be in TPC envelope coordinates due to tilt in sims + + std::vector world_center = {vec3d_envelope(0), + vec3d_envelope(1), + vec3d_envelope(2)}; TrkrDefs::hitsetkey hitsetkey = getTpcHitSetKeyFromCoords(world_center); unsigned int layer = TrkrDefs::getLayer(hitsetkey); @@ -1210,7 +1249,8 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector &world) { - // Look up TPC surface index values from world position of surface center + // the input position is assumed to be in tpc envelope coords - i.e. tilt removed + // Look up TPC surface index values from tpc envelope position of surface center // layer unsigned int layer = 999; double layer_rad = sqrt(pow(world[0], 2) + pow(world[1], 2)); @@ -1220,6 +1260,7 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector= tpc_ref_radius_low && layer_rad < tpc_ref_radius_high) { layer = ilayer; @@ -1248,7 +1289,7 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector 3 && layer == 7) + { + std::cout << " layer_rad " << layer_rad << " m_layerRadius[layer] " << m_layerRadius[layer-7] << " found layer " << layer << " side " << side << " world " << world[0] << " " << world[1] << " " << world[2] << " phi_world " << phi_world << " readout_mod " << readout_mod << std::endl; + } + if (readout_mod >= m_nTpcModulesPerLayer) { std::cout << PHWHERE @@ -1271,16 +1318,13 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector 3) + if (Verbosity() > 3 && layer == 7) { - if (layer == 30) - { - std::cout << " world = " << world[0] << " " << world[1] - << " " << world[2] << " phi_world " - << phi_world * 180 / M_PI << " layer " << layer - << " readout_mod " << readout_mod << " side " << side - << " hitsetkey " << hitset_key << std::endl; - } + std::cout << " world = " << world[0] << " " << world[1] + << " " << world[2] << " phi_world " + << phi_world * 180 / M_PI << " layer " << layer + << " readout_mod " << readout_mod << " side " << side + << " hitsetkey " << hitset_key << std::endl; } return hitset_key; diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index 272182b713..4180db74f3 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -303,6 +303,10 @@ class MakeActsGeometry : public SubsysReco bool m_use_module_tilt_always = false; bool m_use_new_silicon_rotation_order = false; + + Acts::Transform3 m_tpc_world_envelope_transform; + Acts::Transform3 m_tpc_envelope_world_transform; + }; #endif diff --git a/offline/packages/trackreco/MakeSourceLinks.cc b/offline/packages/trackreco/MakeSourceLinks.cc index f2975ac952..74c9300d97 100644 --- a/offline/packages/trackreco/MakeSourceLinks.cc +++ b/offline/packages/trackreco/MakeSourceLinks.cc @@ -50,12 +50,12 @@ namespace } // namespace -void MakeSourceLinks::initialize(PHG4TpcGeomContainer* cellgeo) +void MakeSourceLinks::initialize(PHG4TpcGeomContainer* cellgeo, ActsGeometry *tGeometry) { // get the TPC layer radii from the geometry object - if (cellgeo) + if (cellgeo && tGeometry) { - _clusterMover.initialize_geometry(cellgeo); + _clusterMover.initialize_geometry(cellgeo, tGeometry); } } diff --git a/offline/packages/trackreco/MakeSourceLinks.h b/offline/packages/trackreco/MakeSourceLinks.h index 7cabf268dc..62b5031624 100644 --- a/offline/packages/trackreco/MakeSourceLinks.h +++ b/offline/packages/trackreco/MakeSourceLinks.h @@ -42,7 +42,7 @@ class MakeSourceLinks public: MakeSourceLinks() = default; - void initialize(PHG4TpcGeomContainer* cellgeo); + void initialize(PHG4TpcGeomContainer* cellgeo, ActsGeometry *tGeometry); void setVerbosity(int verbosity) { m_verbosity = verbosity; } diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 1cf72bdfdc..f7a58fb813 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -436,7 +436,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) SourceLinkVec sourceLinks; MakeSourceLinks makeSourceLinks; - makeSourceLinks.initialize(_tpccellgeo); + makeSourceLinks.initialize(_tpccellgeo, m_tGeometry); makeSourceLinks.setVerbosity(Verbosity()); makeSourceLinks.set_pp_mode(m_pp_mode); makeSourceLinks.set_cluster_edge_rejection(m_cluster_edge_rejection); diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index fc6de17328..2c173d2ed2 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -297,7 +297,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) SourceLinkVec sourceLinks; MakeSourceLinks makeSourceLinks; - makeSourceLinks.initialize(_tpccellgeo); + makeSourceLinks.initialize(_tpccellgeo, m_tGeometry); makeSourceLinks.setVerbosity(Verbosity()); makeSourceLinks.set_pp_mode(false); @@ -1116,4 +1116,4 @@ Acts::Vector3 PHCosmicsTrkFitter::calculateMomentum(TrackSeed* tpcseed, const st momentum.z() = pz; return momentum; -} \ No newline at end of file +} diff --git a/simulation/g4simulation/g4detectors/Makefile.am b/simulation/g4simulation/g4detectors/Makefile.am index 9e219fe9e0..acff3e0c83 100644 --- a/simulation/g4simulation/g4detectors/Makefile.am +++ b/simulation/g4simulation/g4detectors/Makefile.am @@ -100,6 +100,7 @@ pkginclude_HEADERS = \ PHG4TpcCylinderGeomContainer.h \ PHG4TpcGeom.h \ PHG4TpcGeomv1.h \ + PHG4TpcGeomv2.h \ PHG4TpcGeomContainer.h \ PHG4ZDCDefs.h \ PHG4ZDCSubsystem.h @@ -137,6 +138,7 @@ ROOTDICTS = \ PHG4TpcCylinderGeomContainer_Dict.cc \ PHG4TpcGeom_Dict.cc \ PHG4TpcGeomv1_Dict.cc \ + PHG4TpcGeomv2_Dict.cc \ PHG4TpcGeomContainer_Dict.cc pcmdir = $(libdir) @@ -177,6 +179,7 @@ libg4detectors_io_la_SOURCES = \ PHG4TpcCylinderGeomContainer.cc \ PHG4TpcGeom.cc \ PHG4TpcGeomv1.cc \ + PHG4TpcGeomv2.cc \ PHG4TpcGeomContainer.cc libg4detectors_la_SOURCES = \ diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeom.h b/simulation/g4simulation/g4detectors/PHG4TpcGeom.h index bdb3bfbae7..521cf2fa9c 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeom.h +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeom.h @@ -192,6 +192,38 @@ class PHG4TpcGeom : public PHObject return -99999; } + virtual double get_rot_x() const + { + PHOOL_VIRTUAL_WARN("get_rot_x()"); + return std::numeric_limits::quiet_NaN(); + } + virtual double get_rot_y() const + { + PHOOL_VIRTUAL_WARN("get_rot_y()"); + return std::numeric_limits::quiet_NaN(); + } + virtual double get_rot_z() const + { + PHOOL_VIRTUAL_WARN("get_rot_z()"); + return std::numeric_limits::quiet_NaN(); + } + virtual double get_place_x() const + { + PHOOL_VIRTUAL_WARN("get_place_x()"); + return std::numeric_limits::quiet_NaN(); + } + virtual double get_place_y() const + { + PHOOL_VIRTUAL_WARN("get_place_y()"); + return std::numeric_limits::quiet_NaN(); + } + virtual double get_place_z() const + { + PHOOL_VIRTUAL_WARN("get_place_z()"); + return std::numeric_limits::quiet_NaN(); + } + + virtual const std::array, 2> &get_sector_min_phi(); virtual const std::array, 2> &get_sector_max_phi(); @@ -211,6 +243,17 @@ class PHG4TpcGeom : public PHObject { PHOOL_VIRTUAL_WARN("set_phi_bias(const std::array, 2>&)"); } + + + + /* + double get_rot_x() const override { return rot_x; } + double get_rot_y() const override { return rot_y; } + double get_rot_z() const override { return rot_z; } + double get_place_x() const override { return place_x; } + double get_place_y() const override { return place_y; } + double get_place_z() const override { return place_z; } + */ virtual void set_layer(const int) { PHOOL_VIRTUAL_WARN("set_layer(const int)"); } virtual void set_radius(const double) { PHOOL_VIRTUAL_WARN("set_radius(const double)"); } @@ -237,7 +280,15 @@ class PHG4TpcGeom : public PHObject virtual void set_adc_clock(const double) { PHOOL_VIRTUAL_WARN("set_adc_clock(const double)"); } virtual void set_extended_readout_time(const double) { PHOOL_VIRTUAL_WARN("set_extended_readout_time(const double)"); } virtual void set_drift_velocity_sim(const double) { PHOOL_VIRTUAL_WARN("set_drift_velocity_sim(const double)"); } - + + virtual void set_rot_x(const double) { PHOOL_VIRTUAL_WARN("set_rot_x(const double)"); } + virtual void set_rot_y(const double) { PHOOL_VIRTUAL_WARN("set_rot_y(const double)"); } + virtual void set_rot_z(const double) { PHOOL_VIRTUAL_WARN("set_rot_z(const double)"); } + + virtual void set_place_x(const double) { PHOOL_VIRTUAL_WARN("set_place_x(const double)"); } + virtual void set_place_y(const double) { PHOOL_VIRTUAL_WARN("set_place_y(const double)"); } + virtual void set_place_z(const double) { PHOOL_VIRTUAL_WARN("set_place_z(const double)"); } + //! load parameters from PHParameters, which interface to Database/XML/ROOT files virtual void ImportParameters(const PHParameters & /*param*/) { return; } diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc new file mode 100644 index 0000000000..050baf86a9 --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc @@ -0,0 +1,593 @@ +#include "PHG4TpcGeomv2.h" +#include "PHG4CylinderCellDefs.h" + +#include + +#include + +namespace +{ + // streamer for internal 2dimensional arrays + using array_t = std::array, PHG4TpcGeomv2::NSides>; + std::ostream& operator<<(std::ostream& out, const array_t& array) + { + out << "{ "; + for (const auto& iside : array) + { + out << "{"; + bool first = true; + for (const auto& value : iside) + { + if (!first) + { + out << ", "; + } + first = false; + out << value; + } + out << "} "; + } + out << " }"; + return out; + } +} // namespace + +std::ostream& operator<<(std::ostream& out, const PHG4TpcGeomv2& geom) +{ + out << "PHG4TpcGeomv2 - layer: " << geom.layer << std::endl; + out + << " binnig: " << geom.binning + << ", radius: " << geom.radius + << ", nzbins: " << geom.nzbins + << ", zmin: " << geom.zmin + << ", zstep: " << geom.zstep + << ", nphibins: " << geom.nphibins + << ", phimin: " << geom.phimin + << ", phistep: " << geom.phistep + << ", thickness: " << geom.thickness + << std::endl; + + out << " sector_R_bias: " << geom.sector_R_bias << std::endl; + out << " sector_Phi_bias: " << geom.sector_Phi_bias << std::endl; + out << " sector_min_Phi: " << geom.sector_min_Phi << std::endl; + out << " sector_max_Phi: " << geom.sector_max_Phi << std::endl; + + return out; +} + +void PHG4TpcGeomv2::set_zbins(const int i) +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + nzbins = i; +} + +void PHG4TpcGeomv2::set_zmin(const double z) +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + zmin = z; +} + +int PHG4TpcGeomv2::get_zbins() const +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return nzbins; +} + +double +PHG4TpcGeomv2::get_zmin() const +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return zmin; +} + +double +PHG4TpcGeomv2::get_zstep() const +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return zstep; +} + +void PHG4TpcGeomv2::set_zstep(const double z) +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + zstep = z; +} + +int PHG4TpcGeomv2::get_phibins() const +{ + check_binning_method_phi("PHG4TpcGeomv2::get_phibins"); + return nphibins; +} + +double +PHG4TpcGeomv2::get_phistep() const +{ + check_binning_method_phi("PHG4TpcGeomv2::get_phistep"); + return phistep; +} + +double +PHG4TpcGeomv2::get_phimin() const +{ + check_binning_method_phi("PHG4TpcGeomv2::get_phimin"); + return phimin; +} + +void PHG4TpcGeomv2::set_phibins(const int i) +{ + check_binning_method_phi("PHG4TpcGeomv2::set_phibins"); + nphibins = i; +} + +void PHG4TpcGeomv2::set_phistep(const double phi) +{ + check_binning_method_phi("PHG4TpcGeomv2::set_phistep"); + phistep = phi; +} + +void PHG4TpcGeomv2::set_phimin(const double phi) +{ + check_binning_method_phi("PHG4TpcGeomv2::set_phimin"); + phimin = phi; +} + +int PHG4TpcGeomv2::get_etabins() const +{ + check_binning_method_eta("PHG4TpcGeomv2::get_etabins"); + return nzbins; +} + +double +PHG4TpcGeomv2::get_etastep() const +{ + check_binning_method_eta("PHG4TpcGeomv2::get_etastep"); + return zstep; +} +double +PHG4TpcGeomv2::get_etamin() const +{ + check_binning_method_eta("PHG4TpcGeomv2::get_etamin"); + return zmin; +} + +void PHG4TpcGeomv2::set_etamin(const double z) +{ + check_binning_method_eta("PHG4TpcGeomv2::set_etamin"); + zmin = z; +} + +void PHG4TpcGeomv2::set_etastep(const double z) +{ + check_binning_method_eta("PHG4TpcGeomv2::set_etastep"); + zstep = z; +} + +void PHG4TpcGeomv2::set_etabins(const int i) +{ + check_binning_method_eta("PHG4TpcGeomv2::set_etabins"); + nzbins = i; +} + +void PHG4TpcGeomv2::identify(std::ostream& os) const +{ + os << "PHG4TpcGeomv2::identify - layer: " << layer << std::endl; + + os + << " binning: " << binning + << ", radius: " << radius + << ", nzbins: " << nzbins + << ", zmin: " << zmin + << ", zstep: " << zstep + << ", nphibins: " << nphibins + << ", phimin: " << phimin + << ", phistep: " << phistep + << ", thickness: " << thickness + << std::endl; + + os << " sector_R_bias: " << sector_R_bias << std::endl; + os << " sector_Phi_bias: " << sector_Phi_bias << std::endl; + os << " sector_min_Phi: " << sector_min_Phi << std::endl; + os << " sector_max_Phi: " << sector_max_Phi << std::endl; +} + +std::pair +PHG4TpcGeomv2::get_zbounds(const int ibin) const +{ + if (ibin < 0 || ibin > nzbins) + { + std::cout << PHWHERE << " Asking for invalid bin in z: " << ibin << std::endl; + exit(1); + } + check_binning_method(PHG4CylinderCellDefs::sizebinning); + double zlow = zmin + ibin * zstep; + double zhigh = zlow + zstep; + return std::make_pair(zlow, zhigh); +} + +std::pair +PHG4TpcGeomv2::get_etabounds(const int ibin) const +{ + if (ibin < 0 || ibin > nzbins) + { + std::cout << PHWHERE << " Asking for invalid bin in z: " << ibin << std::endl; + exit(1); + } + check_binning_method_eta("PHG4TpcGeomv2::get_etabounds"); + // check_binning_method(PHG4CylinderCellDefs::etaphibinning); + double zlow = zmin + ibin * zstep; + double zhigh = zlow + zstep; + return std::make_pair(zlow, zhigh); +} + +std::pair +PHG4TpcGeomv2::get_phibounds(const int ibin) const +{ + if (ibin < 0 || ibin > nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + double philow = phimin + ibin * phistep; + double phihigh = philow + phistep; + return std::make_pair(philow, phihigh); +} + +int PHG4TpcGeomv2::get_zbin(const double z) const +{ + if (z < zmin || z > (zmin + nzbins * zstep)) + { + // cout << PHWHERE << "Asking for bin for z outside of z range: " << z << endl; + return -1; + } + + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return floor((z - zmin) / zstep); +} + +int PHG4TpcGeomv2::get_etabin(const double eta) const +{ + if (eta < zmin || eta > (zmin + nzbins * zstep)) + { + // cout << "Asking for bin for eta outside of eta range: " << eta << endl; + return -1; + } + check_binning_method_eta(); + return floor((eta - zmin) / zstep); +} + +int PHG4TpcGeomv2::get_phibin_new(const double phi) const +{ + double norm_phi = phi; + if (phi < phimin || phi > (phimin + nphibins * phistep)) + { + int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); + norm_phi += 2 * M_PI * nwraparound; + } + check_binning_method_phi(); + return floor((norm_phi - phimin) / phistep); +} + +int PHG4TpcGeomv2::find_phibin(const double phi, int side) const +{ + double norm_phi = phi; + if (phi < phimin || phi > (phimin + nphibins * phistep)) + { + int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); + norm_phi += 2 * M_PI * nwraparound; + } + // if (phi > M_PI){ + // norm_phi = phi - 2* M_PI; + // } + // if (phi < phimin){ + // norm_phi = phi + 2* M_PI; + // } + //side = 0; + + int phi_bin = -1; + + for (std::size_t s = 0; s < sector_max_Phi[side].size(); s++) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi > sector_min_Phi[side][s]) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (floor(std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s); + break; + } + if (s == 11) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi >= -M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = floor(std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s; + break; + } + if (norm_phi > sector_min_Phi[side][s] + 2 * M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = floor(std::abs(sector_max_Phi[side][s] - (norm_phi - 2 * M_PI)) / phistep) + nphibins / 12 * s; + break; + } + } + } + return phi_bin; +} + +float PHG4TpcGeomv2::get_pad_float(const double phi, int side) const +{ + double norm_phi = phi; + if (phi < phimin || phi > (phimin + nphibins * phistep)) + { + int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); + norm_phi += 2 * M_PI * nwraparound; + } + // if (phi > M_PI){ + // norm_phi = phi - 2* M_PI; + // } + // if (phi < phimin){ + // norm_phi = phi + 2* M_PI; + // } + //side = 0; + + float phi_bin = -1; + + for (std::size_t s = 0; s < sector_max_Phi[side].size(); s++) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi > sector_min_Phi[side][s]) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s; + break; + } + if (s == 11) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi >= -M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s; + break; + } + if (norm_phi > sector_min_Phi[side][s] + 2 * M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (std::abs(sector_max_Phi[side][s] - (norm_phi - 2 * M_PI)) / phistep) + nphibins / 12 * s; + break; + } + } + } + return phi_bin - 0.5; +} + +float PHG4TpcGeomv2::get_tbin_float(const double z) const +{ + if (z < zmin || z > (zmin + nzbins * zstep)) + { + // cout << PHWHERE << "Asking for bin for z outside of z range: " << z << endl; + return -1; + } + + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return ((z - zmin) / zstep) - 0.5; +} + +int PHG4TpcGeomv2::get_phibin(const double phi, int side) const +{ + double new_phi = phi; + if (phi > M_PI) + { + new_phi = phi - 2 * M_PI; + } + if (phi < phimin) + { + new_phi = phi + 2 * M_PI; + } + // Get phi-bin number + int phi_bin = find_phibin(new_phi, side); + + //side = 0; + // If phi-bin is not defined, check that it is in the dead area and put it to the edge of sector + if (phi_bin < 0) + { + // + for (std::size_t s = 0; s < sector_max_Phi[side].size(); s++) + { + double daPhi = 0; + if (s == 0) + { + daPhi = fabs(sector_min_Phi[side][11] + 2 * M_PI - sector_max_Phi[side][s]); + } + else + { + daPhi = fabs(sector_min_Phi[side][s - 1] - sector_max_Phi[side][s]); + } + + double min_phi = sector_max_Phi[side][s]; + double max_phi = sector_max_Phi[side][s] + daPhi; + if (new_phi <= max_phi && new_phi >= min_phi) + { + if (fabs(max_phi - new_phi) > fabs(new_phi - min_phi)) + { + new_phi = min_phi - phistep / 5; + } + else + { + new_phi = max_phi + phistep / 5; + } + } + } + // exit(1); + + phi_bin = find_phibin(new_phi, side); + if (phi_bin < 0) + { + std::cout << PHWHERE << "Asking for bin for phi outside of phi range: " << phi << std::endl; + exit(1); + // phi_bin=0; + } + } + return phi_bin; +} + +double +PHG4TpcGeomv2::get_zcenter(const int ibin) const +{ + if (ibin < 0 || ibin > nzbins) + { + std::cout << PHWHERE << "Asking for invalid bin in z: " << ibin << std::endl; + exit(1); + } + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return zmin + (ibin + 0.5) * zstep; +} + +double +PHG4TpcGeomv2::get_etacenter(const int ibin) const +{ + if (ibin < 0 || ibin > nzbins) + { + std::cout << PHWHERE << "Asking for invalid bin in eta: " << ibin << std::endl; + std::cout << "minbin: 0, maxbin " << nzbins << std::endl; + exit(1); + } + check_binning_method_eta(); + return zmin + (ibin + 0.5) * zstep; +} + +double +PHG4TpcGeomv2::get_phicenter_new(const int ibin) const +{ + if (ibin < 0 || ibin > nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + check_binning_method_phi(); + + return (phimin + (ibin + 0.5) * phistep); +} + +double +PHG4TpcGeomv2::get_phicenter(const int ibin, const int side) const +{ + // double phi_center = -999; + if (ibin < 0 || ibin > nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + check_binning_method_phi(); + + //const int side = 0; + unsigned int pads_per_sector = nphibins / 12; + unsigned int sector = ibin / pads_per_sector; + double phi_center = (sector_max_Phi[side][sector] - (ibin + 0.5 - sector * pads_per_sector) * phistep); + if (phi_center <= -M_PI) + { + phi_center += 2 * M_PI; + } + return phi_center; +} + +double +PHG4TpcGeomv2::get_phi(const float ibin, const int side) const +{ + // double phi_center = -999; + if (ibin < 0 || ibin > nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + check_binning_method_phi(); + + //const int side = 0; + unsigned int pads_per_sector = nphibins / 12; + unsigned int sector = ibin / pads_per_sector; + double phi = (sector_max_Phi[side][sector] - (ibin + 0.5 - sector * pads_per_sector) * phistep); + if (phi <= -M_PI) + { + phi += 2 * M_PI; + } + return phi; +} + +std::string +PHG4TpcGeomv2::methodname(const int i) const +{ + switch (i) + { + case PHG4CylinderCellDefs::sizebinning: + return "Bins in cm"; + break; + case PHG4CylinderCellDefs::etaphibinning: + return "Eta/Phi bins"; + break; + case PHG4CylinderCellDefs::etaslatbinning: + return "Eta/numslat bins"; + break; + case PHG4CylinderCellDefs::spacalbinning: + return "SPACAL Tower bins"; + break; + default: + break; + } + return "Unknown"; +} + +void PHG4TpcGeomv2::check_binning_method(const int i) const +{ + if (binning != i) + { + std::cout << "different binning method used " << methodname(binning) + << ", not : " << methodname(i) + << std::endl; + exit(1); + } + return; +} + +void PHG4TpcGeomv2::check_binning_method_eta(const std::string& src) const +{ + if (binning != PHG4CylinderCellDefs::etaphibinning && + binning != PHG4CylinderCellDefs::etaslatbinning && + binning != PHG4CylinderCellDefs::spacalbinning) + { + if (!src.empty()) + { + std::cout << src << " : "; + } + + std::cout << "different binning method used " << methodname(binning) + << ", not : " << methodname(PHG4CylinderCellDefs::etaphibinning) + << " or " << methodname(PHG4CylinderCellDefs::etaslatbinning) + << " or " << methodname(PHG4CylinderCellDefs::spacalbinning) + << std::endl; + exit(1); + } + return; +} + +void PHG4TpcGeomv2::check_binning_method_phi(const std::string& src) const +{ + if (binning != PHG4CylinderCellDefs::etaphibinning && + binning != PHG4CylinderCellDefs::sizebinning && + binning != PHG4CylinderCellDefs::etaslatbinning && + binning != PHG4CylinderCellDefs::spacalbinning) + { + if (!src.empty()) + { + std::cout << src << " : "; + } + + std::cout << "different binning method used " << methodname(binning) + << ", not : " << methodname(PHG4CylinderCellDefs::etaphibinning) + << " or " << methodname(PHG4CylinderCellDefs::sizebinning) + << " or " << methodname(PHG4CylinderCellDefs::etaslatbinning) + << " or " << methodname(PHG4CylinderCellDefs::spacalbinning) + << std::endl; + exit(1); + } + return; +} diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h new file mode 100644 index 0000000000..235256b67c --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h @@ -0,0 +1,158 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef G4DETECTORS_PHG4TPCGEOMV1_H +#define G4DETECTORS_PHG4TPCGEOMV1_H + +#include "PHG4TpcGeom.h" + +#include +#include +#include // for cout, ostream +#include +#include // for pair + +class PHG4TpcGeomv2 : public PHG4TpcGeom +{ + public: + PHG4TpcGeomv2() = default; + + ~PHG4TpcGeomv2() override = default; + + // from PHObject + void identify(std::ostream& os = std::cout) const override; + + int get_layer() const override { return layer; } + double get_radius() const override { return radius; } + double get_thickness() const override { return thickness; } + int get_binning() const override { return binning; } + int get_zbins() const override; + int get_phibins() const override; + double get_zmin() const override; + double get_phistep() const override; + double get_phimin() const override; + double get_zstep() const override; + int get_etabins() const override; + double get_etastep() const override; + double get_etamin() const override; + + double get_max_driftlength() const override { return max_driftlength; } + double get_CM_halfwidth() const override { return CM_halfwidth; } + double get_adc_clock() const override { return adc_clock; } // default sim value + double get_extended_readout_time() const override { return extended_readout_time; } + double get_drift_velocity_sim() const override { return drift_velocity_sim; } + + double get_rot_x() const override { return rot_x; } + double get_rot_y() const override { return rot_y; } + double get_rot_z() const override { return rot_z; } + double get_place_x() const override { return place_x; } + double get_place_y() const override { return place_y; } + double get_place_z() const override { return place_z; } + + std::pair get_zbounds(const int ibin) const override; + std::pair get_phibounds(const int ibin) const override; + std::pair get_etabounds(const int ibin) const override; + double get_etacenter(const int ibin) const override; + double get_zcenter(const int ibin) const override; + double get_phicenter(const int ibin, const int side = 0) const override; + double get_phicenter_new(const int ibin) const override; + double get_phi(const float ibin, const int side = 0) const override; + + int get_etabin(const double eta) const override; + int get_zbin(const double z) const override; + int get_phibin(const double phi, int side = 0) const override; + int get_phibin_new(const double phi) const override; + + float get_pad_float(const double phi, int side = 0) const override; + float get_tbin_float(const double z) const override; + int find_phibin(const double phi, int side = 0) const override; + + void set_layer(const int i) override { layer = i; } + void set_binning(const int i) override { binning = i; } + void set_radius(const double r) override { radius = r; } + void set_thickness(const double t) override { thickness = t; } + void set_zbins(const int i) override; + void set_zmin(const double z) override; + void set_zstep(const double z) override; + void set_phibins(const int i) override; + void set_phistep(const double phi) override; + void set_phimin(const double phi) override; + void set_etabins(const int i) override; + void set_etamin(const double z) override; + void set_etastep(const double z) override; + // capture the z geometry related setup parameters + void set_max_driftlength(const double val) override { max_driftlength = val; } + void set_CM_halfwidth(const double val) override { CM_halfwidth = val; } + void set_adc_clock(const double val) override { adc_clock = val; } + void set_extended_readout_time(const double val) override { extended_readout_time = val; } + void set_drift_velocity_sim(const double val) override { drift_velocity_sim = val; } + void set_rot_x(const double val) override { rot_x = val; } + void set_rot_y(const double val) override { rot_y = val; } + void set_rot_z(const double val) override { rot_z = val; } + void set_place_x(const double val) override { place_x = val; } + void set_place_y(const double val) override { place_y = val; } + void set_place_z(const double val) override { place_z = val; } + + static const int NSides = 2; + + void set_r_bias(const std::array, NSides> &dr) override { sector_R_bias = dr; } + void set_phi_bias(const std::array, NSides> &dphi) override { sector_Phi_bias = dphi; } + + void set_sector_min_phi(const std::array, NSides> &s_min_phi) override + { + sector_min_Phi = s_min_phi; + } + void set_sector_max_phi(const std::array, NSides> &s_max_phi) override + { + sector_max_Phi = s_max_phi; + } + + const std::array, NSides> &get_sector_min_phi() override + { + return sector_min_Phi; + } + const std::array, NSides> &get_sector_max_phi() override + { + return sector_max_Phi; + } + + protected: + void check_binning_method(const int i) const; + void check_binning_method_eta(const std::string& src = "") const; + void check_binning_method_phi(const std::string& src = "") const; + std::string methodname(const int i) const; + int layer{-999}; + int binning{0}; + double radius{std::numeric_limits::quiet_NaN()}; + int nzbins{-1}; + double zmin{std::numeric_limits::quiet_NaN()}; + double zstep{std::numeric_limits::quiet_NaN()}; + int nphibins{-1}; + double phimin{-M_PI}; + double phistep{std::numeric_limits::quiet_NaN()}; + double thickness{std::numeric_limits::quiet_NaN()}; + + double max_driftlength{std::numeric_limits::quiet_NaN()}; + double CM_halfwidth{std::numeric_limits::quiet_NaN()}; + double adc_clock{std::numeric_limits::quiet_NaN()}; + double extended_readout_time{std::numeric_limits::quiet_NaN()}; + double drift_velocity_sim{std::numeric_limits::quiet_NaN()}; + + double rot_x{std::numeric_limits::quiet_NaN()}; + double rot_y{std::numeric_limits::quiet_NaN()}; + double rot_z{std::numeric_limits::quiet_NaN()}; + double place_x{std::numeric_limits::quiet_NaN()}; + double place_y{std::numeric_limits::quiet_NaN()}; + double place_z{std::numeric_limits::quiet_NaN()}; + + std::array, NSides> sector_R_bias; + std::array, NSides> sector_Phi_bias; + std::array, NSides> sector_min_Phi; + std::array, NSides> sector_max_Phi; + + // streamer + friend std::ostream& operator<<(std::ostream&, const PHG4TpcGeomv2&); + + ClassDefOverride(PHG4TpcGeomv2, 1) +}; + +#endif diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2LinkDef.h b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2LinkDef.h new file mode 100644 index 0000000000..e25664077d --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class PHG4TpcGeomv2 + ; + +#endif /* __CINT__ */ diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.cc b/simulation/g4simulation/g4eval/SvtxTruthEval.cc index 2ecaccf41c..f2fcd220a7 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.cc @@ -457,8 +457,16 @@ void SvtxTruthEval::LayerClusterG4Hits(const std::set& truth_hits, std // we do not assume that the truth hits know what layer they are in for (auto *this_g4hit : truth_hits) { - float rbegin = std::sqrt(this_g4hit->get_x(0) * this_g4hit->get_x(0) + this_g4hit->get_y(0) * this_g4hit->get_y(0)); - float rend = std::sqrt(this_g4hit->get_x(1) * this_g4hit->get_x(1) + this_g4hit->get_y(1) * this_g4hit->get_y(1)); + // The truth hits are in world coordinates + // They have to be transformed to envelope coords to find what layer they are in + // Then the cluster positions have to be transformed back to world coordinates + Acts::Vector3 world0(this_g4hit->get_x(0), this_g4hit->get_y(0), this_g4hit->get_z(0)); + Acts::Vector3 env0 = _tgeometry->transformTpcWorldToEnvelope(world0); + Acts::Vector3 world1(this_g4hit->get_x(1), this_g4hit->get_y(1), this_g4hit->get_z(1)); + Acts::Vector3 env1 = _tgeometry->transformTpcWorldToEnvelope(world1); + + float rbegin = std::sqrt(env0.x() * env0.x() + env0.y() * env0.y()); + float rend = std::sqrt(env1.x() * env1.x() + env1.y() * env1.y()); // std::cout << " Eval: g4hit " << this_g4hit->get_hit_id() << " layer " << layer << " rbegin " << rbegin << " rend " << rend << std::endl; // make sure the entry point is at lower radius @@ -468,21 +476,21 @@ void SvtxTruthEval::LayerClusterG4Hits(const std::set& truth_hits, std if (rbegin < rend) { - xl[0] = this_g4hit->get_x(0); - yl[0] = this_g4hit->get_y(0); - zl[0] = this_g4hit->get_z(0); - xl[1] = this_g4hit->get_x(1); - yl[1] = this_g4hit->get_y(1); - zl[1] = this_g4hit->get_z(1); + xl[0] = env0.x(); + yl[0] = env0.y(); + zl[0] = env0.z(); + xl[1] = env1.x(); + yl[1] = env1.y(); + zl[1] = env1.z(); } else { - xl[0] = this_g4hit->get_x(1); - yl[0] = this_g4hit->get_y(1); - zl[0] = this_g4hit->get_z(1); - xl[1] = this_g4hit->get_x(0); - yl[1] = this_g4hit->get_y(0); - zl[1] = this_g4hit->get_z(0); + xl[0] = env1.x(); + yl[0] = env1.y(); + zl[0] = env1.z(); + xl[1] = env0.x(); + yl[1] = env0.y(); + zl[1] = env0.z(); std::swap(rbegin, rend); // std::cout << "swapped in and out " << std::endl; } @@ -659,6 +667,14 @@ void SvtxTruthEval::LayerClusterG4Hits(const std::set& truth_hits, std } } + // convert cluster position back to world coordinates + Acts::Vector3 clus_env(gx,gy,gz); + Acts::Vector3 clus_world = _tgeometry->transformTpcEnvelopeToWorld(clus_env); + gx = clus_world.x(); + gy = clus_world.y(); + gz = clus_world.z(); + // what is gr used for? + } // if TPC else { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc index 5d0eb1e66c..6f736ccc39 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc @@ -3,7 +3,7 @@ #include "PHG4TpcDisplayAction.h" #include -#include +#include #include #include @@ -118,10 +118,26 @@ void PHG4TpcDetector::ConstructMe(G4LogicalVolume *logicWorld) ConstructTpcCageVolume(tpc_envelope_logic); ConstructTpcGasVolume(tpc_envelope_logic); - new G4PVPlacement(nullptr, G4ThreeVector(m_Params->get_double_param("place_x") * cm, m_Params->get_double_param("place_y") * cm, m_Params->get_double_param("place_z") * cm), + G4RotationMatrix rot; + rot.rotateX(m_Params->get_double_param("rot_x")*rad); + rot.rotateY(m_Params->get_double_param("rot_y")*rad); + rot.rotateZ(m_Params->get_double_param("rot_z")*rad); + + G4ThreeVector trans(m_Params->get_double_param("place_x") * cm, m_Params->get_double_param("place_y") * cm, m_Params->get_double_param("place_z") * cm); + + new G4PVPlacement( + G4Transform3D(rot, trans), tpc_envelope_logic, "tpc_envelope", - logicWorld, false, false, OverlapCheck()); - + logicWorld, + false, false, OverlapCheck()); + + /* + G4ThreeVector test_env(10.0, 40.0, 80.0); + std::cout << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + G4ThreeVector test_glob = test_env.transform(rot); + std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; + */ + // geometry node add_geometry_node(); } @@ -538,7 +554,12 @@ void PHG4TpcDetector::add_geometry_node() auto *newNode = new PHIODataNode(geonode, geonode_name, "PHObject"); geomNode->addNode(newNode); } - + else + { + std::cout << "PHG4TpcGeomContainer already exists with name " << geonode_name << " and it should not! " << std::endl; + geonode->identify(); + } + m_cdb = CDBInterface::instance(); std::string calibdir = m_cdb->getUrl("TPC_FEE_CHANNEL_MAP"); @@ -695,7 +716,7 @@ void PHG4TpcDetector::add_geometry_node() << " phibins " << NPhiBins[iregion] << " phistep " << phi_bin_width_cdb[layer] << std::endl; } - auto *layerseggeo = new PHG4TpcGeomv1; + auto *layerseggeo = new PHG4TpcGeomv2; layerseggeo->set_layer(layer); double r_length = Thickness[iregion]; @@ -731,6 +752,12 @@ void PHG4TpcDetector::add_geometry_node() layerseggeo->set_adc_clock(m_Params->get_double_param("tpc_adc_clock")); layerseggeo->set_extended_readout_time(m_Params->get_double_param("extended_readout_time")); layerseggeo->set_drift_velocity_sim(m_Params->get_double_param("drift_velocity_sim")); + layerseggeo->set_rot_x(m_Params->get_double_param("rot_x")); + layerseggeo->set_rot_y(m_Params->get_double_param("rot_y")); + layerseggeo->set_rot_z(m_Params->get_double_param("rot_z")); + layerseggeo->set_place_x(m_Params->get_double_param("place_x")); + layerseggeo->set_place_y(m_Params->get_double_param("place_y")); + layerseggeo->set_place_z(m_Params->get_double_param("place_z")); } // Chris Pinkenburg: greater causes huge memory growth which causes problems diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 9de4cf6639..24d753cb66 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -390,6 +390,14 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) } } + /* + Acts::Vector3 test_env(10.0, 40.0, 80.0); + std::cout << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + Acts::Vector3 test_glob = m_tGeometry-> transformTpcEnvelopeToWorld(test_env); + std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; + Acts::Vector3 test_env_check = m_tGeometry-> transformTpcWorldToEnvelope(test_glob); + std::cout << " test_env_check " << test_env_check.x() << " " << test_env_check.y() << " " << test_env_check.z() << std::endl; + */ return Fun4AllReturnCodes::EVENT_OK; } @@ -556,11 +564,22 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // values between 0 and 1 const double f = gsl_ran_flat(RandomGenerator.get(), 0.0, 1.0); - const double x_start = hiter->second->get_x(0) + f * (hiter->second->get_x(1) - hiter->second->get_x(0)); - const double y_start = hiter->second->get_y(0) + f * (hiter->second->get_y(1) - hiter->second->get_y(0)); - const double z_start = hiter->second->get_z(0) + f * (hiter->second->get_z(1) - hiter->second->get_z(0)); + const double x_start_glob = hiter->second->get_x(0) + f * (hiter->second->get_x(1) - hiter->second->get_x(0)); + const double y_start_glob = hiter->second->get_y(0) + f * (hiter->second->get_y(1) - hiter->second->get_y(0)); + const double z_start_glob = hiter->second->get_z(0) + f * (hiter->second->get_z(1) - hiter->second->get_z(0)); const double t_start = hiter->second->get_t(0) + f * (hiter->second->get_t(1) - hiter->second->get_t(0)); + Acts::Vector3 start_glob(x_start_glob, y_start_glob, z_start_glob); + Acts::Vector3 start = m_tGeometry->transformTpcWorldToEnvelope(start_glob); // we drift in tpc envelope coords, where E is in the z direction + + const double x_start = start.x(); + const double y_start = start.y(); + const double z_start = start.z(); + /* + std::cout << " xg " << x_start_glob << " x " << x_start + <<" yg " << y_start_glob << " y " << y_start + <<" zg " << z_start_glob << " z " << z_start << std::endl; + */ unsigned int side = 0; if (z_start > 0) { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index de2810e918..f290d7d92f 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -38,6 +38,7 @@ class DistortedTrackContainer; class TpcClusterBuilder; class PHG4TpcGeomContainer; class ClusHitsVerbose; +class ActsGeometry; class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface { diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index eb39ed8033..5fb3ee433b 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -330,9 +330,11 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) } // end debug printing // get the global vector3 to then get the surface local phi and z - Acts::Vector3 global(clusx, clusy, clusz); + Acts::Vector3 global_env(clusx, clusy, clusz); TrkrDefs::subsurfkey subsurfkey = 0; + // get_tpc_surface_from coords and the Acts transform both expect coordinates in world (i.e. tilted TPC) coordinates + Acts::Vector3 global = m_tGeometry->transformTpcEnvelopeToWorld(global_env); Surface surface = m_tGeometry->get_tpc_surface_from_coords( hitsetkey, global, subsurfkey); From 51170d0452aa99fd320fb5903dbcdc4234a2e920 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 Jun 2026 12:42:03 -0400 Subject: [PATCH 699/866] replace bizarre value limits by clamp --- simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index cb2ec42d8b..0f702bc573 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -421,10 +421,9 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { m_waveforms.at(i).at(j) += m_fixpedestal; } - // saturate at 2^14 - 1 - m_waveforms.at(i).at(j) = std::min<__gnu_cxx::__alloc_traits >::value_type>(m_waveforms.at(i).at(j), 16383); - m_waveforms.at(i).at(j) = std::max<__gnu_cxx::__alloc_traits >::value_type>(m_waveforms.at(i).at(j), 0); - + // saturate at 2^14 - 1 and make sure values are >= 0 + auto& sample = m_waveforms.at(i).at(j); + sample = std::clamp(sample, 0.F, 16383.F); m_CaloWaveformContainer->get_tower_at_channel(i)->set_waveform_value(j, m_waveforms.at(i).at(j)); } } From 1c7b3bbd955510eb5c3a19920c5a5c9ca55e4b3e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 Jun 2026 17:21:49 -0400 Subject: [PATCH 700/866] simplify overriding of calib and field names --- .../g4waveformsim/CaloWaveformSim.cc | 25 ++++++++++++---- .../g4waveformsim/CaloWaveformSim.h | 30 +++++++++---------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 0f702bc573..9ed0333d50 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -72,11 +73,9 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) std::string templatefilename = std::string(calibroot) + "/CaloWaveSim/" + m_templatefile; TFile *ft = TFile::Open(templatefilename.c_str()); assert(ft && ft->IsOpen()); - h_template = static_cast(ft->Get("hpwaveform")); + ft->GetObject("hpwaveform",h_template); - // Determine run number - EventHeader *evtHeader = findNode::getClass(topNode, "EventHeader"); - m_runNumber = evtHeader ? evtHeader->get_RunNumber() : -1; + m_runNumber = recoConsts::instance()->get_IntFlag("RUNNUMBER"); if (Verbosity() > 0) { std::cout << "CaloWaveformSim::InitRun Run Number: " << m_runNumber << std::endl; @@ -128,14 +127,28 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) } // Data energy calibration - if (!m_overrideCalibName) + if (m_calibName.empty()) { m_calibName = m_detector + "_calib_ADC_to_ETower"; } - if (!m_overrideFieldName) + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << " using " << m_calibName << " as calib name" << std::endl; + } + } + if (m_fieldname.empty()) { m_fieldname = m_detector + "_calib_ADC_to_ETower"; } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << " using " << m_fieldname << " as fieldname" << std::endl; + } + } url = m_giveDirectURL ? m_directURL : CDBInterface::instance()->getUrl(m_calibName); if (!url.empty()) { diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index 80290a5321..1d95664326 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -10,12 +10,16 @@ #ifndef G4WAVEFORMSIM_CALOWAVEFORMSIM_H #define G4WAVEFORMSIM_CALOWAVEFORMSIM_H +#include + #include #include -#include + #include + #include #include + #include #include @@ -46,20 +50,16 @@ class CaloWaveformSim : public SubsysReco void set_fieldname(const std::string &fieldname) { m_fieldname = fieldname; - m_overrideFieldName = true; } void set_calibName(const std::string &calibName) { m_calibName = calibName; - m_overrideCalibName = true; } void set_directURL_calib(const std::string &url) { m_giveDirectURL = true; m_directURL = url; } - void set_overrideCalibName(bool overrideCalib) { m_overrideCalibName = overrideCalib; } - void set_overrideFieldName(bool overrideField) { m_overrideFieldName = overrideField; } // Calibration settings (MC energy) void set_MC_fieldname(const std::string &MC_fieldname) @@ -159,19 +159,17 @@ class CaloWaveformSim : public SubsysReco std::string m_detector{"CEMC"}; // Data energy calibration - std::string m_fieldname{"Femc_datadriven_qm1_correction"}; - std::string m_calibName{"cemc_pi0_twrSlope_v1"}; - bool m_overrideCalibName{false}; - bool m_overrideFieldName{false}; + std::string m_fieldname; + std::string m_calibName; bool m_giveDirectURL{false}; - std::string m_directURL{""}; + std::string m_directURL; // MC energy calibration std::string m_MC_fieldname{"Femc_datadriven_qm1_correction"}; std::string m_MC_calibName{"cemc_pi0_twrSlope_v1"}; bool m_overrideMCFieldName{false}; bool m_overrideMCCalibName{false}; bool m_giveDirectURL_MC{false}; - std::string m_directURL_MC{""}; + std::string m_directURL_MC; bool m_smear_const{false}; float factor_const{0.}; @@ -183,14 +181,14 @@ class CaloWaveformSim : public SubsysReco bool m_overrideTimeCalibName{false}; bool m_dotimecalib{true}; bool m_giveDirectURL_time{false}; - std::string m_directURL_time{""}; + std::string m_directURL_time; // MC time calibration std::string m_MC_fieldname_time{"time"}; std::string m_MC_calibName_time{"CEMC_meanTime"}; bool m_overrideMCTimeFieldName{false}; bool m_overrideMCTimeCalibName{false}; bool m_giveDirectURL_MC_time{false}; - std::string m_directURL_MC_time{""}; + std::string m_directURL_MC_time; // Waveform settings std::string m_templatefile{"waveformtemptempohcalcosmic.root"}; @@ -223,8 +221,10 @@ class CaloWaveformSim : public SubsysReco unsigned int (*encode_tower)(unsigned int, unsigned int){TowerInfoDefs::encode_emcal}; unsigned int (*decode_tower)(unsigned int){TowerInfoDefs::decode_emcal}; - CDBTTree *cdbttree{nullptr}, *cdbttree_MC{nullptr}; - CDBTTree *cdbttree_time{nullptr}, *cdbttree_MC_time{nullptr}; + CDBTTree *cdbttree{nullptr}; + CDBTTree *cdbttree_MC{nullptr}; + CDBTTree *cdbttree_time{nullptr}; + CDBTTree *cdbttree_MC_time{nullptr}; TProfile *h_template{nullptr}; LightCollectionModel light_collection_model; From 592552942d964616775cba01b206e4771ab14869 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 Jun 2026 18:29:47 -0400 Subject: [PATCH 701/866] cleanup override url for data calib --- .../g4waveformsim/CaloWaveformSim.cc | 46 ++++++++++++------- .../g4waveformsim/CaloWaveformSim.h | 11 ++--- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 9ed0333d50..c2edf77f1a 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -67,7 +67,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) const char *calibroot = getenv("CALIBRATIONROOT"); if (!calibroot) { - std::cerr << "CaloWaveformSim::InitRun missing CALIBRATIONROOT" << std::endl; + std::cout << "CaloWaveformSim::InitRun missing CALIBRATIONROOT" << std::endl; exit(1); } std::string templatefilename = std::string(calibroot) + "/CaloWaveSim/" + m_templatefile; @@ -82,7 +82,6 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) } // Detector-specific setup - std::string url; if (m_dettype == CaloTowerDefs::CEMC) { m_detector = "CEMC"; @@ -127,37 +126,50 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) } // Data energy calibration - if (m_calibName.empty()) + // First check if the url is overridden in the macro (default is empty) + // Then check if the calibration name is overridden in the macro (default is empty) + if (m_directURL.empty()) { - m_calibName = m_detector + "_calib_ADC_to_ETower"; + if (m_calibName.empty()) + { + m_calibName = m_detector + "_calib_ADC_to_ETower"; + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_calibName << " as calib name" << std::endl; + } + } + m_directURL = CDBInterface::instance()->getUrl(m_calibName); } else { if (Verbosity() > 2) { - std::cout << PHWHERE << " using " << m_calibName << " as calib name" << std::endl; + std::cout << PHWHERE << Name() << ": using " << m_directURL << " as cdb file" << std::endl; } } - if (m_fieldname.empty()) + if (!m_directURL.empty()) { - m_fieldname = m_detector + "_calib_ADC_to_ETower"; + cdbttree = new CDBTTree(m_directURL); } else { - if (Verbosity() > 2) - { - std::cout << PHWHERE << " using " << m_fieldname << " as fieldname" << std::endl; - } + std::cout << Name() << ": CaloWaveformSim::InitRun No data calibration for " << m_calibName << std::endl; + exit(1); } - url = m_giveDirectURL ? m_directURL : CDBInterface::instance()->getUrl(m_calibName); - if (!url.empty()) + // check if the fieldname was overridden in the macro (default is empty), otherwise set it + if (m_fieldname.empty()) { - cdbttree = new CDBTTree(url); + m_fieldname = m_detector + "_calib_ADC_to_ETower"; } else { - std::cerr << "CaloWaveformSim::InitRun No data calibration for " << m_calibName << std::endl; - exit(1); + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_fieldname << " as fieldname" << std::endl; + } } // MC energy calibration (optional) @@ -169,7 +181,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) { m_MC_fieldname = m_detector + "_calib_ADC_to_ETower"; } - url = m_giveDirectURL_MC ? m_directURL_MC : CDBInterface::instance()->getUrl(m_MC_calibName); + std::string url = m_giveDirectURL_MC ? m_directURL_MC : CDBInterface::instance()->getUrl(m_MC_calibName); if (!url.empty()) { cdbttree_MC = new CDBTTree(url); diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index 1d95664326..a750c1a908 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -57,7 +57,6 @@ class CaloWaveformSim : public SubsysReco } void set_directURL_calib(const std::string &url) { - m_giveDirectURL = true; m_directURL = url; } @@ -155,17 +154,17 @@ class CaloWaveformSim : public SubsysReco LightCollectionModel &get_light_collection_model() { return light_collection_model; } private: - CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::CEMC}; - std::string m_detector{"CEMC"}; + CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::DETECTOR_INVALID}; + std::string m_detector; // Data energy calibration std::string m_fieldname; std::string m_calibName; - bool m_giveDirectURL{false}; std::string m_directURL; + // MC energy calibration - std::string m_MC_fieldname{"Femc_datadriven_qm1_correction"}; - std::string m_MC_calibName{"cemc_pi0_twrSlope_v1"}; + std::string m_MC_fieldname; + std::string m_MC_calibName; bool m_overrideMCFieldName{false}; bool m_overrideMCCalibName{false}; bool m_giveDirectURL_MC{false}; From 34ed7c70d793b3fd531a0a51f53fe9f1dc091e70 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 Jun 2026 19:26:53 -0400 Subject: [PATCH 702/866] cleanup override url for mc calib --- .../g4waveformsim/CaloWaveformSim.cc | 45 +++++++++++++++---- .../g4waveformsim/CaloWaveformSim.h | 8 ---- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index c2edf77f1a..ca194e9402 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -138,7 +138,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) { if (Verbosity() > 2) { - std::cout << PHWHERE << Name() << ": using " << m_calibName << " as calib name" << std::endl; + std::cout << PHWHERE << Name() << ": replacing calib name with " << m_calibName << std::endl; } } m_directURL = CDBInterface::instance()->getUrl(m_calibName); @@ -147,7 +147,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) { if (Verbosity() > 2) { - std::cout << PHWHERE << Name() << ": using " << m_directURL << " as cdb file" << std::endl; + std::cout << PHWHERE << Name() << ": using " << m_directURL << " as direct cdb file" << std::endl; } } if (!m_directURL.empty()) @@ -168,29 +168,56 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) { if (Verbosity() > 2) { - std::cout << PHWHERE << Name() << ": using " << m_fieldname << " as fieldname" << std::endl; + std::cout << PHWHERE << Name() << ": replacing fieldname with " << m_fieldname << std::endl; } } // MC energy calibration (optional) - if (!m_overrideMCCalibName) + if (m_directURL_MC.empty()) + { + if (m_MC_calibName.empty()) { m_MC_calibName = m_detector + "_MC_RECALIB"; } - if (!m_overrideMCFieldName) + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": replacing MC calib name with " << m_MC_calibName << std::endl; + } + } + std::cout << PHWHERE << Name() << ": m_MC_calibName: " << m_MC_calibName + << ", m_MC_fieldname: " << m_MC_fieldname << std::endl; + m_directURL_MC = CDBInterface::instance()->getUrl(m_MC_calibName); + } + else { - m_MC_fieldname = m_detector + "_calib_ADC_to_ETower"; + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_directURL_MC << " as direct MC cdb file" << std::endl; + } } - std::string url = m_giveDirectURL_MC ? m_directURL_MC : CDBInterface::instance()->getUrl(m_MC_calibName); - if (!url.empty()) + if (!m_directURL_MC.empty()) { - cdbttree_MC = new CDBTTree(url); + cdbttree_MC = new CDBTTree(m_directURL_MC); } else if (Verbosity() > 0) { std::cout << "CaloWaveformSim::InitRun No MC calibration for " << m_MC_calibName << std::endl; } + if (m_MC_fieldname.empty()) + { + m_MC_fieldname = m_detector + "_calib_ADC_to_ETower"; + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_MC_fieldname << " as MC fieldname" << std::endl; + } + } + std::string url; // Time calibration (data) if (!m_overrideTimeCalibName) { diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index a750c1a908..fac76c14de 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -64,20 +64,15 @@ class CaloWaveformSim : public SubsysReco void set_MC_fieldname(const std::string &MC_fieldname) { m_MC_fieldname = MC_fieldname; - m_overrideMCFieldName = true; } void set_MC_calibName(const std::string &MC_calibName) { m_MC_calibName = MC_calibName; - m_overrideMCCalibName = true; } void set_directURL_MCcalib(const std::string &url) { - m_giveDirectURL_MC = true; m_directURL_MC = url; } - void set_overrideMCFieldName(bool overrideField) { m_overrideMCFieldName = overrideField; } - void set_overrideMCCalibName(bool overrideCalib) { m_overrideMCCalibName = overrideCalib; } // Time calibration (data) void set_fieldname_time(const std::string &fieldname_time) @@ -165,9 +160,6 @@ class CaloWaveformSim : public SubsysReco // MC energy calibration std::string m_MC_fieldname; std::string m_MC_calibName; - bool m_overrideMCFieldName{false}; - bool m_overrideMCCalibName{false}; - bool m_giveDirectURL_MC{false}; std::string m_directURL_MC; bool m_smear_const{false}; From 4df2b548a4756d4865b27be601de2a0e6b4039b6 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 Jun 2026 20:54:43 -0400 Subject: [PATCH 703/866] cleanup override url for time calib --- .../g4waveformsim/CaloWaveformSim.cc | 118 ++++++++---------- .../g4waveformsim/CaloWaveformSim.h | 38 ++---- 2 files changed, 68 insertions(+), 88 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index ca194e9402..734760b544 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -73,7 +73,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) std::string templatefilename = std::string(calibroot) + "/CaloWaveSim/" + m_templatefile; TFile *ft = TFile::Open(templatefilename.c_str()); assert(ft && ft->IsOpen()); - ft->GetObject("hpwaveform",h_template); + ft->GetObject("hpwaveform", h_template); m_runNumber = recoConsts::instance()->get_IntFlag("RUNNUMBER"); if (Verbosity() > 0) @@ -138,7 +138,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) { if (Verbosity() > 2) { - std::cout << PHWHERE << Name() << ": replacing calib name with " << m_calibName << std::endl; + std::cout << PHWHERE << Name() << ": replacing calib name with " << m_calibName << std::endl; } } m_directURL = CDBInterface::instance()->getUrl(m_calibName); @@ -175,20 +175,18 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) // MC energy calibration (optional) if (m_directURL_MC.empty()) { - if (m_MC_calibName.empty()) - { - m_MC_calibName = m_detector + "_MC_RECALIB"; - } + if (m_MC_calibName.empty()) + { + m_MC_calibName = m_detector + "_MC_RECALIB"; + } else { if (Verbosity() > 2) { - std::cout << PHWHERE << Name() << ": replacing MC calib name with " << m_MC_calibName << std::endl; + std::cout << PHWHERE << Name() << ": replacing MC calib name with " << m_MC_calibName << std::endl; } } - std::cout << PHWHERE << Name() << ": m_MC_calibName: " << m_MC_calibName - << ", m_MC_fieldname: " << m_MC_fieldname << std::endl; - m_directURL_MC = CDBInterface::instance()->getUrl(m_MC_calibName); + m_directURL_MC = CDBInterface::instance()->getUrl(m_MC_calibName); } else { @@ -217,55 +215,57 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) std::cout << PHWHERE << Name() << ": using " << m_MC_fieldname << " as MC fieldname" << std::endl; } } - std::string url; + // Time calibration (data) - if (!m_overrideTimeCalibName) - { - m_calibName_time = m_detector + "_meanTime"; - } - if (m_giveDirectURL_time) - { - url = m_directURL_time; - } - else + if (m_dotimecalib) { - url = CDBInterface::instance()->getUrl(m_calibName_time); - if (url.empty()) + if (m_directURL_time.empty()) { - if (m_dotimecalib) + if (m_calibName_time.empty()) + { + m_calibName_time = m_detector + "_meanTime"; + } + else { - std::cerr << "CaloWaveformSim::InitRun No time calibration for " << m_calibName_time << std::endl; - exit(1); + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": replacing calib name with " << m_calibName << std::endl; + } } + m_directURL_time = CDBInterface::instance()->getUrl(m_calibName_time); + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_directURL_time << " as direct time cdb file" << std::endl; + } + } + if (m_directURL_time.empty()) + { + std::cout << "CaloWaveformSim::InitRun No time calibration for " << m_calibName_time << std::endl; + exit(1); } - } - if (m_dotimecalib) - { - cdbttree_time = new CDBTTree(url); - } - if (Verbosity() > 0 && m_dotimecalib) - { - std::cout << "CaloWaveformSim::InitRun Time calibration from " << url << std::endl; - } - // Time calibration (MC) - if (!m_overrideMCTimeCalibName) - { - m_MC_calibName_time = m_detector + "_MC_meanTime"; - } - if (m_giveDirectURL_MC_time) - { - url = m_directURL_MC_time; - cdbttree_MC_time = new CDBTTree(url); - } - else - { - url = CDBInterface::instance()->getUrl(m_MC_calibName_time); - if (!url.empty()) + cdbttree_time = new CDBTTree(m_directURL_time); + if (Verbosity() > 0 && m_dotimecalib) + { + std::cout << "CaloWaveformSim::InitRun Time calibration from " << m_directURL_time << std::endl; + } + // Time calibration (MC) + if (m_directURL_MC_time.empty()) + { + if (m_MC_calibName_time.empty()) + { + m_MC_calibName_time = m_detector + "_MC_meanTime"; + } + m_directURL_MC_time = CDBInterface::instance()->getUrl(m_MC_calibName_time); + } + if (!m_directURL_MC_time.empty()) { - cdbttree_MC_time = new CDBTTree(url); + cdbttree_MC_time = new CDBTTree(m_directURL_MC_time); } - else if (m_dotimecalib) + else { std::cerr << "CaloWaveformSim::InitRun No MC time calibration for " << m_MC_calibName_time << std::endl; exit(1); @@ -346,8 +346,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) exit(1); } - std::map tbt_smear; - + std::map tbt_smear; // loop over hits for (PHG4HitContainer::ConstIterator hititer = hits->getHits().first; hititer != hits->getHits().second; hititer++) @@ -373,13 +372,13 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { auto it = tbt_smear.find(key); - if(it != tbt_smear.end()) + if (it != tbt_smear.end()) { e_vis *= it->second; } else { - tbt_smear[key] = 1.0+ gsl_ran_gaussian(m_RandomGenerator,factor_const); + tbt_smear[key] = 1.0 + gsl_ran_gaussian(m_RandomGenerator, factor_const); e_vis *= tbt_smear[key]; } } @@ -405,7 +404,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) float t0 = hit->get_t(0) / m_sampletime; unsigned int tower_index = decode_tower(key); // here I will add the truth matching part - // for the cell reco, the truth matching info relys on edep not light yield, I will be consistent here :) + // for the cell reco, the truth matching info relies on edep not light yield, I will be consistent here :) TowerInfo *tower = m_CaloWaveformContainer->get_tower_at_channel(tower_index); TowerInfo::EdepMap &edepMap = tower->get_hitEdepMap(); TowerInfo::ShowerEdepMap &showerMap = tower->get_showerEdepMap(); @@ -474,7 +473,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) m_waveforms.at(i).at(j) += m_fixpedestal; } // saturate at 2^14 - 1 and make sure values are >= 0 - auto& sample = m_waveforms.at(i).at(j); + auto &sample = m_waveforms.at(i).at(j); sample = std::clamp(sample, 0.F, 16383.F); m_CaloWaveformContainer->get_tower_at_channel(i)->set_waveform_value(j, m_waveforms.at(i).at(j)); } @@ -545,13 +544,6 @@ void CaloWaveformSim::maphitetaphi(PHG4Hit *g4hit, unsigned short &etabin, unsig } } -//____________________________________________________________________________.. -int CaloWaveformSim::End(PHCompositeNode * /*topNode*/) -{ - std::cout << "CaloWaveformSim::End(PHCompositeNode *topNode) This is the End..." << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - void CaloWaveformSim::CreateNodeTree(PHCompositeNode *topNode) { PHNodeIterator topNodeItr(topNode); diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index fac76c14de..fc505104cd 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -40,7 +40,6 @@ class CaloWaveformSim : public SubsysReco int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode *topNode) override; // Detector configuration void set_detector_type(CaloTowerDefs::DetectorSystem dettype) { m_dettype = dettype; } @@ -83,7 +82,6 @@ class CaloWaveformSim : public SubsysReco void set_calibName_time(const std::string &calibName_time) { m_calibName_time = calibName_time; - m_overrideTimeCalibName = true; } void set_directURL_timecalib(const std::string &url) { @@ -91,23 +89,18 @@ class CaloWaveformSim : public SubsysReco m_directURL_time = url; } void set_dotimecalib(bool dotimecalib) { m_dotimecalib = dotimecalib; } - void set_overrideTimeFieldName(bool overrideField) { m_overrideTimeFieldName = overrideField; } - void set_overrideTimeCalibName(bool overrideCalib) { m_overrideTimeCalibName = overrideCalib; } // Time calibration (MC) void set_MC_fieldname_time(const std::string &MC_fieldname_time) { m_MC_fieldname_time = MC_fieldname_time; - m_overrideMCTimeFieldName = true; } void set_MC_calibName_time(const std::string &MC_calibName_time) { m_MC_calibName_time = MC_calibName_time; - m_overrideMCTimeCalibName = true; } void set_directURL_MCtimecalib(const std::string &url) { - m_giveDirectURL_MC_time = true; m_directURL_MC_time = url; } void set_smear_const(float val) @@ -115,8 +108,6 @@ class CaloWaveformSim : public SubsysReco m_smear_const = true; factor_const = val; } - void set_overrideMCTimeFieldName(bool overrideField) { m_overrideMCTimeFieldName = overrideField; } - void set_overrideMCTimeCalibName(bool overrideCalib) { m_overrideMCTimeCalibName = overrideCalib; } // Waveform template & sampling void set_templatefile(const std::string &templatefile) { m_templatefile = templatefile; } @@ -149,6 +140,17 @@ class CaloWaveformSim : public SubsysReco LightCollectionModel &get_light_collection_model() { return light_collection_model; } private: + void CreateNodeTree(PHCompositeNode *topNode); + void maphitetaphi(PHG4Hit *g4hit, + unsigned short &etabin, + unsigned short &phibin, + float &correction); + double template_function(double *x, double *par); + + // function pointers for use different decoders for hcals and cemc + unsigned int (*encode_tower)(unsigned int, unsigned int){TowerInfoDefs::encode_emcal}; + unsigned int (*decode_tower)(unsigned int){TowerInfoDefs::decode_emcal}; + CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::DETECTOR_INVALID}; std::string m_detector; @@ -167,18 +169,14 @@ class CaloWaveformSim : public SubsysReco // Data time calibration std::string m_fieldname_time{"time"}; - std::string m_calibName_time{"CEMC_meanTime"}; + std::string m_calibName_time; bool m_overrideTimeFieldName{false}; - bool m_overrideTimeCalibName{false}; bool m_dotimecalib{true}; bool m_giveDirectURL_time{false}; std::string m_directURL_time; // MC time calibration std::string m_MC_fieldname_time{"time"}; - std::string m_MC_calibName_time{"CEMC_meanTime"}; - bool m_overrideMCTimeFieldName{false}; - bool m_overrideMCTimeCalibName{false}; - bool m_giveDirectURL_MC_time{false}; + std::string m_MC_calibName_time; std::string m_directURL_MC_time; // Waveform settings @@ -209,9 +207,6 @@ class CaloWaveformSim : public SubsysReco std::vector> m_waveforms; int m_runNumber{0}; - unsigned int (*encode_tower)(unsigned int, unsigned int){TowerInfoDefs::encode_emcal}; - unsigned int (*decode_tower)(unsigned int){TowerInfoDefs::decode_emcal}; - CDBTTree *cdbttree{nullptr}; CDBTTree *cdbttree_MC{nullptr}; CDBTTree *cdbttree_time{nullptr}; @@ -220,13 +215,6 @@ class CaloWaveformSim : public SubsysReco LightCollectionModel light_collection_model; NoiseType m_noiseType{NOISE_TREE}; - - void CreateNodeTree(PHCompositeNode *topNode); - void maphitetaphi(PHG4Hit *g4hit, - unsigned short &etabin, - unsigned short &phibin, - float &correction); - double template_function(double *x, double *par); }; #endif // G4WAVEFORMSIM_CALOWAVEFORMSIM_H From 6cfd0637b9fd1290012623eb6549ca18c96ab74d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sat, 20 Jun 2026 21:10:03 -0400 Subject: [PATCH 704/866] iwyu --- .../g4waveformsim/CaloWaveformSim.cc | 20 ++++++----- .../g4waveformsim/CaloWaveformSim.h | 36 +++++++++---------- .../g4simulation/g4waveformsim/Makefile.am | 11 +++--- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 734760b544..aa54a82c5b 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -6,39 +6,43 @@ #include #include #include // for hit_idbits -#include -#include #include // for CDBTTree #include -#include - #include +#include +#include #include #include +#include #include #include #include #include +#include + #include #include #include -#include // for PHG4CylinderGeom_Spaca... #include #include #include #include #include -#include + +#include + #include #include -#include -#include +#include +#include +#include +#include double CaloWaveformSim::template_function(double *x, double *par) { diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index fc505104cd..e0f6760111 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -17,7 +17,6 @@ #include -#include #include #include @@ -28,7 +27,6 @@ class TProfile; class PHG4Hit; class PHG4CylinderCellGeom_Spacalv1; class PHG4CylinderGeom_Spacalv3; -class TTree; class CDBTTree; class TowerInfoContainer; @@ -77,7 +75,6 @@ class CaloWaveformSim : public SubsysReco void set_fieldname_time(const std::string &fieldname_time) { m_fieldname_time = fieldname_time; - m_overrideTimeFieldName = true; } void set_calibName_time(const std::string &calibName_time) { @@ -85,7 +82,6 @@ class CaloWaveformSim : public SubsysReco } void set_directURL_timecalib(const std::string &url) { - m_giveDirectURL_time = true; m_directURL_time = url; } void set_dotimecalib(bool dotimecalib) { m_dotimecalib = dotimecalib; } @@ -151,7 +147,22 @@ class CaloWaveformSim : public SubsysReco unsigned int (*encode_tower)(unsigned int, unsigned int){TowerInfoDefs::encode_emcal}; unsigned int (*decode_tower)(unsigned int){TowerInfoDefs::decode_emcal}; + // containers + TowerInfoContainer *m_CaloWaveformContainer{nullptr}; + TowerInfoContainer *m_PedestalContainer{nullptr}; + + CDBTTree *cdbttree{nullptr}; + CDBTTree *cdbttree_MC{nullptr}; + CDBTTree *cdbttree_time{nullptr}; + CDBTTree *cdbttree_MC_time{nullptr}; + TProfile *h_template{nullptr}; + + gsl_rng *m_RandomGenerator{nullptr}; + PHG4CylinderCellGeom_Spacalv1 *geo{nullptr}; + const PHG4CylinderGeom_Spacalv3 *layergeom{nullptr}; + CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::DETECTOR_INVALID}; + std::string m_detector; // Data energy calibration @@ -170,15 +181,14 @@ class CaloWaveformSim : public SubsysReco // Data time calibration std::string m_fieldname_time{"time"}; std::string m_calibName_time; - bool m_overrideTimeFieldName{false}; - bool m_dotimecalib{true}; - bool m_giveDirectURL_time{false}; std::string m_directURL_time; // MC time calibration std::string m_MC_fieldname_time{"time"}; std::string m_MC_calibName_time; std::string m_directURL_MC_time; + bool m_dotimecalib{true}; + // Waveform settings std::string m_templatefile{"waveformtemptempohcalcosmic.root"}; int m_nsamples{31}; @@ -187,10 +197,6 @@ class CaloWaveformSim : public SubsysReco int m_nchannels{24576}; float m_sampling_fraction{1.0f}; - // containers - TowerInfoContainer *m_CaloWaveformContainer{nullptr}; - TowerInfoContainer *m_PedestalContainer{nullptr}; - // Shaping & noise int m_fixpedestal{1500}; int m_gaussian_noise{3}; @@ -201,17 +207,9 @@ class CaloWaveformSim : public SubsysReco float m_peakpos{6.}; float m_pedestal_scale{1.}; - gsl_rng *m_RandomGenerator{nullptr}; - PHG4CylinderCellGeom_Spacalv1 *geo{nullptr}; - const PHG4CylinderGeom_Spacalv3 *layergeom{nullptr}; std::vector> m_waveforms; int m_runNumber{0}; - CDBTTree *cdbttree{nullptr}; - CDBTTree *cdbttree_MC{nullptr}; - CDBTTree *cdbttree_time{nullptr}; - CDBTTree *cdbttree_MC_time{nullptr}; - TProfile *h_template{nullptr}; LightCollectionModel light_collection_model; NoiseType m_noiseType{NOISE_TREE}; diff --git a/simulation/g4simulation/g4waveformsim/Makefile.am b/simulation/g4simulation/g4waveformsim/Makefile.am index bc96947bdc..744aec7ea8 100644 --- a/simulation/g4simulation/g4waveformsim/Makefile.am +++ b/simulation/g4simulation/g4waveformsim/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign AM_CPPFLAGS = \ -I$(includedir) \ - -I$(OFFLINE_MAIN)/include \ + -isystem$(OFFLINE_MAIN)/include \ -isystem$(ROOTSYS)/include AM_LDFLAGS = \ @@ -20,15 +20,12 @@ libCaloWaveformSim_la_SOURCES = \ CaloWaveformSim.cc libCaloWaveformSim_la_LIBADD = \ - -lphool \ - -lSubsysReco \ -lcalo_io \ - -lfun4all \ + -lcdbobjects \ -lg4detectors \ -lg4detectors_io \ - -lcalo_io \ - -lcdbobjects \ - -lphg4hit + -lphg4hit \ + -lSubsysReco BUILT_SOURCES = testexternals.cc From 450f84b14a4e215989d5f65b2ee850b92135c44c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 Jun 2026 09:15:01 -0400 Subject: [PATCH 705/866] fix valgrind leaks, listen to the rabbit --- .../g4waveformsim/CaloWaveformSim.cc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index aa54a82c5b..4319689d8c 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -58,6 +58,11 @@ CaloWaveformSim::CaloWaveformSim(const std::string &name) CaloWaveformSim::~CaloWaveformSim() { gsl_rng_free(m_RandomGenerator); + delete cdbttree; + delete cdbttree_MC; + delete cdbttree_time; + delete cdbttree_MC_time; + delete h_template; } int CaloWaveformSim::InitRun(PHCompositeNode *topNode) @@ -78,6 +83,12 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) TFile *ft = TFile::Open(templatefilename.c_str()); assert(ft && ft->IsOpen()); ft->GetObject("hpwaveform", h_template); + if (!h_template) + { + std::cout << "Could not get hpwaveform TProfile from " << templatefilename << std::endl; + gSystem->Exit(1); + } + h_template->SetDirectory(nullptr); m_runNumber = recoConsts::instance()->get_IntFlag("RUNNUMBER"); if (Verbosity() > 0) @@ -102,7 +113,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) m_sampling_fraction = 0.162166; m_nchannels = 1536; } - else // HCALOUT + else if (m_dettype == CaloTowerDefs::HCALOUT) { m_detector = "HCALOUT"; encode_tower = TowerInfoDefs::encode_hcal; @@ -110,7 +121,11 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) m_sampling_fraction = 3.38021e-02; m_nchannels = 1536; } - + else + { + std::cout << PHWHERE << " Invalid detector type " << m_dettype << ", must call set_dettype() first" << std::endl; + exit(1); + } // Gain settings // nobody understands this construct, please keep in mind that other // people have to read this and figure out what it does From 264fce4bf6ab109e7b8c3957b11c3efa1d64fb58 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 21 Jun 2026 09:41:49 -0400 Subject: [PATCH 706/866] promote NoRunTTree() method to input mgr base class --- offline/framework/fun4all/Fun4AllInputManager.h | 5 +++-- offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4all/Fun4AllInputManager.h b/offline/framework/fun4all/Fun4AllInputManager.h index a198906c48..b3f66d5817 100644 --- a/offline/framework/fun4all/Fun4AllInputManager.h +++ b/offline/framework/fun4all/Fun4AllInputManager.h @@ -50,8 +50,9 @@ class Fun4AllInputManager : public Fun4AllBase, public InputFileHandler void InputNode(const std::string &innode) { m_InputNode = innode; } const std::string &TopNodeName() const { return m_TopNodeName; } void Verbosity(const uint64_t ival) override; - - protected: + virtual int NoRunTTree() {return -1;} + +protected: Fun4AllInputManager(const std::string &name = "DUMMY", const std::string &nodename = "DST", const std::string &topnodename = "TOP"); Fun4AllSyncManager *MySyncManager() { return m_MySyncManager; } void DisableReadCache() { m_disable_read_cache_flag = true; } diff --git a/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h b/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h index 13cdec2ba4..66ccebd165 100644 --- a/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h +++ b/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h @@ -28,7 +28,7 @@ class Fun4AllNoSyncDstInputManager : public Fun4AllDstInputManager int setSyncBranches(PHNodeIOManager* /*IManager*/) override { return 0; } // turn off reading of the runwise TTree to make run mixing for embedding possible - int NoRunTTree(); + int NoRunTTree() override; int SkipForThisManager(const int nevents) override { return PushBackEvents(nevents); } int HasSyncObject() const override { return 0; } From aeb7495af49ffe26ee47709240f3526d341700ee Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 10:02:25 -0400 Subject: [PATCH 707/866] trigger jenkins From 31e892a79d20beac755094c2c16786c017efa4c5 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 11:46:59 -0400 Subject: [PATCH 708/866] put the debug flag into the data struct --- offline/packages/tpc/TpcClusterizer.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 28a6ea7a9a..751fd28c0c 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -160,6 +160,7 @@ namespace hitMaskTpcSet *hotMap = nullptr; bool maskDead = false; bool maskHot = false; + bool debug = false; std::vector association_vector; std::vector cluster_vector; @@ -909,13 +910,13 @@ namespace { TrkrCluster* clus = nullptr; - if (m_debug) + if (my_data.debug) { - clus = new TrkrClusterv6; + clus = new TrkrClusterv6; } else { - clus = new TrkrClusterv5; + clus = new TrkrClusterv5; } // auto *clus = new TrkrClusterv6; @@ -957,6 +958,7 @@ namespace clus->setTBinHi(tbinhi); clus->setPadPhase(padphase); clus->setTBinPhase(tbinphase); + my_data.cluster_vector.push_back(clus); b_made_cluster = true; } @@ -1762,7 +1764,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.phioffset = PhiOffset; thread_pair.data.tbins = NTBinsSide; thread_pair.data.toffset = TOffset; - + thread_pair.data.debug = m_debug; thread_pair.data.radius = layergeom->get_radius(); thread_pair.data.drift_velocity = m_tGeometry->get_drift_velocity(); thread_pair.data.pads_per_sector = 0; From 4f21774a48ebe0aaa8c1c4711213775ae3b1f67f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 11:47:12 -0400 Subject: [PATCH 709/866] add the functions to the base class --- offline/packages/trackbase/TrkrCluster.h | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index f37440646b..ffae2910d6 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -104,6 +104,35 @@ class TrkrCluster : public PHObject virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } + virtual void setSLEdge(const char) {}; + virtual void setSREdge(const char) {}; + virtual void setTLEdge(const char) {}; + virtual void setTREdge(const char) {}; + virtual void setDLEdge(const char) {}; + virtual void setDREdge(const char) {}; + virtual void setHLEdge(const char) {}; + virtual void setHREdge(const char) {}; + virtual void setSLMix(const int) {}; + virtual void setSRMix(const int) {}; + virtual void setTLMix(const int) {}; + virtual void setTRMix(const int) {}; + virtual void setPhiBinLo(const float) {}; + virtual void setPhiBinHi(const float) {}; + virtual void setTBinLo(const float) {}; + virtual void setTBinHi(const float) {}; + virtual void setPadPhase(const float) {}; + virtual void setTBinPhase(const float) {}; + virtual void setRSize(const float) {}; + virtual void setCenAdc(const unsigned int) {}; + virtual void setPadCen(const float) {}; + virtual void setTBinCen(const float) {}; + virtual void setPadMax(const float) {}; + virtual void setTBinMax(const float) {}; + virtual void setPhiError(const float) {}; + virtual void setZError(const float) {}; + virtual void setPhiSize(const float) {}; + virtual void setZSize(const float) {}; + /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } From e08f803676c1f09f9d7eeccd35a72c5ef9841a94 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 11:52:22 -0400 Subject: [PATCH 710/866] fix compilation --- offline/QA/Tracking/TpcSeedsQA.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/QA/Tracking/TpcSeedsQA.cc b/offline/QA/Tracking/TpcSeedsQA.cc index dc78d7d51c..3a23895c18 100644 --- a/offline/QA/Tracking/TpcSeedsQA.cc +++ b/offline/QA/Tracking/TpcSeedsQA.cc @@ -73,7 +73,7 @@ int TpcSeedsQA::InitRun(PHCompositeNode *topNode) // global position wrapper m_globalPositionWrapper.loadNodes(topNode); - m_clusterMover.initialize_geometry(g4geom); + m_clusterMover.initialize_geometry(g4geom, actsgeom); m_clusterMover.set_verbosity(0); auto *hm = QAHistManagerDef::getHistoManager(); From dd0c6b9e7ae7c7b74fbb2fadf2ead0f46f78b458 Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Mon, 22 Jun 2026 23:53:24 +0800 Subject: [PATCH 711/866] add truth track fitter --- offline/packages/trackreco/Makefile.am | 6 +- .../packages/trackreco/PHTruthTrackFitter.cc | 628 ++++++++++++++++++ .../packages/trackreco/PHTruthTrackFitter.h | 90 +++ 3 files changed, 722 insertions(+), 2 deletions(-) create mode 100644 offline/packages/trackreco/PHTruthTrackFitter.cc create mode 100644 offline/packages/trackreco/PHTruthTrackFitter.h diff --git a/offline/packages/trackreco/Makefile.am b/offline/packages/trackreco/Makefile.am index e4f9f448cc..7c34ef2652 100644 --- a/offline/packages/trackreco/Makefile.am +++ b/offline/packages/trackreco/Makefile.am @@ -75,8 +75,9 @@ pkginclude_HEADERS = \ PHTrackSetMerging.h \ PHTrackSetCopyMerging.h \ PHTruthClustering.h \ - PHTruthTrackSeeding.h \ PHTruthSiliconAssociation.h \ + PHTruthTrackFitter.h \ + PHTruthTrackSeeding.h \ PHTruthVertexing.h \ PrelimDistortionCorrection.h \ PrelimDistortionCorrectionAuAu.h \ @@ -161,9 +162,10 @@ libtrack_reco_la_SOURCES = \ PHTrackPropagating.cc \ PHTrackFitting.cc \ PHTruthClustering.cc \ + PHTruthSiliconAssociation.cc \ + PHTruthTrackFitter.cc \ PHTruthTrackSeeding.cc \ PHTruthVertexing.cc \ - PHTruthSiliconAssociation.cc \ PrelimDistortionCorrection.cc \ PrelimDistortionCorrectionAuAu.cc \ SecondaryVertexFinder.cc \ diff --git a/offline/packages/trackreco/PHTruthTrackFitter.cc b/offline/packages/trackreco/PHTruthTrackFitter.cc new file mode 100644 index 0000000000..9466c40df5 --- /dev/null +++ b/offline/packages/trackreco/PHTruthTrackFitter.cc @@ -0,0 +1,628 @@ +#include "PHTruthTrackFitter.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + template + inline constexpr T square(const T& x) + { + return x * x; + } + + bool is_finite(float value) + { + return std::isfinite(value); + } + + float average_or(float a, float b, float fallback) + { + const bool aok = is_finite(a); + const bool bok = is_finite(b); + + if (aok && bok) + { + return 0.5 * (a + b); + } + if (aok) + { + return a; + } + if (bok) + { + return b; + } + + return fallback; + } + + bool valid_track_id(unsigned int trackid) + { + return trackid != std::numeric_limits::max(); + } +} // namespace + +PHTruthTrackFitter::PHTruthTrackFitter(const std::string& name) + : SubsysReco(name) +{ +} + +int PHTruthTrackFitter::InitRun(PHCompositeNode* topNode) +{ + if (Verbosity() > 0) + { + std::cout << "PHTruthTrackFitter::InitRun - output track map: " << m_trackMapName << std::endl; + } + + if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + if (getNodes(topNode) != Fun4AllReturnCodes::EVENT_OK) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::process_event(PHCompositeNode* /*topNode*/) +{ + m_trackMap->Reset(); + + unsigned int skipped_tracks = 0; + for (auto seed : *m_seedMap) + { + if (!seed) + { + continue; + } + + auto* tpc_seed = getSeed(m_tpcSeeds, seed->get_tpc_seed_index()); + auto* silicon_seed = getSeed(m_siliconSeeds, seed->get_silicon_seed_index()); + + if (!tpc_seed && !silicon_seed) + { + ++skipped_tracks; + continue; + } + + const auto truth_track_id = getTruthTrackId(seed, tpc_seed, silicon_seed); + if (!valid_track_id(truth_track_id)) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - could not determine truth id for seed" << std::endl; + } + ++skipped_tracks; + continue; + } + + auto* g4particle = m_g4TruthInfo->GetParticle(truth_track_id); + if (!g4particle) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - no PHG4Particle for track id " + << truth_track_id << std::endl; + } + ++skipped_tracks; + continue; + } + + const auto* g4vertex = m_g4TruthInfo->GetVtx(g4particle->get_vtx_id()); + if (!g4vertex) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - no PHG4VtxPoint for track id " + << truth_track_id << std::endl; + } + ++skipped_tracks; + continue; + } + + SvtxTrack_v4 track; + track.set_tpc_seed(tpc_seed); + track.set_silicon_seed(silicon_seed); + track.set_crossing(getCrossing(tpc_seed, silicon_seed)); + track.set_vertex_id(g4particle->get_vtx_id()); + track.set_charge(getCharge(g4particle, tpc_seed, silicon_seed)); + track.set_chisq(0); + + track.set_x(g4vertex->get_x()); + track.set_y(g4vertex->get_y()); + track.set_z(g4vertex->get_z()); + track.set_px(g4particle->get_px()); + track.set_py(g4particle->get_py()); + track.set_pz(g4particle->get_pz()); + + for (int i = 0; i < 6; ++i) + { + for (int j = i; j < 6; ++j) + { + track.set_error(i, j, 0); + } + } + track.set_error(0, 0, square(m_positionError)); + track.set_error(1, 1, square(m_positionError)); + track.set_error(2, 2, square(m_zError)); + + unsigned int state_index = 1; + for (const auto* track_seed : {silicon_seed, tpc_seed}) + { + if (!track_seed) + { + continue; + } + + for (auto iter = track_seed->begin_cluster_keys(); iter != track_seed->end_cluster_keys(); ++iter) + { + if (addStateFromCluster(&track, *iter, truth_track_id, g4particle, g4vertex, state_index)) + { + ++state_index; + } + } + } + + if (track.size_states() <= 1) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - no truth states for track id " + << truth_track_id << std::endl; + } + ++skipped_tracks; + continue; + } + + track.set_ndf(std::max(0, 2 * static_cast(track.size_states()) - 5)); + + const unsigned int track_id = m_trackMap->size(); + track.set_id(track_id); + m_trackMap->insertWithKey(&track, track_id); + } + + if (Verbosity() > 0) + { + std::cout << "PHTruthTrackFitter::process_event - built " << m_trackMap->size() + << " truth tracks, skipped " << skipped_tracks << std::endl; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::End(PHCompositeNode* /*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::createNodes(PHCompositeNode* topNode) +{ + PHNodeIterator iter(topNode); + + auto* dst_node = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dst_node) + { + std::cerr << PHWHERE << "DST node is missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + PHNodeIterator dst_iter(dst_node); + auto* svtx_node = dynamic_cast(dst_iter.findFirst("PHCompositeNode", "SVTX")); + if (!svtx_node) + { + svtx_node = new PHCompositeNode("SVTX"); + dst_node->addNode(svtx_node); + } + + m_trackMap = findNode::getClass(topNode, m_trackMapName); + if (!m_trackMap) + { + m_trackMap = new SvtxTrackMap_v2; + auto* track_node = new PHIODataNode(m_trackMap, m_trackMapName, "PHObject"); + svtx_node->addNode(track_node); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::getNodes(PHCompositeNode* topNode) +{ + m_seedMap = findNode::getClass(topNode, m_svtxSeedMapName); + if (!m_seedMap) + { + std::cout << PHWHERE << "No " << m_svtxSeedMapName << " on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_tpcSeeds = findNode::getClass(topNode, "TpcTrackSeedContainer"); + if (!m_tpcSeeds) + { + std::cout << PHWHERE << "No TpcTrackSeedContainer on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_siliconSeeds = findNode::getClass(topNode, "SiliconTrackSeedContainer"); + if (!m_siliconSeeds) + { + std::cout << PHWHERE << "No SiliconTrackSeedContainer on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_clusterMap = findNode::getClass(topNode, m_clusterMapName); + if (!m_clusterMap) + { + std::cout << PHWHERE << "No " << m_clusterMapName << " on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_clusterHitMap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + if (!m_clusterHitMap) + { + std::cout << PHWHERE << "No TRKR_CLUSTERHITASSOC on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_hitTruthAssoc = findNode::getClass(topNode, "TRKR_HITTRUTHASSOC"); + if (!m_hitTruthAssoc) + { + std::cout << PHWHERE << "No TRKR_HITTRUTHASSOC on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_g4TruthInfo = findNode::getClass(topNode, "G4TruthInfo"); + if (!m_g4TruthInfo) + { + std::cout << PHWHERE << "No G4TruthInfo on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_g4HitsTpc = findNode::getClass(topNode, "G4HIT_TPC"); + m_g4HitsIntt = findNode::getClass(topNode, "G4HIT_INTT"); + m_g4HitsMvtx = findNode::getClass(topNode, "G4HIT_MVTX"); + m_g4HitsMicromegas = findNode::getClass(topNode, "G4HIT_MICROMEGAS"); + + return Fun4AllReturnCodes::EVENT_OK; +} + +TrackSeed* PHTruthTrackFitter::getSeed(TrackSeedContainer* container, unsigned int index) const +{ + if (!container || index >= container->size()) + { + return nullptr; + } + + return container->get(index); +} + +unsigned int PHTruthTrackFitter::getTruthTrackId(const TrackSeed* svtxSeed, + const TrackSeed* tpcSeed, + const TrackSeed* siliconSeed) const +{ + for (const auto* seed : {svtxSeed, tpcSeed, siliconSeed}) + { + if (!seed) + { + continue; + } + + const auto truth_track_id = seed->get_truth_track_id(); + if (valid_track_id(truth_track_id)) + { + return truth_track_id; + } + } + + std::map truth_counts; + countTruthHits(tpcSeed, truth_counts); + countTruthHits(siliconSeed, truth_counts); + + if (truth_counts.empty()) + { + return m_invalidTruthTrackId; + } + + const auto best_iter = std::max_element(truth_counts.begin(), truth_counts.end(), + [](const auto& lhs, const auto& rhs) + { return lhs.second < rhs.second; }); + + return best_iter->first >= 0 ? static_cast(best_iter->first) : m_invalidTruthTrackId; +} + +void PHTruthTrackFitter::countTruthHits(const TrackSeed* seed, std::map& counts) const +{ + if (!seed) + { + return; + } + + for (auto iter = seed->begin_cluster_keys(); iter != seed->end_cluster_keys(); ++iter) + { + for (const auto* g4hit : getTruthHits(*iter)) + { + if (!g4hit) + { + continue; + } + + const auto track_id = g4hit->get_trkid(); + if (track_id >= 0) + { + ++counts[track_id]; + } + } + } +} + +std::vector PHTruthTrackFitter::getTruthHits(TrkrDefs::cluskey cluskey) const +{ + std::vector truth_hits; + if (!m_clusterHitMap || !m_hitTruthAssoc) + { + return truth_hits; + } + + const auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); + const auto trkrid = TrkrDefs::getTrkrId(hitsetkey); + const auto hitrange = m_clusterHitMap->getHits(cluskey); + + std::set used_g4hits; + for (auto clushititer = hitrange.first; clushititer != hitrange.second; ++clushititer) + { + const auto hitkey = clushititer->second; + + TrkrHitTruthAssoc::MMap temp_map; + m_hitTruthAssoc->getG4Hits(hitsetkey, hitkey, temp_map); + + for (const auto& hit_truth_iter : temp_map) + { + const auto g4hitkey = hit_truth_iter.second.second; + if (!used_g4hits.insert(g4hitkey).second) + { + continue; + } + + const auto* g4hit = getG4Hit(trkrid, g4hitkey); + if (g4hit) + { + truth_hits.push_back(g4hit); + } + } + } + + return truth_hits; +} + +const PHG4Hit* PHTruthTrackFitter::getG4Hit(unsigned int trkrid, PHG4HitDefs::keytype g4hitkey) const +{ + PHG4HitContainer* container = nullptr; + switch (trkrid) + { + case TrkrDefs::tpcId: + container = m_g4HitsTpc; + break; + case TrkrDefs::inttId: + container = m_g4HitsIntt; + break; + case TrkrDefs::mvtxId: + container = m_g4HitsMvtx; + break; + case TrkrDefs::micromegasId: + container = m_g4HitsMicromegas; + break; + default: + break; + } + + return container ? container->findHit(g4hitkey) : nullptr; +} + +bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track, + TrkrDefs::cluskey cluskey, + unsigned int truthTrackId, + const PHG4Particle* particle, + const PHG4VtxPoint* vertex, + unsigned int stateIndex) const +{ + if (!m_clusterMap->findCluster(cluskey)) + { + return false; + } + + double weight_sum = 0; + double x = 0; + double y = 0; + double z = 0; + double px = 0; + double py = 0; + double pz = 0; + double local_x = 0; + double local_y = 0; + + for (const auto* g4hit : getTruthHits(cluskey)) + { + if (!g4hit || g4hit->get_trkid() != static_cast(truthTrackId)) + { + continue; + } + + const auto hit_x = average_or(g4hit->get_x(0), g4hit->get_x(1), std::numeric_limits::quiet_NaN()); + const auto hit_y = average_or(g4hit->get_y(0), g4hit->get_y(1), std::numeric_limits::quiet_NaN()); + const auto hit_z = average_or(g4hit->get_z(0), g4hit->get_z(1), std::numeric_limits::quiet_NaN()); + if (!is_finite(hit_x) || !is_finite(hit_y) || !is_finite(hit_z)) + { + continue; + } + + const auto hit_px = average_or(g4hit->get_px(0), g4hit->get_px(1), particle->get_px()); + const auto hit_py = average_or(g4hit->get_py(0), g4hit->get_py(1), particle->get_py()); + const auto hit_pz = average_or(g4hit->get_pz(0), g4hit->get_pz(1), particle->get_pz()); + const auto hit_local_x = average_or(g4hit->get_local_x(0), g4hit->get_local_x(1), 0); + const auto hit_local_y = average_or(g4hit->get_local_y(0), g4hit->get_local_y(1), 0); + + double weight = g4hit->get_edep(); + if (!std::isfinite(weight) || weight <= 0) + { + weight = 1; + } + + weight_sum += weight; + x += weight * hit_x; + y += weight * hit_y; + z += weight * hit_z; + px += weight * hit_px; + py += weight * hit_py; + pz += weight * hit_pz; + local_x += weight * hit_local_x; + local_y += weight * hit_local_y; + } + + if (weight_sum <= 0) + { + return false; + } + + x /= weight_sum; + y /= weight_sum; + z /= weight_sum; + px /= weight_sum; + py /= weight_sum; + pz /= weight_sum; + local_x /= weight_sum; + local_y /= weight_sum; + + float pathlength = getPathLength(vertex, x, y, z, stateIndex); + while (track->count_states(pathlength) != 0) + { + pathlength += 1.e-3; + } + + SvtxTrackState_v3 state(pathlength); + state.set_name("PHTruthTrackFitter"); + state.set_cluskey(cluskey); + state.set_x(x); + state.set_y(y); + state.set_z(z); + state.set_px(px); + state.set_py(py); + state.set_pz(pz); + state.set_localX(local_x); + state.set_localY(local_y); + + for (int i = 0; i < 6; ++i) + { + for (int j = i; j < 6; ++j) + { + state.set_error(i, j, 0); + } + } + state.set_error(0, 0, square(m_positionError)); + state.set_error(1, 1, square(m_positionError)); + state.set_error(2, 2, square(m_zError)); + + track->insert_state(&state); + return true; +} + +float PHTruthTrackFitter::getPathLength(const PHG4VtxPoint* vertex, + float x, float y, float z, + unsigned int stateIndex) const +{ + if (vertex) + { + const auto dx = x - vertex->get_x(); + const auto dy = y - vertex->get_y(); + const auto dz = z - vertex->get_z(); + const auto pathlength = std::sqrt(square(dx) + square(dy) + square(dz)); + if (std::isfinite(pathlength) && pathlength > 0) + { + return pathlength; + } + } + + return static_cast(stateIndex); +} + +int PHTruthTrackFitter::getCharge(const PHG4Particle* particle, + const TrackSeed* tpcSeed, + const TrackSeed* siliconSeed) const +{ + for (const auto* seed : {tpcSeed, siliconSeed}) + { + if (!seed) + { + continue; + } + + const auto charge = seed->get_charge(); + if (std::abs(charge) == 1) + { + return charge; + } + } + + const auto* pdg_particle = particle ? TDatabasePDG::Instance()->GetParticle(particle->get_pid()) : nullptr; + if (pdg_particle && pdg_particle->Charge() < 0) + { + return -1; + } + + return 1; +} + +short int PHTruthTrackFitter::getCrossing(const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const +{ + for (const auto* seed : {siliconSeed, tpcSeed}) + { + if (!seed) + { + continue; + } + + const auto crossing = seed->get_crossing(); + if (crossing != std::numeric_limits::max()) + { + return crossing; + } + } + + return m_defaultCrossing; +} diff --git a/offline/packages/trackreco/PHTruthTrackFitter.h b/offline/packages/trackreco/PHTruthTrackFitter.h new file mode 100644 index 0000000000..207d95668b --- /dev/null +++ b/offline/packages/trackreco/PHTruthTrackFitter.h @@ -0,0 +1,90 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef TRACKRECO_PHTRUTHTRACKFITTER_H +#define TRACKRECO_PHTRUTHTRACKFITTER_H + +#include + +#include +#include + +#include +#include +#include +#include + +class PHCompositeNode; +class PHG4Hit; +class PHG4HitContainer; +class PHG4Particle; +class PHG4TruthInfoContainer; +class PHG4VtxPoint; +class SvtxTrack; +class SvtxTrackMap; +class TrackSeed; +class TrackSeedContainer; +class TrkrClusterContainer; +class TrkrClusterHitAssoc; +class TrkrHitTruthAssoc; + +class PHTruthTrackFitter : public SubsysReco +{ + public: + PHTruthTrackFitter(const std::string& name = "PHTruthTrackFitter"); + ~PHTruthTrackFitter() override = default; + + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + int End(PHCompositeNode* topNode) override; + + void setTrackMapName(const std::string& name) { m_trackMapName = name; } + void setSvtxSeedMapName(const std::string& name) { m_svtxSeedMapName = name; } + void setTrkrClusterContainerName(const std::string& name) { m_clusterMapName = name; } + void setDefaultCrossing(short int crossing) { m_defaultCrossing = crossing; } + void setPositionError(float value) { m_positionError = value; } + void setZError(float value) { m_zError = value; } + + private: + int createNodes(PHCompositeNode* topNode); + int getNodes(PHCompositeNode* topNode); + + TrackSeed* getSeed(TrackSeedContainer* container, unsigned int index) const; + unsigned int getTruthTrackId(const TrackSeed* svtxSeed, const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; + void countTruthHits(const TrackSeed* seed, std::map& counts) const; + + std::vector getTruthHits(TrkrDefs::cluskey cluskey) const; + const PHG4Hit* getG4Hit(unsigned int trkrid, PHG4HitDefs::keytype g4hitkey) const; + + bool addStateFromCluster(SvtxTrack* track, TrkrDefs::cluskey cluskey, unsigned int truthTrackId, + const PHG4Particle* particle, const PHG4VtxPoint* vertex, + unsigned int stateIndex) const; + float getPathLength(const PHG4VtxPoint* vertex, float x, float y, float z, unsigned int stateIndex) const; + int getCharge(const PHG4Particle* particle, const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; + short int getCrossing(const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; + + std::string m_trackMapName = "SvtxTrackMap"; + std::string m_svtxSeedMapName = "SvtxTrackSeedContainer"; + std::string m_clusterMapName = "TRKR_CLUSTER"; + + TrackSeedContainer* m_seedMap = nullptr; + TrackSeedContainer* m_tpcSeeds = nullptr; + TrackSeedContainer* m_siliconSeeds = nullptr; + SvtxTrackMap* m_trackMap = nullptr; + TrkrClusterContainer* m_clusterMap = nullptr; + TrkrClusterHitAssoc* m_clusterHitMap = nullptr; + TrkrHitTruthAssoc* m_hitTruthAssoc = nullptr; + PHG4TruthInfoContainer* m_g4TruthInfo = nullptr; + + PHG4HitContainer* m_g4HitsTpc = nullptr; + PHG4HitContainer* m_g4HitsIntt = nullptr; + PHG4HitContainer* m_g4HitsMvtx = nullptr; + PHG4HitContainer* m_g4HitsMicromegas = nullptr; + + short int m_defaultCrossing = 0; + float m_positionError = 0.005; + float m_zError = 0.01; + + static constexpr unsigned int m_invalidTruthTrackId = std::numeric_limits::max(); +}; + +#endif From b907bb5a1079aa093debd1509e639297aa3ce169 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 12:44:13 -0400 Subject: [PATCH 712/866] all of the member variables should now be the correct type --- offline/packages/trackbase/TrkrClusterv6.h | 130 ++++++++++----------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 37ffdffbbf..adbd3d4728 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -60,7 +60,7 @@ class TrkrClusterv6 : public TrkrCluster { return (coor >= 0 && coor < 2) ? m_local[coor] : std::numeric_limits::quiet_NaN(); } - void setPosition(int coor, float xi) override + void setPosition(const int coor, const float xi) override { if (coor >= 0 && coor < 2) { @@ -68,36 +68,36 @@ class TrkrClusterv6 : public TrkrCluster } } float getLocalX() const override { return m_local[0]; } - void setLocalX(float loc0) override { m_local[0] = loc0; } + void setLocalX(const float loc0) override { m_local[0] = loc0; } float getLocalY() const override { return m_local[1]; } - void setLocalY(float loc1) override { m_local[1] = loc1; } + void setLocalY(const float loc1) override { m_local[1] = loc1; } TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } - void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } // // cluster info // unsigned int getAdc() const override { return m_adc; } - void setAdc(unsigned int adc) override { m_adc = adc; } + void setAdc(const unsigned int adc) override { m_adc = adc; } unsigned int getMaxAdc() const override { return m_maxadc; } - void setMaxAdc(uint16_t maxadc) override { m_maxadc = maxadc; } + void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } unsigned int getCenAdc() const override { return m_cenadc; } - void setCenAdc(uint16_t cenadc) { m_cenadc = cenadc; } + void setCenAdc(const uint16_t cenadc) { m_cenadc = cenadc; } float getPadCen() const override { return m_padcen; } - void setPadCen(float padcen) { m_padcen = padcen; } + void setPadCen(const float padcen) { m_padcen = padcen; } float getTBinCen() const override { return m_tbincen; } - void setTBinCen(float tbincen) { m_tbincen = tbincen; } + void setTBinCen(const float tbincen) { m_tbincen = tbincen; } float getPadMax() const override { return m_padmax; } - void setPadMax(float padmax) { m_padmax = padmax; } + void setPadMax(const float padmax) { m_padmax = padmax; } float getTBinMax() const override { return m_tbinmax; } - void setTBinMax(float tbinmax) { m_tbinmax = tbinmax; } + void setTBinMax(const float tbinmax) { m_tbinmax = tbinmax; } // // convenience interface @@ -105,80 +105,80 @@ class TrkrClusterv6 : public TrkrCluster float getRPhiError() const override { return m_phierr; } float getZError() const override { return m_zerr; } - void setPhiError(float phierror) { m_phierr = phierror; } - void setZError(float zerror) { m_zerr = zerror; } + void setPhiError(const float phierror) { m_phierr = phierror; } + void setZError(const float zerror) { m_zerr = zerror; } char getSize() const override { return m_phisize * m_zsize; } - // void setSize(char size) { m_size = size; } + // void setSize(const char size) { m_size = size; } float getRSize() const override { return (float) m_rsize; } - void setRSize(unsigned char rsize) { m_rsize = rsize; } + void setRSize(const unsigned char rsize) { m_rsize = rsize; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(const char phisize) { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(const char zsize) { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } - void setOverlap(char overlap) override { m_overlap = overlap; } + void setOverlap(const char overlap) override { m_overlap = overlap; } char getEdge() const override { return m_edge; } - void setEdge(char edge) override { m_edge = edge; } + void setEdge(const char edge) override { m_edge = edge; } char getSLEdge() const override { return m_sledge; } - void setSLEdge(char sledge) { m_sledge = sledge; } + void setSLEdge(const char sledge) { m_sledge = sledge; } char getSREdge() const override { return m_sredge; } - void setSREdge(char sredge) { m_sredge = sredge; } + void setSREdge(const char sredge) { m_sredge = sredge; } char getTLEdge() const override { return m_tledge; } - void setTLEdge(char tledge) { m_tledge = tledge; } + void setTLEdge(const char tledge) { m_tledge = tledge; } char getTREdge() const override { return m_tredge; } - void setTREdge(char tredge) { m_tredge = tredge; } + void setTREdge(const char tredge) { m_tredge = tredge; } char getDLEdge() const override { return m_dledge; } - void setDLEdge(char dledge) { m_dledge = dledge; } + void setDLEdge(const char dledge) { m_dledge = dledge; } char getDREdge() const override { return m_dredge; } - void setDREdge(char dredge) { m_dredge = dredge; } + void setDREdge(const char dredge) { m_dredge = dredge; } char getHLEdge() const override { return m_hledge; } - void setHLEdge(char hledge) { m_hledge = hledge; } + void setHLEdge(const char hledge) { m_hledge = hledge; } char getHREdge() const override { return m_hredge; } - void setHREdge(char hredge) { m_hredge = hredge; } + void setHREdge(const char hredge) { m_hredge = hredge; } int getSLMix() const override { return m_slmix; } - void setSLMix(char slmix) { m_slmix = slmix; } + void setSLMix(const char slmix) { m_slmix = slmix; } int getSRMix() const override { return m_srmix; } - void setSRMix(char srmix) { m_srmix = srmix; } + void setSRMix(const char srmix) { m_srmix = srmix; } int getTLMix() const override { return m_tlmix; } - void setTLMix(char tlmix) { m_tlmix = tlmix; } + void setTLMix(const char tlmix) { m_tlmix = tlmix; } int getTRMix() const override { return m_trmix; } - void setTRMix(char trmix) { m_trmix = trmix; } + void setTRMix(const char trmix) { m_trmix = trmix; } float getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(float phibinlo) { m_phibinlo = phibinlo; } + void setPhiBinLo(const float phibinlo) { m_phibinlo = phibinlo; } float getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(float phibinhi) { m_phibinhi = phibinhi; } + void setPhiBinHi(const float phibinhi) { m_phibinhi = phibinhi; } - float getTBinLo() const override { return m_tbinlo; } - void setTBinLo(float tbinlo) { m_tbinlo = tbinlo; } + char getTBinLo() const override { return m_tbinlo; } + void setTBinLo(const char tbinlo) { m_tbinlo = tbinlo; } - float getTBinHi() const override { return m_tbinhi; } - void setTBinHi(float tbinhi) { m_tbinhi = tbinhi; } + char getTBinHi() const override { return m_tbinhi; } + void setTBinHi(const char tbinhi) { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } - void setPadPhase(float padphase) { m_padphase = padphase; } + void setPadPhase(const float padphase) { m_padphase = padphase; } float getTBinPhase() const override { return m_tbinphase; } - void setTBinPhase(float tbinphase){ m_tbinphase = tbinphase; } + void setTBinPhase(const float tbinphase){ m_tbinphase = tbinphase; } private: float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; @@ -186,34 +186,34 @@ class TrkrClusterv6 : public TrkrCluster TrkrDefs::subsurfkey m_subsurfkey {TrkrDefs::SUBSURFKEYMAX}; //< unique identifier for hitsetkey-surface maps 16 bit float m_phierr{0}; float m_zerr{0}; - unsigned short int m_adc{0}; //< cluster sum adc 16 - unsigned short int m_maxadc{0}; //< cluster max adc 16 - unsigned short int m_cenadc{0}; //< cluster centroid adc 16 + unsigned short m_adc{0}; //< cluster sum adc 16 + unsigned short m_maxadc{0}; //< cluster max adc 16 + unsigned short m_cenadc{0}; //< cluster centroid adc 16 float m_padcen{0}; float m_tbincen{0}; - float m_padmax{0}; - float m_tbinmax{0}; - unsigned char m_rsize{0}; // 8bit - char m_phisize{0}; // 8bit - char m_zsize{0}; // 8bit - char m_overlap{0}; // 8bit - char m_edge{0}; // 8bit - cumul 2*64 - char m_sledge{0}; // 8bit - char m_sredge{0}; // 8bit - char m_tledge{0}; // 8bit - char m_tredge{0}; // 8bit - char m_dledge{0}; // 8bit - char m_dredge{0}; // 8bit - char m_hledge{0}; // 8bit - char m_hredge{0}; // 8bit - char m_slmix{0}; // 8bit - char m_srmix{0}; // 8bit - char m_tlmix{0}; // 8bit - char m_trmix{0}; // 8bit - float m_phibinlo{0}; - float m_phibinhi{0}; - float m_tbinlo{0}; - float m_tbinhi{0}; + int m_padmax{0}; + int m_tbinmax{0}; + unsigned char m_rsize{0}; + unsigned char m_phisize{0}; + unsigned char m_zsize{0}; + char m_overlap{0}; + char m_edge{0}; + char m_sledge{0}; + char m_sredge{0}; + char m_tledge{0}; + char m_tredge{0}; + char m_dledge{0}; + char m_dredge{0}; + char m_hledge{0}; + char m_hredge{0}; + char m_slmix{0}; + char m_srmix{0}; + char m_tlmix{0}; + char m_trmix{0}; + char m_phibinlo{0}; + char m_phibinhi{0}; + char m_tbinlo{0}; + char m_tbinhi{0}; float m_padphase{0}; float m_tbinphase{0}; From 2505444b4467b6b7056bc1ff9890d0b5e7da4bb3 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 22 Jun 2026 11:22:00 -0600 Subject: [PATCH 713/866] Update offline/packages/trackreco/PHTrackPruner.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/trackreco/PHTrackPruner.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index 12816dc596..bbd6cdee1f 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -197,7 +197,7 @@ bool PHTrackPruner::checkTrack(SvtxTrack *track) } // high pt cut - if( m_track_pt_high_cut>0 && track->get_pt() < m_track_pt_high_cut) + if( m_track_pt_high_cut>0 && track->get_pt() > m_track_pt_high_cut) { if (Verbosity() > 1) { std::cout <<"Track pt "<get_pt()<<" , pt cut "< Date: Mon, 22 Jun 2026 14:54:12 -0400 Subject: [PATCH 714/866] try to make everything consistent --- offline/packages/tpc/TpcClusterizer.cc | 3 - offline/packages/trackbase/TrkrCluster.h | 40 ++++++------- offline/packages/trackbase/TrkrClusterv6.h | 70 +++++++++++----------- 3 files changed, 55 insertions(+), 58 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 751fd28c0c..a2ed3c0169 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -919,9 +919,6 @@ namespace clus = new TrkrClusterv5; } - // auto *clus = new TrkrClusterv6; - // auto *clus = new TrkrClusterv5; - // auto clus = std::make_unique(); clus_base = clus; clus->setLocalX(local(0)); clus->setLocalY(clust); diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index ffae2910d6..2312df181b 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -82,8 +82,8 @@ class TrkrCluster : public PHObject virtual unsigned int getCenAdc() const { return UINT_MAX; } virtual float getPadCen() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinCen() const { return std::numeric_limits::quiet_NaN(); } - virtual float getPadMax() const { return std::numeric_limits::quiet_NaN(); } - virtual float getTBinMax() const { return std::numeric_limits::quiet_NaN(); } + virtual int getPadMax() const { return std::numeric_limits::max(); } + virtual int getTBinMax() const { return std::numeric_limits::max(); } virtual char getSLEdge() const { return std::numeric_limits::max(); } virtual char getSREdge() const { return std::numeric_limits::max(); } virtual char getTLEdge() const { return std::numeric_limits::max(); } @@ -96,10 +96,10 @@ class TrkrCluster : public PHObject virtual int getSRMix() const { return std::numeric_limits::max(); } virtual int getTLMix() const { return std::numeric_limits::max(); } virtual int getTRMix() const { return std::numeric_limits::max(); } - virtual float getPhiBinLo() const { return std::numeric_limits::quiet_NaN(); } - virtual float getPhiBinHi() const { return std::numeric_limits::quiet_NaN(); } - virtual float getTBinLo() const { return std::numeric_limits::quiet_NaN(); } - virtual float getTBinHi() const { return std::numeric_limits::quiet_NaN(); } + virtual char getPhiBinLo() const { return std::numeric_limits::max(); } + virtual char getPhiBinHi() const { return std::numeric_limits::max(); } + virtual char getTBinLo() const { return std::numeric_limits::max(); } + virtual char getTBinHi() const { return std::numeric_limits::max(); } virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } @@ -112,26 +112,26 @@ class TrkrCluster : public PHObject virtual void setDREdge(const char) {}; virtual void setHLEdge(const char) {}; virtual void setHREdge(const char) {}; - virtual void setSLMix(const int) {}; - virtual void setSRMix(const int) {}; - virtual void setTLMix(const int) {}; - virtual void setTRMix(const int) {}; - virtual void setPhiBinLo(const float) {}; - virtual void setPhiBinHi(const float) {}; - virtual void setTBinLo(const float) {}; - virtual void setTBinHi(const float) {}; + virtual void setSLMix(const char) {}; + virtual void setSRMix(const char) {}; + virtual void setTLMix(const char) {}; + virtual void setTRMix(const char) {}; + virtual void setPhiBinLo(const char) {}; + virtual void setPhiBinHi(const char) {}; + virtual void setTBinLo(const char) {}; + virtual void setTBinHi(const char) {}; virtual void setPadPhase(const float) {}; virtual void setTBinPhase(const float) {}; - virtual void setRSize(const float) {}; - virtual void setCenAdc(const unsigned int) {}; + virtual void setRSize(const char) {}; + virtual void setCenAdc(const uint16_t) {}; virtual void setPadCen(const float) {}; virtual void setTBinCen(const float) {}; - virtual void setPadMax(const float) {}; - virtual void setTBinMax(const float) {}; + virtual void setPadMax(const int) {}; + virtual void setTBinMax(const int) {}; virtual void setPhiError(const float) {}; virtual void setZError(const float) {}; - virtual void setPhiSize(const float) {}; - virtual void setZSize(const float) {}; + virtual void setPhiSize(const char) {}; + virtual void setZSize(const char) {}; /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index adbd3d4728..52276126d0 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -85,19 +85,19 @@ class TrkrClusterv6 : public TrkrCluster void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } unsigned int getCenAdc() const override { return m_cenadc; } - void setCenAdc(const uint16_t cenadc) { m_cenadc = cenadc; } + void setCenAdc(const uint16_t cenadc) override { m_cenadc = cenadc; } float getPadCen() const override { return m_padcen; } - void setPadCen(const float padcen) { m_padcen = padcen; } + void setPadCen(const float padcen) override { m_padcen = padcen; } float getTBinCen() const override { return m_tbincen; } - void setTBinCen(const float tbincen) { m_tbincen = tbincen; } + void setTBinCen(const float tbincen) override { m_tbincen = tbincen; } - float getPadMax() const override { return m_padmax; } - void setPadMax(const float padmax) { m_padmax = padmax; } + int getPadMax() const override { return m_padmax; } + void setPadMax(const int padmax) override { m_padmax = padmax; } - float getTBinMax() const override { return m_tbinmax; } - void setTBinMax(const float tbinmax) { m_tbinmax = tbinmax; } + int getTBinMax() const override { return m_tbinmax; } + void setTBinMax(const int tbinmax) override { m_tbinmax = tbinmax; } // // convenience interface @@ -105,20 +105,20 @@ class TrkrClusterv6 : public TrkrCluster float getRPhiError() const override { return m_phierr; } float getZError() const override { return m_zerr; } - void setPhiError(const float phierror) { m_phierr = phierror; } - void setZError(const float zerror) { m_zerr = zerror; } + void setPhiError(const float phierror) override { m_phierr = phierror; } + void setZError(const float zerror) override { m_zerr = zerror; } char getSize() const override { return m_phisize * m_zsize; } // void setSize(const char size) { m_size = size; } float getRSize() const override { return (float) m_rsize; } - void setRSize(const unsigned char rsize) { m_rsize = rsize; } + void setRSize(const char rsize) override { m_rsize = rsize; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(const char phisize) { m_phisize = phisize; } + void setPhiSize(const char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(const char zsize) { m_zsize = zsize; } + void setZSize(const char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } void setOverlap(const char overlap) override { m_overlap = overlap; } @@ -127,58 +127,58 @@ class TrkrClusterv6 : public TrkrCluster void setEdge(const char edge) override { m_edge = edge; } char getSLEdge() const override { return m_sledge; } - void setSLEdge(const char sledge) { m_sledge = sledge; } + void setSLEdge(const char sledge) override { m_sledge = sledge; } char getSREdge() const override { return m_sredge; } - void setSREdge(const char sredge) { m_sredge = sredge; } + void setSREdge(const char sredge) override { m_sredge = sredge; } char getTLEdge() const override { return m_tledge; } - void setTLEdge(const char tledge) { m_tledge = tledge; } + void setTLEdge(const char tledge) override { m_tledge = tledge; } char getTREdge() const override { return m_tredge; } - void setTREdge(const char tredge) { m_tredge = tredge; } + void setTREdge(const char tredge) override { m_tredge = tredge; } char getDLEdge() const override { return m_dledge; } - void setDLEdge(const char dledge) { m_dledge = dledge; } + void setDLEdge(const char dledge) override { m_dledge = dledge; } char getDREdge() const override { return m_dredge; } - void setDREdge(const char dredge) { m_dredge = dredge; } + void setDREdge(const char dredge) override { m_dredge = dredge; } char getHLEdge() const override { return m_hledge; } - void setHLEdge(const char hledge) { m_hledge = hledge; } + void setHLEdge(const char hledge) override { m_hledge = hledge; } char getHREdge() const override { return m_hredge; } - void setHREdge(const char hredge) { m_hredge = hredge; } + void setHREdge(const char hredge) override { m_hredge = hredge; } int getSLMix() const override { return m_slmix; } - void setSLMix(const char slmix) { m_slmix = slmix; } + void setSLMix(const char slmix) override { m_slmix = slmix; } int getSRMix() const override { return m_srmix; } - void setSRMix(const char srmix) { m_srmix = srmix; } + void setSRMix(const char srmix) override { m_srmix = srmix; } int getTLMix() const override { return m_tlmix; } - void setTLMix(const char tlmix) { m_tlmix = tlmix; } + void setTLMix(const char tlmix) override { m_tlmix = tlmix; } int getTRMix() const override { return m_trmix; } - void setTRMix(const char trmix) { m_trmix = trmix; } + void setTRMix(const char trmix) override { m_trmix = trmix; } - float getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(const float phibinlo) { m_phibinlo = phibinlo; } + char getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(const char phibinlo) override { m_phibinlo = phibinlo; } - float getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(const float phibinhi) { m_phibinhi = phibinhi; } + char getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(const char phibinhi) override { m_phibinhi = phibinhi; } char getTBinLo() const override { return m_tbinlo; } - void setTBinLo(const char tbinlo) { m_tbinlo = tbinlo; } + void setTBinLo(const char tbinlo) override { m_tbinlo = tbinlo; } char getTBinHi() const override { return m_tbinhi; } - void setTBinHi(const char tbinhi) { m_tbinhi = tbinhi; } + void setTBinHi(const char tbinhi) override { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } - void setPadPhase(const float padphase) { m_padphase = padphase; } + void setPadPhase(const float padphase) override { m_padphase = padphase; } float getTBinPhase() const override { return m_tbinphase; } - void setTBinPhase(const float tbinphase){ m_tbinphase = tbinphase; } + void setTBinPhase(const float tbinphase) override { m_tbinphase = tbinphase; } private: float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; @@ -193,9 +193,9 @@ class TrkrClusterv6 : public TrkrCluster float m_tbincen{0}; int m_padmax{0}; int m_tbinmax{0}; - unsigned char m_rsize{0}; - unsigned char m_phisize{0}; - unsigned char m_zsize{0}; + char m_rsize{0}; + char m_phisize{0}; + char m_zsize{0}; char m_overlap{0}; char m_edge{0}; char m_sledge{0}; From dc21c7e51b1b7f0996ee8e7771e653fe6ebf18f5 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 15:17:56 -0400 Subject: [PATCH 715/866] fix rabbit suggestions --- offline/packages/tpc/TpcClusterizer.cc | 1 + offline/packages/trackbase/TrkrCluster.h | 16 +++++++-------- offline/packages/trackbase/TrkrClusterv6.h | 24 +++++++++++----------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index a2ed3c0169..45e3011fcf 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1850,6 +1850,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.pedestal = pedestal; thread_pair.data.sector = sector; thread_pair.data.side = side; + thread_pair.data.debug = m_debug; thread_pair.data.do_assoc = do_hit_assoc; thread_pair.data.do_wedge_emulation = do_wedge_emulation; thread_pair.data.tGeometry = m_tGeometry; diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 2312df181b..d6cefd9e65 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -96,10 +96,10 @@ class TrkrCluster : public PHObject virtual int getSRMix() const { return std::numeric_limits::max(); } virtual int getTLMix() const { return std::numeric_limits::max(); } virtual int getTRMix() const { return std::numeric_limits::max(); } - virtual char getPhiBinLo() const { return std::numeric_limits::max(); } - virtual char getPhiBinHi() const { return std::numeric_limits::max(); } - virtual char getTBinLo() const { return std::numeric_limits::max(); } - virtual char getTBinHi() const { return std::numeric_limits::max(); } + virtual int getPhiBinLo() const { return std::numeric_limits::max(); } + virtual int getPhiBinHi() const { return std::numeric_limits::max(); } + virtual int getTBinLo() const { return std::numeric_limits::max(); } + virtual int getTBinHi() const { return std::numeric_limits::max(); } virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } @@ -116,10 +116,10 @@ class TrkrCluster : public PHObject virtual void setSRMix(const char) {}; virtual void setTLMix(const char) {}; virtual void setTRMix(const char) {}; - virtual void setPhiBinLo(const char) {}; - virtual void setPhiBinHi(const char) {}; - virtual void setTBinLo(const char) {}; - virtual void setTBinHi(const char) {}; + virtual void setPhiBinLo(const int) {}; + virtual void setPhiBinHi(const int) {}; + virtual void setTBinLo(const int) {}; + virtual void setTBinHi(const int) {}; virtual void setPadPhase(const float) {}; virtual void setTBinPhase(const float) {}; virtual void setRSize(const char) {}; diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 52276126d0..46b77b4dd8 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -162,17 +162,17 @@ class TrkrClusterv6 : public TrkrCluster int getTRMix() const override { return m_trmix; } void setTRMix(const char trmix) override { m_trmix = trmix; } - char getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(const char phibinlo) override { m_phibinlo = phibinlo; } + int getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(const int phibinlo) override { m_phibinlo = phibinlo; } - char getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(const char phibinhi) override { m_phibinhi = phibinhi; } + int getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(const int phibinhi) override { m_phibinhi = phibinhi; } - char getTBinLo() const override { return m_tbinlo; } - void setTBinLo(const char tbinlo) override { m_tbinlo = tbinlo; } + int getTBinLo() const override { return m_tbinlo; } + void setTBinLo(const int tbinlo) override { m_tbinlo = tbinlo; } - char getTBinHi() const override { return m_tbinhi; } - void setTBinHi(const char tbinhi) override { m_tbinhi = tbinhi; } + int getTBinHi() const override { return m_tbinhi; } + void setTBinHi(const int tbinhi) override { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } void setPadPhase(const float padphase) override { m_padphase = padphase; } @@ -210,10 +210,10 @@ class TrkrClusterv6 : public TrkrCluster char m_srmix{0}; char m_tlmix{0}; char m_trmix{0}; - char m_phibinlo{0}; - char m_phibinhi{0}; - char m_tbinlo{0}; - char m_tbinhi{0}; + int m_phibinlo{0}; + int m_phibinhi{0}; + int m_tbinlo{0}; + int m_tbinhi{0}; float m_padphase{0}; float m_tbinphase{0}; From 2a789518fddfad051a6649fb34be59dc04cd89c1 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 15:53:10 -0400 Subject: [PATCH 716/866] add crossing to ntp_gtrack --- simulation/g4simulation/g4eval/SvtxEvaluator.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 0ac2c85287..7cc5d184b3 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -174,7 +174,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gfpx:gfpy:gfpz:gfx:gfy:gfz:" "gembed:gprimary:gparentflavor:gparentid:gprimaryflavor:gprimaryid:" "trackID:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:" - "siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" + "crossing:siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" "charge:quality:chisq:ndf:nhits:layers:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:nlmaps:nlintt:nltpc:nlmms:" "vertexID:vx:vy:vz:dca2d:dca2dsigma:dca3dxy:dca3dxysigma:dca3dz:dca3dzsigma:pcax:pcay:pcaz:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" "npedge:nredge:nbig:novlp:merr:msize:" @@ -2893,6 +2893,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float quality = std::numeric_limits::quiet_NaN(); float chisq = std::numeric_limits::quiet_NaN(); float ndf = std::numeric_limits::quiet_NaN(); + float crossing = std::numeric_limits::quiet_NaN(); float local_nhits = 0; float nmaps = 0; float nintt = 0; @@ -2977,6 +2978,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) quality = track->get_quality(); chisq = track->get_chisq(); ndf = track->get_ndf(); + short int crossing_int = track->get_crossing(); + if (crossing_int != SHRT_MAX) + { + crossing = (float) crossing_int; + } TrackSeed* silseed = track->get_silicon_seed(); TrackSeed* tpcseed = track->get_tpc_seed(); if (tpcseed) @@ -3344,6 +3350,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) deltapt, deltaeta, deltaphi, + crossing, siqr, siphi, sithe, From 638d7c59520864d50529ca72ebbd219b07d56f52 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Mon, 22 Jun 2026 15:47:16 -0500 Subject: [PATCH 717/866] CaloTowerStatus: Z-Score Patch - Modified `CaloTowerStatus::LoadCalib` to calculate `need_z_score` based on whether `z_score_threshold` deviates from its default. - Wrapped the `GetFloatValue` call for the z_score field in a conditional check, eliminating the slowdowns for EMCal Hot Map CDB TTree that do not have the "CEMC_sigma" field. --- offline/packages/CaloReco/CaloTowerStatus.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 795ee97c3f..277e5efc6b 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -154,6 +154,9 @@ void CaloTowerStatus::LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotM unsigned int ntowers = m_raw_towers->size(); m_cdbInfo_vec.resize(ntowers); + // Check if we actually need to evaluate the z_score + bool need_z_score = (z_score_threshold != z_score_threshold_default); + for (unsigned int channel = 0; channel < ntowers; channel++) { unsigned int key = m_raw_towers->encode_key(channel); @@ -165,7 +168,12 @@ void CaloTowerStatus::LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotM if (m_doHotMap && cdbttree_hotMap) { m_cdbInfo_vec[channel].hotMap_val = cdbttree_hotMap->GetIntValue(key, m_fieldname_hotMap); - m_cdbInfo_vec[channel].z_score = cdbttree_hotMap->GetFloatValue(key, m_fieldname_z_score); + + // Only fetch the z_score field if the custom threshold requires it + if (need_z_score) + { + m_cdbInfo_vec[channel].z_score = cdbttree_hotMap->GetFloatValue(key, m_fieldname_z_score); + } } } } From 5e25f6c264c43688dbf35f81e99b7eb34dc860d8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 21:05:41 -0400 Subject: [PATCH 718/866] clang-tidy --- offline/packages/trackreco/PHTrackPruner.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index bbd6cdee1f..6e0cdb9878 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -108,7 +108,7 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) << std::endl; } - if (_svtx_track_map->size() == 0) + if (_svtx_track_map->empty()) { return Fun4AllReturnCodes::EVENT_OK; } From 7aef9730f5c20b9ef282f92dca70f17c076c6ed8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 21:23:35 -0400 Subject: [PATCH 719/866] make base class and derived classes consistent --- offline/packages/trackbase/TrkrCluster.h | 14 ++++++------- offline/packages/trackbase/TrkrClusterv4.cc | 2 +- offline/packages/trackbase/TrkrClusterv4.h | 4 ++-- offline/packages/trackbase/TrkrClusterv5.cc | 2 +- offline/packages/trackbase/TrkrClusterv5.h | 22 ++++++++++----------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index d6cefd9e65..4eaeac407e 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -52,21 +52,21 @@ class TrkrCluster : public PHObject // cluster position // virtual float getLocalX() const { return std::numeric_limits::quiet_NaN(); } - virtual void setLocalX(float) {} + virtual void setLocalX(const float) {} virtual float getLocalY() const { return std::numeric_limits::quiet_NaN(); } - virtual void setLocalY(float) {} + virtual void setLocalY(const float) {} // // cluster info // - virtual void setAdc(unsigned int) {} + virtual void setAdc(const unsigned int) {} virtual unsigned int getAdc() const { return UINT_MAX; } - virtual void setMaxAdc(uint16_t) {} + virtual void setMaxAdc(const uint16_t) {} virtual unsigned int getMaxAdc() const { return UINT_MAX; } virtual char getOverlap() const { return std::numeric_limits::max(); } - virtual void setOverlap(char) {} + virtual void setOverlap(const char) {} virtual char getEdge() const { return std::numeric_limits::max(); } - virtual void setEdge(char) {} + virtual void setEdge(const char) {} virtual void setTime(const float) {} virtual float getTime() const { return std::numeric_limits::quiet_NaN(); } virtual char getSize() const { return std::numeric_limits::max(); } @@ -137,7 +137,7 @@ class TrkrCluster : public PHObject virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual TrkrDefs::subsurfkey getSubSurfKey() const { return TrkrDefs::SUBSURFKEYMAX; } - virtual void setSubSurfKey(TrkrDefs::subsurfkey /*id*/) {} + virtual void setSubSurfKey(const TrkrDefs::subsurfkey /*id*/) {} // Global coordinate functions are deprecated, use local // coordinate functions only diff --git a/offline/packages/trackbase/TrkrClusterv4.cc b/offline/packages/trackbase/TrkrClusterv4.cc index 542c1530cc..8ee11bf797 100644 --- a/offline/packages/trackbase/TrkrClusterv4.cc +++ b/offline/packages/trackbase/TrkrClusterv4.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv4.h b/offline/packages/trackbase/TrkrClusterv4.h index ec0bc4703c..439e3d9aef 100644 --- a/offline/packages/trackbase/TrkrClusterv4.h +++ b/offline/packages/trackbase/TrkrClusterv4.h @@ -160,10 +160,10 @@ class TrkrClusterv4 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } void setOverlap(char overlap) override { m_overlap = overlap; } diff --git a/offline/packages/trackbase/TrkrClusterv5.cc b/offline/packages/trackbase/TrkrClusterv5.cc index 58e08745ad..a0cc7fbe52 100644 --- a/offline/packages/trackbase/TrkrClusterv5.cc +++ b/offline/packages/trackbase/TrkrClusterv5.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index ebb0bae961..ee3ac20755 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -54,12 +54,12 @@ class TrkrClusterv5 : public TrkrCluster float getPosition(int coor) const override { return m_local[coor]; } void setPosition(int coor, float xi) override { m_local[coor] = xi; } float getLocalX() const override { return m_local[0]; } - void setLocalX(float loc0) override { m_local[0] = loc0; } + void setLocalX(const float loc0) override { m_local[0] = loc0; } float getLocalY() const override { return m_local[1]; } - void setLocalY(float loc1) override { m_local[1] = loc1; } + void setLocalY(const float loc1) override { m_local[1] = loc1; } TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } - void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } // // cluster info @@ -69,7 +69,7 @@ class TrkrClusterv5 : public TrkrCluster return m_adc; } - void setAdc(unsigned int adc) override + void setAdc(const unsigned int adc) override { m_adc = adc; } @@ -79,7 +79,7 @@ class TrkrClusterv5 : public TrkrCluster return m_maxadc; } - void setMaxAdc(uint16_t maxadc) override + void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } @@ -96,11 +96,11 @@ class TrkrClusterv5 : public TrkrCluster return m_zerr; } - void setPhiError(float phierror) + void setPhiError(const float phierror) override { m_phierr = phierror; } - void setZError(float zerror) + void setZError(const float zerror) override { m_zerr = zerror; } @@ -156,16 +156,16 @@ class TrkrClusterv5 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(const char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(const char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } - void setOverlap(char overlap) override { m_overlap = overlap; } + void setOverlap(const char overlap) override { m_overlap = overlap; } char getEdge() const override { return m_edge; } - void setEdge(char edge) override { m_edge = edge; } + void setEdge(const char edge) override { m_edge = edge; } // float getPhiSize() const override //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} From 3854e03585d80e1ead504ce61dab0f602ce0414d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 21:39:12 -0400 Subject: [PATCH 720/866] resolve some clang-tidy issues --- .../TrackingDiagnostics/TrackResiduals.cc | 20 +++++++++---------- .../TrackingDiagnostics/TrackResiduals.h | 20 +++++++++---------- offline/packages/tpc/TpcClusterizer.cc | 3 ++- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index d123176d70..d8f816fad6 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -1843,16 +1843,16 @@ void TrackResiduals::createBranches() m_clustree->Branch("tbinhi", &m_tbinhi, "m_tbinhi/F"); m_clustree->Branch("padphase", &m_padphase, "m_padphase/F"); m_clustree->Branch("tbinphase", &m_tbinphase, "m_tbinphase/F"); - m_clustree->Branch("overlap", &m_overlap, "m_overlap/I"); - m_clustree->Branch("nedge", &m_nedge, "m_nedge/I"); - m_clustree->Branch("sledge", &m_sledge, "m_sledge/I"); - m_clustree->Branch("sredge", &m_sredge, "m_sredge/I"); - m_clustree->Branch("tledge", &m_tledge, "m_tledge/I"); - m_clustree->Branch("tredge", &m_tredge, "m_tredge/I"); - m_clustree->Branch("dledge", &m_dledge, "m_dledge/I"); - m_clustree->Branch("dredge", &m_dredge, "m_dredge/I"); - m_clustree->Branch("hledge", &m_hledge, "m_hledge/I"); - m_clustree->Branch("hredge", &m_hredge, "m_hredge/I"); + m_clustree->Branch("overlap", &m_overlap, "m_overlap/C"); + m_clustree->Branch("nedge", &m_nedge, "m_nedge/C"); + m_clustree->Branch("sledge", &m_sledge, "m_sledge/C"); + m_clustree->Branch("sredge", &m_sredge, "m_sredge/C"); + m_clustree->Branch("tledge", &m_tledge, "m_tledge/C"); + m_clustree->Branch("tredge", &m_tredge, "m_tredge/C"); + m_clustree->Branch("dledge", &m_dledge, "m_dledge/C"); + m_clustree->Branch("dredge", &m_dredge, "m_dredge/C"); + m_clustree->Branch("hledge", &m_hledge, "m_hledge/C"); + m_clustree->Branch("hredge", &m_hredge, "m_hredge/C"); m_clustree->Branch("slmix", &m_slmix, "m_slmix/I"); m_clustree->Branch("srmix", &m_srmix, "m_srmix/I"); m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/I"); diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 6601fc47c9..6729bfbb04 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -251,16 +251,16 @@ class TrackResiduals : public SubsysReco int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); - int m_overlap = std::numeric_limits::quiet_NaN(); - int m_nedge = std::numeric_limits::quiet_NaN(); - int m_sledge = std::numeric_limits::quiet_NaN(); - int m_sredge = std::numeric_limits::quiet_NaN(); - int m_tledge = std::numeric_limits::quiet_NaN(); - int m_tredge = std::numeric_limits::quiet_NaN(); - int m_dledge = std::numeric_limits::quiet_NaN(); - int m_dredge = std::numeric_limits::quiet_NaN(); - int m_hledge = std::numeric_limits::quiet_NaN(); - int m_hredge = std::numeric_limits::quiet_NaN(); + char m_overlap = std::numeric_limits::quiet_NaN(); + char m_nedge = std::numeric_limits::quiet_NaN(); + char m_sledge = std::numeric_limits::quiet_NaN(); + char m_sredge = std::numeric_limits::quiet_NaN(); + char m_tledge = std::numeric_limits::quiet_NaN(); + char m_tredge = std::numeric_limits::quiet_NaN(); + char m_dledge = std::numeric_limits::quiet_NaN(); + char m_dredge = std::numeric_limits::quiet_NaN(); + char m_hledge = std::numeric_limits::quiet_NaN(); + char m_hredge = std::numeric_limits::quiet_NaN(); int m_slmix = std::numeric_limits::quiet_NaN(); int m_srmix = std::numeric_limits::quiet_NaN(); int m_tlmix = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 45e3011fcf..6548abeb5f 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -85,6 +85,7 @@ namespace unsigned short edge = 0; }; + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) struct ClusterCounters { int overlap = 0; @@ -114,7 +115,7 @@ namespace *this = ClusterCounters{}; } }; - + // NOLINTEND(misc-non-private-member-variables-in-classes) using vec_dVerbose = std::vector>>; // Neural network parameters and modules From bdf6a589eff54c742a07ed50c7c48f8595e072e3 Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Tue, 23 Jun 2026 11:56:59 +0800 Subject: [PATCH 721/866] store truth id in truth track seeds --- offline/packages/trackreco/PHTruthSiliconAssociation.cc | 2 ++ offline/packages/trackreco/PHTruthTrackSeeding.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/offline/packages/trackreco/PHTruthSiliconAssociation.cc b/offline/packages/trackreco/PHTruthSiliconAssociation.cc index a0281767ca..7e55450fe5 100644 --- a/offline/packages/trackreco/PHTruthSiliconAssociation.cc +++ b/offline/packages/trackreco/PHTruthSiliconAssociation.cc @@ -556,6 +556,8 @@ std::set PHTruthSiliconAssociation::getInttCrossings(TrackSeed *si_tr unsigned int PHTruthSiliconAssociation::buildTrackSeed(const std::set &clusters, PHG4Particle *g4particle, TrackSeedContainer *container) { auto track = std::make_unique(); + track->set_truth_track_id(g4particle->get_track_id()); + bool silicon = false; for (const auto &cluskey : clusters) { diff --git a/offline/packages/trackreco/PHTruthTrackSeeding.cc b/offline/packages/trackreco/PHTruthTrackSeeding.cc index 5828ff420d..7b210ea484 100644 --- a/offline/packages/trackreco/PHTruthTrackSeeding.cc +++ b/offline/packages/trackreco/PHTruthTrackSeeding.cc @@ -252,6 +252,8 @@ void PHTruthTrackSeeding::buildTrackSeed(const std::vector& c // This method is called separately for silicon and tpc seeds auto track = std::make_unique(); + track->set_truth_track_id(g4particle->get_track_id()); + bool silicon = false; bool tpc = false; for (const auto& cluskey : clusters) From edbd44ed868c831eab405b8b50eb035b12584262 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 Jun 2026 09:29:20 -0400 Subject: [PATCH 722/866] fix more inconsistencies and make mixs chars and phi and tbin lo/hi ushort --- offline/packages/trackbase/TrkrCluster.h | 24 ++++++++-------- offline/packages/trackbase/TrkrClusterv6.h | 32 +++++++++++----------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 4eaeac407e..2035e19796 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -92,14 +92,14 @@ class TrkrCluster : public PHObject virtual char getDREdge() const { return std::numeric_limits::max(); } virtual char getHLEdge() const { return std::numeric_limits::max(); } virtual char getHREdge() const { return std::numeric_limits::max(); } - virtual int getSLMix() const { return std::numeric_limits::max(); } - virtual int getSRMix() const { return std::numeric_limits::max(); } - virtual int getTLMix() const { return std::numeric_limits::max(); } - virtual int getTRMix() const { return std::numeric_limits::max(); } - virtual int getPhiBinLo() const { return std::numeric_limits::max(); } - virtual int getPhiBinHi() const { return std::numeric_limits::max(); } - virtual int getTBinLo() const { return std::numeric_limits::max(); } - virtual int getTBinHi() const { return std::numeric_limits::max(); } + virtual char getSLMix() const { return std::numeric_limits::max(); } + virtual char getSRMix() const { return std::numeric_limits::max(); } + virtual char getTLMix() const { return std::numeric_limits::max(); } + virtual char getTRMix() const { return std::numeric_limits::max(); } + virtual unsigned short getPhiBinLo() const { return std::numeric_limits::max(); } + virtual unsigned short getPhiBinHi() const { return std::numeric_limits::max(); } + virtual unsigned short getTBinLo() const { return std::numeric_limits::max(); } + virtual unsigned short getTBinHi() const { return std::numeric_limits::max(); } virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } @@ -116,10 +116,10 @@ class TrkrCluster : public PHObject virtual void setSRMix(const char) {}; virtual void setTLMix(const char) {}; virtual void setTRMix(const char) {}; - virtual void setPhiBinLo(const int) {}; - virtual void setPhiBinHi(const int) {}; - virtual void setTBinLo(const int) {}; - virtual void setTBinHi(const int) {}; + virtual void setPhiBinLo(const unsigned short) {}; + virtual void setPhiBinHi(const unsigned short) {}; + virtual void setTBinLo(const unsigned short) {}; + virtual void setTBinHi(const unsigned short) {}; virtual void setPadPhase(const float) {}; virtual void setTBinPhase(const float) {}; virtual void setRSize(const char) {}; diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 46b77b4dd8..b599fd1d24 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -150,29 +150,29 @@ class TrkrClusterv6 : public TrkrCluster char getHREdge() const override { return m_hredge; } void setHREdge(const char hredge) override { m_hredge = hredge; } - int getSLMix() const override { return m_slmix; } + char getSLMix() const override { return m_slmix; } void setSLMix(const char slmix) override { m_slmix = slmix; } - int getSRMix() const override { return m_srmix; } + char getSRMix() const override { return m_srmix; } void setSRMix(const char srmix) override { m_srmix = srmix; } - int getTLMix() const override { return m_tlmix; } + char getTLMix() const override { return m_tlmix; } void setTLMix(const char tlmix) override { m_tlmix = tlmix; } - int getTRMix() const override { return m_trmix; } + char getTRMix() const override { return m_trmix; } void setTRMix(const char trmix) override { m_trmix = trmix; } - int getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(const int phibinlo) override { m_phibinlo = phibinlo; } + unsigned short getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(const unsigned short phibinlo) override { m_phibinlo = phibinlo; } - int getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(const int phibinhi) override { m_phibinhi = phibinhi; } + unsigned short getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(const unsigned short phibinhi) override { m_phibinhi = phibinhi; } - int getTBinLo() const override { return m_tbinlo; } - void setTBinLo(const int tbinlo) override { m_tbinlo = tbinlo; } + unsigned short getTBinLo() const override { return m_tbinlo; } + void setTBinLo(const unsigned short tbinlo) override { m_tbinlo = tbinlo; } - int getTBinHi() const override { return m_tbinhi; } - void setTBinHi(const int tbinhi) override { m_tbinhi = tbinhi; } + unsigned short getTBinHi() const override { return m_tbinhi; } + void setTBinHi(const unsigned short tbinhi) override { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } void setPadPhase(const float padphase) override { m_padphase = padphase; } @@ -210,10 +210,10 @@ class TrkrClusterv6 : public TrkrCluster char m_srmix{0}; char m_tlmix{0}; char m_trmix{0}; - int m_phibinlo{0}; - int m_phibinhi{0}; - int m_tbinlo{0}; - int m_tbinhi{0}; + unsigned short m_phibinlo{0}; + unsigned short m_phibinhi{0}; + unsigned short m_tbinlo{0}; + unsigned short m_tbinhi{0}; float m_padphase{0}; float m_tbinphase{0}; From 10d5b5294466b88ca984022bb7c5c856e37d2d60 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 Jun 2026 09:42:09 -0400 Subject: [PATCH 723/866] add crossing into vertex tuples --- simulation/g4simulation/g4eval/SvtxEvaluator.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 7cc5d184b3..b844e6bd46 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -99,7 +99,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) if (_do_vertex_eval) { _ntp_vertex = new TNtuple("ntp_vertex", "vertex => max truth", - "event:seed:vertexID:vx:vy:vz:ntracks:chi2:ndof:" + "event:seed:vertexID:vx:vy:vz:ntracks:chi2:ndof:crossing:" "gvx:gvy:gvz:gvt:gembed:gntracks:gntracksmaps:" "gnembed:nfromtruth:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); @@ -109,7 +109,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) { _ntp_gpoint = new TNtuple("ntp_gpoint", "g4point => best vertex", "event:seed:gvx:gvy:gvz:gvt:gntracks:gembed:" - "vx:vy:vz:ntracks:" + "vx:vy:vz:ntracks:crossing:" "nfromtruth:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -1190,6 +1190,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float vx = vertex->get_x(); float vy = vertex->get_y(); float vz = vertex->get_z(); + float crossing = vertex->get_beam_crossing(); float ntracks = vertex->size_tracks(); float chi2 = vertex->get_chisq(); float ndof = vertex->get_ndof(); @@ -1228,6 +1229,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ntracks, chi2, ndof, + crossing, gvx, gvy, gvz, @@ -1373,12 +1375,13 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float vz = std::numeric_limits::quiet_NaN(); float ntracks = std::numeric_limits::quiet_NaN(); float nfromtruth = std::numeric_limits::quiet_NaN(); - + float crossing = std::numeric_limits::quiet_NaN(); if (vertex) { vx = vertex->get_x(); vy = vertex->get_y(); vz = vertex->get_z(); + crossing = vertex->get_beam_crossing(); ntracks = vertex->size_tracks(); nfromtruth = vertexeval->get_ntracks_contribution(vertex, point); } @@ -1394,6 +1397,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) vy, vz, ntracks, + crossing, nfromtruth, nhit_tpc_all, nhit_tpc_in, From 497ed8d0f58826246b9e3dacc60fa7ad21685af9 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 Jun 2026 09:49:50 -0400 Subject: [PATCH 724/866] change instantiation from 0s to max or quiet nan --- offline/packages/trackbase/TrkrClusterv6.h | 64 +++++++++++----------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index b599fd1d24..683aeded6e 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -184,38 +184,38 @@ class TrkrClusterv6 : public TrkrCluster float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; //< 2D local position [cm] 2 * 32 64bit - cumul 1*64 TrkrDefs::subsurfkey m_subsurfkey {TrkrDefs::SUBSURFKEYMAX}; //< unique identifier for hitsetkey-surface maps 16 bit - float m_phierr{0}; - float m_zerr{0}; - unsigned short m_adc{0}; //< cluster sum adc 16 - unsigned short m_maxadc{0}; //< cluster max adc 16 - unsigned short m_cenadc{0}; //< cluster centroid adc 16 - float m_padcen{0}; - float m_tbincen{0}; - int m_padmax{0}; - int m_tbinmax{0}; - char m_rsize{0}; - char m_phisize{0}; - char m_zsize{0}; - char m_overlap{0}; - char m_edge{0}; - char m_sledge{0}; - char m_sredge{0}; - char m_tledge{0}; - char m_tredge{0}; - char m_dledge{0}; - char m_dredge{0}; - char m_hledge{0}; - char m_hredge{0}; - char m_slmix{0}; - char m_srmix{0}; - char m_tlmix{0}; - char m_trmix{0}; - unsigned short m_phibinlo{0}; - unsigned short m_phibinhi{0}; - unsigned short m_tbinlo{0}; - unsigned short m_tbinhi{0}; - float m_padphase{0}; - float m_tbinphase{0}; + float m_phierr{std::numeric_limits::quiet_NaN()}; + float m_zerr{std::numeric_limits::quiet_NaN()}; + unsigned short m_adc{std::numeric_limits::max()}; //< cluster sum adc 16 + unsigned short m_maxadc{std::numeric_limits::max()}; //< cluster max adc 16 + unsigned short m_cenadc{std::numeric_limits::max()}; //< cluster centroid adc 16 + float m_padcen{std::numeric_limits::quiet_NaN()}; + float m_tbincen{std::numeric_limits::quiet_NaN()}; + int m_padmax{std::numeric_limits::max()}; + int m_tbinmax{std::numeric_limits::max()}; + char m_rsize{std::numeric_limits::max()}; + char m_phisize{std::numeric_limits::max()}; + char m_zsize{std::numeric_limits::max()}; + char m_overlap{std::numeric_limits::max()}; + char m_edge{std::numeric_limits::max()}; + char m_sledge{std::numeric_limits::max()}; + char m_sredge{std::numeric_limits::max()}; + char m_tledge{std::numeric_limits::max()}; + char m_tredge{std::numeric_limits::max()}; + char m_dledge{std::numeric_limits::max()}; + char m_dredge{std::numeric_limits::max()}; + char m_hledge{std::numeric_limits::max()}; + char m_hredge{std::numeric_limits::max()}; + char m_slmix{std::numeric_limits::max()}; + char m_srmix{std::numeric_limits::max()}; + char m_tlmix{std::numeric_limits::max()}; + char m_trmix{std::numeric_limits::max()}; + unsigned short m_phibinlo{std::numeric_limits::max()}; + unsigned short m_phibinhi{std::numeric_limits::max()}; + unsigned short m_tbinlo{std::numeric_limits::max()}; + unsigned short m_tbinhi{std::numeric_limits::max()}; + float m_padphase{std::numeric_limits::quiet_NaN()}; + float m_tbinphase{std::numeric_limits::quiet_NaN()}; ClassDefOverride(TrkrClusterv6, 1) }; From 5e357d834043708cef8cb208b237e2d563b49b0a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 Jun 2026 12:23:08 -0400 Subject: [PATCH 725/866] change to char --- .../TrackingDiagnostics/TrackResiduals.cc | 8 +++--- .../TrackingDiagnostics/TrackResiduals.h | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index d8f816fad6..71a6a0a19d 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -1853,10 +1853,10 @@ void TrackResiduals::createBranches() m_clustree->Branch("dredge", &m_dredge, "m_dredge/C"); m_clustree->Branch("hledge", &m_hledge, "m_hledge/C"); m_clustree->Branch("hredge", &m_hredge, "m_hredge/C"); - m_clustree->Branch("slmix", &m_slmix, "m_slmix/I"); - m_clustree->Branch("srmix", &m_srmix, "m_srmix/I"); - m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/I"); - m_clustree->Branch("trmix", &m_trmix, "m_trmix/I"); + m_clustree->Branch("slmix", &m_slmix, "m_slmix/C"); + m_clustree->Branch("srmix", &m_srmix, "m_srmix/C"); + m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/C"); + m_clustree->Branch("trmix", &m_trmix, "m_trmix/C"); m_clustree->Branch("erphi", &m_scluselx, "m_scluselx/F"); m_clustree->Branch("ez", &m_scluselz, "m_scluselz/F"); m_clustree->Branch("maxadc", &m_clusmaxadc, "m_clusmaxadc/F"); diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 6729bfbb04..2fb8b6f648 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -251,20 +251,20 @@ class TrackResiduals : public SubsysReco int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); - char m_overlap = std::numeric_limits::quiet_NaN(); - char m_nedge = std::numeric_limits::quiet_NaN(); - char m_sledge = std::numeric_limits::quiet_NaN(); - char m_sredge = std::numeric_limits::quiet_NaN(); - char m_tledge = std::numeric_limits::quiet_NaN(); - char m_tredge = std::numeric_limits::quiet_NaN(); - char m_dledge = std::numeric_limits::quiet_NaN(); - char m_dredge = std::numeric_limits::quiet_NaN(); - char m_hledge = std::numeric_limits::quiet_NaN(); - char m_hredge = std::numeric_limits::quiet_NaN(); - int m_slmix = std::numeric_limits::quiet_NaN(); - int m_srmix = std::numeric_limits::quiet_NaN(); - int m_tlmix = std::numeric_limits::quiet_NaN(); - int m_trmix = std::numeric_limits::quiet_NaN(); + char m_overlap = std::numeric_limits::max(); + char m_nedge = std::numeric_limits::max(); + char m_sledge = std::numeric_limits::max(); + char m_sredge = std::numeric_limits::max(); + char m_tledge = std::numeric_limits::max(); + char m_tredge = std::numeric_limits::max(); + char m_dledge = std::numeric_limits::max(); + char m_dredge = std::numeric_limits::max(); + char m_hledge = std::numeric_limits::max(); + char m_hredge = std::numeric_limits::max(); + char m_slmix = std::numeric_limits::max(); + char m_srmix = std::numeric_limits::max(); + char m_tlmix = std::numeric_limits::max(); + char m_trmix = std::numeric_limits::max(); float m_phibinlo = std::numeric_limits::quiet_NaN(); float m_phibinhi = std::numeric_limits::quiet_NaN(); float m_tbinlo = std::numeric_limits::quiet_NaN(); From efd853db2d69f6fd616e3831295e65c06875dcbf Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Wed, 24 Jun 2026 15:40:43 +0800 Subject: [PATCH 726/866] simplify truth id handling in truth fitter --- .../packages/trackreco/PHTruthTrackFitter.cc | 51 +++++-------------- .../packages/trackreco/PHTruthTrackFitter.h | 2 - 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/offline/packages/trackreco/PHTruthTrackFitter.cc b/offline/packages/trackreco/PHTruthTrackFitter.cc index 9466c40df5..0e300be389 100644 --- a/offline/packages/trackreco/PHTruthTrackFitter.cc +++ b/offline/packages/trackreco/PHTruthTrackFitter.cc @@ -337,6 +337,7 @@ unsigned int PHTruthTrackFitter::getTruthTrackId(const TrackSeed* svtxSeed, const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const { + auto truth_track_id = m_invalidTruthTrackId; for (const auto* seed : {svtxSeed, tpcSeed, siliconSeed}) { if (!seed) @@ -344,52 +345,26 @@ unsigned int PHTruthTrackFitter::getTruthTrackId(const TrackSeed* svtxSeed, continue; } - const auto truth_track_id = seed->get_truth_track_id(); - if (valid_track_id(truth_track_id)) + const auto seed_truth_track_id = seed->get_truth_track_id(); + if (!valid_track_id(seed_truth_track_id)) { - return truth_track_id; + continue; } - } - - std::map truth_counts; - countTruthHits(tpcSeed, truth_counts); - countTruthHits(siliconSeed, truth_counts); - - if (truth_counts.empty()) - { - return m_invalidTruthTrackId; - } - - const auto best_iter = std::max_element(truth_counts.begin(), truth_counts.end(), - [](const auto& lhs, const auto& rhs) - { return lhs.second < rhs.second; }); - - return best_iter->first >= 0 ? static_cast(best_iter->first) : m_invalidTruthTrackId; -} - -void PHTruthTrackFitter::countTruthHits(const TrackSeed* seed, std::map& counts) const -{ - if (!seed) - { - return; - } - for (auto iter = seed->begin_cluster_keys(); iter != seed->end_cluster_keys(); ++iter) - { - for (const auto* g4hit : getTruthHits(*iter)) + if (valid_track_id(truth_track_id) && seed_truth_track_id != truth_track_id) { - if (!g4hit) - { - continue; - } - - const auto track_id = g4hit->get_trkid(); - if (track_id >= 0) + if (Verbosity() > 0) { - ++counts[track_id]; + std::cout << "PHTruthTrackFitter::getTruthTrackId - inconsistent seed truth ids " + << truth_track_id << " and " << seed_truth_track_id << std::endl; } + return m_invalidTruthTrackId; } + + truth_track_id = seed_truth_track_id; } + + return truth_track_id; } std::vector PHTruthTrackFitter::getTruthHits(TrkrDefs::cluskey cluskey) const diff --git a/offline/packages/trackreco/PHTruthTrackFitter.h b/offline/packages/trackreco/PHTruthTrackFitter.h index 207d95668b..68482705c3 100644 --- a/offline/packages/trackreco/PHTruthTrackFitter.h +++ b/offline/packages/trackreco/PHTruthTrackFitter.h @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -50,7 +49,6 @@ class PHTruthTrackFitter : public SubsysReco TrackSeed* getSeed(TrackSeedContainer* container, unsigned int index) const; unsigned int getTruthTrackId(const TrackSeed* svtxSeed, const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; - void countTruthHits(const TrackSeed* seed, std::map& counts) const; std::vector getTruthHits(TrkrDefs::cluskey cluskey) const; const PHG4Hit* getG4Hit(unsigned int trkrid, PHG4HitDefs::keytype g4hitkey) const; From 62cc59121ad8b3d5138df725d674eaeec82cc928 Mon Sep 17 00:00:00 2001 From: "Joseph (Joe) Osborn" <53052717+osbornjd@users.noreply.github.com> Date: Wed, 24 Jun 2026 10:57:37 -0400 Subject: [PATCH 727/866] Revert "feat: implement v6 option in tpc clusterizer" --- .../TrackingDiagnostics/TrackResiduals.cc | 173 ---------- .../TrackingDiagnostics/TrackResiduals.h | 53 +-- .../TrackingDiagnostics/TrkrNtuplizer.cc | 60 +--- offline/packages/tpc/TpcClusterizer.cc | 321 +++--------------- offline/packages/tpc/TpcClusterizer.h | 6 - offline/packages/trackbase/TrkrCluster.h | 63 +--- offline/packages/trackbase/TrkrClusterv4.cc | 2 +- offline/packages/trackbase/TrkrClusterv4.h | 4 +- offline/packages/trackbase/TrkrClusterv5.cc | 2 +- offline/packages/trackbase/TrkrClusterv5.h | 22 +- offline/packages/trackbase/TrkrClusterv6.h | 158 ++++----- 11 files changed, 168 insertions(+), 696 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 71a6a0a19d..1a5a69fae0 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -46,8 +46,6 @@ #include #include -#include - #include #include #include @@ -59,7 +57,6 @@ #include #include #include -#include #include @@ -129,7 +126,6 @@ int TrackResiduals::InitRun(PHCompositeNode* topNode) void TrackResiduals::clearClusterStateVectors() { m_cluskeys.clear(); - m_clussize.clear(); m_clusphisize.clear(); m_cluszsize.clear(); m_idealsurfcenterx.clear(); @@ -187,23 +183,7 @@ void TrackResiduals::clearClusterStateVectors() m_statelzlocderivqop.clear(); m_clusedge.clear(); - m_clussledge.clear(); - m_clussredge.clear(); - m_clustledge.clear(); - m_clustredge.clear(); - m_clusdledge.clear(); - m_clusdredge.clear(); - m_clushledge.clear(); - m_clushredge.clear(); - m_clusslmix.clear(); - m_clussrmix.clear(); - m_clustlmix.clear(); - m_clustrmix.clear(); m_clusoverlap.clear(); - m_clusPadCen.clear(); - m_clusTBinCen.clear(); - m_clusPadMax.clear(); - m_clusTBinMax.clear(); m_cluslx.clear(); m_cluslz.clear(); m_cluselx.clear(); @@ -217,14 +197,7 @@ void TrackResiduals::clearClusterStateVectors() m_clusgzunmoved.clear(); m_clusAdc.clear(); m_clusMaxAdc.clear(); - m_clusCenAdc.clear(); m_cluslayer.clear(); - m_clusphibinlo.clear(); - m_clusphibinhi.clear(); - m_clustbinlo.clear(); - m_clustbinhi.clear(); - m_cluspadphase.clear(); - m_clustbinphase.clear(); m_statelx.clear(); m_statelz.clear(); @@ -328,21 +301,6 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) } } - EventHeader* eventheader = findNode::getClass(topNode, "EventHeader"); - - if(eventheader) - { - m_evt_id = eventheader->get_EvtSequence(); - } - else - { - m_evt_id = -1; - } - - auto *rcs = recoConsts::instance(); - m_runnumber = rcs->get_IntFlag("RUNNUMBER"); - m_segment = rcs->get_IntFlag("RUNSEGMENT"); - m_ntpcclus = 0; if (Verbosity() > 1) { @@ -704,37 +662,11 @@ void TrackResiduals::fillClusterTree(TrkrClusterContainer* clusters, m_scluseta = acos(glob.z() / std::sqrt(square(glob.x()) + square(glob.y()) + square(glob.z()))); m_adc = cluster->getAdc(); m_clusmaxadc = cluster->getMaxAdc(); - m_cluscenadc = cluster->getCenAdc(); - m_padcen = cluster->getPadCen(); - m_tbincen = cluster->getTBinCen(); - m_padmax = cluster->getPadMax(); - m_tbinmax = cluster->getTBinMax(); m_scluslx = cluster->getLocalX(); m_scluslz = cluster->getLocalY(); - m_phibinlo = cluster->getPhiBinLo(); - m_phibinhi = cluster->getPhiBinHi(); - m_tbinlo = cluster->getTBinLo(); - m_tbinhi = cluster->getTBinHi(); - m_padphase = cluster->getPadPhase(); - m_tbinphase = cluster->getTBinPhase(); auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, m_sclusgr, key); - m_size = cluster->getRSize(); m_phisize = cluster->getPhiSize(); m_zsize = cluster->getZSize(); - m_overlap = cluster->getOverlap(); - m_nedge = cluster->getEdge(); - m_sledge = cluster->getSLEdge(); - m_sredge = cluster->getSREdge(); - m_tledge = cluster->getTLEdge(); - m_tredge = cluster->getTREdge(); - m_dledge = cluster->getDLEdge(); - m_dredge = cluster->getDREdge(); - m_hledge = cluster->getHLEdge(); - m_hredge = cluster->getHREdge(); - m_slmix = cluster->getSLMix(); - m_srmix = cluster->getSRMix(); - m_tlmix = cluster->getTLMix(); - m_trmix = cluster->getTRMix(); m_scluselx = std::sqrt(para_errors.first); m_scluselz = std::sqrt(para_errors.second); @@ -1155,19 +1087,7 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); - m_clussledge.push_back(cluster->getSLEdge()); - m_clussredge.push_back(cluster->getSREdge()); - m_clustledge.push_back(cluster->getTLEdge()); - m_clustredge.push_back(cluster->getTREdge()); - m_clusdledge.push_back(cluster->getDLEdge()); - m_clusdredge.push_back(cluster->getDREdge()); - m_clushledge.push_back(cluster->getHLEdge()); - m_clushredge.push_back(cluster->getHREdge()); m_clusoverlap.push_back(cluster->getOverlap()); - m_clusslmix.push_back(cluster->getSLMix()); - m_clussrmix.push_back(cluster->getSRMix()); - m_clustlmix.push_back(cluster->getTLMix()); - m_clustrmix.push_back(cluster->getTRMix()); // get new local coords from moved cluster Surface surf = geometry->maps().getSurface(ckey, cluster); @@ -1240,21 +1160,9 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); - m_clusCenAdc.push_back(cluster->getCenAdc()); - m_clusPadCen.push_back(cluster->getPadCen()); - m_clusTBinCen.push_back(cluster->getTBinCen()); - m_clusPadMax.push_back(cluster->getPadMax()); - m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); - m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); - m_clusphibinlo.push_back(cluster->getPhiBinLo()); - m_clusphibinhi.push_back(cluster->getPhiBinHi()); - m_clustbinlo.push_back(cluster->getTBinLo()); - m_clustbinhi.push_back(cluster->getTBinHi()); - m_cluspadphase.push_back(cluster->getPadPhase()); - m_clustbinphase.push_back(cluster->getTBinPhase()); auto misaligncenter = surf->center(geometry->geometry().getGeoContext()); auto misalignnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); @@ -1508,18 +1416,6 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); - m_clussledge.push_back(cluster->getSLEdge()); - m_clussredge.push_back(cluster->getSREdge()); - m_clustledge.push_back(cluster->getTLEdge()); - m_clustredge.push_back(cluster->getTREdge()); - m_clusdledge.push_back(cluster->getDLEdge()); - m_clusdredge.push_back(cluster->getDREdge()); - m_clushledge.push_back(cluster->getHLEdge()); - m_clushredge.push_back(cluster->getHREdge()); - m_clusslmix.push_back(cluster->getSLMix()); - m_clussrmix.push_back(cluster->getSRMix()); - m_clustlmix.push_back(cluster->getTLMix()); - m_clustrmix.push_back(cluster->getTRMix()); m_clusoverlap.push_back(cluster->getOverlap()); // This is the nominal position of the cluster in local coords, completely uncorrected - is that what we want? @@ -1542,21 +1438,9 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); - m_clusCenAdc.push_back(cluster->getCenAdc()); - m_clusPadCen.push_back(cluster->getPadCen()); - m_clusTBinCen.push_back(cluster->getTBinCen()); - m_clusPadMax.push_back(cluster->getPadMax()); - m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); - m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); - m_clusphibinlo.push_back(cluster->getPhiBinLo()); - m_clusphibinhi.push_back(cluster->getPhiBinHi()); - m_clustbinlo.push_back(cluster->getTBinLo()); - m_clustbinhi.push_back(cluster->getTBinHi()); - m_cluspadphase.push_back(cluster->getPadPhase()); - m_clustbinphase.push_back(cluster->getTBinPhase()); if (Verbosity() > 1) { @@ -1723,7 +1607,6 @@ void TrackResiduals::createBranches() m_eventtree->Branch("run", &m_runnumber, "m_runnumber/I"); m_eventtree->Branch("segment", &m_segment, "m_segment/I"); m_eventtree->Branch("event", &m_event, "m_event/I"); - m_eventtree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_eventtree->Branch("gl1bco", &m_bco, "m_bco/I"); m_eventtree->Branch("nmvtx", &m_nmvtx_all, "m_nmvtx_all/I"); m_eventtree->Branch("nintt", &m_nintt_all, "m_nintt_all/I"); @@ -1744,7 +1627,6 @@ void TrackResiduals::createBranches() m_failedfits->Branch("segment", &m_segment, "m_segment/I"); m_failedfits->Branch("trackid", &m_trackid, "m_trackid/I"); m_failedfits->Branch("event", &m_event, "m_event/I"); - m_failedfits->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_failedfits->Branch("silseedx", &m_silseedx, "m_silseedx/F"); m_failedfits->Branch("silseedy", &m_silseedy, "m_silseedy/F"); m_failedfits->Branch("silseedz", &m_silseedz, "m_silseedz/F"); @@ -1771,7 +1653,6 @@ void TrackResiduals::createBranches() m_vertextree->Branch("run", &m_runnumber, "m_runnumber/I"); m_vertextree->Branch("segment", &m_segment, "m_segment/I"); m_vertextree->Branch("event", &m_event, "m_event/I"); - m_vertextree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_vertextree->Branch("firedTriggers", &m_firedTriggers); m_vertextree->Branch("gl1BunchCrossing", &m_gl1BunchCrossing, "m_gl1BunchCrossing/l"); m_vertextree->Branch("gl1bco", &m_bco, "m_bco/l"); @@ -1794,7 +1675,6 @@ void TrackResiduals::createBranches() m_hittree->Branch("run", &m_runnumber, "m_runnumber/I"); m_hittree->Branch("segment", &m_segment, "m_segment/I"); m_hittree->Branch("event", &m_event, "m_event/I"); - m_hittree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_hittree->Branch("gl1bco", &m_bco, "m_bco/l"); m_hittree->Branch("hitsetkey", &m_hitsetkey, "m_hitsetkey/i"); m_hittree->Branch("gx", &m_hitgx, "m_hitgx/F"); @@ -1824,7 +1704,6 @@ void TrackResiduals::createBranches() m_clustree->Branch("run", &m_runnumber, "m_runnumber/I"); m_clustree->Branch("segment", &m_segment, "m_segment/I"); m_clustree->Branch("event", &m_event, "m_event/I"); - m_clustree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_clustree->Branch("gl1bco", &m_bco, "m_bco/l"); m_clustree->Branch("lx", &m_scluslx, "m_scluslx/F"); m_clustree->Branch("lz", &m_scluslz, "m_scluslz/F"); @@ -1834,37 +1713,11 @@ void TrackResiduals::createBranches() m_clustree->Branch("phi", &m_sclusphi, "m_sclusphi/F"); m_clustree->Branch("eta", &m_scluseta, "m_scluseta/F"); m_clustree->Branch("adc", &m_adc, "m_adc/F"); - m_clustree->Branch("size", &m_size, "m_size/I"); m_clustree->Branch("phisize", &m_phisize, "m_phisize/I"); m_clustree->Branch("zsize", &m_zsize, "m_zsize/I"); - m_clustree->Branch("phibinlo", &m_phibinlo, "m_phibinlo/F"); - m_clustree->Branch("phibinhi", &m_phibinhi, "m_phibinhi/F"); - m_clustree->Branch("tbinlo", &m_tbinlo, "m_tbinlo/F"); - m_clustree->Branch("tbinhi", &m_tbinhi, "m_tbinhi/F"); - m_clustree->Branch("padphase", &m_padphase, "m_padphase/F"); - m_clustree->Branch("tbinphase", &m_tbinphase, "m_tbinphase/F"); - m_clustree->Branch("overlap", &m_overlap, "m_overlap/C"); - m_clustree->Branch("nedge", &m_nedge, "m_nedge/C"); - m_clustree->Branch("sledge", &m_sledge, "m_sledge/C"); - m_clustree->Branch("sredge", &m_sredge, "m_sredge/C"); - m_clustree->Branch("tledge", &m_tledge, "m_tledge/C"); - m_clustree->Branch("tredge", &m_tredge, "m_tredge/C"); - m_clustree->Branch("dledge", &m_dledge, "m_dledge/C"); - m_clustree->Branch("dredge", &m_dredge, "m_dredge/C"); - m_clustree->Branch("hledge", &m_hledge, "m_hledge/C"); - m_clustree->Branch("hredge", &m_hredge, "m_hredge/C"); - m_clustree->Branch("slmix", &m_slmix, "m_slmix/C"); - m_clustree->Branch("srmix", &m_srmix, "m_srmix/C"); - m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/C"); - m_clustree->Branch("trmix", &m_trmix, "m_trmix/C"); m_clustree->Branch("erphi", &m_scluselx, "m_scluselx/F"); m_clustree->Branch("ez", &m_scluselz, "m_scluselz/F"); m_clustree->Branch("maxadc", &m_clusmaxadc, "m_clusmaxadc/F"); - m_clustree->Branch("cenadc", &m_cluscenadc, "m_cluscenadc/F"); - m_clustree->Branch("padcen", &m_padcen, "m_padcen/F"); - m_clustree->Branch("tbincen", &m_tbincen, "m_tbincen/F"); - m_clustree->Branch("padmax", &m_padmax, "m_padmax/F"); - m_clustree->Branch("tbinmax", &m_tbinmax, "m_tbinmax/F"); m_clustree->Branch("sector", &m_clussector, "m_clussector/I"); m_clustree->Branch("side", &m_side, "m_side/I"); m_clustree->Branch("stave", &m_staveid, "m_staveid/I"); @@ -1881,7 +1734,6 @@ void TrackResiduals::createBranches() m_tree->Branch("run", &m_runnumber, "m_runnumber/I"); m_tree->Branch("segment", &m_segment, "m_segment/I"); m_tree->Branch("event", &m_event, "m_event/I"); - m_tree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_tree->Branch("mbdcharge",&m_totalmbd, "m_totalmbd/F"); m_tree->Branch("mbdzvtx", &m_mbdvtxz, "m_mbdvtxz/F"); m_tree->Branch("firedTriggers", &m_firedTriggers); @@ -1963,27 +1815,7 @@ void TrackResiduals::createBranches() m_tree->Branch("clusside", &m_clside); m_tree->Branch("cluskeys", &m_cluskeys); m_tree->Branch("clusedge", &m_clusedge); - m_tree->Branch("clussledge", &m_clussledge); - m_tree->Branch("clussredge", &m_clussredge); - m_tree->Branch("clustledge", &m_clustledge); - m_tree->Branch("clustredge", &m_clustredge); - m_tree->Branch("clusdledge", &m_clusdledge); - m_tree->Branch("clusdredge", &m_clusdredge); - m_tree->Branch("clushledge", &m_clushledge); - m_tree->Branch("clushredge", &m_clushredge); - m_tree->Branch("clusslmix", &m_clusslmix); - m_tree->Branch("clussrmix", &m_clussrmix); - m_tree->Branch("clustlmix", &m_clustlmix); - m_tree->Branch("clustrmix", &m_clustrmix); m_tree->Branch("clusoverlap", &m_clusoverlap); - m_tree->Branch("clusphibinlo", &m_clusphibinlo); - m_tree->Branch("clusphibinhi", &m_clusphibinhi); - m_tree->Branch("clustbinlo", &m_clustbinlo); - m_tree->Branch("clustbinhi", &m_clustbinhi); - m_tree->Branch("clusPadCen", &m_clusPadCen); - m_tree->Branch("clusTBinCen", &m_clusTBinCen); - m_tree->Branch("clusPadMax", &m_clusPadMax); - m_tree->Branch("clusTBinMax", &m_clusTBinMax); m_tree->Branch("cluslx", &m_cluslx); m_tree->Branch("cluslz", &m_cluslz); m_tree->Branch("cluselx", &m_cluselx); @@ -1992,8 +1824,6 @@ void TrackResiduals::createBranches() m_tree->Branch("clusgy", &m_clusgy); m_tree->Branch("clusgz", &m_clusgz); m_tree->Branch("clusgr", &m_clusgr); - m_tree->Branch("cluspadphase", &m_cluspadphase); - m_tree->Branch("clustbinphase", &m_clustbinphase); if (m_doAlignment) { m_tree->Branch("clusgxunmoved", &m_clusgxunmoved); @@ -2002,8 +1832,6 @@ void TrackResiduals::createBranches() } m_tree->Branch("clusAdc", &m_clusAdc); m_tree->Branch("clusMaxAdc", &m_clusMaxAdc); - m_tree->Branch("clusCenAdc", &m_clusCenAdc); - m_tree->Branch("clussize", &m_clussize); m_tree->Branch("clusphisize", &m_clusphisize); m_tree->Branch("cluszsize", &m_cluszsize); @@ -2407,7 +2235,6 @@ void TrackResiduals::fillEventTree(PHCompositeNode* topNode) if (Verbosity() > 1) { std::cout << " m_event:" << m_event << std::endl; - std::cout << " m_evt_id:" << m_evt_id << std::endl; std::cout << " m_ntpc_clus0:" << m_ntpc_clus0 << std::endl; std::cout << " m_ntpc_clus1: " << m_ntpc_clus1 << std::endl; std::cout << " m_nmvtx_all:" << m_nmvtx_all << std::endl; diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 2fb8b6f648..7e789faba5 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -128,7 +128,6 @@ class TrackResiduals : public SubsysReco bool m_doMicromegasOnly = false; int m_event = 0; - int m_evt_id = -1; int m_segment = std::numeric_limits::quiet_NaN(); int m_runnumber = std::numeric_limits::quiet_NaN(); int m_ntpcclus = std::numeric_limits::quiet_NaN(); @@ -247,34 +246,8 @@ class TrackResiduals : public SubsysReco float m_scluseta = std::numeric_limits::quiet_NaN(); float m_adc = std::numeric_limits::quiet_NaN(); float m_clusmaxadc = std::numeric_limits::quiet_NaN(); - float m_cluscenadc = std::numeric_limits::quiet_NaN(); - int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); - char m_overlap = std::numeric_limits::max(); - char m_nedge = std::numeric_limits::max(); - char m_sledge = std::numeric_limits::max(); - char m_sredge = std::numeric_limits::max(); - char m_tledge = std::numeric_limits::max(); - char m_tredge = std::numeric_limits::max(); - char m_dledge = std::numeric_limits::max(); - char m_dredge = std::numeric_limits::max(); - char m_hledge = std::numeric_limits::max(); - char m_hredge = std::numeric_limits::max(); - char m_slmix = std::numeric_limits::max(); - char m_srmix = std::numeric_limits::max(); - char m_tlmix = std::numeric_limits::max(); - char m_trmix = std::numeric_limits::max(); - float m_phibinlo = std::numeric_limits::quiet_NaN(); - float m_phibinhi = std::numeric_limits::quiet_NaN(); - float m_tbinlo = std::numeric_limits::quiet_NaN(); - float m_tbinhi = std::numeric_limits::quiet_NaN(); - float m_padphase = std::numeric_limits::quiet_NaN(); - float m_tbinphase = std::numeric_limits::quiet_NaN(); - float m_padcen = std::numeric_limits::quiet_NaN(); - float m_tbincen = std::numeric_limits::quiet_NaN(); - float m_padmax = std::numeric_limits::quiet_NaN(); - float m_tbinmax = std::numeric_limits::quiet_NaN(); float m_scluslx = std::numeric_limits::quiet_NaN(); float m_scluslz = std::numeric_limits::quiet_NaN(); float m_sclusgx = std::numeric_limits::quiet_NaN(); @@ -297,11 +270,6 @@ class TrackResiduals : public SubsysReco //! clusters on track information std::vector m_clusAdc; std::vector m_clusMaxAdc; - std::vector m_clusCenAdc; - std::vector m_clusPadCen; - std::vector m_clusTBinCen; - std::vector m_clusPadMax; - std::vector m_clusTBinMax; std::vector m_cluslx; std::vector m_cluslz; std::vector m_cluselx; @@ -320,29 +288,10 @@ class TrackResiduals : public SubsysReco std::vector m_clsector; std::vector m_clside; std::vector m_cluslayer; - std::vector m_clussize; std::vector m_clusphisize; std::vector m_cluszsize; - std::vector m_clusoverlap; std::vector m_clusedge; - std::vector m_clussledge; - std::vector m_clussredge; - std::vector m_clustledge; - std::vector m_clustredge; - std::vector m_clusdledge; - std::vector m_clusdredge; - std::vector m_clushledge; - std::vector m_clushredge; - std::vector m_clusslmix; - std::vector m_clussrmix; - std::vector m_clustlmix; - std::vector m_clustrmix; - std::vector m_clusphibinlo; - std::vector m_clusphibinhi; - std::vector m_clustbinlo; - std::vector m_clustbinhi; - std::vector m_cluspadphase; - std::vector m_clustbinphase; + std::vector m_clusoverlap; std::vector m_cluskeys; std::vector m_idealsurfcenterx; std::vector m_idealsurfcentery; diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index 1c90c4688c..d5fddf6538 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -289,11 +289,6 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) nclue, ncluadc, nclumaxadc, - nclucenadc, - nclupadcen, - nclutbincen, - nclupadmax, - nclutbinmax, ncluthick, ncluafac, nclubfac, @@ -306,25 +301,7 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) ncluzsize, nclupedge, ncluredge, - nclusledge, - nclusredge, - nclutledge, - nclutredge, - ncludledge, - ncludredge, - ncluhledge, - ncluhredge, - ncluslmix, - nclusrmix, - nclutlmix, - nclutrmix, ncluovlp, - ncluphibinlo, - ncluphibinhi, - nclutbinlo, - nclutbinhi, - nclupadphase, - nclutbinphase, nclutrackID, ncluniter, clusize = ncluniter + 1 @@ -360,7 +337,7 @@ int TrkrNtuplizer::Init(PHCompositeNode* /*unused*/) std::string str_vertex = {"vertexID:vx:vy:vz:ntracks:chi2:ndof"}; std::string str_event = {"event:seed:run:seg:job"}; std::string str_hit = {"hitID:e:adc:layer:phielem:zelem:cellID:ecell:phibin:zbin:tbin:phi:r:x:y:z"}; - std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:cenadc:padcen:tbincen:padmax:tbinmax:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:sledge:sredge:tledge:tredge:dledge:dredge:hledge:hredge:slmix:srmix:tlmix:trmix:ovlp:phibinlo:phibinhi:tbinlo:tbinhi:padphase:tbinphase:trackID:niter"}; + std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:ovlp:trackID:niter"}; std::string str_seed = {"seedID:siter:spt:sptot:seta:sphi:syxint:srzint:sxyslope:srzslope:sX0:sY0:sdZ0:sR0:scharge:sdedx:spidedx:skdedx:sprdedx:sn1pix:snsil:sntpc:snhits"}; std::string str_residual = {"alpha:beta:resphio:resphi:resz"}; std::string str_track = {"trackID:crossing:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:charge:quality:chisq:ndf:nhits:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:dedx:pidedx:kdedx:prdedx:vertexID:vx:vy:vz:dca2d:dca2dsigma:dca3dxy:dca3dxysigma:dca3dz:dca3dzsigma:pcax:pcay:pcaz:hlxpt:hlxeta:hlxphi:hlxX0:hlxY0:hlxZ0:hlxcharge"}; @@ -1409,7 +1386,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } //----------------------- - // fill the Vertex NTuple and fixed NaN placeholders + // fill the Vertex NTuple and fixed NaN placeholders //----------------------- bool doit = true; if (_ntp_vertex && doit) @@ -1432,7 +1409,8 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) for (auto & iter : *vertexmap) { SvtxVertex* vertex = iter.second; - if (!vertex) { continue; } + if (!vertex) { continue; +} float fx_vertex[n_vertex::vtxsize]; for (float& i : fx_vertex) @@ -1475,6 +1453,8 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) _timer->stop(); std::cout << "vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; } + + //-------------------- // fill the Hit NTuple //-------------------- @@ -2304,11 +2284,6 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c fXcluster[n_cluster::nclue] = cluster->getAdc(); fXcluster[n_cluster::ncluadc] = cluster->getAdc(); fXcluster[n_cluster::nclumaxadc] = cluster->getMaxAdc(); - fXcluster[n_cluster::nclucenadc] = cluster->getCenAdc(); - fXcluster[n_cluster::nclupadcen] = cluster->getPadCen(); - fXcluster[n_cluster::nclutbincen] = cluster->getTBinCen(); - fXcluster[n_cluster::nclupadmax] = cluster->getPadMax(); - fXcluster[n_cluster::nclutbinmax] = cluster->getTBinMax(); fXcluster[n_cluster::nclulayer] = layer_local; if (layer_local < 3) @@ -2336,7 +2311,7 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c } } */ - fXcluster[n_cluster::nclusize] = cluster->getRSize(); + fXcluster[n_cluster::nclusize] = cluster->getSize(); fXcluster[n_cluster::ncluphisize] = cluster->getPhiSize(); fXcluster[n_cluster::ncluzsize] = cluster->getZSize(); fXcluster[n_cluster::nclupedge] = cluster->getEdge(); @@ -2346,25 +2321,8 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c { fXcluster[n_cluster::ncluredge] = 1; } - fXcluster[n_cluster::nclusledge] = cluster->getSLEdge(); - fXcluster[n_cluster::nclusredge] = cluster->getSREdge(); - fXcluster[n_cluster::nclutledge] = cluster->getTLEdge(); - fXcluster[n_cluster::nclutredge] = cluster->getTREdge(); - fXcluster[n_cluster::ncludledge] = cluster->getDLEdge(); - fXcluster[n_cluster::ncludredge] = cluster->getDREdge(); - fXcluster[n_cluster::ncluhledge] = cluster->getHLEdge(); - fXcluster[n_cluster::ncluhredge] = cluster->getHREdge(); - fXcluster[n_cluster::ncluslmix] = cluster->getSLMix(); - fXcluster[n_cluster::nclusrmix] = cluster->getSRMix(); - fXcluster[n_cluster::nclutlmix] = cluster->getTLMix(); - fXcluster[n_cluster::nclutrmix] = cluster->getTRMix(); - fXcluster[n_cluster::ncluovlp] = cluster->getOverlap(); - fXcluster[n_cluster::ncluphibinlo] = cluster->getPhiBinLo(); - fXcluster[n_cluster::ncluphibinhi] = cluster->getPhiBinHi(); - fXcluster[n_cluster::nclutbinlo] = cluster->getTBinLo(); - fXcluster[n_cluster::nclutbinhi] = cluster->getTBinHi(); - fXcluster[n_cluster::nclupadphase] = cluster->getPadPhase(); - fXcluster[n_cluster::nclutbinphase] = cluster->getTBinPhase(); + + fXcluster[n_cluster::ncluovlp] = 3; // cluster->getOvlp(); fXcluster[n_cluster::nclutrackID] = std::numeric_limits::quiet_NaN(); fXcluster[n_cluster::ncluniter] = 0; diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 6548abeb5f..687d5b58f9 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -16,7 +16,6 @@ #include #include #include -#include #include // for hitkey, getLayer #include #include @@ -85,37 +84,6 @@ namespace unsigned short edge = 0; }; - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - struct ClusterCounters - { - int overlap = 0; - - int nedge = 0; // Total No. of Edges - - int sledge = 0; // Touching Left Sector Edge - int sredge = 0; // Touching Right Sector Edge - - int tledge = 0; // Touching Left Time Edge - int tredge = 0; // Touching Right Time Edge - - int dledge = 0; // Touching Left Dead Edge - int dredge = 0; // Touching Right Dead Edge - - int hledge = 0; // Touching Left Hot Edge - int hredge = 0; // Touching Right Hot Edge - - int slmix = 0; // Touching Cluster at Left in Phibin - int srmix = 0; // Touching Cluster at Right in Phibin - - int tlmix = 0; // Touching Cluster at Left in Timebin - int trmix = 0; // Touching Cluster at Right in Timebin - - void clear() - { - *this = ClusterCounters{}; - } - }; - // NOLINTEND(misc-non-private-member-variables-in-classes) using vec_dVerbose = std::vector>>; // Neural network parameters and modules @@ -161,7 +129,6 @@ namespace hitMaskTpcSet *hotMap = nullptr; bool maskDead = false; bool maskHot = false; - bool debug = false; std::vector association_vector; std::vector cluster_vector; @@ -209,14 +176,13 @@ namespace } } - void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, ClusterCounters &counts, bool &ttop_edge, bool &tbottom_edge) + void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, int &touch, int &edge) { const int FitRangeT = (int) my_data.maxHalfSizeT; const int NTBinsMax = (int) my_data.tbins; - // const int FixedWindow = (int) my_data.FixedWindow; + const int FixedWindow = (int) my_data.FixedWindow; tup = 0; tdown = 0; - /* if (FixedWindow != 0) { tup = FixedWindow; @@ -224,16 +190,15 @@ namespace if (tbin + tup >= NTBinsMax) { tup = NTBinsMax - tbin - 1; - counts.nedge++; + edge++; } if ((tbin - tdown) <= 0) { tdown = tbin; - counts.edge++; + edge++; } return; } - */ for (int it = 0; it < FitRangeT; it++) { int ct = tbin + it; @@ -241,12 +206,7 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tup = it; - if (!ttop_edge) - { - counts.nedge++; - counts.tredge = 1; - ttop_edge = true; - } + edge++; break; // truncate edge } @@ -256,7 +216,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - counts.overlap++; + touch++; break; } if (my_data.do_split) @@ -268,7 +228,7 @@ namespace adcval[phibin][ct + 2] + adcval[phibin][ct + 3]) { // rising again tup = it + 1; - counts.overlap++; + touch++; break; } } @@ -281,12 +241,7 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tdown = it; - if (!tbottom_edge) - { - counts.nedge++; - counts.tledge = 1; - tbottom_edge = true; - } + edge++; break; // truncate edge } if (adcval[phibin][ct] <= 0) @@ -295,7 +250,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - counts.overlap++; + touch++; break; } if (my_data.do_split) @@ -306,7 +261,7 @@ namespace adcval[phibin][ct - 2] + adcval[phibin][ct - 3]) { // rising again tdown = it + 1; - counts.overlap++; + touch++; break; } } @@ -316,14 +271,13 @@ namespace return; } - void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, ClusterCounters &counts, bool &phitop_edge, bool &phibottom_edge) + void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, int &touch, int &edge) { int FitRangePHI = (int) my_data.maxHalfSizePhi; int NPhiBinsMax = (int) my_data.phibins; - // const int FixedWindow = (int) my_data.FixedWindow; + const int FixedWindow = (int) my_data.FixedWindow; phidown = 0; phiup = 0; - /* if (FixedWindow != 0) { phiup = FixedWindow; @@ -340,19 +294,13 @@ namespace } return; } - */ for (int iphi = 0; iphi < FitRangePHI; iphi++) { int cphi = phibin + iphi; if (cphi < 0 || cphi >= NPhiBinsMax) { // phiup = iphi; - if (!phitop_edge) - { - counts.nedge++; - counts.sredge = 1; - phitop_edge = true; - } + edge++; break; // truncate edge } @@ -364,7 +312,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - counts.overlap++; + touch++; break; } if (my_data.do_split) @@ -375,7 +323,7 @@ namespace adcval[cphi + 2][tbin] + adcval[cphi + 3][tbin]) { // rising again phiup = iphi + 1; - counts.overlap++; + touch++; break; } } @@ -389,12 +337,7 @@ namespace if (cphi < 0 || cphi >= NPhiBinsMax) { // phidown = iphi; - if (!phibottom_edge) - { - counts.nedge++; - counts.sledge = 1; - phibottom_edge = true; - } + edge++; break; // truncate edge } @@ -405,7 +348,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - counts.overlap++; + touch++; break; } if (my_data.do_split) @@ -416,7 +359,7 @@ namespace adcval[cphi - 2][tbin] + adcval[cphi - 3][tbin]) { // rising again phidown = iphi + 1; - counts.overlap++; + touch++; break; } } @@ -426,61 +369,6 @@ namespace return; } - void check_cluster_touching(const std::vector& ihit_list, const std::vector>& adcval, int phibins, int tbins, ClusterCounters &counts) - { - // Encode (iphi, it) into single integer for fast lookup - std::unordered_set cluster_hits; - cluster_hits.reserve(ihit_list.size()); - - auto encode = [tbins](int phi, int t) - { - return phi * tbins + t; - }; - - for (const auto &hit : ihit_list) - { - cluster_hits.insert(encode(hit.iphi, hit.it)); - } - - for (const auto &hit : ihit_list) - { - int iphi = hit.iphi; - int it = hit.it; - - for (int dphi = -1; dphi <= 1; ++dphi) - { - for (int dt = -1; dt <= 1; ++dt) - { - if (dphi == 0 && dt == 0) { continue; } - - int nphi = iphi + dphi; - int nt = it + dt; - - if (nphi < 0 || nphi >= phibins || - nt < 0 || nt >= tbins) { - continue; - } - - // skip same cluster - if (cluster_hits.contains(encode(nphi, nt))) { continue; } - - // neighbor has signal → touching - if (adcval[nphi][nt] > 0 && - adcval[nphi][nt] != USHRT_MAX) - { - // Check Phi - if (dphi == -1) { counts.slmix = 1; } - if (dphi == 1) { counts.srmix = 1; } - - // Check Time - if (dt == -1) { counts.tlmix = 1; } - if (dt == 1) { counts.trmix = 1; } - } - } - } - } - } - int is_hit_isolated(int iphi, int it, int NPhiBinsMax, int NTBinsMax, const std::vector> &adcval) { // check isolated hits @@ -538,25 +426,20 @@ namespace return isiso; } - void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, ClusterCounters &counts) + void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, int &touch, int &edge) { - bool ttop_edge = false; - bool tbottom_edge = false; - bool phitop_edge = false; - bool phibottom_edge = false; - // search along phi at the peak in t // const int NPhiBinsMax = (int) my_data.phibins; // const int NTBinsMax = (int) my_data.tbins; int tup = 0; int tdown = 0; - find_t_range(phibin, tbin, my_data, adcval, tdown, tup, counts, ttop_edge, tbottom_edge); + find_t_range(phibin, tbin, my_data, adcval, tdown, tup, touch, edge); // now we have the t extent of the cluster, go find the phi edges for (int it = tbin - tdown; it <= (tbin + tup); it++) { int phiup = 0; int phidown = 0; - find_phi_range(phibin, it, my_data, adcval, phidown, phiup, counts, phitop_edge, phibottom_edge); + find_phi_range(phibin, it, my_data, adcval, phidown, phiup, touch, edge); for (int iphi = (phibin - phidown); iphi <= (phibin + phiup); iphi++) { if (adcval[iphi][it] > 0 && adcval[iphi][it] != USHRT_MAX) @@ -573,7 +456,7 @@ namespace hit.it = it; hit.adc = adcval[iphi][it]; - if (counts.overlap > 0) + if (touch > 0) { if ((iphi == (phibin - phidown)) || (iphi == (phibin + phiup))) @@ -589,7 +472,7 @@ namespace } void calc_cluster_parameter(const int iphi_center, const int it_center, - const std::vector &ihit_list, thread_data &my_data, ClusterCounters counts) + const std::vector &ihit_list, thread_data &my_data, int ntouch, int nedge) { // // get z range from layer geometry @@ -605,8 +488,6 @@ namespace double iphi_sum = 0.0; double iphi2_sum = 0.0; - double it_sum = 0.0; - double radius = my_data.layergeom->get_radius(); // returns center of layer int phibinhi = -1; @@ -616,12 +497,6 @@ namespace int clus_size = ihit_list.size(); int max_adc = 0; - int phibinmax = -1; - int tbinmax = -1; - double cen_adc = 0; - - int size = 0; - if (clus_size <= my_data.min_clus_size) { return; @@ -646,16 +521,14 @@ namespace training_hits->phistep = my_data.layergeom->get_phistep(); training_hits->zstep = my_data.layergeom->get_zstep() * my_data.tGeometry->get_drift_velocity(); training_hits->layer = my_data.layer; - training_hits->ntouch = counts.overlap; - training_hits->nedge = counts.nedge; + training_hits->ntouch = ntouch; + training_hits->nedge = nedge; training_hits->v_adc.fill(0); } // std::cout << "process list" << std::endl; std::vector hitkeyvec; - std::map, double> adc_map; - // keep track of the hit locations in a given cluster std::map m_phi{}; std::map m_z{}; @@ -671,18 +544,7 @@ namespace continue; } - size++; - - int adc_int = static_cast(std::round(adc)); - - if (adc_int > max_adc) - { - max_adc = adc_int; - phibinmax = iphi; - tbinmax = it; - } - - // max_adc = std::max(max_adc, static_cast(std::round(adc))); // preserves rounding (0.5 -> 1) + 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); @@ -703,12 +565,8 @@ namespace t_sum += t * adc; t2_sum += square(t) * adc; - it_sum += it * adc; - adc_sum += adc; - adc_map[{iphi, it}] += adc; - if (my_data.fillClusHitsVerbose) { auto pnew = m_phi.try_emplace(iphi, adc); @@ -765,15 +623,13 @@ namespace left_pad >= my_data.phioffset && deadset.contains(TpcDefs::genHitKey(left_pad, 0))) { - counts.nedge++; - counts.dledge = 1; + nedge++; } if (right_pad < (my_data.phibins + my_data.phioffset) && deadset.contains(TpcDefs::genHitKey(right_pad, 0))) { - counts.nedge++; - counts.dredge = 1; + nedge++; } } } @@ -790,62 +646,24 @@ namespace left_pad >= my_data.phioffset && hotset.contains(TpcDefs::genHitKey(left_pad, 0))) { - counts.nedge++; - counts.hledge = 1; + nedge++; } if (right_pad < (my_data.phibins + my_data.phioffset) && hotset.contains(TpcDefs::genHitKey(right_pad, 0))) { - counts.nedge++; - counts.hredge = 1; + nedge++; } } } - // This is local position - double clusiphi = iphi_sum / adc_sum; - double clusit = it_sum / adc_sum; - // This is the global position + double clusiphi = iphi_sum / adc_sum; double clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); - double clust = t_sum / adc_sum; - - // ADC of centroid bin - int iphi_centroid = static_cast(std::floor(clusiphi)); - int it_centroid = static_cast(std::floor(clusit)); - - auto it_cent = adc_map.find({iphi_centroid, it_centroid}); - if (it_cent != adc_map.end()) - { - cen_adc = it_cent->second; - } - else - { - cen_adc = 0.0; // centroid may not land on a real hit - } - - // Max ADC position in global coordinates - double maxphi = my_data.layergeom->get_phi(phibinmax, my_data.side); - double maxt = my_data.layergeom->get_zcenter(tbinmax); - - // Phase relative to max ADC position - double padphase = 0.0; - double tbinphase = 0.0; - - if (my_data.layergeom->get_phistep() > 0) - { - padphase = (clusphi - maxphi) / my_data.layergeom->get_phistep(); - } - - if (my_data.layergeom->get_zstep() > 0) - { - tbinphase = (clust - maxt) / my_data.layergeom->get_zstep(); - } double clusx = radius * cos(clusphi); double clusy = radius * sin(clusphi); - + double clust = t_sum / adc_sum; // needed for surface identification double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); // convert z drift length to z position in the TPC @@ -884,7 +702,6 @@ namespace char tsize = tbinhi - tbinlo + 1; char phisize = phibinhi - phibinlo + 1; - char rsize = size; // std::cout << "phisize: " << (int) phisize << " phibinhi " << phibinhi << " phibinlo " << phibinlo << std::endl; // phi_cov = (weighted mean of dphi^2) - (weighted mean of dphi)^2, which is essentially the weighted mean of dphi^2. The error is then: // e_phi = sigma_dphi/sqrt(N) = sqrt( sigma_dphi^2 / N ) -- where N is the number of samples of the distribution with standard deviation sigma_dphi @@ -909,54 +726,20 @@ 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) { - TrkrCluster* clus = nullptr; - - if (my_data.debug) - { - clus = new TrkrClusterv6; - } - else - { - clus = new TrkrClusterv5; - } - + auto *clus = new TrkrClusterv5; + // auto clus = std::make_unique(); clus_base = clus; - clus->setLocalX(local(0)); - clus->setLocalY(clust); - clus->setSubSurfKey(subsurfkey); clus->setAdc(adc_sum); clus->setMaxAdc(max_adc); - clus->setCenAdc(cen_adc); - clus->setPadCen(clusiphi); - clus->setTBinCen(clusit); - clus->setPadMax(phibinmax); - clus->setTBinMax(tbinmax); - clus->setPhiError(sqrt(phi_err_square)); - clus->setZError(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(), 2))); - clus->setRSize(rsize); + clus->setEdge(nedge); clus->setPhiSize(phisize); clus->setZSize(tsize); - clus->setOverlap(counts.overlap); - clus->setEdge(counts.nedge); - clus->setSLEdge(counts.sledge); - clus->setSREdge(counts.sredge); - clus->setTLEdge(counts.tledge); - clus->setTREdge(counts.tredge); - clus->setDLEdge(counts.dledge); - clus->setDREdge(counts.dredge); - clus->setHLEdge(counts.hledge); - clus->setHREdge(counts.hredge); - clus->setSLMix(counts.slmix); - clus->setSRMix(counts.srmix); - clus->setTLMix(counts.tlmix); - clus->setTRMix(counts.trmix); - clus->setPhiBinLo(phibinlo); - clus->setPhiBinHi(phibinhi); - clus->setTBinLo(tbinlo); - clus->setTBinHi(tbinhi); - clus->setPadPhase(padphase); - clus->setTBinPhase(tbinphase); - + clus->setSubSurfKey(subsurfkey); + clus->setOverlap(ntouch); + clus->setLocalX(local(0)); + clus->setLocalY(clust); + clus->setPhiError(sqrt(phi_err_square)); + clus->setZError(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(), 2))); my_data.cluster_vector.push_back(clus); b_made_cluster = true; } @@ -1254,9 +1037,6 @@ namespace } } */ - - std::vector> adcval_orig = adcval; - // std::cout << "done filling " << std::endl; while (!all_hit_map.empty()) { @@ -1284,10 +1064,9 @@ namespace // start with highest adc hit // -> cluster around it and get vector of hits std::vector ihit_list; - // Setting all the counters - ClusterCounters counts; - - get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); + int ntouch = 0; + int nedge = 0; + get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); if (my_data->FixedWindow > 0) { @@ -1323,16 +1102,11 @@ namespace my_data->FixedWindow = 0; // reset hit list and try again without fixed window ihit_list.clear(); - // resetting all the counters - counts.clear(); - get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); + get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); // std::cout << " stepdown size after " << ihit_list.size() << std::endl; my_data->FixedWindow = window_cache; } } - - check_cluster_touching(ihit_list, adcval_orig, my_data->phibins, my_data->tbins, counts); - if (ihit_list.size() <= 1) { remove_hits(ihit_list, all_hit_map, adcval); @@ -1343,7 +1117,7 @@ namespace // -> add hits to truth association // remove hits from all_hit_map // repeat untill all_hit_map empty - calc_cluster_parameter(iphi, it, ihit_list, *my_data, counts); + calc_cluster_parameter(iphi, it, ihit_list, *my_data, ntouch, nedge); remove_hits(ihit_list, all_hit_map, adcval); ihit_list.clear(); } @@ -1762,7 +1536,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.phioffset = PhiOffset; thread_pair.data.tbins = NTBinsSide; thread_pair.data.toffset = TOffset; - thread_pair.data.debug = m_debug; + thread_pair.data.radius = layergeom->get_radius(); thread_pair.data.drift_velocity = m_tGeometry->get_drift_velocity(); thread_pair.data.pads_per_sector = 0; @@ -1851,7 +1625,6 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.pedestal = pedestal; thread_pair.data.sector = sector; thread_pair.data.side = side; - thread_pair.data.debug = m_debug; thread_pair.data.do_assoc = do_hit_assoc; thread_pair.data.do_wedge_emulation = do_wedge_emulation; thread_pair.data.tGeometry = m_tGeometry; diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index c566f5b4f8..801207654e 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -91,11 +91,6 @@ class TpcClusterizer : public SubsysReco m_hotChannelMapName = hmap; } - void DetailedClusterAnalysis() - { - m_debug = true; - } - private: bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; @@ -140,7 +135,6 @@ class TpcClusterizer : public SubsysReco bool m_maskDeadChannels {false}; bool m_maskHotChannels {false}; bool m_maskFromFile {false}; - bool m_debug{false}; std::string m_deadChannelMapName; std::string m_hotChannelMapName; }; diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 2035e19796..f37440646b 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -52,21 +52,21 @@ class TrkrCluster : public PHObject // cluster position // virtual float getLocalX() const { return std::numeric_limits::quiet_NaN(); } - virtual void setLocalX(const float) {} + virtual void setLocalX(float) {} virtual float getLocalY() const { return std::numeric_limits::quiet_NaN(); } - virtual void setLocalY(const float) {} + virtual void setLocalY(float) {} // // cluster info // - virtual void setAdc(const unsigned int) {} + virtual void setAdc(unsigned int) {} virtual unsigned int getAdc() const { return UINT_MAX; } - virtual void setMaxAdc(const uint16_t) {} + virtual void setMaxAdc(uint16_t) {} virtual unsigned int getMaxAdc() const { return UINT_MAX; } virtual char getOverlap() const { return std::numeric_limits::max(); } - virtual void setOverlap(const char) {} + virtual void setOverlap(char) {} virtual char getEdge() const { return std::numeric_limits::max(); } - virtual void setEdge(const char) {} + virtual void setEdge(char) {} virtual void setTime(const float) {} virtual float getTime() const { return std::numeric_limits::quiet_NaN(); } virtual char getSize() const { return std::numeric_limits::max(); } @@ -82,8 +82,8 @@ class TrkrCluster : public PHObject virtual unsigned int getCenAdc() const { return UINT_MAX; } virtual float getPadCen() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinCen() const { return std::numeric_limits::quiet_NaN(); } - virtual int getPadMax() const { return std::numeric_limits::max(); } - virtual int getTBinMax() const { return std::numeric_limits::max(); } + virtual float getPadMax() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinMax() const { return std::numeric_limits::quiet_NaN(); } virtual char getSLEdge() const { return std::numeric_limits::max(); } virtual char getSREdge() const { return std::numeric_limits::max(); } virtual char getTLEdge() const { return std::numeric_limits::max(); } @@ -92,52 +92,23 @@ class TrkrCluster : public PHObject virtual char getDREdge() const { return std::numeric_limits::max(); } virtual char getHLEdge() const { return std::numeric_limits::max(); } virtual char getHREdge() const { return std::numeric_limits::max(); } - virtual char getSLMix() const { return std::numeric_limits::max(); } - virtual char getSRMix() const { return std::numeric_limits::max(); } - virtual char getTLMix() const { return std::numeric_limits::max(); } - virtual char getTRMix() const { return std::numeric_limits::max(); } - virtual unsigned short getPhiBinLo() const { return std::numeric_limits::max(); } - virtual unsigned short getPhiBinHi() const { return std::numeric_limits::max(); } - virtual unsigned short getTBinLo() const { return std::numeric_limits::max(); } - virtual unsigned short getTBinHi() const { return std::numeric_limits::max(); } + virtual int getSLMix() const { return std::numeric_limits::max(); } + virtual int getSRMix() const { return std::numeric_limits::max(); } + virtual int getTLMix() const { return std::numeric_limits::max(); } + virtual int getTRMix() const { return std::numeric_limits::max(); } + virtual float getPhiBinLo() const { return std::numeric_limits::quiet_NaN(); } + virtual float getPhiBinHi() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinLo() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinHi() const { return std::numeric_limits::quiet_NaN(); } virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } - virtual void setSLEdge(const char) {}; - virtual void setSREdge(const char) {}; - virtual void setTLEdge(const char) {}; - virtual void setTREdge(const char) {}; - virtual void setDLEdge(const char) {}; - virtual void setDREdge(const char) {}; - virtual void setHLEdge(const char) {}; - virtual void setHREdge(const char) {}; - virtual void setSLMix(const char) {}; - virtual void setSRMix(const char) {}; - virtual void setTLMix(const char) {}; - virtual void setTRMix(const char) {}; - virtual void setPhiBinLo(const unsigned short) {}; - virtual void setPhiBinHi(const unsigned short) {}; - virtual void setTBinLo(const unsigned short) {}; - virtual void setTBinHi(const unsigned short) {}; - virtual void setPadPhase(const float) {}; - virtual void setTBinPhase(const float) {}; - virtual void setRSize(const char) {}; - virtual void setCenAdc(const uint16_t) {}; - virtual void setPadCen(const float) {}; - virtual void setTBinCen(const float) {}; - virtual void setPadMax(const int) {}; - virtual void setTBinMax(const int) {}; - virtual void setPhiError(const float) {}; - virtual void setZError(const float) {}; - virtual void setPhiSize(const char) {}; - virtual void setZSize(const char) {}; - /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual TrkrDefs::subsurfkey getSubSurfKey() const { return TrkrDefs::SUBSURFKEYMAX; } - virtual void setSubSurfKey(const TrkrDefs::subsurfkey /*id*/) {} + virtual void setSubSurfKey(TrkrDefs::subsurfkey /*id*/) {} // Global coordinate functions are deprecated, use local // coordinate functions only diff --git a/offline/packages/trackbase/TrkrClusterv4.cc b/offline/packages/trackbase/TrkrClusterv4.cc index 8ee11bf797..542c1530cc 100644 --- a/offline/packages/trackbase/TrkrClusterv4.cc +++ b/offline/packages/trackbase/TrkrClusterv4.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - constexpr T square(const T& x) + inline constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv4.h b/offline/packages/trackbase/TrkrClusterv4.h index 439e3d9aef..ec0bc4703c 100644 --- a/offline/packages/trackbase/TrkrClusterv4.h +++ b/offline/packages/trackbase/TrkrClusterv4.h @@ -160,10 +160,10 @@ class TrkrClusterv4 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) override { m_phisize = phisize; } + void setPhiSize(char phisize) { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) override { m_zsize = zsize; } + void setZSize(char zsize) { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } void setOverlap(char overlap) override { m_overlap = overlap; } diff --git a/offline/packages/trackbase/TrkrClusterv5.cc b/offline/packages/trackbase/TrkrClusterv5.cc index a0cc7fbe52..58e08745ad 100644 --- a/offline/packages/trackbase/TrkrClusterv5.cc +++ b/offline/packages/trackbase/TrkrClusterv5.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - constexpr T square(const T& x) + inline constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index ee3ac20755..ebb0bae961 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -54,12 +54,12 @@ class TrkrClusterv5 : public TrkrCluster float getPosition(int coor) const override { return m_local[coor]; } void setPosition(int coor, float xi) override { m_local[coor] = xi; } float getLocalX() const override { return m_local[0]; } - void setLocalX(const float loc0) override { m_local[0] = loc0; } + void setLocalX(float loc0) override { m_local[0] = loc0; } float getLocalY() const override { return m_local[1]; } - void setLocalY(const float loc1) override { m_local[1] = loc1; } + void setLocalY(float loc1) override { m_local[1] = loc1; } TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } - void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } // // cluster info @@ -69,7 +69,7 @@ class TrkrClusterv5 : public TrkrCluster return m_adc; } - void setAdc(const unsigned int adc) override + void setAdc(unsigned int adc) override { m_adc = adc; } @@ -79,7 +79,7 @@ class TrkrClusterv5 : public TrkrCluster return m_maxadc; } - void setMaxAdc(const uint16_t maxadc) override + void setMaxAdc(uint16_t maxadc) override { m_maxadc = maxadc; } @@ -96,11 +96,11 @@ class TrkrClusterv5 : public TrkrCluster return m_zerr; } - void setPhiError(const float phierror) override + void setPhiError(float phierror) { m_phierr = phierror; } - void setZError(const float zerror) override + void setZError(float zerror) { m_zerr = zerror; } @@ -156,16 +156,16 @@ class TrkrClusterv5 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(const char phisize) override { m_phisize = phisize; } + void setPhiSize(char phisize) { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(const char zsize) override { m_zsize = zsize; } + void setZSize(char zsize) { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } - void setOverlap(const char overlap) override { m_overlap = overlap; } + void setOverlap(char overlap) override { m_overlap = overlap; } char getEdge() const override { return m_edge; } - void setEdge(const char edge) override { m_edge = edge; } + void setEdge(char edge) override { m_edge = edge; } // float getPhiSize() const override //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 683aeded6e..37ffdffbbf 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -60,7 +60,7 @@ class TrkrClusterv6 : public TrkrCluster { return (coor >= 0 && coor < 2) ? m_local[coor] : std::numeric_limits::quiet_NaN(); } - void setPosition(const int coor, const float xi) override + void setPosition(int coor, float xi) override { if (coor >= 0 && coor < 2) { @@ -68,36 +68,36 @@ class TrkrClusterv6 : public TrkrCluster } } float getLocalX() const override { return m_local[0]; } - void setLocalX(const float loc0) override { m_local[0] = loc0; } + void setLocalX(float loc0) override { m_local[0] = loc0; } float getLocalY() const override { return m_local[1]; } - void setLocalY(const float loc1) override { m_local[1] = loc1; } + void setLocalY(float loc1) override { m_local[1] = loc1; } TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } - void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } // // cluster info // unsigned int getAdc() const override { return m_adc; } - void setAdc(const unsigned int adc) override { m_adc = adc; } + void setAdc(unsigned int adc) override { m_adc = adc; } unsigned int getMaxAdc() const override { return m_maxadc; } - void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } + void setMaxAdc(uint16_t maxadc) override { m_maxadc = maxadc; } unsigned int getCenAdc() const override { return m_cenadc; } - void setCenAdc(const uint16_t cenadc) override { m_cenadc = cenadc; } + void setCenAdc(uint16_t cenadc) { m_cenadc = cenadc; } float getPadCen() const override { return m_padcen; } - void setPadCen(const float padcen) override { m_padcen = padcen; } + void setPadCen(float padcen) { m_padcen = padcen; } float getTBinCen() const override { return m_tbincen; } - void setTBinCen(const float tbincen) override { m_tbincen = tbincen; } + void setTBinCen(float tbincen) { m_tbincen = tbincen; } - int getPadMax() const override { return m_padmax; } - void setPadMax(const int padmax) override { m_padmax = padmax; } + float getPadMax() const override { return m_padmax; } + void setPadMax(float padmax) { m_padmax = padmax; } - int getTBinMax() const override { return m_tbinmax; } - void setTBinMax(const int tbinmax) override { m_tbinmax = tbinmax; } + float getTBinMax() const override { return m_tbinmax; } + void setTBinMax(float tbinmax) { m_tbinmax = tbinmax; } // // convenience interface @@ -105,117 +105,117 @@ class TrkrClusterv6 : public TrkrCluster float getRPhiError() const override { return m_phierr; } float getZError() const override { return m_zerr; } - void setPhiError(const float phierror) override { m_phierr = phierror; } - void setZError(const float zerror) override { m_zerr = zerror; } + void setPhiError(float phierror) { m_phierr = phierror; } + void setZError(float zerror) { m_zerr = zerror; } char getSize() const override { return m_phisize * m_zsize; } - // void setSize(const char size) { m_size = size; } + // void setSize(char size) { m_size = size; } float getRSize() const override { return (float) m_rsize; } - void setRSize(const char rsize) override { m_rsize = rsize; } + void setRSize(unsigned char rsize) { m_rsize = rsize; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(const char phisize) override { m_phisize = phisize; } + void setPhiSize(char phisize) { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(const char zsize) override { m_zsize = zsize; } + void setZSize(char zsize) { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } - void setOverlap(const char overlap) override { m_overlap = overlap; } + void setOverlap(char overlap) override { m_overlap = overlap; } char getEdge() const override { return m_edge; } - void setEdge(const char edge) override { m_edge = edge; } + void setEdge(char edge) override { m_edge = edge; } char getSLEdge() const override { return m_sledge; } - void setSLEdge(const char sledge) override { m_sledge = sledge; } + void setSLEdge(char sledge) { m_sledge = sledge; } char getSREdge() const override { return m_sredge; } - void setSREdge(const char sredge) override { m_sredge = sredge; } + void setSREdge(char sredge) { m_sredge = sredge; } char getTLEdge() const override { return m_tledge; } - void setTLEdge(const char tledge) override { m_tledge = tledge; } + void setTLEdge(char tledge) { m_tledge = tledge; } char getTREdge() const override { return m_tredge; } - void setTREdge(const char tredge) override { m_tredge = tredge; } + void setTREdge(char tredge) { m_tredge = tredge; } char getDLEdge() const override { return m_dledge; } - void setDLEdge(const char dledge) override { m_dledge = dledge; } + void setDLEdge(char dledge) { m_dledge = dledge; } char getDREdge() const override { return m_dredge; } - void setDREdge(const char dredge) override { m_dredge = dredge; } + void setDREdge(char dredge) { m_dredge = dredge; } char getHLEdge() const override { return m_hledge; } - void setHLEdge(const char hledge) override { m_hledge = hledge; } + void setHLEdge(char hledge) { m_hledge = hledge; } char getHREdge() const override { return m_hredge; } - void setHREdge(const char hredge) override { m_hredge = hredge; } + void setHREdge(char hredge) { m_hredge = hredge; } - char getSLMix() const override { return m_slmix; } - void setSLMix(const char slmix) override { m_slmix = slmix; } + int getSLMix() const override { return m_slmix; } + void setSLMix(char slmix) { m_slmix = slmix; } - char getSRMix() const override { return m_srmix; } - void setSRMix(const char srmix) override { m_srmix = srmix; } + int getSRMix() const override { return m_srmix; } + void setSRMix(char srmix) { m_srmix = srmix; } - char getTLMix() const override { return m_tlmix; } - void setTLMix(const char tlmix) override { m_tlmix = tlmix; } + int getTLMix() const override { return m_tlmix; } + void setTLMix(char tlmix) { m_tlmix = tlmix; } - char getTRMix() const override { return m_trmix; } - void setTRMix(const char trmix) override { m_trmix = trmix; } + int getTRMix() const override { return m_trmix; } + void setTRMix(char trmix) { m_trmix = trmix; } - unsigned short getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(const unsigned short phibinlo) override { m_phibinlo = phibinlo; } + float getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(float phibinlo) { m_phibinlo = phibinlo; } - unsigned short getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(const unsigned short phibinhi) override { m_phibinhi = phibinhi; } + float getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(float phibinhi) { m_phibinhi = phibinhi; } - unsigned short getTBinLo() const override { return m_tbinlo; } - void setTBinLo(const unsigned short tbinlo) override { m_tbinlo = tbinlo; } + float getTBinLo() const override { return m_tbinlo; } + void setTBinLo(float tbinlo) { m_tbinlo = tbinlo; } - unsigned short getTBinHi() const override { return m_tbinhi; } - void setTBinHi(const unsigned short tbinhi) override { m_tbinhi = tbinhi; } + float getTBinHi() const override { return m_tbinhi; } + void setTBinHi(float tbinhi) { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } - void setPadPhase(const float padphase) override { m_padphase = padphase; } + void setPadPhase(float padphase) { m_padphase = padphase; } float getTBinPhase() const override { return m_tbinphase; } - void setTBinPhase(const float tbinphase) override { m_tbinphase = tbinphase; } + void setTBinPhase(float tbinphase){ m_tbinphase = tbinphase; } private: float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; //< 2D local position [cm] 2 * 32 64bit - cumul 1*64 TrkrDefs::subsurfkey m_subsurfkey {TrkrDefs::SUBSURFKEYMAX}; //< unique identifier for hitsetkey-surface maps 16 bit - float m_phierr{std::numeric_limits::quiet_NaN()}; - float m_zerr{std::numeric_limits::quiet_NaN()}; - unsigned short m_adc{std::numeric_limits::max()}; //< cluster sum adc 16 - unsigned short m_maxadc{std::numeric_limits::max()}; //< cluster max adc 16 - unsigned short m_cenadc{std::numeric_limits::max()}; //< cluster centroid adc 16 - float m_padcen{std::numeric_limits::quiet_NaN()}; - float m_tbincen{std::numeric_limits::quiet_NaN()}; - int m_padmax{std::numeric_limits::max()}; - int m_tbinmax{std::numeric_limits::max()}; - char m_rsize{std::numeric_limits::max()}; - char m_phisize{std::numeric_limits::max()}; - char m_zsize{std::numeric_limits::max()}; - char m_overlap{std::numeric_limits::max()}; - char m_edge{std::numeric_limits::max()}; - char m_sledge{std::numeric_limits::max()}; - char m_sredge{std::numeric_limits::max()}; - char m_tledge{std::numeric_limits::max()}; - char m_tredge{std::numeric_limits::max()}; - char m_dledge{std::numeric_limits::max()}; - char m_dredge{std::numeric_limits::max()}; - char m_hledge{std::numeric_limits::max()}; - char m_hredge{std::numeric_limits::max()}; - char m_slmix{std::numeric_limits::max()}; - char m_srmix{std::numeric_limits::max()}; - char m_tlmix{std::numeric_limits::max()}; - char m_trmix{std::numeric_limits::max()}; - unsigned short m_phibinlo{std::numeric_limits::max()}; - unsigned short m_phibinhi{std::numeric_limits::max()}; - unsigned short m_tbinlo{std::numeric_limits::max()}; - unsigned short m_tbinhi{std::numeric_limits::max()}; - float m_padphase{std::numeric_limits::quiet_NaN()}; - float m_tbinphase{std::numeric_limits::quiet_NaN()}; + float m_phierr{0}; + float m_zerr{0}; + unsigned short int m_adc{0}; //< cluster sum adc 16 + unsigned short int m_maxadc{0}; //< cluster max adc 16 + unsigned short int m_cenadc{0}; //< cluster centroid adc 16 + float m_padcen{0}; + float m_tbincen{0}; + float m_padmax{0}; + float m_tbinmax{0}; + unsigned char m_rsize{0}; // 8bit + char m_phisize{0}; // 8bit + char m_zsize{0}; // 8bit + char m_overlap{0}; // 8bit + char m_edge{0}; // 8bit - cumul 2*64 + char m_sledge{0}; // 8bit + char m_sredge{0}; // 8bit + char m_tledge{0}; // 8bit + char m_tredge{0}; // 8bit + char m_dledge{0}; // 8bit + char m_dredge{0}; // 8bit + char m_hledge{0}; // 8bit + char m_hredge{0}; // 8bit + char m_slmix{0}; // 8bit + char m_srmix{0}; // 8bit + char m_tlmix{0}; // 8bit + char m_trmix{0}; // 8bit + float m_phibinlo{0}; + float m_phibinhi{0}; + float m_tbinlo{0}; + float m_tbinhi{0}; + float m_padphase{0}; + float m_tbinphase{0}; ClassDefOverride(TrkrClusterv6, 1) }; From 95f03f62fa98103cd65afea377eca0033773bc75 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 24 Jun 2026 11:13:40 -0400 Subject: [PATCH 728/866] replace boolean by direct comparison --- offline/packages/CaloReco/CaloTowerStatus.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 277e5efc6b..d50a792adf 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -154,9 +154,6 @@ void CaloTowerStatus::LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotM unsigned int ntowers = m_raw_towers->size(); m_cdbInfo_vec.resize(ntowers); - // Check if we actually need to evaluate the z_score - bool need_z_score = (z_score_threshold != z_score_threshold_default); - for (unsigned int channel = 0; channel < ntowers; channel++) { unsigned int key = m_raw_towers->encode_key(channel); @@ -170,7 +167,7 @@ void CaloTowerStatus::LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotM m_cdbInfo_vec[channel].hotMap_val = cdbttree_hotMap->GetIntValue(key, m_fieldname_hotMap); // Only fetch the z_score field if the custom threshold requires it - if (need_z_score) + if (z_score_threshold != z_score_threshold_default) { m_cdbInfo_vec[channel].z_score = cdbttree_hotMap->GetFloatValue(key, m_fieldname_z_score); } From 3e03d3b0b224f042d1943ad5a9ffab68ccb485e0 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Wed, 24 Jun 2026 19:46:07 -0400 Subject: [PATCH 729/866] Separate luminosity calculation into its own Subsys reco module (StreamingLumiReco) --- offline/packages/bcolumicount/Makefile.am | 12 +- .../bcolumicount/StreamingBcoCheck.cc | 69 ++++++ .../packages/bcolumicount/StreamingBcoCheck.h | 25 ++ .../bcolumicount/StreamingBcoLumiCheck.h | 26 --- .../packages/bcolumicount/StreamingBcoReco.cc | 218 ++++++++++++++++++ .../packages/bcolumicount/StreamingBcoReco.h | 53 +++++ ...gBcoLumiCheck.cc => StreamingLumiCheck.cc} | 17 +- .../bcolumicount/StreamingLumiCheck.h | 26 +++ .../packages/bcolumicount/StreamingLumiInfo.h | 10 + .../bcolumicount/StreamingLumiInfov1.h | 14 +- ...ingBcoLumiReco.cc => StreamingLumiReco.cc} | 88 ++----- ...amingBcoLumiReco.h => StreamingLumiReco.h} | 33 +-- 12 files changed, 464 insertions(+), 127 deletions(-) create mode 100644 offline/packages/bcolumicount/StreamingBcoCheck.cc create mode 100644 offline/packages/bcolumicount/StreamingBcoCheck.h delete mode 100644 offline/packages/bcolumicount/StreamingBcoLumiCheck.h create mode 100644 offline/packages/bcolumicount/StreamingBcoReco.cc create mode 100644 offline/packages/bcolumicount/StreamingBcoReco.h rename offline/packages/bcolumicount/{StreamingBcoLumiCheck.cc => StreamingLumiCheck.cc} (85%) create mode 100644 offline/packages/bcolumicount/StreamingLumiCheck.h rename offline/packages/bcolumicount/{StreamingBcoLumiReco.cc => StreamingLumiReco.cc} (70%) rename offline/packages/bcolumicount/{StreamingBcoLumiReco.h => StreamingLumiReco.h} (65%) diff --git a/offline/packages/bcolumicount/Makefile.am b/offline/packages/bcolumicount/Makefile.am index fb546ed53a..297fc5f840 100644 --- a/offline/packages/bcolumicount/Makefile.am +++ b/offline/packages/bcolumicount/Makefile.am @@ -44,8 +44,10 @@ pkginclude_HEADERS = \ StreamingBcoInfov1.h \ StreamingLumiInfo.h \ StreamingLumiInfov1.h \ - StreamingBcoLumiReco.h \ - StreamingBcoLumiCheck.h + StreamingBcoReco.h \ + StreamingBcoCheck.h \ + StreamingLumiReco.h \ + StreamingLumiCheck.h libbcolumicount_io_la_SOURCES = \ @@ -59,8 +61,10 @@ libbcolumicount_io_la_SOURCES = \ libbcolumicount_la_SOURCES = \ BcoLumiReco.cc \ - StreamingBcoLumiReco.cc \ - StreamingBcoLumiCheck.cc + StreamingBcoReco.cc \ + StreamingBcoCheck.cc \ + StreamingLumiReco.cc \ + StreamingLumiCheck.cc BUILT_SOURCES = testexternals.cc diff --git a/offline/packages/bcolumicount/StreamingBcoCheck.cc b/offline/packages/bcolumicount/StreamingBcoCheck.cc new file mode 100644 index 0000000000..e18dfb7333 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoCheck.cc @@ -0,0 +1,69 @@ +#include "StreamingBcoCheck.h" + +//#include "BcoInfo.h" +#include "StreamingBcoInfo.h" +#include "StreamingLumiInfo.h" +//#include "BcoStreamingLumiInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE + + +#include + +StreamingBcoCheck::StreamingBcoCheck(const std::string &name) + : SubsysReco(name) +{ + return; +} + +int StreamingBcoCheck::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + + return iret; +} + +int StreamingBcoCheck::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoCheck::process_event(PHCompositeNode *topNode) +{ + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (streaming_bco_info) + { + if (Verbosity() > 1) + { + std::cout << "bco : " << streaming_bco_info->get_bco() << std::endl; + std::cout << "usable bco tag : " << streaming_bco_info->get_usable_bco_tag() << std::endl; + std::cout << "bco streaming window : (" << streaming_bco_info->get_bco_streaming_window().first << ", " << streaming_bco_info->get_bco_streaming_window().second << ")" << std::endl; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} \ No newline at end of file diff --git a/offline/packages/bcolumicount/StreamingBcoCheck.h b/offline/packages/bcolumicount/StreamingBcoCheck.h new file mode 100644 index 0000000000..5def0f329c --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoCheck.h @@ -0,0 +1,25 @@ +#ifndef BCOLUMICOUNT_STREAMINGBCOCHECK_H +#define BCOLUMICOUNT_STREAMINGBCOCHECK_H + +#include +#include + +#include + +#include + + +class StreamingBcoCheck : public SubsysReco +{ + public: + StreamingBcoCheck(const std::string &name = "BCOCHECKSTREAMINGOUTPUT"); + ~StreamingBcoCheck() override = default; + + int Init(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + + private: + static int CreateNodeTree(PHCompositeNode *topNode); +}; + +#endif // BCOLUMICOUNT_STREAMINGBCOCHECK_H diff --git a/offline/packages/bcolumicount/StreamingBcoLumiCheck.h b/offline/packages/bcolumicount/StreamingBcoLumiCheck.h deleted file mode 100644 index 579ca524c0..0000000000 --- a/offline/packages/bcolumicount/StreamingBcoLumiCheck.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef BCOLUMICOUNT_STREAMINGBCOLUMICHECK_H -#define BCOLUMICOUNT_STREAMINGBCOLUMICHECK_H - -#include -#include - -#include - -#include - - -class StreamingBcoLumiCheck : public SubsysReco -{ - public: - StreamingBcoLumiCheck(const std::string &name = "BCOLUMICHECKSTREAMINGOUTPUT"); - ~StreamingBcoLumiCheck() override = default; - - int Init(PHCompositeNode *topNode) override; - int InitRun(PHCompositeNode *topNode) override; - int process_event(PHCompositeNode *topNode) override; - - private: - static int CreateNodeTree(PHCompositeNode *topNode); -}; - -#endif // BCOLUMICOUNT_STREAMINGBCOLUMICHECK_H diff --git a/offline/packages/bcolumicount/StreamingBcoReco.cc b/offline/packages/bcolumicount/StreamingBcoReco.cc new file mode 100644 index 0000000000..6d37a1ccca --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoReco.cc @@ -0,0 +1,218 @@ +#include "StreamingBcoReco.h" + +#include "BcoInfo.h" +#include "StreamingBcoInfo.h" +#include "StreamingBcoInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE + +#include +#include +#include // for Packet + +#include + +#include + +StreamingBcoReco::StreamingBcoReco(const std::string &name) + : SubsysReco(name) +{ + hm = new Fun4AllHistoManager("bco_histos"); + Fun4AllServer *se = Fun4AllServer::instance(); + se->registerHistoManager(hm); + return; +} + +int StreamingBcoReco::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + h_bco_diff = new TH1I("h_bco_diff", ";bco diff;", 3500, 0, 3500); + std::string hist_name = "h_bco_diff_bit"; + for (int bit=0; bitregisterHisto(h_bco_diff_trigbits[bit]); + } + h_bco_tag = new TH1I("h_bco_tag", ";usable bco tag;", 2, -0.5, 1.5); + hm->registerHisto(h_bco_diff); + hm->registerHisto(h_bco_tag); + + return iret; +} + +// Do we even need to include this now that the lumi calculatin has been separated? Or should I remove `InitRun` entirely? +int StreamingBcoReco::InitRun(PHCompositeNode * topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *runNode; + runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << " Run Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoReco::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (!streaming_bco_info) + { + streaming_bco_info = new StreamingBcoInfov1(); + PHIODataNode *bconode = new PHIODataNode(streaming_bco_info, "STREAMINGBCOINFO", "PHObject"); + dstNode->addNode(bconode); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoReco::process_event(PHCompositeNode *topNode) +{ + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); + SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); + //Gl1Packet *gl1packet = findNode::getClass(topNode, 14001); + Event *evt = findNode::getClass(topNode, "PRDF"); + if (evt) + { + if (Verbosity() > 2) + { + evt->identify(); + } + if (evt->getEvtType() != DATAEVENT) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + Packet *packet = evt->getPacket(14001); + if (!packet) + { + if (Verbosity() > 0) + { + std::cout << "no gl1 packet 14001" << std::endl; + evt->identify(); + } + return Fun4AllReturnCodes::ABORTEVENT; + } + uint64_t gtm_bco = packet->lValue(0, "BCO"); + uint64_t gl1_scaledvec = packet->lValue(0, "ScaledVector"); + //uint64_t gl1_livevec = packet->lValue(0, "TriggerVector"); + + int bunchno = packet->lValue(0,"BunchNumber"); + if (bunchno < 0 || bunchno >= m_bunches) + { + if (Verbosity() > 0) + { + std::cout << PHWHERE << " invalid bunch number: " << bunchno << std::endl; + } + delete packet; + return Fun4AllReturnCodes::ABORTEVENT; + } + + delete packet; + + if (Verbosity() > 2) + { + if (!syncobject) + { + std::cout << PHWHERE << " SyncObject missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + std::cout << "Event No: " << syncobject->EventNumber() /*<< std::hex*/ + << " gl1 bco: " << gtm_bco < 2) + { + std::cout << "prev event: " << bcoinfo->get_previous_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_previous_bco() << std::dec << std::endl; + std::cout << "curr event: " << bcoinfo->get_current_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_current_bco() << std::dec << std::endl; + std::cout << "futu event: " << bcoinfo->get_future_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_future_bco() << std::dec << std::endl; + } + + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (!streaming_bco_info) + { + std::cout << PHWHERE << " STREAMINGBCOINFO node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + m_bco = bcoinfo->get_current_bco(); + if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} + uint64_t bco_prev = bcoinfo->get_previous_bco(); + uint64_t bco_futu = bcoinfo->get_future_bco(); + uint64_t bco_diff_prev = m_bco - bco_prev; + uint64_t bco_diff_futu = bco_futu - m_bco; + + // special case if BCO is within 20 of previous BCO? + if (bco_diff_prev < m_default_positive_window_length) + { + m_usable_bco_tag = true; + } + else + { + m_usable_bco_tag = false; + } + if (bco_diff_futu < m_default_positive_window_length) + { + // double check boundaries for overlap!! + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); + } + else + { + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, get_bco() + m_default_positive_window_length); + } + if (Verbosity() > 2) + { + std::cout << "bco_diff_prev : " << bco_diff_prev << std::endl; + std::cout << "bco_diff_futu : " << bco_diff_futu << std::endl; + } + h_bco_diff->Fill(bco_diff_prev); + h_bco_tag->Fill(m_usable_bco_tag); + for (int bit=0; bit> static_cast(bit)) & 0x1U) == 0x1U; + //bool scaled_trigger_fired = ((gl1_scaledvec >> bit) & 0x1U) == 0x1U; + + if (trigger_fired) + { + h_bco_diff_trigbits[bit]->Fill(bco_diff_prev); + } + } + + streaming_bco_info->set_bco(get_bco()); + streaming_bco_info->set_usable_bco_tag(get_usable_bco_tag()); + streaming_bco_info->set_bco_streaming_window(get_bco_streaming_window()); + if (syncobject) + { + streaming_bco_info->set_evtno(syncobject->EventNumber()); + } + } + } + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/bcolumicount/StreamingBcoReco.h b/offline/packages/bcolumicount/StreamingBcoReco.h new file mode 100644 index 0000000000..0e3ef015c7 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoReco.h @@ -0,0 +1,53 @@ +#ifndef BCOLUMICOUNT_STREAMINGBCORECO_H +#define BCOLUMICOUNT_STREAMINGBCORECO_H + +#include +#include + +#include +#include +#include + +class TH1; + +class StreamingBcoReco : public SubsysReco +{ + public: + StreamingBcoReco(const std::string &name = "STREAMINGBCOLUMIRECO"); + ~StreamingBcoReco() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + + virtual int get_evtno() const { return m_evtno; } + + virtual uint64_t get_bco() const { return m_bco; } + + virtual bool get_usable_bco_tag() const { return m_usable_bco_tag; } + + virtual std::pair get_bco_streaming_window() const { return m_bco_streaming_window; } + + virtual void set_default_positive_window_length(int val) { m_default_positive_window_length = val; } + virtual void set_default_negative_window_length(int val) { m_default_negative_window_length = val; } + + + + private: + static int CreateNodeTree(PHCompositeNode *topNode); + const int trigbits = 40; + Fun4AllHistoManager *hm = nullptr; + TH1 *h_bco_diff = nullptr; + TH1 *h_bco_diff_trigbits[40] = {nullptr}; + TH1 *h_bco_tag = nullptr; + + uint64_t m_bco{0}; + int m_bunches = 120; + int m_evtno{0}; + bool m_usable_bco_tag = false; + std::pair m_bco_streaming_window; + unsigned int m_default_positive_window_length{340}; + unsigned int m_default_negative_window_length{20}; +}; + +#endif // BCOLUMICOUNT_STREAMINGBCORECO_H diff --git a/offline/packages/bcolumicount/StreamingBcoLumiCheck.cc b/offline/packages/bcolumicount/StreamingLumiCheck.cc similarity index 85% rename from offline/packages/bcolumicount/StreamingBcoLumiCheck.cc rename to offline/packages/bcolumicount/StreamingLumiCheck.cc index f6bf88b584..b2527bb24d 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiCheck.cc +++ b/offline/packages/bcolumicount/StreamingLumiCheck.cc @@ -1,4 +1,4 @@ -#include "StreamingBcoLumiCheck.h" +#include "StreamingLumiCheck.h" //#include "BcoInfo.h" #include "StreamingBcoInfo.h" @@ -26,20 +26,20 @@ #include -StreamingBcoLumiCheck::StreamingBcoLumiCheck(const std::string &name) +StreamingLumiCheck::StreamingLumiCheck(const std::string &name) : SubsysReco(name) { return; } -int StreamingBcoLumiCheck::Init(PHCompositeNode *topNode) +int StreamingLumiCheck::Init(PHCompositeNode *topNode) { int iret = CreateNodeTree(topNode); return iret; } -int StreamingBcoLumiCheck::InitRun(PHCompositeNode *topNode) +int StreamingLumiCheck::InitRun(PHCompositeNode *topNode) { StreamingLumiInfo *streaming_lumi_info = findNode::getClass(topNode, "STREAMINGLUMIINFO"); if (streaming_lumi_info) @@ -51,7 +51,7 @@ int StreamingBcoLumiCheck::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -int StreamingBcoLumiCheck::CreateNodeTree(PHCompositeNode *topNode) +int StreamingLumiCheck::CreateNodeTree(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); PHCompositeNode *dstNode; @@ -63,8 +63,8 @@ int StreamingBcoLumiCheck::CreateNodeTree(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; } - -int StreamingBcoLumiCheck::process_event(PHCompositeNode *topNode) +/* +int StreamingLumiCheck::process_event(PHCompositeNode *topNode) { StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); if (streaming_bco_info) @@ -78,4 +78,5 @@ int StreamingBcoLumiCheck::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/offline/packages/bcolumicount/StreamingLumiCheck.h b/offline/packages/bcolumicount/StreamingLumiCheck.h new file mode 100644 index 0000000000..8fc89ff5e9 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiCheck.h @@ -0,0 +1,26 @@ +#ifndef BCOLUMICOUNT_STREAMINGLUMICHECK_H +#define BCOLUMICOUNT_STREAMINGLUMICHECK_H + +#include +#include + +#include + +#include + + +class StreamingLumiCheck : public SubsysReco +{ + public: + StreamingLumiCheck(const std::string &name = "LUMICHECKSTREAMINGOUTPUT"); + ~StreamingLumiCheck() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + //int process_event(PHCompositeNode *topNode) override; + + private: + static int CreateNodeTree(PHCompositeNode *topNode); +}; + +#endif // BCOLUMICOUNT_STREAMINGLUMICHECK_H diff --git a/offline/packages/bcolumicount/StreamingLumiInfo.h b/offline/packages/bcolumicount/StreamingLumiInfo.h index 1644b91d3b..9bea6a3dff 100644 --- a/offline/packages/bcolumicount/StreamingLumiInfo.h +++ b/offline/packages/bcolumicount/StreamingLumiInfo.h @@ -8,6 +8,7 @@ #include #include #include +#include /// @@ -27,6 +28,15 @@ class StreamingLumiInfo : public PHObject /// isValid returns non zero if object contains valid data //int isValid() const override; + virtual const std::array get_bunchnumber_lumi_raw() const { return std::array{}; } + virtual void set_bunchnumber_lumi_raw(const std::array& /*vals*/) { return; } + + virtual const std::array get_bunchnumber_lumi_live() const { return std::array{}; } + virtual void set_bunchnumber_lumi_live(const std::array& /*vals*/) { return; } + + virtual const std::array get_bunchnumber_lumi_scaled() const { return std::array{}; } + virtual void set_bunchnumber_lumi_scaled(const std::array& /*vals*/) { return; } + virtual double get_lumi_raw() const { return 0; } virtual void set_lumi_raw(double /*val*/) { return; } diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.h b/offline/packages/bcolumicount/StreamingLumiInfov1.h index b18a8a8c89..b8993c1f8d 100644 --- a/offline/packages/bcolumicount/StreamingLumiInfov1.h +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.h @@ -28,6 +28,15 @@ class StreamingLumiInfov1 : public StreamingLumiInfo /// isValid returns non zero if object contains valid data //int isValid() const override; + virtual const std::array get_bunchnumber_lumi_raw() const override { return m_bunchnumber_lumi_raw; } + virtual void set_bunchnumber_lumi_raw(const std::array& vals) override { m_bunchnumber_lumi_raw = vals; } + + virtual const std::array get_bunchnumber_lumi_live() const override { return m_bunchnumber_lumi_live; } + virtual void set_bunchnumber_lumi_live(const std::array& vals) override { m_bunchnumber_lumi_live = vals; } + + virtual const std::array get_bunchnumber_lumi_scaled() const override { return m_bunchnumber_lumi_scaled; } + virtual void set_bunchnumber_lumi_scaled(const std::array& vals) override { m_bunchnumber_lumi_scaled = vals; } + virtual double get_lumi_raw() const override { return m_lumi_raw; } virtual void set_lumi_raw(double val) override { m_lumi_raw = val; } @@ -39,12 +48,15 @@ class StreamingLumiInfov1 : public StreamingLumiInfo private: + std::array m_bunchnumber_lumi_raw{0.}; + std::array m_bunchnumber_lumi_live{0.}; + std::array m_bunchnumber_lumi_scaled{0.}; + double m_lumi_raw{0.}; double m_lumi_live{0.}; double m_lumi_scaled{0.}; - ClassDefOverride(StreamingLumiInfov1, 1) }; diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc b/offline/packages/bcolumicount/StreamingLumiReco.cc similarity index 70% rename from offline/packages/bcolumicount/StreamingBcoLumiReco.cc rename to offline/packages/bcolumicount/StreamingLumiReco.cc index 1e3c66d47f..57068b838c 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc +++ b/offline/packages/bcolumicount/StreamingLumiReco.cc @@ -1,8 +1,6 @@ -#include "StreamingBcoLumiReco.h" +#include "StreamingLumiReco.h" #include "BcoInfo.h" -#include "StreamingBcoInfo.h" -#include "StreamingBcoInfov1.h" #include "StreamingLumiInfo.h" #include "StreamingLumiInfov1.h" @@ -23,6 +21,8 @@ #include // for PHNodeIterator #include #include // for PHWHERE +#include // for MDB_NS_xsec + #include #include @@ -32,34 +32,19 @@ #include -StreamingBcoLumiReco::StreamingBcoLumiReco(const std::string &name) +StreamingLumiReco::StreamingLumiReco(const std::string &name) : SubsysReco(name) { - hm = new Fun4AllHistoManager("bco_histos"); - Fun4AllServer *se = Fun4AllServer::instance(); - se->registerHistoManager(hm); return; } -int StreamingBcoLumiReco::Init(PHCompositeNode *topNode) +int StreamingLumiReco::Init(PHCompositeNode *topNode) { int iret = CreateNodeTree(topNode); - h_bco_diff = new TH1I("h_bco_diff", ";bco diff;", 3500, 0, 3500); - std::string hist_name = "h_bco_diff_bit"; - for (int bit=0; bitregisterHisto(h_bco_diff_trigbits[bit]); - } - h_bco_tag = new TH1I("h_bco_tag", ";usable bco tag;", 2, -0.5, 1.5); - hm->registerHisto(h_bco_diff); - hm->registerHisto(h_bco_tag); - return iret; } -int StreamingBcoLumiReco::InitRun(PHCompositeNode * topNode) +int StreamingLumiReco::InitRun(PHCompositeNode * topNode) { PHNodeIterator iter(topNode); PHCompositeNode *runNode; @@ -79,7 +64,7 @@ int StreamingBcoLumiReco::InitRun(PHCompositeNode * topNode) return Fun4AllReturnCodes::EVENT_OK; } -int StreamingBcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) +int StreamingLumiReco::CreateNodeTree(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); PHCompositeNode *dstNode; @@ -89,17 +74,10 @@ int StreamingBcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); - if (!streaming_bco_info) - { - streaming_bco_info = new StreamingBcoInfov1(); - PHIODataNode *bconode = new PHIODataNode(streaming_bco_info, "STREAMINGBCOINFO", "PHObject"); - dstNode->addNode(bconode); - } return Fun4AllReturnCodes::EVENT_OK; } -int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) +int StreamingLumiReco::process_event(PHCompositeNode *topNode) { BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); @@ -125,9 +103,7 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::ABORTEVENT; } - uint64_t gtm_bco = packet->lValue(0, "BCO"); - uint64_t gl1_scaledvec = packet->lValue(0, "ScaledVector"); - //uint64_t gl1_livevec = packet->lValue(0, "TriggerVector"); + uint64_t gtm_bco = packet->lValue(0, "BCO"); int bunchno = packet->lValue(0,"BunchNumber"); if (bunchno < 0 || bunchno >= m_bunches) @@ -175,12 +151,6 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) << " bco: " << bcoinfo->get_future_bco() << std::dec << std::endl; } - StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); - if (!streaming_bco_info) - { - std::cout << PHWHERE << " STREAMINGBCOINFO node missing" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } m_bco = bcoinfo->get_current_bco(); if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} uint64_t bco_prev = bcoinfo->get_previous_bco(); @@ -200,29 +170,17 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) if (bco_diff_futu < m_default_positive_window_length) { // double check boundaries for overlap!! - m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); + m_bco_streaming_window = std::make_pair(m_bco - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); } else { - m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, get_bco() + m_default_positive_window_length); + m_bco_streaming_window = std::make_pair(m_bco - m_default_negative_window_length, m_bco + m_default_positive_window_length); } if (Verbosity() > 2) { - std::cout << "bco_diff_prev : " << bco_diff_prev << std::endl; std::cout << "bco_diff_futu : " << bco_diff_futu << std::endl; } - h_bco_diff->Fill(bco_diff_prev); - h_bco_tag->Fill(m_usable_bco_tag); - for (int bit=0; bit> static_cast(bit)) & 0x1U) == 0x1U; - //bool scaled_trigger_fired = ((gl1_scaledvec >> bit) & 0x1U) == 0x1U; - if (trigger_fired) - { - h_bco_diff_trigbits[bit]->Fill(bco_diff_prev); - } - } // Double check Zhiwan's logic for assigning the adjusted bunch! int lower = m_bco_streaming_window.first - m_bco; int upper = m_bco_streaming_window.second - m_bco; @@ -250,27 +208,19 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) // m_bunchnumber_crossings[adjusted_bunch] += 1; //} } - - streaming_bco_info->set_bco(get_bco()); - streaming_bco_info->set_usable_bco_tag(get_usable_bco_tag()); - streaming_bco_info->set_bco_streaming_window(get_bco_streaming_window()); - if (syncobject) - { - streaming_bco_info->set_evtno(syncobject->EventNumber()); - } } } return Fun4AllReturnCodes::EVENT_OK; } -int StreamingBcoLumiReco::EndRun(int /*runnumber*/) +int StreamingLumiReco::EndRun(int /*runnumber*/) { uint64_t rawgl1scalers_per_bunch = m_rawgl1scaler/120.; for (int i=0; iset_bunchnumber_lumi_raw(get_bunchnumber_lumi_raw()); + m_streaming_lumi_info->set_bunchnumber_lumi_live(get_bunchnumber_lumi_live()); + m_streaming_lumi_info->set_bunchnumber_lumi_scaled(get_bunchnumber_lumi_scaled()); + m_streaming_lumi_info->set_lumi_raw(get_lumi_raw()); m_streaming_lumi_info->set_lumi_live(get_lumi_live()); m_streaming_lumi_info->set_lumi_scaled(get_lumi_scaled()); + if (Verbosity() > 1) { - std::cout << "MBD xsec : " << m_xsec_MBDNS << std::endl; + std::cout << "MBD xsec : " << sphenix_constants::m_xsec_MBDNS << std::endl; std::cout << "total lumi (raw) : " << m_lumi_raw << std::endl; } diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.h b/offline/packages/bcolumicount/StreamingLumiReco.h similarity index 65% rename from offline/packages/bcolumicount/StreamingBcoLumiReco.h rename to offline/packages/bcolumicount/StreamingLumiReco.h index 77e4e27f0e..65c763d545 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.h +++ b/offline/packages/bcolumicount/StreamingLumiReco.h @@ -1,5 +1,5 @@ -#ifndef BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H -#define BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H +#ifndef BCOLUMICOUNT_STREAMINGLUMIRECO_H +#define BCOLUMICOUNT_STREAMINGLUMIRECO_H #include "StreamingLumiInfo.h" @@ -12,24 +12,20 @@ class TH1; -class StreamingBcoLumiReco : public SubsysReco +class StreamingLumiReco : public SubsysReco { public: - StreamingBcoLumiReco(const std::string &name = "STREAMINGBCOLUMIRECO"); - ~StreamingBcoLumiReco() override = default; + StreamingLumiReco(const std::string &name = "STREAMINGBCOLUMIRECO"); + ~StreamingLumiReco() override = default; int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; int EndRun(const int runnumber) override; - virtual uint64_t get_bco() const { return m_bco; } - - virtual int get_evtno() const { return m_evtno; } - - virtual bool get_usable_bco_tag() const { return m_usable_bco_tag; } - - virtual std::pair get_bco_streaming_window() const { return m_bco_streaming_window; } + virtual const std::array get_bunchnumber_lumi_raw() const { return m_bunchnumber_lumi_raw; } + virtual const std::array get_bunchnumber_lumi_live() const { return m_bunchnumber_lumi_live; } + virtual const std::array get_bunchnumber_lumi_scaled() const { return m_bunchnumber_lumi_scaled; } virtual double get_lumi_raw() const { return m_lumi_raw; } virtual double get_lumi_live() const { return m_lumi_live; } @@ -39,24 +35,17 @@ class StreamingBcoLumiReco : public SubsysReco virtual void set_default_negative_window_length(int val) { m_default_negative_window_length = val; } - private: static int CreateNodeTree(PHCompositeNode *topNode); - const int trigbits = 40; - Fun4AllHistoManager *hm = nullptr; - TH1 *h_bco_diff = nullptr; - TH1 *h_bco_diff_trigbits[40] = {nullptr}; - TH1 *h_bco_tag = nullptr; - uint64_t m_bco{0}; int m_bunches = 120; - int m_evtno{0}; + uint64_t m_bco{0}; bool m_usable_bco_tag = false; std::pair m_bco_streaming_window; unsigned int m_default_positive_window_length{340}; unsigned int m_default_negative_window_length{20}; - double m_xsec_MBDNS = 24.07*1e9; //convert to pb from Vernier scan DOUBLE CHECK VALUE! + //double m_xsec_MBDNS = 24.07*1e9; //convert to pb from Vernier scan DOUBLE CHECK VALUE! uint64_t m_rawgl1scaler{0}; @@ -78,4 +67,4 @@ class StreamingBcoLumiReco : public SubsysReco }; -#endif // BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H +#endif // BCOLUMICOUNT_STREAMINGLUMIRECO_H From 1ecfb4b1bbcfc1dafa05a83eea82500a57dc2a45 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Wed, 24 Jun 2026 21:01:31 -0400 Subject: [PATCH 730/866] Read output of StreamingBcoReco into StreamingLumiReco rather than output of BcoLumiReco. Update lumi calculation code accordingly. --- .../bcolumicount/StreamingLumiReco.cc | 68 +++---------------- .../packages/bcolumicount/StreamingLumiReco.h | 3 - 2 files changed, 9 insertions(+), 62 deletions(-) diff --git a/offline/packages/bcolumicount/StreamingLumiReco.cc b/offline/packages/bcolumicount/StreamingLumiReco.cc index 57068b838c..d78aa69c0e 100644 --- a/offline/packages/bcolumicount/StreamingLumiReco.cc +++ b/offline/packages/bcolumicount/StreamingLumiReco.cc @@ -1,6 +1,6 @@ #include "StreamingLumiReco.h" -#include "BcoInfo.h" +#include "StreamingBcoInfo.h" #include "StreamingLumiInfo.h" #include "StreamingLumiInfov1.h" @@ -79,9 +79,7 @@ int StreamingLumiReco::CreateNodeTree(PHCompositeNode *topNode) int StreamingLumiReco::process_event(PHCompositeNode *topNode) { - BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); - SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); - //Gl1Packet *gl1packet = findNode::getClass(topNode, 14001); + StreamingBcoInfo *streaming_bcoinfo = findNode::getClass(topNode, "STREAMINGBCOINFO"); Event *evt = findNode::getClass(topNode, "PRDF"); if (evt) { @@ -129,69 +127,21 @@ int StreamingLumiReco::process_event(PHCompositeNode *topNode) delete packet; - if (Verbosity() > 2) - { - if (!syncobject) - { - std::cout << PHWHERE << " SyncObject missing" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - std::cout << "Event No: " << syncobject->EventNumber() /*<< std::hex*/ - << " gl1 bco: " << gtm_bco < 2) - { - std::cout << "prev event: " << bcoinfo->get_previous_evtno() /*<< std::hex*/ - << " bco: " << bcoinfo->get_previous_bco() << std::dec << std::endl; - std::cout << "curr event: " << bcoinfo->get_current_evtno() /*<< std::hex*/ - << " bco: " << bcoinfo->get_current_bco() << std::dec << std::endl; - std::cout << "futu event: " << bcoinfo->get_future_evtno() /*<< std::hex*/ - << " bco: " << bcoinfo->get_future_bco() << std::dec << std::endl; - } - - m_bco = bcoinfo->get_current_bco(); - if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} - uint64_t bco_prev = bcoinfo->get_previous_bco(); - uint64_t bco_futu = bcoinfo->get_future_bco(); - uint64_t bco_diff_prev = m_bco - bco_prev; - uint64_t bco_diff_futu = bco_futu - m_bco; - - // special case if BCO is within 20 of previous BCO? - if (bco_diff_prev < m_default_positive_window_length) - { - m_usable_bco_tag = true; - } - else - { - m_usable_bco_tag = false; - } - if (bco_diff_futu < m_default_positive_window_length) - { - // double check boundaries for overlap!! - m_bco_streaming_window = std::make_pair(m_bco - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); - } - else - { - m_bco_streaming_window = std::make_pair(m_bco - m_default_negative_window_length, m_bco + m_default_positive_window_length); - } - if (Verbosity() > 2) - { - std::cout << "bco_diff_futu : " << bco_diff_futu << std::endl; - } + if (gtm_bco != streaming_bcoinfo->get_bco()) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " bco " << streaming_bcoinfo->get_bco() << std::endl;} // Double check Zhiwan's logic for assigning the adjusted bunch! - int lower = m_bco_streaming_window.first - m_bco; - int upper = m_bco_streaming_window.second - m_bco; + int lower = streaming_bcoinfo->get_bco_streaming_window().first - streaming_bcoinfo->get_bco(); + int upper = streaming_bcoinfo->get_bco_streaming_window().second - streaming_bcoinfo->get_bco(); for(int i = lower; i< upper;i++) { int adjusted_bunch = bunchno + i; - while (adjusted_bunch < 0) + while (adjusted_bunch < 0) { adjusted_bunch += 120; } - while (adjusted_bunch > 119) + while (adjusted_bunch > 119) { adjusted_bunch -= 120; } @@ -199,7 +149,7 @@ int StreamingLumiReco::process_event(PHCompositeNode *topNode) if (adjusted_bunch>110) { continue; } // Make sure this is the correct way to count crossings! Need to zero out for each run! - if(i!=0 || m_usable_bco_tag) + if(i!=0 || streaming_bcoinfo->get_usable_bco_tag()) { m_bunchnumber_crossings[adjusted_bunch] += 1; } diff --git a/offline/packages/bcolumicount/StreamingLumiReco.h b/offline/packages/bcolumicount/StreamingLumiReco.h index 65c763d545..7f74a30367 100644 --- a/offline/packages/bcolumicount/StreamingLumiReco.h +++ b/offline/packages/bcolumicount/StreamingLumiReco.h @@ -39,9 +39,6 @@ class StreamingLumiReco : public SubsysReco static int CreateNodeTree(PHCompositeNode *topNode); int m_bunches = 120; - uint64_t m_bco{0}; - bool m_usable_bco_tag = false; - std::pair m_bco_streaming_window; unsigned int m_default_positive_window_length{340}; unsigned int m_default_negative_window_length{20}; From 54554dd330d895d8bdc90a67f8973495a3fcb857 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 16 Jun 2026 14:41:49 -0400 Subject: [PATCH 731/866] min pt cut set to 0.2 by default. --- offline/packages/trackreco/PHMicromegasTpcTrackMatching.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h index 7f9f8e2611..23bd75854f 100644 --- a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h +++ b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h @@ -48,7 +48,7 @@ class PHMicromegasTpcTrackMatching : public SubsysReco int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode*) override; int End(PHCompositeNode*) override; - + // deprecated calls inline void set_sc_calib_mode(const bool) {} inline void set_collision_rate(const double) {} @@ -77,7 +77,7 @@ class PHMicromegasTpcTrackMatching : public SubsysReco unsigned int _max_tpc_layer = 55; // pt cut for field-on data - float _pt_cut = 0.5; + float _pt_cut = 0.2; // delta_phi window between the last cluster in the tracklet and the projection float _dphi_cut = 0.9; @@ -90,7 +90,7 @@ class PHMicromegasTpcTrackMatching : public SubsysReco TrackSeedContainer* _si_track_map{nullptr}; std::string _clustermap_name = "TRKR_CLUSTER"; - + //! default rphi search window for each layer std::array _rphi_search_win{0.25, 13.0}; From a547e64a66ab6be95ec77700a3f71ddd678f0d64 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Mon, 22 Jun 2026 14:23:43 -0400 Subject: [PATCH 732/866] added negative and positive charge-separated matrix containers. --- offline/packages/tpccalib/PHTpcResiduals.cc | 81 +++++++++++++-------- offline/packages/tpccalib/PHTpcResiduals.h | 6 ++ 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 788e4ae06d..e3264d92ac 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -128,6 +128,8 @@ namespace PHTpcResiduals::PHTpcResiduals(const std::string& name) : SubsysReco(name) , m_matrix_container(new TpcSpaceChargeMatrixContainerv2) + , m_matrix_container_pos(new TpcSpaceChargeMatrixContainerv2) + , m_matrix_container_neg(new TpcSpaceChargeMatrixContainerv2) { } @@ -186,11 +188,13 @@ int PHTpcResiduals::End(PHCompositeNode* /*topNode*/) std::cout << "PHTpcResiduals::End - writing matrices to " << m_outputfile << std::endl; // save matrix container in output file - if (m_matrix_container) + if (m_matrix_container || m_matrix_container_pos || m_matrix_container_neg) { std::unique_ptr outputfile(TFile::Open(m_outputfile.c_str(), "RECREATE")); outputfile->cd(); - m_matrix_container->Write("TpcSpaceChargeMatrixContainer"); + if( m_matrix_container ) { m_matrix_container->Write("TpcSpaceChargeMatrixContainer"); } + if( m_matrix_container_pos ) { m_matrix_container_pos->Write("TpcSpaceChargeMatrixContainer_pos"); } + if( m_matrix_container_neg ) { m_matrix_container_neg->Write("TpcSpaceChargeMatrixContainer_neg"); } } // print counters @@ -650,43 +654,58 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) continue; } - // Fill distortion matrices - m_matrix_container->add_to_lhs(index, 0, 0, square(clusR) / erp); - m_matrix_container->add_to_lhs(index, 0, 1, 0); - m_matrix_container->add_to_lhs(index, 0, 2, clusR * trackAlpha / erp); + std::vector containers; + containers.emplace_back( m_matrix_container.get() ); + if( track->get_positive_charge() ) { + containers.emplace_back( m_matrix_container_pos.get() ); + } else { + containers.emplace_back( m_matrix_container_neg.get() ); + } + + + for( auto& container:containers ) + { - m_matrix_container->add_to_lhs(index, 1, 0, 0); - m_matrix_container->add_to_lhs(index, 1, 1, 1. / ez); - m_matrix_container->add_to_lhs(index, 1, 2, trackBeta / ez); + if( !container ) continue; - m_matrix_container->add_to_lhs(index, 2, 0, clusR * trackAlpha / erp); - m_matrix_container->add_to_lhs(index, 2, 1, trackBeta / ez); - m_matrix_container->add_to_lhs(index, 2, 2, square(trackAlpha) / erp + square(trackBeta) / ez); + // Fill distortion matrices + container->add_to_lhs(index, 0, 0, square(clusR) / erp); + container->add_to_lhs(index, 0, 1, 0); + container->add_to_lhs(index, 0, 2, clusR * trackAlpha / erp); - m_matrix_container->add_to_rhs(index, 0, clusR * drphi / erp); - m_matrix_container->add_to_rhs(index, 1, dz / ez); - m_matrix_container->add_to_rhs(index, 2, trackAlpha * drphi / erp + trackBeta * dz / ez); + container->add_to_lhs(index, 1, 0, 0); + container->add_to_lhs(index, 1, 1, 1. / ez); + container->add_to_lhs(index, 1, 2, trackBeta / ez); - // also update rphi reduced matrices - m_matrix_container->add_to_lhs_rphi(index, 0, 0, square(clusR) / erp); - m_matrix_container->add_to_lhs_rphi(index, 0, 1, clusR * trackAlpha / erp); - m_matrix_container->add_to_lhs_rphi(index, 1, 0, clusR * trackAlpha / erp); - m_matrix_container->add_to_lhs_rphi(index, 1, 1, square(trackAlpha) / erp); + container->add_to_lhs(index, 2, 0, clusR * trackAlpha / erp); + container->add_to_lhs(index, 2, 1, trackBeta / ez); + container->add_to_lhs(index, 2, 2, square(trackAlpha) / erp + square(trackBeta) / ez); - m_matrix_container->add_to_rhs_rphi(index, 0, clusR * drphi / erp); - m_matrix_container->add_to_rhs_rphi(index, 1, trackAlpha * drphi / erp); + container->add_to_rhs(index, 0, clusR * drphi / erp); + container->add_to_rhs(index, 1, dz / ez); + container->add_to_rhs(index, 2, trackAlpha * drphi / erp + trackBeta * dz / ez); - // also update z reduced matrices - m_matrix_container->add_to_lhs_z(index, 0, 0, 1. / ez); - m_matrix_container->add_to_lhs_z(index, 0, 1, trackBeta / ez); - m_matrix_container->add_to_lhs_z(index, 1, 0, trackBeta / ez); - m_matrix_container->add_to_lhs_z(index, 1, 1, square(trackBeta) / ez); + // also update rphi reduced matrices + container->add_to_lhs_rphi(index, 0, 0, square(clusR) / erp); + container->add_to_lhs_rphi(index, 0, 1, clusR * trackAlpha / erp); + container->add_to_lhs_rphi(index, 1, 0, clusR * trackAlpha / erp); + container->add_to_lhs_rphi(index, 1, 1, square(trackAlpha) / erp); - m_matrix_container->add_to_rhs_z(index, 0, dz / ez); - m_matrix_container->add_to_rhs_z(index, 1, trackBeta * dz / ez); + container->add_to_rhs_rphi(index, 0, clusR * drphi / erp); + container->add_to_rhs_rphi(index, 1, trackAlpha * drphi / erp); - // update entries in cell - m_matrix_container->add_to_entries(index); + // also update z reduced matrices + container->add_to_lhs_z(index, 0, 0, 1. / ez); + container->add_to_lhs_z(index, 0, 1, trackBeta / ez); + container->add_to_lhs_z(index, 1, 0, trackBeta / ez); + container->add_to_lhs_z(index, 1, 1, square(trackBeta) / ez); + + container->add_to_rhs_z(index, 0, dz / ez); + container->add_to_rhs_z(index, 1, trackBeta * dz / ez); + + // update entries in cell + container->add_to_entries(index); + } // increment number of accepted clusters ++m_accepted_clusters; diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index 1e750aad3a..9d4aaa1514 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -193,6 +193,12 @@ class PHTpcResiduals : public SubsysReco /// matrix container std::unique_ptr m_matrix_container; + /// matrix container positive charges only + std::unique_ptr m_matrix_container_pos; + + /// matrix container negative charges only + std::unique_ptr m_matrix_container_neg; + // TODO: check if needed int m_event = 0; From 913c0b2f3c6be42227610620098a4e689bbcb75c Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 23 Jun 2026 12:55:34 -0400 Subject: [PATCH 733/866] added accessor to all entries in container. --- offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h | 4 ++++ .../packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc | 6 ++++++ offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h | 3 +++ 3 files changed, 13 insertions(+) diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h index 701bc147d0..767e0f5135 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h @@ -45,6 +45,10 @@ class TpcSpaceChargeMatrixContainer : public PHObject virtual int get_cell_index( int /*iphibin*/, int /*irbin*/, int /*izbin*/ ) const { return -1; } + /// get all entries + virtual int get_entries() const + { return 0; } + /// get entries for a given cell virtual int get_entries( int /*cell_index*/ ) const { return 0; } diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc index 3fa25bbbf3..216b8d9fff 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc @@ -8,6 +8,8 @@ #include "TpcSpaceChargeMatrixContainerv2.h" +#include + //___________________________________________________________ TpcSpaceChargeMatrixContainerv2::TpcSpaceChargeMatrixContainerv2() { @@ -56,6 +58,10 @@ int TpcSpaceChargeMatrixContainerv2::get_cell_index(int iphi, int ir, int iz) co return iz + m_zbins * (ir + m_rbins * iphi); } +//___________________________________________________________ +int TpcSpaceChargeMatrixContainerv2::get_entries() const +{ return std::accumulate( m_entries.begin(), m_entries.end(), (int)0); } + //___________________________________________________________ int TpcSpaceChargeMatrixContainerv2::get_entries(int cell_index) const { diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h index 8005e4f1f3..5942a8c126 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h @@ -39,6 +39,9 @@ class TpcSpaceChargeMatrixContainerv2 : public TpcSpaceChargeMatrixContainer /// get grid index for given sub-indexes int get_cell_index(int iphibin, int irbin, int izbin) const override; + /// get all entries + int get_entries() const override; + /// get entries for a given cell int get_entries(int cell_index) const override; From 54e9407e88519eb31aa5b1e1bd2d3ddee356f6b1 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 23 Jun 2026 12:55:46 -0400 Subject: [PATCH 734/866] Added charge-dependent matrix containers. --- offline/packages/tpccalib/PHTpcResiduals.cc | 22 +++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index e3264d92ac..19459422f4 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -192,9 +192,21 @@ int PHTpcResiduals::End(PHCompositeNode* /*topNode*/) { std::unique_ptr outputfile(TFile::Open(m_outputfile.c_str(), "RECREATE")); outputfile->cd(); - if( m_matrix_container ) { m_matrix_container->Write("TpcSpaceChargeMatrixContainer"); } - if( m_matrix_container_pos ) { m_matrix_container_pos->Write("TpcSpaceChargeMatrixContainer_pos"); } - if( m_matrix_container_neg ) { m_matrix_container_neg->Write("TpcSpaceChargeMatrixContainer_neg"); } + + if( m_matrix_container ) { + std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_all object. entries: " << m_matrix_container->get_entries() << std::endl; + m_matrix_container->Write("TpcSpaceChargeMatrixContainer_all"); + } + + if( m_matrix_container_pos ) { + std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_pos object. entries: " << m_matrix_container_pos->get_entries() << std::endl; + m_matrix_container->Write("TpcSpaceChargeMatrixContainer_pos"); + } + + if( m_matrix_container_neg ) { + std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_neg object. entries: " << m_matrix_container_neg->get_entries() << std::endl; + m_matrix_container->Write("TpcSpaceChargeMatrixContainer_neg"); + } } // print counters @@ -795,5 +807,7 @@ int PHTpcResiduals::getNodes(PHCompositeNode* topNode) //____________________________________________________________________________ void PHTpcResiduals::setGridDimensions(const int phiBins, const int rBins, const int zBins) { - m_matrix_container->set_grid_dimensions(phiBins, rBins, zBins); + if( m_matrix_container ) { m_matrix_container->set_grid_dimensions(phiBins, rBins, zBins); } + if( m_matrix_container_pos ) { m_matrix_container_pos->set_grid_dimensions(phiBins, rBins, zBins); } + if( m_matrix_container_neg ) { m_matrix_container_neg->set_grid_dimensions(phiBins, rBins, zBins); } } From efe5881f8b9be04f4cc86fac2e18ea5b5ee8f96a Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 23 Jun 2026 16:23:04 -0400 Subject: [PATCH 735/866] added some debug output --- .../packages/tpccalib/TpcSpaceChargeMatrixInversion.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc index 9c787730aa..1797e949b5 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc @@ -163,6 +163,12 @@ bool TpcSpaceChargeMatrixInversion::add_from_file(const std::string& shortfilena { std::cout << "TpcSpaceChargeMatrixInversion::add_from_file - could not find object name " << objectname << " in file " << filename << std::endl; return false; + } else if( Verbosity() ) { + std::cout << "TpcSpaceChargeMatrixInversion::add_from_file -" + << " file: " << filename + << " objectname: " << objectname + << " entries: " << source->get_entries() + << std::endl; } // add object @@ -200,6 +206,8 @@ void TpcSpaceChargeMatrixInversion::calculate_distortion_corrections(const Inver exit(1); } + std::cout << "TpcSpaceChargeMatrixInversion::calculate_distortion_corrections - entries: " << m_matrix_container->get_entries() << std::endl; + // get grid dimensions from matrix container int phibins = 0; int rbins = 0; From c7d6d62b526520dd50086655c38a193641227457 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 23 Jun 2026 16:23:49 -0400 Subject: [PATCH 736/866] fixed writing charge dependent matrices to output. --- offline/packages/tpccalib/PHTpcResiduals.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 19459422f4..524378ed09 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -200,12 +200,12 @@ int PHTpcResiduals::End(PHCompositeNode* /*topNode*/) if( m_matrix_container_pos ) { std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_pos object. entries: " << m_matrix_container_pos->get_entries() << std::endl; - m_matrix_container->Write("TpcSpaceChargeMatrixContainer_pos"); + m_matrix_container_pos->Write("TpcSpaceChargeMatrixContainer_pos"); } if( m_matrix_container_neg ) { std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_neg object. entries: " << m_matrix_container_neg->get_entries() << std::endl; - m_matrix_container->Write("TpcSpaceChargeMatrixContainer_neg"); + m_matrix_container_neg->Write("TpcSpaceChargeMatrixContainer_neg"); } } From 008bfe7fcd30260f82a6c5c91d365186ac4ca46e Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 23 Jun 2026 16:24:15 -0400 Subject: [PATCH 737/866] restored original name --- offline/packages/tpccalib/PHTpcResiduals.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 524378ed09..3a5b33d389 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -194,8 +194,8 @@ int PHTpcResiduals::End(PHCompositeNode* /*topNode*/) outputfile->cd(); if( m_matrix_container ) { - std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_all object. entries: " << m_matrix_container->get_entries() << std::endl; - m_matrix_container->Write("TpcSpaceChargeMatrixContainer_all"); + std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer object. entries: " << m_matrix_container->get_entries() << std::endl; + m_matrix_container->Write("TpcSpaceChargeMatrixContainer"); } if( m_matrix_container_pos ) { From 4d747f2e15e21f59a40bfe960c5ba05ae9b14265 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 24 Jun 2026 22:57:24 -0400 Subject: [PATCH 738/866] add option to ignore edge clusters, as per Christof's suggestion. --- offline/packages/tpccalib/PHTpcResiduals.cc | 15 +++++++++++++-- offline/packages/tpccalib/PHTpcResiduals.h | 12 ++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 3a5b33d389..e8e147153e 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -141,6 +141,7 @@ int PHTpcResiduals::Init(PHCompositeNode* /*topNode*/) std::cout << "PHTpcResiduals::Init - m_maxTBeta: " << m_maxTBeta << std::endl; std::cout << "PHTpcResiduals::Init - m_maxResidualDrphi: " << m_maxResidualDrphi << " cm" << std::endl; std::cout << "PHTpcResiduals::Init - m_maxResidualDz: " << m_maxResidualDz << " cm" << std::endl; + std::cout << "PHTpcResiduals::Init - m_ignoreEdgeClusters: " << m_ignoreEdgeClusters << std::endl; std::cout << "PHTpcResiduals::Init - m_minRPhiErr: " << m_minRPhiErr << " cm" << std::endl; std::cout << "PHTpcResiduals::Init - m_minZErr: " << m_minZErr << " cm" << std::endl; std::cout << "PHTpcResiduals::Init - m_minPt: " << m_minPt << " GeV/c" << std::endl; @@ -472,8 +473,6 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) for (const auto& cluskey : get_cluster_keys(track)) { - // increment counter - ++m_total_clusters; // make sure cluster is from TPC const auto detId = TrkrDefs::getTrkrId(cluskey); @@ -482,6 +481,10 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) continue; } + // increment counter + /* only counts TPC clusters */ + ++m_total_clusters; + // find matching track state const auto stateiter = std::find_if( track->begin_states(), track->end_states(), [&cluskey]( const auto& state_pair ) { return state_pair.second->get_cluskey() == cluskey; } ); @@ -494,6 +497,14 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) // calculate residuals with respect to cluster auto* const cluster = m_clusterContainer->findCluster(cluskey); + + // check cluster + if( !cluster ) { continue; } + + // check if cluster is an edge + if( m_ignoreEdgeClusters && cluster->getEdge() > 0 && cluster->getEdge() < std::numeric_limits::max() ) + { continue; } + const auto globClusPos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(cluskey, cluster, crossing); const double clusR = get_r(globClusPos(0), globClusPos(1)); const double clusPhi = std::atan2(globClusPos(1), globClusPos(0)); diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index 9d4aaa1514..3db64d5f4c 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -63,11 +63,20 @@ class PHTpcResiduals : public SubsysReco } //@} + /// true to remove "edge" clusters + /** these are clusters that touch the edge of a detector and are considered pathological */ + void setIgnoreEdgeClusters( bool value ) + { m_ignoreEdgeClusters = value; } + + /// minimum value for RPhi error. + /** a too small rphi error is usually a sign of pathological TPC cluster */ void setMinRPhiErr(float minRPhiErr) { m_minRPhiErr = minRPhiErr; } + /// minimum value for z error. + /** a too small z error is usually a sign of pathological TPC cluster */ void setMinZErr(float minZErr) { m_minZErr = minZErr; @@ -171,6 +180,9 @@ class PHTpcResiduals : public SubsysReco float m_maxTBeta = 1.5; float m_maxResidualDz = 0.5; // cm + /// ignore edge clusters + bool m_ignoreEdgeClusters = false; + float m_minRPhiErr = 0.005; // 0.005cm -- 50um float m_minZErr = 0.01; // 0.01cm -- 100um From d42c6871e40ab23b5bb2edfcba88948def95f325 Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Thu, 25 Jun 2026 14:14:20 +0800 Subject: [PATCH 739/866] address clang-tidy warnings in truth fitter --- offline/packages/trackreco/PHTruthTrackFitter.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHTruthTrackFitter.cc b/offline/packages/trackreco/PHTruthTrackFitter.cc index 0e300be389..f3ed94c29f 100644 --- a/offline/packages/trackreco/PHTruthTrackFitter.cc +++ b/offline/packages/trackreco/PHTruthTrackFitter.cc @@ -41,7 +41,7 @@ namespace { template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } @@ -108,7 +108,7 @@ int PHTruthTrackFitter::process_event(PHCompositeNode* /*topNode*/) m_trackMap->Reset(); unsigned int skipped_tracks = 0; - for (auto seed : *m_seedMap) + for (auto *seed : *m_seedMap) { if (!seed) { From 58c5b3716cf5621750eb726b7f0d18565ffba732 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Fri, 12 Jun 2026 10:27:19 -0400 Subject: [PATCH 740/866] Trying again! --- .../TrackingDiagnostics/TrackResiduals.cc | 173 ++++++++++ .../TrackingDiagnostics/TrackResiduals.h | 53 ++- .../TrackingDiagnostics/TrkrNtuplizer.cc | 60 +++- offline/packages/tpc/TpcClusterizer.cc | 305 +++++++++++++++--- 4 files changed, 536 insertions(+), 55 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 1a5a69fae0..d123176d70 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -46,6 +46,8 @@ #include #include +#include + #include #include #include @@ -57,6 +59,7 @@ #include #include #include +#include #include @@ -126,6 +129,7 @@ int TrackResiduals::InitRun(PHCompositeNode* topNode) void TrackResiduals::clearClusterStateVectors() { m_cluskeys.clear(); + m_clussize.clear(); m_clusphisize.clear(); m_cluszsize.clear(); m_idealsurfcenterx.clear(); @@ -183,7 +187,23 @@ void TrackResiduals::clearClusterStateVectors() m_statelzlocderivqop.clear(); m_clusedge.clear(); + m_clussledge.clear(); + m_clussredge.clear(); + m_clustledge.clear(); + m_clustredge.clear(); + m_clusdledge.clear(); + m_clusdredge.clear(); + m_clushledge.clear(); + m_clushredge.clear(); + m_clusslmix.clear(); + m_clussrmix.clear(); + m_clustlmix.clear(); + m_clustrmix.clear(); m_clusoverlap.clear(); + m_clusPadCen.clear(); + m_clusTBinCen.clear(); + m_clusPadMax.clear(); + m_clusTBinMax.clear(); m_cluslx.clear(); m_cluslz.clear(); m_cluselx.clear(); @@ -197,7 +217,14 @@ void TrackResiduals::clearClusterStateVectors() m_clusgzunmoved.clear(); m_clusAdc.clear(); m_clusMaxAdc.clear(); + m_clusCenAdc.clear(); m_cluslayer.clear(); + m_clusphibinlo.clear(); + m_clusphibinhi.clear(); + m_clustbinlo.clear(); + m_clustbinhi.clear(); + m_cluspadphase.clear(); + m_clustbinphase.clear(); m_statelx.clear(); m_statelz.clear(); @@ -301,6 +328,21 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) } } + EventHeader* eventheader = findNode::getClass(topNode, "EventHeader"); + + if(eventheader) + { + m_evt_id = eventheader->get_EvtSequence(); + } + else + { + m_evt_id = -1; + } + + auto *rcs = recoConsts::instance(); + m_runnumber = rcs->get_IntFlag("RUNNUMBER"); + m_segment = rcs->get_IntFlag("RUNSEGMENT"); + m_ntpcclus = 0; if (Verbosity() > 1) { @@ -662,11 +704,37 @@ void TrackResiduals::fillClusterTree(TrkrClusterContainer* clusters, m_scluseta = acos(glob.z() / std::sqrt(square(glob.x()) + square(glob.y()) + square(glob.z()))); m_adc = cluster->getAdc(); m_clusmaxadc = cluster->getMaxAdc(); + m_cluscenadc = cluster->getCenAdc(); + m_padcen = cluster->getPadCen(); + m_tbincen = cluster->getTBinCen(); + m_padmax = cluster->getPadMax(); + m_tbinmax = cluster->getTBinMax(); m_scluslx = cluster->getLocalX(); m_scluslz = cluster->getLocalY(); + m_phibinlo = cluster->getPhiBinLo(); + m_phibinhi = cluster->getPhiBinHi(); + m_tbinlo = cluster->getTBinLo(); + m_tbinhi = cluster->getTBinHi(); + m_padphase = cluster->getPadPhase(); + m_tbinphase = cluster->getTBinPhase(); auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, m_sclusgr, key); + m_size = cluster->getRSize(); m_phisize = cluster->getPhiSize(); m_zsize = cluster->getZSize(); + m_overlap = cluster->getOverlap(); + m_nedge = cluster->getEdge(); + m_sledge = cluster->getSLEdge(); + m_sredge = cluster->getSREdge(); + m_tledge = cluster->getTLEdge(); + m_tredge = cluster->getTREdge(); + m_dledge = cluster->getDLEdge(); + m_dredge = cluster->getDREdge(); + m_hledge = cluster->getHLEdge(); + m_hredge = cluster->getHREdge(); + m_slmix = cluster->getSLMix(); + m_srmix = cluster->getSRMix(); + m_tlmix = cluster->getTLMix(); + m_trmix = cluster->getTRMix(); m_scluselx = std::sqrt(para_errors.first); m_scluselz = std::sqrt(para_errors.second); @@ -1087,7 +1155,19 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); + m_clussledge.push_back(cluster->getSLEdge()); + m_clussredge.push_back(cluster->getSREdge()); + m_clustledge.push_back(cluster->getTLEdge()); + m_clustredge.push_back(cluster->getTREdge()); + m_clusdledge.push_back(cluster->getDLEdge()); + m_clusdredge.push_back(cluster->getDREdge()); + m_clushledge.push_back(cluster->getHLEdge()); + m_clushredge.push_back(cluster->getHREdge()); m_clusoverlap.push_back(cluster->getOverlap()); + m_clusslmix.push_back(cluster->getSLMix()); + m_clussrmix.push_back(cluster->getSRMix()); + m_clustlmix.push_back(cluster->getTLMix()); + m_clustrmix.push_back(cluster->getTRMix()); // get new local coords from moved cluster Surface surf = geometry->maps().getSurface(ckey, cluster); @@ -1160,9 +1240,21 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); + m_clusCenAdc.push_back(cluster->getCenAdc()); + m_clusPadCen.push_back(cluster->getPadCen()); + m_clusTBinCen.push_back(cluster->getTBinCen()); + m_clusPadMax.push_back(cluster->getPadMax()); + m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); + m_clusphibinlo.push_back(cluster->getPhiBinLo()); + m_clusphibinhi.push_back(cluster->getPhiBinHi()); + m_clustbinlo.push_back(cluster->getTBinLo()); + m_clustbinhi.push_back(cluster->getTBinHi()); + m_cluspadphase.push_back(cluster->getPadPhase()); + m_clustbinphase.push_back(cluster->getTBinPhase()); auto misaligncenter = surf->center(geometry->geometry().getGeoContext()); auto misalignnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); @@ -1416,6 +1508,18 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); + m_clussledge.push_back(cluster->getSLEdge()); + m_clussredge.push_back(cluster->getSREdge()); + m_clustledge.push_back(cluster->getTLEdge()); + m_clustredge.push_back(cluster->getTREdge()); + m_clusdledge.push_back(cluster->getDLEdge()); + m_clusdredge.push_back(cluster->getDREdge()); + m_clushledge.push_back(cluster->getHLEdge()); + m_clushredge.push_back(cluster->getHREdge()); + m_clusslmix.push_back(cluster->getSLMix()); + m_clussrmix.push_back(cluster->getSRMix()); + m_clustlmix.push_back(cluster->getTLMix()); + m_clustrmix.push_back(cluster->getTRMix()); m_clusoverlap.push_back(cluster->getOverlap()); // This is the nominal position of the cluster in local coords, completely uncorrected - is that what we want? @@ -1438,9 +1542,21 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); + m_clusCenAdc.push_back(cluster->getCenAdc()); + m_clusPadCen.push_back(cluster->getPadCen()); + m_clusTBinCen.push_back(cluster->getTBinCen()); + m_clusPadMax.push_back(cluster->getPadMax()); + m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); + m_clusphibinlo.push_back(cluster->getPhiBinLo()); + m_clusphibinhi.push_back(cluster->getPhiBinHi()); + m_clustbinlo.push_back(cluster->getTBinLo()); + m_clustbinhi.push_back(cluster->getTBinHi()); + m_cluspadphase.push_back(cluster->getPadPhase()); + m_clustbinphase.push_back(cluster->getTBinPhase()); if (Verbosity() > 1) { @@ -1607,6 +1723,7 @@ void TrackResiduals::createBranches() m_eventtree->Branch("run", &m_runnumber, "m_runnumber/I"); m_eventtree->Branch("segment", &m_segment, "m_segment/I"); m_eventtree->Branch("event", &m_event, "m_event/I"); + m_eventtree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_eventtree->Branch("gl1bco", &m_bco, "m_bco/I"); m_eventtree->Branch("nmvtx", &m_nmvtx_all, "m_nmvtx_all/I"); m_eventtree->Branch("nintt", &m_nintt_all, "m_nintt_all/I"); @@ -1627,6 +1744,7 @@ void TrackResiduals::createBranches() m_failedfits->Branch("segment", &m_segment, "m_segment/I"); m_failedfits->Branch("trackid", &m_trackid, "m_trackid/I"); m_failedfits->Branch("event", &m_event, "m_event/I"); + m_failedfits->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_failedfits->Branch("silseedx", &m_silseedx, "m_silseedx/F"); m_failedfits->Branch("silseedy", &m_silseedy, "m_silseedy/F"); m_failedfits->Branch("silseedz", &m_silseedz, "m_silseedz/F"); @@ -1653,6 +1771,7 @@ void TrackResiduals::createBranches() m_vertextree->Branch("run", &m_runnumber, "m_runnumber/I"); m_vertextree->Branch("segment", &m_segment, "m_segment/I"); m_vertextree->Branch("event", &m_event, "m_event/I"); + m_vertextree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_vertextree->Branch("firedTriggers", &m_firedTriggers); m_vertextree->Branch("gl1BunchCrossing", &m_gl1BunchCrossing, "m_gl1BunchCrossing/l"); m_vertextree->Branch("gl1bco", &m_bco, "m_bco/l"); @@ -1675,6 +1794,7 @@ void TrackResiduals::createBranches() m_hittree->Branch("run", &m_runnumber, "m_runnumber/I"); m_hittree->Branch("segment", &m_segment, "m_segment/I"); m_hittree->Branch("event", &m_event, "m_event/I"); + m_hittree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_hittree->Branch("gl1bco", &m_bco, "m_bco/l"); m_hittree->Branch("hitsetkey", &m_hitsetkey, "m_hitsetkey/i"); m_hittree->Branch("gx", &m_hitgx, "m_hitgx/F"); @@ -1704,6 +1824,7 @@ void TrackResiduals::createBranches() m_clustree->Branch("run", &m_runnumber, "m_runnumber/I"); m_clustree->Branch("segment", &m_segment, "m_segment/I"); m_clustree->Branch("event", &m_event, "m_event/I"); + m_clustree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_clustree->Branch("gl1bco", &m_bco, "m_bco/l"); m_clustree->Branch("lx", &m_scluslx, "m_scluslx/F"); m_clustree->Branch("lz", &m_scluslz, "m_scluslz/F"); @@ -1713,11 +1834,37 @@ void TrackResiduals::createBranches() m_clustree->Branch("phi", &m_sclusphi, "m_sclusphi/F"); m_clustree->Branch("eta", &m_scluseta, "m_scluseta/F"); m_clustree->Branch("adc", &m_adc, "m_adc/F"); + m_clustree->Branch("size", &m_size, "m_size/I"); m_clustree->Branch("phisize", &m_phisize, "m_phisize/I"); m_clustree->Branch("zsize", &m_zsize, "m_zsize/I"); + m_clustree->Branch("phibinlo", &m_phibinlo, "m_phibinlo/F"); + m_clustree->Branch("phibinhi", &m_phibinhi, "m_phibinhi/F"); + m_clustree->Branch("tbinlo", &m_tbinlo, "m_tbinlo/F"); + m_clustree->Branch("tbinhi", &m_tbinhi, "m_tbinhi/F"); + m_clustree->Branch("padphase", &m_padphase, "m_padphase/F"); + m_clustree->Branch("tbinphase", &m_tbinphase, "m_tbinphase/F"); + m_clustree->Branch("overlap", &m_overlap, "m_overlap/I"); + m_clustree->Branch("nedge", &m_nedge, "m_nedge/I"); + m_clustree->Branch("sledge", &m_sledge, "m_sledge/I"); + m_clustree->Branch("sredge", &m_sredge, "m_sredge/I"); + m_clustree->Branch("tledge", &m_tledge, "m_tledge/I"); + m_clustree->Branch("tredge", &m_tredge, "m_tredge/I"); + m_clustree->Branch("dledge", &m_dledge, "m_dledge/I"); + m_clustree->Branch("dredge", &m_dredge, "m_dredge/I"); + m_clustree->Branch("hledge", &m_hledge, "m_hledge/I"); + m_clustree->Branch("hredge", &m_hredge, "m_hredge/I"); + m_clustree->Branch("slmix", &m_slmix, "m_slmix/I"); + m_clustree->Branch("srmix", &m_srmix, "m_srmix/I"); + m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/I"); + m_clustree->Branch("trmix", &m_trmix, "m_trmix/I"); m_clustree->Branch("erphi", &m_scluselx, "m_scluselx/F"); m_clustree->Branch("ez", &m_scluselz, "m_scluselz/F"); m_clustree->Branch("maxadc", &m_clusmaxadc, "m_clusmaxadc/F"); + m_clustree->Branch("cenadc", &m_cluscenadc, "m_cluscenadc/F"); + m_clustree->Branch("padcen", &m_padcen, "m_padcen/F"); + m_clustree->Branch("tbincen", &m_tbincen, "m_tbincen/F"); + m_clustree->Branch("padmax", &m_padmax, "m_padmax/F"); + m_clustree->Branch("tbinmax", &m_tbinmax, "m_tbinmax/F"); m_clustree->Branch("sector", &m_clussector, "m_clussector/I"); m_clustree->Branch("side", &m_side, "m_side/I"); m_clustree->Branch("stave", &m_staveid, "m_staveid/I"); @@ -1734,6 +1881,7 @@ void TrackResiduals::createBranches() m_tree->Branch("run", &m_runnumber, "m_runnumber/I"); m_tree->Branch("segment", &m_segment, "m_segment/I"); m_tree->Branch("event", &m_event, "m_event/I"); + m_tree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_tree->Branch("mbdcharge",&m_totalmbd, "m_totalmbd/F"); m_tree->Branch("mbdzvtx", &m_mbdvtxz, "m_mbdvtxz/F"); m_tree->Branch("firedTriggers", &m_firedTriggers); @@ -1815,7 +1963,27 @@ void TrackResiduals::createBranches() m_tree->Branch("clusside", &m_clside); m_tree->Branch("cluskeys", &m_cluskeys); m_tree->Branch("clusedge", &m_clusedge); + m_tree->Branch("clussledge", &m_clussledge); + m_tree->Branch("clussredge", &m_clussredge); + m_tree->Branch("clustledge", &m_clustledge); + m_tree->Branch("clustredge", &m_clustredge); + m_tree->Branch("clusdledge", &m_clusdledge); + m_tree->Branch("clusdredge", &m_clusdredge); + m_tree->Branch("clushledge", &m_clushledge); + m_tree->Branch("clushredge", &m_clushredge); + m_tree->Branch("clusslmix", &m_clusslmix); + m_tree->Branch("clussrmix", &m_clussrmix); + m_tree->Branch("clustlmix", &m_clustlmix); + m_tree->Branch("clustrmix", &m_clustrmix); m_tree->Branch("clusoverlap", &m_clusoverlap); + m_tree->Branch("clusphibinlo", &m_clusphibinlo); + m_tree->Branch("clusphibinhi", &m_clusphibinhi); + m_tree->Branch("clustbinlo", &m_clustbinlo); + m_tree->Branch("clustbinhi", &m_clustbinhi); + m_tree->Branch("clusPadCen", &m_clusPadCen); + m_tree->Branch("clusTBinCen", &m_clusTBinCen); + m_tree->Branch("clusPadMax", &m_clusPadMax); + m_tree->Branch("clusTBinMax", &m_clusTBinMax); m_tree->Branch("cluslx", &m_cluslx); m_tree->Branch("cluslz", &m_cluslz); m_tree->Branch("cluselx", &m_cluselx); @@ -1824,6 +1992,8 @@ void TrackResiduals::createBranches() m_tree->Branch("clusgy", &m_clusgy); m_tree->Branch("clusgz", &m_clusgz); m_tree->Branch("clusgr", &m_clusgr); + m_tree->Branch("cluspadphase", &m_cluspadphase); + m_tree->Branch("clustbinphase", &m_clustbinphase); if (m_doAlignment) { m_tree->Branch("clusgxunmoved", &m_clusgxunmoved); @@ -1832,6 +2002,8 @@ void TrackResiduals::createBranches() } m_tree->Branch("clusAdc", &m_clusAdc); m_tree->Branch("clusMaxAdc", &m_clusMaxAdc); + m_tree->Branch("clusCenAdc", &m_clusCenAdc); + m_tree->Branch("clussize", &m_clussize); m_tree->Branch("clusphisize", &m_clusphisize); m_tree->Branch("cluszsize", &m_cluszsize); @@ -2235,6 +2407,7 @@ void TrackResiduals::fillEventTree(PHCompositeNode* topNode) if (Verbosity() > 1) { std::cout << " m_event:" << m_event << std::endl; + std::cout << " m_evt_id:" << m_evt_id << std::endl; std::cout << " m_ntpc_clus0:" << m_ntpc_clus0 << std::endl; std::cout << " m_ntpc_clus1: " << m_ntpc_clus1 << std::endl; std::cout << " m_nmvtx_all:" << m_nmvtx_all << std::endl; diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 7e789faba5..6601fc47c9 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -128,6 +128,7 @@ class TrackResiduals : public SubsysReco bool m_doMicromegasOnly = false; int m_event = 0; + int m_evt_id = -1; int m_segment = std::numeric_limits::quiet_NaN(); int m_runnumber = std::numeric_limits::quiet_NaN(); int m_ntpcclus = std::numeric_limits::quiet_NaN(); @@ -246,8 +247,34 @@ class TrackResiduals : public SubsysReco float m_scluseta = std::numeric_limits::quiet_NaN(); float m_adc = std::numeric_limits::quiet_NaN(); float m_clusmaxadc = std::numeric_limits::quiet_NaN(); + float m_cluscenadc = std::numeric_limits::quiet_NaN(); + int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); + int m_overlap = std::numeric_limits::quiet_NaN(); + int m_nedge = std::numeric_limits::quiet_NaN(); + int m_sledge = std::numeric_limits::quiet_NaN(); + int m_sredge = std::numeric_limits::quiet_NaN(); + int m_tledge = std::numeric_limits::quiet_NaN(); + int m_tredge = std::numeric_limits::quiet_NaN(); + int m_dledge = std::numeric_limits::quiet_NaN(); + int m_dredge = std::numeric_limits::quiet_NaN(); + int m_hledge = std::numeric_limits::quiet_NaN(); + int m_hredge = std::numeric_limits::quiet_NaN(); + int m_slmix = std::numeric_limits::quiet_NaN(); + int m_srmix = std::numeric_limits::quiet_NaN(); + int m_tlmix = std::numeric_limits::quiet_NaN(); + int m_trmix = std::numeric_limits::quiet_NaN(); + float m_phibinlo = std::numeric_limits::quiet_NaN(); + float m_phibinhi = std::numeric_limits::quiet_NaN(); + float m_tbinlo = std::numeric_limits::quiet_NaN(); + float m_tbinhi = std::numeric_limits::quiet_NaN(); + float m_padphase = std::numeric_limits::quiet_NaN(); + float m_tbinphase = std::numeric_limits::quiet_NaN(); + float m_padcen = std::numeric_limits::quiet_NaN(); + float m_tbincen = std::numeric_limits::quiet_NaN(); + float m_padmax = std::numeric_limits::quiet_NaN(); + float m_tbinmax = std::numeric_limits::quiet_NaN(); float m_scluslx = std::numeric_limits::quiet_NaN(); float m_scluslz = std::numeric_limits::quiet_NaN(); float m_sclusgx = std::numeric_limits::quiet_NaN(); @@ -270,6 +297,11 @@ class TrackResiduals : public SubsysReco //! clusters on track information std::vector m_clusAdc; std::vector m_clusMaxAdc; + std::vector m_clusCenAdc; + std::vector m_clusPadCen; + std::vector m_clusTBinCen; + std::vector m_clusPadMax; + std::vector m_clusTBinMax; std::vector m_cluslx; std::vector m_cluslz; std::vector m_cluselx; @@ -288,10 +320,29 @@ class TrackResiduals : public SubsysReco std::vector m_clsector; std::vector m_clside; std::vector m_cluslayer; + std::vector m_clussize; std::vector m_clusphisize; std::vector m_cluszsize; - std::vector m_clusedge; std::vector m_clusoverlap; + std::vector m_clusedge; + std::vector m_clussledge; + std::vector m_clussredge; + std::vector m_clustledge; + std::vector m_clustredge; + std::vector m_clusdledge; + std::vector m_clusdredge; + std::vector m_clushledge; + std::vector m_clushredge; + std::vector m_clusslmix; + std::vector m_clussrmix; + std::vector m_clustlmix; + std::vector m_clustrmix; + std::vector m_clusphibinlo; + std::vector m_clusphibinhi; + std::vector m_clustbinlo; + std::vector m_clustbinhi; + std::vector m_cluspadphase; + std::vector m_clustbinphase; std::vector m_cluskeys; std::vector m_idealsurfcenterx; std::vector m_idealsurfcentery; diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index d5fddf6538..1c90c4688c 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -289,6 +289,11 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) nclue, ncluadc, nclumaxadc, + nclucenadc, + nclupadcen, + nclutbincen, + nclupadmax, + nclutbinmax, ncluthick, ncluafac, nclubfac, @@ -301,7 +306,25 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) ncluzsize, nclupedge, ncluredge, + nclusledge, + nclusredge, + nclutledge, + nclutredge, + ncludledge, + ncludredge, + ncluhledge, + ncluhredge, + ncluslmix, + nclusrmix, + nclutlmix, + nclutrmix, ncluovlp, + ncluphibinlo, + ncluphibinhi, + nclutbinlo, + nclutbinhi, + nclupadphase, + nclutbinphase, nclutrackID, ncluniter, clusize = ncluniter + 1 @@ -337,7 +360,7 @@ int TrkrNtuplizer::Init(PHCompositeNode* /*unused*/) std::string str_vertex = {"vertexID:vx:vy:vz:ntracks:chi2:ndof"}; std::string str_event = {"event:seed:run:seg:job"}; std::string str_hit = {"hitID:e:adc:layer:phielem:zelem:cellID:ecell:phibin:zbin:tbin:phi:r:x:y:z"}; - std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:ovlp:trackID:niter"}; + std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:cenadc:padcen:tbincen:padmax:tbinmax:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:sledge:sredge:tledge:tredge:dledge:dredge:hledge:hredge:slmix:srmix:tlmix:trmix:ovlp:phibinlo:phibinhi:tbinlo:tbinhi:padphase:tbinphase:trackID:niter"}; std::string str_seed = {"seedID:siter:spt:sptot:seta:sphi:syxint:srzint:sxyslope:srzslope:sX0:sY0:sdZ0:sR0:scharge:sdedx:spidedx:skdedx:sprdedx:sn1pix:snsil:sntpc:snhits"}; std::string str_residual = {"alpha:beta:resphio:resphi:resz"}; std::string str_track = {"trackID:crossing:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:charge:quality:chisq:ndf:nhits:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:dedx:pidedx:kdedx:prdedx:vertexID:vx:vy:vz:dca2d:dca2dsigma:dca3dxy:dca3dxysigma:dca3dz:dca3dzsigma:pcax:pcay:pcaz:hlxpt:hlxeta:hlxphi:hlxX0:hlxY0:hlxZ0:hlxcharge"}; @@ -1386,7 +1409,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } //----------------------- - // fill the Vertex NTuple and fixed NaN placeholders + // fill the Vertex NTuple and fixed NaN placeholders //----------------------- bool doit = true; if (_ntp_vertex && doit) @@ -1409,8 +1432,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) for (auto & iter : *vertexmap) { SvtxVertex* vertex = iter.second; - if (!vertex) { continue; -} + if (!vertex) { continue; } float fx_vertex[n_vertex::vtxsize]; for (float& i : fx_vertex) @@ -1453,8 +1475,6 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) _timer->stop(); std::cout << "vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; } - - //-------------------- // fill the Hit NTuple //-------------------- @@ -2284,6 +2304,11 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c fXcluster[n_cluster::nclue] = cluster->getAdc(); fXcluster[n_cluster::ncluadc] = cluster->getAdc(); fXcluster[n_cluster::nclumaxadc] = cluster->getMaxAdc(); + fXcluster[n_cluster::nclucenadc] = cluster->getCenAdc(); + fXcluster[n_cluster::nclupadcen] = cluster->getPadCen(); + fXcluster[n_cluster::nclutbincen] = cluster->getTBinCen(); + fXcluster[n_cluster::nclupadmax] = cluster->getPadMax(); + fXcluster[n_cluster::nclutbinmax] = cluster->getTBinMax(); fXcluster[n_cluster::nclulayer] = layer_local; if (layer_local < 3) @@ -2311,7 +2336,7 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c } } */ - fXcluster[n_cluster::nclusize] = cluster->getSize(); + fXcluster[n_cluster::nclusize] = cluster->getRSize(); fXcluster[n_cluster::ncluphisize] = cluster->getPhiSize(); fXcluster[n_cluster::ncluzsize] = cluster->getZSize(); fXcluster[n_cluster::nclupedge] = cluster->getEdge(); @@ -2321,8 +2346,25 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c { fXcluster[n_cluster::ncluredge] = 1; } - - fXcluster[n_cluster::ncluovlp] = 3; // cluster->getOvlp(); + fXcluster[n_cluster::nclusledge] = cluster->getSLEdge(); + fXcluster[n_cluster::nclusredge] = cluster->getSREdge(); + fXcluster[n_cluster::nclutledge] = cluster->getTLEdge(); + fXcluster[n_cluster::nclutredge] = cluster->getTREdge(); + fXcluster[n_cluster::ncludledge] = cluster->getDLEdge(); + fXcluster[n_cluster::ncludredge] = cluster->getDREdge(); + fXcluster[n_cluster::ncluhledge] = cluster->getHLEdge(); + fXcluster[n_cluster::ncluhredge] = cluster->getHREdge(); + fXcluster[n_cluster::ncluslmix] = cluster->getSLMix(); + fXcluster[n_cluster::nclusrmix] = cluster->getSRMix(); + fXcluster[n_cluster::nclutlmix] = cluster->getTLMix(); + fXcluster[n_cluster::nclutrmix] = cluster->getTRMix(); + fXcluster[n_cluster::ncluovlp] = cluster->getOverlap(); + fXcluster[n_cluster::ncluphibinlo] = cluster->getPhiBinLo(); + fXcluster[n_cluster::ncluphibinhi] = cluster->getPhiBinHi(); + fXcluster[n_cluster::nclutbinlo] = cluster->getTBinLo(); + fXcluster[n_cluster::nclutbinhi] = cluster->getTBinHi(); + fXcluster[n_cluster::nclupadphase] = cluster->getPadPhase(); + fXcluster[n_cluster::nclutbinphase] = cluster->getTBinPhase(); fXcluster[n_cluster::nclutrackID] = std::numeric_limits::quiet_NaN(); fXcluster[n_cluster::ncluniter] = 0; diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 687d5b58f9..5e0d58e112 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include // for hitkey, getLayer #include #include @@ -84,6 +85,36 @@ namespace unsigned short edge = 0; }; + struct ClusterCounters + { + int overlap = 0; + + int nedge = 0; // Total No. of Edges + + int sledge = 0; // Touching Left Sector Edge + int sredge = 0; // Touching Right Sector Edge + + int tledge = 0; // Touching Left Time Edge + int tredge = 0; // Touching Right Time Edge + + int dledge = 0; // Touching Left Dead Edge + int dredge = 0; // Touching Right Dead Edge + + int hledge = 0; // Touching Left Hot Edge + int hredge = 0; // Touching Right Hot Edge + + int slmix = 0; // Touching Cluster at Left in Phibin + int srmix = 0; // Touching Cluster at Right in Phibin + + int tlmix = 0; // Touching Cluster at Left in Timebin + int trmix = 0; // Touching Cluster at Right in Timebin + + void clear() + { + *this = ClusterCounters{}; + } + }; + using vec_dVerbose = std::vector>>; // Neural network parameters and modules @@ -176,13 +207,14 @@ namespace } } - void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, int &touch, int &edge) + void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, ClusterCounters &counts, bool &ttop_edge, bool &tbottom_edge) { const int FitRangeT = (int) my_data.maxHalfSizeT; const int NTBinsMax = (int) my_data.tbins; - const int FixedWindow = (int) my_data.FixedWindow; + // const int FixedWindow = (int) my_data.FixedWindow; tup = 0; tdown = 0; + /* if (FixedWindow != 0) { tup = FixedWindow; @@ -190,15 +222,16 @@ namespace if (tbin + tup >= NTBinsMax) { tup = NTBinsMax - tbin - 1; - edge++; + counts.nedge++; } if ((tbin - tdown) <= 0) { tdown = tbin; - edge++; + counts.edge++; } return; } + */ for (int it = 0; it < FitRangeT; it++) { int ct = tbin + it; @@ -206,7 +239,12 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tup = it; - edge++; + if (!ttop_edge) + { + counts.nedge++; + counts.tredge = 1; + ttop_edge = true; + } break; // truncate edge } @@ -216,7 +254,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -228,7 +266,7 @@ namespace adcval[phibin][ct + 2] + adcval[phibin][ct + 3]) { // rising again tup = it + 1; - touch++; + counts.overlap++; break; } } @@ -241,7 +279,12 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tdown = it; - edge++; + if (!tbottom_edge) + { + counts.nedge++; + counts.tledge = 1; + tbottom_edge = true; + } break; // truncate edge } if (adcval[phibin][ct] <= 0) @@ -250,7 +293,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -261,7 +304,7 @@ namespace adcval[phibin][ct - 2] + adcval[phibin][ct - 3]) { // rising again tdown = it + 1; - touch++; + counts.overlap++; break; } } @@ -271,13 +314,14 @@ namespace return; } - void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, int &touch, int &edge) + void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, ClusterCounters &counts, bool &phitop_edge, bool &phibottom_edge) { int FitRangePHI = (int) my_data.maxHalfSizePhi; int NPhiBinsMax = (int) my_data.phibins; - const int FixedWindow = (int) my_data.FixedWindow; + // const int FixedWindow = (int) my_data.FixedWindow; phidown = 0; phiup = 0; + /* if (FixedWindow != 0) { phiup = FixedWindow; @@ -294,13 +338,19 @@ namespace } return; } + */ for (int iphi = 0; iphi < FitRangePHI; iphi++) { int cphi = phibin + iphi; if (cphi < 0 || cphi >= NPhiBinsMax) { // phiup = iphi; - edge++; + if (!phitop_edge) + { + counts.nedge++; + counts.sredge = 1; + phitop_edge = true; + } break; // truncate edge } @@ -312,7 +362,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -323,7 +373,7 @@ namespace adcval[cphi + 2][tbin] + adcval[cphi + 3][tbin]) { // rising again phiup = iphi + 1; - touch++; + counts.overlap++; break; } } @@ -337,7 +387,12 @@ namespace if (cphi < 0 || cphi >= NPhiBinsMax) { // phidown = iphi; - edge++; + if (!phibottom_edge) + { + counts.nedge++; + counts.sledge = 1; + phibottom_edge = true; + } break; // truncate edge } @@ -348,7 +403,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -359,7 +414,7 @@ namespace adcval[cphi - 2][tbin] + adcval[cphi - 3][tbin]) { // rising again phidown = iphi + 1; - touch++; + counts.overlap++; break; } } @@ -369,6 +424,61 @@ namespace return; } + void check_cluster_touching(const std::vector& ihit_list, const std::vector>& adcval, int phibins, int tbins, ClusterCounters &counts) + { + // Encode (iphi, it) into single integer for fast lookup + std::unordered_set cluster_hits; + cluster_hits.reserve(ihit_list.size()); + + auto encode = [tbins](int phi, int t) + { + return phi * tbins + t; + }; + + for (const auto &hit : ihit_list) + { + cluster_hits.insert(encode(hit.iphi, hit.it)); + } + + for (const auto &hit : ihit_list) + { + int iphi = hit.iphi; + int it = hit.it; + + for (int dphi = -1; dphi <= 1; ++dphi) + { + for (int dt = -1; dt <= 1; ++dt) + { + if (dphi == 0 && dt == 0) { continue; } + + int nphi = iphi + dphi; + int nt = it + dt; + + if (nphi < 0 || nphi >= phibins || + nt < 0 || nt >= tbins) { + continue; + } + + // skip same cluster + if (cluster_hits.contains(encode(nphi, nt))) { continue; } + + // neighbor has signal → touching + if (adcval[nphi][nt] > 0 && + adcval[nphi][nt] != USHRT_MAX) + { + // Check Phi + if (dphi == -1) { counts.slmix = 1; } + if (dphi == 1) { counts.srmix = 1; } + + // Check Time + if (dt == -1) { counts.tlmix = 1; } + if (dt == 1) { counts.trmix = 1; } + } + } + } + } + } + int is_hit_isolated(int iphi, int it, int NPhiBinsMax, int NTBinsMax, const std::vector> &adcval) { // check isolated hits @@ -426,20 +536,25 @@ namespace return isiso; } - void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, int &touch, int &edge) + void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, ClusterCounters &counts) { + bool ttop_edge = false; + bool tbottom_edge = false; + bool phitop_edge = false; + bool phibottom_edge = false; + // search along phi at the peak in t // const int NPhiBinsMax = (int) my_data.phibins; // const int NTBinsMax = (int) my_data.tbins; int tup = 0; int tdown = 0; - find_t_range(phibin, tbin, my_data, adcval, tdown, tup, touch, edge); + find_t_range(phibin, tbin, my_data, adcval, tdown, tup, counts, ttop_edge, tbottom_edge); // now we have the t extent of the cluster, go find the phi edges for (int it = tbin - tdown; it <= (tbin + tup); it++) { int phiup = 0; int phidown = 0; - find_phi_range(phibin, it, my_data, adcval, phidown, phiup, touch, edge); + find_phi_range(phibin, it, my_data, adcval, phidown, phiup, counts, phitop_edge, phibottom_edge); for (int iphi = (phibin - phidown); iphi <= (phibin + phiup); iphi++) { if (adcval[iphi][it] > 0 && adcval[iphi][it] != USHRT_MAX) @@ -456,7 +571,7 @@ namespace hit.it = it; hit.adc = adcval[iphi][it]; - if (touch > 0) + if (counts.overlap > 0) { if ((iphi == (phibin - phidown)) || (iphi == (phibin + phiup))) @@ -472,7 +587,7 @@ namespace } 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) + const std::vector &ihit_list, thread_data &my_data, ClusterCounters counts) { // // get z range from layer geometry @@ -488,6 +603,8 @@ namespace double iphi_sum = 0.0; double iphi2_sum = 0.0; + double it_sum = 0.0; + double radius = my_data.layergeom->get_radius(); // returns center of layer int phibinhi = -1; @@ -497,6 +614,12 @@ namespace int clus_size = ihit_list.size(); int max_adc = 0; + int phibinmax = -1; + int tbinmax = -1; + double cen_adc = 0; + + int size = 0; + if (clus_size <= my_data.min_clus_size) { return; @@ -521,14 +644,16 @@ namespace training_hits->phistep = my_data.layergeom->get_phistep(); training_hits->zstep = my_data.layergeom->get_zstep() * my_data.tGeometry->get_drift_velocity(); training_hits->layer = my_data.layer; - training_hits->ntouch = ntouch; - training_hits->nedge = nedge; + training_hits->ntouch = counts.overlap; + training_hits->nedge = counts.nedge; training_hits->v_adc.fill(0); } // std::cout << "process list" << std::endl; std::vector hitkeyvec; + std::map, double> adc_map; + // keep track of the hit locations in a given cluster std::map m_phi{}; std::map m_z{}; @@ -544,7 +669,18 @@ namespace continue; } - max_adc = std::max(max_adc, static_cast(std::round(adc))); // preserves rounding (0.5 -> 1) + size++; + + int adc_int = static_cast(std::round(adc)); + + if (adc_int > max_adc) + { + max_adc = adc_int; + phibinmax = iphi; + tbinmax = 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); @@ -565,8 +701,12 @@ namespace t_sum += t * adc; t2_sum += square(t) * adc; + it_sum += it * adc; + adc_sum += adc; + adc_map[{iphi, it}] += adc; + if (my_data.fillClusHitsVerbose) { auto pnew = m_phi.try_emplace(iphi, adc); @@ -623,13 +763,15 @@ namespace left_pad >= my_data.phioffset && deadset.contains(TpcDefs::genHitKey(left_pad, 0))) { - nedge++; + counts.nedge++; + counts.dledge = 1; } if (right_pad < (my_data.phibins + my_data.phioffset) && deadset.contains(TpcDefs::genHitKey(right_pad, 0))) { - nedge++; + counts.nedge++; + counts.dredge = 1; } } } @@ -646,24 +788,62 @@ namespace left_pad >= my_data.phioffset && hotset.contains(TpcDefs::genHitKey(left_pad, 0))) { - nedge++; + counts.nedge++; + counts.hledge = 1; } if (right_pad < (my_data.phibins + my_data.phioffset) && hotset.contains(TpcDefs::genHitKey(right_pad, 0))) { - nedge++; + counts.nedge++; + counts.hredge = 1; } } } - // This is the global position + // This is local position double clusiphi = iphi_sum / adc_sum; + double clusit = it_sum / adc_sum; + + // This is the global position double clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); + double clust = t_sum / adc_sum; + + // ADC of centroid bin + int iphi_centroid = static_cast(std::floor(clusiphi)); + int it_centroid = static_cast(std::floor(clusit)); + + auto it_cent = adc_map.find({iphi_centroid, it_centroid}); + if (it_cent != adc_map.end()) + { + cen_adc = it_cent->second; + } + else + { + cen_adc = 0.0; // centroid may not land on a real hit + } + + // Max ADC position in global coordinates + double maxphi = my_data.layergeom->get_phi(phibinmax, my_data.side); + double maxt = my_data.layergeom->get_zcenter(tbinmax); + + // Phase relative to max ADC position + double padphase = 0.0; + double tbinphase = 0.0; + + if (my_data.layergeom->get_phistep() > 0) + { + padphase = (clusphi - maxphi) / my_data.layergeom->get_phistep(); + } + + if (my_data.layergeom->get_zstep() > 0) + { + tbinphase = (clust - maxt) / my_data.layergeom->get_zstep(); + } double clusx = radius * cos(clusphi); double clusy = radius * sin(clusphi); - double clust = t_sum / adc_sum; + // needed for surface identification double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); // convert z drift length to z position in the TPC @@ -702,6 +882,7 @@ namespace char tsize = tbinhi - tbinlo + 1; char phisize = phibinhi - phibinlo + 1; + char rsize = size; // std::cout << "phisize: " << (int) phisize << " phibinhi " << phibinhi << " phibinlo " << phibinlo << std::endl; // phi_cov = (weighted mean of dphi^2) - (weighted mean of dphi)^2, which is essentially the weighted mean of dphi^2. The error is then: // e_phi = sigma_dphi/sqrt(N) = sqrt( sigma_dphi^2 / N ) -- where N is the number of samples of the distribution with standard deviation sigma_dphi @@ -726,20 +907,45 @@ 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 TrkrClusterv6; + // auto *clus = new TrkrClusterv5; // auto clus = std::make_unique(); clus_base = clus; - clus->setAdc(adc_sum); - clus->setMaxAdc(max_adc); - clus->setEdge(nedge); - clus->setPhiSize(phisize); - clus->setZSize(tsize); - clus->setSubSurfKey(subsurfkey); - clus->setOverlap(ntouch); clus->setLocalX(local(0)); clus->setLocalY(clust); + clus->setSubSurfKey(subsurfkey); + clus->setAdc(adc_sum); + clus->setMaxAdc(max_adc); + clus->setCenAdc(cen_adc); + clus->setPadCen(clusiphi); + clus->setTBinCen(clusit); + clus->setPadMax(phibinmax); + clus->setTBinMax(tbinmax); clus->setPhiError(sqrt(phi_err_square)); clus->setZError(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(), 2))); + clus->setRSize(rsize); + clus->setPhiSize(phisize); + clus->setZSize(tsize); + clus->setOverlap(counts.overlap); + clus->setEdge(counts.nedge); + clus->setSLEdge(counts.sledge); + clus->setSREdge(counts.sredge); + clus->setTLEdge(counts.tledge); + clus->setTREdge(counts.tredge); + clus->setDLEdge(counts.dledge); + clus->setDREdge(counts.dredge); + clus->setHLEdge(counts.hledge); + clus->setHREdge(counts.hredge); + clus->setSLMix(counts.slmix); + clus->setSRMix(counts.srmix); + clus->setTLMix(counts.tlmix); + clus->setTRMix(counts.trmix); + clus->setPhiBinLo(phibinlo); + clus->setPhiBinHi(phibinhi); + clus->setTBinLo(tbinlo); + clus->setTBinHi(tbinhi); + clus->setPadPhase(padphase); + clus->setTBinPhase(tbinphase); my_data.cluster_vector.push_back(clus); b_made_cluster = true; } @@ -1037,6 +1243,9 @@ namespace } } */ + + std::vector> adcval_orig = adcval; + // std::cout << "done filling " << std::endl; while (!all_hit_map.empty()) { @@ -1064,9 +1273,10 @@ namespace // start with highest adc hit // -> cluster around it and get vector of hits std::vector ihit_list; - int ntouch = 0; - int nedge = 0; - get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); + // Setting all the counters + ClusterCounters counts; + + get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); if (my_data->FixedWindow > 0) { @@ -1102,11 +1312,16 @@ namespace my_data->FixedWindow = 0; // reset hit list and try again without fixed window ihit_list.clear(); - get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); + // resetting all the counters + counts.clear(); + get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); // std::cout << " stepdown size after " << ihit_list.size() << std::endl; my_data->FixedWindow = window_cache; } } + + check_cluster_touching(ihit_list, adcval_orig, my_data->phibins, my_data->tbins, counts); + if (ihit_list.size() <= 1) { remove_hits(ihit_list, all_hit_map, adcval); @@ -1117,7 +1332,7 @@ namespace // -> add hits to truth association // remove hits from all_hit_map // repeat untill all_hit_map empty - calc_cluster_parameter(iphi, it, ihit_list, *my_data, ntouch, nedge); + calc_cluster_parameter(iphi, it, ihit_list, *my_data, counts); remove_hits(ihit_list, all_hit_map, adcval); ihit_list.clear(); } From 52ecbba614cd0d0828e31c45f5d5a73e855a69b3 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Fri, 19 Jun 2026 13:26:04 -0400 Subject: [PATCH 741/866] Option for v5 vs v6. --- offline/packages/tpc/TpcClusterizer.cc | 13 ++++++++++++- offline/packages/tpc/TpcClusterizer.h | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 5e0d58e112..28a6ea7a9a 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -907,7 +907,18 @@ 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 TrkrClusterv6; + TrkrCluster* clus = nullptr; + + if (m_debug) + { + clus = new TrkrClusterv6; + } + else + { + clus = new TrkrClusterv5; + } + + // auto *clus = new TrkrClusterv6; // auto *clus = new TrkrClusterv5; // auto clus = std::make_unique(); clus_base = clus; diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index 801207654e..c566f5b4f8 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -91,6 +91,11 @@ class TpcClusterizer : public SubsysReco m_hotChannelMapName = hmap; } + void DetailedClusterAnalysis() + { + m_debug = true; + } + private: bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; @@ -135,6 +140,7 @@ class TpcClusterizer : public SubsysReco bool m_maskDeadChannels {false}; bool m_maskHotChannels {false}; bool m_maskFromFile {false}; + bool m_debug{false}; std::string m_deadChannelMapName; std::string m_hotChannelMapName; }; From bb8523abfb2b63ee041032de8f6657519d0dc4ea Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 11:46:59 -0400 Subject: [PATCH 742/866] put the debug flag into the data struct --- offline/packages/tpc/TpcClusterizer.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 28a6ea7a9a..751fd28c0c 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -160,6 +160,7 @@ namespace hitMaskTpcSet *hotMap = nullptr; bool maskDead = false; bool maskHot = false; + bool debug = false; std::vector association_vector; std::vector cluster_vector; @@ -909,13 +910,13 @@ namespace { TrkrCluster* clus = nullptr; - if (m_debug) + if (my_data.debug) { - clus = new TrkrClusterv6; + clus = new TrkrClusterv6; } else { - clus = new TrkrClusterv5; + clus = new TrkrClusterv5; } // auto *clus = new TrkrClusterv6; @@ -957,6 +958,7 @@ namespace clus->setTBinHi(tbinhi); clus->setPadPhase(padphase); clus->setTBinPhase(tbinphase); + my_data.cluster_vector.push_back(clus); b_made_cluster = true; } @@ -1762,7 +1764,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.phioffset = PhiOffset; thread_pair.data.tbins = NTBinsSide; thread_pair.data.toffset = TOffset; - + thread_pair.data.debug = m_debug; thread_pair.data.radius = layergeom->get_radius(); thread_pair.data.drift_velocity = m_tGeometry->get_drift_velocity(); thread_pair.data.pads_per_sector = 0; From 960d626399cafefcbc5d0b64aa23b281fad2a069 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 11:47:12 -0400 Subject: [PATCH 743/866] add the functions to the base class --- offline/packages/trackbase/TrkrCluster.h | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index f37440646b..ffae2910d6 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -104,6 +104,35 @@ class TrkrCluster : public PHObject virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } + virtual void setSLEdge(const char) {}; + virtual void setSREdge(const char) {}; + virtual void setTLEdge(const char) {}; + virtual void setTREdge(const char) {}; + virtual void setDLEdge(const char) {}; + virtual void setDREdge(const char) {}; + virtual void setHLEdge(const char) {}; + virtual void setHREdge(const char) {}; + virtual void setSLMix(const int) {}; + virtual void setSRMix(const int) {}; + virtual void setTLMix(const int) {}; + virtual void setTRMix(const int) {}; + virtual void setPhiBinLo(const float) {}; + virtual void setPhiBinHi(const float) {}; + virtual void setTBinLo(const float) {}; + virtual void setTBinHi(const float) {}; + virtual void setPadPhase(const float) {}; + virtual void setTBinPhase(const float) {}; + virtual void setRSize(const float) {}; + virtual void setCenAdc(const unsigned int) {}; + virtual void setPadCen(const float) {}; + virtual void setTBinCen(const float) {}; + virtual void setPadMax(const float) {}; + virtual void setTBinMax(const float) {}; + virtual void setPhiError(const float) {}; + virtual void setZError(const float) {}; + virtual void setPhiSize(const float) {}; + virtual void setZSize(const float) {}; + /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } From ad8506957129c0c99ae10df239113dcf6de83788 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 12:44:13 -0400 Subject: [PATCH 744/866] all of the member variables should now be the correct type --- offline/packages/trackbase/TrkrClusterv6.h | 130 ++++++++++----------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 37ffdffbbf..adbd3d4728 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -60,7 +60,7 @@ class TrkrClusterv6 : public TrkrCluster { return (coor >= 0 && coor < 2) ? m_local[coor] : std::numeric_limits::quiet_NaN(); } - void setPosition(int coor, float xi) override + void setPosition(const int coor, const float xi) override { if (coor >= 0 && coor < 2) { @@ -68,36 +68,36 @@ class TrkrClusterv6 : public TrkrCluster } } float getLocalX() const override { return m_local[0]; } - void setLocalX(float loc0) override { m_local[0] = loc0; } + void setLocalX(const float loc0) override { m_local[0] = loc0; } float getLocalY() const override { return m_local[1]; } - void setLocalY(float loc1) override { m_local[1] = loc1; } + void setLocalY(const float loc1) override { m_local[1] = loc1; } TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } - void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } // // cluster info // unsigned int getAdc() const override { return m_adc; } - void setAdc(unsigned int adc) override { m_adc = adc; } + void setAdc(const unsigned int adc) override { m_adc = adc; } unsigned int getMaxAdc() const override { return m_maxadc; } - void setMaxAdc(uint16_t maxadc) override { m_maxadc = maxadc; } + void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } unsigned int getCenAdc() const override { return m_cenadc; } - void setCenAdc(uint16_t cenadc) { m_cenadc = cenadc; } + void setCenAdc(const uint16_t cenadc) { m_cenadc = cenadc; } float getPadCen() const override { return m_padcen; } - void setPadCen(float padcen) { m_padcen = padcen; } + void setPadCen(const float padcen) { m_padcen = padcen; } float getTBinCen() const override { return m_tbincen; } - void setTBinCen(float tbincen) { m_tbincen = tbincen; } + void setTBinCen(const float tbincen) { m_tbincen = tbincen; } float getPadMax() const override { return m_padmax; } - void setPadMax(float padmax) { m_padmax = padmax; } + void setPadMax(const float padmax) { m_padmax = padmax; } float getTBinMax() const override { return m_tbinmax; } - void setTBinMax(float tbinmax) { m_tbinmax = tbinmax; } + void setTBinMax(const float tbinmax) { m_tbinmax = tbinmax; } // // convenience interface @@ -105,80 +105,80 @@ class TrkrClusterv6 : public TrkrCluster float getRPhiError() const override { return m_phierr; } float getZError() const override { return m_zerr; } - void setPhiError(float phierror) { m_phierr = phierror; } - void setZError(float zerror) { m_zerr = zerror; } + void setPhiError(const float phierror) { m_phierr = phierror; } + void setZError(const float zerror) { m_zerr = zerror; } char getSize() const override { return m_phisize * m_zsize; } - // void setSize(char size) { m_size = size; } + // void setSize(const char size) { m_size = size; } float getRSize() const override { return (float) m_rsize; } - void setRSize(unsigned char rsize) { m_rsize = rsize; } + void setRSize(const unsigned char rsize) { m_rsize = rsize; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(const char phisize) { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(const char zsize) { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } - void setOverlap(char overlap) override { m_overlap = overlap; } + void setOverlap(const char overlap) override { m_overlap = overlap; } char getEdge() const override { return m_edge; } - void setEdge(char edge) override { m_edge = edge; } + void setEdge(const char edge) override { m_edge = edge; } char getSLEdge() const override { return m_sledge; } - void setSLEdge(char sledge) { m_sledge = sledge; } + void setSLEdge(const char sledge) { m_sledge = sledge; } char getSREdge() const override { return m_sredge; } - void setSREdge(char sredge) { m_sredge = sredge; } + void setSREdge(const char sredge) { m_sredge = sredge; } char getTLEdge() const override { return m_tledge; } - void setTLEdge(char tledge) { m_tledge = tledge; } + void setTLEdge(const char tledge) { m_tledge = tledge; } char getTREdge() const override { return m_tredge; } - void setTREdge(char tredge) { m_tredge = tredge; } + void setTREdge(const char tredge) { m_tredge = tredge; } char getDLEdge() const override { return m_dledge; } - void setDLEdge(char dledge) { m_dledge = dledge; } + void setDLEdge(const char dledge) { m_dledge = dledge; } char getDREdge() const override { return m_dredge; } - void setDREdge(char dredge) { m_dredge = dredge; } + void setDREdge(const char dredge) { m_dredge = dredge; } char getHLEdge() const override { return m_hledge; } - void setHLEdge(char hledge) { m_hledge = hledge; } + void setHLEdge(const char hledge) { m_hledge = hledge; } char getHREdge() const override { return m_hredge; } - void setHREdge(char hredge) { m_hredge = hredge; } + void setHREdge(const char hredge) { m_hredge = hredge; } int getSLMix() const override { return m_slmix; } - void setSLMix(char slmix) { m_slmix = slmix; } + void setSLMix(const char slmix) { m_slmix = slmix; } int getSRMix() const override { return m_srmix; } - void setSRMix(char srmix) { m_srmix = srmix; } + void setSRMix(const char srmix) { m_srmix = srmix; } int getTLMix() const override { return m_tlmix; } - void setTLMix(char tlmix) { m_tlmix = tlmix; } + void setTLMix(const char tlmix) { m_tlmix = tlmix; } int getTRMix() const override { return m_trmix; } - void setTRMix(char trmix) { m_trmix = trmix; } + void setTRMix(const char trmix) { m_trmix = trmix; } float getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(float phibinlo) { m_phibinlo = phibinlo; } + void setPhiBinLo(const float phibinlo) { m_phibinlo = phibinlo; } float getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(float phibinhi) { m_phibinhi = phibinhi; } + void setPhiBinHi(const float phibinhi) { m_phibinhi = phibinhi; } - float getTBinLo() const override { return m_tbinlo; } - void setTBinLo(float tbinlo) { m_tbinlo = tbinlo; } + char getTBinLo() const override { return m_tbinlo; } + void setTBinLo(const char tbinlo) { m_tbinlo = tbinlo; } - float getTBinHi() const override { return m_tbinhi; } - void setTBinHi(float tbinhi) { m_tbinhi = tbinhi; } + char getTBinHi() const override { return m_tbinhi; } + void setTBinHi(const char tbinhi) { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } - void setPadPhase(float padphase) { m_padphase = padphase; } + void setPadPhase(const float padphase) { m_padphase = padphase; } float getTBinPhase() const override { return m_tbinphase; } - void setTBinPhase(float tbinphase){ m_tbinphase = tbinphase; } + void setTBinPhase(const float tbinphase){ m_tbinphase = tbinphase; } private: float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; @@ -186,34 +186,34 @@ class TrkrClusterv6 : public TrkrCluster TrkrDefs::subsurfkey m_subsurfkey {TrkrDefs::SUBSURFKEYMAX}; //< unique identifier for hitsetkey-surface maps 16 bit float m_phierr{0}; float m_zerr{0}; - unsigned short int m_adc{0}; //< cluster sum adc 16 - unsigned short int m_maxadc{0}; //< cluster max adc 16 - unsigned short int m_cenadc{0}; //< cluster centroid adc 16 + unsigned short m_adc{0}; //< cluster sum adc 16 + unsigned short m_maxadc{0}; //< cluster max adc 16 + unsigned short m_cenadc{0}; //< cluster centroid adc 16 float m_padcen{0}; float m_tbincen{0}; - float m_padmax{0}; - float m_tbinmax{0}; - unsigned char m_rsize{0}; // 8bit - char m_phisize{0}; // 8bit - char m_zsize{0}; // 8bit - char m_overlap{0}; // 8bit - char m_edge{0}; // 8bit - cumul 2*64 - char m_sledge{0}; // 8bit - char m_sredge{0}; // 8bit - char m_tledge{0}; // 8bit - char m_tredge{0}; // 8bit - char m_dledge{0}; // 8bit - char m_dredge{0}; // 8bit - char m_hledge{0}; // 8bit - char m_hredge{0}; // 8bit - char m_slmix{0}; // 8bit - char m_srmix{0}; // 8bit - char m_tlmix{0}; // 8bit - char m_trmix{0}; // 8bit - float m_phibinlo{0}; - float m_phibinhi{0}; - float m_tbinlo{0}; - float m_tbinhi{0}; + int m_padmax{0}; + int m_tbinmax{0}; + unsigned char m_rsize{0}; + unsigned char m_phisize{0}; + unsigned char m_zsize{0}; + char m_overlap{0}; + char m_edge{0}; + char m_sledge{0}; + char m_sredge{0}; + char m_tledge{0}; + char m_tredge{0}; + char m_dledge{0}; + char m_dredge{0}; + char m_hledge{0}; + char m_hredge{0}; + char m_slmix{0}; + char m_srmix{0}; + char m_tlmix{0}; + char m_trmix{0}; + char m_phibinlo{0}; + char m_phibinhi{0}; + char m_tbinlo{0}; + char m_tbinhi{0}; float m_padphase{0}; float m_tbinphase{0}; From 82557400b75782a1f39048c632dcad4b6bd0f4b6 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 14:54:12 -0400 Subject: [PATCH 745/866] try to make everything consistent --- offline/packages/tpc/TpcClusterizer.cc | 3 - offline/packages/trackbase/TrkrCluster.h | 40 ++++++------- offline/packages/trackbase/TrkrClusterv6.h | 70 +++++++++++----------- 3 files changed, 55 insertions(+), 58 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 751fd28c0c..a2ed3c0169 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -919,9 +919,6 @@ namespace clus = new TrkrClusterv5; } - // auto *clus = new TrkrClusterv6; - // auto *clus = new TrkrClusterv5; - // auto clus = std::make_unique(); clus_base = clus; clus->setLocalX(local(0)); clus->setLocalY(clust); diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index ffae2910d6..2312df181b 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -82,8 +82,8 @@ class TrkrCluster : public PHObject virtual unsigned int getCenAdc() const { return UINT_MAX; } virtual float getPadCen() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinCen() const { return std::numeric_limits::quiet_NaN(); } - virtual float getPadMax() const { return std::numeric_limits::quiet_NaN(); } - virtual float getTBinMax() const { return std::numeric_limits::quiet_NaN(); } + virtual int getPadMax() const { return std::numeric_limits::max(); } + virtual int getTBinMax() const { return std::numeric_limits::max(); } virtual char getSLEdge() const { return std::numeric_limits::max(); } virtual char getSREdge() const { return std::numeric_limits::max(); } virtual char getTLEdge() const { return std::numeric_limits::max(); } @@ -96,10 +96,10 @@ class TrkrCluster : public PHObject virtual int getSRMix() const { return std::numeric_limits::max(); } virtual int getTLMix() const { return std::numeric_limits::max(); } virtual int getTRMix() const { return std::numeric_limits::max(); } - virtual float getPhiBinLo() const { return std::numeric_limits::quiet_NaN(); } - virtual float getPhiBinHi() const { return std::numeric_limits::quiet_NaN(); } - virtual float getTBinLo() const { return std::numeric_limits::quiet_NaN(); } - virtual float getTBinHi() const { return std::numeric_limits::quiet_NaN(); } + virtual char getPhiBinLo() const { return std::numeric_limits::max(); } + virtual char getPhiBinHi() const { return std::numeric_limits::max(); } + virtual char getTBinLo() const { return std::numeric_limits::max(); } + virtual char getTBinHi() const { return std::numeric_limits::max(); } virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } @@ -112,26 +112,26 @@ class TrkrCluster : public PHObject virtual void setDREdge(const char) {}; virtual void setHLEdge(const char) {}; virtual void setHREdge(const char) {}; - virtual void setSLMix(const int) {}; - virtual void setSRMix(const int) {}; - virtual void setTLMix(const int) {}; - virtual void setTRMix(const int) {}; - virtual void setPhiBinLo(const float) {}; - virtual void setPhiBinHi(const float) {}; - virtual void setTBinLo(const float) {}; - virtual void setTBinHi(const float) {}; + virtual void setSLMix(const char) {}; + virtual void setSRMix(const char) {}; + virtual void setTLMix(const char) {}; + virtual void setTRMix(const char) {}; + virtual void setPhiBinLo(const char) {}; + virtual void setPhiBinHi(const char) {}; + virtual void setTBinLo(const char) {}; + virtual void setTBinHi(const char) {}; virtual void setPadPhase(const float) {}; virtual void setTBinPhase(const float) {}; - virtual void setRSize(const float) {}; - virtual void setCenAdc(const unsigned int) {}; + virtual void setRSize(const char) {}; + virtual void setCenAdc(const uint16_t) {}; virtual void setPadCen(const float) {}; virtual void setTBinCen(const float) {}; - virtual void setPadMax(const float) {}; - virtual void setTBinMax(const float) {}; + virtual void setPadMax(const int) {}; + virtual void setTBinMax(const int) {}; virtual void setPhiError(const float) {}; virtual void setZError(const float) {}; - virtual void setPhiSize(const float) {}; - virtual void setZSize(const float) {}; + virtual void setPhiSize(const char) {}; + virtual void setZSize(const char) {}; /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index adbd3d4728..52276126d0 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -85,19 +85,19 @@ class TrkrClusterv6 : public TrkrCluster void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } unsigned int getCenAdc() const override { return m_cenadc; } - void setCenAdc(const uint16_t cenadc) { m_cenadc = cenadc; } + void setCenAdc(const uint16_t cenadc) override { m_cenadc = cenadc; } float getPadCen() const override { return m_padcen; } - void setPadCen(const float padcen) { m_padcen = padcen; } + void setPadCen(const float padcen) override { m_padcen = padcen; } float getTBinCen() const override { return m_tbincen; } - void setTBinCen(const float tbincen) { m_tbincen = tbincen; } + void setTBinCen(const float tbincen) override { m_tbincen = tbincen; } - float getPadMax() const override { return m_padmax; } - void setPadMax(const float padmax) { m_padmax = padmax; } + int getPadMax() const override { return m_padmax; } + void setPadMax(const int padmax) override { m_padmax = padmax; } - float getTBinMax() const override { return m_tbinmax; } - void setTBinMax(const float tbinmax) { m_tbinmax = tbinmax; } + int getTBinMax() const override { return m_tbinmax; } + void setTBinMax(const int tbinmax) override { m_tbinmax = tbinmax; } // // convenience interface @@ -105,20 +105,20 @@ class TrkrClusterv6 : public TrkrCluster float getRPhiError() const override { return m_phierr; } float getZError() const override { return m_zerr; } - void setPhiError(const float phierror) { m_phierr = phierror; } - void setZError(const float zerror) { m_zerr = zerror; } + void setPhiError(const float phierror) override { m_phierr = phierror; } + void setZError(const float zerror) override { m_zerr = zerror; } char getSize() const override { return m_phisize * m_zsize; } // void setSize(const char size) { m_size = size; } float getRSize() const override { return (float) m_rsize; } - void setRSize(const unsigned char rsize) { m_rsize = rsize; } + void setRSize(const char rsize) override { m_rsize = rsize; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(const char phisize) { m_phisize = phisize; } + void setPhiSize(const char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(const char zsize) { m_zsize = zsize; } + void setZSize(const char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } void setOverlap(const char overlap) override { m_overlap = overlap; } @@ -127,58 +127,58 @@ class TrkrClusterv6 : public TrkrCluster void setEdge(const char edge) override { m_edge = edge; } char getSLEdge() const override { return m_sledge; } - void setSLEdge(const char sledge) { m_sledge = sledge; } + void setSLEdge(const char sledge) override { m_sledge = sledge; } char getSREdge() const override { return m_sredge; } - void setSREdge(const char sredge) { m_sredge = sredge; } + void setSREdge(const char sredge) override { m_sredge = sredge; } char getTLEdge() const override { return m_tledge; } - void setTLEdge(const char tledge) { m_tledge = tledge; } + void setTLEdge(const char tledge) override { m_tledge = tledge; } char getTREdge() const override { return m_tredge; } - void setTREdge(const char tredge) { m_tredge = tredge; } + void setTREdge(const char tredge) override { m_tredge = tredge; } char getDLEdge() const override { return m_dledge; } - void setDLEdge(const char dledge) { m_dledge = dledge; } + void setDLEdge(const char dledge) override { m_dledge = dledge; } char getDREdge() const override { return m_dredge; } - void setDREdge(const char dredge) { m_dredge = dredge; } + void setDREdge(const char dredge) override { m_dredge = dredge; } char getHLEdge() const override { return m_hledge; } - void setHLEdge(const char hledge) { m_hledge = hledge; } + void setHLEdge(const char hledge) override { m_hledge = hledge; } char getHREdge() const override { return m_hredge; } - void setHREdge(const char hredge) { m_hredge = hredge; } + void setHREdge(const char hredge) override { m_hredge = hredge; } int getSLMix() const override { return m_slmix; } - void setSLMix(const char slmix) { m_slmix = slmix; } + void setSLMix(const char slmix) override { m_slmix = slmix; } int getSRMix() const override { return m_srmix; } - void setSRMix(const char srmix) { m_srmix = srmix; } + void setSRMix(const char srmix) override { m_srmix = srmix; } int getTLMix() const override { return m_tlmix; } - void setTLMix(const char tlmix) { m_tlmix = tlmix; } + void setTLMix(const char tlmix) override { m_tlmix = tlmix; } int getTRMix() const override { return m_trmix; } - void setTRMix(const char trmix) { m_trmix = trmix; } + void setTRMix(const char trmix) override { m_trmix = trmix; } - float getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(const float phibinlo) { m_phibinlo = phibinlo; } + char getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(const char phibinlo) override { m_phibinlo = phibinlo; } - float getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(const float phibinhi) { m_phibinhi = phibinhi; } + char getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(const char phibinhi) override { m_phibinhi = phibinhi; } char getTBinLo() const override { return m_tbinlo; } - void setTBinLo(const char tbinlo) { m_tbinlo = tbinlo; } + void setTBinLo(const char tbinlo) override { m_tbinlo = tbinlo; } char getTBinHi() const override { return m_tbinhi; } - void setTBinHi(const char tbinhi) { m_tbinhi = tbinhi; } + void setTBinHi(const char tbinhi) override { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } - void setPadPhase(const float padphase) { m_padphase = padphase; } + void setPadPhase(const float padphase) override { m_padphase = padphase; } float getTBinPhase() const override { return m_tbinphase; } - void setTBinPhase(const float tbinphase){ m_tbinphase = tbinphase; } + void setTBinPhase(const float tbinphase) override { m_tbinphase = tbinphase; } private: float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; @@ -193,9 +193,9 @@ class TrkrClusterv6 : public TrkrCluster float m_tbincen{0}; int m_padmax{0}; int m_tbinmax{0}; - unsigned char m_rsize{0}; - unsigned char m_phisize{0}; - unsigned char m_zsize{0}; + char m_rsize{0}; + char m_phisize{0}; + char m_zsize{0}; char m_overlap{0}; char m_edge{0}; char m_sledge{0}; From e23cdf102a4bb381b2760e5d2d68fe3fd4694d01 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 15:17:56 -0400 Subject: [PATCH 746/866] fix rabbit suggestions --- offline/packages/tpc/TpcClusterizer.cc | 1 + offline/packages/trackbase/TrkrCluster.h | 16 +++++++-------- offline/packages/trackbase/TrkrClusterv6.h | 24 +++++++++++----------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index a2ed3c0169..45e3011fcf 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -1850,6 +1850,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.pedestal = pedestal; thread_pair.data.sector = sector; thread_pair.data.side = side; + thread_pair.data.debug = m_debug; thread_pair.data.do_assoc = do_hit_assoc; thread_pair.data.do_wedge_emulation = do_wedge_emulation; thread_pair.data.tGeometry = m_tGeometry; diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 2312df181b..d6cefd9e65 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -96,10 +96,10 @@ class TrkrCluster : public PHObject virtual int getSRMix() const { return std::numeric_limits::max(); } virtual int getTLMix() const { return std::numeric_limits::max(); } virtual int getTRMix() const { return std::numeric_limits::max(); } - virtual char getPhiBinLo() const { return std::numeric_limits::max(); } - virtual char getPhiBinHi() const { return std::numeric_limits::max(); } - virtual char getTBinLo() const { return std::numeric_limits::max(); } - virtual char getTBinHi() const { return std::numeric_limits::max(); } + virtual int getPhiBinLo() const { return std::numeric_limits::max(); } + virtual int getPhiBinHi() const { return std::numeric_limits::max(); } + virtual int getTBinLo() const { return std::numeric_limits::max(); } + virtual int getTBinHi() const { return std::numeric_limits::max(); } virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } @@ -116,10 +116,10 @@ class TrkrCluster : public PHObject virtual void setSRMix(const char) {}; virtual void setTLMix(const char) {}; virtual void setTRMix(const char) {}; - virtual void setPhiBinLo(const char) {}; - virtual void setPhiBinHi(const char) {}; - virtual void setTBinLo(const char) {}; - virtual void setTBinHi(const char) {}; + virtual void setPhiBinLo(const int) {}; + virtual void setPhiBinHi(const int) {}; + virtual void setTBinLo(const int) {}; + virtual void setTBinHi(const int) {}; virtual void setPadPhase(const float) {}; virtual void setTBinPhase(const float) {}; virtual void setRSize(const char) {}; diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 52276126d0..46b77b4dd8 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -162,17 +162,17 @@ class TrkrClusterv6 : public TrkrCluster int getTRMix() const override { return m_trmix; } void setTRMix(const char trmix) override { m_trmix = trmix; } - char getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(const char phibinlo) override { m_phibinlo = phibinlo; } + int getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(const int phibinlo) override { m_phibinlo = phibinlo; } - char getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(const char phibinhi) override { m_phibinhi = phibinhi; } + int getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(const int phibinhi) override { m_phibinhi = phibinhi; } - char getTBinLo() const override { return m_tbinlo; } - void setTBinLo(const char tbinlo) override { m_tbinlo = tbinlo; } + int getTBinLo() const override { return m_tbinlo; } + void setTBinLo(const int tbinlo) override { m_tbinlo = tbinlo; } - char getTBinHi() const override { return m_tbinhi; } - void setTBinHi(const char tbinhi) override { m_tbinhi = tbinhi; } + int getTBinHi() const override { return m_tbinhi; } + void setTBinHi(const int tbinhi) override { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } void setPadPhase(const float padphase) override { m_padphase = padphase; } @@ -210,10 +210,10 @@ class TrkrClusterv6 : public TrkrCluster char m_srmix{0}; char m_tlmix{0}; char m_trmix{0}; - char m_phibinlo{0}; - char m_phibinhi{0}; - char m_tbinlo{0}; - char m_tbinhi{0}; + int m_phibinlo{0}; + int m_phibinhi{0}; + int m_tbinlo{0}; + int m_tbinhi{0}; float m_padphase{0}; float m_tbinphase{0}; From b3c34e8eac52b6d167a252fa228d7c077c58a0a1 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 21:23:35 -0400 Subject: [PATCH 747/866] make base class and derived classes consistent --- offline/packages/trackbase/TrkrCluster.h | 14 ++++++------- offline/packages/trackbase/TrkrClusterv4.cc | 2 +- offline/packages/trackbase/TrkrClusterv4.h | 4 ++-- offline/packages/trackbase/TrkrClusterv5.cc | 2 +- offline/packages/trackbase/TrkrClusterv5.h | 22 ++++++++++----------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index d6cefd9e65..4eaeac407e 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -52,21 +52,21 @@ class TrkrCluster : public PHObject // cluster position // virtual float getLocalX() const { return std::numeric_limits::quiet_NaN(); } - virtual void setLocalX(float) {} + virtual void setLocalX(const float) {} virtual float getLocalY() const { return std::numeric_limits::quiet_NaN(); } - virtual void setLocalY(float) {} + virtual void setLocalY(const float) {} // // cluster info // - virtual void setAdc(unsigned int) {} + virtual void setAdc(const unsigned int) {} virtual unsigned int getAdc() const { return UINT_MAX; } - virtual void setMaxAdc(uint16_t) {} + virtual void setMaxAdc(const uint16_t) {} virtual unsigned int getMaxAdc() const { return UINT_MAX; } virtual char getOverlap() const { return std::numeric_limits::max(); } - virtual void setOverlap(char) {} + virtual void setOverlap(const char) {} virtual char getEdge() const { return std::numeric_limits::max(); } - virtual void setEdge(char) {} + virtual void setEdge(const char) {} virtual void setTime(const float) {} virtual float getTime() const { return std::numeric_limits::quiet_NaN(); } virtual char getSize() const { return std::numeric_limits::max(); } @@ -137,7 +137,7 @@ class TrkrCluster : public PHObject virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual TrkrDefs::subsurfkey getSubSurfKey() const { return TrkrDefs::SUBSURFKEYMAX; } - virtual void setSubSurfKey(TrkrDefs::subsurfkey /*id*/) {} + virtual void setSubSurfKey(const TrkrDefs::subsurfkey /*id*/) {} // Global coordinate functions are deprecated, use local // coordinate functions only diff --git a/offline/packages/trackbase/TrkrClusterv4.cc b/offline/packages/trackbase/TrkrClusterv4.cc index 542c1530cc..8ee11bf797 100644 --- a/offline/packages/trackbase/TrkrClusterv4.cc +++ b/offline/packages/trackbase/TrkrClusterv4.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv4.h b/offline/packages/trackbase/TrkrClusterv4.h index ec0bc4703c..439e3d9aef 100644 --- a/offline/packages/trackbase/TrkrClusterv4.h +++ b/offline/packages/trackbase/TrkrClusterv4.h @@ -160,10 +160,10 @@ class TrkrClusterv4 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } void setOverlap(char overlap) override { m_overlap = overlap; } diff --git a/offline/packages/trackbase/TrkrClusterv5.cc b/offline/packages/trackbase/TrkrClusterv5.cc index 58e08745ad..a0cc7fbe52 100644 --- a/offline/packages/trackbase/TrkrClusterv5.cc +++ b/offline/packages/trackbase/TrkrClusterv5.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index ebb0bae961..ee3ac20755 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -54,12 +54,12 @@ class TrkrClusterv5 : public TrkrCluster float getPosition(int coor) const override { return m_local[coor]; } void setPosition(int coor, float xi) override { m_local[coor] = xi; } float getLocalX() const override { return m_local[0]; } - void setLocalX(float loc0) override { m_local[0] = loc0; } + void setLocalX(const float loc0) override { m_local[0] = loc0; } float getLocalY() const override { return m_local[1]; } - void setLocalY(float loc1) override { m_local[1] = loc1; } + void setLocalY(const float loc1) override { m_local[1] = loc1; } TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } - void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } // // cluster info @@ -69,7 +69,7 @@ class TrkrClusterv5 : public TrkrCluster return m_adc; } - void setAdc(unsigned int adc) override + void setAdc(const unsigned int adc) override { m_adc = adc; } @@ -79,7 +79,7 @@ class TrkrClusterv5 : public TrkrCluster return m_maxadc; } - void setMaxAdc(uint16_t maxadc) override + void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } @@ -96,11 +96,11 @@ class TrkrClusterv5 : public TrkrCluster return m_zerr; } - void setPhiError(float phierror) + void setPhiError(const float phierror) override { m_phierr = phierror; } - void setZError(float zerror) + void setZError(const float zerror) override { m_zerr = zerror; } @@ -156,16 +156,16 @@ class TrkrClusterv5 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(const char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(const char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } - void setOverlap(char overlap) override { m_overlap = overlap; } + void setOverlap(const char overlap) override { m_overlap = overlap; } char getEdge() const override { return m_edge; } - void setEdge(char edge) override { m_edge = edge; } + void setEdge(const char edge) override { m_edge = edge; } // float getPhiSize() const override //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} From 4c39ed8a1a3e5a3804de16d1cf714340611c066e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 22 Jun 2026 21:39:12 -0400 Subject: [PATCH 748/866] resolve some clang-tidy issues --- .../TrackingDiagnostics/TrackResiduals.cc | 20 +++++++++---------- .../TrackingDiagnostics/TrackResiduals.h | 20 +++++++++---------- offline/packages/tpc/TpcClusterizer.cc | 3 ++- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index d123176d70..d8f816fad6 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -1843,16 +1843,16 @@ void TrackResiduals::createBranches() m_clustree->Branch("tbinhi", &m_tbinhi, "m_tbinhi/F"); m_clustree->Branch("padphase", &m_padphase, "m_padphase/F"); m_clustree->Branch("tbinphase", &m_tbinphase, "m_tbinphase/F"); - m_clustree->Branch("overlap", &m_overlap, "m_overlap/I"); - m_clustree->Branch("nedge", &m_nedge, "m_nedge/I"); - m_clustree->Branch("sledge", &m_sledge, "m_sledge/I"); - m_clustree->Branch("sredge", &m_sredge, "m_sredge/I"); - m_clustree->Branch("tledge", &m_tledge, "m_tledge/I"); - m_clustree->Branch("tredge", &m_tredge, "m_tredge/I"); - m_clustree->Branch("dledge", &m_dledge, "m_dledge/I"); - m_clustree->Branch("dredge", &m_dredge, "m_dredge/I"); - m_clustree->Branch("hledge", &m_hledge, "m_hledge/I"); - m_clustree->Branch("hredge", &m_hredge, "m_hredge/I"); + m_clustree->Branch("overlap", &m_overlap, "m_overlap/C"); + m_clustree->Branch("nedge", &m_nedge, "m_nedge/C"); + m_clustree->Branch("sledge", &m_sledge, "m_sledge/C"); + m_clustree->Branch("sredge", &m_sredge, "m_sredge/C"); + m_clustree->Branch("tledge", &m_tledge, "m_tledge/C"); + m_clustree->Branch("tredge", &m_tredge, "m_tredge/C"); + m_clustree->Branch("dledge", &m_dledge, "m_dledge/C"); + m_clustree->Branch("dredge", &m_dredge, "m_dredge/C"); + m_clustree->Branch("hledge", &m_hledge, "m_hledge/C"); + m_clustree->Branch("hredge", &m_hredge, "m_hredge/C"); m_clustree->Branch("slmix", &m_slmix, "m_slmix/I"); m_clustree->Branch("srmix", &m_srmix, "m_srmix/I"); m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/I"); diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 6601fc47c9..6729bfbb04 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -251,16 +251,16 @@ class TrackResiduals : public SubsysReco int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); - int m_overlap = std::numeric_limits::quiet_NaN(); - int m_nedge = std::numeric_limits::quiet_NaN(); - int m_sledge = std::numeric_limits::quiet_NaN(); - int m_sredge = std::numeric_limits::quiet_NaN(); - int m_tledge = std::numeric_limits::quiet_NaN(); - int m_tredge = std::numeric_limits::quiet_NaN(); - int m_dledge = std::numeric_limits::quiet_NaN(); - int m_dredge = std::numeric_limits::quiet_NaN(); - int m_hledge = std::numeric_limits::quiet_NaN(); - int m_hredge = std::numeric_limits::quiet_NaN(); + char m_overlap = std::numeric_limits::quiet_NaN(); + char m_nedge = std::numeric_limits::quiet_NaN(); + char m_sledge = std::numeric_limits::quiet_NaN(); + char m_sredge = std::numeric_limits::quiet_NaN(); + char m_tledge = std::numeric_limits::quiet_NaN(); + char m_tredge = std::numeric_limits::quiet_NaN(); + char m_dledge = std::numeric_limits::quiet_NaN(); + char m_dredge = std::numeric_limits::quiet_NaN(); + char m_hledge = std::numeric_limits::quiet_NaN(); + char m_hredge = std::numeric_limits::quiet_NaN(); int m_slmix = std::numeric_limits::quiet_NaN(); int m_srmix = std::numeric_limits::quiet_NaN(); int m_tlmix = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 45e3011fcf..6548abeb5f 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -85,6 +85,7 @@ namespace unsigned short edge = 0; }; + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) struct ClusterCounters { int overlap = 0; @@ -114,7 +115,7 @@ namespace *this = ClusterCounters{}; } }; - + // NOLINTEND(misc-non-private-member-variables-in-classes) using vec_dVerbose = std::vector>>; // Neural network parameters and modules From c3b466d27756b8c45c5976e27e08265f05c81e05 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 Jun 2026 09:29:20 -0400 Subject: [PATCH 749/866] fix more inconsistencies and make mixs chars and phi and tbin lo/hi ushort --- offline/packages/trackbase/TrkrCluster.h | 24 ++++++++-------- offline/packages/trackbase/TrkrClusterv6.h | 32 +++++++++++----------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 4eaeac407e..2035e19796 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -92,14 +92,14 @@ class TrkrCluster : public PHObject virtual char getDREdge() const { return std::numeric_limits::max(); } virtual char getHLEdge() const { return std::numeric_limits::max(); } virtual char getHREdge() const { return std::numeric_limits::max(); } - virtual int getSLMix() const { return std::numeric_limits::max(); } - virtual int getSRMix() const { return std::numeric_limits::max(); } - virtual int getTLMix() const { return std::numeric_limits::max(); } - virtual int getTRMix() const { return std::numeric_limits::max(); } - virtual int getPhiBinLo() const { return std::numeric_limits::max(); } - virtual int getPhiBinHi() const { return std::numeric_limits::max(); } - virtual int getTBinLo() const { return std::numeric_limits::max(); } - virtual int getTBinHi() const { return std::numeric_limits::max(); } + virtual char getSLMix() const { return std::numeric_limits::max(); } + virtual char getSRMix() const { return std::numeric_limits::max(); } + virtual char getTLMix() const { return std::numeric_limits::max(); } + virtual char getTRMix() const { return std::numeric_limits::max(); } + virtual unsigned short getPhiBinLo() const { return std::numeric_limits::max(); } + virtual unsigned short getPhiBinHi() const { return std::numeric_limits::max(); } + virtual unsigned short getTBinLo() const { return std::numeric_limits::max(); } + virtual unsigned short getTBinHi() const { return std::numeric_limits::max(); } virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } @@ -116,10 +116,10 @@ class TrkrCluster : public PHObject virtual void setSRMix(const char) {}; virtual void setTLMix(const char) {}; virtual void setTRMix(const char) {}; - virtual void setPhiBinLo(const int) {}; - virtual void setPhiBinHi(const int) {}; - virtual void setTBinLo(const int) {}; - virtual void setTBinHi(const int) {}; + virtual void setPhiBinLo(const unsigned short) {}; + virtual void setPhiBinHi(const unsigned short) {}; + virtual void setTBinLo(const unsigned short) {}; + virtual void setTBinHi(const unsigned short) {}; virtual void setPadPhase(const float) {}; virtual void setTBinPhase(const float) {}; virtual void setRSize(const char) {}; diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index 46b77b4dd8..b599fd1d24 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -150,29 +150,29 @@ class TrkrClusterv6 : public TrkrCluster char getHREdge() const override { return m_hredge; } void setHREdge(const char hredge) override { m_hredge = hredge; } - int getSLMix() const override { return m_slmix; } + char getSLMix() const override { return m_slmix; } void setSLMix(const char slmix) override { m_slmix = slmix; } - int getSRMix() const override { return m_srmix; } + char getSRMix() const override { return m_srmix; } void setSRMix(const char srmix) override { m_srmix = srmix; } - int getTLMix() const override { return m_tlmix; } + char getTLMix() const override { return m_tlmix; } void setTLMix(const char tlmix) override { m_tlmix = tlmix; } - int getTRMix() const override { return m_trmix; } + char getTRMix() const override { return m_trmix; } void setTRMix(const char trmix) override { m_trmix = trmix; } - int getPhiBinLo() const override { return m_phibinlo; } - void setPhiBinLo(const int phibinlo) override { m_phibinlo = phibinlo; } + unsigned short getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(const unsigned short phibinlo) override { m_phibinlo = phibinlo; } - int getPhiBinHi() const override { return m_phibinhi; } - void setPhiBinHi(const int phibinhi) override { m_phibinhi = phibinhi; } + unsigned short getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(const unsigned short phibinhi) override { m_phibinhi = phibinhi; } - int getTBinLo() const override { return m_tbinlo; } - void setTBinLo(const int tbinlo) override { m_tbinlo = tbinlo; } + unsigned short getTBinLo() const override { return m_tbinlo; } + void setTBinLo(const unsigned short tbinlo) override { m_tbinlo = tbinlo; } - int getTBinHi() const override { return m_tbinhi; } - void setTBinHi(const int tbinhi) override { m_tbinhi = tbinhi; } + unsigned short getTBinHi() const override { return m_tbinhi; } + void setTBinHi(const unsigned short tbinhi) override { m_tbinhi = tbinhi; } float getPadPhase() const override { return m_padphase; } void setPadPhase(const float padphase) override { m_padphase = padphase; } @@ -210,10 +210,10 @@ class TrkrClusterv6 : public TrkrCluster char m_srmix{0}; char m_tlmix{0}; char m_trmix{0}; - int m_phibinlo{0}; - int m_phibinhi{0}; - int m_tbinlo{0}; - int m_tbinhi{0}; + unsigned short m_phibinlo{0}; + unsigned short m_phibinhi{0}; + unsigned short m_tbinlo{0}; + unsigned short m_tbinhi{0}; float m_padphase{0}; float m_tbinphase{0}; From 33e4134971479781c1bdcc73dea16b0925563b76 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 Jun 2026 09:49:50 -0400 Subject: [PATCH 750/866] change instantiation from 0s to max or quiet nan --- offline/packages/trackbase/TrkrClusterv6.h | 64 +++++++++++----------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h index b599fd1d24..683aeded6e 100644 --- a/offline/packages/trackbase/TrkrClusterv6.h +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -184,38 +184,38 @@ class TrkrClusterv6 : public TrkrCluster float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; //< 2D local position [cm] 2 * 32 64bit - cumul 1*64 TrkrDefs::subsurfkey m_subsurfkey {TrkrDefs::SUBSURFKEYMAX}; //< unique identifier for hitsetkey-surface maps 16 bit - float m_phierr{0}; - float m_zerr{0}; - unsigned short m_adc{0}; //< cluster sum adc 16 - unsigned short m_maxadc{0}; //< cluster max adc 16 - unsigned short m_cenadc{0}; //< cluster centroid adc 16 - float m_padcen{0}; - float m_tbincen{0}; - int m_padmax{0}; - int m_tbinmax{0}; - char m_rsize{0}; - char m_phisize{0}; - char m_zsize{0}; - char m_overlap{0}; - char m_edge{0}; - char m_sledge{0}; - char m_sredge{0}; - char m_tledge{0}; - char m_tredge{0}; - char m_dledge{0}; - char m_dredge{0}; - char m_hledge{0}; - char m_hredge{0}; - char m_slmix{0}; - char m_srmix{0}; - char m_tlmix{0}; - char m_trmix{0}; - unsigned short m_phibinlo{0}; - unsigned short m_phibinhi{0}; - unsigned short m_tbinlo{0}; - unsigned short m_tbinhi{0}; - float m_padphase{0}; - float m_tbinphase{0}; + float m_phierr{std::numeric_limits::quiet_NaN()}; + float m_zerr{std::numeric_limits::quiet_NaN()}; + unsigned short m_adc{std::numeric_limits::max()}; //< cluster sum adc 16 + unsigned short m_maxadc{std::numeric_limits::max()}; //< cluster max adc 16 + unsigned short m_cenadc{std::numeric_limits::max()}; //< cluster centroid adc 16 + float m_padcen{std::numeric_limits::quiet_NaN()}; + float m_tbincen{std::numeric_limits::quiet_NaN()}; + int m_padmax{std::numeric_limits::max()}; + int m_tbinmax{std::numeric_limits::max()}; + char m_rsize{std::numeric_limits::max()}; + char m_phisize{std::numeric_limits::max()}; + char m_zsize{std::numeric_limits::max()}; + char m_overlap{std::numeric_limits::max()}; + char m_edge{std::numeric_limits::max()}; + char m_sledge{std::numeric_limits::max()}; + char m_sredge{std::numeric_limits::max()}; + char m_tledge{std::numeric_limits::max()}; + char m_tredge{std::numeric_limits::max()}; + char m_dledge{std::numeric_limits::max()}; + char m_dredge{std::numeric_limits::max()}; + char m_hledge{std::numeric_limits::max()}; + char m_hredge{std::numeric_limits::max()}; + char m_slmix{std::numeric_limits::max()}; + char m_srmix{std::numeric_limits::max()}; + char m_tlmix{std::numeric_limits::max()}; + char m_trmix{std::numeric_limits::max()}; + unsigned short m_phibinlo{std::numeric_limits::max()}; + unsigned short m_phibinhi{std::numeric_limits::max()}; + unsigned short m_tbinlo{std::numeric_limits::max()}; + unsigned short m_tbinhi{std::numeric_limits::max()}; + float m_padphase{std::numeric_limits::quiet_NaN()}; + float m_tbinphase{std::numeric_limits::quiet_NaN()}; ClassDefOverride(TrkrClusterv6, 1) }; From 8ad4113f79df9d116a96ce8a1e303488547a78dc Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 23 Jun 2026 12:23:08 -0400 Subject: [PATCH 751/866] change to char --- .../TrackingDiagnostics/TrackResiduals.cc | 8 +++--- .../TrackingDiagnostics/TrackResiduals.h | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index d8f816fad6..71a6a0a19d 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -1853,10 +1853,10 @@ void TrackResiduals::createBranches() m_clustree->Branch("dredge", &m_dredge, "m_dredge/C"); m_clustree->Branch("hledge", &m_hledge, "m_hledge/C"); m_clustree->Branch("hredge", &m_hredge, "m_hredge/C"); - m_clustree->Branch("slmix", &m_slmix, "m_slmix/I"); - m_clustree->Branch("srmix", &m_srmix, "m_srmix/I"); - m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/I"); - m_clustree->Branch("trmix", &m_trmix, "m_trmix/I"); + m_clustree->Branch("slmix", &m_slmix, "m_slmix/C"); + m_clustree->Branch("srmix", &m_srmix, "m_srmix/C"); + m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/C"); + m_clustree->Branch("trmix", &m_trmix, "m_trmix/C"); m_clustree->Branch("erphi", &m_scluselx, "m_scluselx/F"); m_clustree->Branch("ez", &m_scluselz, "m_scluselz/F"); m_clustree->Branch("maxadc", &m_clusmaxadc, "m_clusmaxadc/F"); diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 6729bfbb04..2fb8b6f648 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -251,20 +251,20 @@ class TrackResiduals : public SubsysReco int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); - char m_overlap = std::numeric_limits::quiet_NaN(); - char m_nedge = std::numeric_limits::quiet_NaN(); - char m_sledge = std::numeric_limits::quiet_NaN(); - char m_sredge = std::numeric_limits::quiet_NaN(); - char m_tledge = std::numeric_limits::quiet_NaN(); - char m_tredge = std::numeric_limits::quiet_NaN(); - char m_dledge = std::numeric_limits::quiet_NaN(); - char m_dredge = std::numeric_limits::quiet_NaN(); - char m_hledge = std::numeric_limits::quiet_NaN(); - char m_hredge = std::numeric_limits::quiet_NaN(); - int m_slmix = std::numeric_limits::quiet_NaN(); - int m_srmix = std::numeric_limits::quiet_NaN(); - int m_tlmix = std::numeric_limits::quiet_NaN(); - int m_trmix = std::numeric_limits::quiet_NaN(); + char m_overlap = std::numeric_limits::max(); + char m_nedge = std::numeric_limits::max(); + char m_sledge = std::numeric_limits::max(); + char m_sredge = std::numeric_limits::max(); + char m_tledge = std::numeric_limits::max(); + char m_tredge = std::numeric_limits::max(); + char m_dledge = std::numeric_limits::max(); + char m_dredge = std::numeric_limits::max(); + char m_hledge = std::numeric_limits::max(); + char m_hredge = std::numeric_limits::max(); + char m_slmix = std::numeric_limits::max(); + char m_srmix = std::numeric_limits::max(); + char m_tlmix = std::numeric_limits::max(); + char m_trmix = std::numeric_limits::max(); float m_phibinlo = std::numeric_limits::quiet_NaN(); float m_phibinhi = std::numeric_limits::quiet_NaN(); float m_tbinlo = std::numeric_limits::quiet_NaN(); From c0388d0084e12259c59356d9fd6b216b316e6014 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 25 Jun 2026 09:31:39 -0400 Subject: [PATCH 752/866] restores clustering performance --- offline/packages/tpc/TpcClusterizer.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 6548abeb5f..32479b6e5f 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -213,10 +213,10 @@ namespace { const int FitRangeT = (int) my_data.maxHalfSizeT; const int NTBinsMax = (int) my_data.tbins; - // const int FixedWindow = (int) my_data.FixedWindow; + const int FixedWindow = (int) my_data.FixedWindow; tup = 0; tdown = 0; - /* + if (FixedWindow != 0) { tup = FixedWindow; @@ -229,11 +229,11 @@ namespace if ((tbin - tdown) <= 0) { tdown = tbin; - counts.edge++; + counts.nedge++; } return; } - */ + for (int it = 0; it < FitRangeT; it++) { int ct = tbin + it; @@ -320,10 +320,10 @@ namespace { int FitRangePHI = (int) my_data.maxHalfSizePhi; int NPhiBinsMax = (int) my_data.phibins; - // const int FixedWindow = (int) my_data.FixedWindow; + const int FixedWindow = (int) my_data.FixedWindow; phidown = 0; phiup = 0; - /* + if (FixedWindow != 0) { phiup = FixedWindow; @@ -331,16 +331,16 @@ namespace if (phibin + phiup >= NPhiBinsMax) { phiup = NPhiBinsMax - phibin - 1; - edge++; + counts.nedge++; } if (phibin - phidown <= 0) { phidown = phibin; - edge++; + counts.nedge++; } return; } - */ + for (int iphi = 0; iphi < FitRangePHI; iphi++) { int cphi = phibin + iphi; From 81cccb72de6ca28c7b943bb8c909381778112a1c Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Thu, 25 Jun 2026 10:07:27 -0400 Subject: [PATCH 753/866] clang-tidy --- offline/packages/tpccalib/PHTpcResiduals.cc | 2 +- offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc | 2 +- offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index e8e147153e..7d8ec8e095 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -689,7 +689,7 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) for( auto& container:containers ) { - if( !container ) continue; + if( !container ) { continue; } // Fill distortion matrices container->add_to_lhs(index, 0, 0, square(clusR) / erp); diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc index 216b8d9fff..e13c9baffd 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc @@ -60,7 +60,7 @@ int TpcSpaceChargeMatrixContainerv2::get_cell_index(int iphi, int ir, int iz) co //___________________________________________________________ int TpcSpaceChargeMatrixContainerv2::get_entries() const -{ return std::accumulate( m_entries.begin(), m_entries.end(), (int)0); } +{ return std::accumulate( m_entries.begin(), m_entries.end(), 0); } //___________________________________________________________ int TpcSpaceChargeMatrixContainerv2::get_entries(int cell_index) const diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc index 1797e949b5..5fa957ab3e 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc @@ -163,7 +163,9 @@ bool TpcSpaceChargeMatrixInversion::add_from_file(const std::string& shortfilena { std::cout << "TpcSpaceChargeMatrixInversion::add_from_file - could not find object name " << objectname << " in file " << filename << std::endl; return false; - } else if( Verbosity() ) { + } + + if( Verbosity() ) { std::cout << "TpcSpaceChargeMatrixInversion::add_from_file -" << " file: " << filename << " objectname: " << objectname From a9a5359fd0203aa501a4926b1dac6b585f513017 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Thu, 25 Jun 2026 12:00:41 -0400 Subject: [PATCH 754/866] Implemented coderabbit suggestions. TpcClusterMover initialization, add ActsGeom for envelope transform. TpcClusterizer, use envelope coords where appropriate. AlignmentTransformation, redo sskey finding. Use envelope center coords in module tilt section. Add PHG4TpcGeom, add g4detectors to makefile. PHG4TpcEndCapDetector, change rot_x etc from deg to rad. TpcClusterBuilder, add check for adc_sum = 0. --- offline/packages/tpc/TpcClusterMover.cc | 7 +- offline/packages/tpc/TpcClusterizer.cc | 6 +- offline/packages/trackbase/ActsGeometry.cc | 7 +- .../trackbase/AlignmentTransformation.cc | 148 +++++++++++------- .../trackbase/AlignmentTransformation.h | 4 +- offline/packages/trackbase/Makefile.am | 1 + .../trackbase_historic/TrackAnalysisUtils.cc | 4 +- .../packages/trackreco/MakeActsGeometry.cc | 26 +-- offline/packages/trackreco/PHActsTrkFitter.cc | 1 + offline/packages/trackreco/PHCASeeding.cc | 14 ++ .../g4simulation/g4detectors/PHG4TpcGeom.h | 12 +- .../g4detectors/PHG4TpcGeomContainer.h | 2 +- .../g4simulation/g4detectors/PHG4TpcGeomv2.cc | 58 +++++-- .../g4simulation/g4detectors/PHG4TpcGeomv2.h | 4 +- .../g4simulation/g4eval/SvtxTruthEval.cc | 3 + .../g4simulation/g4tpc/PHG4TpcDetector.cc | 4 +- .../g4tpc/PHG4TpcEndCapDetector.cc | 14 +- .../g4tpc/PHG4TpcEndCapSubsystem.cc | 3 +- .../g4simulation/g4tpc/PHG4TpcSubsystem.cc | 2 +- .../g4simulation/g4tpc/TpcClusterBuilder.cc | 6 + 20 files changed, 219 insertions(+), 107 deletions(-) diff --git a/offline/packages/tpc/TpcClusterMover.cc b/offline/packages/tpc/TpcClusterMover.cc index d1f391b9ea..a7663349d5 100644 --- a/offline/packages/tpc/TpcClusterMover.cc +++ b/offline/packages/tpc/TpcClusterMover.cc @@ -49,9 +49,14 @@ void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer* cellgeo, ActsGeo { if (_verbosity > 0) { - std::cout << "TpcClusterMover: Initializing layer radii for Tpc from cell geometry object" << std::endl; + std::cout << "TpcClusterMover: Getting ActsGeometry, and getting layer radii for Tpc from cell geometry object" << std::endl; } + if(!tGeometry || !cellgeo) + { + std::cout << PHWHERE << " Failed to get ActsGeometry or TPC cell geometry, cannot continue - quit!" << std::endl; + exit(1); + } _tGeometry = tGeometry; diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index a9ec66a219..ba62fda0f8 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -764,9 +764,11 @@ namespace double nn_z = training_hits->z + std::clamp(ten_pos[0][1][0].item(), -(double) nd, (double) nd) * training_hits->zstep; double nn_x = radius * std::cos(nn_phi); double nn_y = radius * std::sin(nn_phi); - Acts::Vector3 nn_global(nn_x, nn_y, nn_z); + + Acts::Vector3 nn_env_global(nn_x, nn_y, nn_z); + Acts::Vector3 nn_global = my_data.tGeometry->transformTpcEnvelopeToWorld(nn_env_global); nn_global *= Acts::UnitConstants::cm; - Acts::Vector3 nn_local = surface->localToGlobalTransform(my_data.tGeometry->geometry().geoContext).inverse() * nn_global; + Acts::Vector3 nn_local = surface->localToGlobalTransform(my_data.tGeometry->geometry().geoContext).inverse() * nn_global; nn_local /= Acts::UnitConstants::cm; double nn_t = my_data.m_tdriftmax - std::fabs(nn_z) / my_data.tGeometry->get_drift_velocity(); clus_base->setLocalX(nn_local(0)); diff --git a/offline/packages/trackbase/ActsGeometry.cc b/offline/packages/trackbase/ActsGeometry.cc index bac8fdf558..b57a8f1b79 100644 --- a/offline/packages/trackbase/ActsGeometry.cc +++ b/offline/packages/trackbase/ActsGeometry.cc @@ -187,10 +187,11 @@ Surface ActsGeometry::get_tpc_surface_from_coords( double surf_phi = atan2(surf_center_envelope[1], surf_center_envelope[0]); double surfStepPhi = m_tGeometry.tpcSurfStepPhi; - if ((world_phi > surf_phi - surfStepPhi / 2.0) && (world_phi < surf_phi + surfStepPhi / 2.0)) + const double dphi = std::atan2(std::sin(world_phi - surf_phi), std::cos(world_phi - surf_phi)); + if (std::abs(dphi) < surfStepPhi / 2.0) { - if(surf_center.z() < 0 && side != 0) { continue; } - if(surf_center.z() > 0 && side != 1) { continue; } + if(surf_center_envelope.z() < 0 && side != 0) { continue; } + if(surf_center_envelope.z() > 0 && side != 1) { continue; } surf_index = isurf; subsurfkey = isurf; break; diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 78078b0fbc..8cfaa2bf88 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -21,6 +21,9 @@ #include #include +#include +#include + #include #include #include @@ -194,7 +197,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) Acts::GeometryIdentifier id = surf->geometryId(); - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " Add transform for MVTX with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; std::cout << " final mvtx transform:" << std::endl @@ -223,7 +226,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) transform = newMakeTransform(surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, use_intt_survey_geometry); Acts::GeometryIdentifier id = surf->geometryId(); - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " Add transform for INTT with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; } @@ -263,58 +266,82 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) // std::cout << " *** module hitsetkey " << hitsetkey << " this_hitsetkey " << this_hitsetkey << " this layer " << this_layer << " side " << side << " sector " << sector << std::endl; - // is this correct?????? - int subsurfkey_min = (1 - side) * 144 + (144 - sector * 12) - 12 - 6; - int subsurfkey_max = subsurfkey_min + 12; - for (int subsurfkey = subsurfkey_min; subsurfkey < subsurfkey_max; subsurfkey++) - { - int sskey = subsurfkey; - if (sskey < 0) - { - sskey += 288; - } - - 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 - unsigned int this_region = (this_layer - 7) / 16; // 0-2 - Eigen::Vector3d this_center = surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // mm to cm - 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; - transform = newMakeTransform(surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, false); - Acts::GeometryIdentifier id = surf->geometryId(); - - if (localVerbosity) - { - unsigned int layer = this_layer; - std::cout << " Add transform for TPC with surface GeometryIdentifier " << id << std::endl - << " trkrid " << trkrId << " hitsetkey " << this_hitsetkey << " layer " << layer << " sector " << sector << " side " << side - << " subsurfkey " << subsurfkey << std::endl; - Acts::Vector3 center = surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // convert to cm - std::cout << "Ideal surface center: " << std::endl - << center << std::endl; - std::cout << "transform matrix: " << std::endl - << transform.matrix() << std::endl; - } - transformMap->addTransform(id, transform); - transformMapTransient->addTransform(id, transform); - } + // Each TPC hitsetkey has 12 fake surfaces associated with it + // We want to make a transform for every fake surface in this hitsetkey + // Loop over the sector phi angles for the fake surfaces and get each surface + auto layergeom = m_tpccellgeo->GetLayerCellGeom((int) this_layer); + auto sec_min_phi = layergeom->get_sector_min_phi(); + auto min_phi = sec_min_phi[side][sector]; + auto sec_max_phi = layergeom->get_sector_max_phi(); + auto max_phi = sec_max_phi[side][sector]; + double dphi = (max_phi - min_phi)/12.0; + for(int is = 0; is < 12; ++is) + { + double phis = min_phi + is*dphi + dphi/2.0; + double radius = layergeom->get_radius(); + double zcenter = 51.0; + if(side == 0) + { + zcenter *= -1; + } + Acts::Vector3 env_pos(radius*std::cos(phis), radius * std::sin(phis), zcenter); + Acts::Vector3 world_pos = m_tGeometry->transformTpcEnvelopeToWorld(env_pos); + unsigned short sskey = 999; + Surface this_surf = m_tGeometry->get_tpc_surface_from_coords(this_hitsetkey, world_pos, sskey); + if(sskey == 999) + { + std::cout << PHWHERE << "Failed to get surface for layer " << this_layer << " side " << side << " sector " << sector << " quit!" << std::endl; + } + /* + std::cout << " layer " << this_layer << " radius " << radius << " phis " << phis << " min_phi " << min_phi << " max_phi " << max_phi + << " side " << side << " sector " << sector << " world " << world_pos.x() << " " << world_pos.y() << " " << world_pos.z() + <<" world_radius " << sqrt(world_pos.x() * world_pos.x() + world_pos.y() * world_pos.y()) + << " sskey " << sskey << std::endl; + */ + + 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 + unsigned int this_region = (this_layer - 7) / 16; // 0-2 + Eigen::Vector3d this_center = this_surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // mm to cm + //this_center includes the TPC tilt used in PHG4TpcDetector construction, transform to tpc envelope coords + Acts::Vector3 this_center_envelope = m_tGeometry->transformTpcWorldToEnvelope(this_center); + double this_radius = std::sqrt(this_center_envelope[0] * this_center_envelope[0] + this_center_envelope[1] * this_center_envelope[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; + transform = newMakeTransform(this_surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, false); + Acts::GeometryIdentifier id = this_surf->geometryId(); + + if (localVerbosity) + { + std::cout << " Add transform for TPC with surface GeometryIdentifier " << id + << " trkrid " << trkrId << " hitsetkey " << this_hitsetkey << " layer " << this_layer << " sector " << sector + << " side " << side << std::endl; + if(localVerbosity > 1) + { + Acts::Vector3 center = this_surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // convert to cm + std::cout << "Ideal surface center: " << std::endl + << center << std::endl; + std::cout << "transform matrix: " << std::endl + << transform.matrix() << std::endl; + } + } + transformMap->addTransform(id, transform); + transformMapTransient->addTransform(id, transform); + } } - + break; } - + case TrkrDefs::micromegasId: { if (perturbMM) @@ -332,7 +359,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) transform = newMakeTransform(surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, false); Acts::GeometryIdentifier id = surf->geometryId(); - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " Add transform for Micromegas with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; } @@ -461,7 +488,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, } } - if (localVerbosity) + if (localVerbosity > 1) { Acts::Transform3 actstransform = actsTranslationAffine * actsRotationAffine; @@ -526,7 +553,7 @@ Eigen::Vector3d AlignmentTransformation::getTpcLocalFrameTranslation(float modul dy += -Rdiff * (1 - std::cos(gamma)); dz += 0.0; - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " alpha, beta, gamma " << alpha << " " << beta << " " << gamma << " radius " << moduleRadius << " Rdiff " << Rdiff << " dx, dy dz " << dx << " " << dy << " " << dz << std::endl; @@ -548,6 +575,13 @@ int AlignmentTransformation::getNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } + m_tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + if (!m_tpccellgeo) + { + std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return 0; } @@ -621,7 +655,7 @@ void AlignmentTransformation::generateRandomPerturbations(Eigen::Vector3d angleD std::normal_distribution distribution(0, transformDev(2)); perturbationTranslation(2) = distribution(generator); } - if (localVerbosity) + if (localVerbosity > 1) { std::cout << "randomperturbationAngles" << perturbationAngles << " randomperturbationTrans:" << perturbationTranslation << std::endl; } @@ -629,7 +663,7 @@ void AlignmentTransformation::generateRandomPerturbations(Eigen::Vector3d angleD void AlignmentTransformation::extractModuleCenterPositions() { - if (localVerbosity) + if (localVerbosity > 1) { std::cout << "Extracting TPC module center radii:" << std::endl; } @@ -654,7 +688,7 @@ void AlignmentTransformation::extractModuleCenterPositions() double mod_radius = (surf_rad_in + surf_rad_out) / 2.0; TpcModuleRadii[iside][isector][iregion] = mod_radius; - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " hitsetkey_in " << hitsetkey_in << " lin " << lin << " sector " << isector << " side " << iside << " region " << iregion << std::endl; std::cout << " hitsetkey_out " << hitsetkey_out << " lout " << lout << " sector " << isector << " side " << iside << " region " << iregion << std::endl; diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index e8eb3882d1..8df8aeb2ef 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -11,7 +11,7 @@ #include class PHCompositeNode; - +class PHG4TpcGeomContainer; class ActsGeometry; class AlignmentTransformation @@ -148,6 +148,8 @@ class AlignmentTransformation float TpcModuleRadii[2][12][3] = {}; // module radial center in local coords unsigned int innerLayer[3] = {}; double sectorPhi[2][12] = {}; + + PHG4TpcGeomContainer *m_tpccellgeo = nullptr; }; #endif diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 439d73256e..52c4c3e505 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -295,6 +295,7 @@ libtrack_la_LIBADD = \ -lActsPluginRoot \ -lActsExamplesDetectorTGeo \ -lffamodules \ + -lg4detectors \ -lboost_program_options libtrack_io_la_LIBADD = \ diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 49bbd418bb..4d9282e1f1 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -309,10 +309,10 @@ namespace TrackAnalysisUtils globalWrapper.loadNodes(topNode); globalWrapper.set_suppressCrossing(true); - auto* geometry = findNode::getClass(topNode, "ActsGeometry"); - TpcClusterMover mover; + auto* geometry = findNode::getClass(topNode, "ActsGeometry"); auto* tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + TpcClusterMover mover; mover.initialize_geometry(tpccellgeo, geometry); mover.set_verbosity(0); diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 88319fa938..1c51d07283 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -183,8 +183,8 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) m_CM_halfwidth = layergeom->get_CM_halfwidth(); m_maxSurfZ = m_max_driftlength - 0.0001; // add clearance from physical TPC gas volume length to avoid overlaps - // This transform will eventually be built using the tilt and placement variables that will be in layergeom - // TPC envelope to global transformation + // Make the transform from TPC envelope to global coordinates + // This transform is built using the tilt and placement variables from layergeom double rot_x = layergeom->get_rot_x(); double rot_y = layergeom->get_rot_y(); @@ -513,7 +513,7 @@ void MakeActsGeometry::editTPCGeometry(PHCompositeNode *topNode) return; } - if (Verbosity() > 3) + if (Verbosity() > 0) { std::cout << "EditTPCGeometry - gas volume: "; tpc_gas_north_vol->Print(); @@ -559,7 +559,7 @@ void MakeActsGeometry::addActsTpcSurfaces(TGeoVolume *tpc_gas_vol, tpc_gas_measurement_vol[ilayer]->SetFillColor(kYellow); tpc_gas_measurement_vol[ilayer]->SetVisibility(kTRUE); - if (Verbosity() > 3) + if (Verbosity() > 0) { std::cout << " Made box for layer " << ilayer << " with dx " << m_layerThickness[ilayer] << " dy " @@ -899,7 +899,8 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) TrkrDefs::hitsetkey hitsetkey = getTpcHitSetKeyFromCoords(world_center); unsigned int layer = TrkrDefs::getLayer(hitsetkey); - + // unsigned int sector = TpcDefs::getSectorId(hitsetkey); + // unsigned int side = TpcDefs::getSide(hitsetkey); // If there is already an entry for this hitsetkey, add the surface // to its corresponding vector // std::map>::iterator mapIter; @@ -909,11 +910,13 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) if (mapIter != m_clusterSurfaceMapTpcEdit.end()) { + //std::cout << " Adding surface to map with layer " << layer << " side " << side << " sector " << sector << std::endl; mapIter->second.push_back(surf); } else { // Otherwise make a new map entry + // std::cout << "Starting new surfvec for layer " << layer << " side " << side << " sector " << sector << std::endl; std::vector dumvec; dumvec.push_back(surf); std::pair> tmp = @@ -927,7 +930,7 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) //____________________________________________________________________________________________ void MakeActsGeometry::makeMmMapPairs(TrackingVolumePtr &mmVolume) { - if (Verbosity()) + if (Verbosity()>1) { std::cout << "MakeActsGeometry::makeMmMapPairs - mmVolume: " << mmVolume->volumeName() << std::endl; } @@ -989,7 +992,7 @@ void MakeActsGeometry::makeMmMapPairs(TrackingVolumePtr &mmVolume) continue; } - if (Verbosity()) + if (Verbosity()>1) { std::cout << "MakeActsGeometry::makeMmMapPairs - layer: " << layer << " tileid: " << tileid << std::endl; } @@ -1155,7 +1158,7 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) auto vec3d = surf->center(m_geoCtxt); std::vector world_center = {(vec3d(0) - v_globaldisplacement[0]) / 10.0, (vec3d(1) - v_globaldisplacement[1]) / 10.0, (vec3d(2) - v_globaldisplacement[2]) / 10.0}; // convert from mm to cm double layer_rad = sqrt(pow(world_center[0], 2) + pow(world_center[1], 2)); - if (Verbosity() > 0) + if (Verbosity() > 1) { std::cout << "[DEBUG] MVTX surface center (before misalignment): (x,y,z)=(" << vec3d(0) / 10. << "," << vec3d(1) / 10. << "," << vec3d(2) / 10. << "), layer_rad=" << sqrt(pow(vec3d(0) / 10., 2) + pow(vec3d(1) / 10., 2)) << std::endl; std::cout << "[DEBUG] MVTX surface center: (x,y,z)=(" << world_center[0] << "," << world_center[1] << "," << world_center[2] << "), layer_rad=" << layer_rad << std::endl; @@ -1255,7 +1258,8 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector &world) { - // the input position is assumed to be in tpc envelope coords - i.e. tilt removed + // This is used only in simulations + // so the input position is assumed to be in tpc envelope coords - i.e. tilt removed // Look up TPC surface index values from tpc envelope position of surface center // layer unsigned int layer = 999; @@ -1310,8 +1314,8 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector 3 && layer == 7) - { + if (Verbosity() > 3 && layer == 15) + { std::cout << " layer_rad " << layer_rad << " m_layerRadius[layer] " << m_layerRadius[layer-7] << " found layer " << layer << " side " << side << " world " << world[0] << " " << world[1] << " " << world[2] << " phi_world " << phi_world << " readout_mod " << readout_mod << std::endl; } diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index f038e736e1..2fc97257bb 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1005,6 +1005,7 @@ SurfacePtrVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks { const ActsSourceLink asl = sl.get(); const auto* const surf = m_tGeometry->geometry().tGeometry->findSurface(asl.geometryId()); + // std::cout << "sl: " << surf->geometryId() << std::endl; surfaces.push_back(surf); } diff --git a/offline/packages/trackreco/PHCASeeding.cc b/offline/packages/trackreco/PHCASeeding.cc index abfcc6018a..a589cad71c 100644 --- a/offline/packages/trackreco/PHCASeeding.cc +++ b/offline/packages/trackreco/PHCASeeding.cc @@ -31,6 +31,7 @@ #include #include #include // for getLayer, clu... +#include #include // ROOT includes for debugging @@ -57,6 +58,8 @@ #include // for pair, make_pair #include +#include // for uint8_t, uint16_t, uint32_t + //#define _DEBUG_ #if defined(_DEBUG_) @@ -211,6 +214,17 @@ int PHCASeeding::InitializeGeometry(PHCompositeNode* topNode) Acts::Vector3 PHCASeeding::getGlobalPosition(TrkrDefs::cluskey key, TrkrCluster* cluster) const { + /* + unsigned int layer = TrkrDefs::getLayer(key); + unsigned int side = TpcDefs::getSide(key); + unsigned int sector = TpcDefs::getSectorId(key); + std::cout << " _pp_mode = " << _pp_mode + << " layer " << layer + << " side " << side + << " sector " << sector + << " subsurfkey " << cluster->getSubSurfKey() + << std::endl; + */ return _pp_mode ? m_tGeometry->getGlobalPosition(key, cluster) : m_globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, 0); } diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeom.h b/simulation/g4simulation/g4detectors/PHG4TpcGeom.h index 521cf2fa9c..93376c1b72 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeom.h +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeom.h @@ -195,32 +195,32 @@ class PHG4TpcGeom : public PHObject virtual double get_rot_x() const { PHOOL_VIRTUAL_WARN("get_rot_x()"); - return std::numeric_limits::quiet_NaN(); + return 0.0; } virtual double get_rot_y() const { PHOOL_VIRTUAL_WARN("get_rot_y()"); - return std::numeric_limits::quiet_NaN(); + return 0.0; } virtual double get_rot_z() const { PHOOL_VIRTUAL_WARN("get_rot_z()"); - return std::numeric_limits::quiet_NaN(); + return 0.0; } virtual double get_place_x() const { PHOOL_VIRTUAL_WARN("get_place_x()"); - return std::numeric_limits::quiet_NaN(); + return 0.0; } virtual double get_place_y() const { PHOOL_VIRTUAL_WARN("get_place_y()"); - return std::numeric_limits::quiet_NaN(); + return 0.0; } virtual double get_place_z() const { PHOOL_VIRTUAL_WARN("get_place_z()"); - return std::numeric_limits::quiet_NaN(); + return 0.0; } diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h b/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h index a92b24657a..9bca152e81 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h @@ -9,7 +9,7 @@ #include #include // for make_pair, pair -class PHG4TpcGeom; +#include class PHG4TpcGeomContainer : public PHObject { diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc index 050baf86a9..e500c53117 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc @@ -193,7 +193,7 @@ void PHG4TpcGeomv2::identify(std::ostream& os) const std::pair PHG4TpcGeomv2::get_zbounds(const int ibin) const { - if (ibin < 0 || ibin > nzbins) + if (ibin < 0 || ibin >= nzbins) { std::cout << PHWHERE << " Asking for invalid bin in z: " << ibin << std::endl; exit(1); @@ -207,7 +207,7 @@ PHG4TpcGeomv2::get_zbounds(const int ibin) const std::pair PHG4TpcGeomv2::get_etabounds(const int ibin) const { - if (ibin < 0 || ibin > nzbins) + if (ibin < 0 || ibin >= nzbins) { std::cout << PHWHERE << " Asking for invalid bin in z: " << ibin << std::endl; exit(1); @@ -222,7 +222,7 @@ PHG4TpcGeomv2::get_etabounds(const int ibin) const std::pair PHG4TpcGeomv2::get_phibounds(const int ibin) const { - if (ibin < 0 || ibin > nphibins) + if (ibin < 0 || ibin >= nphibins) { std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; exit(1); @@ -235,7 +235,7 @@ PHG4TpcGeomv2::get_phibounds(const int ibin) const int PHG4TpcGeomv2::get_zbin(const double z) const { - if (z < zmin || z > (zmin + nzbins * zstep)) + if (z < zmin || z >= (zmin + nzbins * zstep)) { // cout << PHWHERE << "Asking for bin for z outside of z range: " << z << endl; return -1; @@ -247,7 +247,7 @@ int PHG4TpcGeomv2::get_zbin(const double z) const int PHG4TpcGeomv2::get_etabin(const double eta) const { - if (eta < zmin || eta > (zmin + nzbins * zstep)) + if (eta < zmin || eta >= (zmin + nzbins * zstep)) { // cout << "Asking for bin for eta outside of eta range: " << eta << endl; return -1; @@ -259,7 +259,7 @@ int PHG4TpcGeomv2::get_etabin(const double eta) const int PHG4TpcGeomv2::get_phibin_new(const double phi) const { double norm_phi = phi; - if (phi < phimin || phi > (phimin + nphibins * phistep)) + if (phi < phimin || phi >= (phimin + nphibins * phistep)) { int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); norm_phi += 2 * M_PI * nwraparound; @@ -270,8 +270,14 @@ int PHG4TpcGeomv2::get_phibin_new(const double phi) const int PHG4TpcGeomv2::find_phibin(const double phi, int side) const { + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + double norm_phi = phi; - if (phi < phimin || phi > (phimin + nphibins * phistep)) + if (phi < phimin || phi >= (phimin + nphibins * phistep)) { int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); norm_phi += 2 * M_PI * nwraparound; @@ -315,8 +321,14 @@ int PHG4TpcGeomv2::find_phibin(const double phi, int side) const float PHG4TpcGeomv2::get_pad_float(const double phi, int side) const { + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + double norm_phi = phi; - if (phi < phimin || phi > (phimin + nphibins * phistep)) + if (phi < phimin || phi >= (phimin + nphibins * phistep)) { int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); norm_phi += 2 * M_PI * nwraparound; @@ -360,7 +372,7 @@ float PHG4TpcGeomv2::get_pad_float(const double phi, int side) const float PHG4TpcGeomv2::get_tbin_float(const double z) const { - if (z < zmin || z > (zmin + nzbins * zstep)) + if (z < zmin || z >= (zmin + nzbins * zstep)) { // cout << PHWHERE << "Asking for bin for z outside of z range: " << z << endl; return -1; @@ -372,6 +384,12 @@ float PHG4TpcGeomv2::get_tbin_float(const double z) const int PHG4TpcGeomv2::get_phibin(const double phi, int side) const { + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + double new_phi = phi; if (phi > M_PI) { @@ -431,7 +449,7 @@ int PHG4TpcGeomv2::get_phibin(const double phi, int side) const double PHG4TpcGeomv2::get_zcenter(const int ibin) const { - if (ibin < 0 || ibin > nzbins) + if (ibin < 0 || ibin >= nzbins) { std::cout << PHWHERE << "Asking for invalid bin in z: " << ibin << std::endl; exit(1); @@ -443,7 +461,7 @@ PHG4TpcGeomv2::get_zcenter(const int ibin) const double PHG4TpcGeomv2::get_etacenter(const int ibin) const { - if (ibin < 0 || ibin > nzbins) + if (ibin < 0 || ibin >= nzbins) { std::cout << PHWHERE << "Asking for invalid bin in eta: " << ibin << std::endl; std::cout << "minbin: 0, maxbin " << nzbins << std::endl; @@ -456,7 +474,7 @@ PHG4TpcGeomv2::get_etacenter(const int ibin) const double PHG4TpcGeomv2::get_phicenter_new(const int ibin) const { - if (ibin < 0 || ibin > nphibins) + if (ibin < 0 || ibin >= nphibins) { std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; exit(1); @@ -470,8 +488,14 @@ PHG4TpcGeomv2::get_phicenter_new(const int ibin) const double PHG4TpcGeomv2::get_phicenter(const int ibin, const int side) const { + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + // double phi_center = -999; - if (ibin < 0 || ibin > nphibins) + if (ibin < 0 || ibin >= nphibins) { std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; exit(1); @@ -493,8 +517,14 @@ PHG4TpcGeomv2::get_phicenter(const int ibin, const int side) const double PHG4TpcGeomv2::get_phi(const float ibin, const int side) const { + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + // double phi_center = -999; - if (ibin < 0 || ibin > nphibins) + if (ibin < 0 || ibin >= nphibins) { std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; exit(1); diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h index 235256b67c..773c6451b2 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h @@ -1,7 +1,7 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -#ifndef G4DETECTORS_PHG4TPCGEOMV1_H -#define G4DETECTORS_PHG4TPCGEOMV1_H +#ifndef G4DETECTORS_PHG4TPCGEOMV2_H +#define G4DETECTORS_PHG4TPCGEOMV2_H #include "PHG4TpcGeom.h" diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.cc b/simulation/g4simulation/g4eval/SvtxTruthEval.cc index f2fcd220a7..25d4cbb125 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.cc @@ -324,6 +324,9 @@ std::map> SvtxTruthEval::all_tru std::vector contributing_hits_energy; std::vector> contributing_hits_entry; std::vector> contributing_hits_exit; + // contributing_hits are the original g4hits in world coords + // contributing_hits_entry, contributing_hits_exit are in envelope coords, for use in G4ClusterSize() + // gx, gy, gz are the cluster position in this layer in world coords to compare with data LayerClusterG4Hits(g4hits, contributing_hits, contributing_hits_energy, contributing_hits_entry, contributing_hits_exit, layer, gx, gy, gz, gt, gedep); if (!(gedep > 0)) { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc index 6f736ccc39..e75a34961c 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc @@ -131,12 +131,12 @@ void PHG4TpcDetector::ConstructMe(G4LogicalVolume *logicWorld) logicWorld, false, false, OverlapCheck()); - /* + G4ThreeVector test_env(10.0, 40.0, 80.0); std::cout << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; G4ThreeVector test_glob = test_env.transform(rot); std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; - */ + // geometry node add_geometry_node(); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc b/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc index 583934798d..3029233299 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc @@ -94,9 +94,9 @@ void PHG4TpcEndCapDetector::ConstructMe(G4LogicalVolume *logicWorld) m_Params->get_double_param("place_y") * cm, m_Params->get_double_param("place_z") * cm); G4RotationMatrix rotm_center; - rotm_center.rotateX(m_Params->get_double_param("rot_x") * deg); - rotm_center.rotateY(m_Params->get_double_param("rot_y") * deg); - rotm_center.rotateZ(m_Params->get_double_param("rot_z") * deg); + rotm_center.rotateX(m_Params->get_double_param("rot_x") * rad); + rotm_center.rotateY(m_Params->get_double_param("rot_y") * rad); + rotm_center.rotateZ(m_Params->get_double_param("rot_z") * rad); G4Transform3D transform_center(rotm_center, g4vec_center); int i = 0; @@ -107,6 +107,14 @@ void PHG4TpcEndCapDetector::ConstructMe(G4LogicalVolume *logicWorld) G4Transform3D transform_side2 = transform_center * rotm_otherside * g4vec_front_z; m_EndCapAssembly->MakeImprint(logicWorld, transform_side2, i++, OverlapCheck()); + + G4ThreeVector test_env(10.0, 40.0, 80.0); + std::cout << "Endcap: rot_x " << m_Params->get_double_param("rot_x")*rad << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + G4ThreeVector test_glob1 = test_env.transform(rotm_center); + std::cout << " test_glob1 " << test_glob1.x() << " " << test_glob1.y() << " " << test_glob1.z() << std::endl; + // G4ThreeVector test_glob2 = test_env(transform_side2); + // std::cout << " test_glob2 " << test_glob2.x() << " " << test_glob2.y() << " " << test_glob2.z() << std::endl; + return; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc index ec00172916..e7aae73319 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc @@ -122,7 +122,8 @@ void PHG4TpcEndCapSubsystem::SetDefaultParameters() set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); - set_default_double_param("rot_x", 0.); + // set_default_double_param("rot_x", 0.); + set_default_double_param("rot_x", -0.004); // TEST! //rad set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc index 8d802c7886..e1770da257 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc @@ -144,7 +144,7 @@ void PHG4TpcSubsystem::SetDefaultParameters() set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); - set_default_double_param("rot_x", 0.); + set_default_double_param("rot_x", -0.004); // TEST! // should default to zero set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); set_default_double_param("tpc_length", 205.21); // 2 * (maxdrift 102.325 + CM halfwidth 0.28) cm diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index 5fb3ee433b..e62f31dce7 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -183,6 +183,12 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) adc_sum += adc; } + + if(adc_sum == 0) + { + continue; + } + if (mClusHitsVerbose) { if (verbosity > 10) From a4e04a8c60d442de1c80a25b0e7b545afd835f73 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 25 Jun 2026 13:48:27 -0400 Subject: [PATCH 755/866] use /B for flag instead of /C --- .../TrackingDiagnostics/TrackResiduals.cc | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 71a6a0a19d..4b613c5dd5 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -1843,20 +1843,20 @@ void TrackResiduals::createBranches() m_clustree->Branch("tbinhi", &m_tbinhi, "m_tbinhi/F"); m_clustree->Branch("padphase", &m_padphase, "m_padphase/F"); m_clustree->Branch("tbinphase", &m_tbinphase, "m_tbinphase/F"); - m_clustree->Branch("overlap", &m_overlap, "m_overlap/C"); - m_clustree->Branch("nedge", &m_nedge, "m_nedge/C"); - m_clustree->Branch("sledge", &m_sledge, "m_sledge/C"); - m_clustree->Branch("sredge", &m_sredge, "m_sredge/C"); - m_clustree->Branch("tledge", &m_tledge, "m_tledge/C"); - m_clustree->Branch("tredge", &m_tredge, "m_tredge/C"); - m_clustree->Branch("dledge", &m_dledge, "m_dledge/C"); - m_clustree->Branch("dredge", &m_dredge, "m_dredge/C"); - m_clustree->Branch("hledge", &m_hledge, "m_hledge/C"); - m_clustree->Branch("hredge", &m_hredge, "m_hredge/C"); - m_clustree->Branch("slmix", &m_slmix, "m_slmix/C"); - m_clustree->Branch("srmix", &m_srmix, "m_srmix/C"); - m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/C"); - m_clustree->Branch("trmix", &m_trmix, "m_trmix/C"); + m_clustree->Branch("overlap", &m_overlap, "m_overlap/B"); + m_clustree->Branch("nedge", &m_nedge, "m_nedge/B"); + m_clustree->Branch("sledge", &m_sledge, "m_sledge/B"); + m_clustree->Branch("sredge", &m_sredge, "m_sredge/B"); + m_clustree->Branch("tledge", &m_tledge, "m_tledge/B"); + m_clustree->Branch("tredge", &m_tredge, "m_tredge/B"); + m_clustree->Branch("dledge", &m_dledge, "m_dledge/B"); + m_clustree->Branch("dredge", &m_dredge, "m_dredge/B"); + m_clustree->Branch("hledge", &m_hledge, "m_hledge/B"); + m_clustree->Branch("hredge", &m_hredge, "m_hredge/B"); + m_clustree->Branch("slmix", &m_slmix, "m_slmix/B"); + m_clustree->Branch("srmix", &m_srmix, "m_srmix/B"); + m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/B"); + m_clustree->Branch("trmix", &m_trmix, "m_trmix/B"); m_clustree->Branch("erphi", &m_scluselx, "m_scluselx/F"); m_clustree->Branch("ez", &m_scluselz, "m_scluselz/F"); m_clustree->Branch("maxadc", &m_clusmaxadc, "m_clusmaxadc/F"); From d97ac63e576ec6cbfe6ab124bfe08adb54fb7b56 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Thu, 25 Jun 2026 14:39:54 -0400 Subject: [PATCH 756/866] Fix screwd up file. Implement coderabbit suggestions. Leave -4 mrad tilt hardcoded for this test only (so no macro changes are needed); --- offline/packages/trackbase/AlignmentTransformation.cc | 5 +++-- simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h | 2 +- simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc | 5 +++-- simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc | 3 ++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 8cfaa2bf88..8f25dab812 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -288,9 +288,10 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) Acts::Vector3 world_pos = m_tGeometry->transformTpcEnvelopeToWorld(env_pos); unsigned short sskey = 999; Surface this_surf = m_tGeometry->get_tpc_surface_from_coords(this_hitsetkey, world_pos, sskey); - if(sskey == 999) + if(sskey == 999 || !this_surf) { std::cout << PHWHERE << "Failed to get surface for layer " << this_layer << " side " << side << " sector " << sector << " quit!" << std::endl; + exit(1); } /* std::cout << " layer " << this_layer << " radius " << radius << " phis " << phis << " min_phi " << min_phi << " max_phi " << max_phi @@ -579,7 +580,7 @@ int AlignmentTransformation::getNodes(PHCompositeNode* topNode) if (!m_tpccellgeo) { std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; + exit(1); } return 0; diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h b/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h index 9bca152e81..a92b24657a 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomContainer.h @@ -9,7 +9,7 @@ #include #include // for make_pair, pair -#include +class PHG4TpcGeom; class PHG4TpcGeomContainer : public PHObject { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc index e7aae73319..b340c82202 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc @@ -116,14 +116,15 @@ void PHG4TpcEndCapSubsystem::SetDefaultParameters() { set_default_int_param("construction_verbosity", 0); // sizes are in cm - // angles are in deg + // angles are in rad // units should be converted to G4 units when used // implement your own here// set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); // set_default_double_param("rot_x", 0.); - set_default_double_param("rot_x", -0.004); // TEST! //rad + // angles are in rad + set_default_double_param("rot_x", -0.004); // TEMPORARY TEST! return to 0.0 set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc index e1770da257..e9f491b951 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc @@ -144,7 +144,8 @@ void PHG4TpcSubsystem::SetDefaultParameters() set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); - set_default_double_param("rot_x", -0.004); // TEST! // should default to zero + // angles are in radians + set_default_double_param("rot_x", -0.004); // TEMPORARY TEST! return to 0.0 set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); set_default_double_param("tpc_length", 205.21); // 2 * (maxdrift 102.325 + CM halfwidth 0.28) cm From 45967b3f9334134cbc4e0458b22f6da5ead1e1e8 Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Thu, 25 Jun 2026 15:48:26 -0400 Subject: [PATCH 757/866] Modify check of surface vectors to use radii instead of layer from volume id. --- offline/packages/trackreco/PHActsTrkFitter.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 2fc97257bb..f355b17aa3 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1014,25 +1014,32 @@ SurfacePtrVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const { + // Do not assume volume id has the correct layer, check the surface radius + for (unsigned int i = 0; i < surfaces.size() - 1; i++) { const auto& surface = surfaces.at(i); const auto thisVolume = surface->geometryId().volume(); - const auto thisLayer = surface->geometryId().layer(); + const Acts::Vector3 this_center = surface->center(m_tGeometry->geometry().getGeoContext()); + double thisRadius = sqrt(this_center.x()*this_center.x()+this_center.y()*this_center.y()); + const auto nextSurface = surfaces.at(i + 1); const auto nextVolume = nextSurface->geometryId().volume(); - const auto nextLayer = nextSurface->geometryId().layer(); + const Acts::Vector3 next_center = surface->center(m_tGeometry->geometry().getGeoContext()); + double nextRadius = sqrt(next_center.x()*next_center.x()+next_center.y()*next_center.y()); + /// Implement a check to ensure surfaces are sorted if (nextVolume == thisVolume) { - if (nextLayer < thisLayer) + // if (nextLayer < thisLayer) + if (nextRadius < thisRadius) { std::cout << "PHActsTrkFitter::checkSurfaceVec - " << "Surface not in order... removing surface" - << surface->geometryId() << std::endl; + << surface->geometryId() << " with radius " << thisRadius << std::endl; surfaces.erase(surfaces.begin() + i); From b8106036519083d59a2d75db170c9287f9d84fb2 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Thu, 25 Jun 2026 18:51:37 -0400 Subject: [PATCH 758/866] Fixed the nedge logic. --- offline/packages/tpc/TpcClusterizer.cc | 32 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index 32479b6e5f..c304e74635 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -224,12 +224,22 @@ namespace if (tbin + tup >= NTBinsMax) { tup = NTBinsMax - tbin - 1; - counts.nedge++; + if (!ttop_edge) + { + counts.nedge++; + counts.tredge = 1; + ttop_edge = true; + } } if ((tbin - tdown) <= 0) { tdown = tbin; - counts.nedge++; + if (!tbottom_edge) + { + counts.nedge++; + counts.tledge = 1; + tbottom_edge = true; + } } return; } @@ -331,12 +341,22 @@ namespace if (phibin + phiup >= NPhiBinsMax) { phiup = NPhiBinsMax - phibin - 1; - counts.nedge++; + if (!phitop_edge) + { + counts.nedge++; + counts.sredge = 1; + phitop_edge = true; + } } if (phibin - phidown <= 0) { phidown = phibin; - counts.nedge++; + if (!phibottom_edge) + { + counts.nedge++; + counts.sledge = 1; + phibottom_edge = true; + } } return; } @@ -913,11 +933,11 @@ namespace if (my_data.debug) { - clus = new TrkrClusterv6; + clus = new TrkrClusterv6; } else { - clus = new TrkrClusterv5; + clus = new TrkrClusterv5; } clus_base = clus; From 275ed89cf99c0a8e7e72e6f67c78f2c4ece864ac Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Thu, 25 Jun 2026 23:46:17 -0400 Subject: [PATCH 759/866] Set default TPC tilt angles all to zero after testing. --- simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc | 3 +-- simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc index b340c82202..4cd13647de 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc @@ -122,9 +122,8 @@ void PHG4TpcEndCapSubsystem::SetDefaultParameters() set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); - // set_default_double_param("rot_x", 0.); // angles are in rad - set_default_double_param("rot_x", -0.004); // TEMPORARY TEST! return to 0.0 + set_default_double_param("rot_x", 0.); set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc index e9f491b951..80a04450f4 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc @@ -145,7 +145,7 @@ void PHG4TpcSubsystem::SetDefaultParameters() set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); // angles are in radians - set_default_double_param("rot_x", -0.004); // TEMPORARY TEST! return to 0.0 + set_default_double_param("rot_x", 0.); set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); set_default_double_param("tpc_length", 205.21); // 2 * (maxdrift 102.325 + CM halfwidth 0.28) cm From 7f164080b94e5c7cb905963b2aeafedd4e8f8247 Mon Sep 17 00:00:00 2001 From: Tom Hemmick Date: Fri, 26 Jun 2026 11:11:24 -0400 Subject: [PATCH 760/866] PHGarfield updates for variable electric field and CDB interface. --- offline/packages/PHGarfield/MergeGasFiles.cc | 398 +++++++++---------- offline/packages/PHGarfield/PHGarfield.cc | 135 +++++-- offline/packages/PHGarfield/PHGarfield.h | 11 +- 3 files changed, 304 insertions(+), 240 deletions(-) diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc index 7bbbc3d3bd..8007c5060d 100644 --- a/offline/packages/PHGarfield/MergeGasFiles.cc +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -1,222 +1,212 @@ -#include - -#include -#include -#include - #include +#include -#include #include #include -#include // for pi +#include +#include +#include #include +#include +#include +#include +#include -int main() -{ - // This is a utility to test whether the process of "merging" files is actually different from a single file. - // It may be of no further use afterthe development was complete. - // TKH 6/2/2026 - int nValid = 10000; - TNtuple *Validity = new TNtuple("Validity", "Validity", "Valid:e:b:a:Vxerr:Vyerr:Vzerr"); - - // New version chooses to NOT write output to a file (which seems broken), - // but to instead just tries to merge the files and validate the copy in memory. - const std::string dir = "gasfiles"; - - auto filename = [&](const int i) - { - return dir + "/PART_" + std::to_string(i) + ".gas"; - }; - Garfield::MediumMagboltz gas; - Garfield::MediumMagboltz gas0; +namespace fs = std::filesystem; +std::string mergedName(const std::string& path, unsigned int eindex); - const std::string first = filename(0); - if (!std::filesystem::exists(first)) - { - std::cerr << "Missing first gas file: " << first << std::endl; - return 1; - } +bool searchAndUnpackDirectory( + const std::string& directoryPath, + std::set& Eindices, + std::set& Bindices, + std::map, std::string>& FileList); - if (!gas.LoadGasFile(first)) - { - std::cerr << "Failed to load " << first << std::endl; - return 1; - } - - // Gas 0 only loads the FIRST file. This will test the memory validity of the merge... - if (!gas0.LoadGasFile(first)) - { - std::cerr << "Failed to load " << first << std::endl; - return 1; - } - - for (int i = 1;; ++i) - { - const std::string file = filename(i); - - if (!std::filesystem::exists(file)) +int main(int argc, char* argv[]) +{ + try { - std::cout << "Stopping at first missing file: " << file << std::endl; - break; + if (argc != 3) + { + std::cerr << "Usage:\n" + << argv[0] + << " path_to_gasfiles name_of_output_file\n"; + return 1; + } + + const std::string path = argv[1]; + const std::string output = path + "/" + argv[2]; + + std::set Eindices; + std::set Bindices; + std::map, std::string> FileList; + + if (!searchAndUnpackDirectory(path, Eindices, Bindices, FileList)) + { + std::cerr << PHWHERE << " Imperfect directory." << std::endl; + return 1; + } + + Garfield::MediumMagboltz gas; + + for (const auto Eindex : Eindices) + { + bool firstB = true; + + for (const auto Bindex : Bindices) + { + const auto it = FileList.find({Eindex, Bindex}); + if (it == FileList.end()) + { + std::cerr << PHWHERE << " Missing file for E=" << Eindex + << " B=" << Bindex << std::endl; + return 1; + } + + const std::string& nextfile = it->second; + + if (firstB) + { + gas.LoadGasFile(nextfile); + firstB = false; + } + else + { + gas.MergeGasFile(nextfile, true); + } + } + + const std::string mergedFile = mergedName(path, Eindex); + + std::cout << "Writing " << mergedFile << std::endl; + gas.WriteGasFile(mergedFile); + + std::vector nE; + std::vector nB; + std::vector nA; + gas.GetFieldGrid(nE, nB, nA); + + std::cout << "Merged Gas File created: "<< mergedFile + << " with Grid Dimensions: " + << nE.size() << " E-fields, " + << nB.size() << " B-fields, " + << nA.size() << " Angles." << std::endl; + } + + bool firstE = true; + + for (const auto Eindex : Eindices) + { + //if (Eindex > 10) {break;} + const std::string mergedFile = mergedName(path, Eindex); + + if (!fs::exists(mergedFile)) + { + std::cerr << PHWHERE << " Missing merged file " << mergedFile << std::endl; + return 1; + } + + if (firstE) + { + gas.LoadGasFile(mergedFile); + firstE = false; + } + else + { + gas.MergeGasFile(mergedFile, true); + } + } + + std::cout << "Writing final file " << output << std::endl; + gas.WriteGasFile(output); + + std::vector nE; + std::vector nB; + std::vector nA; + gas.GetFieldGrid(nE, nB, nA); + + std::cout << "Final Gas File created: "<< output + << " with Grid Dimensions: " + << nE.size() << " E-fields, " + << nB.size() << " B-fields, " + << nA.size() << " Angles." << std::endl; + + return 0; } - std::cout << "Merging " << file << std::endl; - - if (!gas.MergeGasFile(file, true)) + catch (const std::exception& e) { - std::cerr << "Failed to merge " << file << std::endl; + std::cerr << PHWHERE << " Exception: " << e.what() << std::endl; return 1; } - } - - // Don't write out since it crashes? - // gas.WriteGasFile("test.gas"); - - // Now perform the validation test... - double emin = 400; - double emax = 400; - // double ne=1; - - double bmin = 1.15; - double bmax = 1.45; - double nb = 50; - - double amin = 0.0; - double amax = 0.2; - // double na=50; - - // Initialize using the current system time - TRandom3 Randy; - Randy.SetSeed(PHRandomSeed()); // new initialization each run - std::cout << std::endl - << std::endl - << "Valid Calls: " << std::endl; - for (int i = 0; i < nValid; i++) - { - double eMag = Randy.Uniform(emin, emax); - double bMag = Randy.Uniform(bmin, bmin + 0.2 * (bmax - bmin) / nb); // Comes from file0... - double a = Randy.Uniform(amin, amax); - double PHI = Randy.Uniform(0.0, 2.0 * std::numbers::pi); - - double ex = 0; - double ey = 0; - double ez = eMag; - - double bx = bMag * sin(a) * cos(PHI); - double by = bMag * sin(a) * sin(PHI); - double bz = bMag * cos(a); - - double vx; - double vy; - double vz; - - double vx0; - double vy0; - double vz0; - - gas.ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); - gas0.ElectronVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0); - - /* - std::cout << " i:" <Fill(1, sqrt(ex * ex + ey * ey + ez * ez), sqrt(bx * bx + by * by + bz * bz), a, DelVx, DelVy, DelVz); - } - - std::cout << std::endl - << std::endl - << "Invalid Calls: " << std::endl; - for (int i = 0; i < nValid; i++) - { - double eMag = Randy.Uniform(emin, emax); - double bMag = Randy.Uniform(bmin + 5.0 * (bmax - bmin) / nb, bmax); // Comes from beyond file0... - double a = Randy.Uniform(amin, amax); - double PHI = Randy.Uniform(0.0, 2.0 * std::numbers::pi); - - double ex = 0; - double ey = 0; - double ez = eMag; - - double bx = bMag * sin(a) * cos(PHI); - double by = bMag * sin(a) * sin(PHI); - double bz = bMag * cos(a); - - double vx; - double vy; - double vz; - double vx0; - double vy0; - double vz0; - gas.ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); - gas0.ElectronVelocity(ex, ey, ez, bx, by, bz, vx0, vy0, vz0); - /* - std::cout << " i:" <Fill(0, sqrt(ex * ex + ey * ey + ez * ez), sqrt(bx * bx + by * by + bz * bz), a, DelVx, DelVy, DelVz); - } + catch (...) + { + std::cerr << PHWHERE << " Unknown exception." << std::endl; + return 1; + } +} - TFile *output = new TFile("GarfieldValidity.root", "RECREATE"); - Validity->Write(); - output->Close(); +bool searchAndUnpackDirectory(const std::string& directoryPath, std::set &Eindices, std::set &Bindices, std::map, std::string> &FileList) +{ + // Check if the directory exists and is valid + if (!fs::exists(directoryPath) || !fs::is_directory(directoryPath)) + { + std::cerr << "Error: Invalid directory path." << std::endl; + return false; + } + + std::regex filePattern(R"(^E([0-9]{3})_B([0-9]{3})\.gas$)"); + std::smatch matchResults; + + // Iterate through all items in the directory + for (const auto& entry : fs::directory_iterator(directoryPath)) + { + // Only process regular files + if (entry.is_regular_file()) + { + std::string filename = entry.path().filename().string(); + + // Check if the filename matches our target pattern + if (std::regex_match(filename, matchResults, filePattern)) + { + // matchResults[1] contains the string after 'E' + // matchResults[2] contains the string after 'B' + // std::stoul automatically handles leading zeros + unsigned int eValue = std::stoul(matchResults[1].str()); + unsigned int bValue = std::stoul(matchResults[2].str()); + Eindices.insert(eValue); + Bindices.insert(bValue); + FileList[{eValue, bValue}] = entry.path().string(); + } + } + } + + // Validate the results. + if (Eindices.empty()) { return false; } + if (Bindices.empty()) { return false; } + + unsigned int maxE = *Eindices.rbegin(); + unsigned int maxB = *Bindices.rbegin(); + for (unsigned int i=0; i<=maxE; i++) + { + for (unsigned int j=0; j<=maxB; j++) + { + if ( !FileList.contains({i,j}) ) { return false; } + } + } + + std::cout << " *** Gas File List Valid ***" << std::endl; + std::cout << "Electric field indices 0 --> " << maxE << std::endl; + std::cout << "Magnetic field indices 0 --> " << maxB << std::endl; + + return true; +} - return 0; +std::string mergedName(const std::string& path, unsigned int eindex) +{ + std::ostringstream name; + name << path << "/MERGED_E" + << std::setw(3) << std::setfill('0') << eindex + << ".gas"; + return name.str(); } diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc index 157ffb893d..259c8803dc 100644 --- a/offline/packages/PHGarfield/PHGarfield.cc +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -1,5 +1,5 @@ #include "PHGarfield.h" - +#include #include #include @@ -20,12 +20,30 @@ #include #include // for basic_ostream, operat... #include +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; PHGarfield::PHGarfield(const std::string& name) - : SubsysReco(name) + : SubsysReco(name), + //m_defaultGasfile("/sphenix/user/hemmick/gasfiles_20260624/Ar75_CF20_iso5.gas") + m_defaultGasfile("/sphenix/user/hemmick/gasfiles_20260624") { } +PHGarfield::~PHGarfield() +{ + // Housekeeping. + delete m_field; + delete m_cdbTPCMAPttree; + delete m_component; + delete m_gas; +} + int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) { if (Verbosity() > 1) @@ -49,7 +67,16 @@ int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) { GetMagneticFieldTesla(x, y, z, bx, by, bz); }); m_component->SetElectricField([this](double x, double y, double z, double& ex, double& ey, double& ez) { GetElectricFieldVcm(x, y, z, ex, ey, ez); }); - InitializeGas("/direct/phenix+u/workarea/hemmick/code.sphenix/tkh/gas/gasfiles/"); + + // Here we fetch the gas from the CDB + std::string gasfile = m_cdb->getUrl("PHGARFIELD_GAS"); + if (gasfile.empty() || !fs::exists(gasfile)) + { + std::cerr << PHWHERE << " Missing CDB gasfile: " << gasfile << std::endl; + std::cerr << PHWHERE << " Using default gasfile: " << m_defaultGasfile << std::endl; + gasfile = m_defaultGasfile; + } + InitializeGas(gasfile); // Diagnostic during code development... FillRadii(); @@ -113,6 +140,25 @@ void PHGarfield::PrintGarfield(double x, double y, double z) const << std::endl; } +void PHGarfield::PrintGasSummary() const +{ + if (!m_GasFilesLoaded) + { + std::cerr << PHWHERE << "No Gas File(s) have been successfully loaded." << std::endl; + return; + } + + std::vector nE; + std::vector nB; + std::vector nA; + m_gas->GetFieldGrid(nE, nB, nA); + + std::cout << "Gas File Grid Dimensions: " << std::endl; + std::cout << nE.size() << " E-fields ranging from " << nE.front() << " to " << nE.back() << std::endl; + std::cout << nB.size() << " B-fields ranging from " << nB.front() << " to " << nB.back() << std::endl; + std::cout << nA.size() << " Angles ranging from " << nA.front() << " to " << nA.back() << std::endl; +} + void PHGarfield::PrintMaps() const { // Print out a few test points of the Garfield information @@ -195,52 +241,77 @@ void PHGarfield::GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, doub ez_vcm = z_cm > 0 ? -400.0 : 400.0; } -void PHGarfield::InitializeGas(const std::string &dir) +void PHGarfield::InitializeGas(const std::string &name) { // Create and fill the gas object so that we can trace particles through the gas... m_gas = new Garfield::MediumMagboltz(); - auto filename = [&](const int i) - { return dir + "/PART_" + std::to_string(i) + ".gas"; }; - - const std::string first = filename(0); - if (!std::filesystem::exists(first)) + if (!std::filesystem::exists(name)) { - std::cerr << "Missing first gas file: " << first << std::endl; + std::cerr << "Missing gas file or gas directory: " << name << std::endl; return; } - if (!m_gas->LoadGasFile(first)) - { - std::cerr << "Failed to load " << first << std::endl; - return; - } - - for (int i = 1;; ++i) - { - const std::string file = filename(i); - - if (!std::filesystem::exists(file)) + if (fs::is_regular_file(name)) { - std::cout << "Stopping at first missing file: " << file << std::endl; - break; + std::cout << "Loading Garfield gas from file: " << name << std::endl; + if (!m_gas->LoadGasFile(name)) + { + std::cerr << "Failed to load " << name << std::endl; + return; + } + m_GasFilesLoaded = true; } - - std::cout << "Merging " << file << std::endl; - - if (!m_gas->MergeGasFile(file, true)) + else if (fs::is_directory(name)) { - std::cerr << "Failed to merge " << file << std::endl; - return; + std::cout << "Loading Garfield gas from directory: " << name << std::endl; + std::regex filePattern(R"(^MERGED_E([0-9]{3})\.gas$)"); + std::smatch matchResults; + + // Iterate through all items in the directory + // NOTE: Map assures that files are properly ordered when merged... + std::map FilesToMerge; + for (const auto& entry : fs::directory_iterator(name)) + { + // Only process regular files + if (entry.is_regular_file()) + { + std::string filepath = entry.path().string(); + std::string filename = entry.path().filename().string(); + + // Check if the filename matches our target pattern + if (std::regex_match(filename, matchResults, filePattern)) + { + //std::cout << "matchResults: " << matchResults[1].str() << std::endl; + FilesToMerge[std::stoul( matchResults[1].str() )]=filepath; + } + } + } + bool firstE = true; + for (const auto& [key, filepath] : FilesToMerge) + { + if (firstE) + { + m_gas->LoadGasFile(filepath); + firstE = false; + m_GasFilesLoaded = true; + } + else + { + m_gas->MergeGasFile(filepath, true); + m_GasFilesLoaded = true; + } + } } - } + + PrintGasSummary(); } -int PHGarfield::process_event(PHCompositeNode*) +int PHGarfield::process_event(PHCompositeNode* topNode) { // Initial implementation doesn't do anything event-by-event. // Nonetheless, a future user might want do do something here... - + (void) topNode; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h index 47d3118898..ff2d8bb957 100644 --- a/offline/packages/PHGarfield/PHGarfield.h +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -21,15 +21,16 @@ class PHGarfield : public SubsysReco { public: PHGarfield(const std::string &name = "PHGarfield"); - ~PHGarfield() override = default; + ~PHGarfield() override; int InitRun(PHCompositeNode *) override; - int process_event(PHCompositeNode * /*topNode*/) override; + int process_event(PHCompositeNode * topNode) override; bool StopHere(const double x, const double y, const double z, const double zPrevious); void PrintMaps() const; void PrintGarfield(double x, double y, double z) const; + void PrintGasSummary() const; // These are left in public namespace for easy plotting macros... // The user is encouraged to add more routine to fit their analysis goals... @@ -40,14 +41,16 @@ class PHGarfield : public SubsysReco private: void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double &bx_t, double &by_t, double &bz_t) const; // Feeds magnetic field to Garfield void GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double &ex_vcm, double &ey_vcm, double &ez_vcm) const; // Feeds electric field to Garfield - void InitializeGas(const std::string &dir); + void InitializeGas(const std::string &name); // Acepts a file or a directory void FillRadii(); static double bounder(double phi, double phi_min); CDBTTree *m_cdbTPCMAPttree{nullptr}; // Locations of the pads from CDB... - PHField3DCartesian *m_field{nullptr}; // The stanards sPHENIX field holding container. + PHField3DCartesian *m_field{nullptr}; // The standard sPHENIX field holding container. Garfield::ComponentUser *m_component{nullptr}; // This handles the interface of the electric and magnetic fields as handed to Garfield Garfield::MediumMagboltz *m_gas{nullptr}; // This is the pre-tabulated gas properties required by Garfield... + std::string m_defaultGasfile; + bool m_GasFilesLoaded{false}; // These are utilities for a spot check of the overall routine: // std::string calibdir; From 7395a6f37fe07c0b97d915e96e379006becc6a3d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 Jun 2026 13:21:05 -0400 Subject: [PATCH 761/866] fix crash is input file contains no data events --- offline/framework/fun4allraw/SingleTriggeredInput.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index f2d3b34ef1..434aaac876 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -729,6 +729,15 @@ void SingleTriggeredInput::FillPool() if (!FilesDone()) { int eventvectorsize = FillEventVector(); + // this seems a unique signature for raw data files which only contain the + // begin and end run event but no data events. FillEventVector() returns -1 + // and since no events were read the m_PacketEventDeque is empty + if (eventvectorsize < 0 && m_PacketEventDeque.empty()) + { + std::cout << Name() << ": No data Events in input file " << FileName() << std::endl; + AllDone(1); + return; + } if (eventvectorsize != 0) { if (Gl1Input()->m_bclkdiffarray_map.empty()) @@ -1226,7 +1235,6 @@ int SingleTriggeredInput::ReadEvent() size_t size = m_PacketEventDeque.begin()->second.size(); std::cout << "deque size: " << size << std::endl; } - auto* ref_evt = m_PacketEventDeque.begin()->second.front(); RunNumber(ref_evt->getRunNumber()); From 9171015afe8801b42ed748b6c1a9adec3ba42ecd Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 Jun 2026 13:21:39 -0400 Subject: [PATCH 762/866] check for runnumber flag and do not call EndRun if it does not exist --- offline/framework/fun4all/Fun4AllServer.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4all/Fun4AllServer.cc b/offline/framework/fun4all/Fun4AllServer.cc index 9dc68afbb0..41e4dd6924 100644 --- a/offline/framework/fun4all/Fun4AllServer.cc +++ b/offline/framework/fun4all/Fun4AllServer.cc @@ -1105,7 +1105,14 @@ int Fun4AllServer::EndRun(const int runno) int Fun4AllServer::End() { recoConsts *rc = recoConsts::instance(); - EndRun(rc->get_IntFlag("RUNNUMBER")); // call SubsysReco EndRun methods for current run + if (rc->FlagExist("RUNNUMBER")) + { + EndRun(rc->get_IntFlag("RUNNUMBER")); // call SubsysReco EndRun methods for current run + } + else + { + std::cout << PHWHERE << " No RUNNUMBER Int Flag set, not calling EndRun() for registered modules" << std::endl; + } int i = 0; std::vector>::iterator iter; gROOT->cd(default_Tdirectory.c_str()); From 4b72c343e8c72fdc4083ee2ce48aafa04e82db3d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 26 Jun 2026 14:33:05 -0400 Subject: [PATCH 763/866] clang-tidy fixes --- offline/packages/trackbase/ActsGeometry.cc | 4 ++-- offline/packages/trackbase/ActsGeometry.h | 4 ++-- offline/packages/trackbase/AlignmentTransformation.cc | 2 +- offline/packages/trackreco/PHActsTrkFitter.cc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackbase/ActsGeometry.cc b/offline/packages/trackbase/ActsGeometry.cc index b57a8f1b79..2e0f3f75c7 100644 --- a/offline/packages/trackbase/ActsGeometry.cc +++ b/offline/packages/trackbase/ActsGeometry.cc @@ -345,14 +345,14 @@ Acts::Vector2 ActsGeometry::getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* c return local; } - Acts::Vector3 ActsGeometry::transformTpcWorldToEnvelope(Acts::Vector3 world) const + Acts::Vector3 ActsGeometry::transformTpcWorldToEnvelope(const Acts::Vector3& world) const { Acts::Vector3 envelope = m_tpc_world_envelope_transform * world; return envelope; } - Acts::Vector3 ActsGeometry::transformTpcEnvelopeToWorld(Acts::Vector3 envelope) const + Acts::Vector3 ActsGeometry::transformTpcEnvelopeToWorld(const Acts::Vector3& envelope) const { Acts::Vector3 world = m_tpc_world_envelope_transform.inverse() * envelope; diff --git a/offline/packages/trackbase/ActsGeometry.h b/offline/packages/trackbase/ActsGeometry.h index d92bf4af38..be9b4e01cd 100644 --- a/offline/packages/trackbase/ActsGeometry.h +++ b/offline/packages/trackbase/ActsGeometry.h @@ -78,8 +78,8 @@ class ActsGeometry Acts::Transform3 makeAffineTransform(Acts::Vector3 rotation, Acts::Vector3 translation) const; - Acts::Vector3 transformTpcWorldToEnvelope(Acts::Vector3 vin) const ; - Acts::Vector3 transformTpcEnvelopeToWorld(Acts::Vector3 vin) const ; + Acts::Vector3 transformTpcWorldToEnvelope(const Acts::Vector3& world) const ; + Acts::Vector3 transformTpcEnvelopeToWorld(const Acts::Vector3& envelope) const ; Acts::Vector2 getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* cluster) const; Acts::Vector2 getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* cluster, short int crossing) const; diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 8f25dab812..0e9556866e 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -269,7 +269,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) // Each TPC hitsetkey has 12 fake surfaces associated with it // We want to make a transform for every fake surface in this hitsetkey // Loop over the sector phi angles for the fake surfaces and get each surface - auto layergeom = m_tpccellgeo->GetLayerCellGeom((int) this_layer); + auto* layergeom = m_tpccellgeo->GetLayerCellGeom((int) this_layer); auto sec_min_phi = layergeom->get_sector_min_phi(); auto min_phi = sec_min_phi[side][sector]; auto sec_max_phi = layergeom->get_sector_max_phi(); diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index f355b17aa3..4738725af7 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1024,7 +1024,7 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const const Acts::Vector3 this_center = surface->center(m_tGeometry->geometry().getGeoContext()); double thisRadius = sqrt(this_center.x()*this_center.x()+this_center.y()*this_center.y()); - const auto nextSurface = surfaces.at(i + 1); + const auto* nextSurface = surfaces.at(i + 1); const auto nextVolume = nextSurface->geometryId().volume(); const Acts::Vector3 next_center = surface->center(m_tGeometry->geometry().getGeoContext()); From 7c2cf3216d31715150d8ef890ba97669b88f8a79 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 Jun 2026 17:53:23 -0400 Subject: [PATCH 764/866] remove dep on libboost_filesystem.so --- offline/framework/fun4all/Makefile.am | 1 - simulation/g4simulation/g4main/Makefile.am | 1 - 2 files changed, 2 deletions(-) diff --git a/offline/framework/fun4all/Makefile.am b/offline/framework/fun4all/Makefile.am index 8f9d9e2019..30ca180fcb 100644 --- a/offline/framework/fun4all/Makefile.am +++ b/offline/framework/fun4all/Makefile.am @@ -66,7 +66,6 @@ libfun4all_la_SOURCES = \ libfun4all_la_LIBADD = \ libSubsysReco.la \ libTDirectoryHelper.la \ - -lboost_filesystem \ -lFROG \ -lffaobjects \ -lphool \ diff --git a/simulation/g4simulation/g4main/Makefile.am b/simulation/g4simulation/g4main/Makefile.am index bff8a37125..c7412330f8 100644 --- a/simulation/g4simulation/g4main/Makefile.am +++ b/simulation/g4simulation/g4main/Makefile.am @@ -36,7 +36,6 @@ libg4testbench_la_LDFLAGS = \ libg4testbench_la_LIBADD = \ libphg4hit.la \ - -lboost_filesystem \ -lffamodules \ -lfun4all \ -lg4decayer \ From 7437470ece72ad4caae8b6516d954369340e70bd Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 Jun 2026 19:07:11 -0400 Subject: [PATCH 765/866] clear fitter cache to get rid of possible leaks --- offline/packages/mbd/MbdSig.cc | 4 ++++ offline/packages/mbd/MbdSig.h | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index 65de1006fc..8c65012756 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -7,12 +7,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -140,6 +142,8 @@ MbdSig::~MbdSig() { _pileupfile->close(); } + // ROOT keeps the current fitter as a process-wide cache after Fit(). + TVirtualFitter::SetFitter(nullptr, 0); delete hRawPulse; delete hSubPulse; delete gRawPulse; diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index 69d5ca7bfd..a00607ba03 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -3,13 +3,16 @@ #include "MbdRunningStats.h" -#include +#include #include +#include #include class TTree; +class TF1; class TGraphErrors; +class TH1; class TH2; class MbdCalib; From dcde38478d4bf977cd43cea963b961e5dcb28396 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 26 Jun 2026 19:07:45 -0400 Subject: [PATCH 766/866] fix memory leak in CaloTowerBuilder --- offline/packages/CaloReco/CaloTowerBuilder.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 2d0f31a017..9d439e4c24 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -13,9 +13,12 @@ #include #include +#include // for CDBTTree + +#include + #include #include // for SubsysReco -#include #include #include // for PHIODataNode @@ -23,10 +26,7 @@ #include // for PHNodeIterator #include // for PHObject #include - -#include // for CDBTTree - -#include +#include #include #include @@ -58,6 +58,7 @@ CaloTowerBuilder::~CaloTowerBuilder() { delete cdbttree; delete cdbttree_tbt_zs; + delete cdbttree_sepd_map; delete WaveformProcessing; } From 0fa4abb137678f309e43673773ce0943f5284b66 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Sat, 27 Jun 2026 14:43:06 -0400 Subject: [PATCH 767/866] Remove InitRun from StreamingBcoReco --- offline/packages/bcolumicount/StreamingBcoReco.cc | 14 -------------- offline/packages/bcolumicount/StreamingBcoReco.h | 1 - 2 files changed, 15 deletions(-) diff --git a/offline/packages/bcolumicount/StreamingBcoReco.cc b/offline/packages/bcolumicount/StreamingBcoReco.cc index 6d37a1ccca..262750fcd5 100644 --- a/offline/packages/bcolumicount/StreamingBcoReco.cc +++ b/offline/packages/bcolumicount/StreamingBcoReco.cc @@ -57,20 +57,6 @@ int StreamingBcoReco::Init(PHCompositeNode *topNode) return iret; } -// Do we even need to include this now that the lumi calculatin has been separated? Or should I remove `InitRun` entirely? -int StreamingBcoReco::InitRun(PHCompositeNode * topNode) -{ - PHNodeIterator iter(topNode); - PHCompositeNode *runNode; - runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); - if (!runNode) - { - std::cout << PHWHERE << " Run Node is missing doing nothing" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - return Fun4AllReturnCodes::EVENT_OK; -} - int StreamingBcoReco::CreateNodeTree(PHCompositeNode *topNode) { PHNodeIterator iter(topNode); diff --git a/offline/packages/bcolumicount/StreamingBcoReco.h b/offline/packages/bcolumicount/StreamingBcoReco.h index 0e3ef015c7..b5ff71d6e7 100644 --- a/offline/packages/bcolumicount/StreamingBcoReco.h +++ b/offline/packages/bcolumicount/StreamingBcoReco.h @@ -17,7 +17,6 @@ class StreamingBcoReco : public SubsysReco ~StreamingBcoReco() override = default; int Init(PHCompositeNode *topNode) override; - int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; virtual int get_evtno() const { return m_evtno; } From 807e1cd7807d45508bab079a9ec1c9a95b75ded1 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Mon, 29 Jun 2026 05:34:36 -0400 Subject: [PATCH 768/866] Add functions for the inclusive correction for the INTT carry-over hit issue in streaming --- .../Fun4AllStreamingInputManager.cc | 155 ++++++++++++++++++ .../fun4allraw/Fun4AllStreamingInputManager.h | 25 +++ .../fun4allraw/SingleInttPoolInput.cc | 2 +- 3 files changed, 181 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index dd5a777309..65eeef318e 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -650,6 +650,28 @@ int Fun4AllStreamingInputManager::FillIntt() return iret; } + if (m_Intt_print_count == 0) + { + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), Post first FillInttPool(), m_RefBCO: "<(m_topNode, "INTTRAWHIT"); @@ -710,6 +732,14 @@ int Fun4AllStreamingInputManager::FillIntt() } } + if (Verbosity() > 2 && m_Intt_print_count < 10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), Post GL1BCO matching, m_RefBCO (40-bit GL1BCO): "<Fill(refbcobitshift); } + if (m_InttHitDuplication){ + m_InttRawHitCount_FEE.clear(); + + for (auto& [bco, hitinfo] : m_InttRawHitMap) + { + if (bco > select_crossings) + { + break; + } + + for (auto *intthititer : hitinfo.InttRawHitVector) + { + uint64_t bco_full = intthititer->get_bco(); + int FPHXbco = intthititer->get_FPHX_BCO(); + int server = intthititer->get_packetid(); // note : the felix server ID + int felix_ch = intthititer->get_fee(); // note : the felix channel ID 0 - 13 + + std::string hit_string = Form("%ld_%d_%d_%d",bco_full,FPHXbco,server,felix_ch); + + // note: "BCOFULL_FPHXBCO_FELIX_FEE" + if (m_InttRawHitCount_FEE.find(hit_string.c_str()) == m_InttRawHitCount_FEE.end()){ + m_InttRawHitCount_FEE[hit_string.c_str()] = 1; + } + else { + m_InttRawHitCount_FEE[hit_string.c_str()] += 1; + } + } + } + + if (Verbosity() > 2 && m_Intt_print_count < 10){ + for (auto &pair : m_InttRawHitCount_FEE){ + std::cout<<"m_InttRawHitCount_FEE key: "< select_crossings) @@ -792,9 +860,96 @@ int Fun4AllStreamingInputManager::FillIntt() << intthititer->get_bco() << std::dec << std::endl; // intthititer->identify(); } + + int FPHXbco = intthititer->get_FPHX_BCO(); + if (m_IsRejectInttNoiseCrossings && m_IsInttStreaming && (FPHXbco < m_InttStreamingSignalCrossing.first || FPHXbco > m_InttStreamingSignalCrossing.second) ){ + + if (Verbosity() > 10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), hits with FPHX_BCO: "<AddHit(intthititer); } } + + if (m_InttHitDuplication){ + for (auto pair : m_InttRawHitCount_FEE){ + + uint64_t ThisStrobe_HL_bco_full; + int ThisStrobe_HL_FPHXBCO; + int ThisStrobe_HL_server; + int ThisStrobe_HL_felix_ch; + + sscanf( + pair.first.c_str(), + "%ld_%d_%d_%d", + &ThisStrobe_HL_bco_full, + &ThisStrobe_HL_FPHXBCO, + &ThisStrobe_HL_server, + &ThisStrobe_HL_felix_ch + ); + + int ThisStrobe_HL_count_perFPHXBCO = pair.second; + + if (m_IsRejectInttNoiseCrossings && m_IsInttStreaming && (ThisStrobe_HL_FPHXBCO < m_InttStreamingSignalCrossing.first || ThisStrobe_HL_FPHXBCO > m_InttStreamingSignalCrossing.second) ){ + + if (Verbosity() > 10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), Doing hit duplication, half-ladder (BCOFULL_FPHXBCO_FELIXID_FELIXChannel): "<10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), don't see the future strobe, GL1_BCO: "<second.InttRawHitVector) + { + int server = source_hit->get_packetid(); // note : the felix server ID + int felix_ch = source_hit->get_fee(); // note : the felix channel ID 0 - 13 + int FPHXbco = source_hit->get_FPHX_BCO(); + uint64_t bco_full = source_hit->get_bco(); + + if (bco_full != future_strobe_bco_full){continue;} + if (server != ThisStrobe_HL_server){continue;} + if (felix_ch != ThisStrobe_HL_felix_ch){continue;} + + if ( + FPHXbco == ThisStrobe_HL_FPHXBCO || + (m_IsDuplicateInttFPHXBCOResetHit && std::find(m_InttResetFphxBcoVec.begin(),m_InttResetFphxBcoVec.end(), FPHXbco) != m_InttResetFphxBcoVec.end()) + ){ + auto *copied_hit = inttcont->AddHit(source_hit); + copied_hit->set_bco(ThisStrobe_HL_bco_full); + copied_hit->set_FPHX_BCO(ThisStrobe_HL_FPHXBCO); + } + } + + } + + } + } + return 0; } int Fun4AllStreamingInputManager::FillMvtx() diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h index e51a59c549..c658665757 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h @@ -10,6 +10,7 @@ #include #include #include +#include class SingleStreamingInput; class Gl1Packet; @@ -69,6 +70,16 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager void runMvtxTriggered(bool b = true) { m_mvtx_is_triggered = b; } + // configuration for INTT hit carry-over issue mitigation (hit duplication) + void EnableInttHitDuplication(bool b = true) { m_InttHitDuplication = b; } + void InttHitCarryOverShiftMaxMultiple(const int i) { m_InttHitCarryOverShiftMaxMultiple = i; } + void SetIsRejectInttNoiseCrossings(bool b = true) {m_IsRejectInttNoiseCrossings = b;} + void SetIsInttStreaming(bool b = true) {m_IsInttStreaming = b;} + void SetIsDuplicateInttFPHXBCOResetHit(bool b = true) {m_IsDuplicateInttFPHXBCOResetHit = b;} + void SetInttResetFphxBcoVec(std::vector input_vec) {m_InttResetFphxBcoVec = input_vec;} + void SetInttStreamingSignalCrossing(std::pair input_pair) {m_InttStreamingSignalCrossing = input_pair;} + + private: struct MvtxRawHitInfo { @@ -159,6 +170,20 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager TH1 *h_taggedAllFees_intt[8]{nullptr}; TH1 *h_gl1taggedfee_intt[8][14]{{nullptr}}; TH2 *h_bcodiff_intt[8]{nullptr}; + + // for INTT hit carry-over issue mitigation (hit duplication) + bool m_InttHitDuplication{false}; // default to false; Should be set to true when running streaming data + const unsigned int m_InttHitCarryOverShift{120}; // 120 BCOs as the default shift. Fixed value + int m_InttHitCarryOverShiftMaxMultiple{4}; // the max multiple of the shift. For a max multiple of M, duplicate hits from N + [1..M] * shift BCOs to N + bool m_IsRejectInttNoiseCrossings{false}; // not allow hits in the abort-gap crossings being saved to the INTTRawHit container + bool m_IsInttStreaming{true}; // is INTT in the streaming readout mode + bool m_IsDuplicateInttFPHXBCOResetHit{true}; // Allow duplicating hits with FPHXBCO in the range given by std::vectorm_InttResetFphxBcoVec + + std::pair m_InttStreamingSignalCrossing{6,116}; + std::map m_InttRawHitCount_FEE; + int m_Intt_print_count{0}; + std::vector m_InttResetFphxBcoVec{0,1,2,3,4,5}; + }; #endif /* FUN4ALL_FUN4ALLSTREAMINGINPUTMANAGER_H */ diff --git a/offline/framework/fun4allraw/SingleInttPoolInput.cc b/offline/framework/fun4allraw/SingleInttPoolInput.cc index 7bca9bc8b6..fd8effd719 100644 --- a/offline/framework/fun4allraw/SingleInttPoolInput.cc +++ b/offline/framework/fun4allraw/SingleInttPoolInput.cc @@ -466,7 +466,7 @@ bool SingleInttPoolInput::GetSomeMoreEvents(const uint64_t ibclk) std::set toerase; for (auto bcliter : m_FEEBclkMap) { - if (bcliter.second <= localbclk) + if (bcliter.second <= localbclk + 120 * 40) { uint64_t highest_bclk = m_InttRawHitMap.rbegin()->first; if ((highest_bclk - m_InttRawHitMap.begin()->first) < MaxBclkDiff()) From 88b9a6cc737f61bd4a79317950f94b3f0e0898ab Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Mon, 29 Jun 2026 13:05:39 -0400 Subject: [PATCH 769/866] added method to dump mbd calibs to disk --- offline/packages/mbd/MbdCalib.cc | 39 ++++++++++++++++++++++++++++++++ offline/packages/mbd/MbdCalib.h | 4 +++- offline/packages/mbd/MbdReco.h | 2 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 30fab1812a..3338e6e3f5 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -973,6 +973,12 @@ int MbdCalib::Download_Shapes(const std::string& dbase_location) return 1; } +void MbdCalib::get_tcorr_range(const int ifeech, int& min, int& max, int& step) +{ + min = _tcorr_minrange[ifeech]; + max = _tcorr_maxrange[ifeech]; + step = (_tcorr_maxrange[ifeech] - _tcorr_minrange[ifeech]) / (_tcorr_npts[ifeech]-1); +} int MbdCalib::Download_TimeCorr(const std::string& dbase_location) { @@ -2426,10 +2432,43 @@ int MbdCalib::Write_Thresholds(const std::string& dbfile) #ifndef ONLINE int MbdCalib::Write_CDB_All() { + Write_CDB_Shapes("mbd_shape.root"); + Write_CDB_TimeCorr("mbd_t0orr.root"); + Write_CDB_SlewCorr("mbd_slewcorr.root"); + Write_CDB_Pileup("mbd_pileup.root"); + Write_CDB_SampMax("mbd_sampmax.root"); + Write_CDB_Ped("mbd_ped.root"); + Write_CDB_Status("mbd_status.root"); + Write_CDB_TTT0("mbd_tt_t0.root"); + Write_CDB_TQT0("mbd_tq_t0.root"); + Write_CDB_T0Corr("mbd_t0corr.root"); + Write_CDB_Gains("mbd_qfit.root"); + Write_CDB_TimeRMS("mbd_trms.root"); + Write_CDB_Thresholds("mbd_thresh.root"); + return 1; } #endif +int MbdCalib::Write_All() +{ + //Write_Shapes("mbd_shape.calib"); + Write_TimeCorr("mbd_t0corr.calib"); + Write_SlewCorr("mbd_slewcorr.calib"); + Write_Pileup("mbd_pileup.calib"); + Write_SampMax("mbd_sampmax.calib"); + Write_Ped("mbd_ped.calib"); + Write_Status("mbd_status.calib"); + Write_TTT0("mbd_tt_t0.calib"); + Write_TQT0("mbd_tq_t0.calib"); + Write_T0Corr("mbd_t0corr.calib"); + Write_Gains("mbd_qfit.calib"); + //Write_TimeRMS("mbd_trms.calib"); + //Write_Thresholds("mbd_thresh.calib"); + + return 1; +} + // dz is what we need to move the MBD z by // dt is what we change the MBD t0 by void MbdCalib::Update_TQT0(const float dz, const float dt) diff --git a/offline/packages/mbd/MbdCalib.h b/offline/packages/mbd/MbdCalib.h index 3d55e42bc9..53b8a6f187 100644 --- a/offline/packages/mbd/MbdCalib.h +++ b/offline/packages/mbd/MbdCalib.h @@ -71,6 +71,7 @@ class MbdCalib return std::numeric_limits::quiet_NaN(); } + void get_tcorr_range(const int ifeech, int& min, int& max, int& step); float get_tcorr(const int ifeech, const int tdc) const { if (tdc<0) @@ -160,7 +161,7 @@ class MbdCalib int Write_CDB_Gains(const std::string& dbfile); int Write_CDB_Pileup(const std::string& dbfile); int Write_CDB_Thresholds(const std::string& dbfile); - static int Write_CDB_All(); + int Write_CDB_All(); #endif int Write_SampMax(const std::string& dbfile); @@ -174,6 +175,7 @@ class MbdCalib int Write_Gains(const std::string& dbfile); int Write_Pileup(const std::string& dbfile); int Write_Thresholds(const std::string& dbfile); + int Write_All(); void Reset_TQT0(); void Reset_TTT0(); diff --git a/offline/packages/mbd/MbdReco.h b/offline/packages/mbd/MbdReco.h index 13a635d602..d824a81930 100644 --- a/offline/packages/mbd/MbdReco.h +++ b/offline/packages/mbd/MbdReco.h @@ -36,7 +36,7 @@ class MbdReco : public SubsysReco void DoOnlyFits() { _fitsonly = 1; } void DoFitEval(const int s) { _fiteval = s; } - void SetCalPass(const int calpass) { _calpass = calpass; } + void SetCalPass(const int calpass) { _calpass = calpass; if (calpass==1) DoOnlyFits(); } void SetProcChargeCh(const bool s) { _always_process_charge = s; } void SetMbdTrigOnly(const int m) { _mbdonly = m; } From f9e25352217d314424667446dc19fbb757aaad02 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Mon, 29 Jun 2026 15:43:12 -0400 Subject: [PATCH 770/866] fixed rabbit complaints --- offline/packages/mbd/MbdCalib.cc | 132 ++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 29 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 3338e6e3f5..22a8ee1575 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -975,9 +975,16 @@ int MbdCalib::Download_Shapes(const std::string& dbase_location) void MbdCalib::get_tcorr_range(const int ifeech, int& min, int& max, int& step) { - min = _tcorr_minrange[ifeech]; - max = _tcorr_maxrange[ifeech]; - step = (_tcorr_maxrange[ifeech] - _tcorr_minrange[ifeech]) / (_tcorr_npts[ifeech]-1); + min = static_cast( _tcorr_minrange[ifeech] ); + max = static_cast( _tcorr_maxrange[ifeech] ); + if ( _tcorr_npts[ifeech] > 1 ) + { + step = (_tcorr_maxrange[ifeech] - _tcorr_minrange[ifeech]) / (_tcorr_npts[ifeech]-1); + } + else + { + step = 0; + } } int MbdCalib::Download_TimeCorr(const std::string& dbase_location) @@ -2432,41 +2439,108 @@ int MbdCalib::Write_Thresholds(const std::string& dbfile) #ifndef ONLINE int MbdCalib::Write_CDB_All() { - Write_CDB_Shapes("mbd_shape.root"); - Write_CDB_TimeCorr("mbd_t0orr.root"); - Write_CDB_SlewCorr("mbd_slewcorr.root"); - Write_CDB_Pileup("mbd_pileup.root"); - Write_CDB_SampMax("mbd_sampmax.root"); - Write_CDB_Ped("mbd_ped.root"); - Write_CDB_Status("mbd_status.root"); - Write_CDB_TTT0("mbd_tt_t0.root"); - Write_CDB_TQT0("mbd_tq_t0.root"); - Write_CDB_T0Corr("mbd_t0corr.root"); - Write_CDB_Gains("mbd_qfit.root"); - Write_CDB_TimeRMS("mbd_trms.root"); - Write_CDB_Thresholds("mbd_thresh.root"); + if ( Write_CDB_Shapes("mbd_shape.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_TimeCorr("mbd_timecorr.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_SlewCorr("mbd_slewcorr.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Pileup("mbd_pileup.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_SampMax("mbd_sampmax.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Ped("mbd_ped.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Status("mbd_status.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_TTT0("mbd_tt_t0.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_TQT0("mbd_tq_t0.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_T0Corr("mbd_t0corr.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Gains("mbd_qfit.root") != 1 ) + { + status = 0; + } + //Write_CDB_TimeRMS("mbd_trms.root"); + //Write_CDB_Thresholds("mbd_thresh.root"); - return 1; + return status; } #endif int MbdCalib::Write_All() { - //Write_Shapes("mbd_shape.calib"); - Write_TimeCorr("mbd_t0corr.calib"); - Write_SlewCorr("mbd_slewcorr.calib"); - Write_Pileup("mbd_pileup.calib"); - Write_SampMax("mbd_sampmax.calib"); - Write_Ped("mbd_ped.calib"); - Write_Status("mbd_status.calib"); - Write_TTT0("mbd_tt_t0.calib"); - Write_TQT0("mbd_tq_t0.calib"); - Write_T0Corr("mbd_t0corr.calib"); - Write_Gains("mbd_qfit.calib"); + int status = 1; + if ( Write_Shapes("mbd_shape.calib") != 1 ) + { + status = 0; + } + if ( Write_TimeCorr("mbd_timecorr.calib") != 1 ) + { + status = 0; + } + if ( Write_SlewCorr("mbd_slewcorr.calib") != 1 ) + { + status = 0; + } + if ( Write_Pileup("mbd_pileup.calib") != 1 ) + { + status = 0; + } + if ( Write_SampMax("mbd_sampmax.calib") != 1 ) + { + status = 0; + } + if ( Write_Ped("mbd_ped.calib") != 1 ) + { + status = 0; + } + if ( Write_Status("mbd_status.calib") != 1 ) + { + status = 0; + } + if ( Write_TTT0("mbd_tt_t0.calib") != 1 ) + { + status = 0; + } + if ( Write_TQT0("mbd_tq_t0.calib") != 1 ) + { + status = 0; + } + if ( Write_T0Corr("mbd_t0corr.calib") != 1 ) + { + status = 0; + } + if ( Write_Gains("mbd_qfit.calib") != 1 ) + { + status = 0; + } //Write_TimeRMS("mbd_trms.calib"); //Write_Thresholds("mbd_thresh.calib"); - return 1; + return status; } // dz is what we need to move the MBD z by From d0130afb48492e79ec3785fa1e32030bee8c899e Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Mon, 29 Jun 2026 15:47:56 -0400 Subject: [PATCH 771/866] fixed rabbit complaints --- offline/packages/mbd/MbdCalib.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 22a8ee1575..358bb6f0ce 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -2439,6 +2439,8 @@ int MbdCalib::Write_Thresholds(const std::string& dbfile) #ifndef ONLINE int MbdCalib::Write_CDB_All() { + int status = 1; + if ( Write_CDB_Shapes("mbd_shape.root") != 1 ) { status = 0; @@ -2493,10 +2495,12 @@ int MbdCalib::Write_CDB_All() int MbdCalib::Write_All() { int status = 1; + /* if ( Write_Shapes("mbd_shape.calib") != 1 ) { status = 0; } + */ if ( Write_TimeCorr("mbd_timecorr.calib") != 1 ) { status = 0; From 721cd5a08e4e113165bdc26b4ea555ef7c9d1f4b Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 30 Jun 2026 09:04:23 -0400 Subject: [PATCH 772/866] first version of waveform vector storage --- offline/packages/CaloBase/Makefile.am | 12 +- offline/packages/CaloBase/TowerInfo.h | 1 + .../CaloBase/TowerInfoContainerSimv3.cc | 156 ++++++++++++++++++ .../CaloBase/TowerInfoContainerSimv3.h | 43 +++++ .../CaloBase/TowerInfoContainerSimv3LinkDef.h | 5 + offline/packages/CaloBase/TowerInfoSimv3.cc | 64 +++++++ offline/packages/CaloBase/TowerInfoSimv3.h | 34 ++++ .../packages/CaloBase/TowerInfoSimv3LinkDef.h | 5 + 8 files changed, 317 insertions(+), 3 deletions(-) create mode 100644 offline/packages/CaloBase/TowerInfoContainerSimv3.cc create mode 100644 offline/packages/CaloBase/TowerInfoContainerSimv3.h create mode 100644 offline/packages/CaloBase/TowerInfoContainerSimv3LinkDef.h create mode 100644 offline/packages/CaloBase/TowerInfoSimv3.cc create mode 100644 offline/packages/CaloBase/TowerInfoSimv3.h create mode 100644 offline/packages/CaloBase/TowerInfoSimv3LinkDef.h diff --git a/offline/packages/CaloBase/Makefile.am b/offline/packages/CaloBase/Makefile.am index 124c62cb55..581e42ff61 100644 --- a/offline/packages/CaloBase/Makefile.am +++ b/offline/packages/CaloBase/Makefile.am @@ -61,13 +61,15 @@ pkginclude_HEADERS = \ TowerInfov4.h \ TowerInfoSimv1.h \ TowerInfoSimv2.h \ + TowerInfoSimv3.h \ TowerInfoContainer.h \ TowerInfoContainerv1.h \ TowerInfoContainerv2.h \ TowerInfoContainerv3.h \ TowerInfoContainerv4.h \ TowerInfoContainerSimv1.h \ - TowerInfoContainerSimv2.h + TowerInfoContainerSimv2.h \ + TowerInfoContainerSimv3.h ROOTDICTS = \ PhotonClusterv1_Dict.cc \ @@ -96,13 +98,15 @@ ROOTDICTS = \ TowerInfov4_Dict.cc \ TowerInfoSimv1_Dict.cc \ TowerInfoSimv2_Dict.cc \ + TowerInfoSimv3_Dict.cc \ TowerInfoContainer_Dict.cc \ TowerInfoContainerv1_Dict.cc \ TowerInfoContainerv2_Dict.cc \ TowerInfoContainerv3_Dict.cc \ TowerInfoContainerv4_Dict.cc \ TowerInfoContainerSimv1_Dict.cc \ - TowerInfoContainerSimv2_Dict.cc + TowerInfoContainerSimv2_Dict.cc \ + TowerInfoContainerSimv3_Dict.cc pcmdir = $(libdir) # more elegant way to create pcm files (without listing them) @@ -135,6 +139,7 @@ libcalo_io_la_SOURCES = \ TowerInfov4.cc \ TowerInfoSimv1.cc \ TowerInfoSimv2.cc \ + TowerInfoSimv3.cc \ TowerInfoDefs.cc \ TowerInfoContainer.cc \ TowerInfoContainerv1.cc \ @@ -142,7 +147,8 @@ libcalo_io_la_SOURCES = \ TowerInfoContainerv3.cc \ TowerInfoContainerv4.cc \ TowerInfoContainerSimv1.cc \ - TowerInfoContainerSimv2.cc + TowerInfoContainerSimv2.cc \ + TowerInfoContainerSimv3.cc endif # Rule for generating table CINT dictionaries. diff --git a/offline/packages/CaloBase/TowerInfo.h b/offline/packages/CaloBase/TowerInfo.h index 2ec6402f2b..213280ab90 100644 --- a/offline/packages/CaloBase/TowerInfo.h +++ b/offline/packages/CaloBase/TowerInfo.h @@ -74,6 +74,7 @@ class TowerInfo : public PHObject } virtual void add_edep(const PHG4HitDefs::keytype /*g4hitid*/, const float /*edep*/) { return; } virtual void add_shower_edep(const int /*showerid*/, const float /*edep*/) { return; } + virtual void set_nsample(int /*nsample*/) { return; } private: ClassDefOverride(TowerInfo, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc new file mode 100644 index 0000000000..4c014dfc16 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc @@ -0,0 +1,156 @@ +#include "TowerInfoContainerSimv3.h" +#include "TowerInfoSimv3.h" + +#include + +#include + +TowerInfoContainerSimv3::TowerInfoContainerSimv3(DETECTOR detec) + : _detector(detec) +{ + int nchannels = 744; + if (_detector == DETECTOR::SEPD) + { + nchannels = 744; + } + else if (_detector == DETECTOR::EMCAL) + { + nchannels = 24576; + } + else if (_detector == DETECTOR::HCAL) + { + nchannels = 1536; + } + else if (_detector == DETECTOR::MBD) + { + nchannels = 256; + } + else if (_detector == DETECTOR::ZDC) + { + nchannels = 52; + } + _clones = new TClonesArray("TowerInfoSimv3", nchannels); + _clones->SetOwner(); + _clones->SetName("TowerInfoContainerSimv3"); + for (int i = 0; i < nchannels; ++i) + { + // as tower numbers are fixed per event + // construct towers once per run, and clear the towers for first use + _clones->ConstructedAt(i, "C"); + } +} + +TowerInfoContainerSimv3::TowerInfoContainerSimv3(const TowerInfoContainerSimv3& source) + : TowerInfoContainer(source) + , _clones(new TClonesArray("TowerInfoSimv3", (int) source.size())) + , _detector(source.get_detectorid()) +{ + _clones->SetOwner(); + _clones->SetName("TowerInfoContainerSimv3"); + for (int i = 0; i < (int) source.size(); ++i) + { + // as tower numbers are fixed per event + // construct towers once per run, and clear the towers for first use + _clones->ConstructedAt(i, "C"); + } +} + +TowerInfoContainerSimv3::~TowerInfoContainerSimv3() +{ + delete _clones; +} + +void TowerInfoContainerSimv3::identify(std::ostream& os) const +{ + os << "TowerInfoContainerSimv3 of size " << size() << std::endl; +} + +void TowerInfoContainerSimv3::Reset() +{ + // clear content of towers in the container for the next event + + for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) + { + TObject* obj = _clones->UncheckedAt(i); + + if (obj == nullptr) + { + std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" + << " _clones->GetSize() = " << _clones->GetSize() + << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() + << " i = " << i << std::endl; + _clones->Print(); + } + + assert(obj); + // same as TClonesArray::Clear() but only clear but not to erase all towers + obj->Clear(); + obj->ResetBit(kHasUUID); + obj->ResetBit(kIsReferenced); + obj->SetUniqueID(0); + } +} + +TowerInfoSimv3* TowerInfoContainerSimv3::get_tower_at_channel(int pos) +{ + return (TowerInfoSimv3*) _clones->At(pos); +} + +TowerInfoSimv3* TowerInfoContainerSimv3::get_tower_at_key(int pos) +{ + int index = (int) decode_key(pos); + return (TowerInfoSimv3*) _clones->At(index); +} + +unsigned int TowerInfoContainerSimv3::encode_key(unsigned int towerIndex) +{ + unsigned int key = 0; + if (_detector == DETECTOR::EMCAL) + { + key = TowerInfoContainer::encode_emcal(towerIndex); + } + else if (_detector == DETECTOR::HCAL) + { + key = TowerInfoContainer::encode_hcal(towerIndex); + } + else if (_detector == DETECTOR::SEPD) + { + key = TowerInfoContainer::encode_epd(towerIndex); + } + else if (_detector == DETECTOR::MBD) + { + key = TowerInfoContainer::encode_mbd(towerIndex); + } + else if (_detector == DETECTOR::ZDC) + { + key = TowerInfoContainer::encode_zdc(towerIndex); + } + return key; +} + +unsigned int TowerInfoContainerSimv3::decode_key(unsigned int tower_key) +{ + unsigned int index = 0; + + if (_detector == DETECTOR::EMCAL) + { + index = TowerInfoContainer::decode_emcal(tower_key); + } + else if (_detector == DETECTOR::HCAL) + { + index = TowerInfoContainer::decode_hcal(tower_key); + } + else if (_detector == DETECTOR::SEPD) + { + index = TowerInfoContainer::decode_epd(tower_key); + } + else if (_detector == DETECTOR::MBD) + { + index = TowerInfoContainer::decode_mbd(tower_key); + } + else if (_detector == DETECTOR::ZDC) + { + index = TowerInfoContainer::decode_zdc(tower_key); + } + return index; +} diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.h b/offline/packages/CaloBase/TowerInfoContainerSimv3.h new file mode 100644 index 0000000000..4a91ba5aec --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.h @@ -0,0 +1,43 @@ +#ifndef TOWERINFOCONTAINERSIMV3_H +#define TOWERINFOCONTAINERSIMV3_H + +#include "TowerInfoContainer.h" +#include "TowerInfoSimv3.h" + +#include + +class PHObject; + +class TowerInfoContainerSimv3 : public TowerInfoContainer +{ + public: + TowerInfoContainerSimv3(DETECTOR detec); + + // default constructor for ROOT IO + TowerInfoContainerSimv3() = default; + PHObject *CloneMe() const override { return new TowerInfoContainerSimv3(*this); } + TowerInfoContainerSimv3(const TowerInfoContainerSimv3 &); + + ~TowerInfoContainerSimv3() override; + + void identify(std::ostream &os = std::cout) const override; + + void Reset() override; + TowerInfoSimv3 *get_tower_at_channel(int pos) override; + TowerInfoSimv3 *get_tower_at_key(int pos) override; + + unsigned int encode_key(unsigned int towerIndex) override; + unsigned int decode_key(unsigned int tower_key) override; + + size_t size() const override { return _clones->GetEntries(); } + DETECTOR get_detectorid() const override { return _detector; } + + protected: + TClonesArray *_clones = nullptr; + DETECTOR _detector = DETECTOR_INVALID; + + private: + ClassDefOverride(TowerInfoContainerSimv3, 1); +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3LinkDef.h b/offline/packages/CaloBase/TowerInfoContainerSimv3LinkDef.h new file mode 100644 index 0000000000..17bb2e4780 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfoContainerSimv3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/CaloBase/TowerInfoSimv3.cc b/offline/packages/CaloBase/TowerInfoSimv3.cc new file mode 100644 index 0000000000..07ee207664 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoSimv3.cc @@ -0,0 +1,64 @@ +#include "TowerInfoSimv3.h" + +#include "TowerInfo.h" + +void TowerInfoSimv3::Reset() +{ + TowerInfoSimv1::Reset(); + for (short& i : _waveform) + { + i = 0; + } +} + +void TowerInfoSimv3::Clear(Option_t* /*unused*/) +{ + TowerInfoSimv1::Clear(); + for (short& i : _waveform) + { + i = 0; + } +} + +void TowerInfoSimv3::set_nsample(int nsample) +{ + if (nsample >= 0) + { + _waveform.resize(nsample, 0); + } +} + +int16_t TowerInfoSimv3::get_waveform_value(int index) const +{ + if (index >= 0 && index < get_nsample()) + { + return _waveform[index]; + } + return 0; +} + +void TowerInfoSimv3::set_waveform_value(int index, int16_t value) +{ + if (index >= 0 && index < get_nsample()) + { + _waveform[index] = value; + } + return; +} + +void TowerInfoSimv3::copy_tower(TowerInfo* tower) +{ + TowerInfoSimv1::copy_tower(tower); + const int nsamples = tower->get_nsample(); + if (nsamples <= 0) + { + set_nsample(0); + return; + } + set_nsample(nsamples); + for (int i = 0; i < nsamples; ++i) + { + _waveform[i] = tower->get_waveform_value(i); + } + return; +} diff --git a/offline/packages/CaloBase/TowerInfoSimv3.h b/offline/packages/CaloBase/TowerInfoSimv3.h new file mode 100644 index 0000000000..837ddad988 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoSimv3.h @@ -0,0 +1,34 @@ +#ifndef TOWERINFOSIMV3_H +#define TOWERINFOSIMV3_H + +#include "TowerInfoSimv1.h" + +#include // For int16_t +#include + +class TowerInfoSimv3 : public TowerInfoSimv1 +{ + public: + TowerInfoSimv3() = default; + ~TowerInfoSimv3() override = default; + + void Reset() override; + void Clear(Option_t* = "") override; + + void copy_tower(TowerInfo* tower) override; + + void set_nsample(int nsample) override; + int get_nsample() const override { return _waveform.size(); } + int16_t get_waveform_value(int index) const override; + void set_waveform_value(int index, int16_t value) override; + + private: + EdepMap _hitedeps; + ShowerEdepMap _showeredeps; + std::vector _waveform; + + ClassDefOverride(TowerInfoSimv3, 1); + // Inherit other methods and properties from TowerInfoSimv1 +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfoSimv3LinkDef.h b/offline/packages/CaloBase/TowerInfoSimv3LinkDef.h new file mode 100644 index 0000000000..306617306f --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoSimv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfoSimv3 + ; + +#endif /* __CINT__ */ From 5f02ced1386df1f18015ec9e1507e72793a7bf5d Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 30 Jun 2026 09:05:01 -0400 Subject: [PATCH 773/866] first version of waveform vector storage for sims --- .../g4simulation/g4waveformsim/CaloWaveformSim.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 4319689d8c..9ff7e5ae3b 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -21,7 +21,7 @@ #include #include -#include +#include #include @@ -607,8 +607,12 @@ void CaloWaveformSim::CreateNodeTree(PHCompositeNode *topNode) DetNode = new PHCompositeNode(DetectorNodeName); dstNode->addNode(DetNode); } - m_CaloWaveformContainer = new TowerInfoContainerSimv2(DetectorEnum); - + m_CaloWaveformContainer = new TowerInfoContainerSimv3(DetectorEnum); + for (size_t index = 0; index < m_CaloWaveformContainer->size(); index++) + { + TowerInfo *twr = m_CaloWaveformContainer->get_tower_at_channel(index); + twr->set_nsample(m_nsamples); + } PHIODataNode *newTowerNode = new PHIODataNode(m_CaloWaveformContainer, "WAVEFORM_" + m_detector, "PHObject"); DetNode->addNode(newTowerNode); } From 47b495c8f0cc03943885a205c43ef3f5b79e0b1e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 30 Jun 2026 10:29:32 -0400 Subject: [PATCH 774/866] remove obsolete m_pedestalsamples, set default samples to 12 --- .../g4simulation/g4waveformsim/CaloWaveformSim.cc | 14 ++++++-------- .../g4simulation/g4waveformsim/CaloWaveformSim.h | 4 +--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 9ff7e5ae3b..4f90bd5484 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -456,32 +456,30 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } } + std::vector waveform_pedestal_vector(m_nsamples); for (int i = 0; i < m_nchannels; i++) { - std::vector m_waveform_pedestal; - m_waveform_pedestal.resize(m_nsamples); if (m_noiseType == NoiseType::NOISE_TREE) { TowerInfo *pedestal_tower = m_PedestalContainer->get_tower_at_channel(i); + int pedestalsamples = pedestal_tower->get_nsample(); float pedestal_mean = 0; for (int j = 0; j < m_nsamples; j++) { - m_waveform_pedestal.at(j) = (j < m_pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(m_pedestalsamples - 1); - pedestal_mean += m_waveform_pedestal.at(j); + waveform_pedestal_vector.at(j) = (j < pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(pedestalsamples - 1); + pedestal_mean += waveform_pedestal_vector.at(j); } pedestal_mean /= m_nsamples; for (int j = 0; j < m_nsamples; j++) { - m_waveform_pedestal.at(j) = (m_waveform_pedestal.at(j) - pedestal_mean) * m_pedestal_scale + pedestal_mean; + waveform_pedestal_vector.at(j) = (waveform_pedestal_vector.at(j) - pedestal_mean) * m_pedestal_scale + pedestal_mean; } } for (int j = 0; j < m_nsamples; j++) { if (m_noiseType == NoiseType::NOISE_TREE) { - // TowerInfo *pedestal_tower = m_PedestalContainer->get_tower_at_channel(i); - // m_waveforms.at(i).at(j) += (j < m_pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(m_pedestalsamples - 1); - m_waveforms.at(i).at(j) += m_waveform_pedestal.at(j); + m_waveforms.at(i).at(j) += waveform_pedestal_vector.at(j); } if (m_noiseType == NoiseType::NOISE_GAUSSIAN) { diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index e0f6760111..41f1792022 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -108,7 +108,6 @@ class CaloWaveformSim : public SubsysReco // Waveform template & sampling void set_templatefile(const std::string &templatefile) { m_templatefile = templatefile; } void set_nsamples(int nsamples) { m_nsamples = nsamples; } - void set_pedestalsamples(int pedestalsamples) { m_pedestalsamples = pedestalsamples; } void set_sampletime(float sampletime) { m_sampletime = sampletime; } void set_nchannels(int nchannels) { m_nchannels = nchannels; } void set_sampling_fraction(float fraction) { m_sampling_fraction = fraction; } @@ -191,8 +190,7 @@ class CaloWaveformSim : public SubsysReco // Waveform settings std::string m_templatefile{"waveformtemptempohcalcosmic.root"}; - int m_nsamples{31}; - int m_pedestalsamples{31}; + int m_nsamples{12}; // number of samples for calos in our default data taking configuration float m_sampletime{50. / 3.}; int m_nchannels{24576}; float m_sampling_fraction{1.0f}; From b1bc5fb5bc5539ce5d4b2a91b6994bdaeda3764c Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 30 Jun 2026 10:34:09 -0400 Subject: [PATCH 775/866] add truth crossing number --- simulation/g4simulation/g4eval/SvtxEvaluator.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index b844e6bd46..28c62f9d20 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -172,7 +174,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:gparentflavor:gparentid:gprimaryflavor:gprimaryid:" + "gembed:gprimary:gcrossing:gparentflavor:gparentid:gprimaryflavor:gprimaryid:" "trackID:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:" "crossing:siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" "charge:quality:chisq:ndf:nhits:layers:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:nlmaps:nlintt:nltpc:nlmms:" @@ -192,7 +194,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:gparentflavor:gparentid:gprimaryflavor:gprimaryid:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" + "gembed:gprimary:gcrossing:gparentflavor:gparentid:gprimaryflavor:gprimaryid:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" "ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" "npedge:nredge:nbig:novlp:merr:msize:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); @@ -2858,7 +2860,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gvy = vtx->get_y(); float gvz = vtx->get_z(); float gvt = vtx->get_t(); - + int gcrossing = std::floor(gvt / sphenix_constants::time_between_crossings); float gfpx = 0.; float gfpy = 0.; float gfpz = 0.; @@ -3340,6 +3342,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfz, gembed, gprimary, + (float) gcrossing, gparentflavor, gparentid, gprimaryflavor, @@ -3812,7 +3815,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); float gprimary = std::numeric_limits::quiet_NaN(); - + int gcrossing = std::numeric_limits::max(); int ispure = 0; float nfromtruth = std::numeric_limits::quiet_NaN(); float nwrong = std::numeric_limits::quiet_NaN(); @@ -3942,6 +3945,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gvz = vtx->get_z(); gvt = vtx->get_t(); + gcrossing = std::floor(gvt / sphenix_constants::time_between_crossings); PHG4Hit* outerhit = nullptr; if (_do_eval_light == false) { @@ -4090,6 +4094,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfz, gembed, gprimary, + (float) gcrossing, gparentflavor, gparentid, gprimaryflavor, From 31638d5b718f21863ec6fc7b78da66970d698cf3 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 30 Jun 2026 10:51:15 -0400 Subject: [PATCH 776/866] initialize variables to invalid, not to the CEMC, remove unused m_runNumber --- simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc | 7 +------ simulation/g4simulation/g4waveformsim/CaloWaveformSim.h | 5 ++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 4f90bd5484..558e629766 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -89,12 +89,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) gSystem->Exit(1); } h_template->SetDirectory(nullptr); - - m_runNumber = recoConsts::instance()->get_IntFlag("RUNNUMBER"); - if (Verbosity() > 0) - { - std::cout << "CaloWaveformSim::InitRun Run Number: " << m_runNumber << std::endl; - } + ft->Close(); // Detector-specific setup if (m_dettype == CaloTowerDefs::CEMC) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index 41f1792022..dfdd5a8115 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -192,8 +192,8 @@ class CaloWaveformSim : public SubsysReco std::string m_templatefile{"waveformtemptempohcalcosmic.root"}; int m_nsamples{12}; // number of samples for calos in our default data taking configuration float m_sampletime{50. / 3.}; - int m_nchannels{24576}; - float m_sampling_fraction{1.0f}; + int m_nchannels{-1}; + float m_sampling_fraction{std::numeric_limits::quiet_NaN()}; // Shaping & noise int m_fixpedestal{1500}; @@ -206,7 +206,6 @@ class CaloWaveformSim : public SubsysReco float m_pedestal_scale{1.}; std::vector> m_waveforms; - int m_runNumber{0}; LightCollectionModel light_collection_model; From 574ea9073f9c4bccb29fda0dd97481e3ee309fd5 Mon Sep 17 00:00:00 2001 From: Hao-Ren Jheng Date: Tue, 30 Jun 2026 14:23:52 -0400 Subject: [PATCH 777/866] Properly copy and add sPHENIX primary particles for pileup vertices --- .../g4main/Fun4AllDstPileupMerger.cc | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc b/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc index 327d611f64..0ddc40a477 100644 --- a/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc +++ b/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc @@ -274,6 +274,70 @@ void Fun4AllDstPileupMerger::copy_background_event(PHCompositeNode *dstNode, dou } } + // also need to copy the sPHENIX primary particle info + { + // sPHENIX primary particles + const auto range = container_truth->GetSPHENIXPrimaryParticleRange(); + for (auto iter = range.first; iter != range.second; ++iter) + { + const auto &source = iter->second; + if (!source) // guard + { + std::cout << __PRETTY_FUNCTION__ << " - " << __LINE__ << " - null source (sPHENIX primary) particle" << std::endl; + continue; + } + + auto keyiter = trkid_map.find(source->get_track_id()); + if (keyiter == trkid_map.end()) // guard against missing track id in map + { + std::cout << __PRETTY_FUNCTION__ << " - " << __LINE__ << " - track id " << source->get_track_id() << " not found in map" << std::endl; + continue; + } + + auto *dest = new PHG4Particle_t(source); + dest->set_track_id(keyiter->second); + + if (source->get_parent_id() == 0) + { + dest->set_parent_id(0); + } + else + { + keyiter = trkid_map.find(source->get_parent_id()); + if (keyiter != trkid_map.end()) + { + dest->set_parent_id(keyiter->second); + } + else + { + std::cout << "Fun4AllDstPileupMerger::copy_background_event - track id " << source->get_parent_id() << " not found in map" << std::endl; + } + } + + keyiter = trkid_map.find(source->get_primary_id()); + if (keyiter != trkid_map.end()) + { + dest->set_primary_id(keyiter->second); + } + else + { + std::cout << "Fun4AllDstPileupMerger::copy_background_event - track id " << source->get_primary_id() << " not found in map" << std::endl; + } + + keyiter = vtxid_map.find(source->get_vtx_id()); + if (keyiter != vtxid_map.end()) + { + dest->set_vtx_id(keyiter->second); + } + else + { + std::cout << "Fun4AllDstPileupMerger::copy_background_event - vertex id " << source->get_vtx_id() << " not found in map" << std::endl; + } + + m_g4truthinfo->AddsPHENIXPrimaryParticle(dest->get_track_id(), dest); + } + } + // vertex embed flags /* embed flag is stored only for primary vertices, consistently with PHG4TruthEventAction */ for (const auto &pair : vtxid_map) From 50920ff842331708d4b3c0c14fa35b2c29c52939 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Tue, 30 Jun 2026 15:53:15 -0400 Subject: [PATCH 778/866] add zero field line projections --- .../trackreco/PHActsSiliconSeeding.cc | 40 ++++++++++++++++--- .../packages/trackreco/PHActsSiliconSeeding.h | 5 +++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index 277be758f5..8fd7133c39 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -54,6 +54,28 @@ namespace { return x * x; } + + Acts::Vector3 get_line_surface_intersection(const Surface& surf, + const std::vector& fitpars, + const Acts::Vector3& global, + ActsGeometry* tGeometry) + { + Acts::Vector3 const sensorCenter = surf->center(tGeometry->geometry().getGeoContext()) * 0.1; + Acts::Vector3 sensorNormal = -surf->normal(tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); + sensorNormal /= sensorNormal.norm(); + + Acts::Vector3 const linePoint(0., fitpars[1], fitpars[3]); + Acts::Vector3 tangent(1., fitpars[0], fitpars[2]); + tangent /= tangent.norm(); + + // Keep the line direction consistent with the measured cluster direction when possible. + if ((global - linePoint).dot(tangent) < 0) + { + tangent = -1. * tangent; + } + + return TrackFitUtils::get_line_plane_intersection(linePoint, tangent, sensorCenter, sensorNormal); + } } // namespace PHActsSiliconSeeding::PHActsSiliconSeeding(const std::string& name) @@ -807,7 +829,8 @@ std::vector PHActsSiliconSeeding::findMatches( std::vector& keys, TrackSeed& seed) { - auto fitpars = TrackFitUtils::fitClusters(clusters, keys, true); + auto fitpars = m_zeroField ? TrackFitUtils::fitClustersZeroField(clusters, keys, true) + : TrackFitUtils::fitClusters(clusters, keys, true); float avgtripletx = 0; float avgtriplety = 0; for (auto& pos : clusters) @@ -934,7 +957,8 @@ std::vector PHActsSiliconSeeding::findMatches( /// If we added a cluster, refit the track to get a better projection if (dummyclusters.size() > clusters.size()) { - dummypars = TrackFitUtils::fitClusters(dummyclusters, dummykeys, false); + dummypars = m_zeroField ? TrackFitUtils::fitClustersZeroField(dummyclusters, dummykeys, false) + : TrackFitUtils::fitClusters(dummyclusters, dummykeys, false); } auto range = m_clusterMap->getClusters(hitsetkey); for (auto clusIter = range.first; clusIter != range.second; ++clusIter) @@ -951,10 +975,12 @@ std::vector PHActsSiliconSeeding::findMatches( auto* const cluster = clusIter->second; auto glob = m_tGeometry->getGlobalPosition( cluskey, cluster); - auto intersection = TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); + auto intersection = m_zeroField ? get_line_surface_intersection(surf, fitpars, glob, m_tGeometry) + : TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); if (!dummypars.empty()) { - intersection = TrackFitUtils::get_helix_surface_intersection(surf, dummypars, glob, m_tGeometry); + intersection = m_zeroField ? get_line_surface_intersection(surf, dummypars, glob, m_tGeometry) + : TrackFitUtils::get_helix_surface_intersection(surf, dummypars, glob, m_tGeometry); } auto local = (surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; @@ -1145,7 +1171,8 @@ std::vector> PHActsSiliconSeeding::iterateLayers( { std::vector> inttMatches; auto dummypos = positions; - auto fitpars = TrackFitUtils::fitClusters(dummypos, keys, true); + auto fitpars = m_zeroField ? TrackFitUtils::fitClustersZeroField(dummypos, keys, true) + : TrackFitUtils::fitClusters(dummypos, keys, true); float avgtripletx = 0; float avgtriplety = 0; for (const auto& pos : positions) @@ -1258,7 +1285,8 @@ std::vector> PHActsSiliconSeeding::iterateLayers( auto* const cluster = clusIter->second; auto glob = m_tGeometry->getGlobalPosition( cluskey, cluster); - auto intersection = TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); + auto intersection = m_zeroField ? get_line_surface_intersection(surf, fitpars, glob, m_tGeometry) + : TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); auto local = (surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; m_projgx = intersection.x(); diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.h b/offline/packages/trackreco/PHActsSiliconSeeding.h index 09081d088f..d5e49d7a2e 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.h +++ b/offline/packages/trackreco/PHActsSiliconSeeding.h @@ -176,6 +176,10 @@ class PHActsSiliconSeeding : public SubsysReco { m_bField = field; } + void zeroField(const bool flag = true) + { + m_zeroField = flag; + } void minpt(const float pt) { m_minSeedPt = pt; @@ -353,6 +357,7 @@ class PHActsSiliconSeeding : public SubsysReco /// B field value in z direction /// bfield for space point grid neds to be in kiloTesla float m_bField = 1.4 * Acts::UnitConstants::T; + bool m_zeroField = false; std::vector> zBinNeighborsTop; std::vector> zBinNeighborsBottom; int nphineighbors = 1; From f167aa94c10ac2531a8523006951fc088ab387db Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 30 Jun 2026 18:05:45 -0400 Subject: [PATCH 779/866] snapshot --- offline/packages/CaloBase/TowerInfov3.cc | 10 ++++++++++ offline/packages/CaloBase/TowerInfov3.h | 2 ++ .../g4simulation/g4waveformsim/CaloWaveformSim.cc | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/offline/packages/CaloBase/TowerInfov3.cc b/offline/packages/CaloBase/TowerInfov3.cc index 19fb5581e0..6f6ee0925c 100644 --- a/offline/packages/CaloBase/TowerInfov3.cc +++ b/offline/packages/CaloBase/TowerInfov3.cc @@ -46,3 +46,13 @@ void TowerInfov3::copy_tower(TowerInfo* tower) } return; } + +void TowerInfov3::identify(std::ostream& os) const +{ + os << "TowerInfov3" << std::endl; + for (int i = 0; i < nsample; ++i) + { + std::cout << "sample " << i << ": " << get_waveform_value(i) << std::endl; + } + return; +} diff --git a/offline/packages/CaloBase/TowerInfov3.h b/offline/packages/CaloBase/TowerInfov3.h index 8121ee3693..4cf8f396f1 100644 --- a/offline/packages/CaloBase/TowerInfov3.h +++ b/offline/packages/CaloBase/TowerInfov3.h @@ -21,6 +21,8 @@ class TowerInfov3 : public TowerInfov2 void copy_tower(TowerInfo* tower) override; + void identify(std::ostream& os) const override; + private: static const int nsample = 31; int16_t _waveform[nsample] = {0}; // Initializes the entire array to zero diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 558e629766..2982bbe09f 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -449,6 +449,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) gSystem->Exit(1); exit(1); } + m_PedestalContainer->identify(); } std::vector waveform_pedestal_vector(m_nsamples); @@ -463,6 +464,11 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { waveform_pedestal_vector.at(j) = (j < pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(pedestalsamples - 1); pedestal_mean += waveform_pedestal_vector.at(j); + if (pedestal_tower->get_waveform_value(j) < 100) + { + std::cout << Name() << " channel: " << j << " too small pedestal value for index " << j << ": " << pedestal_tower->get_waveform_value(j) << std::endl; + pedestal_tower->identify(); + } } pedestal_mean /= m_nsamples; for (int j = 0; j < m_nsamples; j++) From 6cba011262a77ada348dbe84c259597fbf0ba398 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Tue, 30 Jun 2026 19:43:07 -0400 Subject: [PATCH 780/866] EMCal SiPM Occupancy --- .../g4waveformsim/CaloWaveformSim.cc | 47 ++++++++++++++++++- .../g4waveformsim/CaloWaveformSim.h | 23 +++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 4319689d8c..441bd3e8d7 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -366,6 +366,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } std::map tbt_smear; + std::map tower_photon_count_mean; // loop over hits for (PHG4HitContainer::ConstIterator hititer = hits->getHits().first; hititer != hits->getHits().second; hititer++) @@ -384,6 +385,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) float correction = 1.; maphitetaphi(hit, etabin, phibin, correction); unsigned int key = encode_tower(etabin, phibin); + unsigned int tower_index = decode_tower(key); float calibconst = cdbttree->GetFloatValue(key, m_fieldname); float e_vis = hit->get_light_yield(); e_vis *= correction; @@ -397,10 +399,26 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } else { - tbt_smear[key] = 1.0 + gsl_ran_gaussian(m_RandomGenerator, factor_const); + float val = 1.0+ gsl_ran_gaussian(m_RandomGenerator,factor_const); + if(val < 0.0f) + { + val = 0; + } + tbt_smear[key] = val; e_vis *= tbt_smear[key]; } } + + if (m_use_sipm_occupancy && m_dettype == CaloTowerDefs::CEMC) + { + double kPhotonElecYieldVisibleGeV = kPhotoelectronsPerGeV / kSamplingFraction; + const double photon_count_mean = static_cast(e_vis) * kPhotonElecYieldVisibleGeV; + if (photon_count_mean > 0.) + { + tower_photon_count_mean[tower_index] += photon_count_mean; + } + } + float e_dep = e_vis / m_sampling_fraction; float ADC = (calibconst != 0) ? e_dep / calibconst : 0.; ADC *= m_gain; @@ -421,7 +439,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } float t0 = hit->get_t(0) / m_sampletime; - unsigned int tower_index = decode_tower(key); + // here I will add the truth matching part // for the cell reco, the truth matching info relies on edep not light yield, I will be consistent here :) TowerInfo *tower = m_CaloWaveformContainer->get_tower_at_channel(tower_index); @@ -441,6 +459,31 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } } + if (m_use_sipm_occupancy && m_dettype == CaloTowerDefs::CEMC) + { + for (const auto &entry : tower_photon_count_mean) + { + const unsigned int tower_index = entry.first; + const double photon_count_mean = entry.second; + if (photon_count_mean <= 0. || tower_index >= m_waveforms.size()) + { + continue; + } + + const double poisson_param_per_pixel = photon_count_mean / kSiPMEffectivePixel; + const double expected_active_pixels = + kSiPMEffectivePixel * (1. - std::exp(-poisson_param_per_pixel)); + const double occupancy_ratio = + std::max(0., std::min(1., expected_active_pixels / photon_count_mean)); + //std::cout << "occupancy_ratio: " << occupancy_ratio << std::endl; + for (int isample = 0; isample < m_nsamples; ++isample) + { + m_waveforms.at(tower_index).at(isample) *= occupancy_ratio; + } + } + } + + // do noise here and add to waveform if (m_noiseType == NoiseType::NOISE_TREE) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index e0f6760111..c7020b4b69 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -71,6 +71,11 @@ class CaloWaveformSim : public SubsysReco m_directURL_MC = url; } + void set_use_sipm_occupancy(bool use_sipm_occupancy = true) + { + m_use_sipm_occupancy = use_sipm_occupancy; + } + // Time calibration (data) void set_fieldname_time(const std::string &fieldname_time) { @@ -105,6 +110,19 @@ class CaloWaveformSim : public SubsysReco factor_const = val; } + void set_kSamplingFraction(double val) + { + kSamplingFraction = val; + } + void set_kPhotoelectronsPerGeV(double val) + { + kPhotoelectronsPerGeV = val; + } + void set_kSiPMEffectivePixel(double val) + { + kSiPMEffectivePixel = val; + } + // Waveform template & sampling void set_templatefile(const std::string &templatefile) { m_templatefile = templatefile; } void set_nsamples(int nsamples) { m_nsamples = nsamples; } @@ -212,6 +230,11 @@ class CaloWaveformSim : public SubsysReco LightCollectionModel light_collection_model; + bool m_use_sipm_occupancy{false}; + double kSamplingFraction = 2e-2; + double kPhotoelectronsPerGeV = 500.; + double kSiPMEffectivePixel = 40000 * 4.; + NoiseType m_noiseType{NOISE_TREE}; }; From a009ee5fff9308970ebe7e976e5326da162fc4c0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 1 Jul 2026 12:54:18 -0400 Subject: [PATCH 781/866] hide verbosity --- offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc index a6294c7ff0..6e18788b17 100644 --- a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc @@ -835,7 +835,9 @@ int PHMicromegasTpcTrackMatching::process_event(PHCompositeNode* topNode) * 1/ drphi and dz are actually calculated in Tile's local reference frame, not in world coordinates * 2/ drphi also includes SC distortion correction, which the world coordinates don't */ - std::cout + if(Verbosity() > 1) + { + std::cout << " Try_mms: " << (int) layer << " drphi " << drphi << " dz " << dz @@ -844,6 +846,7 @@ int PHMicromegasTpcTrackMatching::process_event(PHCompositeNode* topNode) << " pt " << tracklet_tpc->get_pt() << " charge " << tracklet_tpc->get_charge() << std::endl; + } } } // end loop over clusters From f880553684a974050a4e43c8567a6039e4f7804a Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Thu, 2 Jul 2026 00:14:15 -0400 Subject: [PATCH 782/866] photon statistics --- .../g4waveformsim/CaloWaveformSim.cc | 18 +++++++++++++----- .../g4waveformsim/CaloWaveformSim.h | 6 ++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 441bd3e8d7..057721ef3a 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -465,20 +465,28 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { const unsigned int tower_index = entry.first; const double photon_count_mean = entry.second; - if (photon_count_mean <= 0. || tower_index >= m_waveforms.size()) + + double photon_count = photon_count_mean; + if (m_use_photon_statistics) + { + const double sigma = std::sqrt(std::max(0., photon_count_mean)); + photon_count = std::max(0., photon_count + gsl_ran_gaussian(m_RandomGenerator, sigma)); + } + + if (photon_count_mean <= 0. || photon_count <= 0. || tower_index >= m_waveforms.size()) { continue; } - const double poisson_param_per_pixel = photon_count_mean / kSiPMEffectivePixel; + const double poisson_param_per_pixel = photon_count / kSiPMEffectivePixel; const double expected_active_pixels = kSiPMEffectivePixel * (1. - std::exp(-poisson_param_per_pixel)); const double occupancy_ratio = - std::max(0., std::min(1., expected_active_pixels / photon_count_mean)); - //std::cout << "occupancy_ratio: " << occupancy_ratio << std::endl; + std::max(0., std::min(1., expected_active_pixels / photon_count)); + const double photon_stat_fac = photon_count / photon_count_mean; for (int isample = 0; isample < m_nsamples; ++isample) { - m_waveforms.at(tower_index).at(isample) *= occupancy_ratio; + m_waveforms.at(tower_index).at(isample) *= occupancy_ratio * photon_stat_fac; } } } diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index c7020b4b69..70e4f17bb6 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -76,6 +76,11 @@ class CaloWaveformSim : public SubsysReco m_use_sipm_occupancy = use_sipm_occupancy; } + void set_use_photon_statistics( bool state=true ) + { + m_use_photon_statistics = state; + } + // Time calibration (data) void set_fieldname_time(const std::string &fieldname_time) { @@ -230,6 +235,7 @@ class CaloWaveformSim : public SubsysReco LightCollectionModel light_collection_model; + bool m_use_photon_statistics{false}; bool m_use_sipm_occupancy{false}; double kSamplingFraction = 2e-2; double kPhotoelectronsPerGeV = 500.; From a3d221519117c1ab81ac7c913893f2fbc2d26ffa Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Thu, 2 Jul 2026 01:47:56 -0400 Subject: [PATCH 783/866] Validate INTT streaming configuration setters --- .../Fun4AllStreamingInputManager.cc | 39 +++++++++++++++++-- .../fun4allraw/Fun4AllStreamingInputManager.h | 6 ++- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 65eeef318e..030a99a834 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -824,7 +824,10 @@ int Fun4AllStreamingInputManager::FillIntt() int server = intthititer->get_packetid(); // note : the felix server ID int felix_ch = intthititer->get_fee(); // note : the felix channel ID 0 - 13 - std::string hit_string = Form("%ld_%d_%d_%d",bco_full,FPHXbco,server,felix_ch); + std::string hit_string = + Form("%" PRIu64 "_%d_%d_%d", + bco_full, FPHXbco, server, felix_ch + ); // note: "BCOFULL_FPHXBCO_FELIX_FEE" if (m_InttRawHitCount_FEE.find(hit_string.c_str()) == m_InttRawHitCount_FEE.end()){ @@ -883,15 +886,22 @@ int Fun4AllStreamingInputManager::FillIntt() int ThisStrobe_HL_server; int ThisStrobe_HL_felix_ch; - sscanf( + const int nparsed = sscanf( pair.first.c_str(), - "%ld_%d_%d_%d", + "%" SCNu64 "_%d_%d_%d", &ThisStrobe_HL_bco_full, &ThisStrobe_HL_FPHXBCO, &ThisStrobe_HL_server, &ThisStrobe_HL_felix_ch ); + if (nparsed != 4) + { + std::cerr << "Fun4AllStreamingInputManager::FillIntt(), Failed to parse hit key: " << pair.first.c_str() << std::endl; + gSystem->Exit(1); + exit(1); + } + int ThisStrobe_HL_count_perFPHXBCO = pair.second; if (m_IsRejectInttNoiseCrossings && m_IsInttStreaming && (ThisStrobe_HL_FPHXBCO < m_InttStreamingSignalCrossing.first || ThisStrobe_HL_FPHXBCO > m_InttStreamingSignalCrossing.second) ){ @@ -1679,3 +1689,26 @@ void Fun4AllStreamingInputManager::createQAHistos() h_tagBcoFelixAllFees_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCOAllFees_Felix%i") % i).str())); } } + + +void Fun4AllStreamingInputManager::SetInttStreamingSignalCrossing(std::pair input_pair) { + + if (input_pair.first > input_pair.second) + { + std::cout << "In Fun4AllStreamingInputManager, Error: streaming signal crossing range is reversed: " + << input_pair.first << ", " << input_pair.second << std::endl; + std::exit(1); + } + + m_InttStreamingSignalCrossing = input_pair; +} + +void Fun4AllStreamingInputManager::InttHitCarryOverShiftMaxMultiple(const int i) { + if (i < 0) + { + std::cout << "In Fun4AllStreamingInputManagerm, Error: InttHitCarryOverShiftMaxMultiple must be non-negative" + << std::endl; + std::exit(1); + } + m_InttHitCarryOverShiftMaxMultiple = i; +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h index c658665757..ca496622e2 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h @@ -11,6 +11,7 @@ #include #include #include +#include class SingleStreamingInput; class Gl1Packet; @@ -72,12 +73,13 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager // configuration for INTT hit carry-over issue mitigation (hit duplication) void EnableInttHitDuplication(bool b = true) { m_InttHitDuplication = b; } - void InttHitCarryOverShiftMaxMultiple(const int i) { m_InttHitCarryOverShiftMaxMultiple = i; } void SetIsRejectInttNoiseCrossings(bool b = true) {m_IsRejectInttNoiseCrossings = b;} void SetIsInttStreaming(bool b = true) {m_IsInttStreaming = b;} void SetIsDuplicateInttFPHXBCOResetHit(bool b = true) {m_IsDuplicateInttFPHXBCOResetHit = b;} void SetInttResetFphxBcoVec(std::vector input_vec) {m_InttResetFphxBcoVec = input_vec;} - void SetInttStreamingSignalCrossing(std::pair input_pair) {m_InttStreamingSignalCrossing = input_pair;} + + void SetInttStreamingSignalCrossing(std::pair input_pair); + void InttHitCarryOverShiftMaxMultiple(const int i); private: From c49adec2d6d6ac74bec64712f97c627acbe01449 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Thu, 2 Jul 2026 02:04:06 -0400 Subject: [PATCH 784/866] update for SetInttResetFphxBcoVec --- offline/framework/fun4allraw/Fun4AllStreamingInputManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h index ca496622e2..86a951a8e3 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h @@ -76,7 +76,7 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager void SetIsRejectInttNoiseCrossings(bool b = true) {m_IsRejectInttNoiseCrossings = b;} void SetIsInttStreaming(bool b = true) {m_IsInttStreaming = b;} void SetIsDuplicateInttFPHXBCOResetHit(bool b = true) {m_IsDuplicateInttFPHXBCOResetHit = b;} - void SetInttResetFphxBcoVec(std::vector input_vec) {m_InttResetFphxBcoVec = input_vec;} + void SetInttResetFphxBcoVec(const std::vector& input_vec) {m_InttResetFphxBcoVec = input_vec;} void SetInttStreamingSignalCrossing(std::pair input_pair); void InttHitCarryOverShiftMaxMultiple(const int i); From 0ba7377eff4a5e8fbe01d3ae034bf6ff12861143 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 2 Jul 2026 08:51:10 -0400 Subject: [PATCH 785/866] do not produce streamers for virtual base classes (ClassDefOverride = 0) --- offline/packages/CaloBase/TowerInfo.h | 3 ++- offline/packages/CaloBase/TowerInfoContainer.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfo.h b/offline/packages/CaloBase/TowerInfo.h index 213280ab90..f8b3984396 100644 --- a/offline/packages/CaloBase/TowerInfo.h +++ b/offline/packages/CaloBase/TowerInfo.h @@ -74,10 +74,11 @@ class TowerInfo : public PHObject } virtual void add_edep(const PHG4HitDefs::keytype /*g4hitid*/, const float /*edep*/) { return; } virtual void add_shower_edep(const int /*showerid*/, const float /*edep*/) { return; } +// methods in v5 and simv3 virtual void set_nsample(int /*nsample*/) { return; } private: - ClassDefOverride(TowerInfo, 1); + ClassDefOverride(TowerInfo, 0); }; #endif diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index 63b763172c..335d8f0a09 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -57,7 +57,7 @@ class TowerInfoContainer : public PHObject virtual DETECTOR get_detectorid() const { return DETECTOR_INVALID; } private: - ClassDefOverride(TowerInfoContainer, 1); + ClassDefOverride(TowerInfoContainer, 0); }; #endif From 444f03b4c1dab4633c06b8baec050cb7e09e78c3 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 2 Jul 2026 08:53:09 -0400 Subject: [PATCH 786/866] cleanup of CaloWaveformSim.cc --- simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 2982bbe09f..8b67888d0a 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -449,7 +449,6 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) gSystem->Exit(1); exit(1); } - m_PedestalContainer->identify(); } std::vector waveform_pedestal_vector(m_nsamples); @@ -464,7 +463,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { waveform_pedestal_vector.at(j) = (j < pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(pedestalsamples - 1); pedestal_mean += waveform_pedestal_vector.at(j); - if (pedestal_tower->get_waveform_value(j) < 100) + if (Verbosity() > 2 && pedestal_tower->get_waveform_value(j) < 100) { std::cout << Name() << " channel: " << j << " too small pedestal value for index " << j << ": " << pedestal_tower->get_waveform_value(j) << std::endl; pedestal_tower->identify(); From c32cbc8ea84c7635342f203174f28d9bfa19ef4d Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 2 Jul 2026 09:02:41 -0400 Subject: [PATCH 787/866] fix clang-tidy --- .../Fun4AllStreamingInputManager.cc | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 030a99a834..aba54f36c2 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -45,6 +45,7 @@ #include #include #include // for operator<<, basic_ostream, endl +#include #include // for pair Fun4AllStreamingInputManager::Fun4AllStreamingInputManager(const std::string &name, const std::string &dstnodename, const std::string &topnodename) @@ -824,13 +825,11 @@ int Fun4AllStreamingInputManager::FillIntt() int server = intthititer->get_packetid(); // note : the felix server ID int felix_ch = intthititer->get_fee(); // note : the felix channel ID 0 - 13 - std::string hit_string = - Form("%" PRIu64 "_%d_%d_%d", - bco_full, FPHXbco, server, felix_ch - ); + std::string hit_string = std::format("{}_{}_{}_{}", + bco_full, FPHXbco, server, felix_ch); // note: "BCOFULL_FPHXBCO_FELIX_FEE" - if (m_InttRawHitCount_FEE.find(hit_string.c_str()) == m_InttRawHitCount_FEE.end()){ + if (!m_InttRawHitCount_FEE.contains(hit_string)){ m_InttRawHitCount_FEE[hit_string.c_str()] = 1; } else { @@ -879,23 +878,20 @@ int Fun4AllStreamingInputManager::FillIntt() } if (m_InttHitDuplication){ - for (auto pair : m_InttRawHitCount_FEE){ - - uint64_t ThisStrobe_HL_bco_full; - int ThisStrobe_HL_FPHXBCO; - int ThisStrobe_HL_server; - int ThisStrobe_HL_felix_ch; - - const int nparsed = sscanf( - pair.first.c_str(), - "%" SCNu64 "_%d_%d_%d", - &ThisStrobe_HL_bco_full, - &ThisStrobe_HL_FPHXBCO, - &ThisStrobe_HL_server, - &ThisStrobe_HL_felix_ch - ); - - if (nparsed != 4) + for (const auto& pair : m_InttRawHitCount_FEE){ + + uint64_t ThisStrobe_HL_bco_full = 0; + int ThisStrobe_HL_FPHXBCO = 0; + int ThisStrobe_HL_server = 0; + int ThisStrobe_HL_felix_ch = 0; + + char separator1 = 0; + char separator2 = 0; + char separator3 = 0; + + std::stringstream key_stream(pair.first); + if (!(key_stream >> ThisStrobe_HL_bco_full >> separator1 >> ThisStrobe_HL_FPHXBCO >> separator2 >> ThisStrobe_HL_server >> separator3 >> ThisStrobe_HL_felix_ch) || + separator1 != '_' || separator2 != '_' || separator3 != '_') { std::cerr << "Fun4AllStreamingInputManager::FillIntt(), Failed to parse hit key: " << pair.first.c_str() << std::endl; gSystem->Exit(1); From 64b9eac99d06dd39c51b83b35847684fb2a44ac1 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 2 Jul 2026 10:11:13 -0400 Subject: [PATCH 788/866] remove old crud, replace Clear() by Reset() for Simv3, implement rabbits suggestions --- .../CaloBase/TowerInfoContainerSimv3.cc | 23 +++++++--------- .../CaloBase/TowerInfoContainerSimv3.h | 1 + offline/packages/CaloBase/TowerInfoSimv3.cc | 26 ++++++++----------- offline/packages/CaloBase/TowerInfoSimv3.h | 4 --- offline/packages/CaloBase/TowerInfov1.cc | 5 ++-- 5 files changed, 23 insertions(+), 36 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc index 4c014dfc16..b44f1ceead 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc @@ -2,6 +2,7 @@ #include "TowerInfoSimv3.h" #include +#include #include @@ -30,8 +31,6 @@ TowerInfoContainerSimv3::TowerInfoContainerSimv3(DETECTOR detec) nchannels = 52; } _clones = new TClonesArray("TowerInfoSimv3", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv3"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,13 +44,13 @@ TowerInfoContainerSimv3::TowerInfoContainerSimv3(const TowerInfoContainerSimv3& , _clones(new TClonesArray("TowerInfoSimv3", (int) source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv3"); for (int i = 0; i < (int) source.size(); ++i) { // as tower numbers are fixed per event // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } @@ -71,23 +70,19 @@ void TowerInfoContainerSimv3::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); + TowerInfo *twr = (TowerInfoSimv3*) _clones->UncheckedAt(i); - if (obj == nullptr) + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.h b/offline/packages/CaloBase/TowerInfoContainerSimv3.h index 4a91ba5aec..e52213252e 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.h @@ -17,6 +17,7 @@ class TowerInfoContainerSimv3 : public TowerInfoContainer TowerInfoContainerSimv3() = default; PHObject *CloneMe() const override { return new TowerInfoContainerSimv3(*this); } TowerInfoContainerSimv3(const TowerInfoContainerSimv3 &); + TowerInfoContainerSimv3 &operator=(const TowerInfoContainerSimv3 &) = delete; ~TowerInfoContainerSimv3() override; diff --git a/offline/packages/CaloBase/TowerInfoSimv3.cc b/offline/packages/CaloBase/TowerInfoSimv3.cc index 07ee207664..3d2ad4d220 100644 --- a/offline/packages/CaloBase/TowerInfoSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoSimv3.cc @@ -2,30 +2,26 @@ #include "TowerInfo.h" +#include + +#include + void TowerInfoSimv3::Reset() { TowerInfoSimv1::Reset(); - for (short& i : _waveform) - { - i = 0; - } -} - -void TowerInfoSimv3::Clear(Option_t* /*unused*/) -{ - TowerInfoSimv1::Clear(); - for (short& i : _waveform) - { - i = 0; - } + std::ranges::fill(_waveform,0); } void TowerInfoSimv3::set_nsample(int nsample) { - if (nsample >= 0) + if (nsample > 0) { _waveform.resize(nsample, 0); + return; } + std::cout << PHWHERE << " invalid number of samples: " << nsample << std::endl; + gSystem->Exit(1); + exit(1); } int16_t TowerInfoSimv3::get_waveform_value(int index) const @@ -52,7 +48,7 @@ void TowerInfoSimv3::copy_tower(TowerInfo* tower) const int nsamples = tower->get_nsample(); if (nsamples <= 0) { - set_nsample(0); + _waveform.clear(); return; } set_nsample(nsamples); diff --git a/offline/packages/CaloBase/TowerInfoSimv3.h b/offline/packages/CaloBase/TowerInfoSimv3.h index 837ddad988..a718a8e03e 100644 --- a/offline/packages/CaloBase/TowerInfoSimv3.h +++ b/offline/packages/CaloBase/TowerInfoSimv3.h @@ -13,7 +13,6 @@ class TowerInfoSimv3 : public TowerInfoSimv1 ~TowerInfoSimv3() override = default; void Reset() override; - void Clear(Option_t* = "") override; void copy_tower(TowerInfo* tower) override; @@ -23,12 +22,9 @@ class TowerInfoSimv3 : public TowerInfoSimv1 void set_waveform_value(int index, int16_t value) override; private: - EdepMap _hitedeps; - ShowerEdepMap _showeredeps; std::vector _waveform; ClassDefOverride(TowerInfoSimv3, 1); - // Inherit other methods and properties from TowerInfoSimv1 }; #endif diff --git a/offline/packages/CaloBase/TowerInfov1.cc b/offline/packages/CaloBase/TowerInfov1.cc index 0a88070bc2..1a9907fa6f 100644 --- a/offline/packages/CaloBase/TowerInfov1.cc +++ b/offline/packages/CaloBase/TowerInfov1.cc @@ -11,13 +11,12 @@ TowerInfov1::TowerInfov1(TowerInfo& tower) void TowerInfov1::Reset() { _time = 0; - _energy = std::numeric_limits::quiet_NaN(); + _energy = 0; } void TowerInfov1::Clear(Option_t* /*unused*/) { - _time = 0; - _energy = 0; + TowerInfov1::Reset(); } void TowerInfov1::copy_tower(TowerInfo* tower) From 9164997e18eec1464a34f363b13b89ab089b2b8f Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Thu, 2 Jul 2026 11:38:29 -0400 Subject: [PATCH 789/866] tidy --- simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 057721ef3a..5a10831d2e 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -400,7 +400,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) else { float val = 1.0+ gsl_ran_gaussian(m_RandomGenerator,factor_const); - if(val < 0.0f) + if(val < 0.0F) { val = 0; } From e58b9400a47c22c85d4addd526a580d1777caa44 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Thu, 2 Jul 2026 16:01:44 -0400 Subject: [PATCH 790/866] CD: New KFP methods for variable calculation --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 222 +++++++++++++----- .../KFParticle_sPHENIX/KFParticle_Tools.h | 42 ++-- .../KFParticle_eventReconstruction.cc | 53 +++-- .../KFParticle_sPHENIX/KFParticle_nTuple.cc | 63 +++-- .../KFParticle_sPHENIX/KFParticle_nTuple.h | 23 +- .../KFParticle_sPHENIX/KFParticle_sPHENIX.h | 66 +++--- .../KFParticle_truthAndDetTools.cc | 34 ++- .../KFParticle_truthAndDetTools.h | 12 +- 8 files changed, 303 insertions(+), 212 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index d7067e4cef..68c260a6b2 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -85,10 +85,10 @@ KFParticle_Tools::KFParticle_Tools() , m_track_min_pt(0.) , m_track_max_pt(5e3) , m_track_ptchi2(std::numeric_limits::max()) - , m_track_ip_xy(-100.) - , m_track_ipchi2_xy(-1) - , m_track_ip(-1.) - , m_track_ipchi2(-1) + , m_track_PV_dca_xy(-100.) + , m_track_PV_dca_stddev_xy(-1) + , m_track_PV_dca(-1.) + , m_track_PV_dca_stddev(-1) , m_track_chi2ndof(100.) , m_nMVTXStates(3) , m_nINTTStates(1) @@ -101,7 +101,7 @@ KFParticle_Tools::KFParticle_Tools() , m_dira_min(-1.01) , m_dira_max(1.01) , m_mother_pt(0.) - , m_mother_ipchi2(std::numeric_limits::max()) + , m_mother_PV_dca_stddev(std::numeric_limits::max()) , m_get_charge_conjugate(false) , m_extrapolateTracksToSV(true) , m_vtx_map_node_name("SvtxVertexMap") @@ -444,10 +444,10 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart { bool goodTrack = false; - float min_ip = 0; - float min_ipchi2 = 0; - float min_ip_xy = 0; - float min_ipchi2_xy = 0; + float min_PV_dca = 0; + float min_PV_dca_stddev = 0; + float min_PV_dca_xy = 0; + float min_PV_dca_stddev_xy = 0; float pt = 0; float pterr = 0; @@ -461,10 +461,10 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart float ptchi2 = pow(pterr / pt, 2); float trackchi2ndof = particle.GetChi2() / particle.GetNDF(); - calcMinIP(particle, primaryVertices, min_ip, min_ipchi2); - calcMinIP(particle, primaryVertices, min_ip_xy, min_ipchi2_xy, false); + calcMinPV_DCA(particle, primaryVertices, min_PV_dca, min_PV_dca_stddev); + calcMinPV_DCA(particle, primaryVertices, min_PV_dca_xy, min_PV_dca_stddev_xy, false); - if (isInRange(m_track_min_pt, pt, m_track_max_pt) && ptchi2 <= m_track_ptchi2 && min_ip >= m_track_ip && min_ipchi2 >= m_track_ipchi2 && min_ip_xy >= m_track_ip_xy && min_ipchi2_xy >= m_track_ipchi2_xy && trackchi2ndof <= m_track_chi2ndof) + if (isInRange(m_track_min_pt, pt, m_track_max_pt) && ptchi2 <= m_track_ptchi2 && min_PV_dca >= m_track_PV_dca && min_PV_dca_stddev >= m_track_PV_dca_stddev && min_PV_dca_xy >= m_track_PV_dca_xy && min_PV_dca_stddev_xy >= m_track_PV_dca_stddev_xy && trackchi2ndof <= m_track_chi2ndof) { goodTrack = true; } @@ -477,10 +477,10 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart { printSelectionCheck("Track pT", m_track_min_pt, pt, m_track_max_pt); printSelectionCheck("Track pT chi^2", 0, ptchi2, m_track_ptchi2); - printSelectionCheck("IP", m_track_ip, min_ip, std::numeric_limits::max()); - printSelectionCheck("IP chi^2", m_track_ipchi2, min_ipchi2, std::numeric_limits::max()); - printSelectionCheck("IP xy", m_track_ip_xy, min_ip_xy, std::numeric_limits::max()); - printSelectionCheck("IP xy chi^2", m_track_ipchi2_xy, min_ipchi2_xy, std::numeric_limits::max()); + printSelectionCheck("PV DCA", m_track_PV_dca, min_PV_dca, std::numeric_limits::max()); + printSelectionCheck("PV DCA Std. Dev.", m_track_PV_dca_stddev, min_PV_dca_stddev, std::numeric_limits::max()); + printSelectionCheck("PV DCA xy", m_track_PV_dca_xy, min_PV_dca_xy, std::numeric_limits::max()); + printSelectionCheck("PV DCA xy Std. Dev.", m_track_PV_dca_stddev_xy, min_PV_dca_stddev_xy, std::numeric_limits::max()); printSelectionCheck("Track chi^2/nDoF", 0, trackchi2ndof, m_track_chi2ndof); } } @@ -488,49 +488,49 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart return goodTrack; } -int KFParticle_Tools::calcMinIP(const KFParticle &track, const std::vector &PVs, - float &minimumIP, float &minimumIPchi2, bool do3D) +int KFParticle_Tools::calcMinPV_DCA(const KFParticle &track, const std::vector &PVs, + float &minimumPV_DCA, float &minimumPV_DCA_stddev, bool do3D) { std::vector ip; - std::vector ipchi2; + std::vector ip_significance; for (const auto &PV : PVs) { - float thisIPchi2 = 0; + float thisPV_DCA_stddev = 0; if (do3D) { ip.push_back(track.GetDistanceFromVertex(PV)); - track.GetDeviationFromVertex(PV); + thisPV_DCA_stddev = track.GetDeviationFromVertex(PV); } else { ip.push_back(abs(track.GetDistanceFromVertexXY(PV))); - track.GetDeviationFromVertexXY(PV); + thisPV_DCA_stddev = track.GetDeviationFromVertexXY(PV); } - thisIPchi2 = std::max(thisIPchi2, 0.F); - ipchi2.push_back(thisIPchi2); // Τhere are times where the IPchi2 calc fails + thisPV_DCA_stddev = std::max(thisPV_DCA_stddev, 0.F); + ip_significance.push_back(thisPV_DCA_stddev); // Τhere are times where the PV_DCA_stddev calc fails } - auto minmax_ip = minmax_element(ip.begin(), ip.end()); // Order the IP from small to large - minimumIP = *minmax_ip.first; - auto minmax_ipchi2 = minmax_element(ipchi2.begin(), ipchi2.end()); // Order the IP chi2 from small to large - minimumIPchi2 = *minmax_ipchi2.first; + auto minmax_PV_dca = minmax_element(ip.begin(), ip.end()); // Order the PV_DCA from small to large + minimumPV_DCA = *minmax_PV_dca.first; + auto minmax_PV_dca_stddev = minmax_element(ip_significance.begin(), ip_significance.end()); // Order the PV_DCA chi2 from small to large + minimumPV_DCA_stddev = *minmax_PV_dca_stddev.first; return 0; } -std::vector KFParticle_Tools::findAllGoodTracks(const std::vector &daughterParticles, const std::vector &primaryVertices) +std::vector KFParticle_Tools::findAllGoodTracks(const std::vector &daughterParticles)//, const std::vector &primaryVertices) { std::vector goodTrackIndex; for (unsigned int i_parts = 0; i_parts < daughterParticles.size(); ++i_parts) { - if (isGoodTrack(daughterParticles[i_parts], primaryVertices)) - { + //if (isGoodTrack(daughterParticles[i_parts], primaryVertices)) + //{ goodTrackIndex.push_back(i_parts); - } + //} } removeDuplicates(goodTrackIndex); @@ -538,7 +538,7 @@ std::vector KFParticle_Tools::findAllGoodTracks(const std::vector> KFParticle_Tools::findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks) +std::vector> KFParticle_Tools::findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks, const std::vector &primaryVertices) { std::vector> goodTracksThatMeet; @@ -548,6 +548,39 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector dummy_tracks = {daughterParticles[*i_it], daughterParticles[*j_it]}; + if (m_require_bunch_crossing_match) + { + std::vector crossings; + for (auto &track : dummy_tracks) + { + SvtxTrack *thisTrack = toolSet.getTrack(track.Id(), m_dst_trackmap); + if (thisTrack) + { + crossings.push_back(thisTrack->get_crossing()); + } + } + + removeDuplicates(crossings); + + if (crossings.size() !=1) + { + continue; + } + } + + KFParticle dummy_mother; + dummy_mother.SetConstructMethod(2); + + for (auto &track : dummy_tracks) + { + dummy_mother.AddDaughter(track); + } + for (auto &track : dummy_tracks) + { + track.SetProductionVertex(dummy_mother); + } + float dca = daughterParticles[*i_it].GetDistanceFromParticle(daughterParticles[*j_it]); float dca_xy = abs(daughterParticles[*i_it].GetDistanceFromParticleXY(daughterParticles[*j_it])); @@ -575,19 +608,40 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector= m_min_radial_SV)); if (m_verbosity >= 11) { - printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); + printSelectionCheck("SV chi^2/nDoF", 0., vertexchi2ndof, m_vertex_chi2ndof); printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, std::numeric_limits::max()); } } - if (nTracks == 2 && vertexchi2ndof > m_vertex_chi2ndof) + //Now check if tracks are good as we need full reco to make DCA calc make sense + if (nTracks == 2) { - continue; - } + if (vertexchi2ndof > m_vertex_chi2ndof) + { + continue; + } + + if (sv_radial_position < m_min_radial_SV) + { + continue; + } + + bool rejectComboDueToTrack = false; + + for (auto &track : dummy_tracks) + { + bool trackPassesCuts = isGoodTrack(track, primaryVertices); + if (!trackPassesCuts) + { + rejectComboDueToTrack = true; + } + } + + if (rejectComboDueToTrack) + { + continue; + } - if (nTracks == 2 && sv_radial_position < m_min_radial_SV) - { - continue; } goodTracksThatMeet.push_back(combination); @@ -602,7 +656,7 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector> KFParticle_Tools::findNProngs(std::vector daughterParticles, const std::vector &goodTrackIndex, std::vector> goodTracksThatMeet, - int nRequiredTracks, unsigned int nProngs) + int nRequiredTracks, unsigned int nProngs, const std::vector &primaryVertices) { unsigned int nGoodProngs = goodTracksThatMeet.size(); @@ -653,6 +707,24 @@ std::vector> KFParticle_Tools::findNProngs(std::vector dummy_tracks; + for (auto &id : combination) + { + dummy_tracks.push_back(daughterParticles[id]); + } + dummy_mother.SetConstructMethod(2); + + for (auto &track : dummy_tracks) + { + dummy_mother.AddDaughter(track); + } + for (auto &track : dummy_tracks) + { + track.SetProductionVertex(dummy_mother); + } + float vertexchi2ndof = particleVertex.GetChi2() / particleVertex.GetNDF(); float sv_radial_position = sqrt(pow(particleVertex.GetX(), 2) + pow(particleVertex.GetY(), 2)); @@ -661,19 +733,38 @@ std::vector> KFParticle_Tools::findNProngs(std::vector= m_min_radial_SV)); if (m_verbosity >= 11) { - printSelectionCheck("SV chi^2/nDoFA", 0., vertexchi2ndof, m_vertex_chi2ndof); + printSelectionCheck("SV chi^2/nDoF", 0., vertexchi2ndof, m_vertex_chi2ndof); printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, std::numeric_limits::max()); } } - if ((unsigned int) nRequiredTracks == nProngs && vertexchi2ndof > m_vertex_chi2ndof) + if ((unsigned int) nRequiredTracks == nProngs) { - continue; - } + if (vertexchi2ndof > m_vertex_chi2ndof) + { + continue; + } - if ((unsigned int) nRequiredTracks == nProngs && sv_radial_position < m_min_radial_SV) - { - continue; + if (sv_radial_position < m_min_radial_SV) + { + continue; + } + + bool rejectComboDueToTrack = false; + + for (auto &track : dummy_tracks) + { + bool trackPassesCuts = isGoodTrack(track, primaryVertices); + if (!trackPassesCuts) + { + rejectComboDueToTrack = true; + } + } + + if (rejectComboDueToTrack) + { + continue; + } } goodTracksThatMeet.push_back(combination); @@ -692,7 +783,7 @@ std::vector> KFParticle_Tools::findNProngs(std::vector> KFParticle_Tools::appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks) +std::vector> KFParticle_Tools::appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks, const std::vector &primaryVertices) { std::vector> goodTracksThatMeet; std::vector> goodTracksThatMeetIntermediates; //, vectorOfGoodTracks; @@ -709,14 +800,14 @@ std::vector> KFParticle_Tools::appendTracksToIntermediates(KFPa { dummyTrackID.push_back(k); } - dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size()); + dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size(), primaryVertices); if (v_intermediateResonances.size() > 2) { for (unsigned int p = 3; p <= v_intermediateResonances.size(); ++p) { dummyTrackList = findNProngs(v_intermediateResonances, dummyTrackID, dummyTrackList, - (int) v_intermediateResonances.size(), (int) p); + (int) v_intermediateResonances.size(), (int) p, primaryVertices); } } @@ -729,11 +820,11 @@ std::vector> KFParticle_Tools::appendTracksToIntermediates(KFPa } else { - goodTracksThatMeet = findTwoProngs(daughterParticles, goodTrackIndex, num_remaining_tracks); + goodTracksThatMeet = findTwoProngs(daughterParticles, goodTrackIndex, num_remaining_tracks, primaryVertices); for (int p = 3; p <= num_remaining_tracks; ++p) { - goodTracksThatMeet = findNProngs(daughterParticles, goodTrackIndex, goodTracksThatMeet, num_remaining_tracks, p); + goodTracksThatMeet = findNProngs(daughterParticles, goodTrackIndex, goodTracksThatMeet, num_remaining_tracks, p, primaryVertices); } for (auto &i : goodTracksThatMeet) @@ -743,17 +834,18 @@ std::vector> KFParticle_Tools::appendTracksToIntermediates(KFPa std::vector dummyTrackID; // I already have the track ids stored in goodTracksThatMeet[i] for (int j : i) { - v_intermediateResonances.push_back(daughterParticles[i[j]]); + v_intermediateResonances.push_back(daughterParticles[j]); + //v_intermediateResonances.push_back(daughterParticles[i[j]]); } dummyTrackID.reserve(v_intermediateResonances.size()); for (unsigned int k = 0; k < v_intermediateResonances.size(); ++k) { dummyTrackID.push_back(k); } - dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size()); + dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size(), primaryVertices); for (unsigned int p = 3; p <= v_intermediateResonances.size(); ++p) { - dummyTrackList = findNProngs(v_intermediateResonances, dummyTrackID, dummyTrackList, (int) v_intermediateResonances.size(), (int) p); + dummyTrackList = findNProngs(v_intermediateResonances, dummyTrackID, dummyTrackList, (int) v_intermediateResonances.size(), (int) p, primaryVertices); } if (!dummyTrackList.empty()) @@ -1051,11 +1143,11 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida float calculated_fdchi2 = flightDistanceChi2(particle, vertex); - float calculated_ip_xy = abs(particle.GetDistanceFromVertexXY(vertex)); - float calculated_ipchi2_xy = particle.GetDeviationFromVertexXY(vertex); + float calculated_PV_dca_xy = abs(particle.GetDistanceFromVertexXY(vertex)); + float calculated_PV_dca_stddev_xy = particle.GetDeviationFromVertexXY(vertex); float calculated_dira_xy = eventDIRA(particle, vertex, false); - float calculated_ip = particle.GetDistanceFromVertex(vertex); - float calculated_ipchi2 = particle.GetDeviationFromVertex(vertex); + float calculated_PV_dca = particle.GetDistanceFromVertex(vertex); + float calculated_PV_dca_stddev = particle.GetDeviationFromVertex(vertex); float calculated_dira = eventDIRA(particle, vertex); float calculated_decay_time_significance = calculated_decayTime / calculated_decayTimeErr; @@ -1067,7 +1159,7 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida const float speed = 2.99792458e-2; calculated_decayTime /= speed; - if (calculated_fdchi2 >= m_fdchi2 && calculated_ip <= m_mother_ip && calculated_ipchi2 <= m_mother_ipchi2 && calculated_ip_xy <= m_mother_ip_xy && calculated_ipchi2_xy <= m_mother_ipchi2_xy && calculated_decay_time_significance >= m_mother_min_decay_time_significance && calculated_decay_length_significance >= m_mother_min_decay_length_significance && calculated_decay_length_xy_significance >= m_mother_min_decay_length_xy_significance && isInRange(m_dira_min, calculated_dira, m_dira_max) && isInRange(m_dira_xy_min, calculated_dira_xy, m_dira_xy_max) && isInRange(m_min_decayTime, calculated_decayTime, m_max_decayTime) && isInRange(m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy) && isInRange(m_min_decayLength, calculated_decayLength, m_max_decayLength) && isInRange(m_min_decayLength_xy, calculated_decayLength_xy, m_max_decayLength_xy)) + if (calculated_fdchi2 >= m_fdchi2 && calculated_PV_dca <= m_mother_PV_dca && calculated_PV_dca_stddev <= m_mother_PV_dca_stddev && calculated_PV_dca_xy <= m_mother_PV_dca_xy && calculated_PV_dca_stddev_xy <= m_mother_PV_dca_stddev_xy && calculated_decay_time_significance >= m_mother_min_decay_time_significance && calculated_decay_length_significance >= m_mother_min_decay_length_significance && calculated_decay_length_xy_significance >= m_mother_min_decay_length_xy_significance && isInRange(m_dira_min, calculated_dira, m_dira_max) && isInRange(m_dira_xy_min, calculated_dira_xy, m_dira_xy_max) && isInRange(m_min_decayTime, calculated_decayTime, m_max_decayTime) && isInRange(m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy) && isInRange(m_min_decayLength, calculated_decayLength, m_max_decayLength) && isInRange(m_min_decayLength_xy, calculated_decayLength_xy, m_max_decayLength_xy)) { goodCandidate = true; } @@ -1080,10 +1172,10 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida printSelectionCheck("Mother DIRA", m_dira_min, calculated_dira, m_dira_max); printSelectionCheck("Mother DIRA xy", m_dira_xy_min, calculated_dira_xy, m_dira_xy_max); printSelectionCheck("Mother FD chi^2", m_fdchi2, calculated_fdchi2, std::numeric_limits::max()); - printSelectionCheck("Mother IP", 0, calculated_ip, m_mother_ip); - printSelectionCheck("Mother IP chi^2", 0., calculated_ipchi2, m_mother_ipchi2); - printSelectionCheck("Mother IP xy", 0., calculated_ip_xy, m_mother_ip_xy); - printSelectionCheck("Mother IP xy chi^2", 0., calculated_ipchi2_xy, m_mother_ipchi2_xy); + printSelectionCheck("Mother PV DCA", 0, calculated_PV_dca, m_mother_PV_dca); + printSelectionCheck("Mother PV DCA Std. Dev.", 0., calculated_PV_dca_stddev, m_mother_PV_dca_stddev); + printSelectionCheck("Mother PV DCA xy", 0., calculated_PV_dca_xy, m_mother_PV_dca_xy); + printSelectionCheck("Mother PV DCA xy Std. Dev.", 0., calculated_PV_dca_stddev_xy, m_mother_PV_dca_stddev_xy); printSelectionCheck("Mother Decay Time", m_min_decayTime, calculated_decayTime, m_max_decayTime); printSelectionCheck("Mother Decay Time Significance", m_mother_min_decay_time_significance, calculated_decay_time_significance, std::numeric_limits::max()); printSelectionCheck("Mother Decay Time xy", m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 434a64cf4d..74514e3276 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -71,18 +71,18 @@ class KFParticle_Tools : protected KFParticle_MVA /*const*/ bool isGoodTrack(const KFParticle &particle, const std::vector &primaryVertices); - int calcMinIP(const KFParticle &track, const std::vector &PVs, float &minimumIP, float &minimumIPchi2, bool do3D = true); + int calcMinPV_DCA(const KFParticle &track, const std::vector &PVs, float &minimumPV_DCA, float &minimumPV_DCA_stddev, bool do3D = true); - std::vector findAllGoodTracks(const std::vector &daughterParticles, const std::vector &primaryVertices); + std::vector findAllGoodTracks(const std::vector &daughterParticles);//, const std::vector &primaryVertices); - std::vector> findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks); + std::vector> findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks, const std::vector &primaryVertices); std::vector> findNProngs(std::vector daughterParticles, const std::vector &goodTrackIndex, std::vector> goodTracksThatMeet, - int nRequiredTracks, unsigned int nProngs); + int nRequiredTracks, unsigned int nProngs, const std::vector &primaryVertices); - std::vector> appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks); + std::vector> appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks, const std::vector &primaryVertices); /// Calculates the cosine of the angle betweent the flight direction and momentum float eventDIRA(const KFParticle &particle, const KFParticle &vertex, bool do3D = true); @@ -142,14 +142,14 @@ class KFParticle_Tools : protected KFParticle_MVA std::vector m_intermediate_min_pt; std::vector m_intermediate_min_dira; std::vector m_intermediate_min_fdchi2; - std::vector m_intermediate_min_ip_xy; - std::vector m_intermediate_max_ip_xy; - std::vector m_intermediate_min_ipchi2_xy; - std::vector m_intermediate_max_ipchi2_xy; - std::vector m_intermediate_min_ip; - std::vector m_intermediate_max_ip; - std::vector m_intermediate_min_ipchi2; - std::vector m_intermediate_max_ipchi2; + std::vector m_intermediate_min_PV_dca_xy; + std::vector m_intermediate_max_PV_dca_xy; + std::vector m_intermediate_min_PV_dca_stddev_xy; + std::vector m_intermediate_max_PV_dca_stddev_xy; + std::vector m_intermediate_min_PV_dca; + std::vector m_intermediate_max_PV_dca; + std::vector m_intermediate_min_PV_dca_stddev; + std::vector m_intermediate_max_PV_dca_stddev; std::vector m_intermediate_vertex_volume; bool m_use_PID{false}; @@ -198,13 +198,13 @@ class KFParticle_Tools : protected KFParticle_MVA float m_track_ptchi2{std::numeric_limits::max()}; - float m_track_ip_xy{-100}; + float m_track_PV_dca_xy{-100}; - float m_track_ipchi2_xy{-1000}; + float m_track_PV_dca_stddev_xy{-1000}; - float m_track_ip{-1}; + float m_track_PV_dca{-1}; - float m_track_ipchi2{-1}; + float m_track_PV_dca_stddev{-1}; float m_track_chi2ndof{std::numeric_limits::max()}; @@ -234,13 +234,13 @@ class KFParticle_Tools : protected KFParticle_MVA float m_mother_pt{-1}; - float m_mother_ip{std::numeric_limits::max()}; + float m_mother_PV_dca{std::numeric_limits::max()}; - float m_mother_ipchi2{std::numeric_limits::max()}; + float m_mother_PV_dca_stddev{std::numeric_limits::max()}; - float m_mother_ip_xy{std::numeric_limits::max()}; + float m_mother_PV_dca_xy{std::numeric_limits::max()}; - float m_mother_ipchi2_xy{std::numeric_limits::max()}; + float m_mother_PV_dca_stddev_xy{std::numeric_limits::max()}; float m_mother_vertex_volume{std::numeric_limits::max()}; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index 3c40fd4e58..e8a22c2f24 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -74,7 +74,7 @@ void KFParticle_eventReconstruction::createDecay(PHCompositeNode* topNode, std:: nPVs = primaryVertices.size(); - std::vector goodTrackIndex = findAllGoodTracks(daughterParticles, primaryVertices); + std::vector goodTrackIndex = findAllGoodTracks(daughterParticles);//, primaryVertices); if (m_verbosity >= 10) { @@ -103,10 +103,10 @@ void KFParticle_eventReconstruction::buildBasicChain(std::vector& se const std::vector& goodTrackIndexBasic, const std::vector& primaryVerticesBasic, PHCompositeNode* topNode) { - std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesBasic, goodTrackIndexBasic, m_num_tracks); + std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesBasic, goodTrackIndexBasic, m_num_tracks, primaryVerticesBasic); for (int p = 3; p < m_num_tracks + 1; ++p) { - goodTracksThatMeet = findNProngs(daughterParticlesBasic, goodTrackIndexBasic, goodTracksThatMeet, m_num_tracks, p); + goodTracksThatMeet = findNProngs(daughterParticlesBasic, goodTrackIndexBasic, goodTracksThatMeet, m_num_tracks, p, primaryVerticesBasic); } if (m_verbosity >= 10) @@ -140,13 +140,13 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte for (int i = 0; i < m_num_intermediate_states; ++i) { std::vector vertices; - std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesAdv, goodTrackIndexAdv, m_num_tracks_from_intermediate[i]); + std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesAdv, goodTrackIndexAdv, m_num_tracks_from_intermediate[i], primaryVerticesAdv); for (int p = 3; p <= m_num_tracks_from_intermediate[i]; ++p) { goodTracksThatMeet = findNProngs(daughterParticlesAdv, goodTrackIndexAdv, goodTracksThatMeet, - m_num_tracks_from_intermediate[i], p); + m_num_tracks_from_intermediate[i], p, primaryVerticesAdv); } if (m_verbosity >= 10) @@ -156,8 +156,9 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte getCandidateDecay(potentialIntermediates[i], vertices, potentialDaughters[i], daughterParticlesAdv, goodTracksThatMeet, primaryVerticesAdv, track_start, track_stop, true, i, m_constrain_int_mass, topNode); - track_start += track_stop; + track_start = track_stop; track_stop += m_num_tracks_from_intermediate[i + 1]; + if (track_stop > m_num_tracks) break; } int num_tracks_used_by_intermediates = 0; for (int i = 0; i < m_num_intermediate_states; ++i) @@ -260,7 +261,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte uniqueCombinations = findUniqueDaughterCombinations(num_tracks_used_by_intermediates, m_num_tracks); // Unique comb of remaining trackIDs - listOfTracksToAppend = appendTracksToIntermediates(motherDecayProducts, daughterParticlesAdv, goodTrackIndexAdv_withoutIntermediates, num_remaining_tracks); + listOfTracksToAppend = appendTracksToIntermediates(motherDecayProducts, daughterParticlesAdv, goodTrackIndexAdv_withoutIntermediates, num_remaining_tracks, primaryVerticesAdv); for (auto& uniqueCombination : uniqueCombinations) { @@ -299,7 +300,8 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte m_constrain_to_vertex, false, 0, num_mother_decay_products, m_constrain_int_mass, required_unique_vertexID, topNode); if (isGood) { - + /* + * Moving this to SV calculation for speed if (m_require_bunch_crossing_match) { KFParticle_truthAndDetTools toolSet; @@ -330,6 +332,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte continue; } } + */ goodCandidates.push_back(candidate); if (m_constrain_to_vertex) @@ -468,16 +471,16 @@ void KFParticle_eventReconstruction::getCandidateDecay(std::vector& isIntermediate, intermediateNumber, nTracks, constrainMass, required_unique_vertexID, topNode); if (isIntermediate && isGood) { - float min_ip = 0; - float min_ipchi2 = 0; - float min_ip_xy = 0; - float min_ipchi2_xy = 0; - calcMinIP(candidate, primaryVerticesCand, min_ip, min_ipchi2); - calcMinIP(candidate, primaryVerticesCand, min_ip_xy , min_ipchi2_xy, false); - if (!isInRange(m_intermediate_min_ip[intermediateNumber], min_ip, m_intermediate_max_ip[intermediateNumber]) - || !isInRange(m_intermediate_min_ipchi2[intermediateNumber], min_ipchi2, m_intermediate_max_ipchi2[intermediateNumber]) - || !isInRange(m_intermediate_min_ip_xy[intermediateNumber], min_ip_xy, m_intermediate_max_ip_xy[intermediateNumber]) - || !isInRange(m_intermediate_min_ipchi2_xy[intermediateNumber], min_ipchi2_xy, m_intermediate_max_ipchi2_xy[intermediateNumber])) + float min_PV_dca = 0; + float min_PV_dca_stddev = 0; + float min_PV_dca_xy = 0; + float min_PV_dca_stddev_xy = 0; + calcMinPV_DCA(candidate, primaryVerticesCand, min_PV_dca, min_PV_dca_stddev); + calcMinPV_DCA(candidate, primaryVerticesCand, min_PV_dca_xy , min_PV_dca_stddev_xy, false); + if (!isInRange(m_intermediate_min_PV_dca[intermediateNumber], min_PV_dca, m_intermediate_max_PV_dca[intermediateNumber]) + || !isInRange(m_intermediate_min_PV_dca_stddev[intermediateNumber], min_PV_dca_stddev, m_intermediate_max_PV_dca_stddev[intermediateNumber]) + || !isInRange(m_intermediate_min_PV_dca_xy[intermediateNumber], min_PV_dca_xy, m_intermediate_max_PV_dca_xy[intermediateNumber]) + || !isInRange(m_intermediate_min_PV_dca_stddev_xy[intermediateNumber], min_PV_dca_stddev_xy, m_intermediate_max_PV_dca_stddev_xy[intermediateNumber])) { isGood = false; } @@ -571,21 +574,21 @@ int KFParticle_eventReconstruction::selectBestCombination(bool PVconstraint, boo } else { - float current_IPchi2 = 0; - float best_IPchi2 = 0; + float current_PV_DCAchi2 = 0; + float best_PV_DCAchi2 = 0; if (m_use_2D_matching_tools) { - current_IPchi2 = possibleCandidates[i].GetDeviationFromVertexXY(possibleVertex[i]); - best_IPchi2 = smallestMassError.GetDeviationFromVertexXY(possibleVertex[bestCombinationIndex]); + current_PV_DCAchi2 = possibleCandidates[i].GetDeviationFromVertexXY(possibleVertex[i]); + best_PV_DCAchi2 = smallestMassError.GetDeviationFromVertexXY(possibleVertex[bestCombinationIndex]); } else { - current_IPchi2 = possibleCandidates[i].GetDeviationFromVertex(possibleVertex[i]); - best_IPchi2 = smallestMassError.GetDeviationFromVertex(possibleVertex[bestCombinationIndex]); + current_PV_DCAchi2 = possibleCandidates[i].GetDeviationFromVertex(possibleVertex[i]); + best_PV_DCAchi2 = smallestMassError.GetDeviationFromVertex(possibleVertex[bestCombinationIndex]); } - if (current_IPchi2 < best_IPchi2) + if (current_PV_DCAchi2 < best_PV_DCAchi2) { smallestMassError = possibleCandidates[i]; bestCombinationIndex = i; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index 392e0c4267..8053b515ca 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -84,15 +84,15 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch(TString(mother_name) + "_DIRA", &m_calculated_mother_dira, TString(mother_name) + "_DIRA/F"); m_tree->Branch(TString(mother_name) + "_DIRA_xy", &m_calculated_mother_dira_xy, TString(mother_name) + "_DIRA_xy/F"); m_tree->Branch(TString(mother_name) + "_FDchi2", &m_calculated_mother_fdchi2, TString(mother_name) + "_FDchi2/F"); - m_tree->Branch(TString(mother_name) + "_IP", &m_calculated_mother_ip, TString(mother_name) + "_IP/F"); - m_tree->Branch(TString(mother_name) + "_IPchi2", &m_calculated_mother_ipchi2, TString(mother_name) + "_IPchi2/F"); - m_tree->Branch(TString(mother_name) + "_IPErr", &m_calculated_mother_ip_err, TString(mother_name) + "_IPErr/F"); - m_tree->Branch(TString(mother_name) + "_IP_xy", &m_calculated_mother_ip_xy, TString(mother_name) + "_IP_xy/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA", &m_calculated_mother_PV_dca, TString(mother_name) + "_PV_DCA/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA_StdDev", &m_calculated_mother_PV_dca_sig, TString(mother_name) + "_PV_DCA_StdDev/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA_Err", &m_calculated_mother_PV_dca_err, TString(mother_name) + "_PV_DCA_Err/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA_xy", &m_calculated_mother_PV_dca_xy, TString(mother_name) + "_PV_DCA_xy/F"); } if (m_get_all_PVs) { - m_tree->Branch(TString(mother_name) + "_IP_allPV", &allPV_mother_IP); - m_tree->Branch(TString(mother_name) + "_IPchi2_allPV", &allPV_mother_IPchi2); + m_tree->Branch(TString(mother_name) + "_PV_DCA_allPV", &allPV_mother_PV_DCA); + m_tree->Branch(TString(mother_name) + "_PV_DCA_StdDev_allPV", &allPV_mother_PV_DCA_StdDev); } m_tree->Branch(TString(mother_name) + "_x", &m_calculated_mother_x, TString(mother_name) + "_x/F"); m_tree->Branch(TString(mother_name) + "_y", &m_calculated_mother_y, TString(mother_name) + "_y/F"); @@ -144,15 +144,15 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch(TString(intermediate_name) + "_FDchi2", &m_calculated_intermediate_fdchi2[i], TString(intermediate_name) + "_FDchi2/F"); if (m_constrain_to_vertex_nTuple) { - m_tree->Branch(TString(intermediate_name) + "_IP", &m_calculated_intermediate_ip[i], TString(intermediate_name) + "_IP/F"); - m_tree->Branch(TString(intermediate_name) + "_IPchi2", &m_calculated_intermediate_ipchi2[i], TString(intermediate_name) + "_IPchi2/F"); - m_tree->Branch(TString(intermediate_name) + "_IPErr", &m_calculated_intermediate_ip_err[i], TString(intermediate_name) + "_IPErr/F"); - m_tree->Branch(TString(intermediate_name) + "_IP_xy", &m_calculated_intermediate_ip_xy[i], TString(intermediate_name) + "_IP_xy/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA", &m_calculated_intermediate_PV_dca[i], TString(intermediate_name) + "_PV_DCA/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_StdDev", &m_calculated_intermediate_PV_dca_sig[i], TString(intermediate_name) + "_PV_DCA_StdDev/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_Err", &m_calculated_intermediate_PV_dca_err[i], TString(intermediate_name) + "_PV_DCA_Err/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_xy", &m_calculated_intermediate_PV_dca_xy[i], TString(intermediate_name) + "_PV_DCA_xy/F"); } if (m_get_all_PVs) { - m_tree->Branch(TString(intermediate_name) + "_IP_allPV", &allPV_intermediates_IP[i]); - m_tree->Branch(TString(intermediate_name) + "_IPchi2_allPV", &allPV_intermediates_IPchi2[i]); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_allPV", &allPV_intermediates_PV_DCA[i]); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_StdDev_allPV", &allPV_intermediates_PV_DCA_StdDev[i]); } m_tree->Branch(TString(intermediate_name) + "_x", &m_calculated_intermediate_x[i], TString(intermediate_name) + "_x/F"); m_tree->Branch(TString(intermediate_name) + "_y", &m_calculated_intermediate_y[i], TString(intermediate_name) + "_y/F"); @@ -201,17 +201,16 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch(TString(daughter_number) + "_mass", &m_calculated_daughter_mass[i], TString(daughter_number) + "_mass/F"); if (m_constrain_to_vertex_nTuple) { - m_tree->Branch(TString(daughter_number) + "_IP", &m_calculated_daughter_ip[i], TString(daughter_number) + "_IP/F"); - m_tree->Branch(TString(daughter_number) + "_IPchi2", &m_calculated_daughter_ipchi2[i], TString(daughter_number) + "_IPchi2/F"); - m_tree->Branch(TString(daughter_number) + "_IPErr", &m_calculated_daughter_ip_err[i], TString(daughter_number) + "_IPErr/F"); - m_tree->Branch(TString(daughter_number) + "_IP_xy", &m_calculated_daughter_ip_xy[i], TString(daughter_number) + "_IP_xy/F"); - m_tree->Branch(TString(daughter_number) + "_DCA_sig", &m_calculated_daughter_PV_dca_sig[i], TString(daughter_number) + "_DCA_sig/F"); - m_tree->Branch(TString(daughter_number) + "_DCA_sig_xy", &m_calculated_daughter_PV_dca_xy_sig[i], TString(daughter_number) + "_DCA_sig_xy/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA", &m_calculated_daughter_PV_dca[i], TString(daughter_number) + "_PV_DCA/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_Err", &m_calculated_daughter_PV_dca_err[i], TString(daughter_number) + "_PV_DCA_Err/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_xy", &m_calculated_daughter_PV_dca_xy[i], TString(daughter_number) + "_PV_DCA_xy/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_sig", &m_calculated_daughter_PV_dca_sig[i], TString(daughter_number) + "_PV_DCA_sig/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_sig_xy", &m_calculated_daughter_PV_dca_xy_sig[i], TString(daughter_number) + "_PV_DCA_sig_xy/F"); } if (m_get_all_PVs) { - m_tree->Branch(TString(daughter_number) + "_IP_allPV", &allPV_daughter_IP[i]); - m_tree->Branch(TString(daughter_number) + "_IPchi2_allPV", &allPV_daughter_IPchi2[i]); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_allPV", &allPV_daughter_PV_DCA[i]); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_StdDev_allPV", &allPV_daughter_PV_DCA_StdDev[i]); } m_tree->Branch(TString(daughter_number) + "_x", &m_calculated_daughter_x[i], TString(daughter_number) + "_x/F"); m_tree->Branch(TString(daughter_number) + "_y", &m_calculated_daughter_y[i], TString(daughter_number) + "_y/F"); @@ -412,10 +411,10 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_calculated_mother_dira = kfpTupleTools.eventDIRA(motherParticle, vertex_fillbranch); m_calculated_mother_dira_xy = kfpTupleTools.eventDIRA(motherParticle, vertex_fillbranch, false); m_calculated_mother_fdchi2 = kfpTupleTools.flightDistanceChi2(motherParticle, vertex_fillbranch); - m_calculated_mother_ip = motherParticle.GetDistanceFromVertex(vertex_fillbranch); - m_calculated_mother_ipchi2 = motherParticle.GetDeviationFromVertex(vertex_fillbranch); - m_calculated_mother_ip_err = m_calculated_mother_ip / std::sqrt(m_calculated_mother_ipchi2); - m_calculated_mother_ip_xy = motherParticle.GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_mother_PV_dca = motherParticle.GetDistanceFromVertex(vertex_fillbranch); + m_calculated_mother_PV_dca_sig = motherParticle.GetDeviationFromVertex(vertex_fillbranch); + m_calculated_mother_PV_dca_err = m_calculated_mother_PV_dca / std::sqrt(m_calculated_mother_PV_dca_sig); + m_calculated_mother_PV_dca_xy = motherParticle.GetDistanceFromVertexXY(vertex_fillbranch); } m_calculated_mother_x = motherParticle.GetX(); m_calculated_mother_y = motherParticle.GetY(); @@ -454,10 +453,10 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_calculated_intermediate_fdchi2[i] = kfpTupleTools.flightDistanceChi2(intermediateArray[i], motherParticle); if (m_constrain_to_vertex_nTuple) { - m_calculated_intermediate_ip[i] = intermediateArray[i].GetDistanceFromVertex(vertex_fillbranch); - m_calculated_intermediate_ipchi2[i] = intermediateArray[i].GetDeviationFromVertex(vertex_fillbranch); - m_calculated_intermediate_ip_err[i] = m_calculated_intermediate_ip[i] / std::sqrt(m_calculated_intermediate_ipchi2[i]); - m_calculated_intermediate_ip_xy[i] = intermediateArray[i].GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_intermediate_PV_dca[i] = intermediateArray[i].GetDistanceFromVertex(vertex_fillbranch); + m_calculated_intermediate_PV_dca_sig[i] = intermediateArray[i].GetDeviationFromVertex(vertex_fillbranch); + m_calculated_intermediate_PV_dca_err[i] = m_calculated_intermediate_PV_dca[i] / std::sqrt(m_calculated_intermediate_PV_dca_sig[i]); + m_calculated_intermediate_PV_dca_xy[i] = intermediateArray[i].GetDistanceFromVertexXY(vertex_fillbranch); } m_calculated_intermediate_x[i] = intermediateArray[i].GetX(); m_calculated_intermediate_y[i] = intermediateArray[i].GetY(); @@ -502,10 +501,10 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_calculated_daughter_mass[i] = daughterArray[i].GetMass(); if (m_constrain_to_vertex_nTuple) { - m_calculated_daughter_ip[i] = daughterArray[i].GetDistanceFromVertex(vertex_fillbranch); - m_calculated_daughter_ipchi2[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); - m_calculated_daughter_ip_err[i] = m_calculated_daughter_ip[i] / std::sqrt(m_calculated_daughter_ipchi2[i]); - m_calculated_daughter_ip_xy[i] = daughterArray[i].GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_daughter_PV_dca[i] = daughterArray[i].GetDistanceFromVertex(vertex_fillbranch); + m_calculated_daughter_PV_dca_sig[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); + m_calculated_daughter_PV_dca_err[i] = m_calculated_daughter_PV_dca[i] / std::sqrt(m_calculated_daughter_PV_dca_sig[i]); + m_calculated_daughter_PV_dca_xy[i] = daughterArray[i].GetDistanceFromVertexXY(vertex_fillbranch); m_calculated_daughter_PV_dca_sig[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); m_calculated_daughter_PV_dca_xy_sig[i] = daughterArray[i].GetDeviationFromVertexXY(vertex_fillbranch); } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h index fd01a27a2f..cc84bf22c2 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h @@ -105,10 +105,10 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ float m_calculated_mother_dira{-1}; float m_calculated_mother_dira_xy{-1}; float m_calculated_mother_fdchi2{-1}; - float m_calculated_mother_ip{-1}; - float m_calculated_mother_ip_xy{-1}; - float m_calculated_mother_ipchi2{-1}; - float m_calculated_mother_ip_err{-1}; + float m_calculated_mother_PV_dca{-1}; + float m_calculated_mother_PV_dca_xy{-1}; + float m_calculated_mother_PV_dca_sig{-1}; + float m_calculated_mother_PV_dca_err{-1}; float m_calculated_mother_x{-1}; float m_calculated_mother_y{-1}; float m_calculated_mother_z{-1}; @@ -143,10 +143,10 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ float m_calculated_intermediate_decaylength_xy_err[max_intermediates]{0}; float m_calculated_intermediate_dira[max_intermediates]{0}; float m_calculated_intermediate_fdchi2[max_intermediates]{0}; - float m_calculated_intermediate_ip[max_intermediates]{0}; - float m_calculated_intermediate_ip_xy[max_intermediates]{0}; - float m_calculated_intermediate_ipchi2[max_intermediates]{0}; - float m_calculated_intermediate_ip_err[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca_xy[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca_sig[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca_err[max_intermediates]{0}; float m_calculated_intermediate_x[max_intermediates]{0}; float m_calculated_intermediate_y[max_intermediates]{0}; float m_calculated_intermediate_z[max_intermediates]{0}; @@ -172,12 +172,11 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ // static const int max_tracks {20}; float m_calculated_daughter_mass[max_tracks]{0}; - float m_calculated_daughter_ip[max_tracks]{0}; - float m_calculated_daughter_ip_xy[max_tracks]{0}; + float m_calculated_daughter_PV_dca[max_tracks]{0}; + float m_calculated_daughter_PV_dca_err[max_tracks]{0}; float m_calculated_daughter_PV_dca_sig[max_tracks]{0}; + float m_calculated_daughter_PV_dca_xy[max_tracks]{0}; float m_calculated_daughter_PV_dca_xy_sig[max_tracks]{0}; - float m_calculated_daughter_ipchi2[max_tracks]{0}; - float m_calculated_daughter_ip_err[max_tracks]{0}; float m_calculated_daughter_x[max_tracks]{0}; float m_calculated_daughter_y[max_tracks]{0}; float m_calculated_daughter_z[max_tracks]{0}; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 0812ed8f14..47809ca4e4 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -186,13 +186,13 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void setMaximumTrackPTchi2(float ptchi2) { m_track_ptchi2 = ptchi2; } - void setMinimumTrackIP_XY(float ip) { m_track_ip_xy = ip; } + void setMinimumTrackPV_DCA_XY(float ip) { m_track_PV_dca_xy = ip; } - void setMinimumTrackIPchi2_XY(float ipchi2) { m_track_ipchi2_xy = ipchi2; } + void setMinimumTrackPV_DCA_StdDev_XY(float ip_significance) { m_track_PV_dca_stddev_xy = ip_significance; } - void setMinimumTrackIP(float ip) { m_track_ip = ip; } + void setMinimumTrackPV_DCA(float ip) { m_track_PV_dca = ip; } - void setMinimumTrackIPchi2(float ipchi2) { m_track_ipchi2 = ipchi2; } + void setMinimumTrackPV_DCA_StdDev(float ip_significance) { m_track_PV_dca_stddev = ip_significance; } void setMaximumTrackchi2nDOF(float trackchi2ndof) { m_track_chi2ndof = trackchi2ndof; } @@ -202,7 +202,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void setMinTPChits(int nHits) { m_nTPCStates = nHits; } //Actually state counting but use this for backwards compatibility! - void setMinTPOThits(int nHits) { m_nTPCStates = nHits; } //Actually state counting but use this for backwards compatibility! + void setMinTPOThits(int nHits) { m_nTPOTStates = nHits; } //Actually state counting but use this for backwards compatibility! void setMaximumDaughterDCA_XY(float dca) { m_comb_DCA_xy = dca; } @@ -224,13 +224,13 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void setMotherPT(float mother_pt) { m_mother_pt = mother_pt; } - void setMotherIP(float mother_ip) { m_mother_ip = mother_ip; } + void setMotherPV_DCA(float mother_PV_dca) { m_mother_PV_dca = mother_PV_dca; } - void setMotherIP_XY(float mother_ip) { m_mother_ip_xy = mother_ip; } + void setMotherPV_DCA_XY(float mother_PV_dca) { m_mother_PV_dca_xy = mother_PV_dca; } - void setMotherIPchi2(float mother_ipchi2) { m_mother_ipchi2 = mother_ipchi2; } + void setMotherPV_DCA_StdDev(float mother_PV_dca_stddev) { m_mother_PV_dca_stddev = mother_PV_dca_stddev; } - void setMotherIPchi2_XY(float mother_ipchi2) { m_mother_ipchi2_xy = mother_ipchi2; } + void setMotherPV_DCA_StdDev_XY(float mother_PV_dca_stddev) { m_mother_PV_dca_stddev_xy = mother_PV_dca_stddev; } void setMaximumMotherVertexVolume(float vertexvol) { m_mother_vertex_volume = vertexvol; } @@ -275,59 +275,59 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K m_intermediate_min_pt = intermediate_min_pt; } - void setIntermediateMinIP_XY(const std::vector &intermediate_min_IP) + void setIntermediateMinPV_DCA_XY(const std::vector &intermediate_min_PV_DCA) { - for (unsigned int i = 0; i < intermediate_min_IP.size(); ++i) m_intermediate_min_ip_xy.push_back(intermediate_min_IP[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA.size(); ++i) m_intermediate_min_PV_dca_xy.push_back(intermediate_min_PV_DCA[i]); } - void setIntermediateIPRange_XY(const std::vector /*unused*/> &intermediate_IP_range) + void setIntermediatePV_DCARange_XY(const std::vector /*unused*/> &intermediate_PV_DCA_range) { - for (unsigned int i = 0; i < intermediate_IP_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_range.size(); ++i) { - m_intermediate_min_ip_xy.push_back(intermediate_IP_range[i].first); - m_intermediate_max_ip_xy.push_back(intermediate_IP_range[i].second); + m_intermediate_min_PV_dca_xy.push_back(intermediate_PV_DCA_range[i].first); + m_intermediate_max_PV_dca_xy.push_back(intermediate_PV_DCA_range[i].second); } } - void setIntermediateMinIP(const std::vector &intermediate_min_IP) + void setIntermediateMinPV_DCA(const std::vector &intermediate_min_PV_DCA) { - for (unsigned int i = 0; i < intermediate_min_IP.size(); ++i) m_intermediate_min_ip.push_back(intermediate_min_IP[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA.size(); ++i) m_intermediate_min_PV_dca.push_back(intermediate_min_PV_DCA[i]); } - void setIntermediateIPRange(const std::vector /*unused*/> &intermediate_IP_range) + void setIntermediatePV_DCARange(const std::vector /*unused*/> &intermediate_PV_DCA_range) { - for (unsigned int i = 0; i < intermediate_IP_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_range.size(); ++i) { - m_intermediate_min_ip.push_back(intermediate_IP_range[i].first); - m_intermediate_max_ip.push_back(intermediate_IP_range[i].second); + m_intermediate_min_PV_dca.push_back(intermediate_PV_DCA_range[i].first); + m_intermediate_max_PV_dca.push_back(intermediate_PV_DCA_range[i].second); } } - void setIntermediateMinIPchi2_XY(const std::vector &intermediate_min_IPchi2) + void setIntermediateMinPV_DCA_StdDev_XY(const std::vector &intermediate_min_PV_DCA_StdDev) { - for (unsigned int i = 0; i < intermediate_min_IPchi2.size(); ++i) m_intermediate_min_ipchi2_xy.push_back(intermediate_min_IPchi2[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA_StdDev.size(); ++i) m_intermediate_min_PV_dca_stddev_xy.push_back(intermediate_min_PV_DCA_StdDev[i]); } - void setIntermediateIPchi2Range_XY(const std::vector /*unused*/> &intermediate_IPchi2_range) + void setIntermediatePV_DCA_StdDevRange_XY(const std::vector /*unused*/> &intermediate_PV_DCA_StdDev_range) { - for (unsigned int i = 0; i < intermediate_IPchi2_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_StdDev_range.size(); ++i) { - m_intermediate_min_ipchi2_xy.push_back(intermediate_IPchi2_range[i].first); - m_intermediate_max_ipchi2_xy.push_back(intermediate_IPchi2_range[i].second); + m_intermediate_min_PV_dca_stddev_xy.push_back(intermediate_PV_DCA_StdDev_range[i].first); + m_intermediate_max_PV_dca_stddev_xy.push_back(intermediate_PV_DCA_StdDev_range[i].second); } } - void setIntermediateMinIPchi2(const std::vector &intermediate_min_IPchi2) + void setIntermediateMinPV_DCA_StdDev(const std::vector &intermediate_min_PV_DCA_StdDev) { - for (unsigned int i = 0; i < intermediate_min_IPchi2.size(); ++i) m_intermediate_min_ipchi2.push_back(intermediate_min_IPchi2[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA_StdDev.size(); ++i) m_intermediate_min_PV_dca_stddev.push_back(intermediate_min_PV_DCA_StdDev[i]); } - void setIntermediateIPchi2Range(const std::vector /*unused*/> &intermediate_IPchi2_range) + void setIntermediatePV_DCA_StdDevRange(const std::vector /*unused*/> &intermediate_PV_DCA_StdDev_range) { - for (unsigned int i = 0; i < intermediate_IPchi2_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_StdDev_range.size(); ++i) { - m_intermediate_min_ipchi2.push_back(intermediate_IPchi2_range[i].first); - m_intermediate_max_ipchi2.push_back(intermediate_IPchi2_range[i].second); + m_intermediate_min_PV_dca_stddev.push_back(intermediate_PV_DCA_StdDev_range[i].first); + m_intermediate_max_PV_dca_stddev.push_back(intermediate_PV_DCA_StdDev_range[i].second); } } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc index 14b353ff43..28a102150e 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc @@ -146,8 +146,8 @@ void KFParticle_truthAndDetTools::initializeTruthBranches(TTree *m_tree, int dau m_tree->Branch((daughter_number + "_true_ID").c_str(), &m_true_daughter_id[daughter_id], (daughter_number + "_true_ID/I").c_str()); if (m_constrain_to_vertex_truthMatch) { - m_tree->Branch((daughter_number + "_true_IP").c_str(), &m_true_daughter_ip[daughter_id], (daughter_number + "_true_IP/F").c_str()); - m_tree->Branch((daughter_number + "_true_IP_xy").c_str(), &m_true_daughter_ip_xy[daughter_id], (daughter_number + "_true_IP_xy/F").c_str()); + m_tree->Branch((daughter_number + "_true_PV_DCA").c_str(), &m_true_daughter_ip[daughter_id], (daughter_number + "_true_PV_DCA/F").c_str()); + m_tree->Branch((daughter_number + "_true_PV_DCA_xy").c_str(), &m_true_daughter_ip_xy[daughter_id], (daughter_number + "_true_PV_DCA_xy/F").c_str()); } m_tree->Branch((daughter_number + "_true_px").c_str(), &m_true_daughter_px[daughter_id], (daughter_number + "_true_px/F").c_str()); m_tree->Branch((daughter_number + "_true_py").c_str(), &m_true_daughter_py[daughter_id], (daughter_number + "_true_py/F").c_str()); @@ -289,8 +289,7 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre if (truePoint == nullptr && isParticleValid) { - // PHG4Particle *g4mother = m_truthinfo->GetParticle(g4particle->get_parent_id()); - PHG4Particle *g4mother = m_truthinfo->GetPrimaryParticle(g4particle->get_parent_id()); + PHG4Particle *g4mother = trutheval->get_parent_particle(g4particle); if (!g4mother) { std::cout << "KFParticle truth matching: True mother not found!\n"; @@ -299,7 +298,7 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre } else { - truePoint = m_truthinfo->GetVtx(g4mother->get_vtx_id()); // Note, this may not be the PV for a decay with tertiaries + truePoint = trutheval->get_vertex(g4mother); } } @@ -352,7 +351,6 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre void KFParticle_truthAndDetTools::fillGeant4Branch(PHG4Particle *particle, int daughter_id) { Float_t pT = sqrt(pow(particle->get_px(), 2) + pow(particle->get_py(), 2)); - m_true_daughter_track_history_PDG_ID[daughter_id].push_back(particle->get_pid()); m_true_daughter_track_history_PDG_mass[daughter_id].push_back(0); m_true_daughter_track_history_px[daughter_id].push_back((Float_t) particle->get_px()); @@ -1502,19 +1500,19 @@ void KFParticle_truthAndDetTools::allPVInfo(PHCompositeNode *topNode, allPV_y.push_back(primaryVertice.GetY()); allPV_z.push_back(primaryVertice.GetZ()); - allPV_mother_IP.push_back(motherParticle.GetDistanceFromVertex(primaryVertice)); - allPV_mother_IPchi2.push_back(motherParticle.GetDeviationFromVertex(primaryVertice)); + allPV_mother_PV_DCA.push_back(motherParticle.GetDistanceFromVertex(primaryVertice)); + allPV_mother_PV_DCA_StdDev.push_back(motherParticle.GetDeviationFromVertex(primaryVertice)); for (unsigned int j = 0; j < daughters.size(); ++j) { - allPV_daughter_IP[j].push_back(daughters[j].GetDistanceFromVertex(primaryVertice)); - allPV_daughter_IPchi2[j].push_back(daughters[j].GetDeviationFromVertex(primaryVertice)); + allPV_daughter_PV_DCA[j].push_back(daughters[j].GetDistanceFromVertex(primaryVertice)); + allPV_daughter_PV_DCA_StdDev[j].push_back(daughters[j].GetDeviationFromVertex(primaryVertice)); } for (unsigned int j = 0; j < intermediates.size(); ++j) { - allPV_intermediates_IP[j].push_back(intermediates[j].GetDistanceFromVertex(primaryVertice)); - allPV_intermediates_IPchi2[j].push_back(intermediates[j].GetDeviationFromVertex(primaryVertice)); + allPV_intermediates_PV_DCA[j].push_back(intermediates[j].GetDistanceFromVertex(primaryVertice)); + allPV_intermediates_PV_DCA_StdDev[j].push_back(intermediates[j].GetDeviationFromVertex(primaryVertice)); } } } @@ -1550,8 +1548,8 @@ void KFParticle_truthAndDetTools::clearVectors() detector_nStates_TPOT[i] = 0; // PV vectors - allPV_daughter_IP[i].clear(); - allPV_daughter_IPchi2[i].clear(); + allPV_daughter_PV_DCA[i].clear(); + allPV_daughter_PV_DCA_StdDev[i].clear(); // Detailed Calo if (m_get_detailed_calorimetry) @@ -1567,12 +1565,12 @@ void KFParticle_truthAndDetTools::clearVectors() allPV_z.clear(); allPV_z.clear(); - allPV_mother_IP.clear(); - allPV_mother_IPchi2.clear(); + allPV_mother_PV_DCA.clear(); + allPV_mother_PV_DCA_StdDev.clear(); for (int i = 0; i < m_num_intermediate_states_nTuple; ++i) { - allPV_intermediates_IP[i].clear(); - allPV_intermediates_IPchi2[i].clear(); + allPV_intermediates_PV_DCA[i].clear(); + allPV_intermediates_PV_DCA_StdDev[i].clear(); } } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h index 0dc0dff847..7d789cd5db 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h @@ -226,12 +226,12 @@ class KFParticle_truthAndDetTools std::vector allPV_x; std::vector allPV_y; std::vector allPV_z; - std::vector allPV_mother_IP; - std::vector allPV_mother_IPchi2; - std::vector allPV_daughter_IP[max_tracks]; - std::vector allPV_daughter_IPchi2[max_tracks]; - std::vector allPV_intermediates_IP[max_tracks]; - std::vector allPV_intermediates_IPchi2[max_tracks]; + std::vector allPV_mother_PV_DCA; + std::vector allPV_mother_PV_DCA_StdDev; + std::vector allPV_daughter_PV_DCA[max_tracks]; + std::vector allPV_daughter_PV_DCA_StdDev[max_tracks]; + std::vector allPV_intermediates_PV_DCA[max_tracks]; + std::vector allPV_intermediates_PV_DCA_StdDev[max_tracks]; PHG4TruthInfoContainer *m_truthinfo{nullptr}; PHHepMCGenEventMap *m_geneventmap{nullptr}; From 6f8ee41ff33e7b4b625da3be3046de85357d79d6 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Thu, 2 Jul 2026 17:55:24 -0400 Subject: [PATCH 791/866] CD: Patched DCA calculation in KFParticle --- .../KFParticle_sPHENIX/KFParticle_Tools.cc | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 68c260a6b2..1f0ca0ecf0 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -527,10 +527,7 @@ std::vector KFParticle_Tools::findAllGoodTracks(const std::vector> KFParticle_Tools::findTwoProngs(std::vector= 10) { @@ -597,8 +594,8 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector combination = {*i_it, *j_it}; @@ -675,10 +672,39 @@ std::vector> KFParticle_Tools::findNProngs(std::vector combination; + combination.push_back(i_it); for (unsigned int i = 0; i < nProngs - 1; ++i) { - float dca = daughterParticles[i_it].GetDistanceFromParticle(daughterParticles[goodTracksThatMeet[i_prongs][i]]); - float dca_xy = abs(daughterParticles[i_it].GetDistanceFromParticleXY(daughterParticles[goodTracksThatMeet[i_prongs][i]])); + particleVertex += daughterParticles[goodTracksThatMeet[i_prongs][i]]; + combination.push_back(goodTracksThatMeet[i_prongs][i]); + } + + KFParticle dummy_mother; + std::vector dummy_tracks; + for (auto &id : combination) + { + dummy_tracks.push_back(daughterParticles[id]); + } + dummy_mother.SetConstructMethod(2); + + for (auto &track : dummy_tracks) + { + dummy_mother.AddDaughter(track); + } + for (auto &track : dummy_tracks) + { + track.SetProductionVertex(dummy_mother); + } + + for (unsigned int i = 1; i < combination.size(); ++i) + { + float dca = dummy_tracks[0].GetDistanceFromParticle(dummy_tracks[i]); + float dca_xy = dummy_tracks[0].GetDistanceFromParticleXY(dummy_tracks[i]); if (m_verbosity >= 10) { @@ -698,33 +724,6 @@ std::vector> KFParticle_Tools::findNProngs(std::vector combination; - combination.push_back(i_it); - for (unsigned int i = 0; i < nProngs - 1; ++i) - { - particleVertex += daughterParticles[goodTracksThatMeet[i_prongs][i]]; - combination.push_back(goodTracksThatMeet[i_prongs][i]); - } - - KFParticle dummy_mother; - std::vector dummy_tracks; - for (auto &id : combination) - { - dummy_tracks.push_back(daughterParticles[id]); - } - dummy_mother.SetConstructMethod(2); - - for (auto &track : dummy_tracks) - { - dummy_mother.AddDaughter(track); - } - for (auto &track : dummy_tracks) - { - track.SetProductionVertex(dummy_mother); - } - float vertexchi2ndof = particleVertex.GetChi2() / particleVertex.GetNDF(); float sv_radial_position = sqrt(pow(particleVertex.GetX(), 2) + pow(particleVertex.GetY(), 2)); From bdedb9ee01baab1c8a616ddc49cc2e0a7bb9527e Mon Sep 17 00:00:00 2001 From: Cameron Dean <59485912+cdean-github@users.noreply.github.com> Date: Thu, 2 Jul 2026 18:27:16 -0400 Subject: [PATCH 792/866] Update offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../KFParticle_sPHENIX/KFParticle_eventReconstruction.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index e8a22c2f24..b99e0a32d8 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -156,6 +156,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte getCandidateDecay(potentialIntermediates[i], vertices, potentialDaughters[i], daughterParticlesAdv, goodTracksThatMeet, primaryVerticesAdv, track_start, track_stop, true, i, m_constrain_int_mass, topNode); + if (i + 1 >= m_num_intermediate_states) break; track_start = track_stop; track_stop += m_num_tracks_from_intermediate[i + 1]; if (track_stop > m_num_tracks) break; From d712e8af449657832111561705cd3c190b544afe Mon Sep 17 00:00:00 2001 From: Cameron Dean <59485912+cdean-github@users.noreply.github.com> Date: Thu, 2 Jul 2026 18:28:22 -0400 Subject: [PATCH 793/866] Update offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 1f0ca0ecf0..6e53eb267e 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -579,7 +579,7 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector= 10) { From 881bc722c3587798d591663a957f3d1deb3d3da2 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Thu, 2 Jul 2026 18:31:19 -0400 Subject: [PATCH 794/866] CD: CPP check suggestions --- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc | 2 +- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index 1f0ca0ecf0..4351412146 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -650,7 +650,7 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector> KFParticle_Tools::findNProngs(std::vector daughterParticles, +std::vector> KFParticle_Tools::findNProngs(const std::vector &daughterParticles, const std::vector &goodTrackIndex, std::vector> goodTracksThatMeet, int nRequiredTracks, unsigned int nProngs, const std::vector &primaryVertices) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 74514e3276..478701533a 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -77,7 +77,7 @@ class KFParticle_Tools : protected KFParticle_MVA std::vector> findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks, const std::vector &primaryVertices); - std::vector> findNProngs(std::vector daughterParticles, + std::vector> findNProngs(const std::vector &daughterParticles, const std::vector &goodTrackIndex, std::vector> goodTracksThatMeet, int nRequiredTracks, unsigned int nProngs, const std::vector &primaryVertices); From 3160f52675f30e1dcb981056de074a0113c34569 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 2 Jul 2026 20:01:04 -0400 Subject: [PATCH 795/866] Update CaloStatusSkimmer.cc --- .../packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 1ba5b822e4..3d94defdf6 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -177,7 +177,8 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_SEPD" << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + //Temporarily turned off the event abort because the sEPD towers were removed from calofitting dsts. + //return Fun4AllReturnCodes::ABORTEVENT; } const uint32_t ntowers = sepd_towers->size(); for (uint32_t ch = 0; ch < ntowers; ++ch) From d16b8f8e6530bf292f3b29e2910dcb6098ab2b02 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Thu, 2 Jul 2026 20:09:00 -0400 Subject: [PATCH 796/866] Update CaloStatusSkimmer.cc To make the change safer, only run the sEPD section if the towers doesn't evaluate to a nullptr --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 3d94defdf6..669d678c6d 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -1,7 +1,7 @@ #include "CaloStatusSkimmer.h" -#include #include +#include #include #include @@ -20,12 +20,11 @@ //____________________________________________________________________________.. CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) - : SubsysReco(name) + : SubsysReco(name) { - //std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; + // std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; } - //____________________________________________________________________________.. int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) { @@ -33,7 +32,7 @@ int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) if (b_produce_QA_histograms) { - auto* hm = QAHistManagerDef::getHistoManager(); + auto *hm = QAHistManagerDef::getHistoManager(); assert(hm); h_EMC_nTowers_notinstr = new TH1F("h_EMC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in EMCal; nNotInstrTowers; Counts", 24577, -0.5, 24576.5); @@ -177,32 +176,35 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) { std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_SEPD" << std::endl; } - //Temporarily turned off the event abort because the sEPD towers were removed from calofitting dsts. - //return Fun4AllReturnCodes::ABORTEVENT; + // Temporarily turned off the event abort because the sEPD towers were removed from calofitting dsts. + // return Fun4AllReturnCodes::ABORTEVENT; } - const uint32_t ntowers = sepd_towers->size(); - for (uint32_t ch = 0; ch < ntowers; ++ch) + if (sepd_towers) { - TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) + const uint32_t ntowers = sepd_towers->size(); + for (uint32_t ch = 0; ch < ntowers; ++ch) { - ++notinstr_sEPD; + TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_sEPD; + } } - } - if (Verbosity() > 9) - { - std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_sEPD << std::endl; - } + if (Verbosity() > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_sEPD << std::endl; + } - if(b_produce_QA_histograms) - { - h_sEPD_nTowers_notinstr->Fill(notinstr_sEPD); - } + if (b_produce_QA_histograms) + { + h_sEPD_nTowers_notinstr->Fill(notinstr_sEPD); + } - if (notinstr_sEPD >= m_sEPD_skim_threshold) - { - sEPD_skim_count++; + if (notinstr_sEPD >= m_sEPD_skim_threshold) + { + sEPD_skim_count++; + } } } @@ -234,7 +236,7 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_ZDC << std::endl; } - if(b_produce_QA_histograms) + if (b_produce_QA_histograms) { h_ZDC_nTowers_notinstr->Fill(notinstr_ZDC); } From 2b2daff79a82d508f8d401265bbb392fa775bfb5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 3 Jul 2026 09:03:29 -0400 Subject: [PATCH 797/866] use common encode/decode in base class, replace Clear() by Reset() --- .../packages/CaloBase/TowerInfoContainer.cc | 53 +++++++++++++ .../packages/CaloBase/TowerInfoContainer.h | 4 +- .../CaloBase/TowerInfoContainerSimv1.cc | 74 ++----------------- .../CaloBase/TowerInfoContainerSimv1.h | 7 +- .../CaloBase/TowerInfoContainerSimv2.cc | 74 ++----------------- .../CaloBase/TowerInfoContainerSimv2.h | 3 - .../CaloBase/TowerInfoContainerSimv3.cc | 53 ------------- .../CaloBase/TowerInfoContainerSimv3.h | 3 - .../packages/CaloBase/TowerInfoContainerv1.cc | 74 ++----------------- .../packages/CaloBase/TowerInfoContainerv1.h | 7 +- .../packages/CaloBase/TowerInfoContainerv2.cc | 74 ++----------------- .../packages/CaloBase/TowerInfoContainerv2.h | 3 - .../packages/CaloBase/TowerInfoContainerv3.cc | 74 ++----------------- .../packages/CaloBase/TowerInfoContainerv3.h | 7 +- .../packages/CaloBase/TowerInfoContainerv4.cc | 74 ++----------------- .../packages/CaloBase/TowerInfoContainerv4.h | 7 +- offline/packages/CaloBase/TowerInfoSimv1.cc | 8 -- offline/packages/CaloBase/TowerInfoSimv1.h | 1 - offline/packages/CaloBase/TowerInfoSimv2.cc | 9 --- offline/packages/CaloBase/TowerInfoSimv2.h | 1 - offline/packages/CaloBase/TowerInfov1.cc | 5 -- offline/packages/CaloBase/TowerInfov1.h | 3 - offline/packages/CaloBase/TowerInfov2.cc | 8 -- offline/packages/CaloBase/TowerInfov2.h | 2 - offline/packages/CaloBase/TowerInfov3.cc | 9 --- offline/packages/CaloBase/TowerInfov3.h | 1 - offline/packages/CaloBase/TowerInfov4.cc | 10 +-- offline/packages/CaloBase/TowerInfov4.h | 1 - 28 files changed, 106 insertions(+), 543 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoContainer.cc b/offline/packages/CaloBase/TowerInfoContainer.cc index 45f25d6fae..72091971aa 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.cc +++ b/offline/packages/CaloBase/TowerInfoContainer.cc @@ -77,3 +77,56 @@ unsigned int TowerInfoContainer::getTowerEtaBin(unsigned int key) unsigned int etabin = TowerInfoDefs::getCaloTowerEtaBin(key); return etabin; } + +unsigned int TowerInfoContainer::encode_key(unsigned int towerIndex) +{ + unsigned int key = 0; + if (get_detectorid() == DETECTOR::EMCAL) + { + key = TowerInfoContainer::encode_emcal(towerIndex); + } + else if (get_detectorid() == DETECTOR::HCAL) + { + key = TowerInfoContainer::encode_hcal(towerIndex); + } + else if (get_detectorid() == DETECTOR::SEPD) + { + key = TowerInfoContainer::encode_epd(towerIndex); + } + else if (get_detectorid() == DETECTOR::MBD) + { + key = TowerInfoContainer::encode_mbd(towerIndex); + } + else if (get_detectorid() == DETECTOR::ZDC) + { + key = TowerInfoContainer::encode_zdc(towerIndex); + } + return key; +} + +unsigned int TowerInfoContainer::decode_key(unsigned int tower_key) +{ + unsigned int index = 0; + + if (get_detectorid() == DETECTOR::EMCAL) + { + index = TowerInfoContainer::decode_emcal(tower_key); + } + else if (get_detectorid() == DETECTOR::HCAL) + { + index = TowerInfoContainer::decode_hcal(tower_key); + } + else if (get_detectorid() == DETECTOR::SEPD) + { + index = TowerInfoContainer::decode_epd(tower_key); + } + else if (get_detectorid() == DETECTOR::MBD) + { + index = TowerInfoContainer::decode_mbd(tower_key); + } + else if (get_detectorid() == DETECTOR::ZDC) + { + index = TowerInfoContainer::decode_zdc(tower_key); + } + return index; +} diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index 335d8f0a09..ec3296d088 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -36,8 +36,8 @@ class TowerInfoContainer : public PHObject virtual TowerInfo* get_tower_at_key(int /*key*/) { return nullptr; } virtual size_t size() const { return 0; } - virtual unsigned int encode_key(unsigned int /*towerIndex*/) { return std::numeric_limits::max(); } - virtual unsigned int decode_key(unsigned int /*towerIndex*/) { return std::numeric_limits::max(); } + virtual unsigned int encode_key(unsigned int towerIndex); + virtual unsigned int decode_key(unsigned int towerIndex); virtual unsigned int encode_epd(unsigned int /*towerIndex*/); virtual unsigned int encode_hcal(unsigned int /*towerIndex*/); diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc index 0c00f1b1b8..e505687345 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc @@ -2,6 +2,7 @@ #include "TowerInfoSimv1.h" #include +#include #include @@ -30,8 +31,6 @@ TowerInfoContainerSimv1::TowerInfoContainerSimv1(DETECTOR detec) nchannels = 52; } _clones = new TClonesArray("TowerInfoSimv1", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv1"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,8 +44,6 @@ TowerInfoContainerSimv1::TowerInfoContainerSimv1(const TowerInfoContainerSimv1& , _clones(new TClonesArray("TowerInfoSimv1", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv1"); for (unsigned int i = 0; i < source.size(); ++i) { // as tower numbers are fixed per event @@ -71,23 +68,19 @@ void TowerInfoContainerSimv1::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); - - if (obj == nullptr) + TowerInfo *twr = (TowerInfoSimv1 *) _clones->UncheckedAt(i); + + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +94,3 @@ TowerInfoSimv1* TowerInfoContainerSimv1::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfoSimv1*) _clones->At(index); } - -unsigned int TowerInfoContainerSimv1::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerSimv1::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.h b/offline/packages/CaloBase/TowerInfoContainerSimv1.h index 0053a5c1c5..d53e343ddd 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.h @@ -26,15 +26,12 @@ class TowerInfoContainerSimv1 : public TowerInfoContainer TowerInfoSimv1 *get_tower_at_channel(int pos) override; TowerInfoSimv1 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones {nullptr}; + DETECTOR _detector {DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerSimv1, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc index 479d21d68a..f82aac9f6d 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc @@ -2,6 +2,7 @@ #include "TowerInfoSimv2.h" #include +#include #include @@ -30,8 +31,6 @@ TowerInfoContainerSimv2::TowerInfoContainerSimv2(DETECTOR detec) nchannels = 52; } _clones = new TClonesArray("TowerInfoSimv2", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv2"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,8 +44,6 @@ TowerInfoContainerSimv2::TowerInfoContainerSimv2(const TowerInfoContainerSimv2& , _clones(new TClonesArray("TowerInfoSimv2", (int) source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv2"); for (int i = 0; i < (int) source.size(); ++i) { // as tower numbers are fixed per event @@ -71,23 +68,19 @@ void TowerInfoContainerSimv2::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); - - if (obj == nullptr) + TowerInfo *twr = (TowerInfoSimv2 *) _clones->UncheckedAt(i); + + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +94,3 @@ TowerInfoSimv2* TowerInfoContainerSimv2::get_tower_at_key(int pos) int index = (int) decode_key(pos); return (TowerInfoSimv2*) _clones->At(index); } - -unsigned int TowerInfoContainerSimv2::encode_key(unsigned int towerIndex) -{ - unsigned int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerSimv2::decode_key(unsigned int tower_key) -{ - unsigned int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.h b/offline/packages/CaloBase/TowerInfoContainerSimv2.h index c5a467b3be..8ad1e473f6 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.h @@ -26,9 +26,6 @@ class TowerInfoContainerSimv2 : public TowerInfoContainer TowerInfoSimv2 *get_tower_at_channel(int pos) override; TowerInfoSimv2 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc index b44f1ceead..440f16caae 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc @@ -96,56 +96,3 @@ TowerInfoSimv3* TowerInfoContainerSimv3::get_tower_at_key(int pos) int index = (int) decode_key(pos); return (TowerInfoSimv3*) _clones->At(index); } - -unsigned int TowerInfoContainerSimv3::encode_key(unsigned int towerIndex) -{ - unsigned int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerSimv3::decode_key(unsigned int tower_key) -{ - unsigned int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.h b/offline/packages/CaloBase/TowerInfoContainerSimv3.h index e52213252e..721085418d 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.h @@ -27,9 +27,6 @@ class TowerInfoContainerSimv3 : public TowerInfoContainer TowerInfoSimv3 *get_tower_at_channel(int pos) override; TowerInfoSimv3 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index bfddca6e40..7325247618 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -2,6 +2,7 @@ #include "TowerInfov1.h" #include +#include #include @@ -30,8 +31,6 @@ TowerInfoContainerv1::TowerInfoContainerv1(DETECTOR detec) nchannels = 52; } _clones = new TClonesArray("TowerInfov1", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv1"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -50,8 +49,6 @@ TowerInfoContainerv1::TowerInfoContainerv1(const TowerInfoContainerv1& source) , _clones(new TClonesArray("TowerInfov1", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv1"); for (unsigned int i = 0; i < source.size(); ++i) { // as tower numbers are fixed per event @@ -71,23 +68,19 @@ void TowerInfoContainerv1::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); - - if (obj == nullptr) + TowerInfo *twr = (TowerInfov1 *) _clones->UncheckedAt(i); + + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +94,3 @@ TowerInfov1* TowerInfoContainerv1::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov1*) _clones->At(index); } - -unsigned int TowerInfoContainerv1::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainerv1::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainerv1::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainerv1::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainerv1::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainerv1::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv1::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainerv1::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainerv1::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainerv1::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainerv1::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainerv1::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.h b/offline/packages/CaloBase/TowerInfoContainerv1.h index 7267482c18..067a44d014 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerv1.h @@ -29,15 +29,12 @@ class TowerInfoContainerv1 : public TowerInfoContainer TowerInfov1 *get_tower_at_channel(int pos) override; TowerInfov1 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones {nullptr}; + DETECTOR _detector {DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv1, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.cc b/offline/packages/CaloBase/TowerInfoContainerv2.cc index 94d3378945..5c53f241f2 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv2.cc @@ -2,6 +2,7 @@ #include "TowerInfov2.h" #include +#include #include @@ -30,8 +31,6 @@ TowerInfoContainerv2::TowerInfoContainerv2(DETECTOR detec) nchannels = 52; } _clones = new TClonesArray("TowerInfov2", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv2"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,8 +44,6 @@ TowerInfoContainerv2::TowerInfoContainerv2(const TowerInfoContainerv2& source) , _clones(new TClonesArray("TowerInfov2", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv2"); for (unsigned int i = 0; i < source.size(); ++i) { // as tower numbers are fixed per event @@ -71,23 +68,19 @@ void TowerInfoContainerv2::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); - - if (obj == nullptr) + TowerInfo *twr = (TowerInfov2 *) _clones->UncheckedAt(i); + + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +94,3 @@ TowerInfov2* TowerInfoContainerv2::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov2*) _clones->At(index); } - -unsigned int TowerInfoContainerv2::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv2::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.h b/offline/packages/CaloBase/TowerInfoContainerv2.h index 1c39159828..61fcaa240e 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.h +++ b/offline/packages/CaloBase/TowerInfoContainerv2.h @@ -30,9 +30,6 @@ class TowerInfoContainerv2 : public TowerInfoContainer TowerInfov2 *get_tower_at_channel(int pos) override; TowerInfov2 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.cc b/offline/packages/CaloBase/TowerInfoContainerv3.cc index 5397eecbb6..331347acc1 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv3.cc @@ -2,6 +2,7 @@ #include "TowerInfov3.h" #include +#include #include @@ -30,8 +31,6 @@ TowerInfoContainerv3::TowerInfoContainerv3(DETECTOR detec) nchannels = 52; } _clones = new TClonesArray("TowerInfov3", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv3"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,8 +44,6 @@ TowerInfoContainerv3::TowerInfoContainerv3(const TowerInfoContainerv3& source) , _clones(new TClonesArray("TowerInfov3", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv3"); for (unsigned int i = 0; i < source.size(); ++i) { // as tower numbers are fixed per event @@ -71,23 +68,19 @@ void TowerInfoContainerv3::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); - - if (obj == nullptr) + TowerInfo *twr = (TowerInfov3 *) _clones->UncheckedAt(i); + + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +94,3 @@ TowerInfov3* TowerInfoContainerv3::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov3*) _clones->At(index); } - -unsigned int TowerInfoContainerv3::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv3::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.h b/offline/packages/CaloBase/TowerInfoContainerv3.h index c8d89670cd..ca771fe897 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.h +++ b/offline/packages/CaloBase/TowerInfoContainerv3.h @@ -29,15 +29,12 @@ class TowerInfoContainerv3 : public TowerInfoContainer TowerInfov3 *get_tower_at_channel(int pos) override; TowerInfov3 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones {nullptr}; + DETECTOR _detector {DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv3, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.cc b/offline/packages/CaloBase/TowerInfoContainerv4.cc index b124ba27c7..ecd939ef60 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv4.cc @@ -2,6 +2,7 @@ #include "TowerInfov4.h" #include +#include #include @@ -30,8 +31,6 @@ TowerInfoContainerv4::TowerInfoContainerv4(DETECTOR detec) nchannels = 52; } _clones = new TClonesArray("TowerInfov4", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv4"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,8 +44,6 @@ TowerInfoContainerv4::TowerInfoContainerv4(const TowerInfoContainerv4& source) , _clones(new TClonesArray("TowerInfov4", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv4"); for (unsigned int i = 0; i < source.size(); ++i) { // as tower numbers are fixed per event @@ -71,23 +68,19 @@ void TowerInfoContainerv4::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); - - if (obj == nullptr) + TowerInfo *twr = (TowerInfov4 *) _clones->UncheckedAt(i); + + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +94,3 @@ TowerInfov4* TowerInfoContainerv4::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov4*) _clones->At(index); } - -unsigned int TowerInfoContainerv4::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv4::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.h b/offline/packages/CaloBase/TowerInfoContainerv4.h index df7af1b974..5b633b61b1 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.h +++ b/offline/packages/CaloBase/TowerInfoContainerv4.h @@ -30,15 +30,12 @@ class TowerInfoContainerv4 : public TowerInfoContainer TowerInfov4 *get_tower_at_channel(int pos) override; TowerInfov4 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones {nullptr}; + DETECTOR _detector {DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv4, 1); diff --git a/offline/packages/CaloBase/TowerInfoSimv1.cc b/offline/packages/CaloBase/TowerInfoSimv1.cc index bd6c09b02b..c43e325f69 100644 --- a/offline/packages/CaloBase/TowerInfoSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoSimv1.cc @@ -10,14 +10,6 @@ void TowerInfoSimv1::Reset() return; } -void TowerInfoSimv1::Clear(Option_t* /*unused*/) -{ - TowerInfov2::Clear(); - _hitedeps.clear(); - _showeredeps.clear(); - return; -} - void TowerInfoSimv1::copy_tower(TowerInfo* tower) { TowerInfov2::copy_tower(tower); diff --git a/offline/packages/CaloBase/TowerInfoSimv1.h b/offline/packages/CaloBase/TowerInfoSimv1.h index 796e8c7c50..11ae8d0d23 100644 --- a/offline/packages/CaloBase/TowerInfoSimv1.h +++ b/offline/packages/CaloBase/TowerInfoSimv1.h @@ -10,7 +10,6 @@ class TowerInfoSimv1 : public TowerInfov2 ~TowerInfoSimv1() override = default; void Reset() override; - void Clear(Option_t* = "") override; void copy_tower(TowerInfo* tower) override; diff --git a/offline/packages/CaloBase/TowerInfoSimv2.cc b/offline/packages/CaloBase/TowerInfoSimv2.cc index e14e6686bf..d20944f354 100644 --- a/offline/packages/CaloBase/TowerInfoSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoSimv2.cc @@ -11,15 +11,6 @@ void TowerInfoSimv2::Reset() } } -void TowerInfoSimv2::Clear(Option_t* /*unused*/) -{ - TowerInfoSimv1::Clear(); - for (short& i : _waveform) - { - i = 0; - } -} - int16_t TowerInfoSimv2::get_waveform_value(int index) const { if (index >= 0 && index < nsample) diff --git a/offline/packages/CaloBase/TowerInfoSimv2.h b/offline/packages/CaloBase/TowerInfoSimv2.h index 88492a0af4..07ab6025c4 100644 --- a/offline/packages/CaloBase/TowerInfoSimv2.h +++ b/offline/packages/CaloBase/TowerInfoSimv2.h @@ -12,7 +12,6 @@ class TowerInfoSimv2 : public TowerInfoSimv1 ~TowerInfoSimv2() override = default; void Reset() override; - void Clear(Option_t* = "") override; void copy_tower(TowerInfo* tower) override; diff --git a/offline/packages/CaloBase/TowerInfov1.cc b/offline/packages/CaloBase/TowerInfov1.cc index 1a9907fa6f..c6b9609d79 100644 --- a/offline/packages/CaloBase/TowerInfov1.cc +++ b/offline/packages/CaloBase/TowerInfov1.cc @@ -14,11 +14,6 @@ void TowerInfov1::Reset() _energy = 0; } -void TowerInfov1::Clear(Option_t* /*unused*/) -{ - TowerInfov1::Reset(); -} - void TowerInfov1::copy_tower(TowerInfo* tower) { set_time(tower->get_time()); diff --git a/offline/packages/CaloBase/TowerInfov1.h b/offline/packages/CaloBase/TowerInfov1.h index cab6dc539e..1d1ee792ea 100644 --- a/offline/packages/CaloBase/TowerInfov1.h +++ b/offline/packages/CaloBase/TowerInfov1.h @@ -11,9 +11,6 @@ class TowerInfov1 : public TowerInfo ~TowerInfov1() override = default; void Reset() override; - //! Clear is used by TClonesArray to reset the tower to initial state without calling destructor/constructor - void Clear(Option_t* = "") override; - void set_time(float t) override { _time = t * 1000; } float get_time() override { return _time / 1000.; } void set_time_short(short t) override { _time = t * 1000; } diff --git a/offline/packages/CaloBase/TowerInfov2.cc b/offline/packages/CaloBase/TowerInfov2.cc index ff21ed4957..149d59eac8 100644 --- a/offline/packages/CaloBase/TowerInfov2.cc +++ b/offline/packages/CaloBase/TowerInfov2.cc @@ -9,14 +9,6 @@ void TowerInfov2::Reset() _status = 0; } -void TowerInfov2::Clear(Option_t* /*unused*/) -{ - TowerInfov1::Clear(); - _chi2 = 0; - _pedestal = 0; - _status = 0; -} - void TowerInfov2::copy_tower(TowerInfo* tower) { TowerInfov1::copy_tower(tower); diff --git a/offline/packages/CaloBase/TowerInfov2.h b/offline/packages/CaloBase/TowerInfov2.h index dd8889ff48..983ecfa145 100644 --- a/offline/packages/CaloBase/TowerInfov2.h +++ b/offline/packages/CaloBase/TowerInfov2.h @@ -13,8 +13,6 @@ class TowerInfov2 : public TowerInfov1 ~TowerInfov2() override = default; void Reset() override; - void Clear(Option_t* = "") override; - void set_chi2(float chi2) override { _chi2 = chi2; } float get_chi2() override { return _chi2; } diff --git a/offline/packages/CaloBase/TowerInfov3.cc b/offline/packages/CaloBase/TowerInfov3.cc index 6f6ee0925c..7695ed525d 100644 --- a/offline/packages/CaloBase/TowerInfov3.cc +++ b/offline/packages/CaloBase/TowerInfov3.cc @@ -10,15 +10,6 @@ void TowerInfov3::Reset() } } -void TowerInfov3::Clear(Option_t* /*unused*/) -{ - TowerInfov2::Clear(); - for (short& i : _waveform) - { - i = 0; - } -} - int16_t TowerInfov3::get_waveform_value(int index) const { if (index >= 0 && index < nsample) diff --git a/offline/packages/CaloBase/TowerInfov3.h b/offline/packages/CaloBase/TowerInfov3.h index 4cf8f396f1..51a6d53455 100644 --- a/offline/packages/CaloBase/TowerInfov3.h +++ b/offline/packages/CaloBase/TowerInfov3.h @@ -12,7 +12,6 @@ class TowerInfov3 : public TowerInfov2 ~TowerInfov3() override = default; void Reset() override; - void Clear(Option_t* = "") override; // Getter and setter for waveform int get_nsample() const override { return nsample; } diff --git a/offline/packages/CaloBase/TowerInfov4.cc b/offline/packages/CaloBase/TowerInfov4.cc index e1b95ba4f3..fb694b7c34 100644 --- a/offline/packages/CaloBase/TowerInfov4.cc +++ b/offline/packages/CaloBase/TowerInfov4.cc @@ -5,16 +5,8 @@ void TowerInfov4::Reset() { - energy = std::numeric_limits::quiet_NaN(); - time = 0; - chi2 = 0; - status = 0; -} - -void TowerInfov4::Clear(Option_t* /*unused*/) -{ - time = 0; energy = 0; + time = 0; chi2 = 0; status = 0; } diff --git a/offline/packages/CaloBase/TowerInfov4.h b/offline/packages/CaloBase/TowerInfov4.h index 6a44ca385b..f371422329 100644 --- a/offline/packages/CaloBase/TowerInfov4.h +++ b/offline/packages/CaloBase/TowerInfov4.h @@ -15,7 +15,6 @@ class TowerInfov4 : public TowerInfo ~TowerInfov4() override = default; void Reset() override; - void Clear(Option_t* = "") override; void set_energy(float _energy) override { energy = _energy; } float get_energy() override { return energy; } From 7036b8ecc095426bf2389a4a41e0542ea49468cf Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 3 Jul 2026 09:47:44 -0400 Subject: [PATCH 798/866] use common get_channel, add TowerInfov5 for variable size waveform samples --- offline/packages/CaloBase/Makefile.am | 6 ++ .../packages/CaloBase/TowerInfoContainer.cc | 26 +++++++ .../packages/CaloBase/TowerInfoContainer.h | 3 +- .../CaloBase/TowerInfoContainerSimv1.cc | 22 +----- .../CaloBase/TowerInfoContainerSimv2.cc | 22 +----- .../CaloBase/TowerInfoContainerSimv3.cc | 22 +----- .../packages/CaloBase/TowerInfoContainerv1.cc | 22 +----- .../packages/CaloBase/TowerInfoContainerv2.cc | 22 +----- .../packages/CaloBase/TowerInfoContainerv3.cc | 22 +----- .../packages/CaloBase/TowerInfoContainerv4.cc | 22 +----- .../packages/CaloBase/TowerInfoContainerv5.cc | 76 +++++++++++++++++++ .../packages/CaloBase/TowerInfoContainerv5.h | 43 +++++++++++ .../CaloBase/TowerInfoContainerv5LinkDef.h | 5 ++ offline/packages/CaloBase/TowerInfov5.cc | 69 +++++++++++++++++ offline/packages/CaloBase/TowerInfov5.h | 33 ++++++++ .../packages/CaloBase/TowerInfov5LinkDef.h | 5 ++ 16 files changed, 272 insertions(+), 148 deletions(-) create mode 100644 offline/packages/CaloBase/TowerInfoContainerv5.cc create mode 100644 offline/packages/CaloBase/TowerInfoContainerv5.h create mode 100644 offline/packages/CaloBase/TowerInfoContainerv5LinkDef.h create mode 100644 offline/packages/CaloBase/TowerInfov5.cc create mode 100644 offline/packages/CaloBase/TowerInfov5.h create mode 100644 offline/packages/CaloBase/TowerInfov5LinkDef.h diff --git a/offline/packages/CaloBase/Makefile.am b/offline/packages/CaloBase/Makefile.am index 581e42ff61..de70f081e1 100644 --- a/offline/packages/CaloBase/Makefile.am +++ b/offline/packages/CaloBase/Makefile.am @@ -59,6 +59,7 @@ pkginclude_HEADERS = \ TowerInfov2.h \ TowerInfov3.h \ TowerInfov4.h \ + TowerInfov5.h \ TowerInfoSimv1.h \ TowerInfoSimv2.h \ TowerInfoSimv3.h \ @@ -67,6 +68,7 @@ pkginclude_HEADERS = \ TowerInfoContainerv2.h \ TowerInfoContainerv3.h \ TowerInfoContainerv4.h \ + TowerInfoContainerv5.h \ TowerInfoContainerSimv1.h \ TowerInfoContainerSimv2.h \ TowerInfoContainerSimv3.h @@ -96,6 +98,7 @@ ROOTDICTS = \ TowerInfov2_Dict.cc \ TowerInfov3_Dict.cc \ TowerInfov4_Dict.cc \ + TowerInfov5_Dict.cc \ TowerInfoSimv1_Dict.cc \ TowerInfoSimv2_Dict.cc \ TowerInfoSimv3_Dict.cc \ @@ -104,6 +107,7 @@ ROOTDICTS = \ TowerInfoContainerv2_Dict.cc \ TowerInfoContainerv3_Dict.cc \ TowerInfoContainerv4_Dict.cc \ + TowerInfoContainerv5_Dict.cc \ TowerInfoContainerSimv1_Dict.cc \ TowerInfoContainerSimv2_Dict.cc \ TowerInfoContainerSimv3_Dict.cc @@ -137,6 +141,7 @@ libcalo_io_la_SOURCES = \ TowerInfov2.cc \ TowerInfov3.cc \ TowerInfov4.cc \ + TowerInfov5.cc \ TowerInfoSimv1.cc \ TowerInfoSimv2.cc \ TowerInfoSimv3.cc \ @@ -146,6 +151,7 @@ libcalo_io_la_SOURCES = \ TowerInfoContainerv2.cc \ TowerInfoContainerv3.cc \ TowerInfoContainerv4.cc \ + TowerInfoContainerv5.cc \ TowerInfoContainerSimv1.cc \ TowerInfoContainerSimv2.cc \ TowerInfoContainerSimv3.cc diff --git a/offline/packages/CaloBase/TowerInfoContainer.cc b/offline/packages/CaloBase/TowerInfoContainer.cc index 72091971aa..d6b27229e9 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.cc +++ b/offline/packages/CaloBase/TowerInfoContainer.cc @@ -130,3 +130,29 @@ unsigned int TowerInfoContainer::decode_key(unsigned int tower_key) } return index; } + +int TowerInfoContainer::get_channels(DETECTOR detec) +{ + int nchannels = 744; + if (detec == DETECTOR::SEPD) + { + nchannels = 744; + } + else if (detec == DETECTOR::EMCAL) + { + nchannels = 24576; + } + else if (detec == DETECTOR::HCAL) + { + nchannels = 1536; + } + else if (detec == DETECTOR::MBD) + { + nchannels = 256; + } + else if (detec == DETECTOR::ZDC) + { + nchannels = 52; + } + return nchannels; +} diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index ec3296d088..fa15a2b02f 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -55,7 +55,8 @@ class TowerInfoContainer : public PHObject virtual unsigned int getTowerEtaBin(unsigned int /*towerIndex*/); virtual DETECTOR get_detectorid() const { return DETECTOR_INVALID; } - + virtual int get_channels(DETECTOR detec); + private: ClassDefOverride(TowerInfoContainer, 0); }; diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc index e505687345..9fc3ec6c08 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc @@ -9,27 +9,7 @@ TowerInfoContainerSimv1::TowerInfoContainerSimv1(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfoSimv1", nchannels); for (int i = 0; i < nchannels; ++i) { diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc index f82aac9f6d..4e69480a70 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc @@ -9,27 +9,7 @@ TowerInfoContainerSimv2::TowerInfoContainerSimv2(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfoSimv2", nchannels); for (int i = 0; i < nchannels; ++i) { diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc index 440f16caae..3b32c10647 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc @@ -9,27 +9,7 @@ TowerInfoContainerSimv3::TowerInfoContainerSimv3(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfoSimv3", nchannels); for (int i = 0; i < nchannels; ++i) { diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index 7325247618..d273e143c8 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -9,27 +9,7 @@ TowerInfoContainerv1::TowerInfoContainerv1(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov1", nchannels); for (int i = 0; i < nchannels; ++i) { diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.cc b/offline/packages/CaloBase/TowerInfoContainerv2.cc index 5c53f241f2..3c9c0cefa1 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv2.cc @@ -9,27 +9,7 @@ TowerInfoContainerv2::TowerInfoContainerv2(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov2", nchannels); for (int i = 0; i < nchannels; ++i) { diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.cc b/offline/packages/CaloBase/TowerInfoContainerv3.cc index 331347acc1..699aa52556 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv3.cc @@ -9,27 +9,7 @@ TowerInfoContainerv3::TowerInfoContainerv3(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov3", nchannels); for (int i = 0; i < nchannels; ++i) { diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.cc b/offline/packages/CaloBase/TowerInfoContainerv4.cc index ecd939ef60..af977e186d 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv4.cc @@ -9,27 +9,7 @@ TowerInfoContainerv4::TowerInfoContainerv4(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov4", nchannels); for (int i = 0; i < nchannels; ++i) { diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.cc b/offline/packages/CaloBase/TowerInfoContainerv5.cc new file mode 100644 index 0000000000..0d2d1127c9 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerv5.cc @@ -0,0 +1,76 @@ +#include "TowerInfoContainerv5.h" +#include "TowerInfov5.h" + +#include +#include + +#include + +TowerInfoContainerv5::TowerInfoContainerv5(DETECTOR detec) + : _detector(detec) +{ + int nchannels = get_channels(detec); + _clones = new TClonesArray("TowerInfov5", nchannels); + for (int i = 0; i < nchannels; ++i) + { + // as tower numbers are fixed per event + // construct towers once per run, and clear the towers for first use + _clones->ConstructedAt(i, "C"); + } +} + +TowerInfoContainerv5::TowerInfoContainerv5(const TowerInfoContainerv5& source) + : TowerInfoContainer(source) + , _clones(new TClonesArray("TowerInfov5", source.size())) + , _detector(source.get_detectorid()) +{ + for (unsigned int i = 0; i < source.size(); ++i) + { + // as tower numbers are fixed per event + // construct towers once per run, and clear the towers for first use + _clones->ConstructedAt(i, "C"); + } +} + +TowerInfoContainerv5::~TowerInfoContainerv5() +{ + delete _clones; +} + +void TowerInfoContainerv5::identify(std::ostream& os) const +{ + os << "TowerInfoContainerv5 of size " << size() << std::endl; +} + +void TowerInfoContainerv5::Reset() +{ + // clear content of towers in the container for the next event + + for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) + { + TowerInfo *twr = (TowerInfov5 *) _clones->UncheckedAt(i); + + if (twr == nullptr) + { + std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" + << " _clones->GetSize() = " << _clones->GetSize() + << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() + << " i = " << i << std::endl; + _clones->Print(); + gSystem->Exit(1); + exit(1); + } + twr->Reset(); + } +} + +TowerInfov5* TowerInfoContainerv5::get_tower_at_channel(int pos) +{ + return (TowerInfov5*) _clones->At(pos); +} + +TowerInfov5* TowerInfoContainerv5::get_tower_at_key(int pos) +{ + int index = decode_key(pos); + return (TowerInfov5*) _clones->At(index); +} diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.h b/offline/packages/CaloBase/TowerInfoContainerv5.h new file mode 100644 index 0000000000..d5bd8383f4 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerv5.h @@ -0,0 +1,43 @@ +#ifndef TOWERINFOCONTAINERV5_H +#define TOWERINFOCONTAINERV5_H + +#include "TowerInfoContainer.h" +#include "TowerInfov5.h" + +#include + +#include +#include + +class PHObject; + +class TowerInfoContainerv5 : public TowerInfoContainer +{ + public: + TowerInfoContainerv5(DETECTOR detec); + + // default constructor for ROOT IO + TowerInfoContainerv5() = default; + PHObject *CloneMe() const override { return new TowerInfoContainerv5(*this); } + TowerInfoContainerv5(const TowerInfoContainerv5 &); + + ~TowerInfoContainerv5() override; + + void identify(std::ostream &os = std::cout) const override; + + void Reset() override; + TowerInfov5 *get_tower_at_channel(int pos) override; + TowerInfov5 *get_tower_at_key(int pos) override; + + size_t size() const override { return _clones->GetEntries(); } + DETECTOR get_detectorid() const override { return _detector; } + + protected: + TClonesArray *_clones {nullptr}; + DETECTOR _detector {DETECTOR_INVALID}; + + private: + ClassDefOverride(TowerInfoContainerv5, 1); +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfoContainerv5LinkDef.h b/offline/packages/CaloBase/TowerInfoContainerv5LinkDef.h new file mode 100644 index 0000000000..b50eef6f7b --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerv5LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfoContainerv5 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/CaloBase/TowerInfov5.cc b/offline/packages/CaloBase/TowerInfov5.cc new file mode 100644 index 0000000000..02637b7298 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfov5.cc @@ -0,0 +1,69 @@ +#include "TowerInfov5.h" +#include "TowerInfo.h" + +#include + +#include + +void TowerInfov5::Reset() +{ + TowerInfov2::Reset(); + std::ranges::fill(_waveform,0); +} + +void TowerInfov5::set_nsample(int nsample) +{ + if (nsample > 0) + { + _waveform.resize(nsample, 0); + return; + } + std::cout << PHWHERE << " invalid number of samples: " << nsample << std::endl; + gSystem->Exit(1); + exit(1); +} + +int16_t TowerInfov5::get_waveform_value(int index) const +{ + if (index >= 0 && index < get_nsample()) + { + return _waveform[index]; + } + return 0; +} + +void TowerInfov5::set_waveform_value(int index, int16_t value) +{ + if (index >= 0 && index < get_nsample()) + { + _waveform[index] = value; + } + return; +} + +void TowerInfov5::copy_tower(TowerInfo* tower) +{ + TowerInfov2::copy_tower(tower); + const int nsamples = tower->get_nsample(); + if (nsamples <= 0) + { + _waveform.clear(); + return; + } + set_nsample(nsamples); + for (int i = 0; i < nsamples; ++i) + { + _waveform[i] = tower->get_waveform_value(i); + } + return; +} + +void TowerInfov5::identify(std::ostream& os) const +{ + os << "TowerInfov5" << std::endl; + for (int i = 0; i < get_nsample(); ++i) + { + std::cout << "sample " << i << ": " << get_waveform_value(i) << std::endl; + } + return; +} diff --git a/offline/packages/CaloBase/TowerInfov5.h b/offline/packages/CaloBase/TowerInfov5.h new file mode 100644 index 0000000000..9ed02740ca --- /dev/null +++ b/offline/packages/CaloBase/TowerInfov5.h @@ -0,0 +1,33 @@ +#ifndef TOWERINFOV5_H +#define TOWERINFOV5_H + +#include "TowerInfov2.h" + +#include // For int16_t + +class TowerInfov5 : public TowerInfov2 +{ + public: + TowerInfov5() = default; + ~TowerInfov5() override = default; + + void Reset() override; + + void identify(std::ostream& os) const override; + + void copy_tower(TowerInfo* tower) override; + + // Getter and setter for waveform + void set_nsample(int nsample) override; + int get_nsample() const override { return _waveform.size(); } + int16_t get_waveform_value(int index) const override; + void set_waveform_value(int index, int16_t value) override; + + private: + std::vector _waveform; + + ClassDefOverride(TowerInfov5, 1); + // Inherit other methods and properties from TowerInfov2 +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfov5LinkDef.h b/offline/packages/CaloBase/TowerInfov5LinkDef.h new file mode 100644 index 0000000000..08368bf568 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfov5LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfov5 + ; + +#endif /* __CINT__ */ From 093ddb35031bb6982a5b8e6b436886213b27ba60 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 3 Jul 2026 11:14:15 -0400 Subject: [PATCH 799/866] include what you use --- offline/packages/CaloBase/PhotonClusterv1.cc | 4 ++-- offline/packages/CaloBase/PhotonClusterv1.h | 1 + offline/packages/CaloBase/TowerInfoContainer.cc | 2 -- offline/packages/CaloBase/TowerInfoContainer.h | 1 - offline/packages/CaloBase/TowerInfoContainerSimv1.cc | 2 +- offline/packages/CaloBase/TowerInfoContainerSimv1.h | 3 +++ offline/packages/CaloBase/TowerInfoContainerSimv2.cc | 2 +- offline/packages/CaloBase/TowerInfoContainerSimv2.h | 3 +++ offline/packages/CaloBase/TowerInfoContainerSimv3.cc | 2 +- offline/packages/CaloBase/TowerInfoContainerSimv3.h | 3 +++ offline/packages/CaloBase/TowerInfoContainerv1.cc | 2 -- offline/packages/CaloBase/TowerInfoContainerv2.cc | 2 +- offline/packages/CaloBase/TowerInfoContainerv3.cc | 2 +- offline/packages/CaloBase/TowerInfoContainerv4.cc | 2 +- offline/packages/CaloBase/TowerInfoContainerv5.cc | 2 +- offline/packages/CaloBase/TowerInfoSimv1.h | 2 ++ offline/packages/CaloBase/TowerInfoSimv3.cc | 4 ++++ offline/packages/CaloBase/TowerInfov1.cc | 2 -- offline/packages/CaloBase/TowerInfov3.cc | 2 ++ offline/packages/CaloBase/TowerInfov4.cc | 2 -- offline/packages/CaloBase/TowerInfov5.cc | 4 ++++ offline/packages/CaloBase/TowerInfov5.h | 2 ++ 22 files changed, 33 insertions(+), 18 deletions(-) diff --git a/offline/packages/CaloBase/PhotonClusterv1.cc b/offline/packages/CaloBase/PhotonClusterv1.cc index 19879e25ed..028e8afd17 100644 --- a/offline/packages/CaloBase/PhotonClusterv1.cc +++ b/offline/packages/CaloBase/PhotonClusterv1.cc @@ -1,5 +1,5 @@ #include "PhotonClusterv1.h" -#include + #include #include #include @@ -80,4 +80,4 @@ float PhotonClusterv1::get_shower_shape_parameter(const std::string& name) const return it->second; } return std::numeric_limits::quiet_NaN(); -} \ No newline at end of file +} diff --git a/offline/packages/CaloBase/PhotonClusterv1.h b/offline/packages/CaloBase/PhotonClusterv1.h index 4561805c59..e782abc1d8 100644 --- a/offline/packages/CaloBase/PhotonClusterv1.h +++ b/offline/packages/CaloBase/PhotonClusterv1.h @@ -3,6 +3,7 @@ #include "RawClusterv1.h" +#include #include #include diff --git a/offline/packages/CaloBase/TowerInfoContainer.cc b/offline/packages/CaloBase/TowerInfoContainer.cc index d6b27229e9..af506f53b7 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.cc +++ b/offline/packages/CaloBase/TowerInfoContainer.cc @@ -1,8 +1,6 @@ #include "TowerInfoContainer.h" #include "TowerInfoDefs.h" -#include - void TowerInfoContainer::identify(std::ostream& os) const { os << "TowerInfoContainer Base Class " << std::endl; diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index fa15a2b02f..ec54ccca31 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -5,7 +5,6 @@ #include #include -#include #include class TowerInfo; diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc index 9fc3ec6c08..e34910a527 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc @@ -4,7 +4,7 @@ #include #include -#include +#include TowerInfoContainerSimv1::TowerInfoContainerSimv1(DETECTOR detec) : _detector(detec) diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.h b/offline/packages/CaloBase/TowerInfoContainerSimv1.h index d53e343ddd..927f07becf 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.h @@ -6,6 +6,9 @@ #include +#include // for size_t +#include + class PHObject; class TowerInfoContainerSimv1 : public TowerInfoContainer diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc index 4e69480a70..baa0a9f7dc 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc @@ -4,7 +4,7 @@ #include #include -#include +#include TowerInfoContainerSimv2::TowerInfoContainerSimv2(DETECTOR detec) : _detector(detec) diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.h b/offline/packages/CaloBase/TowerInfoContainerSimv2.h index 8ad1e473f6..174c786318 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.h @@ -6,6 +6,9 @@ #include +#include // for size_t +#include + class PHObject; class TowerInfoContainerSimv2 : public TowerInfoContainer diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc index 3b32c10647..becb6359b4 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc @@ -4,7 +4,7 @@ #include #include -#include +#include TowerInfoContainerSimv3::TowerInfoContainerSimv3(DETECTOR detec) : _detector(detec) diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.h b/offline/packages/CaloBase/TowerInfoContainerSimv3.h index 721085418d..8cf7247a1d 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.h @@ -6,6 +6,9 @@ #include +#include // for size_t +#include + class PHObject; class TowerInfoContainerSimv3 : public TowerInfoContainer diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index d273e143c8..474d570787 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -4,8 +4,6 @@ #include #include -#include - TowerInfoContainerv1::TowerInfoContainerv1(DETECTOR detec) : _detector(detec) { diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.cc b/offline/packages/CaloBase/TowerInfoContainerv2.cc index 3c9c0cefa1..e4fe00ecff 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv2.cc @@ -4,7 +4,7 @@ #include #include -#include +#include TowerInfoContainerv2::TowerInfoContainerv2(DETECTOR detec) : _detector(detec) diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.cc b/offline/packages/CaloBase/TowerInfoContainerv3.cc index 699aa52556..5e6e4aae38 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv3.cc @@ -4,7 +4,7 @@ #include #include -#include +#include TowerInfoContainerv3::TowerInfoContainerv3(DETECTOR detec) : _detector(detec) diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.cc b/offline/packages/CaloBase/TowerInfoContainerv4.cc index af977e186d..8a47028cf2 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv4.cc @@ -4,7 +4,7 @@ #include #include -#include +#include TowerInfoContainerv4::TowerInfoContainerv4(DETECTOR detec) : _detector(detec) diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.cc b/offline/packages/CaloBase/TowerInfoContainerv5.cc index 0d2d1127c9..cd8415de21 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv5.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv5.cc @@ -4,7 +4,7 @@ #include #include -#include +#include TowerInfoContainerv5::TowerInfoContainerv5(DETECTOR detec) : _detector(detec) diff --git a/offline/packages/CaloBase/TowerInfoSimv1.h b/offline/packages/CaloBase/TowerInfoSimv1.h index 11ae8d0d23..5deb55fc3d 100644 --- a/offline/packages/CaloBase/TowerInfoSimv1.h +++ b/offline/packages/CaloBase/TowerInfoSimv1.h @@ -3,6 +3,8 @@ #include "TowerInfov2.h" +#include + class TowerInfoSimv1 : public TowerInfov2 { public: diff --git a/offline/packages/CaloBase/TowerInfoSimv3.cc b/offline/packages/CaloBase/TowerInfoSimv3.cc index 3d2ad4d220..c95501e0d0 100644 --- a/offline/packages/CaloBase/TowerInfoSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoSimv3.cc @@ -6,6 +6,10 @@ #include +#include +#include +#include + void TowerInfoSimv3::Reset() { TowerInfoSimv1::Reset(); diff --git a/offline/packages/CaloBase/TowerInfov1.cc b/offline/packages/CaloBase/TowerInfov1.cc index c6b9609d79..92e399be9a 100644 --- a/offline/packages/CaloBase/TowerInfov1.cc +++ b/offline/packages/CaloBase/TowerInfov1.cc @@ -1,7 +1,5 @@ #include "TowerInfov1.h" -#include - TowerInfov1::TowerInfov1(TowerInfo& tower) : _time(tower.get_time()) , _energy(tower.get_energy()) diff --git a/offline/packages/CaloBase/TowerInfov3.cc b/offline/packages/CaloBase/TowerInfov3.cc index 7695ed525d..b95c786683 100644 --- a/offline/packages/CaloBase/TowerInfov3.cc +++ b/offline/packages/CaloBase/TowerInfov3.cc @@ -1,6 +1,8 @@ #include "TowerInfov3.h" #include "TowerInfo.h" +#include + void TowerInfov3::Reset() { TowerInfov2::Reset(); diff --git a/offline/packages/CaloBase/TowerInfov4.cc b/offline/packages/CaloBase/TowerInfov4.cc index fb694b7c34..6b2e83b030 100644 --- a/offline/packages/CaloBase/TowerInfov4.cc +++ b/offline/packages/CaloBase/TowerInfov4.cc @@ -1,8 +1,6 @@ #include "TowerInfov4.h" #include "TowerInfo.h" -#include - void TowerInfov4::Reset() { energy = 0; diff --git a/offline/packages/CaloBase/TowerInfov5.cc b/offline/packages/CaloBase/TowerInfov5.cc index 02637b7298..6eeea279fb 100644 --- a/offline/packages/CaloBase/TowerInfov5.cc +++ b/offline/packages/CaloBase/TowerInfov5.cc @@ -5,6 +5,10 @@ #include +#include +#include +#include + void TowerInfov5::Reset() { TowerInfov2::Reset(); diff --git a/offline/packages/CaloBase/TowerInfov5.h b/offline/packages/CaloBase/TowerInfov5.h index 9ed02740ca..d7e419978b 100644 --- a/offline/packages/CaloBase/TowerInfov5.h +++ b/offline/packages/CaloBase/TowerInfov5.h @@ -4,6 +4,8 @@ #include "TowerInfov2.h" #include // For int16_t +#include // for ostream +#include class TowerInfov5 : public TowerInfov2 { From 622223b2bba04b5a7c477aeb4bd712264cc26529 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 3 Jul 2026 11:15:24 -0400 Subject: [PATCH 800/866] clang-format --- offline/packages/CaloBase/PhotonClusterv1.cc | 4 ---- offline/packages/CaloBase/PhotonClusterv1.h | 8 +++----- offline/packages/CaloBase/TowerInfo.h | 2 +- offline/packages/CaloBase/TowerInfoContainer.h | 2 +- offline/packages/CaloBase/TowerInfoContainerSimv1.cc | 4 ++-- offline/packages/CaloBase/TowerInfoContainerSimv1.h | 4 ++-- offline/packages/CaloBase/TowerInfoContainerSimv2.cc | 4 ++-- offline/packages/CaloBase/TowerInfoContainerSimv2.h | 2 +- offline/packages/CaloBase/TowerInfoContainerSimv3.cc | 2 +- offline/packages/CaloBase/TowerInfoContainerSimv3.h | 2 +- offline/packages/CaloBase/TowerInfoContainerv1.cc | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv1.h | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv2.cc | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv3.cc | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv3.h | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv4.cc | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv4.h | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv5.cc | 4 ++-- offline/packages/CaloBase/TowerInfoContainerv5.h | 4 ++-- offline/packages/CaloBase/TowerInfoSimv1.h | 2 +- offline/packages/CaloBase/TowerInfoSimv3.cc | 2 +- offline/packages/CaloBase/TowerInfov4.h | 1 - offline/packages/CaloBase/TowerInfov5.cc | 2 +- 23 files changed, 35 insertions(+), 42 deletions(-) diff --git a/offline/packages/CaloBase/PhotonClusterv1.cc b/offline/packages/CaloBase/PhotonClusterv1.cc index 028e8afd17..66984ad98a 100644 --- a/offline/packages/CaloBase/PhotonClusterv1.cc +++ b/offline/packages/CaloBase/PhotonClusterv1.cc @@ -29,9 +29,6 @@ void PhotonClusterv1::reset_photon_properties() return; } - - - void PhotonClusterv1::identify(std::ostream& os) const { // @warning: Call base class identify first to maintain output order @@ -65,7 +62,6 @@ bool PhotonClusterv1::pass_photon_cuts() const // if (it_core->second > 0.3f) return false; //} - // @warning: Add more sophisticated photon ID cuts as needed // Consider using cluster properties like get_ecore(), get_prob(), etc. diff --git a/offline/packages/CaloBase/PhotonClusterv1.h b/offline/packages/CaloBase/PhotonClusterv1.h index e782abc1d8..1914fefea4 100644 --- a/offline/packages/CaloBase/PhotonClusterv1.h +++ b/offline/packages/CaloBase/PhotonClusterv1.h @@ -15,8 +15,7 @@ class PhotonClusterv1 : public RawClusterv1 ~PhotonClusterv1() override = default; - - explicit PhotonClusterv1(const RawCluster & rc); + explicit PhotonClusterv1(const RawCluster& rc); //! Copy constructor PhotonClusterv1(const PhotonClusterv1& other) = default; @@ -30,7 +29,6 @@ class PhotonClusterv1 : public RawClusterv1 bool pass_photon_cuts() const override; void identify_photon(std::ostream& os = std::cout) const override; - void reset_photon_properties() override; //! @name PhotonCluster Setter Implementations @@ -46,8 +44,8 @@ class PhotonClusterv1 : public RawClusterv1 private: //! @warning Photon-specific data members - memory managed only in this derived class // Photon energy and isolation energy now sourced from RawCluster - //float m_conversion_prob{0.0f}; //!< Probability of photon conversion - //bool m_is_converted{false}; //!< Conversion flag + // float m_conversion_prob{0.0f}; //!< Probability of photon conversion + // bool m_is_converted{false}; //!< Conversion flag std::map m_shower_shapes; //!< Named shower shape parameters ClassDefOverride(PhotonClusterv1, 1) //!< ROOT dictionary generation diff --git a/offline/packages/CaloBase/TowerInfo.h b/offline/packages/CaloBase/TowerInfo.h index f8b3984396..fbcce0b0bf 100644 --- a/offline/packages/CaloBase/TowerInfo.h +++ b/offline/packages/CaloBase/TowerInfo.h @@ -74,7 +74,7 @@ class TowerInfo : public PHObject } virtual void add_edep(const PHG4HitDefs::keytype /*g4hitid*/, const float /*edep*/) { return; } virtual void add_shower_edep(const int /*showerid*/, const float /*edep*/) { return; } -// methods in v5 and simv3 + // methods in v5 and simv3 virtual void set_nsample(int /*nsample*/) { return; } private: diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index ec54ccca31..6e963cc914 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -55,7 +55,7 @@ class TowerInfoContainer : public PHObject virtual DETECTOR get_detectorid() const { return DETECTOR_INVALID; } virtual int get_channels(DETECTOR detec); - + private: ClassDefOverride(TowerInfoContainer, 0); }; diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc index e34910a527..a8840b1817 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc @@ -48,8 +48,8 @@ void TowerInfoContainerSimv1::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfoSimv1 *) _clones->UncheckedAt(i); - + TowerInfo* twr = (TowerInfoSimv1*) _clones->UncheckedAt(i); + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.h b/offline/packages/CaloBase/TowerInfoContainerSimv1.h index 927f07becf..0df3f029d5 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.h @@ -33,8 +33,8 @@ class TowerInfoContainerSimv1 : public TowerInfoContainer DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones {nullptr}; - DETECTOR _detector {DETECTOR_INVALID}; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerSimv1, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc index baa0a9f7dc..08e87a64e3 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc @@ -48,8 +48,8 @@ void TowerInfoContainerSimv2::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfoSimv2 *) _clones->UncheckedAt(i); - + TowerInfo* twr = (TowerInfoSimv2*) _clones->UncheckedAt(i); + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.h b/offline/packages/CaloBase/TowerInfoContainerSimv2.h index 174c786318..13849b9537 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.h @@ -6,7 +6,7 @@ #include -#include // for size_t +#include // for size_t #include class PHObject; diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc index becb6359b4..fd1b4e9757 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc @@ -50,7 +50,7 @@ void TowerInfoContainerSimv3::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfoSimv3*) _clones->UncheckedAt(i); + TowerInfo* twr = (TowerInfoSimv3*) _clones->UncheckedAt(i); if (twr == nullptr) { diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.h b/offline/packages/CaloBase/TowerInfoContainerSimv3.h index 8cf7247a1d..4e40d23281 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv3.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.h @@ -6,7 +6,7 @@ #include -#include // for size_t +#include // for size_t #include class PHObject; diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index 474d570787..f94d9e2571 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -46,8 +46,8 @@ void TowerInfoContainerv1::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfov1 *) _clones->UncheckedAt(i); - + TowerInfo* twr = (TowerInfov1*) _clones->UncheckedAt(i); + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.h b/offline/packages/CaloBase/TowerInfoContainerv1.h index 067a44d014..795f06ba0e 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerv1.h @@ -33,8 +33,8 @@ class TowerInfoContainerv1 : public TowerInfoContainer DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones {nullptr}; - DETECTOR _detector {DETECTOR_INVALID}; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv1, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.cc b/offline/packages/CaloBase/TowerInfoContainerv2.cc index e4fe00ecff..b18c19f109 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv2.cc @@ -48,8 +48,8 @@ void TowerInfoContainerv2::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfov2 *) _clones->UncheckedAt(i); - + TowerInfo* twr = (TowerInfov2*) _clones->UncheckedAt(i); + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.cc b/offline/packages/CaloBase/TowerInfoContainerv3.cc index 5e6e4aae38..64a3dc2b99 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv3.cc @@ -48,8 +48,8 @@ void TowerInfoContainerv3::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfov3 *) _clones->UncheckedAt(i); - + TowerInfo* twr = (TowerInfov3*) _clones->UncheckedAt(i); + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.h b/offline/packages/CaloBase/TowerInfoContainerv3.h index ca771fe897..aeb8388f81 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.h +++ b/offline/packages/CaloBase/TowerInfoContainerv3.h @@ -33,8 +33,8 @@ class TowerInfoContainerv3 : public TowerInfoContainer DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones {nullptr}; - DETECTOR _detector {DETECTOR_INVALID}; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv3, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.cc b/offline/packages/CaloBase/TowerInfoContainerv4.cc index 8a47028cf2..1ac5122613 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv4.cc @@ -48,8 +48,8 @@ void TowerInfoContainerv4::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfov4 *) _clones->UncheckedAt(i); - + TowerInfo* twr = (TowerInfov4*) _clones->UncheckedAt(i); + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.h b/offline/packages/CaloBase/TowerInfoContainerv4.h index 5b633b61b1..3d26d258f8 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.h +++ b/offline/packages/CaloBase/TowerInfoContainerv4.h @@ -34,8 +34,8 @@ class TowerInfoContainerv4 : public TowerInfoContainer DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones {nullptr}; - DETECTOR _detector {DETECTOR_INVALID}; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv4, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.cc b/offline/packages/CaloBase/TowerInfoContainerv5.cc index cd8415de21..61f9387450 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv5.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv5.cc @@ -48,8 +48,8 @@ void TowerInfoContainerv5::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TowerInfo *twr = (TowerInfov5 *) _clones->UncheckedAt(i); - + TowerInfo* twr = (TowerInfov5*) _clones->UncheckedAt(i); + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.h b/offline/packages/CaloBase/TowerInfoContainerv5.h index d5bd8383f4..3bfbf77f60 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv5.h +++ b/offline/packages/CaloBase/TowerInfoContainerv5.h @@ -33,8 +33,8 @@ class TowerInfoContainerv5 : public TowerInfoContainer DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones {nullptr}; - DETECTOR _detector {DETECTOR_INVALID}; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv5, 1); diff --git a/offline/packages/CaloBase/TowerInfoSimv1.h b/offline/packages/CaloBase/TowerInfoSimv1.h index 5deb55fc3d..ac24439d74 100644 --- a/offline/packages/CaloBase/TowerInfoSimv1.h +++ b/offline/packages/CaloBase/TowerInfoSimv1.h @@ -3,7 +3,7 @@ #include "TowerInfov2.h" -#include +#include class TowerInfoSimv1 : public TowerInfov2 { diff --git a/offline/packages/CaloBase/TowerInfoSimv3.cc b/offline/packages/CaloBase/TowerInfoSimv3.cc index c95501e0d0..602bc3d655 100644 --- a/offline/packages/CaloBase/TowerInfoSimv3.cc +++ b/offline/packages/CaloBase/TowerInfoSimv3.cc @@ -13,7 +13,7 @@ void TowerInfoSimv3::Reset() { TowerInfoSimv1::Reset(); - std::ranges::fill(_waveform,0); + std::ranges::fill(_waveform, 0); } void TowerInfoSimv3::set_nsample(int nsample) diff --git a/offline/packages/CaloBase/TowerInfov4.h b/offline/packages/CaloBase/TowerInfov4.h index f371422329..25a8e0ce75 100644 --- a/offline/packages/CaloBase/TowerInfov4.h +++ b/offline/packages/CaloBase/TowerInfov4.h @@ -24,7 +24,6 @@ class TowerInfov4 : public TowerInfo void set_time_short(short t) override { time = t * 1000; } short get_time_short() override { return short(time / 1000); } - void set_chi2(float _chi2) override { float lnChi2; diff --git a/offline/packages/CaloBase/TowerInfov5.cc b/offline/packages/CaloBase/TowerInfov5.cc index 6eeea279fb..1c4b45cae2 100644 --- a/offline/packages/CaloBase/TowerInfov5.cc +++ b/offline/packages/CaloBase/TowerInfov5.cc @@ -12,7 +12,7 @@ void TowerInfov5::Reset() { TowerInfov2::Reset(); - std::ranges::fill(_waveform,0); + std::ranges::fill(_waveform, 0); } void TowerInfov5::set_nsample(int nsample) From c85cd8020789989b573c23e177f0c656c0e78300 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 3 Jul 2026 11:33:01 -0400 Subject: [PATCH 801/866] include what you use --- simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc | 2 +- simulation/g4simulation/g4waveformsim/CaloWaveformSim.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 89ef408ff7..2401884e6e 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -17,11 +17,11 @@ #include #include #include -#include #include #include #include +#include #include diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index b4c058217c..e309a11cc6 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -19,6 +19,7 @@ #include +#include #include #include From 6269cc5b0bf271ae9d83272105bc010a6d7dd310 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 3 Jul 2026 12:12:18 -0400 Subject: [PATCH 802/866] fixthe copy ctors to make deep copies --- offline/packages/CaloBase/TowerInfoContainerSimv1.cc | 6 +++--- offline/packages/CaloBase/TowerInfoContainerSimv2.cc | 6 +++--- offline/packages/CaloBase/TowerInfoContainerv1.cc | 6 +++--- offline/packages/CaloBase/TowerInfoContainerv2.cc | 6 +++--- offline/packages/CaloBase/TowerInfoContainerv3.cc | 6 +++--- offline/packages/CaloBase/TowerInfoContainerv4.cc | 6 +++--- offline/packages/CaloBase/TowerInfoContainerv5.cc | 6 +++--- offline/packages/CaloBase/TowerInfov5.cc | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc index a8840b1817..ba7ba0a661 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc @@ -26,9 +26,9 @@ TowerInfoContainerSimv1::TowerInfoContainerSimv1(const TowerInfoContainerSimv1& { for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc index 08e87a64e3..e9eeff969c 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc @@ -26,9 +26,9 @@ TowerInfoContainerSimv2::TowerInfoContainerSimv2(const TowerInfoContainerSimv2& { for (int i = 0; i < (int) source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index f94d9e2571..9b7755bc51 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -29,9 +29,9 @@ TowerInfoContainerv1::TowerInfoContainerv1(const TowerInfoContainerv1& source) { for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.cc b/offline/packages/CaloBase/TowerInfoContainerv2.cc index b18c19f109..dfedb29906 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv2.cc @@ -26,9 +26,9 @@ TowerInfoContainerv2::TowerInfoContainerv2(const TowerInfoContainerv2& source) { for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.cc b/offline/packages/CaloBase/TowerInfoContainerv3.cc index 64a3dc2b99..921e474871 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv3.cc @@ -26,9 +26,9 @@ TowerInfoContainerv3::TowerInfoContainerv3(const TowerInfoContainerv3& source) { for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.cc b/offline/packages/CaloBase/TowerInfoContainerv4.cc index 1ac5122613..ffa93bf98c 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv4.cc @@ -26,9 +26,9 @@ TowerInfoContainerv4::TowerInfoContainerv4(const TowerInfoContainerv4& source) { for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.cc b/offline/packages/CaloBase/TowerInfoContainerv5.cc index 61f9387450..010086b037 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv5.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv5.cc @@ -26,9 +26,9 @@ TowerInfoContainerv5::TowerInfoContainerv5(const TowerInfoContainerv5& source) { for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } diff --git a/offline/packages/CaloBase/TowerInfov5.cc b/offline/packages/CaloBase/TowerInfov5.cc index 1c4b45cae2..dd9703a441 100644 --- a/offline/packages/CaloBase/TowerInfov5.cc +++ b/offline/packages/CaloBase/TowerInfov5.cc @@ -67,7 +67,7 @@ void TowerInfov5::identify(std::ostream& os) const os << "TowerInfov5" << std::endl; for (int i = 0; i < get_nsample(); ++i) { - std::cout << "sample " << i << ": " << get_waveform_value(i) << std::endl; + os << "sample " << i << ": " << get_waveform_value(i) << std::endl; } return; } From 67e7fbf58939ee5b8ef81805f884adc97a764458 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 3 Jul 2026 17:25:12 -0400 Subject: [PATCH 803/866] fix clang-tidy --- offline/packages/CaloBase/TowerInfoContainer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index 6e963cc914..5432528474 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -36,7 +36,7 @@ class TowerInfoContainer : public PHObject virtual size_t size() const { return 0; } virtual unsigned int encode_key(unsigned int towerIndex); - virtual unsigned int decode_key(unsigned int towerIndex); + virtual unsigned int decode_key(unsigned int tower_key); virtual unsigned int encode_epd(unsigned int /*towerIndex*/); virtual unsigned int encode_hcal(unsigned int /*towerIndex*/); From 4f13e96105ac5fa04b6ae81ba8242045bf5e3f73 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Tue, 7 Jul 2026 08:53:34 -0400 Subject: [PATCH 804/866] CD: Trying to make Jenkins happy --- .../HFTrackEfficiency/HFTrackEfficiency.cc | 41 +------------------ .../KFParticle_sPHENIX/KFParticle_Tools.cc | 8 +++- .../KFParticle_eventReconstruction.cc | 10 ++++- 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index b37b7e2211..23ab068663 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -120,23 +120,7 @@ int HFTrackEfficiency::process_event(PHCompositeNode *topNode) trackeval = m_svtx_evalstack->get_track_eval(); } m_svtx_evalstack->next_event(topNode); -/* - m_dst_truth_reco_map = findNode::getClass(topNode, "PHG4ParticleSvtxMap"); - if (m_dst_truth_reco_map) - { - if (Verbosity() >= VERBOSITY_MORE) - { - std::cout << __FILE__ << ": PHG4ParticleSvtxMap found, truth matching will be more accurate" << std::endl; - } - } - else - { - if (Verbosity() >= VERBOSITY_MORE) - { - std::cout << __FILE__ << ": PHG4ParticleSvtxMap not found, reverting to true matching by momentum relations. Truth matching will be less accurate" << std::endl; - } - } -*/ + if (m_decay_descriptor.empty() && !m_decayMap->empty()) { getDecayDescriptor(); @@ -251,7 +235,6 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) for (unsigned int i = 1; i < decay.size(); ++i) { m_dst_track = nullptr; - //int truth_ID = -1; if (std::find(std::begin(trackableParticles), std::end(trackableParticles), std::abs(decay[i].second)) != std::end(trackableParticles)) @@ -278,24 +261,19 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_z = thisVtx->point3d().z(); // We need the G4 ID, not the HepMC ID to use the truth/reco map - //if (m_dst_truth_reco_map) - //{ PHG4TruthInfoContainer::ConstRange range = m_truthInfo->GetParticleRange(); for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { - //PHG4Particle *daughterG4 = iter->second; daughterG4 = iter->second; if (std::abs(daughterG4->get_px() - daughterTrueLV->x()) <= 5e-3 && std::abs(daughterG4->get_py() - daughterTrueLV->y()) <= 5e-3 && std::abs(daughterG4->get_pz() - daughterTrueLV->z()) <= 5e-3 && daughterG4->get_pid() == decay[i].second) { - //truth_ID = daughterG4->get_track_id(); break; } } - //} } else { @@ -303,7 +281,6 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { - //PHG4Particle *daughterG4 = iter->second; daughterG4 = iter->second; PHG4Particle *motherG4 = nullptr; @@ -348,7 +325,6 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_z = thisVtx->get_z(); m_true_track_PID[index] = daughterG4->get_pid(); - //truth_ID = daughterG4->get_track_id(); delete mother3Vector; } @@ -415,7 +391,6 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_z = thisVtx->get_z(); m_true_track_PID[index] = daughterG4->get_pid(); - truth_ID = daughterG4->get_track_id(); delete mother3Vector; break; @@ -430,21 +405,9 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_min_true_track_pT = std::min(m_true_track_pT[index], m_min_true_track_pT); m_max_true_track_pT = std::max(m_true_track_pT[index], m_max_true_track_pT); - //if (m_dst_truth_reco_map && truth_ID >= 0) if (trackeval && daughterG4) { - //std::map> reco_set = m_dst_truth_reco_map->get(truth_ID); - //if (reco_set.empty()) - //{ - // continue; - //} - //const auto &best_weight = reco_set.rbegin(); - //if (best_weight->second.empty()) - //{ - // continue; - //} - //unsigned int best_reco_id = *best_weight->second.rbegin(); - m_dst_track = trackeval->best_track_from(daughterG4);//m_input_trackMap->get(best_reco_id); + m_dst_track = trackeval->best_track_from(daughterG4); if (m_dst_track) { m_used_truth_reco_map[index] = true; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index ca1c49d695..ec1e348635 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -524,6 +524,7 @@ int KFParticle_Tools::calcMinPV_DCA(const KFParticle &track, const std::vector KFParticle_Tools::findAllGoodTracks(const std::vector &daughterParticles)//, const std::vector &primaryVertices) { std::vector goodTrackIndex; + goodTrackIndex.reserve(daughterParticles.size()); for (unsigned int i_parts = 0; i_parts < daughterParticles.size(); ++i_parts) { @@ -549,9 +550,11 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector crossings; - for (auto &track : dummy_tracks) + crossings.reserve(dummy_tracks.size()); + for (const auto &track : dummy_tracks) { - SvtxTrack *thisTrack = toolSet.getTrack(track.Id(), m_dst_trackmap); + int track_id = track.Id(); //Jenkins complains if accessed in getTrack() + SvtxTrack *thisTrack = toolSet.getTrack(track_id, m_dst_trackmap); if (thisTrack) { crossings.push_back(thisTrack->get_crossing()); @@ -686,6 +689,7 @@ std::vector> KFParticle_Tools::findNProngs(const std::vector dummy_tracks; + dummy_tracks.reserve(combination.size()); for (auto &id : combination) { dummy_tracks.push_back(daughterParticles[id]); diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index b99e0a32d8..47a4db156c 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -156,10 +156,16 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte getCandidateDecay(potentialIntermediates[i], vertices, potentialDaughters[i], daughterParticlesAdv, goodTracksThatMeet, primaryVerticesAdv, track_start, track_stop, true, i, m_constrain_int_mass, topNode); - if (i + 1 >= m_num_intermediate_states) break; + if (i + 1 >= m_num_intermediate_states) + { + break; + } track_start = track_stop; track_stop += m_num_tracks_from_intermediate[i + 1]; - if (track_stop > m_num_tracks) break; + if (track_stop > m_num_tracks) + { + break; + } } int num_tracks_used_by_intermediates = 0; for (int i = 0; i < m_num_intermediate_states; ++i) From 6616fbb1a2d0076c827d4e8eb3c2d2d11d080ed0 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Tue, 7 Jul 2026 11:58:47 -0400 Subject: [PATCH 805/866] Start implementing specifying the (local) alignment parameter file. --- .../trackbase/AlignmentTransformation.h | 16 +++++++--- .../packages/trackreco/MakeActsGeometry.cc | 30 +++++++++--------- offline/packages/trackreco/MakeActsGeometry.h | 31 ++++++++++++++----- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index 8df8aeb2ef..7601f94004 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -17,9 +17,12 @@ class ActsGeometry; class AlignmentTransformation { public: + + /// constructor AlignmentTransformation() = default; - ~AlignmentTransformation() {} + /// destructor + ~AlignmentTransformation() = default; void createMap(PHCompositeNode* topNode); void createAlignmentTransformContainer(PHCompositeNode* topNode); @@ -34,6 +37,9 @@ class AlignmentTransformation Eigen::Vector3d perturbationAnglesGlobal = Eigen::Vector3d(0.0, 0.0, 0.0); Eigen::Vector3d perturbationTranslation = Eigen::Vector3d(0.0, 0.0, 0.0); + /// assign local alignment parameter file to be used instead of CDB, if found + void setAlignmentParamsFile(const std::string& value ) { alignmentParamsFile = value; } + void setMVTXParams(double mvtxDevs[6]) { mvtxAngleDev(0) = mvtxDevs[0]; @@ -129,14 +135,14 @@ 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); - Eigen::Vector3d getTpcLocalFrameTranslation(float moduleRadius, float layerRadius, Eigen::Vector3d& localRotation) const; + Eigen::Vector3d getTpcLocalFrameTranslation(float moduleRadius, float layerRadius, Eigen::Vector3d& localRotation) const; void extractModuleCenterPositions(); - double extractModuleCenter(TrkrDefs::hitsetkey hitsetkey, double sectorphi); + double extractModuleCenter(TrkrDefs::hitsetkey hitsetkey, double sectorphi); alignmentTransformationContainer* transformMap = NULL; alignmentTransformationContainer* transformMapTransient = NULL; diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 1c51d07283..9c696db310 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -175,12 +175,11 @@ int MakeActsGeometry::Init(PHCompositeNode * /*topNode*/) int MakeActsGeometry::InitRun(PHCompositeNode *topNode) { - m_geomContainerTpc = - findNode::getClass(topNode, "TPCGEOMCONTAINER"); + m_geomContainerTpc = findNode::getClass(topNode, "TPCGEOMCONTAINER"); PHG4TpcGeom *layergeom = m_geomContainerTpc->GetLayerCellGeom(20); // z geometry is the same for all layers m_max_driftlength = layergeom->get_max_driftlength(); - m_CM_halfwidth = layergeom->get_CM_halfwidth(); + m_CM_halfwidth = layergeom->get_CM_halfwidth(); m_maxSurfZ = m_max_driftlength - 0.0001; // add clearance from physical TPC gas volume length to avoid overlaps // Make the transform from TPC envelope to global coordinates @@ -203,7 +202,7 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) m_tpc_envelope_world_transform.translation() = trans; // and the inverse m_tpc_world_envelope_transform = m_tpc_envelope_world_transform.inverse(); - + // test Acts::Vector3 test_env(10.0, 40.0, 80.0); std::cout << "MakeActsGeometry::InitRun transform tests north" << std::endl; @@ -211,7 +210,7 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) Acts::Vector3 test_glob = m_tpc_envelope_world_transform * test_env; std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; Acts::Vector3 test_env_check = m_tpc_world_envelope_transform * test_glob; - std::cout << " test_env_check " << test_env_check.x() << " " << test_env_check.y() << " " << test_env_check.z() << std::endl; + std::cout << " test_env_check " << test_env_check.x() << " " << test_env_check.y() << " " << test_env_check.z() << std::endl; Acts::Vector3 test_envs(10.0, 40.0, -80.0); std::cout << "MakeActsGeometry::InitRun transform tests south" << std::endl; @@ -219,10 +218,11 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) Acts::Vector3 test_globs = m_tpc_envelope_world_transform * test_envs; std::cout << " test_glob " << test_globs.x() << " " << test_globs.y() << " " << test_globs.z() << std::endl; Acts::Vector3 test_env_checks = m_tpc_world_envelope_transform * test_globs; - std::cout << " test_env_check " << test_env_checks.x() << " " << test_env_checks.y() << " " << test_env_checks.z() << std::endl; + std::cout << " test_env_check " << test_env_checks.x() << " " << test_env_checks.y() << " " << test_env_checks.z() << std::endl; // Alignment Transformation declaration of instance - must be here to set initial alignment flag AlignmentTransformation alignment_transformation; + alignment_transformation.setAlignmentParamsFile(m_alignmentParamsFile); alignment_transformation.createAlignmentTransformContainer(topNode); // set parameter for sampling probability distribution @@ -245,8 +245,8 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) alignment_transformation.setUseNewSiliconRotationOrder(m_use_new_silicon_rotation_order); alignment_transformation.setUseModuleTiltAlways(m_use_module_tilt_always); - - + + if (buildAllGeometry(topNode) != Fun4AllReturnCodes::EVENT_OK) { return Fun4AllReturnCodes::ABORTEVENT; @@ -784,7 +784,7 @@ void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& r matDeco = std::make_shared(); } config.materialDecorator = matDeco; - // this does the building now. The TGeoDetector owns the + // this does the building now. The TGeoDetector owns the // tracking geometry m_TGeoDetector = std::make_unique(config); @@ -892,7 +892,7 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) auto vec3d = surf->center(m_geoCtxt); vec3d /= 10.0; auto vec3d_envelope = m_tpc_world_envelope_transform * vec3d; // needs to be in TPC envelope coordinates due to tilt in sims - + std::vector world_center = {vec3d_envelope(0), vec3d_envelope(1), vec3d_envelope(2)}; @@ -910,13 +910,13 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) if (mapIter != m_clusterSurfaceMapTpcEdit.end()) { - //std::cout << " Adding surface to map with layer " << layer << " side " << side << " sector " << sector << std::endl; + //std::cout << " Adding surface to map with layer " << layer << " side " << side << " sector " << sector << std::endl; mapIter->second.push_back(surf); } else { // Otherwise make a new map entry - // std::cout << "Starting new surfvec for layer " << layer << " side " << side << " sector " << sector << std::endl; + // std::cout << "Starting new surfvec for layer " << layer << " side " << side << " sector " << sector << std::endl; std::vector dumvec; dumvec.push_back(surf); std::pair> tmp = @@ -1270,7 +1270,7 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector= tpc_ref_radius_low && layer_rad < tpc_ref_radius_high) { layer = ilayer; @@ -1299,7 +1299,7 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector= m_nTpcModulesPerLayer) { std::cout << PHWHERE diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index 4180db74f3..bd9f1309bc 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -137,17 +137,22 @@ class MakeActsGeometry : public SubsysReco double getSurfStepPhi() { return m_surfStepPhi; } double getSurfStepZ() { return m_surfStepZ; } + /// assign local alignment parameter file to be used instead of CDB, if found + void set_alignmentParamsFile(const std::string& value ) { m_alignmentParamsFile = value; } + + /// assign TPC drift velocity void set_drift_velocity(double vd) { m_drift_velocity = vd; } + + /// assign TPC T0 void set_tpc_tzero(double tz) { m_tpc_tzero = tz; } void set_sampa_tzero_bias(double tzb) { m_sampa_tzero_bias = tzb; } void set_apply_tpc_tzero_correction(bool flag) { m_apply_tpc_tzero_correction = flag; } - + void set_nSurfPhi(unsigned int value) { m_nSurfPhi = value; } - // void set_maxSurfZ(double value) {m_maxSurfZ = value;} // set to TPC gas volume length - + void set_mvtx_applymisalign(bool b) { m_mvtxapplymisalign = b; } void set_intt_survey(bool surv) { m_inttSurvey = surv; } @@ -275,18 +280,28 @@ class MakeActsGeometry : public SubsysReco std::map base_layer_map = {{10, 0}, {12, 3}, {14, 7}, {16, 55}}; unsigned int mvtx_chips_per_stave = 9; - + /// Verbosity value handed from PHActsSourceLinks // int m_verbosity = 0; - double m_drift_velocity = 0.; // cm/ns, override from macro - double m_max_driftlength = 0.; // override from macro - double m_CM_halfwidth = 0.; // central membrane half width in cm + /// local alignment parameter file + /** this is passed to Alignment Transformation and used instead of CDB if found */ + std::string m_alignmentParamsFile = "./localAlignmentParamsFile.txt"; + /// TPC drift velocity overriden from macro (cm/ns) + double m_drift_velocity = 0.; + + /// maximum drift length, overriden from macro (cm) + double m_max_driftlength = 0.; + + /// central membrane half width (cm) overriden from macro + double m_CM_halfwidth = 0.; + + /// T0 correction bool m_apply_tpc_tzero_correction = false; double m_tpc_tzero = 0.0; // ns, override from macro double m_sampa_tzero_bias = 0.0; // ns, override from macro - + /// Magnetic field components to set Acts magnetic field std::string m_magField = "1.4"; double m_magFieldRescale = -1.; From af2a2a9423c5c98635bb85c954a8600d2609485d Mon Sep 17 00:00:00 2001 From: Hugo Pereira Da Costa Date: Wed, 8 Jul 2026 12:00:43 -0400 Subject: [PATCH 806/866] Make sure that alignmentParamsFile is not an empty string before opening. --- .../trackbase/AlignmentTransformation.cc | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index 0e9556866e..b3c1bbfba2 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -77,11 +77,17 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) // load alignment constants file std::ifstream datafile; - datafile.open(alignmentParamsFile); // looks for default file name on disk + if( !alignmentParamsFile.empty() ) + { + // looks for default file name on disk + datafile.open(alignmentParamsFile); + } + if (datafile.is_open()) { - std::cout << "AlignmentTransformation: Reading alignment parameters from disk file: " - << alignmentParamsFile << " localVerbosity = " << localVerbosity << std::endl; + std::cout + << "AlignmentTransformation: Reading alignment parameters from disk file: " + << alignmentParamsFile << " localVerbosity = " << localVerbosity << std::endl; } else { @@ -165,7 +171,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) std::cout << hitsetkey << " " << alpha << " " << beta << " " << gamma << " " << dx << " " << dy << " " << dz << " " << dgrx << " " << dgry << " " << dgrz << std::endl; } - + // Perturbation translations and angles for stave and sensor Eigen::Vector3d sensorAngles(alpha, beta, gamma); Eigen::Vector3d millepedeTranslation(dx, dy, dz); @@ -285,7 +291,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) zcenter *= -1; } Acts::Vector3 env_pos(radius*std::cos(phis), radius * std::sin(phis), zcenter); - Acts::Vector3 world_pos = m_tGeometry->transformTpcEnvelopeToWorld(env_pos); + Acts::Vector3 world_pos = m_tGeometry->transformTpcEnvelopeToWorld(env_pos); unsigned short sskey = 999; Surface this_surf = m_tGeometry->get_tpc_surface_from_coords(this_hitsetkey, world_pos, sskey); if(sskey == 999 || !this_surf) @@ -299,7 +305,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) <<" world_radius " << sqrt(world_pos.x() * world_pos.x() + world_pos.y() * world_pos.y()) << " sskey " << sskey << std::endl; */ - + Eigen::Vector3d localFrameTranslation(0, 0, 0); use_module_tilt = false; if (test_layer < 4 || use_module_tilt_always) @@ -312,18 +318,18 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) double this_radius = std::sqrt(this_center_envelope[0] * this_center_envelope[0] + this_center_envelope[1] * this_center_envelope[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 + + // set this flag for later use use_module_tilt = true; } Acts::Transform3 transform; transform = newMakeTransform(this_surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, false); Acts::GeometryIdentifier id = this_surf->geometryId(); - + if (localVerbosity) { - std::cout << " Add transform for TPC with surface GeometryIdentifier " << id + std::cout << " Add transform for TPC with surface GeometryIdentifier " << id << " trkrid " << trkrId << " hitsetkey " << this_hitsetkey << " layer " << this_layer << " sector " << sector << " side " << side << std::endl; if(localVerbosity > 1) @@ -339,10 +345,10 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) transformMapTransient->addTransform(id, transform); } } - + break; } - + case TrkrDefs::micromegasId: { if (perturbMM) @@ -464,7 +470,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, { if(use_module_tilt) { - // use module tilt transforms with local rotation followed by local translation + // use module tilt transforms with local rotation followed by local translation transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; } else @@ -475,7 +481,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, } else { - // silicon and TPOT + // silicon and TPOT if(use_new_silicon_rotation_order) { // use new transform order for silicon as well as TPC @@ -488,11 +494,11 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, } } } - + if (localVerbosity > 1) { Acts::Transform3 actstransform = actsTranslationAffine * actsRotationAffine; - + std::cout << "newMakeTransform" << std::endl; std::cout << "Input sensorAngles: " << std::endl << sensorAngles << std::endl; @@ -526,7 +532,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, std::cout << std::endl; } } - + return transform; } @@ -582,7 +588,7 @@ int AlignmentTransformation::getNodes(PHCompositeNode* topNode) std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; exit(1); } - + return 0; } @@ -685,7 +691,7 @@ void AlignmentTransformation::extractModuleCenterPositions() TrkrDefs::hitsetkey hitsetkey_out = TpcDefs::genHitSetKey(lout, isector, iside); double surf_rad_out = extractModuleCenter(hitsetkey_out, sectorphi); - + double mod_radius = (surf_rad_in + surf_rad_out) / 2.0; TpcModuleRadii[iside][isector][iregion] = mod_radius; @@ -714,7 +720,7 @@ double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetke TrkrDefs::subsurfkey subsurfkey = 0; // std::cout << "extractModuleCenter: sectorphi " << sectorphi << " world " << world(0) << " " << world(1) << " " << world(2) << std::endl; - + // Note: the "world" position here is in pre-tilt tpc envelope coordinates, not global coordinates // But, get_tpc_surface_from_coords() expects a global position as input, so we convert to world coordinates Acts::Vector3 world_envelope = m_tGeometry->transformTpcEnvelopeToWorld(world); From 6616e609243e93b387cc09bfbe9bd85f9e8e0a6f Mon Sep 17 00:00:00 2001 From: Anthony Denis Frawley Date: Wed, 8 Jul 2026 13:41:54 -0400 Subject: [PATCH 807/866] Improves diagnostic output to the log file, showing what TPC position parameters were used. Adds TPC position parameters to the PHG4TpcGeomv2::identify() method. --- offline/packages/trackbase/ActsGeometry.cc | 7 ++++-- .../packages/trackreco/MakeActsGeometry.cc | 16 +++++++------- .../g4simulation/g4detectors/PHG4TpcGeomv2.cc | 3 +++ .../g4simulation/g4tpc/PHG4TpcDetector.cc | 22 ++++++++++++++----- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/offline/packages/trackbase/ActsGeometry.cc b/offline/packages/trackbase/ActsGeometry.cc index 2e0f3f75c7..c6b320142b 100644 --- a/offline/packages/trackbase/ActsGeometry.cc +++ b/offline/packages/trackbase/ActsGeometry.cc @@ -188,7 +188,7 @@ Surface ActsGeometry::get_tpc_surface_from_coords( double surfStepPhi = m_tGeometry.tpcSurfStepPhi; const double dphi = std::atan2(std::sin(world_phi - surf_phi), std::cos(world_phi - surf_phi)); - if (std::abs(dphi) < surfStepPhi / 2.0) + if (std::abs(dphi) <= surfStepPhi / 2.0) { if(surf_center_envelope.z() < 0 && side != 0) { continue; } if(surf_center_envelope.z() > 0 && side != 1) { continue; } @@ -201,7 +201,10 @@ Surface ActsGeometry::get_tpc_surface_from_coords( if(surf_index == 999) { std::cout << "Error: surface not found in ActsGeometry::get_tpc_surface_from_coords " - << " layer " << layer << " side " << side << " sector " << sector << " world_phi " << world_phi << " world[0] " << world[0] << " world[1] " << world[1] << " hitsetkey " << hitsetkey << std::endl; + << " layer " << layer << " side " << side << " sector " << sector + << " world_phi (deg) " << world_phi* 180.0/M_PI + << " world[0] " << world[0] << " world[1] " << world[1] + << " hitsetkey " << hitsetkey << std::endl; return nullptr; } diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 1c51d07283..9f880724d3 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -205,21 +205,21 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) m_tpc_world_envelope_transform = m_tpc_envelope_world_transform.inverse(); // test - Acts::Vector3 test_env(10.0, 40.0, 80.0); + Acts::Vector3 test_env(0.0, 0.0, 113.025); std::cout << "MakeActsGeometry::InitRun transform tests north" << std::endl; - std::cout << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + std::cout << " test envelope position (mm) " << test_env.x()*10 << " " << test_env.y()*10 << " " << test_env.z()*10 << std::endl; Acts::Vector3 test_glob = m_tpc_envelope_world_transform * test_env; - std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; + std::cout << " test global position (mm) " << test_glob.x()*10 << " " << test_glob.y()*10 << " " << test_glob.z()*10 << std::endl; Acts::Vector3 test_env_check = m_tpc_world_envelope_transform * test_glob; - std::cout << " test_env_check " << test_env_check.x() << " " << test_env_check.y() << " " << test_env_check.z() << std::endl; + std::cout << " test inverse transform (mm) " << test_env_check.x()*10 << " " << test_env_check.y()*10 << " " << test_env_check.z()*10 << std::endl; - Acts::Vector3 test_envs(10.0, 40.0, -80.0); + Acts::Vector3 test_envs(0.0, 0.0, -113.025); std::cout << "MakeActsGeometry::InitRun transform tests south" << std::endl; - std::cout << " test_env " << test_envs.x() << " " << test_envs.y() << " " << test_envs.z() << std::endl; + std::cout << " test envelope position (mm) " << test_envs.x()*10 << " " << test_envs.y()*10 << " " << test_envs.z()*10 << std::endl; Acts::Vector3 test_globs = m_tpc_envelope_world_transform * test_envs; - std::cout << " test_glob " << test_globs.x() << " " << test_globs.y() << " " << test_globs.z() << std::endl; + std::cout << " test global position (mm) " << test_globs.x()*10 << " " << test_globs.y()*10 << " " << test_globs.z()*10 << std::endl; Acts::Vector3 test_env_checks = m_tpc_world_envelope_transform * test_globs; - std::cout << " test_env_check " << test_env_checks.x() << " " << test_env_checks.y() << " " << test_env_checks.z() << std::endl; + std::cout << " test inverse transform (mm) " << test_env_checks.x()*10 << " " << test_env_checks.y()*10 << " " << test_env_checks.z()*10 << std::endl; // Alignment Transformation declaration of instance - must be here to set initial alignment flag AlignmentTransformation alignment_transformation; diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc index e500c53117..85273db301 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc @@ -188,6 +188,9 @@ void PHG4TpcGeomv2::identify(std::ostream& os) const os << " sector_Phi_bias: " << sector_Phi_bias << std::endl; os << " sector_min_Phi: " << sector_min_Phi << std::endl; os << " sector_max_Phi: " << sector_max_Phi << std::endl; + + os << " rotation: rot_x " << rot_x << " rot_y " << rot_y << " rot_z " << rot_z << std::endl; + os << " translation: place_x " << place_x << " place_y " << place_y << " place_z " << place_z << std::endl; } std::pair diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc index e75a34961c..073988fc16 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc @@ -131,12 +131,22 @@ void PHG4TpcDetector::ConstructMe(G4LogicalVolume *logicWorld) logicWorld, false, false, OverlapCheck()); - - G4ThreeVector test_env(10.0, 40.0, 80.0); - std::cout << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; - G4ThreeVector test_glob = test_env.transform(rot); - std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; - + std::cout + << PHWHERE << std::endl + << " place_x " << m_Params->get_double_param("place_x")*cm + << " place_y " << m_Params->get_double_param("place_y")*cm + << " place_z " << m_Params->get_double_param("place_z")*cm + << " mm " << std::endl; + std::cout + << " rot_x " << m_Params->get_double_param("rot_x")*rad + << " rot_y " << m_Params->get_double_param("rot_y")*rad + << " rot_z " << m_Params->get_double_param("rot_z")*rad + << " rad " << std::endl; + + G4Point3D test_env(0.0*cm, 0.0*cm, 113.025*cm); + std::cout << " test envelope position (mm) " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + G4Point3D test_glob = test_env.transform(G4Transform3D(rot,trans)); + std::cout << " test global position (mm) " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; // geometry node add_geometry_node(); From 5ea833f4c4d05fe49363c2bf416953e0b1508e42 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 9 Jul 2026 02:20:57 -0400 Subject: [PATCH 808/866] fix uninitialized var use, removenot needed casts --- offline/packages/uspin/SpinDBContentv1.cc | 80 ++++++++++++++--------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/offline/packages/uspin/SpinDBContentv1.cc b/offline/packages/uspin/SpinDBContentv1.cc index acb110d585..0c67da5cbb 100644 --- a/offline/packages/uspin/SpinDBContentv1.cc +++ b/offline/packages/uspin/SpinDBContentv1.cc @@ -17,41 +17,41 @@ void SpinDBContentv1::InitializeV1() for (int icross = 0; icross < GetNCrossing(); icross++) { - bpol[icross] = (float) GetErrorValue(); - bpolerr[icross] = (float) GetErrorValue(); - bpolsys[icross] = (float) GetErrorValue(); - ypol[icross] = (float) GetErrorValue(); - ypolerr[icross] = (float) GetErrorValue(); - ypolsys[icross] = (float) GetErrorValue(); + bpol[icross] = GetErrorValue(); + bpolerr[icross] = GetErrorValue(); + bpolsys[icross] = GetErrorValue(); + ypol[icross] = GetErrorValue(); + ypolerr[icross] = GetErrorValue(); + ypolsys[icross] = GetErrorValue(); bpat[icross] = GetErrorValue(); ypat[icross] = GetErrorValue(); - scaler_mbd_vtxcut[icross] = (long long) GetErrorValue(); - scaler_mbd_nocut[icross] = (long long) GetErrorValue(); - scaler_zdc_nocut[icross] = (long long) GetErrorValue(); + scaler_mbd_vtxcut[icross] = GetErrorValue(); + scaler_mbd_nocut[icross] = GetErrorValue(); + scaler_zdc_nocut[icross] = GetErrorValue(); bad_bunch[icross] = GetErrorValue(); } - cross_angle = (float) GetErrorValue(); - cross_angle_std = (float) GetErrorValue(); - cross_angle_min = (float) GetErrorValue(); - cross_angle_max = (float) GetErrorValue(); - - asym_bf = (float) GetErrorValue(); - asym_bb = (float) GetErrorValue(); - asym_yf = (float) GetErrorValue(); - asym_yb = (float) GetErrorValue(); - asymerr_bf = (float) GetErrorValue(); - asymerr_bb = (float) GetErrorValue(); - asymerr_yf = (float) GetErrorValue(); - asymerr_yb = (float) GetErrorValue(); - phase_bf = (float) GetErrorValue(); - phase_bb = (float) GetErrorValue(); - phase_yf = (float) GetErrorValue(); - phase_yb = (float) GetErrorValue(); - phaseerr_bf = (float) GetErrorValue(); - phaseerr_bb = (float) GetErrorValue(); - phaseerr_yf = (float) GetErrorValue(); - phaseerr_yb = (float) GetErrorValue(); + cross_angle = GetErrorValue(); + cross_angle_std = GetErrorValue(); + cross_angle_min = GetErrorValue(); + cross_angle_max = GetErrorValue(); + + asym_bf = GetErrorValue(); + asym_bb = GetErrorValue(); + asym_yf = GetErrorValue(); + asym_yb = GetErrorValue(); + asymerr_bf = GetErrorValue(); + asymerr_bb = GetErrorValue(); + asymerr_yf = GetErrorValue(); + asymerr_yb = GetErrorValue(); + phase_bf = GetErrorValue(); + phase_bb = GetErrorValue(); + phase_yf = GetErrorValue(); + phase_yb = GetErrorValue(); + phaseerr_bf = GetErrorValue(); + phaseerr_bb = GetErrorValue(); + phaseerr_yf = GetErrorValue(); + phaseerr_yb = GetErrorValue(); } ///////////////////////////////////////////////////////////////// @@ -307,6 +307,8 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, float &value, float &error) { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = bpol[bunch]; @@ -320,6 +322,9 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, float &value, float &error, { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = bpol[bunch]; @@ -334,6 +339,8 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, double &value, double &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = (double) bpol[bunch]; @@ -347,6 +354,9 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, double &value, double &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = (double) bpol[bunch]; @@ -361,6 +371,8 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, float &value, float &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = ypol[bunch]; @@ -374,6 +386,9 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, float &value, float &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = ypol[bunch]; @@ -388,6 +403,8 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, double &value, double &err { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = (double) ypol[bunch]; @@ -401,6 +418,9 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, double &value, double &err { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = (double) ypol[bunch]; From f80580199702fe3c15ae269ed4c60e4d73e19651 Mon Sep 17 00:00:00 2001 From: "Blair D. Seidlitz" Date: Thu, 9 Jul 2026 12:29:38 -0400 Subject: [PATCH 809/866] Copy data MBD PMT container for data embeding --- .../packages/CaloEmbedding/CopyIODataNodes.cc | 75 +++++++++++++++++++ .../packages/CaloEmbedding/CopyIODataNodes.h | 4 + 2 files changed, 79 insertions(+) diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.cc b/offline/packages/CaloEmbedding/CopyIODataNodes.cc index 08428dccfe..c480ecc76f 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.cc +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.cc @@ -11,6 +11,9 @@ #include #include +#include +#include +#include #include #include @@ -56,6 +59,10 @@ int CopyIODataNodes::InitRun(PHCompositeNode *topNode) { CreateMbdOut(topNode, se->topNode()); } + if (m_CopyMbdPmtContainerFlag) + { + CreateMbdPmtContainer(topNode, se->topNode()); + } if (m_CopySyncObjectFlag) { CreateSyncObject(topNode, se->topNode()); @@ -92,6 +99,10 @@ int CopyIODataNodes::process_event(PHCompositeNode *topNode) { CopyMbdOut(topNode, se->topNode()); } + if (m_CopyMbdPmtContainerFlag) + { + CopyMbdPmtContainer(topNode, se->topNode()); + } if (m_CopySyncObjectFlag) { CopySyncObject(topNode, se->topNode()); @@ -364,6 +375,41 @@ void CopyIODataNodes::CreateMbdOut(PHCompositeNode *from_topNode, PHCompositeNod } +void CopyIODataNodes::CreateMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + MbdPmtContainer *from_mbdpmtcontainer = findNode::getClass(from_topNode, "MbdPmtContainer"); + if (!from_mbdpmtcontainer) + { + std::cout << "Could not locate MbdPmtContainer on " << from_topNode->getName() << std::endl; + m_CopyMbdPmtContainerFlag = false; + return; + } + + MbdPmtContainer *to_mbdpmtcontainer = findNode::getClass(to_topNode, "MbdPmtContainer_data"); + if (!to_mbdpmtcontainer) + { + PHNodeIterator iter(to_topNode); + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + dstNode = new PHCompositeNode("DST"); + to_topNode->addNode(dstNode); + } + + PHNodeIterator dstiter(dstNode); + PHCompositeNode *mbdNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "MBD")); + if (!mbdNode) + { + mbdNode = new PHCompositeNode("MBD"); + dstNode->addNode(mbdNode); + } + + to_mbdpmtcontainer = new MbdPmtContainerV1(); + PHIODataNode *newNode = new PHIODataNode(to_mbdpmtcontainer, "MbdPmtContainer_data", "PHObject"); + mbdNode->addNode(newNode); + } +} + void CopyIODataNodes::CreateTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { std::cout << "copying tower info" << std::endl; @@ -410,6 +456,35 @@ void CopyIODataNodes::CopyMbdOut(PHCompositeNode *from_topNode, PHCompositeNode return; } +void CopyIODataNodes::CopyMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + MbdPmtContainer *from_mbdpmtcontainer = findNode::getClass(from_topNode, "MbdPmtContainer"); + MbdPmtContainer *to_mbdpmtcontainer = findNode::getClass(to_topNode, "MbdPmtContainer_data"); + if (!from_mbdpmtcontainer || !to_mbdpmtcontainer) + { + return; + } + + to_mbdpmtcontainer->Reset(); + const short nPMTs = from_mbdpmtcontainer->get_npmt(); + to_mbdpmtcontainer->set_npmt(nPMTs); + for (short i = 0; i < nPMTs; ++i) + { + MbdPmtHit *from_mbdpmt = from_mbdpmtcontainer->get_pmt(i); + MbdPmtHit *to_mbdpmt = to_mbdpmtcontainer->get_pmt(i); + to_mbdpmt->set_pmt(from_mbdpmt->get_pmt(), from_mbdpmt->get_q(), from_mbdpmt->get_tt(), from_mbdpmt->get_tq()); + } + + if (Verbosity() > 0) + { + std::cout << "From MbdPmtContainer identify()" << std::endl; + from_mbdpmtcontainer->identify(); + std::cout << "To MbdPmtContainer identify()" << std::endl; + to_mbdpmtcontainer->identify(); + } + return; +} + void CopyIODataNodes::CreateSyncObject(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { SyncObject *from_syncobject = findNode::getClass(from_topNode, "Sync"); diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.h b/offline/packages/CaloEmbedding/CopyIODataNodes.h index 5045792a2d..03ff2ca3bc 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.h +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.h @@ -35,6 +35,7 @@ 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; } + void CopyMbdPmtContainer(bool flag = true) { m_CopyMbdPmtContainerFlag = flag; } void set_CopyTowerInfo(const std::string& set_from_towerInfo_name,const std::string& set_to_towerInfo_name) { from_towerInfo_name = set_from_towerInfo_name; @@ -65,6 +66,8 @@ class CopyIODataNodes : public SubsysReco void CopySyncObject(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); void CopyTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); void CreateTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CreateMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CopyMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); bool m_CopyCentralityInfoFlag = true; bool m_CopyEventHeaderFlag = true; @@ -74,6 +77,7 @@ class CopyIODataNodes : public SubsysReco bool m_CopyRunHeaderFlag = true; bool m_CopySyncObjectFlag = true; bool m_CopyTowerInfoFlag = false; + bool m_CopyMbdPmtContainerFlag = false; std::string from_towerInfo_name = {}; std::string to_towerInfo_name = {}; From 60ef6409ad26e7cd0588250640f31f47c75c5f52 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 10 Jul 2026 00:41:28 -0400 Subject: [PATCH 810/866] fix another source of uninit vars --- offline/packages/uspin/SpinDBContent.cc | 61 ++++++++++++++++++++++++- offline/packages/uspin/SpinDBContent.h | 16 +++---- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/offline/packages/uspin/SpinDBContent.cc b/offline/packages/uspin/SpinDBContent.cc index 9df8f70610..56c967afc9 100644 --- a/offline/packages/uspin/SpinDBContent.cc +++ b/offline/packages/uspin/SpinDBContent.cc @@ -2,7 +2,66 @@ #include -void SpinDBContent::identify(std::ostream& os) const +void SpinDBContent::identify(std::ostream &os) const { os << "virtual SpinDBContent object" << std::endl; } + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, float &value, float &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, float &value, float &error, float &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, double &value, double &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, double &value, double &error, double &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, float &value, float &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, float &value, float &error, float &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, double &value, double &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, double &value, double &error, double &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} diff --git a/offline/packages/uspin/SpinDBContent.h b/offline/packages/uspin/SpinDBContent.h index a8cc7ea486..fb75d49a93 100644 --- a/offline/packages/uspin/SpinDBContent.h +++ b/offline/packages/uspin/SpinDBContent.h @@ -71,14 +71,14 @@ class SpinDBContent : public PHObject virtual int GetBadRunFlag() const = 0; virtual int GetCrossingShift() const = 0; - virtual int GetPolarizationBlue(int, float&, float&) const { return -1; } - virtual int GetPolarizationBlue(int, float&, float&, float&) const { return -1; } - virtual int GetPolarizationBlue(int, double&, double&) const { return -1; } - virtual int GetPolarizationBlue(int, double&, double&, double&) const { return -1; } - virtual int GetPolarizationYellow(int, float&, float&) const { return -1; } - virtual int GetPolarizationYellow(int, float&, float&, float&) const { return -1; } - virtual int GetPolarizationYellow(int, double&, double&) const { return -1; } - virtual int GetPolarizationYellow(int, double&, double&, double&) const { return -1; } + virtual int GetPolarizationBlue(int, float&, float&) const; + virtual int GetPolarizationBlue(int, float&, float&, float&) const; + virtual int GetPolarizationBlue(int, double&, double&) const; + virtual int GetPolarizationBlue(int, double&, double&, double&) const; + virtual int GetPolarizationYellow(int, float&, float&) const; + virtual int GetPolarizationYellow(int, float&, float&, float&) const; + virtual int GetPolarizationYellow(int, double&, double&) const; + virtual int GetPolarizationYellow(int, double&, double&, double&) const; virtual int GetSpinPatternBlue(int) const { return -1; } virtual int GetSpinPatternYellow(int) const { return -1; } From fe708c0f0fa5aa6f0a4cc7e06cad39e05d0108e5 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Fri, 10 Jul 2026 10:07:26 -0400 Subject: [PATCH 811/866] set aveform to zero if pedestal is zero (dead channel) --- .../g4simulation/g4waveformsim/CaloWaveformSim.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 2401884e6e..be4a2c2c3f 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -514,7 +514,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { waveform_pedestal_vector.at(j) = (j < pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(pedestalsamples - 1); pedestal_mean += waveform_pedestal_vector.at(j); - if (Verbosity() > 2 && pedestal_tower->get_waveform_value(j) < 100) + if (Verbosity() > 1 && pedestal_tower->get_waveform_value(j) == 0) { std::cout << Name() << " channel: " << j << " too small pedestal value for index " << j << ": " << pedestal_tower->get_waveform_value(j) << std::endl; pedestal_tower->identify(); @@ -530,7 +530,14 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { if (m_noiseType == NoiseType::NOISE_TREE) { - m_waveforms.at(i).at(j) += waveform_pedestal_vector.at(j); + if (waveform_pedestal_vector.at(j) == 0) + { + m_waveforms.at(i).at(j) = 0; + } + else + { + m_waveforms.at(i).at(j) += waveform_pedestal_vector.at(j); + } } if (m_noiseType == NoiseType::NOISE_GAUSSIAN) { From 222baa7617992fbea6f76808b465566abde688a9 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Fri, 10 Jul 2026 11:44:47 -0400 Subject: [PATCH 812/866] Add TrkrHitv3 for INTT BCO payload --- .../intt/InttCombinedRawDataDecoder.cc | 4 +- offline/packages/trackbase/Makefile.am | 9 ++-- offline/packages/trackbase/TrkrHitv1.cc | 2 - offline/packages/trackbase/TrkrHitv1.h | 12 +---- offline/packages/trackbase/TrkrHitv2.cc | 2 - offline/packages/trackbase/TrkrHitv2.h | 12 +---- offline/packages/trackbase/TrkrHitv3.cc | 17 ++++++ offline/packages/trackbase/TrkrHitv3.h | 54 +++++++++++++++++++ offline/packages/trackbase/TrkrHitv3LinkDef.h | 5 ++ 9 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 offline/packages/trackbase/TrkrHitv3.cc create mode 100644 offline/packages/trackbase/TrkrHitv3.h create mode 100644 offline/packages/trackbase/TrkrHitv3LinkDef.h diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 574d7bf783..de20509f1c 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -499,7 +499,7 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) } - hit = new TrkrHitv2; + hit = new TrkrHitv3; //--hit->setAdc(adc); hit->setAdc(dac); hit->setFPHXBCO(intthit->get_FPHX_BCO()); diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 29d090c40a..fb0a7e7348 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -130,7 +130,8 @@ pkginclude_HEADERS = \ TrkrHitTruthAssoc.h \ TrkrHitTruthAssocv1.h \ TrkrHitv1.h \ - TrkrHitv2.h + TrkrHitv2.h \ + TrkrHitv3.h ROOTDICTS = \ CMFlashClusterContainer_Dict.cc \ @@ -201,7 +202,8 @@ ROOTDICTS = \ TrkrHitTruthAssocv1_Dict.cc \ TrkrHit_Dict.cc \ TrkrHitv1_Dict.cc \ - TrkrHitv2_Dict.cc + TrkrHitv2_Dict.cc \ + TrkrHitv3_Dict.cc pcmdir = $(libdir) @@ -287,7 +289,8 @@ libtrack_io_la_SOURCES = \ TrkrHitSetTpcv1.cc \ TrkrHitTruthAssocv1.cc \ TrkrHitv1.cc \ - TrkrHitv2.cc + TrkrHitv2.cc \ + TrkrHitv3.cc libtrack_la_LIBADD = \ libtrack_io.la \ diff --git a/offline/packages/trackbase/TrkrHitv1.cc b/offline/packages/trackbase/TrkrHitv1.cc index b96c56b42d..b0001fb30e 100644 --- a/offline/packages/trackbase/TrkrHitv1.cc +++ b/offline/packages/trackbase/TrkrHitv1.cc @@ -13,8 +13,6 @@ void TrkrHitv1::CopyFrom(const TrkrHit& source) // copy adc setAdc(source.getAdc()); - setFPHXBCO(source.getFPHXBCO()); - setBCO(source.getBCO()); } unsigned int TrkrHitv1::getAdc() const diff --git a/offline/packages/trackbase/TrkrHitv1.h b/offline/packages/trackbase/TrkrHitv1.h index 6ac15306e2..7ab629a1c3 100644 --- a/offline/packages/trackbase/TrkrHitv1.h +++ b/offline/packages/trackbase/TrkrHitv1.h @@ -28,9 +28,7 @@ class TrkrHitv1 : public TrkrHit // PHObject virtual overloads void identify(std::ostream& os = std::cout) const override { - os << "TrkrHitV1 class with adc = " << m_adc - << " and FPHX_BCO = " << m_fphx_bco - << " and BCO = " << m_bco << std::endl; + os << "TrkrHitV1 class with adc = " << m_adc << std::endl; } void Reset() override {} int isValid() const override { return 0; } @@ -51,17 +49,11 @@ class TrkrHitv1 : public TrkrHit double getEnergy() const override { return m_edep; } void setAdc(const unsigned int adc) override { m_adc = adc; } unsigned int getAdc() const override; - void setFPHXBCO(const uint16_t bco) override { m_fphx_bco = bco; } - uint16_t getFPHXBCO() const override { return m_fphx_bco; } - void setBCO(const uint64_t bco) override { m_bco = bco; } - uint64_t getBCO() const override { return m_bco; } protected: double m_edep = 0; unsigned int m_adc = 0; - uint16_t m_fphx_bco = 0; - uint64_t m_bco = 0; - ClassDefOverride(TrkrHitv1, 3); + ClassDefOverride(TrkrHitv1, 1); }; #endif // TRACKBASE_TRKRHITV1_H diff --git a/offline/packages/trackbase/TrkrHitv2.cc b/offline/packages/trackbase/TrkrHitv2.cc index 27a87085d3..6ef48d6435 100644 --- a/offline/packages/trackbase/TrkrHitv2.cc +++ b/offline/packages/trackbase/TrkrHitv2.cc @@ -14,8 +14,6 @@ void TrkrHitv2::CopyFrom(const TrkrHit& source) // copy adc setAdc(source.getAdc()); - setFPHXBCO(source.getFPHXBCO()); - setBCO(source.getBCO()); } // these set and get the energy before digitization diff --git a/offline/packages/trackbase/TrkrHitv2.h b/offline/packages/trackbase/TrkrHitv2.h index c637ad8cc9..8c83192019 100644 --- a/offline/packages/trackbase/TrkrHitv2.h +++ b/offline/packages/trackbase/TrkrHitv2.h @@ -33,9 +33,7 @@ class TrkrHitv2 : public TrkrHit // PHObject virtual overloads void identify(std::ostream& os = std::cout) const override { - os << "TrkrHitv2 class with adc = " << m_adc - << " and FPHX_BCO = " << m_fphx_bco - << " and BCO = " << m_bco << std::endl; + os << "TrkrHitv2 class with adc = " << m_adc << std::endl; } void Reset() override {} int isValid() const override { return 0; } @@ -59,16 +57,10 @@ class TrkrHitv2 : public TrkrHit // after digitization, these are the adc values void setAdc(const unsigned int adc) override; unsigned int getAdc() const override; - void setFPHXBCO(const uint16_t bco) override { m_fphx_bco = bco; } - uint16_t getFPHXBCO() const override { return m_fphx_bco; } - void setBCO(const uint64_t bco) override { m_bco = bco; } - uint64_t getBCO() const override { return m_bco; } protected: unsigned short m_adc = 0; - uint16_t m_fphx_bco = 0; - uint64_t m_bco = 0; - ClassDefOverride(TrkrHitv2, 3); + ClassDefOverride(TrkrHitv2, 1); }; #endif // TRACKBASE_TRKRHITV2_H diff --git a/offline/packages/trackbase/TrkrHitv3.cc b/offline/packages/trackbase/TrkrHitv3.cc new file mode 100644 index 0000000000..02c4958a5e --- /dev/null +++ b/offline/packages/trackbase/TrkrHitv3.cc @@ -0,0 +1,17 @@ +#include "TrkrHitv3.h" + +void TrkrHitv3::CopyFrom(const TrkrHit& source) +{ + // do nothing if copying onto oneself + if (this == &source) + { + return; + } + + // parent class method + TrkrHitv2::CopyFrom(source); + + // copy timing information + setFPHXBCO(source.getFPHXBCO()); + setBCO(source.getBCO()); +} diff --git a/offline/packages/trackbase/TrkrHitv3.h b/offline/packages/trackbase/TrkrHitv3.h new file mode 100644 index 0000000000..c4d06a0efc --- /dev/null +++ b/offline/packages/trackbase/TrkrHitv3.h @@ -0,0 +1,54 @@ +/** + * @file trackbase/TrkrHitv3.h + * @author Cheng-Wei Shih + * @brief Derived class v3 for hit object with INTT timing information + */ +#ifndef TRACKBASE_TRKRHITV3_H +#define TRACKBASE_TRKRHITV3_H + +#include "TrkrHitv2.h" + +#include +#include + +class TrkrHitv3 : public TrkrHitv2 +{ + public: + //! ctor + explicit TrkrHitv3() = default; + + //! dtor + ~TrkrHitv3() override = default; + + void identify(std::ostream& os = std::cout) const override + { + os << "TrkrHitv3 class with adc = " << m_adc + << " and FPHX_BCO = " << m_fphx_bco + << " and BCO = " << m_bco << std::endl; + } + + //! import PHObject CopyFrom, in order to avoid clang warning + using PHObject::CopyFrom; + + //! copy content from base class + void CopyFrom(const TrkrHit&) override; + + //! copy content from base class + void CopyFrom(TrkrHit* source) override + { + CopyFrom(*source); + } + + void setFPHXBCO(const uint16_t bco) override { m_fphx_bco = bco; } + uint16_t getFPHXBCO() const override { return m_fphx_bco; } + void setBCO(const uint64_t bco) override { m_bco = bco; } + uint64_t getBCO() const override { return m_bco; } + + protected: + uint16_t m_fphx_bco = 0; + uint64_t m_bco = 0; + + ClassDefOverride(TrkrHitv3, 1); +}; + +#endif // TRACKBASE_TRKRHITV3_H diff --git a/offline/packages/trackbase/TrkrHitv3LinkDef.h b/offline/packages/trackbase/TrkrHitv3LinkDef.h new file mode 100644 index 0000000000..11a8703b56 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TrkrHitv3 + ; + +#endif From 514930750dbc463589487197c5154c7425054d82 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 10 Jul 2026 15:01:43 -0400 Subject: [PATCH 813/866] Changed laserClusters to store hitsetkey, hitkey, and adc for hits rather than coordinates. Only hardware cluster centroid is saved other than these (maintains use of fit if turned on). Laser clusterizer updated to function with these new clusters. Nothing else changed yet, so no testing as of now --- offline/packages/tpc/LaserClusterizer.cc | 356 ++++++------------ offline/packages/trackbase/LaserCluster.h | 18 + .../packages/trackbase/LaserClusterLinkDef.h | 2 + offline/packages/trackbase/LaserClusterv3.cc | 78 ++++ offline/packages/trackbase/LaserClusterv3.h | 116 ++++++ .../trackbase/LaserClusterv3LinkDef.h | 5 + offline/packages/trackbase/Makefile.am | 3 + 7 files changed, 334 insertions(+), 244 deletions(-) create mode 100644 offline/packages/trackbase/LaserClusterv3.cc create mode 100644 offline/packages/trackbase/LaserClusterv3.h create mode 100644 offline/packages/trackbase/LaserClusterv3LinkDef.h diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 925b0c6e8a..45495edb70 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include // for hitkey, getLayer #include @@ -432,9 +432,6 @@ namespace { findConnectedRegions3(clusHits, maxADCKey, my_data.Verbosity); - double rSum = 0.0; - double phiSum = 0.0; - double tSum = 0.0; double layerSum = 0.0; double iphiSum = 0.0; @@ -444,28 +441,28 @@ namespace double maxAdc = 0.0; TrkrDefs::hitsetkey maxKey = 0; - double secondmaxAdc = 0.0; - TrkrDefs::hitsetkey secondmaxKey = 0; + //double secondmaxAdc = 0.0; + //TrkrDefs::hitsetkey secondmaxKey = 0; unsigned int nHits = clusHits.size(); - auto *clus = new LaserClusterv2; + auto *clus = new LaserClusterv3; int meanSide = 0; - std::vector usedLayer; - std::vector usedIPhi; - std::vector usedIT; + std::vector usedLayer; + std::vector usedIPhi; + std::vector usedIT; - double meanLayer = 0.0; - double meanIPhi = 0.0; - double meanIT = 0.0; + float meanLayer = 0.0; + float meanIPhi = 0.0; + float meanIT = 0.0; for (auto &clusHit : clusHits) { - double coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; + int coords[3] = {(int)clusHit.first.get<0>(), (int)clusHit.first.get<1>(), (int)clusHit.first.get<2>()}; std::pair spechitkey = clusHit.second.second; - unsigned int adc = clusHit.second.first; + uint16_t adc = clusHit.second.first; int side = TpcDefs::getSide(spechitkey.second); @@ -478,17 +475,8 @@ namespace 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 (double i : usedLayer) + for (int i : usedLayer) { if (coords[0] == i) { @@ -503,7 +491,7 @@ namespace } bool foundIPhi = false; - for (double i : usedIPhi) + for (int i : usedIPhi) { if (coords[1] == i) { @@ -518,7 +506,7 @@ namespace } bool foundIT = false; - for (double i : usedIT) + for (int i : usedIT) { if (coords[2] == i) { @@ -532,67 +520,39 @@ namespace 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, (double) adc); + clus->addHit(spechitkey.second, spechitkey.first, adc); - rSum += r * adc; - phiSum += phi * adc; - tSum += t * adc; + layerSum += 1.0 * coords[0] * adc; + iphiSum += 1.0 * coords[1] * adc; + itSum += 1.0 * coords[2] * adc; - layerSum += coords[0] * adc; - iphiSum += coords[1] * adc; - itSum += coords[2] * adc; + meanLayer += 1.0 * coords[0]; + meanIPhi += 1.0 * coords[1]; + meanIT += 1.0 * coords[2]; - meanLayer += coords[0]; - meanIPhi += coords[1]; - meanIT += coords[2]; + adcSum += 1.0*adc; - adcSum += adc; - - if (adc > maxAdc) + if (1.0*adc > maxAdc) { - secondmaxAdc = maxAdc; - secondmaxKey = maxKey; + //secondmaxAdc = maxAdc; + //secondmaxKey = maxKey; maxAdc = adc; maxKey = spechitkey.second; } - else if (adc > secondmaxAdc) + //else if (1.0*adc > secondmaxAdc) { - secondmaxAdc = adc; - secondmaxKey = spechitkey.second; + //secondmaxAdc = adc; + //secondmaxKey = spechitkey.second; } } - if (nHits == 0) + if (nHits == 0 || clus->getNhits() == 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; - if (meanSide < 0) - { - clusZ = -clusZ; - for (int i = 0; i < (int) clus->getNhits(); 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()); @@ -609,29 +569,54 @@ namespace double sigmaWeightedIPhi = 0.0; double sigmaWeightedIT = 0.0; - 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); - 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); + LaserClusterHitInfo LCHI = clus->getHit(i); + uint8_t layer = TrkrDefs::getLayer(LCHI.hitsetkey); + uint16_t iphi = TpcDefs::getPad(LCHI.hitkey); + uint16_t it = TpcDefs::getTBin(LCHI.hitkey); + + sigmaLayer += pow(layer - meanLayer, 2); + sigmaIPhi += pow(iphi - meanIPhi, 2); + sigmaIT += pow(it - meanIT, 2); + + sigmaWeightedLayer += LCHI.adc * pow(layer - (layerSum / adcSum), 2); + sigmaWeightedIPhi += LCHI.adc * pow(iphi - (iphiSum / adcSum), 2); + sigmaWeightedIT += LCHI.adc * pow(it - (itSum / adcSum), 2); } - bool fitSuccess = false; - ROOT::Fit::Fitter *fit3D = new ROOT::Fit::Fitter; + clus->setNLayers(usedLayer.size()); + clus->setNIPhi(usedIPhi.size()); + clus->setNIT(usedIT.size()); + clus->setLayer(layerSum / adcSum); + clus->setIPhi(iphiSum / adcSum); + clus->setIT(itSum / adcSum); + clus->setSDLayer(sqrt(sigmaLayer / nHits)); + clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); + clus->setSDIT(sqrt(sigmaIT / nHits)); + clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); + clus->setSDWeightedIPhi(sqrt(sigmaWeightedIPhi / adcSum)); + clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); if (my_data.doFitting) { + 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); + + for (int i = 0; i < (int) clus->getNhits(); i++) + { + LaserClusterHitInfo LCHI = clus->getHit(i); + uint8_t layer = TrkrDefs::getLayer(LCHI.hitsetkey); + uint16_t iphi = TpcDefs::getPad(LCHI.hitkey); + uint16_t it = TpcDefs::getTBin(LCHI.hitkey); + my_data.hitHist->Fill(layer, iphi, it, LCHI.adc); + } + + bool fitSuccess = false; + ROOT::Fit::Fitter *fit3D = new ROOT::Fit::Fitter; + double par_init[7] = { maxAdc, meanLayer, @@ -726,179 +711,62 @@ namespace { std::cout << "fit success: " << fitSuccess << std::endl; } - } - pthread_mutex_unlock(&mythreadlock); - - if (my_data.doFitting && fitSuccess) - { - 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))); - - double RLow = layergeomLow->get_radius(); - double RHigh = layergeomHigh->get_radius(); - - double phiHigh_RLow = -999.0; - 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 (fitSuccess) { - phiHigh_RHigh = layergeomHigh->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); - } + const ROOT::Fit::FitResult &result = fit3D->Result(); - double phiLow_RLow = layergeomLow->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); - double phiLow_RHigh = layergeomHigh->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + PHG4TpcGeom *layergeomLow = my_data.geom_container->GetLayerCellGeom((int) floor(result.Parameter(1))); + PHG4TpcGeom *layergeomHigh = my_data.geom_container->GetLayerCellGeom((int) ceil(result.Parameter(1))); - double meanR = (result.Parameter(1) - floor(result.Parameter(1))) * (RHigh - RLow) + RLow; + //double RLow = layergeomLow->get_radius(); + //double RHigh = layergeomHigh->get_radius(); - 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 phiHigh_RLow = -999.0; + 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()) + { + phiHigh_RHigh = layergeomHigh->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + } - 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) - { - meanPhi = meanPhi_RLow; - } + //double phiLow_RLow = layergeomLow->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + //double phiLow_RHigh = layergeomHigh->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); - if (phiHigh_RLow == -999.0 && phiHigh_RHigh == -999.0) - { - clus->setAdc(adcSum); - clus->setX(clusX); - clus->setY(clusY); - clus->setZ(clusZ); - clus->setFitMode(false); - clus->setLayer(layerSum / adcSum); - clus->setIPhi(iphiSum / adcSum); - clus->setIT(itSum / adcSum); - clus->setNLayers(usedLayer.size()); - clus->setNIPhi(usedIPhi.size()); - clus->setNIT(usedIT.size()); - clus->setSDLayer(sqrt(sigmaLayer / nHits)); - clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); - clus->setSDIT(sqrt(sigmaIT / nHits)); - clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); - clus->setSDWeightedIPhi(sqrt(sigmaWeightedIPhi / adcSum)); - clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); + if (phiHigh_RLow == -999.0 && phiHigh_RHigh == -999.0) + { + clus->setFitMode(false); + } + else + { + clus->setFitMode(true); + clus->setLayer(result.Parameter(1)); + clus->setIPhi(result.Parameter(2)); + clus->setIT(result.Parameter(4)); + clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); + clus->setSDWeightedIPhi(result.Parameter(3)); + clus->setSDWeightedIT(result.Parameter(5)); + } } - else + + delete fit3D; + if (my_data.hitHist) { - clus->setAdc(adcSum); - clus->setX(meanR * cos(meanPhi)); - clus->setY(meanR * sin(meanPhi)); - clus->setZ(clusZ); - clus->setFitMode(true); - clus->setLayer(result.Parameter(1)); - clus->setIPhi(result.Parameter(2)); - clus->setIT(result.Parameter(4)); - clus->setNLayers(usedLayer.size()); - clus->setNIPhi(usedIPhi.size()); - clus->setNIT(usedIT.size()); - clus->setSDLayer(sqrt(sigmaLayer / nHits)); - clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); - clus->setSDIT(sqrt(sigmaIT / nHits)); - clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); - clus->setSDWeightedIPhi(result.Parameter(3)); - clus->setSDWeightedIT(result.Parameter(5)); + delete my_data.hitHist; + my_data.hitHist = nullptr; } - } - else - { - clus->setAdc(adcSum); - clus->setX(clusX); - clus->setY(clusY); - clus->setZ(clusZ); - clus->setFitMode(false); - clus->setLayer(layerSum / adcSum); - clus->setIPhi(iphiSum / adcSum); - clus->setIT(itSum / adcSum); - clus->setNLayers(usedLayer.size()); - clus->setNIPhi(usedIPhi.size()); - clus->setNIT(usedIT.size()); - clus->setSDLayer(sqrt(sigmaLayer / nHits)); - clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); - clus->setSDIT(sqrt(sigmaIT / nHits)); - clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); - clus->setSDWeightedIPhi(sqrt(sigmaWeightedIPhi / adcSum)); - clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); + pthread_mutex_unlock(&mythreadlock); } - pthread_mutex_lock(&mythreadlock); - // Get surface of max ADC hit - bool alignmentflag = alignmentTransformationContainer::use_alignment; - alignmentTransformationContainer::use_alignment = false; - Acts::Vector3 ideal(clus->getX(), clus->getY(), clus->getZ()); - TrkrDefs::subsurfkey subsurfkey = 0; - - Surface surface = my_data.tGeometry->get_tpc_surface_from_coords( - maxKey, - ideal, - subsurfkey); - - if (!surface) - { - // try second maximum ADC hit - if (secondmaxKey != 0) - { - surface = my_data.tGeometry->get_tpc_surface_from_coords( - secondmaxKey, - ideal, - subsurfkey); - } - - // if still no surface, skip this cluster - if (!surface) - { - // clean up - alignmentTransformationContainer::use_alignment = alignmentflag; - delete clus; - delete fit3D; - if (my_data.hitHist) - { - delete my_data.hitHist; - my_data.hitHist = nullptr; - } - pthread_mutex_unlock(&mythreadlock); - return; - } - } - - // Convert from ideal TPC coordinates to surface coordinates - Acts::Vector3 local = surface->localToGlobalTransform(my_data.tGeometry->geometry().getGeoContext()).inverse() * (ideal * Acts::UnitConstants::cm); - local /= Acts::UnitConstants::cm; - - // Convert back to TPC coordinates with alignment applied - alignmentTransformationContainer::use_alignment = true; - Acts::Vector3 global = surface->localToGlobalTransform(my_data.tGeometry->geometry().getGeoContext()) * (local * Acts::UnitConstants::cm); - global /= Acts::UnitConstants::cm; - clus->setX(global(0)); - clus->setY(global(1)); - clus->setZ(global(2)); - - alignmentTransformationContainer::use_alignment = alignmentflag; - pthread_mutex_unlock(&mythreadlock); - - - const auto ckey = TrkrDefs::genClusKey(maxKey, my_data.cluster_vector.size()); + 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); + pthread_mutex_unlock(&mythreadlock); - - delete fit3D; - - if (my_data.hitHist) - { - delete my_data.hitHist; - my_data.hitHist = nullptr; - } } void ProcessModuleData(thread_data *my_data) diff --git a/offline/packages/trackbase/LaserCluster.h b/offline/packages/trackbase/LaserCluster.h index a4c42e2081..3e82851023 100644 --- a/offline/packages/trackbase/LaserCluster.h +++ b/offline/packages/trackbase/LaserCluster.h @@ -9,9 +9,18 @@ #include +#include + #include #include +struct LaserClusterHitInfo +{ + TrkrDefs::hitsetkey hitsetkey = 0; + TrkrDefs::hitkey hitkey = 0; + uint16_t adc = 0; +}; + /** * @brief Base class for laser cluster object * @@ -60,6 +69,13 @@ class LaserCluster : public PHObject virtual float getIT() const { return std::numeric_limits::quiet_NaN(); } virtual void setIT(float) {} + virtual unsigned int getLayerInt() const { return std::numeric_limits::quiet_NaN(); } + virtual void setLayerInt(unsigned int) {} + virtual unsigned int getIPhiInt() const { return std::numeric_limits::quiet_NaN(); } + virtual void setIPhiInt(unsigned int) {} + virtual unsigned int getITInt() const { return std::numeric_limits::quiet_NaN(); } + virtual void setITInt(unsigned int) {} + // // cluster info // @@ -121,6 +137,8 @@ class LaserCluster : public PHObject virtual void setHitAdc(int, float) {} virtual float getHitAdc(int) const { return std::numeric_limits::quiet_NaN(); } + virtual void addHit(TrkrDefs::hitsetkey, TrkrDefs::hitkey, uint16_t) {} + virtual LaserClusterHitInfo getHit(int) const { return LaserClusterHitInfo(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()); } protected: LaserCluster() = default; diff --git a/offline/packages/trackbase/LaserClusterLinkDef.h b/offline/packages/trackbase/LaserClusterLinkDef.h index 4502785e29..e7645e16b6 100644 --- a/offline/packages/trackbase/LaserClusterLinkDef.h +++ b/offline/packages/trackbase/LaserClusterLinkDef.h @@ -1,5 +1,7 @@ #ifdef __CINT__ #pragma link C++ class LaserCluster+; +#pragma link C++ struct LaserClusterHitInfo+; +#pragma link C++ class std::vector+; #endif diff --git a/offline/packages/trackbase/LaserClusterv3.cc b/offline/packages/trackbase/LaserClusterv3.cc new file mode 100644 index 0000000000..a0f9e308c8 --- /dev/null +++ b/offline/packages/trackbase/LaserClusterv3.cc @@ -0,0 +1,78 @@ +/** + * @file trackbase/LaserClusterv3.cc + * @author Ben Kimelman + * @date July 2026 + * @brief Implementation of LaserClusterv3 + */ +#include "LaserClusterv3.h" + +#include +#include // for swap + +void LaserClusterv3::identify(std::ostream& os) const +{ + os << "---LaserClusterv3--------------------" << std::endl; + + os << " " << m_hits.size() << " hits"; + os << " fit? " << m_fitMode; + os << " (layer, iphi, it) = (" << m_posHardware[0]; + os << ", " << m_posHardware[1] << ", "; + os << m_posHardware[2] << ")"; + os << " adc = " << getAdc() << std::endl; + + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int LaserClusterv3::isValid() const +{ + if(getNhits() == 0) + { + return 0; + } + + return 1; +} + +unsigned int LaserClusterv3::getAdc() const +{ + unsigned int adc = 0; + for(const auto &LCHI : m_hits) + { + adc += (unsigned int) LCHI.adc; + } + return adc; +} + +void LaserClusterv3::CopyFrom( const LaserCluster& source ) +{ + // do nothing if copying onto oneself + if( this == &source ) + { + return; + } + + // parent class method + LaserCluster::CopyFrom( source ); + setLayerInt( source.getLayerInt() ); + setIPhiInt( source.getIPhiInt() ); + setITInt( source.getITInt() ); + setNLayers( source.getNLayers() ); + setNIPhi( source.getNIPhi() ); + setNIT( source.getNIT() ); + setSDLayer( source.getSDLayer() ); + setSDIPhi( source.getSDIPhi() ); + setSDIT( source.getSDIT() ); + setSDWeightedLayer( source.getSDWeightedLayer() ); + setSDWeightedIPhi( source.getSDWeightedIPhi() ); + setSDWeightedIT( source.getSDWeightedIT() ); + + + for(int i=0; i<(int)source.getNhits(); i++){ + LaserClusterHitInfo LCHI = source.getHit(i); + addHit(LCHI.hitsetkey, LCHI.hitkey, LCHI.adc); + } +} + diff --git a/offline/packages/trackbase/LaserClusterv3.h b/offline/packages/trackbase/LaserClusterv3.h new file mode 100644 index 0000000000..1b158e4e5e --- /dev/null +++ b/offline/packages/trackbase/LaserClusterv3.h @@ -0,0 +1,116 @@ +/** + * @file trackbase/LaserClusterv3.h + * @author Ben Kimelman + * @date July 2026 + * @brief Version 3 of CMFLashCluster + */ +#ifndef TRACKBASE_LASERCLUSTERV3_H +#define TRACKBASE_LASERCLUSTERV3_H + +#include "LaserCluster.h" + +#include +#include + +class PHObject; + +/** + * @brief Version 3 of LaserCluster + * + * Note - D. McGlinchey June 2018: + * CINT does not like "override", so ignore where CINT + * complains. Should be checked with ROOT 6 once + * migration occurs. + */ + + +class LaserClusterv3 : public LaserCluster +{ + public: + //! ctor + LaserClusterv3() = default; + + // PHObject virtual overloads + void Reset() override {} + int isValid() const override; + PHObject* CloneMe() const override { return new LaserClusterv3(*this); } + + //! copy content from base class + void CopyFrom( const LaserCluster& ) override; + + //! copy content from base class + void CopyFrom( LaserCluster* source ) override + { CopyFrom( *source ); } + + bool getFitMode() const override { return m_fitMode; } + void setFitMode(bool fitMode) override { m_fitMode = fitMode; } + + unsigned int getLayerInt() const override { return m_posHardware[0]; } + void setLayerInt(unsigned int layer) override { m_posHardware[0] = layer; } + unsigned int getIPhiInt() const override { return m_posHardware[1]; } + void setIPhiInt(unsigned int iphi) override { m_posHardware[1] = iphi; } + unsigned int getITInt() const override { return m_posHardware[2]; } + void setITInt(unsigned int it) override { m_posHardware[2] = it; } + + unsigned int getNhits() const override {return (unsigned int)m_hits.size();} + + // + // cluster info + // + unsigned int getAdc() const override; + + void setNLayers(unsigned int nLayers) override { m_nLayers = nLayers; } + unsigned int getNLayers() const override { return m_nLayers; } + + void setNIPhi(unsigned int nIPhi) override { m_nIPhi = nIPhi; } + unsigned int getNIPhi() const override { return m_nIPhi; } + + void setNIT(unsigned int nIT) override { m_nIT = nIT; } + unsigned int getNIT() const override { return m_nIT; } + + void setSDLayer(float SDLayer) override { m_SDLayer = SDLayer; } + float getSDLayer() const override { return m_SDLayer; } + + void setSDIPhi(float SDIPhi) override { m_SDIPhi = SDIPhi; } + float getSDIPhi() const override { return m_SDIPhi; } + + void setSDIT(float SDIT) override { m_SDIT = SDIT; } + float getSDIT() const override { return m_SDIT; } + + void setSDWeightedLayer(float SDLayer) override { m_SDWeightedLayer = SDLayer; } + float getSDWeightedLayer() const override { return m_SDWeightedLayer; } + + void setSDWeightedIPhi(float SDIPhi) override { m_SDWeightedIPhi = SDIPhi; } + float getSDWeightedIPhi() const override { return m_SDWeightedIPhi; } + + void setSDWeightedIT(float SDIT) override { m_SDWeightedIT = SDIT; } + float getSDWeightedIT() const override { return m_SDWeightedIT; } + + void addHit(TrkrDefs::hitsetkey hitsetkey, TrkrDefs::hitkey hitkey, uint16_t adc) override { m_hits.push_back(LaserClusterHitInfo(hitsetkey, hitkey, adc)); }; + LaserClusterHitInfo getHit(int hitIndex) const override { return m_hits[hitIndex]; }; + + void identify(std::ostream& os = std::cout) const override; + + protected: + + std::vector m_hits; + + unsigned int m_posHardware[3] = {std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; + bool m_fitMode{false}; + + /// number of TPC clusters used to create this central mebrane cluster + unsigned int m_nhits = std::numeric_limits::max(); + unsigned int m_nLayers = std::numeric_limits::max(); + unsigned int m_nIPhi = std::numeric_limits::max(); + unsigned int m_nIT = std::numeric_limits::max(); + float m_SDLayer = std::numeric_limits::quiet_NaN(); + float m_SDIPhi = std::numeric_limits::quiet_NaN(); + float m_SDIT = std::numeric_limits::quiet_NaN(); + float m_SDWeightedLayer = std::numeric_limits::quiet_NaN(); + float m_SDWeightedIPhi = std::numeric_limits::quiet_NaN(); + float m_SDWeightedIT = std::numeric_limits::quiet_NaN(); + + ClassDefOverride(LaserClusterv3, 1) +}; + +#endif //TRACKBASE_LASERCLUSTERV3_H diff --git a/offline/packages/trackbase/LaserClusterv3LinkDef.h b/offline/packages/trackbase/LaserClusterv3LinkDef.h new file mode 100644 index 0000000000..769b08954f --- /dev/null +++ b/offline/packages/trackbase/LaserClusterv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class LaserClusterv3+; + +#endif diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 52c4c3e505..4024980385 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -69,6 +69,7 @@ pkginclude_HEADERS = \ LaserClusterContainerv1.h \ LaserClusterv1.h \ LaserClusterv2.h \ + LaserClusterv3.h \ MaterialWiper.h \ MagneticFieldOptions.h \ MvtxDefs.h \ @@ -151,6 +152,7 @@ ROOTDICTS = \ LaserCluster_Dict.cc \ LaserClusterv1_Dict.cc \ LaserClusterv2_Dict.cc \ + LaserClusterv3_Dict.cc \ MvtxEventInfo_Dict.cc \ MvtxEventInfov1_Dict.cc \ MvtxEventInfov2_Dict.cc \ @@ -239,6 +241,7 @@ libtrack_io_la_SOURCES = \ LaserClusterContainerv1.cc \ LaserClusterv1.cc \ LaserClusterv2.cc \ + LaserClusterv3.cc \ MvtxDefs.cc \ MvtxEventInfo.cc \ MvtxEventInfov1.cc \ From e7118426e107dbb0f088d6f9546884a27c4b6f4d Mon Sep 17 00:00:00 2001 From: bkimelman Date: Fri, 10 Jul 2026 15:03:56 -0400 Subject: [PATCH 814/866] commit of lam fits as is, no updated for new clusters yet --- offline/packages/tpccalib/TpcLaminationFitting.cc | 6 ++++++ offline/packages/tpccalib/TpcLaminationFitting.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 28e718d69b..9de1358121 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -75,6 +75,9 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) //m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;m;B") %(s == 1 ? "North" : "South")).str().c_str(), 101, -0.101, 0.101, 101, -10.1, 10.1); //m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;A (asymptote);C (decay constant)") %(s == 1 ? "North" : "South")).str().c_str(), 101, -1.005, 0.005, 101, -0.0025, 0.5025); + + clusterMap[s] = new TH2D((boost::format("clusterMap_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s;#phi;R [cm]") %(s == 1 ? "North" : "South")).str().c_str(), 2000, 0.0, 2*TMath::Pi(), 2000, 28, 80); + for (int l = 0; l < 18; l++) { double shift = (l * M_PI / 9); @@ -422,8 +425,10 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) } TVector3 tmp_pos(pos[0], pos[1], pos[2]); + if(cmclus->getNLayers() > m_nLayerCut && (!m_useSDLayerCut || cmclus->getSDWeightedLayer() > 0.5)) { + clusterMap[side]->Fill(tmp_pos.Phi(), tmp_pos.Perp(), weight); for (int l = 0; l < 18; l++) { double shift = m_laminationIdeal[l][side]; @@ -1175,6 +1180,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) for(int s=0; s<2; s++) { + clusterMap[s]->Write(); for(int l=0; l<18; l++) { m_side = s; diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index b42fe76416..84618b3043 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -115,6 +115,8 @@ class TpcLaminationFitting : public SubsysReco TH2 *phiDistortionLamination[2]{nullptr}; //TH2 *scaleFactorMap[2]{nullptr}; + TH2 *clusterMap[2]{nullptr}; + unsigned int m_nLayerCut{1}; bool m_useSDLayerCut{true}; bool m_adcWeight{false}; From 8f07569445226e4c80e1a280623fa2563b1b7641 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Fri, 10 Jul 2026 15:42:19 -0400 Subject: [PATCH 815/866] Adding new parameters to evaluator. --- .../g4simulation/g4eval/SvtxEvaluator.cc | 223 +++++++++++++++++- 1 file changed, 217 insertions(+), 6 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 28c62f9d20..52b674433b 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -148,8 +148,11 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) { _ntp_cluster = new TNtuple("ntp_cluster", "svtxcluster => max truth", "event:seed:hitID:x:y:z:r:phi:eta:theta:ex:ey:ez:ephi:pez:pephi:" - "e:adc:maxadc:layer:phielem:zelem:size:phisize:zsize:" - "pedge:redge:ovlp:" + "e:adc:maxadc:cenadc:padcen:tbincen:padmax:tbinmax:layer:phielem:zelem:" + "size:phisize:zsize:" + "pedge:redge:sledge:sredge:tledge:tredge:dledge:dredge:hledge:hredge:" + "slmix:srmix:tlmix:trmix:ovlp:" + "phibinlo:phibinhi:tbinlo:tbinhi:padphase:tbinphase:" "trackID:niter:g4hitID:gx:" "gy:gz:gr:gphi:geta:gt:gtrackID:gflavor:" "gpx:gpy:gpz:gvx:gvy:gvz:gvt:" @@ -179,7 +182,8 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "crossing:siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" "charge:quality:chisq:ndf:nhits:layers:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:nlmaps:nlintt:nltpc:nlmms:" "vertexID:vx:vy:vz:dca2d:dca2dsigma:dca3dxy:dca3dxysigma:dca3dz:dca3dzsigma:pcax:pcay:pcaz:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" - "npedge:nredge:nbig:novlp:merr:msize:" + "nedge:npedge:nredge:nsledge:nsredge:ntledge:ntredge:ndledge:ndredge:nhledge:nhredge:" + "nslmix:nsrmix:ntlmix:ntrmix:nbig:novlp:merr:msize:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -196,7 +200,8 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gfpx:gfpy:gfpz:gfx:gfy:gfz:" "gembed:gprimary:gcrossing:gparentflavor:gparentid:gprimaryflavor:gprimaryid:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" "ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" - "npedge:nredge:nbig:novlp:merr:msize:" + "nedge:npedge:nredge:nsledge:nsredge:ntledge:ntredge:ndledge:ndredge:nhledge:nhredge:" + "nslmix:nsrmix:ntlmix:ntrmix:nbig:novlp:merr:msize:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -410,7 +415,7 @@ void SvtxEvaluator::printInputInfo(PHCompositeNode* topNode) } } - std::cout << "---SVXTRACKS-------------" << std::endl; + std::cout << "---SVTXTRACKS-------------" << std::endl; SvtxTrackMap* trackmap = findNode::getClass(topNode, _trackmapname); if (trackmap) { @@ -428,7 +433,7 @@ void SvtxEvaluator::printInputInfo(PHCompositeNode* topNode) } } - std::cout << "---SVXVERTEXES-------------" << std::endl; + std::cout << "---SVTXVERTEXES-------------" << std::endl; SvtxVertexMap* vertexmap = nullptr; if (_use_initial_vertex) { @@ -1949,9 +1954,27 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float phisize = 0; float zsize = 0; float maxadc = -999; + float padcen = -999.; + float tbincen = -999.; + float padmax = -999; + float tbinmax = -999; float redge = std::numeric_limits::quiet_NaN(); float pedge = std::numeric_limits::quiet_NaN(); + float sledge = std::numeric_limits::quiet_NaN(); + float sredge = std::numeric_limits::quiet_NaN(); + float tledge = std::numeric_limits::quiet_NaN(); + float tredge = std::numeric_limits::quiet_NaN(); + float dledge = std::numeric_limits::quiet_NaN(); + float dredge = std::numeric_limits::quiet_NaN(); + float hledge = std::numeric_limits::quiet_NaN(); + float hredge = std::numeric_limits::quiet_NaN(); + float slmix = std::numeric_limits::quiet_NaN(); + float srmix = std::numeric_limits::quiet_NaN(); + float tlmix = std::numeric_limits::quiet_NaN(); + float trmix = std::numeric_limits::quiet_NaN(); float ovlp = std::numeric_limits::quiet_NaN(); + float padphase = -999.; + float tbinphase = -999.; auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, r, cluster_key); phisize = cluster->getPhiSize(); @@ -1960,8 +1983,26 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ez = sqrt(para_errors.second); ephi = sqrt(para_errors.first); maxadc = cluster->getMaxAdc(); + padcen = cluster->getPadCen(); + tbincen = cluster->getTBinCen(); + padmax = cluster->getPadMax(); + tbinmax = cluster->getTBinMax(); pedge = cluster->getEdge(); + sledge = cluster->getSLEdge(); + sredge = cluster->getSREdge(); + tledge = cluster->getTLEdge(); + tredge = cluster->getTREdge(); + dledge = cluster->getDLEdge(); + dredge = cluster->getDREdge(); + hledge = cluster->getHLEdge(); + hredge = cluster->getHREdge(); + slmix = cluster->getSLMix(); + srmix = cluster->getSRMix(); + tlmix = cluster->getTLMix(); + trmix = cluster->getTRMix(); ovlp = cluster->getOverlap(); + padphase = cluster->getPadPhase(); + tbinphase = cluster->getTBinPhase(); if (hitsetlayer == 7 || hitsetlayer == 22 || hitsetlayer == 23 || hitsetlayer == 38 || hitsetlayer == 39) { @@ -1970,6 +2011,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float e = cluster->getAdc(); float adc = cluster->getAdc(); + float cenadc = cluster->getCenAdc(); + float phibinlo = cluster->getPhiBinLo(); + float phibinhi = cluster->getPhiBinHi(); + float tbinlo = cluster->getTBinLo(); + float tbinhi = cluster->getTBinHi(); float local_layer = (float) TrkrDefs::getLayer(cluster_key); float sector = TpcDefs::getSectorId(cluster_key); float side = TpcDefs::getSide(cluster_key); @@ -2133,6 +2179,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) e, adc, maxadc, + cenadc, + padcen, + tbincen, + padmax, + tbinmax, local_layer, sector, side, @@ -2141,7 +2192,25 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) zsize, pedge, redge, + sledge, + sredge, + tledge, + tredge, + dledge, + dredge, + hledge, + hredge, + slmix, + srmix, + tlmix, + trmix, ovlp, + phibinlo, + phibinhi, + tbinlo, + tbinhi, + padphase, + tbinphase, trackID, niter, g4hitID, @@ -2282,9 +2351,27 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float phisize = 0; float zsize = 0; float maxadc = -999; + float padcen = -999.; + float tbincen = -999.; + float padmax = 999; + float tbinmax= 999; float redge = std::numeric_limits::quiet_NaN(); float pedge = std::numeric_limits::quiet_NaN(); + float sledge = std::numeric_limits::quiet_NaN(); + float sredge = std::numeric_limits::quiet_NaN(); + float tledge = std::numeric_limits::quiet_NaN(); + float tredge = std::numeric_limits::quiet_NaN(); + float dledge = std::numeric_limits::quiet_NaN(); + float dredge = std::numeric_limits::quiet_NaN(); + float hledge = std::numeric_limits::quiet_NaN(); + float hredge = std::numeric_limits::quiet_NaN(); + float slmix = std::numeric_limits::quiet_NaN(); + float srmix = std::numeric_limits::quiet_NaN(); + float tlmix = std::numeric_limits::quiet_NaN(); + float trmix = std::numeric_limits::quiet_NaN(); float ovlp = std::numeric_limits::quiet_NaN(); + float padphase = -999.; + float tbinphase = -999.; auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, r, cluster_key); phisize = cluster->getPhiSize(); @@ -2293,11 +2380,34 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ez = sqrt(para_errors.second); ephi = sqrt(para_errors.first); maxadc = cluster->getMaxAdc(); + padcen = cluster->getPadCen(); + tbincen = cluster->getTBinCen(); + padmax = cluster->getPadMax(); + tbinmax = cluster->getTBinMax(); pedge = cluster->getEdge(); + sledge = cluster->getSLEdge(); + sredge = cluster->getSREdge(); + tledge = cluster->getTLEdge(); + tredge = cluster->getTREdge(); + dledge = cluster->getDLEdge(); + dredge = cluster->getDREdge(); + hledge = cluster->getHLEdge(); + hredge = cluster->getHREdge(); + slmix = cluster->getSLMix(); + srmix = cluster->getSRMix(); + tlmix = cluster->getTLMix(); + trmix = cluster->getTRMix(); ovlp = cluster->getOverlap(); + padphase = cluster->getPadPhase(); + tbinphase = cluster->getTBinPhase(); float e = cluster->getAdc(); float adc = cluster->getAdc(); + float cenadc = cluster->getCenAdc(); + float phibinlo = cluster->getPhiBinLo(); + float phibinhi = cluster->getPhiBinHi(); + float tbinlo = cluster->getTBinLo(); + float tbinhi = cluster->getTBinHi(); float local_layer = (float) TrkrDefs::getLayer(cluster_key); float sector = TpcDefs::getSectorId(cluster_key); float side = TpcDefs::getSide(cluster_key); @@ -2430,6 +2540,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) e, adc, maxadc, + cenadc, + padcen, + tbincen, + padmax, + tbinmax, local_layer, sector, side, @@ -2438,7 +2553,25 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) zsize, pedge, redge, + sledge, + sredge, + tledge, + tredge, + dledge, + dredge, + hledge, + hredge, + slmix, + srmix, + tlmix, + trmix, ovlp, + phibinlo, + phibinhi, + tbinlo, + tbinhi, + padphase, + tbinphase, trackID, niter, g4hitID, @@ -2956,8 +3089,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float ntrutpc3 = std::numeric_limits::quiet_NaN(); float nwrongtpc3 = std::numeric_limits::quiet_NaN(); float layersfromtruth = std::numeric_limits::quiet_NaN(); + float nedge = 0; float npedge = 0; float nredge = 0; + float nsledge = 0; + float nsredge = 0; + float ntledge = 0; + float ntredge = 0; + float ndledge = 0; + float ndredge = 0; + float nhledge = 0; + float nhredge = 0; + float nslmix = 0; + float nsrmix = 0; + float ntlmix = 0; + float ntrmix = 0; float nbig = 0; float novlp = 0; float merr = 0; @@ -3089,10 +3235,23 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gphierr = sqrt(para_errors.first); govlp = cluster->getOverlap(); gedge = cluster->getEdge(); + nsledge = cluster->getSLEdge(); + nsredge = cluster->getSREdge(); + ntledge = cluster->getTLEdge(); + ntredge = cluster->getTREdge(); + ndledge = cluster->getDLEdge(); + ndredge = cluster->getDREdge(); + nhledge = cluster->getHLEdge(); + nhredge = cluster->getHREdge(); + nslmix = cluster->getSLMix(); + nsrmix = cluster->getSRMix(); + ntlmix = cluster->getTLMix(); + ntrmix = cluster->getTRMix(); if (gedge > 0) { npedge++; + nedge = gedge; } if (gphisize >= 4) { @@ -3418,8 +3577,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ntrutpc3, nwrongtpc3, layersfromtruth, + nedge, npedge, nredge, + nsledge, + nsredge, + ntledge, + ntredge, + ndledge, + ndredge, + nhledge, + nhredge, + nslmix, + nsrmix, + ntlmix, + ntrmix, nbig, novlp, merr, @@ -3520,8 +3692,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float nlintt = 0; float nltpc = 0; float nlmms = 0; + float nedge = 0; float npedge = 0; float nredge = 0; + float nsledge = 0; + float nsredge = 0; + float ntledge = 0; + float ntredge = 0; + float ndledge = 0; + float ndredge = 0; + float nhledge = 0; + float nhredge = 0; + float nslmix = 0; + float nsrmix = 0; + float ntlmix = 0; + float ntrmix = 0; float nbig = 0; float novlp = 0; float merr = 0; @@ -3615,10 +3800,23 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) rphierr = sqrt(para_errors.first); rovlp = cluster->getOverlap(); pedge = cluster->getEdge(); + nsledge = cluster->getSLEdge(); + nsredge = cluster->getSREdge(); + ntledge = cluster->getTLEdge(); + ntredge = cluster->getTREdge(); + ndledge = cluster->getDLEdge(); + ndredge = cluster->getDREdge(); + nhledge = cluster->getHLEdge(); + nhredge = cluster->getHREdge(); + nslmix = cluster->getSLMix(); + nsrmix = cluster->getSRMix(); + ntlmix = cluster->getTLMix(); + ntrmix = cluster->getTRMix(); if (pedge > 0) { npedge++; + nedge = pedge; } if (rphisize >= 4) { @@ -4118,8 +4316,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ntrutpc3, nwrongtpc3, layersfromtruth, + nedge, npedge, nredge, + nsledge, + nsredge, + ntledge, + ntredge, + ndledge, + ndredge, + nhledge, + nhredge, + nslmix, + nsrmix, + ntlmix, + ntrmix, nbig, novlp, merr, From b83b7b5f8fa69ad6927a1b352fccf5cf52313928 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Fri, 10 Jul 2026 15:47:44 -0400 Subject: [PATCH 816/866] Adding new parameters to evaluator. --- simulation/g4simulation/g4eval/SvtxEvaluator.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 52b674433b..d42a1a8e8d 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -1956,8 +1956,8 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float maxadc = -999; float padcen = -999.; float tbincen = -999.; - float padmax = -999; - float tbinmax = -999; + float padmax = -999.; + float tbinmax = -999.; float redge = std::numeric_limits::quiet_NaN(); float pedge = std::numeric_limits::quiet_NaN(); float sledge = std::numeric_limits::quiet_NaN(); @@ -2350,11 +2350,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float size = 0; float phisize = 0; float zsize = 0; - float maxadc = -999; + float maxadc = -999.; float padcen = -999.; float tbincen = -999.; - float padmax = 999; - float tbinmax= 999; + float padmax = -999.; + float tbinmax= -999.; float redge = std::numeric_limits::quiet_NaN(); float pedge = std::numeric_limits::quiet_NaN(); float sledge = std::numeric_limits::quiet_NaN(); From d8101138cc6cd84d181d439bab177c7b51513004 Mon Sep 17 00:00:00 2001 From: Ishan Goel Date: Fri, 10 Jul 2026 16:05:01 -0400 Subject: [PATCH 817/866] Adding v6 parameters also. --- simulation/g4simulation/g4eval/SvtxEvaluator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index d42a1a8e8d..206275afa8 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -1953,7 +1953,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float size = 0; float phisize = 0; float zsize = 0; - float maxadc = -999; + float maxadc = -999.; float padcen = -999.; float tbincen = -999.; float padmax = -999.; From 0fb9f6bd85abe91014f9b5c67506c093abf6a696 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Sun, 12 Jul 2026 21:03:15 -0400 Subject: [PATCH 818/866] propagate single zero samples properly --- .../g4waveformsim/CaloWaveformSim.cc | 45 ++++++++++--------- .../g4waveformsim/CaloWaveformSim.h | 12 ++--- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index be4a2c2c3f..01ade77a48 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -39,8 +39,8 @@ #include #include -#include #include +#include #include #include @@ -108,7 +108,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) m_sampling_fraction = 0.162166; m_nchannels = 1536; } - else if (m_dettype == CaloTowerDefs::HCALOUT) + else if (m_dettype == CaloTowerDefs::HCALOUT) { m_detector = "HCALOUT"; encode_tower = TowerInfoDefs::encode_hcal; @@ -394,12 +394,12 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } else { - float val = 1.0+ gsl_ran_gaussian(m_RandomGenerator,factor_const); - if(val < 0.0F) + float val = 1.0 + gsl_ran_gaussian(m_RandomGenerator, factor_const); + if (val < 0.0F) { val = 0; } - tbt_smear[key] = val; + tbt_smear[key] = val; e_vis *= tbt_smear[key]; } } @@ -460,7 +460,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { const unsigned int tower_index = entry.first; const double photon_count_mean = entry.second; - + double photon_count = photon_count_mean; if (m_use_photon_statistics) { @@ -486,7 +486,6 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } } - // do noise here and add to waveform if (m_noiseType == NoiseType::NOISE_TREE) @@ -514,30 +513,36 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { waveform_pedestal_vector.at(j) = (j < pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(pedestalsamples - 1); pedestal_mean += waveform_pedestal_vector.at(j); - if (Verbosity() > 1 && pedestal_tower->get_waveform_value(j) == 0) - { - std::cout << Name() << " channel: " << j << " too small pedestal value for index " << j << ": " << pedestal_tower->get_waveform_value(j) << std::endl; - pedestal_tower->identify(); - } + // it should be around 5000+, dead channels have zero's but who knows what else is out there in the future + if (Verbosity() > 1 && pedestal_tower->get_waveform_value(j) < 1000) + { + std::cout << Name() << " channel: " << j << " too small pedestal value for index " << j << ": " << pedestal_tower->get_waveform_value(j) << std::endl; + pedestal_tower->identify(); + } } pedestal_mean /= m_nsamples; for (int j = 0; j < m_nsamples; j++) { - waveform_pedestal_vector.at(j) = (waveform_pedestal_vector.at(j) - pedestal_mean) * m_pedestal_scale + pedestal_mean; + // only modify the waveform_pedestal_vector if it is > 0, otherwise there is something wrong with the pedestal + // (for dead channels all samples of the waveform are zero). Doing it this way will also catch single zero samples + if (waveform_pedestal_vector.at(j) == 0) + { + waveform_pedestal_vector.at(j) = (waveform_pedestal_vector.at(j) - pedestal_mean) * m_pedestal_scale + pedestal_mean; + } } } for (int j = 0; j < m_nsamples; j++) { if (m_noiseType == NoiseType::NOISE_TREE) { - if (waveform_pedestal_vector.at(j) == 0) - { - m_waveforms.at(i).at(j) = 0; - } - else - { + if (waveform_pedestal_vector.at(j) == 0) + { + m_waveforms.at(i).at(j) = 0; + } + else + { m_waveforms.at(i).at(j) += waveform_pedestal_vector.at(j); - } + } } if (m_noiseType == NoiseType::NOISE_GAUSSIAN) { diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index e309a11cc6..4302003e86 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -77,7 +77,7 @@ class CaloWaveformSim : public SubsysReco m_use_sipm_occupancy = use_sipm_occupancy; } - void set_use_photon_statistics( bool state=true ) + void set_use_photon_statistics(bool state = true) { m_use_photon_statistics = state; } @@ -118,7 +118,7 @@ class CaloWaveformSim : public SubsysReco void set_kSamplingFraction(double val) { - kSamplingFraction = val; + kSamplingFraction = val; } void set_kPhotoelectronsPerGeV(double val) { @@ -126,7 +126,7 @@ class CaloWaveformSim : public SubsysReco } void set_kSiPMEffectivePixel(double val) { - kSiPMEffectivePixel = val; + kSiPMEffectivePixel = val; } // Waveform template & sampling @@ -214,7 +214,7 @@ class CaloWaveformSim : public SubsysReco // Waveform settings std::string m_templatefile{"waveformtemptempohcalcosmic.root"}; - int m_nsamples{12}; // number of samples for calos in our default data taking configuration + int m_nsamples{12}; // number of samples for calos in our default data taking configuration float m_sampletime{50. / 3.}; int m_nchannels{-1}; float m_sampling_fraction{std::numeric_limits::quiet_NaN()}; @@ -235,9 +235,9 @@ class CaloWaveformSim : public SubsysReco bool m_use_photon_statistics{false}; bool m_use_sipm_occupancy{false}; - double kSamplingFraction = 2e-2; + double kSamplingFraction = 2e-2; double kPhotoelectronsPerGeV = 500.; - double kSiPMEffectivePixel = 40000 * 4.; + double kSiPMEffectivePixel = 40000 * 4.; NoiseType m_noiseType{NOISE_TREE}; }; From c31a3b709842ce57da9e860ff11531f62384d500 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 13 Jul 2026 16:15:11 -0400 Subject: [PATCH 819/866] fix typo --- simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 01ade77a48..12dfcd7cbf 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -525,7 +525,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { // only modify the waveform_pedestal_vector if it is > 0, otherwise there is something wrong with the pedestal // (for dead channels all samples of the waveform are zero). Doing it this way will also catch single zero samples - if (waveform_pedestal_vector.at(j) == 0) + if (waveform_pedestal_vector.at(j) != 0) { waveform_pedestal_vector.at(j) = (waveform_pedestal_vector.at(j) - pedestal_mean) * m_pedestal_scale + pedestal_mean; } From 533edc4a88650b8aaa1d4664800624a591ed9ea8 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 13 Jul 2026 16:19:41 -0400 Subject: [PATCH 820/866] comment better --- simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index 12dfcd7cbf..a429a4c8a8 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -535,6 +535,9 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { if (m_noiseType == NoiseType::NOISE_TREE) { + // set samples which have zero pedestal (dead channels in real data) to zero + // they are supposed to be masked out later, so this is just a safeguard in case + // that changes or doesn't work if (waveform_pedestal_vector.at(j) == 0) { m_waveforms.at(i).at(j) = 0; From dba35860a511aa67d139b2b55842c0f8af1a96b5 Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Tue, 14 Jul 2026 17:07:25 +0800 Subject: [PATCH 821/866] add truth hit interpolation in truth fitter --- .../packages/trackreco/PHTruthTrackFitter.cc | 135 +++++++++++++++++- .../packages/trackreco/PHTruthTrackFitter.h | 6 + 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHTruthTrackFitter.cc b/offline/packages/trackreco/PHTruthTrackFitter.cc index f3ed94c29f..956f40d0f6 100644 --- a/offline/packages/trackreco/PHTruthTrackFitter.cc +++ b/offline/packages/trackreco/PHTruthTrackFitter.cc @@ -1,5 +1,7 @@ #include "PHTruthTrackFitter.h" +#include +#include #include #include #include @@ -37,6 +39,7 @@ #include #include #include +#include namespace { @@ -76,6 +79,71 @@ namespace { return trackid != std::numeric_limits::max(); } + + struct InterpolationData + { + double x = 0; + double y = 0; + double z = 0; + double px = 0; + double py = 0; + double pz = 0; + double weight = 1; + + double r() const + { + return std::sqrt(square(x) + square(y)); + } + }; + + template + double interpolate_r(const std::vector& hits, double r_extrap, double fallback) + { + double sw = 0; + double swr = 0; + double swr2 = 0; + double swq = 0; + double swrq = 0; + + for (const auto& hit : hits) + { + const auto q = hit.*member; + const auto r = hit.r(); + if (!std::isfinite(q) || !std::isfinite(r) || !std::isfinite(hit.weight) || hit.weight <= 0) + { + continue; + } + + sw += hit.weight; + swr += hit.weight * r; + swr2 += hit.weight * square(r); + swq += hit.weight * q; + swrq += hit.weight * r * q; + } + + /* + * Fit q(r) = a*r + b with weighted least squares, where q is one of + * x/y/z/px/py/pz. The sums above form the normal equations: + * + * a*swr2 + b*swr = swrq + * a*swr + b*sw = swq + * + * alpha and beta are the Cramer's-rule numerators for the slope and + * intercept. Keeping the final division common is the same as returning + * slope*r_extrap + intercept, but avoids one extra division. + */ + const auto denom = sw * swr2 - square(swr); + const auto scale = std::max(std::abs(sw * swr2), square(swr)); + if (scale <= 0 || std::abs(denom) <= std::numeric_limits::epsilon() * scale) + { + return fallback; + } + + const auto alpha = sw * swrq - swr * swq; + const auto beta = swr2 * swq - swr * swrq; + const auto value = (alpha * r_extrap + beta) / denom; + return std::isfinite(value) ? value : fallback; + } } // namespace PHTruthTrackFitter::PHTruthTrackFitter(const std::string& name) @@ -108,7 +176,7 @@ int PHTruthTrackFitter::process_event(PHCompositeNode* /*topNode*/) m_trackMap->Reset(); unsigned int skipped_tracks = 0; - for (auto *seed : *m_seedMap) + for (auto* seed : *m_seedMap) { if (!seed) { @@ -320,6 +388,13 @@ int PHTruthTrackFitter::getNodes(PHCompositeNode* topNode) m_g4HitsMvtx = findNode::getClass(topNode, "G4HIT_MVTX"); m_g4HitsMicromegas = findNode::getClass(topNode, "G4HIT_MICROMEGAS"); + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + if (m_extrapolateToClusterRadius && !m_tGeometry) + { + std::cout << PHWHERE << "No ActsGeometry on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -437,11 +512,13 @@ bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track, const PHG4VtxPoint* vertex, unsigned int stateIndex) const { - if (!m_clusterMap->findCluster(cluskey)) + auto* cluster = m_clusterMap->findCluster(cluskey); + if (!cluster) { return false; } + std::vector interpolation_hits; double weight_sum = 0; double x = 0; double y = 0; @@ -479,6 +556,29 @@ bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track, weight = 1; } + for (int endpoint = 0; endpoint < 2; ++endpoint) + { + const auto endpoint_x = g4hit->get_x(endpoint); + const auto endpoint_y = g4hit->get_y(endpoint); + const auto endpoint_z = g4hit->get_z(endpoint); + if (!is_finite(endpoint_x) || !is_finite(endpoint_y) || !is_finite(endpoint_z)) + { + continue; + } + + const auto endpoint_px = g4hit->get_px(endpoint); + const auto endpoint_py = g4hit->get_py(endpoint); + const auto endpoint_pz = g4hit->get_pz(endpoint); + + interpolation_hits.push_back({endpoint_x, + endpoint_y, + endpoint_z, + is_finite(endpoint_px) ? endpoint_px : particle->get_px(), + is_finite(endpoint_py) ? endpoint_py : particle->get_py(), + is_finite(endpoint_pz) ? endpoint_pz : particle->get_pz(), + weight}); + } + weight_sum += weight; x += weight * hit_x; y += weight * hit_y; @@ -504,6 +604,25 @@ bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track, local_x /= weight_sum; local_y /= weight_sum; + if (m_extrapolateToClusterRadius && !interpolation_hits.empty()) + { + const auto cluster_radius = getClusterRadius(cluskey, cluster); + if (std::isfinite(cluster_radius) && cluster_radius > 0) + { + x = interpolate_r<&InterpolationData::x>(interpolation_hits, cluster_radius, x); + y = interpolate_r<&InterpolationData::y>(interpolation_hits, cluster_radius, y); + z = interpolate_r<&InterpolationData::z>(interpolation_hits, cluster_radius, z); + px = interpolate_r<&InterpolationData::px>(interpolation_hits, cluster_radius, px); + py = interpolate_r<&InterpolationData::py>(interpolation_hits, cluster_radius, py); + pz = interpolate_r<&InterpolationData::pz>(interpolation_hits, cluster_radius, pz); + } + else if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::addStateFromCluster - invalid cluster radius for cluster " + << cluskey << ", using truth hit average" << std::endl; + } + } + float pathlength = getPathLength(vertex, x, y, z, stateIndex); while (track->count_states(pathlength) != 0) { @@ -537,6 +656,18 @@ bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track, return true; } +float PHTruthTrackFitter::getClusterRadius(TrkrDefs::cluskey cluskey, TrkrCluster* cluster) const +{ + if (!m_tGeometry || !cluster) + { + return std::numeric_limits::quiet_NaN(); + } + + const auto global = m_tGeometry->getGlobalPosition(cluskey, cluster); + const auto radius = std::sqrt(square(global.x()) + square(global.y())); + return std::isfinite(radius) ? radius : std::numeric_limits::quiet_NaN(); +} + float PHTruthTrackFitter::getPathLength(const PHG4VtxPoint* vertex, float x, float y, float z, unsigned int stateIndex) const diff --git a/offline/packages/trackreco/PHTruthTrackFitter.h b/offline/packages/trackreco/PHTruthTrackFitter.h index 68482705c3..1991cf8399 100644 --- a/offline/packages/trackreco/PHTruthTrackFitter.h +++ b/offline/packages/trackreco/PHTruthTrackFitter.h @@ -12,6 +12,7 @@ #include #include +class ActsGeometry; class PHCompositeNode; class PHG4Hit; class PHG4HitContainer; @@ -22,6 +23,7 @@ class SvtxTrack; class SvtxTrackMap; class TrackSeed; class TrackSeedContainer; +class TrkrCluster; class TrkrClusterContainer; class TrkrClusterHitAssoc; class TrkrHitTruthAssoc; @@ -42,6 +44,7 @@ class PHTruthTrackFitter : public SubsysReco void setDefaultCrossing(short int crossing) { m_defaultCrossing = crossing; } void setPositionError(float value) { m_positionError = value; } void setZError(float value) { m_zError = value; } + void setExtrapolateToClusterRadius(bool value) { m_extrapolateToClusterRadius = value; } private: int createNodes(PHCompositeNode* topNode); @@ -56,6 +59,7 @@ class PHTruthTrackFitter : public SubsysReco bool addStateFromCluster(SvtxTrack* track, TrkrDefs::cluskey cluskey, unsigned int truthTrackId, const PHG4Particle* particle, const PHG4VtxPoint* vertex, unsigned int stateIndex) const; + float getClusterRadius(TrkrDefs::cluskey cluskey, TrkrCluster* cluster) const; float getPathLength(const PHG4VtxPoint* vertex, float x, float y, float z, unsigned int stateIndex) const; int getCharge(const PHG4Particle* particle, const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; short int getCrossing(const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; @@ -71,6 +75,7 @@ class PHTruthTrackFitter : public SubsysReco TrkrClusterContainer* m_clusterMap = nullptr; TrkrClusterHitAssoc* m_clusterHitMap = nullptr; TrkrHitTruthAssoc* m_hitTruthAssoc = nullptr; + ActsGeometry* m_tGeometry = nullptr; PHG4TruthInfoContainer* m_g4TruthInfo = nullptr; PHG4HitContainer* m_g4HitsTpc = nullptr; @@ -81,6 +86,7 @@ class PHTruthTrackFitter : public SubsysReco short int m_defaultCrossing = 0; float m_positionError = 0.005; float m_zError = 0.01; + bool m_extrapolateToClusterRadius = true; static constexpr unsigned int m_invalidTruthTrackId = std::numeric_limits::max(); }; From 6e2a2b91bc1c4b6a2d37f8004201445370181678 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Tue, 14 Jul 2026 11:03:22 -0400 Subject: [PATCH 822/866] Input gl1rawhitdst for luminosity calculation instead of gl1 raw data (PRDF) and remove unnecessary inputs from StreamingBcoReco. --- .../packages/bcolumicount/StreamingBcoReco.cc | 176 +++++++----------- .../packages/bcolumicount/StreamingBcoReco.h | 2 +- .../bcolumicount/StreamingLumiReco.cc | 111 +++++------ 3 files changed, 111 insertions(+), 178 deletions(-) diff --git a/offline/packages/bcolumicount/StreamingBcoReco.cc b/offline/packages/bcolumicount/StreamingBcoReco.cc index 262750fcd5..ca60549b8b 100644 --- a/offline/packages/bcolumicount/StreamingBcoReco.cc +++ b/offline/packages/bcolumicount/StreamingBcoReco.cc @@ -43,13 +43,13 @@ int StreamingBcoReco::Init(PHCompositeNode *topNode) { int iret = CreateNodeTree(topNode); h_bco_diff = new TH1I("h_bco_diff", ";bco diff;", 3500, 0, 3500); - std::string hist_name = "h_bco_diff_bit"; - for (int bit=0; bitregisterHisto(h_bco_diff_trigbits[bit]); - } + //std::string hist_name = "h_bco_diff_bit"; + //for (int bit=0; bitregisterHisto(h_bco_diff_trigbits[bit]); + //} h_bco_tag = new TH1I("h_bco_tag", ";usable bco tag;", 2, -0.5, 1.5); hm->registerHisto(h_bco_diff); hm->registerHisto(h_bco_tag); @@ -81,123 +81,81 @@ int StreamingBcoReco::process_event(PHCompositeNode *topNode) { BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); - //Gl1Packet *gl1packet = findNode::getClass(topNode, 14001); - Event *evt = findNode::getClass(topNode, "PRDF"); - if (evt) + if (Verbosity() > 2) + { + if (!syncobject) + { + std::cout << PHWHERE << " SyncObject missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + std::cout << "Event No: " << syncobject->EventNumber() << std::endl; + } + if (bcoinfo) { if (Verbosity() > 2) { - evt->identify(); + std::cout << "prev event: " << bcoinfo->get_previous_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_previous_bco() << std::dec << std::endl; + std::cout << "curr event: " << bcoinfo->get_current_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_current_bco() << std::dec << std::endl; + std::cout << "futu event: " << bcoinfo->get_future_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_future_bco() << std::dec << std::endl; } - if (evt->getEvtType() != DATAEVENT) + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (!streaming_bco_info) { + std::cout << PHWHERE << " STREAMINGBCOINFO node missing" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } - Packet *packet = evt->getPacket(14001); - if (!packet) + m_bco = bcoinfo->get_current_bco(); + // No longer reading in the raw data for this check, but it should not be necessary + //if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} + uint64_t bco_prev = bcoinfo->get_previous_bco(); + uint64_t bco_futu = bcoinfo->get_future_bco(); + uint64_t bco_diff_prev = m_bco - bco_prev; + uint64_t bco_diff_futu = bco_futu - m_bco; + + // special case if BCO is within 20 of previous BCO? + if (bco_diff_prev < m_default_positive_window_length) { - if (Verbosity() > 0) - { - std::cout << "no gl1 packet 14001" << std::endl; - evt->identify(); - } - return Fun4AllReturnCodes::ABORTEVENT; + m_usable_bco_tag = true; } - uint64_t gtm_bco = packet->lValue(0, "BCO"); - uint64_t gl1_scaledvec = packet->lValue(0, "ScaledVector"); - //uint64_t gl1_livevec = packet->lValue(0, "TriggerVector"); - - int bunchno = packet->lValue(0,"BunchNumber"); - if (bunchno < 0 || bunchno >= m_bunches) + else { - if (Verbosity() > 0) - { - std::cout << PHWHERE << " invalid bunch number: " << bunchno << std::endl; - } - delete packet; - return Fun4AllReturnCodes::ABORTEVENT; + m_usable_bco_tag = false; + } + if (bco_diff_futu < m_default_positive_window_length) + { + // double check boundaries for overlap!! + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); + } + else + { + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, get_bco() + m_default_positive_window_length); } - - delete packet; - if (Verbosity() > 2) { - if (!syncobject) - { - std::cout << PHWHERE << " SyncObject missing" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - std::cout << "Event No: " << syncobject->EventNumber() /*<< std::hex*/ - << " gl1 bco: " << gtm_bco <Fill(bco_diff_prev); + h_bco_tag->Fill(m_usable_bco_tag); + // There is no longer a need to read in the .evt file here, so we won't have access to this info. If we wish to access it we can in a different module + //for (int bit=0; bit> static_cast(bit)) & 0x1U) == 0x1U; + // if (trigger_fired) + // { + // h_bco_diff_trigbits[bit]->Fill(bco_diff_prev); + // } + //} + + streaming_bco_info->set_bco(get_bco()); + streaming_bco_info->set_usable_bco_tag(get_usable_bco_tag()); + streaming_bco_info->set_bco_streaming_window(get_bco_streaming_window()); + if (syncobject) { - if (Verbosity() > 2) - { - std::cout << "prev event: " << bcoinfo->get_previous_evtno() /*<< std::hex*/ - << " bco: " << bcoinfo->get_previous_bco() << std::dec << std::endl; - std::cout << "curr event: " << bcoinfo->get_current_evtno() /*<< std::hex*/ - << " bco: " << bcoinfo->get_current_bco() << std::dec << std::endl; - std::cout << "futu event: " << bcoinfo->get_future_evtno() /*<< std::hex*/ - << " bco: " << bcoinfo->get_future_bco() << std::dec << std::endl; - } - - StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); - if (!streaming_bco_info) - { - std::cout << PHWHERE << " STREAMINGBCOINFO node missing" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - m_bco = bcoinfo->get_current_bco(); - if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} - uint64_t bco_prev = bcoinfo->get_previous_bco(); - uint64_t bco_futu = bcoinfo->get_future_bco(); - uint64_t bco_diff_prev = m_bco - bco_prev; - uint64_t bco_diff_futu = bco_futu - m_bco; - - // special case if BCO is within 20 of previous BCO? - if (bco_diff_prev < m_default_positive_window_length) - { - m_usable_bco_tag = true; - } - else - { - m_usable_bco_tag = false; - } - if (bco_diff_futu < m_default_positive_window_length) - { - // double check boundaries for overlap!! - m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); - } - else - { - m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, get_bco() + m_default_positive_window_length); - } - if (Verbosity() > 2) - { - std::cout << "bco_diff_prev : " << bco_diff_prev << std::endl; - std::cout << "bco_diff_futu : " << bco_diff_futu << std::endl; - } - h_bco_diff->Fill(bco_diff_prev); - h_bco_tag->Fill(m_usable_bco_tag); - for (int bit=0; bit> static_cast(bit)) & 0x1U) == 0x1U; - //bool scaled_trigger_fired = ((gl1_scaledvec >> bit) & 0x1U) == 0x1U; - - if (trigger_fired) - { - h_bco_diff_trigbits[bit]->Fill(bco_diff_prev); - } - } - - streaming_bco_info->set_bco(get_bco()); - streaming_bco_info->set_usable_bco_tag(get_usable_bco_tag()); - streaming_bco_info->set_bco_streaming_window(get_bco_streaming_window()); - if (syncobject) - { - streaming_bco_info->set_evtno(syncobject->EventNumber()); - } + streaming_bco_info->set_evtno(syncobject->EventNumber()); } } return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/bcolumicount/StreamingBcoReco.h b/offline/packages/bcolumicount/StreamingBcoReco.h index b5ff71d6e7..a88e6ecfda 100644 --- a/offline/packages/bcolumicount/StreamingBcoReco.h +++ b/offline/packages/bcolumicount/StreamingBcoReco.h @@ -37,7 +37,7 @@ class StreamingBcoReco : public SubsysReco const int trigbits = 40; Fun4AllHistoManager *hm = nullptr; TH1 *h_bco_diff = nullptr; - TH1 *h_bco_diff_trigbits[40] = {nullptr}; + //TH1 *h_bco_diff_trigbits[40] = {nullptr}; TH1 *h_bco_tag = nullptr; uint64_t m_bco{0}; diff --git a/offline/packages/bcolumicount/StreamingLumiReco.cc b/offline/packages/bcolumicount/StreamingLumiReco.cc index d78aa69c0e..0d72b47ec2 100644 --- a/offline/packages/bcolumicount/StreamingLumiReco.cc +++ b/offline/packages/bcolumicount/StreamingLumiReco.cc @@ -23,11 +23,6 @@ #include // for PHWHERE #include // for MDB_NS_xsec - -#include -#include -#include // for Packet - #include #include @@ -80,83 +75,63 @@ int StreamingLumiReco::CreateNodeTree(PHCompositeNode *topNode) int StreamingLumiReco::process_event(PHCompositeNode *topNode) { StreamingBcoInfo *streaming_bcoinfo = findNode::getClass(topNode, "STREAMINGBCOINFO"); - Event *evt = findNode::getClass(topNode, "PRDF"); - if (evt) + Gl1Packet *gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); + if (!gl1packet) { - if (Verbosity() > 2) - { - evt->identify(); - } - if (evt->getEvtType() != DATAEVENT) + if (Verbosity() > 0) { - return Fun4AllReturnCodes::ABORTEVENT; + std::cout << "no gl1 packet 14001" << std::endl; } - Packet *packet = evt->getPacket(14001); - if (!packet) - { - if (Verbosity() > 0) - { - std::cout << "no gl1 packet 14001" << std::endl; - evt->identify(); - } - return Fun4AllReturnCodes::ABORTEVENT; - } - uint64_t gtm_bco = packet->lValue(0, "BCO"); + return Fun4AllReturnCodes::ABORTEVENT; + } + uint64_t gtm_bco = gl1packet->lValue(0, "BCO"); - int bunchno = packet->lValue(0,"BunchNumber"); - if (bunchno < 0 || bunchno >= m_bunches) + int bunchno = gl1packet->lValue(0,"BunchNumber"); + if (bunchno < 0 || bunchno >= m_bunches) + { + if (Verbosity() > 0) { - if (Verbosity() > 0) - { - std::cout << PHWHERE << " invalid bunch number: " << bunchno << std::endl; - } - delete packet; - return Fun4AllReturnCodes::ABORTEVENT; + std::cout << PHWHERE << " invalid bunch number: " << bunchno << std::endl; } + return Fun4AllReturnCodes::ABORTEVENT; + } - // SYNTAX TAKEN FROM ZHIWANS CODE, why = and not +=? If this is correct it seems like a waste to call it for every event (would just need it for the last event in a particular crossing?) - m_bunchnumber_MBDNS_raw[bunchno] = packet->lValue(0, "GL1PRAW"); - m_bunchnumber_MBDNS_live[bunchno] = packet->lValue(0, "GL1PLIVE"); - m_bunchnumber_MBDNS_scaled[bunchno] = packet->lValue(0, "GL1PSCALED"); + // SYNTAX TAKEN FROM ZHIWANS CODE, why = and not +=? If this is correct it seems like a waste to call it for every event (would just need it for the last event in a particular crossing?) + m_bunchnumber_MBDNS_raw[bunchno] = gl1packet->lValue(0, "GL1PRAW"); + m_bunchnumber_MBDNS_live[bunchno] = gl1packet->lValue(0, "GL1PLIVE"); + m_bunchnumber_MBDNS_scaled[bunchno] = gl1packet->lValue(0, "GL1PSCALED"); - if(packet->lValue(0, 0)) - { - m_rawgl1scaler = packet->lValue(0, 0); - } + if(gl1packet->lValue(0, 0)) + { + m_rawgl1scaler = gl1packet->lValue(0, 0); + } - delete packet; + if (streaming_bcoinfo) + { + if (gtm_bco != streaming_bcoinfo->get_bco()) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " bco " << streaming_bcoinfo->get_bco() << std::endl;} - if (streaming_bcoinfo) + // Double check Zhiwan's logic for assigning the adjusted bunch! + int lower = streaming_bcoinfo->get_bco_streaming_window().first - streaming_bcoinfo->get_bco(); + int upper = streaming_bcoinfo->get_bco_streaming_window().second - streaming_bcoinfo->get_bco(); + for(int i = lower; i< upper;i++) { - if (gtm_bco != streaming_bcoinfo->get_bco()) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " bco " << streaming_bcoinfo->get_bco() << std::endl;} + int adjusted_bunch = bunchno + i; + while (adjusted_bunch < 0) + { + adjusted_bunch += 120; + } + while (adjusted_bunch > 119) + { + adjusted_bunch -= 120; + } + // ABORT GAP! + if (adjusted_bunch>110) { continue; } - // Double check Zhiwan's logic for assigning the adjusted bunch! - int lower = streaming_bcoinfo->get_bco_streaming_window().first - streaming_bcoinfo->get_bco(); - int upper = streaming_bcoinfo->get_bco_streaming_window().second - streaming_bcoinfo->get_bco(); - for(int i = lower; i< upper;i++) + // Make sure this is the correct way to count crossings! Need to zero out for each run! + if(i!=0 || streaming_bcoinfo->get_usable_bco_tag()) { - int adjusted_bunch = bunchno + i; - while (adjusted_bunch < 0) - { - adjusted_bunch += 120; - } - while (adjusted_bunch > 119) - { - adjusted_bunch -= 120; - } - // ABORT GAP! - if (adjusted_bunch>110) { continue; } - - // Make sure this is the correct way to count crossings! Need to zero out for each run! - if(i!=0 || streaming_bcoinfo->get_usable_bco_tag()) - { - m_bunchnumber_crossings[adjusted_bunch] += 1; - } - //else if (m_usable_bco_tag) - //{ - // m_bunchnumber_crossings[adjusted_bunch] += 1; - //} + m_bunchnumber_crossings[adjusted_bunch] += 1; } } } From b2a4bcb3862ca9a9eb3fc19a76fcb8b697173649 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 14 Jul 2026 12:55:52 -0400 Subject: [PATCH 823/866] Add collision time to vtx ntuple --- simulation/g4simulation/g4histos/G4VtxNtuple.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/simulation/g4simulation/g4histos/G4VtxNtuple.cc b/simulation/g4simulation/g4histos/G4VtxNtuple.cc index 6446506dac..907cb2559d 100644 --- a/simulation/g4simulation/g4histos/G4VtxNtuple.cc +++ b/simulation/g4simulation/g4histos/G4VtxNtuple.cc @@ -27,7 +27,7 @@ int G4VtxNtuple::Init(PHCompositeNode * /*unused*/) { delete hm; // make cppcheck happy hm = new Fun4AllHistoManager(Name()); - ntup = new TNtuple("vtxntup", "G4Vtxs", "vx:vy:vz"); + ntup = new TNtuple("vtxntup", "G4Vtxs", "vx:vy:vz:vt"); hm->registerHisto(ntup); return 0; } @@ -38,7 +38,10 @@ int G4VtxNtuple::process_event(PHCompositeNode *topNode) if (truthinfo) { PHG4VtxPoint *gvertex = truthinfo->GetPrimaryVtx(truthinfo->GetPrimaryVertexIndex()); - ntup->Fill(gvertex->get_x(), gvertex->get_y(), gvertex->get_z()); + if (gvertex) + { + ntup->Fill(gvertex->get_x(), gvertex->get_y(), gvertex->get_z(), gvertex->get_t()); + } } return 0; } From bba93d2109bfaa08ad3b6e97c41d399e2c0835d9 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 14 Jul 2026 12:56:54 -0400 Subject: [PATCH 824/866] make enum explicit, do not rely on order --- generators/phhepmc/PHHepMCGenHelper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generators/phhepmc/PHHepMCGenHelper.h b/generators/phhepmc/PHHepMCGenHelper.h index 4accf6b1d6..d60f6b862f 100644 --- a/generators/phhepmc/PHHepMCGenHelper.h +++ b/generators/phhepmc/PHHepMCGenHelper.h @@ -43,9 +43,9 @@ class PHHepMCGenHelper enum VTXFUNC { //! uniform distribution with half width set via set_vertex_distribution_width() - Uniform, + Uniform = 0, //! normal distribution with sigma width set via set_vertex_distribution_width() - Gaus + Gaus = 1 }; //! toss a new vertex according to a Uniform or Gaus distribution From ae287cab6abfdf9ec930ae3736ae7ee426dd0de4 Mon Sep 17 00:00:00 2001 From: Cheng-Wei Shih Date: Tue, 14 Jul 2026 14:25:39 -0400 Subject: [PATCH 825/866] default value of getFPHXBCO changes to max() --- offline/packages/trackbase/TrkrHit.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/TrkrHit.h b/offline/packages/trackbase/TrkrHit.h index 963b321fa6..079fd929d3 100644 --- a/offline/packages/trackbase/TrkrHit.h +++ b/offline/packages/trackbase/TrkrHit.h @@ -15,6 +15,7 @@ #include #include #include +#include /** * @brief Base class for hit object @@ -60,7 +61,7 @@ class TrkrHit : public PHObject // optional per-hit timing payload used by detectors that need to retain // the frontend bunch-counter value alongside the digitized hit. virtual void setFPHXBCO(const uint16_t) {} - virtual uint16_t getFPHXBCO() const { return 0; } + virtual uint16_t getFPHXBCO() const { return std::numeric_limits::max(); } virtual void setBCO(const uint64_t) {} virtual uint64_t getBCO() const { return 0; } /* From 07f96cf82d7caad52d149eac44fbd4d7079eac84 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Tue, 14 Jul 2026 14:31:51 -0400 Subject: [PATCH 826/866] Fix clangtidy errors --- offline/packages/bcolumicount/StreamingBcoReco.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/offline/packages/bcolumicount/StreamingBcoReco.h b/offline/packages/bcolumicount/StreamingBcoReco.h index a88e6ecfda..e54ef36dc6 100644 --- a/offline/packages/bcolumicount/StreamingBcoReco.h +++ b/offline/packages/bcolumicount/StreamingBcoReco.h @@ -34,14 +34,13 @@ class StreamingBcoReco : public SubsysReco private: static int CreateNodeTree(PHCompositeNode *topNode); - const int trigbits = 40; + //const int trigbits = 40; Fun4AllHistoManager *hm = nullptr; TH1 *h_bco_diff = nullptr; //TH1 *h_bco_diff_trigbits[40] = {nullptr}; TH1 *h_bco_tag = nullptr; uint64_t m_bco{0}; - int m_bunches = 120; int m_evtno{0}; bool m_usable_bco_tag = false; std::pair m_bco_streaming_window; From 2523ff4fcf56a06589a64fb7c5b90b3c35b3cb21 Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Wed, 15 Jul 2026 14:36:37 +0800 Subject: [PATCH 827/866] hide truth interpolation data members --- .../packages/trackreco/PHTruthTrackFitter.cc | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/offline/packages/trackreco/PHTruthTrackFitter.cc b/offline/packages/trackreco/PHTruthTrackFitter.cc index 956f40d0f6..04e356d7ed 100644 --- a/offline/packages/trackreco/PHTruthTrackFitter.cc +++ b/offline/packages/trackreco/PHTruthTrackFitter.cc @@ -80,23 +80,44 @@ namespace return trackid != std::numeric_limits::max(); } - struct InterpolationData - { - double x = 0; - double y = 0; - double z = 0; - double px = 0; - double py = 0; - double pz = 0; - double weight = 1; + class InterpolationData + { + public: + InterpolationData(double x, double y, double z, double px, double py, double pz, double weight) + : m_x(x) + , m_y(y) + , m_z(z) + , m_px(px) + , m_py(py) + , m_pz(pz) + , m_weight(weight) + { + } double r() const { - return std::sqrt(square(x) + square(y)); + return std::sqrt(square(m_x) + square(m_y)); } + + double x() const { return m_x; } + double y() const { return m_y; } + double z() const { return m_z; } + double px() const { return m_px; } + double py() const { return m_py; } + double pz() const { return m_pz; } + double weight() const { return m_weight; } + + private: + double m_x = 0; + double m_y = 0; + double m_z = 0; + double m_px = 0; + double m_py = 0; + double m_pz = 0; + double m_weight = 1; }; - template + template double interpolate_r(const std::vector& hits, double r_extrap, double fallback) { double sw = 0; @@ -107,18 +128,19 @@ namespace for (const auto& hit : hits) { - const auto q = hit.*member; + const auto q = (hit.*accessor)(); const auto r = hit.r(); - if (!std::isfinite(q) || !std::isfinite(r) || !std::isfinite(hit.weight) || hit.weight <= 0) + const auto weight = hit.weight(); + if (!std::isfinite(q) || !std::isfinite(r) || !std::isfinite(weight) || weight <= 0) { continue; } - sw += hit.weight; - swr += hit.weight * r; - swr2 += hit.weight * square(r); - swq += hit.weight * q; - swrq += hit.weight * r * q; + sw += weight; + swr += weight * r; + swr2 += weight * square(r); + swq += weight * q; + swrq += weight * r * q; } /* @@ -570,13 +592,13 @@ bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track, const auto endpoint_py = g4hit->get_py(endpoint); const auto endpoint_pz = g4hit->get_pz(endpoint); - interpolation_hits.push_back({endpoint_x, - endpoint_y, - endpoint_z, - is_finite(endpoint_px) ? endpoint_px : particle->get_px(), - is_finite(endpoint_py) ? endpoint_py : particle->get_py(), - is_finite(endpoint_pz) ? endpoint_pz : particle->get_pz(), - weight}); + interpolation_hits.emplace_back(endpoint_x, + endpoint_y, + endpoint_z, + is_finite(endpoint_px) ? endpoint_px : particle->get_px(), + is_finite(endpoint_py) ? endpoint_py : particle->get_py(), + is_finite(endpoint_pz) ? endpoint_pz : particle->get_pz(), + weight); } weight_sum += weight; From 3eb8ee670a304ca150098cd14a699b8e6eb763b7 Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Tue, 14 Jul 2026 18:34:48 -0400 Subject: [PATCH 828/866] Micromegas and Silicon side drift calibration QA modules with coderabbit changes addressed --- offline/QA/Tracking/Makefile.am | 9 +- offline/QA/Tracking/MicromegasDriftQA.cc | 618 +++++++++++++++++++++++ offline/QA/Tracking/MicromegasDriftQA.h | 118 +++++ offline/QA/Tracking/SiliconDriftQA.cc | 338 +++++++++++++ offline/QA/Tracking/SiliconDriftQA.h | 119 +++++ 5 files changed, 1200 insertions(+), 2 deletions(-) create mode 100644 offline/QA/Tracking/MicromegasDriftQA.cc create mode 100644 offline/QA/Tracking/MicromegasDriftQA.h create mode 100644 offline/QA/Tracking/SiliconDriftQA.cc create mode 100644 offline/QA/Tracking/SiliconDriftQA.h diff --git a/offline/QA/Tracking/Makefile.am b/offline/QA/Tracking/Makefile.am index 75cbdf164b..d2afc07c08 100644 --- a/offline/QA/Tracking/Makefile.am +++ b/offline/QA/Tracking/Makefile.am @@ -21,7 +21,9 @@ pkginclude_HEADERS = \ MicromegasClusterQA.h \ CosmicTrackQA.h \ TrackFittingQA.h \ - VertexQA.h + VertexQA.h \ + SiliconDriftQA.h \ + MicromegasDriftQA.h lib_LTLIBRARIES = \ libtrackingqa.la @@ -37,7 +39,9 @@ libtrackingqa_la_SOURCES = \ MicromegasClusterQA.cc \ CosmicTrackQA.cc \ TrackFittingQA.cc \ - VertexQA.cc + VertexQA.cc \ + SiliconDriftQA.cc \ + MicromegasDriftQA.cc libtrackingqa_la_LIBADD = \ -lphool \ @@ -49,6 +53,7 @@ libtrackingqa_la_LIBADD = \ -lmvtx_io \ -lintt_io \ -ltrack_io \ + -ltrack \ -ltrackbase_historic_io \ -ltrack_reco \ -lqautils diff --git a/offline/QA/Tracking/MicromegasDriftQA.cc b/offline/QA/Tracking/MicromegasDriftQA.cc new file mode 100644 index 0000000000..e20f1e02dc --- /dev/null +++ b/offline/QA/Tracking/MicromegasDriftQA.cc @@ -0,0 +1,618 @@ +#include "MicromegasDriftQA.h" + +#include + +#include +#include + +#include +#include +#include // for PHWHERE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + template + class range_adaptor + { + public: + explicit 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: + T m_range; + }; + + double normalize_angle(double phi) + { + while (phi < 0) + { + phi += 2 * M_PI; + } + while (phi >= 2 * M_PI) + { + phi -= 2 * M_PI; + } + return phi; + } + + bool phi_in_range(double phi, double min, double max) + { + phi = normalize_angle(phi); + min = normalize_angle(min); + max = normalize_angle(max); + return (min < max) ? (phi >= min && phi <= max) + : (phi >= min || phi <= max); + } + + //! helix-plane intersection via Newton-Raphson + // identical to the version in MicromegasTrackEvaluator_hp.cc + bool helix_plane_intersection( + double t_min, + double t_max, + double zmin, + double zmax, + double R, + double X0, + double Y0, + double intersect_rz, + double slope_rz, + const TVector3& ptile, + const TVector3& ntile, + TVector3& intersect) + { + // number of iterations and tolerance for Newton-Raphson method + const int max_iter = 10; + const double tol = 1e-6; + + // define C + const double C = ntile.X() * (X0 - ptile.X()) + ntile.Y() * (Y0 - ptile.Y()) + ntile.Z() * (intersect_rz - ptile.Z()); + + // define the function and the corresponding derivative used in the Newton-Raphson method + auto f = [&](double t) + { + const double xt = X0 + R * std::cos(t); + const double yt = Y0 + R * std::sin(t); + const double Rt = std::sqrt(xt * xt + yt * yt); + return ntile.X() * R * std::cos(t) + ntile.Y() * R * std::sin(t) + ntile.Z() * slope_rz * Rt + C; + }; + + auto df = [&](double t) + { + const double xt = X0 + R * std::cos(t); + const double yt = Y0 + R * std::sin(t); + const double Rt = std::sqrt(xt * xt + yt * yt); + return -ntile.X() * R * std::sin(t) + ntile.Y() * R * std::cos(t) + ntile.Z() * R * slope_rz * (Y0 * std::cos(t) - X0 * std::sin(t)) / Rt; + }; + + auto solve_from = [&](double t_seed, TVector3& result) -> bool + { + double t = t_seed; + for (int i = 0; i < max_iter; ++i) + { + const double ft = f(t); + const double dft = df(t); + if (std::abs(dft) < 1e-8) + { + return false; + } + const double t_new = t - ft / dft; + + const double x = X0 + R * std::cos(t_new); + const double y = Y0 + R * std::sin(t_new); + const double Rt_n = std::sqrt(x * x + y * y); + const double z = slope_rz * Rt_n + intersect_rz; + const double phi = std::atan2(y, x); + + const TVector3 cand(x, y, z); + const bool phi_ok = phi_in_range(phi, t_min - 1e-4, t_max + 1e-4); + const bool z_ok = (z >= zmin - 1e-4 && z <= zmax + 1e-4); + const bool proj_ok = (std::abs(ntile.Dot(cand - ptile)) <= 0.05); + + if (std::abs(t_new - t) < tol && proj_ok && phi_ok && z_ok) + { + result = cand; + return true; + } + t = t_new; + } + return false; + }; + + auto wrap = [&](double t) + { + while (t > t_max) + { + t -= 2 * M_PI; + } + while (t < t_min) + { + t += 2 * M_PI; + } + return t; + }; + + // the helix-plane equation can have more than one solution: + // look for a solution within the tile acceptance from three different phi seeds + std::vector t_seeds; + const double t_center = 0.5 * (t_min + t_max); + const double delta = 2.0 * M_PI / 3.0; + for (int i = 0; i < 3; ++i) + { + t_seeds.push_back(wrap(t_center + i * delta)); + } + + for (const double t_seed : t_seeds) + { + if (solve_from(t_seed, intersect)) + { + return true; + } + } + return false; + } + + //! piecewise fit function used for the drift velocity extraction + // par[0] = constrained slope, par[1..8] = per-tile offsets + double fit_function_2d(double* x, double* par) + { + const int itile = static_cast(std::floor(x[0])); + const double z = x[1]; + if (itile < 0 || itile >= 8) + { + TF2::RejectPoint(); + return 0.; + } + return par[itile + 1] + par[0] * z; + } + + //! z-view tile names + const std::array k_tile_names = + {"SCOZ", "SCIZ", "NCIZ", "NCOZ", "SEZ", "NEZ", "SWZ", "NWZ"}; + + //! number of z bins of the dz vs z histograms + constexpr int k_nzbins = 220; + + //! z_track range (cm) + constexpr double k_max_z = 110; + + //! dz range (cm) + constexpr double k_max_dz = 10; + +} // namespace + +//____________________________________________________________________________.. +MicromegasDriftQA::MicromegasDriftQA(const std::string& name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::InitRun(PHCompositeNode* topNode) +{ + if (Verbosity()) + { + std::cout << Name() << "::InitRun" + << " drift_velocity=" << m_drift_velocity << " cm/ns" + << " min_tpc_layer=" << m_min_tpc_layer + << " max_tpc_layer=" << m_max_tpc_layer + << std::endl; + } + + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } + + createHistos(); + + // reference histograms initialized in header file to histos in HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + for (int itile = 0; itile < 8; itile++) + { + h_ztrk_dz[itile] = dynamic_cast(hm->getHisto(std::format("{}ztrk_dz_{}", getHistoPrefix(), k_tile_names[itile]))); + } + h_dz = dynamic_cast(hm->getHisto(std::format("{}dz", getHistoPrefix()))); + h_tile = dynamic_cast(hm->getHisto(std::format("{}tile", getHistoPrefix()))); + h_ylocal = dynamic_cast(hm->getHisto(std::format("{}ylocal", getHistoPrefix()))); + h_ntracks = dynamic_cast(hm->getHisto(std::format("{}ntracks", getHistoPrefix()))); + h_driftSummary = dynamic_cast(hm->getHisto(std::format("{}driftSummary", getHistoPrefix()))); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::process_event(PHCompositeNode* topNode) +{ + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } + + int nmatched = 0; + + for (const auto& [track_id, track] : *m_track_map) + { + // require valid beam-crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) + { + continue; + } + + // collect distortion-corrected TPC cluster positions in the selected layer range + std::vector tpc_positions; + for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (!seed) + { + continue; + } + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + const auto ckey = *it; + if (TrkrDefs::getTrkrId(ckey) != TrkrDefs::tpcId) + { + continue; + } + const auto layer = TrkrDefs::getLayer(ckey); + if (layer < m_min_tpc_layer || layer >= m_max_tpc_layer) + { + continue; + } + auto* cl = m_cluster_map->findCluster(ckey); + if (cl) + { + tpc_positions.push_back( + m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing)); + } + } + } + + // need at least 3 TPC clusters in range + if (tpc_positions.size() < 3) + { + continue; + } + + // helix fit: straight line in r-z, circle in x-y + const auto [slope_rz, intersect_rz] = TrackFitUtils::line_fit(tpc_positions); + const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin(tpc_positions); + + // reject badly reconstructed / low-pT tracks + if (R < 40.0) + { + continue; + } + + // extrapolate to the TPOT z-view modules + const auto mm_range = m_micromegas_geomcontainer->get_begin_end(); + for (const auto& [mm_layer, base_layergeom] : range_adaptor(mm_range)) + { + const auto* layergeom = static_cast(base_layergeom); + assert(layergeom); + + // skip the phi layer; only the z-view layer matters here + if (layergeom->get_segmentation_type() != MicromegasDefs::SegmentationType::SEGMENTATION_Z) + { + continue; + } + + const double layer_radius = layergeom->get_radius(); + auto [xplus, yplus, xminus, yminus] = + TrackFitUtils::circle_circle_intersection(layer_radius, R, X0, Y0); + + if (!std::isfinite(xplus)) + { + continue; + } + + // pick the solution closest in phi to the last TPC cluster + const double last_phi = std::atan2(tpc_positions.back().y(), tpc_positions.back().x()); + const double phi_plus = std::atan2(yplus, xplus); + const double phi_minus = std::atan2(yminus, xminus); + const double phi = (std::abs(last_phi - phi_plus) < std::abs(last_phi - phi_minus)) ? phi_plus : phi_minus; + + const double r_cyl = layer_radius; + const double z_cyl = intersect_rz + slope_rz * r_cyl; + const TVector3 world_cyl(r_cyl * std::cos(phi), r_cyl * std::sin(phi), z_cyl); + + const int tileid = layergeom->find_tile_cylindrical(world_cyl); + if (tileid < 0) + { + continue; + } + + const auto tile_center = layergeom->get_world_from_local_coords(tileid, m_tGeometry, {0, 0}); + const TVector3 ptile(tile_center.x(), tile_center.y(), tile_center.z()); + + const auto tile_norm = layergeom->get_world_from_local_vect(tileid, m_tGeometry, {0, 0, 1}); + const TVector3 ntile(tile_norm.x(), tile_norm.y(), tile_norm.z()); + + const auto phi_range = layergeom->get_phi_range(tileid, m_tGeometry); + const double zmin = layergeom->get_zmin(); + const double zmax = layergeom->get_zmax(); + + TVector3 intersection; + if (!helix_plane_intersection(phi_range.first, phi_range.second, zmin, zmax, + R, X0, Y0, intersect_rz, slope_rz, ptile, ntile, intersection)) + { + continue; + } + + const auto local_intersection = layergeom->get_local_from_world_coords( + tileid, m_tGeometry, {intersection.x(), intersection.y(), intersection.z()}); + const double y_local = local_intersection.y(); + + // reject track states near the tile edge + if (std::abs(y_local) > m_y_local_cut) + { + continue; + } + + // find the nearest TPOT cluster on this tile + const auto hitsetkey = MicromegasDefs::genHitSetKey(mm_layer, MicromegasDefs::SegmentationType::SEGMENTATION_Z, tileid); + const auto clusrange = m_cluster_map->getClusters(hitsetkey); + + double dmin = -1; + double z_cluster = 0; + for (const auto& [ckey, cl] : range_adaptor(clusrange)) + { + const double cl_y_local = cl->getLocalY(); + const double d = std::abs(y_local - cl_y_local); + if (dmin < 0 || d < dmin) + { + dmin = d; + const auto gpos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing); + z_cluster = gpos.z(); + } + } + + // require cluster within the z search window + if (dmin < 0 || dmin > m_z_search_win) + { + continue; + } + + // fill histograms + const double z_track = intersection.z(); + const double dz = z_track - z_cluster; + + h_ztrk_dz[tileid]->Fill(z_track, dz); + h_dz->Fill(dz); + h_tile->Fill(tileid); + h_ylocal->Fill(y_local); + + ++nmatched; + break; + } + } + + h_ntracks->Fill(nmatched); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::End(PHCompositeNode* /*topNode*/) +{ + if (!(h_ztrk_dz[0] && h_driftSummary)) + { + std::cout << PHWHERE << " histograms not found, skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + int nEntries = 0; + for (const auto* h : h_ztrk_dz) + { + nEntries += static_cast(h->GetEntries()); + } + if (Verbosity()) + { + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + } + + // record input drift velocity even if the fit is skipped + h_driftSummary->SetBinContent(3, m_drift_velocity); + + if (nEntries < 8 * m_min_slice_entries) + { + std::cout << Name() << "::End - not enough entries (" << nEntries << "), skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + // build mean-dz TH2 via FitSlicesY, one tile at a time + // x = tile [0,8), y = z_track (cm), content = mean dz (cm) + auto* h_fit = new TH2F("h_fit_micromegas", "", 8, 0, 8, k_nzbins, -k_max_z, k_max_z); + h_fit->SetDirectory(nullptr); + + for (int itile = 0; itile < 8; ++itile) + { + auto* h2d = h_ztrk_dz[itile]; + + // fit vertical slices; require a minimum of m_min_slice_entries per slice + TObjArray slices; + slices.SetOwner(kTRUE); + h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries, "QNR", &slices); + auto* h_mean = dynamic_cast(slices.At(1)); + if (!h_mean) + { + continue; + } + + for (int iz = 1; iz <= h_mean->GetNbinsX(); ++iz) + { + const double entries = h2d->Integral(iz, iz, 1, h2d->GetNbinsY()); + if (entries > 0) + { + h_fit->SetBinContent(itile + 1, iz, h_mean->GetBinContent(iz)); + } + } + } + + // 2D piecewise fit: the eight tiles are fitted simultaneously with a shared + // slope and per-tile offsets. This eliminates the need for perfect + // translational TPOT alignment. + auto* fit2d = new TF2("fit2d_micromegas", fit_function_2d, 0, 8, -k_max_z, k_max_z, 9); + for (int i = 0; i < 9; ++i) + { + fit2d->SetParameter(i, 0.0); + } + h_fit->Fit(fit2d, "0RQ"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double new_drift = m_drift_velocity / (1.0 + slope); + const double drift_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + + std::cout << Name() << "::End" + << " slope=" << slope + << " input_drift=" << m_drift_velocity << " cm/ns" + << " new_drift=" << new_drift << " cm/ns +/- " << drift_err << " cm/ns" + << std::endl; + + // store fit results in the summary histogram + h_driftSummary->SetBinContent(1, slope); + h_driftSummary->SetBinContent(2, slope_err); + h_driftSummary->SetBinContent(4, new_drift); + h_driftSummary->SetBinContent(5, drift_err); + + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::load_nodes(PHCompositeNode* topNode) +{ + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + if (!m_tGeometry) + { + std::cout << PHWHERE << " ActsGeometry node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_micromegas_geomcontainer = findNode::getClass(topNode, "CYLINDERGEOM_MICROMEGAS_FULL"); + if (!m_micromegas_geomcontainer) + { + std::cout << PHWHERE << " CYLINDERGEOM_MICROMEGAS_FULL node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_track_map = findNode::getClass(topNode, m_trackmapname); + if (!m_track_map) + { + std::cout << PHWHERE << " " << m_trackmapname << " node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + if (!m_cluster_map) + { + std::cout << PHWHERE << " TRKR_CLUSTER node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_globalPositionWrapper.loadNodes(topNode); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +std::string MicromegasDriftQA::getHistoPrefix() const +{ + // define prefix to all histos in HistoManager + return std::string("h_") + Name() + std::string("_"); +} + +//____________________________________________________________________________.. +void MicromegasDriftQA::createHistos() +{ + // initialize HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + // create and register histos in HistoManager + for (int itile = 0; itile < 8; itile++) + { + auto* h = new TH2F(std::format("{}ztrk_dz_{}", getHistoPrefix(), k_tile_names[itile]).c_str(), + std::format("{};z_{{track}} (cm);#Deltaz (track#minuscluster) (cm)", k_tile_names[itile]).c_str(), + k_nzbins, -k_max_z, k_max_z, 100, -k_max_dz, k_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}dz", getHistoPrefix()).c_str(), + ";#Deltaz (track#minuscluster) (cm);track states", 100, -k_max_dz, k_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}tile", getHistoPrefix()).c_str(), + ";tile;track states", 8, -0.5, 7.5); + for (int itile = 0; itile < 8; itile++) + { + h->GetXaxis()->SetBinLabel(itile + 1, k_tile_names[itile]); + } + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}ylocal", getHistoPrefix()).c_str(), + ";y_{local} (cm);track states", 100, -30, 30); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}ntracks", getHistoPrefix()).c_str(), + ";matched track states per event;events", 20, -0.5, 19.5); + hm->registerHisto(h); + } + + { + // summary of the drift velocity fit performed in End() + auto* h = new TH1F(std::format("{}driftSummary", getHistoPrefix()).c_str(), + "drift velocity fit summary", 5, 0.5, 5.5); + h->GetXaxis()->SetBinLabel(1, "slope"); + h->GetXaxis()->SetBinLabel(2, "slope_err"); + h->GetXaxis()->SetBinLabel(3, "v_{in} (cm/ns)"); + h->GetXaxis()->SetBinLabel(4, "v_{new} (cm/ns)"); + h->GetXaxis()->SetBinLabel(5, "v_{new} err (cm/ns)"); + hm->registerHisto(h); + } +} \ No newline at end of file diff --git a/offline/QA/Tracking/MicromegasDriftQA.h b/offline/QA/Tracking/MicromegasDriftQA.h new file mode 100644 index 0000000000..c39176d774 --- /dev/null +++ b/offline/QA/Tracking/MicromegasDriftQA.h @@ -0,0 +1,118 @@ +#ifndef QA_TRACKING_MICROMEGASDRIFTQA_H +#define QA_TRACKING_MICROMEGASDRIFTQA_H + +/* + * Bade Sayki June 10th, 2026 -- LANL + * This QA module is created to monitor the calibration of the drift velocity in the TPC by fitting a helix to the clusters within a certain layer range, and projecting it to the TPOT z view module plane. The default layers in the TPC are set to be 39-55, which correspond to R3. + * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's MicromegasTrackEvaluator_hp module. It is meant to be a more lightweight and specialized version. + * If you have any questions, please feel free to message me on mattermost. + * Claude Code tool was used to format and debug this module + */ + +#include +#include + +#include + +class ActsGeometry; +class PHCompositeNode; +class PHG4CylinderGeomContainer; +class SvtxTrackMap; +class TrkrClusterContainer; +class TH1; +class TH2; + +class MicromegasDriftQA : public SubsysReco +{ + public: + explicit MicromegasDriftQA(const std::string& name = "MicromegasDriftQA"); + + ~MicromegasDriftQA() override = default; + + //! run initialization: load nodes, create and register histograms + int InitRun(PHCompositeNode* topNode) override; + + //! event processing: fill histograms + int process_event(PHCompositeNode* topNode) override; + + //! end of processing: fit accumulated distributions, fill summary histogram + int End(PHCompositeNode* topNode) override; + + //! track map name + void set_trackmapname(const std::string& value) { m_trackmapname = value; } + + //! initial drift velocity (cm/ns); starting point for the fit. Use the drift velocity used at reconstruction. + void set_drift_velocity(double value) { m_drift_velocity = value; } + + //! TPC layer range used for the helix fit (default: R3) + void set_min_tpc_layer(unsigned int value) { m_min_tpc_layer = value; } + void set_max_tpc_layer(unsigned int value) { m_max_tpc_layer = value; } + + //! reject track states near the tile edge (cm, local y) + void set_y_local_cut(double value) { m_y_local_cut = value; } + + //! search window to match a Micromegas cluster to the prediction (cm) + void set_z_search_window(double value) { m_z_search_win = value; } + + //! minimum entries per z slice required by FitSlicesY + void set_min_slice_entries(int value) { m_min_slice_entries = value; } + + private: + int load_nodes(PHCompositeNode* topNode); + + void createHistos(); + std::string getHistoPrefix() const; + + //!@name histograms (owned by the QA histogram manager) + //@{ + + //! z_track vs dz, one per z-view tile + TH2* h_ztrk_dz[8]{nullptr}; + + //! dz = z_track - z_cluster, all tiles + TH1* h_dz{nullptr}; + + //! matched track states per tile + TH1* h_tile{nullptr}; + + //! local y of the track state on the tile + TH1* h_ylocal{nullptr}; + + //! number of matched track states per event + TH1* h_ntracks{nullptr}; + + //! drift velocity fit summary, filled in End() + TH1* h_driftSummary{nullptr}; + + //@} + + //!@name nodes + //@{ + ActsGeometry* m_tGeometry{nullptr}; + TpcGlobalPositionWrapper m_globalPositionWrapper; + PHG4CylinderGeomContainer* m_micromegas_geomcontainer{nullptr}; + TrkrClusterContainer* m_cluster_map{nullptr}; + SvtxTrackMap* m_track_map{nullptr}; + //@} + + //! track map name + std::string m_trackmapname{"SvtxTrackMap"}; + + //! initial drift velocity (cm/ns) + double m_drift_velocity{0.00745}; + + //! TPC layer range used for the helix fit + unsigned int m_min_tpc_layer{39}; + unsigned int m_max_tpc_layer{55}; + + //! reject track states near the tile edge (cm) + double m_y_local_cut{22.0}; + + //! search window to match a Micromegas cluster to the prediction (cm) + double m_z_search_win{3.0}; + + //! minimum entries per z slice for FitSlicesY + int m_min_slice_entries{10}; +}; + +#endif // QA_TRACKING_MICROMEGASDRIFTQA_H diff --git a/offline/QA/Tracking/SiliconDriftQA.cc b/offline/QA/Tracking/SiliconDriftQA.cc new file mode 100644 index 0000000000..ab97edf4b1 --- /dev/null +++ b/offline/QA/Tracking/SiliconDriftQA.cc @@ -0,0 +1,338 @@ +#include "SiliconDriftQA.h" + +#include + +#include +#include + +#include +#include +#include // for PHWHERE + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + //! pt + template + T get_pt(const T& px, const T& py) + { + return std::sqrt(px * px + py * py); + } + + //! piecewise fit function used for the drift velocity extraction + // par[0] = constrained slope + // par[1] = offset for eta < 0 + // par[2] = offset for eta >= 0 + double fit_function_2d(double* x, double* par) + { + const int ieta = static_cast(std::floor(x[0])); + const double z = x[1]; + if (ieta < 0 || ieta > 1) + { + TF2::RejectPoint(); + return 0.; + } + return par[ieta + 1] + par[0] * z; + } + + //! suffixes used in histogram names for the two eta bins + const char* k_eta_suffix[2] = {"negeta", "poseta"}; + + //! number of z bins of the dz vs z histograms + constexpr int k_nzbins = 200; + +} // namespace + +//____________________________________________________________________________.. +SiliconDriftQA::SiliconDriftQA(const std::string& name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +int SiliconDriftQA::InitRun(PHCompositeNode* /*topNode*/) +{ + createHistos(); + + // reference histograms initialized in header file to histos in HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + for (int ieta = 0; ieta < 2; ieta++) + { + h_zsi_dz[ieta] = dynamic_cast(hm->getHisto(std::format("{}zsi_dz_{}", getHistoPrefix(), k_eta_suffix[ieta]))); + } + h_dz = dynamic_cast(hm->getHisto(std::format("{}dz", getHistoPrefix()))); + h_ntracks = dynamic_cast(hm->getHisto(std::format("{}ntracks", getHistoPrefix()))); + h_driftSummary = dynamic_cast(hm->getHisto(std::format("{}driftSummary", getHistoPrefix()))); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int SiliconDriftQA::process_event(PHCompositeNode* topNode) +{ + auto* track_map = findNode::getClass(topNode, m_trackmapname); + if (!track_map) + { + std::cout << PHWHERE << " " << m_trackmapname << " node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + int naccepted = 0; + + for (const auto& [track_id, track] : *track_map) + { + // require valid beam-crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) + { + if (Verbosity()) + { + std::cout << PHWHERE << " invalid crossing, track ignored." << std::endl; + } + continue; + } + + // require both seeds + const auto* si_seed = track->get_silicon_seed(); + const auto* tpc_seed = track->get_tpc_seed(); + if (!si_seed || !tpc_seed) + { + continue; + } + + // count clusters per subsystem + unsigned int n_tpc = 0; + unsigned int n_mvtx = 0; + unsigned int n_intt = 0; + + for (const auto* seed : {si_seed, tpc_seed}) + { + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + switch (TrkrDefs::getTrkrId(*it)) + { + case TrkrDefs::tpcId: + ++n_tpc; + break; + case TrkrDefs::mvtxId: + ++n_mvtx; + break; + case TrkrDefs::inttId: + ++n_intt; + break; + default: + break; + } + } + } + + // apply selection cuts + if (n_tpc < m_min_nclusters_tpc) + { + continue; + } + if (n_mvtx < m_min_nclusters_mvtx) + { + continue; + } + if (n_intt < m_min_nclusters_intt) + { + continue; + } + + const float eta = tpc_seed->get_eta(); + if (std::abs(eta) > m_max_eta) + { + continue; + } + + const float pt = get_pt(track->get_px(), track->get_py()); + if (pt < m_min_pt) + { + continue; + } + + // get seed z positions at POCA + const auto si_pos = TrackSeedHelper::get_xyz(si_seed); + const auto tpc_pos = TrackSeedHelper::get_xyz(tpc_seed); + + const float z_si = si_pos.z(); + const float z_tpc = tpc_pos.z(); + + // dz = (z_tpc + sign(eta)*crossing*crossing_interval*dv) - z_si + const double sign_eta = (eta >= 0) ? 1.0 : -1.0; + const float z_tpc_corr = z_tpc + sign_eta * crossing * m_crossing_interval * m_drift_velocity; + const float dz = z_tpc_corr - z_si; + + // fill histograms + const int ieta = (eta >= 0) ? 1 : 0; + h_zsi_dz[ieta]->Fill(z_si, dz); + h_dz->Fill(dz); + + ++naccepted; + } + + h_ntracks->Fill(naccepted); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int SiliconDriftQA::End(PHCompositeNode* /*topNode*/) +{ + if (!(h_zsi_dz[0] && h_zsi_dz[1] && h_driftSummary)) + { + std::cout << PHWHERE << " histograms not found, skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + const int nEntries = static_cast(h_zsi_dz[0]->GetEntries() + h_zsi_dz[1]->GetEntries()); + if (Verbosity()) + { + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + } + + // record input drift velocity even if the fit is skipped + h_driftSummary->SetBinContent(3, m_drift_velocity); + + if (nEntries < 2 * m_min_slice_entries) + { + std::cout << Name() << "::End - not enough entries (" << nEntries << "), skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + // build mean-dz TH2 via FitSlicesY, one eta bin at a time + // x = eta bin [0,2), y = z_si (cm), content = mean dz (cm) + auto* h_fit = new TH2F("h_fit_silicon", "", 2, 0, 2, k_nzbins, -m_max_z, m_max_z); + h_fit->SetDirectory(nullptr); + + for (int ieta = 0; ieta < 2; ++ieta) + { + auto* h2d = h_zsi_dz[ieta]; + + // fit vertical slices; require a minimum of m_min_slice_entries per slice + TObjArray slices; + slices.SetOwner(kTRUE); + h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries, "QNR", &slices); + auto* h_mean = dynamic_cast(slices.At(1)); + if (!h_mean) + { + continue; + } + + for (int iz = 1; iz <= h_mean->GetNbinsX(); ++iz) + { + const double entries = h2d->Integral(iz, iz, 1, h2d->GetNbinsY()); + if (entries > 0) + { + h_fit->SetBinContent(ieta + 1, iz, h_mean->GetBinContent(iz)); + } + } + } + + // 2D piecewise fit: shared slope + per-eta offset + auto* fit2d = new TF2("fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3); + for (int i = 0; i < 3; ++i) + { + fit2d->SetParameter(i, 0.0); + } + h_fit->Fit(fit2d, "0RQ"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double off_neg = fit2d->GetParameter(1); // ieta=0, eta<0 + const double off_pos = fit2d->GetParameter(2); // ieta=1, eta>=0 + + const double dv_new = m_drift_velocity / (1.0 + slope); + const double dv_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + const double t0_new = (off_pos - off_neg) / (2.0 * dv_new); + + std::cout << Name() << "::End" + << " slope=" << slope + << " dv_in=" << m_drift_velocity << " cm/ns" + << " dv_new=" << dv_new << " +/- " << dv_err << " cm/ns" + << " t0_new=" << t0_new << " ns" + << std::endl; + + // store fit results in the summary histogram + h_driftSummary->SetBinContent(1, slope); + h_driftSummary->SetBinContent(2, slope_err); + h_driftSummary->SetBinContent(4, dv_new); + h_driftSummary->SetBinContent(5, dv_err); + h_driftSummary->SetBinContent(6, t0_new); + + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +std::string SiliconDriftQA::getHistoPrefix() const +{ + // define prefix to all histos in HistoManager + return std::string("h_") + Name() + std::string("_"); +} + +//____________________________________________________________________________.. +void SiliconDriftQA::createHistos() +{ + // initialize HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + // create and register histos in HistoManager + for (int ieta = 0; ieta < 2; ieta++) + { + auto* h = new TH2F(std::format("{}zsi_dz_{}", getHistoPrefix(), k_eta_suffix[ieta]).c_str(), + std::format("{};z_{{silicon}} (cm);#Deltaz_{{TPC-silicon}} (cm)", + (ieta == 0 ? "#eta_{TPC} < 0" : "#eta_{TPC} #geq 0")) + .c_str(), + k_nzbins, -m_max_z, m_max_z, 200, -m_max_dz, m_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}dz", getHistoPrefix()).c_str(), + ";#Deltaz_{TPC-silicon} (cm);tracks", 200, -m_max_dz, m_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}ntracks", getHistoPrefix()).c_str(), + ";accepted tracks per event;events", 50, -0.5, 49.5); + hm->registerHisto(h); + } + + { + // summary of the drift velocity fit performed in End() + auto* h = new TH1F(std::format("{}driftSummary", getHistoPrefix()).c_str(), + "drift velocity fit summary", 6, 0.5, 6.5); + h->GetXaxis()->SetBinLabel(1, "slope"); + h->GetXaxis()->SetBinLabel(2, "slope_err"); + h->GetXaxis()->SetBinLabel(3, "v_{in} (cm/ns)"); + h->GetXaxis()->SetBinLabel(4, "v_{new} (cm/ns)"); + h->GetXaxis()->SetBinLabel(5, "v_{new} err (cm/ns)"); + h->GetXaxis()->SetBinLabel(6, "t_{0} (ns)"); + hm->registerHisto(h); + } +} \ No newline at end of file diff --git a/offline/QA/Tracking/SiliconDriftQA.h b/offline/QA/Tracking/SiliconDriftQA.h new file mode 100644 index 0000000000..ab851a2278 --- /dev/null +++ b/offline/QA/Tracking/SiliconDriftQA.h @@ -0,0 +1,119 @@ +#ifndef QA_TRACKING_SILICONDRIFTQA_H +#define QA_TRACKING_SILICONDRIFTQA_H + +/* + * QA version of SiliconDriftEvaluator (B. Sayki, LANL). + * + * Monitors the TPC drift velocity calibration by comparing the z position of + * the TPC seed and the silicon seed at the beam line, following the standard + * sPHENIX QA module conventions + * Claude code was used in formatting and debugging of this module + * v_new = v_in / (1 + slope) + * t0 = (offset_pos - offset_neg) / (2 v_new) + */ + +#include + +#include + +class PHCompositeNode; +class TH1; +class TH2; + +class SiliconDriftQA : public SubsysReco +{ + public: + explicit SiliconDriftQA(const std::string& name = "SiliconDriftQA"); + + ~SiliconDriftQA() override = default; + + //! run initialization: create and register histograms + int InitRun(PHCompositeNode* topNode) override; + + //! event processing: fill histograms + int process_event(PHCompositeNode* topNode) override; + + //! end of processing: fit accumulated distributions, fill summary histogram + int End(PHCompositeNode* topNode) override; + + //! track map name + void set_trackmapname(const std::string& value) { m_trackmapname = value; } + + //! initial drift velocity (cm/ns); starting point for the fit and used in the crossing correction + void set_drift_velocity(double value) { m_drift_velocity = value; } + + //! bunch-crossing interval in ns (default: 106.65237 ns) + void set_crossing_interval(double value) { m_crossing_interval = value; } + + //! minimum pT cut on tracks (GeV) + void set_min_pt(double value) { m_min_pt = value; } + + //! minimum number of TPC clusters required + void set_min_nclusters_tpc(unsigned int value) { m_min_nclusters_tpc = value; } + + //! minimum number of MVTX clusters required + void set_min_nclusters_mvtx(unsigned int value) { m_min_nclusters_mvtx = value; } + + //! minimum number of INTT clusters required + void set_min_nclusters_intt(unsigned int value) { m_min_nclusters_intt = value; } + + //! maximum abs(eta) of TPC seed accepted + void set_max_eta(double value) { m_max_eta = value; } + + //! half-range of the z_si histogram axis (cm) + void set_max_z(double value) { m_max_z = value; } + + //! half-range of the dz histogram axis (cm) + void set_max_dz(double value) { m_max_dz = value; } + + //! minimum entries per z slice required by FitSlicesY + void set_min_slice_entries(int value) { m_min_slice_entries = value; } + + private: + void createHistos(); + std::string getHistoPrefix() const; + + //!@name histograms (owned by the QA histogram manager) + //@{ + + //! z_si vs dz, one per eta bin (0: eta<0, 1: eta>=0) + TH2* h_zsi_dz[2]{nullptr, nullptr}; + + //! crossing-corrected dz = z_tpc_corr - z_si (cm) + TH1* h_dz{nullptr}; + + //! number of accepted tracks per event + TH1* h_ntracks{nullptr}; + + //! drift velocity fit summary, filled in End() + TH1* h_driftSummary{nullptr}; + + //@} + + //! track map name + std::string m_trackmapname{"SvtxTrackMap"}; + + //! initial drift velocity (cm/ns) + double m_drift_velocity{0.00749}; + + //! bunch-crossing interval (ns) + double m_crossing_interval{106.65237}; + + //!@name track selection cuts + //@{ + double m_min_pt{0.5}; + unsigned int m_min_nclusters_tpc{20}; + unsigned int m_min_nclusters_mvtx{3}; + unsigned int m_min_nclusters_intt{2}; + double m_max_eta{0.9}; + //@} + + //! histogram ranges + double m_max_z{20.0}; + double m_max_dz{10.0}; + + //! minimum entries per z slice for FitSlicesY + int m_min_slice_entries{10}; +}; + +#endif // QA_TRACKING_SILICONDRIFTQA_H \ No newline at end of file From e12f3dc5b557004977d557f0011d4d599475d72b Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Wed, 15 Jul 2026 12:02:03 -0400 Subject: [PATCH 829/866] Vector size allocation fix --- offline/QA/Tracking/MicromegasDriftQA.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/QA/Tracking/MicromegasDriftQA.cc b/offline/QA/Tracking/MicromegasDriftQA.cc index e20f1e02dc..ab6ddc7f0d 100644 --- a/offline/QA/Tracking/MicromegasDriftQA.cc +++ b/offline/QA/Tracking/MicromegasDriftQA.cc @@ -164,12 +164,12 @@ namespace // the helix-plane equation can have more than one solution: // look for a solution within the tile acceptance from three different phi seeds - std::vector t_seeds; + std::vector t_seeds(3); const double t_center = 0.5 * (t_min + t_max); const double delta = 2.0 * M_PI / 3.0; for (int i = 0; i < 3; ++i) { - t_seeds.push_back(wrap(t_center + i * delta)); + t_seeds[i]=wrap(t_center + i * delta); } for (const double t_seed : t_seeds) From 9c9f4a360e5413661f52ba276dc2d7e6fc836c89 Mon Sep 17 00:00:00 2001 From: cdean-github Date: Thu, 16 Jul 2026 10:23:33 -0400 Subject: [PATCH 830/866] CD: Jenkins complaint --- offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index ec1e348635..f62e79f313 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -71,8 +71,6 @@ #include // for _Rb_tree_iterator, map #include // for allocator_traits<>::va... -KFParticle_truthAndDetTools toolSet; - /// KFParticle constructor KFParticle_Tools::KFParticle_Tools() : m_has_intermediates(false) @@ -553,8 +551,7 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vectorget_crossing()); From 5c963898c111181baa50982948dc8007a9112603 Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Fri, 17 Jul 2026 15:08:22 +0800 Subject: [PATCH 831/866] allow truth seeding of secondary particles --- offline/packages/trackreco/PHTruthTrackSeeding.cc | 5 ++++- offline/packages/trackreco/PHTruthTrackSeeding.h | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHTruthTrackSeeding.cc b/offline/packages/trackreco/PHTruthTrackSeeding.cc index 7b210ea484..21a337dbff 100644 --- a/offline/packages/trackreco/PHTruthTrackSeeding.cc +++ b/offline/packages/trackreco/PHTruthTrackSeeding.cc @@ -120,7 +120,10 @@ int PHTruthTrackSeeding::Process(PHCompositeNode* topNode) std::vector ClusterKeyListSilicon; std::vector ClusterKeyListTpc; - PHG4TruthInfoContainer::ConstRange range = m_g4truth_container->GetPrimaryParticleRange(); + PHG4TruthInfoContainer::ConstRange range = + m_include_secondaries + ? m_g4truth_container->GetParticleRange() + : m_g4truth_container->GetPrimaryParticleRange(); for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) diff --git a/offline/packages/trackreco/PHTruthTrackSeeding.h b/offline/packages/trackreco/PHTruthTrackSeeding.h index abe597b30f..20ab6627eb 100644 --- a/offline/packages/trackreco/PHTruthTrackSeeding.h +++ b/offline/packages/trackreco/PHTruthTrackSeeding.h @@ -60,6 +60,12 @@ class PHTruthTrackSeeding : public PHTrackSeeding _max_layer = maxLayer; } + //! include Geant4 secondary particles when building truth seeds + void set_include_secondaries(bool includeSecondaries) + { + m_include_secondaries = includeSecondaries; + } + //! minimal truth momentum cut double get_min_momentum() const { @@ -106,6 +112,9 @@ class PHTruthTrackSeeding : public PHTrackSeeding unsigned int _min_layer = 0; unsigned int _max_layer = 60; + //! include Geant4 secondary particles in addition to primaries + bool m_include_secondaries = false; + //! minimal truth momentum cut (GeV) double _min_momentum = 50e-3; From f205ad67ffbc858565610f5867d42a3d830689c9 Mon Sep 17 00:00:00 2001 From: Xu-Dong Yu Date: Fri, 17 Jul 2026 16:15:33 +0800 Subject: [PATCH 832/866] allow disabling the Acts material map --- .../packages/trackreco/MakeActsGeometry.cc | 62 +++++++++++++------ offline/packages/trackreco/MakeActsGeometry.h | 7 +++ 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 73259fb679..fa133d7254 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -646,11 +647,18 @@ void MakeActsGeometry::buildActsSurfaces() std::vector argstr = { "-n1", - "--geo-tgeo-jsonconfig", responseFile, - "--mat-input-type", "file", - "--mat-input-file", materialFile + "--geo-tgeo-jsonconfig", responseFile }; + if (m_useActsMaterialMap) + { + argstr.insert(argstr.end(), + { + "--mat-input-type", "file", + "--mat-input-file", materialFile + }); + } + double fieldstrength = std::numeric_limits::quiet_NaN(); if( isConstantField( m_magField, fieldstrength ) ) { @@ -723,12 +731,9 @@ void MakeActsGeometry::setMaterialResponseFile(std::string &responseFile, std::string &materialFile) { responseFile = "tgeo-sphenix-mms.json"; - materialFile = "sphenix-mm-material.json"; - // Check to see if files exist locally - if not, use defaults - std::ifstream file; - - file.open(responseFile); - if (!file.is_open()) + // Check to see if the geometry response file exists locally. If not, use CDB. + std::ifstream responseStream(responseFile); + if (!responseStream.is_open()) { std::cout << responseFile << " not found locally, use CDB version" @@ -736,19 +741,29 @@ void MakeActsGeometry::setMaterialResponseFile(std::string &responseFile, responseFile = CDBInterface::instance()->getUrl("ACTSGEOMETRYCONFIG"); } - file.open(materialFile); - if (!file.is_open()) + if (m_useActsMaterialMap) { - std::cout << materialFile - << " not found locally, use CDB version" + materialFile = "sphenix-mm-material.json"; + std::ifstream materialStream(materialFile); + if (!materialStream.is_open()) + { + std::cout << materialFile + << " not found locally, use CDB version" + << std::endl; + materialFile = CDBInterface::instance()->getUrl("ACTSMATERIALMAP"); + } + + std::cout << "Using Acts material file : " << materialFile << std::endl; - materialFile = CDBInterface::instance()->getUrl("ACTSMATERIALMAP"); + } + else + { + materialFile.clear(); + std::cout << "Using empty Acts material map" << std::endl; } - std::cout << "using Acts material file : " << materialFile - << std::endl; - std::cout << "Using Acts TGeoResponse file : " << responseFile - << std::endl; + std::cout << "Using Acts TGeoResponse file : " << responseFile + << std::endl; return; } @@ -770,9 +785,16 @@ void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& r config.readJson(responseFile); std::shared_ptr matDeco = nullptr; - if (materialFile.find(".json") != std::string::npos || - materialFile.find(".cbor") != std::string::npos) + if (m_useActsMaterialMap) { + if (materialFile.find(".json") == std::string::npos && + materialFile.find(".cbor") == std::string::npos) + { + std::cout << "Unsupported Acts material map format: " << materialFile + << std::endl; + exit(1); + } + // Set up the converter first Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig; // Set up the json-based decorator diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index bd9f1309bc..9dff95623b 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -77,6 +77,12 @@ class MakeActsGeometry : public SubsysReco m_magFieldRescale = magFieldRescale; } + /// enable or disable the ACTS surface and volume material map + void setUseActsMaterialMap(bool value) + { + m_useActsMaterialMap = value; + } + // void useInttSurveyGeom(const bool useSurveyGeom) { m_useInttSurveyGeom = useSurveyGeom; } void setMvtxDev(double array[6]) @@ -231,6 +237,7 @@ class MakeActsGeometry : public SubsysReco std::vector v_globaldisplacement = {0., 0., 0.}; bool m_useField = true; + bool m_useActsMaterialMap = true; std::map m_misalignmentFactor; /// Several maps that connect Acts world to sPHENIX G4 world From 4ea03ae51a14bf20d973c0d8e437a23ed932725a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Fri, 17 Jul 2026 16:02:29 -0400 Subject: [PATCH 833/866] fix clang-tidy --- offline/packages/trackreco/MakeActsGeometry.cc | 2 +- offline/packages/trackreco/MakeActsGeometry.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index fa133d7254..bfd8352a10 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -728,7 +728,7 @@ void MakeActsGeometry::buildActsSurfaces() void MakeActsGeometry::setMaterialResponseFile(std::string &responseFile, - std::string &materialFile) + std::string &materialFile) const { responseFile = "tgeo-sphenix-mms.json"; // Check to see if the geometry response file exists locally. If not, use CDB. diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index 9dff95623b..cdc2f231a2 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -188,7 +188,7 @@ class MakeActsGeometry : public SubsysReco void makeGeometry(int argc, char *argv[], const std::string& responseFile, const std::string& materialFile); void setMaterialResponseFile(std::string &responseFile, - std::string &materialFile); + std::string &materialFile) const; /// Get hitsetkey from TGeoNode for each detector geometry void getInttKeyFromNode(TGeoNode *gnode); From ad1c3c76bbc9972f4c4896b76bb142625285d313 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Mon, 20 Jul 2026 14:47:31 -0400 Subject: [PATCH 834/866] Added helper class for new modified version of laser clusters and implemented use of these laser clusters where needed --- offline/QA/Tpc/Makefile.am | 1 + offline/QA/Tpc/TpcLaserQA.cc | 38 +++- offline/QA/Tpc/TpcLaserQA.h | 13 ++ offline/packages/tpc/LaserClusterHelper.cc | 117 +++++++++++ offline/packages/tpc/LaserClusterHelper.h | 32 +++ offline/packages/tpc/Makefile.am | 2 + .../tpccalib/TpcCentralMembraneMatching.cc | 10 +- .../tpccalib/TpcCentralMembraneMatching.h | 5 + .../packages/tpccalib/TpcLaminationFitting.cc | 191 ++++++++---------- .../packages/tpccalib/TpcLaminationFitting.h | 14 ++ 10 files changed, 310 insertions(+), 113 deletions(-) create mode 100644 offline/packages/tpc/LaserClusterHelper.cc create mode 100644 offline/packages/tpc/LaserClusterHelper.h diff --git a/offline/QA/Tpc/Makefile.am b/offline/QA/Tpc/Makefile.am index 4025cd381a..71dd9bb00e 100644 --- a/offline/QA/Tpc/Makefile.am +++ b/offline/QA/Tpc/Makefile.am @@ -28,6 +28,7 @@ libtpcqa_la_SOURCES = \ libtpcqa_la_LIBADD = \ -lphool \ -lSubsysReco \ + -lg4detectors_io \ -lg4tpc \ -ltrack_io \ -ltrackbase_historic_io \ diff --git a/offline/QA/Tpc/TpcLaserQA.cc b/offline/QA/Tpc/TpcLaserQA.cc index 5fd399d05e..b06ae2fbc4 100644 --- a/offline/QA/Tpc/TpcLaserQA.cc +++ b/offline/QA/Tpc/TpcLaserQA.cc @@ -30,7 +30,7 @@ TpcLaserQA::TpcLaserQA(const std::string &name) { } -int TpcLaserQA::InitRun(PHCompositeNode * /*topNode*/) +int TpcLaserQA::InitRun(PHCompositeNode* topNode) { createHistos(); @@ -54,6 +54,21 @@ int TpcLaserQA::InitRun(PHCompositeNode * /*topNode*/) } } + m_tGeometry = findNode::getClass(topNode,"ActsGeometry"); + if(!m_tGeometry) + { + std::cout << "LaserClusterHelper::loadNodes - ActsGeometry not found on node tree" << std::endl; + } + + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + if(!m_geom_container) + { + std::cout << "LaserClusterHelper::loadNodes - TPCGEOMCONTAINER not found on node tree" << std::endl; + } + + m_laserClusterHelper.set_useZ(m_useZ); + m_laserClusterHelper.loadNodes(topNode); + return Fun4AllReturnCodes::EVENT_OK; } @@ -111,11 +126,24 @@ int TpcLaserQA::process_event(PHCompositeNode *topNode) const unsigned int nhits = cmclus->getNhits(); for (unsigned int i = 0; i < nhits; i++) { - float layer = cmclus->getHitLayer(i); - float hitAdc = cmclus->getHitAdc(i); - float hitIT = cmclus->getHitIT(i); + Acts::Vector3 global = m_laserClusterHelper.getClusterCentroid(cmclus); + + if(global.hasNaN()) + { + continue; + } + + LaserClusterHitInfo LCHI = cmclus->getHit(i); + + float layer = 1.0*TrkrDefs::getLayer(LCHI.hitsetkey); + float hitAdc = 1.0*LCHI.adc; + float hitIT = 1.0*TpcDefs::getTBin(LCHI.hitkey); + + //float layer = cmclus->getHitLayer(i); + //float hitAdc = cmclus->getHitAdc(i); + //float hitIT = cmclus->getHitIT(i); - double phi = std::atan2(cmclus->getHitY(i), cmclus->getHitX(i)); + double phi = std::atan2(global(1), global(0)); if (phi < -M_PI / 12.) { phi += 2 * M_PI; } diff --git a/offline/QA/Tpc/TpcLaserQA.h b/offline/QA/Tpc/TpcLaserQA.h index 02e98bfc4d..ddb4ffaa5f 100644 --- a/offline/QA/Tpc/TpcLaserQA.h +++ b/offline/QA/Tpc/TpcLaserQA.h @@ -3,6 +3,11 @@ #include +#include + +#include +#include + #include class PHCompositeNode; @@ -19,6 +24,8 @@ class TpcLaserQA : public SubsysReco int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode* topNode) override; + void set_useZ(bool use) { m_useZ = use; } + private: void createHistos(); std::string getHistoPrefix() const; @@ -34,6 +41,12 @@ class TpcLaserQA : public SubsysReco TH1* m_sample_R1[2][12]{{nullptr}}; TH1* m_sample_R2[2][12]{{nullptr}}; TH1* m_sample_R3[2][12]{{nullptr}}; + + ActsGeometry *m_tGeometry{nullptr}; + PHG4TpcGeomContainer *m_geom_container{nullptr}; + + LaserClusterHelper m_laserClusterHelper; + bool m_useZ{false}; }; #endif diff --git a/offline/packages/tpc/LaserClusterHelper.cc b/offline/packages/tpc/LaserClusterHelper.cc new file mode 100644 index 0000000000..54aded41de --- /dev/null +++ b/offline/packages/tpc/LaserClusterHelper.cc @@ -0,0 +1,117 @@ +#include "LaserClusterHelper.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +//____________________________________________________________________________ +void LaserClusterHelper::loadNodes(PHCompositeNode* topNode) +{ + m_tGeometry = findNode::getClass(topNode,"ActsGeometry"); + if(!m_tGeometry) + { + std::cout << "LaserClusterHelper::loadNodes - ActsGeometry not found on node tree" << std::endl; + } + + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + if(!m_geom_container) + { + std::cout << "LaserClusterHelper::loadNodes - TPCGEOMCONTAINER not found on node tree" << std::endl; + } +} + +//____________________________________________________________________________ +Acts::Vector3 LaserClusterHelper::getHitGlobalPosition(TrkrDefs::hitsetkey hitsetkey, TrkrDefs::hitkey hitkey) const +{ + const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + + if(!m_tGeometry || !m_geom_container) + { + return invalid; + } + + const int layer = TrkrDefs::getLayer(hitsetkey); + const int side = TpcDefs::getSide(hitsetkey); + + PHG4TpcGeom *layer_geom = m_geom_container->GetLayerCellGeom(layer); + if(!layer_geom) + { + return invalid; + } + + const int iphi = TpcDefs::getPad(hitkey); + const int it = TpcDefs::getTBin(hitkey); + + const double radius = layer_geom->get_radius(); + const double phi = layer_geom->get_phi(iphi, side); + + const double env_x = radius * cos(phi); + const double env_y = radius * sin(phi); + double env_z = 0.0; + //hard code at 0 until better z coordinate calibration is determined + if(m_useZ) + { + double vdrift = m_tGeometry->get_drift_velocity(); + double tdriftmax = layer_geom->get_max_driftlength() / vdrift; + + double zdriftlength = layer_geom->get_zcenter(it) * vdrift; + // convert z drift length to z position in the TPC + env_z = tdriftmax * vdrift - zdriftlength; + if (side == 0) + { + env_z = -env_z; + } + } + + Acts::Vector3 env_global(env_x, env_y, env_z); + return m_tGeometry->transformTpcEnvelopeToWorld(env_global); +} + +//____________________________________________________________________________ +Acts::Vector3 LaserClusterHelper::getClusterCentroid(LaserCluster* cluster) const +{ + const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + + if(!cluster) + { + return invalid; + } + + Acts::Vector3 weightedSum(0.0, 0.0, 0.0); + double adcSum = 0.0; + + const unsigned int nhits = cluster->getNhits(); + for(unsigned int i=0; igetHit(i); + const Acts::Vector3 global = getHitGlobalPosition(hit.hitsetkey, hit.hitkey); + if(global.hasNaN()) + { + continue; + } + + weightedSum += hit.adc * global; + adcSum += hit.adc; + } + + if(adcSum <= 0.0) + { + return invalid; + } + + return weightedSum / adcSum; +} \ No newline at end of file diff --git a/offline/packages/tpc/LaserClusterHelper.h b/offline/packages/tpc/LaserClusterHelper.h new file mode 100644 index 0000000000..102fd47f4b --- /dev/null +++ b/offline/packages/tpc/LaserClusterHelper.h @@ -0,0 +1,32 @@ +#ifndef TPC_LASERCLUSTERHELPER_H +#define TPC_LASERCLUSTERHELPER_H + +#include +#include + +class ActsGeometry; +class LaserCluster; +class PHCompositeNode; +class PHG4TpcGeomContainer; + +class LaserClusterHelper +{ + public: + LaserClusterHelper () = default; + + void loadNodes(PHCompositeNode *topNode); + + Acts::Vector3 getHitGlobalPosition(TrkrDefs::hitsetkey, TrkrDefs::hitkey) const; + Acts::Vector3 getClusterCentroid(LaserCluster*) const; + + void set_useZ(bool use) { m_useZ = use; } + private: + + ActsGeometry *m_tGeometry{nullptr}; + PHG4TpcGeomContainer *m_geom_container{nullptr}; + + bool m_useZ{false}; + +}; + +#endif diff --git a/offline/packages/tpc/Makefile.am b/offline/packages/tpc/Makefile.am index 55c956b98b..f67554f630 100644 --- a/offline/packages/tpc/Makefile.am +++ b/offline/packages/tpc/Makefile.am @@ -35,6 +35,7 @@ lib_LTLIBRARIES = \ libtpc.la pkginclude_HEADERS = \ + LaserClusterHelper.h \ LaserClusterizer.h \ LaserEventInfo.h \ LaserEventInfov1.h \ @@ -76,6 +77,7 @@ dist_mydata_DATA = \ # sources for tpc library libtpc_la_SOURCES = \ + LaserClusterHelper.cc \ LaserClusterizer.cc \ LaserEventInfov1.cc \ LaserEventInfov2.cc \ diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index e790bb2b1d..3015acae7c 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -1494,7 +1494,8 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) // Do the static + average distortion corrections if the container was found // since incorrect z values are in cluster do to wrong t0 of laser flash, fixing based on the side for now // Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); - Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); + Acts::Vector3 pos = m_laserClusterHelper.getClusterCentroid(cmclus); + //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); TVector3 tmp_raw(pos[0], pos[1], pos[2]); if (m_dcc_in_module_edge) { @@ -1579,12 +1580,12 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) if (Verbosity() > 2) { - double raw_rad = std::sqrt(cmclus->getX() * cmclus->getX() + cmclus->getY() * cmclus->getY()); + double raw_rad = std::sqrt(tmp_raw.X() * tmp_raw.X() + tmp_raw.Y() * tmp_raw.Y()); double static_rad = sqrt(tmp_static.X() * tmp_static.X() + tmp_static.Y() * tmp_static.Y()); double corr_rad = sqrt(tmp_pos.X() * tmp_pos.X() + tmp_pos.Y() * tmp_pos.Y()); std::cout << "cluster " << clusterIndex << std::endl; clusterIndex++; - std::cout << "found raw cluster " << cmkey << " side " << side << " with x " << cmclus->getX() << " y " << cmclus->getY() << " z " << cmclus->getZ() << " radius " << raw_rad << std::endl; + std::cout << "found raw cluster " << cmkey << " side " << side << " with x " << tmp_raw.X() << " y " << tmp_raw.Y() << " z " << tmp_raw.Z() << " radius " << raw_rad << std::endl; std::cout << " --- static corrected positions: " << tmp_static.X() << " " << tmp_static.Y() << " " << tmp_static.Z() << " radius " << static_rad << std::endl; std::cout << " --- corrected positions: " << tmp_pos.X() << " " << tmp_pos.Y() << " " << tmp_pos.Z() << " radius " << corr_rad << std::endl; } @@ -2787,6 +2788,9 @@ int TpcCentralMembraneMatching::GetNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTRUN; } + m_laserClusterHelper.set_useZ(m_useZ); + m_laserClusterHelper.loadNodes(topNode); + // input tpc distortion correction module edge m_dcc_in_module_edge = findNode::getClass(topNode, "TpcDistortionCorrectionContainerModuleEdge"); if (m_dcc_in_module_edge) diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.h b/offline/packages/tpccalib/TpcCentralMembraneMatching.h index 2bc44e5ede..c30a147f1c 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.h +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.h @@ -9,6 +9,7 @@ * \author Tony Frawley , Hugo Pereira Da Costa */ +#include #include #include @@ -126,6 +127,7 @@ class TpcCentralMembraneMatching : public SubsysReco void set_phiHistInRad(bool rad){ m_phiHist_in_rad = rad; } + void set_useZ(bool use) { m_useZ = use; } // void set_laminationFile(const std::string& filename) //{ @@ -423,6 +425,9 @@ class TpcCentralMembraneMatching : public SubsysReco std::vector m_reco_RMatches[2]; double m_recoRotation[2][3]{{-999, -999, -999}, {-999, -999, -999}}; + + LaserClusterHelper m_laserClusterHelper; + bool m_useZ{false}; }; #endif // PHTPCCENTRALMEMBRANEMATCHER_H diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 9de1358121..3658ea6309 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -120,82 +120,6 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) } } - /* - //Make map for run and ZDC rate for pp mode - m_run_ZDC_map_pp.insert(std::pair(49709, 555.0)); - m_run_ZDC_map_pp.insert(std::pair(52077, 0.0)); - m_run_ZDC_map_pp.insert(std::pair(52078, 0.0)); - m_run_ZDC_map_pp.insert(std::pair(53534, 3013.5)); - m_run_ZDC_map_pp.insert(std::pair(53630, 6849.3)); - m_run_ZDC_map_pp.insert(std::pair(53631, 5577.8)); - m_run_ZDC_map_pp.insert(std::pair(53632, 5151.2)); - m_run_ZDC_map_pp.insert(std::pair(53652, 4600.0)); - m_run_ZDC_map_pp.insert(std::pair(53687, 3967.2)); - m_run_ZDC_map_pp.insert(std::pair(53716, 3070.1)); - m_run_ZDC_map_pp.insert(std::pair(53738, 4510.7)); - m_run_ZDC_map_pp.insert(std::pair(53739, 4165.0)); - m_run_ZDC_map_pp.insert(std::pair(53741, 3738.1)); - m_run_ZDC_map_pp.insert(std::pair(53742, 3721.4)); - m_run_ZDC_map_pp.insert(std::pair(53743, 3693.4)); - m_run_ZDC_map_pp.insert(std::pair(53744, 3581.9)); - m_run_ZDC_map_pp.insert(std::pair(53756, 4471.4)); - m_run_ZDC_map_pp.insert(std::pair(53783, 4825.7)); - m_run_ZDC_map_pp.insert(std::pair(53871, 6871.5)); - m_run_ZDC_map_pp.insert(std::pair(53876, 5082.3)); - m_run_ZDC_map_pp.insert(std::pair(53877, 4758.5)); - m_run_ZDC_map_pp.insert(std::pair(53879, 4315.0)); - - //beam off go into pp - m_run_ZDC_map_pp.insert(std::pair(53098, 0.0)); - m_run_ZDC_map_pp.insert(std::pair(53271, 0.0)); - - m_run_ZDC_map_auau.insert(std::pair(54966, 12400.)); - m_run_ZDC_map_auau.insert(std::pair(54967, 11600.)); - m_run_ZDC_map_auau.insert(std::pair(54968, 10500.)); - m_run_ZDC_map_auau.insert(std::pair(54969, 9680.)); - */ - - /* - for(int module=0; module<4; module++) - { - double spacing[nRadii]; - for(int j=0; j m_phiModMax[s]) - { - phi[s] -= M_PI / 9; - } - m_truthR[s].push_back(RValues[module][j]); - m_truthPhi[s].push_back(phi[s]); - } - - } - } - } - */ CDBTTree *cdbttree = new CDBTTree(m_stripePatternFile); cdbttree->LoadCalibrations(); auto cdbMap = cdbttree->GetDoubleEntryMap(); @@ -217,32 +141,6 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) std::cerr << "stripe pattern file passed has no stripes on one side. Exiting" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - /* - for(int i=0; i<32; i++) - { - for(int j=0; j<11; j++) - { - int index0 = 18 + i*100 + j; - int index1 = i*100 + j; - - double R0 = cdbttree->GetDoubleValue(index0, "truthR"); - double Phi0 = cdbttree->GetDoubleValue(index0, "truthPhi"); - if(!std::isnan(R0) && !std::isnan(Phi0)) - { - m_truthR[0].push_back(R0); - m_truthPhi[0].push_back(Phi0); - } - - double R1 = cdbttree->GetDoubleValue(index1, "truthR"); - double Phi1 = cdbttree->GetDoubleValue(index1, "truthPhi"); - if(!std::isnan(R1) && !std::isnan(Phi1)) - { - m_truthR[1].push_back(R1); - m_truthPhi[1].push_back(Phi1); - } - } - } - */ int ret = GetNodes(topNode); return ret; @@ -251,7 +149,6 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) //______________________________________ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) { - //m_correctedCMcluster_map = findNode::getClass(topNode, "LAMINATION_CLUSTER"); m_correctedCMcluster_map = findNode::getClass(topNode, "LASER_CLUSTER"); if (!m_correctedCMcluster_map) { @@ -259,6 +156,25 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } + /* + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + if (!m_geom_container) + { + std::cout << PHWHERE << "ERROR: Can't find node TPCGEOMCONTAINER" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + if (!m_tGeometry) + { + std::cout << PHWHERE << "ActsGeometry not found on node tree. Exiting" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + */ + + m_laserClusterHelper.set_useZ(m_useZ); + m_laserClusterHelper.loadNodes(topNode); + m_dcc_in_module_edge = findNode::getClass(topNode, "TpcDistortionCorrectionContainerModuleEdge"); if (m_dcc_in_module_edge) { @@ -399,7 +315,16 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) { const auto &[cmkey, cmclus_orig] = *cmitr; LaserCluster *cmclus = cmclus_orig; + + bool side = (bool) TpcDefs::getSide(cmkey); + double weight = 1.0; + if(m_adcWeight) + { + weight = 1.0*cmclus->getAdc(); + } + //const unsigned int adc = cmclus->getAdc(); + /* bool side = (bool) TpcDefs::getSide(cmkey); if (cmclus->getNLayers() < m_nLayerCut) { @@ -412,9 +337,65 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) weight = 1.0*cmclus->getAdc(); } + double meanR = 0.0; + double meanPhi = 0.0; + double meanZ = 0.0; + double meanAdc = 0.0; + for(int i=0; i<(int)cmclus->getNhits(); i++) + { + LaserClusterHitInfo LCHI = cmclus->getHit(i); + int layer = TrkrDefs::getLayer(LCHI.hitsetkey); + PHG4TpcGeom *layer_geom = m_geom_container->GetLayerCellGeom(layer); + double radius = layer_geom->get_radius(); + double phi = layer_geom->get_phi(TpcDefs::getTBin(LCHI.hitkey), TpcDefs::getSide(LCHI.hitsetkey)); + + double tdriftmax = layer_geom->get_max_driftlength() / m_tGeometry->get_drift_velocity(); + + double zdriftlength = layer_geom->get_zcenter(TpcDefs::getPad(LCHI.hitkey)) * m_tGeometry->get_drift_velocity(); + // convert z drift length to z position in the TPC + double env_z = tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength; + if (TpcDefs::getSide(LCHI.hitsetkey) == 0) + { + env_z = -env_z; + } + + double env_x = radius * cos(phi); + double env_y = radius * sin(phi); + + //hard code at 0 until better z coordinate calibration is determined + env_z = 0.0; + + Acts::Vector3 env_global(env_x, env_y, env_z); + Acts::Vector3 global = m_tGeometry->transformTpcEnvelopeToWorld(env_global); + + double global_x = global.x(); + double global_y = global.y(); + double global_z = global.z(); + + double global_R = sqrt(global_x*global_x + global_y*global_y); + double global_phi = atan2(global_y, global_x); + + meanR += global_R * LCHI.adc; + meanPhi += global_phi * LCHI.adc; + meanZ += global_z * LCHI.adc; + meanAdc += LCHI.adc; + } + + meanR /= meanAdc; + meanPhi /= meanAdc; + meanZ /= meanAdc; //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); - Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); + //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); + Acts::Vector3 pos(meanR * cos(meanPhi), meanR * sin(meanPhi), meanZ); + */ + + Acts::Vector3 pos = m_laserClusterHelper.getClusterCentroid(cmclus); + if(pos.hasNaN()) + { + continue; + } + if (m_dcc_in_module_edge) { pos = m_distortionCorrection.get_corrected_position(pos, m_dcc_in_module_edge); diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 84618b3043..92d813d3ca 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -1,9 +1,15 @@ #ifndef TPCCALIB_TPCLAMINATIONFITTING_H #define TPCCALIB_TPCLAMINATIONFITTING_H + +#include +#include + +#include #include #include +#include #include #include @@ -66,6 +72,8 @@ class TpcLaminationFitting : public SubsysReco void set_lam_grid_dimensions(int phibins, int rbins); + void set_useZ(bool use) { m_useZ = use; } + int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -194,6 +202,12 @@ class TpcLaminationFitting : public SubsysReco double m_phiModMin[2]{-M_PI/18, 0.0}; double m_phiModMax[2]{M_PI/18, M_PI/9}; + + ActsGeometry *m_tGeometry {nullptr}; + PHG4TpcGeomContainer *m_geom_container {nullptr}; + + LaserClusterHelper m_laserClusterHelper; + bool m_useZ{false}; }; #endif From b3c56696fc8b90008da273bb598becbbe200ba3b Mon Sep 17 00:00:00 2001 From: bkimelman Date: Mon, 20 Jul 2026 15:19:12 -0400 Subject: [PATCH 835/866] Fixes from Coderabbit --- offline/QA/Tpc/TpcLaserQA.cc | 14 +++++++------- offline/packages/tpc/LaserClusterizer.cc | 7 ++++--- .../tpccalib/TpcCentralMembraneMatching.cc | 4 ++++ offline/packages/trackbase/LaserCluster.h | 6 +++--- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/offline/QA/Tpc/TpcLaserQA.cc b/offline/QA/Tpc/TpcLaserQA.cc index b06ae2fbc4..a60e2ccc67 100644 --- a/offline/QA/Tpc/TpcLaserQA.cc +++ b/offline/QA/Tpc/TpcLaserQA.cc @@ -123,17 +123,17 @@ int TpcLaserQA::process_event(PHCompositeNode *topNode) nS++; } + const unsigned int nhits = cmclus->getNhits(); for (unsigned int i = 0; i < nhits; i++) - { - Acts::Vector3 global = m_laserClusterHelper.getClusterCentroid(cmclus); + { + LaserClusterHitInfo LCHI = cmclus->getHit(i); - if(global.hasNaN()) + Acts::Vector3 hitGlobal = m_laserClusterHelper.getHitGlobalPosition(LCHI.hitsetkey, LCHI.hitkey); + if(hitGlobal.hasNaN()) { continue; - } - - LaserClusterHitInfo LCHI = cmclus->getHit(i); + } float layer = 1.0*TrkrDefs::getLayer(LCHI.hitsetkey); float hitAdc = 1.0*LCHI.adc; @@ -143,7 +143,7 @@ int TpcLaserQA::process_event(PHCompositeNode *topNode) //float hitAdc = cmclus->getHitAdc(i); //float hitIT = cmclus->getHitIT(i); - double phi = std::atan2(global(1), global(0)); + double phi = std::atan2(hitGlobal(1), hitGlobal(0)); if (phi < -M_PI / 12.) { phi += 2 * M_PI; } diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 45495edb70..9caa41ed76 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -431,7 +431,9 @@ namespace void calc_cluster_parameter(std::vector &clusHits, thread_data &my_data, std::pair maxADCKey) { findConnectedRegions3(clusHits, maxADCKey, my_data.Verbosity); - + + unsigned int nHits = clusHits.size(); + if(nHits == 0) return; double layerSum = 0.0; double iphiSum = 0.0; @@ -444,8 +446,6 @@ namespace //double secondmaxAdc = 0.0; //TrkrDefs::hitsetkey secondmaxKey = 0; - unsigned int nHits = clusHits.size(); - auto *clus = new LaserClusterv3; int meanSide = 0; @@ -550,6 +550,7 @@ namespace if (nHits == 0 || clus->getNhits() == 0) { + delete clus; return; } diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index 3015acae7c..87c344bbab 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -1495,6 +1495,10 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) // since incorrect z values are in cluster do to wrong t0 of laser flash, fixing based on the side for now // Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); Acts::Vector3 pos = m_laserClusterHelper.getClusterCentroid(cmclus); + if(pos.hasNaN()) + { + continue; + } //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); TVector3 tmp_raw(pos[0], pos[1], pos[2]); if (m_dcc_in_module_edge) diff --git a/offline/packages/trackbase/LaserCluster.h b/offline/packages/trackbase/LaserCluster.h index 3e82851023..d6431c56e4 100644 --- a/offline/packages/trackbase/LaserCluster.h +++ b/offline/packages/trackbase/LaserCluster.h @@ -69,11 +69,11 @@ class LaserCluster : public PHObject virtual float getIT() const { return std::numeric_limits::quiet_NaN(); } virtual void setIT(float) {} - virtual unsigned int getLayerInt() const { return std::numeric_limits::quiet_NaN(); } + virtual unsigned int getLayerInt() const { return std::numeric_limits::max(); } virtual void setLayerInt(unsigned int) {} - virtual unsigned int getIPhiInt() const { return std::numeric_limits::quiet_NaN(); } + virtual unsigned int getIPhiInt() const { return std::numeric_limits::max(); } virtual void setIPhiInt(unsigned int) {} - virtual unsigned int getITInt() const { return std::numeric_limits::quiet_NaN(); } + virtual unsigned int getITInt() const { return std::numeric_limits::max(); } virtual void setITInt(unsigned int) {} // From efa5e4bc372bb4c27507f5ada3e8362057228e27 Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Mon, 20 Jul 2026 17:32:04 -0400 Subject: [PATCH 836/866] TPOT and Silicon side subsysreco modules for drift velocity calibrations --- .../packages/tpc/MicromegasDriftEvaluator.cc | 548 ++++++++++++++++++ .../packages/tpc/MicromegasDriftEvaluator.h | 152 +++++ .../tpc/MicromegasDriftEvaluatorLinkDef.h | 6 + offline/packages/tpc/SiliconDriftEvaluator.cc | 372 ++++++++++++ offline/packages/tpc/SiliconDriftEvaluator.h | 219 +++++++ .../tpc/SiliconDriftEvaluatorLinkDef.h | 5 + 6 files changed, 1302 insertions(+) create mode 100644 offline/packages/tpc/MicromegasDriftEvaluator.cc create mode 100644 offline/packages/tpc/MicromegasDriftEvaluator.h create mode 100644 offline/packages/tpc/MicromegasDriftEvaluatorLinkDef.h create mode 100644 offline/packages/tpc/SiliconDriftEvaluator.cc create mode 100644 offline/packages/tpc/SiliconDriftEvaluator.h create mode 100644 offline/packages/tpc/SiliconDriftEvaluatorLinkDef.h diff --git a/offline/packages/tpc/MicromegasDriftEvaluator.cc b/offline/packages/tpc/MicromegasDriftEvaluator.cc new file mode 100644 index 0000000000..747e5c0cf6 --- /dev/null +++ b/offline/packages/tpc/MicromegasDriftEvaluator.cc @@ -0,0 +1,548 @@ +#include "MicromegasDriftEvaluator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace +{ + + 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: + T m_range; + }; + + template inline constexpr T square(T x) { return x * x; } + template inline T get_r(T x, T y) { return std::sqrt(square(x) + square(y)); } + + double normalize_angle(double phi) + { + while (phi < 0) phi += 2 * M_PI; + while (phi >= 2 * M_PI) phi -= 2 * M_PI; + return phi; + } + + bool phi_in_range(double phi, double min, double max) + { + phi = normalize_angle(phi); + min = normalize_angle(min); + max = normalize_angle(max); + return (min < max) ? (phi >= min && phi <= max) + : (phi >= min || phi <= max); + } + + // This function is identical to the version in MicromegasTrackEvaluator_hp.cc + + bool helix_plane_intersection( + double t_min, + double t_max, + double zmin, + double zmax, + double R, + double X0, + double Y0, + double intersect_rz, + double slope_rz, + const TVector3& ptile, + const TVector3& ntile, + TVector3& intersect) + { + // Number of iterations and tolerance for Newton Raphson method + const int max_iter = 10; + const double tol = 1e-6; + + // Define C + double C = ntile.X() * (X0 - ptile.X()) + ntile.Y() * (Y0 - ptile.Y()) + ntile.Z() * (intersect_rz - ptile.Z()); + + // Defines the function and the corresponding derivative to be used in the Newton Raphson method + auto f = [&](double t) + { + double xt = X0 + R * std::cos(t); + double yt = Y0 + R * std::sin(t); + double Rt = std::sqrt(xt*xt + yt*yt); + return ntile.X() * R * std::cos(t) + + ntile.Y() * R * std::sin(t) + + ntile.Z() * slope_rz * Rt + + C; + }; + + auto df = [&](double t) + { + double xt = X0 + R * std::cos(t); + double yt = Y0 + R * std::sin(t); + double Rt = std::sqrt(xt*xt + yt*yt); + return -ntile.X() * R * std::sin(t) + + ntile.Y() * R * std::cos(t) + + ntile.Z() * R * slope_rz * (Y0*std::cos(t) - X0*std::sin(t)) / Rt; + }; + + auto solve_from = [&](double t_seed, TVector3& result) -> bool + { + double t = t_seed; + for (int i = 0; i < max_iter; ++i) + { + double ft = f(t); + double dft = df(t); + if (std::abs(dft) < 1e-8) return false; + double t_new = t - ft / dft; + + double x = X0 + R * std::cos(t_new); + double y = Y0 + R * std::sin(t_new); + double Rt_n = std::sqrt(x*x + y*y); + double z = slope_rz * Rt_n + intersect_rz; + double phi = std::atan2(y, x); + + TVector3 cand(x, y, z); + bool phi_ok = phi_in_range(phi, t_min - 1e-4, t_max + 1e-4); + bool z_ok = (z >= zmin - 1e-4 && z <= zmax + 1e-4); + bool proj_ok = (std::abs(ntile.Dot(cand - ptile)) <= 0.05); + + if (std::abs(t_new - t) < tol && proj_ok && phi_ok && z_ok) + { + result = cand; + return true; + } + t = t_new; + } + return false; + }; + + auto wrap = [&](double t) + { + while (t > t_max) t -= 2 * M_PI; + while (t < t_min) t += 2 * M_PI; + return t; + }; + + std::vector t_seeds; + double t_center = 0.5 * (t_min + t_max); + double delta = 2.0 * M_PI / 3.0; + + // Wrap the angle + for (int i = 0; i < 3; ++i) + { + double t = wrap(t_center + i * delta); + t_seeds.push_back(t); + } + + // Looks for the solution within the tile acceptance in three different phi seeds in the Newton-Raphson (helix_plane could have more than one solution) + for (double t_seed : t_seeds) + { + if (solve_from(t_seed, intersect)) return true; + } + return false; + } + + // this is a piecewise fit function for the drift velocity plot + double fit_function_2d(double* x, double* par) + { + const int itile = static_cast(std::floor(x[0])); + const double z = x[1]; + if (itile < 0 || itile >= 8) { TF2::RejectPoint(); return 0.; } + return par[itile + 1] + par[0] * z; + } + + double linear_function(double* x, double* par) + { return par[0] * x[0] + par[1]; } + + const std::array k_tile_names = + { "SCOZ", "SCIZ", "NCIZ", "NCOZ", "SEZ", "NEZ", "SWZ", "NWZ" }; + +} + +MicromegasDriftEvaluator::MicromegasDriftEvaluator(const std::string& name) + : SubsysReco(name) +{} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::Init(PHCompositeNode* topNode) +{ + std::cout << Name() << "::Init" + << " drift_velocity=" << m_drift_velocity << " cm/ns" + << " min_tpc_layer=" << m_min_tpc_layer + << " max_tpc_layer=" << m_max_tpc_layer + << std::endl; + + PHNodeIterator iter(topNode); + auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cerr << Name() << "::Init - DST node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + iter = PHNodeIterator(dstNode); + auto evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); + if (!evalNode) + { + evalNode = new PHCompositeNode("EVAL"); + dstNode->addNode(evalNode); + } + + auto newNode = new PHIODataNode(new Container, "MicromegasDriftEvaluator::Container", "PHObject"); + newNode->SplitLevel(99); + evalNode->addNode(newNode); + + m_hist3D = new TH3F("MicromegasDriftEval_hist3D", ";tile;z_{track} (cm);#Deltaz (track#minuscluster) (cm)",8, 0, 8,220, -110, 110, 100, -10, 10); + m_hist3D->SetDirectory(nullptr); + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::InitRun(PHCompositeNode* topNode) +{ return load_nodes(topNode); } + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::process_event(PHCompositeNode* topNode) +{ + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) return res; + + if (m_container) m_container->Reset(); + evaluate_tracks(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::End(PHCompositeNode*) +{ + if (!m_hist3D) + { + std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + const int nEntries = static_cast(m_hist3D->GetEntries()); + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + + auto h_fit = new TH2F("h_fit", "", 8, 0, 8, 220, -110, 110); + h_fit->SetDirectory(nullptr); + + for (int j = 0; j < 8; ++j) + { + m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); + auto h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(Form("h_%s", k_tile_names[j])); + h2d->SetDirectory(nullptr); + + // Fit vertical slices; require a minimum of 10 entries per slice + h2d->FitSlicesY(nullptr, 0, -1, 10); + auto h_mean = static_cast(gDirectory->Get(Form("h_%s_1", k_tile_names[j]))); + + if (!h_mean) + { + delete h2d; + continue; + } + + for (int i = 0; i < h_mean->GetNbinsX(); ++i) + { + const double entries = h2d->Integral(i + 1, i + 1, 1, m_hist3D->GetNbinsZ()); + if (entries > 0) + { h_fit->SetBinContent(j + 1, i + 1, h_mean->GetBinContent(i + 1)); } + } + delete h2d; + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + // This part fits the 8 micromegas modules one at a time but constrains the slopes to be identical. This eliminates the need for perfect translational TPOT alignment + auto fit2d = new TF2("fit2d", fit_function_2d, 0, 8, -110, 110, 9); + for (int i = 0; i < 9; ++i) fit2d->SetParameter(i, 0.0); + + h_fit->Fit(fit2d, "0R"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double new_drift = m_drift_velocity / (1.0 + slope); + const double drift_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + + std::cout << Name() << "::End" << " slope=" << slope<< " input_drift=" << m_drift_velocity << " cm/ns" << " new_drift=" << new_drift << " cm/ns +/- " << drift_err << " cm/ns"<< std::endl; + + // Plot the whole thing + auto canvas = new TCanvas("drift_calib", "Drift velocity calibration", 2000, 1000); + canvas->Divide(4, 2); + + for (int j = 0; j < 8; ++j) + { + canvas->cd(j + 1); + + m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); + auto h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(Form("hplot_%s", k_tile_names[j])); + h2d->SetTitle(Form("%s;z_{track} (cm);#Deltaz (track#minuscluster) (cm)",k_tile_names[j])); + h2d->SetStats(0); + h2d->Draw("COLZ"); + + auto h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", j), j + 1, j + 1); //These give you the Gaussian means for each slice + h_fit_proj->SetMarkerStyle(20); + h_fit_proj->SetMarkerColor(kRed); + h_fit_proj->SetLineColor(kBlack); + + auto f1d = new TF1(Form("f1d_%i", j), linear_function, -110, 110, 2); + f1d->SetParameter(0, slope); + f1d->SetParameter(1, fit2d->GetParameter(j + 1)); + f1d->SetLineColor(kGreen + 2); + f1d->SetLineWidth(2); + f1d->Draw("same"); + + auto leg = new TLegend(0.35, 0.75, 0.92, 0.92); + leg->SetHeader(Form("%i entries, v_{in}=%.2f m/ms", nEntries, m_drift_velocity * 1e5), "C"); + leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); + leg->AddEntry(f1d,Form("slope=%.4f v_{new}=%.3f#pm%.3f m/ms",slope, new_drift * 1e5, drift_err * 1e5), "l"); + leg->Draw(); + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + canvas->SaveAs(m_plot_filename.c_str()); + std::cout << Name() << "::End - QA canvas saved to " << m_plot_filename << std::endl; + + // write histograms, fit and results to a ROOT file + if (!m_root_filename.empty()) + { + std::unique_ptr outfile(TFile::Open(m_root_filename.c_str(), "RECREATE")); + if (outfile && !outfile->IsZombie()) + { + outfile->cd(); + m_hist3D->Write(); + h_fit->Write("h_fit_micromegas"); + fit2d->Write(); + canvas->Write(); + TParameter("slope", slope).Write(); + TParameter("drift_velocity_in", m_drift_velocity).Write(); + TParameter("drift_velocity_new", new_drift).Write(); + TParameter("drift_velocity_err", drift_err).Write(); + outfile->Close(); + std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; + } + else + { std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; } + } + + delete canvas; + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::load_nodes(PHCompositeNode* topNode) +{ + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + assert(m_tGeometry); + + m_micromegas_geomcontainer = findNode::getClass(topNode, "CYLINDERGEOM_MICROMEGAS_FULL"); + assert(m_micromegas_geomcontainer); + + m_track_map = findNode::getClass(topNode, m_trackmapname); + + m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + assert(m_cluster_map); + + m_container = findNode::getClass(topNode, "MicromegasDriftEvaluator::Container"); + assert(m_container); + + m_globalPositionWrapper.loadNodes(topNode); + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +void MicromegasDriftEvaluator::evaluate_tracks() +{ + if (!(m_track_map && m_cluster_map && m_container && m_hist3D)) return; + + m_container->clear_tracks(); + + for (const auto& [track_id, track] : *m_track_map) + { + //valid crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) continue; + + std::vector tpc_positions; + + // Also count clusters per subsystem for the cuts + unsigned int n_tpc = 0; + unsigned int n_mvtx = 0; + unsigned int n_intt = 0; + unsigned int n_mm = 0; + + for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (!seed) continue; + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + const auto ckey = *it; + const auto detid = TrkrDefs::getTrkrId(ckey); + const auto layer = TrkrDefs::getLayer(ckey); + + switch (detid) + { + case TrkrDefs::tpcId: + ++n_tpc; + if (layer >= m_min_tpc_layer && layer < m_max_tpc_layer) + { + const auto cl = m_cluster_map->findCluster(ckey); + if (cl) + { + tpc_positions.push_back( + m_globalPositionWrapper.getGlobalPositionDistortionCorrected( + ckey, cl, crossing)); + } + } + break; + case TrkrDefs::mvtxId: ++n_mvtx; break; + case TrkrDefs::inttId: ++n_intt; break; + case TrkrDefs::micromegasId: ++n_mm; break; + default: break; + } + } + } + + // need at least 3 TPC clusters in range + if (tpc_positions.size() < 3) continue; + + const auto [slope_rz, intersect_rz] = TrackFitUtils::line_fit(tpc_positions); + const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin(tpc_positions); + + // reject badly reconstructed / low-pT tracks + if (R < 40.0) continue; + + const auto mm_range = m_micromegas_geomcontainer->get_begin_end(); + for (const auto& [mm_layer, base_layergeom] : range_adaptor(mm_range)) + { + const auto layergeom =static_cast(base_layergeom); + assert(layergeom); + + // skip the phi layer. Only the z-view layer matters here + if (layergeom->get_segmentation_type() != + MicromegasDefs::SegmentationType::SEGMENTATION_Z) continue; + + const double layer_radius = layergeom->get_radius(); + auto [xplus, yplus, xminus, yminus] = + TrackFitUtils::circle_circle_intersection(layer_radius, R, X0, Y0); + + if (!std::isfinite(xplus)) continue; + + // pick the solution closest in phi to the last TPC cluster + const double last_phi = std::atan2(tpc_positions.back().y(), tpc_positions.back().x()); + const double phi_plus = std::atan2(yplus, xplus); + const double phi_minus = std::atan2(yminus, xminus); + const double phi = (std::abs(last_phi - phi_plus) < std::abs(last_phi - phi_minus)) ? phi_plus : phi_minus; + + const double r_cyl = layer_radius; + const double z_cyl = intersect_rz + slope_rz * r_cyl; + const TVector3 world_cyl(r_cyl * std::cos(phi), r_cyl * std::sin(phi), z_cyl); + + const int tileid = layergeom->find_tile_cylindrical(world_cyl); + if (tileid < 0) continue; + + const auto tile_center = layergeom->get_world_from_local_coords(tileid, m_tGeometry, {0, 0}); + const TVector3 ptile(tile_center.x(), tile_center.y(), tile_center.z()); + + const auto tile_norm = layergeom->get_world_from_local_vect(tileid, m_tGeometry, {0, 0, 1}); + const TVector3 ntile(tile_norm.x(), tile_norm.y(), tile_norm.z()); + + const auto phi_range = layergeom->get_phi_range(tileid, m_tGeometry); + const double zmin = layergeom->get_zmin(); + const double zmax = layergeom->get_zmax(); + + TVector3 intersection; + if (!helix_plane_intersection(phi_range.first, phi_range.second, zmin, zmax, R, X0, Y0, intersect_rz, slope_rz, ptile, ntile, intersection)) + continue; + + const auto local_intersection = layergeom->get_local_from_world_coords(tileid, m_tGeometry,{intersection.x(), intersection.y(), intersection.z()}); + const double y_local = local_intersection.y(); + + if (std::abs(y_local) > m_y_local_cut) continue; + + //find the nearest TPOT cluster + const auto hitsetkey = MicromegasDefs::genHitSetKey(mm_layer,MicromegasDefs::SegmentationType::SEGMENTATION_Z,tileid); + const auto clusrange = m_cluster_map->getClusters(hitsetkey); + + double dmin = -1; + ClusterStruct best_cluster; + + for (const auto& [ckey, cl] : range_adaptor(clusrange)) + { + const double cl_y_local = cl->getLocalY(); + const double d = std::abs(y_local - cl_y_local); + if (dmin < 0 || d < dmin) + { + dmin = d; + const auto gpos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing); + best_cluster._layer = mm_layer; + best_cluster._tile = tileid; + best_cluster._z = gpos.z(); + } + } + + // require cluster within the z search window + if (dmin < 0 || dmin > m_z_search_win) continue; + + //fill track struct and histogram + TrackStruct track_struct; + track_struct._chisquare = track->get_chisq(); + track_struct._ndf = track->get_ndf(); + track_struct._nclusters_tpc = n_tpc; + track_struct._nclusters_mvtx = n_mvtx; + track_struct._nclusters_intt = n_intt; + track_struct._nclusters_micromegas = n_mm; + + track_struct._trk_state_z._layer = mm_layer; + track_struct._trk_state_z._tile = tileid; + track_struct._trk_state_z._z = intersection.z(); + track_struct._trk_state_z._y_local = y_local; + + track_struct._found_cluster_z = best_cluster; + + const double z_track = track_struct._trk_state_z._z; + const double z_cluster = track_struct._found_cluster_z._z; + m_hist3D->Fill(tileid + 0.5, z_track, z_track - z_cluster); + + m_container->add_track(track_struct); + break; + } + } +} \ No newline at end of file diff --git a/offline/packages/tpc/MicromegasDriftEvaluator.h b/offline/packages/tpc/MicromegasDriftEvaluator.h new file mode 100644 index 0000000000..95860e5774 --- /dev/null +++ b/offline/packages/tpc/MicromegasDriftEvaluator.h @@ -0,0 +1,152 @@ +#ifndef G4EVAL_MicromegasDriftEvaluator_H +#define G4EVAL_MicromegasDriftEvaluator_H + +/* + * Bade Sayki June 10th, 2026 -- LANL + * This module is created to calibrate the drift velocity in the TPC by fitting a helix to the clusters within a certain layer range, and projecting it to the TPOT z view module plane. The default layers in the TPC are set to be 39-55, which correspond to R3. + * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's MicromegasTrackEvaluator_hp module. It is meant to be a more lightweight and specialized version. + * It accumulates a TH3F(tile, z_track, dz) histogram during process_event, then in End() fits a piecewise function to suggest an updated drift velocity. + * If you have any questions, please feel free to message me on mattermost. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +class ActsGeometry; +class PHG4CylinderGeomContainer; +class TH3F; +class TrkrCluster; +class TrkrClusterContainer; +class SvtxTrackMap; + +class MicromegasDriftEvaluator : public SubsysReco +{ + public: + + explicit MicromegasDriftEvaluator( const std::string& name = "MicromegasDriftEvaluator" ); + + int Init(PHCompositeNode*) override; + int InitRun(PHCompositeNode*) override; + int process_event(PHCompositeNode*) override; + int End(PHCompositeNode*) override; + + struct TrackStateStruct + { + unsigned short _layer = 0; + unsigned short _tile = 0; + double _z = 0; + double _y_local = 0; + }; + + struct ClusterStruct + { + unsigned short _layer = 0; + unsigned short _tile = 0; + double _z = 0; + }; + + struct TrackStruct + { + float _chisquare = 0; + int _ndf = 0; + + unsigned int _nclusters_tpc = 0; + unsigned int _nclusters_mvtx = 0; + unsigned int _nclusters_intt = 0; + unsigned int _nclusters_micromegas = 0; + + TrackStateStruct _trk_state_z; + ClusterStruct _found_cluster_z; + + using List = std::vector; + }; + + + class Container : public PHObject + { + public: + + explicit Container() = default; + Container(const Container&) = delete; + Container& operator=(const Container&) = delete; + + void Reset() override { _tracks.clear(); } + + const TrackStruct::List& tracks() const { return _tracks; } + void add_track(const TrackStruct& t) { _tracks.push_back(t); } + void clear_tracks() { _tracks.clear(); } + + private: + + TrackStruct::List _tracks; + + TrackStateStruct _unused_state; + ClusterStruct _unused_cluster; + + ClassDefOverride(Container, 1) + }; + + void set_trackmapname(const std::string& v) { m_trackmapname = v; } + + /// This function is specifically used to give the fitting function a starting point. Use the initial drift velocity you used when reconstructing. + void set_drift_velocity(double v) { m_drift_velocity = v; } + + /// TPC layer range used for the helix fit. The default is R3, but this is an area with huge static distortions. It can easily be adjusted in the Fun4All macro with these functions. + void set_min_tpc_layer(unsigned int v) { m_min_tpc_layer = v; } + void set_max_tpc_layer(unsigned int v) { m_max_tpc_layer = v; } + + /// This one rejects track states near tile edge + void set_y_local_cut(double v) { m_y_local_cut = v; } + + /// Search window to match a Micromegas cluster to the prediction + void set_z_search_window(double v) { m_z_search_win = v; } + + /// Output filename for the QA plot. Make this a .png + void set_plot_filename(const std::string& v) { m_plot_filename = v; } + + /// Output ROOT filename for histograms and fit results. Set empty to disable. + void set_root_filename(const std::string& v) { m_root_filename = v; } + + /// If true (default), append -- to output filenames, following sPHENIX convention + void set_add_run_segment(bool v) { m_add_run_segment = v; } + + /// Manually set the segment number used in output filenames (otherwise parsed from the input filename) + void set_segment(int v) { m_segment = v; } + + private: + + int load_nodes(PHCompositeNode*); + std::string make_output_filename(const std::string&) const; + void evaluate_tracks(); + + Container* m_container = nullptr; + ActsGeometry* m_tGeometry = nullptr; + TpcGlobalPositionWrapper m_globalPositionWrapper; + PHG4CylinderGeomContainer* m_micromegas_geomcontainer = nullptr; + TrkrClusterContainer* m_cluster_map = nullptr; + SvtxTrackMap* m_track_map = nullptr; + + std::string m_trackmapname = "SvtxTrackMap"; + + //These are all adjustable in your F4A macro. You should probably put in a better m_plot_filename. + double m_drift_velocity = 0.00745; + unsigned int m_min_tpc_layer = 39; + unsigned int m_max_tpc_layer = 55; + double m_y_local_cut = 22.0; + double m_z_search_win = 3.0; + std::string m_plot_filename = "drift_calib_QA.png"; + std::string m_root_filename = "drift_calib_QA.root"; + bool m_add_run_segment = true; + int m_segment = -1; + + TH3F* m_hist3D = nullptr; +}; + +#endif \ No newline at end of file diff --git a/offline/packages/tpc/MicromegasDriftEvaluatorLinkDef.h b/offline/packages/tpc/MicromegasDriftEvaluatorLinkDef.h new file mode 100644 index 0000000000..3cf77233e7 --- /dev/null +++ b/offline/packages/tpc/MicromegasDriftEvaluatorLinkDef.h @@ -0,0 +1,6 @@ +#ifdef __CINT__ + +#pragma link C++ class MicromegasDriftEvaluator::Container+; + +#endif + diff --git a/offline/packages/tpc/SiliconDriftEvaluator.cc b/offline/packages/tpc/SiliconDriftEvaluator.cc new file mode 100644 index 0000000000..135454c737 --- /dev/null +++ b/offline/packages/tpc/SiliconDriftEvaluator.cc @@ -0,0 +1,372 @@ +#include "SiliconDriftEvaluator.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//_____________________________________________________________________ +namespace +{ + + //! pt + template T get_pt( const T& px, const T& py ) { return std::sqrt( px*px + py*py ); } + + //_____________________________________________________________________ + // par[0] = constrained slope + // par[1] = offset for eta < 0 + // par[2] = offset for eta >= 0 + // + double fit_function_2d( double* x, double* par ) + { + const int ieta = static_cast( std::floor( x[0] ) ); + const double z = x[1]; + if( ieta < 0 || ieta > 1 ) { TF2::RejectPoint(); return 0.; } + return par[ieta + 1] + par[0] * z; + } + + //! 1D version used to draw per-eta overlay lines on QA canvas + double linear_function( double* x, double* par ) + { return par[0] * x[0] + par[1]; } + + //! human-readable label for each eta bin + const char* k_eta_labels[2] = { "#eta_{TPC} < 0", "#eta_{TPC} #geq 0" }; + +} + +//_____________________________________________________________________ +SiliconDriftEvaluator::SiliconDriftEvaluator( const std::string& name ): + SubsysReco( name ) +{} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::Init( PHCompositeNode* topNode ) +{ + // find DST node + PHNodeIterator iter( topNode ); + auto dstNode = dynamic_cast( iter.findFirst( "PHCompositeNode", "DST" ) ); + if( !dstNode ) + { + std::cout << "SiliconDriftEvaluator::Init - DST Node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + // get EVAL node + iter = PHNodeIterator( dstNode ); + auto evalNode = dynamic_cast( iter.findFirst( "PHCompositeNode", "EVAL" ) ); + if( !evalNode ) + { + // create + std::cout << "SiliconDriftEvaluator::Init - EVAL node missing - creating" << std::endl; + evalNode = new PHCompositeNode( "EVAL" ); + dstNode->addNode( evalNode ); + } + + // add container to output tree + auto newNode = new PHIODataNode( new Container, "SiliconDriftEvaluator::Container", "PHObject" ); + + // overwrite split level for easier offline browsing + newNode->SplitLevel( 99 ); + evalNode->addNode( newNode ); + + // book 3D accumulator histogram + // x = eta bin: 0 = eta<0, 1 = eta>=0 + // y = z_si (cm) + // z = dz (cm) + m_hist3D = new TH3F("SiliconDriftEval_hist3D",";#eta bin;z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)", 2, 0, 2, 200, -m_max_z, m_max_z, 200, -m_max_dz, m_max_dz ); + m_hist3D->SetDirectory( nullptr ); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::InitRun( PHCompositeNode* topNode ) +{ return load_nodes( topNode ); } + +//_____________________________________________________________________ +int SiliconDriftEvaluator::process_event( PHCompositeNode* topNode ) +{ + // load nodes + const auto res = load_nodes( topNode ); + if( res != Fun4AllReturnCodes::EVENT_OK ) return res; + + // cleanup output + if( m_container ) m_container->Reset(); + + evaluate_tracks(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::End( PHCompositeNode* ) +{ + if( !m_hist3D ) + { + std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + const int nEntries = static_cast( m_hist3D->GetEntries() ); + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + + // build mean-dz TH2F via FitSlicesY, one eta bin at a time + // x = eta bin [0,2), y = z_si (cm), content = mean dz (cm) + auto h_fit = new TH2F( "h_fit_silicon", "", + 2, 0, 2, + 200, -m_max_z, m_max_z ); + h_fit->SetDirectory( nullptr ); + + for( int ieta = 0; ieta < 2; ++ieta ) + { + m_hist3D->GetXaxis()->SetRange( ieta + 1, ieta + 1 ); + auto h2d = static_cast( m_hist3D->Project3D( "zy" ) ); + h2d->SetName( Form( "h2d_etabin_%i", ieta ) ); + h2d->SetDirectory( nullptr ); + + // fit vertical slices; require a minimum of m_min_slice_entries per slice + h2d->FitSlicesY( nullptr, 0, -1, m_min_slice_entries ); + auto h_mean = static_cast( gDirectory->Get( Form( "h2d_etabin_%i_1", ieta ) ) ); + + if( !h_mean ) + { + delete h2d; + continue; + } + + for( int iz = 1; iz <= h_mean->GetNbinsX(); ++iz ) + { + const double entries = h2d->Integral( iz, iz, 1, m_hist3D->GetNbinsZ() ); + if( entries > 0 ) + { h_fit->SetBinContent( ieta + 1, iz, h_mean->GetBinContent( iz ) ); } + } + + delete h2d; + } + + m_hist3D->GetXaxis()->SetRange( 0, 0 ); + + // 2D piecewise fit: shared slope + per-eta offset + auto fit2d = new TF2( "fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3 ); + for( int i = 0; i < 3; ++i ) fit2d->SetParameter( i, 0.0 ); + h_fit->Fit( fit2d, "0R" ); + + const double slope = fit2d->GetParameter( 0 ); + const double slope_err = fit2d->GetParError( 0 ); + const double off_neg = fit2d->GetParameter( 1 ); // ieta=0, eta<0 + const double off_pos = fit2d->GetParameter( 2 ); // ieta=1, eta>=0 + + const double dv_new = m_drift_velocity / ( 1.0 + slope ); + const double dv_err = m_drift_velocity / std::pow( 1.0 + slope, 2 ) * slope_err; + const double t0_new = ( off_pos - off_neg ) / ( 2.0 * dv_new ); + + std::cout << Name() << "::End" << " slope=" << slope << " dv_in=" << m_drift_velocity << " cm/ns"<< " dv_new="<< dv_new << " +/- " << dv_err << " cm/ns"<< " t0_new=" << t0_new << " ns"<< std::endl; + + // draw the plot + auto canvas = new TCanvas( "silicon_drift_calib", "Silicon drift velocity calibration", 1400, 700 ); + canvas->Divide( 2, 1 ); + + for( int ieta = 0; ieta < 2; ++ieta ) + { + canvas->cd( ieta + 1 ); + gPad->SetTopMargin( 0.13 ); + gPad->SetRightMargin( 0.18 ); + + // 2D distribution for this eta bin + m_hist3D->GetXaxis()->SetRange( ieta + 1, ieta + 1 ); + auto h2d = static_cast( m_hist3D->Project3D( "zy" ) ); + h2d->SetName( Form( "hplot_etabin_%i", ieta ) ); + h2d->SetTitle( ";z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)" ); + h2d->SetStats( 0 ); + h2d->Draw( "COLZ" ); + + // mean-dz points from FitSlicesY + auto h_fit_proj = h_fit->ProjectionY( Form( "h_fit_proj_%i", ieta ), ieta + 1, ieta + 1 ); + h_fit_proj->SetMarkerStyle( 20 ); + h_fit_proj->SetMarkerSize( 0.6 ); + h_fit_proj->SetMarkerColor( kRed ); + h_fit_proj->SetLineColor( kRed ); + h_fit_proj->Draw( "same P" ); + + // 1D fit line for this eta bin + auto f1d = new TF1( Form( "f1d_etabin_%i", ieta ), linear_function, -m_max_z, m_max_z, 2 ); + f1d->SetParameter( 0, slope ); + f1d->SetParameter( 1, ( ieta == 0 ) ? off_neg : off_pos ); + f1d->SetLineColor( kGreen + 2 ); + f1d->SetLineWidth( 2 ); + f1d->Draw( "same" ); + + // reference line at dz = 0 + auto zero = new TLine( -m_max_z, 0, m_max_z, 0 ); + zero->SetLineStyle( 2 ); + zero->SetLineColor( kGray + 1 ); + zero->Draw(); + + auto leg = new TLegend( 0.13, 0.76, 0.82, 0.95 ); + leg->SetBorderSize( 0 ); + leg->SetFillStyle( 0 ); + leg->SetTextSize( 0.033 ); + leg->SetHeader( Form( "%s entries: %i v_{in}=%.4f cm/ns", + k_eta_labels[ieta], nEntries, m_drift_velocity ), "C" ); + leg->AddEntry( h_fit_proj, "Gaussian slice mean", "p" ); + leg->AddEntry( f1d, Form( "slope=%.4f v_{new}=%.4f#pm%.4f cm/ns t_{0}=%.1f ns", slope, dv_new, dv_err, t0_new ), "l" ); + leg->Draw(); + } + + m_hist3D->GetXaxis()->SetRange( 0, 0 ); + + canvas->SaveAs( m_plot_filename.c_str() ); + std::cout << Name() << "::End - QA canvas saved to " << m_plot_filename << std::endl; + + // write histograms, fit and results to a ROOT file + if( !m_root_filename.empty() ) + { + std::unique_ptr outfile( TFile::Open( m_root_filename.c_str(), "RECREATE" ) ); + if( outfile && !outfile->IsZombie() ) + { + outfile->cd(); + m_hist3D->Write(); + h_fit->Write( "h_fit_silicon" ); + fit2d->Write(); + canvas->Write(); + TParameter( "slope", slope ).Write(); + TParameter( "drift_velocity_in", m_drift_velocity ).Write(); + TParameter( "drift_velocity_new", dv_new ).Write(); + TParameter( "drift_velocity_err", dv_err ).Write(); + TParameter( "t0_new", t0_new ).Write(); + outfile->Close(); + std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; + } + else + { std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; } + } + + delete canvas; + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::load_nodes( PHCompositeNode* topNode ) +{ + // track map + m_track_map = findNode::getClass( topNode, m_trackmapname ); + + // local container + m_container = findNode::getClass( topNode, "SiliconDriftEvaluator::Container" ); + assert( m_container ); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +void SiliconDriftEvaluator::evaluate_tracks() +{ + if( !( m_track_map && m_container && m_hist3D ) ) return; + + // clear array + m_container->clearTracks(); + + for( const auto& [track_id, track] : *m_track_map ) + { + // require valid beam-crossing + const auto crossing = track->get_crossing(); + if( crossing == SHRT_MAX ) + { + std::cout << "SiliconDriftEvaluator::evaluate_tracks - invalid crossing, track ignored." << std::endl; + continue; + } + + // require both seeds + const auto* si_seed = track->get_silicon_seed(); + const auto* tpc_seed = track->get_tpc_seed(); + if( !si_seed || !tpc_seed ) continue; + + // count clusters per subsystem + unsigned int n_tpc = 0; + unsigned int n_mvtx = 0; + unsigned int n_intt = 0; + + for( const auto* seed : { track->get_silicon_seed(), track->get_tpc_seed() } ) + { + if( !seed ) continue; + for( auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it ) + { + switch( TrkrDefs::getTrkrId( *it ) ) + { + case TrkrDefs::tpcId: ++n_tpc; break; + case TrkrDefs::mvtxId: ++n_mvtx; break; + case TrkrDefs::inttId: ++n_intt; break; + default: break; + } + } + } + + // apply selection cuts + if( n_tpc < m_min_nclusters_tpc ) continue; + if( n_mvtx < m_min_nclusters_mvtx ) continue; + if( n_intt < m_min_nclusters_intt ) continue; + + const float eta = tpc_seed->get_eta(); + if( std::abs( eta ) > m_max_eta ) continue; + + const float pt = get_pt( track->get_px(), track->get_py() ); + if( pt < m_min_pt ) continue; + + // get seed z positions at POCA + const auto si_pos = TrackSeedHelper::get_xyz( si_seed ); + const auto tpc_pos = TrackSeedHelper::get_xyz( tpc_seed ); + + const float z_si = si_pos.z(); + const float z_tpc = tpc_pos.z(); + + // dz = (z_tpc + sign(eta)*crossing*crossing_interval*dv) - z_si + const double sign_eta = ( eta >= 0 ) ? 1.0 : -1.0; + const float z_tpc_corr = z_tpc + sign_eta * crossing * m_crossing_interval * m_drift_velocity; + const float dz = z_tpc_corr - z_si; + + // fill track struct + TrackStruct track_struct; + track_struct._nclusters_mvtx = n_mvtx; + track_struct._nclusters_intt = n_intt; + track_struct._nclusters_tpc = n_tpc; + track_struct._pt = pt; + track_struct._eta = eta; + track_struct._phi = tpc_seed->get_phi(); + track_struct._z_tpc = z_tpc; + track_struct._z_si = z_si; + track_struct._crossing = crossing; + track_struct._dz = dz; + + // fill histogram + // eta bin centre: 0.5 for eta<0, 1.5 for eta>=0 + const double eta_bin = ( eta >= 0 ) ? 1.5 : 0.5; + m_hist3D->Fill( eta_bin, z_si, dz ); + + m_container->addTrack( track_struct ); + } +} \ No newline at end of file diff --git a/offline/packages/tpc/SiliconDriftEvaluator.h b/offline/packages/tpc/SiliconDriftEvaluator.h new file mode 100644 index 0000000000..333f6c2529 --- /dev/null +++ b/offline/packages/tpc/SiliconDriftEvaluator.h @@ -0,0 +1,219 @@ +#ifndef G4EVAL_SiliconDriftEvaluator_H +#define G4EVAL_SiliconDriftEvaluator_H + +/* + * Bade Sayki June 16th, 2026 -- LANL + * This module is created to calibrate the drift velocity in the TPC by projecting the silicon seeds and the TPC seeds to the beam axis and calculating the z residuals. + * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's TrackingEvaluator_hp module. It is meant to be a more lightweight and specialized version. + */ + +#include +#include + +#include +#include + +class SvtxTrackMap; +class TH2F; +class TH3F; + +class SiliconDriftEvaluator : public SubsysReco +{ + public: + + //! constructor + SiliconDriftEvaluator( const std::string& = "SiliconDriftEvaluator" ); + + //! global initialization + virtual int Init(PHCompositeNode*); + + //! run initialization + virtual int InitRun(PHCompositeNode*); + + //! event processing + virtual int process_event(PHCompositeNode*); + + //! end of processing + virtual int End(PHCompositeNode*); + + // track information stored in the Container + class TrackStruct + { + public: + + using List = std::vector; + + //cluster counts + unsigned int _nclusters_mvtx = 0; + unsigned int _nclusters_intt = 0; + unsigned int _nclusters_tpc = 0; + + + //tpc seed kinematics + float _pt = 0; + float _eta = 0; + float _phi = 0; + + //seed z positions + + // z position of the TPC seed at the beamline + float _z_tpc = 0; + + //! z position of the silicon seed at the beamline + float _z_si = 0; + + + //! beam-bunch crossing number + short int _crossing = 0; + + //! crossing-corrected dz = z_tpc_corr - z_si (cm) + float _dz = 0; + + }; + + //! track container stored on the node tree + class Container : public PHObject + { + public: + + //! constructor + explicit Container() = default; + + //! copy constructor + explicit Container( const Container& ) = delete; + + //! assignment operator + Container& operator=( const Container& ) = delete; + + //! reset + void Reset() override + { _tracks.clear(); } + + //!@name accessors + //@{ + + const TrackStruct::List& tracks() const + { return _tracks; } + + + // modifiers + + void addTrack( const TrackStruct& track ) + { _tracks.push_back( track ); } + + void clearTracks() + { _tracks.clear(); } + + + private: + + //! tracks array + TrackStruct::List _tracks; + + ClassDefOverride(Container, 1) + + }; + + //! track map name + void set_trackmapname( const std::string& value ) + { m_trackmapname = value; } + + // initial drift velocity (cm/ns); used as starting point for the fit and for the crossing correction + void set_drift_velocity( double value ) + { m_drift_velocity = value; } + + // bunch-crossing interval in ns (default: 106.65237 ns) + void set_crossing_interval( double value ) + { m_crossing_interval = value; } + + // minimum pT cut on tracks (GeV) + void set_min_pt( double value ) + { m_min_pt = value; } + + // minimum number of TPC clusters required + void set_min_nclusters_tpc( unsigned int value ) + { m_min_nclusters_tpc = value; } + + // minimum number of MVTX clusters required + void set_min_nclusters_mvtx( unsigned int value ) + { m_min_nclusters_mvtx = value; } + + // minimum number of INTT clusters required + void set_min_nclusters_intt( unsigned int value ) + { m_min_nclusters_intt = value; } + + // maximum abs(eta) of TPC seed accepted + void set_max_eta( double value ) + { m_max_eta = value; } + + // half-range of the z_si histogram axis (cm) + void set_max_z( double value ) + { m_max_z = value; } + + // half-range of the dz histogram axis (cm) + void set_max_dz( double value ) + { m_max_dz = value; } + + //! minimum entries per z slice required by FitSlicesY + void set_min_slice_entries( int value ) + { m_min_slice_entries = value; } + + // output drift plot filename. Do this in your macro. + void set_plot_filename( const std::string& value ) + { m_plot_filename = value; } + + // output ROOT filename for histograms and fit results. Do this in your macro. + void set_root_filename( const std::string& value ) + { m_root_filename = value; } + + private: + + //! load nodes + int load_nodes( PHCompositeNode* ); + + //! evaluate tracks + void evaluate_tracks(); + + //! evaluation node + Container* m_container = nullptr; + + //! track map + SvtxTrackMap* m_track_map = nullptr; + + //! 3D accumulator histogram: x = eta bin [2], y = z_si, z = dz + TH3F* m_hist3D = nullptr; + + //! track map name + std::string m_trackmapname = "SvtxTrackMap"; + + //! initial drift velocity (cm/ns) + double m_drift_velocity = 0.00747; + + //! bunch-crossing interval (ns) + double m_crossing_interval = 106.65237; + + // track selection cuts + + double m_min_pt = 0.5; + unsigned int m_min_nclusters_tpc = 20; + unsigned int m_min_nclusters_mvtx = 3; + unsigned int m_min_nclusters_intt = 2; + double m_max_eta = 0.9; + + + //! histogram range + double m_max_z = 20.0; + double m_max_dz = 10.0; + + //! minimum entries per z slice for FitSlicesY + int m_min_slice_entries = 10; + + //! output QA plot filename + std::string m_plot_filename = "silicon_drift_calib.png"; + + //! output ROOT filename for histograms and fit results + std::string m_root_filename = "silicon_drift_calib.root"; + +}; + +#endif // G4EVAL_SiliconDriftEvaluator_H \ No newline at end of file diff --git a/offline/packages/tpc/SiliconDriftEvaluatorLinkDef.h b/offline/packages/tpc/SiliconDriftEvaluatorLinkDef.h new file mode 100644 index 0000000000..28c8b6830d --- /dev/null +++ b/offline/packages/tpc/SiliconDriftEvaluatorLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class SiliconDriftEvaluator::Container+; + +#endif From 8fc060d994a09c78937a4329183dbd4a47840374 Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Mon, 20 Jul 2026 19:17:56 -0400 Subject: [PATCH 837/866] moved into calib --- offline/packages/tpccalib/Makefile.am | 9 +++++ .../MicromegasDriftEvaluator.cc | 0 .../MicromegasDriftEvaluator.h | 29 +++++++------- .../MicromegasDriftEvaluatorLinkDef.h | 4 +- .../SiliconDriftEvaluator.cc | 0 .../{tpc => tpccalib}/SiliconDriftEvaluator.h | 40 +++++++------------ .../SiliconDriftEvaluatorLinkDef.h | 0 7 files changed, 40 insertions(+), 42 deletions(-) rename offline/packages/{tpc => tpccalib}/MicromegasDriftEvaluator.cc (100%) rename offline/packages/{tpc => tpccalib}/MicromegasDriftEvaluator.h (81%) rename offline/packages/{tpc => tpccalib}/MicromegasDriftEvaluatorLinkDef.h (95%) rename offline/packages/{tpc => tpccalib}/SiliconDriftEvaluator.cc (100%) rename offline/packages/{tpc => tpccalib}/SiliconDriftEvaluator.h (81%) rename offline/packages/{tpc => tpccalib}/SiliconDriftEvaluatorLinkDef.h (100%) diff --git a/offline/packages/tpccalib/Makefile.am b/offline/packages/tpccalib/Makefile.am index faf8c05386..ad4dad6bc4 100644 --- a/offline/packages/tpccalib/Makefile.am +++ b/offline/packages/tpccalib/Makefile.am @@ -32,12 +32,15 @@ libtpccalib_la_LIBADD = \ -lodbc++ \ -lSubsysReco \ -lg4detectors_io \ + -lmicromegas_io \ -ltrack_io \ -ltrackbase_historic_io \ -ltrack_reco \ -ltpc_io pkginclude_HEADERS = \ + MicromegasDriftEvaluator.h \ + SiliconDriftEvaluator.h \ TpcDirectLaserReconstruction.h \ TpcSpaceChargeMatrixContainer.h \ TpcSpaceChargeMatrixContainerv1.h \ @@ -50,12 +53,16 @@ pkginclude_HEADERS = \ ROOTDICTS = \ + MicromegasDriftEvaluator_Dict.cc \ + SiliconDriftEvaluator_Dict.cc \ TpcSpaceChargeMatrixContainer_Dict.cc \ TpcSpaceChargeMatrixContainerv1_Dict.cc \ TpcSpaceChargeMatrixContainerv2_Dict.cc pcmdir = $(libdir) nobase_dist_pcm_DATA = \ + MicromegasDriftEvaluator_Dict_rdict.pcm \ + SiliconDriftEvaluator_Dict_rdict.pcm \ TpcSpaceChargeMatrixContainer_Dict_rdict.pcm \ TpcSpaceChargeMatrixContainerv1_Dict_rdict.pcm \ TpcSpaceChargeMatrixContainerv2_Dict_rdict.pcm @@ -66,6 +73,8 @@ libtpccalib_io_la_SOURCES = \ TpcSpaceChargeMatrixContainerv2.cc libtpccalib_la_SOURCES = \ + MicromegasDriftEvaluator.cc \ + SiliconDriftEvaluator.cc \ TpcDirectLaserReconstruction.cc \ TpcSpaceChargeMatrixInversion.cc \ TpcSpaceChargeReconstructionHelper.cc \ diff --git a/offline/packages/tpc/MicromegasDriftEvaluator.cc b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc similarity index 100% rename from offline/packages/tpc/MicromegasDriftEvaluator.cc rename to offline/packages/tpccalib/MicromegasDriftEvaluator.cc diff --git a/offline/packages/tpc/MicromegasDriftEvaluator.h b/offline/packages/tpccalib/MicromegasDriftEvaluator.h similarity index 81% rename from offline/packages/tpc/MicromegasDriftEvaluator.h rename to offline/packages/tpccalib/MicromegasDriftEvaluator.h index 95860e5774..743deb0d34 100644 --- a/offline/packages/tpc/MicromegasDriftEvaluator.h +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.h @@ -7,6 +7,7 @@ * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's MicromegasTrackEvaluator_hp module. It is meant to be a more lightweight and specialized version. * It accumulates a TH3F(tile, z_track, dz) histogram during process_event, then in End() fits a piecewise function to suggest an updated drift velocity. * If you have any questions, please feel free to message me on mattermost. + * Claude Code tool was used to format and comment this module. */ #include @@ -93,32 +94,32 @@ class MicromegasDriftEvaluator : public SubsysReco ClassDefOverride(Container, 1) }; - void set_trackmapname(const std::string& v) { m_trackmapname = v; } + void set_trackmapname(const std::string& value) { m_trackmapname = value; } /// This function is specifically used to give the fitting function a starting point. Use the initial drift velocity you used when reconstructing. - void set_drift_velocity(double v) { m_drift_velocity = v; } + void set_drift_velocity(double value) { m_drift_velocity = value; } /// TPC layer range used for the helix fit. The default is R3, but this is an area with huge static distortions. It can easily be adjusted in the Fun4All macro with these functions. - void set_min_tpc_layer(unsigned int v) { m_min_tpc_layer = v; } - void set_max_tpc_layer(unsigned int v) { m_max_tpc_layer = v; } + void set_min_tpc_layer(unsigned int value) { m_min_tpc_layer = value; } + void set_max_tpc_layer(unsigned int value) { m_max_tpc_layer = value; } /// This one rejects track states near tile edge - void set_y_local_cut(double v) { m_y_local_cut = v; } + void set_y_local_cut(double value) { m_y_local_cut = value; } /// Search window to match a Micromegas cluster to the prediction - void set_z_search_window(double v) { m_z_search_win = v; } + void set_z_search_window(double value) { m_z_search_win = value; } /// Output filename for the QA plot. Make this a .png - void set_plot_filename(const std::string& v) { m_plot_filename = v; } + void set_plot_filename(const std::string& value) { m_plot_filename = value; } - /// Output ROOT filename for histograms and fit results. Set empty to disable. - void set_root_filename(const std::string& v) { m_root_filename = v; } + /// Output ROOT filename for histograms and fit results. + void set_root_filename(const std::string& value) { m_root_filename = value; } /// If true (default), append -- to output filenames, following sPHENIX convention - void set_add_run_segment(bool v) { m_add_run_segment = v; } + void set_add_run_segment(bool value) { m_add_run_segment = value; } /// Manually set the segment number used in output filenames (otherwise parsed from the input filename) - void set_segment(int v) { m_segment = v; } + void set_segment(int value) { m_segment = value; } private: @@ -136,13 +137,13 @@ class MicromegasDriftEvaluator : public SubsysReco std::string m_trackmapname = "SvtxTrackMap"; //These are all adjustable in your F4A macro. You should probably put in a better m_plot_filename. - double m_drift_velocity = 0.00745; + double m_drift_velocity = 0.00747; unsigned int m_min_tpc_layer = 39; unsigned int m_max_tpc_layer = 55; double m_y_local_cut = 22.0; double m_z_search_win = 3.0; - std::string m_plot_filename = "drift_calib_QA.png"; - std::string m_root_filename = "drift_calib_QA.root"; + std::string m_plot_filename = "micromegas_drift_calib.png"; + std::string m_root_filename = "micromegas_drift_calib.root"; bool m_add_run_segment = true; int m_segment = -1; diff --git a/offline/packages/tpc/MicromegasDriftEvaluatorLinkDef.h b/offline/packages/tpccalib/MicromegasDriftEvaluatorLinkDef.h similarity index 95% rename from offline/packages/tpc/MicromegasDriftEvaluatorLinkDef.h rename to offline/packages/tpccalib/MicromegasDriftEvaluatorLinkDef.h index 3cf77233e7..1c864da87a 100644 --- a/offline/packages/tpc/MicromegasDriftEvaluatorLinkDef.h +++ b/offline/packages/tpccalib/MicromegasDriftEvaluatorLinkDef.h @@ -1,6 +1,6 @@ #ifdef __CINT__ - + #pragma link C++ class MicromegasDriftEvaluator::Container+; - + #endif diff --git a/offline/packages/tpc/SiliconDriftEvaluator.cc b/offline/packages/tpccalib/SiliconDriftEvaluator.cc similarity index 100% rename from offline/packages/tpc/SiliconDriftEvaluator.cc rename to offline/packages/tpccalib/SiliconDriftEvaluator.cc diff --git a/offline/packages/tpc/SiliconDriftEvaluator.h b/offline/packages/tpccalib/SiliconDriftEvaluator.h similarity index 81% rename from offline/packages/tpc/SiliconDriftEvaluator.h rename to offline/packages/tpccalib/SiliconDriftEvaluator.h index 333f6c2529..d99e1c7254 100644 --- a/offline/packages/tpc/SiliconDriftEvaluator.h +++ b/offline/packages/tpccalib/SiliconDriftEvaluator.h @@ -5,6 +5,7 @@ * Bade Sayki June 16th, 2026 -- LANL * This module is created to calibrate the drift velocity in the TPC by projecting the silicon seeds and the TPC seeds to the beam axis and calculating the z residuals. * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's TrackingEvaluator_hp module. It is meant to be a more lightweight and specialized version. + * Claude tool was used to format and comment this module. */ #include @@ -115,56 +116,43 @@ class SiliconDriftEvaluator : public SubsysReco }; //! track map name - void set_trackmapname( const std::string& value ) - { m_trackmapname = value; } + void set_trackmapname( const std::string& value ) { m_trackmapname = value; } // initial drift velocity (cm/ns); used as starting point for the fit and for the crossing correction - void set_drift_velocity( double value ) - { m_drift_velocity = value; } + void set_drift_velocity( double value ) { m_drift_velocity = value; } // bunch-crossing interval in ns (default: 106.65237 ns) - void set_crossing_interval( double value ) - { m_crossing_interval = value; } + void set_crossing_interval( double value ) { m_crossing_interval = value; } // minimum pT cut on tracks (GeV) - void set_min_pt( double value ) - { m_min_pt = value; } + void set_min_pt( double value ) { m_min_pt = value; } // minimum number of TPC clusters required - void set_min_nclusters_tpc( unsigned int value ) - { m_min_nclusters_tpc = value; } + void set_min_nclusters_tpc( unsigned int value ) { m_min_nclusters_tpc = value; } // minimum number of MVTX clusters required - void set_min_nclusters_mvtx( unsigned int value ) - { m_min_nclusters_mvtx = value; } + void set_min_nclusters_mvtx( unsigned int value ) { m_min_nclusters_mvtx = value; } // minimum number of INTT clusters required - void set_min_nclusters_intt( unsigned int value ) - { m_min_nclusters_intt = value; } + void set_min_nclusters_intt( unsigned int value ) { m_min_nclusters_intt = value; } // maximum abs(eta) of TPC seed accepted - void set_max_eta( double value ) - { m_max_eta = value; } + void set_max_eta( double value ) { m_max_eta = value; } // half-range of the z_si histogram axis (cm) - void set_max_z( double value ) - { m_max_z = value; } + void set_max_z( double value ) { m_max_z = value; } // half-range of the dz histogram axis (cm) - void set_max_dz( double value ) - { m_max_dz = value; } + void set_max_dz( double value ) { m_max_dz = value; } //! minimum entries per z slice required by FitSlicesY - void set_min_slice_entries( int value ) - { m_min_slice_entries = value; } + void set_min_slice_entries( int value ) { m_min_slice_entries = value; } // output drift plot filename. Do this in your macro. - void set_plot_filename( const std::string& value ) - { m_plot_filename = value; } + void set_plot_filename( const std::string& value ) { m_plot_filename = value; } // output ROOT filename for histograms and fit results. Do this in your macro. - void set_root_filename( const std::string& value ) - { m_root_filename = value; } + void set_root_filename( const std::string& value ) { m_root_filename = value; } private: diff --git a/offline/packages/tpc/SiliconDriftEvaluatorLinkDef.h b/offline/packages/tpccalib/SiliconDriftEvaluatorLinkDef.h similarity index 100% rename from offline/packages/tpc/SiliconDriftEvaluatorLinkDef.h rename to offline/packages/tpccalib/SiliconDriftEvaluatorLinkDef.h From f3e7ccf528e0eda633f7fbd8dd62b791f012ec15 Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Mon, 20 Jul 2026 20:16:13 -0400 Subject: [PATCH 838/866] Unit correction and clang-format --- .../tpccalib/MicromegasDriftEvaluator.cc | 657 +++++++++--------- .../tpccalib/MicromegasDriftEvaluator.h | 87 ++- .../tpccalib/SiliconDriftEvaluator.cc | 591 ++++++++-------- .../packages/tpccalib/SiliconDriftEvaluator.h | 211 +++--- 4 files changed, 794 insertions(+), 752 deletions(-) diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc index 747e5c0cf6..aee2378e65 100644 --- a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc @@ -1,63 +1,75 @@ #include "MicromegasDriftEvaluator.h" - + #include #include #include #include -#include #include #include +#include +#include #include +#include #include #include #include -#include -#include #include #include - + #include +#include #include #include +#include #include #include #include #include -#include -#include -#include #include - +#include + #include #include #include #include #include - - + namespace { - - 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: + 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: T m_range; }; - - template inline constexpr T square(T x) { return x * x; } - template inline T get_r(T x, T y) { return std::sqrt(square(x) + square(y)); } - + + template + inline constexpr T square(T x) + { + return x * x; + } + template + inline T get_r(T x, T y) + { + return std::sqrt(square(x) + square(y)); + } + double normalize_angle(double phi) { - while (phi < 0) phi += 2 * M_PI; + while (phi < 0) phi += 2 * M_PI; while (phi >= 2 * M_PI) phi -= 2 * M_PI; return phi; } - + bool phi_in_range(double phi, double min, double max) { phi = normalize_angle(phi); @@ -66,73 +78,68 @@ namespace return (min < max) ? (phi >= min && phi <= max) : (phi >= min || phi <= max); } - + // This function is identical to the version in MicromegasTrackEvaluator_hp.cc - + bool helix_plane_intersection( - double t_min, - double t_max, - double zmin, - double zmax, - double R, - double X0, - double Y0, - double intersect_rz, - double slope_rz, - const TVector3& ptile, - const TVector3& ntile, - TVector3& intersect) + double t_min, + double t_max, + double zmin, + double zmax, + double R, + double X0, + double Y0, + double intersect_rz, + double slope_rz, + const TVector3& ptile, + const TVector3& ntile, + TVector3& intersect) { // Number of iterations and tolerance for Newton Raphson method - const int max_iter = 10; - const double tol = 1e-6; - + const int max_iter = 10; + const double tol = 1e-6; + // Define C double C = ntile.X() * (X0 - ptile.X()) + ntile.Y() * (Y0 - ptile.Y()) + ntile.Z() * (intersect_rz - ptile.Z()); - + // Defines the function and the corresponding derivative to be used in the Newton Raphson method auto f = [&](double t) { double xt = X0 + R * std::cos(t); double yt = Y0 + R * std::sin(t); - double Rt = std::sqrt(xt*xt + yt*yt); - return ntile.X() * R * std::cos(t) - + ntile.Y() * R * std::sin(t) - + ntile.Z() * slope_rz * Rt - + C; + double Rt = std::sqrt(xt * xt + yt * yt); + return ntile.X() * R * std::cos(t) + ntile.Y() * R * std::sin(t) + ntile.Z() * slope_rz * Rt + C; }; - + auto df = [&](double t) { double xt = X0 + R * std::cos(t); double yt = Y0 + R * std::sin(t); - double Rt = std::sqrt(xt*xt + yt*yt); - return -ntile.X() * R * std::sin(t) - + ntile.Y() * R * std::cos(t) - + ntile.Z() * R * slope_rz * (Y0*std::cos(t) - X0*std::sin(t)) / Rt; + double Rt = std::sqrt(xt * xt + yt * yt); + return -ntile.X() * R * std::sin(t) + ntile.Y() * R * std::cos(t) + ntile.Z() * R * slope_rz * (Y0 * std::cos(t) - X0 * std::sin(t)) / Rt; }; - + auto solve_from = [&](double t_seed, TVector3& result) -> bool { double t = t_seed; for (int i = 0; i < max_iter; ++i) { - double ft = f(t); + double ft = f(t); double dft = df(t); if (std::abs(dft) < 1e-8) return false; double t_new = t - ft / dft; - - double x = X0 + R * std::cos(t_new); - double y = Y0 + R * std::sin(t_new); - double Rt_n = std::sqrt(x*x + y*y); - double z = slope_rz * Rt_n + intersect_rz; - double phi = std::atan2(y, x); - + + double x = X0 + R * std::cos(t_new); + double y = Y0 + R * std::sin(t_new); + double Rt_n = std::sqrt(x * x + y * y); + double z = slope_rz * Rt_n + intersect_rz; + double phi = std::atan2(y, x); + TVector3 cand(x, y, z); - bool phi_ok = phi_in_range(phi, t_min - 1e-4, t_max + 1e-4); - bool z_ok = (z >= zmin - 1e-4 && z <= zmax + 1e-4); + bool phi_ok = phi_in_range(phi, t_min - 1e-4, t_max + 1e-4); + bool z_ok = (z >= zmin - 1e-4 && z <= zmax + 1e-4); bool proj_ok = (std::abs(ntile.Dot(cand - ptile)) <= 0.05); - + if (std::abs(t_new - t) < tol && proj_ok && phi_ok && z_ok) { result = cand; @@ -142,407 +149,427 @@ namespace } return false; }; - + auto wrap = [&](double t) { while (t > t_max) t -= 2 * M_PI; while (t < t_min) t += 2 * M_PI; return t; }; - + std::vector t_seeds; double t_center = 0.5 * (t_min + t_max); double delta = 2.0 * M_PI / 3.0; - + // Wrap the angle for (int i = 0; i < 3; ++i) - { - double t = wrap(t_center + i * delta); - t_seeds.push_back(t); - } - + { + double t = wrap(t_center + i * delta); + t_seeds.push_back(t); + } + // Looks for the solution within the tile acceptance in three different phi seeds in the Newton-Raphson (helix_plane could have more than one solution) for (double t_seed : t_seeds) - { - if (solve_from(t_seed, intersect)) return true; - } + { + if (solve_from(t_seed, intersect)) return true; + } return false; } - + // this is a piecewise fit function for the drift velocity plot double fit_function_2d(double* x, double* par) { - const int itile = static_cast(std::floor(x[0])); - const double z = x[1]; - if (itile < 0 || itile >= 8) { TF2::RejectPoint(); return 0.; } + const int itile = static_cast(std::floor(x[0])); + const double z = x[1]; + if (itile < 0 || itile >= 8) + { + TF2::RejectPoint(); + return 0.; + } return par[itile + 1] + par[0] * z; } - + double linear_function(double* x, double* par) - { return par[0] * x[0] + par[1]; } - + { + return par[0] * x[0] + par[1]; + } + const std::array k_tile_names = - { "SCOZ", "SCIZ", "NCIZ", "NCOZ", "SEZ", "NEZ", "SWZ", "NWZ" }; - -} - + {"SCOZ", "SCIZ", "NCIZ", "NCOZ", "SEZ", "NEZ", "SWZ", "NWZ"}; + +} // namespace + MicromegasDriftEvaluator::MicromegasDriftEvaluator(const std::string& name) : SubsysReco(name) -{} - +{ +} + // --------------------------------------------------------------------------- int MicromegasDriftEvaluator::Init(PHCompositeNode* topNode) { std::cout << Name() << "::Init" << " drift_velocity=" << m_drift_velocity << " cm/ns" - << " min_tpc_layer=" << m_min_tpc_layer - << " max_tpc_layer=" << m_max_tpc_layer + << " min_tpc_layer=" << m_min_tpc_layer + << " max_tpc_layer=" << m_max_tpc_layer << std::endl; - + PHNodeIterator iter(topNode); auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) - { - std::cerr << Name() << "::Init - DST node missing" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - + { + std::cerr << Name() << "::Init - DST node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + iter = PHNodeIterator(dstNode); auto evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); if (!evalNode) - { - evalNode = new PHCompositeNode("EVAL"); - dstNode->addNode(evalNode); - } - + { + evalNode = new PHCompositeNode("EVAL"); + dstNode->addNode(evalNode); + } + auto newNode = new PHIODataNode(new Container, "MicromegasDriftEvaluator::Container", "PHObject"); newNode->SplitLevel(99); evalNode->addNode(newNode); - - m_hist3D = new TH3F("MicromegasDriftEval_hist3D", ";tile;z_{track} (cm);#Deltaz (track#minuscluster) (cm)",8, 0, 8,220, -110, 110, 100, -10, 10); + + m_hist3D = new TH3F("MicromegasDriftEval_hist3D", ";tile;z_{track} (cm);#Deltaz (track#minuscluster) (cm)", 8, 0, 8, 220, -110, 110, 100, -10, 10); m_hist3D->SetDirectory(nullptr); - + return Fun4AllReturnCodes::EVENT_OK; } - + // --------------------------------------------------------------------------- int MicromegasDriftEvaluator::InitRun(PHCompositeNode* topNode) -{ return load_nodes(topNode); } - +{ + return load_nodes(topNode); +} + // --------------------------------------------------------------------------- int MicromegasDriftEvaluator::process_event(PHCompositeNode* topNode) { const auto res = load_nodes(topNode); if (res != Fun4AllReturnCodes::EVENT_OK) return res; - + if (m_container) m_container->Reset(); evaluate_tracks(); - + return Fun4AllReturnCodes::EVENT_OK; } - + // --------------------------------------------------------------------------- int MicromegasDriftEvaluator::End(PHCompositeNode*) { if (!m_hist3D) - { - std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - + { + std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + const int nEntries = static_cast(m_hist3D->GetEntries()); std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; - + auto h_fit = new TH2F("h_fit", "", 8, 0, 8, 220, -110, 110); h_fit->SetDirectory(nullptr); - + for (int j = 0; j < 8; ++j) { m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); auto h2d = static_cast(m_hist3D->Project3D("zy")); h2d->SetName(Form("h_%s", k_tile_names[j])); h2d->SetDirectory(nullptr); - + // Fit vertical slices; require a minimum of 10 entries per slice h2d->FitSlicesY(nullptr, 0, -1, 10); auto h_mean = static_cast(gDirectory->Get(Form("h_%s_1", k_tile_names[j]))); - + if (!h_mean) - { - delete h2d; - continue; - } - + { + delete h2d; + continue; + } + for (int i = 0; i < h_mean->GetNbinsX(); ++i) + { + const double entries = h2d->Integral(i + 1, i + 1, 1, m_hist3D->GetNbinsZ()); + if (entries > 0) { - const double entries = h2d->Integral(i + 1, i + 1, 1, m_hist3D->GetNbinsZ()); - if (entries > 0) - { h_fit->SetBinContent(j + 1, i + 1, h_mean->GetBinContent(i + 1)); } + h_fit->SetBinContent(j + 1, i + 1, h_mean->GetBinContent(i + 1)); } + } delete h2d; } - + m_hist3D->GetXaxis()->SetRange(0, 0); - - // This part fits the 8 micromegas modules one at a time but constrains the slopes to be identical. This eliminates the need for perfect translational TPOT alignment + + // This part fits the 8 micromegas modules one at a time but constrains the slopes to be identical. This eliminates the need for perfect translational TPOT alignment auto fit2d = new TF2("fit2d", fit_function_2d, 0, 8, -110, 110, 9); for (int i = 0; i < 9; ++i) fit2d->SetParameter(i, 0.0); - + h_fit->Fit(fit2d, "0R"); - + const double slope = fit2d->GetParameter(0); const double slope_err = fit2d->GetParError(0); const double new_drift = m_drift_velocity / (1.0 + slope); const double drift_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; - - std::cout << Name() << "::End" << " slope=" << slope<< " input_drift=" << m_drift_velocity << " cm/ns" << " new_drift=" << new_drift << " cm/ns +/- " << drift_err << " cm/ns"<< std::endl; - + + std::cout << Name() << "::End" << " slope=" << slope << " input_drift=" << m_drift_velocity << " cm/ns" << " new_drift=" << new_drift << " cm/ns +/- " << drift_err << " cm/ns" << std::endl; + // Plot the whole thing auto canvas = new TCanvas("drift_calib", "Drift velocity calibration", 2000, 1000); canvas->Divide(4, 2); - + for (int j = 0; j < 8; ++j) - { - canvas->cd(j + 1); - - m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); - auto h2d = static_cast(m_hist3D->Project3D("zy")); - h2d->SetName(Form("hplot_%s", k_tile_names[j])); - h2d->SetTitle(Form("%s;z_{track} (cm);#Deltaz (track#minuscluster) (cm)",k_tile_names[j])); - h2d->SetStats(0); - h2d->Draw("COLZ"); - - auto h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", j), j + 1, j + 1); //These give you the Gaussian means for each slice - h_fit_proj->SetMarkerStyle(20); - h_fit_proj->SetMarkerColor(kRed); - h_fit_proj->SetLineColor(kBlack); - - auto f1d = new TF1(Form("f1d_%i", j), linear_function, -110, 110, 2); - f1d->SetParameter(0, slope); - f1d->SetParameter(1, fit2d->GetParameter(j + 1)); - f1d->SetLineColor(kGreen + 2); - f1d->SetLineWidth(2); - f1d->Draw("same"); - - auto leg = new TLegend(0.35, 0.75, 0.92, 0.92); - leg->SetHeader(Form("%i entries, v_{in}=%.2f m/ms", nEntries, m_drift_velocity * 1e5), "C"); - leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); - leg->AddEntry(f1d,Form("slope=%.4f v_{new}=%.3f#pm%.3f m/ms",slope, new_drift * 1e5, drift_err * 1e5), "l"); - leg->Draw(); - } - + { + canvas->cd(j + 1); + + m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); + auto h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(Form("hplot_%s", k_tile_names[j])); + h2d->SetTitle(Form("%s;z_{track} (cm);#Deltaz (track#minuscluster) (cm)", k_tile_names[j])); + h2d->SetStats(0); + h2d->Draw("COLZ"); + + auto h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", j), j + 1, j + 1); // These give you the Gaussian means for each slice + h_fit_proj->SetMarkerStyle(20); + h_fit_proj->SetMarkerColor(kRed); + h_fit_proj->SetLineColor(kBlack); + + auto f1d = new TF1(Form("f1d_%i", j), linear_function, -110, 110, 2); + f1d->SetParameter(0, slope); + f1d->SetParameter(1, fit2d->GetParameter(j + 1)); + f1d->SetLineColor(kGreen + 2); + f1d->SetLineWidth(2); + f1d->Draw("same"); + + auto leg = new TLegend(0.35, 0.75, 0.92, 0.92); + leg->SetHeader(Form("%i entries, v_{in}=%.2f m/ms", nEntries, m_drift_velocity * 1e4), "C"); + leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); + leg->AddEntry(f1d, Form("slope=%.4f v_{new}=%.3f#pm%.3f m/ms", slope, new_drift * 1e4, drift_err * 1e4), "l"); + leg->Draw(); + } + m_hist3D->GetXaxis()->SetRange(0, 0); - + canvas->SaveAs(m_plot_filename.c_str()); std::cout << Name() << "::End - QA canvas saved to " << m_plot_filename << std::endl; - + // write histograms, fit and results to a ROOT file if (!m_root_filename.empty()) + { + std::unique_ptr outfile(TFile::Open(m_root_filename.c_str(), "RECREATE")); + if (outfile && !outfile->IsZombie()) + { + outfile->cd(); + m_hist3D->Write(); + h_fit->Write("h_fit_micromegas"); + fit2d->Write(); + canvas->Write(); + TParameter("slope", slope).Write(); + TParameter("drift_velocity_in", m_drift_velocity).Write(); + TParameter("drift_velocity_new", new_drift).Write(); + TParameter("drift_velocity_err", drift_err).Write(); + outfile->Close(); + std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; + } + else { - std::unique_ptr outfile(TFile::Open(m_root_filename.c_str(), "RECREATE")); - if (outfile && !outfile->IsZombie()) - { - outfile->cd(); - m_hist3D->Write(); - h_fit->Write("h_fit_micromegas"); - fit2d->Write(); - canvas->Write(); - TParameter("slope", slope).Write(); - TParameter("drift_velocity_in", m_drift_velocity).Write(); - TParameter("drift_velocity_new", new_drift).Write(); - TParameter("drift_velocity_err", drift_err).Write(); - outfile->Close(); - std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; - } - else - { std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; } + std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; } - + } + delete canvas; delete fit2d; delete h_fit; - + return Fun4AllReturnCodes::EVENT_OK; } - + // --------------------------------------------------------------------------- int MicromegasDriftEvaluator::load_nodes(PHCompositeNode* topNode) { m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); assert(m_tGeometry); - + m_micromegas_geomcontainer = findNode::getClass(topNode, "CYLINDERGEOM_MICROMEGAS_FULL"); assert(m_micromegas_geomcontainer); - + m_track_map = findNode::getClass(topNode, m_trackmapname); - + m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); assert(m_cluster_map); - + m_container = findNode::getClass(topNode, "MicromegasDriftEvaluator::Container"); assert(m_container); - + m_globalPositionWrapper.loadNodes(topNode); - + return Fun4AllReturnCodes::EVENT_OK; } - + // --------------------------------------------------------------------------- void MicromegasDriftEvaluator::evaluate_tracks() { if (!(m_track_map && m_cluster_map && m_container && m_hist3D)) return; - + m_container->clear_tracks(); - + for (const auto& [track_id, track] : *m_track_map) { - //valid crossing + // valid crossing const auto crossing = track->get_crossing(); if (crossing == SHRT_MAX) continue; - + std::vector tpc_positions; - + // Also count clusters per subsystem for the cuts - unsigned int n_tpc = 0; + unsigned int n_tpc = 0; unsigned int n_mvtx = 0; unsigned int n_intt = 0; - unsigned int n_mm = 0; - + unsigned int n_mm = 0; + for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) { if (!seed) continue; for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) { - const auto ckey = *it; - const auto detid = TrkrDefs::getTrkrId(ckey); - const auto layer = TrkrDefs::getLayer(ckey); - + const auto ckey = *it; + const auto detid = TrkrDefs::getTrkrId(ckey); + const auto layer = TrkrDefs::getLayer(ckey); + switch (detid) { - case TrkrDefs::tpcId: - ++n_tpc; - if (layer >= m_min_tpc_layer && layer < m_max_tpc_layer) + case TrkrDefs::tpcId: + ++n_tpc; + if (layer >= m_min_tpc_layer && layer < m_max_tpc_layer) + { + const auto cl = m_cluster_map->findCluster(ckey); + if (cl) { - const auto cl = m_cluster_map->findCluster(ckey); - if (cl) - { - tpc_positions.push_back( + tpc_positions.push_back( m_globalPositionWrapper.getGlobalPositionDistortionCorrected( - ckey, cl, crossing)); - } + ckey, cl, crossing)); } - break; - case TrkrDefs::mvtxId: ++n_mvtx; break; - case TrkrDefs::inttId: ++n_intt; break; - case TrkrDefs::micromegasId: ++n_mm; break; - default: break; + } + break; + case TrkrDefs::mvtxId: + ++n_mvtx; + break; + case TrkrDefs::inttId: + ++n_intt; + break; + case TrkrDefs::micromegasId: + ++n_mm; + break; + default: + break; } } } - + // need at least 3 TPC clusters in range if (tpc_positions.size() < 3) continue; - + const auto [slope_rz, intersect_rz] = TrackFitUtils::line_fit(tpc_positions); const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin(tpc_positions); - + // reject badly reconstructed / low-pT tracks if (R < 40.0) continue; - + const auto mm_range = m_micromegas_geomcontainer->get_begin_end(); for (const auto& [mm_layer, base_layergeom] : range_adaptor(mm_range)) + { + const auto layergeom = static_cast(base_layergeom); + assert(layergeom); + + // skip the phi layer. Only the z-view layer matters here + if (layergeom->get_segmentation_type() != + MicromegasDefs::SegmentationType::SEGMENTATION_Z) continue; + + const double layer_radius = layergeom->get_radius(); + auto [xplus, yplus, xminus, yminus] = + TrackFitUtils::circle_circle_intersection(layer_radius, R, X0, Y0); + + if (!std::isfinite(xplus)) continue; + + // pick the solution closest in phi to the last TPC cluster + const double last_phi = std::atan2(tpc_positions.back().y(), tpc_positions.back().x()); + const double phi_plus = std::atan2(yplus, xplus); + const double phi_minus = std::atan2(yminus, xminus); + const double phi = (std::abs(last_phi - phi_plus) < std::abs(last_phi - phi_minus)) ? phi_plus : phi_minus; + + const double r_cyl = layer_radius; + const double z_cyl = intersect_rz + slope_rz * r_cyl; + const TVector3 world_cyl(r_cyl * std::cos(phi), r_cyl * std::sin(phi), z_cyl); + + const int tileid = layergeom->find_tile_cylindrical(world_cyl); + if (tileid < 0) continue; + + const auto tile_center = layergeom->get_world_from_local_coords(tileid, m_tGeometry, {0, 0}); + const TVector3 ptile(tile_center.x(), tile_center.y(), tile_center.z()); + + const auto tile_norm = layergeom->get_world_from_local_vect(tileid, m_tGeometry, {0, 0, 1}); + const TVector3 ntile(tile_norm.x(), tile_norm.y(), tile_norm.z()); + + const auto phi_range = layergeom->get_phi_range(tileid, m_tGeometry); + const double zmin = layergeom->get_zmin(); + const double zmax = layergeom->get_zmax(); + + TVector3 intersection; + if (!helix_plane_intersection(phi_range.first, phi_range.second, zmin, zmax, R, X0, Y0, intersect_rz, slope_rz, ptile, ntile, intersection)) + continue; + + const auto local_intersection = layergeom->get_local_from_world_coords(tileid, m_tGeometry, {intersection.x(), intersection.y(), intersection.z()}); + const double y_local = local_intersection.y(); + + if (std::abs(y_local) > m_y_local_cut) continue; + + // find the nearest TPOT cluster + const auto hitsetkey = MicromegasDefs::genHitSetKey(mm_layer, MicromegasDefs::SegmentationType::SEGMENTATION_Z, tileid); + const auto clusrange = m_cluster_map->getClusters(hitsetkey); + + double dmin = -1; + ClusterStruct best_cluster; + + for (const auto& [ckey, cl] : range_adaptor(clusrange)) { - const auto layergeom =static_cast(base_layergeom); - assert(layergeom); - - // skip the phi layer. Only the z-view layer matters here - if (layergeom->get_segmentation_type() != - MicromegasDefs::SegmentationType::SEGMENTATION_Z) continue; - - const double layer_radius = layergeom->get_radius(); - auto [xplus, yplus, xminus, yminus] = - TrackFitUtils::circle_circle_intersection(layer_radius, R, X0, Y0); - - if (!std::isfinite(xplus)) continue; - - // pick the solution closest in phi to the last TPC cluster - const double last_phi = std::atan2(tpc_positions.back().y(), tpc_positions.back().x()); - const double phi_plus = std::atan2(yplus, xplus); - const double phi_minus = std::atan2(yminus, xminus); - const double phi = (std::abs(last_phi - phi_plus) < std::abs(last_phi - phi_minus)) ? phi_plus : phi_minus; - - const double r_cyl = layer_radius; - const double z_cyl = intersect_rz + slope_rz * r_cyl; - const TVector3 world_cyl(r_cyl * std::cos(phi), r_cyl * std::sin(phi), z_cyl); - - const int tileid = layergeom->find_tile_cylindrical(world_cyl); - if (tileid < 0) continue; - - const auto tile_center = layergeom->get_world_from_local_coords(tileid, m_tGeometry, {0, 0}); - const TVector3 ptile(tile_center.x(), tile_center.y(), tile_center.z()); - - const auto tile_norm = layergeom->get_world_from_local_vect(tileid, m_tGeometry, {0, 0, 1}); - const TVector3 ntile(tile_norm.x(), tile_norm.y(), tile_norm.z()); - - const auto phi_range = layergeom->get_phi_range(tileid, m_tGeometry); - const double zmin = layergeom->get_zmin(); - const double zmax = layergeom->get_zmax(); - - TVector3 intersection; - if (!helix_plane_intersection(phi_range.first, phi_range.second, zmin, zmax, R, X0, Y0, intersect_rz, slope_rz, ptile, ntile, intersection)) - continue; - - const auto local_intersection = layergeom->get_local_from_world_coords(tileid, m_tGeometry,{intersection.x(), intersection.y(), intersection.z()}); - const double y_local = local_intersection.y(); - - if (std::abs(y_local) > m_y_local_cut) continue; - - //find the nearest TPOT cluster - const auto hitsetkey = MicromegasDefs::genHitSetKey(mm_layer,MicromegasDefs::SegmentationType::SEGMENTATION_Z,tileid); - const auto clusrange = m_cluster_map->getClusters(hitsetkey); - - double dmin = -1; - ClusterStruct best_cluster; - - for (const auto& [ckey, cl] : range_adaptor(clusrange)) - { - const double cl_y_local = cl->getLocalY(); - const double d = std::abs(y_local - cl_y_local); - if (dmin < 0 || d < dmin) - { - dmin = d; - const auto gpos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing); - best_cluster._layer = mm_layer; - best_cluster._tile = tileid; - best_cluster._z = gpos.z(); - } - } - - // require cluster within the z search window - if (dmin < 0 || dmin > m_z_search_win) continue; - - //fill track struct and histogram - TrackStruct track_struct; - track_struct._chisquare = track->get_chisq(); - track_struct._ndf = track->get_ndf(); - track_struct._nclusters_tpc = n_tpc; - track_struct._nclusters_mvtx = n_mvtx; - track_struct._nclusters_intt = n_intt; - track_struct._nclusters_micromegas = n_mm; - - track_struct._trk_state_z._layer = mm_layer; - track_struct._trk_state_z._tile = tileid; - track_struct._trk_state_z._z = intersection.z(); - track_struct._trk_state_z._y_local = y_local; - - track_struct._found_cluster_z = best_cluster; - - const double z_track = track_struct._trk_state_z._z; - const double z_cluster = track_struct._found_cluster_z._z; - m_hist3D->Fill(tileid + 0.5, z_track, z_track - z_cluster); - - m_container->add_track(track_struct); - break; + const double cl_y_local = cl->getLocalY(); + const double d = std::abs(y_local - cl_y_local); + if (dmin < 0 || d < dmin) + { + dmin = d; + const auto gpos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing); + best_cluster._layer = mm_layer; + best_cluster._tile = tileid; + best_cluster._z = gpos.z(); + } } + + // require cluster within the z search window + if (dmin < 0 || dmin > m_z_search_win) continue; + + // fill track struct and histogram + TrackStruct track_struct; + track_struct._chisquare = track->get_chisq(); + track_struct._ndf = track->get_ndf(); + track_struct._nclusters_tpc = n_tpc; + track_struct._nclusters_mvtx = n_mvtx; + track_struct._nclusters_intt = n_intt; + track_struct._nclusters_micromegas = n_mm; + + track_struct._trk_state_z._layer = mm_layer; + track_struct._trk_state_z._tile = tileid; + track_struct._trk_state_z._z = intersection.z(); + track_struct._trk_state_z._y_local = y_local; + + track_struct._found_cluster_z = best_cluster; + + const double z_track = track_struct._trk_state_z._z; + const double z_cluster = track_struct._found_cluster_z._z; + m_hist3D->Fill(tileid + 0.5, z_track, z_track - z_cluster); + + m_container->add_track(track_struct); + break; + } } } \ No newline at end of file diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.h b/offline/packages/tpccalib/MicromegasDriftEvaluator.h index 743deb0d34..609dafdc4a 100644 --- a/offline/packages/tpccalib/MicromegasDriftEvaluator.h +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.h @@ -6,7 +6,7 @@ * This module is created to calibrate the drift velocity in the TPC by fitting a helix to the clusters within a certain layer range, and projecting it to the TPOT z view module plane. The default layers in the TPC are set to be 39-55, which correspond to R3. * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's MicromegasTrackEvaluator_hp module. It is meant to be a more lightweight and specialized version. * It accumulates a TH3F(tile, z_track, dz) histogram during process_event, then in End() fits a piecewise function to suggest an updated drift velocity. - * If you have any questions, please feel free to message me on mattermost. + * If you have any questions, please feel free to message me on mattermost. * Claude Code tool was used to format and comment this module. */ @@ -29,9 +29,8 @@ class SvtxTrackMap; class MicromegasDriftEvaluator : public SubsysReco { - public: - - explicit MicromegasDriftEvaluator( const std::string& name = "MicromegasDriftEvaluator" ); + public: + explicit MicromegasDriftEvaluator(const std::string& name = "MicromegasDriftEvaluator"); int Init(PHCompositeNode*) override; int InitRun(PHCompositeNode*) override; @@ -40,40 +39,38 @@ class MicromegasDriftEvaluator : public SubsysReco struct TrackStateStruct { - unsigned short _layer = 0; - unsigned short _tile = 0; - double _z = 0; - double _y_local = 0; + unsigned short _layer = 0; + unsigned short _tile = 0; + double _z = 0; + double _y_local = 0; }; struct ClusterStruct { - unsigned short _layer = 0; - unsigned short _tile = 0; - double _z = 0; + unsigned short _layer = 0; + unsigned short _tile = 0; + double _z = 0; }; struct TrackStruct { float _chisquare = 0; - int _ndf = 0; + int _ndf = 0; - unsigned int _nclusters_tpc = 0; - unsigned int _nclusters_mvtx = 0; - unsigned int _nclusters_intt = 0; + unsigned int _nclusters_tpc = 0; + unsigned int _nclusters_mvtx = 0; + unsigned int _nclusters_intt = 0; unsigned int _nclusters_micromegas = 0; - TrackStateStruct _trk_state_z; - ClusterStruct _found_cluster_z; + TrackStateStruct _trk_state_z; + ClusterStruct _found_cluster_z; using List = std::vector; }; - class Container : public PHObject { - public: - + public: explicit Container() = default; Container(const Container&) = delete; Container& operator=(const Container&) = delete; @@ -81,15 +78,14 @@ class MicromegasDriftEvaluator : public SubsysReco void Reset() override { _tracks.clear(); } const TrackStruct::List& tracks() const { return _tracks; } - void add_track(const TrackStruct& t) { _tracks.push_back(t); } - void clear_tracks() { _tracks.clear(); } - - private: + void add_track(const TrackStruct& t) { _tracks.push_back(t); } + void clear_tracks() { _tracks.clear(); } + private: TrackStruct::List _tracks; TrackStateStruct _unused_state; - ClusterStruct _unused_cluster; + ClusterStruct _unused_cluster; ClassDefOverride(Container, 1) }; @@ -121,31 +117,30 @@ class MicromegasDriftEvaluator : public SubsysReco /// Manually set the segment number used in output filenames (otherwise parsed from the input filename) void set_segment(int value) { m_segment = value; } - private: - - int load_nodes(PHCompositeNode*); + private: + int load_nodes(PHCompositeNode*); std::string make_output_filename(const std::string&) const; void evaluate_tracks(); - Container* m_container = nullptr; - ActsGeometry* m_tGeometry = nullptr; - TpcGlobalPositionWrapper m_globalPositionWrapper; + Container* m_container = nullptr; + ActsGeometry* m_tGeometry = nullptr; + TpcGlobalPositionWrapper m_globalPositionWrapper; PHG4CylinderGeomContainer* m_micromegas_geomcontainer = nullptr; - TrkrClusterContainer* m_cluster_map = nullptr; - SvtxTrackMap* m_track_map = nullptr; - - std::string m_trackmapname = "SvtxTrackMap"; - - //These are all adjustable in your F4A macro. You should probably put in a better m_plot_filename. - double m_drift_velocity = 0.00747; - unsigned int m_min_tpc_layer = 39; - unsigned int m_max_tpc_layer = 55; - double m_y_local_cut = 22.0; - double m_z_search_win = 3.0; - std::string m_plot_filename = "micromegas_drift_calib.png"; - std::string m_root_filename = "micromegas_drift_calib.root"; - bool m_add_run_segment = true; - int m_segment = -1; + TrkrClusterContainer* m_cluster_map = nullptr; + SvtxTrackMap* m_track_map = nullptr; + + std::string m_trackmapname = "SvtxTrackMap"; + + // These are all adjustable in your F4A macro. You should probably put in a better m_plot_filename. + double m_drift_velocity = 0.00747; + unsigned int m_min_tpc_layer = 39; + unsigned int m_max_tpc_layer = 55; + double m_y_local_cut = 22.0; + double m_z_search_win = 3.0; + std::string m_plot_filename = "micromegas_drift_calib.png"; + std::string m_root_filename = "micromegas_drift_calib.root"; + bool m_add_run_segment = true; + int m_segment = -1; TH3F* m_hist3D = nullptr; }; diff --git a/offline/packages/tpccalib/SiliconDriftEvaluator.cc b/offline/packages/tpccalib/SiliconDriftEvaluator.cc index 135454c737..4c6a0200c6 100644 --- a/offline/packages/tpccalib/SiliconDriftEvaluator.cc +++ b/offline/packages/tpccalib/SiliconDriftEvaluator.cc @@ -1,372 +1,397 @@ #include "SiliconDriftEvaluator.h" - + #include -#include #include #include +#include #include #include #include #include - + #include +#include #include #include +#include #include #include #include #include #include -#include -#include #include - + #include #include #include #include #include - + //_____________________________________________________________________ namespace { - + //! pt - template T get_pt( const T& px, const T& py ) { return std::sqrt( px*px + py*py ); } - + template + T get_pt(const T& px, const T& py) + { + return std::sqrt(px * px + py * py); + } + //_____________________________________________________________________ // par[0] = constrained slope - // par[1] = offset for eta < 0 + // par[1] = offset for eta < 0 // par[2] = offset for eta >= 0 // - double fit_function_2d( double* x, double* par ) + double fit_function_2d(double* x, double* par) { - const int ieta = static_cast( std::floor( x[0] ) ); - const double z = x[1]; - if( ieta < 0 || ieta > 1 ) { TF2::RejectPoint(); return 0.; } + const int ieta = static_cast(std::floor(x[0])); + const double z = x[1]; + if (ieta < 0 || ieta > 1) + { + TF2::RejectPoint(); + return 0.; + } return par[ieta + 1] + par[0] * z; } - + //! 1D version used to draw per-eta overlay lines on QA canvas - double linear_function( double* x, double* par ) - { return par[0] * x[0] + par[1]; } - + double linear_function(double* x, double* par) + { + return par[0] * x[0] + par[1]; + } + //! human-readable label for each eta bin - const char* k_eta_labels[2] = { "#eta_{TPC} < 0", "#eta_{TPC} #geq 0" }; - -} - + const char* k_eta_labels[2] = {"#eta_{TPC} < 0", "#eta_{TPC} #geq 0"}; + +} // namespace + //_____________________________________________________________________ -SiliconDriftEvaluator::SiliconDriftEvaluator( const std::string& name ): - SubsysReco( name ) -{} - +SiliconDriftEvaluator::SiliconDriftEvaluator(const std::string& name) + : SubsysReco(name) +{ +} + //_____________________________________________________________________ -int SiliconDriftEvaluator::Init( PHCompositeNode* topNode ) +int SiliconDriftEvaluator::Init(PHCompositeNode* topNode) { // find DST node - PHNodeIterator iter( topNode ); - auto dstNode = dynamic_cast( iter.findFirst( "PHCompositeNode", "DST" ) ); - if( !dstNode ) - { - std::cout << "SiliconDriftEvaluator::Init - DST Node missing" << std::endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - + PHNodeIterator iter(topNode); + auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << "SiliconDriftEvaluator::Init - DST Node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + // get EVAL node - iter = PHNodeIterator( dstNode ); - auto evalNode = dynamic_cast( iter.findFirst( "PHCompositeNode", "EVAL" ) ); - if( !evalNode ) - { - // create - std::cout << "SiliconDriftEvaluator::Init - EVAL node missing - creating" << std::endl; - evalNode = new PHCompositeNode( "EVAL" ); - dstNode->addNode( evalNode ); - } - + iter = PHNodeIterator(dstNode); + auto evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); + if (!evalNode) + { + // create + std::cout << "SiliconDriftEvaluator::Init - EVAL node missing - creating" << std::endl; + evalNode = new PHCompositeNode("EVAL"); + dstNode->addNode(evalNode); + } + // add container to output tree - auto newNode = new PHIODataNode( new Container, "SiliconDriftEvaluator::Container", "PHObject" ); - + auto newNode = new PHIODataNode(new Container, "SiliconDriftEvaluator::Container", "PHObject"); + // overwrite split level for easier offline browsing - newNode->SplitLevel( 99 ); - evalNode->addNode( newNode ); - + newNode->SplitLevel(99); + evalNode->addNode(newNode); + // book 3D accumulator histogram // x = eta bin: 0 = eta<0, 1 = eta>=0 // y = z_si (cm) // z = dz (cm) - m_hist3D = new TH3F("SiliconDriftEval_hist3D",";#eta bin;z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)", 2, 0, 2, 200, -m_max_z, m_max_z, 200, -m_max_dz, m_max_dz ); - m_hist3D->SetDirectory( nullptr ); - + m_hist3D = new TH3F("SiliconDriftEval_hist3D", ";#eta bin;z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)", 2, 0, 2, 200, -m_max_z, m_max_z, 200, -m_max_dz, m_max_dz); + m_hist3D->SetDirectory(nullptr); + return Fun4AllReturnCodes::EVENT_OK; } - + //_____________________________________________________________________ -int SiliconDriftEvaluator::InitRun( PHCompositeNode* topNode ) -{ return load_nodes( topNode ); } - +int SiliconDriftEvaluator::InitRun(PHCompositeNode* topNode) +{ + return load_nodes(topNode); +} + //_____________________________________________________________________ -int SiliconDriftEvaluator::process_event( PHCompositeNode* topNode ) +int SiliconDriftEvaluator::process_event(PHCompositeNode* topNode) { // load nodes - const auto res = load_nodes( topNode ); - if( res != Fun4AllReturnCodes::EVENT_OK ) return res; - + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) return res; + // cleanup output - if( m_container ) m_container->Reset(); - + if (m_container) m_container->Reset(); + evaluate_tracks(); - + return Fun4AllReturnCodes::EVENT_OK; } - + //_____________________________________________________________________ -int SiliconDriftEvaluator::End( PHCompositeNode* ) +int SiliconDriftEvaluator::End(PHCompositeNode*) { - if( !m_hist3D ) - { - std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - - const int nEntries = static_cast( m_hist3D->GetEntries() ); + if (!m_hist3D) + { + std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + const int nEntries = static_cast(m_hist3D->GetEntries()); std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; - + // build mean-dz TH2F via FitSlicesY, one eta bin at a time // x = eta bin [0,2), y = z_si (cm), content = mean dz (cm) - auto h_fit = new TH2F( "h_fit_silicon", "", - 2, 0, 2, - 200, -m_max_z, m_max_z ); - h_fit->SetDirectory( nullptr ); - - for( int ieta = 0; ieta < 2; ++ieta ) + auto h_fit = new TH2F("h_fit_silicon", "", + 2, 0, 2, + 200, -m_max_z, m_max_z); + h_fit->SetDirectory(nullptr); + + for (int ieta = 0; ieta < 2; ++ieta) + { + m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); + auto h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(Form("h2d_etabin_%i", ieta)); + h2d->SetDirectory(nullptr); + + // fit vertical slices; require a minimum of m_min_slice_entries per slice + h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries); + auto h_mean = static_cast(gDirectory->Get(Form("h2d_etabin_%i_1", ieta))); + + if (!h_mean) { - m_hist3D->GetXaxis()->SetRange( ieta + 1, ieta + 1 ); - auto h2d = static_cast( m_hist3D->Project3D( "zy" ) ); - h2d->SetName( Form( "h2d_etabin_%i", ieta ) ); - h2d->SetDirectory( nullptr ); - - // fit vertical slices; require a minimum of m_min_slice_entries per slice - h2d->FitSlicesY( nullptr, 0, -1, m_min_slice_entries ); - auto h_mean = static_cast( gDirectory->Get( Form( "h2d_etabin_%i_1", ieta ) ) ); - - if( !h_mean ) - { - delete h2d; - continue; - } - - for( int iz = 1; iz <= h_mean->GetNbinsX(); ++iz ) - { - const double entries = h2d->Integral( iz, iz, 1, m_hist3D->GetNbinsZ() ); - if( entries > 0 ) - { h_fit->SetBinContent( ieta + 1, iz, h_mean->GetBinContent( iz ) ); } - } - delete h2d; + continue; } - - m_hist3D->GetXaxis()->SetRange( 0, 0 ); - - // 2D piecewise fit: shared slope + per-eta offset - auto fit2d = new TF2( "fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3 ); - for( int i = 0; i < 3; ++i ) fit2d->SetParameter( i, 0.0 ); - h_fit->Fit( fit2d, "0R" ); - - const double slope = fit2d->GetParameter( 0 ); - const double slope_err = fit2d->GetParError( 0 ); - const double off_neg = fit2d->GetParameter( 1 ); // ieta=0, eta<0 - const double off_pos = fit2d->GetParameter( 2 ); // ieta=1, eta>=0 - - const double dv_new = m_drift_velocity / ( 1.0 + slope ); - const double dv_err = m_drift_velocity / std::pow( 1.0 + slope, 2 ) * slope_err; - const double t0_new = ( off_pos - off_neg ) / ( 2.0 * dv_new ); - - std::cout << Name() << "::End" << " slope=" << slope << " dv_in=" << m_drift_velocity << " cm/ns"<< " dv_new="<< dv_new << " +/- " << dv_err << " cm/ns"<< " t0_new=" << t0_new << " ns"<< std::endl; - - // draw the plot - auto canvas = new TCanvas( "silicon_drift_calib", "Silicon drift velocity calibration", 1400, 700 ); - canvas->Divide( 2, 1 ); - - for( int ieta = 0; ieta < 2; ++ieta ) + + for (int iz = 1; iz <= h_mean->GetNbinsX(); ++iz) { - canvas->cd( ieta + 1 ); - gPad->SetTopMargin( 0.13 ); - gPad->SetRightMargin( 0.18 ); - - // 2D distribution for this eta bin - m_hist3D->GetXaxis()->SetRange( ieta + 1, ieta + 1 ); - auto h2d = static_cast( m_hist3D->Project3D( "zy" ) ); - h2d->SetName( Form( "hplot_etabin_%i", ieta ) ); - h2d->SetTitle( ";z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)" ); - h2d->SetStats( 0 ); - h2d->Draw( "COLZ" ); - - // mean-dz points from FitSlicesY - auto h_fit_proj = h_fit->ProjectionY( Form( "h_fit_proj_%i", ieta ), ieta + 1, ieta + 1 ); - h_fit_proj->SetMarkerStyle( 20 ); - h_fit_proj->SetMarkerSize( 0.6 ); - h_fit_proj->SetMarkerColor( kRed ); - h_fit_proj->SetLineColor( kRed ); - h_fit_proj->Draw( "same P" ); - - // 1D fit line for this eta bin - auto f1d = new TF1( Form( "f1d_etabin_%i", ieta ), linear_function, -m_max_z, m_max_z, 2 ); - f1d->SetParameter( 0, slope ); - f1d->SetParameter( 1, ( ieta == 0 ) ? off_neg : off_pos ); - f1d->SetLineColor( kGreen + 2 ); - f1d->SetLineWidth( 2 ); - f1d->Draw( "same" ); - - // reference line at dz = 0 - auto zero = new TLine( -m_max_z, 0, m_max_z, 0 ); - zero->SetLineStyle( 2 ); - zero->SetLineColor( kGray + 1 ); - zero->Draw(); - - auto leg = new TLegend( 0.13, 0.76, 0.82, 0.95 ); - leg->SetBorderSize( 0 ); - leg->SetFillStyle( 0 ); - leg->SetTextSize( 0.033 ); - leg->SetHeader( Form( "%s entries: %i v_{in}=%.4f cm/ns", - k_eta_labels[ieta], nEntries, m_drift_velocity ), "C" ); - leg->AddEntry( h_fit_proj, "Gaussian slice mean", "p" ); - leg->AddEntry( f1d, Form( "slope=%.4f v_{new}=%.4f#pm%.4f cm/ns t_{0}=%.1f ns", slope, dv_new, dv_err, t0_new ), "l" ); - leg->Draw(); + const double entries = h2d->Integral(iz, iz, 1, m_hist3D->GetNbinsZ()); + if (entries > 0) + { + h_fit->SetBinContent(ieta + 1, iz, h_mean->GetBinContent(iz)); + } } - - m_hist3D->GetXaxis()->SetRange( 0, 0 ); - - canvas->SaveAs( m_plot_filename.c_str() ); + + delete h2d; + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + // 2D piecewise fit: shared slope + per-eta offset + auto fit2d = new TF2("fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3); + for (int i = 0; i < 3; ++i) fit2d->SetParameter(i, 0.0); + h_fit->Fit(fit2d, "0R"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double off_neg = fit2d->GetParameter(1); // ieta=0, eta<0 + const double off_pos = fit2d->GetParameter(2); // ieta=1, eta>=0 + + const double dv_new = m_drift_velocity / (1.0 + slope); + const double dv_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + const double t0_new = (off_pos - off_neg) / (2.0 * dv_new); + + std::cout << Name() << "::End" << " slope=" << slope << " dv_in=" << m_drift_velocity << " cm/ns" << " dv_new=" << dv_new << " +/- " << dv_err << " cm/ns" << " t0_new=" << t0_new << " ns" << std::endl; + + // draw the plot + auto canvas = new TCanvas("silicon_drift_calib", "Silicon drift velocity calibration", 1400, 700); + canvas->Divide(2, 1); + + for (int ieta = 0; ieta < 2; ++ieta) + { + canvas->cd(ieta + 1); + gPad->SetTopMargin(0.13); + gPad->SetRightMargin(0.18); + + // 2D distribution for this eta bin + m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); + auto h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(Form("hplot_etabin_%i", ieta)); + h2d->SetTitle(";z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)"); + h2d->SetStats(0); + h2d->Draw("COLZ"); + + // mean-dz points from FitSlicesY + auto h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", ieta), ieta + 1, ieta + 1); + h_fit_proj->SetMarkerStyle(20); + h_fit_proj->SetMarkerSize(0.6); + h_fit_proj->SetMarkerColor(kRed); + h_fit_proj->SetLineColor(kRed); + h_fit_proj->Draw("same P"); + + // 1D fit line for this eta bin + auto f1d = new TF1(Form("f1d_etabin_%i", ieta), linear_function, -m_max_z, m_max_z, 2); + f1d->SetParameter(0, slope); + f1d->SetParameter(1, (ieta == 0) ? off_neg : off_pos); + f1d->SetLineColor(kGreen + 2); + f1d->SetLineWidth(2); + f1d->Draw("same"); + + // reference line at dz = 0 + auto zero = new TLine(-m_max_z, 0, m_max_z, 0); + zero->SetLineStyle(2); + zero->SetLineColor(kGray + 1); + zero->Draw(); + + auto leg = new TLegend(0.13, 0.76, 0.82, 0.95); + leg->SetBorderSize(0); + leg->SetFillStyle(0); + leg->SetTextSize(0.033); + leg->SetHeader(Form("%s entries: %i v_{in}=%.4f cm/ns", + k_eta_labels[ieta], nEntries, m_drift_velocity), + "C"); + leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); + leg->AddEntry(f1d, Form("slope=%.4f v_{new}=%.4f#pm%.4f cm/ns t_{0}=%.1f ns", slope, dv_new, dv_err, t0_new), "l"); + leg->Draw(); + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + canvas->SaveAs(m_plot_filename.c_str()); std::cout << Name() << "::End - QA canvas saved to " << m_plot_filename << std::endl; - + // write histograms, fit and results to a ROOT file - if( !m_root_filename.empty() ) + if (!m_root_filename.empty()) + { + std::unique_ptr outfile(TFile::Open(m_root_filename.c_str(), "RECREATE")); + if (outfile && !outfile->IsZombie()) + { + outfile->cd(); + m_hist3D->Write(); + h_fit->Write("h_fit_silicon"); + fit2d->Write(); + canvas->Write(); + TParameter("slope", slope).Write(); + TParameter("drift_velocity_in", m_drift_velocity).Write(); + TParameter("drift_velocity_new", dv_new).Write(); + TParameter("drift_velocity_err", dv_err).Write(); + TParameter("t0_new", t0_new).Write(); + outfile->Close(); + std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; + } + else { - std::unique_ptr outfile( TFile::Open( m_root_filename.c_str(), "RECREATE" ) ); - if( outfile && !outfile->IsZombie() ) - { - outfile->cd(); - m_hist3D->Write(); - h_fit->Write( "h_fit_silicon" ); - fit2d->Write(); - canvas->Write(); - TParameter( "slope", slope ).Write(); - TParameter( "drift_velocity_in", m_drift_velocity ).Write(); - TParameter( "drift_velocity_new", dv_new ).Write(); - TParameter( "drift_velocity_err", dv_err ).Write(); - TParameter( "t0_new", t0_new ).Write(); - outfile->Close(); - std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; - } - else - { std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; } + std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; } - + } + delete canvas; delete fit2d; delete h_fit; - + return Fun4AllReturnCodes::EVENT_OK; } - + //_____________________________________________________________________ -int SiliconDriftEvaluator::load_nodes( PHCompositeNode* topNode ) +int SiliconDriftEvaluator::load_nodes(PHCompositeNode* topNode) { // track map - m_track_map = findNode::getClass( topNode, m_trackmapname ); - + m_track_map = findNode::getClass(topNode, m_trackmapname); + // local container - m_container = findNode::getClass( topNode, "SiliconDriftEvaluator::Container" ); - assert( m_container ); - + m_container = findNode::getClass(topNode, "SiliconDriftEvaluator::Container"); + assert(m_container); + return Fun4AllReturnCodes::EVENT_OK; } - + //_____________________________________________________________________ void SiliconDriftEvaluator::evaluate_tracks() { - if( !( m_track_map && m_container && m_hist3D ) ) return; - + if (!(m_track_map && m_container && m_hist3D)) return; + // clear array m_container->clearTracks(); - - for( const auto& [track_id, track] : *m_track_map ) + + for (const auto& [track_id, track] : *m_track_map) + { + // require valid beam-crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) { - // require valid beam-crossing - const auto crossing = track->get_crossing(); - if( crossing == SHRT_MAX ) - { - std::cout << "SiliconDriftEvaluator::evaluate_tracks - invalid crossing, track ignored." << std::endl; - continue; - } - - // require both seeds - const auto* si_seed = track->get_silicon_seed(); - const auto* tpc_seed = track->get_tpc_seed(); - if( !si_seed || !tpc_seed ) continue; - - // count clusters per subsystem - unsigned int n_tpc = 0; - unsigned int n_mvtx = 0; - unsigned int n_intt = 0; - - for( const auto* seed : { track->get_silicon_seed(), track->get_tpc_seed() } ) - { - if( !seed ) continue; - for( auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it ) - { - switch( TrkrDefs::getTrkrId( *it ) ) - { - case TrkrDefs::tpcId: ++n_tpc; break; - case TrkrDefs::mvtxId: ++n_mvtx; break; - case TrkrDefs::inttId: ++n_intt; break; - default: break; - } - } - } - - // apply selection cuts - if( n_tpc < m_min_nclusters_tpc ) continue; - if( n_mvtx < m_min_nclusters_mvtx ) continue; - if( n_intt < m_min_nclusters_intt ) continue; - - const float eta = tpc_seed->get_eta(); - if( std::abs( eta ) > m_max_eta ) continue; - - const float pt = get_pt( track->get_px(), track->get_py() ); - if( pt < m_min_pt ) continue; - - // get seed z positions at POCA - const auto si_pos = TrackSeedHelper::get_xyz( si_seed ); - const auto tpc_pos = TrackSeedHelper::get_xyz( tpc_seed ); - - const float z_si = si_pos.z(); - const float z_tpc = tpc_pos.z(); - - // dz = (z_tpc + sign(eta)*crossing*crossing_interval*dv) - z_si - const double sign_eta = ( eta >= 0 ) ? 1.0 : -1.0; - const float z_tpc_corr = z_tpc + sign_eta * crossing * m_crossing_interval * m_drift_velocity; - const float dz = z_tpc_corr - z_si; - - // fill track struct - TrackStruct track_struct; - track_struct._nclusters_mvtx = n_mvtx; - track_struct._nclusters_intt = n_intt; - track_struct._nclusters_tpc = n_tpc; - track_struct._pt = pt; - track_struct._eta = eta; - track_struct._phi = tpc_seed->get_phi(); - track_struct._z_tpc = z_tpc; - track_struct._z_si = z_si; - track_struct._crossing = crossing; - track_struct._dz = dz; - - // fill histogram - // eta bin centre: 0.5 for eta<0, 1.5 for eta>=0 - const double eta_bin = ( eta >= 0 ) ? 1.5 : 0.5; - m_hist3D->Fill( eta_bin, z_si, dz ); - - m_container->addTrack( track_struct ); + std::cout << "SiliconDriftEvaluator::evaluate_tracks - invalid crossing, track ignored." << std::endl; + continue; } + + // require both seeds + const auto* si_seed = track->get_silicon_seed(); + const auto* tpc_seed = track->get_tpc_seed(); + if (!si_seed || !tpc_seed) continue; + + // count clusters per subsystem + unsigned int n_tpc = 0; + unsigned int n_mvtx = 0; + unsigned int n_intt = 0; + + for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (!seed) continue; + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + switch (TrkrDefs::getTrkrId(*it)) + { + case TrkrDefs::tpcId: + ++n_tpc; + break; + case TrkrDefs::mvtxId: + ++n_mvtx; + break; + case TrkrDefs::inttId: + ++n_intt; + break; + default: + break; + } + } + } + + // apply selection cuts + if (n_tpc < m_min_nclusters_tpc) continue; + if (n_mvtx < m_min_nclusters_mvtx) continue; + if (n_intt < m_min_nclusters_intt) continue; + + const float eta = tpc_seed->get_eta(); + if (std::abs(eta) > m_max_eta) continue; + + const float pt = get_pt(track->get_px(), track->get_py()); + if (pt < m_min_pt) continue; + + // get seed z positions at POCA + const auto si_pos = TrackSeedHelper::get_xyz(si_seed); + const auto tpc_pos = TrackSeedHelper::get_xyz(tpc_seed); + + const float z_si = si_pos.z(); + const float z_tpc = tpc_pos.z(); + + // dz = (z_tpc + sign(eta)*crossing*crossing_interval*dv) - z_si + const double sign_eta = (eta >= 0) ? 1.0 : -1.0; + const float z_tpc_corr = z_tpc + sign_eta * crossing * m_crossing_interval * m_drift_velocity; + const float dz = z_tpc_corr - z_si; + + // fill track struct + TrackStruct track_struct; + track_struct._nclusters_mvtx = n_mvtx; + track_struct._nclusters_intt = n_intt; + track_struct._nclusters_tpc = n_tpc; + track_struct._pt = pt; + track_struct._eta = eta; + track_struct._phi = tpc_seed->get_phi(); + track_struct._z_tpc = z_tpc; + track_struct._z_si = z_si; + track_struct._crossing = crossing; + track_struct._dz = dz; + + // fill histogram + // eta bin centre: 0.5 for eta<0, 1.5 for eta>=0 + const double eta_bin = (eta >= 0) ? 1.5 : 0.5; + m_hist3D->Fill(eta_bin, z_si, dz); + + m_container->addTrack(track_struct); + } } \ No newline at end of file diff --git a/offline/packages/tpccalib/SiliconDriftEvaluator.h b/offline/packages/tpccalib/SiliconDriftEvaluator.h index d99e1c7254..2f188e6c39 100644 --- a/offline/packages/tpccalib/SiliconDriftEvaluator.h +++ b/offline/packages/tpccalib/SiliconDriftEvaluator.h @@ -1,207 +1,202 @@ #ifndef G4EVAL_SiliconDriftEvaluator_H #define G4EVAL_SiliconDriftEvaluator_H - + /* * Bade Sayki June 16th, 2026 -- LANL * This module is created to calibrate the drift velocity in the TPC by projecting the silicon seeds and the TPC seeds to the beam axis and calculating the z residuals. * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's TrackingEvaluator_hp module. It is meant to be a more lightweight and specialized version. * Claude tool was used to format and comment this module. */ - + #include #include - + #include #include - + class SvtxTrackMap; class TH2F; class TH3F; - + class SiliconDriftEvaluator : public SubsysReco { - public: - + public: //! constructor - SiliconDriftEvaluator( const std::string& = "SiliconDriftEvaluator" ); - + SiliconDriftEvaluator(const std::string& = "SiliconDriftEvaluator"); + //! global initialization virtual int Init(PHCompositeNode*); - + //! run initialization virtual int InitRun(PHCompositeNode*); - + //! event processing virtual int process_event(PHCompositeNode*); - + //! end of processing virtual int End(PHCompositeNode*); - + // track information stored in the Container class TrackStruct { - public: - + public: using List = std::vector; - - //cluster counts + + // cluster counts unsigned int _nclusters_mvtx = 0; unsigned int _nclusters_intt = 0; - unsigned int _nclusters_tpc = 0; - - - //tpc seed kinematics - float _pt = 0; + unsigned int _nclusters_tpc = 0; + + // tpc seed kinematics + float _pt = 0; float _eta = 0; float _phi = 0; - - //seed z positions - + + // seed z positions + // z position of the TPC seed at the beamline float _z_tpc = 0; - + //! z position of the silicon seed at the beamline - float _z_si = 0; - - + float _z_si = 0; + //! beam-bunch crossing number short int _crossing = 0; - + //! crossing-corrected dz = z_tpc_corr - z_si (cm) float _dz = 0; - }; - + //! track container stored on the node tree class Container : public PHObject { - public: - + public: //! constructor explicit Container() = default; - + //! copy constructor - explicit Container( const Container& ) = delete; - + explicit Container(const Container&) = delete; + //! assignment operator - Container& operator=( const Container& ) = delete; - + Container& operator=(const Container&) = delete; + //! reset void Reset() override - { _tracks.clear(); } - + { + _tracks.clear(); + } + //!@name accessors //@{ - + const TrackStruct::List& tracks() const - { return _tracks; } - - + { + return _tracks; + } + // modifiers - - void addTrack( const TrackStruct& track ) - { _tracks.push_back( track ); } - + + void addTrack(const TrackStruct& track) + { + _tracks.push_back(track); + } + void clearTracks() - { _tracks.clear(); } - - - private: - + { + _tracks.clear(); + } + + private: //! tracks array TrackStruct::List _tracks; - + ClassDefOverride(Container, 1) - }; - + //! track map name - void set_trackmapname( const std::string& value ) { m_trackmapname = value; } - + void set_trackmapname(const std::string& value) { m_trackmapname = value; } + // initial drift velocity (cm/ns); used as starting point for the fit and for the crossing correction - void set_drift_velocity( double value ) { m_drift_velocity = value; } - + void set_drift_velocity(double value) { m_drift_velocity = value; } + // bunch-crossing interval in ns (default: 106.65237 ns) - void set_crossing_interval( double value ) { m_crossing_interval = value; } - + void set_crossing_interval(double value) { m_crossing_interval = value; } + // minimum pT cut on tracks (GeV) - void set_min_pt( double value ) { m_min_pt = value; } - + void set_min_pt(double value) { m_min_pt = value; } + // minimum number of TPC clusters required - void set_min_nclusters_tpc( unsigned int value ) { m_min_nclusters_tpc = value; } - + void set_min_nclusters_tpc(unsigned int value) { m_min_nclusters_tpc = value; } + // minimum number of MVTX clusters required - void set_min_nclusters_mvtx( unsigned int value ) { m_min_nclusters_mvtx = value; } - + void set_min_nclusters_mvtx(unsigned int value) { m_min_nclusters_mvtx = value; } + // minimum number of INTT clusters required - void set_min_nclusters_intt( unsigned int value ) { m_min_nclusters_intt = value; } - + void set_min_nclusters_intt(unsigned int value) { m_min_nclusters_intt = value; } + // maximum abs(eta) of TPC seed accepted - void set_max_eta( double value ) { m_max_eta = value; } - + void set_max_eta(double value) { m_max_eta = value; } + // half-range of the z_si histogram axis (cm) - void set_max_z( double value ) { m_max_z = value; } - + void set_max_z(double value) { m_max_z = value; } + // half-range of the dz histogram axis (cm) - void set_max_dz( double value ) { m_max_dz = value; } - + void set_max_dz(double value) { m_max_dz = value; } + //! minimum entries per z slice required by FitSlicesY - void set_min_slice_entries( int value ) { m_min_slice_entries = value; } - - // output drift plot filename. Do this in your macro. - void set_plot_filename( const std::string& value ) { m_plot_filename = value; } - - // output ROOT filename for histograms and fit results. Do this in your macro. - void set_root_filename( const std::string& value ) { m_root_filename = value; } - - private: - + void set_min_slice_entries(int value) { m_min_slice_entries = value; } + + // output drift plot filename. Do this in your macro. + void set_plot_filename(const std::string& value) { m_plot_filename = value; } + + // output ROOT filename for histograms and fit results. Do this in your macro. + void set_root_filename(const std::string& value) { m_root_filename = value; } + + private: //! load nodes - int load_nodes( PHCompositeNode* ); - + int load_nodes(PHCompositeNode*); + //! evaluate tracks void evaluate_tracks(); - + //! evaluation node Container* m_container = nullptr; - + //! track map SvtxTrackMap* m_track_map = nullptr; - + //! 3D accumulator histogram: x = eta bin [2], y = z_si, z = dz TH3F* m_hist3D = nullptr; - + //! track map name std::string m_trackmapname = "SvtxTrackMap"; - + //! initial drift velocity (cm/ns) double m_drift_velocity = 0.00747; - + //! bunch-crossing interval (ns) double m_crossing_interval = 106.65237; - + // track selection cuts - - double m_min_pt = 0.5; - unsigned int m_min_nclusters_tpc = 20; + + double m_min_pt = 0.5; + unsigned int m_min_nclusters_tpc = 20; unsigned int m_min_nclusters_mvtx = 3; unsigned int m_min_nclusters_intt = 2; - double m_max_eta = 0.9; - - + double m_max_eta = 0.9; + //! histogram range - double m_max_z = 20.0; + double m_max_z = 20.0; double m_max_dz = 10.0; - + //! minimum entries per z slice for FitSlicesY int m_min_slice_entries = 10; - + //! output QA plot filename std::string m_plot_filename = "silicon_drift_calib.png"; - + //! output ROOT filename for histograms and fit results std::string m_root_filename = "silicon_drift_calib.root"; - }; - + #endif // G4EVAL_SiliconDriftEvaluator_H \ No newline at end of file From fb735edefdf32f8bf6a595d8bb28bdd4c6acb2ae Mon Sep 17 00:00:00 2001 From: xyu3 Date: Tue, 21 Jul 2026 00:16:48 -0400 Subject: [PATCH 839/866] add charged geantino ionization module --- .../g4simulation/g4detectors/Makefile.am | 2 + .../g4detectors/PHG4GeantinoIonization.cc | 178 ++++++++++++++++++ .../g4detectors/PHG4GeantinoIonization.h | 81 ++++++++ 3 files changed, 261 insertions(+) create mode 100644 simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc create mode 100644 simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h diff --git a/simulation/g4simulation/g4detectors/Makefile.am b/simulation/g4simulation/g4detectors/Makefile.am index acff3e0c83..6035683444 100644 --- a/simulation/g4simulation/g4detectors/Makefile.am +++ b/simulation/g4simulation/g4detectors/Makefile.am @@ -79,6 +79,7 @@ pkginclude_HEADERS = \ PHG4DetectorSubsystem.h \ PHG4DetectorGroupSubsystem.h \ PHG4FullProjSpacalCellReco.h \ + PHG4GeantinoIonization.h \ PHG4GDMLSubsystem.h \ PHG4HcalDefs.h \ PHG4HcalCellReco.h \ @@ -222,6 +223,7 @@ libg4detectors_la_SOURCES = \ PHG4FullProjSpacalDetector.cc \ PHG4FullProjTiltedSpacalDetector.cc \ PHG4FullProjSpacalCellReco.cc \ + PHG4GeantinoIonization.cc \ PHG4GenHit.cc \ PHG4HcalCellReco.cc \ PHG4HcalDetector.cc \ diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc new file mode 100644 index 0000000000..c262d3bfc9 --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc @@ -0,0 +1,178 @@ +#include "PHG4GeantinoIonization.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +namespace +{ + // Silicon MIP stopping power used by the INTT digitizer. + constexpr double siliconMipDedx = 0.003876; // GeV/cm + + // Mean MIP stopping power for the default TPC gas mixture + // Ar/CF4/isobutane = 75/20/5. + constexpr double tpcMipDedx = + (0.75 * 2.44 + 0.20 * 7.00 + 0.05 * 5.93) * 1e-6; // GeV/cm + + // Mean MIP stopping power for the default Micromegas gas mixture + // Ar/isobutane = 90/10. + constexpr double micromegasMipDedx = + (0.90 * 2.44 + 0.10 * 5.93) * 1e-6; // GeV/cm +} // namespace + +PHG4GeantinoIonization::PHG4GeantinoIonization(const std::string& name) + : SubsysReco(name) + , m_detectorConfigs{{ + {"MVTX", "G4HIT_MVTX", siliconMipDedx, true}, + {"INTT", "G4HIT_INTT", siliconMipDedx, true}, + {"TPC", "G4HIT_TPC", tpcMipDedx, true}, + {"MICROMEGAS", "G4HIT_MICROMEGAS", micromegasMipDedx, true}}} +{ +} + +void PHG4GeantinoIonization::set_tpc_gas_fractions( + const double neon, + const double argon, + const double cf4, + const double nitrogen, + const double isobutane) +{ + // Keep these values synchronized with PHG4TpcElectronDrift. With + // eion = * path length, its electrons-per-GeV conversion gives + // the corresponding mean number of primary electrons for this mixture. + constexpr double neonMipDedx = 1.56; // keV/cm + constexpr double argonMipDedx = 2.44; // keV/cm + constexpr double cf4MipDedx = 7.00; // keV/cm + constexpr double nitrogenMipDedx = 2.127; // keV/cm + constexpr double isobutaneMipDedx = 5.93; // keV/cm + + m_detectorConfigs[2].mipDedx = + (neon * neonMipDedx + argon * argonMipDedx + cf4 * cf4MipDedx + + nitrogen * nitrogenMipDedx + isobutane * isobutaneMipDedx) * + 1e-6; +} + +int PHG4GeantinoIonization::process_event(PHCompositeNode* topNode) +{ + const auto* truthInfo = + findNode::getClass(topNode, "G4TruthInfo"); + if (!truthInfo) + { + std::cout << PHWHERE << " Missing G4TruthInfo" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + for (const auto& config : m_detectorConfigs) + { + if (!config.enabled) + { + continue; + } + + auto* hits = + findNode::getClass(topNode, config.hitNodeName); + if (!hits) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Missing optional node " + << config.hitNodeName << std::endl; + } + continue; + } + + const auto counters = process_detector(hits, truthInfo, config); + if (Verbosity() > 0) + { + std::cout << Name() << " " << config.name + << ": inspected " << counters.inspected + << ", modified " << counters.modified + << ", missing particle " << counters.missingParticle + << ", invalid path " << counters.invalidPath + << std::endl; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +PHG4GeantinoIonization::DetectorCounters +PHG4GeantinoIonization::process_detector( + PHG4HitContainer* hits, + const PHG4TruthInfoContainer* truthInfo, + const DetectorConfig& config) const +{ + DetectorCounters counters; + const auto hitRange = hits->getHits(); + for (auto hitIter = hitRange.first; hitIter != hitRange.second; ++hitIter) + { + auto* hit = hitIter->second; + if (!hit) + { + continue; + } + + ++counters.inspected; + + const auto* particle = truthInfo->GetParticle(hit->get_trkid()); + if (!particle) + { + ++counters.missingParticle; + continue; + } + + if (particle->get_name() != m_particleName) + { + continue; + } + + // Keep the operation idempotent. Current stepping actions store negative + // edep/eion sentinels for geantinos. A finite nonnegative value means this + // hit has already been processed. + const double edep = hit->get_edep(); + const double eion = hit->get_eion(); + if (std::isfinite(edep) && edep >= 0 && + std::isfinite(eion) && eion >= 0) + { + continue; + } + + const double dx = hit->get_x(1) - hit->get_x(0); + const double dy = hit->get_y(1) - hit->get_y(0); + const double dz = hit->get_z(1) - hit->get_z(0); + const double pathLength = std::sqrt(dx * dx + dy * dy + dz * dz); + + if (!std::isfinite(pathLength) || pathLength <= 0 || + !std::isfinite(config.mipDedx) || config.mipDedx <= 0) + { + ++counters.invalidPath; + continue; + } + + const double syntheticIonization = config.mipDedx * pathLength; + hit->set_edep(syntheticIonization); + hit->set_eion(syntheticIonization); + ++counters.modified; + + if (Verbosity() > 2) + { + std::cout << Name() << " " << config.name + << " hit " << hitIter->first + << " track " << hit->get_trkid() + << " path length " << pathLength << " cm" + << " synthetic edep/eion " << syntheticIonization << " GeV" + << std::endl; + } + } + + return counters; +} diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h new file mode 100644 index 0000000000..9d40a89829 --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h @@ -0,0 +1,81 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef G4DETECTORS_PHG4GEANTINOIONIZATION_H +#define G4DETECTORS_PHG4GEANTINOIONIZATION_H + +#include + +#include +#include +#include + +class PHCompositeNode; +class PHG4HitContainer; +class PHG4TruthInfoContainer; + +/** + * Replaces the negative energy-deposition sentinel stored for charged + * geantinos with a detector-dependent mean MIP ionization. + * + * This module must run after G4HIT_* nodes are loaded and before detector hit + * reconstruction. It intentionally models only the mean energy deposition; + * downstream detector modules retain their existing fluctuations. + */ +class PHG4GeantinoIonization : public SubsysReco +{ + public: + explicit PHG4GeantinoIonization(const std::string& name = "PHG4GeantinoIonization"); + ~PHG4GeantinoIonization() override = default; + + int process_event(PHCompositeNode* topNode) override; + + void set_particle_name(const std::string& name) { m_particleName = name; } + + void set_mvtx_enabled(bool value) { m_detectorConfigs[0].enabled = value; } + void set_intt_enabled(bool value) { m_detectorConfigs[1].enabled = value; } + void set_tpc_enabled(bool value) { m_detectorConfigs[2].enabled = value; } + void set_micromegas_enabled(bool value) { m_detectorConfigs[3].enabled = value; } + + void set_mvtx_mip_dedx(double value) { m_detectorConfigs[0].mipDedx = value; } + void set_intt_mip_dedx(double value) { m_detectorConfigs[1].mipDedx = value; } + void set_tpc_mip_dedx(double value) { m_detectorConfigs[2].mipDedx = value; } + void set_micromegas_mip_dedx(double value) { m_detectorConfigs[3].mipDedx = value; } + + /** + * Configure the TPC mean MIP stopping power from the same gas fractions + * passed to PHG4TpcElectronDrift. Fractions are expected to sum to one. + */ + void set_tpc_gas_fractions( + double neon, + double argon, + double cf4, + double nitrogen, + double isobutane); + + private: + struct DetectorConfig + { + std::string name; + std::string hitNodeName; + double mipDedx = 0; // GeV/cm + bool enabled = true; + }; + + struct DetectorCounters + { + std::size_t inspected = 0; + std::size_t modified = 0; + std::size_t missingParticle = 0; + std::size_t invalidPath = 0; + }; + + DetectorCounters process_detector( + PHG4HitContainer* hits, + const PHG4TruthInfoContainer* truthInfo, + const DetectorConfig& config) const; + + std::array m_detectorConfigs; + std::string m_particleName = "chargedgeantino"; +}; + +#endif // G4DETECTORS_PHG4GEANTINOIONIZATION_H From c7e46c64237e31a770dfa458778f8c76115df59b Mon Sep 17 00:00:00 2001 From: xyu3 Date: Tue, 21 Jul 2026 03:00:00 -0400 Subject: [PATCH 840/866] update PHG4GeantinoIonization --- .../g4detectors/PHG4GeantinoIonization.cc | 161 ++++++++++++------ .../g4detectors/PHG4GeantinoIonization.h | 42 +++-- 2 files changed, 133 insertions(+), 70 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc index c262d3bfc9..3c5aa88e07 100644 --- a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc @@ -11,32 +11,65 @@ #include #include +#include #include namespace { - // Silicon MIP stopping power used by the INTT digitizer. - constexpr double siliconMipDedx = 0.003876; // GeV/cm - - // Mean MIP stopping power for the default TPC gas mixture - // Ar/CF4/isobutane = 75/20/5. - constexpr double tpcMipDedx = - (0.75 * 2.44 + 0.20 * 7.00 + 0.05 * 5.93) * 1e-6; // GeV/cm - - // Mean MIP stopping power for the default Micromegas gas mixture - // Ar/isobutane = 90/10. - constexpr double micromegasMipDedx = - (0.90 * 2.44 + 0.10 * 5.93) * 1e-6; // GeV/cm + struct GasFractions + { + double neon = 0; + double argon = 0; + double cf4 = 0; + double nitrogen = 0; + double isobutane = 0; + }; + + // Pure-gas MIP stopping powers in keV/cm. They match the values used by + // the current TPC and Micromegas hit-reconstruction modules. + constexpr double neonMipDedx = 1.56; + constexpr double argonMipDedx = 2.44; + constexpr double cf4MipDedx = 7.00; + constexpr double nitrogenMipDedx = 2.127; + constexpr double isobutaneMipDedx = 5.93; + + // Mean silicon MIP stopping powers in GeV/cm. The MVTX value corresponds + // to 9.6 keV in 25 microns; the INTT value is the value documented by its + // hit reconstruction. + double mvtxMipDedx = 0.00384; + double inttMipDedx = 0.00387; + + GasFractions tpcGasFractions{0.00, 0.75, 0.20, 0.00, 0.05}; + GasFractions tpotGasFractions{0.00, 0.90, 0.00, 0.00, 0.10}; + + double calculateMipDedx(const GasFractions& fractions) + { + return fractions.neon * neonMipDedx + + fractions.argon * argonMipDedx + + fractions.cf4 * cf4MipDedx + + fractions.nitrogen * nitrogenMipDedx + + fractions.isobutane * isobutaneMipDedx; + } } // namespace PHG4GeantinoIonization::PHG4GeantinoIonization(const std::string& name) : SubsysReco(name) , m_detectorConfigs{{ - {"MVTX", "G4HIT_MVTX", siliconMipDedx, true}, - {"INTT", "G4HIT_INTT", siliconMipDedx, true}, - {"TPC", "G4HIT_TPC", tpcMipDedx, true}, - {"MICROMEGAS", "G4HIT_MICROMEGAS", micromegasMipDedx, true}}} + {DetectorId::mvtx, "MVTX", "G4HIT_MVTX", true}, + {DetectorId::intt, "INTT", "G4HIT_INTT", true}, + {DetectorId::tpc, "TPC", "G4HIT_TPC", true}, + {DetectorId::tpot, "MICROMEGAS", "G4HIT_MICROMEGAS", true}}} +{ +} + +void PHG4GeantinoIonization::set_mvtx_mip_dedx(const double value) { + mvtxMipDedx = value; +} + +void PHG4GeantinoIonization::set_intt_mip_dedx(const double value) +{ + inttMipDedx = value; } void PHG4GeantinoIonization::set_tpc_gas_fractions( @@ -46,25 +79,39 @@ void PHG4GeantinoIonization::set_tpc_gas_fractions( const double nitrogen, const double isobutane) { - // Keep these values synchronized with PHG4TpcElectronDrift. With - // eion = * path length, its electrons-per-GeV conversion gives - // the corresponding mean number of primary electrons for this mixture. - constexpr double neonMipDedx = 1.56; // keV/cm - constexpr double argonMipDedx = 2.44; // keV/cm - constexpr double cf4MipDedx = 7.00; // keV/cm - constexpr double nitrogenMipDedx = 2.127; // keV/cm - constexpr double isobutaneMipDedx = 5.93; // keV/cm - - m_detectorConfigs[2].mipDedx = - (neon * neonMipDedx + argon * argonMipDedx + cf4 * cf4MipDedx + - nitrogen * nitrogenMipDedx + isobutane * isobutaneMipDedx) * - 1e-6; + tpcGasFractions = {neon, argon, cf4, nitrogen, isobutane}; +} + +void PHG4GeantinoIonization::set_tpot_gas_fractions( + const double neon, + const double argon, + const double cf4, + const double nitrogen, + const double isobutane) +{ + tpotGasFractions = {neon, argon, cf4, nitrogen, isobutane}; +} + +double PHG4GeantinoIonization::mip_dedx(const DetectorId detector) +{ + switch (detector) + { + case DetectorId::mvtx: + return mvtxMipDedx; + case DetectorId::intt: + return inttMipDedx; + case DetectorId::tpc: + return 1e-6 * calculateMipDedx(tpcGasFractions); + case DetectorId::tpot: + return 1e-6 * calculateMipDedx(tpotGasFractions); + } + + return 0; } int PHG4GeantinoIonization::process_event(PHCompositeNode* topNode) { - const auto* truthInfo = - findNode::getClass(topNode, "G4TruthInfo"); + const auto* truthInfo = findNode::getClass(topNode, "G4TruthInfo"); if (!truthInfo) { std::cout << PHWHERE << " Missing G4TruthInfo" << std::endl; @@ -78,8 +125,7 @@ int PHG4GeantinoIonization::process_event(PHCompositeNode* topNode) continue; } - auto* hits = - findNode::getClass(topNode, config.hitNodeName); + auto* hits = findNode::getClass(topNode, config.hitNodeName); if (!hits) { if (Verbosity() > 1) @@ -90,28 +136,22 @@ int PHG4GeantinoIonization::process_event(PHCompositeNode* topNode) continue; } - const auto counters = process_detector(hits, truthInfo, config); - if (Verbosity() > 0) - { - std::cout << Name() << " " << config.name - << ": inspected " << counters.inspected - << ", modified " << counters.modified - << ", missing particle " << counters.missingParticle - << ", invalid path " << counters.invalidPath - << std::endl; - } + process_detector(hits, truthInfo, config); } return Fun4AllReturnCodes::EVENT_OK; } -PHG4GeantinoIonization::DetectorCounters -PHG4GeantinoIonization::process_detector( +void PHG4GeantinoIonization::process_detector( PHG4HitContainer* hits, const PHG4TruthInfoContainer* truthInfo, const DetectorConfig& config) const { - DetectorCounters counters; + std::size_t inspected = 0; + std::size_t modified = 0; + std::size_t missingParticle = 0; + std::size_t invalidPath = 0; + const auto hitRange = hits->getHits(); for (auto hitIter = hitRange.first; hitIter != hitRange.second; ++hitIter) { @@ -121,12 +161,12 @@ PHG4GeantinoIonization::process_detector( continue; } - ++counters.inspected; + ++inspected; const auto* particle = truthInfo->GetParticle(hit->get_trkid()); if (!particle) { - ++counters.missingParticle; + ++missingParticle; continue; } @@ -151,17 +191,19 @@ PHG4GeantinoIonization::process_detector( const double dz = hit->get_z(1) - hit->get_z(0); const double pathLength = std::sqrt(dx * dx + dy * dy + dz * dz); + const double mipDedx = mip_dedx(config.detector); if (!std::isfinite(pathLength) || pathLength <= 0 || - !std::isfinite(config.mipDedx) || config.mipDedx <= 0) + !std::isfinite(mipDedx) || mipDedx <= 0) { - ++counters.invalidPath; + ++invalidPath; continue; } - const double syntheticIonization = config.mipDedx * pathLength; - hit->set_edep(syntheticIonization); + const double syntheticEnergyDeposit = mipDedx * pathLength; + const double syntheticIonization = syntheticEnergyDeposit; + hit->set_edep(syntheticEnergyDeposit); hit->set_eion(syntheticIonization); - ++counters.modified; + ++modified; if (Verbosity() > 2) { @@ -169,10 +211,19 @@ PHG4GeantinoIonization::process_detector( << " hit " << hitIter->first << " track " << hit->get_trkid() << " path length " << pathLength << " cm" - << " synthetic edep/eion " << syntheticIonization << " GeV" + << " synthetic edep " << syntheticEnergyDeposit << " GeV" + << ", eion " << syntheticIonization << " GeV" << std::endl; } } - return counters; + if (Verbosity() > 0) + { + std::cout << Name() << " " << config.name + << ": inspected " << inspected + << ", modified " << modified + << ", missing particle " << missingParticle + << ", invalid path " << invalidPath + << std::endl; + } } diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h index 9d40a89829..8b4ea08656 100644 --- a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h @@ -6,7 +6,6 @@ #include #include -#include #include class PHCompositeNode; @@ -35,11 +34,10 @@ class PHG4GeantinoIonization : public SubsysReco void set_intt_enabled(bool value) { m_detectorConfigs[1].enabled = value; } void set_tpc_enabled(bool value) { m_detectorConfigs[2].enabled = value; } void set_micromegas_enabled(bool value) { m_detectorConfigs[3].enabled = value; } + void set_tpot_enabled(bool value) { set_micromegas_enabled(value); } - void set_mvtx_mip_dedx(double value) { m_detectorConfigs[0].mipDedx = value; } - void set_intt_mip_dedx(double value) { m_detectorConfigs[1].mipDedx = value; } - void set_tpc_mip_dedx(double value) { m_detectorConfigs[2].mipDedx = value; } - void set_micromegas_mip_dedx(double value) { m_detectorConfigs[3].mipDedx = value; } + void set_mvtx_mip_dedx(double value); + void set_intt_mip_dedx(double value); /** * Configure the TPC mean MIP stopping power from the same gas fractions @@ -52,28 +50,42 @@ class PHG4GeantinoIonization : public SubsysReco double nitrogen, double isobutane); + void set_tpot_gas_fractions( + double neon, + double argon, + double cf4, + double nitrogen, + double isobutane); + + void set_tpot_gas_fractions(double argon, double isobutane) + { + set_tpot_gas_fractions(0, argon, 0, 0, isobutane); + } + private: + enum class DetectorId + { + mvtx, + intt, + tpc, + tpot + }; + struct DetectorConfig { + DetectorId detector; std::string name; std::string hitNodeName; - double mipDedx = 0; // GeV/cm bool enabled = true; }; - struct DetectorCounters - { - std::size_t inspected = 0; - std::size_t modified = 0; - std::size_t missingParticle = 0; - std::size_t invalidPath = 0; - }; - - DetectorCounters process_detector( + void process_detector( PHG4HitContainer* hits, const PHG4TruthInfoContainer* truthInfo, const DetectorConfig& config) const; + static double mip_dedx(DetectorId detector); + std::array m_detectorConfigs; std::string m_particleName = "chargedgeantino"; }; From b3bf24a11e6d158803ed267360c9067e1e937dd1 Mon Sep 17 00:00:00 2001 From: xyu3 Date: Tue, 21 Jul 2026 10:20:20 -0400 Subject: [PATCH 841/866] ACTS fitter fix for an empty material map --- offline/packages/trackreco/PHActsTrkFitter.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 4738725af7..be0d0c14f4 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -620,6 +620,13 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } } } + // With an empty ACTS material map, m_materialSurfaces is empty. + // Use the measurement surfaces directly for directed navigation. + if (surfaces.empty()) + { + surfaces = surfaces_tmp; + } + checkSurfaceVec(surfaces); if (Verbosity() > 1) { @@ -1014,6 +1021,11 @@ SurfacePtrVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const { + if (surfaces.size() < 2) + { + return; + } + // Do not assume volume id has the correct layer, check the surface radius for (unsigned int i = 0; i < surfaces.size() - 1; i++) @@ -1027,7 +1039,7 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const const auto* nextSurface = surfaces.at(i + 1); const auto nextVolume = nextSurface->geometryId().volume(); - const Acts::Vector3 next_center = surface->center(m_tGeometry->geometry().getGeoContext()); + const Acts::Vector3 next_center = nextSurface->center(m_tGeometry->geometry().getGeoContext()); double nextRadius = sqrt(next_center.x()*next_center.x()+next_center.y()*next_center.y()); /// Implement a check to ensure surfaces are sorted From 42f042693f71acbcd49bd7890415f889accbb5c6 Mon Sep 17 00:00:00 2001 From: Nikhil Kumar Date: Tue, 21 Jul 2026 12:31:31 -0400 Subject: [PATCH 842/866] Relax missing tower handling in CaloStatusSkimmer Update CaloStatusSkimmer for recent DST content changes by treating missing sEPD/ZDC tower nodes as non-fatal and suppressing repeated warning spam after the first message. The ZDC logic now safely guards tower access when the node is absent. This also removes the missing-node event counter and corresponding QA histogram bin/output. --- .../CaloStatusSkimmer/CaloStatusSkimmer.cc | 71 +++++++++---------- .../CaloStatusSkimmer/CaloStatusSkimmer.h | 4 +- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc index 669d678c6d..d146ccc9e6 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -44,14 +44,13 @@ int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) h_ZDC_nTowers_notinstr = new TH1F("h_ZDC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in ZDC; nNotInstrTowers; Counts", 53, -0.5, 52.5); h_ZDC_nTowers_notinstr->SetDirectory(nullptr); - h_calo_nEvents = new TH1F("h_calo_nEvents", "Number of events", 7, 0.5, 7.5); + h_calo_nEvents = new TH1F("h_calo_nEvents", "Number of events", 6, 0.5, 6.5); h_calo_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); h_calo_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); h_calo_nEvents->GetXaxis()->SetBinLabel(3, "EMCal above not-instr threshold"); h_calo_nEvents->GetXaxis()->SetBinLabel(4, "HCal above not-instr threshold"); h_calo_nEvents->GetXaxis()->SetBinLabel(5, "sEPD above not-instr threshold"); h_calo_nEvents->GetXaxis()->SetBinLabel(6, "ZDC above not-instr threshold"); - h_calo_nEvents->GetXaxis()->SetBinLabel(7, "No TowerInfo nodes found"); h_calo_nEvents->SetDirectory(nullptr); hm->registerHisto(h_calo_nEvents); @@ -77,11 +76,9 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) if (m_EMC_skim_threshold > 0) { - TowerInfoContainer *towers = - findNode::getClass(topNode, "TOWERS_CEMC"); + TowerInfoContainer *towers = findNode::getClass(topNode, "TOWERS_CEMC"); if (!towers) { - n_notowernodecounter++; if (Verbosity() > 0) { std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_CEMC" << std::endl; @@ -119,7 +116,6 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) TowerInfoContainer *hcalout_towers = findNode::getClass(topNode, "TOWERS_HCALOUT"); if (!hcalin_towers || !hcalout_towers) { - n_notowernodecounter++; if (Verbosity() > 0) { std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT" << std::endl; @@ -165,16 +161,18 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) } } + // special handling of the sEPD and ZDC because of DST format changes. + if (m_sEPD_skim_threshold > 0) { - TowerInfoContainer *sepd_towers = - findNode::getClass(topNode, "TOWERS_SEPD"); + TowerInfoContainer *sepd_towers = findNode::getClass(topNode, "TOWERS_SEPD"); + if (!sepd_towers) { - n_notowernodecounter++; - if (Verbosity() > 0) + if (Verbosity() > 0 && !b_printed_missing_sEPD_towers) { - std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_SEPD" << std::endl; + b_printed_missing_sEPD_towers = true; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_SEPD. Further warnings will be suppressed." << std::endl; } // Temporarily turned off the event abort because the sEPD towers were removed from calofitting dsts. // return Fun4AllReturnCodes::ABORTEVENT; @@ -210,40 +208,43 @@ int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) if (m_ZDC_skim_threshold > 0) { - TowerInfoContainer *zdc_towers = - findNode::getClass(topNode, "TOWERS_ZDC"); + TowerInfoContainer *zdc_towers = findNode::getClass(topNode, "TOWERS_ZDC"); if (!zdc_towers) { - n_notowernodecounter++; - if (Verbosity() > 0) + if (Verbosity() > 0 && !b_printed_missing_ZDC_towers) { - std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_ZDC" << std::endl; + b_printed_missing_ZDC_towers = true; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_ZDC. Further warnings will be suppressed." << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + // Temporarily turned off the event abort because the ZDC towers were removed from calofitting dsts. + // return Fun4AllReturnCodes::ABORTEVENT; } - const uint32_t ntowers = zdc_towers->size(); - for (uint32_t ch = 0; ch < ntowers; ++ch) + if (zdc_towers) { - TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); - if (tower->get_isNotInstr()) + const uint32_t ntowers = zdc_towers->size(); + for (uint32_t ch = 0; ch < ntowers; ++ch) { - ++notinstr_ZDC; + TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_ZDC; + } } - } - if (Verbosity() > 9) - { - std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_ZDC << std::endl; - } + if (Verbosity() > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_ZDC << std::endl; + } - if (b_produce_QA_histograms) - { - h_ZDC_nTowers_notinstr->Fill(notinstr_ZDC); - } + if (b_produce_QA_histograms) + { + h_ZDC_nTowers_notinstr->Fill(notinstr_ZDC); + } - if (notinstr_ZDC >= m_ZDC_skim_threshold) - { - ZDC_skim_count++; + if (notinstr_ZDC >= m_ZDC_skim_threshold) + { + ZDC_skim_count++; + } } } @@ -263,7 +264,6 @@ int CaloStatusSkimmer::End([[maybe_unused]] PHCompositeNode *topNode) std::cout << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." << std::endl; std::cout << "CaloStatusSkimmer::End Total events processed: " << n_eventcounter << std::endl; std::cout << "CaloStatusSkimmer::End Total events skimmed: " << n_skimcounter << std::endl; - std::cout << "CaloStatusSkimmer::End Total events with missing tower nodes: " << n_notowernodecounter << std::endl; if (b_produce_QA_histograms) { @@ -273,7 +273,6 @@ int CaloStatusSkimmer::End([[maybe_unused]] PHCompositeNode *topNode) h_calo_nEvents->SetBinContent(4, HCal_skim_count); h_calo_nEvents->SetBinContent(5, sEPD_skim_count); h_calo_nEvents->SetBinContent(6, ZDC_skim_count); - h_calo_nEvents->SetBinContent(7, n_notowernodecounter); } return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h index bc684efc79..305da1c47a 100644 --- a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -57,7 +57,6 @@ class CaloStatusSkimmer : public SubsysReco { private: uint32_t n_eventcounter{0}; uint32_t n_skimcounter{0}; - uint32_t n_notowernodecounter{0}; bool b_produce_QA_histograms{false}; @@ -90,6 +89,9 @@ class CaloStatusSkimmer : public SubsysReco { //Event counter histograms TH1* h_calo_nEvents = nullptr; + // print out the missing sEPD and ZDC towers only Once. + bool b_printed_missing_sEPD_towers = false; + bool b_printed_missing_ZDC_towers = false; }; #endif // CALOSTATUSSKIMMER_H From 76103a17add663fb6909a14a5d848958984a628b Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 21 Jul 2026 13:52:18 -0400 Subject: [PATCH 843/866] clang-tidy fixes --- offline/packages/tpc/LaserClusterHelper.cc | 19 +++++++++++++------ .../packages/tpccalib/TpcLaminationFitting.cc | 12 ++++++++---- .../packages/tpccalib/TpcLaminationFitting.h | 13 +++++-------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/offline/packages/tpc/LaserClusterHelper.cc b/offline/packages/tpc/LaserClusterHelper.cc index 54aded41de..ec9afa36cd 100644 --- a/offline/packages/tpc/LaserClusterHelper.cc +++ b/offline/packages/tpc/LaserClusterHelper.cc @@ -14,6 +14,13 @@ #include #include +namespace +{ + Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); +} + //____________________________________________________________________________ void LaserClusterHelper::loadNodes(PHCompositeNode* topNode) { @@ -33,9 +40,9 @@ void LaserClusterHelper::loadNodes(PHCompositeNode* topNode) //____________________________________________________________________________ Acts::Vector3 LaserClusterHelper::getHitGlobalPosition(TrkrDefs::hitsetkey hitsetkey, TrkrDefs::hitkey hitkey) const { - const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN()); + //const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN()); if(!m_tGeometry || !m_geom_container) { @@ -82,9 +89,9 @@ Acts::Vector3 LaserClusterHelper::getHitGlobalPosition(TrkrDefs::hitsetkey hitse //____________________________________________________________________________ Acts::Vector3 LaserClusterHelper::getClusterCentroid(LaserCluster* cluster) const { - const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN()); + //const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN()); if(!cluster) { diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 3658ea6309..9f3bf2c47e 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -76,7 +76,7 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) //m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;A (asymptote);C (decay constant)") %(s == 1 ? "North" : "South")).str().c_str(), 101, -1.005, 0.005, 101, -0.0025, 0.5025); - clusterMap[s] = new TH2D((boost::format("clusterMap_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s;#phi;R [cm]") %(s == 1 ? "North" : "South")).str().c_str(), 2000, 0.0, 2*TMath::Pi(), 2000, 28, 80); + clusterMap[s] = new TH2D((boost::format("clusterMap_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s;#phi;R [cm]") %(s == 1 ? "North" : "South")).str().c_str(), 20000, 0.0, 2*TMath::Pi(), 2000, 28, 80); for (int l = 0; l < 18; l++) { @@ -316,6 +316,8 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) const auto &[cmkey, cmclus_orig] = *cmitr; LaserCluster *cmclus = cmclus_orig; + if(cmclus->getNLayers() <= m_nLayerCut) continue; + bool side = (bool) TpcDefs::getSide(cmkey); double weight = 1.0; if(m_adcWeight) @@ -409,7 +411,6 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) if(cmclus->getNLayers() > m_nLayerCut && (!m_useSDLayerCut || cmclus->getSDWeightedLayer() > 0.5)) { - clusterMap[side]->Fill(tmp_pos.Phi(), tmp_pos.Perp(), weight); for (int l = 0; l < 18; l++) { double shift = m_laminationIdeal[l][side]; @@ -435,12 +436,15 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) { continue; } - + double phi2pimod = tmp_pos.Phi(); if (phi2pimod < 0.0) { phi2pimod += 2 * M_PI; } + + clusterMap[side]->Fill(phi2pimod, tmp_pos.Perp(), weight); + while(side && phi2pimod > M_PI / 9) { phi2pimod -= M_PI / 9; @@ -1161,7 +1165,6 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) for(int s=0; s<2; s++) { - clusterMap[s]->Write(); for(int l=0; l<18; l++) { m_side = s; @@ -1198,6 +1201,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) outputfile->cd(); for (int s = 0; s < 2; s++) { + clusterMap[s]->Write(); for (const auto &h : {m_dcc_out->m_hDRint[s], m_dcc_out->m_hDPint[s], m_dcc_out->m_hDZint[s], m_dcc_out->m_hentries[s]}) { if (h) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 92d813d3ca..0a68a10afa 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -2,14 +2,14 @@ #define TPCCALIB_TPCLAMINATIONFITTING_H -#include -#include +//#include +//#include #include #include #include -#include +//#include #include #include @@ -197,15 +197,12 @@ class TpcLaminationFitting : public SubsysReco const double adjust = 0.015; */ - std::vector m_truthR[2]; - std::vector m_truthPhi[2]; + std::vector m_truthR[2]{}; + std::vector m_truthPhi[2]{}; double m_phiModMin[2]{-M_PI/18, 0.0}; double m_phiModMax[2]{M_PI/18, M_PI/9}; - ActsGeometry *m_tGeometry {nullptr}; - PHG4TpcGeomContainer *m_geom_container {nullptr}; - LaserClusterHelper m_laserClusterHelper; bool m_useZ{false}; }; From 8a69fcb9e7f596f94c95e4c2d099465527d5c466 Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Tue, 21 Jul 2026 14:18:23 -0400 Subject: [PATCH 844/866] Implemented CodeRabbit suggestion --- offline/packages/tpccalib/MicromegasDriftEvaluator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc index aee2378e65..25ce4fa0cd 100644 --- a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc @@ -410,7 +410,7 @@ int MicromegasDriftEvaluator::load_nodes(PHCompositeNode* topNode) // --------------------------------------------------------------------------- void MicromegasDriftEvaluator::evaluate_tracks() { - if (!(m_track_map && m_cluster_map && m_container && m_hist3D)) return; + if (!(m_tGeometry && m_micromegas_geomcontainer && m_track_map && m_cluster_map && m_container && m_hist3D)) return; m_container->clear_tracks(); From 53ad1284607d139f60ea41d69332d77c0bbea782 Mon Sep 17 00:00:00 2001 From: bkimelman Date: Tue, 21 Jul 2026 14:41:20 -0400 Subject: [PATCH 845/866] Removed unnecessary calls to Acts and Tpc geometry --- offline/QA/Tpc/TpcLaserQA.cc | 12 ------------ offline/QA/Tpc/TpcLaserQA.h | 6 ------ 2 files changed, 18 deletions(-) diff --git a/offline/QA/Tpc/TpcLaserQA.cc b/offline/QA/Tpc/TpcLaserQA.cc index a60e2ccc67..38058f018c 100644 --- a/offline/QA/Tpc/TpcLaserQA.cc +++ b/offline/QA/Tpc/TpcLaserQA.cc @@ -54,18 +54,6 @@ int TpcLaserQA::InitRun(PHCompositeNode* topNode) } } - m_tGeometry = findNode::getClass(topNode,"ActsGeometry"); - if(!m_tGeometry) - { - std::cout << "LaserClusterHelper::loadNodes - ActsGeometry not found on node tree" << std::endl; - } - - m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); - if(!m_geom_container) - { - std::cout << "LaserClusterHelper::loadNodes - TPCGEOMCONTAINER not found on node tree" << std::endl; - } - m_laserClusterHelper.set_useZ(m_useZ); m_laserClusterHelper.loadNodes(topNode); diff --git a/offline/QA/Tpc/TpcLaserQA.h b/offline/QA/Tpc/TpcLaserQA.h index ddb4ffaa5f..ce17c62f32 100644 --- a/offline/QA/Tpc/TpcLaserQA.h +++ b/offline/QA/Tpc/TpcLaserQA.h @@ -5,9 +5,6 @@ #include -#include -#include - #include class PHCompositeNode; @@ -42,9 +39,6 @@ class TpcLaserQA : public SubsysReco TH1* m_sample_R2[2][12]{{nullptr}}; TH1* m_sample_R3[2][12]{{nullptr}}; - ActsGeometry *m_tGeometry{nullptr}; - PHG4TpcGeomContainer *m_geom_container{nullptr}; - LaserClusterHelper m_laserClusterHelper; bool m_useZ{false}; }; From 1074d312434278dad02773441b22c24604d82e14 Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Tue, 21 Jul 2026 14:55:36 -0400 Subject: [PATCH 846/866] clang-tidy errors --- .../tpccalib/MicromegasDriftEvaluator.cc | 46 +++++++++---------- .../tpccalib/SiliconDriftEvaluator.cc | 34 +++++++------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc index 25ce4fa0cd..0987411edc 100644 --- a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc @@ -65,8 +65,8 @@ namespace double normalize_angle(double phi) { - while (phi < 0) phi += 2 * M_PI; - while (phi >= 2 * M_PI) phi -= 2 * M_PI; + while (phi < 0) {phi += 2 * M_PI;} + while (phi >= 2 * M_PI) {phi -= 2 * M_PI;} return phi; } @@ -126,7 +126,7 @@ namespace { double ft = f(t); double dft = df(t); - if (std::abs(dft) < 1e-8) return false; + if (std::abs(dft) < 1e-8) {return false;} double t_new = t - ft / dft; double x = X0 + R * std::cos(t_new); @@ -152,8 +152,8 @@ namespace auto wrap = [&](double t) { - while (t > t_max) t -= 2 * M_PI; - while (t < t_min) t += 2 * M_PI; + while (t > t_max) {t -= 2 * M_PI;} + while (t < t_min) {t += 2 * M_PI;} return t; }; @@ -214,7 +214,7 @@ int MicromegasDriftEvaluator::Init(PHCompositeNode* topNode) << std::endl; PHNodeIterator iter(topNode); - auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + auto* dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) { std::cerr << Name() << "::Init - DST node missing" << std::endl; @@ -222,14 +222,14 @@ int MicromegasDriftEvaluator::Init(PHCompositeNode* topNode) } iter = PHNodeIterator(dstNode); - auto evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); + auto* evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); if (!evalNode) { evalNode = new PHCompositeNode("EVAL"); dstNode->addNode(evalNode); } - auto newNode = new PHIODataNode(new Container, "MicromegasDriftEvaluator::Container", "PHObject"); + auto* newNode = new PHIODataNode(new Container, "MicromegasDriftEvaluator::Container", "PHObject"); newNode->SplitLevel(99); evalNode->addNode(newNode); @@ -249,9 +249,9 @@ int MicromegasDriftEvaluator::InitRun(PHCompositeNode* topNode) int MicromegasDriftEvaluator::process_event(PHCompositeNode* topNode) { const auto res = load_nodes(topNode); - if (res != Fun4AllReturnCodes::EVENT_OK) return res; + if (res != Fun4AllReturnCodes::EVENT_OK) {return res;} - if (m_container) m_container->Reset(); + if (m_container) {m_container->Reset();} evaluate_tracks(); return Fun4AllReturnCodes::EVENT_OK; @@ -269,19 +269,19 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) const int nEntries = static_cast(m_hist3D->GetEntries()); std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; - auto h_fit = new TH2F("h_fit", "", 8, 0, 8, 220, -110, 110); + auto* h_fit = new TH2F("h_fit", "", 8, 0, 8, 220, -110, 110); h_fit->SetDirectory(nullptr); for (int j = 0; j < 8; ++j) { m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); - auto h2d = static_cast(m_hist3D->Project3D("zy")); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); h2d->SetName(Form("h_%s", k_tile_names[j])); h2d->SetDirectory(nullptr); // Fit vertical slices; require a minimum of 10 entries per slice h2d->FitSlicesY(nullptr, 0, -1, 10); - auto h_mean = static_cast(gDirectory->Get(Form("h_%s_1", k_tile_names[j]))); + auto* h_mean = static_cast(gDirectory->Get(Form("h_%s_1", k_tile_names[j]))); if (!h_mean) { @@ -303,8 +303,8 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) m_hist3D->GetXaxis()->SetRange(0, 0); // This part fits the 8 micromegas modules one at a time but constrains the slopes to be identical. This eliminates the need for perfect translational TPOT alignment - auto fit2d = new TF2("fit2d", fit_function_2d, 0, 8, -110, 110, 9); - for (int i = 0; i < 9; ++i) fit2d->SetParameter(i, 0.0); + auto* fit2d = new TF2("fit2d", fit_function_2d, 0, 8, -110, 110, 9); + for (int i = 0; i < 9; ++i) {fit2d->SetParameter(i, 0.0);} h_fit->Fit(fit2d, "0R"); @@ -316,7 +316,7 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) std::cout << Name() << "::End" << " slope=" << slope << " input_drift=" << m_drift_velocity << " cm/ns" << " new_drift=" << new_drift << " cm/ns +/- " << drift_err << " cm/ns" << std::endl; // Plot the whole thing - auto canvas = new TCanvas("drift_calib", "Drift velocity calibration", 2000, 1000); + auto* canvas = new TCanvas("drift_calib", "Drift velocity calibration", 2000, 1000); canvas->Divide(4, 2); for (int j = 0; j < 8; ++j) @@ -324,25 +324,25 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) canvas->cd(j + 1); m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); - auto h2d = static_cast(m_hist3D->Project3D("zy")); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); h2d->SetName(Form("hplot_%s", k_tile_names[j])); h2d->SetTitle(Form("%s;z_{track} (cm);#Deltaz (track#minuscluster) (cm)", k_tile_names[j])); h2d->SetStats(0); h2d->Draw("COLZ"); - auto h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", j), j + 1, j + 1); // These give you the Gaussian means for each slice + auto* h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", j), j + 1, j + 1); // These give you the Gaussian means for each slice h_fit_proj->SetMarkerStyle(20); h_fit_proj->SetMarkerColor(kRed); h_fit_proj->SetLineColor(kBlack); - auto f1d = new TF1(Form("f1d_%i", j), linear_function, -110, 110, 2); + auto* f1d = new TF1(Form("f1d_%i", j), linear_function, -110, 110, 2); f1d->SetParameter(0, slope); f1d->SetParameter(1, fit2d->GetParameter(j + 1)); f1d->SetLineColor(kGreen + 2); f1d->SetLineWidth(2); f1d->Draw("same"); - auto leg = new TLegend(0.35, 0.75, 0.92, 0.92); + auto* leg = new TLegend(0.35, 0.75, 0.92, 0.92); leg->SetHeader(Form("%i entries, v_{in}=%.2f m/ms", nEntries, m_drift_velocity * 1e4), "C"); leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); leg->AddEntry(f1d, Form("slope=%.4f v_{new}=%.3f#pm%.3f m/ms", slope, new_drift * 1e4, drift_err * 1e4), "l"); @@ -410,7 +410,7 @@ int MicromegasDriftEvaluator::load_nodes(PHCompositeNode* topNode) // --------------------------------------------------------------------------- void MicromegasDriftEvaluator::evaluate_tracks() { - if (!(m_tGeometry && m_micromegas_geomcontainer && m_track_map && m_cluster_map && m_container && m_hist3D)) return; + if (!(m_tGeometry && m_micromegas_geomcontainer && m_track_map && m_cluster_map && m_container && m_hist3D)) {return;} m_container->clear_tracks(); @@ -443,7 +443,7 @@ void MicromegasDriftEvaluator::evaluate_tracks() ++n_tpc; if (layer >= m_min_tpc_layer && layer < m_max_tpc_layer) { - const auto cl = m_cluster_map->findCluster(ckey); + auto *const cl = m_cluster_map->findCluster(ckey); if (cl) { tpc_positions.push_back( @@ -479,7 +479,7 @@ void MicromegasDriftEvaluator::evaluate_tracks() const auto mm_range = m_micromegas_geomcontainer->get_begin_end(); for (const auto& [mm_layer, base_layergeom] : range_adaptor(mm_range)) { - const auto layergeom = static_cast(base_layergeom); + const auto* layergeom = static_cast(base_layergeom); assert(layergeom); // skip the phi layer. Only the z-view layer matters here diff --git a/offline/packages/tpccalib/SiliconDriftEvaluator.cc b/offline/packages/tpccalib/SiliconDriftEvaluator.cc index 4c6a0200c6..83f24ba805 100644 --- a/offline/packages/tpccalib/SiliconDriftEvaluator.cc +++ b/offline/packages/tpccalib/SiliconDriftEvaluator.cc @@ -77,7 +77,7 @@ int SiliconDriftEvaluator::Init(PHCompositeNode* topNode) { // find DST node PHNodeIterator iter(topNode); - auto dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + auto* dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) { std::cout << "SiliconDriftEvaluator::Init - DST Node missing" << std::endl; @@ -86,7 +86,7 @@ int SiliconDriftEvaluator::Init(PHCompositeNode* topNode) // get EVAL node iter = PHNodeIterator(dstNode); - auto evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); + auto* evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); if (!evalNode) { // create @@ -96,7 +96,7 @@ int SiliconDriftEvaluator::Init(PHCompositeNode* topNode) } // add container to output tree - auto newNode = new PHIODataNode(new Container, "SiliconDriftEvaluator::Container", "PHObject"); + auto* newNode = new PHIODataNode(new Container, "SiliconDriftEvaluator::Container", "PHObject"); // overwrite split level for easier offline browsing newNode->SplitLevel(99); @@ -123,10 +123,10 @@ int SiliconDriftEvaluator::process_event(PHCompositeNode* topNode) { // load nodes const auto res = load_nodes(topNode); - if (res != Fun4AllReturnCodes::EVENT_OK) return res; + if (res != Fun4AllReturnCodes::EVENT_OK) {return res;} // cleanup output - if (m_container) m_container->Reset(); + if (m_container) {m_container->Reset();} evaluate_tracks(); @@ -147,7 +147,7 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) // build mean-dz TH2F via FitSlicesY, one eta bin at a time // x = eta bin [0,2), y = z_si (cm), content = mean dz (cm) - auto h_fit = new TH2F("h_fit_silicon", "", + auto* h_fit = new TH2F("h_fit_silicon", "", 2, 0, 2, 200, -m_max_z, m_max_z); h_fit->SetDirectory(nullptr); @@ -155,13 +155,13 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) for (int ieta = 0; ieta < 2; ++ieta) { m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); - auto h2d = static_cast(m_hist3D->Project3D("zy")); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); h2d->SetName(Form("h2d_etabin_%i", ieta)); h2d->SetDirectory(nullptr); // fit vertical slices; require a minimum of m_min_slice_entries per slice h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries); - auto h_mean = static_cast(gDirectory->Get(Form("h2d_etabin_%i_1", ieta))); + auto* h_mean = static_cast(gDirectory->Get(Form("h2d_etabin_%i_1", ieta))); if (!h_mean) { @@ -184,8 +184,8 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) m_hist3D->GetXaxis()->SetRange(0, 0); // 2D piecewise fit: shared slope + per-eta offset - auto fit2d = new TF2("fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3); - for (int i = 0; i < 3; ++i) fit2d->SetParameter(i, 0.0); + auto* fit2d = new TF2("fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3); + for (int i = 0; i < 3; ++i) {fit2d->SetParameter(i, 0.0);} h_fit->Fit(fit2d, "0R"); const double slope = fit2d->GetParameter(0); @@ -200,7 +200,7 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) std::cout << Name() << "::End" << " slope=" << slope << " dv_in=" << m_drift_velocity << " cm/ns" << " dv_new=" << dv_new << " +/- " << dv_err << " cm/ns" << " t0_new=" << t0_new << " ns" << std::endl; // draw the plot - auto canvas = new TCanvas("silicon_drift_calib", "Silicon drift velocity calibration", 1400, 700); + auto* canvas = new TCanvas("silicon_drift_calib", "Silicon drift velocity calibration", 1400, 700); canvas->Divide(2, 1); for (int ieta = 0; ieta < 2; ++ieta) @@ -211,14 +211,14 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) // 2D distribution for this eta bin m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); - auto h2d = static_cast(m_hist3D->Project3D("zy")); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); h2d->SetName(Form("hplot_etabin_%i", ieta)); h2d->SetTitle(";z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)"); h2d->SetStats(0); h2d->Draw("COLZ"); // mean-dz points from FitSlicesY - auto h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", ieta), ieta + 1, ieta + 1); + auto* h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", ieta), ieta + 1, ieta + 1); h_fit_proj->SetMarkerStyle(20); h_fit_proj->SetMarkerSize(0.6); h_fit_proj->SetMarkerColor(kRed); @@ -226,7 +226,7 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) h_fit_proj->Draw("same P"); // 1D fit line for this eta bin - auto f1d = new TF1(Form("f1d_etabin_%i", ieta), linear_function, -m_max_z, m_max_z, 2); + auto* f1d = new TF1(Form("f1d_etabin_%i", ieta), linear_function, -m_max_z, m_max_z, 2); f1d->SetParameter(0, slope); f1d->SetParameter(1, (ieta == 0) ? off_neg : off_pos); f1d->SetLineColor(kGreen + 2); @@ -234,12 +234,12 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) f1d->Draw("same"); // reference line at dz = 0 - auto zero = new TLine(-m_max_z, 0, m_max_z, 0); + auto* zero = new TLine(-m_max_z, 0, m_max_z, 0); zero->SetLineStyle(2); zero->SetLineColor(kGray + 1); zero->Draw(); - auto leg = new TLegend(0.13, 0.76, 0.82, 0.95); + auto* leg = new TLegend(0.13, 0.76, 0.82, 0.95); leg->SetBorderSize(0); leg->SetFillStyle(0); leg->SetTextSize(0.033); @@ -304,7 +304,7 @@ int SiliconDriftEvaluator::load_nodes(PHCompositeNode* topNode) //_____________________________________________________________________ void SiliconDriftEvaluator::evaluate_tracks() { - if (!(m_track_map && m_container && m_hist3D)) return; + if (!(m_track_map && m_container && m_hist3D)) {return;} // clear array m_container->clearTracks(); From 696164eea99e9782a3d44b6e7062ff760a49a6d6 Mon Sep 17 00:00:00 2001 From: Bade Sayki Date: Tue, 21 Jul 2026 15:45:30 -0400 Subject: [PATCH 847/866] more clang-tidy errors --- .../tpccalib/MicromegasDriftEvaluator.cc | 124 +++++++++++++----- .../tpccalib/SiliconDriftEvaluator.cc | 82 ++++++++---- 2 files changed, 151 insertions(+), 55 deletions(-) diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc index 0987411edc..567bf092fb 100644 --- a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ namespace class range_adaptor { public: - range_adaptor(const T& range) + explicit range_adaptor(const T& range) : m_range(range) { } @@ -53,7 +54,7 @@ namespace }; template - inline constexpr T square(T x) + constexpr T square(T x) { return x * x; } @@ -65,8 +66,14 @@ namespace double normalize_angle(double phi) { - while (phi < 0) {phi += 2 * M_PI;} - while (phi >= 2 * M_PI) {phi -= 2 * M_PI;} + while (phi < 0) + { + phi += 2 * M_PI; + } + while (phi >= 2 * M_PI) + { + phi -= 2 * M_PI; + } return phi; } @@ -126,7 +133,10 @@ namespace { double ft = f(t); double dft = df(t); - if (std::abs(dft) < 1e-8) {return false;} + if (std::abs(dft) < 1e-8) + { + return false; + } double t_new = t - ft / dft; double x = X0 + R * std::cos(t_new); @@ -152,8 +162,14 @@ namespace auto wrap = [&](double t) { - while (t > t_max) {t -= 2 * M_PI;} - while (t < t_min) {t += 2 * M_PI;} + while (t > t_max) + { + t -= 2 * M_PI; + } + while (t < t_min) + { + t += 2 * M_PI; + } return t; }; @@ -171,7 +187,10 @@ namespace // Looks for the solution within the tile acceptance in three different phi seeds in the Newton-Raphson (helix_plane could have more than one solution) for (double t_seed : t_seeds) { - if (solve_from(t_seed, intersect)) return true; + if (solve_from(t_seed, intersect)) + { + return true; + } } return false; } @@ -249,16 +268,22 @@ int MicromegasDriftEvaluator::InitRun(PHCompositeNode* topNode) int MicromegasDriftEvaluator::process_event(PHCompositeNode* topNode) { const auto res = load_nodes(topNode); - if (res != Fun4AllReturnCodes::EVENT_OK) {return res;} + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } - if (m_container) {m_container->Reset();} + if (m_container) + { + m_container->Reset(); + } evaluate_tracks(); return Fun4AllReturnCodes::EVENT_OK; } // --------------------------------------------------------------------------- -int MicromegasDriftEvaluator::End(PHCompositeNode*) +int MicromegasDriftEvaluator::End(PHCompositeNode* /*topNode*/) { if (!m_hist3D) { @@ -276,12 +301,12 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) { m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); auto* h2d = static_cast(m_hist3D->Project3D("zy")); - h2d->SetName(Form("h_%s", k_tile_names[j])); + h2d->SetName(std::format("h_{}", k_tile_names[j]).c_str()); h2d->SetDirectory(nullptr); // Fit vertical slices; require a minimum of 10 entries per slice h2d->FitSlicesY(nullptr, 0, -1, 10); - auto* h_mean = static_cast(gDirectory->Get(Form("h_%s_1", k_tile_names[j]))); + auto* h_mean = static_cast(gDirectory->Get(std::format("h_{}_1", k_tile_names[j]).c_str())); if (!h_mean) { @@ -304,7 +329,10 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) // This part fits the 8 micromegas modules one at a time but constrains the slopes to be identical. This eliminates the need for perfect translational TPOT alignment auto* fit2d = new TF2("fit2d", fit_function_2d, 0, 8, -110, 110, 9); - for (int i = 0; i < 9; ++i) {fit2d->SetParameter(i, 0.0);} + for (int i = 0; i < 9; ++i) + { + fit2d->SetParameter(i, 0.0); + } h_fit->Fit(fit2d, "0R"); @@ -325,17 +353,17 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); auto* h2d = static_cast(m_hist3D->Project3D("zy")); - h2d->SetName(Form("hplot_%s", k_tile_names[j])); - h2d->SetTitle(Form("%s;z_{track} (cm);#Deltaz (track#minuscluster) (cm)", k_tile_names[j])); - h2d->SetStats(0); + h2d->SetName(std::format("hplot_{}", k_tile_names[j]).c_str()); + h2d->SetTitle(std::format("{};z_{{track}} (cm);#Deltaz (track#minuscluster) (cm)", k_tile_names[j]).c_str()); + h2d->SetStats(false); h2d->Draw("COLZ"); - auto* h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", j), j + 1, j + 1); // These give you the Gaussian means for each slice + auto* h_fit_proj = h_fit->ProjectionY(std::format("h_fit_proj_{}", j).c_str(), j + 1, j + 1); // These give you the Gaussian means for each slice h_fit_proj->SetMarkerStyle(20); h_fit_proj->SetMarkerColor(kRed); h_fit_proj->SetLineColor(kBlack); - auto* f1d = new TF1(Form("f1d_%i", j), linear_function, -110, 110, 2); + auto* f1d = new TF1(std::format("f1d_{}", j).c_str(), linear_function, -110, 110, 2); f1d->SetParameter(0, slope); f1d->SetParameter(1, fit2d->GetParameter(j + 1)); f1d->SetLineColor(kGreen + 2); @@ -343,9 +371,9 @@ int MicromegasDriftEvaluator::End(PHCompositeNode*) f1d->Draw("same"); auto* leg = new TLegend(0.35, 0.75, 0.92, 0.92); - leg->SetHeader(Form("%i entries, v_{in}=%.2f m/ms", nEntries, m_drift_velocity * 1e4), "C"); + leg->SetHeader(std::format("{} entries, v_{{in}}={:.2f} m/ms", nEntries, m_drift_velocity * 1e4).c_str(), "C"); leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); - leg->AddEntry(f1d, Form("slope=%.4f v_{new}=%.3f#pm%.3f m/ms", slope, new_drift * 1e4, drift_err * 1e4), "l"); + leg->AddEntry(f1d, std::format("slope={:.4f} v_{{new}}={:.3f}#pm{:.3f} m/ms", slope, new_drift * 1e4, drift_err * 1e4).c_str(), "l"); leg->Draw(); } @@ -410,7 +438,10 @@ int MicromegasDriftEvaluator::load_nodes(PHCompositeNode* topNode) // --------------------------------------------------------------------------- void MicromegasDriftEvaluator::evaluate_tracks() { - if (!(m_tGeometry && m_micromegas_geomcontainer && m_track_map && m_cluster_map && m_container && m_hist3D)) {return;} + if (!(m_tGeometry && m_micromegas_geomcontainer && m_track_map && m_cluster_map && m_container && m_hist3D)) + { + return; + } m_container->clear_tracks(); @@ -418,7 +449,10 @@ void MicromegasDriftEvaluator::evaluate_tracks() { // valid crossing const auto crossing = track->get_crossing(); - if (crossing == SHRT_MAX) continue; + if (crossing == SHRT_MAX) + { + continue; + } std::vector tpc_positions; @@ -430,7 +464,10 @@ void MicromegasDriftEvaluator::evaluate_tracks() for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) { - if (!seed) continue; + if (!seed) + { + continue; + } for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) { const auto ckey = *it; @@ -443,7 +480,7 @@ void MicromegasDriftEvaluator::evaluate_tracks() ++n_tpc; if (layer >= m_min_tpc_layer && layer < m_max_tpc_layer) { - auto *const cl = m_cluster_map->findCluster(ckey); + auto* const cl = m_cluster_map->findCluster(ckey); if (cl) { tpc_positions.push_back( @@ -468,13 +505,19 @@ void MicromegasDriftEvaluator::evaluate_tracks() } // need at least 3 TPC clusters in range - if (tpc_positions.size() < 3) continue; + if (tpc_positions.size() < 3) + { + continue; + } const auto [slope_rz, intersect_rz] = TrackFitUtils::line_fit(tpc_positions); const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin(tpc_positions); // reject badly reconstructed / low-pT tracks - if (R < 40.0) continue; + if (R < 40.0) + { + continue; + } const auto mm_range = m_micromegas_geomcontainer->get_begin_end(); for (const auto& [mm_layer, base_layergeom] : range_adaptor(mm_range)) @@ -484,13 +527,19 @@ void MicromegasDriftEvaluator::evaluate_tracks() // skip the phi layer. Only the z-view layer matters here if (layergeom->get_segmentation_type() != - MicromegasDefs::SegmentationType::SEGMENTATION_Z) continue; + MicromegasDefs::SegmentationType::SEGMENTATION_Z) + { + continue; + } const double layer_radius = layergeom->get_radius(); auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layer_radius, R, X0, Y0); - if (!std::isfinite(xplus)) continue; + if (!std::isfinite(xplus)) + { + continue; + } // pick the solution closest in phi to the last TPC cluster const double last_phi = std::atan2(tpc_positions.back().y(), tpc_positions.back().x()); @@ -503,7 +552,10 @@ void MicromegasDriftEvaluator::evaluate_tracks() const TVector3 world_cyl(r_cyl * std::cos(phi), r_cyl * std::sin(phi), z_cyl); const int tileid = layergeom->find_tile_cylindrical(world_cyl); - if (tileid < 0) continue; + if (tileid < 0) + { + continue; + } const auto tile_center = layergeom->get_world_from_local_coords(tileid, m_tGeometry, {0, 0}); const TVector3 ptile(tile_center.x(), tile_center.y(), tile_center.z()); @@ -517,12 +569,17 @@ void MicromegasDriftEvaluator::evaluate_tracks() TVector3 intersection; if (!helix_plane_intersection(phi_range.first, phi_range.second, zmin, zmax, R, X0, Y0, intersect_rz, slope_rz, ptile, ntile, intersection)) + { continue; + } const auto local_intersection = layergeom->get_local_from_world_coords(tileid, m_tGeometry, {intersection.x(), intersection.y(), intersection.z()}); const double y_local = local_intersection.y(); - if (std::abs(y_local) > m_y_local_cut) continue; + if (std::abs(y_local) > m_y_local_cut) + { + continue; + } // find the nearest TPOT cluster const auto hitsetkey = MicromegasDefs::genHitSetKey(mm_layer, MicromegasDefs::SegmentationType::SEGMENTATION_Z, tileid); @@ -546,7 +603,10 @@ void MicromegasDriftEvaluator::evaluate_tracks() } // require cluster within the z search window - if (dmin < 0 || dmin > m_z_search_win) continue; + if (dmin < 0 || dmin > m_z_search_win) + { + continue; + } // fill track struct and histogram TrackStruct track_struct; diff --git a/offline/packages/tpccalib/SiliconDriftEvaluator.cc b/offline/packages/tpccalib/SiliconDriftEvaluator.cc index 83f24ba805..3aef6f937b 100644 --- a/offline/packages/tpccalib/SiliconDriftEvaluator.cc +++ b/offline/packages/tpccalib/SiliconDriftEvaluator.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,7 @@ namespace } //! 1D version used to draw per-eta overlay lines on QA canvas + // NOLINTNEXTLINE(readability-non-const-parameter): ROOT TF1 requires this exact signature double linear_function(double* x, double* par) { return par[0] * x[0] + par[1]; @@ -123,10 +125,16 @@ int SiliconDriftEvaluator::process_event(PHCompositeNode* topNode) { // load nodes const auto res = load_nodes(topNode); - if (res != Fun4AllReturnCodes::EVENT_OK) {return res;} + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } // cleanup output - if (m_container) {m_container->Reset();} + if (m_container) + { + m_container->Reset(); + } evaluate_tracks(); @@ -134,7 +142,7 @@ int SiliconDriftEvaluator::process_event(PHCompositeNode* topNode) } //_____________________________________________________________________ -int SiliconDriftEvaluator::End(PHCompositeNode*) +int SiliconDriftEvaluator::End(PHCompositeNode* /*topNode*/) { if (!m_hist3D) { @@ -148,20 +156,20 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) // build mean-dz TH2F via FitSlicesY, one eta bin at a time // x = eta bin [0,2), y = z_si (cm), content = mean dz (cm) auto* h_fit = new TH2F("h_fit_silicon", "", - 2, 0, 2, - 200, -m_max_z, m_max_z); + 2, 0, 2, + 200, -m_max_z, m_max_z); h_fit->SetDirectory(nullptr); for (int ieta = 0; ieta < 2; ++ieta) { m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); auto* h2d = static_cast(m_hist3D->Project3D("zy")); - h2d->SetName(Form("h2d_etabin_%i", ieta)); + h2d->SetName(std::format("h2d_etabin_{}", ieta).c_str()); h2d->SetDirectory(nullptr); // fit vertical slices; require a minimum of m_min_slice_entries per slice h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries); - auto* h_mean = static_cast(gDirectory->Get(Form("h2d_etabin_%i_1", ieta))); + auto* h_mean = static_cast(gDirectory->Get(std::format("h2d_etabin_{}_1", ieta).c_str())); if (!h_mean) { @@ -185,7 +193,10 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) // 2D piecewise fit: shared slope + per-eta offset auto* fit2d = new TF2("fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3); - for (int i = 0; i < 3; ++i) {fit2d->SetParameter(i, 0.0);} + for (int i = 0; i < 3; ++i) + { + fit2d->SetParameter(i, 0.0); + } h_fit->Fit(fit2d, "0R"); const double slope = fit2d->GetParameter(0); @@ -212,13 +223,13 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) // 2D distribution for this eta bin m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); auto* h2d = static_cast(m_hist3D->Project3D("zy")); - h2d->SetName(Form("hplot_etabin_%i", ieta)); + h2d->SetName(std::format("hplot_etabin_{}", ieta).c_str()); h2d->SetTitle(";z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)"); - h2d->SetStats(0); + h2d->SetStats(false); h2d->Draw("COLZ"); // mean-dz points from FitSlicesY - auto* h_fit_proj = h_fit->ProjectionY(Form("h_fit_proj_%i", ieta), ieta + 1, ieta + 1); + auto* h_fit_proj = h_fit->ProjectionY(std::format("h_fit_proj_{}", ieta).c_str(), ieta + 1, ieta + 1); h_fit_proj->SetMarkerStyle(20); h_fit_proj->SetMarkerSize(0.6); h_fit_proj->SetMarkerColor(kRed); @@ -226,7 +237,7 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) h_fit_proj->Draw("same P"); // 1D fit line for this eta bin - auto* f1d = new TF1(Form("f1d_etabin_%i", ieta), linear_function, -m_max_z, m_max_z, 2); + auto* f1d = new TF1(std::format("f1d_etabin_{}", ieta).c_str(), linear_function, -m_max_z, m_max_z, 2); f1d->SetParameter(0, slope); f1d->SetParameter(1, (ieta == 0) ? off_neg : off_pos); f1d->SetLineColor(kGreen + 2); @@ -243,11 +254,12 @@ int SiliconDriftEvaluator::End(PHCompositeNode*) leg->SetBorderSize(0); leg->SetFillStyle(0); leg->SetTextSize(0.033); - leg->SetHeader(Form("%s entries: %i v_{in}=%.4f cm/ns", - k_eta_labels[ieta], nEntries, m_drift_velocity), + leg->SetHeader(std::format("{} entries: {} v_{{in}}={:.4f} cm/ns", + k_eta_labels[ieta], nEntries, m_drift_velocity) + .c_str(), "C"); leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); - leg->AddEntry(f1d, Form("slope=%.4f v_{new}=%.4f#pm%.4f cm/ns t_{0}=%.1f ns", slope, dv_new, dv_err, t0_new), "l"); + leg->AddEntry(f1d, std::format("slope={:.4f} v_{{new}}={:.4f}#pm{:.4f} cm/ns t_{{0}}={:.1f} ns", slope, dv_new, dv_err, t0_new).c_str(), "l"); leg->Draw(); } @@ -304,7 +316,10 @@ int SiliconDriftEvaluator::load_nodes(PHCompositeNode* topNode) //_____________________________________________________________________ void SiliconDriftEvaluator::evaluate_tracks() { - if (!(m_track_map && m_container && m_hist3D)) {return;} + if (!(m_track_map && m_container && m_hist3D)) + { + return; + } // clear array m_container->clearTracks(); @@ -322,7 +337,10 @@ void SiliconDriftEvaluator::evaluate_tracks() // require both seeds const auto* si_seed = track->get_silicon_seed(); const auto* tpc_seed = track->get_tpc_seed(); - if (!si_seed || !tpc_seed) continue; + if (!si_seed || !tpc_seed) + { + continue; + } // count clusters per subsystem unsigned int n_tpc = 0; @@ -331,7 +349,10 @@ void SiliconDriftEvaluator::evaluate_tracks() for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) { - if (!seed) continue; + if (!seed) + { + continue; + } for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) { switch (TrkrDefs::getTrkrId(*it)) @@ -352,15 +373,30 @@ void SiliconDriftEvaluator::evaluate_tracks() } // apply selection cuts - if (n_tpc < m_min_nclusters_tpc) continue; - if (n_mvtx < m_min_nclusters_mvtx) continue; - if (n_intt < m_min_nclusters_intt) continue; + if (n_tpc < m_min_nclusters_tpc) + { + continue; + } + if (n_mvtx < m_min_nclusters_mvtx) + { + continue; + } + if (n_intt < m_min_nclusters_intt) + { + continue; + } const float eta = tpc_seed->get_eta(); - if (std::abs(eta) > m_max_eta) continue; + if (std::abs(eta) > m_max_eta) + { + continue; + } const float pt = get_pt(track->get_px(), track->get_py()); - if (pt < m_min_pt) continue; + if (pt < m_min_pt) + { + continue; + } // get seed z positions at POCA const auto si_pos = TrackSeedHelper::get_xyz(si_seed); From 0fe9dc0ece4c7a464f6b7e03dfb1b3d412236ed1 Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Tue, 21 Jul 2026 19:44:54 -0400 Subject: [PATCH 848/866] updated MB classifier for O+O and species dependence --- .../packages/trigger/MinimumBiasClassifier.cc | 47 ++++++++++++++----- .../packages/trigger/MinimumBiasClassifier.h | 17 ++++--- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index ebce5800ca..ba7e02c3b0 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -44,24 +44,42 @@ int MinimumBiasClassifier::InitRun(PHCompositeNode *topNode) if (m_species == MinimumBiasInfo::SPECIES::AUAU) { - m_useZDC = true; - m_max_charge_cut = 2100; - m_box_cut = true; - m_hit_cut = 2; + m_useZDC = true; + m_box_cut = true; + m_hit_cut = 2; + m_max_charge_cut = 2100; + m_mbd_charge_cut = 0.5; + m_mbd_time_cut = 25.; + m_z_vtx_cut = 60.; + m_mbd_north_cut = 10.; + m_mbd_south_cut = 150.; + m_zdc_cut = 60.; } if (m_species == MinimumBiasInfo::SPECIES::OO) { - m_useZDC = false; - m_max_charge_cut = 300; - m_box_cut = false; - m_hit_cut = 1; + m_useZDC = false; + m_box_cut = false; + m_hit_cut = 1; + m_max_charge_cut = 400; + m_mbd_charge_cut = 0.4; + m_mbd_time_cut = 20.; + m_z_vtx_cut = 150.; + m_mbd_north_cut = 10.; + m_mbd_south_cut = 150.; + m_zdc_cut = 60.; } if (m_species == MinimumBiasInfo::SPECIES::PP) { - m_useZDC = false; - m_max_charge_cut = 300; - m_box_cut = false; - m_hit_cut = 1; + m_useZDC = false; + m_box_cut = false; + m_hit_cut = 1; + m_max_charge_cut = 300; + m_mbd_charge_cut = 0.4; + m_mbd_time_cut = 20.; + m_z_vtx_cut = 60.; + m_mbd_north_cut = 10.; + m_mbd_south_cut = 150.; + m_zdc_cut = 60.; } CDBInterface *m_cdb = CDBInterface::instance(); @@ -250,6 +268,11 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() // return Fun4AllReturnCodes::EVENT_OK; } + if (m_species == MinimumBiasInfo::SPECIES::OO && m_reject_pileup && (m_mbd_charge_sum[0] + m_mbd_charge_sum[1]) > m_pileup_charge_cut && minbiascheck) + { + minbiascheck = false; + } + m_mb_info->setIsAuAuMinimumBias(minbiascheck); if (!minbiascheck && m_abortEvents) { diff --git a/offline/packages/trigger/MinimumBiasClassifier.h b/offline/packages/trigger/MinimumBiasClassifier.h index d373c2374a..a1ccb44039 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.h +++ b/offline/packages/trigger/MinimumBiasClassifier.h @@ -59,6 +59,8 @@ class MinimumBiasClassifier : public SubsysReco void setSpecies(MinimumBiasInfo::SPECIES spec) { m_species = spec; }; + void setRejectPileup(bool v) { m_reject_pileup = v; }; + void abortEvents(const bool abort) { m_abortEvents = abort; }; void set_minbiasNodeName(const std::string &name) @@ -91,6 +93,9 @@ class MinimumBiasClassifier : public SubsysReco bool m_issim{false}; bool m_useZDC{true}; bool m_box_cut{true}; + bool m_reject_pileup{true}; + + float m_pileup_charge_cut{200.}; int m_hit_cut{2}; @@ -100,13 +105,13 @@ class MinimumBiasClassifier : public SubsysReco float m_vertex{std::numeric_limits::quiet_NaN()}; - static constexpr float m_z_vtx_cut{60.}; - static constexpr float m_mbd_north_cut{10.}; - static constexpr float m_mbd_south_cut{150}; - static constexpr float m_mbd_charge_cut{0.5}; - static constexpr float m_mbd_time_cut{25.}; + float m_z_vtx_cut{60.}; + float m_mbd_north_cut{10.}; + float m_mbd_south_cut{150.}; + float m_mbd_charge_cut{0.5}; + float m_mbd_time_cut{25.}; // const int m_mbd_tube_cut{2}; - static constexpr float m_zdc_cut{60.}; + float m_zdc_cut{60.}; MinimumBiasInfo::SPECIES m_species{MinimumBiasInfo::SPECIES::AUAU}; From c39c322b12ffc7890514ec37c763575cbb73bc7b Mon Sep 17 00:00:00 2001 From: hahahachiya Date: Tue, 21 Jul 2026 22:32:47 -0400 Subject: [PATCH 849/866] make some functions virtual to inherit --- .../packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h index 0dc0dff847..2102ccab9a 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h @@ -63,8 +63,8 @@ class KFParticle_truthAndDetTools void fillHepMCBranch(HepMC::GenParticle *particle, int daughter_id); int getHepMCInfo(PHCompositeNode *topNode, TTree *m_tree, const KFParticle &daughter, int daughter_id); - void initializeCaloBranches(TTree *m_tree, int daughter_id, const std::string &daughter_number); - void fillCaloBranch(PHCompositeNode *topNode, TTree *m_tree, const KFParticle &daughter, int daughter_id, bool &isTrackEMCalmatch, const KFParticle &vertex); + virtual void initializeCaloBranches(TTree *m_tree, int daughter_id, const std::string &daughter_number); + virtual void fillCaloBranch(PHCompositeNode *topNode, TTree *m_tree, const KFParticle &daughter, int daughter_id, bool &isTrackEMCalmatch, const KFParticle &vertex); void Get5x5CellInfo(RawClusterDefs::keytype key_in, int daughter_id); void initializeDetectorBranches(TTree *m_tree, int daughter_id, const std::string &daughter_number); From a4a536dba1572046f67ebda67d90c00a7ad80e58 Mon Sep 17 00:00:00 2001 From: xyu3 Date: Tue, 21 Jul 2026 22:37:59 -0400 Subject: [PATCH 850/866] read TPC gas fractions from geometry --- .../g4detectors/PHG4GeantinoIonization.cc | 105 +++++++++++------- .../g4detectors/PHG4GeantinoIonization.h | 27 +---- 2 files changed, 65 insertions(+), 67 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc index 3c5aa88e07..673e2ae582 100644 --- a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc @@ -7,6 +7,9 @@ #include +#include +#include + #include #include @@ -16,15 +19,6 @@ namespace { - struct GasFractions - { - double neon = 0; - double argon = 0; - double cf4 = 0; - double nitrogen = 0; - double isobutane = 0; - }; - // Pure-gas MIP stopping powers in keV/cm. They match the values used by // the current TPC and Micromegas hit-reconstruction modules. constexpr double neonMipDedx = 1.56; @@ -39,17 +33,10 @@ namespace double mvtxMipDedx = 0.00384; double inttMipDedx = 0.00387; - GasFractions tpcGasFractions{0.00, 0.75, 0.20, 0.00, 0.05}; - GasFractions tpotGasFractions{0.00, 0.90, 0.00, 0.00, 0.10}; - - double calculateMipDedx(const GasFractions& fractions) - { - return fractions.neon * neonMipDedx + - fractions.argon * argonMipDedx + - fractions.cf4 * cf4MipDedx + - fractions.nitrogen * nitrogenMipDedx + - fractions.isobutane * isobutaneMipDedx; - } + // PHG4MicromegasDetector and PHG4MicromegasHitReco both use a fixed + // Ar/isobutane 90/10 gas mixture. + constexpr double tpotMipDedx = + 1e-6 * (0.9 * argonMipDedx + 0.1 * isobutaneMipDedx); } // namespace PHG4GeantinoIonization::PHG4GeantinoIonization(const std::string& name) @@ -62,37 +49,69 @@ PHG4GeantinoIonization::PHG4GeantinoIonization(const std::string& name) { } -void PHG4GeantinoIonization::set_mvtx_mip_dedx(const double value) +int PHG4GeantinoIonization::InitRun(PHCompositeNode* topNode) { - mvtxMipDedx = value; -} + if (!m_detectorConfigs[2].enabled) + { + return Fun4AllReturnCodes::EVENT_OK; + } -void PHG4GeantinoIonization::set_intt_mip_dedx(const double value) -{ - inttMipDedx = value; + // Read the gas fractions from the TPC geometry parameters, as is done in + // PHG4TpcElectronDrift. This keeps the synthetic ionization consistent with + // the geometry built by the macro or loaded from the CDB. + const auto* tpcParamsContainer = + findNode::getClass(topNode, "G4GEO_TPC"); + if (!tpcParamsContainer) + { + std::cout << PHWHERE << " Missing G4GEO_TPC" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + const PHParameters* tpcParams = tpcParamsContainer->GetParameters(0); + if (!tpcParams) + { + std::cout << PHWHERE << " Missing TPC geometry parameters" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + const double neonFraction = tpcParams->get_double_param("Ne_frac"); + const double argonFraction = tpcParams->get_double_param("Ar_frac"); + const double cf4Fraction = tpcParams->get_double_param("CF4_frac"); + const double nitrogenFraction = tpcParams->get_double_param("N2_frac"); + const double isobutaneFraction = tpcParams->get_double_param("isobutane_frac"); + + m_tpcMipDedx = + 1e-6 * (neonFraction * neonMipDedx + + argonFraction * argonMipDedx + + cf4Fraction * cf4MipDedx + + nitrogenFraction * nitrogenMipDedx + + isobutaneFraction * isobutaneMipDedx); + + if (Verbosity() > 0) + { + std::cout << Name() + << " TPC gas fractions (Ne/Ar/CF4/N2/isobutane): " + << neonFraction << "/" << argonFraction << "/" + << cf4Fraction << "/" << nitrogenFraction << "/" + << isobutaneFraction + << ", MIP dE/dx: " << m_tpcMipDedx << " GeV/cm" + << std::endl; + } + + return Fun4AllReturnCodes::EVENT_OK; } -void PHG4GeantinoIonization::set_tpc_gas_fractions( - const double neon, - const double argon, - const double cf4, - const double nitrogen, - const double isobutane) +void PHG4GeantinoIonization::set_mvtx_mip_dedx(const double value) { - tpcGasFractions = {neon, argon, cf4, nitrogen, isobutane}; + mvtxMipDedx = value; } -void PHG4GeantinoIonization::set_tpot_gas_fractions( - const double neon, - const double argon, - const double cf4, - const double nitrogen, - const double isobutane) +void PHG4GeantinoIonization::set_intt_mip_dedx(const double value) { - tpotGasFractions = {neon, argon, cf4, nitrogen, isobutane}; + inttMipDedx = value; } -double PHG4GeantinoIonization::mip_dedx(const DetectorId detector) +double PHG4GeantinoIonization::mip_dedx(const DetectorId detector) const { switch (detector) { @@ -101,9 +120,9 @@ double PHG4GeantinoIonization::mip_dedx(const DetectorId detector) case DetectorId::intt: return inttMipDedx; case DetectorId::tpc: - return 1e-6 * calculateMipDedx(tpcGasFractions); + return m_tpcMipDedx; case DetectorId::tpot: - return 1e-6 * calculateMipDedx(tpotGasFractions); + return tpotMipDedx; } return 0; diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h index 8b4ea08656..ceb532bba1 100644 --- a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h @@ -26,6 +26,7 @@ class PHG4GeantinoIonization : public SubsysReco explicit PHG4GeantinoIonization(const std::string& name = "PHG4GeantinoIonization"); ~PHG4GeantinoIonization() override = default; + int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode* topNode) override; void set_particle_name(const std::string& name) { m_particleName = name; } @@ -39,29 +40,6 @@ class PHG4GeantinoIonization : public SubsysReco void set_mvtx_mip_dedx(double value); void set_intt_mip_dedx(double value); - /** - * Configure the TPC mean MIP stopping power from the same gas fractions - * passed to PHG4TpcElectronDrift. Fractions are expected to sum to one. - */ - void set_tpc_gas_fractions( - double neon, - double argon, - double cf4, - double nitrogen, - double isobutane); - - void set_tpot_gas_fractions( - double neon, - double argon, - double cf4, - double nitrogen, - double isobutane); - - void set_tpot_gas_fractions(double argon, double isobutane) - { - set_tpot_gas_fractions(0, argon, 0, 0, isobutane); - } - private: enum class DetectorId { @@ -84,10 +62,11 @@ class PHG4GeantinoIonization : public SubsysReco const PHG4TruthInfoContainer* truthInfo, const DetectorConfig& config) const; - static double mip_dedx(DetectorId detector); + double mip_dedx(DetectorId detector) const; std::array m_detectorConfigs; std::string m_particleName = "chargedgeantino"; + double m_tpcMipDedx = 0; }; #endif // G4DETECTORS_PHG4GEANTINOIONIZATION_H From b84e8b04d4fef6dc329928fec873c0db57faa5d4 Mon Sep 17 00:00:00 2001 From: xyu3 Date: Tue, 21 Jul 2026 23:08:10 -0400 Subject: [PATCH 851/866] load serialized TPC geometry for geantino ionization --- .../g4detectors/PHG4GeantinoIonization.cc | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc index 673e2ae582..b669c58955 100644 --- a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc @@ -10,6 +10,11 @@ #include #include +#include + +#include +#include +#include #include #include @@ -59,12 +64,46 @@ int PHG4GeantinoIonization::InitRun(PHCompositeNode* topNode) // Read the gas fractions from the TPC geometry parameters, as is done in // PHG4TpcElectronDrift. This keeps the synthetic ionization consistent with // the geometry built by the macro or loaded from the CDB. - const auto* tpcParamsContainer = + auto* tpcParamsContainer = findNode::getClass(topNode, "G4GEO_TPC"); if (!tpcParamsContainer) { - std::cout << PHWHERE << " Missing G4GEO_TPC" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; + // Tracking geometry loaded from the CDB initially provides the serialized + // RUN-node parameters. Rebuild G4GEO_TPC from them before TPC hit + // reconstruction, following PHG4TpcElectronDrift::InitRun. + auto* tpcPdbParams = + findNode::getClass(topNode, "G4GEOPARAM_TPC"); + if (!tpcPdbParams) + { + std::cout << PHWHERE + << " Missing both G4GEO_TPC and G4GEOPARAM_TPC" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + PHNodeIterator topIter(topNode); + auto* parNode = dynamic_cast( + topIter.findFirst("PHCompositeNode", "PAR")); + if (!parNode) + { + std::cout << PHWHERE << " Missing PAR node" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + PHNodeIterator parIter(parNode); + auto* parTpcNode = dynamic_cast( + parIter.findFirst("PHCompositeNode", "TPC")); + if (!parTpcNode) + { + parTpcNode = new PHCompositeNode("TPC"); + parNode->addNode(parTpcNode); + } + + tpcParamsContainer = new PHParametersContainer("TPC"); + tpcParamsContainer->CreateAndFillFrom(tpcPdbParams, "TPC"); + parTpcNode->addNode( + new PHDataNode( + tpcParamsContainer, "G4GEO_TPC")); } const PHParameters* tpcParams = tpcParamsContainer->GetParameters(0); From aaeddcd2bd981991f76fcfb305714d612892e5ae Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 21 Jul 2026 23:10:47 -0400 Subject: [PATCH 852/866] suppress clang-tidy warning --- .../tpccalib/MicromegasDriftEvaluator.cc | 12 ++-- .../tpccalib/MicromegasDriftEvaluator.h | 68 +++++++++---------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc index 567bf092fb..0a57bd2315 100644 --- a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc @@ -21,9 +21,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -208,7 +208,9 @@ namespace return par[itile + 1] + par[0] * z; } - double linear_function(double* x, double* par) +// root fitting does not like const parameters suggested by clang-tidy +// using NOLINT to suppress this warning + double linear_function(double* x, double* par) // NOLINT(readability-non-const-parameter) { return par[0] * x[0] + par[1]; } @@ -632,4 +634,4 @@ void MicromegasDriftEvaluator::evaluate_tracks() break; } } -} \ No newline at end of file +} diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.h b/offline/packages/tpccalib/MicromegasDriftEvaluator.h index 609dafdc4a..43bb4393e9 100644 --- a/offline/packages/tpccalib/MicromegasDriftEvaluator.h +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.h @@ -1,5 +1,5 @@ -#ifndef G4EVAL_MicromegasDriftEvaluator_H -#define G4EVAL_MicromegasDriftEvaluator_H +#ifndef TPCCALIB_MICROMEGASDRIFTEVALUATOR_H +#define TPCCALIB_MICROMEGASDRIFTEVALUATOR_H /* * Bade Sayki June 10th, 2026 -- LANL @@ -22,7 +22,7 @@ class ActsGeometry; class PHG4CylinderGeomContainer; -class TH3F; +class TH3; class TrkrCluster; class TrkrClusterContainer; class SvtxTrackMap; @@ -39,28 +39,28 @@ class MicromegasDriftEvaluator : public SubsysReco struct TrackStateStruct { - unsigned short _layer = 0; - unsigned short _tile = 0; - double _z = 0; - double _y_local = 0; + unsigned short _layer {0}; + unsigned short _tile {0}; + double _z {0}; + double _y_local {0}; }; struct ClusterStruct { - unsigned short _layer = 0; - unsigned short _tile = 0; - double _z = 0; + unsigned short _layer {0}; + unsigned short _tile {0}; + double _z {0}; }; struct TrackStruct { - float _chisquare = 0; - int _ndf = 0; + float _chisquare {0}; + int _ndf {0}; - unsigned int _nclusters_tpc = 0; - unsigned int _nclusters_mvtx = 0; - unsigned int _nclusters_intt = 0; - unsigned int _nclusters_micromegas = 0; + unsigned int _nclusters_tpc {0}; + unsigned int _nclusters_mvtx {0}; + unsigned int _nclusters_intt {0}; + unsigned int _nclusters_micromegas {0}; TrackStateStruct _trk_state_z; ClusterStruct _found_cluster_z; @@ -122,27 +122,27 @@ class MicromegasDriftEvaluator : public SubsysReco std::string make_output_filename(const std::string&) const; void evaluate_tracks(); - Container* m_container = nullptr; - ActsGeometry* m_tGeometry = nullptr; + Container* m_container {nullptr}; + ActsGeometry* m_tGeometry {nullptr}; TpcGlobalPositionWrapper m_globalPositionWrapper; - PHG4CylinderGeomContainer* m_micromegas_geomcontainer = nullptr; - TrkrClusterContainer* m_cluster_map = nullptr; - SvtxTrackMap* m_track_map = nullptr; + PHG4CylinderGeomContainer* m_micromegas_geomcontainer {nullptr}; + TrkrClusterContainer* m_cluster_map {nullptr}; + SvtxTrackMap* m_track_map {nullptr}; - std::string m_trackmapname = "SvtxTrackMap"; + std::string m_trackmapname {"SvtxTrackMap"}; // These are all adjustable in your F4A macro. You should probably put in a better m_plot_filename. - double m_drift_velocity = 0.00747; - unsigned int m_min_tpc_layer = 39; - unsigned int m_max_tpc_layer = 55; - double m_y_local_cut = 22.0; - double m_z_search_win = 3.0; - std::string m_plot_filename = "micromegas_drift_calib.png"; - std::string m_root_filename = "micromegas_drift_calib.root"; - bool m_add_run_segment = true; - int m_segment = -1; - - TH3F* m_hist3D = nullptr; + double m_drift_velocity {0.00747}; + unsigned int m_min_tpc_layer {39}; + unsigned int m_max_tpc_layer {55}; + double m_y_local_cut {22.0}; + double m_z_search_win {3.0}; + std::string m_plot_filename {"micromegas_drift_calib.png"}; + std::string m_root_filename {"micromegas_drift_calib.root"}; + bool m_add_run_segment {true}; + int m_segment {-1}; + + TH3* m_hist3D {nullptr}; }; -#endif \ No newline at end of file +#endif From 1a787d90ebc964ef118c3d822bf702fdbe6f908a Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Wed, 22 Jul 2026 03:26:09 -0400 Subject: [PATCH 853/866] fix GetNode method + Centrality Reco Reset --- .../packages/centrality/CentralityInfov2.cc | 6 ++ .../packages/centrality/CentralityInfov2.h | 2 +- offline/packages/centrality/CentralityReco.cc | 7 ++- .../packages/trigger/MinimumBiasClassifier.cc | 58 ++++++------------- 4 files changed, 31 insertions(+), 42 deletions(-) diff --git a/offline/packages/centrality/CentralityInfov2.cc b/offline/packages/centrality/CentralityInfov2.cc index 5704518fa0..d13c0f3ea2 100644 --- a/offline/packages/centrality/CentralityInfov2.cc +++ b/offline/packages/centrality/CentralityInfov2.cc @@ -11,6 +11,12 @@ void CentralityInfov2::identify(std::ostream &os) const return; } +void CentralityInfov2::Reset() +{ + CentralityInfov1::Reset(); + _centrality_bin_map.clear(); +} + bool CentralityInfov2::has_centrality_bin(const PROP prop_id) const { return _centrality_bin_map.contains(prop_id); diff --git a/offline/packages/centrality/CentralityInfov2.h b/offline/packages/centrality/CentralityInfov2.h index 91362b5e85..05072f47a6 100644 --- a/offline/packages/centrality/CentralityInfov2.h +++ b/offline/packages/centrality/CentralityInfov2.h @@ -13,7 +13,7 @@ class CentralityInfov2 : public CentralityInfov1 ~CentralityInfov2() override = default; void identify(std::ostream &os = std::cout) const override; - void Reset() override {} + void Reset() override; PHObject* CloneMe() const override { return new CentralityInfov2(*this); } void CopyTo(CentralityInfo *info) override; diff --git a/offline/packages/centrality/CentralityReco.cc b/offline/packages/centrality/CentralityReco.cc index 57315d24f4..46aaf24562 100644 --- a/offline/packages/centrality/CentralityReco.cc +++ b/offline/packages/centrality/CentralityReco.cc @@ -258,11 +258,14 @@ int CentralityReco::process_event(PHCompositeNode *topNode) } // Get Nodes from the Tree - if (GetNodes(topNode)) + int ret = GetNodes(topNode); + if (ret != Fun4AllReturnCodes::EVENT_OK) { - return Fun4AllReturnCodes::ABORTRUN; + return ret; } + m_central->Reset(); + if (!m_mb_info->isAuAuMinimumBias()) { return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index ba7e02c3b0..ab47326b86 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -42,44 +42,24 @@ int MinimumBiasClassifier::InitRun(PHCompositeNode *topNode) std::cout << __FILE__ << " :: " << __FUNCTION__ << std::endl; } - if (m_species == MinimumBiasInfo::SPECIES::AUAU) - { - m_useZDC = true; - m_box_cut = true; - m_hit_cut = 2; - m_max_charge_cut = 2100; - m_mbd_charge_cut = 0.5; - m_mbd_time_cut = 25.; - m_z_vtx_cut = 60.; - m_mbd_north_cut = 10.; - m_mbd_south_cut = 150.; - m_zdc_cut = 60.; - } if (m_species == MinimumBiasInfo::SPECIES::OO) { - m_useZDC = false; - m_box_cut = false; - m_hit_cut = 1; - m_max_charge_cut = 400; - m_mbd_charge_cut = 0.4; - m_mbd_time_cut = 20.; - m_z_vtx_cut = 150.; - m_mbd_north_cut = 10.; - m_mbd_south_cut = 150.; - m_zdc_cut = 60.; - } - if (m_species == MinimumBiasInfo::SPECIES::PP) - { - m_useZDC = false; - m_box_cut = false; - m_hit_cut = 1; - m_max_charge_cut = 300; - m_mbd_charge_cut = 0.4; - m_mbd_time_cut = 20.; - m_z_vtx_cut = 60.; - m_mbd_north_cut = 10.; - m_mbd_south_cut = 150.; - m_zdc_cut = 60.; + m_useZDC = false; + m_box_cut = false; + m_hit_cut = 1; + m_max_charge_cut = 400; + m_mbd_charge_cut = 0.4; + m_mbd_time_cut = 20.; + m_z_vtx_cut = 150.; + } + else if (m_species == MinimumBiasInfo::SPECIES::PP) + { + m_useZDC = false; + m_box_cut = false; + m_hit_cut = 1; + m_max_charge_cut = 300; + m_mbd_charge_cut = 0.4; + m_mbd_time_cut = 20.; } CDBInterface *m_cdb = CDBInterface::instance(); @@ -289,9 +269,10 @@ int MinimumBiasClassifier::process_event(PHCompositeNode *topNode) } // Get Nodes from the Tree - if (GetNodes(topNode)) + int ret = GetNodes(topNode); + if (ret != Fun4AllReturnCodes::EVENT_OK) { - return Fun4AllReturnCodes::EVENT_OK; + return ret; } if (FillMinimumBiasInfo()) @@ -376,7 +357,6 @@ void MinimumBiasClassifier::CreateNodes(PHCompositeNode *topNode) PHCompositeNode *detNode = dynamic_cast(dstIter.findFirst("PHCompositeNode", "GLOBAL")); if (!detNode) { - std::cout << PHWHERE << "Detector Node missing, making one" << std::endl; detNode = new PHCompositeNode("GLOBAL"); dstNode->addNode(detNode); } From 491b5240a2292e9e55481f649304b9ba0de8b091 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 22 Jul 2026 08:24:42 -0400 Subject: [PATCH 854/866] auto generate pcm files from ROOTDICTS --- offline/packages/tpccalib/Makefile.am | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpccalib/Makefile.am b/offline/packages/tpccalib/Makefile.am index ad4dad6bc4..394740acea 100644 --- a/offline/packages/tpccalib/Makefile.am +++ b/offline/packages/tpccalib/Makefile.am @@ -60,12 +60,8 @@ ROOTDICTS = \ TpcSpaceChargeMatrixContainerv2_Dict.cc pcmdir = $(libdir) -nobase_dist_pcm_DATA = \ - MicromegasDriftEvaluator_Dict_rdict.pcm \ - SiliconDriftEvaluator_Dict_rdict.pcm \ - TpcSpaceChargeMatrixContainer_Dict_rdict.pcm \ - TpcSpaceChargeMatrixContainerv1_Dict_rdict.pcm \ - TpcSpaceChargeMatrixContainerv2_Dict_rdict.pcm +# more elegant way to create pcm files (without listing them) +nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) libtpccalib_io_la_SOURCES = \ $(ROOTDICTS) \ From 577e633c2eaf329dd9541fad91326f038c0d908f Mon Sep 17 00:00:00 2001 From: bkimelman Date: Wed, 22 Jul 2026 08:41:51 -0400 Subject: [PATCH 855/866] additional clang-tidy fixes --- offline/packages/tpc/LaserClusterizer.cc | 13 ++++++++----- offline/packages/tpccalib/TpcLaminationFitting.cc | 5 ++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 9caa41ed76..7cf2ea51ba 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -77,13 +77,13 @@ namespace { PHG4TpcGeomContainer *geom_container = nullptr; ActsGeometry *tGeometry = nullptr; - std::vector hitsets; - std::vector layers; + std::vector hitsets = {}; + std::vector layers = {}; bool side = false; unsigned int sector = 0; unsigned int module = 0; - std::vector cluster_vector; - std::vector cluster_key_vector; + std::vector cluster_vector = {}; + std::vector cluster_key_vector = {}; double adc_threshold = 74.4; int peakTimeBin = 325; int layerMin = 1; @@ -433,7 +433,10 @@ namespace findConnectedRegions3(clusHits, maxADCKey, my_data.Verbosity); unsigned int nHits = clusHits.size(); - if(nHits == 0) return; + if(nHits == 0) + { + return; + } double layerSum = 0.0; double iphiSum = 0.0; diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 9f3bf2c47e..df66d95f94 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -316,7 +316,10 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) const auto &[cmkey, cmclus_orig] = *cmitr; LaserCluster *cmclus = cmclus_orig; - if(cmclus->getNLayers() <= m_nLayerCut) continue; + if(cmclus->getNLayers() <= m_nLayerCut) + { + continue; + } bool side = (bool) TpcDefs::getSide(cmkey); double weight = 1.0; From f124eca313bb1f8cdcedac3263258ce5bfa2fce0 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 22 Jul 2026 10:31:23 -0400 Subject: [PATCH 856/866] revert surface lookup --- offline/packages/trackreco/PHActsTrkFitter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index be0d0c14f4..0a2b4ff722 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1039,7 +1039,7 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const const auto* nextSurface = surfaces.at(i + 1); const auto nextVolume = nextSurface->geometryId().volume(); - const Acts::Vector3 next_center = nextSurface->center(m_tGeometry->geometry().getGeoContext()); + const Acts::Vector3 next_center = surface->center(m_tGeometry->geometry().getGeoContext()); double nextRadius = sqrt(next_center.x()*next_center.x()+next_center.y()*next_center.y()); /// Implement a check to ensure surfaces are sorted From bfcf5b4b74558901db10232b2ea499f1165fcbd2 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 22 Jul 2026 10:48:45 -0400 Subject: [PATCH 857/866] Generate TFile name which makes TFile binary reproducible --- offline/framework/phool/Makefile.am | 2 ++ offline/framework/phool/PHUtils.cc | 19 +++++++++++++++++++ offline/framework/phool/PHUtils.h | 13 +++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 offline/framework/phool/PHUtils.cc create mode 100644 offline/framework/phool/PHUtils.h diff --git a/offline/framework/phool/Makefile.am b/offline/framework/phool/Makefile.am index 22cd13f65d..3af3c76ec8 100644 --- a/offline/framework/phool/Makefile.am +++ b/offline/framework/phool/Makefile.am @@ -60,6 +60,7 @@ libphool_la_SOURCES = \ PHTimer.cc \ PHTimeServer.cc \ PHTimeStamp.cc \ + PHUtils.cc \ recoConsts.cc pkginclude_HEADERS = \ @@ -87,6 +88,7 @@ pkginclude_HEADERS = \ PHTimeServer.h \ PHTimeStamp.h \ PHTypedNodeIterator.h \ + PHUtils.h \ recoConsts.h \ RunnumberRange.h \ sphenix_constants.h diff --git a/offline/framework/phool/PHUtils.cc b/offline/framework/phool/PHUtils.cc new file mode 100644 index 0000000000..34bd50f49f --- /dev/null +++ b/offline/framework/phool/PHUtils.cc @@ -0,0 +1,19 @@ +#include "PHUtils.h" + +#include + +#include +#include + +std::string PHUtils::CreateReproducibleTFileName(const std::string &filename) +{ + std::string outfilename = filename; + if (filename.empty()) + { + std::cout << PHWHERE << " called with empty filename string, returning empty string" << std::endl; + return outfilename; + } + std::filesystem::path p = filename; + outfilename = outfilename + std::string("?reproducible=") + std::string(p.filename()); + return outfilename; +} diff --git a/offline/framework/phool/PHUtils.h b/offline/framework/phool/PHUtils.h new file mode 100644 index 0000000000..5951f2ff16 --- /dev/null +++ b/offline/framework/phool/PHUtils.h @@ -0,0 +1,13 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef PHOOL_PHUTILS_H +#define PHOOL_PHUTILS_H + +#include + +namespace PHUtils +{ + std::string CreateReproducibleTFileName(const std::string &filename); +} + +#endif From 940f1599f9b45a4e1229d941a86b60b0630fc3e4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 22 Jul 2026 10:56:08 -0400 Subject: [PATCH 858/866] create binary identical TFiles for identical content in PHTFileServer --- offline/framework/fun4all/PHTFileServer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/framework/fun4all/PHTFileServer.h b/offline/framework/fun4all/PHTFileServer.h index dc53700f90..31ed067341 100644 --- a/offline/framework/fun4all/PHTFileServer.h +++ b/offline/framework/fun4all/PHTFileServer.h @@ -13,6 +13,8 @@ #ifndef FUN4ALL_PHTFILESERVER_H #define FUN4ALL_PHTFILESERVER_H +#include + #include #include @@ -71,7 +73,7 @@ class PHTFileServer public: //! constructor SafeTFile(const std::string& filename, const std::string& type = "RECREATE") - : TFile(filename.c_str(), type.c_str()) + : TFile(PHUtils::CreateReproducibleTFileName(filename).c_str(), type.c_str()) , _filename(filename) , _counter(1) { From 61820f8facdd5269c51ad6c0ab64e85bf36a94f6 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 22 Jul 2026 11:00:16 -0400 Subject: [PATCH 859/866] create binary identical TFiles for identical content in CDB objects --- offline/database/cdbobjects/CDBHistos.cc | 3 ++- offline/database/cdbobjects/CDBTF.cc | 3 ++- offline/database/cdbobjects/CDBTTree.cc | 5 +++-- offline/database/cdbobjects/Makefile.am | 3 +++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/offline/database/cdbobjects/CDBHistos.cc b/offline/database/cdbobjects/CDBHistos.cc index 2fcf5a1bad..b4858e0b6c 100644 --- a/offline/database/cdbobjects/CDBHistos.cc +++ b/offline/database/cdbobjects/CDBHistos.cc @@ -36,7 +36,8 @@ void CDBHistos::WriteCDBHistos() return; } std::string currdir = gDirectory->GetPath(); - TFile *f = TFile::Open(m_Filename.c_str(), "RECREATE"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(m_Filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); for (auto &iter : m_HistoMap) { iter.second->Write(); diff --git a/offline/database/cdbobjects/CDBTF.cc b/offline/database/cdbobjects/CDBTF.cc index b80a63666f..89fad62695 100644 --- a/offline/database/cdbobjects/CDBTF.cc +++ b/offline/database/cdbobjects/CDBTF.cc @@ -36,7 +36,8 @@ void CDBTF::WriteCDBTF() return; } std::string currdir = gDirectory->GetPath(); - TFile *f = TFile::Open(m_Filename.c_str(), "RECREATE"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(m_Filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); for (auto &iter : m_TFMap) { iter.second->Write(); diff --git a/offline/database/cdbobjects/CDBTTree.cc b/offline/database/cdbobjects/CDBTTree.cc index f43635ce5f..20cd10f399 100644 --- a/offline/database/cdbobjects/CDBTTree.cc +++ b/offline/database/cdbobjects/CDBTTree.cc @@ -1,5 +1,6 @@ #include "CDBTTree.h" +#include #include #include // for TBranch @@ -470,8 +471,8 @@ void CDBTTree::WriteCDBTTree() } std::string currdir = gDirectory->GetPath(); - - TFile *f = TFile::Open(m_Filename.c_str(), "RECREATE"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(m_Filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); if (!empty_single) { WriteSingleCDBTTree(); diff --git a/offline/database/cdbobjects/Makefile.am b/offline/database/cdbobjects/Makefile.am index 5df1880ad3..d2922bbab0 100644 --- a/offline/database/cdbobjects/Makefile.am +++ b/offline/database/cdbobjects/Makefile.am @@ -15,6 +15,9 @@ libcdbobjects_la_SOURCES = \ CDBTTree.cc libcdbobjects_la_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -lphool \ `root-config --libs` ############################################## From e350b46e147ed793d4d013accf5269608c098515 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 22 Jul 2026 11:11:46 -0400 Subject: [PATCH 860/866] create binary identical TFiles for identical content in PdbParameterMapContainer --- offline/database/pdbcal/base/PdbParameterMapContainer.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/database/pdbcal/base/PdbParameterMapContainer.cc b/offline/database/pdbcal/base/PdbParameterMapContainer.cc index 6d10797a60..abb4a2f7dc 100644 --- a/offline/database/pdbcal/base/PdbParameterMapContainer.cc +++ b/offline/database/pdbcal/base/PdbParameterMapContainer.cc @@ -3,6 +3,7 @@ #include "PdbParameterMap.h" #include +#include #include #include @@ -111,7 +112,8 @@ int PdbParameterMapContainer::WriteToFile(const std::string &detector_name, std::cout << "PdbParameterMapContainer::WriteToFile - save to " << fullpath.str() << std::endl; - TFile *f = TFile::Open(fullpath.str().c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(fullpath.str()); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); PdbParameterMapContainer *container = new PdbParameterMapContainer(); for (std::map::const_iterator it = From 5290637c9402335597c6349b876e59d846841781 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 22 Jul 2026 11:17:04 -0400 Subject: [PATCH 861/866] create binary identical TFiles for identical content in PHParameter --- offline/database/PHParameter/PHParameters.cc | 7 +++++-- offline/database/PHParameter/PHParametersContainer.cc | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/offline/database/PHParameter/PHParameters.cc b/offline/database/PHParameter/PHParameters.cc index 1f8fea5f14..5357ce9c4c 100644 --- a/offline/database/PHParameter/PHParameters.cc +++ b/offline/database/PHParameter/PHParameters.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -384,7 +385,8 @@ int PHParameters::WriteToCDBFile(const std::string &filename) { PdbParameterMap *myparm = new PdbParameterMap(); CopyToPdbParameterMap(myparm); - TFile *f = TFile::Open(filename.c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); myparm->Write(); delete f; delete myparm; @@ -416,7 +418,8 @@ int PHParameters::WriteToFile(const std::string &extension, const std::string &d PdbParameterMap *myparm = new PdbParameterMap(); CopyToPdbParameterMap(myparm); - TFile *f = TFile::Open(fullpath.str().c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(fullpath.str()); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); // force xml file writing to use extended precision shown experimentally // to not modify input parameters (.17g) std::string floatformat = TBufferXML::GetFloatFormat(); diff --git a/offline/database/PHParameter/PHParametersContainer.cc b/offline/database/PHParameter/PHParametersContainer.cc index dbe5e0f633..6899838380 100644 --- a/offline/database/PHParameter/PHParametersContainer.cc +++ b/offline/database/PHParameter/PHParametersContainer.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -148,7 +149,8 @@ int PHParametersContainer::WriteToFile(const std::string &extension, const std:: PdbParameterMapContainer *myparm = new PdbParameterMapContainer(); CopyToPdbParameterMapContainer(myparm); - TFile *f = TFile::Open(fullpath.str().c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(fullpath.str()); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); // force xml file writing to use extended precision shown experimentally // to not modify input parameters (.15e) std::string floatformat = TBufferXML::GetFloatFormat(); From 29102d1b7360198f1e5fb0fd02f0b8b730e37025 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Wed, 22 Jul 2026 11:20:43 -0400 Subject: [PATCH 862/866] add missing include --- offline/database/cdbobjects/CDBHistos.cc | 2 ++ offline/database/cdbobjects/CDBTF.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/offline/database/cdbobjects/CDBHistos.cc b/offline/database/cdbobjects/CDBHistos.cc index b4858e0b6c..0776fa0b47 100644 --- a/offline/database/cdbobjects/CDBHistos.cc +++ b/offline/database/cdbobjects/CDBHistos.cc @@ -1,5 +1,7 @@ #include "CDBHistos.h" +#include + #include // for TClass #include // for TIter #include // for TDirectoryAtomicAdapter, TDirectory, gDirec... diff --git a/offline/database/cdbobjects/CDBTF.cc b/offline/database/cdbobjects/CDBTF.cc index 89fad62695..6b80c825f3 100644 --- a/offline/database/cdbobjects/CDBTF.cc +++ b/offline/database/cdbobjects/CDBTF.cc @@ -1,5 +1,7 @@ #include "CDBTF.h" +#include + #include // for TClass #include // for TIter #include // for TDirectoryAtomicAdapter, TDirectory, gDirec... From 211848c8c077bd6b4cac97a2eb7df596216212b8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 22 Jul 2026 11:58:25 -0400 Subject: [PATCH 863/866] use proper include guard --- offline/packages/trackbase/LaserCluster.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/packages/trackbase/LaserCluster.h b/offline/packages/trackbase/LaserCluster.h index d6431c56e4..919d36bd60 100644 --- a/offline/packages/trackbase/LaserCluster.h +++ b/offline/packages/trackbase/LaserCluster.h @@ -7,9 +7,11 @@ #ifndef TRACKBASE_LASERCLUSTER_H #define TRACKBASE_LASERCLUSTER_H +#include "TpcDefs.h" + #include -#include + #include #include From 7aef5cdc9a9c3324259e1762de1fbe2716b3897f Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 22 Jul 2026 12:09:14 -0400 Subject: [PATCH 864/866] a better fix which properly handles approach surfaces --- offline/packages/trackreco/PHActsTrkFitter.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 0a2b4ff722..3e51729785 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -1030,7 +1030,13 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const for (unsigned int i = 0; i < surfaces.size() - 1; i++) { + const auto& surface = surfaces.at(i); + if (std::find(m_materialSurfaces.begin(), m_materialSurfaces.end(), surface) != m_materialSurfaces.end()) + { + continue; + } + const auto thisVolume = surface->geometryId().volume(); const Acts::Vector3 this_center = surface->center(m_tGeometry->geometry().getGeoContext()); @@ -1039,9 +1045,13 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const const auto* nextSurface = surfaces.at(i + 1); const auto nextVolume = nextSurface->geometryId().volume(); - const Acts::Vector3 next_center = surface->center(m_tGeometry->geometry().getGeoContext()); + const Acts::Vector3 next_center = nextSurface->center(m_tGeometry->geometry().getGeoContext()); double nextRadius = sqrt(next_center.x()*next_center.x()+next_center.y()*next_center.y()); - + + if (surface->geometryId().approach() == 2 || nextSurface->geometryId().approach() == 2) + { + continue; + } /// Implement a check to ensure surfaces are sorted if (nextVolume == thisVolume) { @@ -1052,7 +1062,8 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const << "PHActsTrkFitter::checkSurfaceVec - " << "Surface not in order... removing surface" << surface->geometryId() << " with radius " << thisRadius << std::endl; - + std::cout << " approach " << nextSurface->geometryId().approach() << " volume " << nextSurface->geometryId().volume() << " layer " << nextSurface->geometryId().layer() << std::endl; + std::cout << " Next surface is " << nextSurface->geometryId() << " with radius " << nextRadius << std::endl; surfaces.erase(surfaces.begin() + i); /// Subtract one so we don't skip a surface From f6ae650f50df016fba3fe12f515c96be8acaa371 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Wed, 22 Jul 2026 20:50:55 -0400 Subject: [PATCH 865/866] clang-tidy --- offline/packages/tpc/LaserClusterizer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 7cf2ea51ba..a965cb7b58 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -77,13 +77,13 @@ namespace { PHG4TpcGeomContainer *geom_container = nullptr; ActsGeometry *tGeometry = nullptr; - std::vector hitsets = {}; - std::vector layers = {}; + std::vector hitsets; + std::vector layers; bool side = false; unsigned int sector = 0; unsigned int module = 0; - std::vector cluster_vector = {}; - std::vector cluster_key_vector = {}; + std::vector cluster_vector; + std::vector cluster_key_vector; double adc_threshold = 74.4; int peakTimeBin = 325; int layerMin = 1; From de59c12ae8ed425092b2d14bdd3c85e2b2bc46ce Mon Sep 17 00:00:00 2001 From: JAEBEOm PARK Date: Thu, 23 Jul 2026 18:06:50 -0400 Subject: [PATCH 866/866] remove redundant explicit Reset in CentralityReco::process_event The node tree reset already calls CentralityInfov2::Reset() after each event now that it is properly implemented. Co-Authored-By: Claude Fable 5 --- offline/packages/centrality/CentralityReco.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/centrality/CentralityReco.cc b/offline/packages/centrality/CentralityReco.cc index 46aaf24562..d77064ecc7 100644 --- a/offline/packages/centrality/CentralityReco.cc +++ b/offline/packages/centrality/CentralityReco.cc @@ -264,8 +264,6 @@ int CentralityReco::process_event(PHCompositeNode *topNode) return ret; } - m_central->Reset(); - if (!m_mb_info->isAuAuMinimumBias()) { return Fun4AllReturnCodes::EVENT_OK;

-De3-W3X>BRrnOz#mo-Ew$~n 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%0Dv?<#FMI;J-d9YP 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 WxBu^g=hOWgoKews4U9Gs%>Mww3R~L% literal 0 HcmV?d00001 From 6dd4feed1f9ad156d07c07bc91552ea75adf31a9 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Tue, 12 May 2026 22:19:12 -0400 Subject: [PATCH 504/866] CaloTowerStatus: Refactor hot tower identification and add default threshold check - Added a logical split to handle the default behavior: if the z-score threshold is untouched, the code now relies strictly on the non-zero hotMap values. - Refactored the complex if-statement for custom thresholds into an if/else block using descriptive boolean variables (`is_dead`, `exceeds_zscore_limit`, `is_low_yield_cold`) for better readability. - Replaced the C-style `std::fabs` with the modern C++ standard `std::abs`. - Guarded the entire evaluation block behind `m_doHotMap` to improve clarity. --- offline/packages/CaloReco/CaloTowerStatus.cc | 28 ++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index f9e63348b6..b7827ea32a 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -234,12 +234,30 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) { m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); } - if (( hotMap_val == 1 || // dead - std::fabs(z_score) > z_score_threshold || // hot or cold - (hotMap_val == 3 && z_score >= -1 * z_score_threshold_default)) // cold part 2 - && m_doHotMap) + if (m_doHotMap) { - m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); + bool is_hot_tower = false; + + // 1. Default behavior: simply rely on the hotMap value + if (z_score_threshold == z_score_threshold_default) + { + is_hot_tower = (hotMap_val != 0); + } + // 2. Custom behavior: evaluate based on the custom z_score threshold + else + { + bool is_dead = (hotMap_val == 1); + bool exceeds_zscore_limit = (std::abs(z_score) > z_score_threshold); // Captures both hot and cold by sigma + bool is_low_yield_cold = (hotMap_val == 3 && z_score >= -1 * z_score_threshold_default); // Captures the mean-based cold towers + + is_hot_tower = (is_dead || exceeds_zscore_limit || is_low_yield_cold); + } + + // Apply the result + if (is_hot_tower) + { + m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); + } } if (chi2 > std::min(std::max(badChi2_treshold_const, adc * adc * badChi2_treshold_quadratic),badChi2_treshold_max)) { From 6589011221aabb717be317596a87dae67e0156bb Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Wed, 13 May 2026 14:26:29 -0400 Subject: [PATCH 505/866] Bad Tower Status: Use Positive Status Using hotMap_val != 0 treats the CDB missing-value as a hot tower: CDBTTree::GetIntValue returns std::numeric_limits::min() when the channel or field is absent, and that value is nonzero. This is a behavior regression from the previous explicit status checks and could mask towers if a calibration entry is missing or malformed; limit this default path to valid positive/known status codes instead of any nonzero value. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- offline/packages/CaloReco/CaloTowerStatus.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index b7827ea32a..998244ecf0 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -238,10 +238,10 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) { bool is_hot_tower = false; - // 1. Default behavior: simply rely on the hotMap value + // 1. Default behavior: rely on valid positive hotMap status codes only if (z_score_threshold == z_score_threshold_default) { - is_hot_tower = (hotMap_val != 0); + is_hot_tower = (hotMap_val > 0); } // 2. Custom behavior: evaluate based on the custom z_score threshold else From ea5838429ff86f205058cdf062dd1d9f728fc499 Mon Sep 17 00:00:00 2001 From: Apurva Narde <58493193+Steepspace@users.noreply.github.com> Date: Wed, 13 May 2026 14:53:50 -0400 Subject: [PATCH 506/866] CaloTowerStatus: Refactor CDBTTree management for memory efficiency Refactored the calibration loading process to ensure heavy tree objects are freed from memory immediately after use. - Moved m_cdbttree_chi2 and m_cdbttree_hotMap from class members to local variables within InitRun to minimize the memory footprint during the event processing loop. - Updated the LoadCalib method to accept CDBTTree pointers as arguments. - Implemented immediate deletion of the tree objects after populating the m_cdbInfo_vec cache. - Simplified the class destructor as it no longer needs to manage these pointers. --- offline/packages/CaloReco/CaloTowerStatus.cc | 35 +++++++++++--------- offline/packages/CaloReco/CaloTowerStatus.h | 5 +-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 998244ecf0..0727ba735d 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -47,8 +47,6 @@ CaloTowerStatus::~CaloTowerStatus() { std::cout << "CaloTowerStatus::~CaloTowerStatus() Calling dtor" << std::endl; } - delete m_cdbttree_chi2; - delete m_cdbttree_hotMap; } //____________________________________________________________________________.. @@ -78,6 +76,8 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_detector = "SEPD"; } + CDBTTree *cdbttree_chi2 = nullptr; + m_calibName_chi2 = m_detector + "_hotTowers_fracBadChi2"; m_fieldname_chi2 = "fraction"; @@ -86,20 +86,20 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) { calibdir_chi2 = m_directURL_chi2; std::cout << "CaloTowerStatus::InitRun: Using direct URL override for chi2: " << calibdir_chi2 << std::endl; - m_cdbttree_chi2 = new CDBTTree(calibdir_chi2); + cdbttree_chi2 = new CDBTTree(calibdir_chi2); } else { calibdir_chi2 = CDBInterface::instance()->getUrl(m_calibName_chi2); if (!calibdir_chi2.empty()) { - m_cdbttree_chi2 = new CDBTTree(calibdir_chi2); + cdbttree_chi2 = new CDBTTree(calibdir_chi2); if (Verbosity() > 0) { std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_chi2 << " Doing isHot for frac bad chi2" << std::endl; } } - else + else { if (m_doAbortNoChi2) { @@ -114,6 +114,8 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) } } + CDBTTree *cdbttree_hotMap = nullptr; + m_calibName_hotMap = m_detector + "_BadTowerMap"; m_fieldname_hotMap = "status"; m_fieldname_z_score = m_detector + "_sigma"; @@ -123,14 +125,14 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) { calibdir_hotMap = m_directURL_hotMap; std::cout << "CaloTowerStatus::InitRun: Using direct URL override for hot map: " << calibdir_hotMap << std::endl; - m_cdbttree_hotMap = new CDBTTree(calibdir_hotMap); + cdbttree_hotMap = new CDBTTree(calibdir_hotMap); } else { calibdir_hotMap = CDBInterface::instance()->getUrl(m_calibName_hotMap); if (!calibdir_hotMap.empty()) { - m_cdbttree_hotMap = new CDBTTree(calibdir_hotMap); + cdbttree_hotMap = new CDBTTree(calibdir_hotMap); if (Verbosity() > 1) { std::cout << "CaloTowerStatus::Init " << m_detector << " hot map found " << m_calibName_hotMap << " Doing isHot" << std::endl; @@ -148,7 +150,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) { std::cout << "CaloTowerStatus::InitRun hot map info, " << m_calibName_hotMap << " not found, not doing isHot" << std::endl; } - } + } } if (Verbosity() > 0) @@ -170,7 +172,10 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) try { CreateNodeTree(topNode); - LoadCalib(); + LoadCalib(cdbttree_chi2, cdbttree_hotMap); + + delete cdbttree_chi2; + delete cdbttree_hotMap; } catch (std::exception &e) { @@ -184,7 +189,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -void CaloTowerStatus::LoadCalib() +void CaloTowerStatus::LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotMap) { unsigned int ntowers = m_raw_towers->size(); m_cdbInfo_vec.resize(ntowers); @@ -193,14 +198,14 @@ void CaloTowerStatus::LoadCalib() { unsigned int key = m_raw_towers->encode_key(channel); - if (m_doHotChi2) + if (m_doHotChi2 && cdbttree_chi2) { - m_cdbInfo_vec[channel].fraction_badChi2 = m_cdbttree_chi2->GetFloatValue(key, m_fieldname_chi2); + m_cdbInfo_vec[channel].fraction_badChi2 = cdbttree_chi2->GetFloatValue(key, m_fieldname_chi2); } - if (m_doHotMap) + if (m_doHotMap && cdbttree_hotMap) { - m_cdbInfo_vec[channel].hotMap_val = m_cdbttree_hotMap->GetIntValue(key, m_fieldname_hotMap); - m_cdbInfo_vec[channel].z_score = m_cdbttree_hotMap->GetFloatValue(key, m_fieldname_z_score); + m_cdbInfo_vec[channel].hotMap_val = cdbttree_hotMap->GetIntValue(key, m_fieldname_hotMap); + m_cdbInfo_vec[channel].z_score = cdbttree_hotMap->GetFloatValue(key, m_fieldname_z_score); } } } diff --git a/offline/packages/CaloReco/CaloTowerStatus.h b/offline/packages/CaloReco/CaloTowerStatus.h index 9c261155c4..6ae95a5d0f 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.h +++ b/offline/packages/CaloReco/CaloTowerStatus.h @@ -98,9 +98,6 @@ class CaloTowerStatus : public SubsysReco private: TowerInfoContainer *m_raw_towers{nullptr}; - CDBTTree *m_cdbttree_chi2{nullptr}; - CDBTTree *m_cdbttree_hotMap{nullptr}; - bool m_doHotChi2{true}; bool m_doHotMap{true}; bool m_doAbortNoHotMap{false}; @@ -127,7 +124,7 @@ class CaloTowerStatus : public SubsysReco float z_score_threshold = {5}; float z_score_threshold_default = {5}; - void LoadCalib(); + void LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotMap); struct CDBInfo { From 1c6b4f480350df179d025c890c8f49aeab264f8a Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 14 May 2026 14:10:34 -0400 Subject: [PATCH 507/866] cleanup, simplify --- offline/packages/CaloReco/CaloTowerStatus.cc | 71 +++++--------------- offline/packages/CaloReco/CaloTowerStatus.h | 7 +- 2 files changed, 17 insertions(+), 61 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 0727ba735d..f9cc5c039d 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -8,27 +8,17 @@ #include -#include - #include #include // for SubsysReco #include -#include // for PHIODataNode -#include // for PHNode -#include // for PHNodeIterator -#include // for PHObject #include -#include -#include #include +#include #include -#include // for exit -#include // for exception -#include // for operator<<, basic_ostream -#include // for runtime_error +#include // for operator<<, basic_ostream //____________________________________________________________________________.. CaloTowerStatus::CaloTowerStatus(const std::string &name) @@ -40,20 +30,9 @@ CaloTowerStatus::CaloTowerStatus(const std::string &name) } } -//____________________________________________________________________________.. -CaloTowerStatus::~CaloTowerStatus() -{ - if (Verbosity() > 0) - { - std::cout << "CaloTowerStatus::~CaloTowerStatus() Calling dtor" << std::endl; - } -} - //____________________________________________________________________________.. int CaloTowerStatus::InitRun(PHCompositeNode *topNode) { - PHNodeIterator nodeIter(topNode); - if (m_dettype == CaloTowerDefs::CEMC) { m_detector = "CEMC"; @@ -76,21 +55,19 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_detector = "SEPD"; } - CDBTTree *cdbttree_chi2 = nullptr; + CDBTTree *cdbttree_chi2{nullptr}; m_calibName_chi2 = m_detector + "_hotTowers_fracBadChi2"; m_fieldname_chi2 = "fraction"; - std::string calibdir_chi2; if (!m_directURL_chi2.empty()) { - calibdir_chi2 = m_directURL_chi2; - std::cout << "CaloTowerStatus::InitRun: Using direct URL override for chi2: " << calibdir_chi2 << std::endl; - cdbttree_chi2 = new CDBTTree(calibdir_chi2); + std::cout << "CaloTowerStatus::InitRun: Using direct URL override for chi2: " << m_directURL_chi2 << std::endl; + cdbttree_chi2 = new CDBTTree(m_directURL_chi2); } else { - calibdir_chi2 = CDBInterface::instance()->getUrl(m_calibName_chi2); + std::string calibdir_chi2 = CDBInterface::instance()->getUrl(m_calibName_chi2); if (!calibdir_chi2.empty()) { cdbttree_chi2 = new CDBTTree(calibdir_chi2); @@ -155,33 +132,16 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) if (Verbosity() > 0) { - std::cout << "CaloTowerStatus::Init " << m_detector << " doing hotBadChi2=" << std::boolalpha << m_doHotChi2 << " doing hot map=" << std::boolalpha << m_doHotMap << std::endl; + std::cout << "CaloTowerStatus::Init " << m_detector << " doing hotBadChi2=" << std::boolalpha << m_doHotChi2 << " doing hot map=" << std::boolalpha << m_doHotMap << std::endl; } - PHNodeIterator iter(topNode); + LoadCalib(cdbttree_chi2, cdbttree_hotMap); - // Looking for the DST node - PHCompositeNode *dstNode; - dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << Name() << "::" << m_detector << "::" << __PRETTY_FUNCTION__ - << "DST Node missing, doing nothing." << std::endl; - exit(1); - } - try - { - CreateNodeTree(topNode); - LoadCalib(cdbttree_chi2, cdbttree_hotMap); + delete cdbttree_chi2; + delete cdbttree_hotMap; + + CreateNodeTree(topNode); - delete cdbttree_chi2; - delete cdbttree_hotMap; - } - catch (std::exception &e) - { - std::cout << e.what() << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } if (Verbosity() > 0) { topNode->print(); @@ -264,7 +224,7 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); } } - if (chi2 > std::min(std::max(badChi2_treshold_const, adc * adc * badChi2_treshold_quadratic),badChi2_treshold_max)) + if (chi2 > std::min(std::max(badChi2_treshold_const, adc * adc * badChi2_treshold_quadratic), badChi2_treshold_max)) { m_raw_towers->get_tower_at_channel(channel)->set_isBadChi2(true); } @@ -283,10 +243,9 @@ void CaloTowerStatus::CreateNodeTree(PHCompositeNode *topNode) if (!m_raw_towers) { std::cout << Name() << "::" << m_detector.c_str() << "::" << __PRETTY_FUNCTION__ - << " " << RawTowerNodeName << " Node missing, doing bail out!" + << " " << RawTowerNodeName << " Node missing, exiting!" << std::endl; - throw std::runtime_error( - "Failed to find " + RawTowerNodeName + " node in CaloTowerStatus::CreateNodes"); + gSystem->Exit(1); } return; diff --git a/offline/packages/CaloReco/CaloTowerStatus.h b/offline/packages/CaloReco/CaloTowerStatus.h index 6ae95a5d0f..21cb652634 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.h +++ b/offline/packages/CaloReco/CaloTowerStatus.h @@ -5,11 +5,8 @@ #include "CaloTowerDefs.h" -#include // for TowerInfoContainer, TowerIn... - #include -#include #include #include @@ -22,7 +19,7 @@ class CaloTowerStatus : public SubsysReco public: CaloTowerStatus(const std::string &name = "CaloTowerStatus"); - ~CaloTowerStatus() override; + ~CaloTowerStatus() override = default; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -118,7 +115,7 @@ class CaloTowerStatus : public SubsysReco std::string m_directURL_chi2; float badChi2_treshold_const = {1e4}; - float badChi2_treshold_quadratic = {1./100}; + float badChi2_treshold_quadratic = {1. / 100}; float badChi2_treshold_max = {1e8}; float fraction_badChi2_threshold = {0.01}; float z_score_threshold = {5}; From 7fff3252e3eb9012bac12cacd4066f1ba7215e91 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Thu, 14 May 2026 14:21:33 -0400 Subject: [PATCH 508/866] need to create node tree earlier --- offline/packages/CaloReco/CaloTowerStatus.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index f9cc5c039d..4cba2f1fcf 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -55,6 +55,8 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_detector = "SEPD"; } + CreateNodeTree(topNode); + CDBTTree *cdbttree_chi2{nullptr}; m_calibName_chi2 = m_detector + "_hotTowers_fracBadChi2"; @@ -140,8 +142,6 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) delete cdbttree_chi2; delete cdbttree_hotMap; - CreateNodeTree(topNode); - if (Verbosity() > 0) { topNode->print(); From bdf2ea497eb26d18012f3bccd6285d9223b49133 Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Fri, 15 May 2026 20:59:47 -0400 Subject: [PATCH 509/866] (1) Add Subsys reco module (StreamingBcoLumiReco) for producing DST from BcoLumiReco output that contains the gl1 bco, the corresponding streaming window, a boolean to encode if the gl1 bco is usable for analysis, and the luminosity in the streaming data. (2) Add corresponding PHObject classes for storing the luminosity and gl1 info in the DST. (3) Add Subsys reco module to test new DST output. --- offline/packages/bcolumicount/BcoLumiCheck.cc | 71 ----- offline/packages/bcolumicount/BcoLumiCheck.h | 22 -- offline/packages/bcolumicount/Makefile.am | 29 +- .../packages/bcolumicount/StreamingBcoInfo.cc | 23 ++ .../packages/bcolumicount/StreamingBcoInfo.h | 53 ++++ .../bcolumicount/StreamingBcoInfoLinkDef.h | 5 + .../bcolumicount/StreamingBcoInfov1.cc | 24 ++ .../bcolumicount/StreamingBcoInfov1.h | 55 ++++ .../bcolumicount/StreamingBcoInfov1LinkDef.h | 6 + .../bcolumicount/StreamingBcoLumiCheck.cc | 81 +++++ .../bcolumicount/StreamingBcoLumiCheck.h | 26 ++ .../bcolumicount/StreamingBcoLumiReco.cc | 279 ++++++++++++++++++ .../bcolumicount/StreamingBcoLumiReco.h | 78 +++++ .../bcolumicount/StreamingLumiInfo.cc | 23 ++ .../packages/bcolumicount/StreamingLumiInfo.h | 46 +++ .../bcolumicount/StreamingLumiInfoLinkDef.h | 5 + .../bcolumicount/StreamingLumiInfov1.cc | 26 ++ .../bcolumicount/StreamingLumiInfov1.h | 53 ++++ .../bcolumicount/StreamingLumiInfov1LinkDef.h | 5 + 19 files changed, 810 insertions(+), 100 deletions(-) delete mode 100644 offline/packages/bcolumicount/BcoLumiCheck.cc delete mode 100644 offline/packages/bcolumicount/BcoLumiCheck.h create mode 100644 offline/packages/bcolumicount/StreamingBcoInfo.cc create mode 100644 offline/packages/bcolumicount/StreamingBcoInfo.h create mode 100644 offline/packages/bcolumicount/StreamingBcoInfoLinkDef.h create mode 100644 offline/packages/bcolumicount/StreamingBcoInfov1.cc create mode 100644 offline/packages/bcolumicount/StreamingBcoInfov1.h create mode 100644 offline/packages/bcolumicount/StreamingBcoInfov1LinkDef.h create mode 100644 offline/packages/bcolumicount/StreamingBcoLumiCheck.cc create mode 100644 offline/packages/bcolumicount/StreamingBcoLumiCheck.h create mode 100644 offline/packages/bcolumicount/StreamingBcoLumiReco.cc create mode 100644 offline/packages/bcolumicount/StreamingBcoLumiReco.h create mode 100644 offline/packages/bcolumicount/StreamingLumiInfo.cc create mode 100644 offline/packages/bcolumicount/StreamingLumiInfo.h create mode 100644 offline/packages/bcolumicount/StreamingLumiInfoLinkDef.h create mode 100644 offline/packages/bcolumicount/StreamingLumiInfov1.cc create mode 100644 offline/packages/bcolumicount/StreamingLumiInfov1.h create mode 100644 offline/packages/bcolumicount/StreamingLumiInfov1LinkDef.h diff --git a/offline/packages/bcolumicount/BcoLumiCheck.cc b/offline/packages/bcolumicount/BcoLumiCheck.cc deleted file mode 100644 index 3ba12f1776..0000000000 --- a/offline/packages/bcolumicount/BcoLumiCheck.cc +++ /dev/null @@ -1,71 +0,0 @@ -#include "BcoLumiCheck.h" - -#include "BcoInfo.h" - -#include -#include - -#include - -#include -#include // for SubsysReco - -#include -#include // for PHNode -#include // for PHNodeIterator -#include -#include // for PHWHERE - -#include - -BcoLumiCheck::BcoLumiCheck(const std::string &name) - : SubsysReco(name) -{ - return; -} - -int BcoLumiCheck::Init(PHCompositeNode *topNode) -{ - int iret = CreateNodeTree(topNode); - return iret; -} - -int BcoLumiCheck::InitRun(PHCompositeNode * /*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - -int BcoLumiCheck::CreateNodeTree(PHCompositeNode *topNode) -{ - PHNodeIterator iter(topNode); - PHCompositeNode *dstNode; - dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - return Fun4AllReturnCodes::EVENT_OK; -} - -int BcoLumiCheck::process_event(PHCompositeNode *topNode) -{ - BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); - SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); - Gl1Packet *gl1packet = findNode::getClass(topNode, 14001); - if (gl1packet) - { - std::cout << "Event No: " << syncobject->EventNumber() << std::hex - << " gl1: bco 0x" << gl1packet->lValue(0, "BCO") << std::dec << std::endl; - if (bcoinfo) - { - std::cout << "prev event: " << bcoinfo->get_previous_evtno() << std::hex - << " bco: 0x" << bcoinfo->get_previous_bco() << std::dec << std::endl; - std::cout << "curr event: " << bcoinfo->get_current_evtno() << std::hex - << " bco: 0x" << bcoinfo->get_current_bco() << std::dec << std::endl; - std::cout << "futu event: " << bcoinfo->get_future_evtno() << std::hex - << " bco: 0x" << bcoinfo->get_future_bco() << std::dec << std::endl; - } - } - return Fun4AllReturnCodes::EVENT_OK; -} diff --git a/offline/packages/bcolumicount/BcoLumiCheck.h b/offline/packages/bcolumicount/BcoLumiCheck.h deleted file mode 100644 index 75477dea98..0000000000 --- a/offline/packages/bcolumicount/BcoLumiCheck.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BCOLUMICOUNT_BCOLUMICHECK_H -#define BCOLUMICOUNT_BCOLUMICHECK_H - -#include - -#include - -class BcoLumiCheck : public SubsysReco -{ - public: - BcoLumiCheck(const std::string &name = "BCOLUMICHECK"); - ~BcoLumiCheck() override = default; - - int Init(PHCompositeNode *topNode) override; - int InitRun(PHCompositeNode *topNode) override; - int process_event(PHCompositeNode *topNode) override; - - private: - static int CreateNodeTree(PHCompositeNode *topNode); -}; - -#endif // BCOLUMICOUNT_BCOLUMICHECK_H diff --git a/offline/packages/bcolumicount/Makefile.am b/offline/packages/bcolumicount/Makefile.am index 70afc9b224..fb546ed53a 100644 --- a/offline/packages/bcolumicount/Makefile.am +++ b/offline/packages/bcolumicount/Makefile.am @@ -21,11 +21,16 @@ libbcolumicount_la_LIBADD = \ libbcolumicount_io.la \ -lffaobjects \ -lffarawobjects \ - -lSubsysReco + -lSubsysReco \ + -lfun4all ROOTDICTS = \ BcoInfo_Dict.cc \ - BcoInfov1_Dict.cc + BcoInfov1_Dict.cc \ + StreamingBcoInfo_Dict.cc \ + StreamingBcoInfov1_Dict.cc \ + StreamingLumiInfo_Dict.cc \ + StreamingLumiInfov1_Dict.cc pcmdir = $(libdir) # more elegant way to create pcm files (without listing them) @@ -34,18 +39,28 @@ nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) pkginclude_HEADERS = \ BcoInfo.h \ BcoInfov1.h \ - BcoLumiCheck.h \ - BcoLumiReco.h + BcoLumiReco.h \ + StreamingBcoInfo.h \ + StreamingBcoInfov1.h \ + StreamingLumiInfo.h \ + StreamingLumiInfov1.h \ + StreamingBcoLumiReco.h \ + StreamingBcoLumiCheck.h libbcolumicount_io_la_SOURCES = \ $(ROOTDICTS) \ BcoInfo.cc \ - BcoInfov1.cc + BcoInfov1.cc \ + StreamingBcoInfo.cc \ + StreamingBcoInfov1.cc \ + StreamingLumiInfo.cc \ + StreamingLumiInfov1.cc libbcolumicount_la_SOURCES = \ - BcoLumiCheck.cc \ - BcoLumiReco.cc + BcoLumiReco.cc \ + StreamingBcoLumiReco.cc \ + StreamingBcoLumiCheck.cc BUILT_SOURCES = testexternals.cc diff --git a/offline/packages/bcolumicount/StreamingBcoInfo.cc b/offline/packages/bcolumicount/StreamingBcoInfo.cc new file mode 100644 index 0000000000..1519f90368 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfo.cc @@ -0,0 +1,23 @@ +#include "StreamingBcoInfo.h" + +#include + +#include + +void StreamingBcoInfo::Reset() +{ + std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; + return; +} + +void StreamingBcoInfo::identify(std::ostream& os) const +{ + os << "identify yourself: virtual StreamingBcoInfo Object" << std::endl; + return; +} + +//int BcoStreamingLumiInfo::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingBcoInfo.h b/offline/packages/bcolumicount/StreamingBcoInfo.h new file mode 100644 index 0000000000..5b8fe2b943 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfo.h @@ -0,0 +1,53 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGBCOINFO_H +#define BCOLLUMICOUNT_STREAMINGBCOINFO_H + +#include + +#include +#include +#include + + +/// +class StreamingBcoInfo : public PHObject +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingBcoInfo() = default; + /// dtor + ~StreamingBcoInfo() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual uint64_t get_bco() const { return 0; } + + virtual void set_bco(uint64_t /*val*/) { return; } + + virtual int get_evtno() const { return 0; } + + virtual void set_evtno(int /*val*/) { return; } + + virtual bool get_usable_bco_tag() const { return 0; } + + virtual void set_usable_bco_tag(bool /*val*/) { return; } + + virtual std::pair get_bco_streaming_window() const { return std::make_pair(0, 0); } + + virtual void set_bco_streaming_window(std::pair /*val*/) { return; } + + + private: + ClassDefOverride(StreamingBcoInfo, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoInfoLinkDef.h b/offline/packages/bcolumicount/StreamingBcoInfoLinkDef.h new file mode 100644 index 0000000000..d01df73556 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfoLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingBcoInfo + ; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1.cc b/offline/packages/bcolumicount/StreamingBcoInfov1.cc new file mode 100644 index 0000000000..9b97dd855e --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfov1.cc @@ -0,0 +1,24 @@ +#include "StreamingBcoInfov1.h" + +#include + +#include + +void StreamingBcoInfov1::Reset() +{ + set_bco(0); + set_usable_bco_tag(false); + set_bco_streaming_window(std::make_pair(0, 0)); + return; +} + +void StreamingBcoInfov1::identify(std::ostream& os) const +{ + os << "identify yourself: I am a StreamingBcoInfov1 Object\n"; return; +} + +//int StreamingBcoInfov1::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1.h b/offline/packages/bcolumicount/StreamingBcoInfov1.h new file mode 100644 index 0000000000..164bebf70e --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfov1.h @@ -0,0 +1,55 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGBCOINFOV1_H +#define BCOLLUMICOUNT_STREAMINGBCOINFOV1_H + +#include "StreamingBcoInfo.h" + + +#include +#include +#include + + +/// +class StreamingBcoInfov1 : public StreamingBcoInfo +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingBcoInfov1() = default; + /// dtor + ~StreamingBcoInfov1() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual uint64_t get_bco() const override { return m_bco; } + virtual void set_bco(uint64_t val) override { m_bco = val; } + + virtual int get_evtno() const override { return m_evtno; } + virtual void set_evtno(int val) override { m_evtno = val; } + + virtual bool get_usable_bco_tag() const override { return m_usable_bco_tag; } + virtual void set_usable_bco_tag(bool val) override { m_usable_bco_tag = val; } + + virtual std::pair get_bco_streaming_window() const override { return m_bco_streaming_window; } + virtual void set_bco_streaming_window(std::pair val) override { m_bco_streaming_window = val; } + + + private: + uint64_t m_bco; + int m_evtno; + bool m_usable_bco_tag; + std::pair m_bco_streaming_window; + + ClassDefOverride(StreamingBcoInfov1, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1LinkDef.h b/offline/packages/bcolumicount/StreamingBcoInfov1LinkDef.h new file mode 100644 index 0000000000..dc98f8629e --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfov1LinkDef.h @@ -0,0 +1,6 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingBcoInfov1 + ; +#pragma link C++ class std::pair + ; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoLumiCheck.cc b/offline/packages/bcolumicount/StreamingBcoLumiCheck.cc new file mode 100644 index 0000000000..f6bf88b584 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoLumiCheck.cc @@ -0,0 +1,81 @@ +#include "StreamingBcoLumiCheck.h" + +//#include "BcoInfo.h" +#include "StreamingBcoInfo.h" +#include "StreamingLumiInfo.h" +//#include "BcoStreamingLumiInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE + + +#include + +StreamingBcoLumiCheck::StreamingBcoLumiCheck(const std::string &name) + : SubsysReco(name) +{ + return; +} + +int StreamingBcoLumiCheck::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + + return iret; +} + +int StreamingBcoLumiCheck::InitRun(PHCompositeNode *topNode) +{ + StreamingLumiInfo *streaming_lumi_info = findNode::getClass(topNode, "STREAMINGLUMIINFO"); + if (streaming_lumi_info) + { + std::cout << " raw lumi : " << streaming_lumi_info->get_lumi_raw() << std::endl; + std::cout << " live lumi : " << streaming_lumi_info->get_lumi_live() << std::endl; + std::cout << " scaled lumi : " << streaming_lumi_info->get_lumi_scaled() << std::endl; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoLumiCheck::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoLumiCheck::process_event(PHCompositeNode *topNode) +{ + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (streaming_bco_info) + { + if (Verbosity() > 1) + { + std::cout << "bco : " << streaming_bco_info->get_bco() << std::endl; + std::cout << "usable bco tag : " << streaming_bco_info->get_usable_bco_tag() << std::endl; + std::cout << "bco streaming window : (" << streaming_bco_info->get_bco_streaming_window().first << ", " << streaming_bco_info->get_bco_streaming_window().second << ")" << std::endl; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} \ No newline at end of file diff --git a/offline/packages/bcolumicount/StreamingBcoLumiCheck.h b/offline/packages/bcolumicount/StreamingBcoLumiCheck.h new file mode 100644 index 0000000000..579ca524c0 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoLumiCheck.h @@ -0,0 +1,26 @@ +#ifndef BCOLUMICOUNT_STREAMINGBCOLUMICHECK_H +#define BCOLUMICOUNT_STREAMINGBCOLUMICHECK_H + +#include +#include + +#include + +#include + + +class StreamingBcoLumiCheck : public SubsysReco +{ + public: + StreamingBcoLumiCheck(const std::string &name = "BCOLUMICHECKSTREAMINGOUTPUT"); + ~StreamingBcoLumiCheck() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + + private: + static int CreateNodeTree(PHCompositeNode *topNode); +}; + +#endif // BCOLUMICOUNT_STREAMINGBCOLUMICHECK_H diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc new file mode 100644 index 0000000000..5222ce8ce1 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc @@ -0,0 +1,279 @@ +#include "StreamingBcoLumiReco.h" + +#include "BcoInfo.h" +#include "StreamingBcoInfo.h" +#include "StreamingBcoInfov1.h" +#include "StreamingLumiInfo.h" +#include "StreamingLumiInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE + +#include +#include +#include // for Packet + +#include + +StreamingBcoLumiReco::StreamingBcoLumiReco(const std::string &name) + : SubsysReco(name) +{ + hm = new Fun4AllHistoManager("bco_histos"); + Fun4AllServer *se = Fun4AllServer::instance(); + se->registerHistoManager(hm); + return; +} + +int StreamingBcoLumiReco::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + h_bco_diff = new TH1I("h_bco_diff", ";bco diff;", 3500, 0, 3500); + for (int bit=0; bitregisterHisto(h_bco_diff_trigbits[bit]); + } + h_bco_tag = new TH1I("h_bco_tag", "run 81100;usable bco tag;", 2, -0.5, 1.5); + hm->registerHisto(h_bco_diff); + hm->registerHisto(h_bco_tag); + + return iret; +} + +int StreamingBcoLumiReco::InitRun(PHCompositeNode * topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *runNode; + runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << " Run Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + m_streaming_lumi_info = findNode::getClass(topNode, "STREAMINGLUMIINFO"); + if (!m_streaming_lumi_info) + { + m_streaming_lumi_info = new StreamingLumiInfov1(); + PHIODataNode *luminode = new PHIODataNode(m_streaming_lumi_info, "STREAMINGLUMIINFO", "PHObject"); + runNode->addNode(luminode); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (!streaming_bco_info) + { + streaming_bco_info = new StreamingBcoInfov1(); + PHIODataNode *bconode = new PHIODataNode(streaming_bco_info, "STREAMINGBCOINFO", "PHObject"); + dstNode->addNode(bconode); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) +{ + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); + SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); + //Gl1Packet *gl1packet = findNode::getClass(topNode, 14001); + Event *evt = findNode::getClass(topNode, "PRDF"); + if (evt) + { + if (Verbosity() > 2) + { + evt->identify(); + } + if (evt->getEvtType() != DATAEVENT) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + Packet *packet = evt->getPacket(14001); + if (!packet) + { + if (Verbosity() > 0) + { + std::cout << "no gl1 packet 14001" << std::endl; + evt->identify(); + } + return Fun4AllReturnCodes::ABORTEVENT; + } + uint64_t gtm_bco = packet->lValue(0, "BCO"); + uint64_t gl1_scaledvec = packet->lValue(0, "ScaledVector"); + //uint64_t gl1_livevec = packet->lValue(0, "TriggerVector"); + + int bunchno = packet->lValue(0,"BunchNumber"); + + // SYNTAX TAKEN FROM ZHIWANS CODE, why = and not +=? If this is correct it seems like a waste to call it for every event (would just need it for the last event in a particular crossing?) + m_bunchnumber_MBDNS_raw[bunchno] = packet->lValue(0, "GL1PRAW"); + m_bunchnumber_MBDNS_live[bunchno] = packet->lValue(0, "GL1PLIVE"); + m_bunchnumber_MBDNS_scaled[bunchno] = packet->lValue(0, "GL1PSCALED"); + + + if(packet->lValue(0, 0)) + { + m_rawgl1scaler = packet->lValue(0, 0); + } + + delete packet; + + if (Verbosity() > 2) + { + std::cout << "Event No: " << syncobject->EventNumber() /*<< std::hex*/ + << " gl1 bco: " << gtm_bco < 2) + { + std::cout << "prev event: " << bcoinfo->get_previous_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_previous_bco() << std::dec << std::endl; + std::cout << "curr event: " << bcoinfo->get_current_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_current_bco() << std::dec << std::endl; + std::cout << "futu event: " << bcoinfo->get_future_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_future_bco() << std::dec << std::endl; + } + + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + m_bco = bcoinfo->get_current_bco(); + if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} + uint64_t bco_prev = bcoinfo->get_previous_bco(); + uint64_t bco_futu = bcoinfo->get_future_bco(); + uint64_t bco_diff_prev = m_bco - bco_prev; + uint64_t bco_diff_futu = bco_futu - m_bco; + + // TODO: Set BCO window length in the macro + // TODO: Set BCO Negative window length in the macro + // window length: 360, negative window length: 20 + // Therefore, should check if BCO is within 340 + // special case if BCO is within 20 of previous BCO? + if (bco_diff_prev < 340) + { + m_usable_bco_tag = true; + } + else + { + m_usable_bco_tag = false; + } + if (bco_diff_futu < 340) + { + // double check boundaries for overlap!! + m_bco_streaming_window = std::make_pair(get_bco() - 20, bco_futu - 21); + } + else + { + m_bco_streaming_window = std::make_pair(get_bco() - 20, get_bco() + 340); + } + if (Verbosity() > 2) + { + std::cout << "bco_diff_prev : " << bco_diff_prev << std::endl; + std::cout << "bco_diff_futu : " << bco_diff_futu << std::endl; + } + h_bco_diff->Fill(bco_diff_prev); + h_bco_tag->Fill(m_usable_bco_tag); + for (int bit=0; bit> bit) & 0x1U) == 0x1U; + //bool scaled_trigger_fired = ((gl1_scaledvec >> bit) & 0x1U) == 0x1U; + + if (trigger_fired) + { + h_bco_diff_trigbits[bit]->Fill(bco_diff_prev); + } + } + // Double check Zhiwan's logic for assigning the adjusted bunch! + int lower = m_bco_streaming_window.first - m_bco; + int upper = m_bco_streaming_window.second - m_bco; + for(int i = lower; i< upper;i++) + { + int adjusted_bunch = bunchno + i; + while (adjusted_bunch < 0) + { + adjusted_bunch += 120; + } + while (adjusted_bunch > 119) + { + adjusted_bunch -= 120; + } + // ABORT GAP! + if (adjusted_bunch>110) { continue; } + + // Make sure this is the correct way to count crossings! Need to zero out for each run! + if(i!=0) + { + m_bunchnumber_crossings[adjusted_bunch] += 1; + } + else if (m_usable_bco_tag) + { + m_bunchnumber_crossings[adjusted_bunch] += 1; + } + } + + streaming_bco_info->set_bco(get_bco()); + streaming_bco_info->set_usable_bco_tag(get_usable_bco_tag()); + streaming_bco_info->set_bco_streaming_window(get_bco_streaming_window()); + } + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoLumiReco::EndRun(int /*runnumber*/) +{ + uint64_t rawgl1scalers_per_bunch = m_rawgl1scaler/120.; + for (int i=0; i 1) + { + std::cout << "bunchno : " << i << " lumi_raw : " << m_bunchnumber_lumi_raw[i] << std::endl; + } + } + m_streaming_lumi_info->set_lumi_raw(get_lumi_raw()); + m_streaming_lumi_info->set_lumi_live(get_lumi_live()); + m_streaming_lumi_info->set_lumi_scaled(get_lumi_scaled()); + if (Verbosity() > 1) + { + std::cout << "MBD xsec : " << m_xsec_MBDNS << std::endl; + std::cout << "total lumi (raw) : " << m_lumi_raw << std::endl; + } + + m_bunchnumber_lumi_raw.fill(0); + m_bunchnumber_lumi_live.fill(0); + m_bunchnumber_lumi_scaled.fill(0); + m_bunchnumber_crossings.fill(0); + m_bunchnumber_MBDNS_raw.fill(0); + m_bunchnumber_MBDNS_live.fill(0); + m_bunchnumber_MBDNS_scaled.fill(0); + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.h b/offline/packages/bcolumicount/StreamingBcoLumiReco.h new file mode 100644 index 0000000000..76f621a2da --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.h @@ -0,0 +1,78 @@ +#ifndef BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H +#define BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H + +#include +#include +#include "StreamingLumiInfo.h" + +#include +#include +#include + +#include + + +class StreamingBcoLumiReco : public SubsysReco +{ + public: + StreamingBcoLumiReco(const std::string &name = "BCOLUMICHECK"); + ~StreamingBcoLumiReco() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + int EndRun(const int runnumber) override; + + virtual uint64_t get_bco() const { return m_bco; } + + virtual int get_evtno() const { return m_evtno; } + + virtual bool get_usable_bco_tag() const { return m_usable_bco_tag; } + + virtual std::pair get_bco_streaming_window() const { return m_bco_streaming_window; } + + virtual double get_lumi_raw() const { return m_lumi_raw; } + virtual double get_lumi_live() const { return m_lumi_live; } + virtual double get_lumi_scaled() const { return m_lumi_scaled; } + + + + + + private: + static int CreateNodeTree(PHCompositeNode *topNode); + const int trigbits = 40; + Fun4AllHistoManager *hm = nullptr; + TH1I *h_bco_diff = nullptr; + TH1I *h_bco_diff_trigbits[40]; + TH1I *h_bco_tag = nullptr; + + uint64_t m_bco; + int m_bunches = 120; + int m_evtno; + bool m_usable_bco_tag = false; + std::pair m_bco_streaming_window; + + double m_xsec_MBDNS = 24.07*1e9; //convert to pb from Vernier scan DOUBLE CHECK VALUE! + + uint64_t m_rawgl1scaler{0}; + + std::array m_bunchnumber_MBDNS_raw{0}; + std::array m_bunchnumber_MBDNS_live{0}; + std::array m_bunchnumber_MBDNS_scaled{0}; + + std::array m_bunchnumber_crossings{0}; + + std::array m_bunchnumber_lumi_raw{0}; + std::array m_bunchnumber_lumi_live{0}; + std::array m_bunchnumber_lumi_scaled{0}; + + double m_lumi_raw{0.}; + double m_lumi_live{0.}; + double m_lumi_scaled{0.}; + + StreamingLumiInfo *m_streaming_lumi_info = nullptr; + +}; + +#endif // BCOLUMICOUNT_STREAMINGBCOLUMIRECO_H diff --git a/offline/packages/bcolumicount/StreamingLumiInfo.cc b/offline/packages/bcolumicount/StreamingLumiInfo.cc new file mode 100644 index 0000000000..753f82a858 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfo.cc @@ -0,0 +1,23 @@ +#include "StreamingLumiInfo.h" + +#include + +#include + +void StreamingLumiInfo::Reset() +{ + std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; + return; +} + +void StreamingLumiInfo::identify(std::ostream& os) const +{ + os << "identify yourself: virtual StreamingLumiInfo Object" << std::endl; + return; +} + +//int StreamingLumiInfo::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingLumiInfo.h b/offline/packages/bcolumicount/StreamingLumiInfo.h new file mode 100644 index 0000000000..8c68be22d9 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfo.h @@ -0,0 +1,46 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGLUMIINFO_H +#define BCOLLUMICOUNT_STREAMINGLUMIINFO_H + +#include + +#include +#include +#include + + +/// +class StreamingLumiInfo : public PHObject +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingLumiInfo() = default; + /// dtor + ~StreamingLumiInfo() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual double get_lumi_raw() const { return 0; } + virtual void set_lumi_raw(double /*val*/) { return; } + + virtual double get_lumi_live() const { return 0; } + virtual void set_lumi_live(double /*val*/) { return; } + + virtual double get_lumi_scaled() const { return 0; } + virtual void set_lumi_scaled(double /*val*/) { return; } + + + private: + ClassDefOverride(StreamingLumiInfo, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingLumiInfoLinkDef.h b/offline/packages/bcolumicount/StreamingLumiInfoLinkDef.h new file mode 100644 index 0000000000..098d7b8de3 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfoLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingLumiInfo + ; + +#endif diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.cc b/offline/packages/bcolumicount/StreamingLumiInfov1.cc new file mode 100644 index 0000000000..8b554564ce --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.cc @@ -0,0 +1,26 @@ +#include "StreamingLumiInfov1.h" + +#include + +#include + +void StreamingLumiInfov1::Reset() +{ + // Double check that this is only called once per run!! Or... it should just be called in the InitRun hook? + set_lumi_raw(0.); + set_lumi_live(0.); + set_lumi_scaled(0.); + + return; +} + +void StreamingLumiInfov1::identify(std::ostream& os) const +{ + os << "identify yourself: I am a StreamingLumiInfov1 Object\n"; return; +} + +//int StreamingLumiInfov1::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.h b/offline/packages/bcolumicount/StreamingLumiInfov1.h new file mode 100644 index 0000000000..e5478c531c --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.h @@ -0,0 +1,53 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGLUMIINFOV1_H +#define BCOLLUMICOUNT_STREAMINGLUMIINFOV1_H + +#include "StreamingLumiInfo.h" + + +#include +#include +#include + + +/// +class StreamingLumiInfov1 : public StreamingLumiInfo +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingLumiInfov1() = default; + /// dtor + ~StreamingLumiInfov1() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual double get_lumi_raw() const override { return m_lumi_raw; } + virtual void set_lumi_raw(double val) override { m_lumi_raw = val; } + + virtual double get_lumi_live() const override { return m_lumi_live; } + virtual void set_lumi_live(double val) override { m_lumi_live = val; } + + virtual double get_lumi_scaled() const override { return m_lumi_scaled; } + virtual void set_lumi_scaled(double val) override { m_lumi_scaled = val; } + + + private: + double m_lumi_raw; + double m_lumi_live; + double m_lumi_scaled; + + + + ClassDefOverride(StreamingLumiInfov1, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1LinkDef.h b/offline/packages/bcolumicount/StreamingLumiInfov1LinkDef.h new file mode 100644 index 0000000000..7f59d1e0d1 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfov1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingLumiInfov1 + ; + +#endif From 1e3c48cba122d67695038a68b2ef9f631237591a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 16 May 2026 14:35:42 -0400 Subject: [PATCH 510/866] geometry/alignment code updated --- offline/packages/trackbase/ActsGeometry.h | 1 - offline/packages/trackbase/ActsTrackingGeometry.h | 4 ++-- offline/packages/trackbase/AlignmentTransformation.cc | 5 +++-- .../packages/trackbase/alignmentTransformationContainer.h | 2 +- offline/packages/trackbase/sPHENIXActsDetectorElement.cc | 4 ++-- offline/packages/trackbase/sPHENIXActsDetectorElement.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/offline/packages/trackbase/ActsGeometry.h b/offline/packages/trackbase/ActsGeometry.h index 957a1a8e62..df391d98bb 100644 --- a/offline/packages/trackbase/ActsGeometry.h +++ b/offline/packages/trackbase/ActsGeometry.h @@ -10,7 +10,6 @@ class TrkrCluster; class ActsGeometry { public: - ActsGeometry() = default; ~ActsGeometry() = default; void setGeometry(const ActsTrackingGeometry& tGeometry) diff --git a/offline/packages/trackbase/ActsTrackingGeometry.h b/offline/packages/trackbase/ActsTrackingGeometry.h index f9f03d50d3..8320872592 100644 --- a/offline/packages/trackbase/ActsTrackingGeometry.h +++ b/offline/packages/trackbase/ActsTrackingGeometry.h @@ -26,7 +26,7 @@ */ struct ActsTrackingGeometry { - ActsTrackingGeometry() {} + ActsTrackingGeometry() { } ActsTrackingGeometry(std::shared_ptr tGeo, // ActsTrackingGeometry(std::shared_ptr tGeo, std::shared_ptr mag, @@ -49,7 +49,7 @@ struct ActsTrackingGeometry /// Acts context, for Kalman options Acts::CalibrationContext calibContext; - Acts::GeometryContext geoContext; + Acts::GeometryContext geoContext = Acts::GeometryContext::dangerouslyDefaultConstruct(); Acts::MagneticFieldContext magFieldContext; const Acts::GeometryContext& getGeoContext() const diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index aa67288bb6..171d9684ac 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -351,7 +351,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } // copy map into geoContext - m_tGeometry->geometry().geoContext = transformMap; + Acts::GeometryContext gctx{transformMap}; + m_tGeometry->geometry().geoContext = gctx; std::cout << " AlignmentTransformation processed " << linecount << " input lines " << std::endl; @@ -372,7 +373,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, // get the acts transform components // Note that Acts transforms local coordinates of (x,z,y) to global (x,y,z) - auto actsTransform = surf->transform(m_tGeometry->geometry().getGeoContext()); + auto actsTransform = surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext()); Eigen::Matrix3d actsRotationPart = actsTransform.rotation(); Eigen::Vector3d actsTranslationPart = actsTransform.translation(); diff --git a/offline/packages/trackbase/alignmentTransformationContainer.h b/offline/packages/trackbase/alignmentTransformationContainer.h index e6eb6c2df8..8711ec5b45 100644 --- a/offline/packages/trackbase/alignmentTransformationContainer.h +++ b/offline/packages/trackbase/alignmentTransformationContainer.h @@ -23,7 +23,7 @@ * * Association object holding transformations associated with given tracker hitset */ -class alignmentTransformationContainer : public Acts::GeometryContext +class alignmentTransformationContainer { public: alignmentTransformationContainer(); diff --git a/offline/packages/trackbase/sPHENIXActsDetectorElement.cc b/offline/packages/trackbase/sPHENIXActsDetectorElement.cc index 2604ecaf71..3751f68a6c 100644 --- a/offline/packages/trackbase/sPHENIXActsDetectorElement.cc +++ b/offline/packages/trackbase/sPHENIXActsDetectorElement.cc @@ -6,7 +6,7 @@ sPHENIXActsDetectorElement::~sPHENIXActsDetectorElement() = default; -const Acts::Transform3& sPHENIXActsDetectorElement::transform(const Acts::GeometryContext& ctxt) const +const Acts::Transform3& sPHENIXActsDetectorElement::localToGlobalTransform(const Acts::GeometryContext& ctxt) const { if (alignmentTransformationContainer::use_alignment) { @@ -35,7 +35,7 @@ const Acts::Transform3& sPHENIXActsDetectorElement::transform(const Acts::Geomet else { // return the construction transform - const Acts::Transform3& transform = TGeoDetectorElement::transform(ctxt); // ctxt is unused here + const Acts::Transform3& transform = TGeoDetectorElement::nominalTransform(); // ctxt is unused here return transform; } } diff --git a/offline/packages/trackbase/sPHENIXActsDetectorElement.h b/offline/packages/trackbase/sPHENIXActsDetectorElement.h index 87a172458b..98a4813989 100644 --- a/offline/packages/trackbase/sPHENIXActsDetectorElement.h +++ b/offline/packages/trackbase/sPHENIXActsDetectorElement.h @@ -52,7 +52,7 @@ class sPHENIXActsDetectorElement : public ActsPlugins::TGeoDetectorElement ~sPHENIXActsDetectorElement() override; - const Acts::Transform3& transform(const Acts::GeometryContext& ctxt) const override; + const Acts::Transform3& localToGlobalTransform(const Acts::GeometryContext& ctxt) const override; private: std::map base_layer_map = {{10, 0}, {12, 3}, {14, 7}, {16, 55}}; From ac93f35636b8e40c8bfcfbf60a4bc1d907a13930 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 16 May 2026 14:40:26 -0400 Subject: [PATCH 511/866] update outlier finder --- offline/packages/trackbase/ResidualOutlierFinder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/trackbase/ResidualOutlierFinder.h b/offline/packages/trackbase/ResidualOutlierFinder.h index 904aa474d0..d0ace7fb12 100644 --- a/offline/packages/trackbase/ResidualOutlierFinder.h +++ b/offline/packages/trackbase/ResidualOutlierFinder.h @@ -82,7 +82,7 @@ struct ResidualOutlierFinder } const auto predicted = state.predicted(); auto fullCalibrated = state - .template calibrated() + .template calibrated() .data(); Acts::FreeVector freeParams = Acts::transformBoundToFreeParameters(state.referenceSurface(), From c8a3b4301b93e9a10ac09ef06e2b1c98e4900156 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 16 May 2026 14:40:40 -0400 Subject: [PATCH 512/866] remove gsf from build for now, too volatile --- offline/packages/trackbase/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 92b4273988..bcb0b81d96 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -40,7 +40,6 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ ActsAborter.h \ ActsGeometry.h \ - ActsGsfTrackFittingAlgorithm.h \ ActsSourceLink.h \ ActsSurfaceMaps.h \ ActsTrackFittingAlgorithm.h \ @@ -219,7 +218,6 @@ libtrack_la_SOURCES = \ MagneticFieldOptions.cc \ sPHENIXActsDetectorElement.cc \ TGeoDetectorWithOptions.cc \ - TrackFittingAlgorithmFunctionsGsf.cc \ TrackFittingAlgorithmFunctionsKalman.cc \ TrackFitUtils.cc From 0011ffab012deb7fa8976e46acaa44f8b4728ae2 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 16 May 2026 15:02:02 -0400 Subject: [PATCH 513/866] update to v45 --- offline/packages/trackbase_historic/ActsTransformations.cc | 3 +-- offline/packages/trackbase_historic/TrackAnalysisUtils.cc | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/packages/trackbase_historic/ActsTransformations.cc b/offline/packages/trackbase_historic/ActsTransformations.cc index f987d31cf2..5bf08082e5 100644 --- a/offline/packages/trackbase_historic/ActsTransformations.cc +++ b/offline/packages/trackbase_historic/ActsTransformations.cc @@ -295,8 +295,7 @@ void ActsTransformations::fillSvtxTrackStates( { /// Only fill the track states with non-outlier measurement - const auto typeFlags = state.typeFlags(); - if( !typeFlags.test(Acts::TrackStateFlag::MeasurementFlag) ) + if (!state.typeFlags().isMeasurement()) { return true; } // only fill for state vectors with proper smoothed parameters diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 04f5ff341c..0a04d41f26 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -392,7 +392,7 @@ namespace TrackAnalysisUtils { // otherwise take the manual calculation for the TPC // doing it this way just avoids the bounds check that occurs in the surface class method - Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm + Acts::Vector3 loct = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm loct /= Acts::UnitConstants::cm; loc(0) = loct(0); From 036ba65ecf377b6ed146e33586ef582b6e7f0e08 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 16 May 2026 15:16:34 -0400 Subject: [PATCH 514/866] update transform calls --- offline/packages/intt/CylinderGeomInttHelper.cc | 4 ++-- offline/packages/micromegas/CylinderGeomMicromegas.cc | 4 ++-- offline/packages/mvtx/CylinderGeom_MvtxHelper.cc | 4 ++-- offline/packages/tpc/LaserClusterizer.cc | 4 ++-- offline/packages/tpc/TpcClusterizer.cc | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/offline/packages/intt/CylinderGeomInttHelper.cc b/offline/packages/intt/CylinderGeomInttHelper.cc index 952002c7ba..979ee6d0d7 100644 --- a/offline/packages/intt/CylinderGeomInttHelper.cc +++ b/offline/packages/intt/CylinderGeomInttHelper.cc @@ -18,7 +18,7 @@ TVector3 CylinderGeomInttHelper::get_world_from_local_coords(const Surface& surf Acts::Vector3 loc(local.x(), local.y(), local.z()); loc *= Acts::UnitConstants::cm; - Acts::Vector3 glob = surface->transform(tGeometry->geometry().getGeoContext()) * loc; + Acts::Vector3 glob = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()) * loc; glob /= Acts::UnitConstants::cm; return TVector3(glob(0), glob(1), glob(2)); } @@ -53,7 +53,7 @@ TVector3 CylinderGeomInttHelper::get_local_from_world_coords(const Surface& surf global(2) = world[2]; global *= Acts::UnitConstants::cm; - Acts::Vector3 local = surface->transform(tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; diff --git a/offline/packages/micromegas/CylinderGeomMicromegas.cc b/offline/packages/micromegas/CylinderGeomMicromegas.cc index 5681eed3bd..ccf7395d06 100644 --- a/offline/packages/micromegas/CylinderGeomMicromegas.cc +++ b/offline/packages/micromegas/CylinderGeomMicromegas.cc @@ -50,7 +50,7 @@ TVector3 CylinderGeomMicromegas::get_local_from_world_coords( uint tileid, ActsG // convert to local /* this is equivalent to calling surface->globalToLocal but without the "on surface" check, and while returning a full Acts::Vector3 */ - const auto local = surface->transform(geometry->geometry().getGeoContext()).inverse()*global; + const auto local = surface->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse()*global; return TVector3( local.x()/Acts::UnitConstants::cm, local.y()/Acts::UnitConstants::cm, @@ -109,7 +109,7 @@ TVector3 CylinderGeomMicromegas::get_world_from_local_coords( uint tileid, ActsG // convert to global /* this is equivalent to calling surface->localToGlobal but without assuming that the local point is on surface */ - const auto global = surface->transform(geometry->geometry().getGeoContext())*local; + const auto global = surface->localToGlobalTransform(geometry->geometry().getGeoContext())*local; return TVector3( global.x()/Acts::UnitConstants::cm, global.y()/Acts::UnitConstants::cm, diff --git a/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc b/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc index 41db23e434..e077d80964 100644 --- a/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc +++ b/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc @@ -23,7 +23,7 @@ CylinderGeom_MvtxHelper::get_local_from_world_coords ( global *= Acts::UnitConstants::cm; - Acts::Vector3 local = surface->transform(tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; /// The Acts transform swaps a few of the coordinates @@ -67,7 +67,7 @@ CylinderGeom_MvtxHelper::get_world_from_local_coords ( Acts::Vector3 loc(local.x(), local.y(), local.z()); loc *= Acts::UnitConstants::cm; - Acts::Vector3 glob = surface->transform(tGeometry->geometry().getGeoContext()) * loc; + Acts::Vector3 glob = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()) * loc; glob /= Acts::UnitConstants::cm; return TVector3(glob(0), glob(1), glob(2)); diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 8ecd28688e..925b0c6e8a 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -872,12 +872,12 @@ namespace } // Convert from ideal TPC coordinates to surface coordinates - Acts::Vector3 local = surface->transform(my_data.tGeometry->geometry().getGeoContext()).inverse() * (ideal * Acts::UnitConstants::cm); + Acts::Vector3 local = surface->localToGlobalTransform(my_data.tGeometry->geometry().getGeoContext()).inverse() * (ideal * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; // Convert back to TPC coordinates with alignment applied alignmentTransformationContainer::use_alignment = true; - Acts::Vector3 global = surface->transform(my_data.tGeometry->geometry().getGeoContext()) * (local * Acts::UnitConstants::cm); + Acts::Vector3 global = surface->localToGlobalTransform(my_data.tGeometry->geometry().getGeoContext()) * (local * Acts::UnitConstants::cm); global /= Acts::UnitConstants::cm; clus->setX(global(0)); clus->setY(global(1)); diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index dc815eacae..687d5b58f9 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -714,7 +714,7 @@ namespace /// convert to Acts units global *= Acts::UnitConstants::cm; // std::cout << "transform" << std::endl; - Acts::Vector3 local = surface->transform(my_data.tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(my_data.tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; // std::cout << "done transform" << std::endl; // we need the cluster key and all associated hit keys (note: the cluster key includes the hitset key) @@ -763,7 +763,7 @@ namespace double nn_y = radius * std::sin(nn_phi); Acts::Vector3 nn_global(nn_x, nn_y, nn_z); nn_global *= Acts::UnitConstants::cm; - Acts::Vector3 nn_local = surface->transform(my_data.tGeometry->geometry().geoContext).inverse() * nn_global; + Acts::Vector3 nn_local = surface->localToGlobalTransform(my_data.tGeometry->geometry().geoContext).inverse() * nn_global; nn_local /= Acts::UnitConstants::cm; double nn_t = my_data.m_tdriftmax - std::fabs(nn_z) / my_data.tGeometry->get_drift_velocity(); clus_base->setLocalX(nn_local(0)); From 99b9c2d7aa7526dc17274178b45e4f8b2bbf99da Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sat, 16 May 2026 15:17:13 -0400 Subject: [PATCH 515/866] improve makefile --- offline/packages/trackbase_historic/Makefile.am | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/offline/packages/trackbase_historic/Makefile.am b/offline/packages/trackbase_historic/Makefile.am index a27554a914..3f1ed12e2a 100644 --- a/offline/packages/trackbase_historic/Makefile.am +++ b/offline/packages/trackbase_historic/Makefile.am @@ -16,9 +16,9 @@ AM_CPPFLAGS = \ AM_LDFLAGS = \ -L$(libdir) \ - -L$(ROOTSYS)/lib \ -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 + -L$(OFFLINE_MAIN)/lib64 \ + -L$(ROOTSYS)/lib pkginclude_HEADERS = \ ActsTransformations.h \ @@ -180,11 +180,6 @@ libtrackbase_historic_io_la_SOURCES = \ WeightedTrackZeroField.cc \ WeightedTrackMap.cc -AM_LDFLAGS = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 - # dependency on libtrack.so breaks the io only library concept libtrackbase_historic_io_la_LIBADD = \ -lphool \ From 35a64f838bb7ed0bcc182e3b92b5418b79c6be3e Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 17 May 2026 07:05:18 -0400 Subject: [PATCH 516/866] remove gsf from build for now --- offline/packages/trackreco/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/offline/packages/trackreco/Makefile.am b/offline/packages/trackreco/Makefile.am index 4829357b0b..74626f2c60 100644 --- a/offline/packages/trackreco/Makefile.am +++ b/offline/packages/trackreco/Makefile.am @@ -34,7 +34,6 @@ pkginclude_HEADERS = \ MakeActsGeometry.h \ MakeSourceLinks.h \ nanoflann.hpp \ - PHActsGSF.h \ PHActsKDTreeSeeding.h \ PHActsSiliconSeeding.h \ PHActsVertexPropagator.h \ @@ -101,7 +100,6 @@ ACTS_SOURCES = \ ActsPropagator.cc \ MakeActsGeometry.cc \ MakeSourceLinks.cc \ - PHActsGSF.cc \ PHActsKDTreeSeeding.cc \ PHActsSiliconSeeding.cc \ PHActsTrkFitter.cc \ From bc93a21eadd39fd13751dea20e2cc7f6ecdafee8 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Sun, 17 May 2026 07:07:10 -0400 Subject: [PATCH 517/866] update apis for several modules --- offline/packages/trackreco/ActsAlignmentStates.cc | 8 ++++---- offline/packages/trackreco/ActsAlignmentStates.h | 2 +- offline/packages/trackreco/ActsEvaluator.cc | 8 ++++---- offline/packages/trackreco/ActsEvaluator.h | 4 ++-- offline/packages/trackreco/MakeActsGeometry.cc | 14 ++++++-------- offline/packages/trackreco/MakeActsGeometry.h | 2 +- offline/packages/trackreco/MakeSourceLinks.cc | 8 +++----- offline/packages/trackreco/PHActsTrkFitter.cc | 1 - 8 files changed, 21 insertions(+), 26 deletions(-) diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index f9c8570274..070f78e53f 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -56,7 +56,7 @@ void ActsAlignmentStates::loadNodes( PHCompositeNode* topNode ) //_________________________________________________________________ void ActsAlignmentStates::fillAlignmentStateMap( const ActsTrackFittingAlgorithm::TrackContainer& tracks, - const std::vector& tips, + const std::vector& tips, SvtxTrack* track, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { @@ -117,7 +117,7 @@ void ActsAlignmentStates::fillAlignmentStateMap( { /// Collect only track states which were used in smoothing of KF and are measurements if (! state.hasSmoothed() || - ! state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) + ! state.typeFlags().isMeasurement()) { return true; } @@ -276,10 +276,10 @@ std::pair ActsAlignmentStates::get_projectionXY(co // get surface X and Y unit vectors in global frame // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1 Acts::Vector3 xloc(1.0, 0.0, 0.0); - Acts::Vector3 xglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * xloc; + Acts::Vector3 xglob = surface.localToGlobalTransform(m_tGeometry->geometry().getGeoContext()) * xloc; Acts::Vector3 yloc(0.0, 1.0, 0.0); - Acts::Vector3 yglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * yloc; + Acts::Vector3 yglob = surface.localToGlobalTransform(m_tGeometry->geometry().getGeoContext()) * yloc; Acts::Vector3 X = (xglob - sensorCenter) / (xglob - sensorCenter).norm(); Acts::Vector3 Y = (yglob - sensorCenter) / (yglob - sensorCenter).norm(); diff --git a/offline/packages/trackreco/ActsAlignmentStates.h b/offline/packages/trackreco/ActsAlignmentStates.h index caeae77a00..9d891c906d 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.h +++ b/offline/packages/trackreco/ActsAlignmentStates.h @@ -33,7 +33,7 @@ class ActsAlignmentStates explicit ActsAlignmentStates() = default; void fillAlignmentStateMap(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - const std::vector& tips, + const std::vector& tips, SvtxTrack* track, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); diff --git a/offline/packages/trackreco/ActsEvaluator.cc b/offline/packages/trackreco/ActsEvaluator.cc index 4a705f99fd..9edb4a441a 100644 --- a/offline/packages/trackreco/ActsEvaluator.cc +++ b/offline/packages/trackreco/ActsEvaluator.cc @@ -83,7 +83,7 @@ void ActsEvaluator::next_event(PHCompositeNode* topNode) } void ActsEvaluator::process_track(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, @@ -105,7 +105,7 @@ void ActsEvaluator::process_track(const ActsTrackFittingAlgorithm::TrackContaine } void ActsEvaluator::evaluateTrackFit(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, @@ -251,7 +251,7 @@ void ActsEvaluator::visitTrackStates(const Acts::VectorMultiTrajectory& traj, { /// Only fill the track states with non-outlier measurement auto typeFlags = state.typeFlags(); - if (! typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) + if (! typeFlags.isMeasurement()) { return true; } @@ -907,7 +907,7 @@ void ActsEvaluator::fillProtoTrack(const TrackSeed* seed) } else { - Acts::Vector3 loct = (*surf).transform(m_tGeometry->geometry().getGeoContext()).inverse() * globalTruthPos; + Acts::Vector3 loct = (*surf).localToGlobalTransform(m_tGeometry->geometry().getGeoContext()).inverse() * globalTruthPos; m_t_SL_lx.push_back(loct(0)); m_t_SL_ly.push_back(loct(1)); diff --git a/offline/packages/trackreco/ActsEvaluator.h b/offline/packages/trackreco/ActsEvaluator.h index 4af937d018..fae0515049 100644 --- a/offline/packages/trackreco/ActsEvaluator.h +++ b/offline/packages/trackreco/ActsEvaluator.h @@ -51,7 +51,7 @@ class ActsEvaluator void Init(PHCompositeNode* topNode); void process_track(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, @@ -64,7 +64,7 @@ class ActsEvaluator /// Function to evaluate Trajectories fit results from the KF void evaluateTrackFit(const ActsTrackFittingAlgorithm::TrackContainer& trackContainer, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index b4e03ca909..0afea11b6c 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -758,8 +758,6 @@ void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& r m_magneticField = nullptr; } - m_geoCtxt = Acts::GeometryContext(); - unpackVolumes(); return; @@ -1045,14 +1043,14 @@ void MakeActsGeometry::makeInttMapPairs(TrackingVolumePtr &inttVolume) std::cout << std::endl << " Layer type " << assoc_layer->layerType() << std::endl; - auto assoc_det_element = surf->associatedDetectorElement(); + auto assoc_det_element = surf->surfacePlacement(); if (assoc_det_element != nullptr) { std::cout << " Associated detElement has non-null pointer " << assoc_det_element << std::endl; std::cout << std::endl << " Associated detElement found, thickness = " - << assoc_det_element->thickness() << std::endl; + << surf->thickness() << std::endl; } else { @@ -1118,10 +1116,10 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) std::cout << "[DEBUG] MVTX surface center: (x,y,z)=(" << world_center[0] << "," << world_center[1] << "," << world_center[2] << "), layer_rad=" << layer_rad << std::endl; } - auto detelement = surf->associatedDetectorElement(); + auto detelement = surf->surfacePlacement(); if(!detelement) { - std::cout << PHWHERE << " Did not find associatedDetectorElement, have to quit! " << std::endl; + std::cout << PHWHERE << " Did not find surfacePlacement, have to quit! " << std::endl; exit(1); } @@ -1191,14 +1189,14 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) << " Layer type " << assoc_layer->layerType() << std::endl; - auto assoc_det_element = surf->associatedDetectorElement(); + auto assoc_det_element = surf->surfacePlacement(); if (assoc_det_element != nullptr) { std::cout << " Associated detElement has non-null pointer " << assoc_det_element << std::endl; std::cout << std::endl << " Associated detElement found, thickness = " - << assoc_det_element->thickness() << std::endl; + << surf->thickness() << std::endl; } else { diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index b7eb441b23..272182b713 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -268,7 +268,7 @@ class MakeActsGeometry : public SubsysReco /// Acts geometry objects that are needed to create (for example) the fitter TrackingGeometry m_tGeometry; std::shared_ptr m_magneticField; - Acts::GeometryContext m_geoCtxt; + Acts::GeometryContext m_geoCtxt = Acts::GeometryContext::dangerouslyDefaultConstruct(); /// Structs to put on the node tree which carry around ActsGeom info ActsGeometry *m_actsGeometry = nullptr; diff --git a/offline/packages/trackreco/MakeSourceLinks.cc b/offline/packages/trackreco/MakeSourceLinks.cc index d607a4be96..f2975ac952 100644 --- a/offline/packages/trackreco/MakeSourceLinks.cc +++ b/offline/packages/trackreco/MakeSourceLinks.cc @@ -168,8 +168,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( auto* check_cluster = clusterContainer->findCluster(key); Acts::Vector2 check_local2d = tGeometry->getLocalCoords(key, check_cluster) * Acts::UnitConstants::cm; // need mm Acts::Vector3 check_local3d(check_local2d(0), check_local2d(1), 0); - Acts::GeometryContext temp_transient_geocontext; - temp_transient_geocontext = transformMapTransient; + Acts::GeometryContext temp_transient_geocontext{transformMapTransient}; Acts::Vector3 check_before_pos_surf = this_surf->localToGlobal(temp_transient_geocontext, check_local2d, Acts::Vector3(1, 1, 1)); @@ -209,8 +208,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( } // end loop over clusters here - Acts::GeometryContext transient_geocontext; - transient_geocontext = transformMapTransient; + Acts::GeometryContext transient_geocontext{transformMapTransient}; // loop over cluster_vec and make source links for (auto& cluskey : cluster_vec) @@ -503,7 +501,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( /// otherwise take the manual calculation for the TPC // doing it this way just avoids the bounds check that occurs in the surface class method - Acts::Vector3 loct = surf->transform(tGeometry->geometry().getGeoContext()).inverse() * global; // global is in mm + Acts::Vector3 loct = surf->localToGlobalTransform(tGeometry->geometry().getGeoContext()).inverse() * global; // global is in mm loct /= Acts::UnitConstants::cm; localPos(0) = loct(0); diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 9082feda63..717ce4c3cb 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -134,7 +134,6 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) if (m_fitSiliconMMs || m_directNavigation) { m_tGeometry->geometry().tGeometry->visitSurfaces(selector, false); - // std::cout<<"selector.surfaces.size() "< Date: Sun, 17 May 2026 14:02:49 -0400 Subject: [PATCH 518/866] update remaining apis --- .../HelicalFitter.cc | 16 +++++++------- .../TrackingDiagnostics/TrackResiduals.cc | 22 +++++++++---------- .../packages/trackreco/PHActsKDTreeSeeding.cc | 4 ---- .../trackreco/PHActsSiliconSeeding.cc | 10 ++------- offline/packages/trackreco/PHActsTrkFitter.cc | 8 +++---- offline/packages/trackreco/PHActsTrkFitter.h | 4 ++-- .../packages/trackreco/PHCosmicsTrkFitter.cc | 10 ++++----- .../packages/trackreco/PHCosmicsTrkFitter.h | 4 ++-- offline/packages/trackreco/WeightedFitter.cc | 2 +- .../g4simulation/g4tpc/TpcClusterBuilder.cc | 2 +- 10 files changed, 36 insertions(+), 46 deletions(-) diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index e50a41a3f6..8331a8b491 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -594,8 +594,8 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) // fitpoint is the point where the helical fit intersects the plane of the surface // Now transform the helix fitpoint to local coordinates to compare with cluster local coordinates - Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); - Acts::Vector3 fitpoint_mvtx_half_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_mvtx_half * Acts::UnitConstants::cm); + Acts::Vector3 fitpoint_local = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); + Acts::Vector3 fitpoint_mvtx_half_local = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_mvtx_half * Acts::UnitConstants::cm); fitpoint_local /= Acts::UnitConstants::cm; fitpoint_mvtx_half_local /= Acts::UnitConstants::cm; @@ -634,7 +634,7 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) if (Verbosity() > 1) { - Acts::Vector3 loc_check = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); + Acts::Vector3 loc_check = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); loc_check /= Acts::UnitConstants::cm; std::cout << " layer " << layer << std::endl << " cluster global " << global(0) << " " << global(1) << " " << global(2) << std::endl @@ -647,10 +647,10 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) if (Verbosity() > 1) { - Acts::Transform3 transform = surf->transform(_tGeometry->geometry().getGeoContext()); + Acts::Transform3 transform = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()); std::cout << "Transform is:" << std::endl; std::cout << transform.matrix() << std::endl; - Acts::Vector3 loc_check = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); + Acts::Vector3 loc_check = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); loc_check /= Acts::UnitConstants::cm; unsigned int const sector = TpcDefs::getSectorId(cluskey_vec[ivec]); unsigned int const side = TpcDefs::getSide(cluskey_vec[ivec]); @@ -779,7 +779,7 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) Acts::Vector3 ideal_center = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1; Acts::Vector3 ideal_norm = -surf->normal(_tGeometry->geometry().getGeoContext(),Acts::Vector3(1,1,1), Acts::Vector3(1,1,1)); Acts::Vector3 const ideal_local(xloc, zloc, 0.0); // cm - Acts::Vector3 ideal_glob = surf->transform(_tGeometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); + Acts::Vector3 ideal_glob = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); ideal_glob /= Acts::UnitConstants::cm; alignmentTransformationContainer::use_alignment = true; @@ -1953,10 +1953,10 @@ void HelicalFitter::get_projectionXY(const Surface& surf, const std::pairtransform(_tGeometry->geometry().getGeoContext()) * (xloc * Acts::UnitConstants::cm); + Acts::Vector3 xglob = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()) * (xloc * Acts::UnitConstants::cm); xglob /= Acts::UnitConstants::cm; Acts::Vector3 const yloc(0.0, 1.0, 0.0); - Acts::Vector3 yglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (yloc * Acts::UnitConstants::cm); + Acts::Vector3 yglob = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()) * (yloc * Acts::UnitConstants::cm); yglob /= Acts::UnitConstants::cm; // These are the local frame unit vectors transformed to the global frame Acts::Vector3 const X = (xglob - sensorCenter) / (xglob - sensorCenter).norm(); diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index d029ded711..1a5a69fae0 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -1128,7 +1128,7 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr { // otherwise take the manual calculation for the TPC // doing it this way just avoids the bounds check that occurs in the surface class method - Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm + Acts::Vector3 loct = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm loct /= Acts::UnitConstants::cm; loc(0) = loct(0); @@ -1166,7 +1166,7 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr auto misaligncenter = surf->center(geometry->geometry().getGeoContext()); auto misalignnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); - auto misrot = surf->transform(geometry->geometry().getGeoContext()).rotation(); + auto misrot = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); float mgamma = atan2(-misrot(1, 0), misrot(0, 0)); float mbeta = -asin(misrot(0, 1)); @@ -1183,11 +1183,11 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr std::cout << "resids: layer " << layer << " ideal center z " << idealcenter.z() << " mm " << std::endl; std::cout << " surface bounds " << surfbounds[0] << " " << surfbounds[1] << " mm " << std::endl; alignmentTransformationContainer::use_alignment = false; - Acts::Transform3 transform = surf_ideal->transform(geometry->geometry().getGeoContext()); + Acts::Transform3 transform = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()); std::cout << "Ideal transform is:" << std::endl; std::cout << transform.matrix() << std::endl; alignmentTransformationContainer::use_alignment = true; - Acts::Transform3 transform1 = surf_ideal->transform(geometry->geometry().getGeoContext()); + Acts::Transform3 transform1 = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()); std::cout << "Alignment transform is:" << std::endl; std::cout << transform1.matrix() << std::endl; @@ -1199,8 +1199,8 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr // Acts::Vector3 ideal_local(loc.x(), loc.y(), 0.0); auto nominal_loc = geometry->getLocalCoords(ckey, cluster); Acts::Vector3 ideal_local(nominal_loc.x(), nominal_loc.y(), 0.0); - Acts::Vector3 ideal_glob = surf_ideal->transform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); - auto idealrot = surf_ideal->transform(geometry->geometry().getGeoContext()).rotation(); + Acts::Vector3 ideal_glob = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); + auto idealrot = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); //! These calculations are taken from the wikipedia page for Euler angles, //! under the Tait-Bryan angle explanation. Formulas for the angles @@ -1453,7 +1453,7 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr auto misaligncenter = surf->center(geometry->geometry().getGeoContext()); auto misalignnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); - auto misrot = surf->transform(geometry->geometry().getGeoContext()).rotation(); + auto misrot = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); float mgamma = atan2(-misrot(1, 0), misrot(0, 0)); float mbeta = -asin(misrot(0, 1)); @@ -1464,8 +1464,8 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr auto idealcenter = surf->center(geometry->geometry().getGeoContext()); auto idealnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); Acts::Vector3 ideal_local(loc.x(), loc.y(), 0.0); - Acts::Vector3 ideal_glob = surf->transform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); - auto idealrot = surf->transform(geometry->geometry().getGeoContext()).rotation(); + Acts::Vector3 ideal_glob = surf->localToGlobalTransform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); + auto idealrot = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); //! These calculations are taken from the wikipedia page for Euler angles, //! under the Tait-Bryan angle explanation. Formulas for the angles @@ -1552,7 +1552,7 @@ void TrackResiduals::fillStatesWithCircleFit(const TrkrDefs::cluskey& key, } else { - auto local = (surf->transform(geometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); + auto local = (surf->localToGlobalTransform(geometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; m_statelx.push_back(local.x()); m_statelz.push_back(local.y()); @@ -1579,7 +1579,7 @@ void TrackResiduals::fillStatesWithLineFit(const TrkrDefs::cluskey& key, } else { - Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); + Acts::Vector3 loct = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); loct /= Acts::UnitConstants::cm; m_statelx.push_back(loct(0)); m_statelz.push_back(loct(1)); diff --git a/offline/packages/trackreco/PHActsKDTreeSeeding.cc b/offline/packages/trackreco/PHActsKDTreeSeeding.cc index ad5b25307e..6914a0e60f 100644 --- a/offline/packages/trackreco/PHActsKDTreeSeeding.cc +++ b/offline/packages/trackreco/PHActsKDTreeSeeding.cc @@ -554,8 +554,4 @@ void PHActsKDTreeSeeding::configureSeedFinder() m_seedFinderConfig.rMinMiddle = m_rMinMiddle; m_seedFinderConfig.rMaxMiddle = m_rMaxMiddle; - m_seedFinderConfig = - m_seedFinderConfig.toInternalUnits().calculateDerivedQuantities(); - m_seedFinderOptions = - m_seedFinderOptions.toInternalUnits().calculateDerivedQuantities(m_seedFinderConfig); } diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index ab0126913c..397610cd2a 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -84,7 +84,6 @@ PHActsSiliconSeeding::~PHActsSiliconSeeding() int PHActsSiliconSeeding::Init(PHCompositeNode* /*topNode*/) { Acts::SeedFilterConfig sfCfg = configureSeedFilter(); - sfCfg = sfCfg.toInternalUnits(); m_seedFinderCfg.seedFilter = std::make_unique>( sfCfg); @@ -957,7 +956,7 @@ std::vector PHActsSiliconSeeding::findMatches( { intersection = TrackFitUtils::get_helix_surface_intersection(surf, dummypars, glob, m_tGeometry); } - auto local = (surf->transform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); + auto local = (surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; m_projgx = intersection.x(); m_projgy = intersection.y(); @@ -1260,7 +1259,7 @@ std::vector> PHActsSiliconSeeding::iterateLayers( auto glob = m_tGeometry->getGlobalPosition( cluskey, cluster); auto intersection = TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); - auto local = (surf->transform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); + auto local = (surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; m_projgx = intersection.x(); m_projgy = intersection.y(); @@ -1489,8 +1488,6 @@ void PHActsSiliconSeeding::configureSPGrid() m_gridCfg.phiBinDeflectionCoverage = m_numPhiNeighbors; m_gridOptions.bFieldInZ = m_bField; - m_gridCfg = m_gridCfg.toInternalUnits(); - m_gridOptions = m_gridOptions.toInternalUnits(); } Acts::SeedFilterConfig PHActsSiliconSeeding::configureSeedFilter() const @@ -1544,9 +1541,6 @@ void PHActsSiliconSeeding::configureSeeder() m_seedFinderCfg.sigmaError = m_sigmaError; m_seedFinderCfg.helixCutTolerance = m_helixcut; - m_seedFinderCfg = - m_seedFinderCfg.toInternalUnits().calculateDerivedQuantities(); - m_seedFinderOptions = m_seedFinderOptions.toInternalUnits().calculateDerivedQuantities(m_seedFinderCfg); } int PHActsSiliconSeeding::getNodes(PHCompositeNode* topNode) diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index 717ce4c3cb..1cf72bdfdc 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -519,9 +519,9 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) // add tpc sourcelinks to silicon source links sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end()); } - + Acts::GeometryContext geoContext{m_alignmentTransformationMapTransient}; // copy transient map for this track into transient geoContext - m_transient_geocontext = m_alignmentTransformationMapTransient; + m_transient_geocontext = geoContext; // position comes from the silicon seed, unless there is no silicon seed Acts::Vector3 position(0, 0, 0); @@ -868,7 +868,7 @@ bool PHActsTrkFitter::getTrackFitResult( { /// Make a trajectory state for storage, which conforms to Acts track fit /// analysis tool - std::vector trackTips; + std::vector trackTips; trackTips.reserve(1); const auto& outtrack = fitOutput.value(); if (outtrack.hasReferenceSurface()) @@ -1050,7 +1050,7 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const } void PHActsTrkFitter::updateSvtxTrack( - const std::vector& tips, + const std::vector& tips, const Trajectory::IndexedParameters& paramsMap, const ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track) diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index cadfd5bec0..3e0ee71132 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -155,7 +155,7 @@ class PHActsTrkFitter : public SubsysReco /// Convert the acts track fit result to an svtx track void updateSvtxTrack( - const std::vector& tips, + const std::vector& tips, const Trajectory::IndexedParameters& paramsMap, const ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track); @@ -200,7 +200,7 @@ class PHActsTrkFitter : public SubsysReco alignmentTransformationContainer* m_alignmentTransformationMap = nullptr; // added for testing purposes alignmentTransformationContainer* m_alignmentTransformationMapTransient = nullptr; std::set m_transient_id_set; - Acts::GeometryContext m_transient_geocontext; + Acts::GeometryContext m_transient_geocontext = Acts::GeometryContext::dangerouslyDefaultConstruct(); SvtxTrackMap* m_trackMap = nullptr; SvtxTrackMap* m_directedTrackMap = nullptr; TrkrClusterContainer* m_clusterContainer = nullptr; diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index c93861b166..b4f096ba92 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -324,8 +324,9 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) getCharge(tpcseed, charge, cosmicslope); + Acts::GeometryContext geoContext{m_alignmentTransformationMapTransient}; // copy transient map for this track into transient geoContext - m_transient_geocontext = m_alignmentTransformationMapTransient; + m_transient_geocontext = geoContext; { // get positions from cluster keys @@ -581,7 +582,7 @@ bool PHCosmicsTrkFitter::getTrackFitResult(FitResult& fitOutput, /// Make a trajectory state for storage, which conforms to Acts track fit /// analysis tool auto& outtrack = fitOutput.value(); - std::vector trackTips; + std::vector trackTips; trackTips.reserve(1); trackTips.emplace_back(outtrack.tipIndex()); Trajectory::IndexedParameters indexedParams; @@ -637,7 +638,7 @@ inline ActsTrackFittingAlgorithm::TrackFitterResult PHCosmicsTrkFitter::fitTrack } void PHCosmicsTrkFitter::updateSvtxTrack( - std::vector& tips, + std::vector& tips, Trajectory::IndexedParameters& paramsMap, ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track) @@ -989,8 +990,7 @@ void PHCosmicsTrkFitter::getCharge( int& charge, float& cosmicslope) { - Acts::GeometryContext transient_geocontext; - transient_geocontext = m_alignmentTransformationMapTransient; // set local/global transforms to distortion corrected ones for this track + Acts::GeometryContext transient_geocontext{m_alignmentTransformationMapTransient}; std::vector global_vec; diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index 2dc8c579db..79be4c14f8 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -106,7 +106,7 @@ class PHCosmicsTrkFitter : public SubsysReco void getCharge(TrackSeed* track, int& charge, float& cosmicslope); /// Convert the acts track fit result to an svtx track - void updateSvtxTrack(std::vector& tips, + void updateSvtxTrack(std::vector& tips, Trajectory::IndexedParameters& paramsMap, ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track); @@ -150,7 +150,7 @@ class PHCosmicsTrkFitter : public SubsysReco // Used for distortion correction transformations alignmentTransformationContainer* m_alignmentTransformationMapTransient = nullptr; std::set m_transient_id_set; - Acts::GeometryContext m_transient_geocontext; + Acts::GeometryContext m_transient_geocontext = Acts::GeometryContext::dangerouslyDefaultConstruct(); /// Number of acts fits that returned an error int m_nBadFits = 0; diff --git a/offline/packages/trackreco/WeightedFitter.cc b/offline/packages/trackreco/WeightedFitter.cc index 090775a0da..2897b3a337 100644 --- a/offline/packages/trackreco/WeightedFitter.cc +++ b/offline/packages/trackreco/WeightedFitter.cc @@ -390,7 +390,7 @@ WeightedFitter::get_points ( Surface const surf = m_geometry->maps().getSurface(cluster_key, cluster); if (!surf) { continue; } - auto local_to_global_transform = surf->transform(m_geometry->geometry().getGeoContext()); // in mm + auto local_to_global_transform = surf->localToGlobalTransform(m_geometry->geometry().getGeoContext()); // in mm local_to_global_transform.translation() /= Acts::UnitConstants::cm; // converted to cm Eigen::Vector3d local_pos = Eigen::Vector3d { cluster->getLocalX(), cluster->getLocalY(), 0.0 }; // in cm diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index ed2445b1ad..eb39ed8033 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -351,7 +351,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) global *= Acts::UnitConstants::cm; - Acts::Vector3 local = surface->transform(m_tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(m_tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; auto* cluster = new TrkrClusterv4; // From 40e8aa17aeecaadd58e36d79468345619954b69a Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Mon, 18 May 2026 07:12:11 -0400 Subject: [PATCH 519/866] update transform call --- offline/QA/Tracking/CosmicTrackQA.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/QA/Tracking/CosmicTrackQA.cc b/offline/QA/Tracking/CosmicTrackQA.cc index 08f9cdadea..c3ae615158 100644 --- a/offline/QA/Tracking/CosmicTrackQA.cc +++ b/offline/QA/Tracking/CosmicTrackQA.cc @@ -149,7 +149,7 @@ int CosmicTrackQA::process_event(PHCompositeNode *topNode) } else { - Acts::Vector3 loc = surf->transform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); + Acts::Vector3 loc = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); loc /= Acts::UnitConstants::cm; statelx = loc(0); statelz = loc(1); @@ -191,7 +191,7 @@ int CosmicTrackQA::process_event(PHCompositeNode *topNode) } else { - Acts::Vector3 loc = surf->transform(geometry->geometry().getGeoContext()).inverse() * (stateglob * Acts::UnitConstants::cm); + Acts::Vector3 loc = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * (stateglob * Acts::UnitConstants::cm); loc /= Acts::UnitConstants::cm; statelx = loc(0); statelz = loc(1); From 6cd4e87d3a20187b6df94a51afbbfc02f7de4308 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 08:04:56 -0400 Subject: [PATCH 520/866] cppcheck for LiteCaloEval --- calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc b/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc index 588a27b024..acffcc948a 100644 --- a/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc +++ b/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc @@ -14,7 +14,7 @@ #include #include -#include // for Double_t +#include // for Double_t #include #include #include @@ -548,7 +548,7 @@ void LiteCaloEval::Get_Histos(const std::string &infile, const std::string &outf if (!heta_tempp && i == 0) { - std::cout << " warning hist " << hist_name_p.c_str() << " not found" << std::endl; + std::cout << " warning hist " << hist_name_p << " not found" << std::endl; } /// assign heta_tempp to array of tower histos From d7ca606aee2adb5bb09cc72b4dc9c00759e3a406 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 08:07:46 -0400 Subject: [PATCH 521/866] cppcheck for Fun4CalServer --- calibrations/framework/fun4cal/Fun4CalServer.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/calibrations/framework/fun4cal/Fun4CalServer.cc b/calibrations/framework/fun4cal/Fun4CalServer.cc index 5f9ec55b05..1fdc4d05b2 100644 --- a/calibrations/framework/fun4cal/Fun4CalServer.cc +++ b/calibrations/framework/fun4cal/Fun4CalServer.cc @@ -660,7 +660,7 @@ bool Fun4CalServer::connectDB() } catch (odbc::SQLException &e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; std::cout << "countdown: " << countdown << std::endl; countdown--; @@ -673,7 +673,7 @@ bool Fun4CalServer::connectDB() std::cout << "could not connect to DB after 10 tries in 1000 secs, giving up" << std::endl; exit(-1); } - std::cout << "connected to " << database.c_str() << " database." << std::endl; + std::cout << "connected to " << database << " database." << std::endl; return true; } //--------------------------------------------------------------------- @@ -1349,7 +1349,7 @@ int Fun4CalServer::SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const s } catch (odbc::SQLException &e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; return -1; } @@ -1511,7 +1511,7 @@ int Fun4CalServer::SyncOncalTimeStampsToRunDB(const int commit) } catch (odbc::SQLException &e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; return -1; } @@ -2322,7 +2322,7 @@ int Fun4CalServer::AdjustRichTimeStampForMultipleRuns() } catch (odbc::SQLException& e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; return -1; } From d6bd1a2ad1b9a9255d593b5a69966c0050e238cb Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 08:10:24 -0400 Subject: [PATCH 522/866] cppcheck for QAG4SimulationKFParticle --- offline/QA/SimulationModules/QAG4SimulationKFParticle.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc b/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc index b9be814a15..4c24fe241e 100644 --- a/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc +++ b/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc @@ -417,7 +417,7 @@ int QAG4SimulationKFParticle::load_nodes(PHCompositeNode *topNode) m_kfpContainer = findNode::getClass(topNode, m_mother_name + "_KFParticle_Container"); if (!m_kfpContainer) { - std::cout << m_mother_name.c_str() << "_KFParticle_Container - Fatal Error - " + std::cout << m_mother_name << "_KFParticle_Container - Fatal Error - " << "unable to find DST node " << "G4_QA" << std::endl; assert(m_kfpContainer); From 414498c57c16574d34d64c3ab1455dd5a049cc6e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 08:11:40 -0400 Subject: [PATCH 523/866] cppcheck for Fun4AllHistoManager --- offline/framework/fun4all/Fun4AllHistoManager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/framework/fun4all/Fun4AllHistoManager.cc b/offline/framework/fun4all/Fun4AllHistoManager.cc index dde8c7367a..0c05ce9b53 100644 --- a/offline/framework/fun4all/Fun4AllHistoManager.cc +++ b/offline/framework/fun4all/Fun4AllHistoManager.cc @@ -126,7 +126,7 @@ int Fun4AllHistoManager::dumpHistos(const std::string &filename, const std::stri TFile hfile(theoutfile.c_str(), openmode.c_str(), creator.c_str()); if (!hfile.IsOpen()) { - std::cout << PHWHERE << " Could not open output file" << theoutfile.c_str() << std::endl; + std::cout << PHWHERE << " Could not open output file" << theoutfile << std::endl; return -1; } hfile.SetCompressionSettings(compress); From 674f25bef2cb12e51f19e64fd2ce65a82eac246f Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 08:39:50 -0400 Subject: [PATCH 524/866] cppcheck for mvtx_decoder --- offline/framework/fun4allraw/mvtx_decoder/GBTLink.h | 2 +- offline/framework/fun4allraw/mvtx_decoder/GBTWord.h | 2 +- offline/framework/fun4allraw/mvtx_decoder/PixelData.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h b/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h index 4604e9944e..69fa1a9c83 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h +++ b/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h @@ -330,7 +330,7 @@ inline GBTLink::CollectedDataStatus GBTLink::collectROFCableData(/*const Mapping ((gbtWord.activeLanes >> 6) & 0x7) == 0x7) ) { log_error << "Expected all active lanes for links, but " << gbtWord.activeLanes << "found in HBF " << hbfEntry << ", " \ - << gbtWord.asString().data() << std::endl; + << gbtWord.asString() << std::endl; } } else if (gbtWord.isTDH()) // TRIGGER DATA HEADER (TDH) diff --git a/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h b/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h index 10eeb80d5d..16d1c80941 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h +++ b/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h @@ -107,7 +107,7 @@ struct GBTWord { uint8_t data8[GBTWordLength]; // 80 bits GBT word }; #pragma GCC diagnostic pop - +// cppcheck-suppress uninitMemberVar GBTWord() = default; /// check if the GBT Header corresponds to GBT payload header diff --git a/offline/framework/fun4allraw/mvtx_decoder/PixelData.h b/offline/framework/fun4allraw/mvtx_decoder/PixelData.h index 475e7581e6..fcc13fb4ef 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/PixelData.h +++ b/offline/framework/fun4allraw/mvtx_decoder/PixelData.h @@ -40,7 +40,7 @@ class ChipPixelData ~ChipPixelData() = default; uint16_t getChipID() const { return mChipID; } const std::vector& getData() const { return mPixels; } - std::vector& getData() { return (std::vector&)mPixels; } + std::vector& getData() { return static_cast&> (mPixels); } // void setROFlags(uint8_t f = 0) { mROFlags = f; } void setChipID(uint16_t id) { mChipID = id; } From e3be83949f9af91f12fe0dd878c3db838ba392a4 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 08:40:09 -0400 Subject: [PATCH 525/866] cppcheck for Fun4CalServer --- calibrations/framework/fun4cal/Fun4CalServer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calibrations/framework/fun4cal/Fun4CalServer.cc b/calibrations/framework/fun4cal/Fun4CalServer.cc index 1fdc4d05b2..c3612641dc 100644 --- a/calibrations/framework/fun4cal/Fun4CalServer.cc +++ b/calibrations/framework/fun4cal/Fun4CalServer.cc @@ -17,7 +17,7 @@ #include -#include // for Stat_t +#include // for Stat_t #include // for TDirectoryAtomicAdapter #include #include From 25464bc3f24a4369e1d4d5b4797ba5bfe18ceb33 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 10:10:22 -0400 Subject: [PATCH 526/866] initialize vars, remove useless static cast for GBTWord.h, PixelData.h --- offline/framework/fun4allraw/mvtx_decoder/GBTWord.h | 3 +-- offline/framework/fun4allraw/mvtx_decoder/PixelData.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h b/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h index 16d1c80941..0c2060490f 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h +++ b/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h @@ -104,10 +104,9 @@ struct GBTWord { }; // DIAGNOSTIC IB LANE - uint8_t data8[GBTWordLength]; // 80 bits GBT word + uint8_t data8[GBTWordLength]{}; // 80 bits GBT word }; #pragma GCC diagnostic pop -// cppcheck-suppress uninitMemberVar GBTWord() = default; /// check if the GBT Header corresponds to GBT payload header diff --git a/offline/framework/fun4allraw/mvtx_decoder/PixelData.h b/offline/framework/fun4allraw/mvtx_decoder/PixelData.h index fcc13fb4ef..6e3d0a964a 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/PixelData.h +++ b/offline/framework/fun4allraw/mvtx_decoder/PixelData.h @@ -40,7 +40,7 @@ class ChipPixelData ~ChipPixelData() = default; uint16_t getChipID() const { return mChipID; } const std::vector& getData() const { return mPixels; } - std::vector& getData() { return static_cast&> (mPixels); } + std::vector& getData() { return mPixels; } // void setROFlags(uint8_t f = 0) { mROFlags = f; } void setChipID(uint16_t id) { mChipID = id; } From 87940a7546d153035261a48b02bb1d774fcac909 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 10:27:28 -0400 Subject: [PATCH 527/866] cppcheck for CaloTowerStatus ClusterCDFCalculator, replace boost::format by std::format --- offline/packages/CaloReco/CaloTowerStatus.cc | 2 +- .../packages/CaloReco/ClusterCDFCalculator.cc | 63 +++++++++---------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index 4cba2f1fcf..795ee97c3f 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -242,7 +242,7 @@ void CaloTowerStatus::CreateNodeTree(PHCompositeNode *topNode) m_raw_towers = findNode::getClass(topNode, RawTowerNodeName); if (!m_raw_towers) { - std::cout << Name() << "::" << m_detector.c_str() << "::" << __PRETTY_FUNCTION__ + std::cout << Name() << "::" << m_detector << "::" << __PRETTY_FUNCTION__ << " " << RawTowerNodeName << " Node missing, exiting!" << std::endl; gSystem->Exit(1); diff --git a/offline/packages/CaloReco/ClusterCDFCalculator.cc b/offline/packages/CaloReco/ClusterCDFCalculator.cc index 80b908b2b6..df1d8fe6f6 100644 --- a/offline/packages/CaloReco/ClusterCDFCalculator.cc +++ b/offline/packages/CaloReco/ClusterCDFCalculator.cc @@ -5,9 +5,8 @@ #include #include -#include - #include +#include ClusterCDFCalculator::~ClusterCDFCalculator() { @@ -94,9 +93,9 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() for (int binidx = 0; binidx < nBins; ++binidx) { // photon hist - std::string hD2_3x3_name_photon = (boost::format("h_photon_hD2_3x3_en%d") % binidx).str(); - std::string hD2_5x5_name_photon = (boost::format("h_photon_hD2_5x5_en%d") % binidx).str(); - std::string hD2_7x7_name_photon = (boost::format("h_photon_hD2_7x7_en%d") % binidx).str(); + std::string hD2_3x3_name_photon = std::format("h_photon_hD2_3x3_en{}", binidx); + std::string hD2_5x5_name_photon = std::format("h_photon_hD2_5x5_en{}", binidx); + std::string hD2_7x7_name_photon = std::format("h_photon_hD2_7x7_en{}", binidx); file->GetObject(hD2_3x3_name_photon.c_str(), hD2_3x3_photon[binidx]); file->GetObject(hD2_5x5_name_photon.c_str(), hD2_5x5_photon[binidx]); @@ -109,11 +108,11 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() } TH1 *hD2mean3_photon{nullptr}; - file->GetObject((boost::format("h_photon_hD2mean3_en%d") % binidx).str().c_str(), hD2mean3_photon); + file->GetObject(std::format("h_photon_hD2mean3_en{}", binidx).c_str(), hD2mean3_photon); TH1 *hD2mean5_photon{nullptr}; - file->GetObject((boost::format("h_photon_hD2mean5_en%d") % binidx).str().c_str(), hD2mean5_photon); + file->GetObject(std::format("h_photon_hD2mean5_en{}", binidx).c_str(), hD2mean5_photon); TH1 *hD2mean7_photon{nullptr}; - file->GetObject((boost::format("h_photon_hD2mean7_en%d") % binidx).str().c_str(), hD2mean7_photon); + file->GetObject(std::format("h_photon_hD2mean7_en{}", binidx).c_str(), hD2mean7_photon); if (!hD2mean3_photon || !hD2mean5_photon || !hD2mean7_photon) { @@ -126,40 +125,40 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() for (int i = 0; i < NMATRIX_3x3; ++i) { - std::string histName = (boost::format("h_photon_heratio_3x3_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_photon_heratio_3x3_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_3x3_photon[binidx][i]); if (!ratioHistograms_3x3_photon[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_5x5; ++i) { - std::string histName = (boost::format("h_photon_heratio_5x5_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_photon_heratio_5x5_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_5x5_photon[binidx][i]); if (!ratioHistograms_5x5_photon[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_7x7; ++i) { - std::string histName = (boost::format("h_photon_heratio_7x7_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_photon_heratio_7x7_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_7x7_photon[binidx][i]); if (!ratioHistograms_7x7_photon[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName << " is missing." << std::endl; return; } } TH2 *hCovMatrix3x3_photon{nullptr}; - file->GetObject((boost::format("h_photon_hCovMatrix3_en%d") % binidx).str().c_str(), hCovMatrix3x3_photon); + file->GetObject(std::format("h_photon_hCovMatrix3_en{}", binidx).c_str(), hCovMatrix3x3_photon); TH2 *hCovMatrix5x5_photon{nullptr}; - file->GetObject((boost::format("h_photon_hCovMatrix5_en%d") % binidx).str().c_str(), hCovMatrix5x5_photon); + file->GetObject(std::format("h_photon_hCovMatrix5_en{}", binidx).c_str(), hCovMatrix5x5_photon); TH2 *hCovMatrix7x7_photon{nullptr}; - file->GetObject((boost::format("h_photon_hCovMatrix7_en%d") % binidx).str().c_str(), hCovMatrix7x7_photon); + file->GetObject(std::format("h_photon_hCovMatrix7_en{}", binidx).c_str(), hCovMatrix7x7_photon); if (!hCovMatrix3x3_photon || !hCovMatrix5x5_photon || !hCovMatrix7x7_photon) { @@ -200,9 +199,9 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() } // pi0 hist - std::string hD2_3x3_name_pi0 = (boost::format("h_pi0_hD2_3x3_en%d") % binidx).str(); - std::string hD2_5x5_name_pi0 = (boost::format("h_pi0_hD2_5x5_en%d") % binidx).str(); - std::string hD2_7x7_name_pi0 = (boost::format("h_pi0_hD2_7x7_en%d") % binidx).str(); + std::string hD2_3x3_name_pi0 = std::format("h_pi0_hD2_3x3_en{}", binidx); + std::string hD2_5x5_name_pi0 = std::format("h_pi0_hD2_5x5_en{}", binidx); + std::string hD2_7x7_name_pi0 = std::format("h_pi0_hD2_7x7_en{}", binidx); file->GetObject(hD2_3x3_name_pi0.c_str(), hD2_3x3_pi0[binidx]); file->GetObject(hD2_5x5_name_pi0.c_str(), hD2_5x5_pi0[binidx]); @@ -215,11 +214,11 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() } TH1 *hD2mean3_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hD2mean3_en%d") % binidx).str().c_str(), hD2mean3_pi0); + file->GetObject(std::format("h_pi0_hD2mean3_en{}", binidx).c_str(), hD2mean3_pi0); TH1 *hD2mean5_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hD2mean5_en%d") % binidx).str().c_str(), hD2mean5_pi0); + file->GetObject(std::format("h_pi0_hD2mean5_en{}", binidx).c_str(), hD2mean5_pi0); TH1 *hD2mean7_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hD2mean7_en%d") % binidx).str().c_str(), hD2mean7_pi0); + file->GetObject(std::format("h_pi0_hD2mean7_en{}", binidx).c_str(), hD2mean7_pi0); if (!hD2mean3_pi0 || !hD2mean5_pi0 || !hD2mean7_pi0) { @@ -232,40 +231,40 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() for (int i = 0; i < NMATRIX_3x3; ++i) { - std::string histName = (boost::format("h_pi0_heratio_3x3_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_pi0_heratio_3x3_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_3x3_pi0[binidx][i]); if (!ratioHistograms_3x3_pi0[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_5x5; ++i) { - std::string histName = (boost::format("h_pi0_heratio_5x5_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_pi0_heratio_5x5_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_5x5_pi0[binidx][i]); if (!ratioHistograms_5x5_pi0[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_7x7; ++i) { - std::string histName = (boost::format("h_pi0_heratio_7x7_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_pi0_heratio_7x7_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_7x7_pi0[binidx][i]); if (!ratioHistograms_7x7_pi0[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName << " is missing." << std::endl; return; } } TH2 *hCovMatrix3x3_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hCovMatrix3_en%d") % binidx).str().c_str(), hCovMatrix3x3_pi0); + file->GetObject(std::format("h_pi0_hCovMatrix3_en{}", binidx).c_str(), hCovMatrix3x3_pi0); TH2 *hCovMatrix5x5_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hCovMatrix5_en%d") % binidx).str().c_str(), hCovMatrix5x5_pi0); + file->GetObject(std::format("h_pi0_hCovMatrix5_en{}", binidx).c_str(), hCovMatrix5x5_pi0); TH2 *hCovMatrix7x7_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hCovMatrix7_en%d") % binidx).str().c_str(), hCovMatrix7x7_pi0); + file->GetObject(std::format("h_pi0_hCovMatrix7_en{}", binidx).c_str(), hCovMatrix7x7_pi0); if (!hCovMatrix3x3_pi0 || !hCovMatrix5x5_pi0 || !hCovMatrix7x7_pi0) { From 45672aebfffae2a5c724c1f36ee74b8a17f5e33e Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 10:32:14 -0400 Subject: [PATCH 528/866] cppcheck for JetProbeMaker --- offline/packages/jetbase/JetProbeMaker.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/offline/packages/jetbase/JetProbeMaker.cc b/offline/packages/jetbase/JetProbeMaker.cc index ea8e6b891e..21617c915f 100644 --- a/offline/packages/jetbase/JetProbeMaker.cc +++ b/offline/packages/jetbase/JetProbeMaker.cc @@ -5,6 +5,7 @@ #include "Jetv2.h" #include + #include #include #include // for PHNode @@ -15,6 +16,7 @@ #include // for PHWHERE #include + #include int JetProbeMaker::process_event(PHCompositeNode * /*topNode*/) @@ -29,7 +31,7 @@ int JetProbeMaker::process_event(PHCompositeNode * /*topNode*/) fastjet::PseudoJet fjet{}; fjet.reset_PtYPhiM(pt, eta, phi); - Jetv2 *jet = (Jetv2 *) _jets->add_jet(); + Jetv2 *jet = static_cast (_jets->add_jet()); jet->set_px(fjet.px()); jet->set_py(fjet.py()); jet->set_pz(fjet.pz()); From 0aee5247b26dc591b3af832c56a9a597764036d3 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 10:32:26 -0400 Subject: [PATCH 529/866] cppcheck for JetProbeMaker --- offline/packages/jetbase/JetProbeMaker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/jetbase/JetProbeMaker.h b/offline/packages/jetbase/JetProbeMaker.h index b319ff1198..86cfe54842 100644 --- a/offline/packages/jetbase/JetProbeMaker.h +++ b/offline/packages/jetbase/JetProbeMaker.h @@ -19,7 +19,7 @@ class JetProbeMaker : public SubsysReco { public: JetProbeMaker(const std::string &name = "JetProbeMaker"); - ~JetProbeMaker() override{}; + ~JetProbeMaker() override = default; int process_event(PHCompositeNode * /*topNode*/) override; int InitRun(PHCompositeNode *topNode) override; From b687571ea26882a4d6ca3742cde2a18466ccaa92 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 10:39:46 -0400 Subject: [PATCH 530/866] cppcheck for MvtxEventInfov2 --- offline/packages/trackbase/MvtxEventInfov2.cc | 6 ------ offline/packages/trackbase/MvtxEventInfov2.h | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/offline/packages/trackbase/MvtxEventInfov2.cc b/offline/packages/trackbase/MvtxEventInfov2.cc index f1b6fddc14..f9fef23636 100644 --- a/offline/packages/trackbase/MvtxEventInfov2.cc +++ b/offline/packages/trackbase/MvtxEventInfov2.cc @@ -140,12 +140,6 @@ unsigned int MvtxEventInfov2::get_number_L1s() const return mySet.size(); } -std::set MvtxEventInfov2::get_strobe_BCOs() const -{ - std::set mySet = m_strobe_BCOs; - return mySet; -} - std::set MvtxEventInfov2::get_L1_BCOs() const { std::set mySet; diff --git a/offline/packages/trackbase/MvtxEventInfov2.h b/offline/packages/trackbase/MvtxEventInfov2.h index f1e663dd86..a4629c6441 100644 --- a/offline/packages/trackbase/MvtxEventInfov2.h +++ b/offline/packages/trackbase/MvtxEventInfov2.h @@ -51,7 +51,7 @@ class MvtxEventInfov2 : public MvtxEventInfo unsigned int get_number_L1s() const override; // std::set get_strobe_BCOs() const; - std::set get_strobe_BCOs() const override; + std::set get_strobe_BCOs() const override {return m_strobe_BCOs;} std::set get_L1_BCOs() const override; std::set get_strobe_BCO_from_L1_BCO(const uint64_t ival) const override; From b90410ac40c40ddfe0cc80f9331a5dba8e38c91c Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 11:20:39 -0400 Subject: [PATCH 531/866] cppcheck for PHTrackPruner PHSimpleKFProp --- offline/packages/trackreco/PHSimpleKFProp.cc | 3 ++- offline/packages/trackreco/PHTrackPruner.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/offline/packages/trackreco/PHSimpleKFProp.cc b/offline/packages/trackreco/PHSimpleKFProp.cc index b8f769b45a..bc45b3cfd9 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.cc +++ b/offline/packages/trackreco/PHSimpleKFProp.cc @@ -912,7 +912,8 @@ bool PHSimpleKFProp::PropagateStep( return true; } const std::vector& point = _ptclouds[next_layer]->pts[index_out[0]]; - TrkrDefs::cluskey closest_ckey = (*((int64_t*) &point[3])); + //TrkrDefs::cluskey closest_ckey = (*(int64_t*) &point[3]); + TrkrDefs::cluskey closest_ckey = std::bit_cast(point[3]); TrkrCluster* clusterCandidate = _cluster_map->findCluster(closest_ckey); const auto candidate_globalpos = globalPositions.at(closest_ckey); const double cand_x = candidate_globalpos(0); diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index fe0e0a137e..57eb6df854 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -292,7 +292,7 @@ int PHTrackPruner::GetNodes(PHCompositeNode *topNode) _pruned_svtx_seed_map = findNode::getClass(topNode, _pruned_svtx_seed_map_name); if (!_pruned_svtx_seed_map) { - std::cout << "Creating node " << _pruned_svtx_seed_map_name.c_str() << std::endl; + std::cout << "Creating node " << _pruned_svtx_seed_map_name << std::endl; /// Get the DST Node PHNodeIterator iter(topNode); PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); From 75450e624a62b8ab4d9c63938d3fd95c38c6d4c1 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 11:27:43 -0400 Subject: [PATCH 532/866] cppcheck for PHG4GDMLWrite --- simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc index ebd0a7cd0a..77ef3ed8c2 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc @@ -234,7 +234,7 @@ G4Transform3D PHG4GDMLWrite::Write(const G4String& fname, #if XERCES_VERSION_MAJOR >= 3 // DOM L3 as per Xerces 3.0 API xercesc::DOMLSSerializer* writer = - ((xercesc::DOMImplementationLS*) impl)->createLSSerializer(); + static_cast(impl)->createLSSerializer(); xercesc::DOMConfiguration* dc = writer->getDomConfig(); dc->setParameter(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true); @@ -242,8 +242,7 @@ G4Transform3D PHG4GDMLWrite::Write(const G4String& fname, #else xercesc::DOMWriter* writer = - ((xercesc::DOMImplementationLS*) impl)->createDOMWriter(); - + static_cast(impl)->createDOMWriter(); if (writer->canSetFeature(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true)) writer->setFeature(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true); @@ -273,7 +272,7 @@ G4Transform3D PHG4GDMLWrite::Write(const G4String& fname, #if XERCES_VERSION_MAJOR >= 3 // DOM L3 as per Xerces 3.0 API xercesc::DOMLSOutput* theOutput = - ((xercesc::DOMImplementationLS*) impl)->createLSOutput(); + static_cast(impl)->createLSOutput(); theOutput->setByteStream(myFormTarget); writer->write(doc, theOutput); #else From ccda0f6ebb2aea7e38355a162d7ae24543b5270b Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 11:28:27 -0400 Subject: [PATCH 533/866] cppcheck for PHG4ProcessMap --- simulation/g4simulation/g4main/PHG4ProcessMap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulation/g4simulation/g4main/PHG4ProcessMap.cc b/simulation/g4simulation/g4main/PHG4ProcessMap.cc index d44a4668f7..dcadaaa621 100644 --- a/simulation/g4simulation/g4main/PHG4ProcessMap.cc +++ b/simulation/g4simulation/g4main/PHG4ProcessMap.cc @@ -77,7 +77,7 @@ PHG4ProcessMap::GetMCProcess(const G4VProcess* process) const { std::string text = "Unknown process code for "; text += process->GetProcessName(); - std::cerr << "PHG4ProcessMap::GetCodes " << text.c_str() << std::endl; + std::cerr << "PHG4ProcessMap::GetCodes " << text << std::endl; return kPNoProcess; } From 9fbf5e37b658f86de3704f5423b508d0aef0cef3 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Mon, 18 May 2026 12:57:03 -0400 Subject: [PATCH 534/866] fix rabbit and clang-tidy PHSimpleKFProp --- offline/packages/trackreco/PHSimpleKFProp.cc | 24 ++++++++------------ offline/packages/trackreco/PHSimpleKFProp.h | 7 +++--- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/offline/packages/trackreco/PHSimpleKFProp.cc b/offline/packages/trackreco/PHSimpleKFProp.cc index bc45b3cfd9..f0cc26ecff 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.cc +++ b/offline/packages/trackreco/PHSimpleKFProp.cc @@ -49,6 +49,7 @@ #include +#include #include #include #include @@ -60,7 +61,7 @@ namespace { // square template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } @@ -72,12 +73,6 @@ PHSimpleKFProp::PHSimpleKFProp(const std::string& name) : SubsysReco(name) {} -//______________________________________________________ -int PHSimpleKFProp::End(PHCompositeNode* /*unused*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - //______________________________________________________ int PHSimpleKFProp::InitRun(PHCompositeNode* topNode) { @@ -89,7 +84,7 @@ int PHSimpleKFProp::InitRun(PHCompositeNode* topNode) // load magnetic field from node tree /* note: if field is not found it is created with default configuration, as defined in PHFieldUtility */ - const auto field_map = PHFieldUtility::GetFieldMapNode(nullptr, topNode); + auto *const field_map = PHFieldUtility::GetFieldMapNode(nullptr, topNode); // alice kalman filter fitter = std::make_unique(_cluster_map, field_map, _min_clusters_per_track, _max_sin_phi, Verbosity()); @@ -104,7 +99,7 @@ int PHSimpleKFProp::InitRun(PHCompositeNode* topNode) fitter->setFixedClusterError(2, _fixed_clus_err.at(2)); // properly set constField in ALICEKF, based on PHFieldConfig - const auto field_config = PHFieldUtility::GetFieldConfigNode(nullptr, topNode); + auto *const field_config = PHFieldUtility::GetFieldConfigNode(nullptr, topNode); if( field_config->get_field_config() == PHFieldConfig::kFieldUniform ) { fitter->setConstBField(field_config->get_field_mag_z()); } @@ -154,7 +149,7 @@ int PHSimpleKFProp::get_nodes(PHCompositeNode* topNode) } // tpc grometry - auto geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + auto *geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!geom_container) { std::cerr << PHWHERE << "ERROR: Can't find node TPCGEOMCONTAINER" << std::endl; @@ -230,7 +225,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) } // if not a TPC track, ignore - auto track = _track_map->get(track_it); + auto *track = _track_map->get(track_it); const bool is_tpc = std::any_of( track->begin_cluster_keys(), track->end_cluster_keys(), @@ -335,7 +330,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) if (finalchain.size() > kl.at(0).size()) { - local_chains.push_back(std::move(finalchain)); + local_chains.push_back(finalchain); } else { @@ -899,7 +894,7 @@ bool PHSimpleKFProp::PropagateStep( double query_pt[3] = {new_tx, new_ty, new_tz}; std::vector index_out(1); std::vector distance_out(1); - int n_results = _kdtrees[next_layer]->knnSearch(&query_pt[0], 1, &index_out[0], &distance_out[0]); + int n_results = _kdtrees[next_layer]->knnSearch(&query_pt[0], 1, index_out.data(), distance_out.data()); // if no results, then no cluster to add, but propagation is not necessarily done if (!n_results) @@ -912,10 +907,9 @@ bool PHSimpleKFProp::PropagateStep( return true; } const std::vector& point = _ptclouds[next_layer]->pts[index_out[0]]; - //TrkrDefs::cluskey closest_ckey = (*(int64_t*) &point[3]); TrkrDefs::cluskey closest_ckey = std::bit_cast(point[3]); TrkrCluster* clusterCandidate = _cluster_map->findCluster(closest_ckey); - const auto candidate_globalpos = globalPositions.at(closest_ckey); + const auto &candidate_globalpos = globalPositions.at(closest_ckey); const double cand_x = candidate_globalpos(0); const double cand_y = candidate_globalpos(1); const double cand_z = candidate_globalpos(2); diff --git a/offline/packages/trackreco/PHSimpleKFProp.h b/offline/packages/trackreco/PHSimpleKFProp.h index 9a09d65f06..7c4f2726c5 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.h +++ b/offline/packages/trackreco/PHSimpleKFProp.h @@ -47,7 +47,6 @@ class PHSimpleKFProp : public SubsysReco int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode* topNode) override; - int End(PHCompositeNode* topNode) override; // noop void set_field_dir(const double) @@ -141,8 +140,8 @@ class PHSimpleKFProp : public SubsysReco PositionMap PrepareKDTrees(); bool TransportAndRotate( - double old_layer, - double new_layer, + double old_radius, + double new_radius, double& phi, GPUTPCTrackParam& kftrack, GPUTPCTrackParam::GPUTPCTrackFitParam& fp) const; @@ -161,7 +160,7 @@ class PHSimpleKFProp : public SubsysReco // which means we have to have a way to directly pass a list of clusters in order to extend looping tracks std::vector PropagateTrack(TrackSeed* track, PropagationDirection direction, GPUTPCTrackParam& aliceSeed, const PositionMap& globalPositions) const; std::vector PropagateTrack(TrackSeed* track, std::vector& ckeys, PropagationDirection direction, GPUTPCTrackParam& aliceSeed, const PositionMap& globalPositions) const; - std::vector> RemoveBadClusters(const std::vector>& seeds, const PositionMap& globalPositions) const; + std::vector> RemoveBadClusters(const std::vector>& chains, const PositionMap& globalPositions) const; template struct KDPointCloud From f919460f19f1c0d100eb3fae03e3eadc88e7d07c Mon Sep 17 00:00:00 2001 From: bkimelman Date: Mon, 18 May 2026 16:21:46 -0400 Subject: [PATCH 535/866] New setters for lamination fitting code --- .../packages/tpccalib/TpcLaminationFitting.cc | 25 ++++++++++++++----- .../packages/tpccalib/TpcLaminationFitting.h | 11 ++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 9e1eda849d..3570e8ac51 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -57,6 +57,13 @@ void TpcLaminationFitting::set_grid_dimensions(int phibins, int rbins) m_rbins = rbins; } +//___________________________________________________________ +void TpcLaminationFitting::set_lam_grid_dimensions(int phibins, int rbins) +{ + m_lamPhiBins = phibins; + m_lamRBins = rbins; +} + //____________________________________________ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) { @@ -91,7 +98,7 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) if(m_fieldOff) { - m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{ideal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %m_laminationIdeal[l][s]).str().c_str(), 200, 30, 80, 200, m_laminationIdeal[l][s] - 0.2, m_laminationIdeal[l][s] + 0.2); + m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{ideal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %m_laminationIdeal[l][s]).str().c_str(), m_lamRBins, 30, 80, m_lamPhiBins, m_laminationIdeal[l][s] - 0.2, m_laminationIdeal[l][s] + 0.2); m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[0]+[1]", 30, 80); m_fLamination[l][s]->SetParameters(m_laminationOffset[l][s], m_laminationIdeal[l][s]); m_fLamination[l][s]->SetParLimits(0, -0.05, 0.05); @@ -99,7 +106,7 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) } else { - m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{nominal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %(m_laminationIdeal[l][s]+m_laminationOffset[l][s])).str().c_str(), 200, 30, 80, 200, m_laminationIdeal[l][s]+m_laminationOffset[l][s] - 0.2, m_laminationIdeal[l][s]+m_laminationOffset[l][s] + 0.2); + m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{nominal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %(m_laminationIdeal[l][s]+m_laminationOffset[l][s])).str().c_str(), m_lamRBins, 30, 80, m_lamPhiBins, m_laminationIdeal[l][s]+m_laminationOffset[l][s] - 0.2, m_laminationIdeal[l][s]+m_laminationOffset[l][s] + 0.2); m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[3]+[0]*(1-exp(-[2]*(x-[1])))", 30, 80); m_fLamination[l][s]->SetParameters(-0.08, 38, 0.16, 0.0); m_fLamination[l][s]->SetParLimits(0, -0.02, 0.0); @@ -394,6 +401,12 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) continue; } + double weight = 1.0; + if(m_adcWeight) + { + weight = 1.0*cmclus->getAdc(); + } + //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); @@ -408,7 +421,7 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) TVector3 tmp_pos(pos[0], pos[1], pos[2]); - if(cmclus->getNLayers() > m_nLayerCut && cmclus->getSDWeightedLayer() > 0.5) + if(cmclus->getNLayers() > m_nLayerCut && (!m_useSDLayerCut || cmclus->getSDWeightedLayer() > 0.5)) { for (int l = 0; l < 18; l++) { @@ -426,12 +439,12 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) { - m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi); + m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi, weight); } } } - if(cmclus->getSDWeightedLayer() > 0.5) + if(m_useSDLayerCut && cmclus->getSDWeightedLayer() > 0.5) { continue; } @@ -450,7 +463,7 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) phi2pimod -= M_PI / 9; } - m_hPetal[side]->Fill(phi2pimod, tmp_pos.Perp()); + m_hPetal[side]->Fill(phi2pimod, tmp_pos.Perp(), weight); } return Fun4AllReturnCodes::EVENT_OK; diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 5285dff0d2..c2cb550791 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -60,6 +60,12 @@ class TpcLaminationFitting : public SubsysReco void set_nLayerCut(unsigned int cut) { m_nLayerCut = cut; } + void set_useSDLayerCut(bool useCut) { m_useSDLayerCut = useCut; } + + void set_adcWeight(bool useADC) { m_adcWeight = useADC; } + + void set_lam_grid_dimensions(int phibins, int rbins); + int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -110,6 +116,8 @@ class TpcLaminationFitting : public SubsysReco //TH2 *scaleFactorMap[2]{nullptr}; unsigned int m_nLayerCut{1}; + bool m_useSDLayerCut{true}; + bool m_adcWeight{false}; bool m_useHeader{true}; @@ -148,6 +156,9 @@ class TpcLaminationFitting : public SubsysReco double m_rmse{}; int m_nBins{0}; + int m_lamPhiBins{200}; + int m_lamRBins{200}; + int m_phibins{80}; static constexpr float m_phiMin{0}; static constexpr float m_phiMax{2. * M_PI}; From ca045d501f0648671f39e68b316838fa7c04347c Mon Sep 17 00:00:00 2001 From: Dillon Fitzgerald Date: Tue, 19 May 2026 16:34:44 -0400 Subject: [PATCH 536/866] fix cppcheck and clangtidy errors --- .../packages/bcolumicount/StreamingBcoInfov1.h | 6 +++--- .../bcolumicount/StreamingBcoLumiReco.cc | 18 ++++++++++-------- .../bcolumicount/StreamingBcoLumiReco.h | 12 ++++++------ .../bcolumicount/StreamingLumiInfov1.h | 6 +++--- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1.h b/offline/packages/bcolumicount/StreamingBcoInfov1.h index 164bebf70e..ebbcadd123 100644 --- a/offline/packages/bcolumicount/StreamingBcoInfov1.h +++ b/offline/packages/bcolumicount/StreamingBcoInfov1.h @@ -44,9 +44,9 @@ class StreamingBcoInfov1 : public StreamingBcoInfo private: - uint64_t m_bco; - int m_evtno; - bool m_usable_bco_tag; + uint64_t m_bco{0}; + int m_evtno{0}; + bool m_usable_bco_tag{false}; std::pair m_bco_streaming_window; ClassDefOverride(StreamingBcoInfov1, 1) diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc index 5222ce8ce1..29b6ae794b 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.cc +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.cc @@ -43,12 +43,14 @@ int StreamingBcoLumiReco::Init(PHCompositeNode *topNode) { int iret = CreateNodeTree(topNode); h_bco_diff = new TH1I("h_bco_diff", ";bco diff;", 3500, 0, 3500); + std::string hist_name = "h_bco_diff_bit"; for (int bit=0; bitregisterHisto(h_bco_diff_trigbits[bit]); } - h_bco_tag = new TH1I("h_bco_tag", "run 81100;usable bco tag;", 2, -0.5, 1.5); + h_bco_tag = new TH1I("h_bco_tag", ";usable bco tag;", 2, -0.5, 1.5); hm->registerHisto(h_bco_diff); hm->registerHisto(h_bco_tag); @@ -196,7 +198,7 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) h_bco_tag->Fill(m_usable_bco_tag); for (int bit=0; bit> bit) & 0x1U) == 0x1U; + bool trigger_fired = ((gl1_scaledvec >> static_cast(bit)) & 0x1U) == 0x1U; //bool scaled_trigger_fired = ((gl1_scaledvec >> bit) & 0x1U) == 0x1U; if (trigger_fired) @@ -222,14 +224,14 @@ int StreamingBcoLumiReco::process_event(PHCompositeNode *topNode) if (adjusted_bunch>110) { continue; } // Make sure this is the correct way to count crossings! Need to zero out for each run! - if(i!=0) - { - m_bunchnumber_crossings[adjusted_bunch] += 1; - } - else if (m_usable_bco_tag) + if(i!=0 || m_usable_bco_tag) { m_bunchnumber_crossings[adjusted_bunch] += 1; } + //else if (m_usable_bco_tag) + //{ + // m_bunchnumber_crossings[adjusted_bunch] += 1; + //} } streaming_bco_info->set_bco(get_bco()); diff --git a/offline/packages/bcolumicount/StreamingBcoLumiReco.h b/offline/packages/bcolumicount/StreamingBcoLumiReco.h index 76f621a2da..51b6f349ef 100644 --- a/offline/packages/bcolumicount/StreamingBcoLumiReco.h +++ b/offline/packages/bcolumicount/StreamingBcoLumiReco.h @@ -44,12 +44,12 @@ class StreamingBcoLumiReco : public SubsysReco const int trigbits = 40; Fun4AllHistoManager *hm = nullptr; TH1I *h_bco_diff = nullptr; - TH1I *h_bco_diff_trigbits[40]; + TH1I *h_bco_diff_trigbits[40] = {nullptr}; TH1I *h_bco_tag = nullptr; - uint64_t m_bco; + uint64_t m_bco{0}; int m_bunches = 120; - int m_evtno; + int m_evtno{0}; bool m_usable_bco_tag = false; std::pair m_bco_streaming_window; @@ -63,9 +63,9 @@ class StreamingBcoLumiReco : public SubsysReco std::array m_bunchnumber_crossings{0}; - std::array m_bunchnumber_lumi_raw{0}; - std::array m_bunchnumber_lumi_live{0}; - std::array m_bunchnumber_lumi_scaled{0}; + std::array m_bunchnumber_lumi_raw{0.}; + std::array m_bunchnumber_lumi_live{0.}; + std::array m_bunchnumber_lumi_scaled{0.}; double m_lumi_raw{0.}; double m_lumi_live{0.}; diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.h b/offline/packages/bcolumicount/StreamingLumiInfov1.h index e5478c531c..b25f1af295 100644 --- a/offline/packages/bcolumicount/StreamingLumiInfov1.h +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.h @@ -41,9 +41,9 @@ class StreamingLumiInfov1 : public StreamingLumiInfo private: - double m_lumi_raw; - double m_lumi_live; - double m_lumi_scaled; + double m_lumi_raw{0.}; + double m_lumi_live{0.}; + double m_lumi_scaled{0.}; From 171fbeb3ee3ea6c66b1216c1d7cc3b7b0fdd8526 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Thu, 21 May 2026 14:24:21 -0400 Subject: [PATCH 537/866] added MbdCalib::Write_SlewCorr and MbdCalib::Save_CDB_URL --- offline/packages/mbd/MbdCalib.cc | 134 +++++++++++++++++++++---------- offline/packages/mbd/MbdCalib.h | 8 ++ offline/packages/mbd/MbdEvent.h | 2 +- 3 files changed, 99 insertions(+), 45 deletions(-) diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 82d87b7671..30fab1812a 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -7,6 +7,7 @@ #ifndef ONLINE #include #include +#include #endif #include @@ -80,112 +81,112 @@ int MbdCalib::Download_All() if (!_rc->FlagExist("MBD_CALDIR")) { // Always load Status - std::string status_url = _cdb->getUrl("MBD_STATUS"); - if ( ! status_url.empty() ) + _cdb_urls["MBD_STATUS"] = _cdb->getUrl("MBD_STATUS"); + if ( !_cdb_urls["MBD_STATUS"].empty() ) { // if this doesn't exist, the status is assumed to be all good - Download_Status(status_url); + Download_Status(_cdb_urls["MBD_STATUS"]); } if (Verbosity() > 0) { - std::cout << "status_url " << status_url << std::endl; + std::cout << "MBD_STATUS url " << _cdb_urls["MBD_STATUS"] << std::endl; } - if ( !_rawdstflag ) + // note: sampmax and ped will be calculated on the fly if calibs don't exist + _cdb_urls["MBD_SAMPMAX"] = _cdb->getUrl("MBD_SAMPMAX"); + if (Verbosity() > 0) { - // sampmax and ped will be calculated on the fly if calibs don't exist - std::string sampmax_url = _cdb->getUrl("MBD_SAMPMAX"); - if (Verbosity() > 0) - { - std::cout << "sampmax_url " << sampmax_url << std::endl; - } - Download_SampMax(sampmax_url); + std::cout << "MBD_SAMPMAX url " << _cdb_urls["MBD_SAMPMAX"] << std::endl; + } + Download_SampMax(_cdb_urls["MBD_SAMPMAX"]); - std::string ped_url = _cdb->getUrl("MBD_PED"); + if ( !_rawdstflag ) + { + _cdb_urls["MBD_PED"] = _cdb->getUrl("MBD_PED"); if (Verbosity() > 0) { - std::cout << "ped_url " << ped_url << std::endl; + std::cout << "MBD_PED url " << _cdb_urls["MBD_PED"] << std::endl; } - Download_Ped(ped_url); + Download_Ped(_cdb_urls["MBD_PED"]); - std::string pileup_url = _cdb->getUrl("MBD_PILEUP"); - if ( pileup_url.empty() ) + _cdb_urls["MBD_PILEUP"] = _cdb->getUrl("MBD_PILEUP"); + if ( _cdb_urls["MBD_PILEUP"].empty() ) { std::cerr << "ERROR, MBD_PILEUP missing" << std::endl; return -1; } if (Verbosity() > 0) { - std::cout << "pileup_url " << pileup_url << std::endl; + std::cout << "MBD_PILEUP url " << _cdb_urls["MBD_PILEUP"] << std::endl; } - Download_Pileup(pileup_url); + Download_Pileup(_cdb_urls["MBD_PILEUP"]); if (do_templatefit) { - std::string shape_url = _cdb->getUrl("MBD_SHAPES"); - if ( shape_url.empty() ) + _cdb_urls["MBD_SHAPES"] = _cdb->getUrl("MBD_SHAPES"); + if ( _cdb_urls["MBD_SHAPES"].empty() ) { std::cerr << "ERROR, MBD_SHAPES missing" << std::endl; return -1; } if (Verbosity() > 0) { - std::cout << "shape_url " << shape_url << std::endl; + std::cout << "MBD_SHAPES url " << _cdb_urls["MBD_SHAPES"] << std::endl; } - Download_Shapes(shape_url); + Download_Shapes(_cdb_urls["MBD_SHAPES"]); } } if ( !_fitsonly ) { - std::string qfit_url = _cdb->getUrl("MBD_QFIT"); + _cdb_urls["MBD_QFIT"] = _cdb->getUrl("MBD_QFIT"); if (Verbosity() > 0) { - std::cout << "qfit_url " << qfit_url << std::endl; + std::cout << "MBD_QFIT url " << _cdb_urls["MBD_QFIT"] << std::endl; } - Download_Gains(qfit_url); + Download_Gains(_cdb_urls["MBD_QFIT"]); - std::string tt_t0_url = _cdb->getUrl("MBD_TT_T0"); + _cdb_urls["MBD_TT_T0"] = _cdb->getUrl("MBD_TT_T0"); if ( Verbosity() > 0 ) { - std::cout << "tt_t0_url " << tt_t0_url << std::endl; + std::cout << "MBD_TT_T0 url " << _cdb_urls["MBD_TT_T0"] << std::endl; } - Download_TTT0(tt_t0_url); + Download_TTT0(_cdb_urls["MBD_TT_T0"]); - std::string tq_t0_url = _cdb->getUrl("MBD_TQ_T0"); + _cdb_urls["MBD_TQ_T0"] = _cdb->getUrl("MBD_TQ_T0"); if (Verbosity() > 0) { - std::cout << "tq_t0_url " << tq_t0_url << std::endl; + std::cout << "MBD_TQ_T0 url " << _cdb_urls["MBD_TQ_T0"] << std::endl; } - Download_TQT0(tq_t0_url); + Download_TQT0(_cdb_urls["MBD_TQ_T0"]); - std::string t0corr_url = _cdb->getUrl("MBD_T0CORR"); + _cdb_urls["MBD_T0CORR"] = _cdb->getUrl("MBD_T0CORR"); if ( Verbosity() > 0 ) { - std::cout << "t0corr_url " << t0corr_url << std::endl; + std::cout << "MBD_T0CORR url " << _cdb_urls["MBD_T0CORR"] << std::endl; } - Download_T0Corr(t0corr_url); + Download_T0Corr(_cdb_urls["MBD_T0CORR"]); - std::string timecorr_url = _cdb->getUrl("MBD_TIMECORR"); + _cdb_urls["MBD_TIMECORR"] = _cdb->getUrl("MBD_TIMECORR"); if ( Verbosity() > 0 ) { - std::cout << "timecorr_url " << timecorr_url << std::endl; + std::cout << "MBD_TIMECORR url " << _cdb_urls["MBD_TIMECORR"] << std::endl; } - Download_TimeCorr(timecorr_url); + Download_TimeCorr(_cdb_urls["MBD_TIMECORR"]); - std::string slew_url = _cdb->getUrl("MBD_SLEWCORR"); + _cdb_urls["MBD_SLEWCORR"] = _cdb->getUrl("MBD_SLEWCORR"); if ( Verbosity() > 0 ) { - std::cout << "slew_url " << slew_url << std::endl; + std::cout << "MBD_SLEWCORR url " << _cdb_urls["MBD_SLEWCORR"] << std::endl; } - Download_SlewCorr(slew_url); + Download_SlewCorr(_cdb_urls["MBD_SLEWCORR"]); - std::string trms_url = _cdb->getUrl("MBD_TIMERMS"); + _cdb_urls["MBD_TIMERMS"] = _cdb->getUrl("MBD_TIMERMS"); if ( Verbosity() > 0 ) { - std::cout << "trms_url " << trms_url << std::endl; + std::cout << "MBD_TIMERMS url " << _cdb_urls["MBD_TIMERMS"] << std::endl; } - Download_TimeRMS(trms_url); + Download_TimeRMS(_cdb_urls["MBD_TIMERMS"]); } Verbosity(0); @@ -2162,6 +2163,40 @@ int MbdCalib::Write_CDB_SlewCorr(const std::string& dbfile) } #endif +int MbdCalib::Write_SlewCorr(const std::string& dbfile) +{ + std::ofstream cal_slewcorr_file; + cal_slewcorr_file.open(dbfile); + if (!cal_slewcorr_file.is_open()) + { + std::cout << PHWHERE << "unable to open " << dbfile << std::endl; + return -1; + } + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + if ( _mbdgeom->get_type(ifeech) == 1 ) + { + continue; // skip q-channels + } + cal_slewcorr_file << ifeech << "\t" << _scorr_npts[ifeech] << "\t" << _scorr_minrange[ifeech] << "\t" << _scorr_maxrange[ifeech] << std::endl; + for (int ipt=0; ipt<_scorr_npts[ifeech]; ipt++) + { + cal_slewcorr_file << _scorr_y[ifeech][ipt]; + if ( ipt%10 == 9 ) + { + cal_slewcorr_file << std::endl; + } + else + { + cal_slewcorr_file << " "; + } + } + } + cal_slewcorr_file.close(); + + return 1; +} + #ifndef ONLINE int MbdCalib::Write_CDB_TimeRMS(const std::string& dbfile) { @@ -2513,6 +2548,17 @@ void MbdCalib::Reset_Thresholds() _thresh_chi2ndf.fill(std::numeric_limits::quiet_NaN()); } +#ifndef ONLINE +void MbdCalib::Save_CDB_URL() +{ + for (const auto &kv : _cdb_urls) + { + auto named = std::make_unique(kv.first.c_str(), kv.second.c_str()); + named->Write(); + } +} +#endif + void MbdCalib::Reset() { Reset_TTT0(); diff --git a/offline/packages/mbd/MbdCalib.h b/offline/packages/mbd/MbdCalib.h index 65b5a52fee..3d55e42bc9 100644 --- a/offline/packages/mbd/MbdCalib.h +++ b/offline/packages/mbd/MbdCalib.h @@ -12,12 +12,14 @@ #include #include +#include #include #include #include class TTree; class TGraph; +class TNamed; class CDBInterface; class MbdCalib @@ -168,6 +170,7 @@ class MbdCalib int Write_T0Corr(const std::string& dbfile); int Write_Ped(const std::string& dbfile); int Write_TimeCorr(const std::string& dbfile); + int Write_SlewCorr(const std::string& dbfile); int Write_Gains(const std::string& dbfile); int Write_Pileup(const std::string& dbfile); int Write_Thresholds(const std::string& dbfile); @@ -185,6 +188,10 @@ class MbdCalib // void Dump_to_file(const std::string& what = "ALL"); +#ifndef ONLINE + void Save_CDB_URL(); +#endif + void SetRawDstFlag(const int r) { _rawdstflag = r; } void SetFitsOnly(const int f) { _fitsonly = f; } @@ -198,6 +205,7 @@ class MbdCalib #ifndef ONLINE CDBInterface* _cdb{nullptr}; recoConsts* _rc{nullptr}; + std::map _cdb_urls; #endif std::unique_ptr _mbdgeom{nullptr}; diff --git a/offline/packages/mbd/MbdEvent.h b/offline/packages/mbd/MbdEvent.h index 5abd48aeae..31d22303f6 100644 --- a/offline/packages/mbd/MbdEvent.h +++ b/offline/packages/mbd/MbdEvent.h @@ -124,7 +124,7 @@ class MbdEvent int _verbose{0}; int _runnum{0}; int _simflag{0}; - int _rawdstflag{0}; // dst with raw container + int _rawdstflag{0}; // reading from dst with raw container int _fitsonly{0}; // stop reco after waveform fits (for DST_CALOFIT pass) int _nsamples{31}; int _calib_done{0}; From 8493ad154c9d67893f55dafd0567ed310ec3c121 Mon Sep 17 00:00:00 2001 From: Mariia Mitrankova Date: Tue, 26 May 2026 11:40:38 -0400 Subject: [PATCH 538/866] Select only diffuse laser events --- .../packages/tpc/DiffuseLaserEventSelector.cc | 86 +++++++++++++++++++ .../packages/tpc/DiffuseLaserEventSelector.h | 29 +++++++ offline/packages/tpc/Makefile.am | 2 + 3 files changed, 117 insertions(+) create mode 100644 offline/packages/tpc/DiffuseLaserEventSelector.cc create mode 100644 offline/packages/tpc/DiffuseLaserEventSelector.h diff --git a/offline/packages/tpc/DiffuseLaserEventSelector.cc b/offline/packages/tpc/DiffuseLaserEventSelector.cc new file mode 100644 index 0000000000..8a412ba7f2 --- /dev/null +++ b/offline/packages/tpc/DiffuseLaserEventSelector.cc @@ -0,0 +1,86 @@ +#include "DiffuseLaserEventSelector.h" + +#include + +#include + +#include + +#include +#include +#include + +#include + +DiffuseLaserEventSelector::DiffuseLaserEventSelector(const std::string& name) + : SubsysReco(name) +{ +} + +int DiffuseLaserEventSelector::process_event(PHCompositeNode* topNode) +{ + LaserEventInfo* laserEventInfo = + findNode::getClass(topNode, "LaserEventInfo"); + + if (!laserEventInfo) + { + std::cout << PHWHERE + << " LaserEventInfo node is missing. Rejecting event." + << std::endl; + + return Fun4AllReturnCodes::DISCARDEVENT; + } + + EventHeader *eventHeader = findNode::getClass(topNode, "EventHeader"); + if (!eventHeader) + { + std::cout << PHWHERE << " EventHeader Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + bool accept = true; + + /* + if (m_requireTPCDiffuseLaser) + { + accept = accept && laserEventInfo->isLaserEvent(); + } + + if (m_requireGL1Laser) + { + accept = accept && laserEventInfo->isGl1LaserEvent(); + } + + if (m_rejectGL1Pileup) + { + accept = accept && !laserEventInfo->isGl1LaserPileupEvent(); + } + */ + + if((eventHeader->get_RunNumber() > 66153 && laserEventInfo->isGl1LaserEvent()) || (eventHeader->get_RunNumber() <= 66153 && laserEventInfo->isLaserEvent())) + { + accept = true; + } + else + { + accept = false; + } + + /*if (Verbosity() > 1) + { + std::cout << "DiffuseLaserEventSelector:" + << " isLaserEvent = " << laserEventInfo->isLaserEvent() + << " isGl1LaserEvent = " << laserEventInfo->isGl1LaserEvent() + << " isGl1LaserPileupEvent = " + << laserEventInfo->isGl1LaserPileupEvent() + << " accept = " << accept + << std::endl; + }*/ + + if (!accept) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} \ No newline at end of file diff --git a/offline/packages/tpc/DiffuseLaserEventSelector.h b/offline/packages/tpc/DiffuseLaserEventSelector.h new file mode 100644 index 0000000000..6b92a7f86c --- /dev/null +++ b/offline/packages/tpc/DiffuseLaserEventSelector.h @@ -0,0 +1,29 @@ +#ifndef DiffuseLaserEventSelector_H +#define DiffuseLaserEventSelector_H + +#include + +#include + +class PHCompositeNode; + +class DiffuseLaserEventSelector : public SubsysReco +{ + public: + DiffuseLaserEventSelector(const std::string& name = "DiffuseLaserEventSelector"); + + ~DiffuseLaserEventSelector() override = default; + + int process_event(PHCompositeNode* topNode) override; + + void RequireTPCDiffuseLaser(bool b) { m_requireTPCDiffuseLaser = b; } + void RequireGL1Laser(bool b) { m_requireGL1Laser = b; } + void RejectGL1Pileup(bool b) { m_rejectGL1Pileup = b; } + + private: + bool m_requireTPCDiffuseLaser = true; + bool m_requireGL1Laser = false; + bool m_rejectGL1Pileup = true; +}; + +#endif \ No newline at end of file diff --git a/offline/packages/tpc/Makefile.am b/offline/packages/tpc/Makefile.am index 637fa61489..55c956b98b 100644 --- a/offline/packages/tpc/Makefile.am +++ b/offline/packages/tpc/Makefile.am @@ -41,6 +41,7 @@ pkginclude_HEADERS = \ LaserEventInfov2.h \ LaserEventIdentifier.h \ LaserEventRejecter.h \ + DiffuseLaserEventSelector.h \ TrainingHitsContainer.h \ TrainingHits.h \ Tpc3DClusterizer.h \ @@ -79,6 +80,7 @@ libtpc_la_SOURCES = \ LaserEventInfov1.cc \ LaserEventInfov2.cc \ LaserEventIdentifier.cc \ + DiffuseLaserEventSelector.cc \ LaserEventRejecter.cc \ TpcRawDataTree.cc \ Tpc3DClusterizer.cc \ From 6bdcd9b506bd8425990621c386c8111fabcb1e6b Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 26 May 2026 11:50:00 -0400 Subject: [PATCH 539/866] fix clang-tidy, remove redundant booleans --- offline/packages/centrality/CentralityReco.h | 13 +-- .../packages/trigger/MinimumBiasClassifier.cc | 93 ++++++++++++------- .../packages/trigger/MinimumBiasClassifier.h | 61 ++++++------ offline/packages/trigger/TriggerPrimitivev1.h | 1 - 4 files changed, 91 insertions(+), 77 deletions(-) diff --git a/offline/packages/centrality/CentralityReco.h b/offline/packages/centrality/CentralityReco.h index 37f97082ef..bd63287255 100644 --- a/offline/packages/centrality/CentralityReco.h +++ b/offline/packages/centrality/CentralityReco.h @@ -93,20 +93,14 @@ class CentralityReco : public SubsysReco std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; - bool m_use_vtx_function{true}; - bool m_overwrite_divs{false}; - bool m_overwrite_scale{false}; - bool m_overwrite_vtx{false}; - - std::string m_overwrite_url_divs{""}; - std::string m_overwrite_url_scale{""}; - std::string m_overwrite_url_vtx{""}; + std::string m_overwrite_url_divs; + std::string m_overwrite_url_scale; + std::string m_overwrite_url_vtx; const int NDIVS{100}; const float mbd_charge_cut{0.5}; const float mbd_time_cut{25}; - GlobalVertexMap *m_global_vertex_map{nullptr}; MbdOut *m_mbd_out{nullptr}; MbdPmtContainer *m_mbd_container{nullptr}; MbdPmtHit *m_mbd_hit{nullptr}; @@ -118,6 +112,7 @@ class CentralityReco : public SubsysReco float m_mbd_total_charge{0.}; // init to zero for use in first event double m_centrality_scale{std::numeric_limits::quiet_NaN()}; + std::vector, float>> m_vertex_scales{}; std::array m_centrality_map{}; diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index f702fe9754..ebce5800ca 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -5,13 +5,15 @@ #include #include -#include #include #include + #include #include +#include + #include #include @@ -25,7 +27,6 @@ #include #include #include -#include // for _Rb_tree_iterator #include #include // for pair @@ -33,6 +34,7 @@ MinimumBiasClassifier::MinimumBiasClassifier(const std::string &name) : SubsysReco(name) { } + int MinimumBiasClassifier::InitRun(PHCompositeNode *topNode) { if (Verbosity() > 1) @@ -41,47 +43,55 @@ int MinimumBiasClassifier::InitRun(PHCompositeNode *topNode) } if (m_species == MinimumBiasInfo::SPECIES::AUAU) - { - m_useZDC = true; - m_max_charge_cut = 2100; - m_box_cut = true; - m_hit_cut = 2; - } + { + m_useZDC = true; + m_max_charge_cut = 2100; + m_box_cut = true; + m_hit_cut = 2; + } if (m_species == MinimumBiasInfo::SPECIES::OO) - { - m_useZDC = false; - m_max_charge_cut = 300; - m_box_cut = false; - m_hit_cut = 1; - } + { + m_useZDC = false; + m_max_charge_cut = 300; + m_box_cut = false; + m_hit_cut = 1; + } if (m_species == MinimumBiasInfo::SPECIES::PP) - { - m_useZDC = false; - m_max_charge_cut = 300; - m_box_cut = false; - m_hit_cut = 1; - } + { + m_useZDC = false; + m_max_charge_cut = 300; + m_box_cut = false; + m_hit_cut = 1; + } CDBInterface *m_cdb = CDBInterface::instance(); - std::string centscale_url = m_cdb->getUrl("CentralityScale"); - if (m_overwrite_scale) + std::string centscale_url; + if (!m_overwrite_url_scale.empty()) { centscale_url = m_overwrite_url_scale; std::cout << " Overwriting Scale to " << m_overwrite_url_scale << std::endl; } + else + { + centscale_url = m_cdb->getUrl("CentralityScale"); + } if (Download_centralityScale(centscale_url)) { return Fun4AllReturnCodes::ABORTRUN; } - std::string vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); - if (m_overwrite_vtx) + std::string vertexscale_url; + if (!m_overwrite_url_vtx.empty()) { vertexscale_url = m_overwrite_url_vtx; std::cout << " Overwriting Vtx to " << m_overwrite_url_vtx << std::endl; } + else + { + vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); + } if (Download_centralityVertexScales(vertexscale_url)) { @@ -125,11 +135,13 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() // return Fun4AllReturnCodes::EVENT_OK; // } - if (m_global_vertex_map->empty()) { m_mb_info->setIsAuAuMinimumBias(false); - if (m_abortEvents) return 1; + if (m_abortEvents) + { + return 1; + } return 0; } @@ -137,19 +149,25 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() if (!vtx) { m_mb_info->setIsAuAuMinimumBias(false); - if (m_abortEvents) return 1; + if (m_abortEvents) + { + return 1; + } return 0; } if (!vtx->isValid()) { m_mb_info->setIsAuAuMinimumBias(false); - if (m_abortEvents) return 1; + if (m_abortEvents) + { + return 1; + } return 0; } bool minbiascheck = true; - + m_vertex = vtx->get_z(); m_vertex_scale = getVertexScale(); @@ -163,7 +181,10 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() if (!m_zdcinfo) { m_mb_info->setIsAuAuMinimumBias(false); - if (m_abortEvents) return 1; + if (m_abortEvents) + { + return 1; + } return 0; } } @@ -231,9 +252,9 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() m_mb_info->setIsAuAuMinimumBias(minbiascheck); if (!minbiascheck && m_abortEvents) - { - return 1; - } + { + return 1; + } return 0; } @@ -253,9 +274,9 @@ int MinimumBiasClassifier::process_event(PHCompositeNode *topNode) if (FillMinimumBiasInfo()) { if (Verbosity()) - { - std::cout << "MinimumBiasClassifier::process_event Aborting Event - not minbias" << std::endl; - } + { + std::cout << "MinimumBiasClassifier::process_event Aborting Event - not minbias" << std::endl; + } return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/trigger/MinimumBiasClassifier.h b/offline/packages/trigger/MinimumBiasClassifier.h index ea235fbc1e..d373c2374a 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.h +++ b/offline/packages/trigger/MinimumBiasClassifier.h @@ -1,17 +1,18 @@ #ifndef TRIGGER_MINBIASCLASSIFIER_H #define TRIGGER_MINBIASCLASSIFIER_H +#include "MinimumBiasInfo.h" + #include + #include #include #include // for allocator, string #include #include -#include "MinimumBiasInfo.h" // Forward declarations -class MinimumBiasInfo; class PHCompositeNode; class Zdcinfo; class MbdPmtContainer; @@ -23,7 +24,6 @@ class MinimumBiasClassifier : public SubsysReco public: //! constructor - explicit MinimumBiasClassifier(const std::string &name = "MinimumBiasClassifier"); //! destructor @@ -50,12 +50,10 @@ class MinimumBiasClassifier : public SubsysReco void setOverwriteScale(const std::string &url) { m_overwrite_url_scale = url; - m_overwrite_scale = true; } void setOverwriteVtx(const std::string &url) { m_overwrite_url_vtx = url; - m_overwrite_vtx = true; } void setIsSim(const bool sim) { m_issim = sim; } @@ -79,51 +77,52 @@ class MinimumBiasClassifier : public SubsysReco { m_global_vertex_nodename = name; } - + private: + float getVertexScale(); + + MinimumBiasInfo *m_mb_info{nullptr}; + MbdPmtContainer *m_mbd_container{nullptr}; + MbdPmtHit *m_mbd_pmt{nullptr}; + GlobalVertexMap *m_global_vertex_map{nullptr}; + Zdcinfo *m_zdcinfo{nullptr}; + bool m_abortEvents{false}; bool m_issim{false}; bool m_useZDC{true}; bool m_box_cut{true}; + int m_hit_cut{2}; + double m_max_charge_cut{2100}; - - MinimumBiasInfo::SPECIES m_species{MinimumBiasInfo::SPECIES::AUAU}; + double m_centrality_scale{std::numeric_limits::quiet_NaN()}; + double m_vertex_scale{std::numeric_limits::quiet_NaN()}; - float getVertexScale(); - std::string m_dbfilename; + float m_vertex{std::numeric_limits::quiet_NaN()}; + + static constexpr float m_z_vtx_cut{60.}; + static constexpr float m_mbd_north_cut{10.}; + static constexpr float m_mbd_south_cut{150}; + static constexpr float m_mbd_charge_cut{0.5}; + static constexpr float m_mbd_time_cut{25.}; + // const int m_mbd_tube_cut{2}; + static constexpr float m_zdc_cut{60.}; + + MinimumBiasInfo::SPECIES m_species{MinimumBiasInfo::SPECIES::AUAU}; std::string m_mb_info_nodename{"MinimumBiasInfo"}; std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; std::string m_zdc_info_nodename{"Zdcinfo"}; std::string m_global_vertex_nodename{"GlobalVertexMap"}; - - bool m_overwrite_scale{false}; - bool m_overwrite_vtx{false}; - std::string m_overwrite_url_scale{""}; - std::string m_overwrite_url_vtx{""}; - - const float m_z_vtx_cut{60.}; - const float m_mbd_north_cut{10.}; - const float m_mbd_south_cut{150}; - const float m_mbd_charge_cut{0.5}; - const float m_mbd_time_cut{25.}; - // const int m_mbd_tube_cut{2}; - const float m_zdc_cut{60.}; - MinimumBiasInfo *m_mb_info{nullptr}; - MbdPmtContainer *m_mbd_container{nullptr}; - MbdPmtHit *m_mbd_pmt{nullptr}; - GlobalVertexMap *m_global_vertex_map{nullptr}; - Zdcinfo *m_zdcinfo{nullptr}; + std::string m_overwrite_url_scale; + std::string m_overwrite_url_vtx; + std::array m_zdc_energy_sum{}; std::array m_mbd_charge_sum{}; std::array m_mbd_hit{}; - double m_centrality_scale{std::numeric_limits::quiet_NaN()}; - double m_vertex_scale{std::numeric_limits::quiet_NaN()}; - float m_vertex{std::numeric_limits::quiet_NaN()}; std::vector, float>> m_vertex_scales{}; }; diff --git a/offline/packages/trigger/TriggerPrimitivev1.h b/offline/packages/trigger/TriggerPrimitivev1.h index f484449096..6b62d34747 100644 --- a/offline/packages/trigger/TriggerPrimitivev1.h +++ b/offline/packages/trigger/TriggerPrimitivev1.h @@ -6,7 +6,6 @@ #include #include -#include /// class TriggerPrimitivev1 : public TriggerPrimitive From 97aeb59b00060d4c4eadc6c025f8c6aeaee79583 Mon Sep 17 00:00:00 2001 From: mchiu-bnl Date: Tue, 26 May 2026 11:54:02 -0400 Subject: [PATCH 540/866] mbdvtxmap now being filled during calpass 2 --- offline/packages/mbd/MbdReco.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index 5ae4a67271..e705a671d1 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -176,7 +176,7 @@ int MbdReco::process_event(PHCompositeNode *topNode) m_mbdevent->Calculate(m_mbdpmts, m_mbdout, topNode); // For multiple global vertex - if (m_mbdevent->get_bbcn(0) > 0 && m_mbdevent->get_bbcn(1) > 0 && _calpass==0 ) + if ( m_mbdevent->get_bbcn(0) > 0 && m_mbdevent->get_bbcn(1) > 0 && !_fitsonly && _calpass!=1 ) { auto *vertex = new MbdVertexv3(); vertex->set_t(m_mbdevent->get_bbct0()); @@ -185,10 +185,7 @@ int MbdReco::process_event(PHCompositeNode *topNode) vertex->set_t_err(m_tres); vertex->set_beam_crossing(0); - if ( !_fitsonly ) - { - m_mbdvtxmap->insert(vertex); - } + m_mbdvtxmap->insert(vertex); } if (Verbosity() > 0) From 4eb6fbccd7ec20d7ba9035b6482d05bd986bbd85 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 26 May 2026 12:11:15 -0400 Subject: [PATCH 541/866] fix clang-tidy, remove redundant booleans --- offline/packages/centrality/CentralityReco.cc | 171 +++++++++--------- offline/packages/centrality/CentralityReco.h | 51 ++---- 2 files changed, 104 insertions(+), 118 deletions(-) diff --git a/offline/packages/centrality/CentralityReco.cc b/offline/packages/centrality/CentralityReco.cc index bc478366a5..57315d24f4 100644 --- a/offline/packages/centrality/CentralityReco.cc +++ b/offline/packages/centrality/CentralityReco.cc @@ -8,14 +8,9 @@ #include -#include -#include - -#include #include -#include -#include +#include #include @@ -35,47 +30,59 @@ CentralityReco::CentralityReco(const std::string &name) : SubsysReco(name) { - } int CentralityReco::InitRun(PHCompositeNode *topNode) { CDBInterface *m_cdb = CDBInterface::instance(); - std::string centdiv_url = m_cdb->getUrl("Centrality"); - if (m_overwrite_divs) - { - centdiv_url = m_overwrite_url_divs; - std::cout << " Overwriting Divs to " << m_overwrite_url_divs << std::endl; - } + std::string centdiv_url; + if (!m_overwrite_url_divs.empty()) + { + centdiv_url = m_overwrite_url_divs; + std::cout << " Overwriting Divs to " << m_overwrite_url_divs << std::endl; + } + else + { + centdiv_url = m_cdb->getUrl("Centrality"); + } if (Download_centralityDivisions(centdiv_url)) { return Fun4AllReturnCodes::ABORTRUN; } - std::string centscale_url = m_cdb->getUrl("CentralityScale"); - if (m_overwrite_scale) - { - centscale_url = m_overwrite_url_scale; - std::cout << " Overwriting Scale to " << m_overwrite_url_scale << std::endl; - } + std::string centscale_url; + if (!m_overwrite_url_scale.empty()) + { + centscale_url = m_overwrite_url_scale; + std::cout << " Overwriting Scale to " << m_overwrite_url_scale << std::endl; + } + else + { + centscale_url = m_cdb->getUrl("CentralityScale"); + } if (Download_centralityScale(centscale_url)) { return Fun4AllReturnCodes::ABORTRUN; } - std::string vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); - if (m_overwrite_vtx) - { - vertexscale_url = m_overwrite_url_vtx; - std::cout << " Overwriting Vtx to " << m_overwrite_url_vtx << std::endl; - } - + + std::string vertexscale_url; + if (!m_overwrite_url_vtx.empty()) + { + vertexscale_url = m_overwrite_url_vtx; + std::cout << " Overwriting Vtx to " << m_overwrite_url_vtx << std::endl; + } + else + { + vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); + } + if (Download_centralityVertexScales(vertexscale_url)) - { - return Fun4AllReturnCodes::ABORTRUN; - } + { + return Fun4AllReturnCodes::ABORTRUN; + } CreateNodes(topNode); return Fun4AllReturnCodes::EVENT_OK; @@ -117,9 +124,9 @@ int CentralityReco::Download_centralityDivisions(const std::string &dbfile) CDBTTree *cdbttree = new CDBTTree(dbase_file); cdbttree->LoadCalibrations(); if (Verbosity()) - { - cdbttree->Print(); - } + { + cdbttree->Print(); + } for (int idiv = 0; idiv < NDIVS; idiv++) { m_centrality_map[idiv] = cdbttree->GetFloatValue(idiv, "centralitydiv"); @@ -140,7 +147,6 @@ int CentralityReco::Download_centralityDivisions(const std::string &dbfile) } int CentralityReco::Download_centralityVertexScales(const std::string &dbfile) { - std::filesystem::path dbase_file = dbfile; if (dbase_file.extension() == ".root") @@ -148,18 +154,17 @@ int CentralityReco::Download_centralityVertexScales(const std::string &dbfile) CDBTTree *cdbttree = new CDBTTree(dbase_file); cdbttree->LoadCalibrations(); if (Verbosity()) - { - cdbttree->Print(); - } - + { + cdbttree->Print(); + } + int nvertexbins = cdbttree->GetIntValue(0, "nvertexbins"); - for (int iv = 0; iv < nvertexbins; iv++) { float scale = cdbttree->GetDoubleValue(iv, "scale"); float lowvertex = cdbttree->GetDoubleValue(iv, "low_vertex"); - float highvertex = cdbttree->GetDoubleValue(iv, "high_vertex"); + float highvertex = cdbttree->GetDoubleValue(iv, "high_vertex"); m_vertex_scales.emplace_back(std::make_pair(lowvertex, highvertex), scale); } @@ -188,30 +193,27 @@ int CentralityReco::FillVars() std::cout << __FILE__ << " :: " << __FUNCTION__ << std::endl; } - float scale_factor = getVertexScale(); if (Verbosity()) - { - std::cout << scale_factor << "*" << m_centrality_scale << std::endl; - } + { + std::cout << scale_factor << "*" << m_centrality_scale << std::endl; + } for (int i = 0; i < 128; i++) + { + m_mbd_hit = m_mbd_container->get_pmt(i); + + if ((m_mbd_hit->get_q()) < mbd_charge_cut) { - - m_mbd_hit = m_mbd_container->get_pmt(i); - - if ((m_mbd_hit->get_q()) < mbd_charge_cut) - { - continue; - } - if (fabs(m_mbd_hit->get_time()) > mbd_time_cut) - { - continue; - } - m_mbd_total_charge += m_mbd_hit->get_q()*scale_factor*m_centrality_scale; + continue; } - + if (fabs(m_mbd_hit->get_time()) > mbd_time_cut) + { + continue; + } + m_mbd_total_charge += m_mbd_hit->get_q() * scale_factor * m_centrality_scale; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -232,15 +234,15 @@ int CentralityReco::FillCentralityInfo() if (m_centrality_map[i] < m_mbd_total_charge) { binvalue = i + 1; - value = static_cast(i + 1)/static_cast(NDIVS); + value = static_cast(i + 1) / static_cast(NDIVS); break; } } - if (Verbosity()) - { - std::cout << " Centile : " << value << std::endl; - std::cout << " Charge : " << m_mbd_total_charge << std::endl; - } + if (Verbosity()) + { + std::cout << " Centile : " << value << std::endl; + std::cout << " Charge : " << m_mbd_total_charge << std::endl; + } m_central->set_centile(CentralityInfo::PROP::mbd_NS, value); m_central->set_centrality_bin(CentralityInfo::PROP::mbd_NS, binvalue); @@ -262,10 +264,9 @@ int CentralityReco::process_event(PHCompositeNode *topNode) } if (!m_mb_info->isAuAuMinimumBias()) - { - return Fun4AllReturnCodes::EVENT_OK; - } - + { + return Fun4AllReturnCodes::EVENT_OK; + } // Fill Arrays if (FillVars()) @@ -317,18 +318,17 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_mbd_out = findNode::getClass(topNode, m_mbd_out_nodename); if (Verbosity()) - { - std::cout << "Getting MBD Out" << std::endl; - } + { + std::cout << "Getting MBD Out" << std::endl; + } if (!m_mbd_out) - { - std::cout << "no MBD out node " << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + { + std::cout << "no MBD out node " << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -367,22 +367,19 @@ void CentralityReco::CreateNodes(PHCompositeNode *topNode) float CentralityReco::getVertexScale() { - - float mbd_vertex = m_mbd_out->get_zvtx(); for (auto v_range_scale : m_vertex_scales) + { + auto v_range = v_range_scale.first; + if (Verbosity()) { - auto v_range = v_range_scale.first; - if (Verbosity()) - { - std::cout << "vertexrange : "< v_range.first && mbd_vertex <= v_range.second) - { - return v_range_scale.second; - } + std::cout << "vertexrange : " << v_range.first << "-" << v_range.second << std::endl; } + + if (mbd_vertex > v_range.first && mbd_vertex <= v_range.second) + { + return v_range_scale.second; + } + } return 0; } - diff --git a/offline/packages/centrality/CentralityReco.h b/offline/packages/centrality/CentralityReco.h index bd63287255..4c11d49c70 100644 --- a/offline/packages/centrality/CentralityReco.h +++ b/offline/packages/centrality/CentralityReco.h @@ -2,13 +2,14 @@ #define CENTRALITY_CENTRALITYRECO_H #include + #include -#include #include #include // for string, allocator +#include // Forward declarations -class TF1; + class CentralityInfo; class MinimumBiasInfo; class PHCompositeNode; @@ -45,18 +46,15 @@ class CentralityReco : public SubsysReco void setOverwriteDivs(const std::string &url) { m_overwrite_url_divs = url; - m_overwrite_divs = true; } void setOverwriteScale(const std::string &url) { m_overwrite_url_scale = url; - m_overwrite_scale = true; } void setOverwriteVtx(const std::string &url) { m_overwrite_url_vtx = url; - m_overwrite_vtx = true; } void set_minbiasNodeName(const std::string &name) @@ -76,47 +74,38 @@ class CentralityReco : public SubsysReco m_mbd_pmt_nodename = name; } - private: - - float getVertexScale(); - std::string m_dbfilename; - - std::string m_mb_info_nodename{"MinimumBiasInfo"}; - - std::string m_mbd_out_nodename{"MbdOut"}; - - std::string m_centrality_nodename{"CentralityInfo"}; - - std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; - - - std::string m_overwrite_url_divs; - std::string m_overwrite_url_scale; - std::string m_overwrite_url_vtx; - - const int NDIVS{100}; - const float mbd_charge_cut{0.5}; - const float mbd_time_cut{25}; - MbdOut *m_mbd_out{nullptr}; MbdPmtContainer *m_mbd_container{nullptr}; MbdPmtHit *m_mbd_hit{nullptr}; MinimumBiasInfo *m_mb_info{nullptr}; CentralityInfo *m_central{nullptr}; - unsigned int m_key{std::numeric_limits::max()}; + static constexpr int NDIVS{100}; - float m_mbd_total_charge{0.}; // init to zero for use in first event + static constexpr float mbd_charge_cut{0.5}; + static constexpr float mbd_time_cut{25}; + + unsigned int m_key{std::numeric_limits::max()}; double m_centrality_scale{std::numeric_limits::quiet_NaN()}; - std::vector, float>> m_vertex_scales{}; - std::array m_centrality_map{}; + float m_mbd_total_charge{0.}; // init to zero for use in first event + std::string m_mb_info_nodename{"MinimumBiasInfo"}; + std::string m_mbd_out_nodename{"MbdOut"}; + std::string m_centrality_nodename{"CentralityInfo"}; + std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; + + std::string m_overwrite_url_divs; + std::string m_overwrite_url_scale; + std::string m_overwrite_url_vtx; + + std::vector, float>> m_vertex_scales{}; + std::array m_centrality_map{}; }; #endif From 12fb24a071f8ee3995df37244ee7850f86bf0ec0 Mon Sep 17 00:00:00 2001 From: Chris Pinkenburg Date: Tue, 26 May 2026 12:11:44 -0400 Subject: [PATCH 542/866] fix clang-tidy, remove redundant booleans --- offline/packages/centrality/CentralityReco.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/offline/packages/centrality/CentralityReco.h b/offline/packages/centrality/CentralityReco.h index 4c11d49c70..46d8d54bd1 100644 --- a/offline/packages/centrality/CentralityReco.h +++ b/offline/packages/centrality/CentralityReco.h @@ -6,6 +6,7 @@ #include #include #include // for string, allocator +#include #include // Forward declarations @@ -13,7 +14,6 @@ class CentralityInfo; class MinimumBiasInfo; class PHCompositeNode; -class GlobalVertexMap; class MbdOut; class MbdPmtContainer; class MbdPmtHit; From 2ec4fadba91f4fc891308a93004d42fee7e94027 Mon Sep 17 00:00:00 2001 From: Christopher W Platte Date: Tue, 26 May 2026 14:24:40 -0400 Subject: [PATCH 543/866] Added branches to the laminationTree that include the zdc evaluated A,B, and C parameters --- .../packages/tpccalib/TpcLaminationFitting.cc | 23 +++++++++++++------ .../packages/tpccalib/TpcLaminationFitting.h | 4 ++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 1c5cf71f9f..58e98ee68a 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -345,6 +345,11 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) m_laminationTree->Branch("RMSE",&m_rmse); + m_ZDCParameterValuesTree = new TTree("ZDCParameterValuesTree","ZDCParameterValuesTree"); + m_laminationTree->Branch("A_zdc",&m_A_zdc); + m_laminationTree->Branch("B_zdc",&m_B_zdc); + m_laminationTree->Branch("C_zdc",&m_C_zdc); + return Fun4AllReturnCodes::EVENT_OK; } @@ -387,7 +392,7 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) { const auto &[cmkey, cmclus_orig] = *cmitr; LaserCluster *cmclus = cmclus_orig; - // const unsigned int adc = cmclus->getAdc(); + const unsigned int adc = cmclus->getAdc(); bool side = (bool) TpcDefs::getSide(cmkey); if (cmclus->getNLayers() < m_nLayerCut) { @@ -408,7 +413,7 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) TVector3 tmp_pos(pos[0], pos[1], pos[2]); if(cmclus->getNLayers() > m_nLayerCut) - // if(cmclus->getNLayers() > m_nLayerCut && cmclus->getSDWeightedLayer() > 0.5) + // if(cmclus->getNLayers() > m_nLayerCut && cmclus->getSDWeightedLayer() > 0.5) { for (int l = 0; l < 18; l++) { @@ -426,7 +431,7 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) { - m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi); + m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi,adc); } } } @@ -566,10 +571,13 @@ int TpcLaminationFitting::fitLaminations() } else { + m_A_zdc = Af[s]->Eval(m_ZDC_coincidence); + m_B_zdc = Bf[s]->Eval(m_ZDC_coincidence); + m_C_zdc = Cseed[s]; m_fLamination[l][s]->SetParameters(Af[s]->Eval(m_ZDC_coincidence), Bf[s]->Eval(m_ZDC_coincidence), Cseed[s], m_laminationIdeal[l][s] + m_laminationOffset[l][s]); m_fLamination[l][s]->FixParameter(3, m_laminationIdeal[l][s] + m_laminationOffset[l][s]); } - + TF1 *fitSeed = (TF1 *) m_fLamination[l][s]->Clone(); fitSeed->SetName(std::format("fitSeed{}_{}", l, (s == 1 ? "North" : "South")).c_str()); @@ -694,7 +702,7 @@ int TpcLaminationFitting::fitLaminations() } } } - + m_ZDCParameterValuesTree->Fill(); m_distanceToFit[l][s] = distToFunc / nBinsUsed; m_nBinsFit[l][s] = nBinsUsed; if(c>0) { m_fitRMSE[l][s] = sqrt(wc / c); @@ -1090,7 +1098,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } c1->SaveAs(std::format("{}]", m_QAFileName).c_str()); } - + //TFile *simDistortion = new TFile("/cvmfs/sphenix.sdcc.bnl.gov/gcc-12.1.0/release/release_new/new.10/share/calibrations/distortion_maps/average_minus_static_distortion_inverted_10-new.root", "READ"); //TH3 *hIntDistortionP_posz = (TH3 *) simDistortion->Get("hIntDistortionP_posz"); //hIntDistortionP_posz->GetZaxis()->SetRange(2, 2); @@ -1211,7 +1219,8 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) m_parameterScan[s]->Write(); } m_laminationTree->Write(); - + m_ZDCParameterValuesTree->Write(); + m_saveAllLaminationHistograms = true; if(m_saveAllLaminationHistograms) { for(auto &i : m_hLamination) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 5285dff0d2..a33f244f25 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -133,6 +133,7 @@ class TpcLaminationFitting : public SubsysReco bool m_fieldOff{false}; TTree *m_laminationTree{nullptr}; + TTree *m_ZDCParameterValuesTree{nullptr}; bool m_side{false}; int m_lamIndex{0}; double m_lamPhi{0}; @@ -144,6 +145,9 @@ class TpcLaminationFitting : public SubsysReco double m_A_err{0}; double m_B_err{0}; double m_C_err{0}; + double m_A_zdc{0}; + double m_B_zdc{0}; + double m_C_zdc{0}; double m_dist{0}; double m_rmse{}; int m_nBins{0}; From f439c50a1e6f85b40f982c54ef0be2ae8135f383 Mon Sep 17 00:00:00 2001 From: Christopher W Platte Date: Tue, 26 May 2026 14:27:58 -0400 Subject: [PATCH 544/866] removed extra unnecessary tree --- offline/packages/tpccalib/TpcLaminationFitting.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index fab4cce588..7efa7a21cc 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -350,9 +350,6 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) m_laminationTree->Branch("distanceToFit",&m_dist); m_laminationTree->Branch("nBinsFit",&m_nBins); m_laminationTree->Branch("RMSE",&m_rmse); - - - m_ZDCParameterValuesTree = new TTree("ZDCParameterValuesTree","ZDCParameterValuesTree"); m_laminationTree->Branch("A_zdc",&m_A_zdc); m_laminationTree->Branch("B_zdc",&m_B_zdc); m_laminationTree->Branch("C_zdc",&m_C_zdc); From 6e89750e2e4348ea9bbfb77bd44f408057b24ac0 Mon Sep 17 00:00:00 2001 From: Christopher W Platte Date: Tue, 26 May 2026 14:34:23 -0400 Subject: [PATCH 545/866] Uncommented LASER_CLUSTER, commented LAMINATION_CLUSTER --- offline/packages/tpccalib/TpcLaminationFitting.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 7efa7a21cc..95a3bff111 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -248,8 +248,8 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) //______________________________________ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) { - m_correctedCMcluster_map = findNode::getClass(topNode, "LAMINATION_CLUSTER"); - // m_correctedCMcluster_map = findNode::getClass(topNode, "LASER_CLUSTER"); + //m_correctedCMcluster_map = findNode::getClass(topNode, "LAMINATION_CLUSTER"); + m_correctedCMcluster_map = findNode::getClass(topNode, "LASER_CLUSTER"); if (!m_correctedCMcluster_map) { std::cout << PHWHERE << "CORRECTED_CM_CLUSTER Node missing, abort." << std::endl; From 09172884e7d6b941659d0d799a7c918bfd8b367d Mon Sep 17 00:00:00 2001 From: Christopher W Platte Date: Tue, 26 May 2026 14:38:39 -0400 Subject: [PATCH 546/866] Removed extraneous pointers and lines for the extra tree that was removed --- offline/packages/tpccalib/TpcLaminationFitting.cc | 3 +-- offline/packages/tpccalib/TpcLaminationFitting.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 95a3bff111..dcbb70b481 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -711,7 +711,7 @@ int TpcLaminationFitting::fitLaminations() } } } - m_ZDCParameterValuesTree->Fill(); + m_distanceToFit[l][s] = distToFunc / nBinsUsed; m_nBinsFit[l][s] = nBinsUsed; if(c>0) { m_fitRMSE[l][s] = sqrt(wc / c); @@ -1228,7 +1228,6 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) m_parameterScan[s]->Write(); } m_laminationTree->Write(); - m_ZDCParameterValuesTree->Write(); m_saveAllLaminationHistograms = true; if(m_saveAllLaminationHistograms) { diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 867da73308..c952706773 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -141,7 +141,6 @@ class TpcLaminationFitting : public SubsysReco bool m_fieldOff{false}; TTree *m_laminationTree{nullptr}; - TTree *m_ZDCParameterValuesTree{nullptr}; bool m_side{false}; int m_lamIndex{0}; double m_lamPhi{0}; From 803607663d5f511f68ab2b1f12f7d9a90681c5e6 Mon Sep 17 00:00:00 2001 From: Chris Platte <123033602+cplatte24@users.noreply.github.com> Date: Wed, 27 May 2026 11:14:09 -0500 Subject: [PATCH 547/866] Update offline/packages/tpccalib/TpcLaminationFitting.cc Co-authored-by: bkimelman <120117749+bkimelman@users.noreply.github.com> --- offline/packages/tpccalib/TpcLaminationFitting.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index dcbb70b481..78f4e4a3dd 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -1228,7 +1228,6 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) m_parameterScan[s]->Write(); } m_laminationTree->Write(); - m_saveAllLaminationHistograms = true; if(m_saveAllLaminationHistograms) { for(auto &i : m_hLamination) From 6d5a09b02a43d838b409630fa1f0fac20cffb49b Mon Sep 17 00:00:00 2001 From: Chris Platte <123033602+cplatte24@users.noreply.github.com> Date: Wed, 27 May 2026 11:14:53 -0500 Subject: [PATCH 548/866] Delete offline/packages/tpccalib/tpccalib-1.00.tar.gz --- offline/packages/tpccalib/tpccalib-1.00.tar.gz | Bin 406222 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 offline/packages/tpccalib/tpccalib-1.00.tar.gz diff --git a/offline/packages/tpccalib/tpccalib-1.00.tar.gz b/offline/packages/tpccalib/tpccalib-1.00.tar.gz deleted file mode 100644 index 605cabd32088e84d9eed575392cc19992174d054..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 406222 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 A!L+4uAbv`FUWCTeG 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