diff --git a/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx b/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx index 0b1102163c7..b0681d1768a 100644 --- a/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx +++ b/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx @@ -113,6 +113,11 @@ enum class D0CandFlag : uint8_t { struct HfProducerCharmHadronsTrackFemtoDream { + enum TrackCharge { + PositiveCharge = 1, + NegativeCharge = -1 + }; + struct : ProducesGroup { Produces outputCollision; Produces rowMasks; @@ -237,8 +242,8 @@ struct HfProducerCharmHadronsTrackFemtoDream { using FemtoFullCollision = soa::Join::iterator; using FemtoFullCollisionMc = soa::Join::iterator; - using FemtoFullMcgenCollisions = soa::Join; - using FemtoFullMcgenCollision = FemtoFullMcgenCollisions::iterator; + using FemtoMcgenCollisions = soa::Join; + using FemtoMcgenCollision = FemtoMcgenCollisions::iterator; using FemtoHFTracks = soa::Join; using FemtoHFTrack = FemtoHFTracks::iterator; using FemtoHFMcTracks = soa::Join; @@ -255,6 +260,8 @@ struct HfProducerCharmHadronsTrackFemtoDream { Filter filterSelectCandidateLc = (aod::hf_sel_candidate_lc::isSelLcToPKPi >= generalCfg.selectionFlagHadron || aod::hf_sel_candidate_lc::isSelLcToPiKP >= generalCfg.selectionFlagHadron); Filter filterSelectCandidateXic = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= generalCfg.selectionFlagHadron; + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry trackRegistry{"Tracks", {}, OutputObjHandlingPolicy::AnalysisObject}; OutputObj zorroSummary{"zorroSummary"}; @@ -555,7 +562,7 @@ struct HfProducerCharmHadronsTrackFemtoDream { void fillMcCollision(CollisionType const& col) { if (col.has_mcCollision()) { - // auto genMCcol = col.template mcCollision_as(); + // auto genMCcol = col.template mcCollision_as(); // tables.outputMcCollision(genMCcol.multMCNParticlesEta08()); tables.outputCollsMcLabels(tables.outputMcCollision.lastIndex()); } else { @@ -1084,10 +1091,10 @@ struct HfProducerCharmHadronsTrackFemtoDream { /// \param TC type of the femto track cuts /// \return whether or not the tracks fulfills the all selections template - bool isNoSelectedTracks(C const& /*col*/, T const& tracks, TC& trackCuts) + bool isNoSelectedTracks(C const& /*col*/, T const& tracks, TC& trackSelections) { for (auto const& track : tracks) { - if (trackCuts.isSelectedMinimal(track)) { + if (trackSelections.isSelectedMinimal(track)) { return false; } } @@ -1095,18 +1102,101 @@ struct HfProducerCharmHadronsTrackFemtoDream { } template - void fillCharmHadMcGen(const ParticleType& particles) + void fillCharmHadMcGen(const ParticleType& particles, FemtoMcgenCollisions const* collisions = nullptr) { // Filling particle properties tables.rowCandCharmHadGen.reserve(particles.size() + 1); if constexpr (Channel == DecayChannel::DplusToPiKPi) { - for (const auto& particle : particles) { - if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi) { - tables.rowCandCharmHadGen( - particle.mcCollisionId(), - particle.flagMcMatchGen(), - particle.originMcGen()); + constexpr int InvalidMcIndex = -1; + const int64_t timeStamp = -1; // No need for Gen process. + const float bdtScore = -1.f; // No need for Gen particles. + const float dcaXY = 999.f; // No need for Gen particles. + const float sphericity = 2.f; // Not computed. + const aod::femtodreamparticle::cutContainerType bitPos = 1u << 1; + const aod::femtodreamparticle::cutContainerType bitNeg = 1u << 0; + std::vector daughterIds; + std::vector const childIds = {InvalidMcIndex, InvalidMcIndex}; + for (const auto& col : *collisions) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::All); + if (col.posZ() < hfEvSel.zPvPosMin || col.posZ() > hfEvSel.zPvPosMax) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::RejEveSel); + continue; + } + auto groupedMCParticles = particles.sliceBy(perMcCollision, col.globalIndex()); + // MC provides particle multiplicity, but no reconstructed centrality or magnetic field. + const float multiplicityPercentile = 0.f; + const float magneticField = 0.f; + tables.outputCollision(col.posZ(), multiplicityPercentile, col.multMCNParticlesEta08(), sphericity, magneticField); + tables.outputMcCollision(col.multMCNParticlesEta08()); + tables.outputCollsMcLabels(tables.outputMcCollision.lastIndex()); + + bool isTrackFilled = false; + bool isCharmFilled = false; + for (const auto& particle : groupedMCParticles) { + if (std::abs(particle.pdgCode()) != o2::constants::physics::Pdg::kDPlus || + std::abs(particle.flagMcMatchGen()) != hf_decay::hf_cand_3prong::DecayChannelMain::DplusToPiKPi || + !particle.producedByGenerator()) { + continue; + } + daughterIds.clear(); + RecoDecay::getDaughters(particle, &daughterIds, std::array{kPiPlus, kKPlus}); + int prong0Id = InvalidMcIndex; + int prong1Id = InvalidMcIndex; + int prong2Id = InvalidMcIndex; + for (const auto& daughterId : daughterIds) { + const auto daughter = particles.rawIteratorAt(daughterId); + if (std::abs(daughter.pdgCode()) == kKPlus) { + prong1Id = daughter.globalIndex(); + } else if (std::abs(daughter.pdgCode()) == kPiPlus) { + if (prong0Id == InvalidMcIndex) { + prong0Id = daughter.globalIndex(); + } else { + prong2Id = daughter.globalIndex(); + } + } + } + const auto prong0 = particles.rawIteratorAt(prong0Id); + const auto prong1 = particles.rawIteratorAt(prong1Id); + const auto prong2 = particles.rawIteratorAt(prong2Id); + tables.rowCandCharm3Prong(tables.outputCollision.lastIndex(), timeStamp, + particle.pdgCode() > 0 ? PositiveCharge : NegativeCharge, + prong0Id, prong1Id, prong2Id, + prong0.pt(), prong1.pt(), prong2.pt(), + prong0.eta(), prong1.eta(), prong2.eta(), + prong0.phi(), prong1.phi(), prong2.phi(), + true, bdtScore, bdtScore, bdtScore); + const auto particleOrigin = particle.originMcGen() == RecoDecay::OriginType::Prompt + ? aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary + : aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryFromHF; + tables.outputPartsMc(particleOrigin, particle.pdgCode(), particle.pt(), particle.eta(), particle.phi()); + tables.rowCandCharmHadGen(tables.outputPartsMc.lastIndex(), particle.flagMcMatchGen(), particle.originMcGen()); + tables.rowCandMcCharmHad(particle.flagMcMatchGen(), particle.originMcGen()); + tables.outputPartsMcLabels(tables.outputPartsMc.lastIndex()); + isCharmFilled = true; + } + for (const auto& particle : groupedMCParticles) { + if (std::abs(particle.pdgCode()) == std::abs(trackCfg.trkPDGCode.value) && particle.isPhysicalPrimary() && particle.producedByGenerator()) { + tables.outputPartsIndex(particle.globalIndex()); + tables.outputPartsTime(timeStamp); + // Store the PDG code instead of detector PID bits, as in the femto truth producer. + tables.outputParts(tables.outputCollision.lastIndex(), + particle.pt(), particle.eta(), particle.phi(), + aod::femtodreamparticle::ParticleType::kTrack, + particle.pdgCode() > 0 ? bitPos : bitNeg, + std::abs(particle.pdgCode()), dcaXY, childIds, 0.f, 0.f); + isTrackFilled = true; + } } + if (isTrackFilled) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::TrackSelected); + } + if (isCharmFilled) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::CharmSelected); + } + if (isTrackFilled && isCharmFilled) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::PairSelected); + } + tables.rowMasks(isTrackFilled, isCharmFilled, false); } } else if constexpr (Channel == DecayChannel::LcToPKPi) { for (const auto& particle : particles) { @@ -1127,13 +1217,99 @@ struct HfProducerCharmHadronsTrackFemtoDream { } } } else if constexpr (Channel == DecayChannel::DstarToD0Pi) { - for (const auto& particle : particles) { - if (std::abs(particle.flagMcMatchGen()) == hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi) { - tables.rowCandCharmHadGen( - particle.mcCollisionId(), - particle.flagMcMatchGen(), - particle.originMcGen()); + constexpr int InvalidMcIndex = -1; + const int64_t timeStamp = -1; // No need for Gen process. + const float bdtScore = -1.f; // No need for Gen particles. + const float dcaXY = 999.f; // No need for Gen particles. + const float sphericity = 2.f; // Not computed. + const aod::femtodreamparticle::cutContainerType bitPos = 1u << 1; + const aod::femtodreamparticle::cutContainerType bitNeg = 1u << 0; + std::vector daughterIds; + std::vector const childIds = {InvalidMcIndex, InvalidMcIndex}; + for (const auto& col : *collisions) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::All); + if (col.posZ() < hfEvSel.zPvPosMin || col.posZ() > hfEvSel.zPvPosMax) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::RejEveSel); + continue; + } + auto groupedMCParticles = particles.sliceBy(perMcCollision, col.globalIndex()); + // MC provides particle multiplicity, but no reconstructed centrality or magnetic field. + const float multiplicityPercentile = 0.f; + const float magneticField = 0.f; + tables.outputCollision(col.posZ(), multiplicityPercentile, col.multMCNParticlesEta08(), sphericity, magneticField); + tables.outputMcCollision(col.multMCNParticlesEta08()); + tables.outputCollsMcLabels(tables.outputMcCollision.lastIndex()); + + bool isTrackFilled = false; + bool isCharmFilled = false; + for (const auto& particle : groupedMCParticles) { + if (std::abs(particle.pdgCode()) != o2::constants::physics::Pdg::kDStar || + std::abs(particle.flagMcMatchGen()) != hf_decay::hf_cand_dstar::DecayChannelMain::DstarToPiKPi || + !particle.producedByGenerator()) { + continue; + } + daughterIds.clear(); + RecoDecay::getDaughters(particle, &daughterIds, std::array{kPiPlus, kKPlus}); + int prongPosId = InvalidMcIndex; + int prongNegId = InvalidMcIndex; + int softPionId = InvalidMcIndex; + for (const auto& daughterId : daughterIds) { + const auto daughter = particles.rawIteratorAt(daughterId); + if (std::abs(daughter.pdgCode()) != kPiPlus && std::abs(daughter.pdgCode()) != kKPlus) { + continue; + } + const auto mother = daughter.template mothers_first_as(); + if (std::abs(mother.pdgCode()) == o2::constants::physics::Pdg::kDStar) { + softPionId = daughter.globalIndex(); + } else if (daughter.pdgCode() > 0) { + prongPosId = daughter.globalIndex(); + } else { + prongNegId = daughter.globalIndex(); + } + } + const auto prongPos = particles.rawIteratorAt(prongPosId); + const auto prongNeg = particles.rawIteratorAt(prongNegId); + const auto softPion = particles.rawIteratorAt(softPionId); + // The existing pair-mass helper selects the pion/kaon hypothesis with candidateSelFlag == 1. + tables.rowCandCharmDstar(tables.outputCollision.lastIndex(), timeStamp, + particle.pdgCode() > 0 ? PositiveCharge : NegativeCharge, + prongPosId, prongNegId, softPionId, + prongPos.pt(), prongNeg.pt(), softPion.pt(), + prongPos.eta(), prongNeg.eta(), softPion.eta(), + prongPos.phi(), prongNeg.phi(), softPion.phi(), + particle.pdgCode() > 0, bdtScore, bdtScore, bdtScore); + const auto particleOrigin = particle.originMcGen() == RecoDecay::OriginType::Prompt + ? aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary + : aod::femtodreamMCparticle::ParticleOriginMCTruth::kSecondaryFromHF; + tables.outputPartsMc(particleOrigin, particle.pdgCode(), particle.pt(), particle.eta(), particle.phi()); + tables.rowCandCharmHadGen(tables.outputPartsMc.lastIndex(), particle.flagMcMatchGen(), particle.originMcGen()); + tables.rowCandMcCharmHad(particle.flagMcMatchGen(), particle.originMcGen()); + tables.outputPartsMcLabels(tables.outputPartsMc.lastIndex()); + isCharmFilled = true; + } + for (const auto& particle : groupedMCParticles) { + if (std::abs(particle.pdgCode()) == std::abs(trackCfg.trkPDGCode.value) && particle.isPhysicalPrimary() && particle.producedByGenerator()) { + tables.outputPartsIndex(particle.globalIndex()); + tables.outputPartsTime(timeStamp); + // Store the PDG code instead of detector PID bits, as in the femto truth producer. + tables.outputParts(tables.outputCollision.lastIndex(), + particle.pt(), particle.eta(), particle.phi(), + aod::femtodreamparticle::ParticleType::kTrack, + particle.pdgCode() > 0 ? bitPos : bitNeg, + std::abs(particle.pdgCode()), dcaXY, childIds, 0.f, 0.f); + isTrackFilled = true; + } } + if (isTrackFilled) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::TrackSelected); + } + if (isCharmFilled) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::CharmSelected); + } + if (isTrackFilled && isCharmFilled) { + qaRegistry.fill(HIST("hEventQA"), 1 + Event::PairSelected); + } + tables.rowMasks(isTrackFilled, isCharmFilled, false); } } } @@ -1257,10 +1433,9 @@ struct HfProducerCharmHadronsTrackFemtoDream { } PROCESS_SWITCH(HfProducerCharmHadronsTrackFemtoDream, processMcDstarToD0PiWithML, "Provide Mc for DstarToD0Pi with ml", false); - void processMcDstarToD0PiGen(GeneratedDstarMc const& particles) + void processMcDstarToD0PiGen(FemtoMcgenCollisions const& collisions, GeneratedDstarMc const& particles) { - - fillCharmHadMcGen(particles); + fillCharmHadMcGen(particles, &collisions); } PROCESS_SWITCH(HfProducerCharmHadronsTrackFemtoDream, processMcDstarToD0PiGen, "Provide Mc Generated DstarToD0Pi", false); @@ -1314,10 +1489,10 @@ struct HfProducerCharmHadronsTrackFemtoDream { } PROCESS_SWITCH(HfProducerCharmHadronsTrackFemtoDream, processMcDplusToPiKPiWithML, "Provide Mc for DplusToPiKPi with ml", false); - void processMcDplusToPiKPiGen(Generated3ProngMc const& particles) + void processMcDplusToPiKPiGen(FemtoMcgenCollisions const& collisions, Generated3ProngMc const& particles) { - fillCharmHadMcGen(particles); + fillCharmHadMcGen(particles, &collisions); } PROCESS_SWITCH(HfProducerCharmHadronsTrackFemtoDream, processMcDplusToPiKPiGen, "Provide Mc Generated DplusToPiKPi", false); diff --git a/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx b/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx index cfbd216ec22..93e90ce8c74 100644 --- a/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx +++ b/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx @@ -186,6 +186,10 @@ struct HfTaskCharmHadronsTrackFemtoDream { using FilteredCharmMcCandDstars = soa::Filtered>; using FilteredCharmMcCandDstar = FilteredCharmMcCandDstars::iterator; + using CharmGenCand3Prongs = soa::Join; + using CharmGenCandDstars = soa::Join; + using FilteredFDGenParts = soa::Filtered>; + using FilteredCollisions = soa::Filtered>; using FilteredCollision = FilteredCollisions::iterator; @@ -225,6 +229,8 @@ struct HfTaskCharmHadronsTrackFemtoDream { Partition partitionMcTrk1Ka = (aod::femtodreamparticle::partType == static_cast(aod::femtodreamparticle::ParticleType::kTrack)) && (ncheckbit(aod::femtodreamparticle::cut, trackSel.cutBitTrack1)) && (aod::femtodreamparticle::pidcut == PidTrackPass); + Partition partitionGenTrk1 = (aod::femtodreamparticle::partType == static_cast(aod::femtodreamparticle::ParticleType::kTrack)) && (aod::femtodreamparticle::pidcut == static_cast(kProton)); + /// Partition for particle 2 Partition partitionCharmHadron3Prong = aod::fdhf::bdtBkg < charmSel.charmHadBkgBDTmax && aod::fdhf::bdtFD < charmSel.charmHadFdBDTmax && aod::fdhf::bdtFD > charmSel.charmHadFdBDTmin&& aod::fdhf::bdtPrompt charmSel.charmHadPromptBDTmin; Partition partitionCharmHadron3ProngXic = aod::fdhf::bdtBkg < charmSel.charmHadBkgBDTmax && aod::fdhf::bdtFD < charmSel.charmHadFdBDTmax && aod::fdhf::bdtFD > charmSel.charmHadFdBDTmin&& aod::fdhf::bdtPrompt charmSel.charmHadPromptBDTmin; @@ -300,7 +306,7 @@ struct HfTaskCharmHadronsTrackFemtoDream { void init(InitContext& /*context*/) { - std::array processes = {doprocessDataLcTrk, doprocessDataDplusTrk, doprocessDataD0Trk, doprocessDataDstarTrk, doprocessDataXicTrk, doprocessMcLcTrk, doprocessMcDplusTrk, doprocessMcD0Trk, doprocessMcDstarTrk, doprocessMcXicTrk}; + std::array processes = {doprocessDataLcTrk, doprocessDataDplusTrk, doprocessDataD0Trk, doprocessDataDstarTrk, doprocessDataXicTrk, doprocessMcLcTrk, doprocessMcDplusTrk, doprocessMcD0Trk, doprocessMcDstarTrk, doprocessMcXicTrk, doprocessMcDstarTrkGen, doprocessMcDplusTrkGen}; if (std::accumulate(processes.begin(), processes.end(), 0) != 1) { LOGP(fatal, "One and only one process function must be enabled at a time."); } @@ -1308,6 +1314,191 @@ struct HfTaskCharmHadronsTrackFemtoDream { } PROCESS_SWITCH(HfTaskCharmHadronsTrackFemtoDream, processMcDstarTrk, "Enable processing DstarToD0Pi and Tracks correlation for Monte Carlo", false); + template + void processMcGen(FilteredMcColisions const& cols, CandidateType const& candidates) + { + constexpr int SameEvent = 1; + constexpr int MixedEvent = 2; + constexpr int InvalidMixingBin = -1; + const int64_t timeStamp = -1; // No timestamp is available in this Gen process. + const uint8_t nCls = 0; // Gen particles have no detector clusters. + const float nSigma = 999.f; // Gen particles have no detector PID response. + + auto fillPairs = [&](auto const& sliceGenTrk1, auto const& sliceGenCharmHad, auto const& col, auto& container) { + for (auto const& [p1, p2] : combinations(CombinationsFullIndexPolicy(sliceGenTrk1, sliceGenCharmHad))) { + const auto particle = p2.fdMCParticle(); + float kstar = FemtoDreamMath::getkstar(p1, massOne, particle, massTwo); + if (kstar > highkstarCut) { + continue; + } + if (particle.pt() < charmSel.charmHadMinPt || particle.pt() > charmSel.charmHadMaxPt) { + continue; + } + float invMass = getCharmHadronMass(p2); + float deltaInvMassPair = getCharmHadronTrackMass(p2, p1, trackSel.pdgCodeTrack1.value) - invMass; + float chargeTrack = 0.; + if ((p1.cut() & CutBitChargePositive) == CutBitChargePositive) { + chargeTrack = PositiveCharge; + } else { + chargeTrack = NegativeCharge; + } + int pairSign = PairNotDefined; + if (chargeTrack == p2.charge()) { + pairSign = LikeSignPair; + } else if (chargeTrack == -p2.charge()) { + pairSign = UnLikeSignPair; + } else { + pairSign = ReflectedPair; + } + rowFemtoResultPairs( + invMass, + particle.pt(), + p1.pt(), + p2.bdtBkg(), + p2.bdtPrompt(), + p2.bdtFD(), + kstar, + FemtoDreamMath::getkT(p1, massOne, particle, massTwo), + FemtoDreamMath::getmT(p1, massOne, particle, massTwo), + col.multNtr(), + col.multV0M(), + p2.charge(), + pairSign, + deltaInvMassPair, + processType, + p2.flagMc(), + p2.originMcRec()); + container.template setPair_base(kstar, FemtoDreamMath::getmT(p1, massOne, particle, massTwo), p1, particle, col.multNtr(), col.multV0M(), pairQASetting.use4D, pairQASetting.extendedPlots); + } + }; + + for (const auto& col : cols) { + eventHisto.fillQA(col); + auto sliceGenTrk1 = partitionGenTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + auto sliceGenCharmHad = candidates.sliceByCached(aod::femtodreamparticle::fdCollisionId, col.globalIndex(), cache); + if ((col.bitmaskTrackOne() & bitMask) != bitMask || (col.bitmaskTrackTwo() & bitMask) != bitMask) { + continue; + } + if (fillTableWithCharm.value && sliceGenCharmHad.size() == 0) { + continue; + } + for (auto const& part : sliceGenCharmHad) { + const auto particle = part.fdMCParticle(); + float invMass = getCharmHadronMass(part); + registryCharmHadronQa.fill(HIST("CharmHadronQA/hPtVsMass"), particle.pt(), invMass); + if constexpr (Channel == DecayChannel::DstarToD0Pi) { + float invMassD0 = getCharmHadronMass(part, true); + rowFemtoResultCharmDstar( + col.globalIndex(), + part.timeStamp(), + invMass, + invMassD0, + particle.pt(), + particle.eta(), + particle.phi(), + part.prong0Id(), + part.prong1Id(), + part.prong2Id(), + part.charge(), + part.bdtBkg(), + part.bdtPrompt(), + part.bdtFD(), + part.flagMc(), + part.originMcRec()); + } else { + rowFemtoResultCharm3Prong( + col.globalIndex(), + part.timeStamp(), + invMass, + particle.pt(), + particle.eta(), + particle.phi(), + part.prong0Id(), + part.prong1Id(), + part.prong2Id(), + part.charge(), + part.bdtBkg(), + part.bdtPrompt(), + part.bdtFD(), + part.flagMc(), + part.originMcRec()); + } + } + for (auto const& part : sliceGenTrk1) { + float chargeTrack = ((part.cut() & CutBitChargePositive) == CutBitChargePositive) + ? PositiveCharge + : NegativeCharge; + rowFemtoResultTrk( + col.globalIndex(), + part.timeStamp(), + part.pt(), + part.eta(), + part.phi(), + part.trackId(), + chargeTrack, + nCls, + nCls, + nCls, + nSigma, + nSigma); + } + if (sliceGenCharmHad.size() > 0 || sliceGenTrk1.size() > 0) { + rowFemtoResultColl(col.globalIndex(), timeStamp, col.posZ(), col.multNtr()); + } + fillCollision(col); + processType = SameEvent; + fillPairs(sliceGenTrk1, sliceGenCharmHad, col, sameEventCont); + } + + if (mixSetting.doMixEvent) { + Partition partitionMaskedCol1 = (aod::femtodreamcollision::bitmaskTrackOne & bitMask) == bitMask; + partitionMaskedCol1.bindTable(cols); + Partition partitionMaskedCol2 = (aod::femtodreamcollision::bitmaskTrackTwo & bitMask) == bitMask; + partitionMaskedCol2.bindTable(cols); + auto mixEvents = [&](auto const& policy) { + processType = MixedEvent; + for (auto const& [collision1, collision2] : combinations(soa::CombinationsBlockFullIndexPolicy(policy, mixSetting.mixingDepth, InvalidMixingBin, *partitionMaskedCol1.mFiltered, *partitionMaskedCol2.mFiltered))) { + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + registryMixQa.fill(HIST("MixingQA/hMECollisionBins"), colBinningMult.getBin({collision1.posZ(), collision1.multNtr()})); + auto sliceGenTrk1 = partitionGenTrk1->sliceByCached(aod::femtodreamparticle::fdCollisionId, collision1.globalIndex(), cache); + auto sliceGenCharmHad = candidates.sliceByCached(aod::femtodreamparticle::fdCollisionId, collision2.globalIndex(), cache); + fillPairs(sliceGenTrk1, sliceGenCharmHad, collision1, mixedEventCont); + } + }; + switch (mixSetting.mixingBinPolicy) { + case femtodreamcollision::kMult: + mixEvents(colBinningMult); + break; + case femtodreamcollision::kMultPercentile: + mixEvents(colBinningMultPercentile); + break; + case femtodreamcollision::kMultMultPercentile: + mixEvents(colBinningMultMultPercentile); + break; + } + } + } + + void processMcDstarTrkGen(FilteredMcColisions const& cols, + FilteredFDGenParts const&, + CharmGenCandDstars const& candidates, + aod::FDMCParticles const&) + { + processMcGen(cols, candidates); + } + PROCESS_SWITCH(HfTaskCharmHadronsTrackFemtoDream, processMcDstarTrkGen, "Enable generated Dstar and proton correlation for Monte Carlo", false); + + void processMcDplusTrkGen(FilteredMcColisions const& cols, + FilteredFDGenParts const&, + CharmGenCand3Prongs const& candidates, + aod::FDMCParticles const&) + { + processMcGen(cols, candidates); + } + PROCESS_SWITCH(HfTaskCharmHadronsTrackFemtoDream, processMcDplusTrkGen, "Enable generated Dplus and proton correlation for Monte Carlo", false); + void processMcXicTrk(FilteredMcColisions const& cols, FilteredFDMcParts const& parts, o2::aod::FDMCParticles const&,