Skip to content

dEdxFitter added to TPC calibrations#4114

Merged
osbornjd merged 4 commits intosPHENIX-Collaboration:masterfrom
petermic:dedxfitter
Jan 23, 2026
Merged

dEdxFitter added to TPC calibrations#4114
osbornjd merged 4 commits intosPHENIX-Collaboration:masterfrom
petermic:dedxfitter

Conversation

@petermic
Copy link
Copy Markdown
Contributor

@petermic petermic commented Jan 15, 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, ...)

Adds the dE/dx parametrization to the TPC calibrations folder. The module dEdxFitter produces TF1s for the pion, kaon, proton and deuteron bands using an unbinned-fit procedure that minimizes the chi^2/ndf of the four bands to their closest respective sets of tracks.

The output distributions have a single parameter, the normalization constant (the mean excitation is taken to be the expected value calculated from the sPHENIX TPC gas mixture, and the fit function does not include density-effect contributions), which is extracted from batches of tracks that pass configurable quality cuts. The batch size is also a configurable parameter. When End() is called, the fit results from all batches are averaged to produce the final results. If the run was too small to fill one batch, a fit is performed with whatever population of tracks the module has managed to accumulate.

TODOs (if applicable)

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

This module is currently a duplicate of this module from the analysis repository: https://github.com/sPHENIX-Collaboration/analysis/tree/master/Tracking/dEdx

dEdxFitter Module Addition to TPC Calibrations

Motivation / context

  • Provide an automated, per-run dE/dx parametrization for the sPHENIX TPC to produce Bethe–Bloch calibration bands (π, K, p, d) as ROOT TF1/TF2/TF3 objects usable for calibration and reconstruction. Enables extraction of a run-wise normalization parameter from reconstructed tracks (batch-mode fits averaged over the run).

Key changes

  • New fitter core: GlobaldEdxFitter
    • Collects per-track (p, dE/dx) data, computes closest-hypothesis residuals, defines multiple χ²-like fit-quality metrics, and minimizes to extract normalization (and related) parameter(s).
    • Supports configurable batch-mode fits; per-batch minima are averaged at End() to produce final parameters.
    • API: processResidualData, addTrack, get_minimum/_new/_ZS, create_TF1/TF2/TF3, graphing helpers, and utilities to compute betagamma and dedx ratios.
  • SubsysReco integration: dEdxFitter module
    • Integrates with PHENIX node tree (SvtxTrackMap, cluster containers, TPC geometry, vertex map).
    • Applies configurable quality cuts (nmaps, nintt, ntpc, |eta|, |DCAxy|), computes per-track dE/dx from cluster/layer geometry, accumulates tracks, performs batch fits, and writes final Bethe–Bloch bands to a ROOT output file.
    • Config setters for output filename, selection cuts, and tracks-per-fit.
  • Physics utilities: bethe_bloch.h
    • Self-contained Bethe–Bloch parameterizations and constants for the sPHENIX TPC gas mixture (Ar/CF4/isobutane), multiple functional forms (1D/2D/new), and many ROOT-compatible wrapper functions for fitting and plotting.
    • dedx_ratio helper provided. Density-effect contributions are intentionally excluded.
  • Build & tooling
    • New autotools artifacts (configure.ac, Makefile.am, autogen.sh) to build libdedxfitter.la and install headers; adds a small generated test program and test_sample_size.C for diagnostics and stability studies.
  • IO/output
    • processResidualData and test scripts accept input-file patterns; End() writes final TF* objects into a configurable ROOT file.

Potential risk areas

  • Duplication & maintenance: This largely duplicates an analysis-repo implementation — risk of divergence and extra upkeep unless consolidated with the analysis code.
  • IO / path defaults: Example/test scripts and defaults reference local/example paths; CI or production runs may accidentally pick incorrect inputs if not overridden.
  • Reconstruction compatibility: Module depends on specific cluster/geometry/vertex node layouts and TrackAnalysisUtils; API changes upstream could silently break results.
  • Physics model limits: Density-effect corrections are excluded; fits may be biased at higher momentum or under different gas conditions.
  • Fit robustness & selection bias: Results depend on selection cuts, batch size, and averaging strategy — potential bias if detector response varies within a run.
  • Performance & memory: GlobaldEdxFitter stores full vectors and uses ROOT/Minuit minimizers — may be expensive for very large data sets.
  • Thread-safety: Use of ROOT global objects and TF/Minuit suggests the code is likely not safe for concurrent threaded execution without review.
  • Build/packaging: New library exports and autotools files require CI/packaging verification. Note: Jenkins could not re-run on this PR because the contributor’s fork was created from a different upstream — author needs to re-push/rebase their fork to trigger CI.

Possible future improvements

  • Consolidate with the analysis-repo implementation to avoid duplication and ensure a single canonical fitter.
  • Add optional density-effect corrections, extra shape parameters, or multi-parameter fits with returned covariances.
  • Support adaptive/streaming fits to reduce memory footprint and follow time-dependent detector changes.
  • Improve thread-safety (avoid ROOT globals or isolate minimizers) and add unit/integration tests that mock realistic node trees.
  • Replace hard-coded/example input paths with documented configuration files and usage examples; add CI tests exercising build/install and basic fit behavior.

Caveat

  • This summary was produced with AI assistance. AI can make mistakes — please verify file diffs and code directly before making merge decisions.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Adds a TPC dE/dx fitting subsystem: a Bethe‑Bloch model header, a self‑contained GlobaldEdxFitter (header+impl), a SubsysReco dEdxFitter module for event/track processing, Autotools build scripts, and analysis macros for sample‑size studies and visualization.

Changes

Cohort / File(s) Summary
Physics model
calibrations/tpc/dEdx/bethe_bloch.h
New Bethe‑Bloch constants and inline functions for species/mixture dE/dx; multiple analytic parameterizations and ROOT‑compatible wrappers for fits/evaluations (p, log(p), betagamma) and a dedx ratio helper.
Fitting library
calibrations/tpc/dEdx/GlobaldEdxFitter.h, calibrations/tpc/dEdx/GlobaldEdxFitter.cc
New GlobaldEdxFitter class: data ingestion from residual trees, track storage, several fit‑quality metrics and wrappers, multiple minimization entry points (TF1/TF2/TF3 + Minuit2), betagamma diagnostics, TF/graph creation, range/config setters, and reset/serialization helpers.
SubsysReco integration
calibrations/tpc/dEdx/dEdxFitter.h, calibrations/tpc/dEdx/dEdxFitter.cc
New dEdxFitter SubsysReco module: lifecycle (InitRun/process_event/End), node retrieval, per‑track selection and dE/dx extraction, accumulation into GlobaldEdxFitter, periodic minimization and ROOT output of Bethe‑Bloch bands.
Build & tooling
calibrations/tpc/dEdx/Makefile.am, calibrations/tpc/dEdx/configure.ac, calibrations/tpc/dEdx/autogen.sh
Autotools build added for libdedxfitter.la with public headers exported, sources registered, linker flags, generated testexternals target, configure.ac, and autogen.sh helper.
Analysis & tests
calibrations/tpc/dEdx/test_sample_size.C
ROOT macro to run GlobaldEdxFitter across sample sizes/trials, collect minima statistics, produce graphs/histograms, overlay Bethe‑Bloch bands, and save results to a ROOT file.

Sequence Diagram

sequenceDiagram
    participant Event as Reconstruction (Event Loop)
    participant dEdxFitter as dEdxFitter (SubsysReco)
    participant Fitter as GlobaldEdxFitter (Fitting Engine)
    participant Physics as Bethe‑Bloch (Model)
    participant ROOT as ROOT (Minimizer)

    Event->>dEdxFitter: process_event(topNode)
    activate dEdxFitter
    dEdxFitter->>dEdxFitter: GetNodes (Track/Cluster/Geometry)
    dEdxFitter->>dEdxFitter: process_tracks (iterate SvtxTrackMap)
    loop for each track passing cuts
        dEdxFitter->>dEdxFitter: get_dedx(track)
        dEdxFitter->>Fitter: addTrack(dEdx, p)
        activate Fitter
        Fitter->>Fitter: store (p, dEdx)
        deactivate Fitter
    end
    alt accumulated tracks > threshold
        dEdxFitter->>Fitter: get_minimum() / get_minimum_new()
        activate Fitter
        Fitter->>ROOT: run minimizer (TF1/TF2/TF3 / Minuit2)
        ROOT->>Physics: evaluate bethe_bloch wrapper
        Physics-->>ROOT: dE/dx(betagamma, params)
        ROOT-->>Fitter: optimized parameters / minimum
        Fitter-->>dEdxFitter: return minimum
        deactivate Fitter
        dEdxFitter->>dEdxFitter: store minimum, reset fitter
    end
    deactivate dEdxFitter
Loading
✨ 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
Copy Markdown
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: 10

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64138d4 and b209d85.

📒 Files selected for processing (8)
  • calibrations/tpc/dEdx/GlobaldEdxFitter.h
  • calibrations/tpc/dEdx/Makefile.am
  • calibrations/tpc/dEdx/autogen.sh
  • calibrations/tpc/dEdx/bethe_bloch.h
  • calibrations/tpc/dEdx/configure.ac
  • calibrations/tpc/dEdx/dEdxFitter.cc
  • calibrations/tpc/dEdx/dEdxFitter.h
  • calibrations/tpc/dEdx/test_sample_size.C
🧰 Additional context used
📓 Path-based instructions (3)
**/*.C

⚙️ CodeRabbit configuration file

Do NOT review these files

Files:

  • calibrations/tpc/dEdx/test_sample_size.C
**/*.{h,hpp,hxx,hh}

⚙️ CodeRabbit configuration file

**/*.{h,hpp,hxx,hh}: 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.

Files:

  • calibrations/tpc/dEdx/dEdxFitter.h
  • calibrations/tpc/dEdx/GlobaldEdxFitter.h
  • calibrations/tpc/dEdx/bethe_bloch.h
**/*.{cc,cpp,cxx,c}

⚙️ CodeRabbit configuration file

**/*.{cc,cpp,cxx,c}: 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.

Files:

  • calibrations/tpc/dEdx/dEdxFitter.cc
🧬 Code graph analysis (2)
calibrations/tpc/dEdx/dEdxFitter.cc (2)
calibrations/tpc/dEdx/dEdxFitter.h (1)
  • dEdxFitter (19-86)
simulation/g4simulation/g4eval/SvtxHitEval.h (1)
  • _clustermap (84-84)
calibrations/tpc/dEdx/GlobaldEdxFitter.h (1)
calibrations/tpc/dEdx/bethe_bloch.h (3)
  • bethe_bloch_new_1D (48-53)
  • dedx_constants (6-29)
  • bethe_bloch_total (66-71)
🪛 Clang (14.0.6)
calibrations/tpc/dEdx/dEdxFitter.h

[error] 4-4: 'fun4all/SubsysReco.h' file not found

(clang-diagnostic-error)

calibrations/tpc/dEdx/bethe_bloch.h

[error] 4-4: 'TMath.h' file not found

(clang-diagnostic-error)

🪛 Shellcheck (0.11.0)
calibrations/tpc/dEdx/autogen.sh

[warning] 5-5: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

(SC2164)

🔇 Additional comments (2)
calibrations/tpc/dEdx/Makefile.am (1)

1-49: Build configuration looks good.

The Makefile.am correctly installs the public headers, builds the shared library, and provides a test harness. No critical issues found.

calibrations/tpc/dEdx/configure.ac (1)

1-16: Autotools configuration is standard and appropriate.

The configure.ac follows typical patterns for sPHENIX packages. Enabling -Wall -Werror is good practice for catching issues early.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +5 to +6
(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\
libtoolize --force; automake -a --add-missing; autoconf)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Handle cd failure to avoid running autotools in wrong directory

If cd $srcdir fails (e.g., directory doesn't exist), the script continues and runs aclocal, libtoolize, etc. in the wrong location, potentially corrupting the build or producing confusing errors.

Proposed fix
-(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)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(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)
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 5-5: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

(SC2164)

Comment on lines +328 to +344
TF3* GlobaldEdxFitter::create_TF3_new(std::string name)
{
TF3* f = new TF3(name.c_str(),this,&GlobaldEdxFitter::get_fitquality_wrapper_new,min_norm,max_norm,min_B,max_B,min_ZS,max_ZS,0,"GlobaldEdxFitter","get_fitquality_wrapper_new");
return f;
}

TF1* GlobaldEdxFitter::create_TF1(std::string name)
{
TF1* f = new TF1(name.c_str(),this,&GlobaldEdxFitter::get_fitquality_wrapper_new,min_norm,max_norm,0,"GlobaldEdxFitter","get_fitquality_wrapper");
return f;
}

TF2* GlobaldEdxFitter::create_TF2(std::string name)
{
TF2* f = new TF2(name.c_str(),this,&GlobaldEdxFitter::get_fitquality_wrapper_ZS,min_norm,max_norm,min_ZS,max_ZS,0,"GlobaldEdxFitter","get_fitquality_wrapper_ZS");
return f;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify ownership: raw new TF1/TF2/TF3 returns

create_TF1, create_TF2, and create_TF3_new return raw new-allocated ROOT objects. The caller must remember to delete them (or rely on ROOT's ownership model if added to a directory). Consider documenting ownership expectations or returning std::unique_ptr if ROOT ownership is not intended.

Comment on lines +357 to +370
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];
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Memory leak: minimizer is never deleted

ROOT::Math::Factory::CreateMinimizer returns an owning raw pointer. The minimizer is never freed, leaking memory on every call to get_minimum_new().

Proposed fix using unique_ptr
-  ROOT::Math::Minimizer* minimizer = ROOT::Math::Factory::CreateMinimizer("Minuit2");
+  std::unique_ptr<ROOT::Math::Minimizer> minimizer(
+      ROOT::Math::Factory::CreateMinimizer("Minuit2"));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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];
}
std::unique_ptr<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];
}

@sphenix-jenkins-ci
Copy link
Copy Markdown

Build & test report

Report for commit b209d8585c6ec207b4c60215f8996bb185be86ad:
Jenkins on fire


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

Copy link
Copy Markdown
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

♻️ Duplicate comments (1)
calibrations/tpc/dEdx/dEdxFitter.cc (1)

81-100: Check for missing TPC seed before calling get_dedx.

You guard get_silicon_seed() but still call get_dedx(), which uses track->get_tpc_seed() unconditionally. If a track has a silicon seed but no TPC seed, this will crash. Add a TPC seed check before get_dedx().

Proposed fix
     if(!track->get_silicon_seed())
     {
       if(Verbosity()>1) 
       {
         std::cout << "TPC-only track, skipping..." << std::endl;
       }
       continue;
     }
+    if(!track->get_tpc_seed())
+    {
+      if(Verbosity()>1)
+      {
+        std::cout << "No TPC seed, skipping..." << std::endl;
+      }
+      continue;
+    }
 
     std::tuple<int,int,int> nclus = get_nclus(track);
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b209d85 and 8cbb176.

📒 Files selected for processing (7)
  • calibrations/tpc/dEdx/GlobaldEdxFitter.cc
  • calibrations/tpc/dEdx/GlobaldEdxFitter.h
  • calibrations/tpc/dEdx/Makefile.am
  • calibrations/tpc/dEdx/bethe_bloch.h
  • calibrations/tpc/dEdx/dEdxFitter.cc
  • calibrations/tpc/dEdx/dEdxFitter.h
  • calibrations/tpc/dEdx/test_sample_size.C
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{cc,cpp,cxx,c}

⚙️ CodeRabbit configuration file

**/*.{cc,cpp,cxx,c}: 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.

Files:

  • calibrations/tpc/dEdx/dEdxFitter.cc
  • calibrations/tpc/dEdx/GlobaldEdxFitter.cc
**/*.{h,hpp,hxx,hh}

⚙️ CodeRabbit configuration file

**/*.{h,hpp,hxx,hh}: 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.

Files:

  • calibrations/tpc/dEdx/dEdxFitter.h
  • calibrations/tpc/dEdx/GlobaldEdxFitter.h
  • calibrations/tpc/dEdx/bethe_bloch.h
**/*.C

⚙️ CodeRabbit configuration file

Do NOT review these files

Files:

  • calibrations/tpc/dEdx/test_sample_size.C
🧬 Code graph analysis (4)
calibrations/tpc/dEdx/dEdxFitter.cc (2)
calibrations/tpc/dEdx/dEdxFitter.h (1)
  • dEdxFitter (19-86)
simulation/g4simulation/g4eval/SvtxHitEval.h (1)
  • _clustermap (84-84)
calibrations/tpc/dEdx/dEdxFitter.h (3)
calibrations/tpc/dEdx/dEdxFitter.cc (7)
  • dEdxFitter (13-18)
  • InitRun (21-27)
  • InitRun (21-21)
  • process_event (31-50)
  • process_event (31-31)
  • End (205-247)
  • End (205-205)
offline/framework/fun4all/SubsysReco.h (1)
  • SubsysReco (23-74)
calibrations/tpc/dEdx/GlobaldEdxFitter.h (1)
  • GlobaldEdxFitter (14-21)
calibrations/tpc/dEdx/GlobaldEdxFitter.h (1)
calibrations/tpc/dEdx/GlobaldEdxFitter.cc (34)
  • processResidualData (13-61)
  • processResidualData (13-13)
  • addTrack (63-67)
  • addTrack (63-63)
  • get_fitquality (148-211)
  • get_fitquality (148-148)
  • get_fitquality_new (69-146)
  • get_fitquality_new (69-69)
  • create_TF1 (277-281)
  • create_TF1 (277-277)
  • create_TF2 (283-287)
  • create_TF2 (283-283)
  • create_TF3_new (271-275)
  • create_TF3_new (271-271)
  • get_minimum (316-323)
  • get_minimum (316-316)
  • get_minimum_new (289-314)
  • get_minimum_new (289-289)
  • get_minimum_ZS (325-333)
  • get_minimum_ZS (325-325)
  • get_betagamma (213-249)
  • get_betagamma (213-213)
  • graph_vsbetagamma (335-340)
  • graph_vsbetagamma (335-335)
  • graph_vsp (342-346)
  • graph_vsp (342-342)
  • get_fitquality_functor (251-254)
  • get_fitquality_functor (251-251)
  • get_fitquality_wrapper (256-259)
  • get_fitquality_wrapper (256-256)
  • get_fitquality_wrapper_ZS (261-264)
  • get_fitquality_wrapper_ZS (261-261)
  • get_fitquality_wrapper_new (266-269)
  • get_fitquality_wrapper_new (266-266)
calibrations/tpc/dEdx/GlobaldEdxFitter.cc (1)
calibrations/tpc/dEdx/bethe_bloch.h (2)
  • bethe_bloch_new_1D (48-53)
  • bethe_bloch_total (66-71)
🪛 Clang (14.0.6)
calibrations/tpc/dEdx/dEdxFitter.h

[error] 4-4: 'fun4all/SubsysReco.h' file not found

(clang-diagnostic-error)

calibrations/tpc/dEdx/bethe_bloch.h

[error] 4-4: 'TMath.h' file not found

(clang-diagnostic-error)

🔇 Additional comments (1)
calibrations/tpc/dEdx/bethe_bloch.h (1)

1-208: Previous review concerns addressed

The inline keyword has been added to all function definitions, resolving the ODR violation. The TMath.h include now uses angle brackets. The static analyzer warning about TMath.h not found is a false positive—ROOT headers are resolved via the build system's include paths (typically $(ROOTSYS)/include).

Physics constants and Bethe-Bloch formulations look appropriate for sPHENIX TPC gas mixture calibration.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +53 to +57
void dEdxFitter::process_tracks(PHCompositeNode *topNode)
{

for(const auto &[key, track] : *_trackmap)
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Guard against missing node pointers before dereference.

process_tracks() iterates _trackmap and calls helpers that dereference _clustermap, _geometry, _tpcgeom, and _vertexmap even when GetNodes() failed (it only logs). This can crash on runs with missing nodes. Add a fast-fail guard before the loop.

Proposed fix
 void dEdxFitter::process_tracks(PHCompositeNode *topNode)
 {
+  if(!_trackmap || !_clustermap || !_geometry || !_tpcgeom || !_vertexmap)
+  {
+    if(Verbosity()>0)
+    {
+      std::cout << PHWHERE << " missing required nodes, skipping event" << std::endl;
+    }
+    return;
+  }
 
   for(const auto &[key, track] : *_trackmap)
   {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void dEdxFitter::process_tracks(PHCompositeNode *topNode)
{
for(const auto &[key, track] : *_trackmap)
{
void dEdxFitter::process_tracks(PHCompositeNode *topNode)
{
if(!_trackmap || !_clustermap || !_geometry || !_tpcgeom || !_vertexmap)
{
if(Verbosity()>0)
{
std::cout << PHWHERE << " missing required nodes, skipping event" << std::endl;
}
return;
}
for(const auto &[key, track] : *_trackmap)
{

Comment on lines +256 to +259
double GlobaldEdxFitter::get_fitquality_wrapper(double* x, double* par)
{
return get_fitquality(x[0]);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing second argument in get_fitquality call

get_fitquality_wrapper passes only x[0] to get_fitquality(double norm, double ZS_loss), which requires two parameters. This will either fail to compile or invoke undefined behavior if there's a declaration mismatch.

Proposed fix

If ZS_loss should default to zero when using this wrapper:

 double GlobaldEdxFitter::get_fitquality_wrapper(double* x, double* par)
 {
-  return get_fitquality(x[0]);
+  return get_fitquality(x[0], 0.0);
 }

Alternatively, if par should supply ZS_loss:

 double GlobaldEdxFitter::get_fitquality_wrapper(double* x, double* par)
 {
-  return get_fitquality(x[0]);
+  return get_fitquality(x[0], par[0]);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
double GlobaldEdxFitter::get_fitquality_wrapper(double* x, double* par)
{
return get_fitquality(x[0]);
}
double GlobaldEdxFitter::get_fitquality_wrapper(double* x, double* par)
{
return get_fitquality(x[0], par[0]);
}

Comment on lines +300 to +314
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];
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Use-after-free: accessing minimizer result after deletion

minimizer->X() returns a pointer to internal storage owned by the minimizer. Deleting the minimizer at line 312 invalidates xs, so reading xs[0] at line 313 is undefined behavior.

Proposed fix
   minimizer->Minimize();
   const double *xs = minimizer->X();
+  const double result = xs[0];
   delete minimizer;
-  return xs[0];
+  return result;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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];
}
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();
const double result = xs[0];
delete minimizer;
return result;
}

@sphenix-jenkins-ci
Copy link
Copy Markdown

Build & test report

Report for commit 8cbb1765262ad38a115da7eb771819a1fb82cc37:
Jenkins on fire


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@osbornjd
Copy link
Copy Markdown
Contributor

I added this new package to the build list. However, I don't have permission to push to your fork since you forked from Christof's coresoftware instead of the sPHENIX coresoftware, so can you push a commit to re-trigger jenkins now that this package is actually in the build?

Copy link
Copy Markdown
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: 2

♻️ Duplicate comments (3)
calibrations/tpc/dEdx/dEdxFitter.cc (1)

53-57: Guard against missing nodes before dereferencing.

GetNodes() only logs; process_tracks() immediately dereferences _trackmap, _clustermap, _geometry, _tpcgeom, and _vertexmap. If any are missing, this will crash the job.

Proposed fix
 void dEdxFitter::process_tracks()
 {
+  if(!_trackmap || !_clustermap || !_geometry || !_tpcgeom || !_vertexmap)
+  {
+    if(Verbosity()>0)
+    {
+      std::cout << PHWHERE << " missing required nodes, skipping event" << std::endl;
+    }
+    return;
+  }
 
   for(const auto &[key, track] : *_trackmap)
   {
calibrations/tpc/dEdx/GlobaldEdxFitter.cc (2)

40-53: Prevent out‑of‑range GetEntry when skip exceeds available entries.

The loop only breaks on entry == total_entries, so skip > total_entries still calls GetEntry on invalid entries and can reuse stale data.

Proposed fix
   size_t total_entries = t->GetEntriesFast();
 
-  for(size_t entry=skip; entry<(skip+ntracks); entry++)
+  const size_t end_entry = (skip + ntracks < total_entries) ? (skip + ntracks) : total_entries;
+  for(size_t entry = skip; entry < end_entry; ++entry)
   {
-    if(entry==total_entries)
-    {
-      break;
-    }
     if(entry % 1000 == 0)
     {
       std::cout << entry << std::endl;
     }

300-313: Avoid use‑after‑free of the minimizer result.

minimizer->X() returns internal storage owned by the minimizer; deleting it before copying the value makes xs invalid.

Proposed fix
   minimizer->Minimize();
   const double *xs = minimizer->X();
+  const double bestA = xs[0];
   delete minimizer;
-  return xs[0];
+  return bestA;

Comment on lines +4 to +13
#include <fun4all/SubsysReco.h>
#include <string>
#include <trackbase_historic/SvtxTrackMap.h>
#include <trackbase/TrkrClusterContainer.h>
#include <trackbase/ActsGeometry.h>
#include <g4detectors/PHG4TpcGeomContainer.h>
#include <globalvertex/SvtxVertexMap.h>

#include "GlobaldEdxFitter.h"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add missing STL includes to keep this public header self‑contained.

The header uses std::unique_ptr, std::vector, std::tuple, and size_t but doesn’t include their headers, which can break downstream compile order.

Proposed fix
 `#include` <fun4all/SubsysReco.h>
 `#include` <string>
+#include <cstddef>
+#include <memory>
+#include <tuple>
+#include <vector>
 `#include` <trackbase_historic/SvtxTrackMap.h>
 `#include` <trackbase/TrkrClusterContainer.h>
 `#include` <trackbase/ActsGeometry.h>
 `#include` <g4detectors/PHG4TpcGeomContainer.h>
 `#include` <globalvertex/SvtxVertexMap.h>
🧰 Tools
🪛 Clang (14.0.6)

[error] 4-4: 'fun4all/SubsysReco.h' file not found

(clang-diagnostic-error)

Comment on lines +1 to +13
#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"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make GlobaldEdxFitter.h self‑contained by adding STL includes.

This header uses std::string, std::vector, std::pair, and size_t without including their headers, which can fail in downstream TUs.

Proposed fix
 `#ifndef` GLOBALDEDXFITTER_H
 `#define` GLOBALDEDXFITTER_H
 
+#include <cstddef>
+#include <string>
+#include <utility>
+#include <vector>
+
 `#include` "bethe_bloch.h"
 `#include` "TF1.h"
 `#include` "TF2.h"
 `#include` "TF3.h"
 `#include` "TChain.h"
 `#include` "TGraph.h"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#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"
`#ifndef` GLOBALDEDXFITTER_H
`#define` GLOBALDEDXFITTER_H
`#include` <cstddef>
`#include` <string>
`#include` <utility>
`#include` <vector>
`#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"

@sphenix-jenkins-ci
Copy link
Copy Markdown

Build & test report

Report for commit 0296552dac10e4de6182cf5c8138940d1297436e:
Jenkins on fire


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@sphenix-jenkins-ci
Copy link
Copy Markdown

Build & test report

Report for commit 9a19bb92da1535491aeb611f05c6161932b82d11:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@osbornjd osbornjd merged commit 8912872 into sPHENIX-Collaboration:master Jan 23, 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