ATLAS Offline Software
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 
12 #include "AthTruthSelectionTool.h"
15 #include "xAODTruth/TruthVertex.h"
16 
17 #include <vector>
18 #include <cmath>
19 
21 
22 namespace {
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 
44 AthTruthSelectionTool::AthTruthSelectionTool(const std::string& type, const std::string& name,
45  const IInterface* parent) :
47  m_counters{}
48 {
49  // declare interface from base class
50  declareInterface<IAthSelectionTool>(this);
51  // declareProperty( "Property", m_nProperty ); set defaults
52  declareProperty("maxEta", m_maxEta = 2.5);
53  declareProperty("minPt", m_minPt = 400);
54  declareProperty("maxPt", m_maxPt = -1);
55  declareProperty("requireOnlyPrimary", m_requireOnlyPrimary = true);
56  declareProperty("requireCharged", m_requireCharged = true);
57  declareProperty("selectedCharge", m_selectedCharge = 0);
58  declareProperty("requireStable", m_requireStable = true);
59  declareProperty("requireSiHit", m_requireSiHit = 0);
60  declareProperty("maxProdVertRadius", m_maxProdVertRadius = 110.);
61  declareProperty("pdgId", m_pdgId = -1);
62  declareProperty("hasNoGrandparent", m_grandparent = false);
63  declareProperty("ancestorList", m_ancestors = {});
64  declareProperty("poselectronfromgamma", m_poselectronfromgamma = false);
65  declareProperty("radiusCylinder", m_radiusCylinder=-1, "Select truth particle based on extrapolated position on cylinder placed at this radius. Enabled if greater than 0.");
66  declareProperty("minZCylinder", m_minZCylinder=0.0, "Minimum |Z| on cylinder for accepting extrapolated truth particle to surface.");
67  declareProperty("maxZCylinder", m_maxZCylinder=0.0, "Maximum |Z| on cylinder for accepting extrapolated truth particle to surface.");
68  declareProperty("zDisc", m_zDisc=-1.0, "Select truth particle based on extrapolated position on disks placed at +/- z positions. Enabled if greater than 0.");
69  declareProperty("minRadiusDisc", m_minRadiusDisc=0.0, "Minimum radius on disk for accepting extrapolated truth particle to surface.");
70  declareProperty("maxRadiusDisc", m_maxRadiusDisc=0.0, "Maximum radius on disk for accepting extrapolated truth particle to surface.");
71 }
72 
75  // can set cut properties now
76  using P_t = xAOD::TruthParticle;
77  using Accept_t = Accept<P_t>;
78  //
79  const std::vector<Accept_t> filters = {
80  // if p.pt=0, TVector3 generates an error when querying p.eta(); a limit of 1e-7 was not found to be enough to
81  // prevent this
82  // the following also vetoes the case where the p.pt()=NaN, as any inequality with NaN evaluates to false
83  Accept_t([this](const P_t& p) -> bool {
84  return((p.pt() > 0.1) ? (std::abs(p.eta()) < m_maxEta) : false);
85  }, std::string("eta")),
86  Accept_t([this](const P_t& p) -> bool {
87  return(p.pt() > m_minPt);
88  }, std::string("min_pt"))
89  };
90  //
91  m_cutList = CutList<P_t>(filters);
92  if (m_maxProdVertRadius>0) {
93  m_cutList.add(Accept_t([&m_maxProdVertRadius = std::as_const(m_maxProdVertRadius)](const P_t& p) -> bool {
94  return((not (p.hasProdVtx()))or(p.prodVtx()->perp() < m_maxProdVertRadius));
95  },
96  "decay_before_" + std::to_string(m_maxProdVertRadius)));
97  }
98  if (m_maxPt > 0) {
99  m_cutList.add(Accept_t([&m_maxPt = std::as_const(m_maxPt)](const P_t& p) {
100  return(p.pt() < m_maxPt);
101  }, "max_pt"));
102  }
103  if (m_requireSiHit > 0) {
104  m_cutList.add(Accept_t([&m_requireSiHit = std::as_const(m_requireSiHit)](const P_t& p) {
105  static const SG::AuxElement::ConstAccessor< float > nSilHitsAcc("nSilHits");
106  if (nSilHitsAcc.isAvailable(p)) return (nSilHitsAcc(p) >= m_requireSiHit);
107  else return false;
108  }, "siHit"));
109  }
110  if (m_requireOnlyPrimary) {
111  m_cutList.add(Accept_t([](const P_t& p) {
112  return(!HepMC::is_simulation_particle(&p));
113  }, "OnlyPrimary"));
114  }
115  if (m_requireCharged) {
116  m_cutList.add(Accept_t([&m_selectedCharge = std::as_const(m_selectedCharge)](const P_t& p) {
117  if(m_selectedCharge ==0) return(not (p.isNeutral()));
118  else return(not(p.isNeutral()) and p.charge()==m_selectedCharge);
119  }, "charged"));
120  }
121  if (m_requireStable) {
122  m_cutList.add(Accept_t([](const P_t& p) {
123  return(MC::isStable(&p));
124  }, "stable"));
125  }
126  if (m_pdgId > 0) {
127  m_cutList.add(Accept_t([&m_pdgId = std::as_const(m_pdgId)](const P_t& p) {
128  return(std::abs(p.pdgId()) == m_pdgId);
129  }, "pdgId"));
130  }
131  if (m_grandparent) {
132  m_cutList.add(Accept_t([](const P_t& p) {
133  return((p.nParents() == 0) || ((p.nParents() == 1)and((p.parent(0))->nParents() == 0)));
134  }, "hasNoGrandparent"));
135  }
136  //require the truth particles to come from certain ancesters
137  if (!m_ancestors.empty()) {
138  m_cutList.add(Accept_t([&m_ancestors = std::as_const(m_ancestors)](const P_t& p) -> bool {
139  const xAOD::TruthParticle* pTruth = dynamic_cast<const xAOD::TruthParticle*>(&p);
140  if (not pTruth) return false;
141  else return hasAncestor(pTruth, m_ancestors);
142  }, "ancestors"));
143  }
145  m_cutList.add(Accept_t([](const P_t& p) {
146  return((p.absPdgId() == electronId)and(p.nParents() >= 1) and(p.parent(0)) and(p.parent(0)->pdgId() == gammaId));
147  }, "poselectronfromgamma"));
148  }
149  if (m_radiusCylinder > 0) {
150  // m_cutList.add(Accept_t(acceptExtrapolatedTPToSurface, "SelectCylinder"));
151  if (not m_cylinder) {
152  ATH_MSG_VERBOSE("Creating and caching cylinder surface");
153  Amg::Transform3D trnsf;
154  trnsf.setIdentity();
155  m_cylinder = std::make_unique<Trk::CylinderSurface>( trnsf, m_radiusCylinder, 20000.);
156  }
157  m_cutList.add(Accept_t([this](const P_t& p) -> bool {
158  ATH_MSG_VERBOSE("Checking particle for intersection with cylinder of radius " << m_radiusCylinder);
159  //create surface we extrapolate to and cache it
160  const xAOD::TruthVertex* ptruthVertex = p.prodVtx();
161  if (ptruthVertex == nullptr) {
162  //cannot derive production vertex, reject track
163  ATH_MSG_VERBOSE("Rejecting particle without production vertex.");
164  return false;
165  }
166  const auto xPos = ptruthVertex->x();
167  const auto yPos = ptruthVertex->y();
168  const auto z_truth = ptruthVertex->z();
169  const Amg::Vector3D position(xPos, yPos, z_truth);
170  const Amg::Vector3D momentum(p.px(), p.py(), p.pz());
171  const Trk::CurvilinearParameters cParameters(position, momentum, p.charge());
172  const Trk::TrackParameters *exParameters = m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),
173  cParameters,
174  *m_cylinder,
175  Trk::anyDirection, false, Trk::pion).release();
176  if (!exParameters) {
177  ATH_MSG_VERBOSE("Failed extrapolation. Rejecting track.");
178  return false;
179  }
180  ATH_MSG_VERBOSE("Extrapolated parameters to cylinder: " << *exParameters);
181  const float ex_abs_z = fabs(exParameters->position().z());
182  if ( (ex_abs_z > m_minZCylinder) and (ex_abs_z < m_maxZCylinder) ) {
183  ATH_MSG_VERBOSE("Particle accepted.");
184  return true;
185  }
186  //else..
187  ATH_MSG_VERBOSE("Particle rejected");
188  return false;
189  }, "SelectCylinder"));
190  } else if (m_zDisc > 0) {
191  //m_cutList.add(Accept_t(acceptExtrapolatedTPToSurface, "SelectDisc"));
192  if (not m_disc1 || not m_disc2) { //m_disc2 == 0 implied
193  ATH_MSG_VERBOSE("Creating and caching disc surface");
195  m_disc1 = std::make_unique<Trk::DiscSurface>( trnsf_shiftZ, m_minRadiusDisc, m_maxRadiusDisc);
196  trnsf_shiftZ = Amg::Translation3D(0.,0.,-m_zDisc);
197  m_disc2 = std::make_unique<Trk::DiscSurface>( trnsf_shiftZ, m_minRadiusDisc, m_maxRadiusDisc);
198  }
199  m_cutList.add(Accept_t([this](const P_t& p) -> bool {
200  ATH_MSG_VERBOSE("Checking particle for intersection with discs of |z| " << m_zDisc);
201  //create surface we extrapolate to and cache it
202  const xAOD::TruthVertex* ptruthVertex = p.prodVtx();
203  if (ptruthVertex == nullptr) {
204  //cannot derive production vertex, reject track
205  ATH_MSG_VERBOSE("Rejecting particle without production vertex.");
206  return false;
207  }
208  const auto xPos = ptruthVertex->x();
209  const auto yPos = ptruthVertex->y();
210  const auto z_truth = ptruthVertex->z();
211  const Amg::Vector3D position(xPos, yPos, z_truth);
212  const Amg::Vector3D momentum(p.px(), p.py(), p.pz());
213  const Trk::CurvilinearParameters cParameters(position, momentum, p.charge());
214  const Trk::TrackParameters *exParameters = m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),
215  cParameters,
216  *m_disc1, Trk::anyDirection, true, Trk::pion).release();
217  if (exParameters) {
218  //since boundary check is true, should be enough to say we've hit the disk..
219  ATH_MSG_VERBOSE("Successfully extrapolated track to disk at +" << m_zDisc << ": " << *exParameters);
220  float ex_radius = sqrt(pow(exParameters->position().x(),2)+pow(exParameters->position().y(),2));
221  ATH_MSG_VERBOSE("radial position at surface: " << ex_radius);
222  if ((ex_radius > m_minRadiusDisc) and (ex_radius < m_maxRadiusDisc)) {
223  ATH_MSG_VERBOSE("Confirmed within the disk. Accepting particle");
224  return true;
225  }
226  //else...
227  ATH_MSG_VERBOSE("Strange, extrapolation succeeded but extrapolated position not within disc radius! Test next disc");
228  }
229  exParameters = m_extrapolator->extrapolate(Gaudi::Hive::currentContext(),cParameters, *m_disc2, Trk::anyDirection, true, Trk::pion).release();
230  if (exParameters) {
231  //since boundary check is true, should be enough to say we've hit the disk..
232  ATH_MSG_VERBOSE("Successfully extrapolated track to disk at -" << m_zDisc << ": " << *exParameters);
233  float ex_radius = sqrt(pow(exParameters->position().x(),2)+pow(exParameters->position().y(),2));
234  ATH_MSG_VERBOSE("radial position at surface: " << ex_radius);
235  if ((ex_radius > m_minRadiusDisc) and (ex_radius < m_maxRadiusDisc)) {
236  ATH_MSG_VERBOSE("Confirmed within the disk. Accepting particle");
237  return true;
238  }
239  //else...
240  ATH_MSG_VERBOSE("Strange, extrapolation succeeded but extrapolated position not within disc radius! Rejecting");
241  }
242  //else..
243  ATH_MSG_VERBOSE("Particle rejected");
244  return false;
245  }, "SelectDisc"));
246  } //m_zDisc > 0
247 
248  std::string msg = std::to_string(m_cutList.size()) + " truth acceptance cuts are used:\n";
249  for (const auto& i:m_cutList.names()) {
250  msg += i + "\n";
251  }
252  ATH_MSG_INFO(msg);
253 
254  ATH_CHECK(m_extrapolator.retrieve(EnableTool{ m_radiusCylinder > 0 || m_zDisc >0 }));
255 
256  return StatusCode::SUCCESS;
257 }
258 
261  // nop
262  return StatusCode::SUCCESS;
263 }
264 
265 
266 std::vector<std::string>
268  return m_cutList.names();
269 }
270 
273  const xAOD::TruthParticle* pTruth = dynamic_cast<const xAOD::TruthParticle*>(particle);
274 
275  //@TODO
276  if (not pTruth) {
277  return m_cutList.size()+1; // marker for invalid particles
278  }
279  return m_cutList.accept(*pTruth);
280 }
281 
283 AthTruthSelectionTool::testAllCuts(const xAOD::IParticle * particle, std::vector<unsigned int> &counter) const {
284  const xAOD::TruthParticle* pTruth = dynamic_cast<const xAOD::TruthParticle*>(particle);
285 
286  //@TODO
287  if (not pTruth) {
288  return m_cutList.size()+1; // marker for invalid particles
289  }
290  return m_cutList.testAllCuts(*pTruth,counter);
291 }
292 
Trk::anyDirection
@ anyDirection
Definition: PropDirection.h:22
AthTruthSelectionTool::m_grandparent
bool m_grandparent
Definition: AthTruthSelectionTool.h:64
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
AthTruthSelectionTool::m_cylinder
std::unique_ptr< Trk::CylinderSurface > m_cylinder
Definition: AthTruthSelectionTool.h:80
TrackParameters.h
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
IAthSelectionTool::CutResult
Definition: IAthSelectionTool.h:30
AthTruthSelectionTool::finalize
StatusCode finalize() final
Definition: AthTruthSelectionTool.cxx:260
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
AthTruthSelectionTool::m_pdgId
int m_pdgId
Definition: AthTruthSelectionTool.h:63
AthTruthSelectionTool::m_radiusCylinder
float m_radiusCylinder
for cylinder topology: radius of cylinder
Definition: AthTruthSelectionTool.h:72
SG::ConstAccessor
Helper class to provide constant type-safe access to aux data.
Definition: ConstAccessor.h:55
AthTruthSelectionTool::m_requireStable
bool m_requireStable
Definition: AthTruthSelectionTool.h:58
AthTruthSelectionTool::m_requireCharged
bool m_requireCharged
Definition: AthTruthSelectionTool.h:56
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:41
CutList
Templated CutList class to contain a group of cuts.
Definition: CutFlow.h:93
AthTruthSelectionTool::m_minRadiusDisc
float m_minRadiusDisc
for disk topology: minimum radius
Definition: AthTruthSelectionTool.h:76
AthTruthSelectionTool::m_ancestors
std::vector< int > m_ancestors
Definition: AthTruthSelectionTool.h:67
xAOD::TruthVertex_v1::y
float y() const
Vertex y displacement.
AthTruthSelectionTool::m_requireOnlyPrimary
bool m_requireOnlyPrimary
Definition: AthTruthSelectionTool.h:55
uint
unsigned int uint
Definition: LArOFPhaseFill.cxx:20
AthTruthSelectionTool::m_maxEta
float m_maxEta
Definition: AthTruthSelectionTool.h:52
AthTruthSelectionTool::m_disc1
std::unique_ptr< Trk::DiscSurface > m_disc1
Definition: AthTruthSelectionTool.h:81
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ParticleGun_EoverP_Config.momentum
momentum
Definition: ParticleGun_EoverP_Config.py:63
HepMC::is_simulation_particle
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...
Definition: MagicNumbers.h:342
lumiFormat.i
int i
Definition: lumiFormat.py:85
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
AthTruthSelectionTool::names
std::vector< std::string > names() const final
return the names of the cuts as a vector<string>
Definition: AthTruthSelectionTool.cxx:267
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:37
Trk::pion
@ pion
Definition: ParticleHypothesis.h:29
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
xAOD::TruthParticle
TruthParticle_v1 TruthParticle
Typedef to implementation.
Definition: Event/xAOD/xAODTruth/xAODTruth/TruthParticle.h:15
AthTruthSelectionTool::initialize
StatusCode initialize() final
Definition: AthTruthSelectionTool.cxx:74
test_pyathena.parent
parent
Definition: test_pyathena.py:15
AthTruthSelectionTool::m_poselectronfromgamma
bool m_poselectronfromgamma
Definition: AthTruthSelectionTool.h:65
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
AthTruthSelectionTool::m_maxProdVertRadius
double m_maxProdVertRadius
Definition: AthTruthSelectionTool.h:62
AthTruthSelectionTool.h
Trk::ParametersBase
Definition: ParametersBase.h:55
Trk::CurvilinearParametersT
Definition: CurvilinearParametersT.h:48
AthTruthSelectionTool::m_minPt
float m_minPt
Definition: AthTruthSelectionTool.h:54
TruthVertex.h
xAOD::TruthVertex_v1
Class describing a truth vertex in the MC record.
Definition: TruthVertex_v1.h:37
AthTruthSelectionTool::m_selectedCharge
int m_selectedCharge
Definition: AthTruthSelectionTool.h:57
AthTruthSelectionTool::m_extrapolator
PublicToolHandle< Trk::IExtrapolator > m_extrapolator
Too handle for truth-track extrapolation.
Definition: AthTruthSelectionTool.h:89
AthTruthSelectionTool::testAllCuts
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.
Definition: AthTruthSelectionTool.cxx:283
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
MagicNumbers.h
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
AthTruthSelectionTool::m_requireSiHit
int m_requireSiHit
Definition: AthTruthSelectionTool.h:59
xAOD::TruthVertex_v1::x
float x() const
Vertex x displacement.
AthTruthSelectionTool::m_zDisc
float m_zDisc
for disk topology: Z position of disk
Definition: AthTruthSelectionTool.h:75
MC::isStable
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
Definition: HepMCHelpers.h:45
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
xAOD::TruthVertex_v1::z
float z() const
Vertex longitudinal distance along the beam line form the origin.
Amg::Translation3D
Eigen::Translation< double, 3 > Translation3D
Definition: GeoPrimitives.h:44
AthTruthSelectionTool::AthTruthSelectionTool
AthTruthSelectionTool(const std::string &type, const std::string &name, const IInterface *parent)
Definition: AthTruthSelectionTool.cxx:44
AthCommonMsg< AlgTool >::msg
MsgStream & msg() const
Definition: AthCommonMsg.h:24
AthTruthSelectionTool::m_disc2
std::unique_ptr< Trk::DiscSurface > m_disc2
Definition: AthTruthSelectionTool.h:82
AthTruthSelectionTool::m_maxPt
float m_maxPt
Definition: AthTruthSelectionTool.h:53
SG::ConstAccessor::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
AthTruthSelectionTool::m_cutList
CutList< xAOD::TruthParticle > m_cutList
Definition: AthTruthSelectionTool.h:50
AthAlgTool
Definition: AthAlgTool.h:26
Accept
Templated class containing a cut, name of cut and description of cut(optional) Typically,...
Definition: CutFlow.h:28
AthTruthSelectionTool::m_minZCylinder
float m_minZCylinder
for cylinder topology: minimum |z|
Definition: AthTruthSelectionTool.h:73
test_pyathena.counter
counter
Definition: test_pyathena.py:15
AthTruthSelectionTool::accept
virtual IAthSelectionTool::CutResult accept(const xAOD::IParticle *particle) const final
The most important method to determine whether the particle is accepted.
Definition: AthTruthSelectionTool.cxx:272
AthTruthSelectionTool::m_maxRadiusDisc
float m_maxRadiusDisc
for disk topology: maximum radius
Definition: AthTruthSelectionTool.h:77
HepMCHelpers.h
AthTruthSelectionTool::m_maxZCylinder
float m_maxZCylinder
for cylinder topology: maximum |z|
Definition: AthTruthSelectionTool.h:74