ATLAS Offline Software
Loading...
Searching...
No Matches
JetConstituentThinning.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// JetConstituentThinning.cxx, (c) ATLAS Detector software
8
12#include "xAODBase/IParticle.h"
14#include <cmath>
15
17 const std::string &t, const std::string &n, const IInterface *p)
18 : base_class(t, n, p) {}
19
21
23 ATH_MSG_VERBOSE("initialize() ...");
24
25 // Check that we have a jet container
26 if (m_jetSGKey.empty()) {
27 ATH_MSG_FATAL("No jet collection provided!");
28 return StatusCode::FAILURE;
29 }
30
31 ATH_CHECK(m_jetSGKey.initialize());
32 ATH_MSG_INFO("Using " << m_jetSGKey.key() << " as the jet collection");
33
34 // Initialize the selection string parser if provided
35 if (!m_selectionString.empty()) {
36 ATH_CHECK(initializeParser(m_selectionString));
37 ATH_MSG_INFO("Jet selection string: " << m_selectionString);
38 }
39
40 // Build container names from prefixes
41 std::string jetChargedName = m_jetConstituentName + "ChargedParticleFlowObjects";
42 std::string jetNeutralName = m_jetConstituentName + "NeutralParticleFlowObjects";
43 std::string globalChargedName = m_globalConstituentName + "ChargedParticleFlowObjects";
44 std::string globalNeutralName = m_globalConstituentName + "NeutralParticleFlowObjects";
45
46 // Initialize thinning handle keys
51
56
57 ATH_MSG_INFO("Thinning containers:");
58 ATH_MSG_INFO(" Jet constituents: " << jetChargedName << ", " << jetNeutralName);
59 ATH_MSG_INFO(" Global constituents: " << globalChargedName << ", " << globalNeutralName);
60
61 // Initialize otherObjects thinning if requested
62 if (!m_otherObjectsName.empty()) {
65 ATH_MSG_INFO(" OtherObjects: " << m_otherObjectsName);
66 } else {
67 ATH_MSG_INFO(" OtherObjects thinning: disabled");
68 }
69
70 return StatusCode::SUCCESS;
71}
72
74 ATH_MSG_VERBOSE("finalize() ...");
75 return StatusCode::SUCCESS;
76}
77
78// The thinning itself
79StatusCode DerivationFramework::JetConstituentThinning::doThinning(const EventContext& ctx) const {
80
81 // Retrieve jet collection
83 if (!jets.isValid()) {
84 ATH_MSG_ERROR("Failed to retrieve jet collection " << m_jetSGKey.key());
85 return StatusCode::FAILURE;
86 }
87
88 // Get the jets that pass the selection
89 std::vector<const xAOD::Jet*> selectedJets;
90
91 if (!m_selectionString.empty()) {
92 // Use the expression parser
93 std::vector<int> entries = m_parser->evaluateAsVector();
94 if (entries.size() != jets->size()) {
95 ATH_MSG_ERROR("Selection string evaluation size mismatch!");
96 return StatusCode::FAILURE;
97 }
98
99 for (size_t i = 0; i < jets->size(); ++i) {
100 if (entries[i] == 1) {
101 selectedJets.push_back((*jets)[i]);
102 }
103 }
104 } else {
105 // Keep all jets
106 for (const auto* jet : *jets) {
107 selectedJets.push_back(jet);
108 }
109 }
110
111 ATH_MSG_DEBUG("Number of selected jets: " << selectedJets.size()
112 << " out of " << jets->size());
113
114 // Get thinning handles for all containers
119
120 // Initialize masks for all containers
121 std::vector<bool> jetChargedMask(jetChargedContainer.isValid() ? jetChargedContainer->size() : 0, false);
122 std::vector<bool> jetNeutralMask(jetNeutralContainer.isValid() ? jetNeutralContainer->size() : 0, false);
123 std::vector<bool> globalChargedMask(globalChargedContainer.isValid() ? globalChargedContainer->size() : 0, false);
124 std::vector<bool> globalNeutralMask(globalNeutralContainer.isValid() ? globalNeutralContainer->size() : 0, false);
125
126 // Cache mask sizes as int for comparison (avoid repeated static_cast)
127 const int jetChargedMaskSize = static_cast<int>(jetChargedMask.size());
128 const int jetNeutralMaskSize = static_cast<int>(jetNeutralMask.size());
129 const int globalChargedMaskSize = static_cast<int>(globalChargedMask.size());
130 const int globalNeutralMaskSize = static_cast<int>(globalNeutralMask.size());
131
132 // Accessor for originalObjectLink
133 static const SG::AuxElement::ConstAccessor<ElementLink<xAOD::IParticleContainer>> originalAcc("originalObjectLink");
134
135 // Collect otherObjects indices if needed
136 std::vector<const xAOD::IParticle*> otherObjects;
137
138 // Loop over selected jets and mark constituents to keep
139 for (const auto* jet : selectedJets) {
140 if (!jet) continue;
141
142 ATH_MSG_VERBOSE("Processing jet with " << jet->numConstituents() << " constituents");
143
144 for (size_t i = 0; i < jet->numConstituents(); ++i) {
145 const auto& link = jet->constituentLinks().at(i);
146 if (!link.isValid()) {
147 ATH_MSG_VERBOSE(" Invalid constituent link at index " << i);
148 continue;
149 }
150
151 int index = link.index();
152 if (index < 0) {
153 ATH_MSG_VERBOSE(" Constituent link has negative index, skipping");
154 continue;
155 }
156
157 // Cast to FlowElement (all PFlow constituents are FlowElements)
158 const xAOD::FlowElement* flowElement = dynamic_cast<const xAOD::FlowElement*>(*link);
159 if (!flowElement) {
160 ATH_MSG_VERBOSE(" Constituent at index " << i << " is not a FlowElement, skipping");
161 continue;
162 }
163
164 // Check if it's charged or neutral
165 bool isCharged = flowElement->isCharged();
166
167 // Mark in the jet constituent container mask
168 if (isCharged) {
169 if (index < jetChargedMaskSize) {
170 jetChargedMask[index] = true;
171 ATH_MSG_VERBOSE(" Charged constituent at index " << index << ": pt=" << flowElement->pt()
172 << ", eta=" << flowElement->eta());
173 }
174 } else {
175 if (index < jetNeutralMaskSize) {
176 jetNeutralMask[index] = true;
177 ATH_MSG_VERBOSE(" Neutral constituent at index " << index << ": pt=" << flowElement->pt()
178 << ", eta=" << flowElement->eta());
179 }
180 }
181
182 // Mark in the global container mask using originalObjectLink
183 if (originalAcc.isAvailable(*flowElement)) {
184 const ElementLink<xAOD::IParticleContainer>& origLink = originalAcc(*flowElement);
185 if (origLink.isValid()) {
186 int origIndex = origLink.index();
187 if (origIndex >= 0) {
188 if (isCharged && origIndex < globalChargedMaskSize) {
189 globalChargedMask[origIndex] = true;
190 ATH_MSG_VERBOSE(" Global charged constituent at index " << origIndex);
191 } else if (!isCharged && origIndex < globalNeutralMaskSize) {
192 globalNeutralMask[origIndex] = true;
193 ATH_MSG_VERBOSE(" Global neutral constituent at index " << origIndex);
194 }
195 }
196 }
197 }
198
199 // Collect otherObjects for thinning if requested
200 if (!m_otherObjectsName.empty()) {
201 std::vector<const xAOD::IParticle*> others = flowElement->otherObjects();
202 otherObjects.insert(otherObjects.end(), others.begin(), others.end());
203 }
204 }
205 }
206
207 size_t nChargedKept = std::count(jetChargedMask.begin(), jetChargedMask.end(), true);
208 size_t nNeutralKept = std::count(jetNeutralMask.begin(), jetNeutralMask.end(), true);
209 ATH_MSG_DEBUG("Keeping " << nChargedKept << " charged constituents and "
210 << nNeutralKept << " neutral constituents from selected jets");
211
212 if (!m_otherObjectsName.empty()) {
213 ATH_MSG_DEBUG("Found " << otherObjects.size() << " otherObjects from constituents");
214 }
215
216
217 if (jetChargedContainer.isValid()) {
218 jetChargedContainer.keep(jetChargedMask);
219 ATH_MSG_DEBUG("Container " << m_jetChargedKey.key() << ": keeping "
220 << nChargedKept << " out of " << jetChargedContainer->size() << " objects");
221 } else {
222 ATH_MSG_WARNING("Container " << m_jetChargedKey.key() << " not valid, skipping");
223 }
224
225 if (jetNeutralContainer.isValid()) {
226 jetNeutralContainer.keep(jetNeutralMask);
227 size_t nNeutralGlobalKept = std::count(jetNeutralMask.begin(), jetNeutralMask.end(), true);
228 ATH_MSG_DEBUG("Container " << m_jetNeutralKey.key() << ": keeping "
229 << nNeutralGlobalKept << " out of " << jetNeutralContainer->size() << " objects");
230 } else {
231 ATH_MSG_WARNING("Container " << m_jetNeutralKey.key() << " not valid, skipping");
232 }
233
234 if (globalChargedContainer.isValid()) {
235 globalChargedContainer.keep(globalChargedMask);
236 size_t nGlobalChargedKept = std::count(globalChargedMask.begin(), globalChargedMask.end(), true);
237 ATH_MSG_DEBUG("Container " << m_globalChargedKey.key() << ": keeping "
238 << nGlobalChargedKept << " out of " << globalChargedContainer->size() << " objects");
239 } else {
240 ATH_MSG_WARNING("Container " << m_globalChargedKey.key() << " not valid, skipping");
241 }
242
243 if (globalNeutralContainer.isValid()) {
244 globalNeutralContainer.keep(globalNeutralMask);
245 size_t nGlobalNeutralKept = std::count(globalNeutralMask.begin(), globalNeutralMask.end(), true);
246 ATH_MSG_DEBUG("Container " << m_globalNeutralKey.key() << ": keeping "
247 << nGlobalNeutralKept << " out of " << globalNeutralContainer->size() << " objects");
248 } else {
249 ATH_MSG_WARNING("Container " << m_globalNeutralKey.key() << " not valid, skipping");
250 }
251
252 // Thin otherObjects container if requested
253 if (!m_otherObjectsName.empty()) {
255
256 if (!otherObjectsContainer.isValid()) {
257 ATH_MSG_WARNING("OtherObjects container " << m_otherObjectsKey.key() << " not valid, skipping");
258 } else {
259 size_t nObjects = otherObjectsContainer->size();
260 std::vector<bool> mask(nObjects, false);
261 const int maskSize = static_cast<int>(mask.size());
262
263 // Mark objects using their indices
264 for (const auto* other : otherObjects) {
265 if (!other) continue;
266 int index = other->index();
267 if (index >= 0 && index < maskSize) {
268 mask[index] = true;
269 }
270 }
271
272 size_t nKept = std::count(mask.begin(), mask.end(), true);
273 ATH_MSG_DEBUG("OtherObjects container " << m_otherObjectsKey.key() << ": keeping "
274 << nKept << " out of " << nObjects << " objects");
275
276 otherObjectsContainer.keep(mask);
277 }
278 }
279
280 return StatusCode::SUCCESS;
281}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool isCharged(const T &p)
Definition AtlasPID.h:1004
Base class for elements of a container that can have aux data.
Handle for requesting thinning for a data object.
SG::ReadHandleKey< xAOD::JetContainer > m_jetSGKey
SG::ThinningHandleKey< xAOD::IParticleContainer > m_otherObjectsKey
SG::ThinningHandleKey< xAOD::FlowElementContainer > m_globalNeutralKey
SG::ThinningHandleKey< xAOD::FlowElementContainer > m_jetChargedKey
JetConstituentThinning(const std::string &t, const std::string &n, const IInterface *p)
SG::ThinningHandleKey< xAOD::FlowElementContainer > m_jetNeutralKey
virtual StatusCode doThinning(const EventContext &ctx) const override
SG::ThinningHandleKey< xAOD::FlowElementContainer > m_globalChargedKey
void keep(size_t ndx)
Mark that index ndx in the container should be kept (not thinned away).
HandleKey object for adding thinning to an object.
Handle for requesting thinning for a data object.
std::vector< const xAOD::IParticle * > otherObjects() const
virtual double pt() const override
virtual double eta() const override
The pseudorapidity ( ) of the particle.
double entries
Definition listroot.cxx:49
Definition index.py:1
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition FlowElement.h:16