Skip to content

CM Distortion dPhi vs R*dPhi#4184

Open
bkimelman wants to merge 6 commits intosPHENIX-Collaboration:masterfrom
bkimelman:laserClusterTuning
Open

CM Distortion dPhi vs R*dPhi#4184
bkimelman wants to merge 6 commits intosPHENIX-Collaboration:masterfrom
bkimelman:laserClusterTuning

Conversation

@bkimelman
Copy link
Contributor

@bkimelman bkimelman commented Feb 18, 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, ...)

Added toggles to swap phi distortion generated by lamination fitting and stripe matching between dPhi and RdPhi. Originally was just RdPhi, but it has been agreed to use dPhi instead. Toggle defaults to storing dPhi, but can be switched using setter function.

TODOs (if applicable)

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

This PR adds runtime toggles to control whether central membrane (CM) phi distortions are represented/stored as dPhi (angle in radians) or as R*dPhi (radial-scaled angle), and adds an option to save all lamination-fitting histograms. The default is to treat phi histograms as radians (store dPhi).

Motivation / context

  • CM laser calibration produces azimuthal distortion maps used for TPC space-charge and cluster corrections. Historically maps were stored as R*dPhi; storing pure dPhi reduces ambiguity, aligns with analysis conventions, and simplifies downstream interpretation and metadata handling.

Key changes

  • New public setters:
    • TpcCentralMembraneMatching::set_phiHistInRad(bool)
    • TpcLaminationFitting::set_phiHistInRad(bool)
    • TpcLaminationFitting::set_saveAllLaminationHistograms(bool)
  • New private flags (defaults shown):
    • bool m_phiHist_in_rad{true} in TpcCentralMembraneMatching and TpcLaminationFitting (default true → treat histograms as radians → store dPhi)
    • bool m_saveAllLaminationHistograms{false} in TpcLaminationFitting
  • Behavior changes:
    • TpcLaminationFitting::InterpolatePhiDistortions and TpcCentralMembraneMatching interpolation/aggregation now branch on m_phiHist_in_rad: if true, interpolated phi distortions are treated as dPhi (no multiply by R); if false, legacy R*dPhi scaling is applied.
    • GetNodes / container initialization now create TpcDistortionCorrectionContainer histograms consistent with the m_phiHist_in_rad flag.
    • End() in TpcLaminationFitting can optionally write all 18×2 lamination histograms when m_saveAllLaminationHistograms is true; default remains to write only selected histograms.
  • API impact: only new setters/flags added; no changes to existing public method signatures.

Potential risk areas

  • IO / format metadata: Distortion maps written to ROOT/nodes have different units depending on the flag. Consumers assuming legacy R*dPhi will apply incorrect corrections unless the flag/metadata are handled consistently.
  • Reconstruction behavior: Mixing or reusing maps produced with different settings (dPhi vs R*dPhi) will change distortion magnitudes by ~O(R) and can materially alter corrected cluster positions—validate against baseline reconstructions.
  • Data consistency & provenance: Combining maps from different runs/settings can introduce systematic biases unless representation is tracked in filenames/metadata.
  • Testing coverage: New branching increases surface area; ensure calibration macros and regression/unit tests exercise both representations.
  • Thread-safety / performance: Changes are per-instance boolean branches with no apparent shared-state modification; no obvious thread-safety issues or measurable perf regression, but verify in multi-threaded workflows.

Possible future improvements

  • Embed explicit unit metadata (dPhi vs R*dPhi) in output files/ROOT nodes so downstream consumers can detect format automatically.
  • Add conversion utilities to migrate legacy R*dPhi maps ↔ dPhi for compatibility.
  • Centralize unit/metadata handling in TpcDistortionCorrectionContainer to remove per-module branching and reduce duplication.
  • Add unit/regression tests and example macros demonstrating both modes and validation procedures.
  • Add runtime QA/logging to report active mode and check distortion magnitudes for sanity.

Important note

  • This summary was produced with AI-assisted code inspection. The AI can make mistakes or miss affected call sites—please verify all histogram fill/interpolation locations, container usage, calibration macros, and downstream consumers before release.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds configurable flags to treat phi histograms as radians and to control lamination-histogram output; interpolation, DP aggregation, and distortion-container initialization now branch on the phi-units flag to decide whether phi distortions are multiplied by radius.

Changes

Cohort / File(s) Summary
Headers: config setters
offline/packages/tpccalib/TpcCentralMembraneMatching.h, offline/packages/tpccalib/TpcLaminationFitting.h
Added set_phiHistInRad(bool) and private m_phiHist_in_rad{true} to both classes; added set_saveAllLaminationHistograms(bool) and m_saveAllLaminationHistograms{false} to TpcLaminationFitting.
Central membrane matching logic
offline/packages/tpccalib/TpcCentralMembraneMatching.cc
DP interpolation (per-bin, end-of-event aggregation) and distortion-container initialization now branch on m_phiHist_in_rad: when true use interpolated dPhi directly (no R multiplier); when false preserve prior multiply-by-RVal behavior. m_phi_hist_in_radians initialization set from m_phiHist_in_rad, m_interpolate_z set false.
Lamination fitting interpolation & output
offline/packages/tpccalib/TpcLaminationFitting.cc
InterpolatePhiDistortions multiplies phiDistortion by R only when m_phiHist_in_rad is false. End writes all 18x2 lamination histograms only if m_saveAllLaminationHistograms is true; otherwise writes the original subset. Minor formatting edits.

Possibly related PRs

  • CM Distortion Updates #4169: Modifies phi-distortion interpolation and dPhi scaling logic in the same TPC calibration components, overlapping the changes here.
✨ 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: 2

Caution

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

⚠️ Outside diff range comments (1)
offline/packages/tpccalib/TpcCentralMembraneMatching.cc (1)

2879-2889: ⚠️ Potential issue | 🟠 Major

m_dcc_out_aggregated never inherits m_phi_hist_in_radians or m_interpolate_z — this is the container persisted to file.

m_dcc_out (lines 2879–2880) correctly receives both flags when initially created. However, m_dcc_out_aggregated is unconditionally re-created at line 2889 with reset(new TpcDistortionCorrectionContainer) and never has these flags assigned. The shared initialization loop at lines 2932–2954 only sets m_dimensions = 2.

The problem manifests at lines 2664–2665, where histogram fill logic checks m_phiHist_in_rad (a member variable) to decide scaling:

  • If m_phiHist_in_rad = false: histograms store raw dPhi, code multiplies by R before storage
  • If m_phiHist_in_rad = true: histograms store dPhi/R

When m_dcc_out_aggregated is persisted and later loaded from CMDistortionCorrections.root, downstream consumers read m_dcc_out_aggregated->m_phi_hist_in_radians to decide correction application. Since this field defaults to true and is never overwritten, downstream code will misinterpret histograms filled with raw dPhi (when m_phiHist_in_rad = false), applying corrections incorrectly — a silent physics error.

Additionally, m_interpolate_z defaults to true but should match m_dcc_out and be set to false.

🐛 Proposed fix
  m_dcc_out_aggregated.reset(new TpcDistortionCorrectionContainer);
+ m_dcc_out_aggregated->m_phi_hist_in_radians = m_phiHist_in_rad;
+ m_dcc_out_aggregated->m_interpolate_z = false;

Alternatively, consolidate both assignments into the shared initialization loop to prevent future omissions:

  for (const auto& dcc : {m_dcc_out, m_dcc_out_aggregated.get()})
  {
    dcc->m_dimensions = 2;
+   dcc->m_phi_hist_in_radians = m_phiHist_in_rad;
+   dcc->m_interpolate_z = false;
    // create all histograms …
  }

(Remove the individual assignments at lines 2879–2880.)

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;
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

🧩 Analysis chain

🏁 Script executed:

rg -n "m_interpolate_z" --type cpp -C 4

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 6813


🏁 Script executed:

# Look at the context in TpcCentralMembraneMatching.cc around line 2880
sed -n '2860,2890p' offline/packages/tpccalib/TpcCentralMembraneMatching.cc

# Check recent git history for context
git log --oneline -20 offline/packages/tpccalib/TpcCentralMembraneMatching.cc 2>/dev/null || echo "Git history unavailable"

# Search for any comments or documentation about CM and z-interpolation
rg -n "central.{0,30}membran|CM.*distortion" --type cpp -i -A 2 -B 2 | head -50

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 5887


🏁 Script executed:

# Check if there are any comments in the code explaining the CM distortion assumption
sed -n '2850,2885p' offline/packages/tpccalib/TpcCentralMembraneMatching.cc | cat -n

# Look for any documentation about why CM produces 2D corrections
rg -n "fluctuation.*2d|2d.*fluct|dimensions.*2" --type cpp offline/packages/tpccalib/TpcCentralMembraneMatching.cc -B 2 -A 2 | head -40

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 2458


Confirm the PR description documents this z-interpolation change and its analysis impact.

The m_interpolate_z = false assignment is intentional and physically justified. The code comment at line 2934 explicitly states that CM-derived corrections are 2D because "central membrane flashes only provide distortions at z = 0". Setting m_interpolate_z = false logically follows: since the correction has no z-dependence information, applying z-interpolation to zero at readout would be meaningless.

However, this is still a reconstruction behavior change affecting downstream analyses. Per standard practices, the PR description should document the expected impact on analysis outputs and whether reprocessing of existing data is required.


void set_ppMode(bool mode){ ppMode = mode; }

void set_phiHistInRad(bool rad){ m_phiHist_in_rad = rad; }
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

🧩 Analysis chain

🏁 Script executed:

rg -n "m_phiHist_in_rad" --type cpp -C 3

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 5757


🏁 Script executed:

fd "TpcLaminationFitting\.cc" --type f

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 127


Remove set_phiHistInRad() and the unused member m_phiHist_in_rad from TpcLaminationFitting.

The member declared at line 126 and setter at line 53 are never read in TpcLaminationFitting.cc, making the setter a silent no-op. Users calling set_phiHistInRad() will believe they are configuring the module's phi unit handling, but the flag has no effect. Similar members in TpcCentralMembraneMatching are actively used (e.g., conditional logic at lines 2354, 2664, 2671), so this appears to be dead code that should be removed to prevent user misconfiguration.

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.

Caution

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

⚠️ Outside diff range comments (1)
offline/packages/tpccalib/TpcLaminationFitting.cc (1)

756-768: ⚠️ Potential issue | 🟡 Minor

Verify that PR description documents the change in calibration output format and reprocessing implications.

The code change itself is technically sound: line 757 conditionally scales phiDistortion by R based on the m_phiHist_in_rad flag, and both TpcLaminationFitting and TpcCentralMembraneMatching consistently:

  • Use the same flag with the same default (true)
  • Store histogram values matching the flag setting (dPhi if true; R·dPhi if false)
  • Set the container metadata m_phi_hist_in_radians accordingly
  • Properly document the format choice for downstream consumers

The downstream code (TpcDistortionCorrection.cc) correctly adapts based on this container flag, using divisor = 1 when the flag is true (radians) and divisor = r otherwise (cm), so there is no silent format inconsistency.

However, per the learnings context: this PR changes the default calibration output format (from m_phiHist_in_rad = false would imply prior R·dPhi storage, to the new default true storing bare dPhi). The PR description should explicitly state:

  • The new default behavior and what it means for calibration constants
  • Whether previously processed data must be reprocessed
  • Any impact on analysis workflows expecting the old format

@sphenix-jenkins-ci
Copy link

Build & test report

Report for commit e6f71b22a33bb163edd8326a3f78f45691d11e3d:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@sphenix-jenkins-ci
Copy link

Build & test report

Report for commit 5951a0eb5ca60474018159618df5b8ec84041721:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

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.

Caution

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

⚠️ Outside diff range comments (1)
offline/packages/tpccalib/TpcCentralMembraneMatching.cc (1)

2897-2907: ⚠️ Potential issue | 🔴 Critical

m_dcc_out_aggregated never receives m_phi_hist_in_radians or m_interpolate_z initialization.

m_dcc_out is correctly configured at lines 2897–2898. But m_dcc_out_aggregated is unconditionally re-created at line 2907 and the shared loop at lines 2950–2953 only sets m_dimensions = 2. The missing flags will default to m_phi_hist_in_radians = true and m_interpolate_z = true.

The problem manifests at lines 2670–2690, where histograms are populated into m_dcc_out_aggregated using the local m_phiHist_in_rad flag to decide whether to apply R-scaling (multiply by RVal if false, skip if true). However, downstream consumers that read this container object will query its m_phi_hist_in_radians flag—which will have the wrong default value—and apply opposite scaling, corrupting the corrections.

Move both flags into the shared loop to ensure consistency:

🔧 Proposed fix
  for (const auto& dcc : {m_dcc_out, m_dcc_out_aggregated.get()})
  {
    // set dimensions to 2, since central membrane flashes only provide distortions at z = 0
    dcc->m_dimensions = 2;
+   dcc->m_phi_hist_in_radians = m_phiHist_in_rad;
+   dcc->m_interpolate_z = false;

    // create all histograms
    for (int i = 0; i < 2; ++i)
    {

…ired. Will be off by default, but allows for more in-depth QA
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: 1

Comment on lines +757 to +760
if(!m_phiHist_in_rad)
{
phiDistortion *= R;
}
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

🧩 Analysis chain

🏁 Script executed:

fd "TpcDistortionCorrection" --type f

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 228


🏁 Script executed:

rg -n "m_hDPint|hDPint|DPint" --type cpp -C 3 | head -100

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 9481


🏁 Script executed:

rg -n "get_corrected_position" --type cpp -A 20 -B 2 | head -150

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 13348


🏁 Script executed:

rg -n "phiHist_in_rad|phiHistInRad|set_phiHistInRad" --type cpp

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 969


🏁 Script executed:

sed -n '70,120p' offline/packages/tpc/TpcDistortionCorrection.cc

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 1642


🏁 Script executed:

rg -n "m_phi_hist_in_radians|divisor" offline/packages/tpc/TpcDistortionCorrection.cc

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 305


🏁 Script executed:

cat -n offline/packages/tpc/TpcDistortionCorrectionContainer.h | head -60

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 1738


🏁 Script executed:

rg -n "m_dcc_out\|m_dcc_in" offline/packages/tpccalib/TpcLaminationFitting.cc | grep -E "(set_phiHistInRad|m_phi_hist_in_radians)" | head -5

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 60


🏁 Script executed:

git log --oneline -1 --format="%B" 2>/dev/null | head -20 || echo "PR description not directly accessible in repo context"

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 209


PR description must document the default calibration output unit change and reprocessing implications.

The code change itself is internally consistent—the container flag m_phi_hist_in_radians is explicitly set by TpcLaminationFitting and TpcCentralMembraneMatching, and TpcDistortionCorrection::get_corrected_position() reads this flag to apply the correct divisor (1.0 for dPhi [rad], or r for R·dPhi [cm·rad]). However, the PR description states only "Added toggle to save all lamination fitting histograms to file if desired. Will be off by default, but allows for more in-depth QA"—it omits the critical default behavior change.

With m_phiHist_in_rad{true} as the new default, existing calibration files containing R·dPhi (generated with the old default) will be misinterpreted by new code if the container flag is not preserved in saved files. Conversely, new calibrations with dPhi will be wrong if used with legacy analysis expecting R·dPhi.

Before merging, the PR description must explicitly state:

  1. The default output unit change (R·dPhi → dPhi)
  2. Whether existing calibration files must be regenerated
  3. Impact on downstream reconstruction and analysis

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: 1

Comment on lines +1224 to +1229
else
{
m_hLamination[13][0]->Write();
m_hLamination[13][1]->Write();
m_hLamination[14][1]->Write();
}
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

m_hLamination[14][0] (South side, lamination index 14) is missing from the default-save else branch.

The else path writes both sides of index 13 and only the North side ([14][1]) of index 14. m_hLamination[14][0] (South) is silently dropped. If the intent—consistent with the AI summary—is to save both indices 13 and 14 for both sides, this is an omission.

🐛 Proposed fix
  m_hLamination[13][0]->Write();
  m_hLamination[13][1]->Write();
+ m_hLamination[14][0]->Write();
  m_hLamination[14][1]->Write();

@sphenix-jenkins-ci
Copy link

Build & test report

Report for commit 008a0128e539b7b359faee88b9910ccc12d875c0:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

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.

1 participant

Comments