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