CMS 3D CMS Logo

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