ATLAS Offline Software
Loading...
Searching...
No Matches
JetClusterer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <memory>
8#include "fastjet/PseudoJet.hh"
9#include "fastjet/ClusterSequence.hh"
10#include "fastjet/ClusterSequenceArea.hh"
11#include "fastjet/config.h"
12#include "fastjet/contrib/VariableRPlugin.hh"
13
17
18#include "JetEDM/FastJetUtils.h"
19
23
24namespace JetClustererHelper
25{
26
27 void seedsFromEventInfo(const xAOD::EventInfo *ei, std::vector<int> &seeds)
28 {
29 // const xAOD::EventInfo* pevinfo = handle.cptr();
30 auto ievt = ei->eventNumber();
31 auto irun = ei->runNumber();
32
34 {
35 // For MC, use the channel and MC event number
36 ievt = ei->mcEventNumber();
37 irun = ei->mcChannelNumber();
38 }
39 seeds.push_back(ievt);
40 seeds.push_back(irun);
41 }
42}
43
45{
46
47 ATH_MSG_DEBUG("Initializing...");
50 if (m_fjalg == fastjet::undefined_jet_algorithm)
51 {
52 ATH_MSG_ERROR("Invalid jet algorithm name: " << m_jetalg);
53 ATH_MSG_ERROR("Allowed values are Kt, CamKt, AntiKt, etc.");
54 return StatusCode::FAILURE;
55 }
56 if (m_jetrad <= 0)
57 {
58 ATH_MSG_ERROR("Invalid jet size parameter: " << m_jetrad);
59 return StatusCode::FAILURE;
60 }
61
62 // buld an empty ClusterSequence, just for the fastjet splash screen to appear during initialization (?)
63 fastjet::JetDefinition jetdef(m_fjalg, m_jetrad);
65
67 fastjet::ClusterSequence cs(empty, jetdef);
68 cs.inclusive_jets(m_ptmin);
69 m_isVariableR = m_minrad >= 0.0 && m_massscale >= 0.0;
70
71 // Input DataHandles
72 if (!m_finalPseudoJets.empty())
73 {
74 ATH_MSG_WARNING("A non-empty value was found for the FinalPseudoJets WriteHandleKey -- this will be ignored!");
75 }
76
77 ATH_CHECK(m_eventinfokey.initialize());
78 ATH_CHECK(m_inputPseudoJets.initialize());
79 m_finalPseudoJets = name() + "FinalPJ";
80 ATH_CHECK(m_finalPseudoJets.initialize());
81 m_clusterSequence = name() + "ClusterSequence";
82 ATH_CHECK(m_clusterSequence.initialize());
83
85
86 return StatusCode::SUCCESS;
87}
88
89// -----------------------
90// Build the cluster sequence
91std::unique_ptr<fastjet::ClusterSequence> JetClusterer::buildClusterSequence(const PseudoJetVector *pseudoJetVector) const
92{
93
94 fastjet::JetDefinition jetdef(m_fjalg, m_jetrad);
95 using fastjet::contrib::VariableRPlugin;
96 std::unique_ptr<VariableRPlugin> VRJetPlugin(nullptr);
97
98 if (m_isVariableR)
99 {
100 /* clustering algorithm
101 * They correspond to p parameter of Sequential recombination algs
102 * AKTLIKE = -1, CALIKE = 0, KTLIKE = 1
103 */
104 VariableRPlugin::ClusterType VRClusterType = VariableRPlugin::AKTLIKE;
105 switch (m_fjalg)
106 {
107 case fastjet::kt_algorithm:
108 VRClusterType = VariableRPlugin::KTLIKE;
109 break;
110 case fastjet::antikt_algorithm:
111 VRClusterType = VariableRPlugin::AKTLIKE;
112 break;
113 case fastjet::cambridge_algorithm:
114 VRClusterType = VariableRPlugin::CALIKE;
115 break;
116 default:
117 ATH_MSG_ERROR("Unsupported clustering algorithm for Variable-R jet finding.");
118 return nullptr;
119 }
120 VRJetPlugin = std::make_unique<VariableRPlugin>(m_massscale, m_minrad, m_jetrad, VRClusterType, false);
121 jetdef = fastjet::JetDefinition(VRJetPlugin.get());
122 }
123
124 std::unique_ptr<fastjet::ClusterSequence> clSequence(nullptr);
125
126 if (m_useArea)
127 {
128 // Prepare ghost area specifications -------------
129 ATH_MSG_DEBUG("Creating input area cluster sequence");
130 bool seedsok = true;
131 fastjet::AreaDefinition adef = buildAreaDefinition(seedsok);
132
133 if (seedsok)
134 {
135 clSequence = std::make_unique<fastjet::ClusterSequenceArea>(*pseudoJetVector, jetdef, adef);
136 }
137 else
138 {
139 return nullptr;
140 }
141 }
142 else
143 {
144 ATH_MSG_DEBUG("Creating input cluster sequence");
145 clSequence = std::make_unique<fastjet::ClusterSequence>(*pseudoJetVector, jetdef);
146 }
147
148 return clSequence;
149}
150
151void JetClusterer::processPseudoJet(const fastjet::PseudoJet &pj, const PseudoJetContainer &pjCont, xAOD::JetContainer *jets, const xAOD::Vertex *originVertex) const
152{
153
154 // -------------------------------------
155 // translate to xAOD::Jet
156 ATH_MSG_DEBUG("Converting pseudojets to xAOD::Jet");
157 static const SG::AuxElement::Accessor<const fastjet::PseudoJet *> pjAccessor("PseudoJet");
159
160 // create the xAOD::Jet from the PseudoJet, doing the signal & constituents extraction
161 xAOD::Jet &jet = pjTranslator.translate(pj, pjCont, *jets, originVertex);
162
163 // Add the PseudoJet onto the xAOD jet. Maybe we should do it in the above JetFromPseudojet call ??
164 pjAccessor(jet) = &pj;
165
166 jet.setInputType(xAOD::JetInput::Type(m_inputType.value()));
168 jet.setAlgorithmType(ialg);
169 jet.setSizeParameter(m_jetrad.value());
170 if (m_isVariableR)
171 {
174 }
175 if (m_useArea)
176 jet.setAttribute(xAOD::JetAttribute::JetGhostArea, m_ghostarea.value());
177
178 ATH_MSG_VERBOSE(" xAOD::Jet with pt " << std::setprecision(4) << jet.pt() * 1e-3 << " has " << jet.getConstituents().size() << " constituents");
179 ATH_MSG_VERBOSE(" Leading constituent is of type " << jet.getConstituents()[0].rawConstituent()->type());
180
181 // Perhaps better to make configurable
182 if (originVertex)
183 {
184 jet.setAssociatedObject("OriginVertex", originVertex);
185 }
186 else
187 {
188 ATH_MSG_VERBOSE("Could not set OriginVertex for jet!");
189 }
190}
191
192std::pair<std::unique_ptr<xAOD::JetContainer>, std::unique_ptr<SG::IAuxStore>> JetClusterer::getJets() const
193{
194 // Return this in case of any problems
195 auto nullreturn = std::make_pair(std::unique_ptr<xAOD::JetContainer>(nullptr), std::unique_ptr<SG::IAuxStore>(nullptr));
196
197 // -----------------------
198 // retrieve input
200 if (!pjContHandle.isValid())
201 {
202 ATH_MSG_ERROR("No valid PseudoJetContainer with key " << m_inputPseudoJets.key());
203 return nullreturn;
204 }
205
206 // Build the container to be returned
207 // Avoid memory leaks with unique_ptr
208 auto jets = std::make_unique<xAOD::JetContainer>();
209 auto auxCont = std::make_unique<xAOD::JetAuxContainer>();
210 jets->setStore(auxCont.get());
211
212 const PseudoJetVector *pseudoJetVector = pjContHandle->casVectorPseudoJet();
213 ATH_MSG_DEBUG("Pseudojet input container has size " << pseudoJetVector->size());
214
215 std::unique_ptr<fastjet::ClusterSequence> clSequence = buildClusterSequence(pseudoJetVector);
216
217 if (!clSequence)
218 return nullreturn;
219
220 // -----------------------
221 // Build a new pointer to a PseudoJetVector containing the final PseudoJet
222 // This allows us to own the vector of PseudoJet which we will put in the evt store.
223 // Thus the contained PseudoJet will be kept frozen there and we can safely use pointer to them from the xAOD::Jet objects
224 auto pjVector = std::make_unique<PseudoJetVector>(fastjet::sorted_by_pt(clSequence->inclusive_jets(m_ptmin)));
225 ATH_MSG_DEBUG("Found jet count: " << pjVector->size());
226 if (msgLvl(MSG::VERBOSE))
227 {
228 for (const auto &pj : *pjVector)
229 {
230 msg() << " Pseudojet with pt " << std::setprecision(4) << pj.Et() * 1e-3 << " has " << pj.constituents().size() << " constituents" << endmsg;
231 }
232 }
233
234 // No PseudoJets, so there's nothing else to do
235 // Delete the cluster sequence before we go
236 if (!pjVector->empty())
237 {
238
239 for (const fastjet::PseudoJet &pj : *pjVector)
240 {
241 processPseudoJet(pj, *pjContHandle, jets.get(), nullptr);
242 // we want the rank to start with zero, but this is after the
243 // jet has been added, thus the "size() - 1" here.
244 m_jetRankAccessor(*jets.get()->back()) = jets->size() - 1;
245 }
246
247 // -------------------------------------
248 // record final PseudoJetVector
250 if (!pjVectorHandle.record(std::move(pjVector)))
251 {
252 ATH_MSG_ERROR("Can't record PseudoJetVector under key " << m_finalPseudoJets);
253 return nullreturn;
254 }
255 // -------------------------------------
256 // record ClusterSequence
258 if (!clusterSeqHandle.record(std::move(clSequence)))
259 {
260 ATH_MSG_ERROR("Can't record ClusterSequence under key " << m_clusterSequence);
261 return nullreturn;
262 }
263 }
264
265 ATH_MSG_DEBUG("Reconstructed jet count: " << jets->size() << " clusterseq=" << clSequence.get());
266 // Return the jet container and aux, use move to transfer
267 // ownership of pointers to caller
268 return std::make_pair(std::move(jets), std::move(auxCont));
269}
270
271fastjet::AreaDefinition JetClusterer::buildAreaDefinition(bool &seedsok) const
272{
273
274 fastjet::GhostedAreaSpec gspec(5.0, 1, m_ghostarea);
275 seedsok = true;
276 std::vector<int> seeds;
277
278 if (m_ranopt == 1)
279 {
280 // Use run/event number as random number seeds.
281 auto evtInfoHandle = SG::makeHandle(m_eventinfokey);
282 if (!evtInfoHandle.isValid())
283 {
284 ATH_MSG_ERROR("Unable to retrieve event info");
285 seedsok = false;
286 return {};
287 }
288
289 JetClustererHelper::seedsFromEventInfo(evtInfoHandle.cptr(), seeds);
290 }
291
292 ATH_MSG_DEBUG("Active area specs:");
293 ATH_MSG_DEBUG(" Requested ghost area: " << m_ghostarea);
294 ATH_MSG_DEBUG(" Actual ghost area: " << gspec.actual_ghost_area());
295 ATH_MSG_DEBUG(" Max eta: " << gspec.ghost_etamax());
296 ATH_MSG_DEBUG(" # ghosts: " << gspec.n_ghosts());
297 ATH_MSG_DEBUG(" # rapidity bins: " << gspec.nrap());
298 ATH_MSG_DEBUG(" # phi bins: " << gspec.nphi());
299
300 if (seeds.size() == 2)
301 {
302 ATH_MSG_DEBUG(" Random seeds: " << seeds[0] << ", " << seeds[1]);
303 }
304 else
305 {
306 ATH_MSG_WARNING("Random generator size is not 2: " << seeds.size());
307 ATH_MSG_DEBUG(" Random seeds: ");
308 for (auto seed : seeds)
309 ATH_MSG_DEBUG(" " << seed);
310 }
311
312 // We use with_fixed_seed() as recommended for thread safety in
313 // fastjet 3.4.0.
314 return fastjet::AreaDefinition(fastjet::active_area,
315 gspec)
316 .with_fixed_seed(seeds);
317}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Handle class for reading from StoreGate.
std::vector< fastjet::PseudoJet > PseudoJetVector
static const Attributes_t empty
bool msgLvl(const MSG::Level lvl) const
Gaudi::Property< float > m_ghostarea
fastjet::AreaDefinition buildAreaDefinition(bool &seedsok) const
Build the area definition when running with area calculation. The seedsok flag is set to false when e...
std::pair< std::unique_ptr< xAOD::JetContainer >, std::unique_ptr< SG::IAuxStore > > getJets() const override
Return the final jets with their aux store.
Gaudi::Property< std::string > m_jetalg
SG::WriteHandleKey< jet::ClusterSequence > m_clusterSequence
Gaudi::Property< int > m_inputType
Gaudi::Property< float > m_massscale
Gaudi::Property< float > m_ptmin
Gaudi::Property< std::string > m_jetRank
SG::ReadHandleKey< xAOD::EventInfo > m_eventinfokey
Handle to EventInfo. This is used to get the evt&run number to set the Ghost area random seeds.
Gaudi::Property< int > m_ranopt
StatusCode initialize() override
Dummy implementation of the initialisation function.
Gaudi::Property< float > m_minrad
void processPseudoJet(const fastjet::PseudoJet &pj, const PseudoJetContainer &pjCont, xAOD::JetContainer *jets, const xAOD::Vertex *vertex) const
translate to xAOD::Jet
SG::AuxElement::Accessor< int > m_jetRankAccessor
Gaudi::Property< float > m_jetrad
std::unique_ptr< fastjet::ClusterSequence > buildClusterSequence(const PseudoJetVector *pseudoJetvector) const
Used to create the cluster sequence.
fastjet::JetAlgorithm m_fjalg
SG::ReadHandleKey< PseudoJetContainer > m_inputPseudoJets
Handle Input PseudoJetContainer.
SG::WriteHandleKey< PseudoJetVector > m_finalPseudoJets
used to build the key under which the final PJ will be stored in evtStore()
xAOD::Jet & translate(const fastjet::PseudoJet &pj, const PseudoJetContainer &pjCont, xAOD::JetContainer &jetCont, const xAOD::Vertex *originVertex=nullptr) const
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
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.
uint64_t mcEventNumber() const
The MC generator's event number.
bool eventType(EventType type) const
Check for one particular bitmask value.
@ IS_SIMULATION
true: simulation, false: data
uint32_t runNumber() const
The current event's run number.
uint32_t mcChannelNumber() const
The MC generator's channel number.
uint64_t eventNumber() const
The current event's event number.
void seedsFromEventInfo(const xAOD::EventInfo *ei, std::vector< int > &seeds)
Fill seeds vector from run & event number. This functio is separated from the class so it's easier to...
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
ID algId(const std::string &n)
Converts a string into a JetAlgorithmType::ID.
fastjet::JetAlgorithm fastJetDef(ID id)
ID
//////////////////////////////////////// JetAlgorithmType::ID defines most common physics jet finding...
Jet_v1 Jet
Definition of the current "jet version".
EventInfo_v1 EventInfo
Definition of the latest event info version.
Vertex_v1 Vertex
Define the latest version of the vertex class.
JetContainer_v1 JetContainer
Definition of the current "jet container version".
MsgStream & msg
Definition testRead.cxx:32