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