ATLAS Offline Software
Loading...
Searching...
No Matches
SoftKillerWeightTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "fastjet/ClusterSequenceArea.hh"
8#include "fastjet/Selector.hh"
9#include "fastjet/RectangularGrid.hh"
10#include "fastjet/contrib/SoftKiller.hh"
11
12#include "xAODPFlow/PFO.h"
15
16
17using namespace std;
18
19namespace {
20 const static SG::AuxElement::ConstAccessor<float> acc_clambda("CENTER_LAMBDA");
21}
22
25 , m_isCaloSplit(false)
26 , m_gridSpacing(0.6)
27 , m_eCalGrid(0.5)
28 , m_hCalGrid(0.5)
29 , m_rapmin(0.0)
30 , m_rapmax(2.5)
32 , m_rapmaxApplied(10)
34
35{
36
37 declareProperty("SKGridSize", m_gridSpacing);
38 declareProperty("SKRapMin", m_rapmin);
39 declareProperty("SKRapMax", m_rapmax);
40 declareProperty("SKRapMinApplied", m_rapminApplied);
41 declareProperty("SKRapMaxApplied", m_rapmaxApplied);
42 declareProperty("isCaloSplit", m_isCaloSplit);
43 declareProperty("ECalGridSize", m_eCalGrid);
44 declareProperty("HCalGridSize", m_hCalGrid);
45
46 // Option to disregard cPFOs in the weight calculation
47 declareProperty("IgnoreChargedPFO", m_ignoreChargedPFOs);
48}
49
50
53 ATH_MSG_ERROR("SoftKillerWeightTool requires CaloCluster or PFO inputs when isCaloSplit is true."
54 << " It cannot apply split calorimeters on objects of type "
55 << m_inputType);
56 return StatusCode::FAILURE;
57 }
58
61 ATH_MSG_ERROR("Incompatible configuration: setting both IgnoreChargedPFO and ApplyToChargedPFO to true"
62 << "will set all cPFOs to zero");
63 return StatusCode::FAILURE;
64 }
66 ATH_MSG_ERROR("Incompatible configuration: ApplyToNeutralPFO=False -- what kind of pileup do you wish to suppress?");
67 return StatusCode::FAILURE;
68 }
69 }
70 return StatusCode::SUCCESS;
71}
72
74 const static SG::AuxElement::Accessor<float> weightAcc("SoftKillerWeight"); // Handle for PU weighting here
75 double minPt(0.), minPtECal(0.), minPtHCal(0.);
76 if(!m_isCaloSplit) {
77 minPt = getSoftKillerMinPt(*cont);
78 ATH_MSG_VERBOSE("For current event, minpt = " << minPt);
79 }
80 else {
81 std::pair<double,double> minPt_split = getSoftKillerMinPtSplit(*cont);
82 minPtECal = minPt_split.first;
83 minPtHCal = minPt_split.second;
84 ATH_MSG_VERBOSE("For current event, minpt = " << minPtECal << " (ECAL), "
85 << minPtHCal << " (HCAL)");
86 }
87
88 for(xAOD::IParticle* part : *cont) {
89 float w = 1;
90 if(!m_isCaloSplit) w = calculateWeight(*part, minPt);
91 else w = calculateSplitWeight(*part, minPtECal, minPtHCal);
92 // use parent class's type-sensitive setter
93 ATH_CHECK( setEnergyPt(part, part->e()*w, part->pt()*w,&weightAcc) );
94 }
95 return StatusCode::SUCCESS;
96}
97
98
99// Finds the pT cut for this event based on the SK results
100// The partSK collection contains all particles that aren't cut, so particles below
101// its min pT are cut
102double SoftKillerWeightTool::findMinPt(const vector<fastjet::PseudoJet> &partSK) const {
103 if (partSK.empty()) {return 0.;}
104 double minPt = 999999999999;
105
106 for(unsigned int i=0; i < partSK.size(); i++){
107 if( partSK[i].pt() < minPt) minPt = partSK[i].pt();
108 }
109
110 // There is a small rounding error which I account for this way
111 return (minPt - 1e-12);
112}
113
114
115
116// Reweights particles (when calo isn't split)
118 vector<fastjet::PseudoJet> partPJ;
119 partPJ.reserve(cont.size());
120
121 for(xAOD::IParticle* part : cont){
122 // Only use positive E
123 bool accept = part->e() > 1e-9;
124 // For PFlow we would only want to apply the correction to neutral PFOs,
125 // because charged hadron subtraction handles the charged PFOs.
126 // However, we might still want to use the cPFOs for the min pt calculation
128 xAOD::PFO* pfo = static_cast<xAOD::PFO*>(part);
129 accept = !pfo->isCharged();
130 }
132 xAOD::TrackCaloCluster* tcc = static_cast<xAOD::TrackCaloCluster*>(part);
133 accept = (tcc->taste()!= 0);
134 }
136 xAOD::FlowElement* fe = static_cast<xAOD::FlowElement*>(part);
138 if(m_ignoreChargedPFOs) accept = !fe->isCharged();
139 }
140 else
141 accept = !fe->isCharged();
142 }
143 if(accept) {
144 partPJ.emplace_back( part->p4() );
145 }
146 }
147
148 fastjet::Selector selector = fastjet::SelectorAbsRapRange(m_rapmin, m_rapmax);
149 fastjet::RectangularGrid SKgrid(-m_rapmax, m_rapmax, m_gridSpacing, m_gridSpacing, selector);
150 fastjet::contrib::SoftKiller softkiller(SKgrid);
151 std::vector<fastjet::PseudoJet> partSK = softkiller(selector(partPJ));
152
153 return findMinPt(partSK);
154}
155
157 vector<fastjet::PseudoJet> partPJ_ECal;
158 partPJ_ECal.reserve(cont.size());
159 vector<fastjet::PseudoJet> partPJ_HCal;
160 partPJ_HCal.reserve(cont.size());
161
162 for(xAOD::IParticle* part : cont){
163 // Only use positive E
164 bool accept = part->e() > 1e-9;
165 // For PFlow we would only want to apply the correction to neutral PFOs,
166 // because charged hadron subtraction handles the charged PFOs.
167 // However, we might still want to use the cPFOs for the min pt calculation
169 xAOD::PFO* pfo = static_cast<xAOD::PFO*>(part);
170 accept = !pfo->isCharged();
171 }
173 xAOD::TrackCaloCluster* tcc = static_cast<xAOD::TrackCaloCluster*>(part);
174 accept = (tcc->taste()!= 0);
175 }
177 xAOD::FlowElement* fe = static_cast<xAOD::FlowElement*>(part);
179 if(m_ignoreChargedPFOs) accept = !fe->isCharged();
180 }
181 else
182 accept = !fe->isCharged();
183 }
184 if(accept) {
185 double center_lambda = acc_clambda.isAvailable(*part) ? acc_clambda(*part) : 0.;
186 if( center_lambda < m_lambdaCalDivide) partPJ_ECal.emplace_back( part->p4() );
187 if( center_lambda >= m_lambdaCalDivide) partPJ_HCal.emplace_back( part->p4() );
188 }
189 }
190
191 fastjet::Selector selector = fastjet::SelectorAbsRapRange(m_rapmin, m_rapmax);
192 fastjet::RectangularGrid SKgridECal(-m_rapmax, m_rapmax, m_eCalGrid, m_eCalGrid, selector);
193 fastjet::contrib::SoftKiller softkillerECal(SKgridECal);
194 std::vector<fastjet::PseudoJet> partSK_ECal = softkillerECal(selector(partPJ_ECal));
195 double minPtECal = findMinPt(partSK_ECal);
196
197 fastjet::RectangularGrid SKgridHCal(-m_rapmax, m_rapmax, m_hCalGrid, m_hCalGrid, selector);
198 fastjet::contrib::SoftKiller softkillerHCal(SKgridHCal);
199 std::vector<fastjet::PseudoJet> partSK_HCal = softkillerHCal(selector(partPJ_HCal));
200 double minPtHCal = findMinPt(partSK_HCal);
201 return std::make_pair(minPtECal,minPtHCal);
202}
203
205 // If the particle pT is below the SoftKiller pT cut, rescale 4-momentum to 0
206 if( abs(part.eta()) < m_rapminApplied || abs(part.eta()) > m_rapmaxApplied) return 1;
207 if( part.pt() < minPt) return 0;
208 return 1;
209}
210
211
212float SoftKillerWeightTool::calculateSplitWeight(xAOD::IParticle& part, double minPtECal, double minPtHCal) const{
213 if( abs(part.eta()) < m_rapminApplied || abs(part.eta()) > m_rapmaxApplied) return 1;
214 double center_lambda = acc_clambda.isAvailable(part) ? acc_clambda(part) : 0.;
215
216 //Make a separate pT cut for the ECal and HCal
217 if( center_lambda < m_lambdaCalDivide && part.pt() < minPtECal) return 0;
218 if( part.pt() < minPtHCal) return 0;
219 return 1;
220}
221
222
223
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
size_type size() const noexcept
Returns the number of elements in the collection.
JetConstituentModifierBase(const std::string &name)
StatusCode setEnergyPt(xAOD::IParticle *obj, float e, float pt, const SG::AuxElement::Accessor< float > *weightAcc=nullptr) const
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:569
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
double getSoftKillerMinPt(xAOD::IParticleContainer &cont) const
SoftKillerWeightTool(const std::string &name)
StatusCode process_impl(xAOD::IParticleContainer *cont) const
float calculateSplitWeight(xAOD::IParticle &part, double minPtECal, double minPtHCal) const
std::pair< double, double > getSoftKillerMinPtSplit(xAOD::IParticleContainer &cont) const
double findMinPt(const std::vector< fastjet::PseudoJet > &partSK) const
StatusCode initialize()
Dummy implementation of the initialisation function.
float calculateWeight(xAOD::IParticle &part, double minPt) const
signal_t signalType() const
Class providing the definition of the 4-vector interface.
bool isCharged() const
is a charged PFO
Definition PFO_v1.cxx:251
virtual int taste() const
The taste of the particle.
STL namespace.
@ ParticleFlow
The object is a particle-flow object.
Definition ObjectType.h:41
@ FlowElement
The object is a track-calo-cluster.
Definition ObjectType.h:52
@ CaloCluster
The object is a calorimeter cluster.
Definition ObjectType.h:39
@ TrackCaloCluster
The object is a track-calo-cluster.
Definition ObjectType.h:51
PFO_v1 PFO
Definition of the current "pfo version".
Definition PFO.h:17
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition FlowElement.h:16
TrackCaloCluster_v1 TrackCaloCluster
Reference the current persistent version:
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.