ATLAS Offline Software
Loading...
Searching...
No Matches
InDetTrackSelectionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
9#include "InDetAccessor.h"
10
11#ifndef XAOD_ANALYSIS
13#include "TrkTrack/Track.h"
14#include "VxVertex/Vertex.h"
17#endif
18
19#include <memory>
20#include <array>
21
22using namespace InDetAccessor;
23
24namespace {
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; }
27
28 template <class Trk_Helper, unsigned int n_summary_types>
29 class MinTRTHitsCut {
30 public:
31 MinTRTHitsCut( double maxTrtEtaAcceptance,
32 double maxEtaForTrtHitCuts,
33 int min_n_hits,
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)
39 {}
40
41 uint8_t nHits(Trk_Helper helper, const asg::AsgMessaging &msgHelper) const {
42 return getSummarySum(helper,msgHelper,m_summaryTypes);
43 }
44 bool operator()(Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
45 double absEta = std::abs( helper.eta( msgHelper) );
46 return (absEta <= m_maxTrtEtaAcceptance || absEta > m_maxEtaForTrtHitCuts) || nHits(helper,msgHelper) >=m_minNHits;
47 }
48 private:
49 double m_maxTrtEtaAcceptance;
50 double m_maxEtaForTrtHitCuts;
51 int m_minNHits;
52 std::array<xAOD::SummaryType, n_summary_types> m_summaryTypes;
53 };
54
55 // return the first bin whose value is lower or equal than the given value
56 // the bins have to be in ascending order;
57 template <typename T>
58 unsigned int findBin(const std::vector<T> &bins, T value) {
59 if (bins.empty() || bins[0]>value) return bins.size();
60 unsigned int bin_i=bins.size();
61 while ( value < bins[--bin_i]) {};
62 return bin_i;
63 }
64 // return true if the given bins are in ascending order
65 template <typename T>
66 bool checkOrder(const std::vector<T> &bins) {
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;
70 }
71 return true;
72 }
73}
74
75InDet::InDetTrackSelectionTool::InDetTrackSelectionTool(const std::string& name)
76 : asg::AsgTool(name)
77 , m_acceptInfo( "InDetTrackSelection" )
78#ifndef XAOD_ANALYSIS
79#endif // XAOD_ANALYSIS
80{
81
82 // set the cut selection: default is "no cut"
83 setCutLevelPrivate(InDet::CutLevel::NoCut);
84
85#ifndef XAOD_STANDALONE
86 declareInterface<IInDetTrackSelectionTool>(this);
87#endif
88
89}
90
91// we must define the destructor in order to use forward-declaration with unique_ptr
93
104 // Make sure we haven't already been initialized - this would be a sign of improper usage.
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;
109 }
110
111 // Greet the user:
113
114 // if the CutLevel string is set to something recognizable,
115 // then do a soft set on the cuts (i.e. not overwriting those already set)
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." );
120 ATH_MSG_ERROR( "Cut level options are:" );
121 for (const auto& opt : s_mapCutLevel) {
122 ATH_MSG_ERROR( "\t" << opt.first );
123 }
124 } else {
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 );
128 }
129 }
130
131#ifndef XAOD_ANALYSIS
132 if (m_initTrkTools) {
134 if (!m_trackSumTool.empty()) {
135 ATH_CHECK( m_trackSumTool.retrieve() );
136 ATH_MSG_DEBUG( "Track summary tool retrieved." );
138 }
139 ATH_CHECK( m_extrapolator.retrieve() );
140 ATH_MSG_DEBUG( "Retrieved tool " << m_extrapolator );
141 } else {
142 m_extrapolator.disable();
143 m_trackSumTool.disable();
144 }
145#endif // XAOD_ANALYSIS
146
147 // Need messaging helper for cut functions
148 m_msgHelper = std::make_unique<asg::AsgMessaging>(this) ;
149
150
151#ifndef XAOD_ANALYSIS
152 // setup cut functions for Trk::Tracks
155#else
157#endif
158 // setup cut functions for xAOD::TrackParticles
159 for (const auto& cutFamily : m_trackParticleCuts) {
160 const std::string& cutFamilyName = cutFamily.first;
161 // lock(m_mutex) is not needed because this is inside of non-const initialize method.
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;
166 }
167 ATH_MSG_VERBOSE("Adding cut family " << cutFamilyName);
168 }
169
170 m_isInitialized = true;
171
172 return StatusCode::SUCCESS;
173}
174
175namespace {
176 template <typename T>
177 inline T sqr(T a) { return a *a;}
178}
179template <int VERBOSE, class Trk_Helper>
180StatusCode InDet::InDetTrackSelectionTool::setupCuts(std::map< std::string, std::vector< std::function<bool(Trk_Helper helper, const asg::AsgMessaging &msgHelper)> > > &trackCuts) {
181 // track parameter cuts
182 if (m_minPt > 0.) {
183 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum Pt: " << m_minPt << " MeV" );
184 trackCuts["Pt"].push_back( [minPt = m_minPt](Trk_Helper helper, const asg::AsgMessaging &msgHelper) -> bool { return helper.pt(msgHelper) >= minPt; } );
185 }
187 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum |Eta|: " << m_maxAbsEta );
188 trackCuts["Eta"].push_back( [maxAbsEta = m_maxAbsEta](Trk_Helper helper, const asg::AsgMessaging &msgHelper) { return std::abs(helper.eta(msgHelper)) <= maxAbsEta; } );
189 }
190 if (m_minP > 0.) {
191 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum P: " << m_minP << " MeV" );
192 trackCuts["P"].push_back( [maxInvP = 1./m_minP](Trk_Helper helper, const asg::AsgMessaging &msgHelper) { return std::abs(helper.qOverP(msgHelper)) <= maxInvP; } );
193 }
194 if (maxDoubleIsSet(m_maxD0)) {
195 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum d0: " << m_maxD0 << " mm" );
196 trackCuts["D0"].push_back( [maxD0 = m_maxD0](Trk_Helper helper, const asg::AsgMessaging &msgHelper) { return std::abs(helper.d0(msgHelper)) <= maxD0; } );
197 }
198 if (maxDoubleIsSet(m_maxZ0)) {
199 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum z0: " << m_maxZ0 << " mm");
200 trackCuts["Z0"].push_back( [maxZ0 = m_maxZ0](Trk_Helper helper, const asg::AsgMessaging &msgHelper) { return std::abs(helper.z0(msgHelper)) <= maxZ0; } );
201 }
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) {
205 return std::abs( helper.z0(msgHelper) * std::sin(helper.theta(msgHelper))) <= maxZ0SinTheta;
206 });
207 }
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;
212 });
213 }
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;
218 });
219 }
221 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum uncertainty on z0*sin(theta): "
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);
228
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;
232 });
233 }
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);
238 });
239 }
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);
244 });
245 }
247 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum significance on z0*sin(theta): "
249 trackCuts["Z0SinTheta"].push_back([maxZ0SinThetaoverSigmaZ0SinThetaSquared = sqr(m_maxZ0SinThetaoverSigmaZ0SinTheta.value())](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
250
251 double theta = helper.theta(msgHelper);
252 double sinTheta = std::sin(theta);
253 double cosTheta = std::cos(theta);
254 double z0 = helper.z0(msgHelper);
255
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));
260 });
261 }
262
263 // hit cuts
264 if (m_minNInnermostLayerHits > 0) {
265 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum hits from innermost pixel layer: " << m_minNInnermostLayerHits );
266 if constexpr(VERBOSE>0) ATH_MSG_INFO( " (Track will pass if no hit is expected.)" );
267 trackCuts["InnermostLayersHits"].push_back([minNInnermostLayerHits = m_minNInnermostLayerHits](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
268 return ( getSummary(helper, msgHelper, xAOD::numberOfInnermostPixelLayerHits) >= minNInnermostLayerHits
269 || getSummary(helper, msgHelper, xAOD::expectInnermostPixelLayerHit) == 0);
270 });
271 }
273 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum hits from next to innermost pixel layer: " << m_minNNextToInnermostLayerHits );
274 if constexpr(VERBOSE>0) ATH_MSG_INFO( " (Track will pass if no hit is expected.)" );
275 trackCuts["InnermostLayersHits"].push_back([minNNextToInnermostLayerHits = m_minNNextToInnermostLayerHits](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
276 return ( getSummary(helper, msgHelper, xAOD::numberOfNextToInnermostPixelLayerHits) >= minNNextToInnermostLayerHits
277 || getSummary(helper, msgHelper, xAOD::expectNextToInnermostPixelLayerHit) == 0);
278 });
279 }
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.)" );
285 ATH_MSG_WARNING( "A value of minNBothInnermostLayersHits above 2 does not make sense." );
286 ATH_MSG_WARNING( " Use 1 for \"or\" or 2 for \"and\"." );
287 }
288 trackCuts["InnermostLayersHits"].push_back([minNBothInnermostLayersHits = m_minNBothInnermostLayersHits](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
289 return ( std::max( getSummary(helper, msgHelper, xAOD::numberOfInnermostPixelLayerHits),
290 static_cast<uint8_t>( !getSummary(helper, msgHelper, xAOD::expectInnermostPixelLayerHit) ))
291 +std::max( getSummary(helper, msgHelper, xAOD::numberOfNextToInnermostPixelLayerHits),
292 static_cast<uint8_t>( !getSummary(helper, msgHelper, xAOD::expectNextToInnermostPixelLayerHit )))
293 >= minNBothInnermostLayersHits);
294 });
295 }
296 if (m_useMinBiasInnermostLayersCut > 0 ) { // less than zero indicates this cut is manually turned off
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." );
299 trackCuts["InnermostLayersHits"].push_back([](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
300 uint8_t expected_innermost_pixel_layer_hit = getSummary(helper, msgHelper, xAOD::expectInnermostPixelLayerHit);
301 return (expected_innermost_pixel_layer_hit > 0 && getSummary(helper, msgHelper, xAOD::numberOfInnermostPixelLayerHits)>=1)
302 || (expected_innermost_pixel_layer_hit == 0 && ( getSummary(helper, msgHelper, xAOD::expectNextToInnermostPixelLayerHit)==0
304 });
305 }
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) {
309 return getSummary(helper, msgHelper, xAOD::numberOfInnermostPixelLayerSharedHits) <= maxNInnermostLayerSharedHits;
310 });
311 }
312 if (m_minNPixelHits > 0) {
313 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum pixel hits: " << m_minNPixelHits );
314 trackCuts["PixelHits"].push_back( [minNPixelHits = m_minNPixelHits](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
315 return getSummarySum<2,Trk_Helper>(helper, msgHelper, {xAOD::numberOfPixelHits,xAOD::numberOfPixelDeadSensors}) >= minNPixelHits;
316 });
317 }
318 if (m_minNPixelHitsPhysical > 0) {
319 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum physical pixel hits (i.e. dead sensors do not count): "
321 trackCuts["PixelHits"].push_back([minNPixelHitsPhysical = m_minNPixelHitsPhysical](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
322 return getSummary(helper, msgHelper, xAOD::numberOfPixelHits) >= minNPixelHitsPhysical;
323 });
324 }
326 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum pixel holes: " << m_maxNPixelHoles );
327 trackCuts["PixelHits"].push_back([maxNPixelHoles = m_maxNPixelHoles](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
328 return getSummary(helper, msgHelper, xAOD::numberOfPixelHoles) <= maxNPixelHoles;
329 });
330 }
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) {
334 return getSummary(helper, msgHelper, xAOD::numberOfPixelSharedHits) <= maxNPixelSharedHits;
335 });
336 }
337 if (m_minNSctHits > 0) {
338 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum SCT hits: " << m_minNSctHits );
339 trackCuts["SctHits"].push_back( [minNSctHits = m_minNSctHits](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
340 return getSummarySum<2,Trk_Helper>(helper, msgHelper, {xAOD::numberOfSCTHits, xAOD::numberOfSCTDeadSensors}) >= minNSctHits;
341 });
342 }
343 if (m_minNSctHitsPhysical > 0) {
344 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum physical SCT hits (i.e. dead sensors do not count): "
346 trackCuts["SctHits"].push_back([minNSctHitsPhysical = m_minNSctHitsPhysical](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
347 return getSummary(helper, msgHelper, xAOD::numberOfSCTHits) >= minNSctHitsPhysical;
348 });
349 }
351 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum SCT holes: " << m_maxNSctHoles );
352 trackCuts["SctHits"].push_back([maxNSctHoles = m_maxNSctHoles](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
353 return getSummary(helper, msgHelper, xAOD::numberOfSCTHoles) <= maxNSctHoles;
354 });
355 }
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) {
359 return getSummary(helper, msgHelper, xAOD::numberOfSCTSharedHits) <= maxNSctSharedHits;
360 });
361 }
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) {
365 return getSummary(helper, msgHelper, xAOD::numberOfSCTDoubleHoles) <= maxNSctDoubleHoles ;
366 });
367 }
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) {
371 return getSummarySum<4,Trk_Helper>(helper, msgHelper, {xAOD::numberOfPixelHits,
374 xAOD::numberOfSCTDeadSensors} ) >= minNSiHits ;
375 });
376 }
377 if (m_minNSiHitsPhysical > 0) {
378 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum physical silicon hits (i.e. dead sensors do not count): "
380 trackCuts["SiHits"].push_back([minNSiHitsPhysical = m_minNSiHitsPhysical](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
381 return getSummarySum<2,Trk_Helper>(helper, msgHelper,{xAOD::numberOfPixelHits, xAOD::numberOfSCTHits} ) >= minNSiHitsPhysical ;
382 });
383 }
385 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum silicon holes: " << m_maxNSiHoles );
386 trackCuts["SiHits"].push_back([maxNSiHoles = m_maxNSiHoles](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
387 return getSummarySum<2,Trk_Helper>(helper, msgHelper,{xAOD::numberOfPixelHoles, xAOD::numberOfSCTHoles} ) <= maxNSiHoles ;
388 });
389 }
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) {
393 return getSummarySum<2,Trk_Helper>(helper, msgHelper,{xAOD::numberOfPixelSharedHits, xAOD::numberOfSCTSharedHits} ) <= maxNSiSharedHits ;
394 });
395 }
397 if constexpr(VERBOSE>0) ATH_MSG_INFO( " No more than one shared module:" );
398 if constexpr(VERBOSE>0) ATH_MSG_INFO( " i.e. max 1 shared pixel hit or" );
399 if constexpr(VERBOSE>0) ATH_MSG_INFO( " 2 shared SCT hits, and not both." );
400 trackCuts["SiHits"].push_back([](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
401 return getSummary(helper, msgHelper,xAOD::numberOfPixelSharedHits )
402 + getSummary(helper, msgHelper,xAOD::numberOfSCTSharedHits )/2 <= 1 ;
403 });
404 }
406 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum silicon hits if the track has shared hits: "
408 trackCuts["SiHits"].push_back([minNSiHitsIfSiSharedHits = m_minNSiHitsIfSiSharedHits](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
413 xAOD::numberOfSCTDeadSensors}) >=minNSiHitsIfSiSharedHits;
414 });
415 }
418 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Require " << m_minNSiHitsAboveEtaCutoff
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
426 xAOD::numberOfSCTDeadSensors}) >= minNSiHitsAboveEtaCutoff;
427 });
428 }
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." );
431 trackCuts["PixHits"].push_back([](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
432 uint8_t pixel_holes = getSummary(helper, msgHelper,xAOD::numberOfPixelHoles);
433 return pixel_holes == 0 || ( pixel_holes<=1 && getSummary(helper, msgHelper,xAOD::numberOfInnermostPixelLayerHits) >= 1
435 && getSummary(helper, msgHelper,xAOD::numberOfNextToInnermostPixelLayerHits) == 0 );
436 });
437 }
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) {
444 xAOD::numberOfPixelHits, // pixel hits count twice in this definition
445 xAOD::numberOfSCTHits}) >= minNSiHitsMod;
446 });
447 }
449 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum modified Si hits in top half = "
451 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum modified Si hits in bottom half = "
453 trackCuts["SiHits"].push_back([minNSiHitsModTop = m_minNSiHitsModTop,
454 minNSiHitsModBottom = m_minNSiHitsModBottom](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
455 auto [top,bottom] = getSiHitsTopBottom(helper, msgHelper);
456 return top >= minNSiHitsModTop && bottom >= minNSiHitsModBottom;
457 });
458 }
459#endif
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,
467 }
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,
472 }
474 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum TRT hits outside eta acceptance above high energy threshold: "
476 trackCuts["TrtHits"].push_back( MinTRTHitsCut<Trk_Helper,1>( m_maxTrtEtaAcceptance,m_maxEtaForTrtHitCuts, m_minNTrtHighThresholdHits,
478 }
480 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum TRT hits outside eta acceptance above high energy threshold including outliers: "
482 trackCuts["TrtHits"].push_back( MinTRTHitsCut<Trk_Helper,2>( m_maxTrtEtaAcceptance,m_maxEtaForTrtHitCuts, m_minNTrtHighThresholdHitsPlusOutliers,
484 }
485 if (maxDoubleIsSet(m_maxTrtHighEFraction)) { // I think this condition could be instead that it is between 0 and 1
486 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum ratio of high threshold to regular TRT hits outside eta acceptance: "
488 trackCuts["TrtHits"].push_back([maxTrtEtaAcceptance = m_maxTrtEtaAcceptance,
489 maxEtaForTrtHitCuts = m_maxEtaForTrtHitCuts,
490 maxTrtHighEFraction = m_maxTrtHighEFraction](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
491 double absEta = std::abs( helper.eta( msgHelper) );
492 return (absEta <= maxTrtEtaAcceptance || absEta > maxEtaForTrtHitCuts)
494 <= maxTrtHighEFraction * getSummary(helper, msgHelper,xAOD::numberOfTRTHits );
495 });
496 }
498 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum ratio of high threshold to regular TRT hits above eta acceptance including outliers: "
500 trackCuts["TrtHits"].push_back([maxTrtEtaAcceptance = m_maxTrtEtaAcceptance,
501 maxEtaForTrtHitCuts = m_maxEtaForTrtHitCuts,
502 maxTrtHighEFractionWithOutliers = m_maxTrtHighEFractionWithOutliers](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
503 double absEta = std::abs( helper.eta( msgHelper) );
504 return (absEta <= maxTrtEtaAcceptance || absEta > maxEtaForTrtHitCuts)
506 <= maxTrtHighEFractionWithOutliers * ( getSummarySum<2,Trk_Helper>(helper, msgHelper,{xAOD::numberOfTRTHits, xAOD::numberOfTRTOutliers} ));
507 });
508 }
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,
513 maxTrtOutlierFraction = m_maxTrtOutlierFraction](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
514 double absEta = std::abs( helper.eta( msgHelper) );
515 uint8_t trt_outliers = getSummary(helper, msgHelper,xAOD::numberOfTRTOutliers );
516 return ( absEta <= maxTrtEtaAcceptance || absEta > maxEtaForTrtHitCuts)
517 || trt_outliers <= maxTrtOutlierFraction * ( trt_outliers + getSummary(helper, msgHelper,xAOD::numberOfTRTHits) );
518 });
519 }
520 }
521
522 // fit quality cuts
524 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Using pre-defined eta-dependent maximum chi squared (no longer recommended)." );
525 trackCuts["FitQuality"].push_back([](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
526 double eta = helper.eta(msgHelper);
527 double fit_chi_square = getFitChiSquare(helper,msgHelper);
528 double fit_ndof = getFitNDoF(helper,msgHelper);
529 if (std::abs( eta) < 1.9) {
530 return fit_chi_square <= fit_ndof * ( 4.4 + 0.32*sqr(eta) );
531 }
532 else {
533 return fit_chi_square <= fit_ndof * ( 26.9 - 19.6978*std::abs(eta) + 4.4534*sqr(eta) );
534 }
535 });
536 }
538 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Maximum chi squared: " << m_maxChiSq );
539 trackCuts["FitQuality"].push_back([maxChiSq = m_maxChiSq](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
540 return getFitChiSquare(helper,msgHelper) <= maxChiSq;
541 });
542 }
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) {
546 return getFitChiSquare(helper,msgHelper) <= maxChiSqperNdf * getFitNDoF(helper,msgHelper);
547 });
548 }
549 if (m_minProb > 0.) {
550 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum chi squared probability: " << m_minProb );
551 trackCuts["FitQuality"].push_back([minProb = m_minProb](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
552 return TMath::Prob( getFitChiSquare(helper,msgHelper),getFitNDoF(helper,msgHelper)) >= minProb;
553 });
554 }
556 if constexpr(VERBOSE>0) ATH_MSG_INFO( " Minimum chi-sq probability of " << m_minProbAbovePtCutoff
557 << " above pt of " << m_minPtForProbCut*1e-3 << " GeV." );
558 trackCuts["FitQuality"].push_back([minPtForProbCut = m_minPtForProbCut,
559 minProbAbovePtCutoff = m_minProbAbovePtCutoff](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
560 return helper.pt(msgHelper) <= minPtForProbCut
561 || TMath::Prob( getFitChiSquare(helper,msgHelper),getFitNDoF(helper,msgHelper)) >= minProbAbovePtCutoff;
562 });
563 }
564
565 // dE/dx cuts
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) {
569 return getNumberOfUsedHitsdEdx(helper,msgHelper) >= minNUsedHitsdEdx;
570 });
571 }
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) {
575 return getNumberOfIBLOverflowsdEdx(helper,msgHelper) >= minNOverflowHitsdEdx;
576 });
577 }
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) {
584 > getSummary(helper, msgHelper, xAOD::numberOfTRTXenonHits)
585 || getEProbabilityHT(helper,msgHelper) >= minEProbabilityHT;
586 });
587 } else {
588 trackCuts["eProbHT"].push_back([minEProbabilityHT = m_minEProbabilityHT](Trk_Helper helper, const asg::AsgMessaging &msgHelper) {
589 return getEProbabilityHT(helper,msgHelper) >= minEProbabilityHT;
590 });
591 }
592 }
593
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;
599 }
600 if constexpr(VERBOSE>0) {
601 for (size_t i_cut=0; i_cut<cutSize-1; ++i_cut) {
603 << " < eta < " << m_vecEtaCutoffsForSiHitsCut[i_cut+1]
604 << " ,Silicon hits >= " << m_vecMinNSiHitsAboveEta[i_cut] );
605 }
606 }
607 if (!checkOrder(m_vecEtaCutoffsForSiHitsCut.value())) {
608 ATH_MSG_ERROR( "Eta values not in ascending order." );
609 return StatusCode::FAILURE;
610 }
611 if constexpr(VERBOSE>0) ATH_MSG_INFO( " for eta > " << m_vecEtaCutoffsForSiHitsCut[cutSize-1]
612 << " ,Silicon hits >= " << m_vecMinNSiHitsAboveEta[cutSize-1] );
613
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()
619 || abs_eta>5.0
620 || getSummarySum<4,Trk_Helper>(helper, msgHelper,{xAOD::numberOfPixelHits,
621 xAOD::numberOfSCTHits,
622 xAOD::numberOfPixelDeadSensors,
623 xAOD::numberOfSCTDeadSensors}) >= (*p_vecMinNSiHitsAboveEta)[bin_i];
624 });
625 }
626
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;
632 }
633 if constexpr(VERBOSE>0) {
634 for (size_t i_cut=0; i_cut<cutSize-1; ++i_cut) {
635 ATH_MSG_INFO( " for " << m_vecEtaCutoffsForPtCut[i_cut]
636 << " < eta < " << m_vecEtaCutoffsForPtCut[i_cut+1]
637 << " ,transverse momentum >= " << m_vecMinPtAboveEta[i_cut] );
638 }
639 }
640 if (!checkOrder(m_vecEtaCutoffsForPtCut.value())) {
641 ATH_MSG_ERROR( "Eta values not in ascending order." );
642 return StatusCode::FAILURE;
643 }
644 if constexpr(VERBOSE>0) ATH_MSG_INFO( " for eta > " << m_vecEtaCutoffsForPtCut[cutSize-1]
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];
651 });
652 }
653
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;
659 }
660 if constexpr(VERBOSE>0) {
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] );
665 }
666 }
667 if (!checkOrder(m_vecPtCutoffsForSctHitsCut.value())) {
668 ATH_MSG_ERROR( "Pt values not in ascending order." );
669 return StatusCode::FAILURE;
670 }
671 if constexpr(VERBOSE>0) ATH_MSG_INFO( " for pt > " << m_vecPtCutoffsForSctHitsCut[cutSize-1]
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) {
675 double pt = helper.pt(msgHelper);
676 unsigned int bin_i = findBin(*p_vecPtCutoffsForSctHitsCut, pt);
677 return bin_i >= p_vecPtCutoffsForSctHitsCut->size()
678 || getSummarySum<2,Trk_Helper>(helper, msgHelper,{xAOD::numberOfSCTHits,
679 xAOD::numberOfSCTDeadSensors}) >= (*p_vecMinNSctHitsAbovePt)[bin_i];
680 });
681 }
682
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;
691 }
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;
696 }
697 }
698
699 std::stringstream pTRangeBuffer;
700 std::copy(m_vecPtCutoffsForZ0SinThetaCut.begin(), m_vecPtCutoffsForZ0SinThetaCut.end(), std::ostream_iterator<double>(pTRangeBuffer, ", "));
701 std::string pTString=pTRangeBuffer.str();
702 if constexpr(VERBOSE>0) ATH_MSG_INFO("Z0SinTheta cuts (<=) for pT above "<<pTString.substr(0, pTString.size()-2)<<"MeV, respectively:");
703 for (size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
704 {
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;
709
710 std::stringstream cutBuffer;
711 std::copy(m_vecvecMaxZ0SinThetaAboveEtaPt[i_cut_eta].begin(), m_vecvecMaxZ0SinThetaAboveEtaPt[i_cut_eta].end(), std::ostream_iterator<double>(cutBuffer, ", "));
712 std::string cutString=cutBuffer.str();
713
714 if constexpr(VERBOSE>0) ATH_MSG_INFO(" for "<<etaRangeBuffer.str()<<": "<<cutString.substr(0, cutString.size()-2));
715 }
716
717 if (!checkOrder(m_vecEtaCutoffsForZ0SinThetaCut.value())) {
718 ATH_MSG_ERROR( "Eta values not in ascending order." );
719 return StatusCode::FAILURE;
720 }
721 if (!checkOrder(m_vecPtCutoffsForZ0SinThetaCut.value())) {
722 ATH_MSG_ERROR( "Pt values not in ascending order." );
723 return StatusCode::FAILURE;
724 }
725
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];
736 });
737 }
738
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;
747 }
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;
752 }
753 }
754
755 std::stringstream pTRangeBuffer;
756 std::copy(m_vecPtCutoffsForD0Cut.begin(), m_vecPtCutoffsForD0Cut.end(), std::ostream_iterator<double>(pTRangeBuffer, ", "));
757 std::string pTString=pTRangeBuffer.str();
758 if constexpr(VERBOSE>0) ATH_MSG_INFO("D0 cuts (<=) for pT above "<<pTString.substr(0, pTString.size()-2)<<"MeV, respectively:");
759 for (size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
760 {
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;
765
766 std::stringstream cutBuffer;
767 std::copy(m_vecvecMaxD0AboveEtaPt[i_cut_eta].begin(), m_vecvecMaxD0AboveEtaPt[i_cut_eta].end(), std::ostream_iterator<double>(cutBuffer, ", "));
768 std::string cutString=cutBuffer.str();
769
770 if constexpr(VERBOSE>0) ATH_MSG_INFO(" for "<<etaRangeBuffer.str()<<": "<<cutString.substr(0, cutString.size()-2));
771 }
772
773 if (!checkOrder(m_vecEtaCutoffsForD0Cut.value())) {
774 ATH_MSG_ERROR( "Eta values not in ascending order." );
775 return StatusCode::FAILURE;
776 }
777 if (!checkOrder(m_vecPtCutoffsForD0Cut.value())) {
778 ATH_MSG_ERROR( "Pt values not in ascending order." );
779 return StatusCode::FAILURE;
780 }
781
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];
792 });
793 }
794
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;
803 }
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;
808 }
809 }
810
811 std::stringstream pTRangeBuffer;
812 std::copy(m_vecPtCutoffsForSctHolesCut.begin(), m_vecPtCutoffsForSctHolesCut.end(), std::ostream_iterator<double>(pTRangeBuffer, ", "));
813 std::string pTString=pTRangeBuffer.str();
814 if constexpr(VERBOSE>0) ATH_MSG_INFO("SctHoles cuts (<=) for pT above "<<pTString.substr(0, pTString.size()-2)<<"MeV, respectively:");
815 for (size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
816 {
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;
821
822 std::stringstream cutBuffer;
823 std::copy(m_vecvecMaxSctHolesAboveEtaPt[i_cut_eta].begin(), m_vecvecMaxSctHolesAboveEtaPt[i_cut_eta].end(), std::ostream_iterator<double>(cutBuffer, ", "));
824 std::string cutString=cutBuffer.str();
825
826 if constexpr(VERBOSE>0) ATH_MSG_INFO(" for "<<etaRangeBuffer.str()<<": "<<cutString.substr(0, cutString.size()-2));
827 }
828
829 if (!checkOrder(m_vecEtaCutoffsForSctHolesCut.value())) {
830 ATH_MSG_ERROR( "Eta values not in ascending order." );
831 return StatusCode::FAILURE;
832 }
833 if (!checkOrder(m_vecPtCutoffsForSctHolesCut.value())) {
834 ATH_MSG_ERROR( "Pt values not in ascending order." );
835 return StatusCode::FAILURE;
836 }
837
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];
848 });
849 }
850
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;
859 }
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;
864 }
865 }
866
867 std::stringstream pTRangeBuffer;
868 std::copy(m_vecPtCutoffsForSctHitsPlusDeadCut.begin(), m_vecPtCutoffsForSctHitsPlusDeadCut.end(), std::ostream_iterator<double>(pTRangeBuffer, ", "));
869 std::string pTString=pTRangeBuffer.str();
870 if constexpr(VERBOSE>0) ATH_MSG_INFO("SctHitsPlusDead cuts (>=) for pT above "<<pTString.substr(0, pTString.size()-2)<<"MeV, respectively:");
871 for (size_t i_cut_eta=0; i_cut_eta<etaSize; ++i_cut_eta)
872 {
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;
877
878 std::stringstream cutBuffer;
879 std::copy(m_vecvecMinSctHitsPlusDeadAboveEtaPt[i_cut_eta].begin(), m_vecvecMinSctHitsPlusDeadAboveEtaPt[i_cut_eta].end(), std::ostream_iterator<double>(cutBuffer, ", "));
880 std::string cutString=cutBuffer.str();
881
882 if constexpr(VERBOSE>0) ATH_MSG_INFO(" for "<<etaRangeBuffer.str()<<": "<<cutString.substr(0, cutString.size()-2));
883 }
884
885 if (!checkOrder(m_vecEtaCutoffsForSctHitsPlusDeadCut.value())) {
886 ATH_MSG_ERROR( "Eta values not in ascending order." );
887 return StatusCode::FAILURE;
888 }
889 if (!checkOrder(m_vecPtCutoffsForSctHitsPlusDeadCut.value())) {
890 ATH_MSG_ERROR( "Pt values not in ascending order." );
891 return StatusCode::FAILURE;
892 }
893
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];
904 });
905 }
906
907 return StatusCode::SUCCESS;
908}
909
910
911template <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) {
915 if (!m_warnInit) {
916 ATH_MSG_WARNING( "Tool is not initialized! Calling accept() will not be very helpful." );
917 m_warnInit = true;
918 }
919 }
920
921 asg::AcceptData acceptData(&m_acceptInfo);
922 bool passAll = true;
923
924 // loop over all cuts
925 UShort_t cutFamilyIndex = 0;
926 for ( const auto& cutFamily : trackCuts ) {
927 bool pass = true;
928
929 for ( const auto& cut : cutFamily.second ) {
930 if (! cut(helper, *m_msgHelper) ) {
931 pass = false;
932 break;
933 }
934 }
935
936 // @TODO really always run through all cuts even if passed is false ?
937 passAll &= pass;
938 acceptData.setCutResult( cutFamilyIndex, pass );
939 cutFamilyIndex++;
940 }
941
942 {
943 // lock access to m_numTracksPassedCuts
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());
947 m_numTracksPassedCuts[idx] += acceptData.getCutResult(idx);
948 }
949 }
950 if (passAll) m_numTracksPassed++;
952
953 return acceptData;
954
955}
956
957
959{
960 if (!m_isInitialized) {
961 ATH_MSG_ERROR( "You are attempting to finalize a tool that has not been initialized()." );
962 }
963
964#ifdef XAOD_ANALYSIS
965 if (m_numTracksProcessed == 0) {
966 ATH_MSG_INFO( "No tracks processed in selection tool." );
967 return StatusCode::SUCCESS;
968 }
969
970 // Only printed out for analysis
972 << m_numTracksPassed*100./m_numTracksProcessed << "% passed all cuts." );
973 for (const auto& cutFamily : m_trackParticleCuts) {
974 // lock(m_mutex) is not needed because this is inside of non-const finalize method.
975 uint64_t numPassed = m_numTracksPassedCuts.at(m_acceptInfo.getCutPosition(cutFamily.first));
976 ATH_MSG_INFO( numPassed << " = " << numPassed*100./m_numTracksProcessed << "% passed "
977 << cutFamily.first << " cut." );
978 }
979#endif
980
981 return StatusCode::SUCCESS;
982}
983
984
993
994
1007{
1008
1009 asg::AcceptData acceptData(&m_acceptInfo);
1010 // Check if this is a track:
1011 if( p->type() != xAOD::Type::TrackParticle ) {
1012 ATH_MSG_ERROR( "accept(...) Function received a non-track" );
1013 return acceptData;
1014 }
1015
1016 // Cast it to a track (we have already checked its type so we do not have to dynamic_cast):
1017 const xAOD::TrackParticle* trk = static_cast< const xAOD::TrackParticle* >( p );
1018
1019 // Let the specific function do the work:
1020 return accept( *trk, nullptr );
1021}
1022
1023
1050 const xAOD::Vertex* vtx ) const
1051{
1052 asg::AcceptData acceptData(&m_acceptInfo);
1053 if (m_trackParticleCuts.empty()) {
1056 return acceptData;
1057 }
1058
1059 InDetAccessor::TrackParticleHelper track_helper(trk,vtx);
1060 return accept( track_helper, m_trackParticleCuts);
1061}
1062
1063#ifndef XAOD_ANALYSIS
1073 const Trk::Vertex* vertex ) const
1074{
1075 if (!m_isInitialized) ATH_MSG_WARNING( "Tool is not initialized! Calling accept() will not be very helpful." );
1076
1077 asg::AcceptData acceptData(&m_acceptInfo);
1078 if (m_trkTrackCuts.empty()) {
1081 return acceptData;
1082 }
1083
1084 const Trk::TrackParameters* perigee = track.perigeeParameters();
1085
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." );
1088 return acceptData;
1089 }
1090
1091 std::unique_ptr<const Trk::TrackParameters> paramsAtVertex;
1092 if (vertex) {
1093 Trk::PerigeeSurface perigeeSurface(vertex->position());
1094 paramsAtVertex =
1095 m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),
1096 *perigee,
1097 perigeeSurface,
1099 true,
1100 track.info().particleHypothesis());
1101 perigee = paramsAtVertex.get();
1102 }
1103
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." );
1108 return acceptData;
1109 }
1110
1111
1112 std::unique_ptr<Trk::TrackSummary> cleanup_summary;
1113 const Trk::TrackSummary* summary = track.trackSummary();
1114 if (summary == nullptr && m_trackSumToolAvailable) {
1115 cleanup_summary = m_trackSumTool->summary(Gaudi::Hive::currentContext(),track);
1116 summary = cleanup_summary.get();
1117 }
1118 if (summary == nullptr) {
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." );
1122 return acceptData;
1123 }
1124
1125 InDetAccessor::TrkTrackHelper track_helper(track,*summary, perigee);
1126 acceptData = accept( track_helper, m_trkTrackCuts);
1127 return acceptData;
1128}
1129
1130#endif // XAOD_ANALYSIS
1131
1147#ifdef __GNUC__
1148#pragma GCC diagnostic push
1149#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1150#endif
1151void InDet::InDetTrackSelectionTool::setCutLevel(InDet::CutLevel level, bool overwrite )
1152{
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." );
1159 }
1160 setCutLevelPrivate(level, overwrite);
1161}
1162#ifdef __GNUC__
1163#pragma GCC diagnostic pop
1164#endif
1165
1166void InDet::InDetTrackSelectionTool::setCutLevelPrivate(InDet::CutLevel level, bool overwrite)
1167{
1168 switch (level) {
1169 case CutLevel::NoCut :
1170 if (m_isInitialized) {
1171 // this check is in here so that it only happens once per call to setCutLevel,
1172 // but will still warn if only the private version is called somehow.
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." );
1175 }
1176 if (overwrite) {
1177 // minimum cuts will default to -1, so if a user wishes to remove a cut
1178 // from a preset level they can do so by setting the minimum to zero.
1179 // maximum cuts can be removed from a preset level by setting them negative.
1180 m_minPt = -1.; // in MeV
1181 m_minP = -1.;
1197 m_minNPixelHits = -1;
1201 m_minNSctHits = -1;
1206 m_minNSiHits = -1;
1213 m_maxOneSharedModule = false;
1215 m_maxEtaForTrtHitCuts = -1.; // this is really a minimum eta above which cuts are not applied
1216 m_minNTrtHits = -1;
1224 m_minProb = -1.;
1229 m_minNUsedHitsdEdx = -1;
1231 m_minEProbabilityHT = -1.;
1232 m_eProbHTonlyForXe = false;
1233#ifndef XAOD_ANALYSIS
1234 m_minNSiHitsMod = -1;
1235 m_minNSiHitsModTop = -1;
1237#endif
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>>();
1256 }
1257 break;
1258 case CutLevel::Loose :
1259 setCutLevelPrivate(CutLevel::NoCut, overwrite); // if hard overwrite, reset all cuts first. will do nothing if !overwrite
1260 // change the cuts if a hard overwrite is asked for or if the cuts are unset
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;
1266 break;
1267 case CutLevel::LoosePrimary :
1268 setCutLevelPrivate(CutLevel::NoCut, overwrite); // implement loose cuts first
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;
1275 break;
1276 case CutLevel::TightPrimary :
1277 setCutLevelPrivate(CutLevel::NoCut, overwrite);
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;
1284 if (overwrite || m_minNSiHitsAboveEtaCutoff < 0) m_minNSiHitsAboveEtaCutoff = 11;
1286 break;
1287 case CutLevel::LooseMuon :
1288 setCutLevelPrivate(CutLevel::NoCut, overwrite); // reset cuts unless we are doing a soft set
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;
1293 if (overwrite || m_maxEtaForTrtHitCuts < 0.) m_maxEtaForTrtHitCuts = 1.9;
1294 if (overwrite || m_minNTrtHitsPlusOutliers < 0) m_minNTrtHitsPlusOutliers = 6;
1296 break;
1297 case CutLevel::LooseElectron :
1298 setCutLevelPrivate(CutLevel::NoCut, overwrite);
1299 if (overwrite || m_minNSiHits < 0) m_minNSiHits = 7;
1300 if (overwrite || m_minNPixelHits < 0) m_minNPixelHits = 1;
1301 break;
1302 case CutLevel::LooseTau :
1303 setCutLevelPrivate(CutLevel::NoCut, overwrite);
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;
1309 break;
1310 case CutLevel::MinBias :
1311 setCutLevelPrivate(CutLevel::NoCut, overwrite);
1312 if (overwrite || m_useMinBiasInnermostLayersCut >= 0) m_useMinBiasInnermostLayersCut = 1; // if this is less than 0, it is turned off
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.;
1318 }
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;
1323 break;
1324 case CutLevel::HILoose:
1325 // HILoose is similar to MinBias, but not identical
1326 setCutLevelPrivate(CutLevel::NoCut, overwrite);
1327 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
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});
1334 }
1335 if (overwrite || m_maxD0 >= LOCAL_MAX_DOUBLE) m_maxD0 = 1.5;
1336 if (overwrite || m_maxZ0SinTheta >= LOCAL_MAX_DOUBLE) m_maxZ0SinTheta = 1.5;
1337 break;
1338 case CutLevel::HITight:
1339 setCutLevelPrivate(CutLevel::NoCut, overwrite);
1340 // HITight is like HILoose but we require 8 SCT hits and 2 pixel hits
1341 setCutLevelPrivate(CutLevel::NoCut, overwrite);
1342 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
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});
1349 }
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;
1353 break;
1354 case CutLevel::HILooseOptimized:
1355 setCutLevelPrivate(CutLevel::NoCut, overwrite);
1356 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1357 if (overwrite || m_maxNPixelHoles >= LOCAL_MAX_INT) m_maxNPixelHoles = 0;
1359 if (overwrite || (m_vecEtaCutoffsForZ0SinThetaCut.empty() &&
1362 m_vecEtaCutoffsForZ0SinThetaCut = std::vector<double>({0.0, 1.1, 1.6, 2.0});
1364 std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1365 2000, 2500, 3000, 5000, 8000, 12000});
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}});
1371 }
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});
1377 std::vector<double>({500, 600, 700, 800, 900, 1000, 1500,
1378 2000, 2500, 3000, 5000, 8000, 12000});
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}});
1384 }
1385 break;
1386 case CutLevel::HITightOptimized:
1387 setCutLevelPrivate(CutLevel::NoCut, overwrite);
1388 if (overwrite || m_maxAbsEta >= LOCAL_MAX_DOUBLE) m_maxAbsEta = 2.5;
1389 if (overwrite || m_maxNPixelHoles >= LOCAL_MAX_INT) m_maxNPixelHoles = 0;
1391 if (overwrite || (m_vecEtaCutoffsForZ0SinThetaCut.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});
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}});
1402 }
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});
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}});
1414 }
1415 if (overwrite || (m_vecEtaCutoffsForSctHolesCut.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});
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}});
1426 }
1427 if (overwrite || (m_vecEtaCutoffsForSctHitsPlusDeadCut.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});
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}});
1438 }
1439 break;
1440 default:
1441 ATH_MSG_ERROR("CutLevel not recognized. Cut selection will remain unchanged.");
1442 break;
1443 }
1444}
1445
1446// initialize the map from strings to cut levels
1447const std::unordered_map<std::string, InDet::CutLevel>
1449 {
1450 {"NoCut", InDet::CutLevel::NoCut},
1451 {"Loose", InDet::CutLevel::Loose},
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}
1462 };
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static Double_t a
static const std::vector< std::string > bins
static const uint32_t nHits
#define sqr(t)
@ top
Gaudi::Property< std::vector< double > > m_vecEtaCutoffsForSctHitsPlusDeadCut
Gaudi::Property< std::vector< double > > m_vecEtaCutoffsForSiHitsCut
Gaudi::Property< double > m_maxTrtHighEFraction
ToolHandle< Trk::ITrackSummaryTool > m_trackSumTool
Gaudi::Property< int > m_minNSiHitsAboveEtaCutoff
Gaudi::Property< bool > m_eProbHTonlyForXe
Gaudi::Property< std::vector< std::vector< double > > > m_vecvecMaxSctHolesAboveEtaPt
Gaudi::Property< double > m_minEtaForStrictNSiHitsCut
static bool maxDoubleIsSet(double cutValue)
Gaudi::Property< int > m_maxNSctDoubleHoles
std::atomic< uint64_t > m_numTracksPassed
a counter of the number of tracks that passed all cuts
virtual const asg::AcceptInfo & getAcceptInfo() const override
Get an object describing the "selection steps" of the tool.
Gaudi::Property< double > m_maxZ0SinThetaoverSigmaZ0SinTheta
Gaudi::Property< int > m_minNBothInnermostLayersHits
Gaudi::Property< std::vector< double > > m_vecEtaCutoffsForD0Cut
Gaudi::Property< double > m_maxZ0overSigmaZ0
StatusCode setupCuts(std::map< std::string, std::vector< std::function< bool(Trk_Helper helper, const asg::AsgMessaging &msgHelper)> > > &trackCuts)
Gaudi::Property< int > m_minNPixelHitsPhysical
virtual asg::AcceptData accept(const xAOD::IParticle *) const override
Get the decision using a generic IParticle pointer.
Gaudi::Property< int > m_minNSiHitsPhysical
Gaudi::Property< double > m_minPtForProbCut
Gaudi::Property< std::vector< std::vector< double > > > m_vecvecMaxZ0SinThetaAboveEtaPt
Gaudi::Property< double > m_maxSigmaZ0SinTheta
Gaudi::Property< bool > m_useExperimentalInnermostLayersCut
Gaudi::Property< double > m_maxD0overSigmaD0
Gaudi::Property< std::vector< double > > m_vecPtCutoffsForSctHitsPlusDeadCut
Gaudi::Property< std::string > m_cutLevel
The string version of the cut level so that it can be set via jobOptions.
Gaudi::Property< std::vector< double > > m_vecPtCutoffsForD0Cut
Gaudi::Property< int > m_minNSiHitsIfSiSharedHits
std::atomic< uint64_t > m_numTracksProcessed
a counter of the number of tracks proccessed
Gaudi::Property< double > m_maxSigmaD0
Gaudi::Property< std::vector< double > > m_vecPtCutoffsForSctHitsCut
Gaudi::Property< int > m_minNInnermostLayerHits
Gaudi::Property< std::vector< std::vector< double > > > m_vecvecMinSctHitsPlusDeadAboveEtaPt
virtual StatusCode finalize() override
Function finalizing the tool.
virtual StatusCode initialize() override
Function initialising the tool.
Gaudi::Property< double > m_minEProbabilityHT
Gaudi::Property< int > m_useMinBiasInnermostLayersCut
Gaudi::Property< double > m_maxEtaForTrtHitCuts
asg::AcceptInfo m_acceptInfo
Object used to store the last decision.
Gaudi::Property< int > m_minNSiHitsModBottom
ToolHandle< Trk::IExtrapolator > m_extrapolator
std::unique_ptr< asg::AsgMessaging > m_msgHelper
Gaudi::Property< int > m_maxNInnermostLayerSharedHits
Gaudi::Property< bool > m_useEtaDependentMaxChiSq
Gaudi::Property< int > m_minNOverflowHitsdEdx
Gaudi::Property< double > m_maxAbsEta
std::map< std::string, std::vector< std::function< bool(InDetAccessor::TrackParticleHelper helper, const asg::AsgMessaging &msgHelper)> > > m_trackParticleCuts
First element is the name of the cut family, second element is the set of cuts.
Gaudi::Property< bool > m_maxOneSharedModule
bool m_trackSumToolAvailable
Whether the summary tool is available.
Gaudi::Property< std::vector< double > > m_vecEtaCutoffsForPtCut
std::map< std::string, std::vector< std::function< bool(InDetAccessor::TrkTrackHelper helper, const asg::AsgMessaging &msgHelper)> > > m_trkTrackCuts
First element is the name of the cut family, second element is the set of cuts.
Gaudi::Property< std::vector< double > > m_vecEtaCutoffsForSctHolesCut
Gaudi::Property< int > m_minNSctHitsPhysical
Gaudi::Property< double > m_minProbAbovePtCutoff
Gaudi::Property< std::vector< double > > m_vecPtCutoffsForSctHolesCut
Gaudi::Property< int > m_minNTrtHighThresholdHitsPlusOutliers
Gaudi::Property< double > m_maxChiSqperNdf
Gaudi::Property< double > m_maxTrtOutlierFraction
Gaudi::Property< int > m_minNNextToInnermostLayerHits
Gaudi::Property< int > m_maxNPixelSharedHits
Gaudi::Property< double > m_maxZ0SinTheta
Gaudi::Property< int > m_minNTrtHighThresholdHits
Gaudi::Property< std::vector< double > > m_vecMinPtAboveEta
Gaudi::Property< std::vector< int > > m_vecMinNSctHitsAbovePt
static const std::unordered_map< std::string, CutLevel > s_mapCutLevel
ASG_TOOL_CLASS2(InDetTrackSelectionTool, IAsgSelectionTool, InDet::IInDetTrackSelectionTool) public ~InDetTrackSelectionTool()
Create a proper constructor for Athena.
static bool maxIntIsSet(int cutValue)
Gaudi::Property< std::vector< int > > m_vecMinNSiHitsAboveEta
Gaudi::Property< int > m_minNTrtHitsPlusOutliers
virtual void setCutLevel(InDet::CutLevel level, bool overwrite=true) override __attribute__((deprecated("For consistency with the athena interface
Function to set the cut level within standalone ROOT.
Gaudi::Property< double > m_maxTrtEtaAcceptance
Gaudi::Property< std::vector< double > > m_vecPtCutoffsForZ0SinThetaCut
Gaudi::Property< double > m_maxTrtHighEFractionWithOutliers
void setCutLevelPrivate(InDet::CutLevel level, bool overwrite=true)
Gaudi::Property< double > m_maxSigmaZ0
Gaudi::Property< std::vector< std::vector< double > > > m_vecvecMaxD0AboveEtaPt
Gaudi::Property< std::vector< double > > m_vecEtaCutoffsForZ0SinThetaCut
Class describing the Line to which the Perigee refers to.
A summary of the information contained by a track.
This class is a simplest representation of a vertex candidate.
void setCutResult(const std::string &cutName, bool cutResult)
Set the result of a cut, based on the cut name (safer)
Definition AcceptData.h:134
bool getCutResult(const std::string &cutName) const
Get the result of a cut, based on the cut name (safer)
Definition AcceptData.h:98
Class mimicking the AthMessaging class from the offline software.
virtual StatusCode initialize()
Dummy implementation of the initialisation function.
Definition AsgTool.h:133
Class providing the definition of the 4-vector interface.
Int_t getNumberOfUsedHitsdEdx(Trk_Helper &helper, const asg::AsgMessaging &msgHelper)
std::tuple< uint8_t, uint8_t > getSiHitsTopBottom(const Trk::Track &track, const asg::AsgMessaging &msgHelper)
double getFitChiSquare(const Trk_Helper &helper, const asg::AsgMessaging &msgHelper)
Int_t getNumberOfIBLOverflowsdEdx(Trk_Helper &helper, const asg::AsgMessaging &msgHelper)
uint8_t getSummarySum(const T_TrkHelper helper, const asg::AsgMessaging &msgHelper, std::array< xAOD::SummaryType, n_summary_types > sumTypes)
double getFitNDoF(const TrkHelper &helper, const asg::AsgMessaging &msgHelper)
float getEProbabilityHT(const Trk_Helper &helper, const asg::AsgMessaging &msgHelper)
uint8_t getSummary(const T_TrkHelper &helper, const asg::AsgMessaging &msgHelper, xAOD::SummaryType sumType)
bool absEta(const xAOD::TauJet &tau, float &out)
@ anyDirection
ParametersBase< TrackParametersDim, Charged > TrackParameters
@ TrackParticle
The object is a charged track particle.
Definition ObjectType.h:43
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
@ expectInnermostPixelLayerHit
Do we expect a 0th-layer barrel hit for this track?
@ numberOfPixelHoles
number of pixel layers on track with absence of hits [unit8_t].
@ numberOfTRTHighThresholdOutliers
number of TRT high threshold outliers (only xenon counted) [unit8_t].
@ numberOfInnermostPixelLayerSharedHits
number of Pixel 0th layer barrel hits shared by several tracks.
@ numberOfTRTXenonHits
number of TRT hits on track in straws with xenon [unit8_t].
@ numberOfTRTHits
number of TRT hits [unit8_t].
@ numberOfNextToInnermostPixelLayerHits
these are the hits in the 1st pixel barrel layer
@ numberOfSCTDeadSensors
number of dead SCT sensors crossed [unit8_t].
@ expectNextToInnermostPixelLayerHit
Do we expect a 1st-layer barrel hit for this track?
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfSCTDoubleHoles
number of Holes in both sides of a SCT module [unit8_t].
@ numberOfInnermostPixelLayerHits
these are the hits in the 0th pixel barrel layer
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
@ numberOfPixelSharedHits
number of Pixel all-layer hits shared by several tracks [unit8_t].
@ numberOfSCTSharedHits
number of SCT hits shared by several tracks [unit8_t].
@ numberOfTRTHighThresholdHits
number of TRT hits which pass the high threshold (only xenon counted) [unit8_t].
@ numberOfTRTOutliers
number of TRT outliers [unit8_t].
@ numberOfPixelDeadSensors
number of dead pixel sensors crossed [unit8_t].
@ numberOfSCTHoles
number of SCT holes [unit8_t].