@@ -111,12 +111,21 @@ struct HfCandidateCreatorXicToXiPiPi {
111111 Configurable<bool > constrainXicPlusToPv{" constrainXicPlusToPv" , false , " Constrain XicPlus to PV" };
112112 Configurable<int > kfConstructMethod{" kfConstructMethod" , 2 , " Construct method of XicPlus: 0 fast mathematics without constraint of fixed daughter particle masses, 2 daughter particle masses stay fixed in construction process" };
113113 Configurable<bool > rejDiffCollTrack{" rejDiffCollTrack" , true , " Reject tracks coming from different collisions (effective only for KFParticle w/o derived data)" };
114+ // configurables for software trigger selections
115+ struct : ConfigurableGroup {
116+ std::string prefix = " softtrig" ;
117+ Configurable<bool > applySoftwareTrigSelections{" applySoftwareTrigSelections" , false , " Enable application of software trigger selections" };
118+ Configurable<float > minDecayLength{" minDecayLength" , 0.015 , " Minimum decay length (computed with DCAFitter)" };
119+ Configurable<float > minCosPA{" minCosPA" , 0.9 , " Minimum coine of pointing angle (computed with DCAFitter)" };
120+ Configurable<float > maxChi2Pca{" maxChi2Pca" , 3 ., " Maximum chi2 PCA (computed with DCAFitter)" };
121+ } softTrigCuts;
114122
115123 Service<o2::ccdb::BasicCCDBManager> ccdb{};
116124 o2::base::MatLayerCylSet* lut{};
117125 o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT;
118126
119127 o2::vertexing::DCAFitterN<3 > df;
128+ o2::vertexing::DCAFitterN<2 > df2Prong;
120129
121130 HfEventSelection hfEvSel;
122131
@@ -196,6 +205,66 @@ struct HfCandidateCreatorXicToXiPiPi {
196205 df.setMinRelChi2Change (minRelChi2Change);
197206 df.setUseAbsDCA (useAbsDCA);
198207 df.setWeightedFinalPCA (useWeightedFinalPCA);
208+
209+ if (softTrigCuts.applySoftwareTrigSelections ) {
210+ float maxRadSoftTrig = 200 .;
211+ float maxDZIniSoftTrig = 1 .e9 ;
212+ float maxDXYIniSoftTrig = 4 .;
213+ float minParamChangeSoftTrig = 1 .e -3 ;
214+ float maxChi2SoftTrig = 0.9 ;
215+ float minRelChi2ChangeSoftTrig = 0.9 ;
216+ df2Prong.setPropagateToPCA (true );
217+ df2Prong.setMaxR (maxRadSoftTrig);
218+ df2Prong.setMaxDZIni (maxDZIniSoftTrig);
219+ df2Prong.setMaxDXYIni (maxDXYIniSoftTrig);
220+ df2Prong.setMinParamChange (minParamChangeSoftTrig);
221+ df2Prong.setMinRelChi2Change (minRelChi2ChangeSoftTrig);
222+ df2Prong.setMaxChi2 (maxChi2SoftTrig);
223+ df2Prong.setUseAbsDCA (false );
224+ df2Prong.setWeightedFinalPCA (false );
225+ }
226+ }
227+
228+ // / Method that reapplies the selections applied in the software trigger
229+ // / \param pVecCascade is the cascade momentum vector
230+ // / \param trackParBachelor is the array with two bachelor track parametrisations
231+ // / \param collision is the collision containing the candidate
232+ template <typename TTrackParCov, typename Coll>
233+ bool isSelectedXicSoftwareTriggers (std::array<float , 3 > const & pVecCascade, std::array<TTrackParCov, 2 > const & trackParBachelor, Coll const & collision)
234+ {
235+ int nCand{0 };
236+ try {
237+ nCand = df2Prong.process (trackParBachelor[0 ], trackParBachelor[1 ]);
238+ } catch (...) {
239+ LOG (error) << " Exception caught in DCA fitter process call for bachelor + bachelor in software trigger selection function!" ;
240+ return false ;
241+ }
242+ if (nCand == 0 ) {
243+ return false ;
244+ }
245+
246+ const auto & vtx = df2Prong.getPCACandidate ();
247+ if (df2Prong.getChi2AtPCACandidate () > softTrigCuts.maxChi2Pca ) {
248+ return false ;
249+ }
250+
251+ std::array<float , 3 > pVecBachFirst{}, pVecBachSecond{};
252+ const auto & trackBachFirstProp = df2Prong.getTrack (0 );
253+ const auto & trackBachSecondProp = df2Prong.getTrack (1 );
254+ trackBachFirstProp.getPxPyPzGlo (pVecBachFirst);
255+ trackBachSecondProp.getPxPyPzGlo (pVecBachSecond);
256+ auto momXiBachBach = RecoDecay::pVec (pVecCascade, pVecBachFirst, pVecBachSecond);
257+
258+ std::array<float , 3 > primVtx = {collision.posX (), collision.posY (), collision.posZ ()};
259+ if (RecoDecay::cpa (primVtx, std::array{vtx[0 ], vtx[1 ], vtx[2 ]}, momXiBachBach) < softTrigCuts.minCosPA ) {
260+ return false ;
261+ }
262+
263+ if (RecoDecay::distance (primVtx, vtx) < softTrigCuts.minDecayLength ) {
264+ return false ;
265+ }
266+
267+ return true ;
199268 }
200269
201270 template <o2::hf_centrality::CentralityEstimator CentEstimator, typename Collision>
@@ -282,6 +351,13 @@ struct HfCandidateCreatorXicToXiPiPi {
282351 auto trackParCovCharmBachelor0 = getTrackParCov (trackCharmBachelor0);
283352 auto trackParCovCharmBachelor1 = getTrackParCov (trackCharmBachelor1);
284353
354+ // if enabled, apply selections of software trigger
355+ if (softTrigCuts.applySoftwareTrigSelections ) {
356+ if (!isSelectedXicSoftwareTriggers (pVecCasc, std::array{trackParCovCharmBachelor0, trackParCovCharmBachelor1}, collision)) {
357+ continue ;
358+ }
359+ }
360+
285361 // reconstruct the 3-prong secondary vertex
286362 try {
287363 if (df.process (trackCasc, trackParCovCharmBachelor0, trackParCovCharmBachelor1) == 0 ) {
@@ -459,9 +535,20 @@ struct HfCandidateCreatorXicToXiPiPi {
459535 continue ;
460536 }
461537 auto casc = cascAodElement.kfCascData_as <KFCascFull>();
538+
462539 auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as <TracksWCovExtraPidPrPi>();
463540 auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as <TracksWCovExtraPidPrPi>();
464541
542+ // if enabled, apply selections of software trigger
543+ if (softTrigCuts.applySoftwareTrigSelections ) {
544+ auto trackParCovCharmBachelor0 = getTrackParCov (trackCharmBachelor0);
545+ auto trackParCovCharmBachelor1 = getTrackParCov (trackCharmBachelor1);
546+ std::array<float , 3 > const pVecCasc = {casc.px (), casc.py (), casc.pz ()};
547+ if (!isSelectedXicSoftwareTriggers (pVecCasc, std::array{trackParCovCharmBachelor0, trackParCovCharmBachelor1}, collision)) {
548+ continue ;
549+ }
550+ }
551+
465552 // -------------------preselect cascade candidates--------------------------------------
466553 if (doCascadePreselection) {
467554 if (std::abs (casc.dcaXYCascToPV ()) > dcaXYToPVCascadeMax) {
0 commit comments