CMS 3D CMS Logo

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