CMS 3D CMS Logo

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