ATLAS Offline Software
Loading...
Searching...
No Matches
FourLeptonVertexingAlgorithm.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
5
10
11namespace {
14 constexpr double MeVtoGeV = 1. / Gaudi::Units::GeV;
15} // anonymous namespace
16
17std::ostream& operator<<(std::ostream& sstr, const xAOD::IParticle* part) {
18 if (part->type() == xAOD::Type::ObjectType::Muon) {
19 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(part);
20 sstr << " Muon pT: " << mu->pt() * MeVtoGeV << " [GeV], eta: " << mu->eta() << ", phi: " << mu->phi() << ", q: " << mu->charge()
21 << ", priamry Author: " << mu->author();
22 } else if (part->type() == xAOD::Type::ObjectType::Electron) {
23 const xAOD::Electron* elec = static_cast<const xAOD::Electron*>(part);
24 sstr << " Electron pT: " << elec->pt() * MeVtoGeV << " [GeV], eta: " << elec->eta() << ", phi: " << elec->phi()
25 << ", q: " << elec->charge();
26 } else if (part->type() == xAOD::Type::ObjectType::TrackParticle) {
27 const xAOD::TrackParticle* trk = static_cast<const xAOD::TrackParticle*>(part);
28 sstr << " Track pT: " << trk->pt() * MeVtoGeV << " [GeV], eta: " << trk->eta() << ", phi: " << trk->phi()
29 << ", q: " << trk->charge() << ", d0: " << trk->d0() << ", z0: " << trk->z0();
30 }
31 sstr << " index: " << part->index();
32 return sstr;
33}
34
35std::ostream& operator<<(std::ostream& sstr, const LeptonQuadruplet& quad) {
36 sstr << std::endl;
37 for (const xAOD::IParticle* lep : quad) { sstr << " **** " << lep << std::endl; }
38 return sstr;
39}
40
41namespace DerivationFramework {
42
44
46 ATH_CHECK(m_muonKey.initialize());
47 ATH_CHECK(m_elecKey.initialize());
48 ATH_CHECK(m_evtKey.initialize());
49 ATH_CHECK(m_vtxKey.initialize());
50 ATH_CHECK(m_fitter.retrieve());
51
52 ATH_CHECK(m_elecSelTool.retrieve(EnableTool{!m_elecSelTool.empty()}));
53 ATH_CHECK(m_muonSelTool.retrieve(EnableTool{!m_muonSelTool.empty()}));
54
55 if (m_muonTrkProp < static_cast<int>(MuonTrk::Primary) ||
56 m_muonTrkProp > static_cast<int>(MuonTrk::MSOnlyExtrapolatedMuonSpectrometerTrackParticle)) {
57 ATH_MSG_FATAL("A bogous muon track particle has been picked " << m_muonTrkProp);
58 return StatusCode::FAILURE;
59 }
60 m_muonTrk = static_cast<MuonTrk>(m_muonTrkProp.value());
61 return StatusCode::SUCCESS;
62 }
64 unsigned int n_processed = std::accumulate(m_num_lep.begin(), m_num_lep.end(), 0, [](const std::atomic<unsigned int>& l, unsigned int n){
65 return n +l;
66 });
67 ATH_MSG_INFO("Proccessed in total "<<n_processed<<" events. Lepton multiplicities observed:");
68 for (unsigned int l = 0 ; l < m_num_lep.size(); ++l) {
69 ATH_MSG_INFO(" ---- Events with "<<l<<" leptons: "<<m_num_lep[l]<<" (elec/muon) "<<m_num_ele[l]<<"/"<<m_num_muo[l]<<" ("<<(100.*m_num_lep[l] / std::max(1u,n_processed))<<"%)" );
70 }
71 const unsigned int n_trials = m_tried_fits;
72 ATH_MSG_INFO("---> Attempted fits "<<m_tried_fits<<" out of which "<<m_good_fits<<" ("<<(100.* m_good_fits / std::max(1u, n_trials) )<<"%) succeeded." );
73 return StatusCode::SUCCESS;
74 }
75 StatusCode FourLeptonVertexingAlgorithm::execute(const EventContext& ctx) const {
78 ATH_CHECK(vtxContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()));
79 xAOD::VertexContainer* out_container = vtxContainer.ptr();
80
81 std::vector<LeptonQuadruplet> all_quads = buildAllQuadruplets(ctx);
82 for (const LeptonQuadruplet& quad : all_quads) {
83 std::unique_ptr<xAOD::Vertex> candidate = fitQuadruplet(ctx, quad);
84 if (candidate) out_container->push_back(std::move(candidate));
85 }
86 return StatusCode::SUCCESS;
87 }
88
90 return elec->pt() >= m_minElecPt && (m_elecSelTool.empty() || m_elecSelTool->accept(elec)) &&
92 }
94 return muon->pt() >= m_minMuonPt && (m_muonSelTool.empty() || m_muonSelTool->accept(*muon)) && muon->trackParticle(m_muonTrk);
95 }
96 std::vector<LeptonQuadruplet> FourLeptonVertexingAlgorithm::buildAllQuadruplets(const EventContext& ctx) const {
97 std::vector<LeptonQuadruplet> to_ret{};
98
101 if (!muonContainer.isValid()) {
102 ATH_MSG_FATAL("Failed to retrieve the muon container for input " << m_muonKey.fullKey());
103 throw std::runtime_error("Invalid key access");
104 }
106 if (!elecContainer.isValid()) {
107 ATH_MSG_FATAL("Failed to retrieve the electron container for input " << m_elecKey.fullKey());
108 throw std::runtime_error("Invalid key access");
109 }
111 using PartVec = std::vector<const xAOD::IParticle*>;
112 PartVec selected_lep{};
113 const size_t num_lep = elecContainer->size() + muonContainer->size();
114 if (num_lep < 4) {
115 ATH_MSG_DEBUG("Less than four objects reconstructed");
116 ++m_num_lep[num_lep];
117 ++m_num_ele[elecContainer->size()];
118 ++m_num_muo[muonContainer->size()];
119 return to_ret;
120 }
121 selected_lep.reserve(num_lep);
122 size_t n_ele{0},n_muo{0};
123 for (const xAOD::Muon* muon : *muonContainer) {
124 if (passSelection(muon)) {
125 ATH_MSG_DEBUG("Add " << muon);
126 selected_lep.push_back(muon);
127 ++n_ele;
128 }
129 }
130 for (const xAOD::Electron* elec : *elecContainer) {
131 if (passSelection(elec)) {
132 ATH_MSG_DEBUG("Add " << elec);
133 selected_lep.push_back(elec);
134 ++n_muo;
135 }
136 }
138 ++m_num_lep[std::min(m_num_lep.size() -1 , n_ele + n_muo)];
139 ++m_num_ele[std::min(m_num_ele.size() -1 , n_ele)];
140 ++m_num_muo[std::min(m_num_muo.size() -1 , n_muo)];
141
142 if (selected_lep.size() < 4) {
143 ATH_MSG_DEBUG("Less than four leptons survived.");
144 return to_ret;
145 }
146 std::sort(selected_lep.begin(),selected_lep.end(),
147 [](const xAOD::IParticle* a, const xAOD::IParticle* b) {
148 return a->pt() > b->pt();});
150 if (selected_lep[0]->pt() < m_LeadPtCut || selected_lep[1]->pt() < m_SubLeadPtCut) return to_ret;
151
152 to_ret.reserve(std::pow(selected_lep.size(), 4));
153 for (PartVec::const_iterator itr1 = selected_lep.begin() + 3; itr1 != selected_lep.end(); ++itr1) {
154 for (PartVec::const_iterator itr2 = selected_lep.begin() + 2; itr2 != itr1; ++itr2) {
155 for (PartVec::const_iterator itr3 = selected_lep.begin() + 1; itr3 != itr2; ++itr3) {
156 if ( (*itr3)->pt() < m_SubLeadPtCut) return to_ret;
157 for (PartVec::const_iterator itr4 = selected_lep.begin(); itr4 != itr3; ++itr4) {
158 LeptonQuadruplet quad{*itr4, *itr3, *itr2, *itr1};
161 if (quad[0]->pt() < m_LeadPtCut) return to_ret;
162 ATH_MSG_DEBUG("Create new quaduplet " << quad);
163 to_ret.push_back(std::move(quad));
164 }
165 }
166 }
167 }
168 return to_ret;
169 }
171 if (part->type() == xAOD::Type::Muon)
172 return static_cast<const xAOD::Muon*>(part)->trackParticle(m_muonTrk);
173 else if (part->type() == xAOD::Type::Electron)
174 return xAOD::EgammaHelpers::getTrackParticlesVec(static_cast<const xAOD::Electron*>(part), !m_elecUseGSF)[0];
175 return dynamic_cast<const xAOD::TrackParticle*>(part);
176 }
178 static const SG::AuxElement::ConstAccessor<float> acc_charge{"charge"};
179 if (acc_charge.isAvailable(*part)) return acc_charge(*part);
180 return trackParticle(part)->charge();
181 }
182 std::unique_ptr<xAOD::Vertex> FourLeptonVertexingAlgorithm::fitQuadruplet(const EventContext& ctx, const LeptonQuadruplet& quad) const {
183 if (!passSelection(quad)) return nullptr;
184 ++m_tried_fits;
185 std::vector<const xAOD::TrackParticle*> trks{};
186 trks.reserve(4);
187 for (const xAOD::IParticle* lep : quad) { trks.push_back(trackParticle(lep)); }
190 if (!evtInfo.isValid()) {
191 ATH_MSG_FATAL("Failed to retrieve the event info " << m_evtKey.fullKey());
192 throw std::runtime_error("Invalid key access");
193 }
194
195 const Amg::Vector3D beam_spot{evtInfo->beamPosX(), evtInfo->beamPosY(), evtInfo->beamPosZ()};
196 std::unique_ptr<xAOD::Vertex> common_vtx = m_fitter->fit(ctx, trks, beam_spot);
197 if (!common_vtx) {
198 ATH_MSG_DEBUG("Fit from " << quad << " failed.");
199 return nullptr;
200 }
201 const float redChi2 = (common_vtx->chiSquared() / common_vtx->numberDoF());
202 ATH_MSG_DEBUG("Fit from " << quad << " gave a vertex with position at " << common_vtx->position() << " with chi2 "
203 << redChi2 << " nDoF: " << common_vtx->numberDoF());
204 if (redChi2 > m_VtxChi2Cut) {
205 ATH_MSG_DEBUG("Reject due to bad chi2");
206 return nullptr;
207 }
208 static const std::vector<float> empty_vec{};
209 if (m_pruneWeight) common_vtx->setTrackWeights(empty_vec);
210 if (m_pruneCov) common_vtx->setCovariance(empty_vec);
211 std::vector<TrkLink> track_links{};
212 for (const xAOD::TrackParticle* trk : trks) {
213 const xAOD::TrackParticleContainer* cont = dynamic_cast<const xAOD::TrackParticleContainer*>(trk->container());
214 TrkLink link{*cont, trk->index(), ctx};
215 link.toPersistent();
216 track_links.push_back(std::move(link));
217 }
218 common_vtx->setTrackParticleLinks(track_links);
219 ++m_good_fits;
220 return common_vtx;
221 }
223 float max_m{-1.};
224 for (unsigned int i = 1; i < quad.size(); ++i) {
225 for (unsigned int j = 0; j < i; ++j) {
226 const xAOD::TrackParticle* trk_a = trackParticle(quad[i]);
227 const xAOD::TrackParticle* trk_b = trackParticle(quad[j]);
228
229 if (std::abs(trk_b->z0() - trk_a->z0()) > m_z0Cut) return false;
230
232 const float di_m1 = (quad[i]->p4() + quad[j]->p4()).M();
233 const bool isSFOS1 = charge(quad[i])*charge(quad[j]) < 0 && quad[i]->type() == quad[j]->type();
235 if (isSFOS1 && di_m1 < m_lowSFOS_Cut) return false;
236 max_m = std::max(di_m1, max_m);
237 for (unsigned int k = 1 ; k < quad.size(); ++k) {
238 if (k == i || k == j) continue;
239 for (unsigned int l = 0; l < k ; ++l) {
240 if (l == i || l == j) continue;
241 const float di_m2 = (quad[k]->p4() + quad[l]->p4()).M();
242 const bool isSFOS2 = charge(quad[k])*charge(quad[l]) < 0 && quad[k]->type() == quad[l]->type();
243 if (isSFOS2 && di_m2 < m_lowSFOS_Cut) return false;
244 max_m = std::max(max_m, di_m2);
245 }
246 }
247 }
248 }
250 if (m_highPair_Cut > max_m) return false;
251
252 return true;
253 }
254} // namespace DerivationFramework
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
std::ostream & operator<<(std::ostream &sstr, const xAOD::IParticle *part)
static Double_t a
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
xAOD::MuonContainer * muonContainer
An algorithm that can be simultaneously executed in multiple threads.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
const xAOD::TrackParticle * trackParticle(const xAOD::IParticle *part) const
SG::WriteHandleKey< xAOD::VertexContainer > m_vtxKey
ToolHandle< IAsgElectronLikelihoodTool > m_elecSelTool
SG::ReadHandleKey< xAOD::ElectronContainer > m_elecKey
std::atomic< unsigned int > m_good_fits
How many vertex fits were actually successful.
std::array< const xAOD::IParticle *, 4 > LeptonQuadruplet
FourLeptonVertexingAlgorithm(const std::string &n, ISvcLocator *p)
SG::ReadHandleKey< xAOD::MuonContainer > m_muonKey
Input containers.
std::vector< LeptonQuadruplet > buildAllQuadruplets(const EventContext &ctx) const
std::atomic< unsigned int > m_tried_fits
How many vertex fits were attempted.
std::unique_ptr< xAOD::Vertex > fitQuadruplet(const EventContext &ctx, const LeptonQuadruplet &quad) const
StatusCode execute(const EventContext &ctx) const override
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition Egamma_v1.cxx:66
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Definition Egamma_v1.cxx:71
virtual double phi() const override final
The azimuthal angle ( ) of the particle.
Definition Egamma_v1.cxx:76
float charge() const
Obtain the charge of the object.
Class providing the definition of the 4-vector interface.
float z0() const
Returns the parameter.
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .).
float d0() const
Returns the parameter.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
float charge() const
Returns the charge.
Eigen::Matrix< double, 3, 1 > Vector3D
constexpr float MeVtoGeV
THE reconstruction tool.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
@ TrackParticle
The object is a charged track particle.
Definition ObjectType.h:43
@ Muon
The object is a muon.
Definition ObjectType.h:48
@ Electron
The object is an electron.
Definition ObjectType.h:46
std::vector< const xAOD::TrackParticle * > getTrackParticlesVec(const xAOD::Egamma *eg, bool useBremAssoc=true, bool allParticles=true)
Return a list of all or only the best TrackParticle associated to the object.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
Muon_v1 Muon
Reference the current persistent version:
Electron_v1 Electron
Definition of the current "egamma version".