ATLAS Offline Software
Loading...
Searching...
No Matches
test-jet-constituents.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
11
13
14#include "TFile.h"
15#include "TTree.h"
16#include "TError.h"
17
18#include <iostream>
19#include <iomanip>
20
21//coverity[root_function]
22int main ATLAS_NOT_THREAD_SAFE (int argc, char *argv[]) {
23
25 using namespace asg::msgUserCode;
26 gErrorIgnoreLevel = kError;
27
28 if (argc < 3 || argc > 4) {
29 std::cerr << "usage: " << argv[0] << ": <DAOD> <jet collection> [max events]"
30 << "\n\n"
31 << "This test checks jet constituents and their thinning.\n"
32 << "It verifies that:\n"
33 << " 1. All jet constituent links are valid\n"
34 << " 2. All constituents can be cast to FlowElement\n"
35 << " 3. Counts charged vs neutral constituents\n"
36 << " 4. Checks originalObjectLink availability\n"
37 << " 5. Validates otherObjects pointers\n"
38 << "\n"
39 << "Arguments:\n"
40 << " <DAOD> : Input DAOD file path\n"
41 << " <jet collection>: Name of jet collection to check\n"
42 << " [max events] : Optional maximum number of events to process\n"
43 << "\n"
44 << "Return codes:\n"
45 << " -1: usage error\n"
46 << " 1: broken constituent links found\n"
47 << " 2: constituent not a FlowElement\n"
48 << " 3: invalid otherObjects in charged FlowElements\n"
49 << " 4: invalid otherObjects in neutral FlowElements\n"
50 << " 0: all constituents valid" << std::endl;
51 return -1;
52 }
53 std::string file = argv[1];
54 std::string jets_name = argv[2];
55 long long maxEvents = -1;
56 if (argc == 4) {
57 maxEvents = std::stoll(argv[3]);
58 }
59
60 // The name of the application:
61 const std::string APP_NAME = "TestJetConstituents";
62
63 // Set up the environment:
65
66 // Set up the event object:
68
69 // Open the file:
70 std::unique_ptr<TFile> ifile(TFile::Open(file.c_str(), "READ"));
71 if ( ! ifile.get() || ifile->IsZombie()) {
72 std::cerr << "Couldn't open file: " << file << std::endl;
73 return 1;
74 }
75
76 // Connect the event object to it:
77 ANA_CHECK( event.readFrom(ifile.get()) );
78
79 unsigned long long nJetsTotal = 0;
80 unsigned long long nConstituentsTotal = 0;
81 unsigned long long nChargedTotal = 0;
82 unsigned long long nNeutralTotal = 0;
83 unsigned long long nInvalidLinks = 0;
84 unsigned long long nNotFlowElement = 0;
85 unsigned long long nWithOriginalLink = 0;
86 unsigned long long nOtherObjectsCharged = 0;
87 unsigned long long nOtherObjectsNeutral = 0;
88 unsigned long long nInvalidOtherObjectsCharged = 0;
89 unsigned long long nInvalidOtherObjectsNeutral = 0;
90 unsigned long long nMissingSignalType = 0;
91
92 unsigned long long entries = event.getEntries();
93 if (maxEvents > 0 && maxEvents < (long long)entries) {
94 entries = maxEvents;
95 }
96 std::cout << "Processing " << entries << " events..." << std::endl;
97
98 for (unsigned long long entry = 0; entry < entries; ++entry) {
99 // Load the event:
100 if (event.getEntry(entry) < 0) {
101 std::cerr << "Couldn't load entry " << entry << " from file "
102 << file << std::endl;
103 return 1;
104 }
105
106 const xAOD::JetContainer *jets = nullptr;
107 ANA_CHECK( event.retrieve(jets, jets_name) );
108
109 for (const xAOD::Jet *const jet : *jets) {
110 nJetsTotal++;
111 size_t nConstituents = jet->numConstituents();
112 nConstituentsTotal += nConstituents;
113
114 for (size_t i = 0; i < nConstituents; ++i) {
115 const auto& link = jet->constituentLinks().at(i);
116
117 // Check if link is valid
118 if (!link.isValid()) {
119 nInvalidLinks++;
120 continue;
121 }
122
123 // Get the actual constituent - might need to follow originalObjectLink
124 const xAOD::IParticle* constituent = *link;
125
126 // Check if this is a view container element that needs dereferencing
127 static SG::AuxElement::ConstAccessor<ElementLink<xAOD::IParticleContainer>> originalAcc("originalObjectLink");
128 if (originalAcc.isAvailable(*constituent)) {
129 const ElementLink<xAOD::IParticleContainer>& origLink = originalAcc(*constituent);
130 if (origLink.isValid()) {
131 constituent = *origLink;
132 nWithOriginalLink++;
133 }
134 }
135
136 // Try to cast to FlowElement
137 const xAOD::FlowElement* flowElement = dynamic_cast<const xAOD::FlowElement*>(constituent);
138 if (!flowElement) {
139 nNotFlowElement++;
140 continue;
141 }
142
143 // Check if charged or neutral
144 bool isCharged = flowElement->isCharged();
145 if (isCharged) {
146 nChargedTotal++;
147 } else {
148 nNeutralTotal++;
149 }
150
151 // Check otherObjects and their validity
152 std::vector<const xAOD::IParticle*> others = flowElement->otherObjects();
153 for (const xAOD::IParticle* other : others) {
154 if (isCharged) {
155 nOtherObjectsCharged++;
156 if (!other) {
157 nInvalidOtherObjectsCharged++;
158 }
159 } else {
160 nOtherObjectsNeutral++;
161 if (!other) {
162 nInvalidOtherObjectsNeutral++;
163 }
164 }
165 }
166 }
167 }
168 }
169
170 // Print summary
171 std::cout << "\n========================================" << std::endl;
172 std::cout << "SUMMARY" << std::endl;
173 std::cout << "========================================" << std::endl;
174 std::cout << "Events processed: " << entries << std::endl;
175 std::cout << "Jets found: " << nJetsTotal << std::endl;
176 std::cout << "Total constituents: " << nConstituentsTotal << std::endl;
177 std::cout << " Charged: " << nChargedTotal
178 << " (" << std::fixed << std::setprecision(1)
179 << (nConstituentsTotal > 0 ? 100.0 * nChargedTotal / nConstituentsTotal : 0.0)
180 << "%)" << std::endl;
181 std::cout << " Neutral: " << nNeutralTotal
182 << " (" << std::fixed << std::setprecision(1)
183 << (nConstituentsTotal > 0 ? 100.0 * nNeutralTotal / nConstituentsTotal : 0.0)
184 << "%)" << std::endl;
185 std::cout << "Invalid constituent links: " << nInvalidLinks << std::endl;
186 std::cout << "Non-FlowElement constituents: " << nNotFlowElement << std::endl;
187 std::cout << "Missing signalType: " << nMissingSignalType << std::endl;
188 std::cout << "Constituents with originalObjectLink: " << nWithOriginalLink << std::endl;
189 std::cout << "\nOther Objects:" << std::endl;
190 std::cout << " Charged otherObjects: " << nOtherObjectsCharged;
191 if (nInvalidOtherObjectsCharged > 0) {
192 std::cout << " (INVALID: " << nInvalidOtherObjectsCharged << ")";
193 }
194 std::cout << std::endl;
195 std::cout << " Neutral otherObjects: " << nOtherObjectsNeutral;
196 if (nInvalidOtherObjectsNeutral > 0) {
197 std::cout << " (INVALID: " << nInvalidOtherObjectsNeutral << ")";
198 }
199 std::cout << std::endl;
200 std::cout << " Total otherObjects: " << (nOtherObjectsCharged + nOtherObjectsNeutral) << std::endl;
201
202 if (nConstituentsTotal > 0) {
203 std::cout << "\nAverage constituents/jet: " << std::fixed << std::setprecision(2)
204 << (double)nConstituentsTotal / nJetsTotal << std::endl;
205 }
206 std::cout << "========================================\n" << std::endl;
207
208 // Return codes
209 if (nInvalidLinks > 0) {
210 std::cerr << "ERROR: Found " << nInvalidLinks << " invalid constituent links!" << std::endl;
211 return 1;
212 }
213 if (nNotFlowElement > 0) {
214 std::cerr << "ERROR: Found " << nNotFlowElement << " constituents that are not FlowElements!" << std::endl;
215 return 2;
216 }
217 if (nInvalidOtherObjectsCharged > 0) {
218 std::cerr << "ERROR: Found " << nInvalidOtherObjectsCharged << " invalid otherObjects in charged FlowElements!" << std::endl;
219 return 3;
220 }
221 if (nInvalidOtherObjectsNeutral > 0) {
222 std::cerr << "ERROR: Found " << nInvalidOtherObjectsNeutral << " invalid otherObjects in neutral FlowElements!" << std::endl;
223 return 4;
224 }
225
226 std::cout << "SUCCESS: All constituent links are valid!" << std::endl;
227 return 0;
228}
bool isCharged(const T &p)
Definition AtlasPID.h:1004
Base class for elements of a container that can have aux data.
#define APP_NAME
macros for messaging and checking status codes
#define ANA_CHECK(EXP)
check whether the given expression was successful
#define ANA_CHECK_SET_TYPE(TYPE)
set the type for ANA_CHECK to report failures
int main(int, char **)
Main class for all the CppUnit test classes.
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
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.
std::vector< const xAOD::IParticle * > otherObjects() const
Class providing the definition of the 4-vector interface.
Tool for accessing xAOD files outside of Athena.
@ kAthenaAccess
Access containers/objects like Athena does.
double entries
Definition listroot.cxx:49
Jet_v1 Jet
Definition of the current "jet version".
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
Definition Init.cxx:31
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition FlowElement.h:16
JetContainer_v1 JetContainer
Definition of the current "jet container version".
TFile * file