ATLAS Offline Software
Loading...
Searching...
No Matches
AthTruthSelectionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
11
16
17#include <vector>
18#include <cmath>
19
21
22namespace {
23 constexpr int electronId(11);
24 constexpr int gammaId(22);
25 bool hasAncestor(const xAOD::TruthParticle* particle, const std::vector<int>& allowedAncestors) {
26 bool pass = false;
27 uint nPar = particle->nParents();
28 for (uint i = 0; i < nPar; i++) {
29 for (const int & ancestorID : allowedAncestors) {
30 if (std::abs(particle->parent(i)->pdgId()) == ancestorID) {
31 return true;
32 }
33 }
34 }
35 for (uint i = 0; i < nPar; i++) {
36 const xAOD::TruthParticle* parent = particle->parent(i);
37 if (hasAncestor(parent, allowedAncestors)) return true;
38 }
39 return pass;
40 }
41}
42
43
44AthTruthSelectionTool::AthTruthSelectionTool(const std::string& type, const std::string& name,
45 const IInterface* parent) :
46 AthAlgTool(type, name, parent)
47{
48 // declare interface from base class
49 declareInterface<IAthSelectionTool>(this);
50}
51
52StatusCode
54 // can set cut properties now
55 using P_t = xAOD::TruthParticle;
56 using Accept_t = Accept<P_t>;
57 //
58 const std::vector<Accept_t> filters = {
59 // if p.pt=0, TVector3 generates an error when querying p.eta(); a limit of 1e-7 was not found to be enough to
60 // prevent this
61 // the following also vetoes the case where the p.pt()=NaN, as any inequality with NaN evaluates to false
62 Accept_t([this](const P_t& p) -> bool {
63 return((p.pt() > 0.1) ? (std::abs(p.eta()) < m_maxEta) : false);
64 }, std::string("eta")),
65 Accept_t([this](const P_t& p) -> bool {
66 return(p.pt() > m_minPt);
67 }, std::string("min_pt"))
68 };
69 //
70 m_cutList = CutList<P_t>(filters);
71 if (m_maxProdVertRadius>0) {
72 m_cutList.add(Accept_t([&m_maxProdVertRadius = std::as_const(m_maxProdVertRadius)](const P_t& p) -> bool {
73 return((not (p.hasProdVtx()))or(p.prodVtx()->perp() < m_maxProdVertRadius));
74 },
75 "decay_before_" + std::to_string(m_maxProdVertRadius)));
76 }
77 if (m_minProdVertRadius>0) {
78 m_cutList.add(Accept_t([&m_minProdVertRadius = std::as_const(m_minProdVertRadius)](const P_t& p) -> bool {
79 return((not (p.hasProdVtx()))or(p.prodVtx()->perp() > m_minProdVertRadius));
80 },
81 "decay_after_" + std::to_string(m_minProdVertRadius)));
82 }
83 if (m_minAbsD0>0) {
84 m_cutList.add(Accept_t([&m_minAbsD0 = std::as_const(m_minAbsD0)](const P_t& p) -> bool {
85 static const SG::ConstAccessor<float> d0Acc("d0");
86 if (d0Acc.isAvailable(p)) return (std::abs(d0Acc(p)) > m_minAbsD0);
87 else return false;
88 }, "min_abs_d0_" + std::to_string(m_minAbsD0)));
89 }
90 if (m_maxPt > 0) {
91 m_cutList.add(Accept_t([&m_maxPt = std::as_const(m_maxPt)](const P_t& p) {
92 return(p.pt() < m_maxPt);
93 }, "max_pt"));
94 }
95 if (m_requireSiHit > 0) {
96 m_cutList.add(Accept_t([&m_requireSiHit = std::as_const(m_requireSiHit)](const P_t& p) {
97 static const SG::AuxElement::ConstAccessor< float > nSilHitsAcc("nSilHits");
98 if (nSilHitsAcc.isAvailable(p)) return (nSilHitsAcc(p) >= m_requireSiHit);
99 else return false;
100 }, "siHit"));
101 }
103 m_cutList.add(Accept_t([](const P_t& p) {
105 }, "OnlyPrimary"));
106 }
107 if (m_requireCharged) {
108 m_cutList.add(Accept_t([&m_selectedCharge = std::as_const(m_selectedCharge)](const P_t& p) {
109 if(m_selectedCharge ==0) return(not (p.isNeutral()));
110 else return(not(p.isNeutral()) and p.charge()==m_selectedCharge);
111 }, "charged"));
112 }
113 if (m_requireStable) {
114 m_cutList.add(Accept_t([](const P_t& p) {
115 return(MC::isStable(&p));
116 }, "stable"));
117 }
118 if (m_pdgId > 0) {
119 m_cutList.add(Accept_t([&m_pdgId = std::as_const(m_pdgId)](const P_t& p) {
120 return(std::abs(p.pdgId()) == m_pdgId);
121 }, "pdgId"));
122 }
123 if (m_vetoPdgId > 0) {
124 m_cutList.add(Accept_t([&m_vetoPdgId = std::as_const(m_vetoPdgId)](const P_t& p) {
125 return(std::abs(p.pdgId()) != m_vetoPdgId);
126 }, "vetoPdgId"));
127 }
128 if (m_grandparent) {
129 m_cutList.add(Accept_t([](const P_t& p) {
130 return((p.nParents() == 0) || ((p.nParents() == 1)and((p.parent(0))->nParents() == 0)));
131 }, "hasNoGrandparent"));
132 }
133 //require the truth particles to come from certain ancesters
134 if (!m_ancestors.empty()) {
135 m_cutList.add(Accept_t([&m_ancestors = std::as_const(m_ancestors)](const P_t& p) -> bool {
136 const xAOD::TruthParticle* pTruth = dynamic_cast<const xAOD::TruthParticle*>(&p);
137 if (not pTruth) return false;
138 else return hasAncestor(pTruth, m_ancestors);
139 }, "ancestors"));
140 }
142 m_cutList.add(Accept_t([](const P_t& p) {
143 return((p.absPdgId() == electronId)and(p.nParents() >= 1) and(p.parent(0)) and(p.parent(0)->pdgId() == gammaId));
144 }, "poselectronfromgamma"));
145 }
146 if (m_radiusCylinder > 0) {
147 // m_cutList.add(Accept_t(acceptExtrapolatedTPToSurface, "SelectCylinder"));
148 if (not m_cylinder) {
149 ATH_MSG_VERBOSE("Creating and caching cylinder surface");
150 Amg::Transform3D trnsf;
151 trnsf.setIdentity();
152 m_cylinder = std::make_unique<Trk::CylinderSurface>( trnsf, m_radiusCylinder, 20000.);
153 }
154 m_cutList.add(Accept_t([this](const P_t& p) -> bool {
155 ATH_MSG_VERBOSE("Checking particle for intersection with cylinder of radius " << m_radiusCylinder);
156 //create surface we extrapolate to and cache it
157 const xAOD::TruthVertex* ptruthVertex = p.prodVtx();
158 if (ptruthVertex == nullptr) {
159 //cannot derive production vertex, reject track
160 ATH_MSG_VERBOSE("Rejecting particle without production vertex.");
161 return false;
162 }
163 const auto xPos = ptruthVertex->x();
164 const auto yPos = ptruthVertex->y();
165 const auto z_truth = ptruthVertex->z();
166 const Amg::Vector3D position(xPos, yPos, z_truth);
167 const Amg::Vector3D momentum(p.px(), p.py(), p.pz());
168 const Trk::CurvilinearParameters cParameters(position, momentum, p.charge());
169 const Trk::TrackParameters *exParameters = m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),
170 cParameters,
171 *m_cylinder,
172 Trk::anyDirection, false, Trk::pion).release();
173 if (!exParameters) {
174 ATH_MSG_VERBOSE("Failed extrapolation. Rejecting track.");
175 return false;
176 }
177 ATH_MSG_VERBOSE("Extrapolated parameters to cylinder: " << *exParameters);
178 const float ex_abs_z = fabs(exParameters->position().z());
179 if ( (ex_abs_z > m_minZCylinder) and (ex_abs_z < m_maxZCylinder) ) {
180 ATH_MSG_VERBOSE("Particle accepted.");
181 return true;
182 }
183 //else..
184 ATH_MSG_VERBOSE("Particle rejected");
185 return false;
186 }, "SelectCylinder"));
187 } else if (m_zDisc > 0) {
188 //m_cutList.add(Accept_t(acceptExtrapolatedTPToSurface, "SelectDisc"));
189 if (not m_disc1 || not m_disc2) { //m_disc2 == 0 implied
190 ATH_MSG_VERBOSE("Creating and caching disc surface");
192 m_disc1 = std::make_unique<Trk::DiscSurface>( trnsf_shiftZ, m_minRadiusDisc, m_maxRadiusDisc);
193 trnsf_shiftZ = Amg::Translation3D(0.,0.,-m_zDisc);
194 m_disc2 = std::make_unique<Trk::DiscSurface>( trnsf_shiftZ, m_minRadiusDisc, m_maxRadiusDisc);
195 }
196 m_cutList.add(Accept_t([this](const P_t& p) -> bool {
197 ATH_MSG_VERBOSE("Checking particle for intersection with discs of |z| " << m_zDisc);
198 //create surface we extrapolate to and cache it
199 const xAOD::TruthVertex* ptruthVertex = p.prodVtx();
200 if (ptruthVertex == nullptr) {
201 //cannot derive production vertex, reject track
202 ATH_MSG_VERBOSE("Rejecting particle without production vertex.");
203 return false;
204 }
205 const auto xPos = ptruthVertex->x();
206 const auto yPos = ptruthVertex->y();
207 const auto z_truth = ptruthVertex->z();
208 const Amg::Vector3D position(xPos, yPos, z_truth);
209 const Amg::Vector3D momentum(p.px(), p.py(), p.pz());
210 const Trk::CurvilinearParameters cParameters(position, momentum, p.charge());
211 const Trk::TrackParameters *exParameters = m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),
212 cParameters,
213 *m_disc1, Trk::anyDirection, true, Trk::pion).release();
214 if (exParameters) {
215 //since boundary check is true, should be enough to say we've hit the disk..
216 ATH_MSG_VERBOSE("Successfully extrapolated track to disk at +" << m_zDisc << ": " << *exParameters);
217 float ex_radius = sqrt(pow(exParameters->position().x(),2)+pow(exParameters->position().y(),2));
218 ATH_MSG_VERBOSE("radial position at surface: " << ex_radius);
219 if ((ex_radius > m_minRadiusDisc) and (ex_radius < m_maxRadiusDisc)) {
220 ATH_MSG_VERBOSE("Confirmed within the disk. Accepting particle");
221 return true;
222 }
223 //else...
224 ATH_MSG_VERBOSE("Strange, extrapolation succeeded but extrapolated position not within disc radius! Test next disc");
225 }
226 exParameters = m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),cParameters, *m_disc2, Trk::anyDirection, true, Trk::pion).release();
227 if (exParameters) {
228 //since boundary check is true, should be enough to say we've hit the disk..
229 ATH_MSG_VERBOSE("Successfully extrapolated track to disk at -" << m_zDisc << ": " << *exParameters);
230 float ex_radius = sqrt(pow(exParameters->position().x(),2)+pow(exParameters->position().y(),2));
231 ATH_MSG_VERBOSE("radial position at surface: " << ex_radius);
232 if ((ex_radius > m_minRadiusDisc) and (ex_radius < m_maxRadiusDisc)) {
233 ATH_MSG_VERBOSE("Confirmed within the disk. Accepting particle");
234 return true;
235 }
236 //else...
237 ATH_MSG_VERBOSE("Strange, extrapolation succeeded but extrapolated position not within disc radius! Rejecting");
238 }
239 //else..
240 ATH_MSG_VERBOSE("Particle rejected");
241 return false;
242 }, "SelectDisc"));
243 } //m_zDisc > 0
244
245 std::string msg = std::to_string(m_cutList.size()) + " truth acceptance cuts are used:\n";
246 for (const auto& i:m_cutList.names()) {
247 msg += i + "\n";
248 }
250
251 ATH_CHECK(m_extrapolator.retrieve(EnableTool{ m_radiusCylinder > 0 || m_zDisc >0 }));
252
253 return StatusCode::SUCCESS;
254}
255
256StatusCode
258 // nop
259 return StatusCode::SUCCESS;
260}
261
262
263std::vector<std::string>
265 return m_cutList.names();
266}
267
270 const xAOD::TruthParticle* pTruth = dynamic_cast<const xAOD::TruthParticle*>(particle);
271
272 //@TODO
273 if (not pTruth) {
274 return m_cutList.size()+1; // marker for invalid particles
275 }
276 return m_cutList.accept(*pTruth);
277}
278
280AthTruthSelectionTool::testAllCuts(const xAOD::IParticle * particle, std::vector<unsigned int> &counter) const {
281 const xAOD::TruthParticle* pTruth = dynamic_cast<const xAOD::TruthParticle*>(particle);
282
283 //@TODO
284 if (not pTruth) {
285 return m_cutList.size()+1; // marker for invalid particles
286 }
287 return m_cutList.testAllCuts(*pTruth,counter);
288}
289
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
header file for truth selection in this package
ATLAS-specific HepMC functions.
unsigned int uint
Templated class containing a cut, name of cut and description of cut(optional) Typically,...
Definition CutFlow.h:28
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
MsgStream & msg() const
std::vector< std::string > names() const final
return the names of the cuts as a vector<string>
std::unique_ptr< Trk::CylinderSurface > m_cylinder
PublicToolHandle< Trk::IExtrapolator > m_extrapolator
Too handle for truth-track extrapolation.
virtual IAthSelectionTool::CutResult testAllCuts(const xAOD::IParticle *p, std::vector< unsigned int > &counter) const final
The most important method to determine whether the particle is accepted.
std::unique_ptr< Trk::DiscSurface > m_disc1
AthTruthSelectionTool(const std::string &type, const std::string &name, const IInterface *parent)
BooleanProperty m_requireOnlyPrimary
CutList< xAOD::TruthParticle > m_cutList
virtual IAthSelectionTool::CutResult accept(const xAOD::IParticle *particle) const final
The most important method to determine whether the particle is accepted.
BooleanProperty m_poselectronfromgamma
std::unique_ptr< Trk::DiscSurface > m_disc2
IntegerArrayProperty m_ancestors
Templated CutList class to contain a group of cuts.
Definition CutFlow.h:93
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:570
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
const Amg::Vector3D & position() const
Access method for the position.
Class providing the definition of the 4-vector interface.
float z() const
Vertex longitudinal distance along the beam line form the origin.
float y() const
Vertex y displacement.
float x() const
Vertex x displacement.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
Eigen::Translation< double, 3 > Translation3D
bool is_simulation_particle(const T &p)
Method to establish if a particle (or barcode) was created during the simulation (TODO update to be s...
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
@ anyDirection
CurvilinearParametersT< TrackParametersDim, Charged, PlaneSurface > CurvilinearParameters
ParametersBase< TrackParametersDim, Charged > TrackParameters
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TruthParticle_v1 TruthParticle
Typedef to implementation.