ATLAS Offline Software
Loading...
Searching...
No Matches
JetIsolationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// JetIsolationTool.cxx
6
10//#include <sstream>
11#include <format>
12
13using std::string;
14using fastjet::PseudoJet;
15
16namespace jet {
17
18 namespace JetIsolation {
19
20 // **************************************************************************
21 // **************************************************************************
22 using FourMom_t = TLorentzVector;
23
24 TVector3 unitVector(const FourMom_t& v){
25 TVector3 v3 = v.Vect();
26 return (1/v3.Mag())*v3;
27 }
28
34 public:
35
39 };
40
42 static constexpr std::array<std::string_view, 6> s_kname = {"Pt","PtPUsub" , "SumPt", "Par", "Perp", "P"};
43
47 double isoSumPt = 0.0;
48 double isoArea = 0.;
49 };
50
51 virtual ~IsolationCalculator() = default;
52
53
54 virtual string baseName() const {return "";}
55 virtual IsolationCalculator * clone(const xAOD::Jet* ) const {return nullptr;}
56 virtual void copyFrom( const IsolationCalculator* o, const xAOD::Jet*){
58 }
59
60
63 virtual IsolationResult jetIsolation(const xAOD::Jet*, std::vector<const xAOD::IParticle*> & ) const {
64 return {};
65 }
66
67 bool scheduleKinematicCalculation(const std::string& kname){
68 auto it = std::ranges::find(s_kname, kname);
69 if( it != s_kname.end( )){
70 m_kinematics.push_back(static_cast<Kinematics>(it-s_kname.begin()) );
71 return true;
72 }
73 return false;
74 }
75
76
79 virtual std::vector<float>
80 calcIsolationVariables(const xAOD::Jet* jet, std::vector<const xAOD::IParticle*>& nearbyConstit) const {
81 IsolationResult result = jetIsolation(jet, nearbyConstit);
82 std::vector<float> calcVector;
83 float pt = jet->jetP4(xAOD::JetConstitScaleMomentum).pt();
84 static const SG::AuxElement::Accessor<float> areaAcc("ActiveArea");
85 float jetArea=0;
86 for(auto k : m_kinematics){
87 float v=-1;
88 switch( k ) {
89 case Pt:
90 v = result.isoP.Pt() / pt; break ;
91 case PtPUsub:
92 jetArea= areaAcc(*jet);
93 v = (result.isoP.Pt() - (result.isoArea-jetArea)*m_rho)/ (pt-jetArea*m_rho);
94 break;
95 case Perp:
96 v = result.isoP.Vect().Dot(unitVector(jet->p4())) /pt; break;
97 case SumPt:
98 v = result.isoSumPt; break;
99 case Par:
100 v = result.isoP.Vect().Perp(unitVector(jet->p4())) /pt ; break;
101 case P:
102 v = result.isoP.Vect().Mag()/pt; break ;
103 }
104 calcVector.push_back(v);
105 }
106 return calcVector;
107 }
108
109 virtual
110 std::vector<std::string> calculationNames() const {
111 std::vector<std::string> v;
112 v.reserve(m_kinematics.size());
113 for(auto k : m_kinematics) {
114 v.emplace_back(baseName() + string(s_kname[k]));
115 }
116 return v;
117 }
118
119
120 void dump() const {
121 std::cout << "Isolation calculator "<< baseName() <<std::endl;
122 for(const auto& n : calculationNames()){
123 std::cout << " - "<< n << std::endl;
124 }
125 }
126
127 void setEventDensity(float rho){
128 m_rho=rho;
129 }
130
131 protected:
133 std::vector<Kinematics> m_kinematics;
135 float m_rho=-9999.; // initialized to obviously wrong value.
136 };
137
138
139 template<typename ISOCRITERIA>
141 public:
142
143 IsolationCalculatorT(double param=0.) : m_iso(param) { }
144
145 virtual IsolationResult
146 jetIsolation(const xAOD::Jet* jet, std::vector<const xAOD::IParticle*> &nearbyConstit) const {
148 double rap = jet->rapidity();
149 double phi = jet->phi();
150 for(const xAOD::IParticle* constit:nearbyConstit){
151 if ( m_iso.inIsolationArea(rap, phi, constit) ) {
152 result.isoP += constit->p4();
153 result.isoSumPt += constit->pt();
154 }
155 }
156 result.isoArea = m_iso.isoArea();
157 return result;
158 }
159
160 virtual string baseName() const {return m_iso.name();}
161
162 virtual IsolationCalculator * clone(const xAOD::Jet* j) const {
164 isoT->m_iso = m_iso;
165 isoT->m_iso.setup(j);
166 isoT->copyFrom(this,j);
167 return isoT;
168 }
169
170 ISOCRITERIA m_iso;
171 };
172
173
178 IsolationAreaBase(double p, const string &n) : m_parameter(p), m_name(n){}
179
180 bool inIsolationArea(double rap, double phi, const xAOD::IParticle* part) const {
181 // we use eta rather than rapidity for constituents, because the later can generate FPE (presumably in very low pt PFlow constit)
182 double dr2 = xAOD::P4Helpers::deltaR2(rap, phi, part->rapidity(), part->phi());
183 return dr2 < m_deltaRmax2;
184 }
185
186 string name() const {
187 std::ostringstream oss; oss << m_name << int(10*m_parameter);
188 return oss.str();
189 }
190
191 double isoArea() const{
192 return m_deltaRmax2*M_PI;
193 }
194
196 string m_name;
197 double m_deltaRmax2 = 0.0;
198
199 };
200
201
202
203 // here we define a short cut to declare implementations of IsolationAreaBase classes.
204 // In most cases, only a definition of the max deltaR is enough to specify the area, hence these shortcuts.
205 // 1st parameter : class name
206 // 2nd parameter : code defining the max deltaR. Can use the variable 'param' representing the size parameter of this IsolationCalculator
207 // 3rd parameter (optional) : (re)-declaration of additional methods.
209#define ISOAREA( calcName, deltaRcode , additionalDecl ) struct calcName : public IsolationAreaBase { \
210 calcName(double p) : IsolationAreaBase(p, #calcName){} \
211 virtual void setup(const xAOD::Jet* j) {double jetRadius=j->getSizeParameter(); double param = m_parameter; m_deltaRmax2=deltaRcode ; m_deltaRmax2*=m_deltaRmax2; (void)(param+jetRadius);} additionalDecl }
212
213
214 ISOAREA( IsoKR , jetRadius*param, ) ;
215 ISOAREA( IsoDelta, jetRadius+param, ) ;
216 ISOAREA( IsoFixedCone, param, ) ;
217 ISOAREA( IsoFixedArea, sqrt(jetRadius*jetRadius+param*M_1_PI) , ) ;
218
219 // For Iso6To8 we need to redefine inIsolationArea
220 ISOAREA( Iso6To8, 0.8 , bool inIsolationArea(double rap, double phi, const xAOD::IParticle* constit)const ; ) ;
221 bool Iso6To8::inIsolationArea(double rap, double phi, const xAOD::IParticle* constit) const {
222 double dr2 = xAOD::P4Helpers::deltaR2(rap, phi, constit->rapidity(), constit->phi());
223 return ( (dr2<0.8*0.8) && (dr2>0.6*0.6) );
224 }
225
226
227 IsolationCalculator *createCalulator(const std::string& n, double parameter){
228
229 if( n == "IsoKR" ) return new IsolationCalculatorT<IsoKR>( parameter);
230 if( n == "IsoDelta" ) return new IsolationCalculatorT<IsoDelta>( parameter);
231 if( n == "IsoFixedCone" ) return new IsolationCalculatorT<IsoFixedCone>( parameter);
232 if( n == "IsoFixedArea" ) return new IsolationCalculatorT<IsoFixedArea>( parameter);
233 if( n == "Iso6To8" ) return new IsolationCalculatorT<Iso6To8>( parameter);
234
235 return nullptr;
236 }
237
238
239 } // namespace JetIsolation
240
242 void colonSplit(const string &in, string &s1, string &s2, string &s3){
243 s2=""; s3="";
244 std::stringstream str(in);
245 std::getline(str, s1, ':' );
246 std::getline(str, s2, ':');
247 std::getline(str, s3);
248 }
249
250
251} // namespace jet
252
253using namespace jet::JetIsolation;
254
255//**********************************************************************
256
258 : asg::AsgTool(name) {
259 declareInterface<IJetDecorator>(this);
260}
261
262//**********************************************************************
263
265
266//**********************************************************************
267
269 ATH_MSG_DEBUG ("Initializing " << name() << "...");
270
271 // a temporary map of isolation calculator
272 std::map<string, IsolationCalculator*> calcMap;
273
274 size_t nmom = m_isolationCodes.size();
275 // decode each isolation calculations as entered by properties
276 for ( size_t i=0; i<nmom; ++i ) {
277 string isocriteria, param_s, kinematic;
278 // decode the string passed as a property :
279 jet::colonSplit(m_isolationCodes[i], isocriteria, param_s, kinematic);
280 if( (param_s.empty())||(kinematic.empty())) {
281 ATH_MSG_ERROR(" Can't extract parameter values or kinematic code from "<<m_isolationCodes[i]);
282 return StatusCode::FAILURE;
283 }
284 string calcId = isocriteria + param_s;
285 // isocriteria + param_s defines a calculator which can then calculate several kinematics.
286 // check if this (isocriteria + param_s ) calculator has already been defined. If not do it now.
287 IsolationCalculator*& isoC = calcMap[calcId];
288 if ( isoC == nullptr ) {
289 isoC = createCalulator( isocriteria, std::stod(param_s)*0.1 );
290 }
291 if( isoC == nullptr ) {
292 ATH_MSG_ERROR(" Unkown isolation criteria "<< isocriteria << " from "<< m_isolationCodes[i] );
293 return StatusCode::FAILURE;
294 }
295 // add this kinematic for this calculator
296 bool ok = isoC->scheduleKinematicCalculation( kinematic);
297 if(!ok) {
298 ATH_MSG_ERROR(" Unkown isolation kinematic "<< kinematic << " from "<< m_isolationCodes[i] );
299 return StatusCode::FAILURE;
300 }
301 }
302
303 if(m_jetContainerName.empty()) {
304 ATH_MSG_ERROR("JetIsolationTool needs to have its input jet container configured!");
305 return StatusCode::FAILURE;
306 }
307
308 // Fill the iso calculator vector from the map
309 // Also fill DecorHandleKeyArrays at the same time
310 int ncalc=0;
311 for ( const auto& pair : calcMap ){
312 m_isoCalculators.push_back(pair.second);
313 ATH_MSG_DEBUG("Will use iso calculation : "<< pair.second->baseName() << " and variables :" );
314
315 for(const auto& kname: pair.second->calculationNames()){
316 ATH_MSG_DEBUG(" --> : "<< kname );
317 m_decorKeys.push_back(std::format("{}.{}", m_jetContainerName.value(), kname));
318 ncalc++;
319 }
320 }
321
322
323 ATH_MSG_INFO("Initialized JetIsolationTool " << name());
324 if ( m_inputConstitKey.empty() ) {
325 ATH_MSG_ERROR(" No input pseudojet collection supplied");
326 return StatusCode::FAILURE;
327 } else {
328 ATH_MSG_INFO(" Input pseudojet collection: " << m_inputConstitKey.key());
329 ATH_CHECK(m_inputConstitKey.initialize());
330 }
331 ATH_MSG_INFO(" Isolation calculations: " << m_isolationCodes);
332 ATH_MSG_DEBUG("Total num calculations="<<ncalc<< " ndecorations="<<m_decorKeys.size());
333
334 ATH_CHECK(m_decorKeys.initialize());
335
336 if(!m_rhoKey.empty()){
337 ATH_CHECK(m_rhoKey.initialize());
338 ATH_MSG_INFO(" Using EventDensity from: " << m_rhoKey.key());
339 }
340
341 return StatusCode::SUCCESS;
342}
343
344//**********************************************************************
345
346StatusCode JetIsolationTool::decorate(const xAOD::JetContainer& jets) const {
347
348
349 ATH_MSG_DEBUG("Modifying jets in container with size " << jets.size());
350 if ( jets.empty() ) return StatusCode::SUCCESS;
351
352 // Fetch the input pseudojets.
353 auto inputConstits = SG::makeHandle(m_inputConstitKey);
354 ATH_MSG_DEBUG("Retrieved input count is " << inputConstits->size());
355
356 // adapt the calculators to these jets (radius, input type, etc...)
357 // Since we're in a const method, we must create a copy of the calculators we own.
358 // We use the 1st jet, assuming all others in the container are similar.
359 std::vector<IsolationCalculator*> calculators; // the adapted calculators.
360 for( const IsolationCalculator * calc : m_isoCalculators ){
361 IsolationCalculator * cloned = calc->clone( jets[0] );
362 cloned->setEventDensity(0);
363 calculators.push_back( cloned );
364 }
365
366 // Retrieve and set EventDensity if needed
367 if(!m_rhoKey.empty()){
368 double rho=0;
370 if (! rhRhoKey->getDensity( xAOD::EventShape::Density, rho ) ) {
371 ATH_MSG_FATAL("Could not retrieve xAOD::EventShape::Density from xAOD::EventShape "<< m_rhoKey.key());
372 return StatusCode::FAILURE;
373 }
374 ATH_MSG_DEBUG("Rho = "<< rho);
375 for( IsolationCalculator * calc : calculators ) calc->setEventDensity(rho);
376 }
377
378 // This will hold all the constituents around a jet which are not constituents of the jet
379 std::vector<const xAOD::IParticle*> nearbyC;
380 nearbyC.reserve( inputConstits->size() );
381 const static SG::AuxElement::ConstAccessor<char> PVMatchedAcc("matchedToPV");
382 // Loop over jets in this collection.
383 for (const xAOD::Jet* jet : jets ) {
384
385 nearbyC.clear();
386 size_t nRejected=0;
387 const std::vector< ElementLink< xAOD::IParticleContainer > >& constitEL = jet->constituentLinks();
388
389 // Fill nearbyC: for now we take ALL constituents which not constituents of the jet.
390 // this is a lot and it may render subsequent iso calculation slower. If so it
391 // could be useful to use a fast look-up map to preselect constituents close to the jet (ex: within 2*jetRadius)
392 for(const xAOD::IParticle *part: (*inputConstits)){
393 if((part->e()<=0) || ( PVMatchedAcc.isAvailable(*part) && !PVMatchedAcc(*part) )){
394 nRejected++;
395 continue;
396 }
397 bool found = std::any_of(constitEL.begin(), constitEL.end(), [&part](const auto& link) { return part == *link; });
398 if(!found){
399 nearbyC.push_back(part);
400 }
401 }
402 if ( (nearbyC.size() + jet->numConstituents()+nRejected) != inputConstits->size() ) {
403 ATH_MSG_WARNING("Inconsistent number of jet constituents found in jet.");
404 }
405
406 ATH_MSG_DEBUG(jet->index()<< " # outside jet: " << nearbyC.size() << ", # rejected :"<< nRejected
407 << ", in jet: "<< jet->numConstituents()
408 << ", total: "<< inputConstits->size() );
409
410
411 // loop over calculators, calculate isolation given the close-by particles not part of the jet.
412 int c=0;
413 for(auto * isoCalc:calculators){
414 // perform all calculations with this isoCalc
415 std::vector<float> results = isoCalc->calcIsolationVariables(jet, nearbyC);
416 // decorate the jet with the calculated values
417 for( float value: results ) {
419 ATH_MSG_DEBUG(" decor "<< decorHandle.decorKey() << " " << value << " "<<c);
420 decorHandle(*jet) = value;
421 }
422 }
423 }
424
425 // clear calculators :
426 for ( IsolationCalculator* calc : calculators ) {
427 delete calc;
428 }
429
430 ATH_MSG_DEBUG("done");
431 return StatusCode::SUCCESS;
432}
433
434
435//**********************************************************************
436
438 ATH_MSG_DEBUG ("Finalizing " << name() << "...");
439 for( size_t i=0;i<m_isoCalculators.size(); i++){
440 delete m_isoCalculators[i];
441 }
442 return StatusCode::SUCCESS;
443}
444
#define M_PI
Scalar phi() const
phi method
#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_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define ISOAREA(calcName, deltaRcode, additionalDecl)
See below for example.
SG::WriteDecorHandleKeyArray< xAOD::JetContainer > m_decorKeys
Gaudi::Property< std::vector< std::string > > m_isolationCodes
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
JetIsolationTool(const std::string &myname)
Ctor.
virtual ~JetIsolationTool()
Dtor.
Gaudi::Property< std::string > m_jetContainerName
std::vector< jet::JetIsolation::IsolationCalculator * > m_isoCalculators
the list of isolation calculation objects (they are actually used only as template objects from which...
friend class jet::JetIsolation::IsolationCalculator
SG::ReadHandleKey< xAOD::IParticleContainer > m_inputConstitKey
SG::ReadHandleKey< xAOD::EventShape > m_rhoKey
virtual StatusCode finalize() override
virtual StatusCode decorate(const xAOD::JetContainer &jets) const override
Decorate a jet collection without otherwise modifying it.
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:569
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
Handle class for adding a decoration to an object.
const std::string & decorKey() const
Return the name of the decoration alias (CONT.DECOR).
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
virtual IsolationResult jetIsolation(const xAOD::Jet *jet, std::vector< const xAOD::IParticle * > &nearbyConstit) const
Compute the isolation 4-momentum from jet and jet inputs.
virtual IsolationCalculator * clone(const xAOD::Jet *j) const
IsolationCalculator : base class for isolation calculations Implementations of this class encapsulate...
bool scheduleKinematicCalculation(const std::string &kname)
virtual std::vector< float > calcIsolationVariables(const xAOD::Jet *jet, std::vector< const xAOD::IParticle * > &nearbyConstit) const
Implement the calculation of isolation variables for this jet.
float m_rho
Value of the event density in case it is needed.
static constexpr std::array< std::string_view, 6 > s_kname
names for isolation variables. Must match EXACTLY the enum.
virtual void copyFrom(const IsolationCalculator *o, const xAOD::Jet *)
virtual std::vector< std::string > calculationNames() const
std::vector< Kinematics > m_kinematics
kinematics isolation variables to be computed
virtual IsolationCalculator * clone(const xAOD::Jet *) const
Kinematics
Define the available isolation variables.
virtual IsolationResult jetIsolation(const xAOD::Jet *, std::vector< const xAOD::IParticle * > &) const
Compute the isolation 4-momentum from jet and jet inputs.
STL class.
Class providing the definition of the 4-vector interface.
virtual double rapidity() const =0
The true rapidity (y) of the particle.
virtual double phi() const =0
The azimuthal angle ( ) of the particle.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
IsolationCalculator * createCalulator(const std::string &n, double parameter)
TLorentzVector FourMom_t
TVector3 unitVector(const FourMom_t &v)
void colonSplit(const string &in, string &s1, string &s2, string &s3)
helper
double deltaR2(double rapidity1, double phi1, double rapidity2, double phi2)
from bare rapidity,phi
Jet_v1 Jet
Definition of the current "jet version".
@ JetConstitScaleMomentum
Definition JetTypes.h:29
JetContainer_v1 JetContainer
Definition of the current "jet container version".
bool inIsolationArea(double rap, double phi, const xAOD::IParticle *part) const
IsolationAreaBase(double p, const string &n)
Holds the 4-vector of all constituents contributing to isolation.