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