ATLAS Offline Software
Loading...
Searching...
No Matches
AsgElectronSelectorTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
14
15// Include this class's header
21// STL includes
22#include <string>
23#include <cstdint>
24#include <cmath>
25#include <unordered_map>
26
27//EDM includes
28#include "xAODEgamma/Electron.h"
30#include "TEnv.h"
31
34
36{
61
62 const std::unordered_map<std::string, int> variableMap = {
63 {"eta", eta},
64 {"et", et},
65 {"f3", f3},
66 {"Rhad", Rhad},
67 {"Rhad1", Rhad1},
68 {"Reta", Reta},
69 {"weta2", weta2},
70 {"f1", f1},
71 {"Eratio", Eratio},
72 {"deltaEta1", deltaEta1},
73 {"d0", d0},
74 {"qd0", qd0},
75 {"d0significance", d0significance},
76 {"Rphi", Rphi},
77 {"dPOverP", dPOverP},
78 {"deltaPhiRescaled2", deltaPhiRescaled2},
79 {"trans_TRTPID", trans_TRTPID},
80 {"wtots1", wtots1},
81 {"EoverP", EoverP},
82 {"nPixHitsPlusDeadSensors", nPixHitsPlusDeadSensors},
83 {"nSCTHitsPlusDeadSensors", nSCTHitsPlusDeadSensors},
84 {"SCTWeightedCharge", SCTWeightedCharge},
85 };
86};
87
88//=============================================================================
89// Standard constructor
90//=============================================================================
92 AsgTool(myname),
93 m_configFile{""},
94 m_mvaTool(nullptr)
95{
96
97 // Declare the needed properties
98 declareProperty("WorkingPoint", m_workingPoint="", "The Working Point");
99 declareProperty("ConfigFile", m_configFile="", "The config file to use");
100
101 // model file name. Managed in the ElectronDNNCalculator.
102 declareProperty("inputModelFileName", m_modelFileName="", "The input file name that holds the model" );
103 // QuantileTransformer file name ( required for preprocessing ). Managed in the ElectronDNNCalculator.
104 declareProperty("quantileFileName", m_quantileFileName="", "The input file name that holds the QuantileTransformer");
105 // especially for trigger electron
106 declareProperty("skipDeltaPoverP",m_skipDeltaPoverP = false,"If true, it will skip the check of deltaPoverP");
107
108 declareProperty("skipAmbiguityCut",m_skipAmbiguityCut = false,"If true, it will skip the ambiguity cut");
109}
110
111
112//=============================================================================
113// Standard destructor
114//=============================================================================
116= default;
117
118
119//=============================================================================
120// Asgena initialize method
121//=============================================================================
123{
124 if (!m_workingPoint.empty()){
126 ATH_MSG_INFO("operating point : " << this->getOperatingPointName());
127 }
128
129 if (m_configFile.empty()){
130 ATH_MSG_ERROR("Could not find configuration file " << m_configFile);
131 return StatusCode::FAILURE;
132 }
133
134 std::string configFile = PathResolverFindCalibFile(m_configFile);
135 if (configFile.empty()){
136 ATH_MSG_ERROR("Could not locate " << m_configFile);
137 return StatusCode::FAILURE;
138 }
139
140
141 ATH_MSG_DEBUG("Configfile to use: " << m_configFile);
142 TEnv env;
143 env.ReadFile(configFile.c_str(), kEnvLocal);
144
145 std::string modelFilename("");
146 std::string quantileFilename("");
147
148 // Get the input model in the tool.
149 ATH_MSG_DEBUG("Get the input model in the tool.");
150
151 if (!m_modelFileName.empty()){ // If the property was set by the user, take that.
152 ATH_MSG_INFO("Setting user specified Model file: " << m_modelFileName);
153 modelFilename = m_modelFileName;
154 }
155 else {
156 modelFilename = env.GetValue("inputModelFileName", "ElectronPhotonSelectorTools/offline/mc16_20210204/ElectronDNNNetwork.json");
157 ATH_MSG_DEBUG("Getting the input Model from: " << modelFilename );
158 }
159 std::string filename = PathResolverFindCalibFile(modelFilename);
160 if (filename.empty()){
161 ATH_MSG_ERROR("Could not find model file " << modelFilename);
162 return StatusCode::FAILURE;
163 }
164
165 // Get the input transformer in the tool.
166 ATH_MSG_DEBUG("Get the input transformer in the tool.");
167
168 if (!m_quantileFileName.empty()){ // If the property was set by the user, take that.
169 ATH_MSG_INFO("Setting user specified QuantileTransformer file: " << m_quantileFileName);
170 quantileFilename = m_quantileFileName;
171 }
172 else {
173 quantileFilename = env.GetValue("inputQuantileFileName", "ElectronPhotonSelectorTools/offline/mc16_20210204/ElectronDNNQuantileTransformer.root");
174 ATH_MSG_DEBUG("Getting the input QuantileTransformer from: " << quantileFilename);
175 }
176 std::string qfilename = PathResolverFindCalibFile(quantileFilename);
177 if (qfilename.empty()){
178 ATH_MSG_ERROR("Could not find QuantileTransformer file " << quantileFilename);
179 return StatusCode::FAILURE;
180 }
181
182 // Variables used in the MVA tool as comma separated string;
183 std::stringstream vars(env.GetValue("Variables", ""));
184 // parse variables string into vector
185 while(vars.good()){
186 std::string substr;
187 std::getline(vars, substr, ',');
188 m_variables.push_back( substr );
190 ATH_MSG_ERROR("Unsupported variable " << substr << " found in the config.");
191 return StatusCode::FAILURE;
192 }
194 }
195
196 // Model is multiclass or not, default is binary model
197 m_multiClass = env.GetValue("multiClass", false);
198 // Include cf node in numerator or denominator when combining different outputs
199 m_cfSignal = env.GetValue("cfSignal", true);
200 // Fractions to multiply different outputs with before combining
201 m_fractions = AsgConfigHelper::HelperDouble("Fractions", env);
202
203 // cut on MVA discriminant
204 m_cutSelector = AsgConfigHelper::HelperDouble("CutSelector", env);
205 m_cutSelectorCF = AsgConfigHelper::HelperDouble("CutSelectorCF", env);
206
207 // cut on ambiguity bit
208 m_cutAmbiguity = AsgConfigHelper::HelperInt("CutAmbiguity", env);
209 // cut on b-layer
210 m_cutBL = AsgConfigHelper::HelperInt("CutBL", env);
211 // cut on pixel hits
212 m_cutPi = AsgConfigHelper::HelperInt("CutPi", env);
213 // cut on precision hits
214 m_cutSCT = AsgConfigHelper::HelperInt("CutSCT", env);
215 // do smooth interpolation between bins
216 m_doSmoothBinInterpolation = env.GetValue("doSmoothBinInterpolation", false);
217
218
219
220 unsigned int numberOfExpectedBinCombinedMVA ;
221 numberOfExpectedBinCombinedMVA = s_fnDiscEtBins * s_fnDiscEtaBins;
222 unsigned int numberOfExpectedEtaBins = s_fnDiscEtBins;
223
224 if (m_cutSelector.size() != numberOfExpectedBinCombinedMVA){
225 ATH_MSG_ERROR("Configuration issue : cutSelector expected size " << numberOfExpectedBinCombinedMVA <<
226 " input size " << m_cutSelector.size());
227 return StatusCode::FAILURE;
228 }
229
230 if (!m_cutSelectorCF.empty()){
231 m_CFReject = true;
232 if (m_cutSelectorCF.size() != numberOfExpectedBinCombinedMVA){
233 ATH_MSG_ERROR("Configuration issue : cutSelectorCF expected size " << numberOfExpectedBinCombinedMVA <<
234 " input size " << m_cutSelectorCF.size());
235 return StatusCode::FAILURE;
236 }
237 if(!m_multiClass){
238 ATH_MSG_ERROR("Configuration issue : CF rejection is only defined "
239 "for multiClass: TRUE");
240 return StatusCode::FAILURE;
241 }
242 }
243 else {
244 m_CFReject = false;
245 }
246 // Create an instance of the class calculating the DNN score
247 m_mvaTool = std::make_unique<ElectronDNNCalculator>(this, filename.c_str(), qfilename.c_str(), m_variables, m_multiClass);
248
249 if (m_multiClass){
250 // Fractions are only needed if multiclass model is used
251 // There are five fractions for the combination, the signal fraction is either one (cfSignal == false) or 1 - cf fraction (cfSignal == true)
252 if (m_fractions.size() != numberOfExpectedEtaBins * 5){
253 ATH_MSG_ERROR("Configuration issue : multiclass but not the right amount of fractions." << m_fractions.size());
254 return StatusCode::FAILURE;
255 }
256 }
257
258 if (!m_cutSCT.empty()){
259 if (m_cutSCT.size() != numberOfExpectedEtaBins){
260 ATH_MSG_ERROR("Configuration issue : cutSCT expected size " << numberOfExpectedEtaBins <<
261 " input size " << m_cutSCT.size());
262 return StatusCode::FAILURE;
263 }
264 }
265
266 if (!m_cutPi.empty()){
267 if (m_cutPi.size() != numberOfExpectedEtaBins){
268 ATH_MSG_ERROR("Configuration issue : cutPi expected size " << numberOfExpectedEtaBins <<
269 " input size " << m_cutPi.size());
270 return StatusCode::FAILURE;
271 }
272 }
273
274 if (!m_cutBL.empty()){
275 if (m_cutBL.size() != numberOfExpectedEtaBins){
276 ATH_MSG_ERROR("Configuration issue : cutBL expected size " << numberOfExpectedEtaBins <<
277 " input size " << m_cutBL.size());
278 return StatusCode::FAILURE;
279 }
280 }
281
282 if (!m_cutAmbiguity.empty()){
283 if (m_cutAmbiguity.size() != numberOfExpectedEtaBins){
284 ATH_MSG_ERROR("Configuration issue : cutAmbiguity expected size " << numberOfExpectedEtaBins <<
285 " input size " << m_cutAmbiguity.size());
286 return StatusCode::FAILURE;
287 }
288 }
289
290 // --------------------------------------------------------------------------
291 // Register the cuts and check that the registration worked:
292 // NOTE: THE ORDER IS IMPORTANT!!! Cut0 corresponds to bit 0, Cut1 to bit 1,...
293 // use an int as a StatusCode
294 int sc(1);
295
296 // Cut position for the kineatic pre-selection
297 m_cutPosition_kinematic = m_acceptMVA.addCut("kinematic", "pass kinematic");
298 if (m_cutPosition_kinematic < 0) sc = 0;
299
300 // NSilicon
301 m_cutPosition_NSilicon = m_acceptMVA.addCut("NSCT", "pass NSCT");
302 if (m_cutPosition_NSilicon < 0) sc = 0;
303
304 // NPixel
305 m_cutPosition_NPixel = m_acceptMVA.addCut("NPixel", "pass NPixel");
306 if (m_cutPosition_NPixel < 0) sc = 0;
307
308 // NBlayer
309 m_cutPosition_NBlayer = m_acceptMVA.addCut("NBlayer", "pass NBlayer");
310 if (m_cutPosition_NBlayer < 0) sc = 0;
311
312 // Ambiguity
313 m_cutPosition_ambiguity = m_acceptMVA.addCut("ambiguity", "pass ambiguity");
314 if (m_cutPosition_ambiguity < 0) sc = 0;
315
316
317 // Cut position for the likelihood selection - DO NOT CHANGE ORDER!
318 m_cutPosition_MVA = m_acceptMVA.addCut("passMVA", "pass MVA");
319 if (m_cutPosition_MVA < 0) sc = 0;
320
321 // Check that we got everything OK
322 if (sc == 0){
323 ATH_MSG_ERROR("ERROR: Something went wrong with the setup of the decision objects...");
324 return StatusCode::FAILURE;
325 }
326
328
329 // define a default vector to return in the calculateMultipleOutputs methods
330 // depending on the number of expected outputs
331 if (m_multiClass){
332 m_defaultVector = {-999., -999., -999., -999., -999., -999.};
333 }
334 else{
335 m_defaultVector = {-999.};
336 }
337
338 return StatusCode::SUCCESS;
339}
340
341
342//=============================================================================
343// return the accept info object
344//=============================================================================
345
350
351//=============================================================================
352// The main accept method: the actual cuts are applied here
353//=============================================================================
354asg::AcceptData AsgElectronSelectorTool::accept( const EventContext& ctx, const xAOD::Electron* eg, double mu ) const
355{
356 ATH_MSG_VERBOSE("\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<", "<<eg<<", "<<mu<<" )");
357
358 // Setup return accept with AcceptInfo
359 asg::AcceptData acceptData(&m_acceptMVA);
360
361 if (!eg){
362 throw std::runtime_error("AsgElectronSelectorTool: Failed, no electron object was passed");
363 }
364
365 const xAOD::CaloCluster* cluster = eg->caloCluster();
366 if (!cluster){
367 ATH_MSG_DEBUG("exiting because cluster is NULL " << cluster);
368 return acceptData;
369 }
370
371 if(!cluster->hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->hasSampling(CaloSampling::CaloSample::EME2)){
372 ATH_MSG_DEBUG("Failed, cluster is missing samplings EMB2 and EME2");
373 return acceptData;
374 }
375
376 const double energy = cluster->e();
377 const float eta = cluster->etaBE(2);
378
379 if(isForwardElectron(eg, eta)){
380 ATH_MSG_DEBUG("Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
381 return acceptData;
382 }
383
384 const xAOD::TrackParticle* track = eg->trackParticle();
385 if (!track){
386 ATH_MSG_DEBUG("exiting because track is NULL " << track);
387 return acceptData;
388 }
389
390 // transverse energy of the electron (using the track eta)
391 double et = (std::cosh(track->eta()) != 0.) ? energy / std::cosh(track->eta()) : 0.;
392
393 // number of track hits
394 uint8_t nSiHitsPlusDeadSensors(0);
395 uint8_t nPixHitsPlusDeadSensors(0);
396 bool passBLayerRequirement(false);
397 uint8_t ambiguityBit(0);
398
399 bool allFound = true;
400 std::string notFoundList = "";
401
402 // get the ambiguity type from the decoration
403 if (!m_skipAmbiguityCut){
404 static const SG::AuxElement::Accessor<uint8_t> ambiguityTypeAcc("ambiguityType");
405 if (ambiguityTypeAcc.isAvailable(*eg)) {
406 ambiguityBit = ambiguityTypeAcc(*eg);
407 }
408 else {
409 allFound = false;
410 notFoundList += "ambiguityType ";
411 }
412 }
413
414 nSiHitsPlusDeadSensors = ElectronSelectorHelpers::numberOfSiliconHitsAndDeadSensors(*track);
415 nPixHitsPlusDeadSensors = ElectronSelectorHelpers::numberOfPixelHitsAndDeadSensors(*track);
416 passBLayerRequirement = ElectronSelectorHelpers::passBLayerRequirement(*track);
417
418 // calculate the output of the selector tool
419
420 std::vector<float> mvaOutputs = calculateMultipleOutputs(ctx, eg, mu);
421 double mvaScore = getDiscriminant(mvaOutputs, eg);
422 ATH_MSG_VERBOSE(Form("PassVars: MVA=%8.5f, eta=%8.5f, et=%8.5f, nSiHitsPlusDeadSensors=%i, nHitsPlusPixDeadSensors=%i, passBLayerRequirement=%i, ambiguityBit=%i, mu=%8.5f",
423 mvaScore, eta, et,
424 nSiHitsPlusDeadSensors, nPixHitsPlusDeadSensors,
425 passBLayerRequirement,
426 ambiguityBit, mu));
427 double mvaScoreCF = 0;
428 if (m_CFReject){
429 mvaScoreCF = combineOutputsCF(mvaOutputs);
430 ATH_MSG_VERBOSE(Form("PassVars: MVA=%8.5f, eta=%8.5f, et=%8.5f, nSiHitsPlusDeadSensors=%i, nHitsPlusPixDeadSensors=%i, passBLayerRequirement=%i, ambiguityBit=%i, mu=%8.5f",
431 mvaScoreCF, eta, et,
432 nSiHitsPlusDeadSensors, nPixHitsPlusDeadSensors,
433 passBLayerRequirement,
434 ambiguityBit, mu));
435 }
436
437 if (!allFound){
438 throw std::runtime_error("AsgElectronSelectorTool: Not all variables needed for the decision are found. The following variables are missing: " + notFoundList );
439 }
440
441 // Set up the individual cuts
442 bool passKine(true);
443 bool passNSilicon(true);
444 bool passNPixel(true);
445 bool passNBlayer(true);
446 bool passAmbiguity(true);
447 bool passMVA(true);
448
449 if (std::abs(eta) > 2.47){
450 ATH_MSG_DEBUG("This electron is fabs(eta)>2.47 Returning False.");
451 passKine = false;
452 }
453
454 unsigned int etBin = getDiscEtBin(et);
455 unsigned int etaBin = getDiscEtaBin(eta);
456
457 // sanity
458 if (etBin >= s_fnDiscEtBins){
459 ATH_MSG_DEBUG("Cannot evaluate model for Et " << et << ". Returning false..");
460 passKine = false;
461 }
462
463 // Return if the kinematic requirements are not fulfilled
464 acceptData.setCutResult(m_cutPosition_kinematic, passKine);
465 if (!passKine){return acceptData;}
466
467 // ambiguity bit
468 if (!m_cutAmbiguity.empty()){
470 ATH_MSG_DEBUG("MVA macro: ambiguity Bit Failed.");
471 passAmbiguity = false;
472 }
473 }
474
475 // blayer cut
476 if (!m_cutBL.empty()) {
477 if(m_cutBL[etaBin] == 1 && !passBLayerRequirement){
478 ATH_MSG_DEBUG("MVA macro: Blayer cut failed.");
479 passNBlayer = false;
480 }
481 }
482 // pixel cut
483 if (!m_cutPi.empty()){
484 if (nPixHitsPlusDeadSensors < m_cutPi[etaBin]){
485 ATH_MSG_DEBUG("MVA macro: Pixels Failed.");
486 passNPixel = false;
487 }
488 }
489 // SCT cut
490 if (!m_cutSCT.empty()){
491 if (nSiHitsPlusDeadSensors < m_cutSCT[etaBin]){
492 ATH_MSG_DEBUG( "MVA macro: Silicon Failed.");
493 passNSilicon = false;
494 }
495 }
496
497 unsigned int ibin_combinedMVA = etBin*s_fnDiscEtaBins+etaBin; // Must change if number of eta bins changes!.
498
499 // First cut on the CF discriminant
500 // If empty, continue only with prompt ID
501 if (!m_cutSelectorCF.empty()){
502 double cutDiscriminantCF;
503 // To protect against a binning mismatch, which should never happen
504 if (ibin_combinedMVA >= m_cutSelectorCF.size()){
505 throw std::runtime_error("AsgElectronSelectorTool: The desired eta/pt bin is outside of the range specified by the input. This should never happen! This indicates a mismatch between the binning in the configuration file and the tool implementation." );
506 }
508 cutDiscriminantCF = interpolateCuts(m_cutSelectorCF, et, eta);
509 }
510 else{
511 cutDiscriminantCF = m_cutSelectorCF.at(ibin_combinedMVA);
512 }
513 // Determine if the calculated mva score value passes the combined cut
514 ATH_MSG_DEBUG("MVA macro: CF Discriminant: ");
515 if (mvaScoreCF < cutDiscriminantCF){
516 ATH_MSG_DEBUG("MVA macro: CF cut failed.");
517 passMVA = false;
518 }
519 }
520
521// (Second) cut on prompt discriminant
522 if (!m_cutSelector.empty()){
523 double cutDiscriminant;
524 // To protect against a binning mismatch, which should never happen
525 if (ibin_combinedMVA >= m_cutSelector.size()){
526 throw std::runtime_error("AsgElectronSelectorTool: The desired eta/pt bin is outside of the range specified by the input. This should never happen! This indicates a mismatch between the binning in the configuration file and the tool implementation." );
527 }
529 cutDiscriminant = interpolateCuts(m_cutSelector, et, eta);
530 }
531 else{
532 cutDiscriminant = m_cutSelector.at(ibin_combinedMVA);
533 }
534 // Determine if the calculated mva score value passes the combined cut
535 ATH_MSG_DEBUG("MVA macro: Prompt Discriminant: ");
536 if (mvaScore < cutDiscriminant){
537 ATH_MSG_DEBUG("MVA macro: Prompt cut failed.");
538 passMVA = false;
539 }
540 }
541
542 // Set the individual cut bits in the return object
543 acceptData.setCutResult(m_cutPosition_NSilicon, passNSilicon);
544 acceptData.setCutResult(m_cutPosition_NPixel, passNPixel);
545 acceptData.setCutResult(m_cutPosition_NBlayer, passNBlayer);
546 acceptData.setCutResult(m_cutPosition_ambiguity, passAmbiguity);
547 acceptData.setCutResult(m_cutPosition_MVA, passMVA);
548
549 return acceptData;
550
551}
552
553//=============================================================================
554// The main result method: the actual mvaScore is calculated here
555//=============================================================================
556double AsgElectronSelectorTool::calculate( const EventContext& ctx, const xAOD::Electron* eg, double mu ) const
557{
558 // Get all outputs of the mva tool
559 std::vector<float> mvaOutputs = calculateMultipleOutputs(ctx, eg, mu);
560
561 return getDiscriminant(mvaOutputs, eg);
562}
563
564double AsgElectronSelectorTool::getDiscriminant(std::vector<float>& mvaOutputs, const xAOD::Electron* eg ) const
565{
566 double discriminant = 0;
567 // If a binary model is used, vector will have one entry, if multiclass is used vector will have six entries
568 if (!m_multiClass){
569 discriminant = transformMLOutput(mvaOutputs.at(0));
570 }
571 else{
572 const xAOD::CaloCluster* cluster = eg->caloCluster();
573 const float eta = cluster->etaBE(2);
574 // combine the six output nodes into one discriminant to cut on, any necessary transformation is applied within combineOutputs()
575 discriminant = combineOutputs(mvaOutputs, eta);
576 }
577
578 return discriminant;
579}
580
581
582std::vector<float> AsgElectronSelectorTool::calculateMultipleOutputs(const EventContext &ctx, const xAOD::Electron *eg, double mu) const
583{
584 ATH_MSG_VERBOSE("\t AsgElectronSelectorTool::calculateMultipleOutputs( &ctx, *eg, mu= "<<(&ctx)<<", "<<eg<<", "<<mu<<" )");
585 if (!eg){
586 throw std::runtime_error("AsgElectronSelectorTool: Failed, no electron object was passed" );
587 }
588
589 const xAOD::CaloCluster* cluster = eg->caloCluster();
590 if (!cluster){
591 ATH_MSG_DEBUG("Failed, no cluster.");
592 // Return a default value
593 return m_defaultVector;
594 }
595
596 if (!cluster->hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->hasSampling(CaloSampling::CaloSample::EME2)){
597 ATH_MSG_DEBUG("Failed, cluster is missing samplings EMB2 and EME2.");
598 // Return a default value
599 return m_defaultVector;
600 }
601
602 const double energy = cluster->e();
603 const float eta = cluster->etaBE(2);
604
605 if (isForwardElectron(eg, eta)){
606 ATH_MSG_DEBUG("Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
607 // Return a default value
608 return m_defaultVector;
609 }
610
611 const xAOD::TrackParticle* track = eg->trackParticle();
612 if (!track){
613 ATH_MSG_DEBUG("Failed, no track.");
614 // Return a default value
615 return m_defaultVector;
616 }
617
618 // transverse energy of the electron (using the track eta)
619 const double et = energy / std::cosh(track->eta());
620
621 // Variables used in the ML model
622 // track quantities
623 double SCTWeightedCharge(0.0);
624 uint8_t nSCTHitsPlusDeadSensors(0);
625 uint8_t nPixHitsPlusDeadSensors(0);
626 float d0(0.0), d0sigma(0.0), d0significance(0.0), qd0(0.0);
627 float trackqoverp(0.0);
628 double dPOverP(0.0);
629 float TRT_PID(0.0);
630 double trans_TRTPID(0.0);
631
632 // Track Cluster matching
633 float deltaEta1(0), deltaPhiRescaled2(0), EoverP(0);
634
635 // Calorimeter
636 float Reta(0), Rphi(0), Rhad1(0), Rhad(0), w2(0), f1(0), Eratio(0), f3(0), wtots1(0);
637
638 bool allFound = true;
639 std::string notFoundList = "";
640
641 // retrieve track variables
642 trackqoverp = track->qOverP();
643 d0 = track->d0();
644 qd0 = (eg->charge())*track->d0();
645 float vard0 = track->definingParametersCovMatrix()(0, 0);
646 if (vard0 > 0){
647 d0sigma = std::sqrt(vard0);
648 }
649 d0significance = std::abs(d0 / d0sigma);
650
651 const static SG::AuxElement::Accessor<float> trans_TRT_PID_acc("transformed_e_probability_ht");
652 if (!trans_TRT_PID_acc.isAvailable(*eg)) {
653 // most probable case, need to compute the variable
654
655 if (!track->summaryValue(TRT_PID, xAOD::eProbabilityHT)) {
656 allFound = false;
657 notFoundList += "eProbabilityHT ";
658 }
659
660 // Transform the TRT PID output for use in the LH tool.
661 const double tau = 15.0;
662 const double fEpsilon = 1.0e-30; // to avoid zero division
663 double pid_tmp = TRT_PID;
664 if (pid_tmp >= 1.0)
665 pid_tmp = 1.0 - 1.0e-15; // this number comes from TMVA
666 else if (pid_tmp <= fEpsilon)
667 pid_tmp = fEpsilon;
668 trans_TRTPID = -std::log(1.0 / pid_tmp - 1.0) * (1. / tau);
669 }
670 else
671 {
672 // it means the variable have been already computed by another tool
673 // usually this is the EGammaVariableCorrection, which means that
674 // it is also fudged (only MC)
675 trans_TRTPID = trans_TRT_PID_acc(*eg);
676 }
677
678 //Change default value of TRT PID to 0.15 instead of 0 when there is no information from the TRT
679 if ((std::abs(trans_TRTPID) < 1.0e-6) && (std::abs(eta) > 2.01)){
680 trans_TRTPID = 0.15;
681 }
682
683 unsigned int index;
684 if (track->indexOfParameterAtPosition(index, xAOD::LastMeasurement)){
685 double refittedTrack_LMqoverp = track->charge() / std::sqrt(std::pow(track->parameterPX(index), 2) +
686 std::pow(track->parameterPY(index), 2) +
687 std::pow(track->parameterPZ(index), 2));
688
689 dPOverP = 1 - trackqoverp / (refittedTrack_LMqoverp);
690 }
691 else if (!m_skipDeltaPoverP) {
692 allFound = false;
693 notFoundList += "deltaPoverP ";
694 }
695
696 EoverP = energy * std::abs(trackqoverp);
697
698 nPixHitsPlusDeadSensors = ElectronSelectorHelpers::numberOfPixelHitsAndDeadSensors(*track);
699 nSCTHitsPlusDeadSensors = ElectronSelectorHelpers::numberOfSCTHitsAndDeadSensors(*track);
700
701 float charge = 0;
702 uint8_t SCT = 0;
703 for (unsigned TPit = 0; TPit < eg->nTrackParticles(); TPit++) {
704 uint8_t temp_NSCTHits = 0;
705 if (eg->trackParticle(TPit)) {
706 eg->trackParticle(TPit)->summaryValue(temp_NSCTHits, xAOD::numberOfSCTHits);
707 SCT += temp_NSCTHits;
708 charge += temp_NSCTHits*(eg->trackParticle(TPit)->charge());
709 }
710 }
711 if (SCT)
712 SCTWeightedCharge = (eg->charge()*charge/SCT);
713 else {
714 ATH_MSG_WARNING("No SCT hit for any track associated to electron ! nTP = " << eg->nTrackParticles());
715 }
716
717 // retrieve Calorimeter variables
718 // reta = e237/e277
719 if (!eg->showerShapeValue(Reta, xAOD::EgammaParameters::Reta)){
720 allFound = false;
721 notFoundList += "Reta ";
722 }
723 // rphi e233/e237
724 if (!eg->showerShapeValue(Rphi, xAOD::EgammaParameters::Rphi)){
725 allFound = false;
726 notFoundList += "Rphi ";
727 }
728 // rhad1 = ethad1/et
729 if (!eg->showerShapeValue(Rhad1, xAOD::EgammaParameters::Rhad1)){
730 allFound = false;
731 notFoundList += "Rhad1 ";
732 }
733 // rhad = ethad/et
734 if (!eg->showerShapeValue(Rhad, xAOD::EgammaParameters::Rhad)){
735 allFound = false;
736 notFoundList += "Rhad ";
737 }
738 // shower width in 2nd sampling
739 if (!eg->showerShapeValue(w2, xAOD::EgammaParameters::weta2)){
740 allFound = false;
741 notFoundList += "weta2 ";
742 }
743 // fraction of energy reconstructed in the 1st sampling
744 if (!eg->showerShapeValue(f1, xAOD::EgammaParameters::f1)){
745 allFound = false;
746 notFoundList += "f1 ";
747 }
748 // E of 2nd max between max and min in strips
749 if (!eg->showerShapeValue(Eratio, xAOD::EgammaParameters::Eratio)){
750 allFound = false;
751 notFoundList += "Eratio ";
752 }
753 // fraction of energy reconstructed in the 3rd sampling
754 if (!eg->showerShapeValue(f3, xAOD::EgammaParameters::f3)){
755 allFound = false;
756 notFoundList += "f3 ";
757 }
758
759 // Set f3 to default value in eta region where it is poorly modelled
760 if (std::abs(eta) > 2.01) {
761 f3 = 0.05;
762 }
763
764 // Shower width in first sampling of the calorimeter
765 if (!eg->showerShapeValue(wtots1, xAOD::EgammaParameters::wtots1)){
766 allFound = false;
767 notFoundList += "wtots1 ";
768 }
769
770 // retrieve Track Cluster matching variables
771 // difference between cluster eta (sampling 1) and the eta of the track
772 if (!eg->trackCaloMatchValue(deltaEta1, xAOD::EgammaParameters::deltaEta1)){
773 allFound = false;
774 notFoundList += "deltaEta1 ";
775 }
776 // difference between the cluster phi (sampling 2) and the phi of the track extrapolated from the last measurement point.
777 if (!eg->trackCaloMatchValue(deltaPhiRescaled2, xAOD::EgammaParameters::deltaPhiRescaled2)){
778 allFound = false;
779 notFoundList += "deltaPhiRescaled2 ";
780 }
781
782
783 ATH_MSG_VERBOSE(Form("Vars: eta=%8.5f, et=%8.5f, f3=%8.5f, rHad==%8.5f, rHad1=%8.5f, Reta=%8.5f, w2=%8.5f, f1=%8.5f, Emaxs1=%8.5f, deltaEta1=%8.5f, d0=%8.5f, qd0=%8.5f, d0significance=%8.5f, Rphi=%8.5f, dPOverP=%8.5f, deltaPhiRescaled2=%8.5f, TRT_PID=%8.5f, trans_TRTPID=%8.5f, mu=%8.5f, wtots1=%8.5f, EoverP=%8.5f, nPixHitsPlusDeadSensors=%2df, nSCTHitsPlusDeadSensors=%2df, SCTWeightedCharge=%8.5f",
784 eta, et, f3, Rhad, Rhad1, Reta,
785 w2, f1, Eratio,
786 deltaEta1, d0, qd0,
787 d0significance,
788 Rphi, dPOverP, deltaPhiRescaled2,
789 TRT_PID, trans_TRTPID,
790 mu,
791 wtots1, EoverP, int(nPixHitsPlusDeadSensors), int(nSCTHitsPlusDeadSensors), SCTWeightedCharge));
792
793 if (!allFound){
794 throw std::runtime_error("AsgElectronSelectorTool: Not all variables needed for MVA calculation are found. The following variables are missing: " + notFoundList );
795 }
796
797 std::vector<double> variableValues;
798 for(const auto varID : m_enum_variables)
799 {
800 switch(varID)
801 {
803 variableValues.push_back(std::abs(eta)); break; // TODO - rename to abseta?
805 variableValues.push_back(et); break;
807 variableValues.push_back(f3); break;
809 variableValues.push_back(Rhad); break;
811 variableValues.push_back(Rhad1); break;
813 variableValues.push_back(Reta); break;
815 variableValues.push_back(w2); break;
817 variableValues.push_back(f1); break;
819 variableValues.push_back(Eratio); break;
821 variableValues.push_back(deltaEta1); break;
823 variableValues.push_back(d0); break;
825 variableValues.push_back(qd0); break;
827 variableValues.push_back(d0significance); break;
829 variableValues.push_back(Rphi); break;
831 variableValues.push_back(dPOverP); break;
833 variableValues.push_back(deltaPhiRescaled2); break;
835 variableValues.push_back(trans_TRTPID); break;
837 variableValues.push_back(wtots1); break;
839 variableValues.push_back(EoverP); break;
841 variableValues.push_back(nPixHitsPlusDeadSensors); break;
843 variableValues.push_back(nSCTHitsPlusDeadSensors); break;
845 variableValues.push_back(SCTWeightedCharge); break;
846 default:
847 // Handle unknown varID or error case
848 throw std::runtime_error("AsgElectronSelectorTool: unknown variable "
849 "index, something went wrong in initialization!" );
850 break;
851 }
852 }
853
854 Eigen::Matrix<float, -1, 1> mvaScores = m_mvaTool->calculate(variableValues);
855
856 // Return a vector of all outputs of the MVA
857 std::vector<float> mvaOutputs;
858 mvaOutputs.reserve(mvaScores.rows());
859 for (int i = 0; i < mvaScores.rows(); i++) {
860 mvaOutputs.push_back(mvaScores(i, 0));
861 }
862
863 return mvaOutputs;
864}
865
866//=============================================================================
868//=============================================================================
870{
871 return m_workingPoint;
872}
873
874//=============================================================================
876{
877 return accept(Gaudi::Hive::currentContext(), part);
878}
879asg::AcceptData AsgElectronSelectorTool::accept( const EventContext& ctx, const xAOD::IParticle* part ) const
880{
881 ATH_MSG_VERBOSE("\t AsgElectronSelectorTool::accept( &ctx, *part= "<<(&ctx)<<", "<<part<<" )");
882 const xAOD::Electron* eg = dynamic_cast<const xAOD::Electron*>(part);
883 if (eg){
884 return accept(ctx, eg);
885 }
886 else {
887 ATH_MSG_DEBUG("AsgElectronSelectorTool::could not cast to const Electron");
888 // Setup return accept with AcceptInfo
889 asg::AcceptData acceptData(&m_acceptMVA);
890 return acceptData;
891 }
892}
893
895{
896 return calculate(Gaudi::Hive::currentContext(), part);
897}
898
899double AsgElectronSelectorTool::calculate( const EventContext& ctx, const xAOD::IParticle* part ) const
900{
901 ATH_MSG_VERBOSE("\t AsgElectronSelectorTool::calculate( &ctx, *part"<<(&ctx)<<", "<<part<<" )");
902 const xAOD::Electron* eg = dynamic_cast<const xAOD::Electron*>(part);
903 if (eg){
904 return calculate(ctx, eg);
905 }
906 else {
907 ATH_MSG_DEBUG("AsgElectronSelectorTool::could not cast to const Electron");
908 // Return a default value
909 return -999.;
910 }
911}
912
913asg::AcceptData AsgElectronSelectorTool::accept( const EventContext& ctx, const xAOD::Egamma* eg, double mu ) const
914{
915 ATH_MSG_VERBOSE("\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<", "<<eg<<", "<<mu<<" )");
916 const xAOD::Electron* ele = dynamic_cast<const xAOD::Electron*>(eg);
917 if (ele){
918 return accept(ctx, ele, mu);
919 }
920 else {
921 ATH_MSG_DEBUG("AsgElectronSelectorTool::could not cast to const Electron");
922 // Setup return accept with AcceptInfo
923 asg::AcceptData acceptData(&m_acceptMVA);
924 return acceptData;
925 }
926}
927
928double AsgElectronSelectorTool::calculate( const EventContext& ctx, const xAOD::Egamma* eg, double mu ) const
929{
930 ATH_MSG_VERBOSE("\t AsgElectronSelectorTool::calculate( &ctx, *eg, mu= "<<(&ctx)<<", "<<eg<<", "<<mu<<" )");
931 const xAOD::Electron* ele = dynamic_cast<const xAOD::Electron*>(eg);
932 if (ele){
933 return calculate(ctx, ele, mu);
934 }
935 else {
936 ATH_MSG_DEBUG("AsgElectronSelectorTool::could not cast to const Electron");
937 return -999.;
938 }
939}
940
942{
943 static const SG::AuxElement::ConstAccessor< uint16_t > accAuthor( "author" );
944
945 if (accAuthor.isAvailable(*eg)){
946 // cannot just do eg->author() because it isn't always filled
947 // at trigger level
948 if (accAuthor(*eg) == xAOD::EgammaParameters::AuthorFwdElectron){
949 ATH_MSG_DEBUG("Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
950 return true;
951 }
952 }
953 else{
954 //Check for fwd via eta range the old logic
955 if (std::abs(eta) > 2.5){
956 ATH_MSG_DEBUG("Failed, cluster->etaBE(2) range due to " << eta << " seems like a fwd electron" );
957 return true;
958 }
959 }
960
961 return false;
962}
963
964
966{
967 // returns transformed or non-transformed output
968 constexpr double oneOverTau = 1. / 10;
969 constexpr double fEpsilon = 1.0e-30; // to avoid zero division
970 if (score >= 1.0) score = 1.0 - 1.0e-15; // this number comes from TMVA
971 else if (score <= fEpsilon) score = fEpsilon;
972 //cppcheck-suppress invalidFunctionArg
973 score = -std::log(1.0 / score - 1.0) * oneOverTau;
974 ATH_MSG_DEBUG("score is " << score);
975 return score;
976}
977
978
979double AsgElectronSelectorTool::combineOutputs( const std::vector<float>& mvaScores, double eta ) const
980{
981 unsigned int etaBin = getDiscEtaBin(eta);
982 double disc = 0;
983
984 if (m_cfSignal){
985 // Put cf node into numerator
986
987 disc = (mvaScores.at(0) * (1 - m_fractions.at(5 * etaBin + 0)) +
988 (mvaScores.at(1) * m_fractions.at(5 * etaBin + 0))) /
989 ((mvaScores.at(2) * m_fractions.at(5 * etaBin + 1)) +
990 (mvaScores.at(3) * m_fractions.at(5 * etaBin + 2)) +
991 (mvaScores.at(4) * m_fractions.at(5 * etaBin + 3)) +
992 (mvaScores.at(5) * m_fractions.at(5 * etaBin + 4)));
993 }
994 else{
995 // Put cf node in denominator
996 disc = mvaScores.at(0) /
997 ((mvaScores.at(1) * m_fractions.at(5 * etaBin + 0)) +
998 (mvaScores.at(2) * m_fractions.at(5 * etaBin + 1)) +
999 (mvaScores.at(3) * m_fractions.at(5 * etaBin + 2)) +
1000 (mvaScores.at(4) * m_fractions.at(5 * etaBin + 3)) +
1001 (mvaScores.at(5) * m_fractions.at(5 * etaBin + 4)));
1002 }
1003
1004 // Log transform to have values in reasonable range
1005 return std::log(disc);
1006}
1007
1008double AsgElectronSelectorTool::combineOutputsCF( const std::vector<float>& mvaScores )
1009{
1010 double disc = 0;
1011 disc = mvaScores.at(0) / mvaScores.at(1);
1012
1013 return std::log(disc);
1014}
1015
1016
1017// Gets the Discriminant Eta bin [0,s_fnDiscEtaBins-1] given the eta
1019{
1020 const unsigned int nEtaBins = s_fnDiscEtaBins;
1021 const double etaBins[nEtaBins] = {0.1, 0.6, 0.8, 1.15, 1.37, 1.52, 1.81, 2.01, 2.37, 2.47};
1022 for (unsigned int etaBin = 0; etaBin < nEtaBins; ++etaBin){
1023 if (std::abs(eta) < etaBins[etaBin]) return etaBin;
1024 }
1025 return (nEtaBins-1);
1026}
1027
1028// Gets the Discriminant Et bin (MeV) [0,s_fnDiscEtBins-1]
1030{
1031 static const double GeV = 1000;
1032 const unsigned int nEtBins = s_fnDiscEtBins;
1033 const double etBins[nEtBins] = {7*GeV,10*GeV,15*GeV,20*GeV,25*GeV,30*GeV,35*GeV,40*GeV,45*GeV,6000*GeV};
1034 for (unsigned int etBin = 0; etBin < nEtBins; ++etBin){
1035 if (et < etBins[etBin]) return etBin;
1036 }
1037 return (nEtBins-1);
1038}
1039
1040
1041// Note that this will only perform the cut interpolation up to ~45 GeV, so
1042// no smoothing is done above this for the high ET LH binning yet
1043double AsgElectronSelectorTool::interpolateCuts( const std::vector<double>& cuts,double et,double eta )
1044{
1045 const int etbin = getDiscEtBin(et);
1046 const int etabin = getDiscEtaBin(eta);
1047 unsigned int ibin_combinedML = etbin*s_fnDiscEtaBins+etabin;
1048 double cut = cuts.at(ibin_combinedML);
1049 const double GeV = 1000;
1050 const double eTBins[10] = {5.5*GeV,8.5*GeV,12.5*GeV,17.5*GeV,22.5*GeV,27.5*GeV,32.5*GeV,37.5*GeV,42.5*GeV,47.5*GeV};
1051
1052 if (et >= eTBins[9]) return cut; // no interpolation for electrons above 47.5 GeV
1053 if (et <= eTBins[0]) return cut; // no interpolation for electrons below 5.5 GeV
1054
1055 // find the bin where the value is smaller than the next bin
1056 // Start with bin = 1, since it always has to be at least in
1057 // bin 1 because of previous cut
1058 int bin = 1;
1059 while ( et > eTBins[bin] ) bin++;
1060
1061 double etLow = eTBins[bin-1];
1062 double etUp = eTBins[bin];
1063 double discLow = cuts.at((bin-1) * s_fnDiscEtaBins+etabin);
1064 double discUp = cuts.at((bin) * s_fnDiscEtaBins+etabin);
1065
1066 double gradient = ( discUp - discLow ) / ( etUp - etLow );
1067
1068 return discLow + (et - etLow) * gradient;
1069}
Scalar eta() const
pseudorapidity method
#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)
double charge(const T &p)
Definition AtlasPID.h:997
static Double_t sc
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
std::vector< std::string > m_variables
Variables used in the MVA Tool.
virtual std::string getOperatingPointName() const override
Get the name of the current operating point.
bool m_doSmoothBinInterpolation
do smooth interpolation between bins
static const unsigned int s_fnDiscEtBins
number of discrimintants vs Et
std::vector< double > m_fractions
Fractions to combine the output nodes of a multiclass model into one discriminant.
virtual const asg::AcceptInfo & getAcceptInfo() const override
Method to get the plain AcceptInfo.
std::string m_workingPoint
Working Point.
std::vector< int > m_enum_variables
Enum version of used variables.
static unsigned int getDiscEtaBin(double eta)
Gets the Discriminant Eta bin [0,s_fnDiscEtaBins-1] given the eta.
bool m_CFReject
Run CF rejection or not.
double getDiscriminant(std::vector< float > &mvaOutputs, const xAOD::Electron *egu) const
Computes discrimiant value from mva output based on whether multiclass is true or false.
int m_cutPosition_kinematic
The position of the kinematic cut bit in the AcceptInfo return object.
std::unique_ptr< const ElectronDNNCalculator > m_mvaTool
Pointer to the class that calculates the MVA score.
bool m_multiClass
Multiclass model or not.
static unsigned int getDiscEtBin(double et)
Gets the Descriminant Et bin the et (MeV) [0,s_fnDiscEtBins-1].
virtual StatusCode initialize() override
Gaudi Service Interface method implementations.
std::vector< int > m_cutBL
cut min on b-layer hits
std::string m_modelFileName
The input file name that holds the model.
bool m_cfSignal
Use the CF output node in the numerator or the denominator.
std::vector< int > m_cutPi
cut min on pixel hits
bool m_skipDeltaPoverP
Flag for skip the use of deltaPoverP in dnn calculation (like at HLT)
double combineOutputs(const std::vector< float > &mvaScores, double eta) const
Combines the six output nodes of a multiclass model into one discriminant.
virtual ~AsgElectronSelectorTool()
Standard destructor.
static double interpolateCuts(const std::vector< double > &cuts, double et, double eta)
Interpolates cut values along pt.
static const unsigned int s_fnDiscEtaBins
number of discriminants vs |eta|
asg::AcceptInfo m_acceptMVA
Accept info.
std::vector< float > calculateMultipleOutputs(const EventContext &ctx, const xAOD::Electron *eg, double mu=-99) const override
The result method for multiple outputs: can return multiple outputs of the MVA.
int m_cutPosition_NPixel
The position of the NPixel cut bit in the AcceptInfo return object.
std::vector< double > m_cutSelectorCF
int m_cutPosition_NSilicon
The position of the NSilicon cut bit in the AcceptInfo return object.
std::vector< int > m_cutSCT
cut min on precision hits
std::vector< int > m_cutAmbiguity
do cut on ambiguity bit
std::vector< double > m_cutSelector
cut on mva output
std::string m_quantileFileName
The input file name that holds the QuantileTransformer.
bool isForwardElectron(const xAOD::Egamma *eg, const float eta) const
check for FwdElectron
AsgElectronSelectorTool(const std::string &myname)
Standard constructor.
int m_cutPosition_NBlayer
The position of the NBlayer cut bit in the AcceptInfo return object.
int m_cutPosition_MVA
The position of the MVA cut bit in the AcceptInfo return object.
double transformMLOutput(float score) const
Applies a logit transformation to the score returned by the underlying MVA tool.
std::vector< float > m_defaultVector
Default vector to return if calculation fails.
double calculate(const xAOD::IParticle *part) const
The main result method: the actual mva score is calculated here.
asg::AcceptData accept(const xAOD::IParticle *part) const override
The main accept method: using the generic interface.
static double combineOutputsCF(const std::vector< float > &mvaScores)
int m_cutPosition_ambiguity
The position of the ambiguity cut bit in the AcceptInfo return object.
std::string m_configFile
The input config file.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:569
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
void setCutResult(const std::string &cutName, bool cutResult)
Set the result of a cut, based on the cut name (safer)
Definition AcceptData.h:134
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
virtual double e() const
The total energy of the particle.
bool hasSampling(const CaloSample s) const
Checks if certain smapling contributes to cluster.
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.
Class providing the definition of the 4-vector interface.
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
const std::unordered_map< std::string, int > variableMap
std::vector< int > HelperInt(const std::string &input, TEnv &env)
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 > ElectronDNNPointToConfFile
bool passAmbiguity(xAOD::AmbiguityTool::AmbiguityType type, const uint16_t criterion)
return true if the ambiguity type is one of several that are stored in a bitmask
std::size_t numberOfPixelHitsAndDeadSensors(const xAOD::TrackParticle &tp)
return the number of Pixel hits plus dead sensors in the track particle
std::size_t numberOfSCTHitsAndDeadSensors(const xAOD::TrackParticle &tp)
return the number of SCT hits plus dead sensors in the track particle
bool passBLayerRequirement(const xAOD::TrackParticle &tp)
return true if effective number of BL hits + outliers is at least one
std::size_t numberOfSiliconHitsAndDeadSensors(const xAOD::TrackParticle &tp)
return the number of Silicon hits plus dead sensors in the track particle
Definition index.py:1
@ deltaPhiRescaled2
difference between the cluster phi (second sampling) and the phi of the track extrapolated to the sec...
@ deltaEta1
difference between the cluster eta (first sampling) and the eta of the track extrapolated to the firs...
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition EgammaDefs.h:30
@ wtots1
shower width is determined in a window detaxdphi = 0,0625 ×~0,2, corresponding typically to 20 strips...
@ f3
fraction of energy reconstructed in 3rd sampling
Definition EgammaEnums.h:55
@ f1
E1/E = fraction of energy reconstructed in the first sampling, where E1 is energy in all strips belon...
Definition EgammaEnums.h:53
@ Eratio
(emaxs1-e2tsts1)/(emaxs1+e2tsts1)
@ weta2
the lateral width is calculated with a window of 3x5 cells using the energy weighted sum over all cel...
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Egamma_v1 Egamma
Definition of the current "egamma version".
Definition Egamma.h:17
@ eProbabilityHT
Electron probability from High Threshold (HT) information [float].
@ numberOfSCTHits
number of hits in SCT [unit8_t].
Electron_v1 Electron
Definition of the current "egamma version".
@ LastMeasurement
Parameter defined at the position of the last measurement.
Extra patterns decribing particle interation process.