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