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