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  if (iId == 5)
104  var += (pt * pt / dr2);
105  else if (iId == 4)
106  var += pt;
107  else if (iId == 3)
108  var += (1. / dr2);
109  else if (iId == 2)
110  var += (1. / dr2);
111  else if (iId == 1)
112  var += pt;
113  else if (iId == 0)
114  var += (pt / dr2);
115  }
116  }
117  }
118 
119  if ((var != 0.) and ((iId == 0) or (iId == 3) or (iId == 5)))
120  var = log(var);
121  else if (iId == 1)
122  var += centre.pt;
123 
124  return var;
125 }
126 
127 //In fact takes the median not the average
128 void PuppiContainer::getRMSAvg(int iOpt,std::vector<PuppiCandidate> const &iConstits,std::vector<PuppiCandidate> const &iParticles,std::vector<PuppiCandidate> const &iChargedParticles) {
129  for(unsigned int i0 = 0; i0 < iConstits.size(); i0++ ) {
130  //Calculate the Puppi Algo to use
131  int pPupId = getPuppiId(iConstits[i0].pt,iConstits[i0].eta);
132  if(pPupId == -1 || fPuppiAlgo[pPupId].numAlgos() <= iOpt){
133  fVals.push_back(-1);
134  continue;
135  }
136  //Get the Puppi Sub Algo (given iteration)
137  int pAlgo = fPuppiAlgo[pPupId].algoId (iOpt);
138  bool pCharged = fPuppiAlgo[pPupId].isCharged(iOpt);
139  double pCone = fPuppiAlgo[pPupId].coneSize (iOpt);
140  // compute the Puppi metric:
141  // - calculate goodVar only for candidates that (1) will not be assigned a predefined weight (e.g 0, 1),
142  // or (2) are required for computations inside puppi-algos (see call to PuppiAlgo::add below)
143  double pVal = -1;
144  if (not(fApplyCHS and (iConstits[i0].id == 1 or iConstits[i0].id == 2))
145  or (std::abs(iConstits[i0].eta) < fPuppiAlgo[pPupId].etaMaxExtrap() and iConstits[i0].puppi_register != 0)) {
146  pVal = goodVar(iConstits[i0],pCharged ? iChargedParticles : iParticles,pAlgo,pCone);
147  }
148  fVals.push_back(pVal);
149 
150  if( ! edm::isFinite(pVal)) {
151  LogDebug( "NotFound" ) << "====> Value is Nan " << pVal << " == " << iConstits[i0].pt << " -- " << iConstits[i0].eta << endl;
152  continue;
153  }
154 
155  // code added by Nhan: now instead for every algorithm give it all the particles
156  for(int i1 = 0; i1 < fNAlgos; i1++){
157  // skip cands outside of algo's etaMaxExtrap, as they would anyway be ignored inside PuppiAlgo::add (see end of the block)
158  if(not(std::abs(iConstits[i0].eta) < fPuppiAlgo[i1].etaMaxExtrap() and iConstits[i0].puppi_register != 0))
159  continue;
160 
161  auto curVal = pVal;
162  // recompute goodVar if algo has changed
163  if (i1 != pPupId) {
164  pAlgo = fPuppiAlgo[i1].algoId (iOpt);
165  pCharged = fPuppiAlgo[i1].isCharged(iOpt);
166  pCone = fPuppiAlgo[i1].coneSize (iOpt);
167  curVal = goodVar(iConstits[i0],pCharged ? iChargedParticles : iParticles,pAlgo,pCone);
168  }
169 
170  fPuppiAlgo[i1].add(iConstits[i0],curVal,iOpt);
171  }
172  }
173  for(int i0 = 0; i0 < fNAlgos; i0++) fPuppiAlgo[i0].computeMedRMS(iOpt,fPVFrac);
174 }
175 
176 //In fact takes the median not the average
177 void PuppiContainer::getRawAlphas(int iOpt,std::vector<PuppiCandidate> const &iConstits,std::vector<PuppiCandidate> const &iParticles,std::vector<PuppiCandidate> const &iChargedParticles) {
178  for(int j0 = 0; j0 < fNAlgos; j0++){
179  for(unsigned int i0 = 0; i0 < iConstits.size(); i0++ ) {
180  //Get the Puppi Sub Algo (given iteration)
181  int pAlgo = fPuppiAlgo[j0].algoId (iOpt);
182  bool pCharged = fPuppiAlgo[j0].isCharged(iOpt);
183  double pCone = fPuppiAlgo[j0].coneSize (iOpt);
184  //Compute the Puppi Metric
185  double const pVal = goodVar(iConstits[i0],pCharged ? iChargedParticles : iParticles,pAlgo,pCone);
186  fRawAlphas.push_back(pVal);
187  if( ! edm::isFinite(pVal)) {
188  LogDebug( "NotFound" ) << "====> Value is Nan " << pVal << " == " << iConstits[i0].pt << " -- " << iConstits[i0].eta << endl;
189  continue;
190  }
191  }
192  }
193 }
194 int PuppiContainer::getPuppiId( float iPt, float iEta) {
195  int lId = -1;
196  for(int i0 = 0; i0 < fNAlgos; i0++) {
197  int nEtaBinsPerAlgo = fPuppiAlgo[i0].etaBins();
198  for (int i1 = 0; i1 < nEtaBinsPerAlgo; i1++){
199  if ( (std::abs(iEta) > fPuppiAlgo[i0].etaMin(i1)) && (std::abs(iEta) < fPuppiAlgo[i0].etaMax(i1)) ){
200  fPuppiAlgo[i0].fixAlgoEtaBin( i1 );
201  if(iPt > fPuppiAlgo[i0].ptMin()){
202  lId = i0;
203  break;
204  }
205  }
206  }
207  }
208  //if(lId == -1) std::cerr << "Error : Full fiducial range is not defined " << std::endl;
209  return lId;
210 }
211 double PuppiContainer::getChi2FromdZ(double iDZ) {
212  //We need to obtain prob of PU + (1-Prob of LV)
213  // Prob(LV) = Gaus(dZ,sigma) where sigma = 1.5mm (its really more like 1mm)
214  //double lProbLV = ROOT::Math::normal_cdf_c(std::abs(iDZ),0.2)*2.; //*2 is to do it double sided
215  //Take iDZ to be corrected by sigma already
216  double lProbLV = ROOT::Math::normal_cdf_c(std::abs(iDZ),1.)*2.; //*2 is to do it double sided
217  double lProbPU = 1-lProbLV;
218  if(lProbPU <= 0) lProbPU = 1e-16; //Quick Trick to through out infs
219  if(lProbPU >= 0) lProbPU = 1-1e-16; //Ditto
220  double lChi2PU = TMath::ChisquareQuantile(lProbPU,1);
221  lChi2PU*=lChi2PU;
222  return lChi2PU;
223 }
224 std::vector<double> const & PuppiContainer::puppiWeights() {
225  int lNParticles = fRecoParticles->size();
226 
227  fPupParticles .clear();
228  fPupParticles.reserve(lNParticles);
229  fWeights .clear();
230  fWeights.reserve(lNParticles);
231  fVals .clear();
232  fVals.reserve(lNParticles);
233  for(int i0 = 0; i0 < fNAlgos; i0++) fPuppiAlgo[i0].reset();
234 
235  int lNMaxAlgo = 1;
236  for(int i0 = 0; i0 < fNAlgos; i0++) lNMaxAlgo = std::max(fPuppiAlgo[i0].numAlgos(),lNMaxAlgo);
237  //Run through all compute mean and RMS
238  for(int i0 = 0; i0 < lNMaxAlgo; i0++) {
239  getRMSAvg(i0,fPFParticles,fPFParticles,fChargedPV);
240  }
241  if (fPuppiDiagnostics) getRawAlphas(0,fPFParticles,fPFParticles,fChargedPV);
242 
243  std::vector<double> pVals;
244  pVals.reserve(lNParticles);
245  for(int i0 = 0; i0 < lNParticles; i0++) {
246  //Refresh
247  pVals.clear();
248  double pWeight = 1;
249  //Get the Puppi Id and if ill defined move on
250  const auto& rParticle = (*fRecoParticles)[i0];
251  int pPupId = getPuppiId(rParticle.pt,rParticle.eta);
252  if(pPupId == -1) {
253  fWeights .push_back(pWeight);
254  fAlphaMed.push_back(-10);
255  fAlphaRMS.push_back(-10);
256  fRecoToPup.push_back(-1);
257  continue;
258  } else {
259  fRecoToPup.push_back(fPupParticles.size());//watch out: there should be no skips after this
260  }
261  // fill the p-values
262  double pChi2 = 0;
263  if(fUseExp){
264  //Compute an Experimental Puppi Weight with delta Z info (very simple example)
265  pChi2 = getChi2FromdZ(rParticle.dZ);
266  //Now make sure Neutrals are not set
267  if(rParticle.pfType > 3) pChi2 = 0;
268  }
269  //Fill and compute the PuppiWeight
270  int lNAlgos = fPuppiAlgo[pPupId].numAlgos();
271  for(int i1 = 0; i1 < lNAlgos; i1++) pVals.push_back(fVals[lNParticles*i1+i0]);
272 
273  pWeight = fPuppiAlgo[pPupId].compute(pVals,pChi2);
274  //Apply the CHS weights
275  if(rParticle.id == 1 && fApplyCHS ) pWeight = 1;
276  if(rParticle.id == 2 && fApplyCHS ) pWeight = 0;
277  //Basic Weight Checks
278  if( ! edm::isFinite(pWeight)) {
279  pWeight = 0.0;
280  LogDebug("PuppiWeightError") << "====> Weight is nan : " << pWeight << " : pt " << rParticle.pt << " -- eta : " << rParticle.eta << " -- Value" << fVals[i0] << " -- id : " << rParticle.id << " -- NAlgos: " << lNAlgos << std::endl;
281  }
282  //Basic Cuts
283  if(pWeight*fPFParticles[i0].pt < fPuppiAlgo[pPupId].neutralPt(fNPV) && rParticle.id == 0 ) pWeight = 0; //threshold cut on the neutral Pt
284  if((fPtMax>0) && (rParticle.id == 0))
285  pWeight = std::clamp((fPFParticles[i0].pt - fPtMaxNeutralsStartSlope) / (fPtMax - fPtMaxNeutralsStartSlope),
286  pWeight,
287  1.);
288  if(pWeight < fPuppiWeightCut) pWeight = 0; //==> Elminate the low Weight stuff
289  if(fInvert) pWeight = 1.-pWeight;
290  //std::cout << "rParticle.pt = " << rParticle.pt << ", rParticle.charge = " << rParticle.charge << ", rParticle.id = " << rParticle.id << ", weight = " << pWeight << std::endl;
291 
292  fWeights .push_back(pWeight);
293  fAlphaMed.push_back(fPuppiAlgo[pPupId].median());
294  fAlphaRMS.push_back(fPuppiAlgo[pPupId].rms());
295  //Now get rid of the thrown out weights for the particle collection
296 
297  // leave these lines in, in case want to move eventually to having no 1-to-1 correspondence between puppi and pf cands
298  // if( std::abs(pWeight) < std::numeric_limits<double>::denorm_min() ) continue; // this line seems not to work like it's supposed to...
299  // if(std::abs(pWeight) <= 0. ) continue;
300 
301  //Produce
302  PuppiCandidate curjet(fPFParticles[i0]);
303  curjet.pt *= pWeight;
304  curjet.m *= pWeight;
305  curjet.px *= pWeight;
306  curjet.py *= pWeight;
307  curjet.pz *= pWeight;
308  curjet.e *= pWeight;
309 
310  fPupParticles.push_back(curjet);
311  }
312  return fWeights;
313 }
#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