CMS 3D CMS Logo

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