[PWGHF] Added trigger for Sc-proton correlation#14786
[PWGHF] Added trigger for Sc-proton correlation#14786singhra1994 wants to merge 10 commits intoAliceO2Group:masterfrom
Conversation
Added parameters for Sigma_C trigger selection and updated event tagging logic for SigmaC candidates.
Added support for SigmaC particle selection in the HfFilterHelper class.
[Trigger,PWGHF] Please consider the following formatting changes to AliceO2Group#14786
fgrosa
left a comment
There was a problem hiding this comment.
Hi @singhra1994 I still didn't look into the helper functions, but I already spotted several issues in the logic of the filter itself. Please implement the suggestions, and then I will take a look at the helper functions as well.
| float deltaEta = std::abs(RecoDecay::eta(pVecSigmaC) - track.eta() && pt3Prong < 3.0); | ||
| if (configSigmaC.isTrigSigmaCP && isTrackProton && deltaEta < 1.0) { | ||
|
|
||
| auto tagBDT = helper.isBDTSelected(scores[2], thresholdBDTScores[5]); |
There was a problem hiding this comment.
be careful that this only works if thresholdBDTScores[5] is tighter than thresholdBDTScores[4]
There was a problem hiding this comment.
I know, I assumed that BDT cut on 3 prong creators should be looser, I only need stronger BDT on sigmaCpr trigger if there is the problem in reaching required selectivity
There was a problem hiding this comment.
Ok! Please put it separately, as cut for your trigger only to avoid confusion (since as it is now in the configurables, it seems that it is applied for all SigmaC states).
[Trigger,PWGHF] Please consider the following formatting changes to AliceO2Group#14786
fgrosa
left a comment
There was a problem hiding this comment.
Hi @singhra1994, thanks for addressing my comments! The code looks correct to me now, but I would like to ask @mfaggin also to check that I didn't overlook any other bug that might affect the SigmaC-K triggers.
Please also address my remaining comments and then as discussed in the trigger meeting, verify that the output of the task is identical for the other triggers before and after your changes, so that we can then merge it. Thanks!
| Configurable<float> minMassSigmaCCorr{"minMassSigmaCCorr", 0.15, "minimum mass of SigmaC for correlation with proton"}; | ||
| Configurable<float> maxMassSigmaCCorr{"maxMassSigmaCCorr", 0.19, "maximum mass of SigmaC for correlation with proton"}; | ||
| Configurable<float> minPtSigmaC{"minPtSigmaC", 4.99, "minimum pT of SigmaC for correlation with proton"}; | ||
| Configurable<float> maxPtSigmaC{"maxPtSigmaC", 12.0, "maximum pT of SigmaC for correlation with proton"}; |
There was a problem hiding this comment.
Put these configurables in the labelled array with masses and pT cuts for resonances (cutsPtDeltaMassCharmReso), adding more columns (and a meaningful name for the label, e.g. SigmaCForPrCorr or something similar)
| Configurable<LabeledArray<double>> thresholdBDTScoreDSToPiKK{"thresholdBDTScoreDSToPiKK", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Ds+ candidates"}; | ||
| Configurable<LabeledArray<double>> thresholdBDTScoreLcToPiKP{"thresholdBDTScoreLcToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc+ candidates"}; | ||
| Configurable<LabeledArray<double>> thresholdBDTScoreXicToPiKP{"thresholdBDTScoreXicToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Xic+ candidates"}; | ||
| Configurable<LabeledArray<double>> thresholdBDTScoreScLcToPiKP{"thresholdBDTScoreScLcToPiKP", {hf_cuts_bdt_multiclass::Cuts[0], hf_cuts_bdt_multiclass::NBinsPt, hf_cuts_bdt_multiclass::NCutBdtScores, hf_cuts_bdt_multiclass::labelsPt, hf_cuts_bdt_multiclass::labelsCutBdt}, "Threshold values for BDT output scores of Lc<--Sc candidates"}; |
There was a problem hiding this comment.
Put this separately, in the cuts for your trigger only
| Configurable<std::vector<int>> trkPIDspecies{"trkPIDspecies", std::vector<int>{o2::track::PID::Proton, o2::track::PID::Pion, o2::track::PID::Kaon}, "Trk sel: Particles species for PID, proton, pion, kaon"}; | ||
| Configurable<std::vector<float>> pidTPCMax{"pidTPCMax", std::vector<float>{3., 0., 0.}, "maximum nSigma TPC"}; | ||
| Configurable<std::vector<float>> pidTOFMax{"pidTOFMax", std::vector<float>{3., 0., 0.}, "maximum nSigma TOF"}; | ||
| Configurable<bool> forceTOF{"forceTOF", false, "fill PID information for associated tracks"}; | ||
| Configurable<float> tofPIDThreshold{"tofPIDThreshold", 1.0, "minimum pT after which TOF PID is applicable"}; | ||
| Configurable<float> minPtProton{"minPtProton", 0.39, "minimum pT for associated proton"}; | ||
| Configurable<float> maxPtProton{"maxPtProton", 4.51, "maximum pT for associated proton"}; |
There was a problem hiding this comment.
If you don't put a prefix to your configurable group, it will be impossible to understand what these configurables refer to. Please either add a suffix, or even better use a LabeledArray containing the cuts for your trigger as done for the others, so that it is easier to configure.
|
|
||
| // array of BDT thresholds | ||
| std::array<LabeledArray<double>, kNCharmParticles> thresholdBDTScores; | ||
| std::array<LabeledArray<double>, kNCharmParticles + 1> thresholdBDTScores; |
There was a problem hiding this comment.
I agree with this comment: leave your BDT fully independent from the others which are general for the triggers.
| float deltaEta = std::abs(RecoDecay::eta(pVecSigmaC) - track.eta() && pt3Prong < 3.0); | ||
| if (configSigmaC.isTrigSigmaCP && isTrackProton && deltaEta < 1.0) { | ||
|
|
||
| auto tagBDT = helper.isBDTSelected(scores[2], thresholdBDTScores[5]); |
There was a problem hiding this comment.
Ok! Please put it separately, as cut for your trigger only to avoid confusion (since as it is now in the configurables, it seems that it is applied for all SigmaC states).
| } | ||
| } | ||
| } | ||
| return true; // Passed all checks |
There was a problem hiding this comment.
Before returning true, I suggest you to fill an histogram of Nsigma Vs Pt to monitor that you are indeed selecting what you want
| return false; | ||
| } | ||
|
|
||
| for (size_t speciesIndex = 0; speciesIndex < mPIDspecies.value.size(); ++speciesIndex) { |
There was a problem hiding this comment.
Is it needed to iterate over the PID hypotheses? Can't you simply test the proton PID since this is the only trigger foreseen?
|
|
||
| /// Delta mass selection on SigmaC candidates for correlation | ||
| template <typename T, typename H2> | ||
| inline bool HfFilterHelper::selectionSigmaCForScPCorr(const T& pTrackSameChargeFirst, const T& pTrackSameChargeSecond, const T& pTrackOppositeCharge, const T& pTrackSoftPi, const float ptSigmaC, const int8_t isSelectedLc, H2 hMassVsPt, const int& activateQA, float mDeltaMassMinSigmaC, float mDeltaMassMaxSigmaC, float mPtMinSigmaC, float mPtMaxSigmaC) |
There was a problem hiding this comment.
why do you need another function? Can't this be included in the already existing one (isSelectedSigmaCInDeltaMassRange) adding new bits?
There was a problem hiding this comment.
I can use a single function but I am afraid it need lot of input in the function, ex.
template <int charge = -1, typename T, typename H2>
inline int8_t HfFilterHelper::isSelectedSigmaCInDeltaMassRange(
const T& pTrackSameChargeFirst,
const T& pTrackSameChargeSecond,
const T& pTrackOppositeCharge,
const T& pTrackSoftPi,
const float ptSigmaC,
const int8_t isSelectedLc,
H2 hMassVsPt,
const int& activateQA,
bool useInvMassforScPr,
float mDeltaMassMinSigmaC,
float mDeltaMassMaxSigmaC,
float mPtMinSigmaC,
float mPtMaxSigmaC)
{}
or I can define some variable as a private member of class and then pass a function to initialize these variables, but as of now I think it would be commit and in second version I can optimize the code
| } | ||
| } | ||
| float deltaEta = std::abs(RecoDecay::eta(pVecSigmaC) - track.eta()); | ||
| if (!keepEvent[kSigmaCPr] && (isTrackProton && deltaEta < 1.0 && pt3Prong > 3.0)) { |
There was a problem hiding this comment.
Why do you have an hard-coded cut on the pt3Prong? Can't you put a configurable?
There was a problem hiding this comment.
Thanks Fabrizio for mentioning it, this is even irrelevant cut , I will remove it. This was a check, I was thinking that that pT Lc and pT Sc are correlated and by applying pTLc cut as a function of pTSc, I will be able to reduce the background. Though, I was wrong, I checked it and found that in the selected invariant mass of Sc, pT of Lc is always remain in the range pTSc -2 to pTSc +0.5. Therefore, from the current version, let me just remove it online.
mfaggin
left a comment
There was a problem hiding this comment.
Hi @fgrosa @singhra1994 I tried to go through the modifications and I posted some comments. It looks to me that the already existing trigger Sc-K is not affected by the proposed modifications, but I have a couple of warnings/comments for the Sc-p part.
| std::array<std::shared_ptr<TH1>, kNCharmParticles> hCharmDeuteronKstarDistr{}; | ||
| std::array<std::shared_ptr<TH2>, nTotBeautyParts> hMassVsPtB{}; | ||
| std::array<std::shared_ptr<TH2>, kNCharmParticles + 23> hMassVsPtC{}; // +9 for resonances (D*+, D*0, Ds*+, Ds1+, Ds2*+, Xic+* right sign, Xic+* wrong sign, Xic0* right sign, Xic0* wrong sign) +2 for SigmaC (SigmaC++, SigmaC0) +2 for SigmaCK pairs (SigmaC++K-, SigmaC0K0s) +3 for charm baryons (Xi+Pi, Xi+Ka, Xi+Pi+Pi) + JPsi + 4 for charm baryons (D0+p, D0+pWrongSign, D*0p, D*0+pWrongSign) | ||
| std::array<std::shared_ptr<TH2>, kNCharmParticles + 24> hMassVsPtC{}; // +9 for resonances (D*+, D*0, Ds*+, Ds1+, Ds2*+, Xic+* right sign, Xic+* wrong sign, Xic0* right sign, Xic0* wrong sign) +2 for SigmaC (SigmaC++, SigmaC0) +2 for SigmaCK pairs (SigmaC++K-, SigmaC0K0s) +3 for charm baryons (Xi+Pi, Xi+Ka, Xi+Pi+Pi) + JPsi + 4 for charm baryons (D0+p, D0+pWrongSign, D*0p, D*0+pWrongSign) |
There was a problem hiding this comment.
(very very minor) update also the comment
| bool isTrackProton = helper.isSelectedTrack4Corr(track, configSigmaC.trkPIDspecies, configSigmaC.pidTPCMax, configSigmaC.pidTOFMax, configSigmaC.minPtProton, configSigmaC.maxPtProton, configSigmaC.tofPIDThreshold, configSigmaC.forceTOF); | ||
|
|
||
| if ((!keepEvent[kSigmaCPPK] || !keepEvent[kSigmaCPr]) && is3Prong[2] > 0 && is3ProngInMass[2] > 0 && isSignalTagged[2] > 0 && (isTrackKaon || isTrackProton)) { | ||
| // we need a candidate Lc->pKpi and a candidate soft kaon |
There was a problem hiding this comment.
(minor) also here update the comment to improve the readibility (this is valid a bit everywhere)
| // check the mass of the SigmaC++,0 candidate | ||
| auto pVecSigmaC = RecoDecay::pVec(pVecFirst, pVecSecond, pVecThird, pVecSoftPi); | ||
| auto ptSigmaC = RecoDecay::pt(pVecSigmaC); | ||
| int8_t whichSigmaC = helper.isSelectedSigmaCInDeltaMassRange<2>(pVecFirst, pVecThird, pVecSecond, pVecSoftPi, ptSigmaC, is3Prong[2], hMassVsPtC[kNCharmParticles + 9], activateQA); |
There was a problem hiding this comment.
a warning here: the function helper.isSelectedSigmaCInDeltaMassRange<2> does a selection around the Sigmac++ mass only (note the <2> template parameter, which refers to the Sigmac charge). This is what we wanted for the already-existing triggers (Sc-K), but in your case you want correlations for both Sc0 and Sc++.
Mine is just a warning just because the masses of Sc0 and Sc++ are very very similar and this should be pretty harmless, but for your interest I suggest you to cross-check once more if there are other charge-dependent selections/functions that might not hold for your use-case.
| @@ -1560,51 +1577,59 @@ struct HfFilter { // Main struct for HF triggers | |||
| /// - it is in the correct mass range | |||
|
|
|||
| // check the charge for SigmaC++K- candidates | |||
There was a problem hiding this comment.
again: update the comment. At this stage not only the Sc-K total charge is checked, but also the Sc one
| } | ||
| } | ||
| } | ||
| float deltaEta = std::abs(RecoDecay::eta(pVecSigmaC) - track.eta()); |
There was a problem hiding this comment.
Again, at this stage it might be useful to have a comment of what you are doing, i.e. the fact that now you want to check the Sc-p correlation etc etc
|
|
||
| // array of BDT thresholds | ||
| std::array<LabeledArray<double>, kNCharmParticles> thresholdBDTScores; | ||
| std::array<LabeledArray<double>, kNCharmParticles + 1> thresholdBDTScores; |
There was a problem hiding this comment.
I agree with this comment: leave your BDT fully independent from the others which are general for the triggers.
| template <typename T1, typename T2, typename H2> | ||
| bool isSelectedTrack4Femto(const T1& track, const T2& trackPar, const int& activateQA, H2 hTPCPID, H2 hTOFPID, const int& trackSpecies); | ||
| template <typename Atrack, typename SpeciesContainer, typename T1, typename T2> | ||
| bool isSelectedTrack4Corr(Atrack const& track, SpeciesContainer const mPIDspecies, T1 const maxTPC, T2 const maxTOF, float minPt = 0.39, float maxPt = 4.6, float ptThreshold = 1.0, bool tofForced = false); |
There was a problem hiding this comment.
personally, I'd avoid default parameter values here
| template <int charge, typename T, typename H2> | ||
| int8_t isSelectedSigmaCInDeltaMassRange(const T& pTrackSameChargeFirst, const T& pTrackSameChargeSecond, const T& pTrackOppositeCharge, const T& pTrackSoftPi, const float ptSigmaC, const int8_t isSelectedLc, H2 hMassVsPt, const int& activateQA); | ||
| template <typename T, typename H2> | ||
| bool selectionSigmaCForScPCorr(const T& pTrackSameChargeFirst, const T& pTrackSameChargeSecond, const T& pTrackOppositeCharge, const T& pTrackSoftPi, const float ptSigmaC, const int8_t isSelectedLc, H2 hMassVsPt, const int& activateQA, float mDeltaMassMinSigmaC = 0.155, float mDeltaMassMaxSigmaC = 0.2, float mPtMinSigmaC = 4.99, float mPtMaxSigmaC = 12.0); |
There was a problem hiding this comment.
personally, I'd avoid default parameter values here
| /// Basic selection of proton or deuteron candidates | ||
| /// \param track is a track | ||
| /// \param mPIDspecies is a vector of different particle species | ||
| /// \param activateQA flag to activate the filling of QA histos | ||
| /// \param maxTPC is a vector of max TPCnSigma for different particle species | ||
| /// \param maxTOF is a vector of max TOFnSigma for different particle species | ||
| /// \param hProtonTPCPID histo with NsigmaTPC vs. p | ||
| /// \param hProtonTOFPID histo with NsigmaTOF vs. p | ||
| /// \return true if track passes all cuts | ||
| template <typename Atrack, typename SpeciesContainer, typename T1, typename T2> |
There was a problem hiding this comment.
this description is not consistent, and confusing. For example, during my review I was looking for an explanation of ptThreshold, which as far as I understand is the minimum pt at which you want to force the TOF for the proton (right?).
Please fix the description and possibly give meanigful names to the variables
| if (speciesIndex == 0) { // First species logic | ||
|
|
||
| if (std::abs(nSigmaTPC) > maxTPC->at(speciesIndex)) { | ||
| return false; // TPC check failed | ||
| } | ||
| if (track.hasTOF()) { | ||
| auto nSigmaTOF = o2::aod::pidutils::tofNSigma(pid, track); | ||
| if (std::abs(nSigmaTOF) > maxTOF->at(speciesIndex)) { | ||
| return false; // TOF check failed | ||
| } | ||
| } | ||
| } else { // Other species logic | ||
| if (std::abs(nSigmaTPC) < maxTPC->at(speciesIndex)) { // Check TPC nSigma first | ||
| if (track.hasTOF()) { | ||
| auto nSigmaTOF = o2::aod::pidutils::tofNSigma(pid, track); | ||
| if (std::abs(nSigmaTOF) < maxTOF->at(speciesIndex)) { | ||
| return false; // Reject if both TPC and TOF are within thresholds | ||
| } | ||
| } else { | ||
| return false; // Reject if only TPC is within threshold and TOF is unavailable | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Here I have a few questions
-
I agree with Fabrizio's comment, I do not understand why you loop over species and not just proton. Do you need to check other species (kaon, pion) because you want to apply a kaon and/or pion PID rejection? This is what I grasp from the code, but comments would help the reader
-
Why you treat differently the case
speciesIndex == 0from the others (once more: comment the code for the sake of readability)? Is it because the casespeciesIndex == 0corresponds to the proton hypothesis, and this is a special case for you (i.e. the "signal" one), while the others are used for PID rejection? If yes, then I find the solution of having the proton hypothesis as the 1st entry of aConfigurablevector a bit error-prone (I'm referring toConfigurable<std::vector<int>> trkPIDspecies). In case you want a PID rejection for other species, then I'd remove the proton from theConfigurablevector, and use this vector only for the species you want to use for the PID rejection (in other words: if by mistake one configures the vector with the order e.g. ka-pi-pr your logic is fully broken, but you can easily remove this possible mistake dedicateing theConfigurablevector for the species to be rejected).
There was a problem hiding this comment.
Hi @mfaggin I have defined this function in this way in HFCL analysis so that every one can use it for each combination of particle selection and rejection
Here, now I am not thinking to use piK rejection and hence code will be modified accordingly
There was a problem hiding this comment.
ok I see. It's not up to me to decide, but since the definition of the trigger program is not like the final analysis, if I were you I'd just keep the piece of code that you need (i.e. treat just the proton case for your trigger) and if somebody else will come then he/she will take care of adding the new functionalities.
I have modified the block trigger SigmaCPPK in such a way that both SigmaCPPK and SigmaCP can be filled in the same block