ATLAS Offline Software
Loading...
Searching...
No Matches
JetCaloQualityToolFE.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
8
12
13#include <iostream>
14#include <iomanip>
15using namespace std;
16
18 : asg::AsgTool(name)
19{
20}
21
23 ATH_MSG_DEBUG( "Inside initialize() method" );
24
25 if(!m_writeDecorKeys.empty()){
26 ATH_MSG_ERROR("OutputDecorKeys should not be configured manually!");
27 return StatusCode::FAILURE;
28 }
29 if(m_jetContainerName.empty()){
30 ATH_MSG_ERROR("JetCaloQualityToolFE needs to have its input jet container name configured!");
31 return StatusCode::FAILURE;
32 }
33
34 // Set the DecorHandleKeys with the correct strings
35 for( const std::string & calcN : m_calculationNames){
36
37 if(calcN == "LArQuality"){
38 m_doLArQ = true;
39 }
40 else if(calcN == "HECQuality"){
41 m_doHECQ = true;
42 }
43 else if(calcN == "NegativeE"){
44 m_doNegE = true;
45 }
46 else if(calcN == "AverageLArQF"){
47 m_doAvgLAr = true;
48 }
49 else if(calcN == "Timing"){
50 m_doTime = true;
51 }
52 else if(calcN == "Centroid"){
53 m_doCentroid = true;
54 }
55 else if(calcN == "BchCorrCell"){
56 m_doBchCorrCell = true;
57 }
58
59 if(calcN == "Centroid"){
60 m_writeDecorKeys.emplace_back(m_jetContainerName + "." + calcN+"R");
61 }
62 else{
63 m_writeDecorKeys.emplace_back(m_jetContainerName + "." + calcN);
64 }
65 }
66
67 // Define OOT calculators.
68 for( const double timeCut : m_timingTimeCuts){
69 // build the moment name from the base-name and the value of the timing cut
70 std::stringstream s;
71 s << std::setprecision(0) << std::fixed << "OotFracClusters" << timeCut;
72 m_writeDecorKeys_OOT.emplace_back(m_jetContainerName + "." + s.str());
73 }
74
75 // Define tresholds for NXConstituents:
76 for( const int fracCut: m_thresholdCuts){
77 std::ostringstream sout;
78 sout << "N" << fracCut << "Constituents";
79 m_writeDecorKeys_Nfrac.emplace_back(m_jetContainerName + "." + sout.str());
80 }
81
82 ATH_CHECK(m_writeDecorKeys.initialize());
83 if(!m_writeDecorKeys_OOT.empty()){
84 ATH_CHECK(m_writeDecorKeys_OOT.initialize());
85 }
86 if(!m_writeDecorKeys_Nfrac.empty()){
88 }
89
90 return StatusCode::SUCCESS;
91}
92
94{
95
96 ATH_MSG_VERBOSE("Begin decorating jets.");
97
98 for(const xAOD::Jet* jet : jets) {
100 }
101
102 return StatusCode::SUCCESS;
103}
104
105std::vector<const xAOD::CaloCluster*> JetCaloQualityToolFE::extractConstituents(const xAOD::Jet& jet) const{
106
107 std::vector<const xAOD::CaloCluster*> clusters;
108
109 // Get the input type:
110 xAOD::Type::ObjectType ctype = jet.rawConstituent(0)->type();
111
112 if ( ctype == xAOD::Type::CaloCluster ) {
113 ATH_MSG_VERBOSE(" Constituents are calo clusters.");
114 for ( size_t i = 0; i < jet.numConstituents(); i++ ) {
115 const xAOD::CaloCluster* constit = static_cast<const xAOD::CaloCluster*>(jet.rawConstituent(i));
116 clusters.push_back(constit);
117 }
118 }
119 else if( ctype == xAOD::Type::FlowElement ){
120
121 ATH_MSG_VERBOSE(" Constituents are FlowElements.");
122
123 //Need to distinguish between ParticleFlow and UFOs
124 const xAOD::FlowElement* constit0 = static_cast<const xAOD::FlowElement*>(jet.rawConstituent(0));
125
126 // If jet constituents are ParticleFlow objects (stored as FlowElements)
127 if(constit0->signalType() & xAOD::FlowElement::PFlow){
128 ATH_MSG_VERBOSE(" Constituents are ParticleFlow objects stored as FlowElements.");
129 for ( size_t i = 0; i < jet.numConstituents(); i++ ) {
130 const xAOD::FlowElement* constit = static_cast<const xAOD::FlowElement*>(jet.rawConstituent(i));
131 // Use only neutral PFOs
132 if(constit->isCharged())
133 continue;
134
135 if(constit->nOtherObjects() >= 1){
136 const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>(constit->otherObject(0));
137 if(cluster != nullptr){
138 clusters.push_back(cluster);
139 }
140 }
141 }
142 }
143 else{ // jet constituents are UFOs (stored as FlowElements)
144 ATH_MSG_VERBOSE(" Constituents are UFOs stored as FlowElements.");
145
146 for ( size_t i = 0; i < jet.numConstituents(); i++ ) {
147 const xAOD::FlowElement* constit = static_cast<const xAOD::FlowElement*>(jet.rawConstituent(i));
148
149 //Reject charged UFOs (but keep combined UFOs)
151 continue;
152
153 // For UFOs, otherObjects are links to the underlying ParticleFlow objects
154 for (size_t n = 0; n < constit->otherObjects().size(); ++n) {
155 if(! constit->otherObject(n)) continue;
156 int index_pfo = constit->otherObject(n)->index();
157 if(index_pfo<0) continue;
158
159 const auto* fe = (constit->otherObject(n));
160 const xAOD::CaloCluster* cluster = nullptr;
161
162 if(fe->type() == xAOD::Type::FlowElement){
163 const xAOD::FlowElement* pfo = dynamic_cast<const xAOD::FlowElement*>(fe);
164 if(!pfo->otherObjects().empty() && pfo->otherObject(0) && pfo->otherObject(0)->type() == xAOD::Type::CaloCluster){
165 cluster = dynamic_cast<const xAOD::CaloCluster*> (pfo->otherObject(0));
166 }
167 }
168 if(!cluster){continue;}
169
170 if(std::find(clusters.begin(), clusters.end(), cluster) == clusters.end()){
171 clusters.push_back(cluster);
172 }
173 }
174 }
175 }
176 }
177
178 return clusters;
179
180}
181
183
184 // First, extract the constituents directly (in case of cluster-based jet) or underlying clusters
185 std::vector<const xAOD::CaloCluster*> clusters = extractConstituents(jet);
186
187 // Calculate moments
188 float sum_E = 0.0;
189 float sum_E_square = 0.0;
190
191 float sum_badLarQ = 0.0;
192 float sum_badHECQ = 0.0;
193 float sum_e_HEC = 0.0;
194 float sum_e_neg = 0.0;
195 float sum_avg_lar_q = 0.0;
196 float sum_timing = 0.0;
197 float centroid_x = 0.0, centroid_y = 0.0, centroid_z = 0.0;
198 float sum_e_bad_cells = 0.0;
199
200 std::vector<float> sum_OOT;
201 sum_OOT.resize(m_timingTimeCuts.size());
202
203 std::vector<int> counter_Nfrac;
204 counter_Nfrac.resize(m_thresholdCuts.size());
205
206 std::vector<float> cluster_energies;
207
208 for ( size_t i = 0; i < clusters.size(); i++){
209
210 const xAOD::CaloCluster* constit = static_cast<const xAOD::CaloCluster*>(clusters[i]);
211
212 float cluster_E = constit->e(xAOD::CaloCluster::UNCALIBRATED);
213
214 sum_E += cluster_E;
215 sum_E_square += cluster_E*cluster_E;
216
217 cluster_energies.push_back(cluster_E);
218
219 //LArQuality || HECQuality
220 double bad_frac=0.0;
221 if(m_doLArQ || m_doHECQ){
223
224 if(m_doLArQ){
225 sum_badLarQ += bad_frac*cluster_E;
226 }
227
228 if(m_doHECQ){
229 float e_HEC = constit->eSample( CaloSampling::HEC0) + constit->eSample( CaloSampling::HEC1) + constit->eSample( CaloSampling::HEC2) + constit->eSample( CaloSampling::HEC3);
230 sum_e_HEC += e_HEC;
231 sum_badHECQ += bad_frac*e_HEC;
232 }
233 }
234
235 //NegativeE
236 if(m_doNegE){
237 double e_pos=0.0;
239 sum_e_neg += cluster_E - e_pos;
240 }
241
242 //JetCalcAverageLArQualityF
243 if(m_doAvgLAr){
244 double avg_lar_q=0.0;
245 constit->retrieveMoment(xAOD::CaloCluster::AVG_LAR_Q, avg_lar_q);
246 sum_avg_lar_q += avg_lar_q*cluster_E*cluster_E;
247 }
248
249 //Centroid
250 if(m_doCentroid){
251 double x = 0.0, y = 0.0, z = 0.0;
255
256 centroid_x += x*cluster_E;
257 centroid_y += y*cluster_E;
258 centroid_z += z*cluster_E;
259 }
260
261 //BchCorrCell
262 if(m_doBchCorrCell){
263 double cells_bad_E = 0.0;
265 sum_e_bad_cells += cells_bad_E;
266 }
267
268 //Timing / OOT
269 if(m_doTime || m_timingTimeCuts.size() > 0){
270 double timing = constit->time();
271
272 if(m_doTime){
273 sum_timing += timing*cluster_E*cluster_E;
274 }
275
276 //OOT
277 for(size_t j = 0; j < m_timingTimeCuts.size(); j++){
278 if(std::abs(timing) > m_timingTimeCuts[j]){
279 sum_OOT[j] += cluster_E;
280 }
281 }
282 }
283 } // end loop over all all constituents
284
285
286 if(m_thresholdCuts.size() > 0){
287
288 std::sort(cluster_energies.rbegin(),cluster_energies.rend());
289
290 for(size_t iFracCut = 0; iFracCut < m_thresholdCuts.size(); iFracCut++){
291
292 int counter = 0;
293 float tmp_sum = 0;
294
295 for(unsigned int iClus = 0; iClus < cluster_energies.size(); iClus++){
296 tmp_sum += cluster_energies[iClus];
297 counter++;
298 if(tmp_sum > m_thresholdCuts[iFracCut]*sum_E/100.) break;
299 }
300 counter_Nfrac[iFracCut] = counter;
301 }
302 }
303
304 //Add the decorations
305 for(size_t i = 0; i < m_calculationNames.size(); i++){
306 std::string calcN = m_calculationNames[i];
307
309
310 if(calcN == "LArQuality"){
311 decHandle(jet) = sum_E != 0. ? sum_badLarQ/sum_E : 0.;
312 }
313 else if(calcN == "HECQuality"){
314 decHandle(jet) = sum_e_HEC != 0. ? sum_badHECQ/sum_e_HEC : 0.;
315 }
316 else if(calcN == "NegativeE"){
317 decHandle(jet) = sum_e_neg;
318 }
319 else if(calcN == "AverageLArQF"){
320 decHandle(jet) = sum_E_square != 0. ? sum_avg_lar_q/sum_E_square : 0.;
321 }
322 else if(calcN == "Timing"){
323 decHandle(jet) = sum_E_square != 0. ? sum_timing/sum_E_square : 0.;
324 }
325 else if(calcN == "Centroid"){
326 decHandle(jet) = sum_E_square != 0. ? sqrt(centroid_x*centroid_x+centroid_y*centroid_y+centroid_z*centroid_z)/sum_E_square : 0.;
327 }
328 else if(calcN == "BchCorrCell"){
329 decHandle(jet) = jet.jetP4(xAOD::JetEMScaleMomentum).E() != 0. ? sum_e_bad_cells/jet.jetP4(xAOD::JetEMScaleMomentum).E() : 0. ;
330 }
331 }
332
333 for( size_t iCut = 0; iCut < m_timingTimeCuts.size(); iCut++){
335 decHandle_timing(jet) = sum_E != 0. ? sum_OOT[iCut]/sum_E : 0. ;
336 }
337
338 for( size_t iFracCut = 0; iFracCut < m_thresholdCuts.size(); iFracCut++){
339 //Variable was previously stored as float rather than int
340 //Keep float to not break e.g. jet calibration with derivations storing variable as float
342 decHandle_frac(jet) = counter_Nfrac[iFracCut];
343 }
344}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
Handle class for adding a decoration to an object.
#define y
#define x
#define z
JetCaloQualityToolFE(const std::string &name)
void fillQualityVariables(const xAOD::Jet &jet) const
Gaudi::Property< std::vector< double > > m_timingTimeCuts
std::vector< const xAOD::CaloCluster * > extractConstituents(const xAOD::Jet &jet) const
SG::WriteDecorHandleKeyArray< xAOD::JetContainer > m_writeDecorKeys
Gaudi::Property< std::string > m_jetContainerName
SG::WriteDecorHandleKeyArray< xAOD::JetContainer > m_writeDecorKeys_OOT
Gaudi::Property< std::vector< int > > m_thresholdCuts
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
virtual StatusCode decorate(const xAOD::JetContainer &jets) const override
Decorate a jet collection without otherwise modifying it.
SG::WriteDecorHandleKeyArray< xAOD::JetContainer > m_writeDecorKeys_Nfrac
Gaudi::Property< std::vector< std::string > > m_calculationNames
size_t index() const
Return the index of this element within its container.
Handle class for adding a decoration to an object.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
bool retrieveMoment(MomentType type, double &value) const
Retrieve individual moment.
flt_t time() const
Access cluster time.
virtual double e() const
The total energy of the particle.
float eSample(const CaloSample sampling) const
@ AVG_LAR_Q
Sum(E_cell_LAr^2 Q_cell_LAr)/Sum(E_cell_LAr^2)
@ CENTER_Z
Cluster Centroid ( )
@ ENG_BAD_CELLS
Total em-scale energy of bad cells in this cluster.
@ ENG_POS
Total positive Energy of this cluster.
@ BADLARQ_FRAC
Energy fraction of LAr cells with quality larger than a given cut.
@ CENTER_X
Cluster Centroid ( )
@ CENTER_Y
Cluster Centroid ( )
std::size_t nOtherObjects() const
std::vector< const xAOD::IParticle * > otherObjects() const
signal_t signalType() const
const xAOD::IParticle * otherObject(std::size_t i) const
virtual Type::ObjectType type() const =0
The type of the object as a simple enumeration.
STL namespace.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
ObjectType
Type of objects that have a representation in the xAOD EDM.
Definition ObjectType.h:32
@ FlowElement
The object is a track-calo-cluster.
Definition ObjectType.h:52
@ CaloCluster
The object is a calorimeter cluster.
Definition ObjectType.h:39
Jet_v1 Jet
Definition of the current "jet version".
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition FlowElement.h:16
@ JetEMScaleMomentum
Definition JetTypes.h:28
JetContainer_v1 JetContainer
Definition of the current "jet container version".