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