CMS 3D CMS Logo

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