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