CMS 3D CMS Logo

PFEGammaAlgo.cc
Go to the documentation of this file.
25 
27 
28 #include <TFile.h>
29 #include <TVector2.h>
30 #include <iomanip>
31 #include <algorithm>
32 #include <functional>
33 #include <numeric>
34 #include <TMath.h>
35 
36 // include combinations header (was never incorporated in boost)
37 #include "combination.hpp"
38 
39 // just for now do this
40 //#define PFLOW_DEBUG
41 
42 #ifdef PFLOW_DEBUG
43 #define docast(x,y) dynamic_cast<x>(y)
44 #define LOGVERB(x) edm::LogVerbatim(x)
45 #define LOGWARN(x) edm::LogWarning(x)
46 #define LOGERR(x) edm::LogError(x)
47 #define LOGDRESSED(x) edm::LogInfo(x)
48 #else
49 #define docast(x,y) reinterpret_cast<x>(y)
50 #define LOGVERB(x) LogTrace(x)
51 #define LOGWARN(x) edm::LogWarning(x)
52 #define LOGERR(x) edm::LogError(x)
53 #define LOGDRESSED(x) LogDebug(x)
54 #endif
55 
56 using namespace std;
57 using namespace reco;
58 using namespace std::placeholders; // for _1, _2, _3...
59 
60 namespace {
61  typedef PFEGammaAlgo::PFSCElement SCElement;
62  typedef PFEGammaAlgo::EEtoPSAssociation EEtoPSAssociation;
63  typedef std::pair<CaloClusterPtr::key_type,CaloClusterPtr> EEtoPSElement;
64  typedef PFEGammaAlgo::PFClusterElement ClusterElement;
65  typedef PFEGammaAlgo::PFFlaggedElement PFFlaggedElement;
66  typedef PFEGammaAlgo::PFSCFlaggedElement SCFlaggedElement;
67  typedef PFEGammaAlgo::PFKFFlaggedElement KFFlaggedElement;
68  typedef PFEGammaAlgo::PFGSFFlaggedElement GSFFlaggedElement;
69  typedef PFEGammaAlgo::PFClusterFlaggedElement ClusterFlaggedElement;
70 
71  class SeedMatchesToProtoObject {
72  public:
73  SeedMatchesToProtoObject(const reco::ElectronSeedRef& s)
74  : scfromseed_(s->caloCluster().castTo<reco::SuperClusterRef>())
75  {
76  ispfsc_ = false;
77  if( scfromseed_.isNonnull() )
78  {
79  const edm::Ptr<reco::PFCluster> testCast(scfromseed_->seed());
80  ispfsc_ = testCast.isNonnull();
81  }
82  }
83  bool operator()(const PFEGammaAlgo::ProtoEGObject& po)
84  {
85  if( scfromseed_.isNull() || !po.parentSC ) return false;
86  if( ispfsc_ )
87  {
88  return ( scfromseed_->seed() == po.parentSC->superClusterRef()->seed() );
89  }
90  return ( scfromseed_->seed()->seed() == po.parentSC->superClusterRef()->seed()->seed() );
91  }
92 
93  private:
94  const reco::SuperClusterRef scfromseed_;
95  bool ispfsc_;
96  };
97 
98  template<bool useConvs=false>
99  bool elementNotCloserToOther(const reco::PFBlockRef& block,
100  const PFBlockElement::Type& keytype,
101  const size_t key,
102  const PFBlockElement::Type& valtype,
103  const size_t test,
104  const float EoPin_cut = 1.0e6) {
107  // this is inside out but I just want something that works right now
108  switch( keytype ) {
110  {
111  const reco::PFBlockElementGsfTrack* elemasgsf =
113  &(block->elements()[key]));
114  if( elemasgsf && valtype == PFBlockElement::ECAL ) {
115  const ClusterElement* elemasclus =
116  reinterpret_cast<const ClusterElement*>(&(block->elements()[test]));
117  float cluster_e = elemasclus->clusterRef()->correctedEnergy();
118  float trk_pin = elemasgsf->Pin().P();
119  if( cluster_e / trk_pin > EoPin_cut ) {
120  LOGDRESSED("elementNotCloserToOther")
121  << "GSF track failed EoP cut to match with cluster!";
122  return false;
123  }
124  }
125  }
126  break;
128  {
129  const reco::PFBlockElementTrack* elemaskf =
131  &(block->elements()[key]));
132  if( elemaskf && valtype == PFBlockElement::ECAL ) {
133  const ClusterElement* elemasclus =
134  reinterpret_cast<const ClusterElement*>(&(block->elements()[test]));
135  float cluster_e = elemasclus->clusterRef()->correctedEnergy();
136  float trk_pin =
137  std::sqrt(elemaskf->trackRef()->innerMomentum().mag2());
138  if( cluster_e / trk_pin > EoPin_cut ) {
139  LOGDRESSED("elementNotCloserToOther")
140  << "KF track failed EoP cut to match with cluster!";
141  return false;
142  }
143  }
144  }
145  break;
146  default:
147  break;
148  }
149 
150  const float dist =
151  block->dist(key,test,block->linkData(),reco::PFBlock::LINKTEST_ALL);
152  if( dist == -1.0f ) return false; // don't associate non-linked elems
153  std::multimap<double, unsigned> dists_to_val;
154  block->associatedElements(test,block->linkData(),dists_to_val,keytype,
156 
157  for( const auto& valdist : dists_to_val ) {
158  const size_t idx = valdist.second;
159  // check track types for conversion info
160  switch( keytype ) {
162  {
163  const reco::PFBlockElementGsfTrack* elemasgsf =
165  &(block->elements()[idx]));
166  if( !useConvs && elemasgsf->trackType(ConvType) ) return false;
167  if( elemasgsf && valtype == PFBlockElement::ECAL ) {
168  const ClusterElement* elemasclus =
169  docast(const ClusterElement*,&(block->elements()[test]));
170  float cluster_e = elemasclus->clusterRef()->correctedEnergy();
171  float trk_pin = elemasgsf->Pin().P();
172  if( cluster_e / trk_pin > EoPin_cut ) continue;
173  }
174  }
175  break;
177  {
178  const reco::PFBlockElementTrack* elemaskf =
180  &(block->elements()[idx]));
181  if( !useConvs && elemaskf->trackType(ConvType) ) return false;
182  if( elemaskf && valtype == PFBlockElement::ECAL ) {
183  const ClusterElement* elemasclus =
184  reinterpret_cast<const ClusterElement*>(&(block->elements()[test]));
185  float cluster_e = elemasclus->clusterRef()->correctedEnergy();
186  float trk_pin =
187  std::sqrt(elemaskf->trackRef()->innerMomentum().mag2());
188  if( cluster_e / trk_pin > EoPin_cut ) continue;
189  }
190  }
191  break;
192  default:
193  break;
194  }
195  if( valdist.first < dist && idx != key ) {
196  LOGDRESSED("elementNotCloserToOther")
197  << "key element of type " << keytype
198  << " is closer to another element of type" << valtype
199  << std::endl;
200  return false; // false if closer element of specified type found
201  }
202  }
203  return true;
204  }
205 
206  bool compatibleEoPOut(const PFFlaggedElement& e, const reco::PFBlockElementGsfTrack* comp)
207  {
208  if( PFBlockElement::ECAL != e.first->type() )
209  {
210  return false;
211  }
212  const ClusterElement* elemascluster = docast(const ClusterElement*,e.first);
213  const float gsf_eta_diff = std::abs(comp->positionAtECALEntrance().eta() - comp->Pout().eta());
214  const reco::PFClusterRef& cRef = elemascluster->clusterRef();
215  return ( gsf_eta_diff <= 0.3 && cRef->energy()/comp->Pout().t() <= 5 );
216  }
217 
218  bool isConversionTrack(const PFFlaggedElement& e)
219  {
221  const reco::PFBlockElementTrack* elemastrk = docast(const reco::PFBlockElementTrack*,e.first);
222  return elemastrk->trackType(ConvType);
223  }
224 
225 
226  template<PFBlockElement::Type keytype,
227  PFBlockElement::Type valtype,
228  bool useConv=false>
229 
230  struct NotCloserToOther {
231  const reco::PFBlockElement* comp;
232  const reco::PFBlockRef& block;
233  const float EoPin_cut;
234  NotCloserToOther(const reco::PFBlockRef& b,
235  const reco::PFBlockElement* e,
236  const float EoPcut=1.0e6): comp(e),
237  block(b),
238  EoPin_cut(EoPcut) {
239  }
240  bool operator () (const PFFlaggedElement& e) {
241  if( !e.second || valtype != e.first->type() ) return false;
242  return elementNotCloserToOther<useConv>(block,
243  keytype,comp->index(),
244  valtype,e.first->index(),
245  EoPin_cut);
246  }
247  };
248 
249  struct LesserByDistance {
250  const reco::PFBlockElement* comp;
251  const reco::PFBlockRef& block;
252  const reco::PFBlock::LinkData& links;
253  LesserByDistance(const reco::PFBlockRef& b,
254  const reco::PFBlock::LinkData& l,
255  const reco::PFBlockElement* e): comp(e),
256  block(b),
257  links(l) {}
258  bool operator () (const PFFlaggedElement& e1,
259  const PFFlaggedElement& e2) {
260  double dist1 = block->dist(comp->index(),
261  e1.first->index(),
262  links,
264  double dist2 = block->dist(comp->index(),
265  e2.first->index(),
266  links,
268  dist1 = ( dist1 == -1.0 ? 1e6 : dist1 );
269  dist2 = ( dist2 == -1.0 ? 1e6 : dist2 );
270  return dist1 < dist2;
271  }
272  };
273 
274  bool isROLinkedByClusterOrTrack(const PFEGammaAlgo::ProtoEGObject& RO1,
275  const PFEGammaAlgo::ProtoEGObject& RO2 ) {
276  // also don't allow ROs where both have clusters
277  // and GSF tracks to merge (10 Dec 2013)
278  if(!RO1.primaryGSFs.empty() && !RO2.primaryGSFs.empty()) {
279  LOGDRESSED("isROLinkedByClusterOrTrack")
280  << "cannot merge, both have GSFs!" << std::endl;
281  return false;
282  }
283  // don't allow EB/EE to mix (11 Sept 2013)
284  if( !RO1.ecalclusters.empty() && !RO2.ecalclusters.empty() ) {
285  if(RO1.ecalclusters.front().first->clusterRef()->layer() !=
286  RO2.ecalclusters.front().first->clusterRef()->layer() ) {
287  LOGDRESSED("isROLinkedByClusterOrTrack")
288  << "cannot merge, different ECAL types!" << std::endl;
289  return false;
290  }
291  }
292  const reco::PFBlockRef& blk = RO1.parentBlock;
293  bool not_closer;
294  // check links track -> cluster
295  for( const auto& cluster: RO1.ecalclusters ) {
296  for( const auto& primgsf : RO2.primaryGSFs ) {
297  not_closer =
298  elementNotCloserToOther(blk,
299  cluster.first->type(),
300  cluster.first->index(),
301  primgsf.first->type(),
302  primgsf.first->index());
303  if( not_closer ) {
304  LOGDRESSED("isROLinkedByClusterOrTrack")
305  << "merged by cluster to primary GSF" << std::endl;
306  return true;
307  } else {
308  LOGDRESSED("isROLinkedByClusterOrTrack")
309  << "cluster to primary GSF failed since"
310  << " cluster closer to another GSF" << std::endl;
311  }
312  }
313  for( const auto& primkf : RO2.primaryKFs) {
314  not_closer =
315  elementNotCloserToOther(blk,
316  cluster.first->type(),
317  cluster.first->index(),
318  primkf.first->type(),
319  primkf.first->index());
320  if( not_closer ) {
321  LOGDRESSED("isROLinkedByClusterOrTrack")
322  << "merged by cluster to primary KF" << std::endl;
323  return true;
324  }
325  }
326  for( const auto& secdkf : RO2.secondaryKFs) {
327  not_closer =
328  elementNotCloserToOther(blk,
329  cluster.first->type(),
330  cluster.first->index(),
331  secdkf.first->type(),
332  secdkf.first->index());
333  if( not_closer ) {
334  LOGDRESSED("isROLinkedByClusterOrTrack")
335  << "merged by cluster to secondary KF" << std::endl;
336  return true;
337  }
338  }
339  // check links brem -> cluster
340  for( const auto& brem : RO2.brems ) {
341  not_closer = elementNotCloserToOther(blk,
342  cluster.first->type(),
343  cluster.first->index(),
344  brem.first->type(),
345  brem.first->index());
346  if( not_closer ) {
347  LOGDRESSED("isROLinkedByClusterOrTrack")
348  << "merged by cluster to brem KF" << std::endl;
349  return true;
350  }
351  }
352  }
353  // check links primary gsf -> secondary kf
354  for( const auto& primgsf : RO1.primaryGSFs ) {
355  for( const auto& secdkf : RO2.secondaryKFs) {
356  not_closer =
357  elementNotCloserToOther(blk,
358  primgsf.first->type(),
359  primgsf.first->index(),
360  secdkf.first->type(),
361  secdkf.first->index());
362  if( not_closer ) {
363  LOGDRESSED("isROLinkedByClusterOrTrack")
364  << "merged by GSF to secondary KF" << std::endl;
365  return true;
366  }
367  }
368  }
369  // check links primary kf -> secondary kf
370  for( const auto& primkf : RO1.primaryKFs ) {
371  for( const auto& secdkf : RO2.secondaryKFs) {
372  not_closer =
373  elementNotCloserToOther(blk,
374  primkf.first->type(),
375  primkf.first->index(),
376  secdkf.first->type(),
377  secdkf.first->index());
378  if( not_closer ) {
379  LOGDRESSED("isROLinkedByClusterOrTrack")
380  << "merged by primary KF to secondary KF" << std::endl;
381  return true;
382  }
383  }
384  }
385  // check links secondary kf -> secondary kf
386  for( const auto& secdkf1 : RO1.secondaryKFs ) {
387  for( const auto& secdkf2 : RO2.secondaryKFs) {
388  not_closer =
389  elementNotCloserToOther<true>(blk,
390  secdkf1.first->type(),
391  secdkf1.first->index(),
392  secdkf2.first->type(),
393  secdkf2.first->index());
394  if( not_closer ) {
395  LOGDRESSED("isROLinkedByClusterOrTrack")
396  << "merged by secondary KF to secondary KF" << std::endl;
397  return true;
398  }
399  }
400  }
401  return false;
402  }
403 
404  bool testIfROMergableByLink(const PFEGammaAlgo::ProtoEGObject& ro, PFEGammaAlgo::ProtoEGObject& comp)
405  {
406  const bool result = ( isROLinkedByClusterOrTrack(comp,ro) || isROLinkedByClusterOrTrack(ro,comp) );
407  return result;
408  }
409 
410  std::vector<const ClusterElement*>
411  getSCAssociatedECALsSafe(const reco::SuperClusterRef& scref,
412  std::vector<PFFlaggedElement>& ecals) {
413  std::vector<const ClusterElement*> cluster_list;
414  auto sccl = scref->clustersBegin();
415  auto scend = scref->clustersEnd();
416  auto pfc = ecals.begin();
417  auto pfcend = ecals.end();
418  for( ; sccl != scend; ++sccl ) {
419  std::vector<const ClusterElement*> matched_pfcs;
420  const double eg_energy = (*sccl)->energy();
421 
422  for( pfc = ecals.begin(); pfc != pfcend; ++pfc ) {
423  const ClusterElement *pfcel =
424  docast(const ClusterElement*, pfc->first);
425  const bool matched =
426  ClusterClusterMapping::overlap(**sccl,*(pfcel->clusterRef()));
427  // need to protect against high energy clusters being attached
428  // to low-energy SCs
429  if( matched && pfcel->clusterRef()->energy() < 1.2*scref->energy()) {
430  matched_pfcs.push_back(pfcel);
431  }
432  }
433  std::sort(matched_pfcs.begin(),matched_pfcs.end());
434 
435  double min_residual = 1e6;
436  std::vector<const ClusterElement*> best_comb;
437  for( size_t i = 1; i <= matched_pfcs.size(); ++i ) {
438  //now we find the combination of PF-clusters which
439  //has the smallest energy residual with respect to the
440  //EG-cluster we are looking at now
441  do {
442  double energy = std::accumulate(matched_pfcs.begin(),
443  matched_pfcs.begin()+i,
444  0.0,
445  [](const double a,
446  const ClusterElement* c)
447  { return a + c->clusterRef()->energy(); });
448  const double resid = std::abs(energy - eg_energy);
449  if( resid < min_residual ) {
450  best_comb.clear();
451  best_comb.reserve(i);
452  min_residual = resid;
453  best_comb.insert(best_comb.begin(),
454  matched_pfcs.begin(),
455  matched_pfcs.begin()+i);
456  }
457  }while(notboost::next_combination(matched_pfcs.begin(),
458  matched_pfcs.begin()+i,
459  matched_pfcs.end()));
460  }
461  for( const auto& clelem : best_comb ) {
462  if( std::find(cluster_list.begin(),cluster_list.end(),clelem) ==
463  cluster_list.end() ) {
464  cluster_list.push_back(clelem);
465  }
466  }
467  }
468  return cluster_list;
469  }
470  bool addPFClusterToROSafe(const ClusterElement* cl,
472  if( RO.ecalclusters.empty() ) {
473  RO.ecalclusters.emplace_back(cl,true);
474  return true;
475  } else {
476  const PFLayer::Layer clayer = cl->clusterRef()->layer();
477  const PFLayer::Layer blayer =
478  RO.ecalclusters.back().first->clusterRef()->layer();
479  if( clayer == blayer ) {
480  RO.ecalclusters.emplace_back(cl,true);
481  return true;
482  }
483  }
484  return false;
485  }
486 
487  // sets the cluster best associated to the GSF track
488  // leave it null if no GSF track
489  void setROElectronCluster(PFEGammaAlgo::ProtoEGObject& RO) {
490  if( RO.ecalclusters.empty() ) return;
491  RO.lateBrem = -1;
492  RO.firstBrem = -1;
493  RO.nBremsWithClusters = -1;
494  const reco::PFBlockElementBrem *firstBrem = nullptr, *lastBrem = nullptr;
495  const reco::PFBlockElementCluster *bremCluster = nullptr, *gsfCluster = nullptr,
496  *kfCluster = nullptr, *gsfCluster_noassc = nullptr;
497  const reco::PFBlockRef& parent = RO.parentBlock;
498  int nBremClusters = 0;
499  constexpr float maxDist = 1e6;
500  float mDist_gsf(maxDist), mDist_gsf_noassc(maxDist), mDist_kf(maxDist);
501  for( const auto& cluster : RO.ecalclusters ) {
502  for( const auto& gsf : RO.primaryGSFs ) {
503  const bool hasclu = elementNotCloserToOther(parent,
504  gsf.first->type(),
505  gsf.first->index(),
506  cluster.first->type(),
507  cluster.first->index());
508  const float deta =
509  std::abs(cluster.first->clusterRef()->positionREP().eta() -
510  gsf.first->positionAtECALEntrance().eta());
511  const float dphi =
512  std::abs(TVector2::Phi_mpi_pi(
513  cluster.first->clusterRef()->positionREP().phi() -
514  gsf.first->positionAtECALEntrance().phi()));
515  const float dist = std::hypot(deta,dphi);
516  if( hasclu && dist < mDist_gsf ) {
517  gsfCluster = cluster.first;
518  mDist_gsf = dist;
519  } else if ( dist < mDist_gsf_noassc ) {
520  gsfCluster_noassc = cluster.first;
521  mDist_gsf_noassc = dist;
522  }
523  }
524  for( const auto& kf : RO.primaryKFs ) {
525  const bool hasclu = elementNotCloserToOther(parent,
526  kf.first->type(),
527  kf.first->index(),
528  cluster.first->type(),
529  cluster.first->index());
530  const float dist = parent->dist(cluster.first->index(),
531  kf.first->index(),
532  parent->linkData(),
534  if( hasclu && dist < mDist_kf ) {
535  kfCluster = cluster.first;
536  mDist_kf = dist;
537  }
538  }
539  for( const auto& brem : RO.brems ) {
540  const bool hasclu = elementNotCloserToOther(parent,
541  brem.first->type(),
542  brem.first->index(),
543  cluster.first->type(),
544  cluster.first->index());
545  if( hasclu ) {
546  ++nBremClusters;
547  if( !firstBrem ||
548  ( firstBrem->indTrajPoint() - 2 >
549  brem.first->indTrajPoint() - 2) ) {
550  firstBrem = brem.first;
551  }
552  if( !lastBrem ||
553  ( lastBrem->indTrajPoint() - 2 <
554  brem.first->indTrajPoint() - 2) ) {
555  lastBrem = brem.first;
556  bremCluster = cluster.first;
557  }
558  }
559  }
560  }
561  if( !gsfCluster && !kfCluster && !bremCluster ) {
562  gsfCluster = gsfCluster_noassc;
563  }
564  RO.nBremsWithClusters = nBremClusters;
565  RO.lateBrem = 0;
566  if( gsfCluster ) {
567  RO.electronClusters.push_back(gsfCluster);
568  } else if ( kfCluster ) {
569  RO.electronClusters.push_back(kfCluster);
570  }
571  if( bremCluster && !gsfCluster && !kfCluster ) {
572  RO.electronClusters.push_back(bremCluster);
573  }
574  if( firstBrem && RO.ecalclusters.size() > 1 ) {
575  RO.firstBrem = firstBrem->indTrajPoint() - 2;
576  if( bremCluster == gsfCluster ) RO.lateBrem = 1;
577  }
578  }
579 }
580 
583 {}
584 
586  const reco::PFBlockRef& blockRef,
587  const reco::Vertex& primaryVtx,
588  unsigned int trackIndex)
589 {
590  const reco::PFBlock& block = *blockRef;
592  //use this to store linkdata in the associatedElements function below
593  const PFBlock::LinkData& linkData = block.linkData();
594  //calculate MVA Variables
595  const float chi2 = elements[trackIndex].trackRef()->chi2()/elements[trackIndex].trackRef()->ndof();
596  const float nlost = elements[trackIndex].trackRef()->hitPattern().numberOfLostHits(HitPattern::MISSING_INNER_HITS);
597  const float nLayers = elements[trackIndex].trackRef()->hitPattern().trackerLayersWithMeasurement();
598  const float trackPt = elements[trackIndex].trackRef()->pt();
599  const float stip = elements[trackIndex].trackRefPF()->STIP();
600 
601  float linkedE = 0;
602  float linkedH = 0;
603  std::multimap<double, unsigned int> ecalAssoTrack;
604  block.associatedElements(trackIndex,linkData,
605  ecalAssoTrack,
608  std::multimap<double, unsigned int> hcalAssoTrack;
609  block.associatedElements(trackIndex,linkData,
610  hcalAssoTrack,
613  if(!ecalAssoTrack.empty())
614  {
615  for (auto & itecal : ecalAssoTrack)
616  {
617  linkedE = linkedE+elements[itecal.second].clusterRef()->energy();
618  }
619  }
620  if(!hcalAssoTrack.empty())
621  {
622  for (auto & ithcal : hcalAssoTrack)
623  {
624  linkedH = linkedH+elements[ithcal.second].clusterRef()->energy();
625  }
626  }
627  const float eOverPt = linkedE / elements[trackIndex].trackRef()->pt();
628  const float hOverPt = linkedH / elements[trackIndex].trackRef()->pt();
629  GlobalVector rvtx(elements[trackIndex].trackRef()->innerPosition().X()-primaryVtx.x(),
630  elements[trackIndex].trackRef()->innerPosition().Y()-primaryVtx.y(),
631  elements[trackIndex].trackRef()->innerPosition().Z()-primaryVtx.z());
632  double vtxPhi = rvtx.phi();
633  //delta Phi between conversion vertex and track
634  float delPhi = fabs(deltaPhi(vtxPhi, elements[trackIndex].trackRef()->innerMomentum().Phi()));
635 
636  float vars[] = { delPhi, nLayers, chi2, eOverPt,
637  hOverPt, trackPt, stip, nlost };
638 
639  return hoc->gbrSingleLeg_->GetAdaBoostClassifier(vars);
640 }
641 
643  switch( pfbe.type() ) {
645  {
646  auto& elements = _currentblock->elements();
647  std::multimap<double,unsigned> tks;
648  _currentblock->associatedElements(pfbe.index(),
650  tks,
653  for( const auto& tk : tks ) {
654  if( PFMuonAlgo::isMuon(elements[tk.second]) ) {
655  return true;
656  }
657  }
658  }
659  break;
661  return PFMuonAlgo::isMuon(pfbe);
662  break;
663  default:
664  break;
665  }
666  return false;
667 }
668 
670  const reco::PFBlockRef& block) {
671  LOGVERB("PFEGammaAlgo")
672  << "Resetting PFEGammaAlgo for new block and running!" << std::endl;
673  _splayedblock.clear();
674  _refinableObjects.clear();
675  _splayedblock.resize(13); // make sure that we always have the HGCAL entry
676 
678  _currentlinks = block->linkData();
679  //LOGDRESSED("PFEGammaAlgo") << *_currentblock << std::endl;
680  LOGVERB("PFEGammaAlgo") << "Splaying block" << std::endl;
681  //unwrap the PF block into a fast access map
682  for( const auto& pfelement : _currentblock->elements() ) {
683  if( isMuon(pfelement) ) continue; // don't allow muons in our element list
684  if (pfelement.type() == PFBlockElement::HCAL &&
685  pfelement.clusterRef()->flags() & reco::CaloCluster::badHcalMarker) continue; // skip also dead area markers for now
686  const size_t itype = (size_t)pfelement.type();
687  if( itype >= _splayedblock.size() ) _splayedblock.resize(itype+1);
688  _splayedblock[itype].emplace_back(&pfelement,true);
689  }
690 
691  // show the result of splaying the tree if it's really *really* needed
692 #ifdef PFLOW_DEBUG
693  std::stringstream splayout;
694  for( size_t itype = 0; itype < _splayedblock.size(); ++itype ) {
695  splayout << "\tType: " << itype << " indices: ";
696  for( const auto& flaggedelement : _splayedblock[itype] ) {
697  splayout << flaggedelement.first->index() << ' ';
698  }
699  if( itype != _splayedblock.size() - 1 ) splayout << std::endl;
700  }
701  LOGVERB("PFEGammaAlgo") << splayout.str();
702 #endif
703 
704  // precleaning of the ECAL clusters with respect to primary KF tracks
705  // we don't allow clusters in super clusters to be locked out this way
707 
709  LOGDRESSED("PFEGammaAlgo")
710  << "Initialized " << _refinableObjects.size() << " proto-EGamma objects"
711  << std::endl;
713 
714  //
715  // now we start the refining steps
716  //
717  //
718 
719  // --- Primary Linking Step ---
720  // since this is particle flow and we try to work from the pixels out
721  // we start by linking the tracks together and finding the ECAL clusters
722  for( auto& RO : _refinableObjects ) {
723  // find the KF tracks associated to GSF primary tracks
725  // do the same for HCAL clusters associated to the GSF
727  // link secondary KF tracks associated to primary KF tracks
729  // pick up clusters that are linked to the GSF primary
731  // link associated KF to ECAL (ECAL part grabs PS clusters too if able)
733  // now finally look for clusters associated to brem tangents
735  }
736 
737  LOGDRESSED("PFEGammaAlgo")
738  << "Dumping after GSF and KF Track (Primary) Linking : " << std::endl;
740 
741  // merge objects after primary linking
742  mergeROsByAnyLink(_refinableObjects);
743 
744  LOGDRESSED("PFEGammaAlgo")
745  << "Dumping after first merging operation : " << std::endl;
747 
748  // --- Secondary Linking Step ---
749  // after this we go through the ECAL clusters on the remaining tracks
750  // and try to link those in...
751  for( auto& RO : _refinableObjects ) {
752  // look for conversion legs
755  // look for tracks that complement conversion legs
757  // look again for ECAL clusters (this time with an e/p cut)
759  }
760 
761  LOGDRESSED("PFEGammaAlgo")
762  << "Dumping after ECAL to Track (Secondary) Linking : " << std::endl;
764 
765  // merge objects after primary linking
766  mergeROsByAnyLink(_refinableObjects);
767 
768  LOGDRESSED("PFEGammaAlgo")
769  << "There are " << _refinableObjects.size()
770  << " after the 2nd merging step." << std::endl;
772 
773  // -- unlinking and proto-object vetos, final sorting
774  for( auto& RO : _refinableObjects ) {
775  // remove secondary KFs (and possibly ECALs) matched to HCAL clusters
777  // remove secondary KFs and ECALs linked to them that have bad E/p_in
778  // and spoil the resolution
780  // put things back in order after partitioning
781  std::sort(RO.ecalclusters.begin(), RO.ecalclusters.end(),
782  [](const PFClusterFlaggedElement& a,
783  const PFClusterFlaggedElement& b)
784  { return ( a.first->clusterRef()->correctedEnergy() >
785  b.first->clusterRef()->correctedEnergy() ) ; });
786  setROElectronCluster(RO);
787  }
788 
789  LOGDRESSED("PFEGammaAlgo")
790  << "There are " << _refinableObjects.size()
791  << " after the unlinking and vetos step." << std::endl;
793 
794  // fill the PF candidates and then build the refined SC
795  fillPFCandidates(hoc,_refinableObjects,outcands_,outcandsextra_);
796 
797 }
798 
799 void PFEGammaAlgo::
800 initializeProtoCands(std::list<PFEGammaAlgo::ProtoEGObject>& egobjs) {
801  // step 1: build SC based proto-candidates
802  // in the future there will be an SC Et requirement made here to control
803  // block size
804  for( auto& element : _splayedblock[PFBlockElement::SC] ) {
805  LOGDRESSED("PFEGammaAlgo")
806  << "creating SC-based proto-object" << std::endl
807  << "\tSC at index: " << element.first->index()
808  << " has type: " << element.first->type() << std::endl;
809  element.second = false;
810  ProtoEGObject fromSC;
811  fromSC.nBremsWithClusters = -1;
812  fromSC.firstBrem = -1;
813  fromSC.lateBrem = -1;
814  fromSC.parentBlock = _currentblock;
815  fromSC.parentSC = docast(const PFSCElement*,element.first);
816  // splay the supercluster so we can knock out used elements
817  bool sc_success =
818  unwrapSuperCluster(fromSC.parentSC,fromSC.ecalclusters,fromSC.ecal2ps);
819  if( sc_success ) {
820  /*
821  auto ins_pos = std::lower_bound(_refinableObjects.begin(),
822  _refinableObjects.end(),
823  fromSC,
824  [&](const ProtoEGObject& a,
825  const ProtoEGObject& b){
826  const double a_en =
827  a.parentSC->superClusterRef()->energy();
828  const double b_en =
829  b.parentSC->superClusterRef()->energy();
830  return a_en < b_en;
831  });
832  */
833  _refinableObjects.insert(_refinableObjects.end(),fromSC);
834  }
835  }
836  // step 2: build GSF-seed-based proto-candidates
837  reco::GsfTrackRef gsfref_forextra;
838  reco::TrackExtraRef gsftrk_extra;
839  reco::ElectronSeedRef theseedref;
840  for( auto& element : _splayedblock[PFBlockElement::GSF] ) {
841  LOGDRESSED("PFEGammaAlgo")
842  << "creating GSF-based proto-object" << std::endl
843  << "\tGSF at index: " << element.first->index()
844  << " has type: " << element.first->type() << std::endl;
845  const PFGSFElement* elementAsGSF =
846  docast(const PFGSFElement*,element.first);
848  continue; // for now, do not allow dedicated brems to make proto-objects
849  }
850  element.second = false;
851 
852  ProtoEGObject fromGSF;
853  fromGSF.nBremsWithClusters = -1;
854  fromGSF.firstBrem = -1;
855  fromGSF.lateBrem = 0;
856  gsfref_forextra = elementAsGSF->GsftrackRef();
857  gsftrk_extra = ( gsfref_forextra.isAvailable() ?
858  gsfref_forextra->extra() : reco::TrackExtraRef() );
859  theseedref = ( gsftrk_extra.isAvailable() ?
860  gsftrk_extra->seedRef().castTo<reco::ElectronSeedRef>() :
862  fromGSF.electronSeed = theseedref;
863  // exception if there's no seed
864  if(fromGSF.electronSeed.isNull() || !fromGSF.electronSeed.isAvailable()) {
865  std::stringstream gsf_err;
866  elementAsGSF->Dump(gsf_err,"\t");
867  throw cms::Exception("PFEGammaAlgo::initializeProtoCands()")
868  << "Found a GSF track with no seed! This should not happen!"
869  << std::endl << gsf_err.str() << std::endl;
870  }
871  // flag this GSF element as globally used and push back the track ref
872  // into the protocand
873  element.second = false;
874  fromGSF.parentBlock = _currentblock;
875  fromGSF.primaryGSFs.emplace_back(elementAsGSF,true);
876  // add the directly matched brem tangents
877  for( auto& brem : _splayedblock[PFBlockElement::BREM] ) {
878  float dist = _currentblock->dist(elementAsGSF->index(),
879  brem.first->index(),
882  if( dist == 0.001f ) {
883  const PFBremElement* eAsBrem =
884  docast(const PFBremElement*,brem.first);
885  fromGSF.brems.emplace_back(eAsBrem,true);
886  fromGSF.localMap.emplace_back(eAsBrem,elementAsGSF);
887  fromGSF.localMap.emplace_back(elementAsGSF,eAsBrem);
888  brem.second = false;
889  }
890  }
891  // if this track is ECAL seeded reset links or import cluster
892  // tracker (this is pixel only, right?) driven seeds just get the GSF
893  // track associated since this only branches for ECAL Driven seeds
894  if( fromGSF.electronSeed->isEcalDriven() ) {
895  // step 2a: either merge with existing ProtoEG object with SC or add
896  // SC directly to this proto EG object if not present
897  LOGDRESSED("PFEGammaAlgo")
898  << "GSF-based proto-object is ECAL driven, merging SC-cand"
899  << std::endl;
900  LOGVERB("PFEGammaAlgo")
901  << "ECAL Seed Ptr: " << fromGSF.electronSeed.get()
902  << " isAvailable: " << fromGSF.electronSeed.isAvailable()
903  << " isNonnull: " << fromGSF.electronSeed.isNonnull()
904  << std::endl;
905  SeedMatchesToProtoObject sctoseedmatch(fromGSF.electronSeed);
906  std::list<ProtoEGObject>::iterator objsbegin = _refinableObjects.begin();
907  std::list<ProtoEGObject>::iterator objsend = _refinableObjects.end();
908  // this auto is a std::list<ProtoEGObject>::iterator
909  auto clusmatch = std::find_if(objsbegin,objsend,sctoseedmatch);
910  if( clusmatch != objsend ) {
911  fromGSF.parentSC = clusmatch->parentSC;
912  fromGSF.ecalclusters = std::move(clusmatch->ecalclusters);
913  fromGSF.ecal2ps = std::move(clusmatch->ecal2ps);
914  _refinableObjects.erase(clusmatch);
915  } else if (fromGSF.electronSeed.isAvailable() &&
916  fromGSF.electronSeed.isNonnull()) {
917  // link tests in the gap region can current split a gap electron
918  // HEY THIS IS A WORK AROUND FOR A KNOWN BUG IN PFBLOCKALGO
919  // MAYBE WE SHOULD FIX IT??????????????????????????????????
920  LOGDRESSED("PFEGammaAlgo")
921  << "Encountered the known GSF-SC splitting bug "
922  << " in PFBlockAlgo! We should really fix this!" << std::endl;
923  } else { // SC was not in a earlier proto-object
924  std::stringstream gsf_err;
925  elementAsGSF->Dump(gsf_err,"\t");
926  throw cms::Exception("PFEGammaAlgo::initializeProtoCands()")
927  << "Expected SuperCluster from ECAL driven GSF seed "
928  << "was not found in the block!" << std::endl
929  << gsf_err.str() << std::endl;
930  } // supercluster in block
931  } // is ECAL driven seed?
932  /*
933  auto ins_pos = std::lower_bound(_refinableObjects.begin(),
934  _refinableObjects.end(),
935  fromGSF,
936  [&](const ProtoEGObject& a,
937  const ProtoEGObject& b){
938  const double a_en = ( a.parentSC ?
939  a.parentSC->superClusterRef()->energy() :
940  a.primaryGSFs[0].first->GsftrackRef()->pt() );
941  const double b_en = ( b.parentSC ?
942  b.parentSC->superClusterRef()->energy() :
943  b.primaryGSFs[0].first->GsftrackRef()->pt() );
944  return a_en < b_en;
945  });
946  */
947  _refinableObjects.insert(_refinableObjects.end(),fromGSF);
948  } // end loop on GSF elements of block
949 }
950 
951  bool PFEGammaAlgo::
953  std::vector<PFClusterFlaggedElement>& ecalclusters,
954  ClusterMap& ecal2ps) {
955  ecalclusters.clear();
956  ecal2ps.clear();
957  LOGVERB("PFEGammaAlgo")
958  << "Pointer to SC element: 0x"
959  << std::hex << thesc << std::dec << std::endl
960  << "cleared ecalclusters and ecal2ps!" << std::endl;
961  auto ecalbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
962  auto ecalend = _splayedblock[reco::PFBlockElement::ECAL].end();
963  auto hgcalbegin = _splayedblock[reco::PFBlockElement::HGCAL].begin();
964  auto hgcalend = _splayedblock[reco::PFBlockElement::HGCAL].end();
965  if( ecalbegin == ecalend && hgcalbegin == hgcalend ) {
966  LOGERR("PFEGammaAlgo::unwrapSuperCluster()")
967  << "There are no ECAL elements in a block with imported SC!"
968  << " This is a bug we should fix this!"
969  << std::endl;
970  return false;
971  }
972  reco::SuperClusterRef scref = thesc->superClusterRef();
973  const bool is_pf_sc = thesc->fromPFSuperCluster();
974  if( !(scref.isAvailable() && scref.isNonnull()) ) {
975  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
976  << "SuperCluster pointed to by block element is null!"
977  << std::endl;
978  }
979  LOGDRESSED("PFEGammaAlgo")
980  << "Got a valid super cluster ref! 0x"
981  << std::hex << scref.get() << std::dec << std::endl;
982  const size_t nscclusters = scref->clustersSize();
983  const size_t nscpsclusters = scref->preshowerClustersSize();
984  size_t npfpsclusters = 0;
985  size_t npfclusters = 0;
986  LOGDRESSED("PFEGammaAlgo")
987  << "Precalculated cluster multiplicities: "
988  << nscclusters << ' ' << nscpsclusters << std::endl;
989  NotCloserToOther<reco::PFBlockElement::SC,reco::PFBlockElement::ECAL>
990  ecalClustersInSC(_currentblock,thesc);
991  NotCloserToOther<reco::PFBlockElement::SC,reco::PFBlockElement::HGCAL>
992  hgcalClustersInSC(_currentblock,thesc);
993  auto ecalfirstnotinsc = std::partition(ecalbegin,ecalend,ecalClustersInSC);
994  auto hgcalfirstnotinsc = std::partition(hgcalbegin,hgcalend,hgcalClustersInSC);
995  //reset the begin and end iterators
996  ecalbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
997  ecalend = _splayedblock[reco::PFBlockElement::ECAL].end();
998 
999  hgcalbegin = _splayedblock[reco::PFBlockElement::HGCAL].begin();
1000  hgcalend = _splayedblock[reco::PFBlockElement::HGCAL].end();
1001 
1002  //get list of associated clusters by det id and energy matching
1003  //(only needed when using non-pf supercluster)
1004  std::vector<const ClusterElement*> safePFClusters = is_pf_sc ? std::vector<const ClusterElement*>() : getSCAssociatedECALsSafe(scref,_splayedblock[reco::PFBlockElement::ECAL]);
1005 
1006  if( ecalfirstnotinsc == ecalbegin &&
1007  hgcalfirstnotinsc == hgcalbegin) {
1008  LOGERR("PFEGammaAlgo::unwrapSuperCluster()")
1009  << "No associated block elements to SuperCluster!"
1010  << " This is a bug we should fix!"
1011  << std::endl;
1012  return false;
1013  }
1014  npfclusters = std::distance(ecalbegin,ecalfirstnotinsc) + std::distance(hgcalbegin,hgcalfirstnotinsc);
1015  // ensure we have found the correct number of PF ecal clusters in the case
1016  // that this is a PF supercluster, otherwise all bets are off
1017  if( is_pf_sc && nscclusters != npfclusters ) {
1018  std::stringstream sc_err;
1019  thesc->Dump(sc_err,"\t");
1020  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
1021  << "The number of found ecal elements ("
1022  << nscclusters << ") in block is not the same as"
1023  << " the number of ecal PF clusters reported by the PFSuperCluster"
1024  << " itself (" << npfclusters
1025  << ")! This should not happen!" << std::endl
1026  << sc_err.str() << std::endl;
1027  }
1028  for( auto ecalitr = ecalbegin; ecalitr != ecalfirstnotinsc; ++ecalitr ) {
1029  const PFClusterElement* elemascluster =
1030  docast(const PFClusterElement*,ecalitr->first);
1031 
1032  // reject clusters that really shouldn't be associated to the SC
1033  // (only needed when using non-pf-supercluster)
1034  if(!is_pf_sc && std::find(safePFClusters.begin(),safePFClusters.end(),elemascluster) ==
1035  safePFClusters.end() ) continue;
1036 
1037  //add cluster
1038  ecalclusters.emplace_back(elemascluster,true);
1039  //mark cluster as used
1040  ecalitr->second = false;
1041 
1042  // process the ES elements
1043  // auto is a pair<Iterator,bool> here, bool is false when placing fails
1044  auto emplaceresult = ecal2ps.emplace(elemascluster,
1045  ClusterMap::mapped_type());
1046  if( !emplaceresult.second ) {
1047  std::stringstream clus_err;
1048  elemascluster->Dump(clus_err,"\t");
1049  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
1050  << "List of pointers to ECAL block elements contains non-unique items!"
1051  << " This is very bad!" << std::endl
1052  << "cluster ptr = 0x" << std::hex << elemascluster << std::dec
1053  << std::endl << clus_err.str() << std::endl;
1054  }
1055  ClusterMap::mapped_type& eslist = emplaceresult.first->second;
1056  npfpsclusters += attachPSClusters(elemascluster,eslist);
1057  } // loop over ecal elements
1058 
1059  for( auto hgcalitr = hgcalbegin; hgcalitr != hgcalfirstnotinsc; ++hgcalitr ) {
1060  const PFClusterElement* elemascluster =
1061  docast(const PFClusterElement*,hgcalitr->first);
1062 
1063  // reject clusters that really shouldn't be associated to the SC
1064  // (only needed when using non-pf-supercluster)
1065  if(!is_pf_sc && std::find(safePFClusters.begin(),safePFClusters.end(),elemascluster) ==
1066  safePFClusters.end() ) continue;
1067 
1068  //add cluster
1069  ecalclusters.emplace_back(elemascluster,true);
1070  //mark cluster as used
1071  hgcalitr->second = false;
1072  } // loop over ecal elements
1073 
1074  /*
1075  if( is_pf_sc && nscpsclusters != npfpsclusters) {
1076  std::stringstream sc_err;
1077  thesc->Dump(sc_err,"\t");
1078  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
1079  << "The number of found PF preshower elements ("
1080  << npfpsclusters << ") in block is not the same as"
1081  << " the number of preshower clusters reported by the PFSuperCluster"
1082  << " itself (" << nscpsclusters << ")! This should not happen!"
1083  << std::endl
1084  << sc_err.str() << std::endl;
1085  }
1086  */
1087 
1088  LOGDRESSED("PFEGammaAlgo")
1089  << " Unwrapped SC has " << npfclusters << " ECAL sub-clusters"
1090  << " and " << npfpsclusters << " PreShower layers 1 & 2 clusters!"
1091  << std::endl;
1092  return true;
1093  }
1094 
1095 
1096  int PFEGammaAlgo::attachPSClusters(const ClusterElement* ecalclus,
1097  ClusterMap::mapped_type& eslist) {
1098  if( ecalclus->clusterRef()->layer() == PFLayer::ECAL_BARREL ) return 0;
1099  edm::Ptr<reco::PFCluster> clusptr = refToPtr(ecalclus->clusterRef());
1100  EEtoPSElement ecalkey(clusptr.key(),clusptr);
1101  auto assc_ps = std::equal_range(eetops_->cbegin(),
1102  eetops_->cend(),
1103  ecalkey,
1104  [](const EEtoPSElement& a, const EEtoPSElement& b){return a.first < b.first;});
1105  for( const auto& ps1 : _splayedblock[reco::PFBlockElement::PS1] ) {
1106  edm::Ptr<reco::PFCluster> temp = refToPtr(ps1.first->clusterRef());
1107  for( auto pscl = assc_ps.first; pscl != assc_ps.second; ++pscl ) {
1108  if( pscl->second == temp ) {
1109  const ClusterElement* pstemp =
1110  docast(const ClusterElement*,ps1.first);
1111  eslist.emplace_back(pstemp,true);
1112  }
1113  }
1114  }
1115  for( const auto& ps2 : _splayedblock[reco::PFBlockElement::PS2] ) {
1116  edm::Ptr<reco::PFCluster> temp = refToPtr(ps2.first->clusterRef());
1117  for( auto pscl = assc_ps.first; pscl != assc_ps.second; ++pscl ) {
1118  if( pscl->second == temp ) {
1119  const ClusterElement* pstemp =
1120  docast(const ClusterElement*,ps2.first);
1121  eslist.emplace_back(pstemp,true);
1122  }
1123  }
1124  }
1125  return eslist.size();
1126  }
1127 
1129  #ifdef PFLOW_DEBUG
1130  edm::LogVerbatim("PFEGammaAlgo")
1131  //<< "Dumping current block: " << std::endl << *_currentblock << std::endl
1132  << "Dumping " << _refinableObjects.size()
1133  << " refinable objects for this block: " << std::endl;
1134  for( const auto& ro : _refinableObjects ) {
1135  std::stringstream info;
1136  info << "Refinable Object:" << std::endl;
1137  if( ro.parentSC ) {
1138  info << "\tSuperCluster element attached to object:" << std::endl
1139  << '\t';
1140  ro.parentSC->Dump(info,"\t");
1141  info << std::endl;
1142  }
1143  if( ro.electronSeed.isNonnull() ) {
1144  info << "\tGSF element attached to object:" << std::endl;
1145  ro.primaryGSFs.front().first->Dump(info,"\t");
1146  info << std::endl;
1147  info << "firstBrem : " << ro.firstBrem
1148  << " lateBrem : " << ro.lateBrem
1149  << " nBrems with cluster : " << ro.nBremsWithClusters
1150  << std::endl;;
1151  if( ro.electronClusters.size() && ro.electronClusters[0] ) {
1152  info << "electron cluster : ";
1153  ro.electronClusters[0]->Dump(info,"\t");
1154  info << std::endl;
1155  } else {
1156  info << " no electron cluster." << std::endl;
1157  }
1158  }
1159  if( ro.primaryKFs.size() ) {
1160  info << "\tPrimary KF tracks attached to object: " << std::endl;
1161  for( const auto& kf : ro.primaryKFs ) {
1162  kf.first->Dump(info,"\t");
1163  info << std::endl;
1164  }
1165  }
1166  if( ro.secondaryKFs.size() ) {
1167  info << "\tSecondary KF tracks attached to object: " << std::endl;
1168  for( const auto& kf : ro.secondaryKFs ) {
1169  kf.first->Dump(info,"\t");
1170  info << std::endl;
1171  }
1172  }
1173  if( ro.brems.size() ) {
1174  info << "\tBrem tangents attached to object: " << std::endl;
1175  for( const auto& brem : ro.brems ) {
1176  brem.first->Dump(info,"\t");
1177  info << std::endl;
1178  }
1179  }
1180  if( ro.ecalclusters.size() ) {
1181  info << "\tECAL clusters attached to object: " << std::endl;
1182  for( const auto& clus : ro.ecalclusters ) {
1183  clus.first->Dump(info,"\t");
1184  info << std::endl;
1185  if( ro.ecal2ps.find(clus.first) != ro.ecal2ps.end() ) {
1186  for( const auto& psclus : ro.ecal2ps.at(clus.first) ) {
1187  info << "\t\t Attached PS Cluster: ";
1188  psclus.first->Dump(info,"");
1189  info << std::endl;
1190  }
1191  }
1192  }
1193  }
1194  edm::LogVerbatim("PFEGammaAlgo") << info.str();
1195  }
1196  #endif
1197  }
1198 
1199  // look through our KF tracks in this block and match
1200  void PFEGammaAlgo::
1202  typedef std::multimap<double, unsigned> MatchedMap;
1203  typedef const reco::PFBlockElementGsfTrack* GsfTrackElementPtr;
1206  MatchedMap matchedGSFs, matchedECALs;
1207  std::unordered_map<GsfTrackElementPtr,MatchedMap> gsf_ecal_cache;
1208  for( auto& kftrack : _splayedblock[reco::PFBlockElement::TRACK] ) {
1209  matchedGSFs.clear();
1210  _currentblock->associatedElements(kftrack.first->index(), _currentlinks,
1211  matchedGSFs,
1214  if( matchedGSFs.empty() ) { // only run this if we aren't associated to GSF
1215  LesserByDistance closestTrackToECAL(_currentblock,_currentlinks,
1216  kftrack.first);
1217  auto ecalbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1218  auto ecalend = _splayedblock[reco::PFBlockElement::ECAL].end();
1219  std::partial_sort(ecalbegin,ecalbegin+1,ecalend,closestTrackToECAL);
1220  PFFlaggedElement& closestECAL =
1222  const float dist = _currentblock->dist(kftrack.first->index(),
1223  closestECAL.first->index(),
1224  _currentlinks,
1226  bool inSC = false;
1227  for( auto& sc : _splayedblock[reco::PFBlockElement::SC] ) {
1228  float dist_sc = _currentblock->dist(sc.first->index(),
1229  closestECAL.first->index(),
1230  _currentlinks,
1232  if( dist_sc != -1.0f) { inSC = true; break; }
1233  }
1234 
1235  if( dist != -1.0f && closestECAL.second ) {
1236  bool gsflinked = false;
1237  // check that this cluster is not associated to a GSF track
1238  for(const auto& gsfflag : _splayedblock[reco::PFBlockElement::GSF]) {
1239  const reco::PFBlockElementGsfTrack* elemasgsf =
1240  docast(const reco::PFBlockElementGsfTrack*,gsfflag.first);
1242  continue; // keep clusters that have a found conversion GSF near
1243  }
1244  // make sure cache exists
1245  if( !gsf_ecal_cache.count(elemasgsf) ) {
1246  matchedECALs.clear();
1247  _currentblock->associatedElements(elemasgsf->index(), _currentlinks,
1248  matchedECALs,
1251  gsf_ecal_cache.emplace(elemasgsf,matchedECALs);
1252  MatchedMap().swap(matchedECALs);
1253  }
1254  const MatchedMap& ecal_matches = gsf_ecal_cache[elemasgsf];
1255  if( !ecal_matches.empty() ) {
1256  if( ecal_matches.begin()->second == closestECAL.first->index() ) {
1257  gsflinked = true;
1258  break;
1259  }
1260  }
1261  } // loop over primary GSF tracks
1262  if( !gsflinked && !inSC) {
1263  // determine if we should remove the matched cluster
1264  const reco::PFBlockElementTrack * kfEle =
1265  docast(const reco::PFBlockElementTrack*,kftrack.first);
1266  const reco::TrackRef& trackref = kfEle->trackRef();
1267 
1268  const int nexhits =
1269  trackref->hitPattern().numberOfLostHits(HitPattern::MISSING_INNER_HITS);
1270  bool fromprimaryvertex = false;
1271  for( auto vtxtks = cfg_.primaryVtx->tracks_begin();
1272  vtxtks != cfg_.primaryVtx->tracks_end(); ++ vtxtks ) {
1273  if( trackref == vtxtks->castTo<reco::TrackRef>() ) {
1274  fromprimaryvertex = true;
1275  break;
1276  }
1277  }// loop over tracks in primary vertex
1278  // if associated to good non-GSF matched track remove this cluster
1279  if( PFTrackAlgoTools::isGoodForEGMPrimary(trackref->algo()) && nexhits == 0 && fromprimaryvertex ) {
1280  closestECAL.second = false;
1281  }
1282  }
1283  } // found a good closest ECAL match
1284  } // no GSF track matched to KF
1285  } // loop over KF elements
1286  }
1287 
1288  void PFEGammaAlgo::
1289  mergeROsByAnyLink(std::list<PFEGammaAlgo::ProtoEGObject>& ROs) {
1290  if( ROs.size() < 2 ) return; // nothing to do with one or zero ROs
1291  bool check_for_merge = true;
1292  while( check_for_merge ) {
1293  // bugfix for early termination merging loop (15 April 2014)
1294  // check all pairwise combinations in the list
1295  // if one has a merge shuffle it to the front of the list
1296  // if there are no merges left to do we can terminate
1297  for( auto it1 = ROs.begin(); it1 != ROs.end(); ++it1 ) {
1298  auto find_start = it1; ++find_start;
1299  auto has_merge = std::find_if(find_start,ROs.end(),
1300  std::bind(testIfROMergableByLink, _1, *it1));
1301  if( has_merge != ROs.end() && it1 != ROs.begin() ) {
1302  std::swap(*(ROs.begin()),*it1);
1303  break;
1304  }
1305  }// ensure mergables are shuffled to the front
1306  ProtoEGObject& thefront = ROs.front();
1307  auto mergestart = ROs.begin(); ++mergestart;
1308  auto nomerge = std::partition(mergestart,ROs.end(),
1309  std::bind(testIfROMergableByLink, _1, thefront));
1310  if( nomerge != mergestart ) {
1311  LOGDRESSED("PFEGammaAlgo::mergeROsByAnyLink()")
1312  << "Found objects " << std::distance(mergestart,nomerge)
1313  << " to merge by links to the front!" << std::endl;
1314  for( auto roToMerge = mergestart; roToMerge != nomerge; ++roToMerge) {
1315  //bugfix! L.Gray 14 Jan 2016
1316  // -- check that the front is still mergeable!
1317  if( !thefront.ecalclusters.empty() && !roToMerge->ecalclusters.empty() ) {
1318  if( thefront.ecalclusters.front().first->clusterRef()->layer() !=
1319  roToMerge->ecalclusters.front().first->clusterRef()->layer() ) {
1320  LOGWARN("PFEGammaAlgo::mergeROsByAnyLink")
1321  << "Tried to merge EB and EE clusters! Skipping!";
1322  ROs.push_back(*roToMerge);
1323  continue;
1324  }
1325  }
1326  //end bugfix
1327  thefront.ecalclusters.insert(thefront.ecalclusters.end(),
1328  roToMerge->ecalclusters.begin(),
1329  roToMerge->ecalclusters.end());
1330  thefront.ecal2ps.insert(roToMerge->ecal2ps.begin(),
1331  roToMerge->ecal2ps.end());
1332  thefront.secondaryKFs.insert(thefront.secondaryKFs.end(),
1333  roToMerge->secondaryKFs.begin(),
1334  roToMerge->secondaryKFs.end());
1335 
1336  thefront.localMap.insert(thefront.localMap.end(),
1337  roToMerge->localMap.begin(),
1338  roToMerge->localMap.end());
1339  // TO FIX -> use best (E_gsf - E_clustersum)/E_GSF
1340  if( !thefront.parentSC && roToMerge->parentSC ) {
1341  thefront.parentSC = roToMerge->parentSC;
1342  }
1343  if( thefront.electronSeed.isNull() &&
1344  roToMerge->electronSeed.isNonnull() ) {
1345  thefront.electronSeed = roToMerge->electronSeed;
1346  thefront.primaryGSFs.insert(thefront.primaryGSFs.end(),
1347  roToMerge->primaryGSFs.begin(),
1348  roToMerge->primaryGSFs.end());
1349  thefront.primaryKFs.insert(thefront.primaryKFs.end(),
1350  roToMerge->primaryKFs.begin(),
1351  roToMerge->primaryKFs.end());
1352  thefront.brems.insert(thefront.brems.end(),
1353  roToMerge->brems.begin(),
1354  roToMerge->brems.end());
1355  thefront.electronClusters = roToMerge->electronClusters;
1356  thefront.nBremsWithClusters = roToMerge->nBremsWithClusters;
1357  thefront.firstBrem = roToMerge->firstBrem;
1358  thefront.lateBrem = roToMerge->lateBrem;
1359  } else if ( thefront.electronSeed.isNonnull() &&
1360  roToMerge->electronSeed.isNonnull()) {
1361  LOGDRESSED("PFEGammaAlgo::mergeROsByAnyLink")
1362  << "Need to implement proper merging of two gsf candidates!"
1363  << std::endl;
1364  }
1365  }
1366  ROs.erase(mergestart,nomerge);
1367  // put the merged element in the back of the cleaned list
1368  ROs.push_back(ROs.front());
1369  ROs.pop_front();
1370  } else {
1371  check_for_merge = false;
1372  }
1373  }
1374  LOGDRESSED("PFEGammaAlgo::mergeROsByAnyLink()")
1375  << "After merging by links there are: " << ROs.size()
1376  << " refinable EGamma objects!" << std::endl;
1377  }
1378 
1379 // pull in KF tracks associated to the RO but not closer to another
1380 // NB: in initializeProtoCands() we forced the GSF tracks not to be
1381 // from a conversion, but we will leave a protection here just in
1382 // case things change in the future
1383 void PFEGammaAlgo::
1388  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1389  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1390  for( auto& gsfflagged : RO.primaryGSFs ) {
1391  const PFGSFElement* seedtk = gsfflagged.first;
1392  // don't process SC-only ROs or secondary seeded ROs
1393  if( RO.electronSeed.isNull() || seedtk->trackType(convType) ) continue;
1394  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::TRACK>
1395  gsfTrackToKFs(_currentblock,seedtk);
1396  // get KF tracks not closer to another and not already used
1397  auto notlinked = std::partition(KFbegin,KFend,gsfTrackToKFs);
1398  // attach tracks and set as used
1399  for( auto kft = KFbegin; kft != notlinked; ++kft ) {
1400  const PFKFElement* elemaskf =
1401  docast(const PFKFElement*,kft->first);
1402  // don't care about things that aren't primaries or directly
1403  // associated secondary tracks
1404  if( isPrimaryTrack(*elemaskf,*seedtk) &&
1405  !elemaskf->trackType(convType) ) {
1406  kft->second = false;
1407  RO.primaryKFs.emplace_back(elemaskf,true);
1408  RO.localMap.emplace_back(seedtk,elemaskf);
1409  RO.localMap.emplace_back(elemaskf,seedtk);
1410  } else if ( elemaskf->trackType(convType) ) {
1411  kft->second = false;
1412  RO.secondaryKFs.emplace_back(elemaskf,true);
1413  RO.localMap.emplace_back(seedtk,elemaskf);
1414  RO.localMap.emplace_back(elemaskf,seedtk);
1415  }
1416  }// loop on closest KFs not closer to other GSFs
1417  } // loop on GSF primaries on RO
1418 }
1419 
1420 void PFEGammaAlgo::
1425  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1426  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1427  for( auto& kfflagged : RO.primaryKFs ) {
1428  const PFKFElement* primkf = kfflagged.first;
1429  // don't process SC-only ROs or secondary seeded ROs
1430  if( primkf->trackType(convType) ) {
1431  throw cms::Exception("PFEGammaAlgo::linkRefinableObjectPrimaryKFsToSecondaryKFs()")
1432  << "A KF track from conversion has been assigned as a primary!!"
1433  << std::endl;
1434  }
1435  NotCloserToOther<reco::PFBlockElement::TRACK,reco::PFBlockElement::TRACK,true>
1436  kfTrackToKFs(_currentblock,primkf);
1437  // get KF tracks not closer to another and not already used
1438  auto notlinked = std::partition(KFbegin,KFend,kfTrackToKFs);
1439  // attach tracks and set as used
1440  for( auto kft = KFbegin; kft != notlinked; ++kft ) {
1441  const PFKFElement* elemaskf =
1442  docast(const PFKFElement*,kft->first);
1443  // don't care about things that aren't primaries or directly
1444  // associated secondary tracks
1445  if( elemaskf->trackType(convType) ) {
1446  kft->second = false;
1447  RO.secondaryKFs.emplace_back(elemaskf,true);
1448  RO.localMap.emplace_back(primkf,elemaskf);
1449  RO.localMap.emplace_back(elemaskf,primkf);
1450  }
1451  }// loop on closest KFs not closer to other KFs
1452  } // loop on KF primaries on RO
1453 }
1454 
1455 // try to associate the tracks to cluster elements which are not used
1456 void PFEGammaAlgo::
1459  RO.electronClusters.push_back(nullptr);
1460  return;
1461  }
1462  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1463  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1464  for( auto& primgsf : RO.primaryGSFs ) {
1465  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::ECAL>
1466  gsfTracksToECALs(_currentblock,primgsf.first);
1467  auto eoverp_test = std::bind(compatibleEoPOut, _1, primgsf.first);
1468  // get set of matching ecals not already in SC
1469  auto notmatched_blk = std::partition(ECALbegin,ECALend,gsfTracksToECALs);
1470  notmatched_blk = std::partition(ECALbegin,notmatched_blk,eoverp_test);
1471  // get set of matching ecals already in the RO
1472  auto notmatched_sc = std::partition(RO.ecalclusters.begin(),
1473  RO.ecalclusters.end(),
1474  gsfTracksToECALs);
1475  notmatched_sc = std::partition(RO.ecalclusters.begin(),
1476  notmatched_sc,
1477  eoverp_test);
1478  // look inside the SC for the ECAL cluster
1479  for( auto ecal = RO.ecalclusters.begin(); ecal != notmatched_sc; ++ecal ) {
1480  const PFClusterElement* elemascluster =
1481  docast(const PFClusterElement*,ecal->first);
1482  PFClusterFlaggedElement temp(elemascluster,true);
1483  LOGDRESSED("PFEGammaAlgo::linkGSFTracktoECAL()")
1484  << "Found a cluster already in RO by GSF extrapolation"
1485  << " at ECAL surface!" << std::endl
1486  << *elemascluster << std::endl;
1487 
1488  RO.localMap.emplace_back(primgsf.first,temp.first);
1489  RO.localMap.emplace_back(temp.first,primgsf.first);
1490  }
1491  // look outside the SC for the ecal cluster
1492  for( auto ecal = ECALbegin; ecal != notmatched_blk; ++ecal ) {
1493  const PFClusterElement* elemascluster =
1494  docast(const PFClusterElement*,ecal->first);
1495  LOGDRESSED("PFEGammaAlgo::linkGSFTracktoECAL()")
1496  << "Found a cluster not already in RO by GSF extrapolation"
1497  << " at ECAL surface!" << std::endl
1498  << *elemascluster << std::endl;
1499  if( addPFClusterToROSafe(elemascluster,RO) ) {
1500  attachPSClusters(elemascluster,RO.ecal2ps[elemascluster]);
1501  RO.localMap.emplace_back(primgsf.first,elemascluster);
1502  RO.localMap.emplace_back(elemascluster,primgsf.first);
1503  ecal->second = false;
1504  }
1505  }
1506  }
1507 }
1508 
1509 // try to associate the tracks to cluster elements which are not used
1510 void PFEGammaAlgo::
1513  auto HCALbegin = _splayedblock[reco::PFBlockElement::HCAL].begin();
1514  auto HCALend = _splayedblock[reco::PFBlockElement::HCAL].end();
1515  for( auto& primgsf : RO.primaryGSFs ) {
1516  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::HCAL>
1517  gsfTracksToHCALs(_currentblock,primgsf.first);
1518  auto notmatched = std::partition(HCALbegin,HCALend,gsfTracksToHCALs);
1519  for( auto hcal = HCALbegin; hcal != notmatched; ++hcal ) {
1520  const PFClusterElement* elemascluster =
1521  docast(const PFClusterElement*,hcal->first);
1522  PFClusterFlaggedElement temp(elemascluster,true);
1523  LOGDRESSED("PFEGammaAlgo::linkGSFTracktoECAL()")
1524  << "Found an HCAL cluster associated to GSF extrapolation"
1525  << std::endl;
1526  RO.hcalClusters.push_back(temp);
1527  RO.localMap.emplace_back(primgsf.first,temp.first);
1528  RO.localMap.emplace_back(temp.first,primgsf.first);
1529  hcal->second = false;
1530  }
1531  }
1532 }
1533 
1534 // try to associate the tracks to cluster elements which are not used
1535 void PFEGammaAlgo::
1538  for( auto& primkf : RO.primaryKFs ) linkKFTrackToECAL(primkf,RO);
1539  for( auto& secdkf : RO.secondaryKFs ) linkKFTrackToECAL(secdkf,RO);
1540 }
1541 
1542 void
1543 PFEGammaAlgo::linkKFTrackToECAL(const KFFlaggedElement& kfflagged,
1544  ProtoEGObject& RO) {
1545  std::vector<PFClusterFlaggedElement>& currentECAL = RO.ecalclusters;
1546  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1547  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1548  NotCloserToOther<reco::PFBlockElement::TRACK,reco::PFBlockElement::ECAL>
1549  kfTrackToECALs(_currentblock,kfflagged.first);
1550  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::ECAL>
1551  kfTrackGSFToECALs(_currentblock,kfflagged.first);
1552  //get the ECAL elements not used and not closer to another KF
1553  auto notmatched_sc = std::partition(currentECAL.begin(),
1554  currentECAL.end(),
1555  kfTrackToECALs);
1556  //get subset ECAL elements not used or closer to another GSF of any type
1557  notmatched_sc = std::partition(currentECAL.begin(),
1558  notmatched_sc,
1559  kfTrackGSFToECALs);
1560  for( auto ecalitr = currentECAL.begin(); ecalitr != notmatched_sc;
1561  ++ecalitr ) {
1562  const PFClusterElement* elemascluster =
1563  docast(const PFClusterElement*,ecalitr->first);
1564  PFClusterFlaggedElement flaggedclus(elemascluster,true);
1565 
1566  LOGDRESSED("PFEGammaAlgo::linkKFTracktoECAL()")
1567  << "Found a cluster already in RO by KF extrapolation"
1568  << " at ECAL surface!" << std::endl
1569  << *elemascluster << std::endl;
1570  RO.localMap.emplace_back(elemascluster,kfflagged.first);
1571  RO.localMap.emplace_back(kfflagged.first,elemascluster);
1572  }
1573  //get the ECAL elements not used and not closer to another KF
1574  auto notmatched_blk = std::partition(ECALbegin,ECALend,kfTrackToECALs);
1575  //get subset ECAL elements not used or closer to another GSF of any type
1576  notmatched_blk = std::partition(ECALbegin,notmatched_blk,kfTrackGSFToECALs);
1577  for( auto ecalitr = ECALbegin; ecalitr != notmatched_blk; ++ecalitr ) {
1578  const PFClusterElement* elemascluster =
1579  docast(const PFClusterElement*,ecalitr->first);
1580  if( addPFClusterToROSafe(elemascluster,RO) ) {
1581  attachPSClusters(elemascluster,RO.ecal2ps[elemascluster]);
1582  ecalitr->second = false;
1583 
1584  LOGDRESSED("PFEGammaAlgo::linkKFTracktoECAL()")
1585  << "Found a cluster not in RO by KF extrapolation"
1586  << " at ECAL surface!" << std::endl
1587  << *elemascluster << std::endl;
1588  RO.localMap.emplace_back(elemascluster,kfflagged.first);
1589  RO.localMap.emplace_back(kfflagged.first,elemascluster);
1590  }
1591  }
1592 }
1593 
1594 void PFEGammaAlgo::
1596  if( RO.brems.empty() ) return;
1597  int FirstBrem = -1;
1598  int TrajPos = -1;
1599  int lastBremTrajPos = -1;
1600  for( auto& bremflagged : RO.brems ) {
1601  bool has_clusters = false;
1602  TrajPos = (bremflagged.first->indTrajPoint())-2;
1603  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1604  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1605  NotCloserToOther<reco::PFBlockElement::BREM,reco::PFBlockElement::ECAL>
1606  BremToECALs(_currentblock,bremflagged.first);
1607  // check for late brem using clusters already in the SC
1608  auto RSCBegin = RO.ecalclusters.begin();
1609  auto RSCEnd = RO.ecalclusters.end();
1610  auto notmatched_rsc = std::partition(RSCBegin,RSCEnd,BremToECALs);
1611  for( auto ecal = RSCBegin; ecal != notmatched_rsc; ++ecal ) {
1612  float deta =
1613  std::abs( ecal->first->clusterRef()->positionREP().eta() -
1614  bremflagged.first->positionAtECALEntrance().eta() );
1615  if( deta < 0.015 ) {
1616  has_clusters = true;
1617  if( lastBremTrajPos == -1 || lastBremTrajPos < TrajPos ) {
1618  lastBremTrajPos = TrajPos;
1619  }
1620  if( FirstBrem == -1 || TrajPos < FirstBrem ) { // set brem information
1621  FirstBrem = TrajPos;
1622  RO.firstBrem = TrajPos;
1623  }
1624  LOGDRESSED("PFEGammaAlgo::linkBremToECAL()")
1625  << "Found a cluster already in SC linked to brem extrapolation"
1626  << " at ECAL surface!" << std::endl;
1627  RO.localMap.emplace_back(ecal->first,bremflagged.first);
1628  RO.localMap.emplace_back(bremflagged.first,ecal->first);
1629  }
1630  }
1631  // grab new clusters from the block (ensured to not be late brem)
1632  auto notmatched_block = std::partition(ECALbegin,ECALend,BremToECALs);
1633  for( auto ecal = ECALbegin; ecal != notmatched_block; ++ecal ) {
1634  float deta =
1635  std::abs( ecal->first->clusterRef()->positionREP().eta() -
1636  bremflagged.first->positionAtECALEntrance().eta() );
1637  if( deta < 0.015 ) {
1638  has_clusters = true;
1639  if( lastBremTrajPos == -1 || lastBremTrajPos < TrajPos ) {
1640  lastBremTrajPos = TrajPos;
1641  }
1642  if( FirstBrem == -1 || TrajPos < FirstBrem ) { // set brem information
1643 
1644  FirstBrem = TrajPos;
1645  RO.firstBrem = TrajPos;
1646  }
1647  const PFClusterElement* elemasclus =
1648  docast(const PFClusterElement*,ecal->first);
1649  if( addPFClusterToROSafe(elemasclus,RO) ) {
1650  attachPSClusters(elemasclus,RO.ecal2ps[elemasclus]);
1651 
1652  RO.localMap.emplace_back(ecal->first,bremflagged.first);
1653  RO.localMap.emplace_back(bremflagged.first,ecal->first);
1654  ecal->second = false;
1655  LOGDRESSED("PFEGammaAlgo::linkBremToECAL()")
1656  << "Found a cluster not already associated by brem extrapolation"
1657  << " at ECAL surface!" << std::endl;
1658  }
1659 
1660  }
1661  }
1662  if(has_clusters) {
1663  if( RO.nBremsWithClusters == -1 ) RO.nBremsWithClusters = 0;
1664  ++RO.nBremsWithClusters;
1665  }
1666  }
1667 }
1668 
1669 void PFEGammaAlgo::
1671  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1672  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1673  auto BeginROskfs = RO.secondaryKFs.begin();
1674  auto EndROskfs = RO.secondaryKFs.end();
1675  auto ronotconv = std::partition(BeginROskfs,EndROskfs,isConversionTrack);
1676  size_t convkfs_end = std::distance(BeginROskfs,ronotconv);
1677  for( size_t idx = 0; idx < convkfs_end; ++idx ) {
1678  const std::vector<PFKFFlaggedElement>& secKFs = RO.secondaryKFs; //we want the entry at the index but we allocate to secondaryKFs in loop which invalidates all iterators, references and pointers, hence we need to get the entry fresh each time
1679  NotCloserToOther<reco::PFBlockElement::TRACK,
1681  true>
1682  TracksToTracks(_currentblock, secKFs[idx].first);
1683  auto notmatched = std::partition(KFbegin,KFend,TracksToTracks);
1684  notmatched = std::partition(KFbegin,notmatched,isConversionTrack);
1685  for( auto kf = KFbegin; kf != notmatched; ++kf ) {
1686  const reco::PFBlockElementTrack* elemaskf =
1687  docast(const reco::PFBlockElementTrack*,kf->first);
1688  RO.secondaryKFs.emplace_back(elemaskf,true);
1689  RO.localMap.emplace_back(secKFs[idx].first,kf->first);
1690  RO.localMap.emplace_back(kf->first,secKFs[idx].first);
1691  kf->second = false;
1692  }
1693  }
1694 }
1695 
1696 void PFEGammaAlgo::
1698  ProtoEGObject& RO) {
1699  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1700  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1701  for( auto& ecal : RO.ecalclusters ) {
1702  NotCloserToOther<reco::PFBlockElement::ECAL,
1704  true>
1705  ECALToTracks(_currentblock,ecal.first);
1706  auto notmatchedkf = std::partition(KFbegin,KFend,ECALToTracks);
1707  auto notconvkf = std::partition(KFbegin,notmatchedkf,isConversionTrack);
1708  // add identified KF conversion tracks
1709  for( auto kf = KFbegin; kf != notconvkf; ++kf ) {
1710  const reco::PFBlockElementTrack* elemaskf =
1711  docast(const reco::PFBlockElementTrack*,kf->first);
1712  RO.secondaryKFs.emplace_back(elemaskf,true);
1713  RO.localMap.emplace_back(ecal.first,elemaskf);
1714  RO.localMap.emplace_back(elemaskf,ecal.first);
1715  kf->second = false;
1716  }
1717  // go through non-conv-identified kfs and check MVA to add conversions
1718  for( auto kf = notconvkf; kf != notmatchedkf; ++kf ) {
1719  float mvaval = evaluateSingleLegMVA(hoc,_currentblock,
1720  *cfg_.primaryVtx,
1721  kf->first->index());
1722  if(mvaval > cfg_.mvaConvCut) {
1723  const reco::PFBlockElementTrack* elemaskf =
1724  docast(const reco::PFBlockElementTrack*,kf->first);
1725  RO.secondaryKFs.emplace_back(elemaskf,true);
1726  RO.localMap.emplace_back(ecal.first,elemaskf);
1727  RO.localMap.emplace_back(elemaskf,ecal.first);
1728  kf->second = false;
1729 
1730  RO.singleLegConversionMvaMap.emplace(elemaskf, mvaval);
1731  }
1732  }
1733  }
1734 }
1735 
1736 void PFEGammaAlgo::
1738  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1739  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1740  for( auto& skf : RO.secondaryKFs ) {
1741  NotCloserToOther<reco::PFBlockElement::TRACK,
1743  false>
1744  TracksToECALwithCut(_currentblock,skf.first,1.5f);
1745  auto notmatched = std::partition(ECALbegin,ECALend,TracksToECALwithCut);
1746  for( auto ecal = ECALbegin; ecal != notmatched; ++ecal ) {
1747  const reco::PFBlockElementCluster* elemascluster =
1748  docast(const reco::PFBlockElementCluster*,ecal->first);
1749  if( addPFClusterToROSafe(elemascluster,RO) ) {
1750  attachPSClusters(elemascluster,RO.ecal2ps[elemascluster]);
1751  RO.localMap.emplace_back(skf.first,elemascluster);
1752  RO.localMap.emplace_back(elemascluster,skf.first);
1753  ecal->second = false;
1754  }
1755  }
1756  }
1757 }
1758 
1759 void PFEGammaAlgo::
1761  const std::list<PFEGammaAlgo::ProtoEGObject>& ROs,
1762  reco::PFCandidateCollection& egcands,
1764  // reset output collections
1765  egcands.clear();
1766  egxs.clear();
1767  refinedscs_.clear();
1768  egcands.reserve(ROs.size());
1769  egxs.reserve(ROs.size());
1770  refinedscs_.reserve(ROs.size());
1771  for( auto& RO : ROs ) {
1772  if( RO.ecalclusters.empty() &&
1774 
1777  if( !RO.primaryGSFs.empty() || !RO.primaryKFs.empty() ) {
1778  cand.setPdgId(-11); // anything with a primary track is an electron
1779  } else {
1780  cand.setPdgId(22); // anything with no primary track is a photon
1781  }
1782  if( !RO.primaryKFs.empty() ) {
1783  cand.setCharge(RO.primaryKFs[0].first->trackRef()->charge());
1784  xtra.setKfTrackRef(RO.primaryKFs[0].first->trackRef());
1785  cand.setTrackRef(RO.primaryKFs[0].first->trackRef());
1786  cand.addElementInBlock(_currentblock,RO.primaryKFs[0].first->index());
1787  }
1788  if( !RO.primaryGSFs.empty() ) {
1789  cand.setCharge(RO.primaryGSFs[0].first->GsftrackRef()->chargeMode());
1790  xtra.setGsfTrackRef(RO.primaryGSFs[0].first->GsftrackRef());
1791  cand.setGsfTrackRef(RO.primaryGSFs[0].first->GsftrackRef());
1792  cand.addElementInBlock(_currentblock,RO.primaryGSFs[0].first->index());
1793  }
1794  if( RO.parentSC ) {
1795  xtra.setSuperClusterPFECALRef(RO.parentSC->superClusterRef());
1796  // we'll set to the refined supercluster back up in the producer
1797  cand.setSuperClusterRef(RO.parentSC->superClusterRef());
1798  xtra.setSuperClusterRef(RO.parentSC->superClusterRef());
1799  cand.addElementInBlock(_currentblock,RO.parentSC->index());
1800  }
1801  // add brems
1802  for( const auto& bremflagged : RO.brems ) {
1803  const PFBremElement* brem = bremflagged.first;
1804  cand.addElementInBlock(_currentblock,brem->index());
1805  }
1806  // add clusters and ps clusters
1807  for( const auto& ecal : RO.ecalclusters ) {
1808  const PFClusterElement* clus = ecal.first;
1809  cand.addElementInBlock(_currentblock,clus->index());
1810  if( RO.ecal2ps.count(clus) ) {
1811  for( auto& ps : RO.ecal2ps.at(clus) ) {
1812  const PFClusterElement* psclus = ps.first;
1813  cand.addElementInBlock(_currentblock,psclus->index());
1814  }
1815  }
1816  }
1817  // add secondary tracks
1818  for( const auto& secdkf : RO.secondaryKFs ) {
1819  const PFKFElement* kf = secdkf.first;
1821  const reco::ConversionRefVector& convrefs = kf->convRefs();
1822  bool no_conv_ref = true;
1823  for( const auto& convref : convrefs ) {
1824  if( convref.isNonnull() && convref.isAvailable() ) {
1825  xtra.addConversionRef(convref);
1826  no_conv_ref = false;
1827  }
1828  }
1829  if( no_conv_ref ) {
1830  //single leg conversions
1831 
1832  //look for stored mva value in map or else recompute
1833  const auto &mvavalmapped = RO.singleLegConversionMvaMap.find(kf);
1834  //FIXME: Abuse single mva value to store both provenance and single leg mva score
1835  //by storing 3.0 + mvaval
1836  float mvaval = ( mvavalmapped != RO.singleLegConversionMvaMap.end() ?
1837  mvavalmapped->second :
1839  *cfg_.primaryVtx,
1840  kf->index()) );
1841 
1842  xtra.addSingleLegConvTrackRefMva(std::make_pair(kf->trackRef(),mvaval));
1843  }
1844  }
1845 
1846  // build the refined supercluster from those clusters left in the cand
1847  refinedscs_.push_back(buildRefinedSuperCluster(RO));
1848 
1849  //*TODO* cluster time is not reliable at the moment, so only use track timing
1850  float trkTime = 0, trkTimeErr = -1;
1851  if (!RO.primaryGSFs.empty() && RO.primaryGSFs[0].first->isTimeValid()) {
1852  trkTime = RO.primaryGSFs[0].first->time();
1853  trkTimeErr = RO.primaryGSFs[0].first->timeError();
1854  } else if (!RO.primaryKFs.empty() && RO.primaryKFs[0].first->isTimeValid()) {
1855  trkTime = RO.primaryKFs[0].first->time();
1856  trkTimeErr = RO.primaryKFs[0].first->timeError();
1857  }
1858  if (trkTimeErr >= 0) {
1859  cand.setTime( trkTime, trkTimeErr );
1860  }
1861 
1862  const reco::SuperCluster& the_sc = refinedscs_.back();
1863  // with the refined SC in hand we build a naive candidate p4
1864  // and set the candidate ECAL position to either the barycenter of the
1865  // supercluster (if super-cluster present) or the seed of the
1866  // new SC generated by the EGAlgo
1867  const double scE = the_sc.energy();
1868  if( scE != 0.0 ) {
1869  const math::XYZPoint& seedPos = the_sc.seed()->position();
1870  math::XYZVector egDir = the_sc.position()-cfg_.primaryVtx->position();
1871  egDir = egDir.Unit();
1872  cand.setP4(math::XYZTLorentzVector(scE*egDir.x(),
1873  scE*egDir.y(),
1874  scE*egDir.z(),
1875  scE ));
1876  math::XYZPointF ecalPOS_f(seedPos.x(),seedPos.y(),seedPos.z());
1877  cand.setPositionAtECALEntrance(ecalPOS_f);
1878  cand.setEcalEnergy(the_sc.rawEnergy(),the_sc.energy());
1879  } else if ( cfg_.produceEGCandsWithNoSuperCluster &&
1880  !RO.primaryGSFs.empty() ) {
1881  const PFGSFElement* gsf = RO.primaryGSFs[0].first;
1882  const reco::GsfTrackRef& gref = gsf->GsftrackRef();
1883  math::XYZTLorentzVector p4(gref->pxMode(),gref->pyMode(),
1884  gref->pzMode(),gref->pMode());
1885  cand.setP4(p4);
1887  } else if ( cfg_.produceEGCandsWithNoSuperCluster &&
1888  !RO.primaryKFs.empty() ) {
1889  const PFKFElement* kf = RO.primaryKFs[0].first;
1890  reco::TrackRef kref = RO.primaryKFs[0].first->trackRef();
1891  math::XYZTLorentzVector p4(kref->px(),kref->py(),kref->pz(),kref->p());
1892  cand.setP4(p4);
1894  }
1895  const float eleMVAValue = calculateEleMVA(hoc,RO,xtra);
1896  fillExtraInfo(RO,xtra);
1897  //std::cout << "PFEG eleMVA: " << eleMVAValue << std::endl;
1898  xtra.setMVA(eleMVAValue);
1899  cand.set_mva_e_pi(eleMVAValue);
1900  egcands.push_back(cand);
1901  egxs.push_back(xtra);
1902  }
1903 }
1904 
1906  const PFEGammaAlgo::ProtoEGObject& ro,
1907  reco::PFCandidateEGammaExtra& xtra) const
1908 {
1909  if( ro.primaryGSFs.empty() )
1910  {
1911  return -2.0f;
1912  }
1913  const PFGSFElement* gsfElement = ro.primaryGSFs.front().first;
1914  const PFKFElement* kfElement = nullptr;
1915  if( !ro.primaryKFs.empty() )
1916  {
1917  kfElement = ro.primaryKFs.front().first;
1918  }
1919  reco::GsfTrackRef refGsf = gsfElement->GsftrackRef();
1920  reco::TrackRef refKf;
1921  constexpr float mEl = 0.000511;
1922  const double eInGsf = std::hypot(refGsf->pMode(),mEl);
1923  double dEtGsfEcal = 1e6;
1924  double sigmaEtaEta = 1e-14;
1925  const double eneHcalGsf = std::accumulate(
1926  ro.hcalClusters.begin(),
1927  ro.hcalClusters.end(),
1928  0.0,
1929  [](const double a, const PFClusterFlaggedElement& b)
1930  { return a + b.first->clusterRef()->energy(); }
1931  );
1932  if( !ro.primaryKFs.empty() )
1933  {
1934  refKf = ro.primaryKFs.front().first->trackRef();
1935  }
1936  const double eOutGsf = gsfElement->Pout().t();
1937  const double etaOutGsf = gsfElement->positionAtECALEntrance().eta();
1938  double firstEcalGsfEnergy {0.0};
1939  double otherEcalGsfEnergy {0.0};
1940  double ecalBremEnergy {0.0};
1941  //shower shape of cluster closest to gsf track
1942  std::vector<const reco::PFCluster*> gsfCluster;
1943  for( const auto& ecal : ro.ecalclusters )
1944  {
1945  const double cenergy = ecal.first->clusterRef()->correctedEnergy();
1946  ElementMap::value_type gsfToEcal(gsfElement,ecal.first);
1947  ElementMap::value_type kfToEcal(kfElement,ecal.first);
1948  bool hasgsf = ( std::find(ro.localMap.begin(), ro.localMap.end(), gsfToEcal) == ro.localMap.end() );
1949  bool haskf = ( std::find(ro.localMap.begin(), ro.localMap.end(), kfToEcal) == ro.localMap.end() );
1950  bool hasbrem = false;
1951  for( const auto& brem : ro.brems )
1952  {
1953  ElementMap::value_type bremToEcal(brem.first,ecal.first);
1954  if( std::find(ro.localMap.begin(), ro.localMap.end(), bremToEcal) != ro.localMap.end() )
1955  {
1956  hasbrem = true;
1957  }
1958  }
1959  if( hasbrem && ecal.first != ro.electronClusters[0] )
1960  {
1961  ecalBremEnergy += cenergy;
1962  }
1963  if( !hasbrem && ecal.first != ro.electronClusters[0] )
1964  {
1965  if( hasgsf ) otherEcalGsfEnergy += cenergy;
1966  if( haskf ) ecalBremEnergy += cenergy; // from conv. brem!
1967  if( !(hasgsf || haskf) ) otherEcalGsfEnergy += cenergy; // stuff from SC
1968  }
1969  }
1970 
1971  if( ro.electronClusters[0] )
1972  {
1973  reco::PFClusterRef cref = ro.electronClusters[0]->clusterRef();
1975  firstEcalGsfEnergy = cref->correctedEnergy();
1976  dEtGsfEcal = cref->positionREP().eta() - etaOutGsf;
1977  gsfCluster.push_back(cref.get());
1978  PFClusterWidthAlgo pfwidth(gsfCluster);
1979  sigmaEtaEta = pfwidth.pflowSigmaEtaEta();
1980  }
1981 
1982  // brem sequence information
1983  float firstBrem {-1.0f};
1984  float earlyBrem {-1.0f};
1985  float lateBrem {-1.0f};
1986  if(ro.nBremsWithClusters > 0)
1987  {
1988  firstBrem = ro.firstBrem;
1989  earlyBrem = ro.firstBrem < 4 ? 1.0f : 0.0f;
1990  lateBrem = ro.lateBrem == 1 ? 1.0f : 0.0f;
1991  }
1992  xtra.setEarlyBrem(earlyBrem);
1993  xtra.setLateBrem(lateBrem);
1994  if( firstEcalGsfEnergy > 0.0 )
1995  {
1996  if( refGsf.isNonnull() )
1997  {
1998  xtra.setGsfTrackPout(gsfElement->Pout());
1999  // normalization observables
2000  const float ptGsf = refGsf->ptMode();
2001  const float etaGsf = refGsf->etaMode();
2002  // tracking observables
2003  const double ptModeErrorGsf = refGsf->ptModeError();
2004  float ptModeErrOverPtGsf = (ptModeErrorGsf > 0. ? ptModeErrorGsf/ptGsf : 1.0);
2005  float chi2Gsf = refGsf->normalizedChi2();
2006  float dPtOverPtGsf = (ptGsf - gsfElement->Pout().pt())/ptGsf;
2007  // kalman filter vars
2008  float nHitKf = refKf.isNonnull() ? refKf->hitPattern().trackerLayersWithMeasurement() : 0;
2009  float chi2Kf = refKf.isNonnull() ? refKf->normalizedChi2() : -0.01;
2010 
2011  //tracker + calorimetry observables
2012  float eTotPinMode = (firstEcalGsfEnergy+otherEcalGsfEnergy+ecalBremEnergy)/ eInGsf;
2013  float eGsfPoutMode = firstEcalGsfEnergy / eOutGsf;
2014  float eTotBremPinPoutMode = (ecalBremEnergy + otherEcalGsfEnergy) / (eInGsf - eOutGsf);
2015  float dEtaGsfEcalClust = std::abs(dEtGsfEcal);
2016  float logSigmaEtaEta = std::log(sigmaEtaEta);
2017  float hOverHe = eneHcalGsf/(eneHcalGsf + firstEcalGsfEnergy);
2018 
2019  xtra.setDeltaEta(dEtaGsfEcalClust);
2020  xtra.setSigmaEtaEta(sigmaEtaEta);
2021  xtra.setHadEnergy(eneHcalGsf);
2022 
2023  // Apply bounds to variables and calculate MVA
2024  dPtOverPtGsf = std::clamp(dPtOverPtGsf, -0.2f, 1.0f);
2025  ptModeErrOverPtGsf = std::min(ptModeErrOverPtGsf,0.3f);
2026  chi2Gsf = std::min(chi2Gsf,10.0f);
2027  chi2Kf = std::min(chi2Kf,10.0f);
2028  eTotPinMode = std::clamp(eTotPinMode,0.0f, 5.0f);
2029  eGsfPoutMode = std::clamp(eGsfPoutMode,0.0f, 5.0f);
2030  eTotBremPinPoutMode = std::clamp(eTotBremPinPoutMode,0.0f, 5.0f);
2031  dEtaGsfEcalClust = std::min(dEtaGsfEcalClust,0.1f);
2032  logSigmaEtaEta = std::max(logSigmaEtaEta,-14.0f);
2033 
2034  // not used for moment, weird behavior of variable
2035  //float dPtOverPtKf = refKf.isNonnull() ? (refKf->pt() - refKf->outerPt())/refKf->pt() : -0.01;
2036  //dPtOverPtKf = std::clamp(dPtOverPtKf,-0.2f, 1.0f);
2037 
2038 /*
2039  * To be used for debugging:
2040  * pretty-print the PFEgamma electron MVA input variables
2041  *
2042  * std::cout << " **** PFEG BDT observables ****" << endl;
2043  * std::cout << " < Normalization > " << endl;
2044  * std::cout << " ptGsf " << ptGsf << " Pin " << eInGsf
2045  * << " Pout " << eOutGsf << " etaGsf " << etaGsf << endl;
2046  * std::cout << " < PureTracking > " << endl;
2047  * std::cout << " ptModeErrOverPtGsf " << ptModeErrOverPtGsf
2048  * << " dPtOverPtGsf " << dPtOverPtGsf
2049  * << " chi2Gsf " << chi2Gsf
2050  * << " nhit_gsf " << nhit_gsf
2051  * << " dPtOverPtKf " << dPtOverPtKf
2052  * << " chi2Kf " << chi2Kf
2053  * << " nHitKf " << nHitKf << endl;
2054  * std::cout << " < track-ecal-hcal-ps " << endl;
2055  * std::cout << " eTotPinMode " << eTotPinMode
2056  * << " eGsfPoutMode " << eGsfPoutMode
2057  * << " eTotBremPinPoutMode " << eTotBremPinPoutMode
2058  * << " dEtaGsfEcalClust " << dEtaGsfEcalClust
2059  * << " logSigmaEtaEta " << logSigmaEtaEta
2060  * << " hOverHe " << hOverHe << " Hcal energy " << eneHcalGsf
2061  * << " lateBrem " << lateBrem
2062  * << " firstBrem " << firstBrem << endl;
2063  */
2064 
2065  float vars[] = { std::log(ptGsf), etaGsf, ptModeErrOverPtGsf, dPtOverPtGsf, chi2Gsf,
2066  nHitKf, chi2Kf, eTotPinMode, eGsfPoutMode, eTotBremPinPoutMode,
2067  dEtaGsfEcalClust, logSigmaEtaEta, hOverHe, lateBrem, firstBrem };
2068 
2069  return hoc->gbrEle_->GetAdaBoostClassifier(vars);
2070  }
2071  }
2072  return -2.0f;
2073 }
2074 
2077  // add tracks associated to clusters that are not T_FROM_GAMMACONV
2078  // info about single-leg convs is already save, so just veto in loops
2079  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
2080  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
2081  for( auto& ecal : RO.ecalclusters ) {
2082  NotCloserToOther<reco::PFBlockElement::ECAL,
2084  true>
2085  ECALToTracks(_currentblock,ecal.first);
2086  auto notmatchedkf = std::partition(KFbegin,KFend,ECALToTracks);
2087  auto notconvkf = std::partition(KFbegin,notmatchedkf,isConversionTrack);
2088  // go through non-conv-identified kfs and check MVA to add conversions
2089  for( auto kf = notconvkf; kf != notmatchedkf; ++kf ) {
2090  const reco::PFBlockElementTrack* elemaskf =
2091  docast(const reco::PFBlockElementTrack*,kf->first);
2092  xtra.addExtraNonConvTrack(_currentblock,*elemaskf);
2093  }
2094  }
2095 }
2096 
2097 // currently stolen from PFECALSuperClusterAlgo, we should
2098 // try to factor this correctly since the operation is the same in
2099 // both places...
2102  if( RO.ecalclusters.empty() ) {
2103  return reco::SuperCluster(0.0,math::XYZPoint(0,0,0));
2104  }
2105 
2106  bool isEE = false;
2107  edm::Ptr<reco::PFCluster> clusptr;
2108  // need the vector of raw pointers for a PF width class
2109  std::vector<const reco::PFCluster*> bare_ptrs;
2110  // calculate necessary parameters and build the SC
2111  double posX(0), posY(0), posZ(0),
2112  rawSCEnergy(0), corrSCEnergy(0), corrPSEnergy(0),
2113  PS1_clus_sum(0), PS2_clus_sum(0),
2114  ePS1(0), ePS2(0), ps1_energy(0.0), ps2_energy(0.0);
2115  int condP1(1), condP2(1);
2116  for( auto& clus : RO.ecalclusters ) {
2117  ePS1 = 0;
2118  ePS2 = 0;
2119  isEE = PFLayer::ECAL_ENDCAP == clus.first->clusterRef()->layer();
2120  clusptr =
2121  edm::refToPtr<reco::PFClusterCollection>(clus.first->clusterRef());
2122  bare_ptrs.push_back(clusptr.get());
2123 
2124  const double cluseraw = clusptr->energy();
2125  double cluscalibe = clusptr->correctedEnergy();
2126  const math::XYZPoint& cluspos = clusptr->position();
2127  posX += cluseraw * cluspos.X();
2128  posY += cluseraw * cluspos.Y();
2129  posZ += cluseraw * cluspos.Z();
2130  // update EE calibrated super cluster energies
2131  if( isEE && RO.ecal2ps.count(clus.first)) {
2132  ePS1 = 0;
2133  ePS2 = 0;
2134  condP1 = condP2 = 1;
2135 
2136  const auto& psclusters = RO.ecal2ps.at(clus.first);
2137 
2138  for( auto i_ps = psclusters.begin(); i_ps != psclusters.end(); ++i_ps) {
2139  const PFClusterRef& psclus = i_ps->first->clusterRef();
2140 
2141  auto const& recH_Frac = psclus->recHitFractions();
2142 
2143  switch( psclus->layer() ) {
2144  case PFLayer::PS1:
2145  for (auto const& recH : recH_Frac){
2146  ESDetId strip1 = recH.recHitRef()->detId();
2147  if(strip1 != ESDetId(0)){
2149  //getStatusCode() == 0 => active channel
2150  // apply correction if all recHits are dead
2151  if(status_p1->getStatusCode() == 0) condP1 = 0;
2152  }
2153  }
2154  break;
2155  case PFLayer::PS2:
2156  for (auto const& recH : recH_Frac){
2157  ESDetId strip2 = recH.recHitRef()->detId();
2158  if(strip2 != ESDetId(0)) {
2160  if(status_p2->getStatusCode() == 0) condP2 = 0;
2161  }
2162  }
2163  break;
2164  default:
2165  break;
2166  }
2167  }
2168 
2169  auto sumPSEnergy = [](double a, const ClusterFlaggedElement& b, const reco::PFBlockElement::Type type)
2170  { return a + (type == b.first->type())*b.first->clusterRef()->energy(); };
2171 
2172  PS1_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
2173  0.0,std::bind(sumPSEnergy, _1, _2, reco::PFBlockElement::PS1));
2174  PS2_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
2175  0.0,std::bind(sumPSEnergy, _1, _2, reco::PFBlockElement::PS2));
2176 
2177  if(condP1 == 1) ePS1 = -1.;
2178  if(condP2 == 1) ePS2 = -1.;
2179 
2180  cluscalibe =
2181  cfg_.thePFEnergyCalibration->energyEm(*clusptr,
2182  PS1_clus_sum,PS2_clus_sum,
2183  ePS1, ePS2,
2185  }
2186  if(ePS1 == -1.) ePS1 = 0;
2187  if(ePS2 == -1.) ePS2 = 0;
2188 
2189  rawSCEnergy += cluseraw;
2190  corrSCEnergy += cluscalibe;
2191  ps1_energy += ePS1;
2192  ps2_energy += ePS2;
2193  corrPSEnergy += ePS1 + ePS2;
2194  }
2195  posX /= rawSCEnergy;
2196  posY /= rawSCEnergy;
2197  posZ /= rawSCEnergy;
2198 
2199  // now build the supercluster
2200  reco::SuperCluster new_sc(corrSCEnergy,math::XYZPoint(posX,posY,posZ));
2201 
2202  clusptr =
2203  edm::refToPtr<reco::PFClusterCollection>(RO.ecalclusters.front().
2204  first->clusterRef());
2205  new_sc.setCorrectedEnergy(corrSCEnergy);
2206  new_sc.setSeed(clusptr);
2207  new_sc.setPreshowerEnergyPlane1(ps1_energy);
2208  new_sc.setPreshowerEnergyPlane2(ps2_energy);
2209  new_sc.setPreshowerEnergy(corrPSEnergy);
2210  for( const auto& clus : RO.ecalclusters ) {
2211  clusptr =
2212  edm::refToPtr<reco::PFClusterCollection>(clus.first->clusterRef());
2213  new_sc.addCluster(clusptr);
2214  auto& hits_and_fractions = clusptr->hitsAndFractions();
2215  for( auto& hit_and_fraction : hits_and_fractions ) {
2216  new_sc.addHitAndFraction(hit_and_fraction.first,hit_and_fraction.second);
2217  }
2218  // put the preshower stuff back in later
2219  if( RO.ecal2ps.count(clus.first) ) {
2220  const auto& cluspsassociation = RO.ecal2ps.at(clus.first);
2221  // EE rechits should be uniquely matched to sets of pre-shower
2222  // clusters at this point, so we throw an exception if otherwise
2223  // now wrapped in EDM debug flags
2224  for( const auto& pscluselem : cluspsassociation ) {
2225  edm::Ptr<reco::PFCluster> psclus =
2226  edm::refToPtr<reco::PFClusterCollection>(pscluselem.first->
2227  clusterRef());
2228 #ifdef PFFLOW_DEBUG
2229  auto found_pscluster = std::find(new_sc.preshowerClustersBegin(),
2230  new_sc.preshowerClustersEnd(),
2231  reco::CaloClusterPtr(psclus));
2232  if( found_pscluster == new_sc.preshowerClustersEnd() ) {
2233 #endif
2234  new_sc.addPreshowerCluster(psclus);
2235 #ifdef PFFLOW_DEBUG
2236  } else {
2237  throw cms::Exception("PFECALSuperClusterAlgo::buildSuperCluster")
2238  << "Found a PS cluster matched to more than one EE cluster!"
2239  << std::endl << std::hex << psclus.get() << " == "
2240  << found_pscluster->get() << std::dec << std::endl;
2241  }
2242 #endif
2243  }
2244  }
2245  }
2246 
2247  // calculate linearly weighted cluster widths
2248  PFClusterWidthAlgo pfwidth(bare_ptrs);
2249  new_sc.setEtaWidth(pfwidth.pflowEtaWidth());
2250  new_sc.setPhiWidth(pfwidth.pflowPhiWidth());
2251 
2252  // cache the value of the raw energy
2253  new_sc.rawEnergy();
2254 
2255  return new_sc;
2256 }
2257 
2258 void PFEGammaAlgo::
2260  // this only means something for ROs with a primary GSF track
2261  if( RO.primaryGSFs.empty() ) return;
2262  // need energy sums to tell if we've added crap or not
2263  const double Pin_gsf = RO.primaryGSFs.front().first->GsftrackRef()->pMode();
2264  const double gsfOuterEta =
2265  RO.primaryGSFs.front().first->positionAtECALEntrance().Eta();
2266  double tot_ecal= 0.0;
2267  std::vector<double> min_brem_dists;
2268  std::vector<double> closest_brem_eta;
2269  // first get the total ecal energy (we should replace this with a cache)
2270  for( const auto& ecal : RO.ecalclusters ) {
2271  tot_ecal += ecal.first->clusterRef()->correctedEnergy();
2272  // we also need to look at the minimum distance to brems
2273  // since energetic brems will be closer to the brem than the track
2274  double min_brem_dist = 5000.0;
2275  double eta = -999.0;
2276  for( const auto& brem : RO.brems ) {
2277  const float dist = _currentblock->dist(brem.first->index(),
2278  ecal.first->index(),
2279  _currentlinks,
2281  if( dist < min_brem_dist && dist != -1.0f ) {
2282  min_brem_dist = dist;
2283  eta = brem.first->positionAtECALEntrance().Eta();
2284  }
2285  }
2286  min_brem_dists.push_back(min_brem_dist);
2287  closest_brem_eta.push_back(eta);
2288  }
2289 
2290  // loop through the ECAL clusters and remove ECAL clusters matched to
2291  // secondary track either in *or* out of the SC if the E/pin is bad
2292  for( auto secd_kf = RO.secondaryKFs.begin();
2293  secd_kf != RO.secondaryKFs.end(); ++secd_kf ) {
2294  reco::TrackRef trkRef = secd_kf->first->trackRef();
2295  const float secpin = secd_kf->first->trackRef()->p();
2296  bool remove_this_kf = false;
2297  for( auto ecal = RO.ecalclusters.begin();
2298  ecal != RO.ecalclusters.end(); ++ecal ) {
2299  size_t bremidx = std::distance(RO.ecalclusters.begin(),ecal);
2300  const float minbremdist = min_brem_dists[bremidx];
2301  const double ecalenergy = ecal->first->clusterRef()->correctedEnergy();
2302  const double Epin = ecalenergy/secpin;
2303  const double detaGsf =
2304  std::abs(gsfOuterEta - ecal->first->clusterRef()->positionREP().Eta());
2305  const double detaBrem =
2306  std::abs(closest_brem_eta[bremidx] -
2307  ecal->first->clusterRef()->positionREP().Eta());
2308 
2309  ElementMap::value_type check_match(ecal->first,secd_kf->first);
2310  auto kf_matched = std::find(RO.localMap.begin(),
2311  RO.localMap.end(),
2312  check_match);
2313 
2314  const float tkdist = _currentblock->dist(secd_kf->first->index(),
2315  ecal->first->index(),
2316  _currentlinks,
2318 
2319  // do not reject this track if it is closer to a brem than the
2320  // secondary track, or if it lies in the delta-eta plane with the
2321  // gsf track or if it is in the dEta plane with the brems
2322  if( Epin > 3 && kf_matched != RO.localMap.end() &&
2323  tkdist != -1.0f && tkdist < minbremdist &&
2324  detaGsf > 0.05 && detaBrem > 0.015) {
2325  double res_with = std::abs((tot_ecal-Pin_gsf)/Pin_gsf);
2326  double res_without = std::abs((tot_ecal-ecalenergy-Pin_gsf)/Pin_gsf);
2327  if(res_without < res_with) {
2328  LOGDRESSED("PFEGammaAlgo")
2329  << " REJECTED_RES totenergy " << tot_ecal
2330  << " Pin_gsf " << Pin_gsf
2331  << " cluster to secondary " << ecalenergy
2332  << " res_with " << res_with
2333  << " res_without " << res_without << std::endl;
2334  tot_ecal -= ecalenergy;
2335  remove_this_kf = true;
2336  ecal = RO.ecalclusters.erase(ecal);
2337  if( ecal == RO.ecalclusters.end() ) break;
2338  }
2339  }
2340  }
2341  if( remove_this_kf ) {
2342  secd_kf = RO.secondaryKFs.erase(secd_kf);
2343  if( secd_kf == RO.secondaryKFs.end() ) break;
2344  }
2345  }
2346 }
2347 
2348 void PFEGammaAlgo::
2350  bool removeFreeECAL,
2351  bool removeSCEcal) {
2352  std::vector<bool> cluster_in_sc;
2353  auto ecal_begin = RO.ecalclusters.begin();
2354  auto ecal_end = RO.ecalclusters.end();
2355  auto hcal_begin = _splayedblock[reco::PFBlockElement::HCAL].begin();
2356  auto hcal_end = _splayedblock[reco::PFBlockElement::HCAL].end();
2357  for( auto secd_kf = RO.secondaryKFs.begin();
2358  secd_kf != RO.secondaryKFs.end(); ++secd_kf ) {
2359  bool remove_this_kf = false;
2360  NotCloserToOther<reco::PFBlockElement::TRACK,reco::PFBlockElement::HCAL>
2361  tracksToHCALs(_currentblock,secd_kf->first);
2362  reco::TrackRef trkRef = secd_kf->first->trackRef();
2363 
2364  bool goodTrack = PFTrackAlgoTools::isGoodForEGM(trkRef->algo());
2365  const float secpin = trkRef->p();
2366 
2367  for( auto ecal = ecal_begin; ecal != ecal_end; ++ecal ) {
2368  const double ecalenergy = ecal->first->clusterRef()->correctedEnergy();
2369  // first check if the cluster is in the SC (use dist calc for fastness)
2370  const size_t clus_idx = std::distance(ecal_begin,ecal);
2371  if( cluster_in_sc.size() < clus_idx + 1) {
2372  float dist = -1.0f;
2373  if( RO.parentSC ) {
2374  dist = _currentblock->dist(secd_kf->first->index(),
2375  ecal->first->index(),
2376  _currentlinks,
2378  }
2379  cluster_in_sc.push_back(dist != -1.0f);
2380  }
2381 
2382  ElementMap::value_type check_match(ecal->first,secd_kf->first);
2383  auto kf_matched = std::find(RO.localMap.begin(),
2384  RO.localMap.end(),
2385  check_match);
2386  // if we've found a secondary KF that matches this ecal cluster
2387  // now we see if it is matched to HCAL
2388  // if it is matched to an HCAL cluster we take different
2389  // actions if the cluster was in an SC or not
2390  if( kf_matched != RO.localMap.end() ) {
2391  auto hcal_matched = std::partition(hcal_begin,hcal_end,tracksToHCALs);
2392  for( auto hcalclus = hcal_begin;
2393  hcalclus != hcal_matched;
2394  ++hcalclus ) {
2395  const reco::PFBlockElementCluster * clusthcal =
2396  dynamic_cast<const reco::PFBlockElementCluster*>(hcalclus->first);
2397  const double hcalenergy = clusthcal->clusterRef()->energy();
2398  const double hpluse = ecalenergy+hcalenergy;
2399  const bool isHoHE = ( (hcalenergy / hpluse ) > 0.1 && goodTrack );
2400  const bool isHoE = ( hcalenergy > ecalenergy );
2401  const bool isPoHE = ( secpin > hpluse );
2402  if( cluster_in_sc[clus_idx] ) {
2403  if(isHoE || isPoHE) {
2404  LOGDRESSED("PFEGammaAlgo")
2405  << "REJECTED TRACK FOR H/E or P/(H+E), CLUSTER IN SC"
2406  << " H/H+E " << (hcalenergy / hpluse)
2407  << " H/E " << (hcalenergy > ecalenergy)
2408  << " P/(H+E) " << (secpin/hpluse)
2409  << " HCAL ENE " << hcalenergy
2410  << " ECAL ENE " << ecalenergy
2411  << " secPIN " << secpin
2412  << " Algo Track " << trkRef->algo() << std::endl;
2413  remove_this_kf = true;
2414  }
2415  } else {
2416  if(isHoHE){
2417  LOGDRESSED("PFEGammaAlgo")
2418  << "REJECTED TRACK FOR H/H+E, CLUSTER NOT IN SC"
2419  << " H/H+E " << (hcalenergy / hpluse)
2420  << " H/E " << (hcalenergy > ecalenergy)
2421  << " P/(H+E) " << (secpin/hpluse)
2422  << " HCAL ENE " << hcalenergy
2423  << " ECAL ENE " << ecalenergy
2424  << " secPIN " << secpin
2425  << " Algo Track " <<trkRef->algo() << std::endl;
2426  remove_this_kf = true;
2427  }
2428  }
2429  }
2430  }
2431  }
2432  if( remove_this_kf ) {
2433  secd_kf = RO.secondaryKFs.erase(secd_kf);
2434  if( secd_kf == RO.secondaryKFs.end() ) break;
2435  }
2436  }
2437 }
2438 
2439 
2440 
2442  const reco::PFBlockElementGsfTrack& GsfEl) {
2443  bool isPrimary = false;
2444 
2445  const GsfPFRecTrackRef& gsfPfRef = GsfEl.GsftrackRefPF();
2446 
2447  if(gsfPfRef.isNonnull()) {
2448  const PFRecTrackRef& kfPfRef = KfEl.trackRefPF();
2449  PFRecTrackRef kfPfRef_fromGsf = (*gsfPfRef).kfPFRecTrackRef();
2450  if(kfPfRef.isNonnull() && kfPfRef_fromGsf.isNonnull()) {
2451  reco::TrackRef kfref= (*kfPfRef).trackRef();
2452  reco::TrackRef kfref_fromGsf = (*kfPfRef_fromGsf).trackRef();
2453  if(kfref.isNonnull() && kfref_fromGsf.isNonnull()) {
2454  if(kfref == kfref_fromGsf)
2455  isPrimary = true;
2456  }
2457  }
2458  }
2459 
2460  return isPrimary;
2461 }
bool isAvailable() const
Definition: Ref.h:575
type
Definition: HCALResponse.h:21
const SuperClusterRef & superClusterRef() const
const math::XYZTLorentzVector & Pout() const
Abstract base class for a PFBlock element (track, cluster...)
const math::XYZPoint & position() const
cluster centroid position
Definition: CaloCluster.h:131
CaloCluster_iterator preshowerClustersBegin() const
fist iterator over PreshowerCluster constituents
Definition: SuperCluster.h:81
const reco::GsfTrackRef & GsftrackRef() const
static const TGPicture * info(bool iBackgroundIsBlack)
std::vector< PFClusterFlaggedElement > ecalclusters
Definition: PFEGammaAlgo.h:88
static bool overlap(const reco::CaloCluster &sc1, const reco::CaloCluster &sc, float minfrac=0.01, bool debug=false)
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:251
void setSuperClusterRef(reco::SuperClusterRef sc)
set reference to the corresponding supercluster
Ptr< typename C::value_type > refToPtr(Ref< C, typename C::value_type, refhelper::FindUsingAdvance< C, typename C::value_type > > const &ref)
Definition: RefToPtr.h:18
double correctedEnergy() const
Definition: CaloCluster.h:127
reco::SuperClusterCollection refinedscs_
Definition: PFEGammaAlgo.h:154
void addHitAndFraction(DetId id, float fraction)
Definition: CaloCluster.h:190
reco::PFBlockRef parentBlock
Definition: PFEGammaAlgo.h:82
void Dump(std::ostream &out=std::cout, const char *tab=" ") const override
print the object inside the element
void unlinkRefinableObjectKFandECALWithBadEoverP(ProtoEGObject &)
key_type key() const
Definition: Ptr.h:185
trackRef_iterator tracks_end() const
last iterator over tracks
Definition: Vertex.cc:81
static bool isMuon(const reco::PFBlockElement &elt)
Definition: PFMuonAlgo.cc:66
void setPositionAtECALEntrance(const math::XYZPointF &pos)
set position at ECAL entrance
Definition: PFCandidate.h:349
void setGsfElectronClusterRef(const reco::PFBlockRef &blk, const reco::PFBlockElementCluster &ref)
set gsf electron cluster ref
const PFClusterRef & clusterRef() const override
void addSingleLegConvTrackRefMva(const std::pair< reco::TrackRef, float > &trackrefmva)
add Single Leg Conversion TrackRef
void setPreshowerEnergyPlane2(double preshowerEnergy2)
Definition: SuperCluster.h:61
std::pair< const PFClusterElement *, bool > PFClusterFlaggedElement
Definition: PFEGammaAlgo.h:70
const self & getMap() const
T const * get() const
Returns C++ pointer to the item.
Definition: Ptr.h:159
double y() const
y coordinate
Definition: Vertex.h:113
void setHadEnergy(float val)
set the had energy. The cluster energies should be entered before
const math::XYZPointF & positionAtECALEntrance() const
std::shared_ptr< PFEnergyCalibration > thePFEnergyCalibration
Definition: PFEGammaAlgo.h:110
Type type() const
const reco::TrackRef & trackRef() const override
void Dump(std::ostream &out=std::cout, const char *tab=" ") const override
print the object inside the element
const ConversionRefVector & convRefs() const override
std::map< unsigned int, Link > LinkData
Definition: PFBlock.h:46
Geom::Phi< T > phi() const
Definition: PV3DBase.h:69
double pflowPhiWidth() const
std::vector< PFClusterFlaggedElement > hcalClusters
Definition: PFEGammaAlgo.h:100
bool isPrimaryTrack(const reco::PFBlockElementTrack &KfEl, const reco::PFBlockElementGsfTrack &GsfEl)
#define X(str)
Definition: MuonsGrabber.cc:48
bool trackType(TrackType trType) const override
void linkRefinableObjectPrimaryGSFTrackToECAL(ProtoEGObject &)
key_type index() const
Definition: Ref.h:266
const GsfPFRecTrackRef & GsftrackRefPF() const
const edm::OwnVector< reco::PFBlockElement > & elements() const
Definition: PFBlock.h:107
const std::vector< std::pair< DetId, float > > & hitsAndFractions() const
Definition: CaloCluster.h:197
edm::Ref< TrackExtraCollection > TrackExtraRef
persistent reference to a TrackExtra
Definition: TrackExtraFwd.h:17
void linkRefinableObjectECALToSingleLegConv(const pfEGHelpers::HeavyObjectCache *hoc, ProtoEGObject &)
std::vector< const PFClusterElement * > electronClusters
Definition: PFEGammaAlgo.h:104
unsigned int index
index type
Definition: Vertex.h:53
const LinkData & linkData() const
Definition: PFBlock.h:112
std::vector< std::vector< PFFlaggedElement > > _splayedblock
Definition: PFEGammaAlgo.h:163
void setSeed(const CaloClusterPtr &r)
list of used xtals by DetId // now inherited by CaloCluster
Definition: SuperCluster.h:96
const math::XYZTLorentzVector & Pin() const
std::pair< const PFGSFElement *, bool > PFGSFFlaggedElement
Definition: PFEGammaAlgo.h:68
edm::Ptr< CaloCluster > CaloClusterPtr
void linkRefinableObjectBremTangentsToECAL(ProtoEGObject &)
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< float > > XYZPointF
point in space with cartesian internal representation
Definition: Point3D.h:10
const reco::Vertex * primaryVtx
Definition: PFEGammaAlgo.h:114
unsigned int indTrajPoint() const
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:20
reco::PFBlockRef _currentblock
Definition: PFEGammaAlgo.h:159
void setGsfTrackRef(const reco::GsfTrackRef &ref)
set gsftrack reference
std::pair< const reco::PFBlockElement *, bool > PFFlaggedElement
Definition: PFEGammaAlgo.h:65
void setPhiWidth(double pw)
Definition: SuperCluster.h:62
const Point & position() const
position
Definition: Vertex.h:109
double pflowEtaWidth() const
std::pair< const PFSCElement *, bool > PFSCFlaggedElement
Definition: PFEGammaAlgo.h:66
const math::XYZPointF & positionAtECALEntrance() const
PFEGConfigInfo cfg_
Definition: PFEGammaAlgo.h:258
void setCharge(Charge q) final
set electric charge
Definition: LeafCandidate.h:93
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
void set_mva_e_pi(float mvaNI)
Definition: PFCandidate.h:312
#define LOGERR(x)
Definition: PFEGammaAlgo.cc:52
std::vector< PFKFFlaggedElement > secondaryKFs
Definition: PFEGammaAlgo.h:97
static double delPhi(const double phi1, const double phi2)
void setEtaWidth(double ew)
Definition: SuperCluster.h:63
void setSigmaEtaEta(float val)
set the sigmaetaeta
#define LOGVERB(x)
Definition: PFEGammaAlgo.cc:50
#define LOGDRESSED(x)
Definition: PFEGammaAlgo.cc:53
void dumpCurrentRefinableObjects() const
void initializeProtoCands(std::list< ProtoEGObject > &)
bool isGoodForEGM(const reco::TrackBase::TrackAlgorithm &)
void linkRefinableObjectPrimaryKFsToSecondaryKFs(ProtoEGObject &)
unsigned index() const
bool unwrapSuperCluster(const reco::PFBlockElementSuperCluster *, std::vector< PFClusterFlaggedElement > &, ClusterMap &)
bool goodTrack(const reco::Track *pTrack, math::XYZPoint leadPV, trackSelectionParameters parameters, bool debug=false)
double pflowSigmaEtaEta() const
void setCorrectedEnergy(double cenergy)
Definition: CaloCluster.h:114
void addElementInBlock(const reco::PFBlockRef &blockref, unsigned elementIndex)
add an element to the current PFCandidate
Definition: PFCandidate.cc:220
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
reco::PFCluster::EEtoPSAssociation EEtoPSAssociation
Definition: PFEGammaAlgo.h:59
T sqrt(T t)
Definition: SSEVec.h:18
double p4[4]
Definition: TauolaWrapper.h:92
PFEGammaAlgo(const PFEGConfigInfo &)
const PFSCElement * parentSC
Definition: PFEGammaAlgo.h:83
bool trackType(TrackType trType) const override
std::vector< reco::PFCandidateEGammaExtra > PFCandidateEGammaExtraCollection
collection of PFCandidateEGammaExtras
const_iterator find(uint32_t rawId) const
std::vector< PFBremFlaggedElement > brems
Definition: PFEGammaAlgo.h:94
void setEarlyBrem(float val)
set EarlyBrem
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double z() const
z coordinate
Definition: Vertex.h:115
void setGsfTrackPout(const math::XYZTLorentzVector &pout)
set the pout (not trivial to get from the GSF track)
double f[11][100]
double energy() const
cluster energy
Definition: CaloCluster.h:126
T const * get() const
Returns C++ pointer to the item.
Definition: Ref.h:243
T min(T a, T b)
Definition: MathUtil.h:58
std::list< ProtoEGObject > _refinableObjects
Definition: PFEGammaAlgo.h:176
bool isNull() const
Checks for null.
Definition: Ref.h:248
void Dump(std::ostream &out=std::cout, const char *tab=" ") const override
print the object inside the element
reco::PFCandidateEGammaExtraCollection outcandsextra_
Definition: PFEGammaAlgo.h:153
double energy() const
cluster energy
Definition: PFCluster.h:82
void linkKFTrackToECAL(const PFKFFlaggedElement &, ProtoEGObject &)
bool isNonnull() const
Checks for non-null.
Definition: Ptr.h:168
void setEcalEnergy(float eeRaw, float eeCorr)
set corrected Ecal energy
Definition: PFCandidate.h:218
Layer
layer definition
Definition: PFLayer.h:31
reco::PFBlock::LinkData _currentlinks
Definition: PFEGammaAlgo.h:160
void buildAndRefineEGObjects(const pfEGHelpers::HeavyObjectCache *hoc, const reco::PFBlockRef &block)
reco::PFCluster::EEtoPSAssociation const * eetops_
Definition: PFEGammaAlgo.h:158
std::vector< reco::PFCandidate > PFCandidateCollection
collection of PFCandidates
double x() const
x coordinate
Definition: Vertex.h:111
double rawEnergy() const
raw uncorrected energy (sum of energies of component BasicClusters)
Definition: SuperCluster.h:47
bool isMuon(const reco::PFBlockElement &)
void fillExtraInfo(const ProtoEGObject &, reco::PFCandidateEGammaExtra &)
float calculateEleMVA(const pfEGHelpers::HeavyObjectCache *hoc, const ProtoEGObject &, reco::PFCandidateEGammaExtra &) const
void setDeltaEta(float val)
set the delta eta
void setGsfTrackRef(const reco::GsfTrackRef &ref)
set gsftrack reference
Definition: PFCandidate.cc:463
reco::ElectronSeedRef electronSeed
Definition: PFEGammaAlgo.h:84
float evaluateSingleLegMVA(const pfEGHelpers::HeavyObjectCache *hoc, const reco::PFBlockRef &blockref, const reco::Vertex &primaryVtx, unsigned int trackIndex)
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:30
void associatedElements(unsigned i, const LinkData &linkData, std::multimap< double, unsigned > &sortedAssociates, reco::PFBlockElement::Type type=PFBlockElement::NONE, LinkTest test=LINKTEST_RECHIT) const
Definition: PFBlock.cc:75
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
void addPreshowerCluster(const CaloClusterPtr &r)
add reference to constituent BasicCluster
Definition: SuperCluster.h:117
double b
Definition: hdecay.h:120
#define docast(x, y)
Definition: PFEGammaAlgo.cc:49
void linkRefinableObjectGSFTracksToKFs(ProtoEGObject &)
void setSuperClusterPFECALRef(reco::SuperClusterRef sc)
set reference to the corresponding supercluster
void addConversionRef(const reco::ConversionRef &convref)
add Conversions from PF
std::vector< Item >::const_iterator const_iterator
std::vector< PFKFFlaggedElement > primaryKFs
Definition: PFEGammaAlgo.h:93
std::unordered_map< const PFClusterElement *, std::vector< PFClusterFlaggedElement > > ClusterMap
Definition: PFEGammaAlgo.h:77
void addCluster(const CaloClusterPtr &r)
add reference to constituent BasicCluster
Definition: SuperCluster.h:111
void fillPFCandidates(const pfEGHelpers::HeavyObjectCache *hoc, const std::list< ProtoEGObject > &, reco::PFCandidateCollection &, reco::PFCandidateEGammaExtraCollection &)
void removeOrLinkECALClustersToKFTracks()
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:40
fixed size matrix
#define LOGWARN(x)
Definition: PFEGammaAlgo.cc:51
reco::SuperCluster buildRefinedSuperCluster(const ProtoEGObject &)
void unlinkRefinableObjectKFandECALMatchedToHCAL(ProtoEGObject &, bool removeFreeECAL=false, bool removeSCECAL=false)
double a
Definition: hdecay.h:121
std::pair< const PFKFElement *, bool > PFKFFlaggedElement
Definition: PFEGammaAlgo.h:69
void mergeROsByAnyLink(std::list< ProtoEGObject > &)
const PFRecTrackRef & trackRefPF() const override
void setSuperClusterRef(const reco::SuperClusterRef &scRef)
Definition: PFCandidate.cc:629
int attachPSClusters(const PFClusterElement *, ClusterMap::mapped_type &)
bool isGoodForEGMPrimary(const reco::TrackBase::TrackAlgorithm &)
void linkRefinableObjectKFTracksToECAL(ProtoEGObject &)
void setKfTrackRef(const reco::TrackRef &ref)
set kf track reference
const CaloClusterPtr & seed() const
seed BasicCluster
Definition: SuperCluster.h:66
void setMVA(float val)
set the result (mostly for debugging)
vars
Definition: DeepTauId.cc:77
void linkRefinableObjectSecondaryKFsToECAL(ProtoEGObject &)
void setLateBrem(float val)
set LateBrem
trackRef_iterator tracks_begin() const
first iterator over tracks
Definition: Vertex.cc:76
void linkRefinableObjectConvSecondaryKFsToSecondaryKFs(ProtoEGObject &)
void setTrackRef(const reco::TrackRef &ref)
set track reference
Definition: PFCandidate.cc:425
reco::PFCandidateCollection outcands_
Definition: PFEGammaAlgo.h:152
bool next_combination(BidIt n_begin, BidIt n_end, BidIt r_begin, BidIt r_end)
Definition: combination.h:22
void setTime(float time, float timeError=0.f)
the timing information
Definition: PFCandidate.h:425
void setPdgId(int pdgId) final
void setPreshowerEnergyPlane1(double preshowerEnergy1)
Definition: SuperCluster.h:60
std::vector< PFGSFFlaggedElement > primaryGSFs
Definition: PFEGammaAlgo.h:91
const std::unique_ptr< const GBRForest > gbrEle_
void setP4(const LorentzVector &p4) final
set 4-momentum
def move(src, dest)
Definition: eostools.py:511
#define constexpr
const ESChannelStatus * channelStatus_
Definition: PFEGammaAlgo.h:262
CaloCluster_iterator preshowerClustersEnd() const
last iterator over PreshowerCluster constituents
Definition: SuperCluster.h:84
void addExtraNonConvTrack(const reco::PFBlockRef &blk, const reco::PFBlockElementTrack &tkref)
track counting for electrons and photons
void setPreshowerEnergy(double preshowerEnergy)
Definition: SuperCluster.h:59
const std::unique_ptr< const GBRForest > gbrSingleLeg_
void linkRefinableObjectPrimaryGSFTrackToHCAL(ProtoEGObject &)
Block of elements.
Definition: PFBlock.h:30