25 template <
unsigned int n_summary_types>
26 std::array<xAOD::SummaryType, n_summary_types> summaryArray( std::array<xAOD::SummaryType, n_summary_types> summary_types) {
return summary_types; }
28 template <
class Trk_Helper,
unsigned int n_summary_types>
31 MinTRTHitsCut(
double maxTrtEtaAcceptance,
32 double maxEtaForTrtHitCuts,
34 std::array<xAOD::SummaryType, n_summary_types> summary_types)
35 : m_maxTrtEtaAcceptance(maxTrtEtaAcceptance),
36 m_maxEtaForTrtHitCuts(maxEtaForTrtHitCuts),
37 m_minNHits(min_n_hits),
38 m_summaryTypes(summary_types)
46 return (absEta <= m_maxTrtEtaAcceptance || absEta > m_maxEtaForTrtHitCuts) || nHits(
helper,msgHelper) >=m_minNHits;
49 double m_maxTrtEtaAcceptance;
50 double m_maxEtaForTrtHitCuts;
52 std::array<xAOD::SummaryType, n_summary_types> m_summaryTypes;
58 unsigned int findBin(
const std::vector<T> &
bins, T
value) {
60 unsigned int bin_i=
bins.size();
67 if (
bins.empty())
return true;
68 for (
unsigned int bin_i=1; bin_i<
bins.size(); ++bin_i) {
69 if (
bins[bin_i-1]>=
bins[bin_i])
return false;
75 InDet::InDetTrackSelectionTool::InDetTrackSelectionTool(
const std::string&
name)
77 , m_acceptInfo(
"InDetTrackSelection" )
85 #ifndef XAOD_STANDALONE
86 declareInterface<IInDetTrackSelectionTool>(
this);
92 InDet::InDetTrackSelectionTool::~InDetTrackSelectionTool() =
default;
105 if (m_isInitialized) {
106 ATH_MSG_ERROR(
"Tool has already been initialized. This is illegitimate." );
107 ATH_MSG_ERROR(
"This call to initialize() will do nothing." );
108 return StatusCode::SUCCESS;
116 if (!m_cutLevel.empty()) {
117 std::unordered_map<std::string, InDet::CutLevel>::const_iterator it_mapCutLevel = s_mapCutLevel.find(m_cutLevel);
118 if ( it_mapCutLevel == s_mapCutLevel.end() ) {
119 ATH_MSG_ERROR(
"The string \"" << m_cutLevel <<
"\" is not recognized as a cut level. No cuts will be changed." );
121 for (
const auto&
opt : s_mapCutLevel) {
125 ATH_MSG_DEBUG(
"Cut level set to \"" << it_mapCutLevel->first <<
"\"." );
126 ATH_MSG_DEBUG(
"This will not overwrite other cuts that have been set.");
127 setCutLevelPrivate( it_mapCutLevel->second,
false );
131 #ifndef XAOD_ANALYSIS
132 if (m_initTrkTools) {
133 m_trackSumToolAvailable =
false;
134 if (!m_trackSumTool.empty()) {
137 m_trackSumToolAvailable =
true;
142 m_extrapolator.disable();
143 m_trackSumTool.disable();
145 #endif // XAOD_ANALYSIS
148 m_msgHelper = std::make_unique<asg::AsgMessaging>(
this) ;
151 #ifndef XAOD_ANALYSIS
153 ATH_CHECK( setupCuts<0>(m_trkTrackCuts) );
154 ATH_CHECK( setupCuts<0>(m_trackParticleCuts) );
156 ATH_CHECK( setupCuts<1>(m_trackParticleCuts) );
159 for (
const auto& cutFamily : m_trackParticleCuts) {
160 const std::string& cutFamilyName = cutFamily.first;
162 m_numTracksPassedCuts.push_back(0);
163 if (m_acceptInfo.addCut( cutFamilyName,
"Selection of tracks according to " + cutFamilyName ) < 0) {
164 ATH_MSG_ERROR(
"Failed to add cut family " << cutFamilyName <<
" because the TAccept object is full." );
165 return StatusCode::FAILURE;
170 m_isInitialized =
true;
172 return StatusCode::SUCCESS;
176 template <
typename T>
177 inline T
sqr(T
a) {
return a *
a;}
179 template <
int VERBOSE,
class Trk_Helper>
184 trackCuts[
"Pt"].push_back( [minPt = m_minPt](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) ->
bool {
return helper.pt(msgHelper) >= minPt; } );
186 if (maxDoubleIsSet(m_maxAbsEta)) {
188 trackCuts[
"Eta"].push_back( [maxAbsEta = m_maxAbsEta](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
return std::abs(
helper.eta(msgHelper)) <= maxAbsEta; } );
192 trackCuts[
"P"].push_back( [maxInvP = 1./m_minP](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
return std::abs(
helper.qOverP(msgHelper)) <= maxInvP; } );
194 if (maxDoubleIsSet(m_maxD0)) {
196 trackCuts[
"D0"].push_back( [maxD0 = m_maxD0](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
return std::abs(
helper.d0(msgHelper)) <= maxD0; } );
198 if (maxDoubleIsSet(m_maxZ0)) {
200 trackCuts[
"Z0"].push_back( [maxZ0 = m_maxZ0](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
return std::abs(
helper.z0(msgHelper)) <= maxZ0; } );
202 if (maxDoubleIsSet(m_maxZ0SinTheta)) {
203 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum z0*sin(theta): " << m_maxZ0SinTheta <<
" mm" );
204 trackCuts[
"Z0SinTheta"].push_back([maxZ0SinTheta = m_maxZ0SinTheta](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
208 if (maxDoubleIsSet(m_maxSigmaD0)) {
209 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum uncertainty on d0: " << m_maxSigmaD0 <<
" mm" );
210 trackCuts[
"D0"].push_back([maxSigmaD0Squared =
sqr(m_maxSigmaD0.value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
211 return getDefiningParametersCov(helper,msgHelper, InDetAccessor::d0,InDetAccessor::d0) <= maxSigmaD0Squared;
214 if (maxDoubleIsSet(m_maxSigmaZ0)) {
215 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum uncertainty on z0: " << m_maxSigmaZ0 <<
" mm" );
216 trackCuts[
"Z0"].push_back([maxSigmaZ0Squared =
sqr(m_maxSigmaZ0.value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
217 return getDefiningParametersCov(helper,msgHelper, InDetAccessor::z0,InDetAccessor::z0) <= maxSigmaZ0Squared;
220 if (maxDoubleIsSet(m_maxSigmaZ0SinTheta)) {
222 << m_maxSigmaZ0SinTheta <<
" mm" );
223 trackCuts[
"Z0SinTheta"].push_back([maxSigmaZ0SinThetaSquared =
sqr(m_maxSigmaZ0SinTheta.value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
224 double theta = helper.theta(msgHelper);
225 double sinTheta = std::sin(theta);
226 double cosTheta = std::cos(theta);
227 double z0 = helper.z0(msgHelper);
229 return ( sqr(z0)*sqr(cosTheta) * getDefiningParametersCov(helper,msgHelper, InDetAccessor::theta,InDetAccessor::theta)
230 + 2*z0 *sinTheta*cosTheta * getDefiningParametersCov(helper,msgHelper, InDetAccessor::theta,InDetAccessor::z0)
231 + sqr(sinTheta) * getDefiningParametersCov(helper,msgHelper, InDetAccessor::z0, InDetAccessor::z0) ) <= maxSigmaZ0SinThetaSquared;
234 if (maxDoubleIsSet(m_maxD0overSigmaD0)) {
235 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum significance on d0: " << m_maxD0overSigmaD0 );
236 trackCuts[
"D0"].push_back([maxD0overSigmaD0Squared =
sqr(m_maxD0overSigmaD0.value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
237 return sqr(helper.d0(msgHelper)) <= maxD0overSigmaD0Squared * getDefiningParametersCov(helper,msgHelper, InDetAccessor::d0,InDetAccessor::d0);
240 if (maxDoubleIsSet(m_maxZ0overSigmaZ0)) {
241 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum significance on z0: " << m_maxZ0overSigmaZ0 );
242 trackCuts[
"Z0"].push_back([maxZ0overSigmaZ0Squared =
sqr(m_maxZ0overSigmaZ0.value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) ->
bool {
243 return sqr(helper.z0(msgHelper)) <= maxZ0overSigmaZ0Squared * getDefiningParametersCov(helper,msgHelper, InDetAccessor::z0,InDetAccessor::z0);
246 if (maxDoubleIsSet(m_maxZ0SinThetaoverSigmaZ0SinTheta)) {
248 << m_maxZ0SinThetaoverSigmaZ0SinTheta );
249 trackCuts[
"Z0SinTheta"].push_back([maxZ0SinThetaoverSigmaZ0SinThetaSquared =
sqr(m_maxZ0SinThetaoverSigmaZ0SinTheta.value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
251 double theta = helper.theta(msgHelper);
252 double sinTheta = std::sin(theta);
253 double cosTheta = std::cos(theta);
254 double z0 = helper.z0(msgHelper);
256 return sqr(z0*sinTheta) <=
257 maxZ0SinThetaoverSigmaZ0SinThetaSquared * ( sqr(z0)*sqr(cosTheta) * getDefiningParametersCov(helper,msgHelper, InDetAccessor::theta,InDetAccessor::theta)
258 + 2*z0 *sinTheta*cosTheta * getDefiningParametersCov(helper,msgHelper, InDetAccessor::theta,InDetAccessor::z0)
259 + sqr(sinTheta) * getDefiningParametersCov(helper,msgHelper, InDetAccessor::z0, InDetAccessor::z0));
264 if (m_minNInnermostLayerHits > 0) {
265 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum hits from innermost pixel layer: " << m_minNInnermostLayerHits );
267 trackCuts[
"InnermostLayersHits"].push_back([minNInnermostLayerHits = m_minNInnermostLayerHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
272 if (m_minNNextToInnermostLayerHits > 0) {
273 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum hits from next to innermost pixel layer: " << m_minNNextToInnermostLayerHits );
275 trackCuts[
"InnermostLayersHits"].push_back([minNNextToInnermostLayerHits = m_minNNextToInnermostLayerHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
280 if (m_minNBothInnermostLayersHits > 0) {
281 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum hits from both innermost pixel layers: " << m_minNBothInnermostLayersHits );
282 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" (If a layer has no hits but one is not expected, the" );
283 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" number of hits in that layer will be taken to be 1.)" );
284 if (m_minNBothInnermostLayersHits > 2) {
285 ATH_MSG_WARNING(
"A value of minNBothInnermostLayersHits above 2 does not make sense." );
288 trackCuts[
"InnermostLayersHits"].push_back([minNBothInnermostLayersHits = m_minNBothInnermostLayersHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
293 >= minNBothInnermostLayersHits);
296 if (m_useMinBiasInnermostLayersCut > 0 ) {
297 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" An innermost layer hit is required if expected, otherwise" );
298 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" a next-to-innermost layer hit is required if it is expected." );
306 if (maxIntIsSet(m_maxNInnermostLayerSharedHits)) {
307 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum shared hits in innermost pixel layer: " << m_maxNInnermostLayerSharedHits );
308 trackCuts[
"InnermostLayersHits"].push_back([maxNInnermostLayerSharedHits = m_maxNInnermostLayerSharedHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
312 if (m_minNPixelHits > 0) {
314 trackCuts[
"PixelHits"].push_back( [minNPixelHits = m_minNPixelHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
318 if (m_minNPixelHitsPhysical > 0) {
319 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum physical pixel hits (i.e. dead sensors do not count): "
320 << m_minNPixelHitsPhysical );
321 trackCuts[
"PixelHits"].push_back([minNPixelHitsPhysical = m_minNPixelHitsPhysical](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
325 if (maxIntIsSet(m_maxNPixelHoles)) {
327 trackCuts[
"PixelHits"].push_back([maxNPixelHoles = m_maxNPixelHoles](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
331 if (maxIntIsSet(m_maxNPixelSharedHits)) {
332 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum pixel shared hits: " << m_maxNPixelSharedHits );
333 trackCuts[
"PixelHits"].push_back([maxNPixelSharedHits = m_maxNPixelSharedHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
337 if (m_minNSctHits > 0) {
339 trackCuts[
"SctHits"].push_back( [minNSctHits = m_minNSctHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
343 if (m_minNSctHitsPhysical > 0) {
344 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum physical SCT hits (i.e. dead sensors do not count): "
345 << m_minNSctHitsPhysical );
346 trackCuts[
"SctHits"].push_back([minNSctHitsPhysical = m_minNSctHitsPhysical](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
350 if (maxIntIsSet(m_maxNSctHoles)) {
352 trackCuts[
"SctHits"].push_back([maxNSctHoles = m_maxNSctHoles](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
356 if (maxIntIsSet(m_maxNSctSharedHits)) {
357 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum SCT shared hits: " << m_maxNSctSharedHits );
358 trackCuts[
"SctHits"].push_back([maxNSctSharedHits = m_maxNSctSharedHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
362 if (maxIntIsSet(m_maxNSctDoubleHoles)) {
363 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum SCT double holes: " << m_maxNSctDoubleHoles );
364 trackCuts[
"SctHits"].push_back([maxNSctDoubleHoles = m_maxNSctDoubleHoles](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
368 if (m_minNSiHits > 0) {
369 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum silicon (pixel + SCT) hits: " << m_minNSiHits );
370 trackCuts[
"SiHits"].push_back([minNSiHits = m_minNSiHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
377 if (m_minNSiHitsPhysical > 0) {
378 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum physical silicon hits (i.e. dead sensors do not count): "
379 << m_minNSiHitsPhysical );
380 trackCuts[
"SiHits"].push_back([minNSiHitsPhysical = m_minNSiHitsPhysical](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
384 if (maxIntIsSet(m_maxNSiHoles)) {
386 trackCuts[
"SiHits"].push_back([maxNSiHoles = m_maxNSiHoles](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
390 if (maxIntIsSet(m_maxNSiSharedHits)) {
391 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum silicon shared hits: " << m_maxNSiSharedHits );
392 trackCuts[
"SiHits"].push_back([maxNSiSharedHits = m_maxNSiSharedHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
396 if (m_maxOneSharedModule) {
405 if (m_minNSiHitsIfSiSharedHits > 0) {
406 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum silicon hits if the track has shared hits: "
407 << m_minNSiHitsIfSiSharedHits );
408 trackCuts[
"SiHits"].push_back([minNSiHitsIfSiSharedHits = m_minNSiHitsIfSiSharedHits](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
416 if (maxDoubleIsSet(m_minEtaForStrictNSiHitsCut)
417 && m_minNSiHitsAboveEtaCutoff > 0) {
419 <<
" silicon hits above eta = " << m_minEtaForStrictNSiHitsCut );
420 trackCuts[
"SiHits"].push_back([minEtaForStrictNSiHitsCut = m_minEtaForStrictNSiHitsCut,
421 minNSiHitsAboveEtaCutoff = m_minNSiHitsAboveEtaCutoff](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
422 return std::abs(
helper.eta(msgHelper)) <= minEtaForStrictNSiHitsCut
429 if (m_useExperimentalInnermostLayersCut) {
430 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Zero pixel holes allowed, except one pix hole is allowed if there is a physical IBL hit and a BLayer hit is expected but there is no BLayer hit." );
438 #ifndef XAOD_ANALYSIS
439 if (m_minNSiHitsMod > 0) {
440 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum modified Si hits (2*pix + sct) (does not include dead sensors)= "
441 << m_minNSiHitsMod );
442 trackCuts[
"SiHits"].push_back([minNSiHitsMod = m_minNSiHitsMod](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
448 if (m_minNSiHitsModTop > 0 || m_minNSiHitsModBottom > 0) {
450 << m_minNSiHitsModTop );
452 << m_minNSiHitsModBottom );
453 trackCuts[
"SiHits"].push_back([minNSiHitsModTop = m_minNSiHitsModTop,
456 return top >= minNSiHitsModTop && bottom >= minNSiHitsModBottom;
460 if (m_maxEtaForTrtHitCuts > 0. && m_maxTrtEtaAcceptance < m_maxEtaForTrtHitCuts) {
461 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" -- TRT hit cuts applied above eta = " << m_maxTrtEtaAcceptance
462 <<
" and below eta = " << m_maxEtaForTrtHitCuts <<
" --" );
463 if (m_minNTrtHits > 0) {
464 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum TRT hits outside eta acceptance: " << m_minNTrtHits );
465 trackCuts[
"TrtHits"].push_back( MinTRTHitsCut<Trk_Helper,1>( m_maxTrtEtaAcceptance, m_maxEtaForTrtHitCuts, m_minNTrtHits,
468 if (m_minNTrtHitsPlusOutliers > 0) {
469 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum TRT hits outside eta acceptance including outliers: " << m_minNTrtHitsPlusOutliers );
470 trackCuts[
"TrtHits"].push_back( MinTRTHitsCut<Trk_Helper,2>( m_maxTrtEtaAcceptance,m_maxEtaForTrtHitCuts, m_minNTrtHitsPlusOutliers,
473 if (m_minNTrtHighThresholdHits > 0) {
474 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum TRT hits outside eta acceptance above high energy threshold: "
475 << m_minNTrtHighThresholdHits );
476 trackCuts[
"TrtHits"].push_back( MinTRTHitsCut<Trk_Helper,1>( m_maxTrtEtaAcceptance,m_maxEtaForTrtHitCuts, m_minNTrtHighThresholdHits,
479 if (m_minNTrtHighThresholdHitsPlusOutliers > 0) {
480 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum TRT hits outside eta acceptance above high energy threshold including outliers: "
481 << m_minNTrtHighThresholdHitsPlusOutliers );
482 trackCuts[
"TrtHits"].push_back( MinTRTHitsCut<Trk_Helper,2>( m_maxTrtEtaAcceptance,m_maxEtaForTrtHitCuts, m_minNTrtHighThresholdHitsPlusOutliers,
485 if (maxDoubleIsSet(m_maxTrtHighEFraction)) {
486 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum ratio of high threshold to regular TRT hits outside eta acceptance: "
487 << m_maxTrtHighEFraction);
488 trackCuts[
"TrtHits"].push_back([maxTrtEtaAcceptance = m_maxTrtEtaAcceptance,
489 maxEtaForTrtHitCuts = m_maxEtaForTrtHitCuts,
492 return (absEta <= maxTrtEtaAcceptance || absEta > maxEtaForTrtHitCuts)
497 if (maxDoubleIsSet(m_maxTrtHighEFractionWithOutliers)) {
498 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum ratio of high threshold to regular TRT hits above eta acceptance including outliers: "
499 << m_maxTrtHighEFractionWithOutliers);
500 trackCuts[
"TrtHits"].push_back([maxTrtEtaAcceptance = m_maxTrtEtaAcceptance,
501 maxEtaForTrtHitCuts = m_maxEtaForTrtHitCuts,
502 maxTrtHighEFractionWithOutliers = m_maxTrtHighEFractionWithOutliers](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
504 return (absEta <= maxTrtEtaAcceptance || absEta > maxEtaForTrtHitCuts)
509 if (m_maxTrtOutlierFraction < 1. && m_maxTrtOutlierFraction >= 0.) {
510 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum fraction of TRT hits that are outliers: " << m_maxTrtOutlierFraction );
511 trackCuts[
"TrtHits"].push_back([maxTrtEtaAcceptance = m_maxTrtEtaAcceptance,
512 maxEtaForTrtHitCuts = m_maxEtaForTrtHitCuts,
516 return ( absEta <= maxTrtEtaAcceptance || absEta > maxEtaForTrtHitCuts)
523 if (m_useEtaDependentMaxChiSq) {
524 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Using pre-defined eta-dependent maximum chi squared (no longer recommended)." );
529 if (std::abs(
eta) < 1.9) {
530 return fit_chi_square <= fit_ndof * ( 4.4 + 0.32*
sqr(
eta) );
533 return fit_chi_square <= fit_ndof * ( 26.9 - 19.6978*std::abs(
eta) + 4.4534*
sqr(
eta) );
537 if (maxDoubleIsSet(m_maxChiSq)) {
539 trackCuts[
"FitQuality"].push_back([maxChiSq = m_maxChiSq](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
543 if (maxDoubleIsSet(m_maxChiSqperNdf)) {
544 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Maximum chi squared per degree of freedom: " << m_maxChiSqperNdf );
545 trackCuts[
"FitQuality"].push_back([maxChiSqperNdf = m_maxChiSqperNdf](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
549 if (m_minProb > 0.) {
551 trackCuts[
"FitQuality"].push_back([minProb = m_minProb](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
555 if (maxDoubleIsSet(m_minPtForProbCut) && m_minProbAbovePtCutoff > 0.) {
556 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum chi-sq probability of " << m_minProbAbovePtCutoff
557 <<
" above pt of " << m_minPtForProbCut*1
e-3 <<
" GeV." );
558 trackCuts[
"FitQuality"].push_back([minPtForProbCut = m_minPtForProbCut,
560 return helper.pt(msgHelper) <= minPtForProbCut
566 if (m_minNUsedHitsdEdx > 0) {
567 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum used hits for dEdx: " << m_minNUsedHitsdEdx );
568 trackCuts[
"dEdxHits"].push_back([minNUsedHitsdEdx = m_minNUsedHitsdEdx](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
572 if (m_minNOverflowHitsdEdx > 0) {
573 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum IBL overflow hits for dEdx: " << m_minNOverflowHitsdEdx );
574 trackCuts[
"dEdxHits"].push_back([minNOverflowHitsdEdx = m_minNOverflowHitsdEdx](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
578 if (m_minEProbabilityHT > 0) {
579 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" Minimum high threshold electron probability: " << m_minEProbabilityHT );
580 if (m_eProbHTonlyForXe) {
581 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" (only applied on tracks where all TRT hits are Xenon)" );
582 trackCuts[
"eProbHT"].push_back([minEProbabilityHT = m_minEProbabilityHT](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
588 trackCuts[
"eProbHT"].push_back([minEProbabilityHT = m_minEProbabilityHT](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
594 if (!m_vecEtaCutoffsForSiHitsCut.empty() || !m_vecMinNSiHitsAboveEta.empty()) {
595 auto cutSize = m_vecEtaCutoffsForSiHitsCut.size();
596 if (cutSize != m_vecMinNSiHitsAboveEta.size()) {
597 ATH_MSG_ERROR(
"Eta cutoffs and Silicon hit cuts must be vectors of the same length." );
598 return StatusCode::FAILURE;
601 for (
size_t i_cut=0; i_cut<cutSize-1; ++i_cut) {
602 ATH_MSG_INFO(
" for " << m_vecEtaCutoffsForSiHitsCut[i_cut]
603 <<
" < eta < " << m_vecEtaCutoffsForSiHitsCut[i_cut+1]
604 <<
" ,Silicon hits >= " << m_vecMinNSiHitsAboveEta[i_cut] );
607 if (!
checkOrder(m_vecEtaCutoffsForSiHitsCut.value())) {
609 return StatusCode::FAILURE;
611 if constexpr(
VERBOSE>0)
ATH_MSG_INFO(
" for eta > " << m_vecEtaCutoffsForSiHitsCut[cutSize-1]
612 <<
" ,Silicon hits >= " << m_vecMinNSiHitsAboveEta[cutSize-1] );
614 trackCuts[
"SiHits"].push_back([p_vecEtaCutoffsForSiHitsCut = &std::as_const(m_vecEtaCutoffsForSiHitsCut.value()),
615 p_vecMinNSiHitsAboveEta = &std::as_const(m_vecMinNSiHitsAboveEta.value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
616 double abs_eta = std::abs(helper.eta(msgHelper));
617 unsigned int bin_i = findBin(*p_vecEtaCutoffsForSiHitsCut, abs_eta);
618 return bin_i >= p_vecMinNSiHitsAboveEta->size()
620 || getSummarySum<4,Trk_Helper>(helper, msgHelper,{xAOD::numberOfPixelHits,
621 xAOD::numberOfSCTHits,
622 xAOD::numberOfPixelDeadSensors,
623 xAOD::numberOfSCTDeadSensors}) >= (*p_vecMinNSiHitsAboveEta)[bin_i];
627 if (!m_vecEtaCutoffsForPtCut.empty() || !m_vecMinPtAboveEta.empty()) {
628 auto cutSize = m_vecEtaCutoffsForPtCut.size();
629 if (cutSize != m_vecMinPtAboveEta.size()) {
630 ATH_MSG_ERROR(
"Eta cutoffs and pT cuts must be vectors of the same length." );
631 return StatusCode::FAILURE;
634 for (
size_t i_cut=0; i_cut<cutSize-1; ++i_cut) {
636 <<
" < eta < " << m_vecEtaCutoffsForPtCut[i_cut+1]
637 <<
" ,transverse momentum >= " << m_vecMinPtAboveEta[i_cut] );
640 if (!
checkOrder(m_vecEtaCutoffsForPtCut.value())) {
642 return StatusCode::FAILURE;
645 << " ,transverse
momentum >= " << m_vecMinPtAboveEta[cutSize-1] );
646 trackCuts["
Pt"].push_back([p_vecEtaCutoffsForPtCut = &std::as_const(m_vecEtaCutoffsForPtCut.
value()),
647 p_vecMinPtAboveEta = &std::as_const(m_vecMinPtAboveEta.
value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
648 double abs_eta = std::abs(
helper.eta(msgHelper));
649 unsigned int bin_i = findBin(*p_vecEtaCutoffsForPtCut, abs_eta);
650 return bin_i >= p_vecMinPtAboveEta->size() || abs_eta > 5.0 ||
helper.pt(msgHelper) >= (*p_vecMinPtAboveEta)[bin_i];
654 if (!m_vecPtCutoffsForSctHitsCut.empty() || !m_vecMinNSctHitsAbovePt.empty()) {
655 auto cutSize = m_vecPtCutoffsForSctHitsCut.size();
656 if (cutSize != m_vecMinNSctHitsAbovePt.size()) {
657 ATH_MSG_ERROR(
"Pt cutoffs and SCT hit cuts must be vectors of the same length." );
658 return StatusCode::FAILURE;
661 for (
size_t i_cut=0; i_cut<cutSize-1; ++i_cut) {
662 ATH_MSG_INFO(
" for " << m_vecPtCutoffsForSctHitsCut[i_cut]
663 <<
" < pt < " << m_vecPtCutoffsForSctHitsCut[i_cut+1]
664 <<
" MeV,\tSCT hits >= " << m_vecMinNSctHitsAbovePt[i_cut] );
667 if (!
checkOrder(m_vecPtCutoffsForSctHitsCut.value())) {
669 return StatusCode::FAILURE;
672 << "
MeV,\
t\tSCT
hits >= " << m_vecMinNSctHitsAbovePt[cutSize-1] );
673 trackCuts["SctHits"].push_back([p_vecPtCutoffsForSctHitsCut = &std::as_const(m_vecPtCutoffsForSctHitsCut.
value()),
674 p_vecMinNSctHitsAbovePt = &std::as_const(m_vecMinNSctHitsAbovePt.
value())](Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
676 unsigned int bin_i = findBin(*p_vecPtCutoffsForSctHitsCut,
pt);
677 return bin_i >= p_vecPtCutoffsForSctHitsCut->size()
683 if (!m_vecPtCutoffsForZ0SinThetaCut.empty() ||
684 !m_vecEtaCutoffsForZ0SinThetaCut.empty() ||
685 !m_vecvecMaxZ0SinThetaAboveEtaPt.empty()) {
686 auto etaSize = m_vecEtaCutoffsForZ0SinThetaCut.size();
687 auto ptSize = m_vecPtCutoffsForZ0SinThetaCut.size();
688 if (etaSize != m_vecvecMaxZ0SinThetaAboveEtaPt.size()) {
689 ATH_MSG_ERROR(
"Eta cutoffs and Z0SinTheta cuts must be vectors of the same length." );
690 return StatusCode::FAILURE;
692 for (
size_t i_size=0; i_size<etaSize-1; ++i_size) {
693 if (ptSize != m_vecvecMaxZ0SinThetaAboveEtaPt[i_size].
size()) {
694 ATH_MSG_ERROR(
"Pt cutoffs and Z0SinTheta cuts must be vectors of the same length." );
695 return StatusCode::FAILURE;
699 std::stringstream pTRangeBuffer;
700 std::copy(m_vecPtCutoffsForZ0SinThetaCut.begin(), m_vecPtCutoffsForZ0SinThetaCut.end(), std::ostream_iterator<Double_t>(pTRangeBuffer,
", "));
701 std::string pTString=pTRangeBuffer.str();
703 for (
size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
705 std::stringstream etaRangeBuffer;
706 etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForZ0SinThetaCut[i_cut_eta] <<
" < |#eta| < ";
707 if(i_cut_eta!=etaSize-1) etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForZ0SinThetaCut[i_cut_eta+1];
708 else etaRangeBuffer << std::setprecision(2) << std::fixed <<m_maxAbsEta;
710 std::stringstream cutBuffer;
711 std::copy(m_vecvecMaxZ0SinThetaAboveEtaPt[i_cut_eta].
begin(), m_vecvecMaxZ0SinThetaAboveEtaPt[i_cut_eta].
end(), std::ostream_iterator<Double_t>(cutBuffer,
", "));
712 std::string cutString=cutBuffer.str();
719 return StatusCode::FAILURE;
721 if (!
checkOrder(m_vecPtCutoffsForZ0SinThetaCut.value())) {
723 return StatusCode::FAILURE;
726 trackCuts[
"Z0SinTheta"].push_back([p_vecEtaCutoffsForZ0SinThetaCut = &std::as_const(m_vecEtaCutoffsForZ0SinThetaCut.value()),
727 p_vecPtCutoffsForZ0SinThetaCut = &std::as_const(m_vecPtCutoffsForZ0SinThetaCut.value()),
728 p_vecvecMaxZ0SinThetaAboveEtaPt = &std::as_const(m_vecvecMaxZ0SinThetaAboveEtaPt.value())] (Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
729 double eta = helper.eta(msgHelper);
730 unsigned int bin_eta = findBin(*p_vecEtaCutoffsForZ0SinThetaCut, std::fabs(eta));
731 double pt = helper.pt(msgHelper);
732 unsigned int bin_pt = findBin(*p_vecPtCutoffsForZ0SinThetaCut, pt);
733 return bin_eta >= p_vecEtaCutoffsForZ0SinThetaCut->size()
734 || bin_pt >= p_vecPtCutoffsForZ0SinThetaCut->size()
735 || std::fabs(helper.z0(msgHelper) * std::sin(helper.theta(msgHelper))) <= (*p_vecvecMaxZ0SinThetaAboveEtaPt)[bin_eta][bin_pt];
739 if (!m_vecPtCutoffsForD0Cut.empty() ||
740 !m_vecEtaCutoffsForD0Cut.empty() ||
741 !m_vecvecMaxD0AboveEtaPt.empty()) {
742 auto etaSize = m_vecEtaCutoffsForD0Cut.size();
743 auto ptSize = m_vecPtCutoffsForD0Cut.size();
744 if (etaSize != m_vecvecMaxD0AboveEtaPt.size()) {
745 ATH_MSG_ERROR(
"Eta cutoffs and D0 cuts must be vectors of the same length." );
746 return StatusCode::FAILURE;
748 for (
size_t i_size=0; i_size<etaSize-1; ++i_size) {
749 if (ptSize != m_vecvecMaxD0AboveEtaPt[i_size].
size()) {
750 ATH_MSG_ERROR(
"Pt cutoffs and D0 cuts must be vectors of the same length." );
751 return StatusCode::FAILURE;
755 std::stringstream pTRangeBuffer;
756 std::copy(m_vecPtCutoffsForD0Cut.begin(), m_vecPtCutoffsForD0Cut.end(), std::ostream_iterator<Double_t>(pTRangeBuffer,
", "));
757 std::string pTString=pTRangeBuffer.str();
759 for (
size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
761 std::stringstream etaRangeBuffer;
762 etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForD0Cut[i_cut_eta] <<
" < |#eta| < ";
763 if(i_cut_eta!=etaSize-1) etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForD0Cut[i_cut_eta+1];
764 else etaRangeBuffer << std::setprecision(2) << std::fixed <<m_maxAbsEta;
766 std::stringstream cutBuffer;
767 std::copy(m_vecvecMaxD0AboveEtaPt[i_cut_eta].
begin(), m_vecvecMaxD0AboveEtaPt[i_cut_eta].
end(), std::ostream_iterator<Double_t>(cutBuffer,
", "));
768 std::string cutString=cutBuffer.str();
775 return StatusCode::FAILURE;
777 if (!
checkOrder(m_vecPtCutoffsForD0Cut.value())) {
779 return StatusCode::FAILURE;
782 trackCuts[
"D0"].push_back([p_vecEtaCutoffsForD0Cut = &std::as_const(m_vecEtaCutoffsForD0Cut.value()),
783 p_vecPtCutoffsForD0Cut = &std::as_const(m_vecPtCutoffsForD0Cut.value()),
784 p_vecvecMaxD0AboveEtaPt = &std::as_const(m_vecvecMaxD0AboveEtaPt.value())] (Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
785 double eta = helper.eta(msgHelper);
786 unsigned int bin_eta = findBin(*p_vecEtaCutoffsForD0Cut, std::fabs(eta));
787 double pt = helper.pt(msgHelper);
788 unsigned int bin_pt = findBin(*p_vecPtCutoffsForD0Cut, pt);
789 return bin_eta >= p_vecEtaCutoffsForD0Cut->size()
790 || bin_pt >= p_vecPtCutoffsForD0Cut->size()
791 || std::fabs(helper.d0(msgHelper)) <= (*p_vecvecMaxD0AboveEtaPt)[bin_eta][bin_pt];
795 if (!m_vecPtCutoffsForSctHolesCut.empty() ||
796 !m_vecEtaCutoffsForSctHolesCut.empty() ||
797 !m_vecvecMaxSctHolesAboveEtaPt.empty()) {
798 auto etaSize = m_vecEtaCutoffsForSctHolesCut.size();
799 auto ptSize = m_vecPtCutoffsForSctHolesCut.size();
800 if (etaSize != m_vecvecMaxSctHolesAboveEtaPt.size()) {
801 ATH_MSG_ERROR(
"Eta cutoffs and SctHoles cuts must be vectors of the same length." );
802 return StatusCode::FAILURE;
804 for (
size_t i_size=0; i_size<etaSize-1; ++i_size) {
805 if (ptSize != m_vecvecMaxSctHolesAboveEtaPt[i_size].
size()) {
806 ATH_MSG_ERROR(
"Pt cutoffs and SctHoles cuts must be vectors of the same length." );
807 return StatusCode::FAILURE;
811 std::stringstream pTRangeBuffer;
812 std::copy(m_vecPtCutoffsForSctHolesCut.begin(), m_vecPtCutoffsForSctHolesCut.end(), std::ostream_iterator<Double_t>(pTRangeBuffer,
", "));
813 std::string pTString=pTRangeBuffer.str();
815 for (
size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
817 std::stringstream etaRangeBuffer;
818 etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForSctHolesCut[i_cut_eta] <<
" < |#eta| < ";
819 if(i_cut_eta!=etaSize-1) etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForSctHolesCut[i_cut_eta+1];
820 else etaRangeBuffer << std::setprecision(2) << std::fixed <<m_maxAbsEta;
822 std::stringstream cutBuffer;
823 std::copy(m_vecvecMaxSctHolesAboveEtaPt[i_cut_eta].
begin(), m_vecvecMaxSctHolesAboveEtaPt[i_cut_eta].
end(), std::ostream_iterator<Double_t>(cutBuffer,
", "));
824 std::string cutString=cutBuffer.str();
831 return StatusCode::FAILURE;
833 if (!
checkOrder(m_vecPtCutoffsForSctHolesCut.value())) {
835 return StatusCode::FAILURE;
838 trackCuts[
"SctHits"].push_back([p_vecEtaCutoffsForSctHolesCut = &std::as_const(m_vecEtaCutoffsForSctHolesCut.value()),
839 p_vecPtCutoffsForSctHolesCut = &std::as_const(m_vecPtCutoffsForSctHolesCut.value()),
840 p_vecvecMaxSctHolesAboveEtaPt = &std::as_const(m_vecvecMaxSctHolesAboveEtaPt.value())] (Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
841 double eta = helper.eta(msgHelper);
842 unsigned int bin_eta = findBin(*p_vecEtaCutoffsForSctHolesCut, std::fabs(eta));
843 double pt = helper.pt(msgHelper);
844 unsigned int bin_pt = findBin(*p_vecPtCutoffsForSctHolesCut, pt);
845 return bin_eta >= p_vecEtaCutoffsForSctHolesCut->size()
846 || bin_pt >= p_vecPtCutoffsForSctHolesCut->size()
847 || getSummary(helper, msgHelper, xAOD::numberOfSCTHoles) <= (*p_vecvecMaxSctHolesAboveEtaPt)[bin_eta][bin_pt];
851 if (!m_vecPtCutoffsForSctHitsPlusDeadCut.empty() ||
852 !m_vecEtaCutoffsForSctHitsPlusDeadCut.empty() ||
853 !m_vecvecMinSctHitsPlusDeadAboveEtaPt.empty()) {
854 auto etaSize = m_vecEtaCutoffsForSctHitsPlusDeadCut.size();
855 auto ptSize = m_vecPtCutoffsForSctHitsPlusDeadCut.size();
856 if (etaSize != m_vecvecMinSctHitsPlusDeadAboveEtaPt.size()) {
857 ATH_MSG_ERROR(
"Eta cutoffs and SctHitsPlusDead cuts must be vectors of the same length." );
858 return StatusCode::FAILURE;
860 for (
size_t i_size=0; i_size<etaSize-1; ++i_size) {
861 if (ptSize != m_vecvecMinSctHitsPlusDeadAboveEtaPt[i_size].
size()) {
862 ATH_MSG_ERROR(
"Pt cutoffs and SctHitsPlusDead cuts must be vectors of the same length." );
863 return StatusCode::FAILURE;
867 std::stringstream pTRangeBuffer;
868 std::copy(m_vecPtCutoffsForSctHitsPlusDeadCut.begin(), m_vecPtCutoffsForSctHitsPlusDeadCut.end(), std::ostream_iterator<Double_t>(pTRangeBuffer,
", "));
869 std::string pTString=pTRangeBuffer.str();
871 for (
size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
873 std::stringstream etaRangeBuffer;
874 etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForSctHitsPlusDeadCut[i_cut_eta] <<
" < |#eta| < ";
875 if(i_cut_eta!=etaSize-1) etaRangeBuffer << std::setprecision(2) << std::fixed << m_vecEtaCutoffsForSctHitsPlusDeadCut[i_cut_eta+1];
876 else etaRangeBuffer << std::setprecision(2) << std::fixed <<m_maxAbsEta;
878 std::stringstream cutBuffer;
879 std::copy(m_vecvecMinSctHitsPlusDeadAboveEtaPt[i_cut_eta].
begin(), m_vecvecMinSctHitsPlusDeadAboveEtaPt[i_cut_eta].
end(), std::ostream_iterator<Double_t>(cutBuffer,
", "));
880 std::string cutString=cutBuffer.str();
887 return StatusCode::FAILURE;
889 if (!
checkOrder(m_vecPtCutoffsForSctHitsPlusDeadCut.value())) {
891 return StatusCode::FAILURE;
894 trackCuts[
"SctHits"].push_back([p_vecEtaCutoffsForSctHitsPlusDeadCut = &std::as_const(m_vecEtaCutoffsForSctHitsPlusDeadCut.value()),
895 p_vecPtCutoffsForSctHitsPlusDeadCut = &std::as_const(m_vecPtCutoffsForSctHitsPlusDeadCut.value()),
896 p_vecvecMinSctHitsPlusDeadAboveEtaPt = &std::as_const(m_vecvecMinSctHitsPlusDeadAboveEtaPt.value())] (Trk_Helper
helper,
const asg::AsgMessaging &msgHelper) {
897 double eta = helper.eta(msgHelper);
898 unsigned int bin_eta = findBin(*p_vecEtaCutoffsForSctHitsPlusDeadCut, std::fabs(eta));
899 double pt = helper.pt(msgHelper);
900 unsigned int bin_pt = findBin(*p_vecPtCutoffsForSctHitsPlusDeadCut, pt);
901 return bin_eta >= p_vecEtaCutoffsForSctHitsPlusDeadCut->size()
902 || bin_pt >= p_vecPtCutoffsForSctHitsPlusDeadCut->size()
903 || getSummarySum<2,Trk_Helper>(helper, msgHelper, {xAOD::numberOfSCTHits, xAOD::numberOfSCTDeadSensors}) >= (*p_vecvecMinSctHitsPlusDeadAboveEtaPt)[bin_eta][bin_pt];
907 return StatusCode::SUCCESS;
911 template <
class Trk_Helper>
913 const std::map< std::string, std::vector< std::function<
bool(Trk_Helper
helper,
const asg::AsgMessaging &msgHelper)> > > &trackCuts)
const {
914 if (!m_isInitialized) {
916 ATH_MSG_WARNING(
"Tool is not initialized! Calling accept() will not be very helpful." );
925 UShort_t cutFamilyIndex = 0;
926 for (
const auto& cutFamily : trackCuts ) {
929 for (
const auto&
cut : cutFamily.second ) {
944 std::lock_guard<std::mutex>
lock(m_mutex);
945 for (
unsigned int idx=0;
idx < trackCuts.size(); ++
idx) {
946 assert(
idx<m_numTracksPassedCuts.size());
950 if (passAll) m_numTracksPassed++;
951 m_numTracksProcessed++;
960 if (!m_isInitialized) {
961 ATH_MSG_ERROR(
"You are attempting to finalize a tool that has not been initialized()." );
965 if (m_numTracksProcessed == 0) {
966 ATH_MSG_INFO(
"No tracks processed in selection tool." );
967 return StatusCode::SUCCESS;
971 ATH_MSG_INFO( m_numTracksPassed <<
" / " << m_numTracksProcessed <<
" = "
972 << m_numTracksPassed*100./m_numTracksProcessed <<
"% passed all cuts." );
973 for (
const auto& cutFamily : m_trackParticleCuts) {
975 ULong64_t numPassed = m_numTracksPassedCuts.at(m_acceptInfo.getCutPosition(cutFamily.first));
976 ATH_MSG_INFO( numPassed <<
" = " << numPassed*100./m_numTracksProcessed <<
"% passed "
977 << cutFamily.first <<
" cut." );
981 return StatusCode::SUCCESS;
1012 ATH_MSG_ERROR(
"accept(...) Function received a non-track" );
1020 return accept( *trk,
nullptr );
1053 if (m_trackParticleCuts.empty()) {
1054 m_numTracksPassed++;
1055 m_numTracksProcessed++;
1060 return accept( track_helper, m_trackParticleCuts);
1063 #ifndef XAOD_ANALYSIS
1075 if (!m_isInitialized)
ATH_MSG_WARNING(
"Tool is not initialized! Calling accept() will not be very helpful." );
1078 if (m_trkTrackCuts.empty()) {
1079 m_numTracksPassed++;
1080 m_numTracksProcessed++;
1086 if ( perigee ==
nullptr || !perigee->covariance() ) {
1087 ATH_MSG_WARNING(
"Track preselection: Zero pointer to parameterbase* received (most likely a track without perigee). This track will not pass any cuts." );
1091 std::unique_ptr<const Trk::TrackParameters> paramsAtVertex;
1095 m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),
1100 track.info().particleHypothesis());
1101 perigee = paramsAtVertex.get();
1104 if ( perigee ==
nullptr || !perigee->covariance() ) {
1105 ATH_MSG_INFO(
"Track preselection: cannot make a measured perigee. This track will not pass any cuts." );
1106 if (!m_initTrkTools)
1107 ATH_MSG_INFO(
"The user should set \"UseTrkTrackTools\" to true if they want the extrapolation tool to try to get a perigee." );
1112 std::unique_ptr<Trk::TrackSummary> cleanup_summary;
1114 if (
summary ==
nullptr && m_trackSumToolAvailable) {
1115 cleanup_summary = m_trackSumTool->summary(Gaudi::Hive::currentContext(),
track);
1116 summary = cleanup_summary.get();
1119 ATH_MSG_INFO(
"Track preselection: cannot get a track summary. This track will not pass any cuts." );
1120 if (!m_initTrkTools)
1121 ATH_MSG_INFO(
"The Trk::Track tools were not set to be initialized. The user should set the property \"UseTrkTrackTools\" to true if they wish to use the summary tool." );
1126 acceptData =
accept( track_helper, m_trkTrackCuts);
1130 #endif // XAOD_ANALYSIS
1148 #pragma GCC diagnostic push
1149 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1153 #ifndef XAOD_STANDALONE
1154 ATH_MSG_WARNING(
"InDetTrackSelectionTool::setCutLevel() is not designed to be called manually in Athena." );
1155 ATH_MSG_WARNING(
"It may not behave as intended. Instead, configure it in the job options through the CutLevel property." );
1156 #endif // XAOD_STANDALONE
1157 if (!m_cutLevel.empty()) {
1158 ATH_MSG_WARNING(
"Cut level already set to " << m_cutLevel <<
". Calling setCutLevel() is not expected." );
1160 setCutLevelPrivate(
level, overwrite);
1163 #pragma GCC diagnostic pop
1170 if (m_isInitialized) {
1173 ATH_MSG_WARNING(
"Trying to set cut level while the tool is already initialized." );
1174 ATH_MSG_WARNING(
"This will almost certainly not exhibit intended behavior." );
1182 m_maxAbsEta = LOCAL_MAX_DOUBLE;
1183 m_maxZ0SinTheta = LOCAL_MAX_DOUBLE;
1184 m_maxZ0 = LOCAL_MAX_DOUBLE;
1185 m_maxD0 = LOCAL_MAX_DOUBLE;
1186 m_maxSigmaD0 = LOCAL_MAX_DOUBLE;
1187 m_maxSigmaZ0 = LOCAL_MAX_DOUBLE;
1188 m_maxSigmaZ0SinTheta = LOCAL_MAX_DOUBLE;
1189 m_maxD0overSigmaD0 = LOCAL_MAX_DOUBLE;
1190 m_maxZ0overSigmaZ0 = LOCAL_MAX_DOUBLE;
1191 m_maxZ0SinThetaoverSigmaZ0SinTheta = LOCAL_MAX_DOUBLE;
1192 m_minNInnermostLayerHits = -1;
1193 m_minNNextToInnermostLayerHits = -1;
1194 m_minNBothInnermostLayersHits = -1;
1195 m_maxNInnermostLayerSharedHits = LOCAL_MAX_INT;
1196 m_useMinBiasInnermostLayersCut = 0;
1197 m_minNPixelHits = -1;
1198 m_minNPixelHitsPhysical = -1;
1199 m_maxNPixelSharedHits = LOCAL_MAX_INT;
1200 m_maxNPixelHoles = LOCAL_MAX_INT;
1202 m_minNSctHitsPhysical = -1;
1203 m_maxNSctHoles = LOCAL_MAX_INT;
1204 m_maxNSctSharedHits = LOCAL_MAX_INT;
1205 m_maxNSctDoubleHoles = LOCAL_MAX_INT;
1207 m_minNSiHitsPhysical = -1;
1208 m_maxNSiSharedHits = LOCAL_MAX_INT;
1209 m_minNSiHitsIfSiSharedHits = -1;
1210 m_maxNSiHoles = LOCAL_MAX_INT;
1211 m_minEtaForStrictNSiHitsCut = LOCAL_MAX_DOUBLE;
1212 m_minNSiHitsAboveEtaCutoff = -1;
1213 m_maxOneSharedModule =
false;
1214 m_maxTrtEtaAcceptance = LOCAL_MAX_DOUBLE;
1215 m_maxEtaForTrtHitCuts = -1.;
1217 m_minNTrtHitsPlusOutliers = -1;
1218 m_minNTrtHighThresholdHits = -1;
1219 m_minNTrtHighThresholdHitsPlusOutliers = -1;
1220 m_maxTrtHighEFraction = LOCAL_MAX_DOUBLE;
1221 m_maxTrtHighEFractionWithOutliers = LOCAL_MAX_DOUBLE;
1222 m_maxTrtOutlierFraction = LOCAL_MAX_DOUBLE;
1223 m_maxChiSq = LOCAL_MAX_DOUBLE;
1225 m_maxChiSqperNdf = LOCAL_MAX_DOUBLE;
1226 m_minPtForProbCut = LOCAL_MAX_DOUBLE;
1227 m_minProbAbovePtCutoff = -1.;
1228 m_useEtaDependentMaxChiSq =
false;
1229 m_minNUsedHitsdEdx = -1;
1230 m_minNOverflowHitsdEdx = -1;
1231 m_minEProbabilityHT = -1.;
1232 m_eProbHTonlyForXe =
false;
1233 #ifndef XAOD_ANALYSIS
1234 m_minNSiHitsMod = -1;
1235 m_minNSiHitsModTop = -1;
1236 m_minNSiHitsModBottom = -1;
1238 m_vecEtaCutoffsForSiHitsCut = std::vector<double>();
1239 m_vecMinNSiHitsAboveEta = std::vector<int>();
1240 m_vecEtaCutoffsForPtCut = std::vector<double>();
1241 m_vecMinPtAboveEta = std::vector<double>();
1242 m_vecPtCutoffsForSctHitsCut = std::vector<double>();
1243 m_vecMinNSctHitsAbovePt = std::vector<int>();
1244 m_vecEtaCutoffsForZ0SinThetaCut = std::vector<double>();
1245 m_vecPtCutoffsForZ0SinThetaCut = std::vector<double>();
1246 m_vecvecMaxZ0SinThetaAboveEtaPt = std::vector<std::vector<double>>();
1247 m_vecEtaCutoffsForD0Cut = std::vector<double>();
1248 m_vecPtCutoffsForD0Cut = std::vector<double>();
1249 m_vecvecMaxD0AboveEtaPt = std::vector<std::vector<double>>();
1250 m_vecEtaCutoffsForSctHolesCut = std::vector<double>();
1251 m_vecPtCutoffsForSctHolesCut = std::vector<double>();
1252 m_vecvecMaxSctHolesAboveEtaPt = std::vector<std::vector<double>>();
1253 m_vecEtaCutoffsForSctHitsPlusDeadCut = std::vector<double>();
1254 m_vecPtCutoffsForSctHitsPlusDeadCut = std::vector<double>();
1255 m_vecvecMinSctHitsPlusDeadAboveEtaPt = std::vector<std::vector<double>>();
1261 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1262 if (overwrite || m_minNSiHits < 0) m_minNSiHits = 8;
1263 m_maxOneSharedModule =
true;
1264 if (overwrite || m_maxNSiHoles >= LOCAL_MAX_INT) m_maxNSiHoles = 2;
1265 if (overwrite || m_maxNPixelHoles >= LOCAL_MAX_INT) m_maxNPixelHoles = 1;
1267 case CutLevel::LoosePrimary :
1269 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1270 if (overwrite || m_minNSiHits < 0) m_minNSiHits = 8;
1271 m_maxOneSharedModule =
true;
1272 if (overwrite || m_maxNSiHoles >= LOCAL_MAX_INT) m_maxNSiHoles = 2;
1273 if (overwrite || m_maxNPixelHoles >= LOCAL_MAX_INT) m_maxNPixelHoles = 1;
1274 if (overwrite || m_minNSiHitsIfSiSharedHits < 0) m_minNSiHitsIfSiSharedHits = 10;
1276 case CutLevel::TightPrimary :
1278 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1279 if (overwrite || m_minNSiHits < 0) m_minNSiHits = 9;
1280 m_maxOneSharedModule =
true;
1281 if (overwrite || m_maxNSiHoles >= LOCAL_MAX_INT) m_maxNSiHoles = 2;
1282 if (overwrite || m_maxNPixelHoles >= LOCAL_MAX_INT) m_maxNPixelHoles = 0;
1283 if (overwrite || m_minEtaForStrictNSiHitsCut >= LOCAL_MAX_DOUBLE) m_minEtaForStrictNSiHitsCut = 1.65;
1284 if (overwrite || m_minNSiHitsAboveEtaCutoff < 0) m_minNSiHitsAboveEtaCutoff = 11;
1285 if (overwrite || m_minNBothInnermostLayersHits < 0) m_minNBothInnermostLayersHits = 1;
1287 case CutLevel::LooseMuon :
1289 if (overwrite || m_minNPixelHits < 0) m_minNPixelHits = 1;
1290 if (overwrite || m_minNSctHits < 0) m_minNSctHits = 5;
1291 if (overwrite || m_maxNSiHoles >= LOCAL_MAX_INT) m_maxNSiHoles = 2;
1292 if (overwrite || m_maxTrtEtaAcceptance >= LOCAL_MAX_DOUBLE ) m_maxTrtEtaAcceptance = 0.1;
1293 if (overwrite || m_maxEtaForTrtHitCuts < 0.) m_maxEtaForTrtHitCuts = 1.9;
1294 if (overwrite || m_minNTrtHitsPlusOutliers < 0) m_minNTrtHitsPlusOutliers = 6;
1295 if (overwrite || m_maxTrtOutlierFraction >= LOCAL_MAX_DOUBLE) m_maxTrtOutlierFraction = 0.9;
1297 case CutLevel::LooseElectron :
1299 if (overwrite || m_minNSiHits < 0) m_minNSiHits = 7;
1300 if (overwrite || m_minNPixelHits < 0) m_minNPixelHits = 1;
1302 case CutLevel::LooseTau :
1304 if (overwrite || m_minPt < 0.0) m_minPt = 1000.0;
1305 if (overwrite || m_minNSiHits < 0) m_minNSiHits = 7;
1306 if (overwrite || m_minNPixelHits < 0) m_minNPixelHits = 2;
1307 if (overwrite || m_maxD0 >= LOCAL_MAX_DOUBLE) m_maxD0 = 1.0;
1308 if (overwrite || m_maxZ0 >= LOCAL_MAX_DOUBLE) m_maxZ0 = 1.5;
1310 case CutLevel::MinBias :
1312 if (overwrite || m_useMinBiasInnermostLayersCut >= 0) m_useMinBiasInnermostLayersCut = 1;
1313 if (overwrite || m_minNPixelHits < 0) m_minNPixelHits = 1;
1314 if (overwrite || m_minNSctHits < 0) m_minNSctHits = 6;
1315 if (overwrite || m_minProbAbovePtCutoff < 0.) {
1316 m_minPtForProbCut = 10000.;
1317 m_minProbAbovePtCutoff = .01;
1319 if (overwrite || m_maxD0 >= LOCAL_MAX_DOUBLE) m_maxD0 = 1.5;
1320 if (overwrite || m_maxZ0SinTheta >= LOCAL_MAX_DOUBLE) m_maxZ0SinTheta = 1.5;
1321 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1322 if (overwrite || m_minPt < 0.) m_minPt = 500.0;
1324 case CutLevel::HILoose:
1327 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1328 if (overwrite || m_useMinBiasInnermostLayersCut >= 0) m_useMinBiasInnermostLayersCut = 1;
1329 if (overwrite || m_minNPixelHits < 0) m_minNPixelHits = 1;
1330 if (overwrite || (m_vecPtCutoffsForSctHitsCut.empty()
1331 && m_vecMinNSctHitsAbovePt.empty())) {
1332 m_vecPtCutoffsForSctHitsCut = std::vector<double>({0.0, 300.0, 400.0});
1333 m_vecMinNSctHitsAbovePt = std::vector<int>({2, 4, 6});
1335 if (overwrite || m_maxD0 >= LOCAL_MAX_DOUBLE) m_maxD0 = 1.5;
1336 if (overwrite || m_maxZ0SinTheta >= LOCAL_MAX_DOUBLE) m_maxZ0SinTheta = 1.5;
1338 case CutLevel::HITight:
1342 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1343 if (overwrite || m_useMinBiasInnermostLayersCut >= 0) m_useMinBiasInnermostLayersCut = 1;
1344 if (overwrite || m_minNPixelHits < 0) m_minNPixelHits = 2;
1345 if (overwrite || (m_vecPtCutoffsForSctHitsCut.empty()
1346 && m_vecMinNSctHitsAbovePt.empty())) {
1347 m_vecPtCutoffsForSctHitsCut = std::vector<double>({0.0, 300.0, 400.0});
1348 m_vecMinNSctHitsAbovePt = std::vector<int>({4, 6, 8});
1350 if (overwrite || m_maxD0 >= LOCAL_MAX_DOUBLE) m_maxD0 = 1.0;
1351 if (overwrite || m_maxZ0SinTheta >= LOCAL_MAX_DOUBLE) m_maxZ0SinTheta = 1.0;
1352 if (overwrite || m_maxChiSqperNdf >= LOCAL_MAX_DOUBLE) m_maxChiSqperNdf = 6.0;
1354 case CutLevel::HILooseOptimized:
1356 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1357 if (overwrite || m_maxNPixelHoles >= LOCAL_MAX_INT) m_maxNPixelHoles = 0;
1358 if (overwrite || m_useMinBiasInnermostLayersCut >= 0) m_useMinBiasInnermostLayersCut = 1;
1359 if (overwrite || (m_vecEtaCutoffsForZ0SinThetaCut.empty() &&
1360 m_vecPtCutoffsForZ0SinThetaCut.empty() &&
1361 m_vecvecMaxZ0SinThetaAboveEtaPt.empty())){
1362 m_vecEtaCutoffsForZ0SinThetaCut = std::vector<double>({0.0, 1.1, 1.6, 2.0});
1363 m_vecPtCutoffsForZ0SinThetaCut =
1364 std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1365 2000, 2500, 3000, 5000, 8000, 12000});
1366 m_vecvecMaxZ0SinThetaAboveEtaPt =
1367 std::vector<std::vector<double>>({{2.10, 2.15, 6.00, 5.00, 3.10, 2.00, 1.75, 1.60, 1.43, 1.40, 1.05, 0.65, 0.60},
1368 {1.44, 1.47, 1.50, 1.55, 1.62, 1.45, 1.45, 1.78, 1.73, 1.50, 1.20, 0.97, 0.53},
1369 {1.40, 1.45, 1.50, 1.46, 1.41, 1.37, 1.25, 1.50, 1.50, 1.36, 1.10, 0.85, 0.52},
1370 {1.51, 1.70, 1.70, 1.71, 1.71, 1.53, 1.54, 1.49, 1.36, 1.20, 0.95, 0.60, 0.55}});
1372 if (overwrite || (m_vecEtaCutoffsForD0Cut.empty() &&
1373 m_vecPtCutoffsForD0Cut.empty() &&
1374 m_vecvecMaxD0AboveEtaPt.empty())){
1375 m_vecEtaCutoffsForD0Cut = std::vector<double>({0.0, 1.1, 1.6, 2.0});
1376 m_vecPtCutoffsForD0Cut =
1377 std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1378 2000, 2500, 3000, 5000, 8000, 12000});
1379 m_vecvecMaxD0AboveEtaPt =
1380 std::vector<std::vector<double>>({{0.81, 0.90, 0.94, 0.92, 0.90, 0.75, 0.65, 0.63, 0.62, 0.60, 0.63, 0.50, 0.55},
1381 {1.00, 0.98, 0.98, 0.92, 0.90, 0.69, 0.67, 0.86, 0.88, 0.88, 0.88, 0.87, 1.06},
1382 {1.19, 1.15, 1.10, 1.08, 1.03, 0.94, 0.85, 0.97, 0.97, 0.96, 0.95, 0.92, 1.04},
1383 {1.33, 1.23, 1.21, 1.15, 1.15, 1.07, 0.94, 0.97, 0.97, 0.97, 0.98, 1.10, 1.10}});
1386 case CutLevel::HITightOptimized:
1388 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1389 if (overwrite || m_maxNPixelHoles >= LOCAL_MAX_INT) m_maxNPixelHoles = 0;
1390 if (overwrite || m_useMinBiasInnermostLayersCut >= 0) m_useMinBiasInnermostLayersCut = 1;
1391 if (overwrite || (m_vecEtaCutoffsForZ0SinThetaCut.empty() &&
1392 m_vecPtCutoffsForZ0SinThetaCut.empty() &&
1393 m_vecvecMaxZ0SinThetaAboveEtaPt.empty())){
1394 m_vecEtaCutoffsForZ0SinThetaCut = std::vector<double>({0.0, 1.1, 1.6, 2.0});
1395 m_vecPtCutoffsForZ0SinThetaCut = std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1396 2000, 2500, 3000, 5000, 8000, 12000});
1397 m_vecvecMaxZ0SinThetaAboveEtaPt =
1398 std::vector<std::vector<double>>({{0.62, 0.70, 0.82, 0.87, 0.74, 0.61, 0.50, 0.48, 0.46, 0.45, 0.30, 0.24, 0.23},
1399 {0.51, 0.53, 0.53, 0.53, 0.52, 0.43, 0.28, 0.27, 0.28, 0.30, 0.24, 0.22, 0.13},
1400 {0.91, 0.89, 0.87, 0.55, 0.59, 0.37, 0.39, 0.31, 0.34, 0.35, 0.30, 0.30, 0.20},
1401 {0.76, 0.71, 0.69, 0.48, 0.48, 0.47, 0.46, 0.42, 0.38, 0.32, 0.28, 0.20, 0.15}});
1403 if (overwrite || (m_vecEtaCutoffsForD0Cut.empty() &&
1404 m_vecPtCutoffsForD0Cut.empty() &&
1405 m_vecvecMaxD0AboveEtaPt.empty())){
1406 m_vecEtaCutoffsForD0Cut = std::vector<double>({0.0, 1.1, 1.6, 2.0});
1407 m_vecPtCutoffsForD0Cut = std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1408 2000, 2500, 3000, 5000, 8000, 12000});
1409 m_vecvecMaxD0AboveEtaPt =
1410 std::vector<std::vector<double>>({{0.34, 0.39, 0.47, 0.49, 0.55, 0.47, 0.44, 0.21, 0.19, 0.17, 0.12, 0.14, 0.15},
1411 {0.32, 0.32, 0.33, 0.33, 0.33, 0.27, 0.16, 0.15, 0.13, 0.15, 0.13, 0.16, 0.20},
1412 {0.95, 0.91, 0.88, 0.35, 0.37, 0.24, 0.26, 0.22, 0.23, 0.24, 0.19, 0.19, 0.23},
1413 {0.68, 0.67, 0.65, 0.42, 0.42, 0.36, 0.35, 0.31, 0.27, 0.26, 0.27, 0.28, 0.30}});
1415 if (overwrite || (m_vecEtaCutoffsForSctHolesCut.empty() &&
1416 m_vecPtCutoffsForSctHolesCut.empty() &&
1417 m_vecvecMaxSctHolesAboveEtaPt.empty())){
1418 m_vecEtaCutoffsForSctHolesCut = std::vector<double>({0.0, 1.1, 1.6, 2.0});
1419 m_vecPtCutoffsForSctHolesCut = std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1420 2000, 2500, 3000, 5000, 8000, 12000});
1421 m_vecvecMaxSctHolesAboveEtaPt =
1422 std::vector<std::vector<double>>({{0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
1423 {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1},
1424 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
1425 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}});
1427 if (overwrite || (m_vecEtaCutoffsForSctHitsPlusDeadCut.empty() &&
1428 m_vecPtCutoffsForSctHitsPlusDeadCut.empty() &&
1429 m_vecvecMinSctHitsPlusDeadAboveEtaPt.empty())){
1430 m_vecEtaCutoffsForSctHitsPlusDeadCut = std::vector<double>({0.0, 1.1, 1.6, 2.0});
1431 m_vecPtCutoffsForSctHitsPlusDeadCut = std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1432 2000, 2500, 3000, 5000, 8000, 12000});
1433 m_vecvecMinSctHitsPlusDeadAboveEtaPt =
1434 std::vector<std::vector<double>>({{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
1435 {0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 0, 0, 0},
1436 {8, 8, 8, 7, 7, 6, 6, 6, 6, 6, 0, 0, 0},
1437 {7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}});
1441 ATH_MSG_ERROR(
"CutLevel not recognized. Cut selection will remain unchanged.");
1447 const std::unordered_map<std::string, InDet::CutLevel>
1452 {
"LoosePrimary", InDet::CutLevel::LoosePrimary},
1453 {
"TightPrimary", InDet::CutLevel::TightPrimary},
1454 {
"LooseMuon", InDet::CutLevel::LooseMuon},
1455 {
"LooseElectron", InDet::CutLevel::LooseElectron},
1456 {
"LooseTau", InDet::CutLevel::LooseTau},
1457 {
"MinBias", InDet::CutLevel::MinBias},
1458 {
"HILoose", InDet::CutLevel::HILoose},
1459 {
"HITight", InDet::CutLevel::HITight},
1460 {
"HILooseOptimized", InDet::CutLevel::HILooseOptimized},
1461 {
"HITightOptimized", InDet::CutLevel::HITightOptimized}