ATLAS Offline Software
Loading...
Searching...
No Matches
PhotonVertexSelectionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Local includes
8
9// EDM includes
15
16// Framework includes
20
21// ROOT includes
22#include "TMVA/Reader.h"
23
24// std includes
25#include <algorithm>
26
27namespace CP {
28
29 // helper function to get the vertex of a track
31 const xAOD::VertexContainer* vertices)
32 {
33 const xAOD::Vertex* vtxWithLargestWeight = nullptr;
34 float largestWeight = 0;
35
36 for (const auto *vtx : *vertices) {
37 //Search for vertex linked to this track
38 const auto& trkLinks=vtx->trackParticleLinks();
39 const size_t nTrackLinks=trkLinks.size();
40 for (unsigned i=0;i<nTrackLinks;++i) {
41 if (trkLinks[i].isValid() && *(trkLinks[i]) == track) {//ptr comparison
42 if( vtx->trackWeights()[i] > largestWeight ){
43 vtxWithLargestWeight = vtx;
44 largestWeight = vtx->trackWeights()[i];
45 }
46 }
47 }
48 }
49
50 return vtxWithLargestWeight;
51 }
52
53 //____________________________________________________________________________
55 : asg::AsgTool(name)
56 {
57 // run 2 NN model:
58 // m_doSkipByZSigma = true, m_isTMVA = true
59 // run 3 NN model:
60 // m_doSkipByZSigma = false, m_isTMVA = false
61
62 // default variables
63 declareProperty("nVars", m_nVars = 4);
64 declareProperty("conversionPtCut", m_convPtCut = 2e3);
65 declareProperty("DoSkipByZSigma", m_doSkipByZSigma = false);
66
67 declareProperty("derivationPrefix", m_derivationPrefix = "");
68
69 // boolean for TMVA, default true
70 declareProperty("isTMVA", m_isTMVA = false);
71
72 // config files (TMVA), default paths if not set
73 declareProperty("ConfigFileCase1",
74 m_TMVAModelFilePath1 = "PhotonVertexSelection/v1/DiphotonVertex_case1.weights.xml");
75 declareProperty("ConfigFileCase2",
76 m_TMVAModelFilePath2 = "PhotonVertexSelection/v1/DiphotonVertex_case2.weights.xml");
77
78 // config files (ONNX), default paths if not set
79 declareProperty("ONNXModelFileCase1", m_ONNXModelFilePath1 = "PhotonVertexSelection/run3nn/model1.onnx");
80 declareProperty("ONNXModelFileCase2", m_ONNXModelFilePath2 = "PhotonVertexSelection/run3nn/model2.onnx");
81 }
82
83 //____________________________________________________________________________
85 = default;
86
87 //____________________________________________________________________________
88 //new additions for ONNX
90 int nVars, const std::vector<std::vector<float>>& input_data,
91 const std::shared_ptr<Ort::Session>& sessionHandle,
92 std::vector<int64_t> input_node_dims,
93 std::vector<const char*> input_node_names,
94 std::vector<const char*> output_node_names) const {
95 //*************************************************************************
96 // score the model using sample data, and inspect values
97 // loading input data
98 const std::vector<std::vector<float>>& input_tensor_values_ = input_data;
99
100 //preparing container to hold input data
101 size_t input_tensor_size = nVars;
102 std::vector<float> input_tensor_values(nVars);
103 input_tensor_values = input_tensor_values_[0]; //0th element since only batch_size of 1, otherwise loop
104
105 // create input tensor object from data values
106 auto memory_info =
107 Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
108 // create tensor using info from inputs
109 Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
110 memory_info, input_tensor_values.data(), input_tensor_size,
111 input_node_dims.data(), input_node_dims.size());
112
113 // check if input is of type tensor
114 assert(input_tensor.IsTensor());
115
116 // debug block for ctests
117 if (msgLvl(MSG::DEBUG)) {
118 for (const auto* name : input_node_names) {
119 ATH_MSG_DEBUG("INPUT NAME = " << name);
120 }
121 for (const auto* name : output_node_names) {
122 ATH_MSG_DEBUG("OUTPUT NAME = " << name);
123 }
124 ATH_MSG_DEBUG("input tensor size = " << input_tensor_size);
125 for (auto dim : input_node_dims) {
126 ATH_MSG_DEBUG("input dim = " << dim);
127 }
128 }
129
130 // run the inference
131 auto output_tensors =
132 sessionHandle->Run(Ort::RunOptions{nullptr}, input_node_names.data(),
133 &input_tensor, input_node_names.size(),
134 output_node_names.data(), output_node_names.size());
135
136 // check size of output tensor
137 assert(output_tensors.size() == 1 && output_tensors.front().IsTensor());
138
139 // get pointer to output tensor float values
140 // float* floatarr = output_tensors.front().GetTensorMutableData<float>();
141 float* floatarr = output_tensors[0].GetTensorMutableData<float>();
142
143 int arrSize = sizeof(*floatarr) / sizeof(floatarr[0]);
144 ATH_MSG_DEBUG("The size of the array is: " << arrSize);
145 ATH_MSG_DEBUG("floatarr[0] = " << floatarr[0]);
146 return floatarr[0];
147 }
148
149 //new additions for ONNX
150 std::tuple<std::vector<int64_t>, std::vector<const char*>>
152 const std::shared_ptr<Ort::Session>& sessionHandle,
153 Ort::AllocatorWithDefaultOptions& allocator) {
154 // input nodes
155 std::vector<int64_t> input_node_dims;
156 size_t num_input_nodes = sessionHandle->GetInputCount();
157 std::vector<const char*> input_node_names(num_input_nodes);
158
159 // Loop the input nodes
160 for( std::size_t i = 0; i < num_input_nodes; i++ ) {
161 // Print input node names
162 char* input_name = sessionHandle->GetInputNameAllocated(i, allocator).release();
163 ATH_MSG_DEBUG("Input "<<i<<" : "<<" name= "<<input_name);
164 input_node_names[i] = input_name;
165
166 // Print input node types
167 Ort::TypeInfo type_info = sessionHandle->GetInputTypeInfo(i);
168 auto tensor_info = type_info.GetTensorTypeAndShapeInfo();
169 ONNXTensorElementDataType type = tensor_info.GetElementType();
170 ATH_MSG_DEBUG("Input "<<i<<" : "<<" type= "<<type);
171
172 // Print input shapes/dims
173 input_node_dims = tensor_info.GetShape();
174 ATH_MSG_DEBUG("Input "<<i<<" : num_dims= "<<input_node_dims.size());
175 for (std::size_t j = 0; j < input_node_dims.size(); j++){
176 if(input_node_dims[j]<0){input_node_dims[j] =1;}
177 ATH_MSG_DEBUG("Input"<<i<<" : dim "<<j<<"= "<<input_node_dims[j]);
178 }
179 }
180 return std::make_tuple(input_node_dims, input_node_names);
181 }
182
183 //new additions for ONNX
184 std::tuple<std::vector<int64_t>, std::vector<const char*>>
186 const std::shared_ptr<Ort::Session>& sessionHandle,
187 Ort::AllocatorWithDefaultOptions& allocator) {
188 // output nodes
189 std::vector<int64_t> output_node_dims;
190 size_t num_output_nodes = sessionHandle->GetOutputCount();
191 std::vector<const char*> output_node_names(num_output_nodes);
192
193 // Loop the output nodes
194 for( std::size_t i = 0; i < num_output_nodes; i++ ) {
195 // Print output node names
196 char* output_name = sessionHandle->GetOutputNameAllocated(i, allocator).release();
197 ATH_MSG_DEBUG("Output "<<i<<" : "<<" name= "<<output_name);
198 output_node_names[i] = output_name;
199
200 Ort::TypeInfo type_info = sessionHandle->GetOutputTypeInfo(i);
201 auto tensor_info = type_info.GetTensorTypeAndShapeInfo();
202 ONNXTensorElementDataType type = tensor_info.GetElementType();
203 ATH_MSG_DEBUG("Output "<<i<<" : "<<" type= "<<type);
204
205 // Print output shapes/dims
206 output_node_dims = tensor_info.GetShape();
207 ATH_MSG_DEBUG("Output "<<i<<" : num_dims= "<<output_node_dims.size());
208 for (std::size_t j = 0; j < output_node_dims.size(); j++){
209 if(output_node_dims[j]<0){output_node_dims[j] =1;}
210 ATH_MSG_DEBUG("Output"<<i<<" : dim "<<j<<"= "<<output_node_dims[j]);
211 }
212 }
213 return std::make_tuple(output_node_dims, output_node_names);
214 }
215
216 //new additions for ONNX
217 std::tuple<std::shared_ptr<Ort::Session>, Ort::AllocatorWithDefaultOptions>
219 const std::string& modelFilePath) {
220 // Find the model file.
221 const std::string modelFileName = PathResolverFindCalibFile( modelFilePath );
222 ATH_MSG_INFO( "Using model file: " << modelFileName );
223
224 // set onnx session options
225 Ort::SessionOptions sessionOptions;
226 sessionOptions.SetIntraOpNumThreads( 1 );
227 sessionOptions.SetGraphOptimizationLevel( ORT_ENABLE_BASIC );
228 // set allocator
229 Ort::AllocatorWithDefaultOptions allocator;
230 // set the onnx runtime session
231 std::shared_ptr<Ort::Session> sessionHandle = std::make_shared<Ort::Session>( env, modelFileName.c_str(), sessionOptions );
232
233 ATH_MSG_INFO( "Created the ONNX Runtime session for model file = " << modelFileName);
234 return std::make_tuple(sessionHandle, allocator);
235 }
236
237 //____________________________________________________________________________
239 {
240 ATH_MSG_INFO("Initializing PhotonVertexSelectionTool...");
241 // initialize the readers or sessions
242 if(m_isTMVA){
243 // Get full path of configuration files for MVA
246 // Setup MVAs
247 std::vector<std::string> var_names = {
248 "deltaZ := TMath::Min(abs(PrimaryVerticesAuxDyn.z-zCommon)/zCommonError,20)",
249 "deltaPhi := abs(deltaPhi(PrimaryVerticesAuxDyn.phi,egamma_phi))" ,
250 "logSumpt := log10(PrimaryVerticesAuxDyn.sumPt)" ,
251 "logSumpt2 := log10(PrimaryVerticesAuxDyn.sumPt2)"
252 };
253 auto *mva1 = new TMVA::Reader(var_names, "!Silent:Color");
254 mva1->BookMVA ("MLP method", m_TMVAModelFilePath1 );
255 m_mva1 = std::unique_ptr<TMVA::Reader>( mva1 );
256
257 auto mva2 = std::make_unique<TMVA::Reader>(var_names, "!Silent:Color");
258 mva2->BookMVA ("MLP method", m_TMVAModelFilePath2 );
259 m_mva2 = std::unique_ptr<TMVA::Reader>( std::move(mva2) );
260 }
261 else{ // assume only ONNX for now
262 // get the ONNX Runtime version in initialization
263 ATH_MSG_INFO("ONNX Runtime version: " << Ort::GetVersionString());
264
265 // create the environment object.
266 Ort::ThreadingOptions tp_options;
267 tp_options.SetGlobalIntraOpNumThreads(1);
268 tp_options.SetGlobalInterOpNumThreads(1);
269
270 // create onnx environment
271 m_env = std::make_unique< Ort::Env >(
272 tp_options,
273 static_cast<OrtLoggingLevel>(m_ONNXLogLevel.value()),
274 "PhotonVertexSelectionTool");
275 ATH_MSG_DEBUG( "Ort::Env object created" );
276
277 // converted
281
282 // unconverted
286 }
287
288 // initialize the containers
289 ATH_CHECK( m_eventInfo.initialize() );
290 ATH_CHECK( m_vertexContainer.initialize() );
291
296 ATH_CHECK( m_deltaPhiKey.initialize() );
297 ATH_CHECK( m_deltaZKey.initialize() );
298 ATH_CHECK( m_sumPt2Key.initialize() );
299 ATH_CHECK( m_sumPtKey.initialize() );
300#ifndef XAOD_STANDALONE
303#endif
304
305 return StatusCode::SUCCESS;
306 }
307
309
310 // Delete the environment object.
311 m_env.reset();
312 ATH_MSG_DEBUG( "Ort::Env object deleted" );
313
314 // Return gracefully.
315 return StatusCode::SUCCESS;
316 }
317
318 //____________________________________________________________________________
320 auto fail = FailType::NoFail;
321
322 const EventContext& ctx = Gaudi::Hive::currentContext();
327
328 // Get the EventInfo
330
331 // Find the common z-position from beam / photon pointing information
332 std::pair<float, float> zCommon = xAOD::PVHelpers::getZCommonAndError(&*eventInfo, &egammas, m_convPtCut);
333 // Vector sum of photons
334 TLorentzVector vegamma = getEgammaVector(&egammas, fail);
335
336 // Retrieve PV collection from TEvent
338
339 bool writeSumPt2 = !sumPt2.isAvailable();
340 bool writeSumPt = !sumPt.isAvailable();
341
342 for (const xAOD::Vertex* vertex: *vertices) {
343
344 // Skip dummy vertices
345 if (!(vertex->vertexType() == xAOD::VxType::VertexType::PriVtx ||
346 vertex->vertexType() == xAOD::VxType::VertexType::PileUp)) continue;
347
348 // Set input variables
349 if (writeSumPt) {
350 sumPt(*vertex) = xAOD::PVHelpers::getVertexSumPt(vertex, 1, false);
351 }
352
353 if (writeSumPt2) {
354 sumPt2(*vertex) = xAOD::PVHelpers::getVertexSumPt(vertex, 2);
355 }
356
357 // Get momentum vector of vertex
358 TLorentzVector vmom = xAOD::PVHelpers::getVertexMomentum(vertex, true, m_derivationPrefix);
359
360 deltaPhi(*vertex) = (fail != FailType::FailEgamVect) ? std::abs(vmom.DeltaPhi(vegamma)) : -999.;
361 deltaZ(*vertex) = std::abs((zCommon.first - vertex->z())/zCommon.second);
362
363 } // loop over vertices
364
365 ATH_MSG_DEBUG("DecorateInputs exit code "<< fail);
366 if(failType!=nullptr)
367 *failType = fail;
368 return StatusCode::SUCCESS;
369 }
370
371 //____________________________________________________________________________
372 std::vector<std::pair<const xAOD::Vertex*, float>>
374 bool ignoreConv,
375 bool noDecorate,
376 yyVtxType* vtxCasePtr,
377 FailType* failTypePtr) const {
378 const xAOD::Vertex *vertex = nullptr;
379 std::vector<std::pair<const xAOD::Vertex*, float> > vertexMLP;
381 FailType failType = FailType::NoFail;
382 if (getVertexImp( egammas, vertex, ignoreConv, noDecorate, vertexMLP, vtxCase, failType ).isSuccess()) {
383 std::sort(vertexMLP.begin(), vertexMLP.end(), sortMLP);
384 }
385 if(vtxCasePtr!=nullptr)
386 *vtxCasePtr = vtxCase;
387 if(failTypePtr!=nullptr)
388 *failTypePtr = failType;
389
390 return vertexMLP;
391 }
392
393 //____________________________________________________________________________
395 const xAOD::Vertex* &prime_vertex,
396 bool ignoreConv) const
397 {
398 std::vector<std::pair<const xAOD::Vertex*, float> > vertexMLP;
400 FailType failType = FailType::NoFail;
401 return getVertexImp( egammas, prime_vertex, ignoreConv, false, vertexMLP, vtxcase, failType );
402 }
403
405 const xAOD::EgammaContainer& egammas,
406 const xAOD::Vertex*& prime_vertex,
407 bool ignoreConv,
408 bool noDecorate,
409 std::vector<std::pair<const xAOD::Vertex*, float>>& vertexMLP,
410 yyVtxType& vtxCase,
411 FailType& fail) const {
412 // Set default vertex case and declare photon container
413 vtxCase = yyVtxType::Unknown;
414 const xAOD::PhotonContainer *photons = dynamic_cast<const xAOD::PhotonContainer*>(&egammas);
415
416 // Retrieve PV collection from TEvent
418
419 if (!noDecorate && !decorateInputs(egammas).isSuccess()){
420 return StatusCode::FAILURE;
421 }
422
423 // Check if a conversion photon has a track attached to a primary/pileup vertex
424 if (!ignoreConv && photons) {
425 prime_vertex = getPrimaryVertexFromConv(photons);
426 if (prime_vertex != nullptr) {
427 vtxCase = yyVtxType::ConvTrack;
429 vertexMLP.emplace_back(prime_vertex, 0.);
430 return StatusCode::SUCCESS;
431 }
432 }
433
434 if (fail != FailType::NoFail){
435 ATH_MSG_VERBOSE("Returning hardest vertex. Fail detected (type="<< fail <<")");
436 vertexMLP.clear();
437 prime_vertex = xAOD::PVHelpers::getHardestVertex(&*vertices);
438 vertexMLP.emplace_back(prime_vertex, 10.);
439 return StatusCode::SUCCESS;
440 }
441
442 // Get the EventInfo
444
445 // If there are any silicon conversions passing selection
446 // ==> use Model 1 (Conv) otherwise Model 2 (Unconv)
447 // Set default for conversion bool as false unless otherwise
448 bool isConverted = false;
449
450 // assume default NoSiTrack (unconverted) unless otherwise
451 vtxCase = yyVtxType::NoSiTracks;
452 if (!ignoreConv && photons) {
453 for (const auto *photon: *photons) {
454 if (!photon)
455 {
456 ATH_MSG_WARNING("Null pointer to photon");
457 return StatusCode::FAILURE;
458 }
459 // find out if pass conversion selection criteria and tag as SiConvTrack case
461 {
462 isConverted = true;
463 vtxCase = yyVtxType::SiConvTrack;
464 }
465 }
466 }
467
468 // if TMVA chosen, declare tmva_reader only once (before for looping vertex)
469 TMVA::Reader *tmva_reader = new TMVA::Reader();
470 if(m_isTMVA){
471 if(isConverted){
472 // If there are any silicon conversions passing selection, use MVA1 (converted case)
473 tmva_reader = m_mva1.get();
474 }
475 // Otherwise, use MVA2 (unconverted case)
476 if(!isConverted){
477 tmva_reader = m_mva2.get();
478 }
479 }
480 ATH_MSG_DEBUG("Vtx Case: " << vtxCase);
481
482 // Vector sum of photons
483 TLorentzVector vegamma = getEgammaVector(&egammas, fail);
484
485 SG::AuxElement::ConstAccessor<float> sumPtA(m_derivationPrefix + "sumPt");
486 SG::AuxElement::ConstAccessor<float> sumPt2A(m_derivationPrefix + "sumPt2");
487 SG::AuxElement::ConstAccessor<float> deltaPhiA(m_derivationPrefix + "deltaPhi");
488 SG::AuxElement::ConstAccessor<float> deltaZA(m_derivationPrefix + "deltaZ");
489
490 // Loop over vertices and find best candidate
491 std::vector<float> ONNXInputVector;
492 std::vector<std::vector<float>> onnx_input_tensor_values;
493 std::vector<float> TMVAInputVector;
494 TString TMVAMethod;
495 float mlp = 0.0, mlp_max = -99999.0;
496 float doSkipByZSigmaScore = -9999.0;
497 // assign threshold score value to compare later for good vtx
498 float thresGoodVtxScore;
499 if(m_doSkipByZSigma){thresGoodVtxScore = doSkipByZSigmaScore;}
500 else{thresGoodVtxScore = mlp_max;}
501 for (const xAOD::Vertex* vertex: *vertices) {
502 // Skip dummy vertices
503 if (!(vertex->vertexType() == xAOD::VxType::VertexType::PriVtx ||
504 vertex->vertexType() == xAOD::VxType::VertexType::PileUp)) continue;
505
506 onnx_input_tensor_values.clear();
507
508 // Variables used as input features in classifier
509 float sumPt, sumPt2, deltaPhi, deltaZ;
510 float log10_sumPt, log10_sumPt2;
511
512 sumPt = (sumPtA)(*vertex);
513 sumPt2 = (sumPt2A)(*vertex);
514 deltaPhi = (deltaPhiA)(*vertex);
515 deltaZ = (deltaZA)(*vertex);
516 ATH_MSG_VERBOSE("sumPt: " << sumPt <<
517 " sumPt2: " << sumPt2 <<
518 " deltaPhi: " << deltaPhi <<
519 " deltaZ: " << deltaZ);
520
521 // setup the vector of input features based on selected inference framework
522 if(m_isTMVA){
523 // Get likelihood probability from TMVA model
524 TMVAMethod = "MLP method";
525 log10_sumPt = static_cast<float>(log10(sumPt));
526 log10_sumPt2 = static_cast<float>(log10(sumPt2));
527 TMVAInputVector = {deltaZ,deltaPhi,log10_sumPt,log10_sumPt2};
528 }
529 else{ //assume ony ONNX for now
530 // Get likelihood probability from onnx model
531 // check if value is 0, assign small number like 1e-8 as dummy, as we will take log later (log(0) is nan)
532 // note that the ordering here is a bit different, following the order used when training
533 ONNXInputVector = {sumPt2, sumPt, deltaPhi, deltaZ};
534 for (long unsigned int i = 0; i < ONNXInputVector.size(); i++) {
535 // skip log for deltaPhi and take log for the rest
536 if (i == 2) {
537 continue;
538 }
539 if (ONNXInputVector[i] != 0 && std::isinf(ONNXInputVector[i]) != true && std::isnan(ONNXInputVector[i]) != true){
540 ONNXInputVector[i] = log(std::abs(ONNXInputVector[i]));
541 }
542 else{
543 ONNXInputVector[i] = log(std::abs(0.00000001)); //log(abs(1e-8))
544 }
545 } //end ONNXInputVector for loop
546 onnx_input_tensor_values.push_back(ONNXInputVector);
547 }
548
549 // Do the actual calculation of classifier score part
550 if(m_isTMVA){
551 mlp = tmva_reader->EvaluateMVA(TMVAInputVector, TMVAMethod);
552 ATH_MSG_VERBOSE("TMVA output: " << (tmva_reader == m_mva1.get() ? "MVA1 ": "MVA2 ")<< mlp);
553 }
554 else{ //assume ony ONNX for now
555 if(isConverted){
556 mlp = getScore(m_nVars, onnx_input_tensor_values,
559 }
560 if(!isConverted){
561 mlp = getScore(m_nVars, onnx_input_tensor_values,
564 }
565 ATH_MSG_VERBOSE("log(abs(sumPt)): " << sumPt <<
566 " log(abs(sumPt2)): " << sumPt2 <<
567 " deltaPhi: " << deltaPhi <<
568 " log(abs(deltaZ)): " << deltaZ);
569 ATH_MSG_VERBOSE("ONNX output, isConverted = " << isConverted << ", mlp=" << mlp);
570 }
571
572 // Skip vertices above 10 sigma from pointing or 15 sigma from conversion (HPV)
573 // Simply displace the mlp variable we calculate before by a predefined value
575 if ((isConverted && deltaZ > 15) || (!isConverted && deltaZ > 10)) {
576 mlp = doSkipByZSigmaScore;
577 }
578 }
579
580 // add the new vertex and its score to vertexMLP container
581 vertexMLP.emplace_back(vertex, mlp);
582
583 // Keep track of maximal likelihood vertex
584 if (mlp > mlp_max) {
585 mlp_max = mlp;
586 prime_vertex = vertex;
587 }
588 } // end loop over vertices
589
590 // from all the looped vertices, decide the max score which should be more than the minimum we set
591 // (which should be more than the initial mlp_max value above or more than the skip vertex by z-sigma score)
592 // if this does not pass, return hardest primary vertex
593 if (mlp_max <= thresGoodVtxScore) {
594 ATH_MSG_DEBUG("No good vertex candidates from pointing, returning hardest vertex.");
595 prime_vertex = xAOD::PVHelpers::getHardestVertex(&*vertices);
597 vertexMLP.clear();
598 vertexMLP.emplace_back(xAOD::PVHelpers::getHardestVertex(&*vertices), 20.);
599 }
600
601 ATH_MSG_VERBOSE("getVertex case "<< (int)vtxCase << " exit code "<< (int)fail);
602 return StatusCode::SUCCESS;
603 }
604
605 //____________________________________________________________________________
606 bool PhotonVertexSelectionTool::sortMLP(const std::pair<const xAOD::Vertex*, float> &a,
607 const std::pair<const xAOD::Vertex*, float> &b)
608 { return a.second > b.second; }
609
610 //____________________________________________________________________________
612 {
613 if (photons == nullptr) {
614 ATH_MSG_WARNING("Passed nullptr photon container, returning nullptr vertex from getPrimaryVertexFromConv");
615 return nullptr;
616 }
617
618 std::vector<const xAOD::Vertex*> vertices;
619 const xAOD::Vertex *conversionVertex = nullptr, *primary = nullptr;
620 const xAOD::TrackParticle *tp = nullptr;
621 size_t NumberOfTracks = 0;
622
623 // Retrieve PV collection from TEvent
625
626
627 for (const auto *photon: *photons) {
628 conversionVertex = photon->vertex();
629 if (conversionVertex == nullptr) continue;
630
631 NumberOfTracks = conversionVertex->nTrackParticles();
632 for (size_t i = 0; i < NumberOfTracks; ++i) {
633 // Get trackParticle in GSF collection
634 const auto *gsfTp = conversionVertex->trackParticle(i);
635 if (gsfTp == nullptr) continue;
636 if (!xAOD::PVHelpers::passConvSelection(*conversionVertex, i, m_convPtCut)) continue;
637
638 // Get trackParticle in InDet collection
640 if (tp == nullptr) continue;
641
642 primary = getVertexFromTrack(tp, &*all_vertices);
643 if (primary == nullptr) continue;
644
645 if (primary->vertexType() == xAOD::VxType::VertexType::PriVtx ||
646 primary->vertexType() == xAOD::VxType::VertexType::PileUp) {
647 if (std::find(vertices.begin(), vertices.end(), primary) == vertices.end()) {
648 vertices.push_back(primary);
649 continue;
650 }
651 }
652 }
653 }
654
655 if (!vertices.empty()) {
656 if (vertices.size() > 1)
657 ATH_MSG_WARNING("Photons associated to different vertices! Returning lead photon association.");
658 return vertices[0];
659 }
660
661 return nullptr;
662 }
663
664 //____________________________________________________________________________
665 TLorentzVector PhotonVertexSelectionTool::getEgammaVector(const xAOD::EgammaContainer *egammas, FailType& failType) const
666 {
667 TLorentzVector v, v1;
668 const xAOD::CaloCluster *cluster = nullptr;
669 for (const xAOD::Egamma* egamma: *egammas) {
670 if (egamma == nullptr) {
671 ATH_MSG_DEBUG("No egamma object to get four vector");
672 failType = FailType::FailEgamVect;
673 continue;
674 }
675 cluster = egamma->caloCluster();
676 if (cluster == nullptr) {
677 ATH_MSG_WARNING("No cluster associated to egamma, not adding to 4-vector.");
678 continue;
679 }
680
681 v1.SetPtEtaPhiM(egamma->e()/cosh(cluster->etaBE(2)),
682 cluster->etaBE(2),
683 cluster->phiBE(2),
684 0.0);
685 v += v1;
686 }
687 return v;
688 }
689
690} // namespace CP
#define ATH_CHECK
Evaluate an expression and check for errors.
#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.
Handle class for adding a decoration to an object.
static Double_t a
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce(T &h)
bool msgLvl(const MSG::Level lvl) const
FailType
Declare the interface that the class provides.
std::unique_ptr< Ort::Env > m_env
Global runtime environment for Onnx Runtime.
const xAOD::Vertex * getPrimaryVertexFromConv(const xAOD::PhotonContainer *photons) const
Get possible vertex directly associated with photon conversions.
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_sumPtKey
TLorentzVector getEgammaVector(const xAOD::EgammaContainer *egammas, FailType &failType) const
Get combined 4-vector of photon container.
std::vector< const char * > m_output_node_names2
Ort::AllocatorWithDefaultOptions m_allocator2
std::shared_ptr< Ort::Session > m_sessionHandle2
StatusCode getVertex(const xAOD::EgammaContainer &egammas, const xAOD::Vertex *&vertex, bool ignoreConv=false) const
Given a list of photons, return the most likely vertex based on MVA likelihood.
std::unique_ptr< TMVA::Reader > m_mva2
std::vector< const char * > m_output_node_names1
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_deltaZKey
Ort::AllocatorWithDefaultOptions m_allocator1
std::unique_ptr< TMVA::Reader > m_mva1
float getScore(int nVars, const std::vector< std::vector< float > > &input_data, const std::shared_ptr< Ort::Session > &sessionHandle, std::vector< int64_t > input_node_dims, std::vector< const char * > input_node_names, std::vector< const char * > output_node_names) const
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_sumPt2Key
std::tuple< std::shared_ptr< Ort::Session >, Ort::AllocatorWithDefaultOptions > setONNXSession(Ort::Env &env, const std::string &modelFilePath)
std::vector< const char * > m_input_node_names2
static bool sortMLP(const std::pair< const xAOD::Vertex *, float > &a, const std::pair< const xAOD::Vertex *, float > &b)
Sort MLP results.
virtual StatusCode initialize()
Function initialising the tool.
std::tuple< std::vector< int64_t >, std::vector< const char * > > getOutputNodes(const std::shared_ptr< Ort::Session > &sessionHandle, Ort::AllocatorWithDefaultOptions &allocator)
StatusCode decorateInputs(const xAOD::EgammaContainer &egammas, FailType *failType=nullptr) const
Given a list of photons, decorate vertex container with MVA variables.
Gaudi::Property< int > m_ONNXLogLevel
ONNX Runtime logging level (0=VERBOSE, 1=INFO, 2=WARNING, 3=ERROR, 4=FATAL).
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo
Container declarations.
StatusCode getVertexImp(const xAOD::EgammaContainer &egammas, const xAOD::Vertex *&vertex, bool ignoreConv, bool noDecorate, std::vector< std::pair< const xAOD::Vertex *, float > > &, yyVtxType &, FailType &) const
Given a list of photons, return the MLPs of all vertices in the event.
std::shared_ptr< Ort::Session > m_sessionHandle1
PhotonVertexSelectionTool(const std::string &name)
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexContainer
int m_nVars
Create a proper constructor for Athena.
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_deltaPhiKey
std::vector< const char * > m_input_node_names1
std::tuple< std::vector< int64_t >, std::vector< const char * > > getInputNodes(const std::shared_ptr< Ort::Session > &sessionHandle, Ort::AllocatorWithDefaultOptions &allocator)
virtual double e() const
energy
Handle class for adding a decoration to an object.
bool isAvailable()
Test to see if this variable exists in the store, for the referenced object.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
elec/gamma data class.
Definition egamma.h:58
float phiBE(const unsigned layer) const
Get the phi in one layer of the EM Calo.
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
const std::vector< float > & trackWeights() const
Get all the track weights.
Select isolated Photons, Electrons and Muons.
const xAOD::Vertex * getVertexFromTrack(const xAOD::TrackParticle *track, const xAOD::VertexContainer *vertices)
std::string decorKeyFromKey(const std::string &key, const std::string &deflt)
Extract the decoration part of key.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
const xAOD::TrackParticle * getOriginalTrackParticleFromGSF(const xAOD::TrackParticle *trkPar)
Helper function for getting the "Original" Track Particle (i.e before GSF) via the GSF Track Particle...
const xAOD::Vertex * getHardestVertex(const xAOD::VertexContainer *vertices)
Return vertex with highest sum pT^2.
float getVertexSumPt(const xAOD::Vertex *vertex, int power=1, bool useAux=true)
Loop over track particles associated with vertex and return scalar sum of pT^power in GeV (from auxda...
TLorentzVector getVertexMomentum(const xAOD::Vertex *vertex, bool useAux=true, const std::string &derivationPrefix="")
Return vector sum of tracks associated with vertex (from auxdata if available and useAux = true).
bool passConvSelection(const xAOD::Photon *photon, float convPtCut=2e3)
Check if photon is converted, and tracks have Si hits and pass selection.
std::pair< float, float > getZCommonAndError(const xAOD::EventInfo *eventInfo, const xAOD::EgammaContainer *egammas, float convPtCut=2e3)
Return zCommon and zCommonError.
@ PileUp
Pile-up vertex.
@ PriVtx
Primary vertex.
PhotonContainer_v1 PhotonContainer
Definition of the current "photon container version".
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
setSAddress setEtaMS setDirPhiMS setDirZMS setBarrelRadius setEndcapAlpha setEndcapRadius setInterceptInner setEtaMap setEtaBin setIsTgcFailure setDeltaPt deltaPhi
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
Egamma_v1 Egamma
Definition of the current "egamma version".
Definition Egamma.h:17
EgammaContainer_v1 EgammaContainer
Definition of the current "egamma container version".