CMS 3D CMS Logo

PuppiContainer.cc
Go to the documentation of this file.
3 #include "Math/ProbFunc.h"
4 #include "TMath.h"
5 #include <iostream>
6 #include <cmath>
9 
10 #include "fastjet/PseudoJet.hh"
11 
12 using namespace std;
13 
15  fPuppiDiagnostics = iConfig.getParameter<bool>("puppiDiagnostics");
16  fApplyCHS = iConfig.getParameter<bool>("applyCHS");
17  fInvert = iConfig.getParameter<bool>("invertPuppi");
18  fUseExp = iConfig.getParameter<bool>("useExp");
19  fPuppiWeightCut = iConfig.getParameter<double>("MinPuppiWeight");
20  fPtMax = iConfig.getParameter<double>("PtMaxNeutrals");
21  fPtMaxNeutralsStartSlope = iConfig.getParameter<double>("PtMaxNeutralsStartSlope");
22  std::vector<edm::ParameterSet> lAlgos = iConfig.getParameter<std::vector<edm::ParameterSet> >("algos");
23  fNAlgos = lAlgos.size();
24  for(unsigned int i0 = 0; i0 < lAlgos.size(); i0++) {
25  PuppiAlgo pPuppiConfig(lAlgos[i0]);
26  fPuppiAlgo.push_back(pPuppiConfig);
27  }
28 }
29 
30 void PuppiContainer::initialize(const std::vector<RecoObj> &iRecoObjects) {
31  //Clear everything
32  fPFParticles .resize(0);
33  fChargedPV .resize(0);
34  fPupParticles .resize(0);
35  fWeights .resize(0);
36  fVals.resize(0);
37  fRawAlphas.resize(0);
38  fAlphaMed .resize(0);
39  fAlphaRMS .resize(0);
40  fPVFrac = 0.;
41  fNPV = 1.;
42  //Link to the RecoObjects
43  fRecoParticles = &iRecoObjects;
44  fPFParticles.reserve(iRecoObjects.size());
45  fChargedPV.reserve(iRecoObjects.size());
46  fRecoToPup.clear();
47  fRecoToPup.reserve(fRecoParticles->size());
48  for (auto const& rParticle : *fRecoParticles){
49  // usage of fastjet::PseudoJet is only needed to enforce
50  // the no-change policy for backports (no numerical differences in outputs)
51  fastjet::PseudoJet curPseudoJet;
52  if (edm::isFinite(rParticle.rapidity)){
53  curPseudoJet.reset_PtYPhiM(rParticle.pt,rParticle.rapidity,rParticle.phi,rParticle.m);//hacked
54  } else {
55  curPseudoJet.reset_PtYPhiM(0, 99., 0, 0);//skipping may have been a better choice
56  }
57  int puppi_register = 0;
58  if(rParticle.id == 0 or rParticle.charge == 0) puppi_register = 0; // zero is neutral hadron
59  if(rParticle.id == 1 and rParticle.charge != 0) puppi_register = rParticle.charge; // from PV use the
60  if(rParticle.id == 2 and rParticle.charge != 0) puppi_register = rParticle.charge+5; // from NPV use the charge as key +5 as key
61  PuppiCandidate pCand;
62  pCand.id = rParticle.id;
63  pCand.puppi_register = puppi_register;
64  pCand.pt = curPseudoJet.pt();
65  pCand.rapidity = curPseudoJet.rap();
66  pCand.eta = curPseudoJet.eta();
67  pCand.phi = curPseudoJet.phi();
68  pCand.m = curPseudoJet.m();
69  pCand.px = curPseudoJet.px();
70  pCand.py = curPseudoJet.py();
71  pCand.pz = curPseudoJet.pz();
72  pCand.e = curPseudoJet.E();
73  // fill vector of pseudojets for internal references
74  fPFParticles.push_back(pCand);
75  //Take Charged particles associated to PV
76  if(std::abs(rParticle.id) == 1) fChargedPV.push_back(pCand);
77  if(std::abs(rParticle.id) >= 1 ) fPVFrac+=1.;
78  }
79  if (fPVFrac != 0) fPVFrac = double(fChargedPV.size())/fPVFrac;
80  else fPVFrac = 0;
81 }
83 
84 double PuppiContainer::goodVar(PuppiCandidate const &iPart,std::vector<PuppiCandidate> const &iParts, int iOpt,const double iRCone) {
85  return var_within_R(iOpt,iParts,iPart,iRCone);
86 }
87 
88 double PuppiContainer::var_within_R(int iId, const vector<PuppiCandidate> & particles, const PuppiCandidate& centre, const double R){
89  if (iId == -1)
90  return 1.;
91 
92  double const r2 = R * R;
93  double var = 0.;
94 
95  for (auto const &cand : particles) {
96  if (std::abs(cand.rapidity - centre.rapidity) < R) {
97  auto const dr2y = reco::deltaR2(cand.rapidity, cand.phi, centre.rapidity, centre.phi);
98  if (dr2y < r2) {
99  auto const dr2 = reco::deltaR2(cand.eta, cand.phi, centre.eta, centre.phi);
100  if (dr2 < 0.0001)
101  continue;
102  auto const pt = cand.pt;
103  switch (iId) {
104  case 5:
105  var += (pt * pt / dr2);
106  break;
107  case 4:
108  var += pt;
109  break;
110  case 3:
111  var += (1. / dr2);
112  break;
113  case 2:
114  var += (1. / dr2);
115  break;
116  case 1:
117  var += pt;
118  break;
119  case 0:
120  var += (pt / dr2);
121  break;
122  }
123  }
124  }
125  }
126 
127  if ((var != 0.) and ((iId == 0) or (iId == 3) or (iId == 5)))
128  var = log(var);
129  else if (iId == 1)
130  var += centre.pt;
131 
132  return var;
133 }
134 
135 //In fact takes the median not the average
136 void PuppiContainer::getRMSAvg(int iOpt,std::vector<PuppiCandidate> const &iConstits,std::vector<PuppiCandidate> const &iParticles,std::vector<PuppiCandidate> const &iChargedParticles) {
137  for(unsigned int i0 = 0; i0 < iConstits.size(); i0++ ) {
138  //Calculate the Puppi Algo to use
139  int pPupId = getPuppiId(iConstits[i0].pt,iConstits[i0].eta);
140  if(pPupId == -1 || fPuppiAlgo[pPupId].numAlgos() <= iOpt){
141  fVals.push_back(-1);
142  continue;
143  }
144  //Get the Puppi Sub Algo (given iteration)
145  int pAlgo = fPuppiAlgo[pPupId].algoId (iOpt);
146  bool pCharged = fPuppiAlgo[pPupId].isCharged(iOpt);
147  double pCone = fPuppiAlgo[pPupId].coneSize (iOpt);
148  // compute the Puppi metric:
149  // - calculate goodVar only for candidates that (1) will not be assigned a predefined weight (e.g 0, 1),
150  // or (2) are required for computations inside puppi-algos (see call to PuppiAlgo::add below)
151  double pVal = -1;
152  if (not(fApplyCHS and (iConstits[i0].id == 1 or iConstits[i0].id == 2))
153  or (std::abs(iConstits[i0].eta) < fPuppiAlgo[pPupId].etaMaxExtrap() and iConstits[i0].puppi_register != 0)) {
154  pVal = goodVar(iConstits[i0],pCharged ? iChargedParticles : iParticles,pAlgo,pCone);
155  }
156  fVals.push_back(pVal);
157 
158  if( ! edm::isFinite(pVal)) {
159  LogDebug( "NotFound" ) << "====> Value is Nan " << pVal << " == " << iConstits[i0].pt << " -- " << iConstits[i0].eta << endl;
160  continue;
161  }
162 
163  // code added by Nhan: now instead for every algorithm give it all the particles
164  for(int i1 = 0; i1 < fNAlgos; i1++){
165  // skip cands outside of algo's etaMaxExtrap, as they would anyway be ignored inside PuppiAlgo::add (see end of the block)
166  if(not(std::abs(iConstits[i0].eta) < fPuppiAlgo[i1].etaMaxExtrap() and iConstits[i0].puppi_register != 0))
167  continue;
168 
169  auto curVal = pVal;
170  // recompute goodVar if algo has changed
171  if (i1 != pPupId) {
172  pAlgo = fPuppiAlgo[i1].algoId (iOpt);
173  pCharged = fPuppiAlgo[i1].isCharged(iOpt);
174  pCone = fPuppiAlgo[i1].coneSize (iOpt);
175  curVal = goodVar(iConstits[i0],pCharged ? iChargedParticles : iParticles,pAlgo,pCone);
176  }
177 
178  fPuppiAlgo[i1].add(iConstits[i0],curVal,iOpt);
179  }
180  }
181  for(int i0 = 0; i0 < fNAlgos; i0++) fPuppiAlgo[i0].computeMedRMS(iOpt,fPVFrac);
182 }
183 
184 //In fact takes the median not the average
185 void PuppiContainer::getRawAlphas(int iOpt,std::vector<PuppiCandidate> const &iConstits,std::vector<PuppiCandidate> const &iParticles,std::vector<PuppiCandidate> const &iChargedParticles) {
186  for(int j0 = 0; j0 < fNAlgos; j0++){
187  for(unsigned int i0 = 0; i0 < iConstits.size(); i0++ ) {
188  //Get the Puppi Sub Algo (given iteration)
189  int pAlgo = fPuppiAlgo[j0].algoId (iOpt);
190  bool pCharged = fPuppiAlgo[j0].isCharged(iOpt);
191  double pCone = fPuppiAlgo[j0].coneSize (iOpt);
192  //Compute the Puppi Metric
193  double const pVal = goodVar(iConstits[i0],pCharged ? iChargedParticles : iParticles,pAlgo,pCone);
194  fRawAlphas.push_back(pVal);
195  if( ! edm::isFinite(pVal)) {
196  LogDebug( "NotFound" ) << "====> Value is Nan " << pVal << " == " << iConstits[i0].pt << " -- " << iConstits[i0].eta << endl;
197  continue;
198  }
199  }
200  }
201 }
202 int PuppiContainer::getPuppiId( float iPt, float iEta) {
203  int lId = -1;
204  for(int i0 = 0; i0 < fNAlgos; i0++) {
205  int nEtaBinsPerAlgo = fPuppiAlgo[i0].etaBins();
206  for (int i1 = 0; i1 < nEtaBinsPerAlgo; i1++){
207  if ( (std::abs(iEta) > fPuppiAlgo[i0].etaMin(i1)) && (std::abs(iEta) < fPuppiAlgo[i0].etaMax(i1)) ){
208  fPuppiAlgo[i0].fixAlgoEtaBin( i1 );
209  if(iPt > fPuppiAlgo[i0].ptMin()){
210  lId = i0;
211  break;
212  }
213  }
214  }
215  }
216  //if(lId == -1) std::cerr << "Error : Full fiducial range is not defined " << std::endl;
217  return lId;
218 }
219 double PuppiContainer::getChi2FromdZ(double iDZ) {
220  //We need to obtain prob of PU + (1-Prob of LV)
221  // Prob(LV) = Gaus(dZ,sigma) where sigma = 1.5mm (its really more like 1mm)
222  //double lProbLV = ROOT::Math::normal_cdf_c(std::abs(iDZ),0.2)*2.; //*2 is to do it double sided
223  //Take iDZ to be corrected by sigma already
224  double lProbLV = ROOT::Math::normal_cdf_c(std::abs(iDZ),1.)*2.; //*2 is to do it double sided
225  double lProbPU = 1-lProbLV;
226  if(lProbPU <= 0) lProbPU = 1e-16; //Quick Trick to through out infs
227  if(lProbPU >= 0) lProbPU = 1-1e-16; //Ditto
228  double lChi2PU = TMath::ChisquareQuantile(lProbPU,1);
229  lChi2PU*=lChi2PU;
230  return lChi2PU;
231 }
232 std::vector<double> const & PuppiContainer::puppiWeights() {
233  int lNParticles = fRecoParticles->size();
234 
235  fPupParticles .clear();
236  fPupParticles.reserve(lNParticles);
237  fWeights .clear();
238  fWeights.reserve(lNParticles);
239  fVals .clear();
240  fVals.reserve(lNParticles);
241  for(int i0 = 0; i0 < fNAlgos; i0++) fPuppiAlgo[i0].reset();
242 
243  int lNMaxAlgo = 1;
244  for(int i0 = 0; i0 < fNAlgos; i0++) lNMaxAlgo = std::max(fPuppiAlgo[i0].numAlgos(),lNMaxAlgo);
245  //Run through all compute mean and RMS
246  for(int i0 = 0; i0 < lNMaxAlgo; i0++) {
247  getRMSAvg(i0,fPFParticles,fPFParticles,fChargedPV);
248  }
249  if (fPuppiDiagnostics) getRawAlphas(0,fPFParticles,fPFParticles,fChargedPV);
250 
251  std::vector<double> pVals;
252  pVals.reserve(lNParticles);
253  for(int i0 = 0; i0 < lNParticles; i0++) {
254  //Refresh
255  pVals.clear();
256  double pWeight = 1;
257  //Get the Puppi Id and if ill defined move on
258  const auto& rParticle = (*fRecoParticles)[i0];
259  int pPupId = getPuppiId(rParticle.pt,rParticle.eta);
260  if(pPupId == -1) {
261  fWeights .push_back(pWeight);
262  fAlphaMed.push_back(-10);
263  fAlphaRMS.push_back(-10);
264  fRecoToPup.push_back(-1);
265  continue;
266  } else {
267  fRecoToPup.push_back(fPupParticles.size());//watch out: there should be no skips after this
268  }
269  // fill the p-values
270  double pChi2 = 0;
271  if(fUseExp){
272  //Compute an Experimental Puppi Weight with delta Z info (very simple example)
273  pChi2 = getChi2FromdZ(rParticle.dZ);
274  //Now make sure Neutrals are not set
275  if(rParticle.pfType > 3) pChi2 = 0;
276  }
277  //Fill and compute the PuppiWeight
278  int lNAlgos = fPuppiAlgo[pPupId].numAlgos();
279  for(int i1 = 0; i1 < lNAlgos; i1++) pVals.push_back(fVals[lNParticles*i1+i0]);
280 
281  pWeight = fPuppiAlgo[pPupId].compute(pVals,pChi2);
282  //Apply the CHS weights
283  if(rParticle.id == 1 && fApplyCHS ) pWeight = 1;
284  if(rParticle.id == 2 && fApplyCHS ) pWeight = 0;
285  //Basic Weight Checks
286  if( ! edm::isFinite(pWeight)) {
287  pWeight = 0.0;
288  LogDebug("PuppiWeightError") << "====> Weight is nan : " << pWeight << " : pt " << rParticle.pt << " -- eta : " << rParticle.eta << " -- Value" << fVals[i0] << " -- id : " << rParticle.id << " -- NAlgos: " << lNAlgos << std::endl;
289  }
290  //Basic Cuts
291  if(pWeight*fPFParticles[i0].pt < fPuppiAlgo[pPupId].neutralPt(fNPV) && rParticle.id == 0 ) pWeight = 0; //threshold cut on the neutral Pt
292  if((fPtMax>0) && (rParticle.id == 0))
293  pWeight = std::clamp((fPFParticles[i0].pt - fPtMaxNeutralsStartSlope) / (fPtMax - fPtMaxNeutralsStartSlope),
294  pWeight,
295  1.);
296  if(pWeight < fPuppiWeightCut) pWeight = 0; //==> Elminate the low Weight stuff
297  if(fInvert) pWeight = 1.-pWeight;
298  //std::cout << "rParticle.pt = " << rParticle.pt << ", rParticle.charge = " << rParticle.charge << ", rParticle.id = " << rParticle.id << ", weight = " << pWeight << std::endl;
299 
300  fWeights .push_back(pWeight);
301  fAlphaMed.push_back(fPuppiAlgo[pPupId].median());
302  fAlphaRMS.push_back(fPuppiAlgo[pPupId].rms());
303  //Now get rid of the thrown out weights for the particle collection
304 
305  // leave these lines in, in case want to move eventually to having no 1-to-1 correspondence between puppi and pf cands
306  // if( std::abs(pWeight) < std::numeric_limits<double>::denorm_min() ) continue; // this line seems not to work like it's supposed to...
307  // if(std::abs(pWeight) <= 0. ) continue;
308 
309  //Produce
310  PuppiCandidate curjet(fPFParticles[i0]);
311  curjet.pt *= pWeight;
312  curjet.m *= pWeight;
313  curjet.px *= pWeight;
314  curjet.py *= pWeight;
315  curjet.pz *= pWeight;
316  curjet.e *= pWeight;
317 
318  fPupParticles.push_back(curjet);
319  }
320  return fWeights;
321 }
#define LogDebug(id)
T getParameter(std::string const &) const
std::vector< double > const & puppiWeights()
double var_within_R(int iId, const std::vector< PuppiCandidate > &particles, const PuppiCandidate &centre, const double R)
double getChi2FromdZ(double iDZ)
constexpr bool isFinite(T x)
void getRMSAvg(int iOpt, std::vector< PuppiCandidate > const &iConstits, std::vector< PuppiCandidate > const &iParticles, std::vector< PuppiCandidate > const &iChargeParticles)
void getRawAlphas(int iOpt, std::vector< PuppiCandidate > const &iConstits, std::vector< PuppiCandidate > const &iParticles, std::vector< PuppiCandidate > const &iChargeParticles)
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
PuppiContainer(const edm::ParameterSet &iConfig)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
int getPuppiId(float iPt, float iEta)
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
double goodVar(PuppiCandidate const &iPart, std::vector< PuppiCandidate > const &iParts, int iOpt, const double iRCone)
void initialize(const std::vector< RecoObj > &iRecoObjects)
void reset(double vett[256])
Definition: TPedValues.cc:11