ATLAS Offline Software
Loading...
Searching...
No Matches
AsgForwardElectronLikelihoodTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
12
13// Include this class's header
18
19// STL includes
20#include <cmath>
21#include <cstdint>
22#include <string>
23
24// EDM includes
28#include "TEnv.h"
30#include "xAODEgamma/Electron.h"
31#include "xAODTracking/Vertex.h"
32
33//=============================================================================
34// Standard constructor
35//=============================================================================
36AsgForwardElectronLikelihoodTool::AsgForwardElectronLikelihoodTool(
37 const std::string& myname)
38 : AsgTool(myname)
39 , m_configFile{ "" }
40 , m_rootForwardTool{ nullptr }
41{
42
43 // Create an instance of the underlying ROOT tool
44 m_rootForwardTool =
45 new Root::TForwardElectronLikelihoodTool(("T" + myname).c_str());
46
47 // Declare the needed properties
48 declareProperty("WorkingPoint", m_WorkingPoint = "", "The Working Point");
49 declareProperty("ConfigFile", m_configFile = "", "The config file to use");
50 declareProperty(
51 "usePVContainer", m_usePVCont = true, "Whether to use the PV container");
52 declareProperty(
53 "nPVdefault", m_nPVdefault = 0, "The default number of PVs if not counted");
54 //
55 // Configurables in the root tool
56 //
57 // pdf file name. Managed in the Asg tool.
58 declareProperty("inputPDFFileName",
59 m_pdfFileName = "",
60 "The input ROOT file name that holds the PDFs");
61 // the variable names, if non-standard - nope, it's done above!
62 declareProperty("VariableNames",
63 m_rootForwardTool->m_variableNames,
64 "Variable names input to the LH");
65
66 // The likelihood cut values
67 declareProperty("CutLikelihood",
68 m_rootForwardTool->m_cutLikelihood,
69 "Cut on likelihood discriminant");
70 // do pileup-dependent discriminant cut
71 declareProperty("DiscCutSlopeForPileupTransform",
72 m_rootForwardTool->m_cutLikelihoodPileupCorrectionA,
73 "Slope correction for pileup dependent discriminant cut");
74 declareProperty("DiscCutForPileupTransform",
75 m_rootForwardTool->m_cutLikelihoodPileupCorrectionB,
76 "Additional offset for pileup dependent discriminant cut");
77 declareProperty("doPileupCorrection",
78 m_rootForwardTool->m_doPileupCorrection,
79 "Do pileup-dependent discriminant cut");
80}
81
82//=============================================================================
83// Standard destructor
84//=============================================================================
89
90//=============================================================================
91// Asg/Athena initialize method
92//=============================================================================
93StatusCode
95{
96
97 ATH_MSG_INFO("initialize : WP " << m_WorkingPoint.size() << " "
98 << m_configFile.size());
99
100 std::string PDFfilename(""); // Default
101
102 if (!m_WorkingPoint.empty()) {
105 ATH_MSG_INFO("operating point : " << this->getOperatingPointName());
106 }
107
108 if (!m_configFile.empty()) {
109 std::string configFile = PathResolverFindCalibFile(m_configFile);
110 if (configFile.empty()) {
111 ATH_MSG_ERROR("Could not locate " << m_configFile);
112 return StatusCode::FAILURE;
113 }
114
115 ATH_MSG_DEBUG("Get the input PDFs in the tool ");
116 TEnv env;
117 env.ReadFile(configFile.c_str(), kEnvLocal);
118
119 // Get the input PDFs in the tool.
120 ATH_MSG_DEBUG("Get the input PDFs in the tool ");
121
122 if (!m_pdfFileName
123 .empty()) { // If the property was set by the user, take that.
124 ATH_MSG_INFO("Setting user specified PDF file " << m_pdfFileName);
125 PDFfilename = m_pdfFileName;
126 } else {
127 if (m_configFile.find("dev/") != std::string::npos) {
128 std::string PDFdevval = env.GetValue(
129 "inputPDFFileName",
130 "ElectronPhotonSelectorTools/offline/mc16_20180716/"
131 "ForwardElectronLikelihoodPdfs.root"); // this is the first PDF ever
132 // released
133 PDFfilename = ("dev/" + PDFdevval);
134 ATH_MSG_DEBUG("Getting the input PDFs from: " << PDFfilename);
135 } else {
136 PDFfilename =
137 env.GetValue("inputPDFFileName",
138 "ElectronPhotonSelectorTools/offline/mc16_20180716/"
139 "ForwardElectronLikelihoodPdfs.root");
140 ATH_MSG_DEBUG("Getting the input PDFs from: " << PDFfilename);
141 }
142 }
143 std::string filename = PathResolverFindCalibFile(PDFfilename);
144
145 if (!filename.empty()) {
146 m_rootForwardTool->setPDFFileName(filename);
147 } else {
148 ATH_MSG_ERROR("Could not find PDF file");
149 return StatusCode::FAILURE;
150 }
151
152 m_rootForwardTool->m_variableNames = env.GetValue("VariableNames", "");
153 m_rootForwardTool->m_cutLikelihood =
154 AsgConfigHelper::HelperDouble("CutLikelihood", env);
155 m_rootForwardTool->m_cutLikelihoodPileupCorrectionA =
156 AsgConfigHelper::HelperDouble("DiscCutSlopeForPileupCorrection", env);
157 m_rootForwardTool->m_cutLikelihoodPileupCorrectionB =
158 AsgConfigHelper::HelperDouble("DiscCutForPileupCorrection", env);
159 m_rootForwardTool->m_doPileupCorrection =
160 env.GetValue("doPileupCorrection", false);
161 } else { // Error if it cant find the conf
162 ATH_MSG_ERROR("Could not find configuration file");
163 return StatusCode::FAILURE;
164 }
165
167
168 // Setup primary vertex key handle
170
171 // Get the name of the current operating point, and massage the other strings
172 // accordingly
174 "Going to massage the labels based on the provided operating point...");
175
176 // Get the message level and set the underlying ROOT tool message level
177 // accordingly
178 m_rootForwardTool->msg().setLevel(this->msg().level());
179
180 // We need to initialize the underlying ROOT TSelectorTool
181 if (m_rootForwardTool->initialize().isFailure()) {
183 "ERROR! Could not initialize the TForwardElectronLikelihoodTool!");
184 return StatusCode::FAILURE;
185 }
186
187 return StatusCode::SUCCESS;
188}
189
190//=============================================================================
191// return the accept info object
192//=============================================================================
193
194const asg::AcceptInfo&
196{
197 return m_rootForwardTool->getAcceptInfo();
198}
199
200//=============================================================================
201// The main accept method: the actual cuts are applied here
202//=============================================================================
205 double mu) const
206{
207
208 const xAOD::Electron* el = dynamic_cast<const xAOD::Electron*>(eg);
209 return accept(el, mu);
210}
211
214 double mu) const
215{
216
217 // Backwards compatbility
218 return accept(Gaudi::Hive::currentContext(), eg, mu);
219}
220
223 const xAOD::Egamma* eg,
224 double mu) const
225{
226
227 const xAOD::Electron* el = dynamic_cast<const xAOD::Electron*>(eg);
228 return accept(ctx, el, mu);
229}
230
231//=============================================================================
232// The main accept method: the actual cuts are applied here
233//=============================================================================
236 const xAOD::Electron* eg,
237 double mu) const
238{
239 if (!eg) {
240 ATH_MSG_ERROR("Failed, no egamma object.");
241 return m_rootForwardTool->accept();
242 }
243
244 const xAOD::CaloCluster* cluster = eg->caloCluster();
245 if (!cluster) {
246 ATH_MSG_WARNING("Failed, no cluster.");
247 return m_rootForwardTool->accept();
248 }
249
250 const double energy = cluster->e();
251 const float eta = (cluster->eta());
252 if (fabs(eta) > 300.0) {
253 ATH_MSG_WARNING("Failed, eta > 3000.");
254 return m_rootForwardTool->accept();
255 }
256
257 // transverse energy of the electron (using the track eta)
258 double et = (cosh(eta) != 0.) ? energy / cosh(eta) : 0.;
259 double ip(0);
260
261 // Get the number of primary vertices in this event
262 if (mu < 0) { // use npv if mu is negative (not given)
263 ip = static_cast<double>(m_usePVCont ? this->getNPrimVertices(ctx)
264 : m_nPVdefault);
265 } else {
266 ip = mu;
267 }
268
269 // for now don't cache.
270 double likelihood = calculate(ctx, eg, ip);
271
272 // Get the answer from the underlying ROOT tool
273 return m_rootForwardTool->accept(likelihood, eta, et, ip);
274}
275
276//=============================================================================
277// Calculate method for EFCaloLH in the trigger; do full LH if !CaloCutsOnly
278//=============================================================================
279double
281 double mu) const
282{
283
284 const xAOD::Electron* el = dynamic_cast<const xAOD::Electron*>(eg);
285 return calculate(el, mu);
286}
287
288double
290 double mu) const
291{
292 // Backward compatbility
293 return calculate(Gaudi::Hive::currentContext(), el, mu);
294}
295
296double
298 const xAOD::Egamma* eg,
299 double mu) const
300{
301
302 const xAOD::Electron* el = dynamic_cast<const xAOD::Electron*>(eg);
303 return calculate(ctx, el, mu);
304}
305
306//=============================================================================
307// The main result method: the actual likelihood is calculated here
308//=============================================================================
309double
311 const xAOD::Electron* eg,
312 double mu) const
313{
314 if (!eg) {
315 ATH_MSG_ERROR("Failed, no egamma object.");
316 return -999;
317 }
318
319 const xAOD::CaloCluster* cluster = eg->caloCluster();
320 if (!cluster) {
321 ATH_MSG_ERROR("Failed, no cluster.");
322 return -999;
323 }
324
325 const double energy = cluster->e();
326 const float eta = cluster->eta();
327 if (fabs(eta) > 300.0) {
328 ATH_MSG_ERROR("Failed, eta range.");
329 ATH_MSG_ERROR("checking at other place ." << eta);
330 return -999;
331 }
332
333 const double et = (cosh(eta) != 0.) ? energy / cosh(eta) : 0.;
334
335 // Shower shape variables
336 double secondDensity(0), significance(0), secondLambda(0), lateral(0),
337 longitudinal(0), fracMax(0), secondR(0), centerLambda(0);
338
339 bool allFound = true;
340 std::string notFoundList = "";
341
342 // secondLambda
344 secondLambda)) {
345 allFound = false;
346 notFoundList += "secondLambda ";
347 }
348 // lateral
349 if (!cluster->retrieveMoment(xAOD::CaloCluster::LATERAL, lateral)) {
350 allFound = false;
351 notFoundList += "lateral ";
352 }
353 // longitudinal
354 if (!cluster->retrieveMoment(xAOD::CaloCluster::LONGITUDINAL, longitudinal)) {
355 allFound = false;
356 notFoundList += "longitudinal ";
357 }
358 // fracMax
359 if (!cluster->retrieveMoment(xAOD::CaloCluster::ENG_FRAC_MAX, fracMax)) {
360 allFound = false;
361 notFoundList += "fracMax ";
362 }
363 // secondR
364 if (!cluster->retrieveMoment(xAOD::CaloCluster::SECOND_R, secondR)) {
365 allFound = false;
366 notFoundList += "secondR ";
367 }
368 // centerlambda
370 centerLambda)) {
371 allFound = false;
372 notFoundList += "centerLambda ";
373 }
375 secondDensity)) {
376 allFound = false;
377 notFoundList += "secondDensity ";
378 }
379 if (!cluster->retrieveMoment(xAOD::CaloCluster::SIGNIFICANCE, significance)) {
380 allFound = false;
381 notFoundList += "significance ";
382 }
383
384 // Get the number of primary vertices in this event
385 double ip = static_cast<double>(m_nPVdefault);
386
387 if (mu < 0) { // use npv if mu is negative (not given)
388 ip = static_cast<double>(m_usePVCont ? this->getNPrimVertices(ctx)
389 : m_nPVdefault);
390 } else {
391 ip = mu;
392 }
393
395 Form("Vars: eta=%8.5f, et=%8.5f, 2nd lambda=%8.5f, lateral=%8.5f, "
396 "longitudinal=%8.5f, center lambda=%8.5f, frac max=%8.5f, "
397 "secondR=%8.5f, significance=%8.5f, 2nd density=%8.5f, ip=%8.5f",
398 eta,
399 et,
400 secondLambda,
401 lateral,
402 longitudinal,
403 centerLambda,
404 fracMax,
405 secondR,
406 significance,
407 secondDensity,
408 ip));
409
410 if (!allFound) {
412 "Skipping LH calculation! The following variables are missing: "
413 << notFoundList);
414 return -999;
415 }
416
417 // Get the answer from the underlying ROOT tool
418 return m_rootForwardTool->calculate(eta,
419 et,
420 secondLambda,
421 lateral,
422 longitudinal,
423 centerLambda,
424 fracMax,
425 secondR,
426 significance,
427 secondDensity,
428 ip);
429}
430
431//=============================================================================
433//=============================================================================
434std::string
439//=============================================================================
442{
443 // Backwards compatibility
444 return accept(Gaudi::Hive::currentContext(), part);
445}
446
449 const xAOD::IParticle* part) const
450{
451 if (part->type() == xAOD::Type::Electron) {
452 const xAOD::Electron* el = static_cast<const xAOD::Electron*>(part);
453 return accept(ctx, el);
454 }
455 ATH_MSG_ERROR("Input is not an electron");
456 return m_rootForwardTool->accept();
457}
458//=============================================================================
459double
461{
462 // Backwards compatibily
463 return calculate(Gaudi::Hive::currentContext(), part);
464}
465
466double
468 const xAOD::IParticle* part) const
469{
470 if (part->type() == xAOD::Type::Electron) {
471 const xAOD::Electron* el = static_cast<const xAOD::Electron*>(part);
472 return calculate(ctx, el);
473 }
474 ATH_MSG_ERROR("Input is not an electron");
475 return -999;
476}
477
478//=============================================================================
479// Helper method to get the number of primary vertices
480// ( This is horrible! We don't want to iterate over all vertices in the event
481// for each electron!!!
482// This is slow!)
483//=============================================================================
484unsigned int
486 const EventContext& ctx) const
487{
488 unsigned int nVtx(0);
490 if (!vtxCont.isValid()) {
491 ATH_MSG_WARNING("Cannot find " << m_primVtxContKey.key()
492 << " container, returning default nVtx");
493 return m_nPVdefault;
494 }
495 for (const auto *vxcand : *vtxCont) {
496 if (vxcand->nTrackParticles() >= 2)
497 nVtx++;
498 }
499 return nVtx;
500}
501
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)
Handle class for reading from StoreGate.
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
static const Attributes_t empty
unsigned int m_nPVdefault
defualt nPV (when not using PVCont)
unsigned int getNPrimVertices(const EventContext &ctx) const
Get the number of primary vertices.
virtual StatusCode initialize() override final
Gaudi Service Interface method implementations.
std::string m_pdfFileName
The input ROOT file name that holds the PDFs.
asg::AcceptData accept(const xAOD::IParticle *part) const override
The main accept method: using the generic interface.
virtual ASG_TOOL_CLASS2(AsgForwardElectronLikelihoodTool, IAsgElectronLikelihoodTool, IAsgSelectionTool) public ~AsgForwardElectronLikelihoodTool()
Standard constructor.
virtual std::string getOperatingPointName() const override
Get the name of the current operating point.
double calculate(const xAOD::IParticle *part) const
The main result method: the actual likelihood is calculated here.
std::string m_WorkingPoint
Get the name of the current operating point.
virtual const asg::AcceptInfo & getAcceptInfo() const override
Method to get the plain AcceptInfo.
Root::TForwardElectronLikelihoodTool * m_rootForwardTool
Pointer to the underlying ROOT based tool.
SG::ReadHandleKey< xAOD::VertexContainer > m_primVtxContKey
read handle key to primary vertex container
bool m_usePVCont
Whether to use the PV (not available for trigger)
virtual bool isValid() override final
Can the handle be successfully dereferenced?
bool retrieveMoment(MomentType type, double &value) const
Retrieve individual moment.
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double e() const
The total energy of the particle.
@ SECOND_ENG_DENS
Second Moment in E/V.
@ SECOND_LAMBDA
Second Moment in .
@ LATERAL
Normalized lateral moment.
@ LONGITUDINAL
Normalized longitudinal moment.
@ ENG_FRAC_MAX
Energy fraction of hottest cell.
@ SECOND_R
Second Moment in .
@ CENTER_LAMBDA
Shower depth at Cluster Centroid.
@ SIGNIFICANCE
Cluster significance.
Class providing the definition of the 4-vector interface.
std::vector< double > HelperDouble(const std::string &input, TEnv &env)
std::string findConfigFile(const std::string &input, const std::map< std::string, std::string > &configmap)
const std::map< std::string, std::string > ForwardLHPointToConfFile
@ Electron
The object is an electron.
Definition ObjectType.h:46
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
Egamma_v1 Egamma
Definition of the current "egamma version".
Definition Egamma.h:17
Electron_v1 Electron
Definition of the current "egamma version".
Extra patterns decribing particle interation process.
MsgStream & msg
Definition testRead.cxx:32