Skip to content

Add ALCARECO skims (KS, Lambda, D*, J/psi, Upsilon, Z) and persist resonance candidates#45

Open
davidwalter2 wants to merge 17 commits into
WMass:AlCaRecoProd_10_6_17_patch1from
davidwalter2:from-CMSSW_10_6_17_patch1
Open

Add ALCARECO skims (KS, Lambda, D*, J/psi, Upsilon, Z) and persist resonance candidates#45
davidwalter2 wants to merge 17 commits into
WMass:AlCaRecoProd_10_6_17_patch1from
davidwalter2:from-CMSSW_10_6_17_patch1

Conversation

@davidwalter2

@davidwalter2 davidwalter2 commented May 5, 2026

Copy link
Copy Markdown

Summary

Adds ALCARECO skims for the muon-momentum-scale calibration covering V0
(KS, Lambda), three-body (D*), dimuon (J/psi, Upsilon, Z) and J/psi+X
(B-meson / quarkonium) channels, and persists a
reco::VertexCompositeCandidateCollection per stream so downstream
consumers can iterate the candidates and follow daughter TrackRefs into
the cloned ALCAReco track collection without going back to generalTracks:

  • TkAlKsToPiPi — V0 (KS → π⁺π⁻)
  • TkAlLambdaToProtonPi — V0 (Λ → pπ⁻)
  • TkAlDstToD0Pi — D*⁺ → D⁰(K⁻π⁺) πs⁺ (three-track topology with a soft-pion tag)
  • TkAlJpsiMuMu, TkAlUpsilonMuMu, TkAlZMuMu — dimuon resonances (V0-pattern: candidate is built upstream by TwoBodyDecayCandidateProducer)
  • TkAlJpsiX — 8 channels: B⁺ → J/ψK⁺, B⁰ → J/ψK*⁰, B⁰ → J/ψKs, Bs → J/ψφ, Λb → J/ψΛ, ψ(2S) → J/ψπ⁺π⁻, Bc⁺ → J/ψπ⁺, plus a J/ψ-only channel on a loose muon selection

Each skim stores the daughter tracks (cloned, with hits + clusters) and
publishes *Resonances candidate collections with daughter TrackRefs
into the cloned tracks. Selection cuts (mass window, charge, V0 Lxy /
cosθXY) are applied at the candidate-builder level.

What's in this PR

16 commits on top of 6e29f933a55, in three blocks:

Block 1 — V0 / D* / dimuon skims + resonance persistence (commits 1–6)

  1. 0960cf87c4f — Infrastructure for TkAlDstToD0Pi (Elisabetta Manca): three-body decay selector module + ALCARECO cff + validation analyzer
  2. 37b68d22f1f — Removes the validation analyzer (kept the selector)
  3. 3149b4a77a1 — Removes HLT preselection so the ALCARECO is usable across triggers
  4. 1d2bf1a7599 — Adds TkAlKsToPiPi + TkAlLambdaToProtonPi V0 skims via AlignmentTracksFromV0Selector
  5. c932a392d9d — Replaces AlignmentTracksFromV0Selector with V0DaughterTrackProducer (extracts daughter tracks from a private ALCARECOTkAlV0Candidates collection — a clone of generalV0Candidates with a lower track-pT cut, leaving the standard reco V0 collection untouched). Adds optional per-track dE/dx ValueMap projection (strip / pixel / joint Harmonic-2) for downstream particle-ID.
  6. df64a66c5fb — Persists the resonance-candidate collection for every stream and adds dimuon streams (J/psi, Upsilon, Z) on the V0 pattern.

Block 2 — output format (commit 7)

  1. b8ebaa3d9f2 — Writes ALCARECO PoolOutputModules at ROOT split level 1 (alcarecoSplitLevel.py customise) so 10_6-produced files stay readable in CMSSW ≥ 15_0 (works around ROOT Replace boost with standard library equivalents cms-sw/cmssw#19773: v11→v14 SiStripCluster schema-evolution read rule not firing on fully-split branches).

Block 3 — TkAlJpsiX stream (commits 8–16, Pietro Lugato)

  1. 4d65009c736 — registers TkAlJpsiX in central AlCa (autoAlca.py: Charmonium, MuOniaParked; AlCaRecoStreams_cff.py, AlCaRecoOutput_cff.py)
  2. 86af90df597 — helix propagation of daughter tracks to a candidate-level common point + more TwoBodyDecayCandidateProducer options
  3. 5952d2d08bb — BuildFile dependencies for the J/psi+X producers (KinematicFit, TransientTrack, …)
  4. e20a850141fCompositeDaughterTrackProducer: merged, deduplicated leaf-track collection across all channels
  5. 04efb4538e5JpsiXCandidateProducer covering all 7 J/psi+X decay channels (track mode for B⁺/Bc, VCC mode for nested resonances)
  6. c560219c6bf — TkAlJpsiX output module keep/drop list
  7. 026705dd9ec — cff wiring of the 7 channels, V0 clone with reduced pT floor, per-channel remappers
  8. 420fe8859d8 — persists muon info (ALCARECOTkAlJpsiXLooseMuons + AlignmentTrackToMuonAssociator track→muon association), adds the J/ψ-only channel on a loose muon ID, fixes the bachelor-eta cut, and rewires ψ(2S) to prompt π⁺π⁻ (was incorrectly sourced from the displaced V0 Ks output)
  9. e77e7e0a5a6 — requires high-purity tracks (D*) and per-daughter pT thresholds

Commit 6 details

  • TwoBodyDecayCandidateProducer: builds a VertexCompositeCandidateCollection from opposite-sign track pairs in a configurable mass window, with optional muon-ID prefilter via muonSrc. Replaces the in-AlignmentTrackSelector pair finding for the dimuon streams; daughters use V0Producer's positive-charge-first convention.
  • AlignmentTrackSelectorWithIndexMapModule: drop-in replacement for AlignmentTrackSelectorModule that, alongside the standard cloned Track + TrackExtra + RecHit + Cluster outputs, emits an edm::ValueMap<unsigned int> (instance label originalIndex) of source-collection indices computed by pointer arithmetic on the selector chain's Track* output. No kinematic fingerprinting. Required because helper::TrackCollectionStoreManager::processTrack rewrites the cloned tracks' TrackExtraRefs to a fresh sequential key, destroying the link to generalTracks.
  • VertexCompositeCandidateRemapper: rewrites each candidate's daughter TrackRefs to point at the cloned ALCAReco track collection via the originalIndex ValueMap chain (selH idx → intermediateTracks idx → intermediateTracks.extra().key() = generalTracks idx). Recurses into nested composites (e.g. for B → J/psi K).
  • Bug fix in DeDxValueMapProjector: previously used selectedTrack.extra().key() as the source-track index, but after TrackCollectionStoreManager's clone-and-store that key is just the position in the new collection (0,1,2,…). The persisted dE/dx values for V0 / D* daughters were therefore values of unrelated generalTracks[j] entries. Switched to the same originalIndex chain.
  • All six streams' cffs rewired to publish a *Resonances VertexCompositeCandidateCollection alongside the cloned-track output; the corresponding _Output_cff.py files keep the new products.
  • Adds recoskim_Run2016G_SingleMuon_AllResonances.py covering all streams in a single test job; removes the older partial test configs (Dst, KsLambda, KsLambdaDst).

TkAlJpsiX details (block 3)

Five-stage single-sequence architecture (ALCARECOTkAlJpsiX_cff.py):
DCS filter + muon selectors → shared candidate construction (J/ψ, V0s, K*⁰, φ, π⁺π⁻) → 8 per-channel JpsiXCandidateProducer / TwoBodyDecayCandidateProducer instances → merged deduplicated leaf-track collection (CompositeDaughterTrackProducer) → AlignmentTrackSelectorWithIndexMap cloning + 3 dE/dx projectors → 8 per-channel VertexCompositeCandidateRemappers. The persisted output is a single deduplicated cloned-track collection + 8 remapped candidate collections + persisted loose muons + a track→muon edm::Association.

  • JpsiXCandidateProducer: two modes — track (bachelor from generalTracks; B⁺, Bc) and vcc (second VertexCompositeCandidate; B⁰, Bs, Λb, ψ(2S)). Dimuon (and X-pair) 4-momenta are helix-propagated to their pair PCA before the mass calculation (removes an O(1–3 MeV) ctau-correlated bias at displaced vertices). Optional J/ψ mass constraint and B-level KinematicConstrainedVertexFitter fit with vertex-prob / pointing-angle / Lxy-significance cuts.
  • Selection presets A / B / C (mass-windows-only / Phase-1-locked kinematic cuts / + B-level Kalman vertex fit) selected via the TKALJPSIX_SELECTION_PRESET env var at python-load time; default B.
  • The shared ALCARECOTkAlV0Candidates clone loosens vertex-quality and IP-significance cuts (vtxChi2Cut 6.63→15, vtxDecaySigXYCut 15→10, cosThetaXYCut 0.998→0.995, tkIPSigXYCut 2→1) on top of the pT floor 0.35→0.1 GeV, for the alignment use case only.

New plugins

  • Alignment/CommonAlignmentProducer/plugins/V0DaughterTrackProducer.cc — KS / Λ daughter extraction
  • Alignment/CommonAlignmentProducer/src/AlignmentThreeBodyDecayTrackSelector.cc — D* daughter selection (used by the existing AlignmentTrackSelectorModule)
  • Alignment/CommonAlignmentProducer/plugins/DeDxValueMapProjector.cc — per-track dE/dx ValueMap projector (ref-based via originalIndex)
  • Alignment/CommonAlignmentProducer/plugins/TwoBodyDecayCandidateProducer.cc — two-track candidate builder (dimuon, K*⁰, φ, π⁺π⁻; asymmetric mass hypotheses, optional Kalman vertex fit, track-track DOCA cut)
  • Alignment/CommonAlignmentProducer/plugins/AlignmentTrackSelectorWithIndexMapModule.cc — selector + originalIndex ValueMap
  • Alignment/CommonAlignmentProducer/plugins/VertexCompositeCandidateRemapper.cc — candidate daughter-ref remapper
  • Alignment/CommonAlignmentProducer/plugins/JpsiXCandidateProducer.cc — J/ψ+X mother-candidate builder (7 channels)
  • Alignment/CommonAlignmentProducer/plugins/CompositeDaughterTrackProducer.cc — merged deduplicated leaf-track extraction from nested candidates
  • Alignment/CommonAlignmentProducer/plugins/AlignmentTrackToMuonAssociator.cc — cloned-track → reco::Muon association

New cff/cfi

  • ALCARECOTkAlV0Candidates_cff.py (private V0Producer clone, shared by V0 skims and TkAlJpsiX)
  • ALCARECOTkAl{KsToPiPi,LambdaToProtonPi,DstToD0Pi,JpsiMuMu,UpsilonMuMu,ZMuMu,JpsiX}_cff.py + each _Output_cff.py
  • alcaDedxJointEstimator_cfi.py
  • AlignmentTrackSelectorWithIndexMap_cfi.py
  • alcarecoSplitLevel.py (split-level-1 customise function)
  • TkAlLooseIdMuonSelector added to TkAlMuonSelectors_cfi.py

Plus updates to BuildFile.xml, AlCaRecoOutput_cff.py, AlCaRecoStreams_cff.py, AlignmentTrackSelector_cfi.py (new ThreeBodyDecaySelector PSet), and autoAlca.py.

Test plan

  • Build with scram b -j16 in CMSSW_10_6_17_patch1
  • Run on 1 RAW file (1000 events SingleMuon Run2016G + 1 file Charmonium); verify all six streams produce expected outputs and edmDumpEventContent shows the new *_*Resonances_*_* candidate branches
  • Verify candidate daughter TrackRefs resolve into the cloned ALCAReco track collection (100% id-match on the first candidate of every event across all streams)
  • Verify dE/dx values are physical (mean ~2.8 MeV/cm, sd ~1, broad value uniqueness — confirms the originalIndex-chain bug fix)
  • Larger production: 100 RAW Charmonium files (run 279654, ~50k events × 10 parallel jobs × 16 threads) — ~30 min wallclock
  • Stage-2 CVH 9-variant scan (KS, Λ, J/psi × no-vtx/vtx/vtx+pointing) on the 100-file ALCAReco — 9/9 success, J/psi mass peaks at 3.093 ± 0.068 GeV
  • Rebuild (scram b -j8) clean after merging the TkAlJpsiX commits (block 3)
  • TkAlJpsiX stream validation on RAW data (block 3 — @pmlugato)

Review fixes applied (commit 444b20f2062)

  • JpsiXCandidateProducer vcc mode: added the missing overlap veto between the J/ψ muon tracks and the X-candidate daughter tracks (track mode already had one via jpsiDaughterKeys). Previously a K*⁰/φ/π⁺π⁻ candidate reusing a J/ψ muon produced a duplicate-track mother candidate — the DOCA cut passed trivially (DOCA = 0) and, under preset C, the multi-track Kalman fit received the same track twice.
  • Daughter pdgId signs: hadrons now carry the sign of the track charge (K⁺ = +321; previously tagged -321 by the lepton convention); leptons unchanged (μ⁻ = +13). Sign is derived from the actual track charge, so same-sign pairs are self-consistent. ⚠️ Any downstream tooling matching on signed pdgId needs a corresponding update; |pdgId| (mass hypothesis) is unchanged.
  • VertexCompositeCandidateRemapper: remapped candidates now carry the source candidate's vertex covariance and fit χ²/ndof (previously dropped).
  • TwoBodyDecayCandidateProducer: KalmanVertexFitter::vertex() exception-guarded (a VertexException drops the pair instead of killing the job); dormant since applyVertexFit=False everywhere, but safe if enabled.
  • AlignmentThreeBodyDecayTrackSelector: end-of-job summary via MessageLogger instead of std::cout.
  • Stale ψ(2S) "V0-mode" comments corrected in ALCARECOTkAlJpsiX_cff.py.

Open items from review

  • The TKALJPSIX_SELECTION_PRESET env-var switch is convenient for private production but makes the cff non-reproducible from the config file alone; central AlCa integration would need it replaced by a cms.Parameter / customise function.
  • The J/ψ-only loose-muon channel is gated by the tight-muon event filter (ALCARECOTkAlJpsiXGoodMuons, filter=True), so events whose muons are all loose-only are not captured.

🤖 Generated with Claude Code

emanca and others added 6 commits March 27, 2026 06:34
…sFromV0Selector

Adds two ALCARECO streams for tracker alignment using KS->pi+pi- and
Lambda0->p pi- decays, plus a new EDFilter (AlignmentTracksFromV0Selector)
that extracts the unique daughter tracks from generalV0Candidates and stores
them with their hits and clusters via the standard alignment
helper::TrackCollectionStoreManager machinery.

The selector follows the ObjectSelectorStream<> pattern of
AlignmentTrackSelectorModule: a small selector struct with a select() method
is wrapped via a typedef, inheriting all five produces<>() calls
(TrackCollection + TrackExtras + TrackingRecHits + Strip/Pixel clusters)
from helper::TrackSelectorBase and the cloneAndStore + put() flow from the
StoreManagerTrait specialization. This avoids the combinatorial track-pair
search done by AlignmentTwoBodyDecayTrackSelector when run on the full
generalTracks collection, and ensures every V0Producer-accepted candidate's
daughter tracks are preserved -- no raw vs. post-fit mass-window mismatch.

Output cff also keeps generalTracks, dedxHarmonic2, dedxPixelHarmonic2 and
dedxHitInfo so the dE/dx ValueMaps remain resolvable for V0 daughter tracks
via candidate.daughter().get().track().

Event-level pre-filter is a CandViewCountFilter on generalV0Candidates
(>=1 candidate); track-level cuts are inherited from V0Producer. No HLT
trigger requirement so the streams are usable for any physics channel
(W/Z+V0, Psi(2S)->J/psi KS via dimuon HLT, inclusive V0 production, ...).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Replaces the previous AlignmentTracksFromV0Selector approach with a small
EDProducer V0DaughterTrackProducer that extracts the unique daughter tracks
from a private V0Candidates collection (ALCARECOTkAlV0Candidates, a clone
of generalV0Candidates with a lower track-pT threshold). This keeps the
standard reco V0 collection untouched.

Adds a new EDProducer DeDxValueMapProjector that re-keys per-track dE/dx
ValueMap<DeDxData> products from the generalTracks-keyed source onto the
selected (cloned) ALCARECO track collection via TrackExtraRef.key(),
emitting ValueMap<float> with just the dEdx scalar. Three projector
instances per skim cover dedxHarmonic2 (strip), dedxPixelHarmonic2 (pixel)
and a new joint strip+pixel Harmonic2-truncated estimator
(alcaDedxJointEstimator, equivalent to dedxPixelAndStripHarmonic2T085 from
RecoTracker/DeDx/python/dedxEstimators_cff.py).

Output_cff for KS, Lambda and D* now keep the three projected dE/dx
ValueMaps. The full generalTracks collection and original dE/dx maps are
no longer needed in the ALCARECO output.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Adds three plugins (Alignment/CommonAlignmentProducer/plugins/):

- TwoBodyDecayCandidateProducer: builds a VertexCompositeCandidateCollection
  from opposite-sign track pairs in a configurable mass window, with optional
  muonSrc filter. Replaces the in-AlignmentTrackSelector pair finding for
  the dimuon ALCARECOs (J/psi, Upsilon, Z) so the candidate object can be
  persisted. Daughters use V0Producer's positive-charge-first convention.
- AlignmentTrackSelectorWithIndexMapModule: drop-in replacement for
  AlignmentTrackSelectorModule that, alongside the standard cloned tracks +
  extras + hits + clusters, emits an edm::ValueMap<unsigned int> (instance
  label "originalIndex") whose value at each cloned track is its index in
  the source TrackCollection. The index is computed by pointer arithmetic
  on the selector chain's Track* output -- no kinematic fingerprinting.
  Required because helper::TrackCollectionStoreManager rewrites the cloned
  tracks' TrackExtraRefs to a fresh sequential key, destroying the link
  back to the source generalTracks.
- VertexCompositeCandidateRemapper: rewrites each candidate's daughter
  TrackRefs to point at the AlignmentTrackSelector's cloned track output,
  using the originalIndex ValueMap chain (selH idx -> intermediateTracks
  idx -> intermediateTracks.extra().key() = generalTracks idx). Recurses
  into nested composites (e.g. for B -> J/psi K).

Bug fix in DeDxValueMapProjector: previously used selectedTrack.extra().key()
as the source-track index, which after StoreManager's clone is just the
position in the new collection (0,1,2,...) -- so the persisted dE/dx
values for V0 / D* daughters were actually values of unrelated
generalTracks[j] entries. Switched to the same originalIndex chain.

All five resonance ALCARECO streams (TkAlJpsiMuMu, TkAlUpsilonMuMu,
TkAlZMuMu, TkAlKsToPiPi, TkAlLambdaToProtonPi) and the D* stream rewired
to publish a *Resonances VertexCompositeCandidateCollection alongside the
cloned-track output; the corresponding _Output_cff.py files keep the new
products. Adds AlignmentTrackSelectorWithIndexMap_cfi.

Adds recoskim_Run2016G_SingleMuon_AllResonances.py covering all streams in
a single test job and removes the older partial test configs.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
@davidwalter2 davidwalter2 changed the title Add ALCARECO skims (KS, Lambda, D*) for the muon-momentum-scale calibration Add ALCARECO skims (KS, Lambda, D*, J/psi, Upsilon, Z) and persist resonance candidates May 7, 2026
davidwalter2 and others added 11 commits May 15, 2026 15:04
ALCARECO PoolOutputModules had no splitLevel set, defaulting to 99
(fully split). Reading such files in CMSSW >= 15_0 hits ROOT cms-sw#19773
(I/O rule not applied for split branches): the SiStripCluster v11->v14
schema rule does not fire and clusters come back empty, breaking the
CVH refit. Add a dataTier-based customise (setAlcaRecoSplitLevel) that
sets splitLevel=1 on every ALCARECO output module, keeping collection
items streamed together so the rule fires. ~1-2% size impact; mirrors
MiniAOD's slimmedMuonTrackExtras SiStripCluster (split level 1).
Wired into the cmsDriver --customise list so it survives regeneration.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
…lor eta cut, fix psi(2S) channel to prompt pi pi
…ertex-info passthrough

- JpsiXCandidateProducer (vcc mode): veto X candidates that reuse one of
  the J/psi muon tracks, mirroring the jpsiDaughterKeys veto in track
  mode; prevents duplicate-track mother candidates (and double-fed
  tracks in the preset-C multi-track fit).
- signedPdgId helper in JpsiXCandidateProducer +
  TwoBodyDecayCandidateProducer: leptons keep pdgId sign opposite to
  charge (mu- = +13), hadrons follow the track charge (K+ = +321);
  previously a K+ track was tagged -321. Sign now derived from the
  actual track charge, so same-sign pairs are self-consistent too.
- VertexCompositeCandidateRemapper: carry vertex covariance and fit
  chi2/ndof into the remapped candidates instead of dropping them.
- TwoBodyDecayCandidateProducer: guard KalmanVertexFitter::vertex()
  against VertexException (treat as dropped pair, don't kill the job).
- AlignmentThreeBodyDecayTrackSelector: end-of-job summary via
  MessageLogger instead of std::cout.
- ALCARECOTkAlJpsiX_cff: correct stale comments still classifying
  psi(2S) as a V0-mode channel (it uses the prompt dipion producer).

Co-Authored-By: Claude Fable 5 <[email protected]>
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.

3 participants