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