ATLAS Offline Software
Loading...
Searching...
No Matches
DiphotonVertexDecorator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6// DiphotonVertexDecorator.cxx
8// To add the diphoton vertex to the evtStore
9
11#include <vector>
12#include <string>
13#include "TString.h"
14
15
21// For DeltaR
24
26
27// Athena initialize
29{
31 ATH_CHECK( m_primaryVertexKey.initialize() );
32 ATH_CHECK( m_photonKey.initialize() );
33 ATH_CHECK( m_diphotonVertexKey.initialize() );
34 ATH_CHECK( m_FEContainerHandleKey.initialize() );
35 return StatusCode::SUCCESS;
36}
37
38
39StatusCode DerivationFramework::DiphotonVertexDecorator::addBranches(const EventContext& ctx) const
40{
41 ATH_MSG_DEBUG( "DiphotonVertexDecorator::AddingBranches" );
42
44
45 if (!PV->empty() && PV->at(0)) {
46 ATH_MSG_DEBUG( "Default PV " << PV->at(0) << ", type = " << PV->at(0)->vertexType() << " , z = " << PV->at(0)->z() );
47 }
48
49 // Select the two highest pt photons that pass a preselection
50
52 const xAOD::Photon *ph1 = nullptr, *ph2 = nullptr;
53
54 for (const xAOD::Photon* ph: *photons)
55 {
56 if (!PhotonPreselect(ph)) continue;
57 if (not ph1 or ph->pt() > ph1->pt()) // new leading photon
58 {
59 ph2 = ph1;
60 ph1 = ph;
61 }
62 else if (not ph2 or ph->pt() > ph2->pt()) ph2 = ph; // new subleading photon
63 }
64
65 const ConstDataVector< xAOD::PhotonContainer > vertexPhotons = {ph1, ph2};
66
69
70 ATH_CHECK( m_photonVertexSelectionTool->decorateInputs(*(vertexPhotons.asDataVector()), &vertexFailType) );
71
72 // Get the photon vertex if possible
73 std::vector<std::pair<const xAOD::Vertex*, float> > vxResult;
74 const xAOD::Vertex *newPV = nullptr;
75
77 SG::Decorator<char> passORDec("passOR");
78 for(const auto *const fe : *FEHandle) passORDec(*fe) = true;
79
80 if (ph1 and ph2)
81 {
82 vxResult = m_photonVertexSelectionTool->getVertex( *( vertexPhotons.asDataVector()) , m_ignoreConv, true, &yyvertexVtxType, &vertexFailType );
83 if(!vxResult.empty()) {
84 newPV = vxResult[0].first; //output of photon vertex selection tool must be sorted according to score
85 }
86 ATH_CHECK(matchFlowElement(ph1,&*FEHandle));
87 ATH_CHECK(matchFlowElement(ph2,&*FEHandle));
88 }
89
90 // Decorate the vertices with the NN score
91 ATH_MSG_DEBUG("PhotonVertexSelection returns vertex " << newPV << " " << (newPV? Form(" with z = %g", newPV->z()) : "") );
92 // Create shallow copy of the PrimaryVertices container
94 xAOD::shallowCopy( *PV, ctx );
95 HggPV.second->setShallowIO(false);
96
98 ATH_CHECK(vertexContainer.recordNonConst(std::move(HggPV.first),
99 std::move(HggPV.second)));
100
101
102 static const SG::Accessor<float> vertexScoreAcc("vertexScore");
103 static const SG::Accessor<int> vertexFailTypeAcc("vertexFailType");
104 static const SG::Accessor<int> vertexCaseAcc("vertexCase");
105 static const SG::Accessor<phlink_t> leadingPhotonLinkAcc("leadingPhotonLink");
106 static const SG::Accessor<phlink_t> subleadingPhotonLinkAcc("subleadingPhotonLink");
107
108 if (newPV) {
109 //loop over vertex container; shallow copy has the same order
110 for (unsigned int iPV=0; iPV<PV->size(); iPV++) {
111 const auto *vx = PV->at(iPV);
112 auto yyvx = vertexContainer->at(iPV);
113 //reset vertex type
114 if (vx == newPV) {
115 //is this the diphoton primary vertex returned from the tool?
116 yyvx->setVertexType( xAOD::VxType::PriVtx );
117 } else if ( vx->vertexType()==xAOD::VxType::PriVtx || vx->vertexType()==xAOD::VxType::PileUp ) {
118 //not overriding the type of dummy vertices of type 0 (NoVtx)
119 yyvx->setVertexType( xAOD::VxType::PileUp );
120 }
121 //decorate score
122 for (const auto& vxR: vxResult) {
123 //find vertex in output from photonVertexSelectionTool
124 if ( vx == vxR.first ) {
125 vertexScoreAcc(*yyvx) = vxR.second;
126 vertexFailTypeAcc(*yyvx) = vertexFailType;
127 vertexCaseAcc(*yyvx) = yyvertexVtxType;
128 leadingPhotonLinkAcc(*yyvx) = phlink_t(*photons, ph1->index());
129 subleadingPhotonLinkAcc(*yyvx) = phlink_t(*photons, ph2->index());
130 break;
131 }
132 }
133 }
134 }
135 else {
136 //no vertex returned by photonVertexSelectionTool, decorate default PV with fit information
138 xAOD::VertexContainer::iterator yyvx_end = vertexContainer->end();
139 for(yyvx_itr = vertexContainer->begin(); yyvx_itr != yyvx_end; ++yyvx_itr ) {
140 if ( (*yyvx_itr)->vertexType()==xAOD::VxType::PriVtx ) {
141 vertexScoreAcc(**yyvx_itr) = -9999;
142 vertexFailTypeAcc(**yyvx_itr) = vertexFailType;
143 vertexCaseAcc(**yyvx_itr) = yyvertexVtxType;
144 leadingPhotonLinkAcc(**yyvx_itr) = (phlink_t()) ;
145 subleadingPhotonLinkAcc(**yyvx_itr) = (phlink_t());
146 }
147 }
148 }
149
150
151 if( !evtStore()->transientContains< xAOD::VertexContainer >( m_diphotonVertexKey.key() ) ){
152 ATH_MSG_WARNING("Unable to find transient xAOD::VertexContainer, \"" << m_diphotonVertexKey.key() << "\"");
153 }
154
155 return StatusCode::SUCCESS;
156}
157
159{
160
161 if (!ph) return false;
162
163 if (!ph->isGoodOQ(34214)) return false;
164
165 bool val(false);
166 bool defined(false);
167
168 static const SG::ConstAccessor<char> DFCommonPhotonsIsEMLooseAcc("DFCommonPhotonsIsEMLoose");
169 if(DFCommonPhotonsIsEMLooseAcc.isAvailable(*ph)){
170 defined = true;
171 val = static_cast<bool>(DFCommonPhotonsIsEMLooseAcc(*ph));
172 }
173 else{
174 defined = ph->passSelection(val, "Loose");
175 }
176
177 if(!defined || !val) return false;
178
179 // veto topo-seeded clusters
181
182 // Check which variable versions are best...
183 const xAOD::CaloCluster *caloCluster(ph->caloCluster());
184 double eta = std::abs(caloCluster->etaBE(2));
185
186 if (eta > m_maxEta) return false;
187 if (m_removeCrack && 1.37 <= eta && eta <= 1.52) return false;
188
189 if (ph->pt() < m_minPhotonPt) return false;
190
191 return true;
192
193}
194
196 const xAOD::IParticle* swclus = eg->caloCluster();
197
198 // Preselect FEs based on proximity: dR<0.4
199 std::vector<const xAOD::FlowElement*> nearbyFE;
200 nearbyFE.reserve(20);
201 for(const auto *const fe : *feCont) {
202 if(xAOD::P4Helpers::isInDeltaR(*fe, *swclus, 0.4, true)) {
203 if( ( !fe->isCharged() && fe->e() > FLT_MIN )) nearbyFE.push_back(fe);
204 } // DeltaR check
205 } // FE loop
206
207 SG::Decorator<char> passORDec("passOR");
208
209 double eg_cl_e = swclus->e();
210 bool doSum = true;
211 double sumE_fe = 0.;
212 const xAOD::IParticle* bestbadmatch = nullptr;
213 std::sort(nearbyFE.begin(),nearbyFE.end(),greaterPtFlowElement);
214 for(const auto& fe : nearbyFE) {
215 if(!xAOD::P4Helpers::isInDeltaR(*fe, *swclus, m_tcMatch_dR, true)) {continue;}
216 // Handle neutral FEs like topoclusters
217 double fe_e = fe->e();
218 // skip cluster if it's above our bad match threshold or outside the matching radius
219 if(fe_e>m_tcMatch_maxRat*eg_cl_e) {
220 ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (fe_e/eg_cl_e));
221 if( !bestbadmatch || (std::abs(fe_e/eg_cl_e-1.) < std::abs(bestbadmatch->e()/eg_cl_e-1.)) ) bestbadmatch = fe;
222 continue;
223 }
224
225 ATH_MSG_VERBOSE("E match with new nFE: " << std::abs(sumE_fe+fe_e - eg_cl_e) / eg_cl_e);
226 if( (doSum = std::abs(sumE_fe+fe_e-eg_cl_e) < std::abs(sumE_fe - eg_cl_e)) ) {
227 passORDec(*fe) = false;
228 sumE_fe += fe_e;
229 } // if we will retain the topocluster
230 else {break;}
231 } // loop over nearby clusters
232 if(sumE_fe<FLT_MIN && bestbadmatch) {
233 passORDec(*bestbadmatch) = false;
234 }
235
236 return StatusCode::SUCCESS;
237}
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
DataVector adapter that acts like it holds const pointers.
Helper class to provide type-safe access to aux data.
ElementLink< xAOD::PhotonContainer > phlink_t
FailType
Declare the interface that the class provides.
DataVector adapter that acts like it holds const pointers.
const DV * asDataVector() const
Return a pointer to this object, as a const DataVector.
DataModel_detail::iterator< DataVector > iterator
Definition DataVector.h:842
SG::ReadHandleKey< xAOD::PhotonContainer > m_photonKey
static bool greaterPtFlowElement(const xAOD::FlowElement *part1, const xAOD::FlowElement *part2)
SG::ReadHandleKey< xAOD::FlowElementContainer > m_FEContainerHandleKey
virtual StatusCode addBranches(const EventContext &ctx) const override final
SG::WriteHandleKey< xAOD::VertexContainer > m_diphotonVertexKey
SG::ReadHandleKey< xAOD::VertexContainer > m_primaryVertexKey
ToolHandle< CP::IPhotonVertexSelectionTool > m_photonVertexSelectionTool
StatusCode matchFlowElement(const xAOD::Photon *eg, const xAOD::FlowElementContainer *pfoCont) const
Helper class to provide type-safe access to aux data.
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
StatusCode recordNonConst(std::unique_ptr< T > data)
Record a non-const object to the store.
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition Egamma_v1.cxx:66
bool isGoodOQ(uint32_t mask) const
Check object quality. Return True is it is Good Object Quality.
bool passSelection(bool &value, const std::string &menu) const
Check if the egamma object pass a selection menu (using the name) If the menu decision is stored in t...
uint16_t author(uint16_t bitmask=EgammaParameters::AuthorALL) const
Get author.
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
Class providing the definition of the 4-vector interface.
virtual double e() const =0
The total energy of the particle.
float z() const
Returns the z position.
SG::Decorator< T, ALLOC > Decorator
Helper class to provide type-safe access to aux data, specialized for JaggedVecElt.
Definition AuxElement.h:576
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
const uint16_t AuthorCaloTopo35
Photon reconstructed by SW CaloTopo35 seeded clusters.
Definition EgammaDefs.h:38
bool isInDeltaR(const xAOD::IParticle &p1, const xAOD::IParticle &p2, double dR, bool useRapidity=true)
Check if 2 xAOD::IParticle are in a cone.
@ PileUp
Pile-up vertex.
@ PriVtx
Primary vertex.
FlowElementContainer_v1 FlowElementContainer
Definition of the current "pfo container version".
typename ShallowCopyResult< T >::type ShallowCopyResult_t
Return type of xAOD::shallowCopy.
Definition ShallowCopy.h:68
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
Vertex_v1 Vertex
Define the latest version of the vertex class.
ShallowCopyResult_t< T > shallowCopy(const T &cont, const EventContext &ctx)
Create a shallow copy of an existing container.
Photon_v1 Photon
Definition of the current "egamma version".