@@ -1008,6 +1008,7 @@ struct ResonanceDaughterInitializer {
10081008 static constexpr float MomentumQuantizationScale = 1000 .f;
10091009 static constexpr std::size_t StoredMCRelationCount = 2 ;
10101010 static constexpr std::size_t MaxCandidateDaughters = 3 ;
1011+ static constexpr int NumberOfITSLayers = 7 ;
10111012
10121013 // / Selected-candidate state and the optional global daughter-ID veto set.
10131014 // / By default only candidate existence is recorded and daughter reuse is
@@ -1132,6 +1133,8 @@ struct ResonanceDaughterInitializer {
11321133 // General daughter output options
11331134 Configurable<bool > cfgFillQA{" cfgFillQA" , false , " Fill QA histograms" };
11341135 Configurable<bool > cfgDetailTrackQA{" cfgDetailTrackQA" , false , " Fill detailed QA histograms for enabled track output tables" };
1136+ Configurable<bool > cfgQAITS{" cfgQAITS" , false , " Fill Micro001 ITS quality vs pT (requires cfgFillQA and cfgFillMicroTracks)" };
1137+ Configurable<bool > cfgQATPC{" cfgQATPC" , false , " Fill Micro001 TPC crossed rows vs pT (requires cfgFillQA and cfgFillMicroTracks)" };
11351138
11361139 // Track pre-selection and DCA cuts
11371140 struct : ConfigurableGroup {
@@ -1243,13 +1246,12 @@ struct ResonanceDaughterInitializer {
12431246 // data-model relation keeps its legacy v000 default target; v001 consumers
12441247 // must use resoCollision_as<T>() with the exact bound v001 table type for
12451248 // dereferencing (aod::ResoCollisions_001 when the parent is not joined).
1246- // Original-collision grouping is provided by the scalar-only version-1
1247- // ResoCollisionGroups_001 table, avoiding a hard source-AO2D relation.
1249+ // Daughter callbacks use the original collision ID from ResoCollisionColls
1250+ // to slice input candidates explicitly. The scalar ResoCollisionGroups_001
1251+ // output is retained for consumers that do not need source-AO2D dereferencing.
12481252 // Collision mappings are always written; cfgBypassCollIndexFill is retained
12491253 // only so existing configuration files remain accepted.
12501254 using ResoCollisionWithIndex = soa::Join<aod::ResoCollisions_001, aod::ResoCollisionColls>;
1251- using SelectedResoCollisions = soa::Join<aod::ResoCollisions_001, aod::ResoCollisionGroups_001>;
1252- PresliceUnsorted<SelectedResoCollisions> reducedCollisionsPerOriginalCollision = aod::resocollisiongroup001::originalCollisionId;
12531255
12541256 /* *
12551257 * @brief Initializes the task
@@ -1263,7 +1265,7 @@ struct ResonanceDaughterInitializer {
12631265 LOGF (fatal, " cfgPairGateMode must be 0 (configured gates) or 1 (V0 or cascade)" );
12641266 }
12651267 const bool useEitherPairGate = FilterForDerivedTables.cfgPairGateMode .value == PairGateModeEither;
1266- const bool processTrackDataEnabled = doprocessData || doprocessDataHybrid || doprocessDataWithPairGate ||
1268+ const bool processTrackDataEnabled = doprocessData || doprocessDataWithPairGate ||
12671269 doprocessDataWithV0PairGate || doprocessDataWithCascPairGate;
12681270 const bool processTrackMCEnabled = doprocessMC || doprocessMCWithPairGate ||
12691271 doprocessMCWithV0PairGate || doprocessMCWithCascPairGate;
@@ -1275,7 +1277,6 @@ struct ResonanceDaughterInitializer {
12751277 const bool anyDataProcessEnabled = processTrackDataEnabled || processV0DataEnabled || processCascDataEnabled;
12761278 const bool anyMCProcessEnabled = processTrackMCEnabled || doprocessV0MC || doprocessCascMC;
12771279 const int enabledTrackProcesses = static_cast <int >(doprocessData) +
1278- static_cast <int >(doprocessDataHybrid) +
12791280 static_cast <int >(doprocessDataWithPairGate) +
12801281 static_cast <int >(doprocessDataWithV0PairGate) +
12811282 static_cast <int >(doprocessDataWithCascPairGate) +
@@ -1311,10 +1312,10 @@ struct ResonanceDaughterInitializer {
13111312 if (static_cast <int >(doprocessCascData) + static_cast <int >(doprocessCascMC) > 1 ) {
13121313 LOGF (fatal, " Only one cascade process can be enabled in ResonanceDaughterInitializer" );
13131314 }
1314- if ((doprocessData || doprocessDataHybrid || doprocessMC) &&
1315+ if ((doprocessData || doprocessMC) &&
13151316 (useEitherPairGate || FilterForDerivedTables.cfgBypassNoPairV0s || FilterForDerivedTables.cfgBypassNoPairCascades ||
13161317 FilterForDerivedTables.cfgGlobalDaughterVeto )) {
1317- LOGF (warn, " Pair-gate options are ignored by processData/processDataHybrid/ processMC; enable the matching *WithPairGate process to apply them" );
1318+ LOGF (warn, " Pair-gate options are ignored by processData/processMC; enable the matching *WithPairGate process to apply them" );
13181319 }
13191320 const auto validatePairGateOutputs = [&](bool pairProcessEnabled,
13201321 bool v0OutputEnabled,
@@ -1513,6 +1514,24 @@ struct ResonanceDaughterInitializer {
15131514 }
15141515 }
15151516
1517+ if ((processTrackDataEnabled || processTrackMCEnabled) && FilterForDerivedTables.cfgFillMicroTracks ) {
1518+ AxisSpec qualityPtAxis = {300 , 0 .f , 30 .f , " #it{p}_{T} (GeV/#it{c})" };
1519+ if (cfgQAITS) {
1520+ AxisSpec itsMapAxis = {128 , -0.5 , 127.5 , " ITS cluster map" };
1521+ AxisSpec itsNClsAxis = {8 , -0.5 , 7.5 , " ITS occupied layers" };
1522+ AxisSpec itsInnerBarrelNClsAxis = {4 , -0.5 , 3.5 , " ITS inner-barrel occupied layers" };
1523+ AxisSpec itsLayerAxis = {NumberOfITSLayers, -0.5 , NumberOfITSLayers - 0.5 , " ITS layer (0 = innermost)" };
1524+ qaRegistry.add (" QA/h2MicroTrackITSClusterMapVsPt" , " ResoMicroTracks ITS cluster map vs pT" , kTH2D , {qualityPtAxis, itsMapAxis});
1525+ qaRegistry.add (" QA/h2MicroTrackITSNClsVsPt" , " ResoMicroTracks ITS occupied layers vs pT" , kTH2D , {qualityPtAxis, itsNClsAxis});
1526+ qaRegistry.add (" QA/h2MicroTrackITSNClsInnerBarrelVsPt" , " ResoMicroTracks ITS inner-barrel occupied layers vs pT" , kTH2D , {qualityPtAxis, itsInnerBarrelNClsAxis});
1527+ qaRegistry.add (" QA/h2MicroTrackITSLayerHitsVsPt" , " ResoMicroTracks ITS hits vs pT (one entry per occupied layer)" , kTH2D , {qualityPtAxis, itsLayerAxis});
1528+ }
1529+ if (cfgQATPC) {
1530+ AxisSpec tpcCrossedRowsAxis = {256 , -0.5 , 255.5 , " TPC crossed rows" };
1531+ qaRegistry.add (" QA/h2MicroTrackTPCCrossedRowsVsPt" , " ResoMicroTracks TPC crossed rows vs pT" , kTH2D , {qualityPtAxis, tpcCrossedRowsAxis});
1532+ }
1533+ }
1534+
15161535 if (processV0DataEnabled || doprocessV0MC) {
15171536 qaRegistry.add (" QA/hGoodV0Indices" , " hGoodV0Indices" , kTH1D , {idxAxis});
15181537 auto v0Selection = qaRegistry.get <TH1 >(HIST (" QA/hGoodV0Indices" ));
@@ -2195,6 +2214,22 @@ struct ResonanceDaughterInitializer {
21952214 qaRegistry.fill (HIST (" QA/h4MicroTrackTOFnSigma" ), track.pt (), track.tofNSigmaPi (), track.tofNSigmaKa (), track.tofNSigmaPr ());
21962215 }
21972216 }
2217+ // Quality QA follows the same selected rows as Micro001, independently
2218+ // of the detailed PID/DCA QA. ITS count getters count occupied layers.
2219+ if (cfgFillQA && cfgQAITS) {
2220+ const auto itsClusterMap = track.itsClusterMap ();
2221+ qaRegistry.fill (HIST (" QA/h2MicroTrackITSClusterMapVsPt" ), track.pt (), itsClusterMap);
2222+ qaRegistry.fill (HIST (" QA/h2MicroTrackITSNClsVsPt" ), track.pt (), track.itsNCls ());
2223+ qaRegistry.fill (HIST (" QA/h2MicroTrackITSNClsInnerBarrelVsPt" ), track.pt (), track.itsNClsInnerBarrel ());
2224+ for (int layer = 0 ; layer < NumberOfITSLayers; ++layer) {
2225+ if ((itsClusterMap & (1u << layer)) != 0 ) {
2226+ qaRegistry.fill (HIST (" QA/h2MicroTrackITSLayerHitsVsPt" ), track.pt (), layer);
2227+ }
2228+ }
2229+ }
2230+ if (cfgFillQA && cfgQATPC) {
2231+ qaRegistry.fill (HIST (" QA/h2MicroTrackTPCCrossedRowsVsPt" ), track.pt (), track.tpcNClsCrossedRows ());
2232+ }
21982233 reso2microtrks (collision.globalIndex (),
21992234 track.globalIndex (),
22002235 track.px (),
@@ -2204,7 +2239,9 @@ struct ResonanceDaughterInitializer {
22042239 static_cast <uint8_t >(o2::aod::resomicrodaughter001::PidNSigma (track.tpcNSigmaKa (), track.tofNSigmaKa (), track.hasTOF ())),
22052240 static_cast <uint8_t >(o2::aod::resomicrodaughter001::PidNSigma (track.tpcNSigmaPr (), track.tofNSigmaPr (), track.hasTOF ())),
22062241 static_cast <uint8_t >(trackSelFlag),
2207- trackFlags);
2242+ trackFlags,
2243+ static_cast <uint8_t >(track.tpcNClsCrossedRows ()),
2244+ track.itsClusterMap ());
22082245 if (!FilterForDerivedTables.cfgBypassTrackIndexFill ) {
22092246 resoMicroTrackTracks (track.globalIndex ());
22102247 }
@@ -2783,31 +2820,6 @@ struct ResonanceDaughterInitializer {
27832820 }
27842821 PROCESS_SWITCH (ResonanceDaughterInitializer, processData, " Process tracks for data" , false );
27852822
2786- /* *
2787- * @brief Processes data tracks using the two-stage hybrid grouping
2788- *
2789- * GroupSlicer associates tracks automatically to the original
2790- * aod::Collision. Reduced collisions retain a scalar original-collision row
2791- * number and are explicitly sliced from the much smaller mapping table. The
2792- * tracks argument is already the selected slice and must not be sliced again.
2793- */
2794- void processDataHybrid (aod::Collision const & originalCollision,
2795- SelectedResoCollisions const & reducedCollisions,
2796- soa::Filtered<aod::ResoTrackCandidates> const & tracks)
2797- {
2798- auto reducedCollisionsThisCollision = reducedCollisions.sliceBy (reducedCollisionsPerOriginalCollision, originalCollision.globalIndex ());
2799- if (reducedCollisionsThisCollision.size () == 0 ) {
2800- return ;
2801- }
2802- if (reducedCollisionsThisCollision.size () > 1 ) {
2803- LOGF (error, " Found %zu reduced collisions for one original collision; skipping the ambiguous association" , reducedCollisionsThisCollision.size ());
2804- return ;
2805- }
2806- auto reducedCollision = reducedCollisionsThisCollision.begin ();
2807- fillTrackTables<false >(reducedCollision, tracks);
2808- }
2809- PROCESS_SWITCH (ResonanceDaughterInitializer, processDataHybrid, " Process data tracks with the two-stage hybrid grouping" , false );
2810-
28112823 /* *
28122824 * @brief Processes data tracks with configurable selected V0 and cascade gates
28132825 */
0 commit comments