ATLAS Offline Software
DiphotonVertexDecorator.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 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 
16 #include "xAODCore/ShallowCopy.h"
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 
40 {
41  ATH_MSG_DEBUG( "DiphotonVertexDecorator::AddingBranches" );
42 
43  SG::ReadHandle<xAOD::VertexContainer> PV (m_primaryVertexKey, ctx);
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 
51  SG::ReadHandle<xAOD::PhotonContainer> photons (m_photonKey, ctx);
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 
76  SG::ReadHandle<xAOD::FlowElementContainer> FEHandle(m_FEContainerHandleKey, ctx);
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
93  std::pair< xAOD::VertexContainer*, xAOD::ShallowAuxContainer* > HggPV = xAOD::shallowCopyContainer( *PV );
94  HggPV.second->setShallowIO(false);
95 
96  SG::WriteHandle<xAOD::VertexContainer> vertexContainer(m_diphotonVertexKey, ctx);
97  ATH_CHECK(vertexContainer.recordNonConst(std::unique_ptr< xAOD::VertexContainer >(HggPV.first),
98  std::unique_ptr< xAOD::ShallowAuxContainer >(HggPV.second)));
99 
100 
101  static const SG::Accessor<float> vertexScoreAcc("vertexScore");
102  static const SG::Accessor<int> vertexFailTypeAcc("vertexFailType");
103  static const SG::Accessor<int> vertexCaseAcc("vertexCase");
104  static const SG::Accessor<phlink_t> leadingPhotonLinkAcc("leadingPhotonLink");
105  static const SG::Accessor<phlink_t> subleadingPhotonLinkAcc("subleadingPhotonLink");
106 
107  if (newPV) {
108  //loop over vertex container; shallow copy has the same order
109  for (unsigned int iPV=0; iPV<PV->size(); iPV++) {
110  const auto *vx = PV->at(iPV);
111  auto yyvx = (HggPV.first)->at(iPV);
112  //reset vertex type
113  if (vx == newPV) {
114  //is this the diphoton primary vertex returned from the tool?
115  yyvx->setVertexType( xAOD::VxType::PriVtx );
116  } else if ( vx->vertexType()==xAOD::VxType::PriVtx || vx->vertexType()==xAOD::VxType::PileUp ) {
117  //not overriding the type of dummy vertices of type 0 (NoVtx)
118  yyvx->setVertexType( xAOD::VxType::PileUp );
119  }
120  //decorate score
121  for (const auto& vxR: vxResult) {
122  //find vertex in output from photonVertexSelectionTool
123  if ( vx == vxR.first ) {
124  vertexScoreAcc(*yyvx) = vxR.second;
125  vertexFailTypeAcc(*yyvx) = vertexFailType;
126  vertexCaseAcc(*yyvx) = yyvertexVtxType;
127  leadingPhotonLinkAcc(*yyvx) = phlink_t(*photons, ph1->index());
128  subleadingPhotonLinkAcc(*yyvx) = phlink_t(*photons, ph2->index());
129  break;
130  }
131  }
132  }
133  }
134  else {
135  //no vertex returned by photonVertexSelectionTool, decorate default PV with fit information
137  xAOD::VertexContainer::iterator yyvx_end = (HggPV.first)->end();
138  for(yyvx_itr = (HggPV.first)->begin(); yyvx_itr != yyvx_end; ++yyvx_itr ) {
139  if ( (*yyvx_itr)->vertexType()==xAOD::VxType::PriVtx ) {
140  vertexScoreAcc(**yyvx_itr) = -9999;
141  vertexFailTypeAcc(**yyvx_itr) = vertexFailType;
142  vertexCaseAcc(**yyvx_itr) = yyvertexVtxType;
143  leadingPhotonLinkAcc(**yyvx_itr) = (phlink_t()) ;
144  subleadingPhotonLinkAcc(**yyvx_itr) = (phlink_t());
145  }
146  }
147  }
148 
149 
150  if( !evtStore()->transientContains< xAOD::VertexContainer >( m_diphotonVertexKey.key() ) ){
151  ATH_MSG_WARNING("Unable to find transient xAOD::VertexContainer, \"" << m_diphotonVertexKey.key() << "\"");
152  }
153 
154  return StatusCode::SUCCESS;
155 }
156 
158 {
159 
160  if (!ph) return false;
161 
162  if (!ph->isGoodOQ(34214)) return false;
163 
164  bool val(false);
165  bool defined(false);
166 
167  static const SG::ConstAccessor<char> DFCommonPhotonsIsEMLooseAcc("DFCommonPhotonsIsEMLoose");
168  if(DFCommonPhotonsIsEMLooseAcc.isAvailable(*ph)){
169  defined = true;
170  val = static_cast<bool>(DFCommonPhotonsIsEMLooseAcc(*ph));
171  }
172  else{
173  defined = ph->passSelection(val, "Loose");
174  }
175 
176  if(!defined || !val) return false;
177 
178  // veto topo-seeded clusters
179  if (ph->author(xAOD::EgammaParameters::AuthorCaloTopo35)) return false;
180 
181  // Check which variable versions are best...
182  const xAOD::CaloCluster *caloCluster(ph->caloCluster());
183  double eta = std::abs(caloCluster->etaBE(2));
184 
185  if (eta > m_maxEta) return false;
186  if (m_removeCrack && 1.37 <= eta && eta <= 1.52) return false;
187 
188  if (ph->pt() < m_minPhotonPt) return false;
189 
190  return true;
191 
192 }
193 
195  const xAOD::IParticle* swclus = eg->caloCluster();
196 
197  // Preselect FEs based on proximity: dR<0.4
198  std::vector<const xAOD::FlowElement*> nearbyFE;
199  nearbyFE.reserve(20);
200  for(const auto *const fe : *feCont) {
201  if(xAOD::P4Helpers::isInDeltaR(*fe, *swclus, 0.4, true)) {
202  if( ( !fe->isCharged() && fe->e() > FLT_MIN )) nearbyFE.push_back(fe);
203  } // DeltaR check
204  } // FE loop
205 
206  SG::Decorator<char> passORDec("passOR");
207 
208  double eg_cl_e = swclus->e();
209  bool doSum = true;
210  double sumE_fe = 0.;
211  const xAOD::IParticle* bestbadmatch = nullptr;
212  std::sort(nearbyFE.begin(),nearbyFE.end(),greaterPtFlowElement);
213  for(const auto& fe : nearbyFE) {
214  if(!xAOD::P4Helpers::isInDeltaR(*fe, *swclus, m_tcMatch_dR, true)) {continue;}
215  // Handle neutral FEs like topoclusters
216  double fe_e = fe->e();
217  // skip cluster if it's above our bad match threshold or outside the matching radius
218  if(fe_e>m_tcMatch_maxRat*eg_cl_e) {
219  ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (fe_e/eg_cl_e));
220  if( !bestbadmatch || (std::abs(fe_e/eg_cl_e-1.) < std::abs(bestbadmatch->e()/eg_cl_e-1.)) ) bestbadmatch = fe;
221  continue;
222  }
223 
224  ATH_MSG_VERBOSE("E match with new nFE: " << std::abs(sumE_fe+fe_e - eg_cl_e) / eg_cl_e);
225  if( (doSum = std::abs(sumE_fe+fe_e-eg_cl_e) < std::abs(sumE_fe - eg_cl_e)) ) {
226  passORDec(*fe) = false;
227  sumE_fe += fe_e;
228  } // if we will retain the topocluster
229  else {break;}
230  } // loop over nearby clusters
231  if(sumE_fe<FLT_MIN && bestbadmatch) {
232  passORDec(*bestbadmatch) = false;
233  }
234 
235  return StatusCode::SUCCESS;
236 }
ShallowCopy.h
DerivationFramework::DiphotonVertexDecorator::initialize
virtual StatusCode initialize() override final
Definition: DiphotonVertexDecorator.cxx:28
ParticleTest.eg
eg
Definition: ParticleTest.py:29
SG::Accessor< float >
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:83
ConstDataVector.h
DataVector adapter that acts like it holds const pointers.
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:67
xAODP4Helpers.h
CP::IPhotonVertexSelectionTool::Unknown
@ Unknown
Definition: IPhotonVertexSelectionTool.h:45
xAOD::Egamma_v1::author
uint16_t author(uint16_t bitmask=EgammaParameters::AuthorALL) const
Get author.
Definition: Egamma_v1.cxx:166
SG::ConstAccessor< char >
DerivationFramework::DiphotonVertexDecorator::PhotonPreselect
bool PhotonPreselect(const xAOD::Photon *ph) const
Definition: DiphotonVertexDecorator.cxx:157
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:41
ConstDataVector::asDataVector
const DV * asDataVector() const
Return a pointer to this object, as a const DataVector.
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:92
xAOD::CaloCluster_v1::etaBE
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.
Definition: CaloCluster_v1.cxx:628
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:62
SG::Decorator< char >
SG::WriteHandle::recordNonConst
StatusCode recordNonConst(std::unique_ptr< T > data)
Record a non-const object to the store.
DataModel_detail::iterator
(Non-const) Iterator class for DataVector/DataList.
Definition: DVLIterator.h:184
CP::IPhotonVertexSelectionTool::yyVtxType
yyVtxType
Definition: IPhotonVertexSelectionTool.h:44
xAOD::EgammaParameters::AuthorCaloTopo35
const uint16_t AuthorCaloTopo35
Photon reconstructed by SW CaloTopo35 seeded clusters.
Definition: EgammaDefs.h:38
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
DerivationFramework::DiphotonVertexDecorator::matchFlowElement
StatusCode matchFlowElement(const xAOD::Photon *eg, const xAOD::FlowElementContainer *pfoCont) const
Definition: DiphotonVertexDecorator.cxx:194
DerivationFramework::DiphotonVertexDecorator::m_photonVertexSelectionTool
ToolHandle< CP::IPhotonVertexSelectionTool > m_photonVertexSelectionTool
Definition: DiphotonVertexDecorator.h:53
xAOD::Egamma_v1::caloCluster
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
Definition: Egamma_v1.cxx:388
CP::IPhotonVertexSelectionTool::FailType
FailType
Declare the interface that the class provides.
Definition: IPhotonVertexSelectionTool.h:33
xAOD::VxType::PriVtx
@ PriVtx
Primary vertex.
Definition: TrackingPrimitives.h:572
DerivationFramework::DiphotonVertexDecorator::m_FEContainerHandleKey
SG::ReadHandleKey< xAOD::FlowElementContainer > m_FEContainerHandleKey
Definition: DiphotonVertexDecorator.h:58
DerivationFramework::DiphotonVertexDecorator::m_primaryVertexKey
SG::ReadHandleKey< xAOD::VertexContainer > m_primaryVertexKey
Definition: DiphotonVertexDecorator.h:55
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
xAOD::Vertex_v1::z
float z() const
Returns the z position.
SG::AuxElement::index
size_t index() const
Return the index of this element within its container.
DataVector
Derived DataVector<T>.
Definition: DataVector.h:795
xAOD::VxType::PileUp
@ PileUp
Pile-up vertex.
Definition: TrackingPrimitives.h:574
phlink_t
ElementLink< xAOD::PhotonContainer > phlink_t
Definition: DiphotonVertexDecorator.cxx:25
DerivationFramework::DiphotonVertexDecorator::m_diphotonVertexKey
SG::WriteHandleKey< xAOD::VertexContainer > m_diphotonVertexKey
Definition: DiphotonVertexDecorator.h:57
xAOD::shallowCopyContainer
std::pair< std::unique_ptr< T >, std::unique_ptr< ShallowAuxContainer > > shallowCopyContainer(const T &cont, [[maybe_unused]] const EventContext &ctx)
Function making a shallow copy of a constant container.
Definition: ShallowCopy.h:110
EventInfo.h
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:73
VertexContainer.h
xAOD::Vertex_v1
Class describing a Vertex.
Definition: Vertex_v1.h:42
xAOD::Photon_v1
Definition: Photon_v1.h:37
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
ConstDataVector
DataVector adapter that acts like it holds const pointers.
Definition: ConstDataVector.h:76
Pythia8_RapidityOrderMPI.val
val
Definition: Pythia8_RapidityOrderMPI.py:14
DiphotonVertexDecorator.h
xAOD::Egamma_v1::pt
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition: Egamma_v1.cxx:65
DerivationFramework::DiphotonVertexDecorator::m_photonKey
SG::ReadHandleKey< xAOD::PhotonContainer > m_photonKey
Definition: DiphotonVertexDecorator.h:56
DerivationFramework::DiphotonVertexDecorator::addBranches
virtual StatusCode addBranches(const EventContext &ctx) const override final
Definition: DiphotonVertexDecorator.cxx:39
SG::ConstAccessor::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
DataVector::at
const T * at(size_type n) const
Access an element, as an rvalue.
xAOD::P4Helpers::isInDeltaR
bool isInDeltaR(const xAOD::IParticle &p1, const xAOD::IParticle &p2, double dR, bool useRapidity=true)
Check if 2 xAOD::IParticle are in a cone.
Definition: xAODP4Helpers.h:174
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
Decorator.h
Helper class to provide type-safe access to aux data.
TrackingPrimitives.h
DataVector::empty
bool empty() const noexcept
Returns true if the collection is empty.
xAOD::IParticle::e
virtual double e() const =0
The total energy of the particle.
xAOD::Egamma_v1::passSelection
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...
xAOD::Egamma_v1::isGoodOQ
bool isGoodOQ(uint32_t mask) const
Check object quality. Return True is it is Good Object Quality.
Definition: Egamma_v1.cxx:236