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  const size_t itype = (size_t)pfelement.type();
847  if( itype >= _splayedblock.size() ) _splayedblock.resize(itype+1);
848  _splayedblock[itype].push_back(std::make_pair(&pfelement,true));
849  }
850 
851  // show the result of splaying the tree if it's really *really* needed
852 #ifdef PFLOW_DEBUG
853  std::stringstream splayout;
854  for( size_t itype = 0; itype < _splayedblock.size(); ++itype ) {
855  splayout << "\tType: " << itype << " indices: ";
856  for( const auto& flaggedelement : _splayedblock[itype] ) {
857  splayout << flaggedelement.first->index() << ' ';
858  }
859  if( itype != _splayedblock.size() - 1 ) splayout << std::endl;
860  }
861  LOGVERB("PFEGammaAlgo") << splayout.str();
862 #endif
863 
864  // precleaning of the ECAL clusters with respect to primary KF tracks
865  // we don't allow clusters in super clusters to be locked out this way
867 
869  LOGDRESSED("PFEGammaAlgo")
870  << "Initialized " << _refinableObjects.size() << " proto-EGamma objects"
871  << std::endl;
873 
874  //
875  // now we start the refining steps
876  //
877  //
878 
879  // --- Primary Linking Step ---
880  // since this is particle flow and we try to work from the pixels out
881  // we start by linking the tracks together and finding the ECAL clusters
882  for( auto& RO : _refinableObjects ) {
883  // find the KF tracks associated to GSF primary tracks
885  // do the same for HCAL clusters associated to the GSF
887  // link secondary KF tracks associated to primary KF tracks
889  // pick up clusters that are linked to the GSF primary
891  // link associated KF to ECAL (ECAL part grabs PS clusters too if able)
893  // now finally look for clusters associated to brem tangents
895  }
896 
897  LOGDRESSED("PFEGammaAlgo")
898  << "Dumping after GSF and KF Track (Primary) Linking : " << std::endl;
900 
901  // merge objects after primary linking
902  mergeROsByAnyLink(_refinableObjects);
903 
904  LOGDRESSED("PFEGammaAlgo")
905  << "Dumping after first merging operation : " << std::endl;
907 
908  // --- Secondary Linking Step ---
909  // after this we go through the ECAL clusters on the remaining tracks
910  // and try to link those in...
911  for( auto& RO : _refinableObjects ) {
912  // look for conversion legs
915  // look for tracks that complement conversion legs
917  // look again for ECAL clusters (this time with an e/p cut)
919  }
920 
921  LOGDRESSED("PFEGammaAlgo")
922  << "Dumping after ECAL to Track (Secondary) Linking : " << std::endl;
924 
925  // merge objects after primary linking
926  mergeROsByAnyLink(_refinableObjects);
927 
928  LOGDRESSED("PFEGammaAlgo")
929  << "There are " << _refinableObjects.size()
930  << " after the 2nd merging step." << std::endl;
932 
933  // -- unlinking and proto-object vetos, final sorting
934  for( auto& RO : _refinableObjects ) {
935  // remove secondary KFs (and possibly ECALs) matched to HCAL clusters
937  // remove secondary KFs and ECALs linked to them that have bad E/p_in
938  // and spoil the resolution
940  // put things back in order after partitioning
941  std::sort(RO.ecalclusters.begin(), RO.ecalclusters.end(),
942  [](const PFClusterFlaggedElement& a,
943  const PFClusterFlaggedElement& b)
944  { return ( a.first->clusterRef()->correctedEnergy() >
945  b.first->clusterRef()->correctedEnergy() ) ; });
946  setROElectronCluster(RO);
947  }
948 
949  LOGDRESSED("PFEGammaAlgo")
950  << "There are " << _refinableObjects.size()
951  << " after the unlinking and vetos step." << std::endl;
953 
954  // fill the PF candidates and then build the refined SC
955  fillPFCandidates(hoc,_refinableObjects,outcands_,outcandsextra_);
956 
957 }
958 
959 void PFEGammaAlgo::
960 initializeProtoCands(std::list<PFEGammaAlgo::ProtoEGObject>& egobjs) {
961  // step 1: build SC based proto-candidates
962  // in the future there will be an SC Et requirement made here to control
963  // block size
964  for( auto& element : _splayedblock[PFBlockElement::SC] ) {
965  LOGDRESSED("PFEGammaAlgo")
966  << "creating SC-based proto-object" << std::endl
967  << "\tSC at index: " << element.first->index()
968  << " has type: " << element.first->type() << std::endl;
969  element.second = false;
970  ProtoEGObject fromSC;
971  fromSC.nBremsWithClusters = -1;
972  fromSC.firstBrem = -1;
973  fromSC.lateBrem = -1;
974  fromSC.parentBlock = _currentblock;
975  fromSC.parentSC = docast(const PFSCElement*,element.first);
976  // splay the supercluster so we can knock out used elements
977  bool sc_success =
978  unwrapSuperCluster(fromSC.parentSC,fromSC.ecalclusters,fromSC.ecal2ps);
979  if( sc_success ) {
980  /*
981  auto ins_pos = std::lower_bound(_refinableObjects.begin(),
982  _refinableObjects.end(),
983  fromSC,
984  [&](const ProtoEGObject& a,
985  const ProtoEGObject& b){
986  const double a_en =
987  a.parentSC->superClusterRef()->energy();
988  const double b_en =
989  b.parentSC->superClusterRef()->energy();
990  return a_en < b_en;
991  });
992  */
993  _refinableObjects.insert(_refinableObjects.end(),fromSC);
994  }
995  }
996  // step 2: build GSF-seed-based proto-candidates
997  reco::GsfTrackRef gsfref_forextra;
998  reco::TrackExtraRef gsftrk_extra;
999  reco::ElectronSeedRef theseedref;
1000  std::list<ProtoEGObject>::iterator objsbegin, objsend;
1001  for( auto& element : _splayedblock[PFBlockElement::GSF] ) {
1002  LOGDRESSED("PFEGammaAlgo")
1003  << "creating GSF-based proto-object" << std::endl
1004  << "\tGSF at index: " << element.first->index()
1005  << " has type: " << element.first->type() << std::endl;
1006  const PFGSFElement* elementAsGSF =
1007  docast(const PFGSFElement*,element.first);
1008  if( elementAsGSF->trackType(reco::PFBlockElement::T_FROM_GAMMACONV) ) {
1009  continue; // for now, do not allow dedicated brems to make proto-objects
1010  }
1011  element.second = false;
1012 
1013  ProtoEGObject fromGSF;
1014  fromGSF.nBremsWithClusters = -1;
1015  fromGSF.firstBrem = -1;
1016  fromGSF.lateBrem = 0;
1017  gsfref_forextra = elementAsGSF->GsftrackRef();
1018  gsftrk_extra = ( gsfref_forextra.isAvailable() ?
1019  gsfref_forextra->extra() : reco::TrackExtraRef() );
1020  theseedref = ( gsftrk_extra.isAvailable() ?
1021  gsftrk_extra->seedRef().castTo<reco::ElectronSeedRef>() :
1022  reco::ElectronSeedRef() );
1023  fromGSF.electronSeed = theseedref;
1024  // exception if there's no seed
1025  if(fromGSF.electronSeed.isNull() || !fromGSF.electronSeed.isAvailable()) {
1026  std::stringstream gsf_err;
1027  elementAsGSF->Dump(gsf_err,"\t");
1028  throw cms::Exception("PFEGammaAlgo::initializeProtoCands()")
1029  << "Found a GSF track with no seed! This should not happen!"
1030  << std::endl << gsf_err.str() << std::endl;
1031  }
1032  // flag this GSF element as globally used and push back the track ref
1033  // into the protocand
1034  element.second = false;
1035  fromGSF.parentBlock = _currentblock;
1036  fromGSF.primaryGSFs.push_back(std::make_pair(elementAsGSF,true));
1037  // add the directly matched brem tangents
1038  for( auto& brem : _splayedblock[PFBlockElement::BREM] ) {
1039  float dist = _currentblock->dist(elementAsGSF->index(),
1040  brem.first->index(),
1041  _currentlinks,
1043  if( dist == 0.001f ) {
1044  const PFBremElement* eAsBrem =
1045  docast(const PFBremElement*,brem.first);
1046  fromGSF.brems.push_back(std::make_pair(eAsBrem,true));
1047  fromGSF.localMap.push_back( ElementMap::value_type(eAsBrem,elementAsGSF) );
1048  fromGSF.localMap.push_back( ElementMap::value_type(elementAsGSF,eAsBrem) );
1049  brem.second = false;
1050  }
1051  }
1052  // if this track is ECAL seeded reset links or import cluster
1053  // tracker (this is pixel only, right?) driven seeds just get the GSF
1054  // track associated since this only branches for ECAL Driven seeds
1055  if( fromGSF.electronSeed->isEcalDriven() ) {
1056  // step 2a: either merge with existing ProtoEG object with SC or add
1057  // SC directly to this proto EG object if not present
1058  LOGDRESSED("PFEGammaAlgo")
1059  << "GSF-based proto-object is ECAL driven, merging SC-cand"
1060  << std::endl;
1061  LOGVERB("PFEGammaAlgo")
1062  << "ECAL Seed Ptr: " << fromGSF.electronSeed.get()
1063  << " isAvailable: " << fromGSF.electronSeed.isAvailable()
1064  << " isNonnull: " << fromGSF.electronSeed.isNonnull()
1065  << std::endl;
1066  SeedMatchesToProtoObject sctoseedmatch(fromGSF.electronSeed);
1067  objsbegin = _refinableObjects.begin();
1068  objsend = _refinableObjects.end();
1069  // this auto is a std::list<ProtoEGObject>::iterator
1070  auto clusmatch = std::find_if(objsbegin,objsend,sctoseedmatch);
1071  if( clusmatch != objsend ) {
1072  fromGSF.parentSC = clusmatch->parentSC;
1073  fromGSF.ecalclusters = std::move(clusmatch->ecalclusters);
1074  fromGSF.ecal2ps = std::move(clusmatch->ecal2ps);
1075  _refinableObjects.erase(clusmatch);
1076  } else if (fromGSF.electronSeed.isAvailable() &&
1077  fromGSF.electronSeed.isNonnull()) {
1078  // link tests in the gap region can current split a gap electron
1079  // HEY THIS IS A WORK AROUND FOR A KNOWN BUG IN PFBLOCKALGO
1080  // MAYBE WE SHOULD FIX IT??????????????????????????????????
1081  LOGDRESSED("PFEGammaAlgo")
1082  << "Encountered the known GSF-SC splitting bug "
1083  << " in PFBlockAlgo! We should really fix this!" << std::endl;
1084  } else { // SC was not in a earlier proto-object
1085  std::stringstream gsf_err;
1086  elementAsGSF->Dump(gsf_err,"\t");
1087  throw cms::Exception("PFEGammaAlgo::initializeProtoCands()")
1088  << "Expected SuperCluster from ECAL driven GSF seed "
1089  << "was not found in the block!" << std::endl
1090  << gsf_err.str() << std::endl;
1091  } // supercluster in block
1092  } // is ECAL driven seed?
1093  /*
1094  auto ins_pos = std::lower_bound(_refinableObjects.begin(),
1095  _refinableObjects.end(),
1096  fromGSF,
1097  [&](const ProtoEGObject& a,
1098  const ProtoEGObject& b){
1099  const double a_en = ( a.parentSC ?
1100  a.parentSC->superClusterRef()->energy() :
1101  a.primaryGSFs[0].first->GsftrackRef()->pt() );
1102  const double b_en = ( b.parentSC ?
1103  b.parentSC->superClusterRef()->energy() :
1104  b.primaryGSFs[0].first->GsftrackRef()->pt() );
1105  return a_en < b_en;
1106  });
1107  */
1108  _refinableObjects.insert(_refinableObjects.end(),fromGSF);
1109  } // end loop on GSF elements of block
1110 }
1111 
1112  bool PFEGammaAlgo::
1114  std::vector<PFClusterFlaggedElement>& ecalclusters,
1115  ClusterMap& ecal2ps) {
1116  ecalclusters.clear();
1117  ecal2ps.clear();
1118  LOGVERB("PFEGammaAlgo")
1119  << "Pointer to SC element: 0x"
1120  << std::hex << thesc << std::dec << std::endl
1121  << "cleared ecalclusters and ecal2ps!" << std::endl;
1122  auto ecalbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1123  auto ecalend = _splayedblock[reco::PFBlockElement::ECAL].end();
1124  auto hgcalbegin = _splayedblock[reco::PFBlockElement::HGCAL].begin();
1125  auto hgcalend = _splayedblock[reco::PFBlockElement::HGCAL].end();
1126  if( ecalbegin == ecalend && hgcalbegin == hgcalend ) {
1127  LOGERR("PFEGammaAlgo::unwrapSuperCluster()")
1128  << "There are no ECAL elements in a block with imported SC!"
1129  << " This is a bug we should fix this!"
1130  << std::endl;
1131  return false;
1132  }
1133  reco::SuperClusterRef scref = thesc->superClusterRef();
1134  const bool is_pf_sc = thesc->fromPFSuperCluster();
1135  if( !(scref.isAvailable() && scref.isNonnull()) ) {
1136  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
1137  << "SuperCluster pointed to by block element is null!"
1138  << std::endl;
1139  }
1140  LOGDRESSED("PFEGammaAlgo")
1141  << "Got a valid super cluster ref! 0x"
1142  << std::hex << scref.get() << std::dec << std::endl;
1143  const size_t nscclusters = scref->clustersSize();
1144  const size_t nscpsclusters = scref->preshowerClustersSize();
1145  size_t npfpsclusters = 0;
1146  size_t npfclusters = 0;
1147  LOGDRESSED("PFEGammaAlgo")
1148  << "Precalculated cluster multiplicities: "
1149  << nscclusters << ' ' << nscpsclusters << std::endl;
1150  NotCloserToOther<reco::PFBlockElement::SC,reco::PFBlockElement::ECAL>
1151  ecalClustersInSC(_currentblock,_currentlinks,thesc);
1152  NotCloserToOther<reco::PFBlockElement::SC,reco::PFBlockElement::HGCAL>
1153  hgcalClustersInSC(_currentblock,_currentlinks,thesc);
1154  auto ecalfirstnotinsc = std::partition(ecalbegin,ecalend,ecalClustersInSC);
1155  auto hgcalfirstnotinsc = std::partition(hgcalbegin,hgcalend,hgcalClustersInSC);
1156  //reset the begin and end iterators
1157  ecalbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1158  ecalend = _splayedblock[reco::PFBlockElement::ECAL].end();
1159 
1160  hgcalbegin = _splayedblock[reco::PFBlockElement::HGCAL].begin();
1161  hgcalend = _splayedblock[reco::PFBlockElement::HGCAL].end();
1162 
1163  //get list of associated clusters by det id and energy matching
1164  //(only needed when using non-pf supercluster)
1165  std::vector<const ClusterElement*> safePFClusters = is_pf_sc ? std::vector<const ClusterElement*>() : getSCAssociatedECALsSafe(scref,_splayedblock[reco::PFBlockElement::ECAL]);
1166 
1167  if( ecalfirstnotinsc == ecalbegin &&
1168  hgcalfirstnotinsc == hgcalbegin) {
1169  LOGERR("PFEGammaAlgo::unwrapSuperCluster()")
1170  << "No associated block elements to SuperCluster!"
1171  << " This is a bug we should fix!"
1172  << std::endl;
1173  return false;
1174  }
1175  npfclusters = std::distance(ecalbegin,ecalfirstnotinsc) + std::distance(hgcalbegin,hgcalfirstnotinsc);
1176  // ensure we have found the correct number of PF ecal clusters in the case
1177  // that this is a PF supercluster, otherwise all bets are off
1178  if( is_pf_sc && nscclusters != npfclusters ) {
1179  std::stringstream sc_err;
1180  thesc->Dump(sc_err,"\t");
1181  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
1182  << "The number of found ecal elements ("
1183  << nscclusters << ") in block is not the same as"
1184  << " the number of ecal PF clusters reported by the PFSuperCluster"
1185  << " itself (" << npfclusters
1186  << ")! This should not happen!" << std::endl
1187  << sc_err.str() << std::endl;
1188  }
1189  for( auto ecalitr = ecalbegin; ecalitr != ecalfirstnotinsc; ++ecalitr ) {
1190  const PFClusterElement* elemascluster =
1191  docast(const PFClusterElement*,ecalitr->first);
1192 
1193  // reject clusters that really shouldn't be associated to the SC
1194  // (only needed when using non-pf-supercluster)
1195  if(!is_pf_sc && std::find(safePFClusters.begin(),safePFClusters.end(),elemascluster) ==
1196  safePFClusters.end() ) continue;
1197 
1198  //add cluster
1199  ecalclusters.push_back(std::make_pair(elemascluster,true));
1200  //mark cluster as used
1201  ecalitr->second = false;
1202 
1203  // process the ES elements
1204  // auto is a pair<Iterator,bool> here, bool is false when placing fails
1205  auto emplaceresult = ecal2ps.emplace(elemascluster,
1206  ClusterMap::mapped_type());
1207  if( !emplaceresult.second ) {
1208  std::stringstream clus_err;
1209  elemascluster->Dump(clus_err,"\t");
1210  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
1211  << "List of pointers to ECAL block elements contains non-unique items!"
1212  << " This is very bad!" << std::endl
1213  << "cluster ptr = 0x" << std::hex << elemascluster << std::dec
1214  << std::endl << clus_err.str() << std::endl;
1215  }
1216  ClusterMap::mapped_type& eslist = emplaceresult.first->second;
1217  npfpsclusters += attachPSClusters(elemascluster,eslist);
1218  } // loop over ecal elements
1219 
1220  for( auto hgcalitr = hgcalbegin; hgcalitr != hgcalfirstnotinsc; ++hgcalitr ) {
1221  const PFClusterElement* elemascluster =
1222  docast(const PFClusterElement*,hgcalitr->first);
1223 
1224  // reject clusters that really shouldn't be associated to the SC
1225  // (only needed when using non-pf-supercluster)
1226  if(!is_pf_sc && std::find(safePFClusters.begin(),safePFClusters.end(),elemascluster) ==
1227  safePFClusters.end() ) continue;
1228 
1229  //add cluster
1230  ecalclusters.push_back(std::make_pair(elemascluster,true));
1231  //mark cluster as used
1232  hgcalitr->second = false;
1233  } // loop over ecal elements
1234 
1235  /*
1236  if( is_pf_sc && nscpsclusters != npfpsclusters) {
1237  std::stringstream sc_err;
1238  thesc->Dump(sc_err,"\t");
1239  throw cms::Exception("PFEGammaAlgo::unwrapSuperCluster()")
1240  << "The number of found PF preshower elements ("
1241  << npfpsclusters << ") in block is not the same as"
1242  << " the number of preshower clusters reported by the PFSuperCluster"
1243  << " itself (" << nscpsclusters << ")! This should not happen!"
1244  << std::endl
1245  << sc_err.str() << std::endl;
1246  }
1247  */
1248 
1249  LOGDRESSED("PFEGammaAlgo")
1250  << " Unwrapped SC has " << npfclusters << " ECAL sub-clusters"
1251  << " and " << npfpsclusters << " PreShower layers 1 & 2 clusters!"
1252  << std::endl;
1253  return true;
1254  }
1255 
1256 
1257 
1258  int PFEGammaAlgo::attachPSClusters(const ClusterElement* ecalclus,
1259  ClusterMap::mapped_type& eslist) {
1260  if( ecalclus->clusterRef()->layer() == PFLayer::ECAL_BARREL ) return 0;
1261  edm::Ptr<reco::PFCluster> clusptr = refToPtr(ecalclus->clusterRef());
1262  EEtoPSElement ecalkey = std::make_pair(clusptr.key(),clusptr);
1263  auto assc_ps = std::equal_range(eetops_->cbegin(),
1264  eetops_->cend(),
1265  ecalkey,
1266  comparePSMapByKey);
1267  for( const auto& ps1 : _splayedblock[reco::PFBlockElement::PS1] ) {
1268  edm::Ptr<reco::PFCluster> temp = refToPtr(ps1.first->clusterRef());
1269  for( auto pscl = assc_ps.first; pscl != assc_ps.second; ++pscl ) {
1270  if( pscl->second == temp ) {
1271  const ClusterElement* pstemp =
1272  docast(const ClusterElement*,ps1.first);
1273  eslist.push_back( PFClusterFlaggedElement(pstemp,true) );
1274  }
1275  }
1276  }
1277  for( const auto& ps2 : _splayedblock[reco::PFBlockElement::PS2] ) {
1278  edm::Ptr<reco::PFCluster> temp = refToPtr(ps2.first->clusterRef());
1279  for( auto pscl = assc_ps.first; pscl != assc_ps.second; ++pscl ) {
1280  if( pscl->second == temp ) {
1281  const ClusterElement* pstemp =
1282  docast(const ClusterElement*,ps2.first);
1283  eslist.push_back( PFClusterFlaggedElement(pstemp,true) );
1284  }
1285  }
1286  }
1287  return eslist.size();
1288  }
1289 
1291  #ifdef PFLOW_DEBUG
1292  edm::LogVerbatim("PFEGammaAlgo")
1293  //<< "Dumping current block: " << std::endl << *_currentblock << std::endl
1294  << "Dumping " << _refinableObjects.size()
1295  << " refinable objects for this block: " << std::endl;
1296  for( const auto& ro : _refinableObjects ) {
1297  std::stringstream info;
1298  info << "Refinable Object:" << std::endl;
1299  if( ro.parentSC ) {
1300  info << "\tSuperCluster element attached to object:" << std::endl
1301  << '\t';
1302  ro.parentSC->Dump(info,"\t");
1303  info << std::endl;
1304  }
1305  if( ro.electronSeed.isNonnull() ) {
1306  info << "\tGSF element attached to object:" << std::endl;
1307  ro.primaryGSFs.front().first->Dump(info,"\t");
1308  info << std::endl;
1309  info << "firstBrem : " << ro.firstBrem
1310  << " lateBrem : " << ro.lateBrem
1311  << " nBrems with cluster : " << ro.nBremsWithClusters
1312  << std::endl;;
1313  if( ro.electronClusters.size() && ro.electronClusters[0] ) {
1314  info << "electron cluster : ";
1315  ro.electronClusters[0]->Dump(info,"\t");
1316  info << std::endl;
1317  } else {
1318  info << " no electron cluster." << std::endl;
1319  }
1320  }
1321  if( ro.primaryKFs.size() ) {
1322  info << "\tPrimary KF tracks attached to object: " << std::endl;
1323  for( const auto& kf : ro.primaryKFs ) {
1324  kf.first->Dump(info,"\t");
1325  info << std::endl;
1326  }
1327  }
1328  if( ro.secondaryKFs.size() ) {
1329  info << "\tSecondary KF tracks attached to object: " << std::endl;
1330  for( const auto& kf : ro.secondaryKFs ) {
1331  kf.first->Dump(info,"\t");
1332  info << std::endl;
1333  }
1334  }
1335  if( ro.brems.size() ) {
1336  info << "\tBrem tangents attached to object: " << std::endl;
1337  for( const auto& brem : ro.brems ) {
1338  brem.first->Dump(info,"\t");
1339  info << std::endl;
1340  }
1341  }
1342  if( ro.ecalclusters.size() ) {
1343  info << "\tECAL clusters attached to object: " << std::endl;
1344  for( const auto& clus : ro.ecalclusters ) {
1345  clus.first->Dump(info,"\t");
1346  info << std::endl;
1347  if( ro.ecal2ps.find(clus.first) != ro.ecal2ps.end() ) {
1348  for( const auto& psclus : ro.ecal2ps.at(clus.first) ) {
1349  info << "\t\t Attached PS Cluster: ";
1350  psclus.first->Dump(info,"");
1351  info << std::endl;
1352  }
1353  }
1354  }
1355  }
1356  edm::LogVerbatim("PFEGammaAlgo") << info.str();
1357  }
1358  #endif
1359  }
1360 
1361  // look through our KF tracks in this block and match
1362  void PFEGammaAlgo::
1364  typedef std::multimap<double, unsigned> MatchedMap;
1365  typedef const reco::PFBlockElementGsfTrack* GsfTrackElementPtr;
1368  MatchedMap matchedGSFs, matchedECALs;
1369  std::unordered_map<GsfTrackElementPtr,MatchedMap> gsf_ecal_cache;
1370  for( auto& kftrack : _splayedblock[reco::PFBlockElement::TRACK] ) {
1371  matchedGSFs.clear();
1372  _currentblock->associatedElements(kftrack.first->index(), _currentlinks,
1373  matchedGSFs,
1376  if( matchedGSFs.empty() ) { // only run this if we aren't associated to GSF
1377  LesserByDistance closestTrackToECAL(_currentblock,_currentlinks,
1378  &kftrack);
1379  auto ecalbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1380  auto ecalend = _splayedblock[reco::PFBlockElement::ECAL].end();
1381  std::partial_sort(ecalbegin,ecalbegin+1,ecalend,closestTrackToECAL);
1382  PFFlaggedElement& closestECAL =
1384  const float dist = _currentblock->dist(kftrack.first->index(),
1385  closestECAL.first->index(),
1386  _currentlinks,
1388  bool inSC = false;
1389  for( auto& sc : _splayedblock[reco::PFBlockElement::SC] ) {
1390  float dist_sc = _currentblock->dist(sc.first->index(),
1391  closestECAL.first->index(),
1392  _currentlinks,
1394  if( dist_sc != -1.0f) { inSC = true; break; }
1395  }
1396 
1397  if( dist != -1.0f && closestECAL.second ) {
1398  bool gsflinked = false;
1399  // check that this cluster is not associated to a GSF track
1400  for(const auto& gsfflag : _splayedblock[reco::PFBlockElement::GSF]) {
1401  const reco::PFBlockElementGsfTrack* elemasgsf =
1402  docast(const reco::PFBlockElementGsfTrack*,gsfflag.first);
1404  continue; // keep clusters that have a found conversion GSF near
1405  }
1406  // make sure cache exists
1407  if( !gsf_ecal_cache.count(elemasgsf) ) {
1408  matchedECALs.clear();
1409  _currentblock->associatedElements(elemasgsf->index(), _currentlinks,
1410  matchedECALs,
1413  gsf_ecal_cache.emplace(elemasgsf,matchedECALs);
1414  MatchedMap().swap(matchedECALs);
1415  }
1416  const MatchedMap& ecal_matches = gsf_ecal_cache[elemasgsf];
1417  if( !ecal_matches.empty() ) {
1418  if( ecal_matches.begin()->second == closestECAL.first->index() ) {
1419  gsflinked = true;
1420  break;
1421  }
1422  }
1423  } // loop over primary GSF tracks
1424  if( !gsflinked && !inSC) {
1425  // determine if we should remove the matched cluster
1426  const reco::PFBlockElementTrack * kfEle =
1427  docast(const reco::PFBlockElementTrack*,kftrack.first);
1428  const reco::TrackRef& trackref = kfEle->trackRef();
1429 
1430  const int nexhits =
1431  trackref->hitPattern().numberOfLostHits(HitPattern::MISSING_INNER_HITS);
1432  bool fromprimaryvertex = false;
1433  for( auto vtxtks = cfg_.primaryVtx->tracks_begin();
1434  vtxtks != cfg_.primaryVtx->tracks_end(); ++ vtxtks ) {
1435  if( trackref == vtxtks->castTo<reco::TrackRef>() ) {
1436  fromprimaryvertex = true;
1437  break;
1438  }
1439  }// loop over tracks in primary vertex
1440  // if associated to good non-GSF matched track remove this cluster
1441  if( PFTrackAlgoTools::isGoodForEGMPrimary(trackref->algo()) && nexhits == 0 && fromprimaryvertex ) {
1442  closestECAL.second = false;
1443  } else { // otherwise associate the cluster and KF track
1444  _recoveredlinks.push_back( ElementMap::value_type(closestECAL.first,kftrack.first) );
1445  _recoveredlinks.push_back( ElementMap::value_type(kftrack.first,closestECAL.first) );
1446  }
1447 
1448 
1449 
1450 
1451  }
1452  } // found a good closest ECAL match
1453  } // no GSF track matched to KF
1454  } // loop over KF elements
1455  }
1456 
1457  void PFEGammaAlgo::
1458  mergeROsByAnyLink(std::list<PFEGammaAlgo::ProtoEGObject>& ROs) {
1459  if( ROs.size() < 2 ) return; // nothing to do with one or zero ROs
1460  bool check_for_merge = true;
1461  while( check_for_merge ) {
1462  // bugfix for early termination merging loop (15 April 2014)
1463  // check all pairwise combinations in the list
1464  // if one has a merge shuffle it to the front of the list
1465  // if there are no merges left to do we can terminate
1466  for( auto it1 = ROs.begin(); it1 != ROs.end(); ++it1 ) {
1467  TestIfROMergableByLink mergeTest(*it1);
1468  auto find_start = it1; ++find_start;
1469  auto has_merge = std::find_if(find_start,ROs.end(),mergeTest);
1470  if( has_merge != ROs.end() && it1 != ROs.begin() ) {
1471  std::swap(*(ROs.begin()),*it1);
1472  break;
1473  }
1474  }// ensure mergables are shuffled to the front
1475  ProtoEGObject& thefront = ROs.front();
1476  TestIfROMergableByLink mergeTest(thefront);
1477  auto mergestart = ROs.begin(); ++mergestart;
1478  auto nomerge = std::partition(mergestart,ROs.end(),mergeTest);
1479  if( nomerge != mergestart ) {
1480  LOGDRESSED("PFEGammaAlgo::mergeROsByAnyLink()")
1481  << "Found objects " << std::distance(mergestart,nomerge)
1482  << " to merge by links to the front!" << std::endl;
1483  for( auto roToMerge = mergestart; roToMerge != nomerge; ++roToMerge) {
1484  //bugfix! L.Gray 14 Jan 2016
1485  // -- check that the front is still mergeable!
1486  if( !thefront.ecalclusters.empty() && !roToMerge->ecalclusters.empty() ) {
1487  if( thefront.ecalclusters.front().first->clusterRef()->layer() !=
1488  roToMerge->ecalclusters.front().first->clusterRef()->layer() ) {
1489  LOGWARN("PFEGammaAlgo::mergeROsByAnyLink")
1490  << "Tried to merge EB and EE clusters! Skipping!";
1491  ROs.push_back(*roToMerge);
1492  continue;
1493  }
1494  }
1495  //end bugfix
1496  thefront.ecalclusters.insert(thefront.ecalclusters.end(),
1497  roToMerge->ecalclusters.begin(),
1498  roToMerge->ecalclusters.end());
1499  thefront.ecal2ps.insert(roToMerge->ecal2ps.begin(),
1500  roToMerge->ecal2ps.end());
1501  thefront.secondaryKFs.insert(thefront.secondaryKFs.end(),
1502  roToMerge->secondaryKFs.begin(),
1503  roToMerge->secondaryKFs.end());
1504 
1505  thefront.localMap.insert(thefront.localMap.end(),
1506  roToMerge->localMap.begin(),
1507  roToMerge->localMap.end());
1508  // TO FIX -> use best (E_gsf - E_clustersum)/E_GSF
1509  if( !thefront.parentSC && roToMerge->parentSC ) {
1510  thefront.parentSC = roToMerge->parentSC;
1511  }
1512  if( thefront.electronSeed.isNull() &&
1513  roToMerge->electronSeed.isNonnull() ) {
1514  thefront.electronSeed = roToMerge->electronSeed;
1515  thefront.primaryGSFs.insert(thefront.primaryGSFs.end(),
1516  roToMerge->primaryGSFs.begin(),
1517  roToMerge->primaryGSFs.end());
1518  thefront.primaryKFs.insert(thefront.primaryKFs.end(),
1519  roToMerge->primaryKFs.begin(),
1520  roToMerge->primaryKFs.end());
1521  thefront.brems.insert(thefront.brems.end(),
1522  roToMerge->brems.begin(),
1523  roToMerge->brems.end());
1524  thefront.electronClusters = roToMerge->electronClusters;
1525  thefront.nBremsWithClusters = roToMerge->nBremsWithClusters;
1526  thefront.firstBrem = roToMerge->firstBrem;
1527  thefront.lateBrem = roToMerge->lateBrem;
1528  } else if ( thefront.electronSeed.isNonnull() &&
1529  roToMerge->electronSeed.isNonnull()) {
1530  LOGWARN("PFEGammaAlgo::mergeROsByAnyLink")
1531  << "Need to implement proper merging of two gsf candidates!"
1532  << std::endl;
1533  }
1534  }
1535  ROs.erase(mergestart,nomerge);
1536  // put the merged element in the back of the cleaned list
1537  ROs.push_back(ROs.front());
1538  ROs.pop_front();
1539  } else {
1540  check_for_merge = false;
1541  }
1542  }
1543  LOGDRESSED("PFEGammaAlgo::mergeROsByAnyLink()")
1544  << "After merging by links there are: " << ROs.size()
1545  << " refinable EGamma objects!" << std::endl;
1546  }
1547 
1548 // pull in KF tracks associated to the RO but not closer to another
1549 // NB: in initializeProtoCands() we forced the GSF tracks not to be
1550 // from a conversion, but we will leave a protection here just in
1551 // case things change in the future
1552 void PFEGammaAlgo::
1557  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1558  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1559  for( auto& gsfflagged : RO.primaryGSFs ) {
1560  const PFGSFElement* seedtk = gsfflagged.first;
1561  // don't process SC-only ROs or secondary seeded ROs
1562  if( RO.electronSeed.isNull() || seedtk->trackType(convType) ) continue;
1563  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::TRACK>
1564  gsfTrackToKFs(_currentblock,_currentlinks,seedtk);
1565  // get KF tracks not closer to another and not already used
1566  auto notlinked = std::partition(KFbegin,KFend,gsfTrackToKFs);
1567  // attach tracks and set as used
1568  for( auto kft = KFbegin; kft != notlinked; ++kft ) {
1569  const PFKFElement* elemaskf =
1570  docast(const PFKFElement*,kft->first);
1571  // don't care about things that aren't primaries or directly
1572  // associated secondary tracks
1573  if( isPrimaryTrack(*elemaskf,*seedtk) &&
1574  !elemaskf->trackType(convType) ) {
1575  kft->second = false;
1576  RO.primaryKFs.push_back(std::make_pair(elemaskf,true));
1577  RO.localMap.push_back( ElementMap::value_type(seedtk,elemaskf) );
1578  RO.localMap.push_back( ElementMap::value_type(elemaskf,seedtk) );
1579  } else if ( elemaskf->trackType(convType) ) {
1580  kft->second = false;
1581  RO.secondaryKFs.push_back(std::make_pair(elemaskf,true));
1582  RO.localMap.push_back( ElementMap::value_type(seedtk,elemaskf) );
1583  RO.localMap.push_back( ElementMap::value_type(elemaskf,seedtk) );
1584  }
1585  }// loop on closest KFs not closer to other GSFs
1586  } // loop on GSF primaries on RO
1587 }
1588 
1589 void PFEGammaAlgo::
1594  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1595  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1596  for( auto& kfflagged : RO.primaryKFs ) {
1597  const PFKFElement* primkf = kfflagged.first;
1598  // don't process SC-only ROs or secondary seeded ROs
1599  if( primkf->trackType(convType) ) {
1600  throw cms::Exception("PFEGammaAlgo::linkRefinableObjectPrimaryKFsToSecondaryKFs()")
1601  << "A KF track from conversion has been assigned as a primary!!"
1602  << std::endl;
1603  }
1604  NotCloserToOther<reco::PFBlockElement::TRACK,reco::PFBlockElement::TRACK,true>
1605  kfTrackToKFs(_currentblock,_currentlinks,primkf);
1606  // get KF tracks not closer to another and not already used
1607  auto notlinked = std::partition(KFbegin,KFend,kfTrackToKFs);
1608  // attach tracks and set as used
1609  for( auto kft = KFbegin; kft != notlinked; ++kft ) {
1610  const PFKFElement* elemaskf =
1611  docast(const PFKFElement*,kft->first);
1612  // don't care about things that aren't primaries or directly
1613  // associated secondary tracks
1614  if( elemaskf->trackType(convType) ) {
1615  kft->second = false;
1616  RO.secondaryKFs.push_back(std::make_pair(elemaskf,true));
1617  RO.localMap.push_back( ElementMap::value_type(primkf,elemaskf) );
1618  RO.localMap.push_back( ElementMap::value_type(elemaskf,primkf) );
1619  }
1620  }// loop on closest KFs not closer to other KFs
1621  } // loop on KF primaries on RO
1622 }
1623 
1624 // try to associate the tracks to cluster elements which are not used
1625 void PFEGammaAlgo::
1628  RO.electronClusters.push_back(nullptr);
1629  return;
1630  }
1631  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1632  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1633  for( auto& primgsf : RO.primaryGSFs ) {
1634  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::ECAL>
1635  gsfTracksToECALs(_currentblock,_currentlinks,primgsf.first);
1636  CompatibleEoPOut eoverp_test(primgsf.first);
1637  // get set of matching ecals not already in SC
1638  auto notmatched_blk = std::partition(ECALbegin,ECALend,gsfTracksToECALs);
1639  notmatched_blk = std::partition(ECALbegin,notmatched_blk,eoverp_test);
1640  // get set of matching ecals already in the RO
1641  auto notmatched_sc = std::partition(RO.ecalclusters.begin(),
1642  RO.ecalclusters.end(),
1643  gsfTracksToECALs);
1644  notmatched_sc = std::partition(RO.ecalclusters.begin(),
1645  notmatched_sc,
1646  eoverp_test);
1647  // look inside the SC for the ECAL cluster
1648  for( auto ecal = RO.ecalclusters.begin(); ecal != notmatched_sc; ++ecal ) {
1649  const PFClusterElement* elemascluster =
1650  docast(const PFClusterElement*,ecal->first);
1651  PFClusterFlaggedElement temp(elemascluster,true);
1652  LOGDRESSED("PFEGammaAlgo::linkGSFTracktoECAL()")
1653  << "Found a cluster already in RO by GSF extrapolation"
1654  << " at ECAL surface!" << std::endl
1655  << *elemascluster << std::endl;
1656 
1657  RO.localMap.push_back(ElementMap::value_type(primgsf.first,temp.first));
1658  RO.localMap.push_back(ElementMap::value_type(temp.first,primgsf.first));
1659  }
1660  // look outside the SC for the ecal cluster
1661  for( auto ecal = ECALbegin; ecal != notmatched_blk; ++ecal ) {
1662  const PFClusterElement* elemascluster =
1663  docast(const PFClusterElement*,ecal->first);
1664  LOGDRESSED("PFEGammaAlgo::linkGSFTracktoECAL()")
1665  << "Found a cluster not already in RO by GSF extrapolation"
1666  << " at ECAL surface!" << std::endl
1667  << *elemascluster << std::endl;
1668  if( addPFClusterToROSafe(elemascluster,RO) ) {
1669  attachPSClusters(elemascluster,RO.ecal2ps[elemascluster]);
1670  RO.localMap.push_back(ElementMap::value_type(primgsf.first,elemascluster));
1671  RO.localMap.push_back(ElementMap::value_type(elemascluster,primgsf.first));
1672  ecal->second = false;
1673  }
1674  }
1675  }
1676 }
1677 
1678 // try to associate the tracks to cluster elements which are not used
1679 void PFEGammaAlgo::
1682  auto HCALbegin = _splayedblock[reco::PFBlockElement::HCAL].begin();
1683  auto HCALend = _splayedblock[reco::PFBlockElement::HCAL].end();
1684  for( auto& primgsf : RO.primaryGSFs ) {
1685  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::HCAL>
1686  gsfTracksToHCALs(_currentblock,_currentlinks,primgsf.first);
1687  CompatibleEoPOut eoverp_test(primgsf.first);
1688  auto notmatched = std::partition(HCALbegin,HCALend,gsfTracksToHCALs);
1689  for( auto hcal = HCALbegin; hcal != notmatched; ++hcal ) {
1690  const PFClusterElement* elemascluster =
1691  docast(const PFClusterElement*,hcal->first);
1692  PFClusterFlaggedElement temp(elemascluster,true);
1693  LOGDRESSED("PFEGammaAlgo::linkGSFTracktoECAL()")
1694  << "Found an HCAL cluster associated to GSF extrapolation"
1695  << std::endl;
1696  RO.hcalClusters.push_back(temp);
1697  RO.localMap.push_back( ElementMap::value_type(primgsf.first,temp.first) );
1698  RO.localMap.push_back( ElementMap::value_type(temp.first,primgsf.first) );
1699  hcal->second = false;
1700  }
1701  }
1702 }
1703 
1704 // try to associate the tracks to cluster elements which are not used
1705 void PFEGammaAlgo::
1708  for( auto& primkf : RO.primaryKFs ) linkKFTrackToECAL(primkf,RO);
1709  for( auto& secdkf : RO.secondaryKFs ) linkKFTrackToECAL(secdkf,RO);
1710 }
1711 
1712 void
1713 PFEGammaAlgo::linkKFTrackToECAL(const KFFlaggedElement& kfflagged,
1714  ProtoEGObject& RO) {
1715  std::vector<PFClusterFlaggedElement>& currentECAL = RO.ecalclusters;
1716  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1717  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1718  NotCloserToOther<reco::PFBlockElement::TRACK,reco::PFBlockElement::ECAL>
1719  kfTrackToECALs(_currentblock,_currentlinks,kfflagged.first);
1720  NotCloserToOther<reco::PFBlockElement::GSF,reco::PFBlockElement::ECAL>
1721  kfTrackGSFToECALs(_currentblock,_currentlinks,kfflagged.first);
1722  //get the ECAL elements not used and not closer to another KF
1723  auto notmatched_sc = std::partition(currentECAL.begin(),
1724  currentECAL.end(),
1725  kfTrackToECALs);
1726  //get subset ECAL elements not used or closer to another GSF of any type
1727  notmatched_sc = std::partition(currentECAL.begin(),
1728  notmatched_sc,
1729  kfTrackGSFToECALs);
1730  for( auto ecalitr = currentECAL.begin(); ecalitr != notmatched_sc;
1731  ++ecalitr ) {
1732  const PFClusterElement* elemascluster =
1733  docast(const PFClusterElement*,ecalitr->first);
1734  PFClusterFlaggedElement flaggedclus(elemascluster,true);
1735 
1736  LOGDRESSED("PFEGammaAlgo::linkKFTracktoECAL()")
1737  << "Found a cluster already in RO by KF extrapolation"
1738  << " at ECAL surface!" << std::endl
1739  << *elemascluster << std::endl;
1740  RO.localMap.push_back(ElementMap::value_type(elemascluster,
1741  kfflagged.first));
1742  RO.localMap.push_back(ElementMap::value_type(kfflagged.first,
1743  elemascluster));
1744  }
1745  //get the ECAL elements not used and not closer to another KF
1746  auto notmatched_blk = std::partition(ECALbegin,ECALend,kfTrackToECALs);
1747  //get subset ECAL elements not used or closer to another GSF of any type
1748  notmatched_blk = std::partition(ECALbegin,notmatched_blk,kfTrackGSFToECALs);
1749  for( auto ecalitr = ECALbegin; ecalitr != notmatched_blk; ++ecalitr ) {
1750  const PFClusterElement* elemascluster =
1751  docast(const PFClusterElement*,ecalitr->first);
1752  if( addPFClusterToROSafe(elemascluster,RO) ) {
1753  attachPSClusters(elemascluster,RO.ecal2ps[elemascluster]);
1754  ecalitr->second = false;
1755 
1756  LOGDRESSED("PFEGammaAlgo::linkKFTracktoECAL()")
1757  << "Found a cluster not in RO by KF extrapolation"
1758  << " at ECAL surface!" << std::endl
1759  << *elemascluster << std::endl;
1760  RO.localMap.push_back(ElementMap::value_type(elemascluster,
1761  kfflagged.first));
1762  RO.localMap.push_back( ElementMap::value_type(kfflagged.first,
1763  elemascluster));
1764  }
1765  }
1766 }
1767 
1768 void PFEGammaAlgo::
1770  if( RO.brems.empty() ) return;
1771  int FirstBrem = -1;
1772  int TrajPos = -1;
1773  int lastBremTrajPos = -1;
1774  for( auto& bremflagged : RO.brems ) {
1775  bool has_clusters = false;
1776  TrajPos = (bremflagged.first->indTrajPoint())-2;
1777  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1778  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1779  NotCloserToOther<reco::PFBlockElement::BREM,reco::PFBlockElement::ECAL>
1780  BremToECALs(_currentblock,_currentlinks,bremflagged.first);
1781  // check for late brem using clusters already in the SC
1782  auto RSCBegin = RO.ecalclusters.begin();
1783  auto RSCEnd = RO.ecalclusters.end();
1784  auto notmatched_rsc = std::partition(RSCBegin,RSCEnd,BremToECALs);
1785  for( auto ecal = RSCBegin; ecal != notmatched_rsc; ++ecal ) {
1786  float deta =
1787  std::abs( ecal->first->clusterRef()->positionREP().eta() -
1788  bremflagged.first->positionAtECALEntrance().eta() );
1789  if( deta < 0.015 ) {
1790  has_clusters = true;
1791  if( lastBremTrajPos == -1 || lastBremTrajPos < TrajPos ) {
1792  lastBremTrajPos = TrajPos;
1793  }
1794  if( FirstBrem == -1 || TrajPos < FirstBrem ) { // set brem information
1795  FirstBrem = TrajPos;
1796  RO.firstBrem = TrajPos;
1797  }
1798  LOGDRESSED("PFEGammaAlgo::linkBremToECAL()")
1799  << "Found a cluster already in SC linked to brem extrapolation"
1800  << " at ECAL surface!" << std::endl;
1801  RO.localMap.push_back( ElementMap::value_type(ecal->first,bremflagged.first) );
1802  RO.localMap.push_back( ElementMap::value_type(bremflagged.first,ecal->first) );
1803  }
1804  }
1805  // grab new clusters from the block (ensured to not be late brem)
1806  auto notmatched_block = std::partition(ECALbegin,ECALend,BremToECALs);
1807  for( auto ecal = ECALbegin; ecal != notmatched_block; ++ecal ) {
1808  float deta =
1809  std::abs( ecal->first->clusterRef()->positionREP().eta() -
1810  bremflagged.first->positionAtECALEntrance().eta() );
1811  if( deta < 0.015 ) {
1812  has_clusters = true;
1813  if( lastBremTrajPos == -1 || lastBremTrajPos < TrajPos ) {
1814  lastBremTrajPos = TrajPos;
1815  }
1816  if( FirstBrem == -1 || TrajPos < FirstBrem ) { // set brem information
1817 
1818  FirstBrem = TrajPos;
1819  RO.firstBrem = TrajPos;
1820  }
1821  const PFClusterElement* elemasclus =
1822  docast(const PFClusterElement*,ecal->first);
1823  if( addPFClusterToROSafe(elemasclus,RO) ) {
1824  attachPSClusters(elemasclus,RO.ecal2ps[elemasclus]);
1825 
1826  RO.localMap.push_back( ElementMap::value_type(ecal->first,bremflagged.first) );
1827  RO.localMap.push_back( ElementMap::value_type(bremflagged.first,ecal->first) );
1828  ecal->second = false;
1829  LOGDRESSED("PFEGammaAlgo::linkBremToECAL()")
1830  << "Found a cluster not already associated by brem extrapolation"
1831  << " at ECAL surface!" << std::endl;
1832  }
1833 
1834  }
1835  }
1836  if(has_clusters) {
1837  if( RO.nBremsWithClusters == -1 ) RO.nBremsWithClusters = 0;
1838  ++RO.nBremsWithClusters;
1839  }
1840  }
1841 }
1842 
1843 void PFEGammaAlgo::
1845  IsConversionTrack<reco::PFBlockElementTrack> isConvKf;
1846  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1847  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1848  auto BeginROskfs = RO.secondaryKFs.begin();
1849  auto EndROskfs = RO.secondaryKFs.end();
1850  auto ronotconv = std::partition(BeginROskfs,EndROskfs,isConvKf);
1851  size_t convkfs_end = std::distance(BeginROskfs,ronotconv);
1852  for( size_t idx = 0; idx < convkfs_end; ++idx ) {
1853  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
1854  NotCloserToOther<reco::PFBlockElement::TRACK,
1856  true>
1857  TracksToTracks(_currentblock,_currentlinks, secKFs[idx].first);
1858  auto notmatched = std::partition(KFbegin,KFend,TracksToTracks);
1859  notmatched = std::partition(KFbegin,notmatched,isConvKf);
1860  for( auto kf = KFbegin; kf != notmatched; ++kf ) {
1861  const reco::PFBlockElementTrack* elemaskf =
1862  docast(const reco::PFBlockElementTrack*,kf->first);
1863  RO.secondaryKFs.push_back( std::make_pair(elemaskf,true) );
1864  RO.localMap.push_back( ElementMap::value_type(secKFs[idx].first,kf->first) );
1865  RO.localMap.push_back( ElementMap::value_type(kf->first,secKFs[idx].first) );
1866  kf->second = false;
1867  }
1868  }
1869 }
1870 
1871 void PFEGammaAlgo::
1873  ProtoEGObject& RO) {
1874  IsConversionTrack<reco::PFBlockElementTrack> isConvKf;
1875  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
1876  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
1877  for( auto& ecal : RO.ecalclusters ) {
1878  NotCloserToOther<reco::PFBlockElement::ECAL,
1880  true>
1881  ECALToTracks(_currentblock,_currentlinks,ecal.first);
1882  auto notmatchedkf = std::partition(KFbegin,KFend,ECALToTracks);
1883  auto notconvkf = std::partition(KFbegin,notmatchedkf,isConvKf);
1884  // add identified KF conversion tracks
1885  for( auto kf = KFbegin; kf != notconvkf; ++kf ) {
1886  const reco::PFBlockElementTrack* elemaskf =
1887  docast(const reco::PFBlockElementTrack*,kf->first);
1888  RO.secondaryKFs.push_back( std::make_pair(elemaskf,true) );
1889  RO.localMap.push_back( ElementMap::value_type(ecal.first,elemaskf) );
1890  RO.localMap.push_back( ElementMap::value_type(elemaskf,ecal.first) );
1891  kf->second = false;
1892  }
1893  // go through non-conv-identified kfs and check MVA to add conversions
1894  for( auto kf = notconvkf; kf != notmatchedkf; ++kf ) {
1895  float mvaval = EvaluateSingleLegMVA(hoc,_currentblock,
1896  *cfg_.primaryVtx,
1897  kf->first->index());
1898  if(mvaval > cfg_.mvaConvCut) {
1899  const reco::PFBlockElementTrack* elemaskf =
1900  docast(const reco::PFBlockElementTrack*,kf->first);
1901  RO.secondaryKFs.push_back( std::make_pair(elemaskf,true) );
1902  RO.localMap.push_back( ElementMap::value_type(ecal.first,elemaskf) );
1903  RO.localMap.push_back( ElementMap::value_type(elemaskf,ecal.first) );
1904  kf->second = false;
1905 
1906  RO.singleLegConversionMvaMap.insert(std::make_pair(elemaskf, mvaval));
1907  }
1908  }
1909  }
1910 }
1911 
1912 void PFEGammaAlgo::
1914  auto ECALbegin = _splayedblock[reco::PFBlockElement::ECAL].begin();
1915  auto ECALend = _splayedblock[reco::PFBlockElement::ECAL].end();
1916  for( auto& skf : RO.secondaryKFs ) {
1917  NotCloserToOther<reco::PFBlockElement::TRACK,
1919  false>
1920  TracksToECALwithCut(_currentblock,_currentlinks,skf.first,1.5f);
1921  auto notmatched = std::partition(ECALbegin,ECALend,TracksToECALwithCut);
1922  for( auto ecal = ECALbegin; ecal != notmatched; ++ecal ) {
1923  const reco::PFBlockElementCluster* elemascluster =
1924  docast(const reco::PFBlockElementCluster*,ecal->first);
1925  if( addPFClusterToROSafe(elemascluster,RO) ) {
1926  attachPSClusters(elemascluster,RO.ecal2ps[elemascluster]);
1927  RO.localMap.push_back(ElementMap::value_type(skf.first,elemascluster));
1928  RO.localMap.push_back(ElementMap::value_type(elemascluster,skf.first));
1929  ecal->second = false;
1930  }
1931  }
1932  }
1933 }
1934 
1935 void PFEGammaAlgo::
1937  const std::list<PFEGammaAlgo::ProtoEGObject>& ROs,
1938  reco::PFCandidateCollection& egcands,
1940  // reset output collections
1941  egcands.clear();
1942  egxs.clear();
1943  refinedscs_.clear();
1944  egcands.reserve(ROs.size());
1945  egxs.reserve(ROs.size());
1946  refinedscs_.reserve(ROs.size());
1947  for( auto& RO : ROs ) {
1948  if( RO.ecalclusters.empty() &&
1950 
1953  if( !RO.primaryGSFs.empty() || !RO.primaryKFs.empty() ) {
1954  cand.setPdgId(-11); // anything with a primary track is an electron
1955  } else {
1956  cand.setPdgId(22); // anything with no primary track is a photon
1957  }
1958  if( !RO.primaryKFs.empty() ) {
1959  cand.setCharge(RO.primaryKFs[0].first->trackRef()->charge());
1960  xtra.setKfTrackRef(RO.primaryKFs[0].first->trackRef());
1961  cand.setTrackRef(RO.primaryKFs[0].first->trackRef());
1962  cand.addElementInBlock(_currentblock,RO.primaryKFs[0].first->index());
1963  }
1964  if( !RO.primaryGSFs.empty() ) {
1965  cand.setCharge(RO.primaryGSFs[0].first->GsftrackRef()->chargeMode());
1966  xtra.setGsfTrackRef(RO.primaryGSFs[0].first->GsftrackRef());
1967  cand.setGsfTrackRef(RO.primaryGSFs[0].first->GsftrackRef());
1968  cand.addElementInBlock(_currentblock,RO.primaryGSFs[0].first->index());
1969  }
1970  if( RO.parentSC ) {
1971  xtra.setSuperClusterPFECALRef(RO.parentSC->superClusterRef());
1972  // we'll set to the refined supercluster back up in the producer
1973  cand.setSuperClusterRef(RO.parentSC->superClusterRef());
1974  xtra.setSuperClusterRef(RO.parentSC->superClusterRef());
1975  cand.addElementInBlock(_currentblock,RO.parentSC->index());
1976  }
1977  // add brems
1978  for( const auto& bremflagged : RO.brems ) {
1979  const PFBremElement* brem = bremflagged.first;
1980  cand.addElementInBlock(_currentblock,brem->index());
1981  }
1982  // add clusters and ps clusters
1983  for( const auto& ecal : RO.ecalclusters ) {
1984  const PFClusterElement* clus = ecal.first;
1985  cand.addElementInBlock(_currentblock,clus->index());
1986  if( RO.ecal2ps.count(clus) ) {
1987  for( auto& ps : RO.ecal2ps.at(clus) ) {
1988  const PFClusterElement* psclus = ps.first;
1989  cand.addElementInBlock(_currentblock,psclus->index());
1990  }
1991  }
1992  }
1993  // add secondary tracks
1994  for( const auto& secdkf : RO.secondaryKFs ) {
1995  const PFKFElement* kf = secdkf.first;
1997  const reco::ConversionRefVector& convrefs = kf->convRefs();
1998  bool no_conv_ref = true;
1999  for( const auto& convref : convrefs ) {
2000  if( convref.isNonnull() && convref.isAvailable() ) {
2001  xtra.addConversionRef(convref);
2002  no_conv_ref = false;
2003  }
2004  }
2005  if( no_conv_ref ) {
2006  //single leg conversions
2007 
2008  //look for stored mva value in map or else recompute
2009  const auto &mvavalmapped = RO.singleLegConversionMvaMap.find(kf);
2010  //FIXME: Abuse single mva value to store both provenance and single leg mva score
2011  //by storing 3.0 + mvaval
2012  float mvaval = ( mvavalmapped != RO.singleLegConversionMvaMap.end() ?
2013  mvavalmapped->second :
2015  *cfg_.primaryVtx,
2016  kf->index()) );
2017 
2018  xtra.addSingleLegConvTrackRefMva(std::make_pair(kf->trackRef(),mvaval));
2019  }
2020  }
2021 
2022  // build the refined supercluster from those clusters left in the cand
2023  refinedscs_.push_back(buildRefinedSuperCluster(RO));
2024 
2025  //*TODO* cluster time is not reliable at the moment, so only use track timing
2026  float trkTime = 0, trkTimeErr = -1;
2027  if (!RO.primaryGSFs.empty() && RO.primaryGSFs[0].first->isTimeValid()) {
2028  trkTime = RO.primaryGSFs[0].first->time();
2029  trkTimeErr = RO.primaryGSFs[0].first->timeError();
2030  } else if (!RO.primaryKFs.empty() && RO.primaryKFs[0].first->isTimeValid()) {
2031  trkTime = RO.primaryKFs[0].first->time();
2032  trkTimeErr = RO.primaryKFs[0].first->timeError();
2033  }
2034  if (trkTimeErr >= 0) {
2035  cand.setTime( trkTime, trkTimeErr );
2036  }
2037 
2038  const reco::SuperCluster& the_sc = refinedscs_.back();
2039  // with the refined SC in hand we build a naive candidate p4
2040  // and set the candidate ECAL position to either the barycenter of the
2041  // supercluster (if super-cluster present) or the seed of the
2042  // new SC generated by the EGAlgo
2043  const double scE = the_sc.energy();
2044  if( scE != 0.0 ) {
2045  const math::XYZPoint& seedPos = the_sc.seed()->position();
2046  math::XYZVector egDir = the_sc.position()-cfg_.primaryVtx->position();
2047  egDir = egDir.Unit();
2048  cand.setP4(math::XYZTLorentzVector(scE*egDir.x(),
2049  scE*egDir.y(),
2050  scE*egDir.z(),
2051  scE ));
2052  math::XYZPointF ecalPOS_f(seedPos.x(),seedPos.y(),seedPos.z());
2053  cand.setPositionAtECALEntrance(ecalPOS_f);
2054  cand.setEcalEnergy(the_sc.rawEnergy(),the_sc.energy());
2055  } else if ( cfg_.produceEGCandsWithNoSuperCluster &&
2056  !RO.primaryGSFs.empty() ) {
2057  const PFGSFElement* gsf = RO.primaryGSFs[0].first;
2058  const reco::GsfTrackRef& gref = gsf->GsftrackRef();
2059  math::XYZTLorentzVector p4(gref->pxMode(),gref->pyMode(),
2060  gref->pzMode(),gref->pMode());
2061  cand.setP4(p4);
2063  } else if ( cfg_.produceEGCandsWithNoSuperCluster &&
2064  !RO.primaryKFs.empty() ) {
2065  const PFKFElement* kf = RO.primaryKFs[0].first;
2066  reco::TrackRef kref = RO.primaryKFs[0].first->trackRef();
2067  math::XYZTLorentzVector p4(kref->px(),kref->py(),kref->pz(),kref->p());
2068  cand.setP4(p4);
2070  }
2071  const float ele_mva_value = calculate_ele_mva(hoc,RO,xtra);
2072  fill_extra_info(RO,xtra);
2073  //std::cout << "PFEG ele_mva: " << ele_mva_value << std::endl;
2074  xtra.setMVA(ele_mva_value);
2075  cand.set_mva_e_pi(ele_mva_value);
2076  egcands.push_back(cand);
2077  egxs.push_back(xtra);
2078  }
2079 }
2080 
2081 float PFEGammaAlgo::
2083  const PFEGammaAlgo::ProtoEGObject& RO,
2085  if( RO.primaryGSFs.empty() ) return -2.0f;
2086  const PFGSFElement* gsfElement = RO.primaryGSFs.front().first;
2087  const PFKFElement* kfElement = nullptr;
2088  if( !RO.primaryKFs.empty() ) kfElement = RO.primaryKFs.front().first;
2089  reco::GsfTrackRef RefGSF= gsfElement->GsftrackRef();
2090  reco::TrackRef RefKF;
2091  constexpr float m_el = 0.000511;
2092  const double Ein_gsf = std::hypot(RefGSF->pMode(),m_el);
2093  double deta_gsfecal = 1e6;
2094  double sigmaEtaEta = 1e-14;
2095  const double Ene_hcalgsf = std::accumulate(RO.hcalClusters.begin(),
2096  RO.hcalClusters.end(),
2097  0.0,
2098  [](const double a,
2099  const PFClusterFlaggedElement& b)
2100  { return a + b.first->clusterRef()->energy(); }
2101  );
2102  if( !RO.primaryKFs.empty() ) {
2103  RefKF = RO.primaryKFs.front().first->trackRef();
2104  }
2105  const double Eout_gsf = gsfElement->Pout().t();
2106  const double Etaout_gsf = gsfElement->positionAtECALEntrance().eta();
2107  double FirstEcalGsfEnergy(0.0), OtherEcalGsfEnergy(0.0), EcalBremEnergy(0.0);
2108  //shower shape of cluster closest to gsf track
2109  std::vector<const reco::PFCluster*> gsfcluster;
2110  for( const auto& ecal : RO.ecalclusters ) {
2111  const double cenergy = ecal.first->clusterRef()->correctedEnergy();
2112  ElementMap::value_type gsfToEcal(gsfElement,ecal.first);
2113  ElementMap::value_type kfToEcal(kfElement,ecal.first);
2114  bool hasgsf =
2115  ( std::find(RO.localMap.begin(), RO.localMap.end(), gsfToEcal) ==
2116  RO.localMap.end() );
2117  bool haskf =
2118  ( std::find(RO.localMap.begin(), RO.localMap.end(), kfToEcal) ==
2119  RO.localMap.end() );
2120  bool hasbrem = false;
2121  for( const auto& brem : RO.brems ) {
2122  ElementMap::value_type bremToEcal(brem.first,ecal.first);
2123  if( std::find(RO.localMap.begin(), RO.localMap.end(), bremToEcal) !=
2124  RO.localMap.end() ) {
2125  hasbrem = true;
2126  }
2127  }
2128  if( hasbrem && ecal.first != RO.electronClusters[0] ) {
2129  EcalBremEnergy += cenergy;
2130  }
2131  if( !hasbrem && ecal.first != RO.electronClusters[0] ) {
2132  if( hasgsf ) OtherEcalGsfEnergy += cenergy;
2133  if( haskf ) EcalBremEnergy += cenergy; // from conv. brem!
2134  if( !(hasgsf || haskf) ) OtherEcalGsfEnergy += cenergy; // stuff from SC
2135  }
2136  }
2137 
2138  if( RO.electronClusters[0] ) {
2139  reco::PFClusterRef cref = RO.electronClusters[0]->clusterRef();
2141  FirstEcalGsfEnergy = cref->correctedEnergy();
2142  deta_gsfecal = cref->positionREP().eta() - Etaout_gsf;
2143  gsfcluster.push_back(&*cref);
2144  PFClusterWidthAlgo pfwidth(gsfcluster);
2145  sigmaEtaEta = pfwidth.pflowSigmaEtaEta();
2146  }
2147 
2148  // brem sequence information
2149  lateBrem = firstBrem = earlyBrem = -1.0f;
2150  if(RO.nBremsWithClusters > 0) {
2151  if (RO.lateBrem == 1) lateBrem = 1.0f;
2152  else lateBrem = 0.0f;
2153  firstBrem = RO.firstBrem;
2154  if(RO.firstBrem < 4) earlyBrem = 1.0f;
2155  else earlyBrem = 0.0f;
2156  }
2157  xtra.setEarlyBrem(earlyBrem);
2158  xtra.setLateBrem(lateBrem);
2159  if( FirstEcalGsfEnergy > 0.0 ) {
2160  if( RefGSF.isNonnull() ) {
2161  xtra.setGsfTrackPout(gsfElement->Pout());
2162  // normalization observables
2163  const float Pt_gsf = RefGSF->ptMode();
2164  lnPt_gsf = std::log(Pt_gsf);
2165  Eta_gsf = RefGSF->etaMode();
2166  // tracking observables
2167  const double ptModeErrorGsf = RefGSF->ptModeError();
2168  dPtOverPt_gsf = (ptModeErrorGsf > 0. ? ptModeErrorGsf/Pt_gsf : 1.0);
2169  nhit_gsf = RefGSF->hitPattern().trackerLayersWithMeasurement();
2170  chi2_gsf = RefGSF->normalizedChi2();
2171  DPtOverPt_gsf = (Pt_gsf - gsfElement->Pout().pt())/Pt_gsf;
2172  // kalman filter vars
2173  nhit_kf = 0;
2174  chi2_kf = -0.01;
2175  DPtOverPt_kf = -0.01;
2176  if( RefKF.isNonnull() ) {
2177  nhit_kf = RefKF->hitPattern().trackerLayersWithMeasurement();
2178  chi2_kf = RefKF->normalizedChi2();
2179  // not used for moment, weird behavior of variable
2180  // DPtOverPt_kf = (RefKF->pt() - RefKF->outerPt())/RefKF->pt();
2181  }
2182  //tracker + calorimetry observables
2183  const double EcalETot =
2184  (FirstEcalGsfEnergy+OtherEcalGsfEnergy+EcalBremEnergy);
2185  EtotPinMode = EcalETot / Ein_gsf;
2186  EGsfPoutMode = FirstEcalGsfEnergy / Eout_gsf;
2187  EtotBremPinPoutMode = ( (EcalBremEnergy + OtherEcalGsfEnergy) /
2188  (Ein_gsf - Eout_gsf) );
2189  DEtaGsfEcalClust = std::abs(deta_gsfecal);
2190  SigmaEtaEta = std::log(sigmaEtaEta);
2192  xtra.setSigmaEtaEta(sigmaEtaEta);
2193 
2194  HOverHE = Ene_hcalgsf/(Ene_hcalgsf + FirstEcalGsfEnergy);
2195  HOverPin = Ene_hcalgsf / Ein_gsf;
2196  xtra.setHadEnergy(Ene_hcalgsf);
2197 
2198  // Apply bounds to variables and calculate MVA
2202  chi2_gsf = std::min(chi2_gsf,10.0f);
2205  chi2_kf = std::min(chi2_kf,10.0f);
2213  SigmaEtaEta = std::max(SigmaEtaEta,-14.0f);
2214  HOverPin = std::max(HOverPin,0.0f);
2215  HOverPin = std::min(HOverPin,5.0f);
2216  /*
2217  std::cout << " **** PFEG BDT observables ****" << endl;
2218  std::cout << " < Normalization > " << endl;
2219  std::cout << " Pt_gsf " << Pt_gsf << " Pin " << Ein_gsf
2220  << " Pout " << Eout_gsf << " Eta_gsf " << Eta_gsf << endl;
2221  std::cout << " < PureTracking > " << endl;
2222  std::cout << " dPtOverPt_gsf " << dPtOverPt_gsf
2223  << " DPtOverPt_gsf " << DPtOverPt_gsf
2224  << " chi2_gsf " << chi2_gsf
2225  << " nhit_gsf " << nhit_gsf
2226  << " DPtOverPt_kf " << DPtOverPt_kf
2227  << " chi2_kf " << chi2_kf
2228  << " nhit_kf " << nhit_kf << endl;
2229  std::cout << " < track-ecal-hcal-ps " << endl;
2230  std::cout << " EtotPinMode " << EtotPinMode
2231  << " EGsfPoutMode " << EGsfPoutMode
2232  << " EtotBremPinPoutMode " << EtotBremPinPoutMode
2233  << " DEtaGsfEcalClust " << DEtaGsfEcalClust
2234  << " SigmaEtaEta " << SigmaEtaEta
2235  << " HOverHE " << HOverHE << " Hcal energy " << Ene_hcalgsf
2236  << " HOverPin " << HOverPin
2237  << " lateBrem " << lateBrem
2238  << " firstBrem " << firstBrem << endl;
2239  */
2240 
2241  float vars[] = { lnPt_gsf, Eta_gsf, dPtOverPt_gsf, DPtOverPt_gsf, chi2_gsf,
2244 
2245  return hoc->gbrEle_->GetAdaBoostClassifier(vars);
2246  }
2247  }
2248  return -2.0f;
2249 }
2250 
2253  // add tracks associated to clusters that are not T_FROM_GAMMACONV
2254  // info about single-leg convs is already save, so just veto in loops
2255  IsConversionTrack<reco::PFBlockElementTrack> isConvKf;
2256  auto KFbegin = _splayedblock[reco::PFBlockElement::TRACK].begin();
2257  auto KFend = _splayedblock[reco::PFBlockElement::TRACK].end();
2258  for( auto& ecal : RO.ecalclusters ) {
2259  NotCloserToOther<reco::PFBlockElement::ECAL,
2261  true>
2262  ECALToTracks(_currentblock,_currentlinks,ecal.first);
2263  auto notmatchedkf = std::partition(KFbegin,KFend,ECALToTracks);
2264  auto notconvkf = std::partition(KFbegin,notmatchedkf,isConvKf);
2265  // go through non-conv-identified kfs and check MVA to add conversions
2266  for( auto kf = notconvkf; kf != notmatchedkf; ++kf ) {
2267  const reco::PFBlockElementTrack* elemaskf =
2268  docast(const reco::PFBlockElementTrack*,kf->first);
2269  xtra.addExtraNonConvTrack(_currentblock,*elemaskf);
2270  }
2271  }
2272 }
2273 
2274 // currently stolen from PFECALSuperClusterAlgo, we should
2275 // try to factor this correctly since the operation is the same in
2276 // both places...
2279  if( RO.ecalclusters.empty() ) {
2280  return reco::SuperCluster(0.0,math::XYZPoint(0,0,0));
2281  }
2282 
2283  SumPSEnergy sumps1(reco::PFBlockElement::PS1),
2284  sumps2(reco::PFBlockElement::PS2);
2285 
2286  bool isEE = false;
2287  edm::Ptr<reco::PFCluster> clusptr;
2288  // need the vector of raw pointers for a PF width class
2289  std::vector<const reco::PFCluster*> bare_ptrs;
2290  // calculate necessary parameters and build the SC
2291  double posX(0), posY(0), posZ(0),
2292  rawSCEnergy(0), corrSCEnergy(0), corrPSEnergy(0),
2293  PS1_clus_sum(0), PS2_clus_sum(0),
2294  ePS1(0), ePS2(0), ps1_energy(0.0), ps2_energy(0.0);
2295  int condP1(1), condP2(1);
2296  for( auto& clus : RO.ecalclusters ) {
2297  ePS1 = 0;
2298  ePS2 = 0;
2299  isEE = PFLayer::ECAL_ENDCAP == clus.first->clusterRef()->layer();
2300  clusptr =
2301  edm::refToPtr<reco::PFClusterCollection>(clus.first->clusterRef());
2302  bare_ptrs.push_back(clusptr.get());
2303 
2304  const double cluseraw = clusptr->energy();
2305  double cluscalibe = clusptr->correctedEnergy();
2306  const math::XYZPoint& cluspos = clusptr->position();
2307  posX += cluseraw * cluspos.X();
2308  posY += cluseraw * cluspos.Y();
2309  posZ += cluseraw * cluspos.Z();
2310  // update EE calibrated super cluster energies
2311  if( isEE && RO.ecal2ps.count(clus.first)) {
2312  ePS1 = 0;
2313  ePS2 = 0;
2314  condP1 = condP2 = 1;
2315 
2316  const auto& psclusters = RO.ecal2ps.at(clus.first);
2317 
2318  for( auto i_ps = psclusters.begin(); i_ps != psclusters.end(); ++i_ps) {
2319  const PFClusterRef& psclus = i_ps->first->clusterRef();
2320 
2321  auto const& recH_Frac = psclus->recHitFractions();
2322 
2323  switch( psclus->layer() ) {
2324  case PFLayer::PS1:
2325  for (auto const& recH : recH_Frac){
2326  ESDetId strip1 = recH.recHitRef()->detId();
2327  if(strip1 != ESDetId(0)){
2329  //getStatusCode() == 0 => active channel
2330  // apply correction if all recHits are dead
2331  if(status_p1->getStatusCode() == 0) condP1 = 0;
2332  }
2333  }
2334  break;
2335  case PFLayer::PS2:
2336  for (auto const& recH : recH_Frac){
2337  ESDetId strip2 = recH.recHitRef()->detId();
2338  if(strip2 != ESDetId(0)) {
2340  if(status_p2->getStatusCode() == 0) condP2 = 0;
2341  }
2342  }
2343  break;
2344  default:
2345  break;
2346  }
2347  }
2348 
2349 
2350  PS1_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
2351  0.0,sumps1);
2352  PS2_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
2353  0.0,sumps2);
2354 
2355  if(condP1 == 1) ePS1 = -1.;
2356  if(condP2 == 1) ePS2 = -1.;
2357 
2358  cluscalibe =
2359  cfg_.thePFEnergyCalibration->energyEm(*clusptr,
2360  PS1_clus_sum,PS2_clus_sum,
2361  ePS1, ePS2,
2363  }
2364  if(ePS1 == -1.) ePS1 = 0;
2365  if(ePS2 == -1.) ePS2 = 0;
2366 
2367  rawSCEnergy += cluseraw;
2368  corrSCEnergy += cluscalibe;
2369  ps1_energy += ePS1;
2370  ps2_energy += ePS2;
2371  corrPSEnergy += ePS1 + ePS2;
2372  }
2373  posX /= rawSCEnergy;
2374  posY /= rawSCEnergy;
2375  posZ /= rawSCEnergy;
2376 
2377  // now build the supercluster
2378  reco::SuperCluster new_sc(corrSCEnergy,math::XYZPoint(posX,posY,posZ));
2379 
2380  clusptr =
2381  edm::refToPtr<reco::PFClusterCollection>(RO.ecalclusters.front().
2382  first->clusterRef());
2383  new_sc.setCorrectedEnergy(corrSCEnergy);
2384  new_sc.setSeed(clusptr);
2385  new_sc.setPreshowerEnergyPlane1(ps1_energy);
2386  new_sc.setPreshowerEnergyPlane2(ps2_energy);
2387  new_sc.setPreshowerEnergy(corrPSEnergy);
2388  for( const auto& clus : RO.ecalclusters ) {
2389  clusptr =
2390  edm::refToPtr<reco::PFClusterCollection>(clus.first->clusterRef());
2391  new_sc.addCluster(clusptr);
2392  auto& hits_and_fractions = clusptr->hitsAndFractions();
2393  for( auto& hit_and_fraction : hits_and_fractions ) {
2394  new_sc.addHitAndFraction(hit_and_fraction.first,hit_and_fraction.second);
2395  }
2396  // put the preshower stuff back in later
2397  if( RO.ecal2ps.count(clus.first) ) {
2398  const auto& cluspsassociation = RO.ecal2ps.at(clus.first);
2399  // EE rechits should be uniquely matched to sets of pre-shower
2400  // clusters at this point, so we throw an exception if otherwise
2401  // now wrapped in EDM debug flags
2402  for( const auto& pscluselem : cluspsassociation ) {
2403  edm::Ptr<reco::PFCluster> psclus =
2404  edm::refToPtr<reco::PFClusterCollection>(pscluselem.first->
2405  clusterRef());
2406 #ifdef PFFLOW_DEBUG
2407  auto found_pscluster = std::find(new_sc.preshowerClustersBegin(),
2408  new_sc.preshowerClustersEnd(),
2409  reco::CaloClusterPtr(psclus));
2410  if( found_pscluster == new_sc.preshowerClustersEnd() ) {
2411 #endif
2412  new_sc.addPreshowerCluster(psclus);
2413 #ifdef PFFLOW_DEBUG
2414  } else {
2415  throw cms::Exception("PFECALSuperClusterAlgo::buildSuperCluster")
2416  << "Found a PS cluster matched to more than one EE cluster!"
2417  << std::endl << std::hex << psclus.get() << " == "
2418  << found_pscluster->get() << std::dec << std::endl;
2419  }
2420 #endif
2421  }
2422  }
2423  }
2424 
2425  // calculate linearly weighted cluster widths
2426  PFClusterWidthAlgo pfwidth(bare_ptrs);
2427  new_sc.setEtaWidth(pfwidth.pflowEtaWidth());
2428  new_sc.setPhiWidth(pfwidth.pflowPhiWidth());
2429 
2430  // cache the value of the raw energy
2431  new_sc.rawEnergy();
2432 
2433  return new_sc;
2434 }
2435 
2436 void PFEGammaAlgo::
2438  // this only means something for ROs with a primary GSF track
2439  if( RO.primaryGSFs.empty() ) return;
2440  // need energy sums to tell if we've added crap or not
2441  const double Pin_gsf = RO.primaryGSFs.front().first->GsftrackRef()->pMode();
2442  const double gsfOuterEta =
2443  RO.primaryGSFs.front().first->positionAtECALEntrance().Eta();
2444  double tot_ecal= 0.0;
2445  std::vector<double> min_brem_dists;
2446  std::vector<double> closest_brem_eta;
2447  // first get the total ecal energy (we should replace this with a cache)
2448  for( const auto& ecal : RO.ecalclusters ) {
2449  tot_ecal += ecal.first->clusterRef()->correctedEnergy();
2450  // we also need to look at the minimum distance to brems
2451  // since energetic brems will be closer to the brem than the track
2452  double min_brem_dist = 5000.0;
2453  double eta = -999.0;
2454  for( const auto& brem : RO.brems ) {
2455  const float dist = _currentblock->dist(brem.first->index(),
2456  ecal.first->index(),
2457  _currentlinks,
2459  if( dist < min_brem_dist && dist != -1.0f ) {
2460  min_brem_dist = dist;
2461  eta = brem.first->positionAtECALEntrance().Eta();
2462  }
2463  }
2464  min_brem_dists.push_back(min_brem_dist);
2465  closest_brem_eta.push_back(eta);
2466  }
2467 
2468  // loop through the ECAL clusters and remove ECAL clusters matched to
2469  // secondary track either in *or* out of the SC if the E/pin is bad
2470  for( auto secd_kf = RO.secondaryKFs.begin();
2471  secd_kf != RO.secondaryKFs.end(); ++secd_kf ) {
2472  reco::TrackRef trkRef = secd_kf->first->trackRef();
2473  const float secpin = secd_kf->first->trackRef()->p();
2474  bool remove_this_kf = false;
2475  for( auto ecal = RO.ecalclusters.begin();
2476  ecal != RO.ecalclusters.end(); ++ecal ) {
2477  size_t bremidx = std::distance(RO.ecalclusters.begin(),ecal);
2478  const float minbremdist = min_brem_dists[bremidx];
2479  const double ecalenergy = ecal->first->clusterRef()->correctedEnergy();
2480  const double Epin = ecalenergy/secpin;
2481  const double detaGsf =
2482  std::abs(gsfOuterEta - ecal->first->clusterRef()->positionREP().Eta());
2483  const double detaBrem =
2484  std::abs(closest_brem_eta[bremidx] -
2485  ecal->first->clusterRef()->positionREP().Eta());
2486 
2487  ElementMap::value_type check_match(ecal->first,secd_kf->first);
2488  auto kf_matched = std::find(RO.localMap.begin(),
2489  RO.localMap.end(),
2490  check_match);
2491 
2492  const float tkdist = _currentblock->dist(secd_kf->first->index(),
2493  ecal->first->index(),
2494  _currentlinks,
2496 
2497  // do not reject this track if it is closer to a brem than the
2498  // secondary track, or if it lies in the delta-eta plane with the
2499  // gsf track or if it is in the dEta plane with the brems
2500  if( Epin > 3 && kf_matched != RO.localMap.end() &&
2501  tkdist != -1.0f && tkdist < minbremdist &&
2502  detaGsf > 0.05 && detaBrem > 0.015) {
2503  double res_with = std::abs((tot_ecal-Pin_gsf)/Pin_gsf);
2504  double res_without = std::abs((tot_ecal-ecalenergy-Pin_gsf)/Pin_gsf);
2505  if(res_without < res_with) {
2506  LOGDRESSED("PFEGammaAlgo")
2507  << " REJECTED_RES totenergy " << tot_ecal
2508  << " Pin_gsf " << Pin_gsf
2509  << " cluster to secondary " << ecalenergy
2510  << " res_with " << res_with
2511  << " res_without " << res_without << std::endl;
2512  tot_ecal -= ecalenergy;
2513  remove_this_kf = true;
2514  ecal = RO.ecalclusters.erase(ecal);
2515  if( ecal == RO.ecalclusters.end() ) break;
2516  }
2517  }
2518  }
2519  if( remove_this_kf ) {
2520  secd_kf = RO.secondaryKFs.erase(secd_kf);
2521  if( secd_kf == RO.secondaryKFs.end() ) break;
2522  }
2523  }
2524 }
2525 
2526 void PFEGammaAlgo::
2528  bool removeFreeECAL,
2529  bool removeSCEcal) {
2530  std::vector<bool> cluster_in_sc;
2531  auto ecal_begin = RO.ecalclusters.begin();
2532  auto ecal_end = RO.ecalclusters.end();
2533  auto hcal_begin = _splayedblock[reco::PFBlockElement::HCAL].begin();
2534  auto hcal_end = _splayedblock[reco::PFBlockElement::HCAL].end();
2535  for( auto secd_kf = RO.secondaryKFs.begin();
2536  secd_kf != RO.secondaryKFs.end(); ++secd_kf ) {
2537  bool remove_this_kf = false;
2538  NotCloserToOther<reco::PFBlockElement::TRACK,reco::PFBlockElement::HCAL>
2539  tracksToHCALs(_currentblock,_currentlinks,secd_kf->first);
2540  reco::TrackRef trkRef = secd_kf->first->trackRef();
2541 
2542  bool goodTrack = PFTrackAlgoTools::isGoodForEGM(trkRef->algo());
2543  const float secpin = trkRef->p();
2544 
2545  for( auto ecal = ecal_begin; ecal != ecal_end; ++ecal ) {
2546  const double ecalenergy = ecal->first->clusterRef()->correctedEnergy();
2547  // first check if the cluster is in the SC (use dist calc for fastness)
2548  const size_t clus_idx = std::distance(ecal_begin,ecal);
2549  if( cluster_in_sc.size() < clus_idx + 1) {
2550  float dist = -1.0f;
2551  if( RO.parentSC ) {
2552  dist = _currentblock->dist(secd_kf->first->index(),
2553  ecal->first->index(),
2554  _currentlinks,
2556  }
2557  cluster_in_sc.push_back(dist != -1.0f);
2558  }
2559 
2560  ElementMap::value_type check_match(ecal->first,secd_kf->first);
2561  auto kf_matched = std::find(RO.localMap.begin(),
2562  RO.localMap.end(),
2563  check_match);
2564  // if we've found a secondary KF that matches this ecal cluster
2565  // now we see if it is matched to HCAL
2566  // if it is matched to an HCAL cluster we take different
2567  // actions if the cluster was in an SC or not
2568  if( kf_matched != RO.localMap.end() ) {
2569  auto hcal_matched = std::partition(hcal_begin,hcal_end,tracksToHCALs);
2570  for( auto hcalclus = hcal_begin;
2571  hcalclus != hcal_matched;
2572  ++hcalclus ) {
2573  const reco::PFBlockElementCluster * clusthcal =
2574  dynamic_cast<const reco::PFBlockElementCluster*>(hcalclus->first);
2575  const double hcalenergy = clusthcal->clusterRef()->energy();
2576  const double hpluse = ecalenergy+hcalenergy;
2577  const bool isHoHE = ( (hcalenergy / hpluse ) > 0.1 && goodTrack );
2578  const bool isHoE = ( hcalenergy > ecalenergy );
2579  const bool isPoHE = ( secpin > hpluse );
2580  if( cluster_in_sc[clus_idx] ) {
2581  if(isHoE || isPoHE) {
2582  LOGDRESSED("PFEGammaAlgo")
2583  << "REJECTED TRACK FOR H/E or P/(H+E), CLUSTER IN SC"
2584  << " H/H+E " << (hcalenergy / hpluse)
2585  << " H/E " << (hcalenergy > ecalenergy)
2586  << " P/(H+E) " << (secpin/hpluse)
2587  << " HCAL ENE " << hcalenergy
2588  << " ECAL ENE " << ecalenergy
2589  << " secPIN " << secpin
2590  << " Algo Track " << trkRef->algo() << std::endl;
2591  remove_this_kf = true;
2592  }
2593  } else {
2594  if(isHoHE){
2595  LOGDRESSED("PFEGammaAlgo")
2596  << "REJECTED TRACK FOR H/H+E, CLUSTER NOT IN SC"
2597  << " H/H+E " << (hcalenergy / hpluse)
2598  << " H/E " << (hcalenergy > ecalenergy)
2599  << " P/(H+E) " << (secpin/hpluse)
2600  << " HCAL ENE " << hcalenergy
2601  << " ECAL ENE " << ecalenergy
2602  << " secPIN " << secpin
2603  << " Algo Track " <<trkRef->algo() << std::endl;
2604  remove_this_kf = true;
2605  }
2606  }
2607  }
2608  }
2609  }
2610  if( remove_this_kf ) {
2611  secd_kf = RO.secondaryKFs.erase(secd_kf);
2612  if( secd_kf == RO.secondaryKFs.end() ) break;
2613  }
2614  }
2615 }
2616 
2617 
2618 
2620  const reco::PFBlockElementGsfTrack& GsfEl) {
2621  bool isPrimary = false;
2622 
2623  const GsfPFRecTrackRef& gsfPfRef = GsfEl.GsftrackRefPF();
2624 
2625  if(gsfPfRef.isNonnull()) {
2626  const PFRecTrackRef& kfPfRef = KfEl.trackRefPF();
2627  PFRecTrackRef kfPfRef_fromGsf = (*gsfPfRef).kfPFRecTrackRef();
2628  if(kfPfRef.isNonnull() && kfPfRef_fromGsf.isNonnull()) {
2629  reco::TrackRef kfref= (*kfPfRef).trackRef();
2630  reco::TrackRef kfref_fromGsf = (*kfPfRef_fromGsf).trackRef();
2631  if(kfref.isNonnull() && kfref_fromGsf.isNonnull()) {
2632  if(kfref == kfref_fromGsf)
2633  isPrimary = true;
2634  }
2635  }
2636  }
2637 
2638  return isPrimary;
2639 }
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:129
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:125
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:188
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:195
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:112
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:124
#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)
Float e1
Definition: deltaR.h:20
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
Float e2
Definition: deltaR.h:21
std::unordered_map< const PFClusterElement *, std::vector< PFClusterFlaggedElement > > ClusterMap
Definition: PFEGammaAlgo.h:78
float EtotPinMode
Definition: PFEGammaAlgo.h:328
void addCluster(const CaloClusterPtr &r)
add reference to constituent BasicCluster
Definition: SuperCluster.h:111
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