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 if (!m_elecSelTool.empty()) ATH_CHECK(m_elecSelTool.retrieve());
53 if (!m_muonSelTool.empty()) ATH_CHECK(m_muonSelTool.retrieve());
54
55 if (m_muonTrkProp < MuonTrk::Primary || m_muonTrk > MuonTrk::MSOnlyExtrapolatedMuonSpectrometerTrackParticle) {
56 ATH_MSG_FATAL("A bogous muon track particle has been picked " << m_muonTrkProp);
57 return StatusCode::FAILURE;
58 }
59 m_muonTrk = static_cast<MuonTrk>(m_muonTrkProp.value());
60 return StatusCode::SUCCESS;
61 }
63 unsigned int n_processed = std::accumulate(m_num_lep.begin(), m_num_lep.end(), 0, [](const std::atomic<unsigned int>& l, unsigned int n){
64 return n +l;
65 });
66 ATH_MSG_INFO("Proccessed in total "<<n_processed<<" events. Lepton multiplicities observed:");
67 for (unsigned int l = 0 ; l < m_num_lep.size(); ++l) {
68 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))<<"%)" );
69 }
70 const unsigned int n_trials = m_tried_fits;
71 ATH_MSG_INFO("---> Attempted fits "<<m_tried_fits<<" out of which "<<m_good_fits<<" ("<<(100.* m_good_fits / std::max(1u, n_trials) )<<"%) succeeded." );
72 return StatusCode::SUCCESS;
73 }
74 StatusCode FourLeptonVertexingAlgorithm::execute(const EventContext& ctx) const {
77 ATH_CHECK(vtxContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()));
78 xAOD::VertexContainer* out_container = vtxContainer.ptr();
79
80 std::vector<LeptonQuadruplet> all_quads = buildAllQuadruplets(ctx);
81 for (const LeptonQuadruplet& quad : all_quads) {
82 std::unique_ptr<xAOD::Vertex> candidate = fitQuadruplet(ctx, quad);
83 if (candidate) out_container->push_back(std::move(candidate));
84 }
85 return StatusCode::SUCCESS;
86 }
87
89 return elec->pt() >= m_minElecPt && (m_elecSelTool.empty() || m_elecSelTool->accept(elec)) &&
91 }
93 return muon->pt() >= m_minMuonPt && (m_muonSelTool.empty() || m_muonSelTool->accept(*muon)) && muon->trackParticle(m_muonTrk);
94 }
95 std::vector<LeptonQuadruplet> FourLeptonVertexingAlgorithm::buildAllQuadruplets(const EventContext& ctx) const {
96 std::vector<LeptonQuadruplet> to_ret{};
97
100 if (!muonContainer.isValid()) {
101 ATH_MSG_FATAL("Failed to retrieve the muon container for input " << m_muonKey.fullKey());
102 throw std::runtime_error("Invalid key access");
103 }
105 if (!elecContainer.isValid()) {
106 ATH_MSG_FATAL("Failed to retrieve the electron container for input " << m_elecKey.fullKey());
107 throw std::runtime_error("Invalid key access");
108 }
110 using PartVec = std::vector<const xAOD::IParticle*>;
111 PartVec selected_lep{};
112 const size_t num_lep = elecContainer->size() + muonContainer->size();
113 if (num_lep < 4) {
114 ATH_MSG_DEBUG("Less than four objects reconstructed");
115 ++m_num_lep[num_lep];
116 ++m_num_ele[elecContainer->size()];
117 ++m_num_muo[muonContainer->size()];
118 return to_ret;
119 }
120 selected_lep.reserve(num_lep);
121 size_t n_ele{0},n_muo{0};
122 for (const xAOD::Muon* muon : *muonContainer) {
123 if (passSelection(muon)) {
124 ATH_MSG_DEBUG("Add " << muon);
125 selected_lep.push_back(muon);
126 ++n_ele;
127 }
128 }
129 for (const xAOD::Electron* elec : *elecContainer) {
130 if (passSelection(elec)) {
131 ATH_MSG_DEBUG("Add " << elec);
132 selected_lep.push_back(elec);
133 ++n_muo;
134 }
135 }
137 ++m_num_lep[std::min(m_num_lep.size() -1 , n_ele + n_muo)];
138 ++m_num_ele[std::min(m_num_ele.size() -1 , n_ele)];
139 ++m_num_muo[std::min(m_num_muo.size() -1 , n_muo)];
140
141 if (selected_lep.size() < 4) {
142 ATH_MSG_DEBUG("Less than four leptons survived.");
143 return to_ret;
144 }
145 std::sort(selected_lep.begin(),selected_lep.end(),
146 [](const xAOD::IParticle* a, const xAOD::IParticle* b) {
147 return a->pt() > b->pt();});
149 if (selected_lep[0]->pt() < m_LeadPtCut || selected_lep[1]->pt() < m_SubLeadPtCut) return to_ret;
150
151 to_ret.reserve(std::pow(selected_lep.size(), 4));
152 for (PartVec::const_iterator itr1 = selected_lep.begin() + 3; itr1 != selected_lep.end(); ++itr1) {
153 for (PartVec::const_iterator itr2 = selected_lep.begin() + 2; itr2 != itr1; ++itr2) {
154 for (PartVec::const_iterator itr3 = selected_lep.begin() + 1; itr3 != itr2; ++itr3) {
155 if ( (*itr3)->pt() < m_SubLeadPtCut) return to_ret;
156 for (PartVec::const_iterator itr4 = selected_lep.begin(); itr4 != itr3; ++itr4) {
157 LeptonQuadruplet quad{*itr4, *itr3, *itr2, *itr1};
160 if (quad[0]->pt() < m_LeadPtCut) return to_ret;
161 ATH_MSG_DEBUG("Create new quaduplet " << quad);
162 to_ret.push_back(std::move(quad));
163 }
164 }
165 }
166 }
167 return to_ret;
168 }
170 if (part->type() == xAOD::Type::Muon)
171 return static_cast<const xAOD::Muon*>(part)->trackParticle(m_muonTrk);
172 else if (part->type() == xAOD::Type::Electron)
173 return xAOD::EgammaHelpers::getTrackParticlesVec(static_cast<const xAOD::Electron*>(part), !m_elecUseGSF)[0];
174 return dynamic_cast<const xAOD::TrackParticle*>(part);
175 }
177 static const SG::AuxElement::ConstAccessor<float> acc_charge{"charge"};
178 if (acc_charge.isAvailable(*part)) return acc_charge(*part);
179 return trackParticle(part)->charge();
180 }
181 std::unique_ptr<xAOD::Vertex> FourLeptonVertexingAlgorithm::fitQuadruplet(const EventContext& ctx, const LeptonQuadruplet& quad) const {
182 if (!passSelection(quad)) return nullptr;
183 ++m_tried_fits;
184 std::vector<const xAOD::TrackParticle*> trks{};
185 trks.reserve(4);
186 for (const xAOD::IParticle* lep : quad) { trks.push_back(trackParticle(lep)); }
189 if (!evtInfo.isValid()) {
190 ATH_MSG_FATAL("Failed to retrieve the event info " << m_evtKey.fullKey());
191 throw std::runtime_error("Invalid key access");
192 }
193
194 const Amg::Vector3D beam_spot{evtInfo->beamPosX(), evtInfo->beamPosY(), evtInfo->beamPosZ()};
195 std::unique_ptr<xAOD::Vertex> common_vtx = m_fitter->fit(ctx, trks, beam_spot);
196 if (!common_vtx) {
197 ATH_MSG_DEBUG("Fit from " << quad << " failed.");
198 return nullptr;
199 }
200 const float redChi2 = (common_vtx->chiSquared() / common_vtx->numberDoF());
201 ATH_MSG_DEBUG("Fit from " << quad << " gave a vertex with position at " << common_vtx->position() << " with chi2 "
202 << redChi2 << " nDoF: " << common_vtx->numberDoF());
203 if (redChi2 > m_VtxChi2Cut) {
204 ATH_MSG_DEBUG("Reject due to bad chi2");
205 return nullptr;
206 }
207 static const std::vector<float> empty_vec{};
208 if (m_pruneWeight) common_vtx->setTrackWeights(empty_vec);
209 if (m_pruneCov) common_vtx->setCovariance(empty_vec);
210 std::vector<TrkLink> track_links{};
211 for (const xAOD::TrackParticle* trk : trks) {
212 const xAOD::TrackParticleContainer* cont = dynamic_cast<const xAOD::TrackParticleContainer*>(trk->container());
213 TrkLink link{*cont, trk->index(), ctx};
214 link.toPersistent();
215 track_links.push_back(std::move(link));
216 }
217 common_vtx->setTrackParticleLinks(track_links);
218 ++m_good_fits;
219 return common_vtx;
220 }
222 float max_m{-1.};
223 for (unsigned int i = 1; i < quad.size(); ++i) {
224 for (unsigned int j = 0; j < i; ++j) {
225 const xAOD::TrackParticle* trk_a = trackParticle(quad[i]);
226 const xAOD::TrackParticle* trk_b = trackParticle(quad[j]);
227
228 if (std::abs(trk_b->z0() - trk_a->z0()) > m_z0Cut) return false;
229
231 const float di_m1 = (quad[i]->p4() + quad[j]->p4()).M();
232 const bool isSFOS1 = charge(quad[i])*charge(quad[j]) < 0 && quad[i]->type() == quad[j]->type();
234 if (isSFOS1 && di_m1 < m_lowSFOS_Cut) return false;
235 max_m = std::max(di_m1, max_m);
236 for (unsigned int k = 1 ; k < quad.size(); ++k) {
237 if (k == i || k == j) continue;
238 for (unsigned int l = 0; l < k ; ++l) {
239 if (l == i || l == j) continue;
240 const float di_m2 = (quad[k]->p4() + quad[l]->p4()).M();
241 const bool isSFOS2 = charge(quad[k])*charge(quad[l]) < 0 && quad[k]->type() == quad[l]->type();
242 if (isSFOS2 && di_m2 < m_lowSFOS_Cut) return false;
243 max_m = std::max(max_m, di_m2);
244 }
245 }
246 }
247 }
249 if (m_highPair_Cut > max_m) return false;
250
251 return true;
252 }
253} // 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
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:569
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
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".