Skip to content

KFParticle: added local dE/dx file option, removed condition on import of daughter BCOs from GL1#4168

Merged
osbornjd merged 4 commits intosPHENIX-Collaboration:masterfrom
petermic:kfparticle_localfile
Feb 6, 2026
Merged

KFParticle: added local dE/dx file option, removed condition on import of daughter BCOs from GL1#4168
osbornjd merged 4 commits intosPHENIX-Collaboration:masterfrom
petermic:kfparticle_localfile

Conversation

@petermic
Copy link
Contributor

@petermic petermic commented Feb 6, 2026

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work for users)
  • Requiring change in macros repository (Please provide links to the macros pull request in the last section)
  • I am a member of GitHub organization of sPHENIX Collaboration, EIC, or ECCE (contact Chris Pinkenburg to join)

What kind of change does this PR introduce? (Bug fix, feature, ...)

Currently, KFParticle is only able to use the dE/dx parametrization currently stored in the CDB, which was derived from run 53877; this parametrization is not in general valid for later (or earlier) runs, so until we can repopulate the CDB with run-by-run dE/dx parametrization calibrations, this PR adds an option to use a local file for dE/dx calibration instead.

In addition, this PR removes a condition on extracting the daughter BCOs from the GL1 packet; now they are always retrieved, regardless of the value of m_trigger_info_available.

TODOs (if applicable)

Links to other PRs in macros and calibration repositories (if applicable)

KFParticle: Local dE/dx file option and GL1 BCO extraction improvements

Motivation & Context

This PR addresses two issues in KFParticle reconstruction:

  1. The current dE/dx calibration stored in CDB is based on run 53877 and is not valid for other data runs. This PR adds a local file alternative while waiting for run-by-run calibrations to be added to the CDB.
  2. Simplifies BCO extraction from GL1 packets by removing an unnecessary condition.

Key Changes

  • Local dE/dx file support: Added m_use_local_PID_file (bool, default=false) and m_local_PID_filename (string, default="") member variables to enable loading dE/dx calibrations from local files as an alternative to CDB.
  • Modified init_dEdx_fits(): Now selects calibration source based on the flag—uses local file with charge-independent keys ("pi_band", "K_band", "p_band") when enabled; otherwise uses original CDB keys ("f_piband", "f_Kband", etc.).
  • Public setter methods: Added useLocalPIDFile(bool) and setLocalPIDFilename(const std::string&) to KFParticle_sPHENIX for easy configuration.
  • Unconditional BCO extraction: Removed m_trigger_info_available condition from BCO calculation in fillBranch()—daughter BCOs are now always retrieved from GL1 packet.
  • Header update: Added include of dedxfitter/bethe_bloch.h to ensure inline functions are properly defined.

Potential Risk Areas

  • Key name mismatch: Local file uses charge-independent keys while CDB uses separate positive/negative keys. Verify consistency between file keys and CDB keys if switching between sources.
  • BCO behavior change: BCO calculation is now unconditional, changing from 0 when trigger info was unavailable to calculated values. Downstream code relying on this BCO=0 behavior should be reviewed.
  • Run-specific calibrations: Operators must ensure the local file contains appropriate calibrations for their data run; using incorrect calibrations could bias PID reconstruction.

Backward Compatibility

Changes are non-breaking: default behavior (m_use_local_PID_file=false) maintains original CDB-based dE/dx loading.

Possible Future Improvements

  • Populate run-by-run dE/dx calibrations in CDB to eliminate the need for local file workaround.
  • Validate and benchmark dE/dx performance with local file calibrations across multiple run conditions.
  • Implement automatic calibration file selection based on run number metadata.

Note: This summary is based on AI-generated code analysis and diff descriptions. While reasonable care is taken to ensure accuracy, human judgment is recommended when reviewing the actual code changes, particularly regarding the BCO extraction behavior change and the local file key naming scheme.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

The changes add support for loading dE/dx fit parameters from a local PID parametrization file with charge-independent keys, alongside the existing CDBInterface URL approach. Configuration is controlled by new boolean and string members, with public setters to enable this in the reconstruction workflow. Additionally, BCO calculation is now unconditional rather than trigger-dependent.

Changes

Cohort / File(s) Summary
PID File Configuration
offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h, offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h
Added m_use_local_PID_file and m_local_PID_filename members with public setter methods to control local PID file usage; included dedxfitter/bethe_bloch.h header.
PID Fit Loading
offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc
Modified init_dEdx_fits to select fit source and keys based on m_use_local_PID_file flag; charge-independent keys ("pi_band", "K_band", "p_band") for local files, original charge-dependent keys for CDBInterface.
BCO Calculation
offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc
Changed BCO computation from conditional (zero when trigger unavailable) to unconditional calculation using gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0].

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc (1)

670-676: ⚠️ Potential issue | 🔴 Critical

Null-pointer dereference of gl1packet when GL1 data is absent.

Both findNode::getClass calls (lines 670, 673) can return nullptr. The previous conditional on m_trigger_info_available (line 676, now commented out) effectively guarded against dereferencing a null pointer. With that guard removed, line 675 will crash if neither "GL1RAWHIT" nor "GL1Packet" nodes are present on topNode.

Please add an explicit null check before dereferencing.

Proposed fix
     auto* gl1packet = findNode::getClass<Gl1Packet>(topNode, "GL1RAWHIT");
     if (!gl1packet)
     {
       gl1packet = findNode::getClass<Gl1Packet>(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;
+    if (gl1packet)
+    {
+      m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0];
+    }
+    else
+    {
+      m_bco = 0;
+    }
offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc (1)

859-870: ⚠️ Potential issue | 🟠 Major

Unbounded queue growth — m_rawzdc_hist, m_rawmbd_hist, m_rawmbdv10_hist, m_bco_hist are never popped.

With the pop() logic commented out (lines 860–864), these queues grow by one entry per event for the lifetime of the job. For a run with N events that's 4 × 8 × N bytes of monotonically growing memory.

Additionally, the rate computation at lines 1247–1249 (back() - front()) now computes a cumulative average over the full run instead of a rolling 50-event window, which changes the physics meaning of inforzdc / informbd / informbdv10. If this is intentional, the queue push at lines 780–783 should also be removed and replaced with first/current tracking. If not, restore the pop logic.

Comment on lines 1207 to 1226
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);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing null-checks on TF1 pointers after GetObject — risk of nullptr dereference.

If the local PID file doesn't contain the expected keys ("pi_band", "K_band", "p_band"), GetObject silently leaves the TF1* members as nullptr. The subsequent pidMap entries will then hold null pointers, and the first call to get_dEdx_fitValuepidMap[PID]->Eval(momentum) will crash.

The pre-existing CDB branch has the same structural risk, but a user-supplied local file is far more likely to have mismatched key names. A defensive check after loading would prevent a silent crash deep in event processing.

Suggested null-check after both branches
   }
 
+  if (!f_pion_plus || !f_kaon_plus || !f_proton_plus ||
+      !f_pion_minus || !f_kaon_minus || !f_proton_minus)
+  {
+    std::cerr << "KFParticle_Tools::init_dEdx_fits: one or more dE/dx fit functions not found in " << dedx_fitparams << std::endl;
+    return;
+  }
+
   pidMap.insert(std::pair<int, TF1 *>(-11, f_pion_plus));

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc (1)

1187-1205: ⚠️ Potential issue | 🔴 Critical

TFile::Open returns nullptr when the file doesn't exist — immediate nullptr dereference on line 1201.

TFile::Open returns a null pointer if the path is invalid or the file is missing. Line 1201 dereferences filefit unconditionally via filefit->IsOpen(), which will segfault. This was a latent risk with the CDB path, but introducing a user-supplied local filename makes it far more likely to trigger in practice (typos, missing files, wrong working directory, etc.).

Proposed fix — guard against nullptr before calling IsOpen
   TFile *filefit = TFile::Open(dedx_fitparams.c_str());
 
-  if (!filefit->IsOpen())
+  if (!filefit || !filefit->IsOpen())
   {
     std::cerr << "Error opening filefit!" << std::endl;
     return;
   }

@sphenix-jenkins-ci
Copy link

Build & test report

Report for commit c37ffe92cbd1700573b83a0814d743489bedb407:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@sphenix-jenkins-ci
Copy link

Build & test report

Report for commit 804a7fac2232fbb49fabf43a9f97edc23662e693:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@sphenix-jenkins-ci
Copy link

Build & test report

Report for commit 96944238e5e4cb0feddcfce1627e00d20f1f6db8:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@osbornjd osbornjd merged commit 01f64aa into sPHENIX-Collaboration:master Feb 6, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants