ATLAS Offline Software
VoronoiWeightTool.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 #include "fastjet/ClusterSequenceArea.hh"
7 #include "fastjet/Selector.hh"
8 #include "fastjet/JetDefinition.hh"
9 #include "fastjet/tools/JetMedianBackgroundEstimator.hh"
10 #include <fastjet/tools/Subtractor.hh>
11 
12 #include "xAODPFlow/PFO.h"
14 #include "xAODPFlow/FlowElement.h"
15 
16 namespace SortHelper {
17  //
18  // For Sorting
19  //
20  struct pt_sort
21  {
22 
23  inline bool operator() (const TLorentzVector& lhs, const TLorentzVector& rhs)
24  {
25  return (lhs.Pt() > rhs.Pt());
26  }
27 
28  inline bool operator() (const TLorentzVector* lhs, const TLorentzVector* rhs)
29  {
30  return (lhs->Pt() > rhs->Pt());
31  }
32 
33  inline bool operator() (const xAOD::IParticle& lhs, const xAOD::IParticle& rhs)
34  {
35  return (lhs.pt() > rhs.pt());
36  }
37 
38  inline bool operator() (const xAOD::IParticle* lhs, const xAOD::IParticle* rhs)
39  {
40  return (lhs->pt() > rhs->pt());
41  }
42  };
43 
44 
45  template<typename T>
46  T sort_container_pt(T* inCont) {
47  T sortedCont(SG::VIEW_ELEMENTS);
48  for(auto el : *inCont) sortedCont.push_back( el );
49  std::sort(sortedCont.begin(), sortedCont.end(), pt_sort());
50  return sortedCont;
51  }
52 
53  template<typename T>
54  const T sort_container_pt(const T* inCont) {
56 
57  for(auto el : *inCont) sortedCont.push_back( el );
58  std::sort(sortedCont.begin(), sortedCont.end(), pt_sort());
59  return *sortedCont.asDataVector();
60  }
61 
62  struct PJcomp {
63  bool operator() (const std::pair<fastjet::PseudoJet, std::vector<float> >& lhsp, const std::pair<fastjet::PseudoJet, std::vector<float> >& rhsp)
64  {
65  fastjet::PseudoJet lhs = lhsp.first;
66  fastjet::PseudoJet rhs = rhsp.first;
67  return lhs.pt()>rhs.pt();
68  //The comparator must be a strict weak ordering.
69  }
70  };
71 
72 
73 } // end SortHelper
74 
75 
78 {
79 
80  declareProperty("doSpread", m_doSpread);
81  declareProperty("nSigma", m_nSigma);
82  declareProperty("maxArea", m_maxArea);
83 
84  declareProperty("IgnoreChargedPFO", m_ignoreChargedPFOs);
85 }
86 
88 
90 
93  ATH_MSG_ERROR("Incompatible configuration: setting both IgnoreChargedPFO and ApplyToChargedPFO to true"
94  << "will set all cPFOs to zero");
95  return StatusCode::FAILURE;
96  }
97  if(!m_applyToNeutralPFO) {
98  ATH_MSG_ERROR("Incompatible configuration: ApplyToNeutralPFO=False -- what kind of pileup do you wish to suppress?");
99  return StatusCode::FAILURE;
100  }
101  }
102  return StatusCode::SUCCESS;
103 }
104 
105 //Have to define custom comparator for PseudoJets in order to have a map from PJs to anything
106 //Comparison is fuzzy to account for rounding errors
107 
109 {
110  std::vector<fastjet::PseudoJet> particles; particles.reserve(particlesin->size());
111 
112  for(xAOD::IParticle* part: *particlesin){
113  // Only use positive E
114  bool accept = part->e() > -1*FLT_MIN;
115  // For PFlow we would only want to apply the correction to neutral PFOs,
116  // because charged hadron subtraction handles the charged PFOs.
117  // However, we might still want to use the cPFOs for the min pt calculation
119  // The auto loop returns an ElementProxy, so we need to dereference/reference
120  const xAOD::PFO* pfo = static_cast<const xAOD::PFO*>(part);
121  accept &= fabs(pfo->charge())<FLT_MIN;
122  }
124  xAOD::TrackCaloCluster* tcc = static_cast<xAOD::TrackCaloCluster*>(part);
125  accept &= (tcc->taste()!= 0);
126  }
128  xAOD::FlowElement* fe = static_cast<xAOD::FlowElement*>(part);
130  if(m_ignoreChargedPFOs) accept &= !fe->isCharged();
131  }
132  else
133  accept &= !fe->isCharged();
134  }
135  if(accept) {
136  particles.emplace_back(part->p4() );
137  // ATH_MSG_VERBOSE( "Accepted particle with pt " << part->pt() );
138  }
139  }
140 
141  std::vector< std::pair< fastjet::PseudoJet, std::vector<float> > > ptvec; //vector of pairs of PJs and their corrected pTs
142  if(makeVoronoiParticles(particles, ptvec) != StatusCode::SUCCESS) ATH_MSG_ERROR("Error in makeVoronoiParticles");
143  std::sort(ptvec.begin(), ptvec.end(), SortHelper::PJcomp());
144 
145  if(m_doSpread && m_nSigma > 0) ATH_MSG_ERROR("Can't combine spreading with nSigma yet");
146  int alg;
147  if(m_doSpread && m_nSigma == 0) alg = 3;
148  if(!m_doSpread && m_nSigma == 0) alg = 1;
149  if(!m_doSpread && m_nSigma > 0) alg = 2;
150 
151  // This tracks the index of the object in the fastjet container
152  size_t i=0;
153  const static SG::AuxElement::Accessor<float> weightAcc("VoronoiWeight"); // Handle for PU weighting here
155  // Skip the check on charged PFOs if needed
156  // A subtle change in this check because fastjet will not return anything
157  // with <= 0 pt
158  bool accept = part->e() > FLT_MIN;
160  // The auto loop returns an ElementProxy, so we need to dereference/reference
161  const xAOD::PFO* pfo = static_cast<const xAOD::PFO*>(part);
162  accept &= fabs(pfo->charge())<FLT_MIN;
163  }
165  xAOD::TrackCaloCluster* tcc = static_cast<xAOD::TrackCaloCluster*>(part);
166  accept &= (tcc->taste()!= 0);
167  }
169  xAOD::FlowElement* fe = static_cast<xAOD::FlowElement*>(part);
171  if(m_ignoreChargedPFOs) accept &= !fe->isCharged();
172  }
173  else
174  accept &= !fe->isCharged();
175  }
176 
177  float newPt(0.);
178  if(accept) {
179  //There should be the same number of positive E particles in the container as particles in the ptvec
180  bool endContainer = part->e()<FLT_MIN;
181  bool endVec = i>=ptvec.size();
182  if(endVec && endContainer){
183  newPt = 0; //remove negative energy particles
184  }
185  else if(endContainer || endVec){
186  ATH_MSG_ERROR("Filtered particle list doesn't have same number of elements as the list returned by FastJet.");
187  return StatusCode::FAILURE;
188  }
189  else{
190  //And the particles should match
191  float Containerpt = part->pt();
192  float PJpt = ptvec[i].first.pt();
193  ATH_MSG_VERBOSE( "Container pt: " << Containerpt << ", fastjet initial pt: " << PJpt
194  << ", subtracted pt: " << ptvec[i].second[alg]);
195  if (fabs(Containerpt-PJpt) > 0.1){
196  ATH_MSG_VERBOSE( fabs(Containerpt-PJpt) );
197  ATH_MSG_ERROR("Particle pt's don't match.");
198  return StatusCode::FAILURE;
199  }
200  newPt = ptvec[i].second[alg];
201  }
202  ++i; // Only increment if the particle was used.
203  }
204  // Call set on every object
205  // Leave it to the base class to determine if the correction
206  // should not be applied
207  float w = part->pt()>FLT_MIN ? newPt/part->pt() : 0.;
208  ATH_CHECK(setEnergyPt(part,part->e()*w,newPt,&weightAcc));
209  }
210  return StatusCode::SUCCESS;
211  }
212 
213 StatusCode VoronoiWeightTool::makeVoronoiParticles(std::vector<fastjet::PseudoJet>& particles,std::vector< std::pair< fastjet::PseudoJet,std::vector<float> > >& correctedptvec) const{
214  std::vector<fastjet::PseudoJet> & inputConst = particles;
215  fastjet::Selector jselector = fastjet::SelectorAbsRapRange(0.0,2.1);
216  fastjet::JetAlgorithm algo = fastjet::kt_algorithm;
217  float jetR = 0.4;
218  fastjet::JetDefinition jetDef(algo, jetR,fastjet::E_scheme, fastjet::Best);
219  fastjet::AreaDefinition area_def(fastjet::voronoi_area, fastjet::VoronoiAreaSpec(0.9));
220 
221  fastjet::ClusterSequenceArea clustSeq(inputConst, jetDef, area_def);
222  fastjet::JetMedianBackgroundEstimator bge(jselector,jetDef,area_def);
223 
224  bge.set_particles(inputConst);
225  std::vector<fastjet::PseudoJet> inclusiveJets = sorted_by_pt(clustSeq.inclusive_jets(0));
226 
227  int nsigma = m_nSigma;
228  float rho = bge.rho();
229  float sigma = bge.sigma();
230  for(unsigned int iJet = 0 ; iJet < inclusiveJets.size() ; iJet++){
231  fastjet::PseudoJet jet = inclusiveJets[iJet];
232  std::vector<fastjet::PseudoJet> constituents = jet.constituents();
233  for(const auto& cons : constituents){
234  float pt = cons.pt();
235  // Allow a limit on the area to prevent over-subtraction in sparse regions
236  float area = m_maxArea<cons.area() ? m_maxArea : cons.area();
237  float subPt = pt-rho*area;
238  float voro0pt = subPt * (subPt > 0);
239  float voro1pt = subPt * (subPt > sqrt(area)*sigma*(float)nsigma);
240  std::vector<float> algopts;
241  algopts.push_back(subPt);
242  algopts.push_back(voro0pt);
243  algopts.push_back(voro1pt);
244  algopts.push_back(0);
245  std::pair <fastjet::PseudoJet,std::vector<float> > pjcptpair (cons,algopts);
246  correctedptvec.push_back(pjcptpair);
247  } // end loop over cons
248  } // end loop over jets
249 
250  if(m_doSpread) spreadPt(correctedptvec);
251 
252  return StatusCode::SUCCESS;
253 }
254 
255 void VoronoiWeightTool::spreadPt(std::vector< std::pair< fastjet::PseudoJet,std::vector<float> > >& correctedptvec, float spreadr, float alpha) const{
256  //default alpha = 2
257  //Set up neighbors within spreadr:
258  size_t Nparticles = correctedptvec.size();
259  std::vector<float> spreadPT(Nparticles);
260  std::vector<bool> isPositive(Nparticles);
261  for(size_t iPart = 0; iPart < Nparticles; iPart++){
262  spreadPT[iPart] = correctedptvec[iPart].second[0];
263  isPositive[iPart] = spreadPT[iPart]>0;
264  }
265 
266  std::vector<std::vector<std::pair<size_t,float> > > particle_drs; //for each particle, list of nearby positive pT particles and their distances
267  for(size_t iPart = 0; iPart < Nparticles; iPart++){
268  fastjet::PseudoJet iparticle = correctedptvec[iPart].first;
269  std::vector<std::pair<size_t,float> > this_particle_drs;
270  for(size_t jPart = 0; jPart < Nparticles; jPart++){
271  if(iPart == jPart) continue;
272  if(!isPositive[jPart]) continue;
273  fastjet::PseudoJet jparticle = correctedptvec[jPart].first;
274  float dphi = iparticle.delta_phi_to(jparticle);
275  float deta = iparticle.eta() - jparticle.eta(); //fastjet::pseudojet::delta_R(const PseudoJet& other) gives rap-phi distance
276  float dr2 = pow(dphi,2) + pow(deta,2);
277  if(dr2 > pow(spreadr,2)) continue;
278  std::pair<size_t,float> jdrpair (jPart,dr2);
279  this_particle_drs.push_back(jdrpair);
280  }
281  particle_drs.push_back(this_particle_drs);
282  }
283 
284  for(size_t i = 0; i < Nparticles; i++){
285  if(!(spreadPT[i]<0)) continue; //only spread from negative pT particles
286  //find closest positive PT particle:
287  float sumdR2 = 0;
288  //iterate over nearby positive pT particles
289  for(size_t j=0; j<particle_drs[i].size(); j++){
290  float dr = particle_drs[i][j].second;
291  if(dr>FLT_MIN) sumdR2 += 1./(pow(dr,alpha/2));
292  }
293  //if at least one neighbor
294  if(sumdR2 > FLT_MIN){
295  float spreadPT_orig = spreadPT[i];
296  for(size_t j=0; j<particle_drs[i].size(); j++){
297  float dr = particle_drs[i][j].second;
298  float realid = particle_drs[i][j].first;
299  if(dr>FLT_MIN){
300  float weight = (1./pow(dr,alpha/2))/sumdR2;
301  if(fabs(weight*spreadPT_orig)>spreadPT[realid]){
302  spreadPT[i]+=spreadPT[realid];
303  spreadPT[realid]=0;
304  }
305  else{
306  spreadPT[realid]+=weight*spreadPT_orig;
307  spreadPT[i]-=weight*spreadPT_orig;
308  }
309  }
310  }
311  }
312  }
313 
314  for(size_t iPart = 0; iPart < Nparticles; iPart++){
315  correctedptvec[iPart].second[3] = spreadPT[iPart] * (spreadPT[iPart] > 0);
316  }
317 }
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
JetConstituentModifierBase::m_applyToNeutralPFO
bool m_applyToNeutralPFO
Definition: JetConstituentModifierBase.h:63
SortHelper
Definition: VoronoiWeightTool.cxx:16
pdg_comparison.sigma
sigma
Definition: pdg_comparison.py:324
SGout2dot.alg
alg
Definition: SGout2dot.py:243
SortHelper::pt_sort
Definition: VoronoiWeightTool.cxx:21
SortHelper::PJcomp::operator()
bool operator()(const std::pair< fastjet::PseudoJet, std::vector< float > > &lhsp, const std::pair< fastjet::PseudoJet, std::vector< float > > &rhsp)
Definition: VoronoiWeightTool.cxx:63
xAOD::JetAlgorithmType::kt_algorithm
@ kt_algorithm
Definition: JetContainerInfo.h:31
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:66
SG::VIEW_ELEMENTS
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
Definition: OwnershipPolicy.h:18
ConstDataVector::end
iterator end() noexcept
Return an iterator pointing past the end of the collection.
VoronoiWeightTool::m_doSpread
bool m_doSpread
Definition: VoronoiWeightTool.h:50
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
xAOD::TrackCaloCluster_v1
Class describing a TrackCaloCluster.
Definition: TrackCaloCluster_v1.h:25
CutsMETMaker::accept
StatusCode accept(const xAOD::Muon *mu)
Definition: CutsMETMaker.cxx:18
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
TrackCaloCluster.h
VoronoiWeightTool::VoronoiWeightTool
VoronoiWeightTool(const std::string &name)
Definition: VoronoiWeightTool.cxx:76
test_pyathena.pt
pt
Definition: test_pyathena.py:11
VoronoiWeightTool::spreadPt
void spreadPt(std::vector< std::pair< fastjet::PseudoJet, std::vector< float > > > &correctedptvec, float spreadr=0.4, float alpha=2) const
Definition: VoronoiWeightTool.cxx:255
python.TurnDataReader.dr
dr
Definition: TurnDataReader.py:112
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:40
JetConstituentModifierBase::m_applyToChargedPFO
bool m_applyToChargedPFO
Definition: JetConstituentModifierBase.h:62
SortHelper::PJcomp
Definition: VoronoiWeightTool.cxx:62
ConstDataVector::asDataVector
const DV * asDataVector() const
Return a pointer to this object, as a const DataVector.
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:200
xAOD::TrackCaloCluster
TrackCaloCluster_v1 TrackCaloCluster
Reference the current persistent version:
Definition: TrackCaloCluster.h:12
xAOD::FlowElement_v1::PFlow
@ PFlow
Definition: FlowElement_v1.h:45
xAOD::FlowElement_v1::isCharged
bool isCharged() const
Definition: FlowElement_v1.cxx:56
PFO.h
CalculateHighPtTerm.jetDef
dictionary jetDef
Definition: ICHEP2016/CalculateHighPtTerm.py:28
VoronoiWeightTool::initialize
StatusCode initialize()
Dummy implementation of the initialisation function.
Definition: VoronoiWeightTool.cxx:89
jet
Definition: JetCalibTools_PlotJESFactors.cxx:23
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
FlowElement.h
lumiFormat.i
int i
Definition: lumiFormat.py:92
VoronoiWeightTool::~VoronoiWeightTool
~VoronoiWeightTool()
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
xAOD::FlowElement
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition: FlowElement.h:16
xAOD::PFO_v1::charge
float charge() const
get charge of PFO
SortHelper::pt_sort::operator()
bool operator()(const TLorentzVector &lhs, const TLorentzVector &rhs)
Definition: VoronoiWeightTool.cxx:23
xAOD::FlowElement_v1::signalType
signal_t signalType() const
plotIsoValidation.el
el
Definition: plotIsoValidation.py:197
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
xAODType::ParticleFlow
@ ParticleFlow
The object is a particle-flow object.
Definition: ObjectType.h:41
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
VoronoiWeightTool.h
xAOD::IParticle::pt
virtual double pt() const =0
The transverse momentum ( ) of the particle.
xAOD::PFO_v1
Class describing a particle flow object.
Definition: PFO_v1.h:35
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
JetConstituentModifierBase
Definition: JetConstituentModifierBase.h:22
ConstDataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
JetConstituentModifierBase::setEnergyPt
StatusCode setEnergyPt(xAOD::IParticle *obj, float e, float pt, const SG::AuxElement::Accessor< float > *weightAcc=nullptr) const
Definition: JetConstituentModifierBase.cxx:61
xAOD::TrackCaloCluster_v1::taste
virtual int taste() const
The taste of the particle.
VoronoiWeightTool::m_ignoreChargedPFOs
bool m_ignoreChargedPFOs
Definition: VoronoiWeightTool.h:57
JetConstituentModifierBase::m_inputType
unsigned int m_inputType
Definition: JetConstituentModifierBase.h:60
SortHelper::sort_container_pt
T sort_container_pt(T *inCont)
Definition: VoronoiWeightTool.cxx:46
ConstDataVector< T >
LArG4FSStartPointFilter.particles
list particles
Definition: LArG4FSStartPointFilter.py:84
VoronoiWeightTool::m_nSigma
int m_nSigma
Definition: VoronoiWeightTool.h:52
VoronoiWeightTool::m_maxArea
float m_maxArea
Definition: VoronoiWeightTool.h:54
area
double area(double R)
Definition: ConvertStaveServices.cxx:42
VoronoiWeightTool::makeVoronoiParticles
StatusCode makeVoronoiParticles(std::vector< fastjet::PseudoJet > &particles, std::vector< std::pair< fastjet::PseudoJet, std::vector< float > > > &) const
Definition: VoronoiWeightTool.cxx:213
python.IoTestsLib.w
def w
Definition: IoTestsLib.py:200
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
ConstDataVector::begin
iterator begin() noexcept
Return an iterator pointing at the beginning of the collection.
VoronoiWeightTool::process_impl
StatusCode process_impl(xAOD::IParticleContainer *cont) const
Definition: VoronoiWeightTool.cxx:108
readCCLHist.float
float
Definition: readCCLHist.py:83
fitman.rho
rho
Definition: fitman.py:532
xAOD::FlowElement_v1
A detector object made of other lower level object(s)
Definition: FlowElement_v1.h:25