CMS 3D CMS Logo

PFAlgo.cc
Go to the documentation of this file.
2 
9 
13 
21 
25 
26 // #include "FWCore/Framework/interface/OrphanHandle.h"
28 // #include "DataFormats/Common/interface/ProductID.h"
31 
32 
35 
38 
39 
40 #include "Math/PxPyPzM4D.h"
41 #include "Math/LorentzVector.h"
42 #include "Math/DisplacementVector3D.h"
43 #include "Math/SMatrix.h"
44 #include "TDecompChol.h"
45 
46 #include "boost/graph/adjacency_matrix.hpp"
47 #include "boost/graph/graph_utility.hpp"
48 #include <numeric>
49 
50 
51 using namespace std;
52 using namespace reco;
53 using namespace boost;
54 
55 typedef std::list< reco::PFBlockRef >::iterator IBR;
56 
57 
58 
60  : pfCandidates_( new PFCandidateCollection),
61  nSigmaECAL_(0),
62  nSigmaHCAL_(1),
63  algo_(1),
64  debug_(false),
65  pfele_(nullptr),
66  pfpho_(nullptr),
67  pfegamma_(nullptr),
68  useVertices_(false)
69 {}
70 
72  if (usePFElectrons_) delete pfele_;
73  if (usePFPhotons_) delete pfpho_;
74  if (useEGammaFilters_) delete pfegamma_;
75 }
76 
77 
78 void
79 PFAlgo::setParameters(double nSigmaECAL,
80  double nSigmaHCAL,
81  const boost::shared_ptr<PFEnergyCalibration>& calibration,
82  const boost::shared_ptr<PFEnergyCalibrationHF>& thepfEnergyCalibrationHF) {
83 
84  nSigmaECAL_ = nSigmaECAL;
86 
87  calibration_ = calibration;
88  thepfEnergyCalibrationHF_ = thepfEnergyCalibrationHF;
89 
90 }
91 
92 
94  return pfmu_;
95 }
96 
97 //PFElectrons: a new method added to set the parameters for electron reconstruction.
98 void
99 PFAlgo::setPFEleParameters(double mvaEleCut,
100  string mvaWeightFileEleID,
101  bool usePFElectrons,
102  const boost::shared_ptr<PFSCEnergyCalibration>& thePFSCEnergyCalibration,
103  const boost::shared_ptr<PFEnergyCalibration>& thePFEnergyCalibration,
106  double coneEcalIsoForEgammaSC,
109  unsigned int nTrackIsoForEgammaSC,
112  bool usePFSCEleCalib,
113  bool useEGElectrons,
114  bool useEGammaSupercluster) {
115 
116  mvaEleCut_ = mvaEleCut;
120  thePFSCEnergyCalibration_ = thePFSCEnergyCalibration;
121  useEGElectrons_ = useEGElectrons;
130 
131 
132  if(!usePFElectrons_) return;
133  mvaWeightFileEleID_ = mvaWeightFileEleID;
134  FILE * fileEleID = fopen(mvaWeightFileEleID_.c_str(), "r");
135  if (fileEleID) {
136  fclose(fileEleID);
137  }
138  else {
139  string err = "PFAlgo: cannot open weight file '";
140  err += mvaWeightFileEleID;
141  err += "'";
142  throw invalid_argument( err );
143  }
146  thePFEnergyCalibration,
158 }
159 
160 void
162  std::string mvaWeightFileConvID,
163  double mvaConvCut,
164  bool useReg,
166  const boost::shared_ptr<PFEnergyCalibration>& thePFEnergyCalibration,
167  double sumPtTrackIsoForPhoton,
169  {
170 
172 
173  //for MVA pass PV if there is one in the collection otherwise pass a dummy
175  if(useVertices_)
176  {
177  dummy = primaryVertex_;
178  }
179  else { // create a dummy PV
181  e(0, 0) = 0.0015 * 0.0015;
182  e(1, 1) = 0.0015 * 0.0015;
183  e(2, 2) = 15. * 15.;
184  reco::Vertex::Point p(0, 0, 0);
185  dummy = reco::Vertex(p, e, 0, 0, 0);
186  }
187  // pv=&dummy;
188  if(! usePFPhotons_) return;
189  FILE * filePhotonConvID = fopen(mvaWeightFileConvID.c_str(), "r");
190  if (filePhotonConvID) {
191  fclose(filePhotonConvID);
192  }
193  else {
194  string err = "PFAlgo: cannot open weight file '";
195  err += mvaWeightFileConvID;
196  err += "'";
197  throw invalid_argument( err );
198  }
199  const reco::Vertex* pv=&dummy;
200  pfpho_ = new PFPhotonAlgo(mvaWeightFileConvID,
201  mvaConvCut,
202  useReg,
203  X0_Map,
204  *pv,
205  thePFEnergyCalibration,
206  sumPtTrackIsoForPhoton,
207  sumPtTrackIsoSlopeForPhoton
208  );
209  return;
210 }
211 
212 void PFAlgo::setEGammaParameters(bool use_EGammaFilters,
213  std::string ele_iso_path_mvaWeightFile,
214  double ele_iso_pt,
215  double ele_iso_mva_barrel,
216  double ele_iso_mva_endcap,
217  double ele_iso_combIso_barrel,
218  double ele_iso_combIso_endcap,
219  double ele_noniso_mva,
220  unsigned int ele_missinghits,
222  const edm::ParameterSet& ele_protectionsForJetMET,
223  const edm::ParameterSet& ele_protectionsForBadHcal,
224  double ph_MinEt,
225  double ph_combIso,
226  double ph_HoE,
227  double ph_sietaieta_eb,
228  double ph_sietaieta_ee,
229  const edm::ParameterSet& ph_protectionsForJetMET,
230  const edm::ParameterSet& ph_protectionsForBadHcal
231  )
232 {
233 
234  useEGammaFilters_ = use_EGammaFilters;
235 
236  if(!useEGammaFilters_ ) return;
237  FILE * fileEGamma_ele_iso_ID = fopen(ele_iso_path_mvaWeightFile.c_str(), "r");
238  if (fileEGamma_ele_iso_ID) {
239  fclose(fileEGamma_ele_iso_ID);
240  }
241  else {
242  string err = "PFAlgo: cannot open weight file '";
243  err += ele_iso_path_mvaWeightFile;
244  err += "'";
245  throw invalid_argument( err );
246  }
247 
248  // ele_iso_mvaID_ = new ElectronMVAEstimator(ele_iso_path_mvaWeightFile_);
250 
251  pfegamma_ = new PFEGammaFilters(ph_MinEt,
252  ph_combIso,
253  ph_HoE,
254  ph_sietaieta_eb,
255  ph_sietaieta_ee,
256  ph_protectionsForJetMET,
257  ph_protectionsForBadHcal,
258  ele_iso_pt,
259  ele_iso_mva_barrel,
260  ele_iso_mva_endcap,
261  ele_iso_combIso_barrel,
262  ele_iso_combIso_endcap,
263  ele_noniso_mva,
264  ele_missinghits,
265  ele_iso_path_mvaWeightFile,
266  ele_protectionsForJetMET,
267  ele_protectionsForBadHcal);
268 
269  return;
270 }
272  const edm::ValueMap<reco::GsfElectronRef> & valueMapGedElectrons,
273  const edm::ValueMap<reco::PhotonRef> & valueMapGedPhotons){
274  if(useEGammaFilters_) {
276  valueMapGedElectrons_ = & valueMapGedElectrons;
277  valueMapGedPhotons_ = & valueMapGedPhotons;
278  }
279 }
280 
281 
282 
283 /*
284 void PFAlgo::setPFPhotonRegWeights(
285  const GBRForest *LCorrForest,
286  const GBRForest *GCorrForest,
287  const GBRForest *ResForest
288  ) {
289  if(usePFPhotons_)
290  pfpho_->setGBRForest(LCorrForest, GCorrForest, ResForest);
291 }
292 */
294  const GBRForest *LCorrForestEB,
295  const GBRForest *LCorrForestEE,
296  const GBRForest *GCorrForestBarrel,
297  const GBRForest *GCorrForestEndcapHr9,
298  const GBRForest *GCorrForestEndcapLr9, const GBRForest *PFEcalResolution
299  ){
300 
301  pfpho_->setGBRForest(LCorrForestEB,LCorrForestEE,
302  GCorrForestBarrel, GCorrForestEndcapHr9,
303  GCorrForestEndcapLr9, PFEcalResolution);
304 }
305 void
307  // std::vector<double> muonHCAL,
308  // std::vector<double> muonECAL,
309  // std::vector<double> muonHO,
310  // double nSigmaTRACK,
311  // double ptError,
312  // std::vector<double> factors45)
313 {
314 
315 
316 
317 
318  pfmu_ = new PFMuonAlgo();
319  pfmu_->setParameters(pset);
320 
321  // Muon parameters
322  muonHCAL_= pset.getParameter<std::vector<double> >("muon_HCAL");
323  muonECAL_= pset.getParameter<std::vector<double> >("muon_ECAL");
324  muonHO_= pset.getParameter<std::vector<double> >("muon_HO");
325  assert ( muonHCAL_.size() == 2 && muonECAL_.size() == 2 && muonHO_.size() == 2);
326  nSigmaTRACK_= pset.getParameter<double>("nsigma_TRACK");
327  ptError_= pset.getParameter<double>("pt_Error");
328  factors45_ = pset.getParameter<std::vector<double> >("factors_45");
329  assert ( factors45_.size() == 2 );
330 
331 }
332 
333 void
335 {
336  goodTrackDeadHcal_ptErrRel_ = pset.getParameter<double>("goodTrackDeadHcal_ptErrRel");
337  goodTrackDeadHcal_chi2n_ = pset.getParameter<double>("goodTrackDeadHcal_chi2n");
338  goodTrackDeadHcal_layers_ = pset.getParameter<uint32_t>("goodTrackDeadHcal_layers");
339  goodTrackDeadHcal_validFr_ = pset.getParameter<double>("goodTrackDeadHcal_validFr");
340  goodTrackDeadHcal_dxy_ = pset.getParameter<double>("goodTrackDeadHcal_dxy");
341 
342  goodPixelTrackDeadHcal_minEta_ = pset.getParameter<double>("goodPixelTrackDeadHcal_minEta");
343  goodPixelTrackDeadHcal_maxPt_ = pset.getParameter<double>("goodPixelTrackDeadHcal_maxPt");
344  goodPixelTrackDeadHcal_ptErrRel_ = pset.getParameter<double>("goodPixelTrackDeadHcal_ptErrRel");
345  goodPixelTrackDeadHcal_chi2n_ = pset.getParameter<double>("goodPixelTrackDeadHcal_chi2n");
346  goodPixelTrackDeadHcal_maxLost3Hit_ = pset.getParameter<int32_t>("goodPixelTrackDeadHcal_maxLost3Hit");
347  goodPixelTrackDeadHcal_maxLost4Hit_ = pset.getParameter<int32_t>("goodPixelTrackDeadHcal_maxLost4Hit");
348  goodPixelTrackDeadHcal_dxy_ = pset.getParameter<double>("goodPixelTrackDeadHcal_dxy");
349  goodPixelTrackDeadHcal_dz_ = pset.getParameter<double>("goodPixelTrackDeadHcal_dz");
350 }
351 
352 void
354  muonHandle_ = muons;
355 }
356 
357 
358 void
360  double minHFCleaningPt,
361  double minSignificance,
362  double maxSignificance,
364  double maxDeltaPhiPt,
365  double minDeltaMet) {
373 }
374 
375 void
377  bool rejectTracks_Step45,
379  bool usePFConversions,
380  bool usePFDecays,
381  double dptRel_DispVtx){
382 
389 
390 }
391 
392 
393 void
397 
398  //Set the vertices for muon cleaning
399  pfmu_->setInputsForCleaning(primaryVertices);
400 
401 
402  //Now find the primary vertex!
403  bool primaryVertexFound = false;
404  nVtx_ = primaryVertices->size();
405  if(usePFPhotons_){
406  pfpho_->setnPU(nVtx_);
407  }
408  for (unsigned short i=0 ;i<primaryVertices->size();++i)
409  {
410  if(primaryVertices->at(i).isValid()&&(!primaryVertices->at(i).isFake()))
411  {
412  primaryVertex_ = primaryVertices->at(i);
413  primaryVertexFound = true;
414  break;
415  }
416  }
417  //Use vertices if the user wants to but only if it exists a good vertex
418  useVertices_ = useVertex && primaryVertexFound;
419  if(usePFPhotons_) {
420  if (useVertices_ ){
422  }
423  else{
425  e(0, 0) = 0.0015 * 0.0015;
426  e(1, 1) = 0.0015 * 0.0015;
427  e(2, 2) = 15. * 15.;
428  reco::Vertex::Point p(0, 0, 0);
429  reco::Vertex dummy = reco::Vertex(p, e, 0, 0, 0);
430  // std::cout << " PFPho " << pfpho_ << std::endl;
431  pfpho_->setPhotonPrimaryVtx(dummy);
432  }
433  }
434 }
435 
436 
438 
439  blockHandle_ = blockHandle;
441 }
442 
443 
444 
446 
447  // reset output collection
448  if(pfCandidates_.get() )
449  pfCandidates_->clear();
450  else
452 
453  if(pfElectronCandidates_.get() )
454  pfElectronCandidates_->clear();
455  else
457 
458  // Clearing pfPhotonCandidates
459  if( pfPhotonCandidates_.get() )
460  pfPhotonCandidates_->clear();
461  else
463 
464  if(pfCleanedCandidates_.get() )
465  pfCleanedCandidates_->clear();
466  else
468 
469  // not a unique_ptr; should not be deleted after transfer
470  pfElectronExtra_.clear();
471  pfPhotonExtra_.clear();
472 
473  if( debug_ ) {
474  cout<<"*********************************************************"<<endl;
475  cout<<"***** Particle flow algorithm *****"<<endl;
476  cout<<"*********************************************************"<<endl;
477  }
478 
479  // sort elements in three lists:
480  std::list< reco::PFBlockRef > hcalBlockRefs;
481  std::list< reco::PFBlockRef > ecalBlockRefs;
482  std::list< reco::PFBlockRef > hoBlockRefs;
483  std::list< reco::PFBlockRef > otherBlockRefs;
484 
485  for( unsigned i=0; i<blocks.size(); ++i ) {
486  // reco::PFBlockRef blockref( blockh,i );
487  reco::PFBlockRef blockref = createBlockRef( blocks, i);
488 
489  const reco::PFBlock& block = *blockref;
491  elements = block.elements();
492 
493  bool singleEcalOrHcal = false;
494  if( elements.size() == 1 ){
495  if( elements[0].type() == reco::PFBlockElement::ECAL ){
496  ecalBlockRefs.push_back( blockref );
497  singleEcalOrHcal = true;
498  }
499  if( elements[0].type() == reco::PFBlockElement::HCAL ){
500  hcalBlockRefs.push_back( blockref );
501  singleEcalOrHcal = true;
502  }
503  if( elements[0].type() == reco::PFBlockElement::HO ){
504  // Single HO elements are likely to be noise. Not considered for now.
505  hoBlockRefs.push_back( blockref );
506  singleEcalOrHcal = true;
507  }
508  }
509 
510  if(!singleEcalOrHcal) {
511  otherBlockRefs.push_back( blockref );
512  }
513  }//loop blocks
514 
515  if( debug_ ){
516  cout<<"# Ecal blocks: "<<ecalBlockRefs.size()
517  <<", # Hcal blocks: "<<hcalBlockRefs.size()
518  <<", # HO blocks: "<<hoBlockRefs.size()
519  <<", # Other blocks: "<<otherBlockRefs.size()<<endl;
520  }
521 
522 
523  // loop on blocks that are not single ecal,
524  // and not single hcal.
525 
526  unsigned nblcks = 0;
527  for( IBR io = otherBlockRefs.begin(); io!=otherBlockRefs.end(); ++io) {
528  if ( debug_ ) std::cout << "Block number " << nblcks++ << std::endl;
529  processBlock( *io, hcalBlockRefs, ecalBlockRefs );
530  }
531 
532  std::list< reco::PFBlockRef > empty;
533 
534  unsigned hblcks = 0;
535  // process remaining single hcal blocks
536  for( IBR ih = hcalBlockRefs.begin(); ih!=hcalBlockRefs.end(); ++ih) {
537  if ( debug_ ) std::cout << "HCAL block number " << hblcks++ << std::endl;
538  processBlock( *ih, empty, empty );
539  }
540 
541  unsigned eblcks = 0;
542  // process remaining single ecal blocks
543  for( IBR ie = ecalBlockRefs.begin(); ie!=ecalBlockRefs.end(); ++ie) {
544  if ( debug_ ) std::cout << "ECAL block number " << eblcks++ << std::endl;
545  processBlock( *ie, empty, empty );
546  }
547 
548  // Post HF Cleaning
549  postCleaning();
550 
551  //Muon post cleaning
552  pfmu_->postClean(pfCandidates_.get());
553 
554  //Add Missing muons
555  if( muonHandle_.isValid())
557 }
558 
559 
561  std::list<reco::PFBlockRef>& hcalBlockRefs,
562  std::list<reco::PFBlockRef>& ecalBlockRefs ) {
563 
564  // debug_ = false;
565  assert(!blockref.isNull() );
566  const reco::PFBlock& block = *blockref;
567 
568  typedef std::multimap<double, unsigned>::iterator IE;
569  typedef std::multimap<double, std::pair<unsigned,::math::XYZVector> >::iterator IS;
570  typedef std::multimap<double, std::pair<unsigned,bool> >::iterator IT;
571  typedef std::multimap< unsigned, std::pair<double, unsigned> >::iterator II;
572 
573  if(debug_) {
574  cout<<"#########################################################"<<endl;
575  cout<<"##### Process Block: #####"<<endl;
576  cout<<"#########################################################"<<endl;
577  cout<<block<<endl;
578  }
579 
580 
581  const edm::OwnVector< reco::PFBlockElement >& elements = block.elements();
582  // make a copy of the link data, which will be edited.
583  PFBlock::LinkData linkData = block.linkData();
584 
585  // keep track of the elements which are still active.
586  vector<bool> active( elements.size(), true );
587 
588 
589  // //PFElectrons:
590  // usePFElectrons_ external configurable parameter to set the usage of pf electron
591  std::vector<reco::PFCandidate> tempElectronCandidates;
592  tempElectronCandidates.clear();
593  if (usePFElectrons_) {
594  if (pfele_->isElectronValidCandidate(blockref,active, primaryVertex_ )){
595  // if there is at least a valid candidate is get the vector of pfcandidates
596  const std::vector<reco::PFCandidate> PFElectCandidates_(pfele_->getElectronCandidates());
597  for ( std::vector<reco::PFCandidate>::const_iterator ec=PFElectCandidates_.begin(); ec != PFElectCandidates_.end(); ++ec )tempElectronCandidates.push_back(*ec);
598 
599  // (***) We're filling the ElectronCandidates into the PFCandiate collection
600  // ..... Once we let PFPhotonAlgo over-write electron-decision, we need to move this to
601  // ..... after the PhotonAlgo has run (Fabian)
602  }
603  // The vector active is automatically changed (it is passed by ref) in PFElectronAlgo
604  // for all the electron candidate
606  pfele_->getAllElectronCandidates().begin(),
607  pfele_->getAllElectronCandidates().end());
608 
609  pfElectronExtra_.insert(pfElectronExtra_.end(),
610  pfele_->getElectronExtra().begin(),
611  pfele_->getElectronExtra().end());
612 
613  }
614  if( /* --- */ usePFPhotons_ /* --- */ ) {
615 
616  if(debug_)
617  cout<<endl<<"--------------- entering PFPhotonAlgo ----------------"<<endl;
618  vector<PFCandidatePhotonExtra> pfPhotonExtraCand;
619  if ( pfpho_->isPhotonValidCandidate(blockref, // passing the reference to the PFBlock
620  active, // std::vector<bool> containing information about acitivity
621  pfPhotonCandidates_, // pointer to candidate vector, to be filled by the routine
622  pfPhotonExtraCand, // candidate extra vector, to be filled by the routine
623  tempElectronCandidates
624  //pfElectronCandidates_ // pointer to some auziliary UNTOUCHED FOR NOW
625  ) ) {
626  if(debug_)
627  std::cout<< " In this PFBlock we found "<<pfPhotonCandidates_->size()<<" Photon Candidates."<<std::endl;
628 
629  // CAUTION: In case we want to allow the PhotonAlgo to 'over-write' what the ElectronAlgo did above
630  // ........ we should NOT fill the PFCandidate-vector with the electrons above (***)
631 
632  // Here we need to add all the photon cands to the pfCandidate list
633  unsigned int extracand =0;
634  PFCandidateCollection::const_iterator cand = pfPhotonCandidates_->begin();
635  for( ; cand != pfPhotonCandidates_->end(); ++cand, ++extracand) {
636  pfCandidates_->push_back(*cand);
637  pfPhotonExtra_.push_back(pfPhotonExtraCand[extracand]);
638  }
639 
640  } // end of 'if' in case photons are found
641  pfPhotonExtraCand.clear();
642  pfPhotonCandidates_->clear();
643  } // end of Photon algo
644 
645  if (usePFElectrons_) {
646  for ( std::vector<reco::PFCandidate>::const_iterator ec=tempElectronCandidates.begin(); ec != tempElectronCandidates.end(); ++ec ){
647  pfCandidates_->push_back(*ec);
648  }
649  tempElectronCandidates.clear();
650  }
651 
652 
653  // New EGamma Reconstruction 10/10/2013
654  if(useEGammaFilters_) {
655 
656  // const edm::ValueMap<reco::GsfElectronRef> & myGedElectronValMap(*valueMapGedElectrons_);
657  bool egmLocalDebug = debug_;
658  bool egmLocalBlockDebug = false;
659 
660  unsigned int negmcandidates = pfEgammaCandidates_->size();
661  for(unsigned int ieg=0 ; ieg < negmcandidates; ++ieg) {
662  // const reco::PFCandidate & egmcand((*pfEgammaCandidates_)[ieg]);
664 
665  const PFCandidate::ElementsInBlocks& theElements = (*pfEgmRef).elementsInBlocks();
666  PFCandidate::ElementsInBlocks::const_iterator iegfirst = theElements.begin();
667  bool sameBlock = false;
668  bool isGoodElectron = false;
669  bool isGoodPhoton = false;
670  bool isPrimaryElectron = false;
671  if(iegfirst->first == blockref)
672  sameBlock = true;
673  if(sameBlock) {
674 
675  if(egmLocalDebug)
676  cout << " I am in looping on EGamma Candidates: pt " << (*pfEgmRef).pt()
677  << " eta,phi " << (*pfEgmRef).eta() << ", " << (*pfEgmRef).phi()
678  << " charge " << (*pfEgmRef).charge() << endl;
679 
680  if((*pfEgmRef).gsfTrackRef().isNonnull()) {
681 
682  reco::GsfElectronRef gedEleRef = (*valueMapGedElectrons_)[pfEgmRef];
683  if(gedEleRef.isNonnull()) {
684  isGoodElectron = pfegamma_->passElectronSelection(*gedEleRef,*pfEgmRef,nVtx_);
685  isPrimaryElectron = pfegamma_->isElectron(*gedEleRef);
686  if(egmLocalDebug){
687  if(isGoodElectron)
688  cout << "** Good Electron, pt " << gedEleRef->pt()
689  << " eta, phi " << gedEleRef->eta() << ", " << gedEleRef->phi()
690  << " charge " << gedEleRef->charge()
691  << " isPrimary " << isPrimaryElectron
692  << " isoDr03 " << (gedEleRef->dr03TkSumPt() + gedEleRef->dr03EcalRecHitSumEt() + gedEleRef->dr03HcalTowerSumEt())
693  << " mva_isolated " << gedEleRef->mva_Isolated()
694  << " mva_e_pi " << gedEleRef->mva_e_pi()
695  << endl;
696  }
697 
698 
699  }
700  }
701  if((*pfEgmRef).superClusterRef().isNonnull()) {
702 
703  reco::PhotonRef gedPhoRef = (*valueMapGedPhotons_)[pfEgmRef];
704  if(gedPhoRef.isNonnull()) {
705  isGoodPhoton = pfegamma_->passPhotonSelection(*gedPhoRef);
706  if(egmLocalDebug) {
707  if(isGoodPhoton)
708  cout << "** Good Photon, pt " << gedPhoRef->pt()
709  << " eta, phi " << gedPhoRef->eta() << ", " << gedPhoRef->phi() << endl;
710  }
711  }
712  }
713  } // end same block
714 
715  if(isGoodElectron && isGoodPhoton) {
716  if(isPrimaryElectron)
717  isGoodPhoton = false;
718  else
719  isGoodElectron = false;
720  }
721 
722  // isElectron
723  if(isGoodElectron) {
724  reco::GsfElectronRef gedEleRef = (*valueMapGedElectrons_)[pfEgmRef];
725  reco::PFCandidate myPFElectron = *pfEgmRef;
726  // run protections
727  bool lockTracks = false;
728  bool isSafe = true;
730  lockTracks = true;
731  isSafe = pfegamma_->isElectronSafeForJetMET(*gedEleRef,myPFElectron,primaryVertex_,lockTracks);
732  }
733 
734  if(isSafe) {
736  myPFElectron.setParticleType(particleType);
737  myPFElectron.setCharge(gedEleRef->charge());
738  myPFElectron.setP4(gedEleRef->p4());
739  myPFElectron.set_mva_e_pi(gedEleRef->mva_e_pi());
740  myPFElectron.set_mva_Isolated(gedEleRef->mva_Isolated());
741 
742  if(egmLocalDebug) {
743  cout << " PFAlgo: found an electron with NEW EGamma code " << endl;
744  cout << " myPFElectron: pt " << myPFElectron.pt()
745  << " eta,phi " << myPFElectron.eta() << ", " <<myPFElectron.phi()
746  << " mva " << myPFElectron.mva_e_pi()
747  << " charge " << myPFElectron.charge() << endl;
748  }
749 
750 
751  // Lock all the elements
752  if(egmLocalBlockDebug)
753  cout << " THE BLOCK " << *blockref << endl;
754  for (PFCandidate::ElementsInBlocks::const_iterator ieb = theElements.begin();
755  ieb<theElements.end(); ++ieb) {
756  active[ieb->second] = false;
757  if(egmLocalBlockDebug||(debug_&&egmLocalDebug))
758  cout << " Elements used " << ieb->second << endl;
759  }
760 
761  // The electron is considered safe for JetMET and the additional tracks pointing to it are locked
762  if(lockTracks) {
763  const PFCandidate::ElementsInBlocks& extraTracks = myPFElectron.egammaExtraRef()->extraNonConvTracks();
764  for (PFCandidate::ElementsInBlocks::const_iterator itrk = extraTracks.begin();
765  itrk<extraTracks.end(); ++itrk) {
766  if(egmLocalBlockDebug||(debug_&&egmLocalDebug))
767  cout << " Extra locked track " << itrk->second << endl;
768  active[itrk->second] = false;
769  }
770  }
771 
772  pfCandidates_->push_back(myPFElectron);
773 
774  }
775  else {
776  if(egmLocalDebug)
777  cout << "PFAlgo: Electron DISCARDED, NOT SAFE FOR JETMET " << endl;
778  }
779  }
780  if(isGoodPhoton) {
781  reco::PhotonRef gedPhoRef = (*valueMapGedPhotons_)[pfEgmRef];
782  reco::PFCandidate myPFPhoton = *pfEgmRef;
783  bool isSafe = true;
785  isSafe = pfegamma_->isPhotonSafeForJetMET(*gedPhoRef,myPFPhoton);
786  }
787 
788 
789 
790  if(isSafe) {
792  myPFPhoton.setParticleType(particleType);
793  myPFPhoton.setCharge(0);
794  myPFPhoton.set_mva_nothing_gamma(1.);
796  myPFPhoton.setVertex( v );
797  myPFPhoton.setP4(gedPhoRef->p4());
798  if(egmLocalDebug) {
799  cout << " PFAlgo: found a photon with NEW EGamma code " << endl;
800  cout << " myPFPhoton: pt " << myPFPhoton.pt()
801  << " eta,phi " << myPFPhoton.eta() << ", " <<myPFPhoton.phi()
802  << " charge " << myPFPhoton.charge() << endl;
803  }
804 
805  // Lock all the elements
806  if(egmLocalBlockDebug)
807  cout << " THE BLOCK " << *blockref << endl;
808  for (PFCandidate::ElementsInBlocks::const_iterator ieb = theElements.begin();
809  ieb<theElements.end(); ++ieb) {
810  active[ieb->second] = false;
811  if(egmLocalBlockDebug||(debug_&&egmLocalDebug))
812  cout << " Elements used " << ieb->second << endl;
813  }
814  pfCandidates_->push_back(myPFPhoton);
815 
816  } // end isSafe
817  } // end isGoodPhoton
818  } // end loop on EGM candidates
819  } // end if use EGammaFilters
820 
821 
822 
823  //Lock extra conversion tracks not used by Photon Algo
824  if (usePFConversions_ )
825  {
826  for(unsigned iEle=0; iEle<elements.size(); iEle++) {
827  PFBlockElement::Type type = elements[iEle].type();
828  if(type==PFBlockElement::TRACK)
829  {
830  if(elements[iEle].trackRef()->algo() == reco::TrackBase::conversionStep)
831  active[iEle]=false;
832  if(elements[iEle].trackRef()->quality(reco::TrackBase::highPurity))continue;
833  const reco::PFBlockElementTrack * trackRef = dynamic_cast<const reco::PFBlockElementTrack*>((&elements[iEle]));
834  if(!(trackRef->trackType(reco::PFBlockElement::T_FROM_GAMMACONV)))continue;
835  if(!elements[iEle].convRefs().empty())active[iEle]=false;
836  }
837  }
838  }
839 
840 
841 
842 
843 
844  if(debug_)
845  cout<<endl<<"--------------- loop 1 ------------------"<<endl;
846 
847  //COLINFEB16
848  // In loop 1, we loop on all elements.
849 
850  // The primary goal is to deal with tracks that are:
851  // - not associated to an HCAL cluster
852  // - not identified as an electron.
853  // Those tracks should be predominantly relatively low energy charged
854  // hadrons which are not detected in the ECAL.
855 
856  // The secondary goal is to prepare for the next loops
857  // - The ecal and hcal elements are sorted in separate vectors
858  // which will be used as a base for the corresponding loops.
859  // - For tracks which are connected to more than one HCAL cluster,
860  // the links between the track and the cluster are cut for all clusters
861  // but the closest one.
862  // - HF only blocks ( HFEM, HFHAD, HFEM+HFAD) are identified
863 
864  // obsolete comments?
865  // loop1:
866  // - sort ecal and hcal elements in separate vectors
867  // - for tracks:
868  // - lock closest ecal cluster
869  // - cut link to farthest hcal cluster, if more than 1.
870 
871  // vectors to store indices to ho, hcal and ecal elements
872  vector<unsigned> hcalIs;
873  vector<unsigned> hoIs;
874  vector<unsigned> ecalIs;
875  vector<unsigned> trackIs;
876  vector<unsigned> ps1Is;
877  vector<unsigned> ps2Is;
878 
879  vector<unsigned> hfEmIs;
880  vector<unsigned> hfHadIs;
881 
882  vector<bool> deadArea(elements.size(), false);
883 
884  for(unsigned iEle=0; iEle<elements.size(); iEle++) {
885  PFBlockElement::Type type = elements[iEle].type();
886 
887  if(debug_ && type != PFBlockElement::BREM ) cout<<endl<<elements[iEle];
888 
889  switch( type ) {
890  case PFBlockElement::TRACK:
891  if ( active[iEle] ) {
892  trackIs.push_back( iEle );
893  if(debug_) cout<<"TRACK, stored index, continue"<<endl;
894  }
895  break;
896  case PFBlockElement::ECAL:
897  if ( active[iEle] ) {
898  ecalIs.push_back( iEle );
899  if(debug_) cout<<"ECAL, stored index, continue"<<endl;
900  }
901  continue;
903  if ( active[iEle] ) {
904  if (elements[iEle].clusterRef()->flags() & reco::CaloCluster::badHcalMarker) {
905  if(debug_) cout<<"HCAL DEAD AREA: remember and skip."<<endl;
906  active[iEle] = false;
907  deadArea[iEle] = true;
908  continue;
909  }
910  hcalIs.push_back( iEle );
911  if(debug_) cout<<"HCAL, stored index, continue"<<endl;
912  }
913  continue;
914  case PFBlockElement::HO:
915  if (useHO_) {
916  if ( active[iEle] ) {
917  hoIs.push_back( iEle );
918  if(debug_) cout<<"HO, stored index, continue"<<endl;
919  }
920  }
921  continue;
922  case PFBlockElement::HFEM:
923  if ( active[iEle] ) {
924  hfEmIs.push_back( iEle );
925  if(debug_) cout<<"HFEM, stored index, continue"<<endl;
926  }
927  continue;
928  case PFBlockElement::HFHAD:
929  if ( active[iEle] ) {
930  hfHadIs.push_back( iEle );
931  if(debug_) cout<<"HFHAD, stored index, continue"<<endl;
932  }
933  continue;
934  default:
935  continue;
936  }
937 
938  // we're now dealing with a track
939  unsigned iTrack = iEle;
940  reco::MuonRef muonRef = elements[iTrack].muonRef();
941  if (debug_ && muonRef.isNonnull()) {
942  cout << "track " << iTrack << " has a valid muon reference. " << std::endl;
943  cout << " - isMuon: " << PFMuonAlgo::isMuon(muonRef) << endl;
944  cout << " - isGlobalTightMuon: " << PFMuonAlgo::isGlobalTightMuon(muonRef) << endl;
945  cout << " - isTrackerTightMuon: " << PFMuonAlgo::isTrackerTightMuon(muonRef) << endl;
946  cout << " - isIsolatedMuon: " << PFMuonAlgo::isIsolatedMuon(muonRef) << endl;
947  }
948 
949  //Check if the track is a primary track of a secondary interaction
950  //If that is the case reconstruct a charged hadron noly using that
951  //track
952  if (active[iTrack] && isFromSecInt(elements[iEle], "primary")){
953  bool isPrimaryTrack = elements[iEle].displacedVertexRef(PFBlockElement::T_TO_DISP)->displacedVertexRef()->isTherePrimaryTracks();
954  if (isPrimaryTrack) {
955  if (debug_) cout << "Primary Track reconstructed alone" << endl;
956 
957  unsigned tmpi = reconstructTrack(elements[iEle]);
958  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEle );
959  active[iTrack] = false;
960  }
961  }
962 
963 
964  if(debug_) {
965  if ( !active[iTrack] )
966  cout << "Already used by electrons, muons, conversions" << endl;
967  }
968 
969  // Track already used as electron, muon, conversion?
970  // Added a check on the activated element
971  if ( ! active[iTrack] ) continue;
972 
973  reco::TrackRef trackRef = elements[iTrack].trackRef();
974  assert( !trackRef.isNull() );
975 
976  if (debug_ ) {
977  cout <<"PFAlgo:processBlock "<<" "<<trackIs.size()<<" "<<ecalIs.size()<<" "<<hcalIs.size()<<" "<<hoIs.size()<<endl;
978  }
979 
980  // look for associated elements of all types
981  //COLINFEB16
982  // all types of links are considered.
983  // the elements are sorted by increasing distance
984  std::multimap<double, unsigned> ecalElems;
985  block.associatedElements( iTrack, linkData,
986  ecalElems ,
989 
990  std::multimap<double, unsigned> hcalElems;
991  block.associatedElements( iTrack, linkData,
992  hcalElems,
995 
996  if (debug_ ) {
997  std::cout << "\tTrack " << iTrack << " is linked to " << ecalElems.size() << " ecal and " << hcalElems.size() << " hcal elements" << std::endl;
998  for (const auto & pair : ecalElems) {
999  std::cout << "ecal: dist " << pair.first << "\t elem " << pair.second << std::endl;
1000  }
1001  for (const auto & pair : hcalElems) {
1002  std::cout << "hcal: dist " << pair.first << "\t elem " << pair.second << (deadArea[pair.second] ? " DEAD AREA MARKER" : "") << std::endl;
1003  }
1004  }
1005  // there's 3 possible options possible here, in principle:
1006  // 1) flag everything that may be associated to a dead hcal marker
1007  // 2) flag everything whose closest hcal link is a dead hcal marker
1008  // 3) flag only things that are linked only to dead hcal marker
1009  // in our first test we go for (2)
1010  //--- option (1) --
1011  //bool hasDeadHcal = false;
1012  //for (auto it = hcalElems.begin(), ed = hcalElems.end(); it != ed; /*NOTE NO ++it HERE */ ) {
1013  // if (deadArea[it->second]) { hasDeadHcal = true; it = hcalElems.erase(it); } // std::multimap::erase returns iterator to next
1014  // else ++it;
1015  //}
1016  //--- option (2) --
1017  bool hasDeadHcal = false;
1018  if (!hcalElems.empty() && deadArea[hcalElems.begin()->second]) {
1019  hasDeadHcal = true;
1020  hcalElems.clear();
1021  }
1022  //--- option (3) --
1023  //bool hasDeadHcal = true;
1024  //for (auto it = hcalElems.begin(), ed = hcalElems.end(); it != ed; /*NOTE NO ++it HERE */ ) {
1025  // if (deadArea[it->second]) { it = hcalElems.erase(it); } // std::multimap::erase returns iterator to next
1026  // else { hasDeadHcal = false; }
1027  //}
1028 
1029  // for tracks with bad Hcal, check the quality
1030  bool goodTrackDeadHcal = false;
1031  if (hasDeadHcal) {
1032  goodTrackDeadHcal = ( trackRef->ptError() < goodTrackDeadHcal_ptErrRel_ * trackRef->pt() &&
1033  trackRef->normalizedChi2() < goodTrackDeadHcal_chi2n_ &&
1034  trackRef->hitPattern().trackerLayersWithMeasurement() >= goodTrackDeadHcal_layers_ &&
1035  trackRef->validFraction() > goodTrackDeadHcal_validFr_ &&
1037  // now we add an extra block for tracks at high |eta|
1038  if (!goodTrackDeadHcal &&
1039  std::abs(trackRef->eta()) > goodPixelTrackDeadHcal_minEta_ && // high eta
1040  trackRef->hitPattern().pixelLayersWithMeasurement() >= 3 && // pixel track
1041  trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::TRACK_HITS) == 0 &&
1042  trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::MISSING_INNER_HITS) == 0 &&
1043  trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::MISSING_OUTER_HITS) <= (
1044  trackRef->hitPattern().pixelLayersWithMeasurement() > 3 ?
1046  trackRef->normalizedChi2() < goodPixelTrackDeadHcal_chi2n_ && // tighter cut
1049  trackRef->ptError() < goodPixelTrackDeadHcal_ptErrRel_*trackRef->pt() && // sanity
1050  trackRef->pt() < goodPixelTrackDeadHcal_maxPt_) { // sanity
1051  goodTrackDeadHcal = true;
1052  // FIXME: may decide to do something to the track pT
1053  }
1054  //if (!goodTrackDeadHcal && trackRef->hitPattern().trackerLayersWithMeasurement() == 4 && trackRef->validFraction() == 1
1055  if (debug_) cout << " track pt " << trackRef->pt() << " +- " << trackRef->ptError()
1056  << " layers valid " << trackRef->hitPattern().trackerLayersWithMeasurement()
1057  << ", lost " << trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::TRACK_HITS)
1058  << ", lost outer " << trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::MISSING_OUTER_HITS)
1059  << ", lost inner " << trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::MISSING_INNER_HITS)
1060  << "(valid fraction " << trackRef->validFraction() << ")"
1061  << " chi2/ndf " << trackRef->normalizedChi2()
1062  << " |dxy| " << std::abs(trackRef->dxy(primaryVertex_.position())) << " +- " << trackRef->dxyError()
1063  << " |dz| " << std::abs(trackRef->dz(primaryVertex_.position())) << " +- " << trackRef->dzError()
1064  << (goodTrackDeadHcal ? " passes " : " fails ") << "quality cuts" << std::endl;
1065  }
1066 
1067  // When a track has no HCAL cluster linked, but another track is linked to the same
1068  // ECAL cluster and an HCAL cluster, link the track to the HCAL cluster for
1069  // later analysis
1070  if ( hcalElems.empty() && !ecalElems.empty() && !hasDeadHcal) {
1071  // debug_ = true;
1072  unsigned ntt = 1;
1073  unsigned index = ecalElems.begin()->second;
1074  std::multimap<double, unsigned> sortedTracks;
1075  block.associatedElements( index, linkData,
1076  sortedTracks,
1079  if (debug_ ) std::cout << "The closest ECAL cluster is linked to " << sortedTracks.size() << " tracks, with distance = " << ecalElems.begin()->first << std::endl;
1080 
1081  // Loop over all tracks
1082  for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
1083  unsigned jTrack = ie->second;
1084  //std::cout << "Track " << jTrack << std::endl;
1085  // Track must be active
1086  if ( !active[jTrack] ) continue;
1087  //std::cout << "Active " << std::endl;
1088 
1089  // The loop is on the other tracks !
1090  if ( jTrack == iTrack ) continue;
1091  //std::cout << "A different track ! " << std::endl;
1092 
1093  // Check if the ECAL closest to this track is the current ECAL
1094  // Otherwise ignore this track in the neutral energy determination
1095  std::multimap<double, unsigned> sortedECAL;
1096  block.associatedElements( jTrack, linkData,
1097  sortedECAL,
1100  if ( sortedECAL.begin()->second != index ) continue;
1101  if (debug_ ) std::cout << " track " << jTrack << " with closest ECAL identical " << std::endl;
1102 
1103 
1104  // Check if this track is also linked to an HCAL
1105  std::multimap<double, unsigned> sortedHCAL;
1106  block.associatedElements( jTrack, linkData,
1107  sortedHCAL,
1110  if ( sortedHCAL.empty() ) continue;
1111  if (debug_ ) std::cout << " and with an HCAL cluster " << sortedHCAL.begin()->second << std::endl;
1112  ntt++;
1113 
1114  // In that case establish a link with the first track
1115  block.setLink( iTrack,
1116  sortedHCAL.begin()->second,
1117  sortedECAL.begin()->first,
1118  linkData,
1119  PFBlock::LINKTEST_RECHIT );
1120 
1121  } // End other tracks
1122 
1123  // Redefine HCAL elements
1124  block.associatedElements( iTrack, linkData,
1125  hcalElems,
1128 
1129  if ( debug_ && !hcalElems.empty() )
1130  std::cout << "Track linked back to HCAL due to ECAL sharing with other tracks" << std::endl;
1131  }
1132 
1133  //MICHELE
1134  //TEMPORARY SOLUTION FOR ELECTRON REJECTION IN PFTAU
1135  //COLINFEB16
1136  // in case particle flow electrons are not reconstructed,
1137  // the mva_e_pi of the charged hadron will be set to 1
1138  // if a GSF element is associated to the current TRACK element
1139  // This information will be used in the electron rejection for tau ID.
1140  std::multimap<double,unsigned> gsfElems;
1141  if (usePFElectrons_ == false) {
1142  block.associatedElements( iTrack, linkData,
1143  gsfElems ,
1145  }
1146  //
1147 
1148  if(hcalElems.empty() && debug_) {
1149  cout<<"no hcal element connected to track "<<iTrack<<endl;
1150  }
1151 
1152  // will now loop on associated elements ...
1153  // typedef std::multimap<double, unsigned>::iterator IE;
1154 
1155  bool hcalFound = false;
1156 
1157  if(debug_)
1158  cout<<"now looping on elements associated to the track"<<endl;
1159 
1160  // ... first on associated ECAL elements
1161  // Check if there is still a free ECAL for this track
1162  for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
1163 
1164  unsigned index = ie->second;
1165  // Sanity checks and optional printout
1166  PFBlockElement::Type type = elements[index].type();
1167  if(debug_) {
1168  double dist = ie->first;
1169  cout<<"\telement "<<elements[index]<<" linked with distance = "<< dist <<endl;
1170  if ( ! active[index] ) cout << "This ECAL is already used - skip it" << endl;
1171  }
1172  assert( type == PFBlockElement::ECAL );
1173 
1174  // This ECAL is not free (taken by an electron?) - just skip it
1175  if ( ! active[index] ) continue;
1176 
1177  // Flag ECAL clusters for which the corresponding track is not linked to an HCAL cluster
1178 
1179  //reco::PFClusterRef clusterRef = elements[index].clusterRef();
1180  //assert( !clusterRef.isNull() );
1181  if( !hcalElems.empty() && debug_)
1182  cout<<"\t\tat least one hcal element connected to the track."
1183  <<" Sparing Ecal cluster for the hcal loop"<<endl;
1184 
1185  } //loop print ecal elements
1186 
1187 
1188  // tracks which are not linked to an HCAL
1189  // are reconstructed now.
1190 
1191  if( hcalElems.empty() ) {
1192 
1193  if ( debug_ )
1194  std::cout << "Now deals with tracks linked to no HCAL clusters. Was HCal active? " << (!hasDeadHcal) << std::endl;
1195  // vector<unsigned> elementIndices;
1196  // elementIndices.push_back(iTrack);
1197 
1198  // The track momentum
1199  double trackMomentum = elements[iTrack].trackRef()->p();
1200  if ( debug_ )
1201  std::cout << elements[iTrack] << std::endl;
1202 
1203  // Is it a "tight" muon ? In that case assume no
1204  //Track momentum corresponds to the calorimeter
1205  //energy for now
1206  bool thisIsAMuon = PFMuonAlgo::isMuon(elements[iTrack]);
1207  if ( thisIsAMuon ) trackMomentum = 0.;
1208 
1209  // If it is not a muon check if Is it a fake track ?
1210  //Michalis: I wonder if we should convert this to dpt/pt?
1211  bool rejectFake = false;
1212  if ( !thisIsAMuon && elements[iTrack].trackRef()->ptError() > ptError_ ) {
1213 
1214  double deficit = trackMomentum;
1215  double resol = neutralHadronEnergyResolution(trackMomentum,
1216  elements[iTrack].trackRef()->eta());
1217  resol *= trackMomentum;
1218 
1219  if ( !ecalElems.empty() ) {
1220  unsigned thisEcal = ecalElems.begin()->second;
1221  reco::PFClusterRef clusterRef = elements[thisEcal].clusterRef();
1222  bool useCluster = true;
1223  if (hasDeadHcal) {
1224  std::multimap<double, unsigned> sortedTracks;
1225  block.associatedElements( thisEcal, linkData,
1226  sortedTracks,
1229  useCluster = (sortedTracks.begin()->second == iTrack);
1230  }
1231  if (useCluster) {
1232  deficit -= clusterRef->energy();
1233  resol = neutralHadronEnergyResolution(trackMomentum,
1234  clusterRef->positionREP().Eta());
1235  resol *= trackMomentum;
1236  }
1237  }
1238 
1239  bool isPrimary = isFromSecInt(elements[iTrack], "primary");
1240 
1241  if ( deficit > nSigmaTRACK_*resol && !isPrimary && !goodTrackDeadHcal) {
1242  rejectFake = true;
1243  active[iTrack] = false;
1244  if ( debug_ )
1245  std::cout << elements[iTrack] << std::endl
1246  << " deficit " << deficit << " > " << nSigmaTRACK_ << " x " << resol
1247  << " track pt " << trackRef->pt() << " +- " << trackRef->ptError()
1248  << " layers valid " << trackRef->hitPattern().trackerLayersWithMeasurement()
1249  << ", lost " << trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::TRACK_HITS)
1250  << ", lost outer " << trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::MISSING_OUTER_HITS)
1251  << ", lost inner " << trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::MISSING_INNER_HITS)
1252  << "(valid fraction " << trackRef->validFraction() <<")"
1253  << " chi2/ndf " << trackRef->normalizedChi2()
1254  << " |dxy| " << std::abs(trackRef->dxy(primaryVertex_.position())) << " +- " << trackRef->dxyError()
1255  << " |dz| " << std::abs(trackRef->dz(primaryVertex_.position())) << " +- " << trackRef->dzError()
1256  << "is probably a fake (1) --> lock the track"
1257  << std::endl;
1258  }
1259  }
1260 
1261  if ( rejectFake ) continue;
1262 
1263  // Create a track candidate
1264  // unsigned tmpi = reconstructTrack( elements[iTrack] );
1265  //active[iTrack] = false;
1266  std::vector<unsigned> tmpi;
1267  std::vector<unsigned> kTrack;
1268 
1269  // Some cleaning : secondary tracks without calo's and large momentum must be fake
1270  double Dpt = trackRef->ptError();
1271 
1272  if ( rejectTracks_Step45_ && ecalElems.empty() &&
1273  trackMomentum > 30. && Dpt > 0.5 &&
1274  ( PFTrackAlgoTools::step45(trackRef->algo())
1275  && !goodTrackDeadHcal) ) {
1276 
1277  double dptRel = Dpt/trackRef->pt()*100;
1278  bool isPrimaryOrSecondary = isFromSecInt(elements[iTrack], "all");
1279 
1280  if ( isPrimaryOrSecondary && dptRel < dptRel_DispVtx_) continue;
1281  unsigned nHits = elements[iTrack].trackRef()->hitPattern().trackerLayersWithMeasurement();
1282  unsigned int NLostHit = trackRef->hitPattern().trackerLayersWithoutMeasurement(HitPattern::TRACK_HITS);
1283 
1284  if ( debug_ )
1285  std::cout << "A track (algo = " << trackRef->algo() << ") with momentum " << trackMomentum
1286  << " / " << elements[iTrack].trackRef()->pt() << " +/- " << Dpt
1287  << " / " << elements[iTrack].trackRef()->eta()
1288  << " without any link to ECAL/HCAL and with " << nHits << " (" << NLostHit
1289  << ") hits (lost hits) has been cleaned" << std::endl;
1290  active[iTrack] = false;
1291  continue;
1292  }
1293 
1294 
1295  tmpi.push_back(reconstructTrack( elements[iTrack]));
1296 
1297  kTrack.push_back(iTrack);
1298  active[iTrack] = false;
1299 
1300  // No ECAL cluster either ... continue...
1301  if ( ecalElems.empty() ) {
1302  (*pfCandidates_)[tmpi[0]].setEcalEnergy( 0., 0. );
1303  (*pfCandidates_)[tmpi[0]].setHcalEnergy( 0., 0. );
1304  (*pfCandidates_)[tmpi[0]].setHoEnergy( 0., 0. );
1305  (*pfCandidates_)[tmpi[0]].setPs1Energy( 0 );
1306  (*pfCandidates_)[tmpi[0]].setPs2Energy( 0 );
1307  (*pfCandidates_)[tmpi[0]].addElementInBlock( blockref, kTrack[0] );
1308  continue;
1309  }
1310 
1311  // Look for closest ECAL cluster
1312  unsigned thisEcal = ecalElems.begin()->second;
1313  reco::PFClusterRef clusterRef = elements[thisEcal].clusterRef();
1314  if ( debug_ ) std::cout << " is associated to " << elements[thisEcal] << std::endl;
1315 
1316 
1317  // Set ECAL energy for muons
1318  if ( thisIsAMuon ) {
1319  (*pfCandidates_)[tmpi[0]].setEcalEnergy( clusterRef->energy(),
1320  std::min(clusterRef->energy(), muonECAL_[0]) );
1321  (*pfCandidates_)[tmpi[0]].setHcalEnergy( 0., 0. );
1322  (*pfCandidates_)[tmpi[0]].setHoEnergy( 0., 0. );
1323  (*pfCandidates_)[tmpi[0]].setPs1Energy( 0 );
1324  (*pfCandidates_)[tmpi[0]].setPs2Energy( 0 );
1325  (*pfCandidates_)[tmpi[0]].addElementInBlock( blockref, kTrack[0] );
1326  }
1327 
1328  double slopeEcal = 1.;
1329  bool connectedToEcal = false;
1330  unsigned iEcal = 99999;
1331  double calibEcal = 0.;
1332  double calibHcal = 0.;
1333  double totalEcal = thisIsAMuon ? -muonECAL_[0] : 0.;
1334 
1335  // Consider charged particles closest to the same ECAL cluster
1336  std::multimap<double, unsigned> sortedTracks;
1337  block.associatedElements( thisEcal, linkData,
1338  sortedTracks,
1341  if (debug_) cout << "the closest ECAL cluster, id " << thisEcal << ", has " << sortedTracks.size() << " associated tracks, now processing them. " << endl;
1342 
1343  if (hasDeadHcal && !sortedTracks.empty()) {
1344  // GP: only allow the ecal cluster closest to this track to be considered
1345  if (debug_) cout << " the closest track to ECAL " << thisEcal << " is " << sortedTracks.begin()->second << " (distance " << sortedTracks.begin()->first << ")" << endl;
1346  if (sortedTracks.begin()->second != iTrack) {
1347  if (debug_) cout << " the closest track to ECAL " << thisEcal << " is " << sortedTracks.begin()->second << " which is not the one being processed. Will skip ECAL linking for this track" << endl;
1348  (*pfCandidates_)[tmpi[0]].setEcalEnergy( 0., 0. );
1349  (*pfCandidates_)[tmpi[0]].setHcalEnergy( 0., 0. );
1350  (*pfCandidates_)[tmpi[0]].setHoEnergy( 0., 0. );
1351  (*pfCandidates_)[tmpi[0]].setPs1Energy( 0 );
1352  (*pfCandidates_)[tmpi[0]].setPs2Energy( 0 );
1353  (*pfCandidates_)[tmpi[0]].addElementInBlock( blockref, kTrack[0] );
1354  continue;
1355  } else {
1356  if (debug_) cout << " the closest track to ECAL " << thisEcal << " is " << sortedTracks.begin()->second << " which is the one being processed. Will skip ECAL linking for all other track" << endl;
1357  sortedTracks.clear();
1358  }
1359  }
1360 
1361  for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
1362  unsigned jTrack = ie->second;
1363 
1364  // Don't consider already used tracks
1365  if ( !active[jTrack] ) continue;
1366 
1367  // The loop is on the other tracks !
1368  if ( jTrack == iTrack ) continue;
1369 
1370  // Check if the ECAL cluster closest to this track is
1371  // indeed the current ECAL cluster. Only tracks not
1372  // linked to an HCAL cluster are considered here
1373  // (GP: this is because if there's a jTrack linked
1374  // to the same Ecal cluster and that also has an Hcal link
1375  // we would have also linked iTrack to that Hcal above)
1376  std::multimap<double, unsigned> sortedECAL;
1377  block.associatedElements( jTrack, linkData,
1378  sortedECAL,
1381  if ( sortedECAL.begin()->second != thisEcal ) continue;
1382 
1383  // Check if this track is a muon
1384  bool thatIsAMuon = PFMuonAlgo::isMuon(elements[jTrack]);
1385  if (debug_) {
1386  cout << " found track " << jTrack << (thatIsAMuon ? " (muon) " : " (non-muon)") << ", with distance = " << sortedECAL.begin()->first << std::endl;
1387  }
1388 
1389 
1390  // Check if this track is not a fake
1391  bool rejectFake = false;
1392  reco::TrackRef trackRef = elements[jTrack].trackRef();
1393  if ( !thatIsAMuon && trackRef->ptError() > ptError_) {
1394  // GP: FIXME this selection should be adapted depending on hasDeadHcal
1395  // but we don't know if jTrack is linked to a dead Hcal or not
1396  double deficit = trackMomentum + trackRef->p() - clusterRef->energy();
1397  double resol = nSigmaTRACK_*neutralHadronEnergyResolution(trackMomentum+trackRef->p(),
1398  clusterRef->positionREP().Eta());
1399  resol *= (trackMomentum+trackRef->p());
1400  if ( deficit > nSigmaTRACK_*resol && !goodTrackDeadHcal) {
1401  rejectFake = true;
1402  kTrack.push_back(jTrack);
1403  active[jTrack] = false;
1404  if ( debug_ )
1405  std::cout << elements[jTrack] << std::endl
1406  << "is probably a fake (2) --> lock the track"
1407  << "(trackMomentum = " << trackMomentum << ", clusterEnergy = " << clusterRef->energy() <<
1408  ", deficit = " << deficit << " > " << nSigmaTRACK_ << " x " << resol <<
1409  " assuming neutralHadronEnergyResolution " << neutralHadronEnergyResolution(trackMomentum+trackRef->p(), clusterRef->positionREP().Eta()) << ") "
1410  << std::endl;
1411  }
1412  }
1413  if ( rejectFake ) continue;
1414 
1415 
1416  // Otherwise, add this track momentum to the total track momentum
1417  /* */
1418  // reco::TrackRef trackRef = elements[jTrack].trackRef();
1419  if ( !thatIsAMuon ) {
1420  if ( debug_ )
1421  std::cout << "Track momentum increased from " << trackMomentum << " GeV ";
1422  trackMomentum += trackRef->p();
1423  if ( debug_ ) {
1424  std::cout << "to " << trackMomentum << " GeV." << std::endl;
1425  std::cout << "with " << elements[jTrack] << std::endl;
1426  }
1427  } else {
1428  totalEcal -= muonECAL_[0];
1429  totalEcal = std::max(totalEcal, 0.);
1430  }
1431 
1432  // And create a charged particle candidate !
1433 
1434  tmpi.push_back(reconstructTrack( elements[jTrack] ));
1435 
1436 
1437  kTrack.push_back(jTrack);
1438  active[jTrack] = false;
1439 
1440  if ( thatIsAMuon ) {
1441  (*pfCandidates_)[tmpi.back()].setEcalEnergy(clusterRef->energy(),
1442  std::min(clusterRef->energy(),muonECAL_[0]));
1443  (*pfCandidates_)[tmpi.back()].setHcalEnergy( 0., 0. );
1444  (*pfCandidates_)[tmpi.back()].setHoEnergy( 0., 0. );
1445  (*pfCandidates_)[tmpi.back()].setPs1Energy( 0 );
1446  (*pfCandidates_)[tmpi.back()].setPs2Energy( 0 );
1447  (*pfCandidates_)[tmpi.back()].addElementInBlock( blockref, kTrack.back() );
1448  }
1449  }
1450 
1451 
1452  if ( debug_ ) std::cout << "Loop over all associated ECAL clusters" << std::endl;
1453  // Loop over all ECAL linked clusters ordered by increasing distance.
1454  for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
1455 
1456  unsigned index = ie->second;
1457  PFBlockElement::Type type = elements[index].type();
1458  assert( type == PFBlockElement::ECAL );
1459  if ( debug_ ) std::cout << elements[index] << std::endl;
1460 
1461  // Just skip clusters already taken
1462  if ( debug_ && ! active[index] ) std::cout << "is not active - ignore " << std::endl;
1463  if ( ! active[index] ) continue;
1464 
1465  // Just skip this cluster if it's closer to another track
1466  /* */
1467  block.associatedElements( index, linkData,
1468  sortedTracks,
1471  bool skip = true;
1472  for (unsigned ic=0; ic<kTrack.size();++ic) {
1473  if ( sortedTracks.begin()->second == kTrack[ic] ) {
1474  skip = false;
1475  break;
1476  }
1477  }
1478  if ( debug_ && skip ) std::cout << "is closer to another track - ignore " << std::endl;
1479  if ( skip ) continue;
1480  /* */
1481 
1482  // The corresponding PFCluster and energy
1483  reco::PFClusterRef clusterRef = elements[index].clusterRef();
1484  assert( !clusterRef.isNull() );
1485 
1486  if ( debug_ ) {
1487  double dist = ie->first;
1488  std::cout <<"Ecal cluster with raw energy = " << clusterRef->energy()
1489  <<" linked with distance = " << dist << std::endl;
1490  }
1491  /*
1492  double dist = ie->first;
1493  if ( !connectedToEcal && dist > 0.1 ) {
1494  std::cout << "Warning - first ECAL cluster at a distance of " << dist << "from the closest track!" << std::endl;
1495  cout<<"\telement "<<elements[index]<<" linked with distance = "<< dist <<endl;
1496  cout<<"\telement "<<elements[iTrack]<<" linked with distance = "<< dist <<endl;
1497  }
1498  */
1499 
1500  // Check the presence of preshower clusters in the vicinity
1501  // Preshower cluster closer to another ECAL cluster are ignored.
1502  //JOSH: This should use the association map already produced by the cluster corrector for consistency,
1503  //but should be ok for now
1504  vector<double> ps1Ene(1,static_cast<double>(0.));
1505  associatePSClusters(index, reco::PFBlockElement::PS1, block, elements, linkData, active, ps1Ene);
1506  vector<double> ps2Ene(1,static_cast<double>(0.));
1507  associatePSClusters(index, reco::PFBlockElement::PS2, block, elements, linkData, active, ps2Ene);
1508 
1509  double ecalEnergy = clusterRef->correctedEnergy();
1510  if ( debug_ )
1511  std::cout << "Corrected ECAL(+PS) energy = " << ecalEnergy << std::endl;
1512 
1513  // Since the electrons were found beforehand, this track must be a hadron. Calibrate
1514  // the energy under the hadron hypothesis.
1515  totalEcal += ecalEnergy;
1516  double previousCalibEcal = calibEcal;
1517  double previousSlopeEcal = slopeEcal;
1518  calibEcal = std::max(totalEcal,0.);
1519  calibHcal = 0.;
1520  calibration_->energyEmHad(trackMomentum,calibEcal,calibHcal,
1521  clusterRef->positionREP().Eta(),
1522  clusterRef->positionREP().Phi());
1523  if ( totalEcal > 0.) slopeEcal = calibEcal/totalEcal;
1524 
1525  if ( debug_ )
1526  std::cout << "The total calibrated energy so far amounts to = " << calibEcal << " (slope = " << slopeEcal << ")" << std::endl;
1527 
1528 
1529  // Stop the loop when adding more ECAL clusters ruins the compatibility
1530  if ( connectedToEcal && calibEcal - trackMomentum >= 0. ) {
1531  // if ( connectedToEcal && calibEcal - trackMomentum >=
1532  // nSigmaECAL_*neutralHadronEnergyResolution(trackMomentum,clusterRef->positionREP().Eta()) ) {
1533  calibEcal = previousCalibEcal;
1534  slopeEcal = previousSlopeEcal;
1535  totalEcal = calibEcal/slopeEcal;
1536 
1537  // Turn this last cluster in a photon
1538  // (The PS clusters are already locked in "associatePSClusters")
1539  active[index] = false;
1540 
1541  // Find the associated tracks
1542  std::multimap<double, unsigned> assTracks;
1543  block.associatedElements( index, linkData,
1544  assTracks,
1547 
1548 
1549  unsigned tmpe = reconstructCluster( *clusterRef, ecalEnergy );
1550  (*pfCandidates_)[tmpe].setEcalEnergy( clusterRef->energy(), ecalEnergy );
1551  (*pfCandidates_)[tmpe].setHcalEnergy( 0., 0. );
1552  (*pfCandidates_)[tmpe].setHoEnergy( 0., 0. );
1553  (*pfCandidates_)[tmpe].setPs1Energy( ps1Ene[0] );
1554  (*pfCandidates_)[tmpe].setPs2Energy( ps2Ene[0] );
1555  (*pfCandidates_)[tmpe].addElementInBlock( blockref, index );
1556  // Check that there is at least one track
1557  if(!assTracks.empty()) {
1558  (*pfCandidates_)[tmpe].addElementInBlock( blockref, assTracks.begin()->second );
1559 
1560  // Assign the position of the track at the ECAL entrance
1561  const ::math::XYZPointF& chargedPosition =
1562  dynamic_cast<const reco::PFBlockElementTrack*>(&elements[assTracks.begin()->second])->positionAtECALEntrance();
1563  (*pfCandidates_)[tmpe].setPositionAtECALEntrance(chargedPosition);
1564  }
1565  break;
1566  }
1567 
1568  // Lock used clusters.
1569  connectedToEcal = true;
1570  iEcal = index;
1571  active[index] = false;
1572  for (unsigned ic=0; ic<tmpi.size();++ic)
1573  (*pfCandidates_)[tmpi[ic]].addElementInBlock( blockref, iEcal );
1574 
1575 
1576  } // Loop ecal elements
1577 
1578  bool bNeutralProduced = false;
1579 
1580  // Create a photon if the ecal energy is too large
1581  if( connectedToEcal ) {
1582  reco::PFClusterRef pivotalRef = elements[iEcal].clusterRef();
1583 
1584  double neutralEnergy = calibEcal - trackMomentum;
1585 
1586  /*
1587  // Check if there are other tracks linked to that ECAL
1588  for(IE ie = sortedTracks.begin(); ie != sortedTracks.end() && neutralEnergy > 0; ++ie ) {
1589  unsigned jTrack = ie->second;
1590 
1591  // The loop is on the other tracks !
1592  if ( jTrack == iTrack ) continue;
1593 
1594  // Check if the ECAL closest to this track is the current ECAL
1595  // Otherwise ignore this track in the neutral energy determination
1596  std::multimap<double, unsigned> sortedECAL;
1597  block.associatedElements( jTrack, linkData,
1598  sortedECAL,
1599  reco::PFBlockElement::ECAL,
1600  reco::PFBlock::LINKTEST_ALL );
1601  if ( sortedECAL.begin()->second != iEcal ) continue;
1602 
1603  // Check if this track is also linked to an HCAL
1604  // (in which case it goes to the next loop and is ignored here)
1605  std::multimap<double, unsigned> sortedHCAL;
1606  block.associatedElements( jTrack, linkData,
1607  sortedHCAL,
1608  reco::PFBlockElement::HCAL,
1609  reco::PFBlock::LINKTEST_ALL );
1610  if ( sortedHCAL.size() ) continue;
1611 
1612  // Otherwise, subtract this track momentum from the ECAL energy
1613  reco::TrackRef trackRef = elements[jTrack].trackRef();
1614  neutralEnergy -= trackRef->p();
1615 
1616  } // End other tracks
1617  */
1618 
1619  // Add a photon is the energy excess is large enough
1620  double resol = neutralHadronEnergyResolution(trackMomentum,pivotalRef->positionREP().Eta());
1621  resol *= trackMomentum;
1622  if ( neutralEnergy > std::max(0.5,nSigmaECAL_*resol) ) {
1623  neutralEnergy /= slopeEcal;
1624  unsigned tmpj = reconstructCluster( *pivotalRef, neutralEnergy );
1625  (*pfCandidates_)[tmpj].setEcalEnergy( pivotalRef->energy(), neutralEnergy );
1626  (*pfCandidates_)[tmpj].setHcalEnergy( 0., 0. );
1627  (*pfCandidates_)[tmpj].setHoEnergy( 0., 0. );
1628  (*pfCandidates_)[tmpj].setPs1Energy( 0. );
1629  (*pfCandidates_)[tmpj].setPs2Energy( 0. );
1630  (*pfCandidates_)[tmpj].addElementInBlock(blockref, iEcal);
1631  bNeutralProduced = true;
1632  for (unsigned ic=0; ic<kTrack.size();++ic)
1633  (*pfCandidates_)[tmpj].addElementInBlock( blockref, kTrack[ic] );
1634  } // End neutral energy
1635 
1636  // Set elements in blocks and ECAL energies to all tracks
1637  for (unsigned ic=0; ic<tmpi.size();++ic) {
1638 
1639  // Skip muons
1640  if ( (*pfCandidates_)[tmpi[ic]].particleId() == reco::PFCandidate::mu ) continue;
1641 
1642  double fraction = trackMomentum > 0 ? (*pfCandidates_)[tmpi[ic]].trackRef()->p()/trackMomentum : 0;
1643  double ecalCal = bNeutralProduced ?
1644  (calibEcal-neutralEnergy*slopeEcal)*fraction : calibEcal*fraction;
1645  double ecalRaw = totalEcal*fraction;
1646 
1647  if (debug_) cout << "The fraction after photon supression is " << fraction << " calibrated ecal = " << ecalCal << endl;
1648 
1649  (*pfCandidates_)[tmpi[ic]].setEcalEnergy( ecalRaw, ecalCal );
1650  (*pfCandidates_)[tmpi[ic]].setHcalEnergy( 0., 0. );
1651  (*pfCandidates_)[tmpi[ic]].setHoEnergy( 0., 0. );
1652  (*pfCandidates_)[tmpi[ic]].setPs1Energy( 0 );
1653  (*pfCandidates_)[tmpi[ic]].setPs2Energy( 0 );
1654  (*pfCandidates_)[tmpi[ic]].addElementInBlock( blockref, kTrack[ic] );
1655  }
1656 
1657  } // End connected ECAL
1658 
1659  // Fill the element_in_block for tracks that are eventually linked to no ECAL clusters at all.
1660  for (unsigned ic=0; ic<tmpi.size();++ic) {
1661  const PFCandidate& pfc = (*pfCandidates_)[tmpi[ic]];
1662  const PFCandidate::ElementsInBlocks& eleInBlocks = pfc.elementsInBlocks();
1663  if ( eleInBlocks.empty() ) {
1664  if ( debug_ )std::cout << "Single track / Fill element in block! " << std::endl;
1665  (*pfCandidates_)[tmpi[ic]].addElementInBlock( blockref, kTrack[ic] );
1666  }
1667  }
1668 
1669  } // end if( hcalElems.empty() )
1670 
1671 
1672  // In case several HCAL elements are linked to this track,
1673  // unlinking all of them except the closest.
1674  for(IE ie = hcalElems.begin(); ie != hcalElems.end(); ++ie ) {
1675 
1676  unsigned index = ie->second;
1677 
1678  PFBlockElement::Type type = elements[index].type();
1679 
1680  if(debug_) {
1681  double dist = block.dist(iTrack,index,linkData,reco::PFBlock::LINKTEST_ALL);
1682  cout<<"\telement "<<elements[index]<<" linked with distance "<< dist <<endl;
1683  }
1684 
1685  assert( type == PFBlockElement::HCAL );
1686 
1687  // all hcal clusters except the closest
1688  // will be unlinked from the track
1689  if( !hcalFound ) { // closest hcal
1690  if(debug_)
1691  cout<<"\t\tclosest hcal cluster, doing nothing"<<endl;
1692 
1693  hcalFound = true;
1694 
1695  // active[index] = false;
1696  // hcalUsed.push_back( index );
1697  }
1698  else { // other associated hcal
1699  // unlink from the track
1700  if(debug_)
1701  cout<<"\t\tsecondary hcal cluster. unlinking"<<endl;
1702  block.setLink( iTrack, index, -1., linkData,
1703  PFBlock::LINKTEST_RECHIT );
1704  }
1705  } //loop hcal elements
1706  } // end of loop 1 on elements iEle of any type
1707 
1708 
1709 
1710  // deal with HF.
1711  if( !(hfEmIs.empty() && hfHadIs.empty() ) ) {
1712  // there is at least one HF element in this block.
1713  // so all elements must be HF.
1714  assert( hfEmIs.size() + hfHadIs.size() == elements.size() );
1715 
1716  if( elements.size() == 1 ) {
1717  //Auguste: HAD-only calibration here
1718  reco::PFClusterRef clusterRef = elements[0].clusterRef();
1719  double energyHF = 0.;
1720  double uncalibratedenergyHF = 0.;
1721  unsigned tmpi = 0;
1722  switch( clusterRef->layer() ) {
1723  case PFLayer::HF_EM:
1724  // do EM-only calibration here
1725  energyHF = clusterRef->energy();
1726  uncalibratedenergyHF = energyHF;
1727  if(thepfEnergyCalibrationHF_->getcalibHF_use()==true){
1728  energyHF = thepfEnergyCalibrationHF_->energyEm(uncalibratedenergyHF,
1729  clusterRef->positionREP().Eta(),
1730  clusterRef->positionREP().Phi());
1731  }
1732  tmpi = reconstructCluster( *clusterRef, energyHF );
1733  (*pfCandidates_)[tmpi].setEcalEnergy( uncalibratedenergyHF, energyHF );
1734  (*pfCandidates_)[tmpi].setHcalEnergy( 0., 0.);
1735  (*pfCandidates_)[tmpi].setHoEnergy( 0., 0.);
1736  (*pfCandidates_)[tmpi].setPs1Energy( 0. );
1737  (*pfCandidates_)[tmpi].setPs2Energy( 0. );
1738  (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfEmIs[0] );
1739  //std::cout << "HF EM alone ! " << energyHF << std::endl;
1740  break;
1741  case PFLayer::HF_HAD:
1742  // do HAD-only calibration here
1743  energyHF = clusterRef->energy();
1744  uncalibratedenergyHF = energyHF;
1745  if(thepfEnergyCalibrationHF_->getcalibHF_use()==true){
1746  energyHF = thepfEnergyCalibrationHF_->energyHad(uncalibratedenergyHF,
1747  clusterRef->positionREP().Eta(),
1748  clusterRef->positionREP().Phi());
1749  }
1750  tmpi = reconstructCluster( *clusterRef, energyHF );
1751  (*pfCandidates_)[tmpi].setHcalEnergy( uncalibratedenergyHF, energyHF );
1752  (*pfCandidates_)[tmpi].setEcalEnergy( 0., 0.);
1753  (*pfCandidates_)[tmpi].setHoEnergy( 0., 0.);
1754  (*pfCandidates_)[tmpi].setPs1Energy( 0. );
1755  (*pfCandidates_)[tmpi].setPs2Energy( 0. );
1756  (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfHadIs[0] );
1757  //std::cout << "HF Had alone ! " << energyHF << std::endl;
1758  break;
1759  default:
1760  assert(0);
1761  }
1762  }
1763  else if( elements.size() == 2 ) {
1764  //Auguste: EM + HAD calibration here
1765  reco::PFClusterRef c0 = elements[0].clusterRef();
1766  reco::PFClusterRef c1 = elements[1].clusterRef();
1767  // 2 HF elements. Must be in each layer.
1768  reco::PFClusterRef cem = ( c0->layer() == PFLayer::HF_EM ? c0 : c1 );
1769  reco::PFClusterRef chad = ( c1->layer() == PFLayer::HF_HAD ? c1 : c0 );
1770 
1771  if( cem->layer() != PFLayer::HF_EM || chad->layer() != PFLayer::HF_HAD ) {
1772  cerr<<"Error: 2 elements, but not 1 HFEM and 1 HFHAD"<<endl;
1773  cerr<<block<<endl;
1774  assert(0);
1775 // assert( c1->layer()== PFLayer::HF_EM &&
1776 // c0->layer()== PFLayer::HF_HAD );
1777  }
1778  // do EM+HAD calibration here
1779  double energyHfEm = cem->energy();
1780  double energyHfHad = chad->energy();
1781  double uncalibratedenergyHFEm = energyHfEm;
1782  double uncalibratedenergyHFHad = energyHfHad;
1783  if(thepfEnergyCalibrationHF_->getcalibHF_use()==true){
1784 
1785  energyHfEm = thepfEnergyCalibrationHF_->energyEmHad(uncalibratedenergyHFEm,
1786  0.0,
1787  c0->positionREP().Eta(),
1788  c0->positionREP().Phi());
1789  energyHfHad = thepfEnergyCalibrationHF_->energyEmHad(0.0,
1790  uncalibratedenergyHFHad,
1791  c1->positionREP().Eta(),
1792  c1->positionREP().Phi());
1793  }
1794  unsigned tmpi = reconstructCluster( *chad, energyHfEm+energyHfHad );
1795  (*pfCandidates_)[tmpi].setEcalEnergy( uncalibratedenergyHFEm, energyHfEm );
1796  (*pfCandidates_)[tmpi].setHcalEnergy( uncalibratedenergyHFHad, energyHfHad);
1797  (*pfCandidates_)[tmpi].setHoEnergy( 0., 0.);
1798  (*pfCandidates_)[tmpi].setPs1Energy( 0. );
1799  (*pfCandidates_)[tmpi].setPs2Energy( 0. );
1800  (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfEmIs[0] );
1801  (*pfCandidates_)[tmpi].addElementInBlock( blockref, hfHadIs[0] );
1802  //std::cout << "HF EM+HAD found ! " << energyHfEm << " " << energyHfHad << std::endl;
1803  }
1804  else {
1805  // 1 HF element in the block,
1806  // but number of elements not equal to 1 or 2
1807  cerr<<"Warning: HF, but n elem different from 1 or 2"<<endl;
1808  cerr<<block<<endl;
1809 // assert(0);
1810 // cerr<<"not ready for navigation in the HF!"<<endl;
1811  }
1812  }
1813 
1814 
1815 
1816  if(debug_) {
1817  cout<<endl;
1818  cout<<endl<<"--------------- loop hcal ---------------------"<<endl;
1819  }
1820 
1821  // track information:
1822  // trackRef
1823  // ecal energy
1824  // hcal energy
1825  // rescale
1826 
1827  for(unsigned i=0; i<hcalIs.size(); i++) {
1828 
1829  unsigned iHcal= hcalIs[i];
1830  PFBlockElement::Type type = elements[iHcal].type();
1831 
1832  assert( type == PFBlockElement::HCAL );
1833 
1834  if(debug_) cout<<endl<<elements[iHcal]<<endl;
1835 
1836  // vector<unsigned> elementIndices;
1837  // elementIndices.push_back(iHcal);
1838 
1839  // associated tracks
1840  std::multimap<double, unsigned> sortedTracks;
1841  block.associatedElements( iHcal, linkData,
1842  sortedTracks,
1845 
1846  std::multimap< unsigned, std::pair<double, unsigned> > associatedEcals;
1847 
1848  std::map< unsigned, std::pair<double, double> > associatedPSs;
1849 
1850  std::multimap<double, std::pair<unsigned,bool> > associatedTracks;
1851 
1852  // A temporary maps for ECAL satellite clusters
1853  std::multimap<double,std::pair<unsigned,::math::XYZVector> > ecalSatellites;
1854  std::pair<unsigned,::math::XYZVector> fakeSatellite = make_pair(iHcal,::math::XYZVector(0.,0.,0.));
1855  ecalSatellites.insert( make_pair(-1., fakeSatellite) );
1856 
1857  std::multimap< unsigned, std::pair<double, unsigned> > associatedHOs;
1858 
1859  PFClusterRef hclusterref = elements[iHcal].clusterRef();
1860  assert(!hclusterref.isNull() );
1861 
1862 
1863  //if there is no track attached to that HCAL, then do not
1864  //reconstruct an HCAL alone, check if it can be recovered
1865  //first
1866 
1867  // if no associated tracks, create a neutral hadron
1868  //if(sortedTracks.empty() ) {
1869 
1870  if( sortedTracks.empty() ) {
1871  if(debug_)
1872  cout<<"\tno associated tracks, keep for later"<<endl;
1873  continue;
1874  }
1875 
1876  // Lock the HCAL cluster
1877  active[iHcal] = false;
1878 
1879 
1880  // in the following, tracks are associated to this hcal cluster.
1881  // will look for an excess of energy in the calorimeters w/r to
1882  // the charged energy, and turn this excess into a neutral hadron or
1883  // a photon.
1884 
1885  if(debug_) cout<<"\t"<<sortedTracks.size()<<" associated tracks:"<<endl;
1886 
1887  double totalChargedMomentum = 0;
1888  double sumpError2 = 0.;
1889  double totalHO = 0.;
1890  double totalEcal = 0.;
1891  double totalHcal = hclusterref->energy();
1892  vector<double> hcalP;
1893  vector<double> hcalDP;
1894  vector<unsigned> tkIs;
1895  double maxDPovP = -9999.;
1896 
1897  //Keep track of how much energy is assigned to calorimeter-vs-track energy/momentum excess
1898  vector< unsigned > chargedHadronsIndices;
1899  vector< unsigned > chargedHadronsInBlock;
1900  double mergedNeutralHadronEnergy = 0;
1901  double mergedPhotonEnergy = 0;
1902  double muonHCALEnergy = 0.;
1903  double muonECALEnergy = 0.;
1904  double muonHCALError = 0.;
1905  double muonECALError = 0.;
1906  unsigned nMuons = 0;
1907 
1908 
1909  ::math::XYZVector photonAtECAL(0.,0.,0.);
1910  std::vector<std::pair<unsigned,::math::XYZVector> > ecalClusters;
1911  double sumEcalClusters=0;
1912  ::math::XYZVector hadronDirection(hclusterref->position().X(),
1913  hclusterref->position().Y(),
1914  hclusterref->position().Z());
1915  hadronDirection = hadronDirection.Unit();
1916  ::math::XYZVector hadronAtECAL = totalHcal * hadronDirection;
1917 
1918  // Loop over all tracks associated to this HCAL cluster
1919  for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
1920 
1921  unsigned iTrack = ie->second;
1922 
1923  // Check the track has not already been used (e.g., in electrons, conversions...)
1924  if ( !active[iTrack] ) continue;
1925  // Sanity check 1
1926  PFBlockElement::Type type = elements[iTrack].type();
1927  assert( type == reco::PFBlockElement::TRACK );
1928  // Sanity check 2
1929  reco::TrackRef trackRef = elements[iTrack].trackRef();
1930  assert( !trackRef.isNull() );
1931 
1932  // The direction at ECAL entrance
1933  const ::math::XYZPointF& chargedPosition =
1934  dynamic_cast<const reco::PFBlockElementTrack*>(&elements[iTrack])->positionAtECALEntrance();
1935  ::math::XYZVector chargedDirection(chargedPosition.X(),chargedPosition.Y(),chargedPosition.Z());
1936  chargedDirection = chargedDirection.Unit();
1937 
1938  // look for ECAL elements associated to iTrack (associated to iHcal)
1939  std::multimap<double, unsigned> sortedEcals;
1940  block.associatedElements( iTrack, linkData,
1941  sortedEcals,
1944 
1945  if(debug_) cout<<"\t\t\tnumber of Ecal elements linked to this track: "
1946  <<sortedEcals.size()<<endl;
1947 
1948  // look for HO elements associated to iTrack (associated to iHcal)
1949  std::multimap<double, unsigned> sortedHOs;
1950  if (useHO_) {
1951  block.associatedElements( iTrack, linkData,
1952  sortedHOs,
1955 
1956  }
1957  if(debug_)
1958  cout<<"PFAlgo : number of HO elements linked to this track: "
1959  <<sortedHOs.size()<<endl;
1960 
1961  // Create a PF Candidate right away if the track is a tight muon
1962  reco::MuonRef muonRef = elements[iTrack].muonRef();
1963 
1964 
1965  bool thisIsAMuon = PFMuonAlgo::isMuon(elements[iTrack]);
1966  bool thisIsAnIsolatedMuon = PFMuonAlgo::isIsolatedMuon(elements[iTrack]);
1967  bool thisIsALooseMuon = false;
1968 
1969 
1970  if(!thisIsAMuon ) {
1971  thisIsALooseMuon = PFMuonAlgo::isLooseMuon(elements[iTrack]);
1972  }
1973 
1974 
1975  if ( thisIsAMuon ) {
1976  if ( debug_ ) {
1977  std::cout << "\t\tThis track is identified as a muon - remove it from the stack" << std::endl;
1978  std::cout << "\t\t" << elements[iTrack] << std::endl;
1979  }
1980 
1981  // Create a muon.
1982 
1983  unsigned tmpi = reconstructTrack( elements[iTrack] );
1984 
1985 
1986  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
1987  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
1988  double muonHcal = std::min(muonHCAL_[0]+muonHCAL_[1],totalHcal);
1989 
1990  // if muon is isolated and muon momentum exceeds the calo energy, absorb the calo energy
1991  // rationale : there has been a EM showering by the muon in the calorimeter - or the coil -
1992  // and we don't want to double count the energy
1993  bool letMuonEatCaloEnergy = false;
1994 
1995  if(thisIsAnIsolatedMuon){
1996  // The factor 1.3 is the e/pi factor in HCAL...
1997  double totalCaloEnergy = totalHcal / 1.30;
1998  unsigned iEcal = 0;
1999  if( !sortedEcals.empty() ) {
2000  iEcal = sortedEcals.begin()->second;
2001  PFClusterRef eclusterref = elements[iEcal].clusterRef();
2002  totalCaloEnergy += eclusterref->energy();
2003  }
2004 
2005  if (useHO_) {
2006  // The factor 1.3 is assumed to be the e/pi factor in HO, too.
2007  unsigned iHO = 0;
2008  if( !sortedHOs.empty() ) {
2009  iHO = sortedHOs.begin()->second;
2010  PFClusterRef eclusterref = elements[iHO].clusterRef();
2011  totalCaloEnergy += eclusterref->energy() / 1.30;
2012  }
2013  }
2014 
2015  // std::cout << "muon p / total calo = " << muonRef->p() << " " << (pfCandidates_->back()).p() << " " << totalCaloEnergy << std::endl;
2016  //if(muonRef->p() > totalCaloEnergy ) letMuonEatCaloEnergy = true;
2017  if( (pfCandidates_->back()).p() > totalCaloEnergy ) letMuonEatCaloEnergy = true;
2018  }
2019 
2020  if(letMuonEatCaloEnergy) muonHcal = totalHcal;
2021  double muonEcal =0.;
2022  unsigned iEcal = 0;
2023  if( !sortedEcals.empty() ) {
2024  iEcal = sortedEcals.begin()->second;
2025  PFClusterRef eclusterref = elements[iEcal].clusterRef();
2026  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal);
2027  muonEcal = std::min(muonECAL_[0]+muonECAL_[1],eclusterref->energy());
2028  if(letMuonEatCaloEnergy) muonEcal = eclusterref->energy();
2029  // If the muon expected energy accounts for the whole ecal cluster energy, lock the ecal cluster
2030  if ( eclusterref->energy() - muonEcal < 0.2 ) active[iEcal] = false;
2031  (*pfCandidates_)[tmpi].setEcalEnergy(eclusterref->energy(), muonEcal);
2032  }
2033  unsigned iHO = 0;
2034  double muonHO =0.;
2035  if (useHO_) {
2036  if( !sortedHOs.empty() ) {
2037  iHO = sortedHOs.begin()->second;
2038  PFClusterRef hoclusterref = elements[iHO].clusterRef();
2039  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHO);
2040  muonHO = std::min(muonHO_[0]+muonHO_[1],hoclusterref->energy());
2041  if(letMuonEatCaloEnergy) muonHO = hoclusterref->energy();
2042  // If the muon expected energy accounts for the whole HO cluster energy, lock the HO cluster
2043  if ( hoclusterref->energy() - muonHO < 0.2 ) active[iHO] = false;
2044  (*pfCandidates_)[tmpi].setHcalEnergy(totalHcal, muonHcal);
2045  (*pfCandidates_)[tmpi].setHoEnergy(hoclusterref->energy(), muonHO);
2046  }
2047  } else {
2048  (*pfCandidates_)[tmpi].setHcalEnergy(totalHcal, muonHcal);
2049  }
2050  setHcalDepthInfo((*pfCandidates_)[tmpi], *hclusterref);
2051 
2052  if(letMuonEatCaloEnergy){
2053  muonHCALEnergy += totalHcal;
2054  if (useHO_) muonHCALEnergy +=muonHO;
2055  muonHCALError += 0.;
2056  muonECALEnergy += muonEcal;
2057  muonECALError += 0.;
2058  photonAtECAL -= muonEcal*chargedDirection;
2059  hadronAtECAL -= totalHcal*chargedDirection;
2060  if ( !sortedEcals.empty() ) active[iEcal] = false;
2061  active[iHcal] = false;
2062  if (useHO_ && !sortedHOs.empty() ) active[iHO] = false;
2063  }
2064  else{
2065  // Estimate of the energy deposit & resolution in the calorimeters
2066  muonHCALEnergy += muonHCAL_[0];
2067  muonHCALError += muonHCAL_[1]*muonHCAL_[1];
2068  if ( muonHO > 0. ) {
2069  muonHCALEnergy += muonHO_[0];
2070  muonHCALError += muonHO_[1]*muonHO_[1];
2071  }
2072  muonECALEnergy += muonECAL_[0];
2073  muonECALError += muonECAL_[1]*muonECAL_[1];
2074  // ... as well as the equivalent "momentum" at ECAL entrance
2075  photonAtECAL -= muonECAL_[0]*chargedDirection;
2076  hadronAtECAL -= muonHCAL_[0]*chargedDirection;
2077  }
2078 
2079  // Remove it from the stack
2080  active[iTrack] = false;
2081  // Go to next track
2082  continue;
2083  }
2084 
2085  //
2086 
2087  if(debug_) cout<<"\t\t"<<elements[iTrack]<<endl;
2088 
2089  // introduce tracking errors
2090  double trackMomentum = trackRef->p();
2091  totalChargedMomentum += trackMomentum;
2092 
2093  // If the track is not a tight muon, but still resembles a muon
2094  // keep it for later for blocks with too large a charged energy
2095  if ( thisIsALooseMuon && !thisIsAMuon ) nMuons += 1;
2096 
2097  // ... and keep anyway the pt error for possible fake rejection
2098  // ... blow up errors of 5th anf 4th iteration, to reject those
2099  // ... tracks first (in case it's needed)
2100  double Dpt = trackRef->ptError();
2101  double blowError = PFTrackAlgoTools::errorScale(trackRef->algo(),factors45_);
2102  // except if it is from an interaction
2103  bool isPrimaryOrSecondary = isFromSecInt(elements[iTrack], "all");
2104 
2105  if ( isPrimaryOrSecondary ) blowError = 1.;
2106 
2107  std::pair<unsigned,bool> tkmuon = make_pair(iTrack,thisIsALooseMuon);
2108  associatedTracks.insert( make_pair(-Dpt*blowError, tkmuon) );
2109 
2110  // Also keep the total track momentum error for comparison with the calo energy
2111  double Dp = trackRef->qoverpError()*trackMomentum*trackMomentum;
2112  sumpError2 += Dp*Dp;
2113 
2114  bool connectedToEcal = false; // Will become true if there is at least one ECAL cluster connected
2115  if( !sortedEcals.empty() )
2116  { // start case: at least one ecal element associated to iTrack
2117 
2118  // Loop over all connected ECAL clusters
2119  for ( IE iec=sortedEcals.begin();
2120  iec!=sortedEcals.end(); ++iec ) {
2121 
2122  unsigned iEcal = iec->second;
2123  double dist = iec->first;
2124 
2125  // Ignore ECAL cluters already used
2126  if( !active[iEcal] ) {
2127  if(debug_) cout<<"\t\tcluster locked"<<endl;
2128  continue;
2129  }
2130 
2131  // Sanity checks
2132  PFBlockElement::Type type = elements[ iEcal ].type();
2133  assert( type == PFBlockElement::ECAL );
2134  PFClusterRef eclusterref = elements[iEcal].clusterRef();
2135  assert(!eclusterref.isNull() );
2136 
2137  // Check if this ECAL is not closer to another track - ignore it in that case
2138  std::multimap<double, unsigned> sortedTracksEcal;
2139  block.associatedElements( iEcal, linkData,
2140  sortedTracksEcal,
2143  unsigned jTrack = sortedTracksEcal.begin()->second;
2144  if ( jTrack != iTrack ) continue;
2145 
2146  // double chi2Ecal = block.chi2(jTrack,iEcal,linkData,
2147  // reco::PFBlock::LINKTEST_ALL);
2148  double distEcal = block.dist(jTrack,iEcal,linkData,
2150 
2151  // totalEcal += eclusterref->energy();
2152  // float ecalEnergyUnCalibrated = eclusterref->energy();
2153  //std::cout << "Ecal Uncalibrated " << ecalEnergyUnCalibrated << std::endl;
2154 
2155  float ecalEnergyCalibrated = eclusterref->correctedEnergy();
2156  ::math::XYZVector photonDirection(eclusterref->position().X(),
2157  eclusterref->position().Y(),
2158  eclusterref->position().Z());
2159  photonDirection = photonDirection.Unit();
2160 
2161  if ( !connectedToEcal ) { // This is the closest ECAL cluster - will add its energy later
2162 
2163  if(debug_) cout<<"\t\t\tclosest: "
2164  <<elements[iEcal]<<endl;
2165 
2166  connectedToEcal = true;
2167  // PJ 1st-April-09 : To be done somewhere !!! (Had to comment it, but it is needed)
2168  // currentChargedHadron.addElementInBlock( blockref, iEcal );
2169 
2170  std::pair<unsigned,::math::XYZVector> satellite =
2171  make_pair(iEcal,ecalEnergyCalibrated*photonDirection);
2172  ecalSatellites.insert( make_pair(-1., satellite) );
2173 
2174  } else { // Keep satellite clusters for later
2175 
2176  std::pair<unsigned,::math::XYZVector> satellite =
2177  make_pair(iEcal,ecalEnergyCalibrated*photonDirection);
2178  ecalSatellites.insert( make_pair(dist, satellite) );
2179 
2180  }
2181 
2182  std::pair<double, unsigned> associatedEcal
2183  = make_pair( distEcal, iEcal );
2184  associatedEcals.insert( make_pair(iTrack, associatedEcal) );
2185 
2186  } // End loop ecal associated to iTrack
2187  } // end case: at least one ecal element associated to iTrack
2188 
2189  if( useHO_ && !sortedHOs.empty() )
2190  { // start case: at least one ho element associated to iTrack
2191 
2192  // Loop over all connected HO clusters
2193  for ( IE ieho=sortedHOs.begin(); ieho!=sortedHOs.end(); ++ieho ) {
2194 
2195  unsigned iHO = ieho->second;
2196  double distHO = ieho->first;
2197 
2198  // Ignore HO cluters already used
2199  if( !active[iHO] ) {
2200  if(debug_) cout<<"\t\tcluster locked"<<endl;
2201  continue;
2202  }
2203 
2204  // Sanity checks
2205  PFBlockElement::Type type = elements[ iHO ].type();
2206  assert( type == PFBlockElement::HO );
2207  PFClusterRef hoclusterref = elements[iHO].clusterRef();
2208  assert(!hoclusterref.isNull() );
2209 
2210  // Check if this HO is not closer to another track - ignore it in that case
2211  std::multimap<double, unsigned> sortedTracksHO;
2212  block.associatedElements( iHO, linkData,
2213  sortedTracksHO,
2216  unsigned jTrack = sortedTracksHO.begin()->second;
2217  if ( jTrack != iTrack ) continue;
2218 
2219  // double chi2HO = block.chi2(jTrack,iHO,linkData,
2220  // reco::PFBlock::LINKTEST_ALL);
2221  //double distHO = block.dist(jTrack,iHO,linkData,
2222  // reco::PFBlock::LINKTEST_ALL);
2223 
2224  // Increment the total energy by the energy of this HO cluster
2225  totalHO += hoclusterref->energy();
2226  active[iHO] = false;
2227  // Keep track for later reference in the PFCandidate.
2228  std::pair<double, unsigned> associatedHO
2229  = make_pair( distHO, iHO );
2230  associatedHOs.insert( make_pair(iTrack, associatedHO) );
2231 
2232  } // End loop ho associated to iTrack
2233  } // end case: at least one ho element associated to iTrack
2234 
2235 
2236  } // end loop on tracks associated to hcal element iHcal
2237 
2238  // Include totalHO in totalHCAL for the time being (it will be calibrated as HCAL energy)
2239  totalHcal += totalHO;
2240 
2241  // test compatibility between calo and tracker. //////////////
2242 
2243  double caloEnergy = 0.;
2244  double slopeEcal = 1.0;
2245  double calibEcal = 0.;
2246  double calibHcal = 0.;
2247  hadronDirection = hadronAtECAL.Unit();
2248 
2249  // Determine the expected calo resolution from the total charged momentum
2250  double Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());
2251  Caloresolution *= totalChargedMomentum;
2252  // Account for muons
2253  Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
2254  totalEcal -= std::min(totalEcal,muonECALEnergy);
2255  totalHcal -= std::min(totalHcal,muonHCALEnergy);
2256  if ( totalEcal < 1E-9 ) photonAtECAL = ::math::XYZVector(0.,0.,0.);
2257  if ( totalHcal < 1E-9 ) hadronAtECAL = ::math::XYZVector(0.,0.,0.);
2258 
2259  // Loop over all ECAL satellites, starting for the closest to the various tracks
2260  // and adding other satellites until saturation of the total track momentum
2261  // Note : for code simplicity, the first element of the loop is the HCAL cluster
2262  // with 0 energy in the ECAL
2263  for ( IS is = ecalSatellites.begin(); is != ecalSatellites.end(); ++is ) {
2264 
2265  // Add the energy of this ECAL cluster
2266  double previousCalibEcal = calibEcal;
2267  double previousCalibHcal = calibHcal;
2268  double previousCaloEnergy = caloEnergy;
2269  double previousSlopeEcal = slopeEcal;
2270  ::math::XYZVector previousHadronAtECAL = hadronAtECAL;
2271  //
2272  totalEcal += sqrt(is->second.second.Mag2());
2273  photonAtECAL += is->second.second;
2274  calibEcal = std::max(0.,totalEcal);
2275  calibHcal = std::max(0.,totalHcal);
2276  hadronAtECAL = calibHcal * hadronDirection;
2277  // Calibrate ECAL and HCAL energy under the hadron hypothesis.
2278  calibration_->energyEmHad(totalChargedMomentum,calibEcal,calibHcal,
2279  hclusterref->positionREP().Eta(),
2280  hclusterref->positionREP().Phi());
2281  caloEnergy = calibEcal+calibHcal;
2282  if ( totalEcal > 0.) slopeEcal = calibEcal/totalEcal;
2283 
2284  hadronAtECAL = calibHcal * hadronDirection;
2285 
2286  // Continue looping until all closest clusters are exhausted and as long as
2287  // the calorimetric energy does not saturate the total momentum.
2288  if ( is->first < 0. || caloEnergy - totalChargedMomentum <= 0. ) {
2289  if(debug_) cout<<"\t\t\tactive, adding "<<is->second.second
2290  <<" to ECAL energy, and locking"<<endl;
2291  active[is->second.first] = false;
2292  double clusterEnergy=sqrt(is->second.second.Mag2());
2293  if(clusterEnergy>50) {
2294  ecalClusters.push_back(is->second);
2295  sumEcalClusters+=clusterEnergy;
2296  }
2297  continue;
2298  }
2299 
2300  // Otherwise, do not consider the last cluster examined and exit.
2301  // active[is->second.first] = true;
2302  totalEcal -= sqrt(is->second.second.Mag2());
2303  photonAtECAL -= is->second.second;
2304  calibEcal = previousCalibEcal;
2305  calibHcal = previousCalibHcal;
2306  hadronAtECAL = previousHadronAtECAL;
2307  slopeEcal = previousSlopeEcal;
2308  caloEnergy = previousCaloEnergy;
2309 
2310  break;
2311 
2312  }
2313 
2314  // Sanity check !
2315  assert(caloEnergy>=0);
2316 
2317 
2318  // And now check for hadronic energy excess...
2319 
2320  //colin: resolution should be measured on the ecal+hcal case.
2321  // however, the result will be close.
2322  // double Caloresolution = neutralHadronEnergyResolution( caloEnergy );
2323  // Caloresolution *= caloEnergy;
2324  // PJ The resolution is on the expected charged calo energy !
2325  //double Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());
2326  //Caloresolution *= totalChargedMomentum;
2327  // that of the charged particles linked to the cluster!
2328 
2329  /* */
2331  if ( totalChargedMomentum - caloEnergy > nSigmaTRACK_*Caloresolution ) {
2332 
2333  /*
2334  cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
2335  cout<<"\t\tsum p = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
2336  cout<<"\t\tsum ecal = "<<totalEcal<<endl;
2337  cout<<"\t\tsum hcal = "<<totalHcal<<endl;
2338  cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
2339  cout<<"\t\t => Calo Energy- total charged momentum = "
2340  <<caloEnergy-totalChargedMomentum<<" +- "<<TotalError<<endl;
2341  cout<<endl;
2342  cout << "\t\tNumber/momentum of muons found in the block : " << nMuons << std::endl;
2343  */
2344  // First consider loose muons
2345  if ( nMuons > 0 ) {
2346  for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) {
2347  unsigned iTrack = it->second.first;
2348  // Only active tracks
2349  if ( !active[iTrack] ) continue;
2350  // Only muons
2351  if ( !it->second.second ) continue;
2352 
2353  double trackMomentum = elements[it->second.first].trackRef()->p();
2354 
2355  // look for ECAL elements associated to iTrack (associated to iHcal)
2356  std::multimap<double, unsigned> sortedEcals;
2357  block.associatedElements( iTrack, linkData,
2358  sortedEcals,
2361  std::multimap<double, unsigned> sortedHOs;
2362  block.associatedElements( iTrack, linkData,
2363  sortedHOs,
2366 
2367  //Here allow for loose muons!
2368  unsigned tmpi = reconstructTrack( elements[iTrack],true);
2369 
2370  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
2371  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
2372  double muonHcal = std::min(muonHCAL_[0]+muonHCAL_[1],totalHcal-totalHO);
2373  double muonHO = 0.;
2374  (*pfCandidates_)[tmpi].setHcalEnergy(totalHcal,muonHcal);
2375  if( !sortedEcals.empty() ) {
2376  unsigned iEcal = sortedEcals.begin()->second;
2377  PFClusterRef eclusterref = elements[iEcal].clusterRef();
2378  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal);
2379  double muonEcal = std::min(muonECAL_[0]+muonECAL_[1],eclusterref->energy());
2380  (*pfCandidates_)[tmpi].setEcalEnergy(eclusterref->energy(),muonEcal);
2381  }
2382  if( useHO_ && !sortedHOs.empty() ) {
2383  unsigned iHO = sortedHOs.begin()->second;
2384  PFClusterRef hoclusterref = elements[iHO].clusterRef();
2385  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHO);
2386  muonHO = std::min(muonHO_[0]+muonHO_[1],hoclusterref->energy());
2387  (*pfCandidates_)[tmpi].setHcalEnergy(max(totalHcal-totalHO,0.0),muonHcal);
2388  (*pfCandidates_)[tmpi].setHoEnergy(hoclusterref->energy(),muonHO);
2389  }
2390  setHcalDepthInfo((*pfCandidates_)[tmpi], *hclusterref);
2391  // Remove it from the block
2392  const ::math::XYZPointF& chargedPosition =
2393  dynamic_cast<const reco::PFBlockElementTrack*>(&elements[it->second.first])->positionAtECALEntrance();
2394  ::math::XYZVector chargedDirection(chargedPosition.X(), chargedPosition.Y(), chargedPosition.Z());
2395  chargedDirection = chargedDirection.Unit();
2396  totalChargedMomentum -= trackMomentum;
2397  // Update the calo energies
2398  if ( totalEcal > 0. )
2399  calibEcal -= std::min(calibEcal,muonECAL_[0]*calibEcal/totalEcal);
2400  if ( totalHcal > 0. )
2401  calibHcal -= std::min(calibHcal,muonHCAL_[0]*calibHcal/totalHcal);
2402  totalEcal -= std::min(totalEcal,muonECAL_[0]);
2403  totalHcal -= std::min(totalHcal,muonHCAL_[0]);
2404  if ( totalEcal > muonECAL_[0] ) photonAtECAL -= muonECAL_[0] * chargedDirection;
2405  if ( totalHcal > muonHCAL_[0] ) hadronAtECAL -= muonHCAL_[0]*calibHcal/totalHcal * chargedDirection;
2406  caloEnergy = calibEcal+calibHcal;
2407  muonHCALEnergy += muonHCAL_[0];
2408  muonHCALError += muonHCAL_[1]*muonHCAL_[1];
2409  if ( muonHO > 0. ) {
2410  muonHCALEnergy += muonHO_[0];
2411  muonHCALError += muonHO_[1]*muonHO_[1];
2412  if ( totalHcal > 0. ) {
2413  calibHcal -= std::min(calibHcal,muonHO_[0]*calibHcal/totalHcal);
2414  totalHcal -= std::min(totalHcal,muonHO_[0]);
2415  }
2416  }
2417  muonECALEnergy += muonECAL_[0];
2418  muonECALError += muonECAL_[1]*muonECAL_[1];
2419  active[iTrack] = false;
2420  // Stop the loop whenever enough muons are removed
2421  //Commented out: Keep looking for muons since they often come in pairs -Matt
2422  //if ( totalChargedMomentum < caloEnergy ) break;
2423  }
2424  // New calo resolution.
2425  Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());
2426  Caloresolution *= totalChargedMomentum;
2427  Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
2428  }
2429  }
2430 
2431  if(debug_){
2432  cout<<"\tBefore Cleaning "<<endl;
2433  cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
2434  cout<<"\t\tsum p = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
2435  cout<<"\t\tsum ecal = "<<totalEcal<<endl;
2436  cout<<"\t\tsum hcal = "<<totalHcal<<endl;
2437  cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
2438  cout<<"\t\t => Calo Energy- total charged momentum = "
2439  <<caloEnergy-totalChargedMomentum<<" +- "<<sqrt(sumpError2 + Caloresolution*Caloresolution)<<endl;
2440  cout<<endl;
2441  }
2442 
2443 
2444  // Second consider bad tracks (if still needed after muon removal)
2445  unsigned corrTrack = 10000000;
2446  double corrFact = 1.;
2447 
2448  if (rejectTracks_Bad_ &&
2449  totalChargedMomentum - caloEnergy > nSigmaTRACK_*Caloresolution) {
2450 
2451  for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) {
2452  unsigned iTrack = it->second.first;
2453  // Only active tracks
2454  if ( !active[iTrack] ) continue;
2455  const reco::TrackRef& trackref = elements[it->second.first].trackRef();
2456 
2457  double dptRel = fabs(it->first)/trackref->pt()*100;
2458  bool isSecondary = isFromSecInt(elements[iTrack], "secondary");
2459  bool isPrimary = isFromSecInt(elements[iTrack], "primary");
2460 
2461  if ( isSecondary && dptRel < dptRel_DispVtx_ ) continue;
2462  // Consider only bad tracks
2463  if ( fabs(it->first) < ptError_ ) break;
2464  // What would become the block charged momentum if this track were removed
2465  double wouldBeTotalChargedMomentum =
2466  totalChargedMomentum - trackref->p();
2467  // Reject worst tracks, as long as the total charged momentum
2468  // is larger than the calo energy
2469 
2470  if ( wouldBeTotalChargedMomentum > caloEnergy ) {
2471 
2472  if (debug_ && isSecondary) {
2473  cout << "In bad track rejection step dptRel = " << dptRel << " dptRel_DispVtx_ = " << dptRel_DispVtx_ << endl;
2474  cout << "The calo energy would be still smaller even without this track but it is attached to a NI"<< endl;
2475  }
2476 
2477 
2478  if(isPrimary || (isSecondary && dptRel < dptRel_DispVtx_)) continue;
2479  active[iTrack] = false;
2480  totalChargedMomentum = wouldBeTotalChargedMomentum;
2481  if ( debug_ )
2482  std::cout << "\tElement " << elements[iTrack]
2483  << " rejected (Dpt = " << -it->first
2484  << " GeV/c, algo = " << trackref->algo() << ")" << std::endl;
2485  // Just rescale the nth worst track momentum to equalize the calo energy
2486  } else {
2487  if(isPrimary) break;
2488  corrTrack = iTrack;
2489  corrFact = (caloEnergy - wouldBeTotalChargedMomentum)/elements[it->second.first].trackRef()->p();
2490  if ( trackref->p()*corrFact < 0.05 ) {
2491  corrFact = 0.;
2492  active[iTrack] = false;
2493  }
2494  totalChargedMomentum -= trackref->p()*(1.-corrFact);
2495  if ( debug_ )
2496  std::cout << "\tElement " << elements[iTrack]
2497  << " (Dpt = " << -it->first
2498  << " GeV/c, algo = " << trackref->algo()
2499  << ") rescaled by " << corrFact
2500  << " Now the total charged momentum is " << totalChargedMomentum << endl;
2501  break;
2502  }
2503  }
2504  }
2505 
2506  // New determination of the calo and track resolution avec track deletion/rescaling.
2507  Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());
2508  Caloresolution *= totalChargedMomentum;
2509  Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
2510 
2511  // Check if the charged momentum is still very inconsistent with the calo measurement.
2512  // In this case, just drop all tracks from 4th and 5th iteration linked to this block
2513 
2514  if ( rejectTracks_Step45_ &&
2515  sortedTracks.size() > 1 &&
2516  totalChargedMomentum - caloEnergy > nSigmaTRACK_*Caloresolution ) {
2517  for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) {
2518  unsigned iTrack = it->second.first;
2519  reco::TrackRef trackref = elements[iTrack].trackRef();
2520  if ( !active[iTrack] ) continue;
2521 
2522  double dptRel = fabs(it->first)/trackref->pt()*100;
2523  bool isPrimaryOrSecondary = isFromSecInt(elements[iTrack], "all");
2524 
2525 
2526 
2527 
2528  if (isPrimaryOrSecondary && dptRel < dptRel_DispVtx_) continue;
2529 
2530  if (PFTrackAlgoTools::step5(trackref->algo())) {
2531  active[iTrack] = false;
2532  totalChargedMomentum -= trackref->p();
2533 
2534  if ( debug_ )
2535  std::cout << "\tElement " << elements[iTrack]
2536  << " rejected (Dpt = " << -it->first
2537  << " GeV/c, algo = " << trackref->algo() << ")" << std::endl;
2538 
2539  }
2540  }
2541 
2542  }
2543 
2544  // New determination of the calo and track resolution avec track deletion/rescaling.
2545  Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum, hclusterref->positionREP().Eta());
2546  Caloresolution *= totalChargedMomentum;
2547  Caloresolution = std::sqrt(Caloresolution*Caloresolution + muonHCALError + muonECALError);
2548 
2549  // Make PF candidates with the remaining tracks in the block
2550  sumpError2 = 0.;
2551  for ( IT it = associatedTracks.begin(); it != associatedTracks.end(); ++it ) {
2552  unsigned iTrack = it->second.first;
2553  if ( !active[iTrack] ) continue;
2554  reco::TrackRef trackRef = elements[iTrack].trackRef();
2555  double trackMomentum = trackRef->p();
2556  double Dp = trackRef->qoverpError()*trackMomentum*trackMomentum;
2557  unsigned tmpi = reconstructTrack( elements[iTrack] );
2558 
2559 
2560  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
2561  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
2562  setHcalDepthInfo((*pfCandidates_)[tmpi], *hclusterref);
2563  std::pair<II,II> myEcals = associatedEcals.equal_range(iTrack);
2564  for (II ii=myEcals.first; ii!=myEcals.second; ++ii ) {
2565  unsigned iEcal = ii->second.second;
2566  if ( active[iEcal] ) continue;
2567  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
2568  }
2569 
2570  if (useHO_) {
2571  std::pair<II,II> myHOs = associatedHOs.equal_range(iTrack);
2572  for (II ii=myHOs.first; ii!=myHOs.second; ++ii ) {
2573  unsigned iHO = ii->second.second;
2574  if ( active[iHO] ) continue;
2575  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHO );
2576  }
2577  }
2578 
2579  if ( iTrack == corrTrack ) {
2580  (*pfCandidates_)[tmpi].rescaleMomentum(corrFact);
2581  trackMomentum *= corrFact;
2582  }
2583  chargedHadronsIndices.push_back( tmpi );
2584  chargedHadronsInBlock.push_back( iTrack );
2585  active[iTrack] = false;
2586  hcalP.push_back(trackMomentum);
2587  hcalDP.push_back(Dp);
2588  if (Dp/trackMomentum > maxDPovP) maxDPovP = Dp/trackMomentum;
2589  sumpError2 += Dp*Dp;
2590  }
2591 
2592  // The total uncertainty of the difference Calo-Track
2593  double TotalError = sqrt(sumpError2 + Caloresolution*Caloresolution);
2594 
2595  if ( debug_ ) {
2596  cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
2597  cout<<"\t\tsum p = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
2598  cout<<"\t\tsum ecal = "<<totalEcal<<endl;
2599  cout<<"\t\tsum hcal = "<<totalHcal<<endl;
2600  cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
2601  cout<<"\t\t => Calo Energy- total charged momentum = "
2602  <<caloEnergy-totalChargedMomentum<<" +- "<<TotalError<<endl;
2603  cout<<endl;
2604  }
2605 
2606  /* */
2607 
2609  double nsigma = nSigmaHCAL(totalChargedMomentum,hclusterref->positionREP().Eta());
2610  //double nsigma = nSigmaHCAL(caloEnergy,hclusterref->positionREP().Eta());
2611  if ( abs(totalChargedMomentum-caloEnergy)<nsigma*TotalError ) {
2612 
2613  // deposited caloEnergy compatible with total charged momentum
2614  // if tracking errors are large take weighted average
2615 
2616  if(debug_) {
2617  cout<<"\t\tcase 1: COMPATIBLE "
2618  <<"|Calo Energy- total charged momentum| = "
2619  <<abs(caloEnergy-totalChargedMomentum)
2620  <<" < "<<nsigma<<" x "<<TotalError<<endl;
2621  if (maxDPovP < 0.1 )
2622  cout<<"\t\t\tmax DP/P = "<< maxDPovP
2623  <<" less than 0.1: do nothing "<<endl;
2624  else
2625  cout<<"\t\t\tmax DP/P = "<< maxDPovP
2626  <<" > 0.1: take weighted averages "<<endl;
2627  }
2628 
2629  // if max DP/P < 10% do nothing
2630  if (maxDPovP > 0.1) {
2631 
2632  // for each track associated to hcal
2633  // int nrows = tkIs.size();
2634  int nrows = chargedHadronsIndices.size();
2635  TMatrixTSym<double> a (nrows);
2636  TVectorD b (nrows);
2637  TVectorD check(nrows);
2638  double sigma2E = Caloresolution*Caloresolution;
2639  for(int i=0; i<nrows; i++) {
2640  double sigma2i = hcalDP[i]*hcalDP[i];
2641  if (debug_){
2642  cout<<"\t\t\ttrack associated to hcal "<<i
2643  <<" P = "<<hcalP[i]<<" +- "
2644  <<hcalDP[i]<<endl;
2645  }
2646  a(i,i) = 1./sigma2i + 1./sigma2E;
2647  b(i) = hcalP[i]/sigma2i + caloEnergy/sigma2E;
2648  for(int j=0; j<nrows; j++) {
2649  if (i==j) continue;
2650  a(i,j) = 1./sigma2E;
2651  } // end loop on j
2652  } // end loop on i
2653 
2654  // solve ax = b
2655  //if (debug_){// debug1
2656  //cout<<" matrix a(i,j) "<<endl;
2657  //a.Print();
2658  //cout<<" vector b(i) "<<endl;
2659  //b.Print();
2660  //} // debug1
2661  TDecompChol decomp(a);
2662  bool ok = false;
2663  TVectorD x = decomp.Solve(b, ok);
2664  // for each track create a PFCandidate track
2665  // with a momentum rescaled to weighted average
2666  if (ok) {
2667  for (int i=0; i<nrows; i++){
2668  // unsigned iTrack = trackInfos[i].index;
2669  unsigned ich = chargedHadronsIndices[i];
2670  double rescaleFactor = x(i)/hcalP[i];
2671  (*pfCandidates_)[ich].rescaleMomentum( rescaleFactor );
2672 
2673  if(debug_){
2674  cout<<"\t\t\told p "<<hcalP[i]
2675  <<" new p "<<x(i)
2676  <<" rescale "<<rescaleFactor<<endl;
2677  }
2678  }
2679  }
2680  else {
2681  cerr<<"not ok!"<<endl;
2682  assert(0);
2683  }
2684  }
2685  }
2686 
2688  else if( caloEnergy > totalChargedMomentum ) {
2689 
2690  //case 2: caloEnergy > totalChargedMomentum + nsigma*TotalError
2691  //there is an excess of energy in the calos
2692  //create a neutral hadron or a photon
2693 
2694  /*
2695  //If it's isolated don't create neutrals since the energy deposit is always coming from a showering muon
2696  bool thisIsAnIsolatedMuon = false;
2697  for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
2698  unsigned iTrack = ie->second;
2699  if(PFMuonAlgo::isIsolatedMuon(elements[iTrack].muonRef())) thisIsAnIsolatedMuon = true;
2700  }
2701 
2702  if(thisIsAnIsolatedMuon){
2703  if(debug_)cout<<" Not looking for neutral b/c this is an isolated muon "<<endl;
2704  break;
2705  }
2706  */
2707  double eNeutralHadron = caloEnergy - totalChargedMomentum;
2708  double ePhoton = (caloEnergy - totalChargedMomentum) / slopeEcal;
2709 
2710  if(debug_) {
2711  if(!sortedTracks.empty() ){
2712  cout<<"\t\tcase 2: NEUTRAL DETECTION "
2713  <<caloEnergy<<" > "<<nsigma<<"x"<<TotalError
2714  <<" + "<<totalChargedMomentum<<endl;
2715  cout<<"\t\tneutral activity detected: "<<endl
2716  <<"\t\t\t photon = "<<ePhoton<<endl
2717  <<"\t\t\tor neutral hadron = "<<eNeutralHadron<<endl;
2718 
2719  cout<<"\t\tphoton or hadron ?"<<endl;}
2720 
2721  if(sortedTracks.empty() )
2722  cout<<"\t\tno track -> hadron "<<endl;
2723  else
2724  cout<<"\t\t"<<sortedTracks.size()
2725  <<" tracks -> check if the excess is photonic or hadronic"<<endl;
2726  }
2727 
2728 
2729  double ratioMax = 0.;
2730  reco::PFClusterRef maxEcalRef;
2731  unsigned maxiEcal= 9999;
2732 
2733  // for each track associated to hcal: iterator IE ie :
2734 
2735  for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
2736 
2737  unsigned iTrack = ie->second;
2738 
2739  PFBlockElement::Type type = elements[iTrack].type();
2740  assert( type == reco::PFBlockElement::TRACK );
2741 
2742  reco::TrackRef trackRef = elements[iTrack].trackRef();
2743  assert( !trackRef.isNull() );
2744 
2745  II iae = associatedEcals.find(iTrack);
2746 
2747  if( iae == associatedEcals.end() ) continue;
2748 
2749  // double distECAL = iae->second.first;
2750  unsigned iEcal = iae->second.second;
2751 
2752  PFBlockElement::Type typeEcal = elements[iEcal].type();
2753  assert(typeEcal == reco::PFBlockElement::ECAL);
2754 
2755  reco::PFClusterRef clusterRef = elements[iEcal].clusterRef();
2756  assert( !clusterRef.isNull() );
2757 
2758  double pTrack = trackRef->p();
2759  double eECAL = clusterRef->energy();
2760  double eECALOverpTrack = eECAL / pTrack;
2761 
2762  if ( eECALOverpTrack > ratioMax ) {
2763  ratioMax = eECALOverpTrack;
2764  maxEcalRef = clusterRef;
2765  maxiEcal = iEcal;
2766  }
2767 
2768  } // end loop on tracks associated to hcal: iterator IE ie
2769 
2770  std::vector<reco::PFClusterRef> pivotalClusterRef;
2771  std::vector<unsigned> iPivotal;
2772  std::vector<double> particleEnergy, ecalEnergy, hcalEnergy, rawecalEnergy, rawhcalEnergy;
2773  std::vector<::math::XYZVector> particleDirection;
2774 
2775  // If the excess is smaller than the ecal energy, assign the whole
2776  // excess to photons
2777  if ( ePhoton < totalEcal || eNeutralHadron-calibEcal < 1E-10 ) {
2778  if ( !maxEcalRef.isNull() ) {
2779  // So the merged photon energy is,
2780  mergedPhotonEnergy = ePhoton;
2781  }
2782  } else {
2783  // Otherwise assign the whole ECAL energy to the photons
2784  if ( !maxEcalRef.isNull() ) {
2785  // So the merged photon energy is,
2786  mergedPhotonEnergy = totalEcal;
2787  }
2788  // ... and assign the remaining excess to neutral hadrons using the direction of ecal clusters
2789  mergedNeutralHadronEnergy = eNeutralHadron-calibEcal;
2790  }
2791 
2792  if ( mergedPhotonEnergy > 0 ) {
2793  // Split merged photon into photons for each energetic ecal cluster (necessary for jet substructure reconstruction)
2794  // make only one merged photon if less than 2 ecal clusters
2795  if ( ecalClusters.size()<=1 ) {
2796  ecalClusters.clear();
2797  ecalClusters.push_back(make_pair(maxiEcal, photonAtECAL));
2798  sumEcalClusters=sqrt(photonAtECAL.Mag2());
2799  }
2800  for(std::vector<std::pair<unsigned,::math::XYZVector> >::const_iterator pae = ecalClusters.begin(); pae != ecalClusters.end(); ++pae ) {
2801  double clusterEnergy=sqrt(pae->second.Mag2());
2802  particleEnergy.push_back(mergedPhotonEnergy*clusterEnergy/sumEcalClusters);
2803  particleDirection.push_back(pae->second);
2804  ecalEnergy.push_back(mergedPhotonEnergy*clusterEnergy/sumEcalClusters);
2805  hcalEnergy.push_back(0.);
2806  rawecalEnergy.push_back(totalEcal);
2807  rawhcalEnergy.push_back(totalHcal);
2808  pivotalClusterRef.push_back(elements[pae->first].clusterRef());
2809  iPivotal.push_back(pae->first);
2810  }
2811  }
2812 
2813  if ( mergedNeutralHadronEnergy > 1.0 ) {
2814  // Split merged neutral hadrons according to directions of energetic ecal clusters (necessary for jet substructure reconstruction)
2815  // make only one merged neutral hadron if less than 2 ecal clusters
2816  if ( ecalClusters.size()<=1 ) {
2817  ecalClusters.clear();
2818  ecalClusters.push_back(make_pair(iHcal, hadronAtECAL));
2819  sumEcalClusters=sqrt(hadronAtECAL.Mag2());
2820  }
2821  for(std::vector<std::pair<unsigned,::math::XYZVector> >::const_iterator pae = ecalClusters.begin(); pae != ecalClusters.end(); ++pae ) {
2822  double clusterEnergy=sqrt(pae->second.Mag2());
2823  particleEnergy.push_back(mergedNeutralHadronEnergy*clusterEnergy/sumEcalClusters);
2824  particleDirection.push_back(pae->second);
2825  ecalEnergy.push_back(0.);
2826  hcalEnergy.push_back(mergedNeutralHadronEnergy*clusterEnergy/sumEcalClusters);
2827  rawecalEnergy.push_back(totalEcal);
2828  rawhcalEnergy.push_back(totalHcal);
2829  pivotalClusterRef.push_back(hclusterref);
2830  iPivotal.push_back(iHcal);
2831  }
2832  }
2833 
2834  // reconstructing a merged neutral
2835  // the type of PFCandidate is known from the
2836  // reference to the pivotal cluster.
2837 
2838  for ( unsigned iPivot=0; iPivot<iPivotal.size(); ++iPivot ) {
2839 
2840  if ( particleEnergy[iPivot] < 0. )
2841  std::cout << "ALARM = Negative energy ! "
2842  << particleEnergy[iPivot] << std::endl;
2843 
2844  bool useDirection = true;
2845  unsigned tmpi = reconstructCluster( *pivotalClusterRef[iPivot],
2846  particleEnergy[iPivot],
2847  useDirection,
2848  particleDirection[iPivot].X(),
2849  particleDirection[iPivot].Y(),
2850  particleDirection[iPivot].Z());
2851 
2852 
2853  (*pfCandidates_)[tmpi].setEcalEnergy( rawecalEnergy[iPivot],ecalEnergy[iPivot] );
2854  if ( !useHO_ ) {
2855  (*pfCandidates_)[tmpi].setHcalEnergy( rawhcalEnergy[iPivot],hcalEnergy[iPivot] );
2856  (*pfCandidates_)[tmpi].setHoEnergy(0., 0.);
2857  } else {
2858  (*pfCandidates_)[tmpi].setHcalEnergy( max(rawhcalEnergy[iPivot]-totalHO,0.0),hcalEnergy[iPivot]*(1.-totalHO/rawhcalEnergy[iPivot]));
2859  (*pfCandidates_)[tmpi].setHoEnergy(totalHO, totalHO * hcalEnergy[iPivot]/rawhcalEnergy[iPivot]);
2860  }
2861  (*pfCandidates_)[tmpi].setPs1Energy( 0. );
2862  (*pfCandidates_)[tmpi].setPs2Energy( 0. );
2863  (*pfCandidates_)[tmpi].set_mva_nothing_gamma( -1. );
2864  // (*pfCandidates_)[tmpi].addElement(&elements[iPivotal]);
2865  // (*pfCandidates_)[tmpi].addElementInBlock(blockref, iPivotal[iPivot]);
2866  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
2867  for ( unsigned ich=0; ich<chargedHadronsInBlock.size(); ++ich) {
2868  unsigned iTrack = chargedHadronsInBlock[ich];
2869  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
2870  // Assign the position of the track at the ECAL entrance
2871  const ::math::XYZPointF& chargedPosition =
2872  dynamic_cast<const reco::PFBlockElementTrack*>(&elements[iTrack])->positionAtECALEntrance();
2873  (*pfCandidates_)[tmpi].setPositionAtECALEntrance(chargedPosition);
2874 
2875  std::pair<II,II> myEcals = associatedEcals.equal_range(iTrack);
2876  for (II ii=myEcals.first; ii!=myEcals.second; ++ii ) {
2877  unsigned iEcal = ii->second.second;
2878  if ( active[iEcal] ) continue;
2879  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
2880  }
2881  }
2882 
2883  }
2884 
2885  } // excess of energy
2886 
2887 
2888  // will now share the hcal energy between the various charged hadron
2889  // candidates, taking into account the potential neutral hadrons
2890 
2891  double totalHcalEnergyCalibrated = calibHcal;
2892  double totalEcalEnergyCalibrated = calibEcal;
2893  //JB: The question is: we've resolved the merged photons cleanly, but how should
2894  //the remaining hadrons be assigned the remaining ecal energy?
2895  //*Temporary solution*: follow HCAL example with fractions...
2896 
2897  /*
2898  if(totalEcal>0) {
2899  // removing ecal energy from abc calibration
2900  totalHcalEnergyCalibrated -= calibEcal;
2901  // totalHcalEnergyCalibrated -= calibration_->paramECALplusHCAL_slopeECAL() * totalEcal;
2902  }
2903  */
2904  // else caloEnergy = hcal only calibrated energy -> ok.
2905 
2906  // remove the energy of the potential neutral hadron
2907  totalHcalEnergyCalibrated -= mergedNeutralHadronEnergy;
2908  // similarly for the merged photons
2909  totalEcalEnergyCalibrated -= mergedPhotonEnergy;
2910  // share between the charged hadrons
2911 
2912  //COLIN can compute this before
2913  // not exactly equal to sum p, this is sum E
2914  double chargedHadronsTotalEnergy = 0;
2915  for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
2916  unsigned index = chargedHadronsIndices[ich];
2917  reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
2918  chargedHadronsTotalEnergy += chargedHadron.energy();
2919  }
2920 
2921  for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
2922  unsigned index = chargedHadronsIndices[ich];
2923  reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
2924  float fraction = chargedHadron.energy()/chargedHadronsTotalEnergy;
2925 
2926  if ( !useHO_ ) {
2927  chargedHadron.setHcalEnergy( fraction * totalHcal, fraction * totalHcalEnergyCalibrated );
2928  chargedHadron.setHoEnergy( 0., 0. );
2929  } else {
2930  chargedHadron.setHcalEnergy( fraction * max(totalHcal-totalHO,0.0), fraction * totalHcalEnergyCalibrated * (1.-totalHO/totalHcal) );
2931  chargedHadron.setHoEnergy( fraction * totalHO, fraction * totalHO * totalHcalEnergyCalibrated / totalHcal );
2932  }
2933  //JB: fixing up (previously omitted) setting of ECAL energy gouzevit
2934  chargedHadron.setEcalEnergy( fraction * totalEcal, fraction * totalEcalEnergyCalibrated );
2935  }
2936 
2937  // Finally treat unused ecal satellites as photons.
2938  for ( IS is = ecalSatellites.begin(); is != ecalSatellites.end(); ++is ) {
2939 
2940  // Ignore satellites already taken
2941  unsigned iEcal = is->second.first;
2942  if ( !active[iEcal] ) continue;
2943 
2944  // Sanity checks again (well not useful, this time!)
2945  PFBlockElement::Type type = elements[ iEcal ].type();
2946  assert( type == PFBlockElement::ECAL );
2947  PFClusterRef eclusterref = elements[iEcal].clusterRef();
2948  assert(!eclusterref.isNull() );
2949 
2950  // Lock the cluster
2951  active[iEcal] = false;
2952 
2953  // Find the associated tracks
2954  std::multimap<double, unsigned> assTracks;
2955  block.associatedElements( iEcal, linkData,
2956  assTracks,
2959 
2960  // Create a photon
2961  unsigned tmpi = reconstructCluster( *eclusterref, sqrt(is->second.second.Mag2()) );
2962  (*pfCandidates_)[tmpi].setEcalEnergy( eclusterref->energy(),sqrt(is->second.second.Mag2()) );
2963  (*pfCandidates_)[tmpi].setHcalEnergy( 0., 0. );
2964  (*pfCandidates_)[tmpi].setHoEnergy( 0., 0. );
2965  (*pfCandidates_)[tmpi].setPs1Energy( associatedPSs[iEcal].first );
2966  (*pfCandidates_)[tmpi].setPs2Energy( associatedPSs[iEcal].second );
2967  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
2968  (*pfCandidates_)[tmpi].addElementInBlock( blockref, sortedTracks.begin()->second) ;
2969  }
2970 
2971 
2972  }
2973 
2974  // end loop on hcal element iHcal= hcalIs[i]
2975 
2976 
2977  // Processing the remaining HCAL clusters
2978  if(debug_) {
2979  cout<<endl;
2980  if(debug_)
2981  cout<<endl
2982  <<"---- loop remaining hcal ------- "<<endl;
2983  }
2984 
2985 
2986  //COLINFEB16
2987  // now dealing with the HCAL elements that are not linked to any track
2988  for(unsigned ihcluster=0; ihcluster<hcalIs.size(); ihcluster++) {
2989  unsigned iHcal = hcalIs[ihcluster];
2990 
2991  // Keep ECAL and HO elements for reference in the PFCandidate
2992  std::vector<unsigned> ecalRefs;
2993  std::vector<unsigned> hoRefs;
2994 
2995  if(debug_)
2996  cout<<endl<<elements[iHcal]<<" ";
2997 
2998 
2999  if( !active[iHcal] ) {
3000  if(debug_)
3001  cout<<"not active"<<endl;
3002  continue;
3003  }
3004 
3005  // Find the ECAL elements linked to it
3006  std::multimap<double, unsigned> ecalElems;
3007  block.associatedElements( iHcal, linkData,
3008  ecalElems ,
3011 
3012  // Loop on these ECAL elements
3013  float totalEcal = 0.;
3014  float ecalMax = 0.;
3015  reco::PFClusterRef eClusterRef;
3016  for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
3017 
3018  unsigned iEcal = ie->second;
3019  double dist = ie->first;
3020  PFBlockElement::Type type = elements[iEcal].type();
3021  assert( type == PFBlockElement::ECAL );
3022 
3023  // Check if already used
3024  if( !active[iEcal] ) continue;
3025 
3026  // Check the distance (one HCALPlusECAL tower, roughly)
3027  // if ( dist > 0.15 ) continue;
3028 
3029  //COLINFEB16
3030  // what could be done is to
3031  // - link by rechit.
3032  // - take in the neutral hadron all the ECAL clusters
3033  // which are within the same CaloTower, according to the distance,
3034  // except the ones which are closer to another HCAL cluster.
3035  // - all the other ECAL linked to this HCAL are photons.
3036  //
3037  // about the closest HCAL cluster.
3038  // it could maybe be easier to loop on the ECAL clusters first
3039  // to cut the links to all HCAL clusters except the closest, as is
3040  // done in the first track loop. But maybe not!
3041  // or add an helper function to the PFAlgo class to ask
3042  // if a given element is the closest of a given type to another one?
3043 
3044  // Check if not closer from another free HCAL
3045  std::multimap<double, unsigned> hcalElems;
3046  block.associatedElements( iEcal, linkData,
3047  hcalElems ,
3050 
3051  bool isClosest = true;
3052  for(IE ih = hcalElems.begin(); ih != hcalElems.end(); ++ih ) {
3053 
3054  unsigned jHcal = ih->second;
3055  double distH = ih->first;
3056 
3057  if ( !active[jHcal] ) continue;
3058 
3059  if ( distH < dist ) {
3060  isClosest = false;
3061  break;
3062  }
3063 
3064  }
3065 
3066  if (!isClosest) continue;
3067 
3068 
3069  if(debug_) {
3070  cout<<"\telement "<<elements[iEcal]<<" linked with dist "<< dist<<endl;
3071  cout<<"Added to HCAL cluster to form a neutral hadron"<<endl;
3072  }
3073 
3074  reco::PFClusterRef eclusterRef = elements[iEcal].clusterRef();
3075  assert( !eclusterRef.isNull() );
3076 
3077  double ecalEnergy = eclusterRef->correctedEnergy();
3078 
3079  //std::cout << "EcalEnergy, ps1, ps2 = " << ecalEnergy
3080  // << ", " << ps1Ene[0] << ", " << ps2Ene[0] << std::endl;
3081  totalEcal += ecalEnergy;
3082  if ( ecalEnergy > ecalMax ) {
3083  ecalMax = ecalEnergy;
3084  eClusterRef = eclusterRef;
3085  }
3086 
3087  ecalRefs.push_back(iEcal);
3088  active[iEcal] = false;
3089 
3090 
3091  }// End loop ECAL
3092 
3093  // Now find the HO clusters linked to the HCAL cluster
3094  double totalHO = 0.;
3095  double hoMax = 0.;
3096  //unsigned jHO = 0;
3097  if (useHO_) {
3098  std::multimap<double, unsigned> hoElems;
3099  block.associatedElements( iHcal, linkData,
3100  hoElems ,
3103 
3104  // Loop on these HO elements
3105  // double totalHO = 0.;
3106  // double hoMax = 0.;
3107  // unsigned jHO = 0;
3108  reco::PFClusterRef hoClusterRef;
3109  for(IE ie = hoElems.begin(); ie != hoElems.end(); ++ie ) {
3110 
3111  unsigned iHO = ie->second;
3112  double dist = ie->first;
3113  PFBlockElement::Type type = elements[iHO].type();
3114  assert( type == PFBlockElement::HO );
3115 
3116  // Check if already used
3117  if( !active[iHO] ) continue;
3118 
3119  // Check the distance (one HCALPlusHO tower, roughly)
3120  // if ( dist > 0.15 ) continue;
3121 
3122  // Check if not closer from another free HCAL
3123  std::multimap<double, unsigned> hcalElems;
3124  block.associatedElements( iHO, linkData,
3125  hcalElems ,
3128 
3129  bool isClosest = true;
3130  for(IE ih = hcalElems.begin(); ih != hcalElems.end(); ++ih ) {
3131 
3132  unsigned jHcal = ih->second;
3133  double distH = ih->first;
3134 
3135  if ( !active[jHcal] ) continue;
3136 
3137  if ( distH < dist ) {
3138  isClosest = false;
3139  break;
3140  }
3141 
3142  }
3143 
3144  if (!isClosest) continue;
3145 
3146  if(debug_ && useHO_) {
3147  cout<<"\telement "<<elements[iHO]<<" linked with dist "<< dist<<endl;
3148  cout<<"Added to HCAL cluster to form a neutral hadron"<<endl;
3149  }
3150 
3151  reco::PFClusterRef hoclusterRef = elements[iHO].clusterRef();
3152  assert( !hoclusterRef.isNull() );
3153 
3154  double hoEnergy = hoclusterRef->energy(); // calibration_->energyEm(*hoclusterRef,ps1Ene,ps2Ene,crackCorrection);
3155 
3156  totalHO += hoEnergy;
3157  if ( hoEnergy > hoMax ) {
3158  hoMax = hoEnergy;
3159  hoClusterRef = hoclusterRef;
3160  //jHO = iHO;
3161  }
3162 
3163  hoRefs.push_back(iHO);
3164  active[iHO] = false;
3165 
3166  }// End loop HO
3167  }
3168 
3169  PFClusterRef hclusterRef
3170  = elements[iHcal].clusterRef();
3171  assert( !hclusterRef.isNull() );
3172 
3173  // HCAL energy
3174  double totalHcal = hclusterRef->energy();
3175  // Include the HO energy
3176  if ( useHO_ ) totalHcal += totalHO;
3177 
3178  // std::cout << "Hcal Energy,eta : " << totalHcal
3179  // << ", " << hclusterRef->positionREP().Eta()
3180  // << std::endl;
3181  // Calibration
3182  //double caloEnergy = totalHcal;
3183  // double slopeEcal = 1.0;
3184  double calibEcal = totalEcal > 0. ? totalEcal : 0.;
3185  double calibHcal = std::max(0.,totalHcal);
3186  if ( hclusterRef->layer() == PFLayer::HF_HAD ||
3187  hclusterRef->layer() == PFLayer::HF_EM ) {
3188  //caloEnergy = totalHcal/0.7;
3189  calibEcal = totalEcal;
3190  } else {
3191  calibration_->energyEmHad(-1.,calibEcal,calibHcal,
3192  hclusterRef->positionREP().Eta(),
3193  hclusterRef->positionREP().Phi());
3194  //caloEnergy = calibEcal+calibHcal;
3195  }
3196 
3197  // std::cout << "CalibEcal,HCal = " << calibEcal << ", " << calibHcal << std::endl;
3198  // std::cout << "-------------------------------------------------------------------" << std::endl;
3199  // ECAL energy : calibration
3200 
3201  // double particleEnergy = caloEnergy;
3202  // double particleEnergy = totalEcal + calibHcal;
3203  // particleEnergy /= (1.-0.724/sqrt(particleEnergy)-0.0226/particleEnergy);
3204 
3205  unsigned tmpi = reconstructCluster( *hclusterRef,
3206  calibEcal+calibHcal );
3207 
3208 
3209  (*pfCandidates_)[tmpi].setEcalEnergy( totalEcal, calibEcal );
3210  if ( !useHO_ ) {
3211  (*pfCandidates_)[tmpi].setHcalEnergy( totalHcal, calibHcal );
3212  (*pfCandidates_)[tmpi].setHoEnergy(0.,0.);
3213  } else {
3214  (*pfCandidates_)[tmpi].setHcalEnergy( max(totalHcal-totalHO,0.0), calibHcal*(1.-totalHO/totalHcal));
3215  (*pfCandidates_)[tmpi].setHoEnergy(totalHO,totalHO*calibHcal/totalHcal);
3216  }
3217  (*pfCandidates_)[tmpi].setPs1Energy( 0. );
3218  (*pfCandidates_)[tmpi].setPs2Energy( 0. );
3219  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
3220  for (unsigned iec=0; iec<ecalRefs.size(); ++iec)
3221  (*pfCandidates_)[tmpi].addElementInBlock( blockref, ecalRefs[iec] );
3222  for (unsigned iho=0; iho<hoRefs.size(); ++iho)
3223  (*pfCandidates_)[tmpi].addElementInBlock( blockref, hoRefs[iho] );
3224 
3225  }//loop hcal elements
3226 
3227 
3228 
3229 
3230  if(debug_) {
3231  cout<<endl;
3232  if(debug_) cout<<endl<<"---- loop ecal------- "<<endl;
3233  }
3234 
3235  // for each ecal element iEcal = ecalIs[i] in turn:
3236 
3237  for(unsigned i=0; i<ecalIs.size(); i++) {
3238  unsigned iEcal = ecalIs[i];
3239 
3240  if(debug_)
3241  cout<<endl<<elements[iEcal]<<" ";
3242 
3243  if( ! active[iEcal] ) {
3244  if(debug_)
3245  cout<<"not active"<<endl;
3246  continue;
3247  }
3248 
3249  PFBlockElement::Type type = elements[ iEcal ].type();
3250  assert( type == PFBlockElement::ECAL );
3251 
3252  PFClusterRef clusterref = elements[iEcal].clusterRef();
3253  assert(!clusterref.isNull() );
3254 
3255  active[iEcal] = false;
3256 
3257  float ecalEnergy = clusterref->correctedEnergy();
3258  // float ecalEnergy = calibration_->energyEm( clusterref->energy() );
3259  double particleEnergy = ecalEnergy;
3260 
3261  unsigned tmpi = reconstructCluster( *clusterref,
3262  particleEnergy );
3263 
3264  (*pfCandidates_)[tmpi].setEcalEnergy( clusterref->energy(),ecalEnergy );
3265  (*pfCandidates_)[tmpi].setHcalEnergy( 0., 0. );
3266  (*pfCandidates_)[tmpi].setHoEnergy( 0., 0. );
3267  (*pfCandidates_)[tmpi].setPs1Energy( 0. );
3268  (*pfCandidates_)[tmpi].setPs2Energy( 0. );
3269  (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
3270 
3271 
3272  } // end loop on ecal elements iEcal = ecalIs[i]
3273 
3274 } // end processBlock
3275 
3277 unsigned PFAlgo::reconstructTrack( const reco::PFBlockElement& elt, bool allowLoose) {
3278 
3279  const reco::PFBlockElementTrack* eltTrack
3280  = dynamic_cast<const reco::PFBlockElementTrack*>(&elt);
3281 
3282  const reco::TrackRef& trackRef = eltTrack->trackRef();
3283  const reco::Track& track = *trackRef;
3284  const reco::MuonRef& muonRef = eltTrack->muonRef();
3285  int charge = track.charge()>0 ? 1 : -1;
3286 
3287  // Assume this particle is a charged Hadron
3288  double px = track.px();
3289  double py = track.py();
3290  double pz = track.pz();
3291  double energy = sqrt(track.p()*track.p() + 0.13957*0.13957);
3292 
3293  if (debug_) cout << "Reconstructing PF candidate from track of pT = " << track.pt() << " eta = " << track.eta() << " phi = " << track.phi() << " px = " << px << " py = " << py << " pz = " << pz << " energy = " << energy << endl;
3294 
3295 
3296  // Create a PF Candidate
3297  ::math::XYZTLorentzVector momentum(px,py,pz,energy);
3300 
3301  // Add it to the stack
3302  pfCandidates_->push_back( PFCandidate( charge,
3303  momentum,
3304  particleType ) );
3305  //Set vertex and stuff like this
3306  pfCandidates_->back().setVertexSource( PFCandidate::kTrkVertex );
3307  pfCandidates_->back().setTrackRef( trackRef );
3308  pfCandidates_->back().setPositionAtECALEntrance( eltTrack->positionAtECALEntrance());
3309  if( muonRef.isNonnull())
3310  pfCandidates_->back().setMuonRef( muonRef );
3311 
3312 
3313  //Set time
3314  if (elt.isTimeValid()) pfCandidates_->back().setTime( elt.time(), elt.timeError() );
3315 
3316  //OK Now try to reconstruct the particle as a muon
3317  bool isMuon=pfmu_->reconstructMuon(pfCandidates_->back(),muonRef,allowLoose);
3318  bool isFromDisp = isFromSecInt(elt, "secondary");
3319 
3320 
3321  if ((!isMuon) && isFromDisp) {
3322  double Dpt = trackRef->ptError();
3323  double dptRel = Dpt/trackRef->pt()*100;
3324  //If the track is ill measured it is better to not refit it, since the track information probably would not be used.
3325  //In the PFAlgo we use the trackref information. If the track error is too big the refitted information might be very different
3326  // from the not refitted one.
3327  if (dptRel < dptRel_DispVtx_){
3328  if (debug_)
3329  cout << "Not refitted px = " << px << " py = " << py << " pz = " << pz << " energy = " << energy << endl;
3330  //reco::TrackRef trackRef = eltTrack->trackRef();
3332  reco::Track trackRefit = vRef->refittedTrack(trackRef);
3333  //change the momentum with the refitted track
3334  ::math::XYZTLorentzVector momentum(trackRefit.px(),
3335  trackRefit.py(),
3336  trackRefit.pz(),
3337  sqrt(trackRefit.p()*trackRefit.p() + 0.13957*0.13957));
3338  if (debug_)
3339  cout << "Refitted px = " << px << " py = " << py << " pz = " << pz << " energy = " << energy << endl;
3340  }
3341  pfCandidates_->back().setFlag( reco::PFCandidate::T_FROM_DISP, true);
3342  pfCandidates_->back().setDisplacedVertexRef( eltTrack->displacedVertexRef(reco::PFBlockElement::T_FROM_DISP)->displacedVertexRef(), reco::PFCandidate::T_FROM_DISP);
3343  }
3344 
3345  // do not label as primary a track which would be recognised as a muon. A muon cannot produce NI. It is with high probability a fake
3346  if(isFromSecInt(elt, "primary") && !isMuon) {
3347  pfCandidates_->back().setFlag( reco::PFCandidate::T_TO_DISP, true);
3348  pfCandidates_->back().setDisplacedVertexRef( eltTrack->displacedVertexRef(reco::PFBlockElement::T_TO_DISP)->displacedVertexRef(), reco::PFCandidate::T_TO_DISP);
3349  }
3350 
3351  // returns index to the newly created PFCandidate
3352  return pfCandidates_->size()-1;
3353 }
3354 
3355 
3356 unsigned
3358  double particleEnergy,
3359  bool useDirection,
3360  double particleX,
3361  double particleY,
3362  double particleZ) {
3363 
3365 
3366  // need to convert the ::math::XYZPoint data member of the PFCluster class=
3367  // to a displacement vector:
3368 
3369  // Transform particleX,Y,Z to a position at ECAL/HCAL entrance
3370  double factor = 1.;
3371  if ( useDirection ) {
3372  switch( cluster.layer() ) {
3373  case PFLayer::ECAL_BARREL:
3374  case PFLayer::HCAL_BARREL1:
3375  factor = std::sqrt(cluster.position().Perp2()/(particleX*particleX+particleY*particleY));
3376  break;
3377  case PFLayer::ECAL_ENDCAP:
3378  case PFLayer::HCAL_ENDCAP:
3379  case PFLayer::HF_HAD:
3380  case PFLayer::HF_EM:
3381  factor = cluster.position().Z()/particleZ;
3382  break;
3383  default:
3384  assert(0);
3385  }
3386  }
3387  //MIKE First of all let's check if we have vertex.
3388  ::math::XYZPoint vertexPos;
3389  if(useVertices_)
3391  else
3392  vertexPos = ::math::XYZPoint(0.0,0.0,0.0);
3393 
3394 
3395  ::math::XYZVector clusterPos( cluster.position().X()-vertexPos.X(),
3396  cluster.position().Y()-vertexPos.Y(),
3397  cluster.position().Z()-vertexPos.Z());
3398  ::math::XYZVector particleDirection ( particleX*factor-vertexPos.X(),
3399  particleY*factor-vertexPos.Y(),
3400  particleZ*factor-vertexPos.Z() );
3401 
3402  //::math::XYZVector clusterPos( cluster.position().X(), cluster.position().Y(),cluster.position().Z() );
3403  //::math::XYZVector particleDirection ( particleX, particleY, particleZ );
3404 
3405  clusterPos = useDirection ? particleDirection.Unit() : clusterPos.Unit();
3406  clusterPos *= particleEnergy;
3407 
3408  // clusterPos is now a vector along the cluster direction,
3409  // with a magnitude equal to the cluster energy.
3410 
3411  double mass = 0;
3412  ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<double> >
3413  momentum( clusterPos.X(), clusterPos.Y(), clusterPos.Z(), mass);
3414  // mathcore is a piece of #$%
3416  // implicit constructor not allowed
3417  tmp = momentum;
3418 
3419  // Charge
3420  int charge = 0;
3421 
3422  // Type
3423  switch( cluster.layer() ) {
3424  case PFLayer::ECAL_BARREL:
3425  case PFLayer::ECAL_ENDCAP:
3426  particleType = PFCandidate::gamma;
3427  break;
3428  case PFLayer::HCAL_BARREL1:
3429  case PFLayer::HCAL_ENDCAP:
3430  particleType = PFCandidate::h0;
3431  break;
3432  case PFLayer::HF_HAD:
3433  particleType = PFCandidate::h_HF;
3434  break;
3435  case PFLayer::HF_EM:
3436  particleType = PFCandidate::egamma_HF;
3437  break;
3438  default:
3439  assert(0);
3440  }
3441 
3442  // The pf candidate
3443  pfCandidates_->push_back( PFCandidate( charge,
3444  tmp,
3445  particleType ) );
3446 
3447  // The position at ECAL entrance (well: watch out, it is not true
3448  // for HCAL clusters... to be fixed)
3449  pfCandidates_->back().
3450  setPositionAtECALEntrance(::math::XYZPointF(cluster.position().X(),
3451  cluster.position().Y(),
3452  cluster.position().Z()));
3453 
3454  //Set the cnadidate Vertex
3455  pfCandidates_->back().setVertex(vertexPos);
3456 
3457  // depth info
3458  setHcalDepthInfo(pfCandidates_->back(), cluster);
3459 
3460  //*TODO* cluster time is not reliable at the moment, so only use track timing
3461 
3462  if(debug_)
3463  cout<<"** candidate: "<<pfCandidates_->back()<<endl;
3464 
3465  // returns index to the newly created PFCandidate
3466  return pfCandidates_->size()-1;
3467 
3468 }
3469 
3470 void
3472  std::array<double,7> energyPerDepth;
3473  std::fill(energyPerDepth.begin(), energyPerDepth.end(), 0.0);
3474  for (auto & hitRefAndFrac : cluster.recHitFractions()) {
3475  const auto & hit = *hitRefAndFrac.recHitRef();
3476  if (DetId(hit.detId()).det() == DetId::Hcal) {
3477  if (hit.depth() == 0) {
3478  edm::LogWarning("setHcalDepthInfo") << "Depth zero found";
3479  continue;
3480  }
3481  if (hit.depth() < 1 || hit.depth() > 7) {
3482  throw cms::Exception("CorruptData") << "Bogus depth " << hit.depth() << " at detid " << hit.detId() << "\n";
3483  }
3484  energyPerDepth[hit.depth()-1] += hitRefAndFrac.fraction()*hit.energy();
3485  }
3486  }
3487  double sum = std::accumulate(energyPerDepth.begin(), energyPerDepth.end(), 0.);
3488  std::array<float,7> depthFractions;
3489  if (sum > 0) {
3490  for (unsigned int i = 0; i < depthFractions.size(); ++i) {
3491  depthFractions[i] = energyPerDepth[i]/sum;
3492  }
3493  } else {
3494  std::fill(depthFractions.begin(), depthFractions.end(), 0.f);
3495  }
3496  cand.setHcalDepthEnergyFractions(depthFractions);
3497 }
3498 
3499 //GMA need the followign two for HO also
3500 
3501 double
3502 PFAlgo::neutralHadronEnergyResolution(double clusterEnergyHCAL, double eta) const {
3503 
3504  // Add a protection
3505  if ( clusterEnergyHCAL < 1. ) clusterEnergyHCAL = 1.;
3506 
3507  double resol = fabs(eta) < 1.48 ?
3508  sqrt (1.02*1.02/clusterEnergyHCAL + 0.065*0.065)
3509  :
3510  sqrt (1.20*1.20/clusterEnergyHCAL + 0.028*0.028);
3511 
3512  return resol;
3513 
3514 }
3515 
3516 double
3517 PFAlgo::nSigmaHCAL(double clusterEnergyHCAL, double eta) const {
3518  double nS = fabs(eta) < 1.48 ?
3519  nSigmaHCAL_ * (1. + exp(-clusterEnergyHCAL/100.))
3520  :
3521  nSigmaHCAL_ * (1. + exp(-clusterEnergyHCAL/100.));
3522 
3523  return nS;
3524 }
3525 
3526 
3527 ostream& operator<<(ostream& out, const PFAlgo& algo) {
3528  if(!out ) return out;
3529 
3530  out<<"====== Particle Flow Algorithm ======= ";
3531  out<<endl;
3532  out<<"nSigmaECAL_ "<<algo.nSigmaECAL_<<endl;
3533  out<<"nSigmaHCAL_ "<<algo.nSigmaHCAL_<<endl;
3534  out<<endl;
3535  out<<(*(algo.calibration_))<<endl;
3536  out<<endl;
3537  out<<"reconstructed particles: "<<endl;
3538 
3539  const std::unique_ptr<reco::PFCandidateCollection>& candidates = algo.pfCandidates();
3540 
3541  if(!candidates.get() ) {
3542  out<<"candidates already transfered"<<endl;
3543  return out;
3544  }
3545  for(PFCandidateConstIterator ic=algo.pfCandidates_->begin();
3546  ic != algo.pfCandidates_->end(); ic++) {
3547  out<<(*ic)<<endl;
3548  }
3549 
3550  return out;
3551 }
3552 
3555  unsigned bi ) {
3556 
3557  if( blockHandle_.isValid() ) {
3558  return reco::PFBlockRef( blockHandle_, bi );
3559  }
3560  else {
3561  return reco::PFBlockRef( &blocks, bi );
3562  }
3563 }
3564 
3565 void
3567  reco::PFBlockElement::Type psElementType,
3568  const reco::PFBlock& block,
3570  const reco::PFBlock::LinkData& linkData,
3571  std::vector<bool>& active,
3572  std::vector<double>& psEne) {
3573 
3574  // Find all PS clusters with type psElement associated to ECAL cluster iEcal,
3575  // within all PFBlockElement "elements" of a given PFBlock "block"
3576  // psElement can be reco::PFBlockElement::PS1 or reco::PFBlockElement::PS2
3577  // Returns a vector of PS cluster energies, and updates the "active" vector.
3578 
3579  // Find all PS clusters linked to the iEcal cluster
3580  std::multimap<double, unsigned> sortedPS;
3581  typedef std::multimap<double, unsigned>::iterator IE;
3582  block.associatedElements( iEcal, linkData,
3583  sortedPS, psElementType,
3585 
3586  // Loop over these PS clusters
3587  double totalPS = 0.;
3588  for ( IE ips=sortedPS.begin(); ips!=sortedPS.end(); ++ips ) {
3589 
3590  // CLuster index and distance to iEcal
3591  unsigned iPS = ips->second;
3592  // double distPS = ips->first;
3593 
3594  // Ignore clusters already in use
3595  if (!active[iPS]) continue;
3596 
3597  // Check that this cluster is not closer to another ECAL cluster
3598  std::multimap<double, unsigned> sortedECAL;
3599  block.associatedElements( iPS, linkData,
3600  sortedECAL,
3603  unsigned jEcal = sortedECAL.begin()->second;
3604  if ( jEcal != iEcal ) continue;
3605 
3606  // Update PS energy
3607  PFBlockElement::Type pstype = elements[ iPS ].type();
3608  assert( pstype == psElementType );
3609  PFClusterRef psclusterref = elements[iPS].clusterRef();
3610  assert(!psclusterref.isNull() );
3611  totalPS += psclusterref->energy();
3612  psEne[0] += psclusterref->energy();
3613  active[iPS] = false;
3614  }
3615 
3616 
3617 }
3618 
3619 
3620 bool
3621 PFAlgo::isFromSecInt(const reco::PFBlockElement& eTrack, string order) const {
3622 
3625  // reco::PFBlockElement::TrackType T_FROM_GAMMACONV = reco::PFBlockElement::T_FROM_GAMMACONV;
3627 
3628  bool bPrimary = (order.find("primary") != string::npos);
3629  bool bSecondary = (order.find("secondary") != string::npos);
3630  bool bAll = (order.find("all") != string::npos);
3631 
3632  bool isToDisp = usePFNuclearInteractions_ && eTrack.trackType(T_TO_DISP);
3633  bool isFromDisp = usePFNuclearInteractions_ && eTrack.trackType(T_FROM_DISP);
3634 
3635  if (bPrimary && isToDisp) return true;
3636  if (bSecondary && isFromDisp ) return true;
3637  if (bAll && ( isToDisp || isFromDisp ) ) return true;
3638 
3639 // bool isFromConv = usePFConversions_ && eTrack.trackType(T_FROM_GAMMACONV);
3640 
3641 // if ((bAll || bSecondary)&& isFromConv) return true;
3642 
3643  bool isFromDecay = (bAll || bSecondary) && usePFDecays_ && eTrack.trackType(T_FROM_V0);
3644 
3645  return isFromDecay;
3646 
3647 
3648 }
3649 
3650 
3651 void
3654 }
3655 
3656 void
3658 
3659  // Check if the post HF Cleaning was requested - if not, do nothing
3660  if ( !postHFCleaning_ ) return;
3661 
3662  //Compute met and met significance (met/sqrt(SumEt))
3663  double metX = 0.;
3664  double metY = 0.;
3665  double sumet = 0;
3666  std::vector<unsigned int> pfCandidatesToBeRemoved;
3667  for(unsigned i=0; i<pfCandidates_->size(); i++) {
3668  const PFCandidate& pfc = (*pfCandidates_)[i];
3669  metX += pfc.px();
3670  metY += pfc.py();
3671  sumet += pfc.pt();
3672  }
3673  double met2 = metX*metX+metY*metY;
3674  // Select events with large MET significance.
3675  double significance = std::sqrt(met2/sumet);
3676  double significanceCor = significance;
3677  if ( significance > minSignificance_ ) {
3678 
3679  double metXCor = metX;
3680  double metYCor = metY;
3681  double sumetCor = sumet;
3682  double met2Cor = met2;
3683  double deltaPhi = 3.14159;
3684  double deltaPhiPt = 100.;
3685  bool next = true;
3686  unsigned iCor = 1E9;
3687 
3688  // Find the HF candidate with the largest effect on the MET
3689  while ( next ) {
3690 
3691  double metReduc = -1.;
3692  // Loop on the candidates
3693  for(unsigned i=0; i<pfCandidates_->size(); ++i) {
3694  const PFCandidate& pfc = (*pfCandidates_)[i];
3695 
3696  // Check that the pfCandidate is in the HF
3697  if ( pfc.particleId() != reco::PFCandidate::h_HF &&
3698  pfc.particleId() != reco::PFCandidate::egamma_HF ) continue;
3699 
3700  // Check if has meaningful pt
3701  if ( pfc.pt() < minHFCleaningPt_ ) continue;
3702 
3703  // Check that it is not already scheculed to be cleaned
3704  bool skip = false;
3705  for(unsigned j=0; j<pfCandidatesToBeRemoved.size(); ++j) {
3706  if ( i == pfCandidatesToBeRemoved[j] ) skip = true;
3707  if ( skip ) break;
3708  }
3709  if ( skip ) continue;
3710 
3711  // Check that the pt and the MET are aligned
3712  deltaPhi = std::acos((metX*pfc.px()+metY*pfc.py())/(pfc.pt()*std::sqrt(met2)));
3713  deltaPhiPt = deltaPhi*pfc.pt();
3714  if ( deltaPhiPt > maxDeltaPhiPt_ ) continue;
3715 
3716  // Now remove the candidate from the MET
3717  double metXInt = metX - pfc.px();
3718  double metYInt = metY - pfc.py();
3719  double sumetInt = sumet - pfc.pt();
3720  double met2Int = metXInt*metXInt+metYInt*metYInt;
3721  if ( met2Int < met2Cor ) {
3722  metXCor = metXInt;
3723  metYCor = metYInt;
3724  metReduc = (met2-met2Int)/met2Int;
3725  met2Cor = met2Int;
3726  sumetCor = sumetInt;
3727  significanceCor = std::sqrt(met2Cor/sumetCor);
3728  iCor = i;
3729  }
3730  }
3731  //
3732  // If the MET must be significanly reduced, schedule the candidate to be cleaned
3733  if ( metReduc > minDeltaMet_ ) {
3734  pfCandidatesToBeRemoved.push_back(iCor);
3735  metX = metXCor;
3736  metY = metYCor;
3737  sumet = sumetCor;
3738  met2 = met2Cor;
3739  } else {
3740  // Otherwise just stop the loop
3741  next = false;
3742  }
3743  }
3744  //
3745  // The significance must be significantly reduced to indeed clean the candidates
3746  if ( significance - significanceCor > minSignificanceReduction_ &&
3747  significanceCor < maxSignificance_ ) {
3748  std::cout << "Significance reduction = " << significance << " -> "
3749  << significanceCor << " = " << significanceCor - significance
3750  << std::endl;
3751  for(unsigned j=0; j<pfCandidatesToBeRemoved.size(); ++j) {
3752  std::cout << "Removed : " << (*pfCandidates_)[pfCandidatesToBeRemoved[j]] << std::endl;
3753  pfCleanedCandidates_->push_back( (*pfCandidates_)[ pfCandidatesToBeRemoved[j] ] );
3754  (*pfCandidates_)[pfCandidatesToBeRemoved[j]].rescaleMomentum(1E-6);
3755  //reco::PFCandidate::ParticleType unknown = reco::PFCandidate::X;
3756  //(*pfCandidates_)[pfCandidatesToBeRemoved[j]].setParticleType(unknown);
3757  }
3758  }
3759  }
3760 
3761 }
3762 
3763 void
3765 
3766 
3767  // No hits to recover, leave.
3768  if ( cleanedHits.empty() ) return;
3769 
3770  //Compute met and met significance (met/sqrt(SumEt))
3771  double metX = 0.;
3772  double metY = 0.;
3773  double sumet = 0;
3774  std::vector<unsigned int> hitsToBeAdded;
3775  for(unsigned i=0; i<pfCandidates_->size(); i++) {
3776  const PFCandidate& pfc = (*pfCandidates_)[i];
3777  metX += pfc.px();
3778  metY += pfc.py();
3779  sumet += pfc.pt();
3780  }
3781  double met2 = metX*metX+metY*metY;
3782  double met2_Original = met2;
3783  // Select events with large MET significance.
3784  // double significance = std::sqrt(met2/sumet);
3785  // double significanceCor = significance;
3786  double metXCor = metX;
3787  double metYCor = metY;
3788  double sumetCor = sumet;
3789  double met2Cor = met2;
3790  bool next = true;
3791  unsigned iCor = 1E9;
3792 
3793  // Find the cleaned hit with the largest effect on the MET
3794  while ( next ) {
3795 
3796  double metReduc = -1.;
3797  // Loop on the candidates
3798  for(unsigned i=0; i<cleanedHits.size(); ++i) {
3799  const PFRecHit& hit = cleanedHits[i];
3800  double length = std::sqrt(hit.position().mag2());
3801  double px = hit.energy() * hit.position().x()/length;
3802  double py = hit.energy() * hit.position().y()/length;
3803  double pt = std::sqrt(px*px + py*py);
3804 
3805  // Check that it is not already scheculed to be cleaned
3806  bool skip = false;
3807  for(unsigned j=0; j<hitsToBeAdded.size(); ++j) {
3808  if ( i == hitsToBeAdded[j] ) skip = true;
3809  if ( skip ) break;
3810  }
3811  if ( skip ) continue;
3812 
3813  // Now add the candidate to the MET
3814  double metXInt = metX + px;
3815  double metYInt = metY + py;
3816  double sumetInt = sumet + pt;
3817  double met2Int = metXInt*metXInt+metYInt*metYInt;
3818 
3819  // And check if it could contribute to a MET reduction
3820  if ( met2Int < met2Cor ) {
3821  metXCor = metXInt;
3822  metYCor = metYInt;
3823  metReduc = (met2-met2Int)/met2Int;
3824  met2Cor = met2Int;
3825  sumetCor = sumetInt;
3826  // significanceCor = std::sqrt(met2Cor/sumetCor);
3827  iCor = i;
3828  }
3829  }
3830  //
3831  // If the MET must be significanly reduced, schedule the candidate to be added
3832  //
3833  if ( metReduc > minDeltaMet_ ) {
3834  hitsToBeAdded.push_back(iCor);
3835  metX = metXCor;
3836  metY = metYCor;
3837  sumet = sumetCor;
3838  met2 = met2Cor;
3839  } else {
3840  // Otherwise just stop the loop
3841  next = false;
3842  }
3843  }
3844  //
3845  // At least 10 GeV MET reduction
3846  if ( std::sqrt(met2_Original) - std::sqrt(met2) > 5. ) {
3847  if ( debug_ ) {
3848  std::cout << hitsToBeAdded.size() << " hits were re-added " << std::endl;
3849  std::cout << "MET reduction = " << std::sqrt(met2_Original) << " -> "
3850  << std::sqrt(met2Cor) << " = " << std::sqrt(met2Cor) - std::sqrt(met2_Original)
3851  << std::endl;
3852  std::cout << "Added after cleaning check : " << std::endl;
3853  }
3854  for(unsigned j=0; j<hitsToBeAdded.size(); ++j) {
3855  const PFRecHit& hit = cleanedHits[hitsToBeAdded[j]];
3856  PFCluster cluster(hit.layer(), hit.energy(),
3857  hit.position().x(), hit.position().y(), hit.position().z() );
3858  reconstructCluster(cluster,hit.energy());
3859  if ( debug_ ) {
3860  std::cout << pfCandidates_->back() << ". time = " << hit.time() << std::endl;
3861  }
3862  }
3863  }
3864 
3865 }
3866 
3867 
3868 
3870  if(!usePFElectrons_) return;
3871  // std::cout << " setElectronExtraRef " << std::endl;
3872  unsigned size=pfCandidates_->size();
3873 
3874  for(unsigned ic=0;ic<size;++ic) {
3875  // select the electrons and add the extra
3876  if((*pfCandidates_)[ic].particleId()==PFCandidate::e) {
3877 
3878  PFElectronExtraEqual myExtraEqual((*pfCandidates_)[ic].gsfTrackRef());
3879  std::vector<PFCandidateElectronExtra>::const_iterator it=find_if(pfElectronExtra_.begin(),pfElectronExtra_.end(),myExtraEqual);
3880  if(it!=pfElectronExtra_.end()) {
3881  // std::cout << " Index " << it-pfElectronExtra_.begin() << std::endl;
3882  reco::PFCandidateElectronExtraRef theRef(extrah,it-pfElectronExtra_.begin());
3883  (*pfCandidates_)[ic].setPFElectronExtraRef(theRef);
3884  }
3885  else {
3886  (*pfCandidates_)[ic].setPFElectronExtraRef(PFCandidateElectronExtraRef());
3887  }
3888  }
3889  else // else save the mva and the extra as well !
3890  {
3891  if((*pfCandidates_)[ic].trackRef().isNonnull()) {
3892  PFElectronExtraKfEqual myExtraEqual((*pfCandidates_)[ic].trackRef());
3893  std::vector<PFCandidateElectronExtra>::const_iterator it=find_if(pfElectronExtra_.begin(),pfElectronExtra_.end(),myExtraEqual);
3894  if(it!=pfElectronExtra_.end()) {
3895  (*pfCandidates_)[ic].set_mva_e_pi(it->mvaVariable(PFCandidateElectronExtra::MVA_MVA));
3896  reco::PFCandidateElectronExtraRef theRef(extrah,it-pfElectronExtra_.begin());
3897  (*pfCandidates_)[ic].setPFElectronExtraRef(theRef);
3898  (*pfCandidates_)[ic].setGsfTrackRef(it->gsfTrackRef());
3899  }
3900  }
3901  }
3902 
3903  }
3904 
3905  size=pfElectronCandidates_->size();
3906  for(unsigned ic=0;ic<size;++ic) {
3907  // select the electrons - this test is actually not needed for this collection
3908  if((*pfElectronCandidates_)[ic].particleId()==PFCandidate::e) {
3909  // find the corresponding extra
3910  PFElectronExtraEqual myExtraEqual((*pfElectronCandidates_)[ic].gsfTrackRef());
3911  std::vector<PFCandidateElectronExtra>::const_iterator it=find_if(pfElectronExtra_.begin(),pfElectronExtra_.end(),myExtraEqual);
3912  if(it!=pfElectronExtra_.end()) {
3913  reco::PFCandidateElectronExtraRef theRef(extrah,it-pfElectronExtra_.begin());
3914  (*pfElectronCandidates_)[ic].setPFElectronExtraRef(theRef);
3915 
3916  }
3917  }
3918  }
3919 
3920 }
3922  if(!usePFPhotons_) return;
3923  unsigned int size=pfCandidates_->size();
3924  unsigned int sizePhExtra = pfPhotonExtra_.size();
3925  for(unsigned ic=0;ic<size;++ic) {
3926  // select the electrons and add the extra
3927  if((*pfCandidates_)[ic].particleId()==PFCandidate::gamma && (*pfCandidates_)[ic].mva_nothing_gamma() > 0.99) {
3928  if((*pfCandidates_)[ic].superClusterRef().isNonnull()) {
3929  bool found = false;
3930  for(unsigned pcextra=0;pcextra<sizePhExtra;++pcextra) {
3931  if((*pfCandidates_)[ic].superClusterRef() == pfPhotonExtra_[pcextra].superClusterRef()) {
3932  reco::PFCandidatePhotonExtraRef theRef(ph_extrah,pcextra);
3933  (*pfCandidates_)[ic].setPFPhotonExtraRef(theRef);
3934  found = true;
3935  break;
3936  }
3937  }
3938  if(!found)
3939  (*pfCandidates_)[ic].setPFPhotonExtraRef((PFCandidatePhotonExtraRef())); // null ref
3940  }
3941  else {
3942  (*pfCandidates_)[ic].setPFPhotonExtraRef((PFCandidatePhotonExtraRef())); // null ref
3943  }
3944  }
3945  }
3946 }
PFLayer::Layer layer() const
cluster layer, see PFLayer.h in this directory
Definition: PFCluster.cc:120
size
Write out results.
double p() const
momentum vector magnitude
Definition: TrackBase.h:615
type
Definition: HCALResponse.h:21
T getParameter(std::string const &) const
unsigned int nTrackIsoForEgammaSC_
Definition: PFAlgo.h:359
edm::Ref< PFBlockCollection > PFBlockRef
persistent reference to PFCluster objects
Definition: PFBlockFwd.h:20
Abstract base class for a PFBlock element (track, cluster...)
static bool isIsolatedMuon(const reco::PFBlockElement &elt)
Definition: PFMuonAlgo.cc:227
const math::XYZPoint & position() const
cluster centroid position
Definition: CaloCluster.h:131
double ptError_
Definition: PFAlgo.h:400
bool isFromSecInt(const reco::PFBlockElement &eTrack, std::string order) const
Definition: PFAlgo.cc:3621
bool usePFConversions_
Definition: PFAlgo.h:383
float goodTrackDeadHcal_dxy_
Definition: PFAlgo.h:408
std::vector< double > muonHCAL_
Variables for muons and fakes.
Definition: PFAlgo.h:396
ParticleType
particle types
Definition: PFCandidate.h:45
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:253
T y() const
Cartesian y coordinate.
double eta() const final
momentum pseudorapidity
double maxDeltaPhiPt_
Definition: PFAlgo.h:427
void setPFMuonAndFakeParameters(const edm::ParameterSet &pset)
Definition: PFAlgo.cc:306
T x() const
Cartesian x coordinate.
void addMissingMuons(edm::Handle< reco::MuonCollection >, reco::PFCandidateCollection *cands)
Definition: PFMuonAlgo.cc:953
double maxSignificance_
Definition: PFAlgo.h:425
double sumEtEcalIsoForEgammaSC_endcap_
Definition: PFAlgo.h:354
bool isElectronSafeForJetMET(const reco::GsfElectron &, const reco::PFCandidate &, const reco::Vertex &, bool &lockTracks)
Definition: CLHEP.h:16
double mvaEleCut_
Definition: PFAlgo.h:346
void set_mva_nothing_gamma(float mva)
set mva for gamma detection
Definition: PFCandidate.h:330
double minHFCleaningPt_
Definition: PFAlgo.h:423
bool isMuon(const Candidate &part)
Definition: pdgIdUtils.h:11
Particle flow cluster, see clustering algorithm in PFClusterAlgo.
Definition: PFCluster.h:47
bool isPhotonValidCandidate(const reco::PFBlockRef &blockRef, std::vector< bool > &active, std::unique_ptr< reco::PFCandidateCollection > &pfPhotonCandidates, std::vector< reco::PFCandidatePhotonExtra > &pfPhotonExtraCandidates, std::vector< reco::PFCandidate > &tempElectronCandidates)
Definition: PFPhotonAlgo.h:82
edm::Ref< PFCandidatePhotonExtraCollection > PFCandidatePhotonExtraRef
persistent reference to a PFCandidatePhotonExtra
double coneEcalIsoForEgammaSC_
Definition: PFAlgo.h:355
static bool isMuon(const reco::PFBlockElement &elt)
Definition: PFMuonAlgo.cc:155
double minDeltaMet_
Definition: PFAlgo.h:428
const std::vector< reco::PFCandidate > & getAllElectronCandidates()
float time() const
timing for cleaned hits
Definition: PFRecHit.h:118
double minSignificance_
Definition: PFAlgo.h:424
float time() const
double errorScale(const reco::TrackBase::TrackAlgorithm &, const std::vector< double > &)
std::unique_ptr< reco::PFCandidateCollection > pfCandidates_
Definition: PFAlgo.h:289
unsigned reconstructCluster(const reco::PFCluster &cluster, double particleEnergy, bool useDirection=false, double particleX=0., double particleY=0., double particleZ=0.)
Definition: PFAlgo.cc:3357
void reconstructParticles(const reco::PFBlockHandle &blockHandle)
Definition: PFAlgo.cc:437
const std::unique_ptr< reco::PFCandidateCollection > & pfCandidates() const
Definition: PFAlgo.h:200
double y() const
y coordinate
Definition: Vertex.h:113
bool useProtectionsForJetMET_
Definition: PFAlgo.h:368
double coneTrackIsoForEgammaSC_
Definition: PFAlgo.h:358
void setParameters(const edm::ParameterSet &)
Definition: PFMuonAlgo.cc:29
float goodPixelTrackDeadHcal_minEta_
Definition: PFAlgo.h:410
const reco::TrackRef & trackRef() const override
double px() const final
x coordinate of momentum vector
double nSigmaHCAL_
number of sigma to judge energy excess in HCAL
Definition: PFAlgo.h:333
std::map< unsigned int, Link > LinkData
Definition: PFBlock.h:46
size_type size() const
Definition: OwnVector.h:264
void setnPU(int nVtx)
Definition: PFPhotonAlgo.h:75
virtual void processBlock(const reco::PFBlockRef &blockref, std::list< reco::PFBlockRef > &hcalBlockRefs, std::list< reco::PFBlockRef > &ecalBlockRefs)
Definition: PFAlgo.cc:560
void setMuonHandle(const edm::Handle< reco::MuonCollection > &)
Definition: PFAlgo.cc:353
#define X(str)
Definition: MuonsGrabber.cc:48
bool trackType(TrackType trType) const override
math::Error< dimension >::type Error
covariance error matrix (3x3)
Definition: Vertex.h:43
void setVertex(const math::XYZPoint &p) override
set vertex
Definition: PFCandidate.h:409
size_type size() const
std::vector< Variable::Flags > flags
Definition: MVATrainer.cc:135
double phi() const
azimuthal angle of momentum vector
Definition: TrackBase.h:645
double pt() const final
transverse momentum
std::vector< Vertex > VertexCollection
collection of Vertex objects
Definition: VertexFwd.h:9
const edm::OwnVector< reco::PFBlockElement > & elements() const
Definition: PFBlock.h:107
int charge() const final
electric charge
Definition: LeafCandidate.h:91
std::vector< PFRecHit > PFRecHitCollection
collection of PFRecHit objects
Definition: PFRecHitFwd.h:9
const edm::ValueMap< reco::PhotonRef > * valueMapGedPhotons_
Definition: PFAlgo.h:371
void checkCleaning(const reco::PFRecHitCollection &cleanedHF)
Check HF Cleaning.
Definition: PFAlgo.cc:3764
edm::Ref< PFCandidateElectronExtraCollection > PFCandidateElectronExtraRef
persistent reference to a PFCandidateElectronExtra
bool passElectronSelection(const reco::GsfElectron &, const reco::PFCandidate &, const int &)
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< float > > XYZPointF
point in space with cartesian internal representation
Definition: Point3D.h:10
double px() const
x coordinate of momentum vector
Definition: TrackBase.h:627
void setDisplacedVerticesParameters(bool rejectTracks_Bad, bool rejectTracks_Step45, bool usePFNuclearInteractions, bool usePFConversions, bool usePFDecays, double dptRel_DispVtx)
Definition: PFAlgo.cc:376
PFCandidateCollection::const_iterator PFCandidateConstIterator
iterator
#define nullptr
double sumEtEcalIsoForEgammaSC_barrel_
Definition: PFAlgo.h:353
PFElectronAlgo * pfele_
Definition: PFAlgo.h:360
void setPFEleParameters(double mvaEleCut, std::string mvaWeightFileEleID, bool usePFElectrons, const boost::shared_ptr< PFSCEnergyCalibration > &thePFSCEnergyCalibration, const boost::shared_ptr< PFEnergyCalibration > &thePFEnergyCalibration, double sumEtEcalIsoForEgammaSC_barrel, double sumEtEcalIsoForEgammaSC_endcap, double coneEcalIsoForEgammaSC, double sumPtTrackIsoForEgammaSC_barrel, double sumPtTrackIsoForEgammaSC_endcap, unsigned int nTrackIsoForEgammaSC, double coneTrackIsoForEgammaSC, bool applyCrackCorrections=false, bool usePFSCEleCalib=true, bool useEGElectrons=false, bool useEGammaSupercluster=true)
Definition: PFAlgo.cc:99
float goodPixelTrackDeadHcal_dxy_
Definition: PFAlgo.h:416
PFMuonAlgo * pfmu_
Definition: PFAlgo.h:362
void setPFVertexParameters(bool useVertex, const reco::VertexCollection *primaryVertices)
Definition: PFAlgo.cc:394
void setEGElectronCollection(const reco::GsfElectronCollection &egelectrons)
Definition: PFAlgo.cc:3652
const Point & position() const
position
Definition: Vertex.h:109
static bool isGlobalTightMuon(const reco::PFBlockElement &elt)
Definition: PFMuonAlgo.cc:188
std::vector< GsfElectron > GsfElectronCollection
collection of GsfElectron objects
int nVtx_
Definition: PFAlgo.h:389
bool rejectTracks_Step45_
Definition: PFAlgo.h:380
const math::XYZPointF & positionAtECALEntrance() const
PositionType const & position() const
rechit cell centre x, y, z
Definition: PFRecHit.h:129
std::vector< ElementInBlock > ElementsInBlocks
Definition: PFCandidate.h:387
double minSignificanceReduction_
Definition: PFAlgo.h:426
void setPFPhotonParameters(bool usePFPhoton, std::string mvaWeightFileConvID, double mvaConvCut, bool useReg, std::string X0_Map, const boost::shared_ptr< PFEnergyCalibration > &thePFEnergyCalibration, double sumPtTrackIsoForPhoton, double sumPtTrackIsoSlopeForPhoton)
Definition: PFAlgo.cc:161
std::vector< double > factors45_
Definition: PFAlgo.h:401
bool useHO_
Definition: PFAlgo.h:339
iterator begin()
Definition: OwnVector.h:244
PFLayer::Layer layer() const
rechit layer
Definition: PFRecHit.h:111
RefToBase< value_type > refAt(size_type i) const
bool useEGammaSupercluster_
Definition: PFAlgo.h:352
U second(std::pair< T, U > const &p)
void setCharge(Charge q) final
set electric charge
Definition: LeafCandidate.h:93
std::unique_ptr< reco::PFCandidateCollection > pfCleanedCandidates_
Definition: PFAlgo.h:295
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
bool isElectron(const reco::GsfElectron &)
void set_mva_e_pi(float mvaNI)
Definition: PFCandidate.h:312
void push_back(D *&d)
Definition: OwnVector.h:290
bool isTimeValid() const
do we have a valid time information
bool usePFNuclearInteractions_
Definition: PFAlgo.h:382
double eta() const
pseudorapidity of momentum vector
Definition: TrackBase.h:651
bool postHFCleaning_
Definition: PFAlgo.h:421
void setEGammaCollections(const edm::View< reco::PFCandidate > &pfEgammaCandidates, const edm::ValueMap< reco::GsfElectronRef > &valueMapGedElectrons, const edm::ValueMap< reco::PhotonRef > &valueMapGedPhotons)
Definition: PFAlgo.cc:271
Particle flow rechit (rechit + geometry and topology information). See clustering algorithm in PFClus...
Definition: PFRecHit.h:32
void setBadHcalTrackParams(const edm::ParameterSet &pset)
Definition: PFAlgo.cc:334
void set_mva_Isolated(float mvaI)
Definition: PFCandidate.h:308
boost::shared_ptr< PFEnergyCalibration > thePFEnergyCalibration()
return the pointer to the calibration function
Definition: PFAlgo.h:238
void setParameters(double nSigmaECAL, double nSigmaHCAL, const boost::shared_ptr< PFEnergyCalibration > &calibration, const boost::shared_ptr< PFEnergyCalibrationHF > &thepfEnergyCalibrationHF)
Definition: PFAlgo.cc:79
T z() const
Cartesian z coordinate.
const edm::View< reco::PFCandidate > * pfEgammaCandidates_
Definition: PFAlgo.h:369
bool useEGElectrons_
Definition: PFAlgo.h:351
void associatePSClusters(unsigned iEcal, reco::PFBlockElement::Type psElementType, const reco::PFBlock &block, const edm::OwnVector< reco::PFBlockElement > &elements, const reco::PFBlock::LinkData &linkData, std::vector< bool > &active, std::vector< double > &psEne)
Associate PS clusters to a given ECAL cluster, and return their energy.
Definition: PFAlgo.cc:3566
std::string mvaWeightFileEleID_
Variables for PFElectrons.
Definition: PFAlgo.h:344
void setParticleType(ParticleType type)
set Particle Type
Definition: PFCandidate.cc:265
bool passPhotonSelection(const reco::Photon &)
T sqrt(T t)
Definition: SSEVec.h:18
bool empty() const
Definition: OwnVector.h:269
double pt() const
track transverse momentum
Definition: TrackBase.h:621
const std::vector< reco::PFCandidateElectronExtra > & getElectronExtra()
bool step45(const reco::TrackBase::TrackAlgorithm &)
PFPhotonAlgo * pfpho_
Definition: PFAlgo.h:361
float goodTrackDeadHcal_validFr_
Definition: PFAlgo.h:407
double energy() const final
energy
void setPFPhotonRegWeights(const GBRForest *LCorrForestEB, const GBRForest *LCorrForestEE, const GBRForest *GCorrForestBarrel, const GBRForest *GCorrForestEndcapHr9, const GBRForest *GCorrForestEndcapLr9, const GBRForest *PFEcalResolution)
Definition: PFAlgo.cc:293
def pv(vc)
Definition: MetAnalyzer.py:7
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double z() const
z coordinate
Definition: Vertex.h:115
reco::Vertex primaryVertex_
Definition: PFAlgo.h:432
double nSigmaHCAL(double clusterEnergy, double clusterEta) const
Definition: PFAlgo.cc:3517
edm::Handle< reco::MuonCollection > muonHandle_
Definition: PFAlgo.h:435
bool usePFSCEleCalib_
Definition: PFAlgo.h:350
std::vector< double > muonECAL_
Definition: PFAlgo.h:397
void setPositionAtECALEntrance(float x, float y, float z)
set position at ECAL entrance
math::XYZPoint Point
point in the space
Definition: Vertex.h:39
T min(T a, T b)
Definition: MathUtil.h:58
float energy() const
rechit energy
Definition: PFRecHit.h:114
std::vector< LinkConnSpec >::const_iterator IT
void setPostHFCleaningParameters(bool postHFCleaning, double minHFCleaningPt, double minSignificance, double maxSignificance, double minSignificanceReduction, double maxDeltaPhiPt, double minDeltaMet)
Definition: PFAlgo.cc:359
bool isValid() const
Definition: HandleBase.h:74
std::vector< PFBlock > PFBlockCollection
collection of PFBlock objects
Definition: PFBlockFwd.h:11
PFEGammaFilters * pfegamma_
Definition: PFAlgo.h:367
bool isNull() const
Checks for null.
Definition: Ref.h:250
int goodPixelTrackDeadHcal_maxLost3Hit_
Definition: PFAlgo.h:414
reco::PFBlockRef createBlockRef(const reco::PFBlockCollection &blocks, unsigned bi)
Definition: PFAlgo.cc:3554
reco::PFCandidatePhotonExtraCollection pfPhotonExtra_
the extra photon collection
Definition: PFAlgo.h:300
ii
Definition: cuy.py:590
double pz() const
z coordinate of momentum vector
Definition: TrackBase.h:639
void setEcalEnergy(float eeRaw, float eeCorr)
set corrected Ecal energy
Definition: PFCandidate.h:218
float mva_e_pi() const
mva for electron-pion discrimination
Definition: PFCandidate.h:314
void setHcalDepthEnergyFractions(const std::array< float, 7 > &fracs)
set the fraction of hcal energy as function of depth (index 0..6 for depth 1..7)
Definition: PFCandidate.h:432
std::unique_ptr< reco::PFCandidateCollection > pfPhotonCandidates_
the unfiltered photon collection
Definition: PFAlgo.h:293
const PFDisplacedTrackerVertexRef & displacedVertexRef(TrackType trType) const override
const std::vector< reco::PFCandidate > & getElectronCandidates()
Definition: DetId.h:18
float goodPixelTrackDeadHcal_maxPt_
Definition: PFAlgo.h:411
std::vector< reco::PFCandidate > PFCandidateCollection
collection of PFCandidates
double x() const
x coordinate
Definition: Vertex.h:111
std::list< reco::PFBlockRef >::iterator IBR
Definition: PFAlgo.cc:55
unsigned reconstructTrack(const reco::PFBlockElement &elt, bool allowLoose=false)
Definition: PFAlgo.cc:3277
int goodTrackDeadHcal_layers_
Definition: PFAlgo.h:406
std::vector< double > muonHO_
Definition: PFAlgo.h:398
bool useVertices_
Definition: PFAlgo.h:433
primaryVertices
Definition: jets_cff.py:130
float goodPixelTrackDeadHcal_ptErrRel_
Definition: PFAlgo.h:412
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:30
void setGBRForest(const GBRForest *LCorrForest, const GBRForest *GCorrForest, const GBRForest *ResForest)
Definition: PFPhotonAlgo.h:49
double dptRel_DispVtx_
Definition: PFAlgo.h:388
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
static bool isLooseMuon(const reco::PFBlockElement &elt)
Definition: PFMuonAlgo.cc:168
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
boost::shared_ptr< PFEnergyCalibration > calibration_
Definition: PFAlgo.h:335
reco::PFBlockHandle blockHandle_
input block handle (full framework case)
Definition: PFAlgo.h:327
double b
Definition: hdecay.h:120
double py() const final
y coordinate of momentum vector
virtual bool trackType(TrackType trType) const
boost::shared_ptr< PFSCEnergyCalibration > thePFSCEnergyCalibration_
Definition: PFAlgo.h:337
void setEGammaParameters(bool use_EGammaFilters, std::string ele_iso_path_mvaWeightFile, double ele_iso_pt, double ele_iso_mva_barrel, double ele_iso_mva_endcap, double ele_iso_combIso_barrel, double ele_iso_combIso_endcap, double ele_noniso_mva, unsigned int ele_missinghits, bool useProtectionsForJetMET, const edm::ParameterSet &ele_protectionsForJetMET, const edm::ParameterSet &ele_protectionsForBadHcal, double ph_MinEt, double ph_combIso, double ph_HoE, double ph_sietaieta_eb, double ph_sietaieta_ee, const edm::ParameterSet &ph_protectionsForJetMET, const edm::ParameterSet &ph_protectionsForBadHcal)
Definition: PFAlgo.cc:212
virtual ~PFAlgo()
destructor
Definition: PFAlgo.cc:71
significance
Definition: met_cff.py:30
void setHoEnergy(float eoRaw, float eoCorr)
set corrected Hcal energy
Definition: PFCandidate.h:238
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
math::XYZVector XYZPoint
bool isElectronValidCandidate(const reco::PFBlockRef &blockRef, std::vector< bool > &active, const reco::Vertex &primaryVertex)
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:40
fixed size matrix
boost::shared_ptr< PFEnergyCalibrationHF > thepfEnergyCalibrationHF_
Definition: PFAlgo.h:336
double a
Definition: hdecay.h:121
reco::PFCandidateEGammaExtraRef egammaExtraRef() const
return a reference to the EGamma extra
Definition: PFCandidate.cc:605
bool rejectTracks_Bad_
Definition: PFAlgo.h:379
PFAlgo()
constructor
Definition: PFAlgo.cc:59
PFMuonAlgo * getPFMuonAlgo()
Definition: PFAlgo.cc:93
bool useEGammaFilters_
Variables for NEW EGAMMA selection.
Definition: PFAlgo.h:366
const std::vector< reco::PFRecHitFraction > & recHitFractions() const
vector of rechit fractions
Definition: PFCluster.h:72
bool debug_
Definition: PFAlgo.h:341
void setPhotonExtraRef(const edm::OrphanHandle< reco::PFCandidatePhotonExtraCollection > &pf_extrah)
Definition: PFAlgo.cc:3921
bool applyCrackCorrectionsElectrons_
Definition: PFAlgo.h:349
int charge() const
track electric charge
Definition: TrackBase.h:567
float goodTrackDeadHcal_ptErrRel_
Variables for track cleaning in bad HCal areas.
Definition: PFAlgo.h:404
bool step5(const reco::TrackBase::TrackAlgorithm &)
double sumPtTrackIsoForEgammaSC_endcap_
Definition: PFAlgo.h:357
std::unique_ptr< reco::PFCandidateCollection > pfElectronCandidates_
the unfiltered electron collection
Definition: PFAlgo.h:291
void setPhotonPrimaryVtx(const reco::Vertex &primary)
Definition: PFPhotonAlgo.h:78
int goodPixelTrackDeadHcal_maxLost4Hit_
Definition: PFAlgo.h:415
const reco::MuonRef & muonRef() const override
float goodPixelTrackDeadHcal_chi2n_
Definition: PFAlgo.h:413
double nSigmaTRACK_
Definition: PFAlgo.h:399
virtual ParticleType particleId() const
Definition: PFCandidate.h:374
double neutralHadronEnergyResolution(double clusterEnergy, double clusterEta) const
todo: use PFClusterTools for this
Definition: PFAlgo.cc:3502
void postCleaning()
Definition: PFAlgo.cc:3657
void postClean(reco::PFCandidateCollection *)
Definition: PFMuonAlgo.cc:849
def check(config)
Definition: trackerTree.py:14
Definition: PFAlgo.h:52
reco::PFCandidateElectronExtraCollection pfElectronExtra_
the unfiltered electron collection
Definition: PFAlgo.h:298
bool usePFPhotons_
Definition: PFAlgo.h:348
const ElementsInBlocks & elementsInBlocks() const
Definition: PFCandidate.cc:691
bool usePFDecays_
Definition: PFAlgo.h:384
void setInputsForCleaning(const reco::VertexCollection *)
Definition: PFMuonAlgo.cc:1168
double phi() const final
momentum azimuthal angle
bool isPhotonSafeForJetMET(const reco::Photon &, const reco::PFCandidate &)
void setP4(const LorentzVector &p4) final
set 4-momentum
float goodTrackDeadHcal_chi2n_
Definition: PFAlgo.h:405
double sumPtTrackIsoForEgammaSC_barrel_
Definition: PFAlgo.h:356
float goodPixelTrackDeadHcal_dz_
Definition: PFAlgo.h:417
void setHcalEnergy(float ehRaw, float ehCorr)
set corrected Hcal energy
Definition: PFCandidate.h:228
void setHcalDepthInfo(reco::PFCandidate &cand, const reco::PFCluster &cluster) const
Definition: PFAlgo.cc:3471
double py() const
y coordinate of momentum vector
Definition: TrackBase.h:633
static bool isTrackerTightMuon(const reco::PFBlockElement &elt)
Definition: PFMuonAlgo.cc:214
const edm::ValueMap< reco::GsfElectronRef > * valueMapGedElectrons_
Definition: PFAlgo.h:370
float timeError() const
friend std::ostream & operator<<(std::ostream &out, const PFAlgo &algo)
void setElectronExtraRef(const edm::OrphanHandle< reco::PFCandidateElectronExtraCollection > &extrah)
Definition: PFAlgo.cc:3869
T mag2() const
The vector magnitude squared. Equivalent to vec.dot(vec)
void setEGElectronCollection(const reco::GsfElectronCollection &egelectrons)
bool reconstructMuon(reco::PFCandidate &, const reco::MuonRef &, bool allowLoose=false)
Definition: PFMuonAlgo.cc:717
double nSigmaECAL_
number of sigma to judge energy excess in ECAL
Definition: PFAlgo.h:330
Block of elements.
Definition: PFBlock.h:30
bool usePFElectrons_
Definition: PFAlgo.h:347