CMS 3D CMS Logo

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