00001 #include "RecoParticleFlow/PFAlgo/interface/PFAlgo.h"
00002 #include "RecoParticleFlow/PFAlgo/interface/PFElectronAlgo.h"
00003 #include "RecoParticleFlow/PFAlgo/interface/PFConversionAlgo.h"
00004
00005 #include "RecoParticleFlow/PFClusterTools/interface/PFEnergyCalibration.h"
00006 #include "RecoParticleFlow/PFClusterTools/interface/PFClusterCalibration.h"
00007
00008 #include "DataFormats/ParticleFlowReco/interface/PFBlock.h"
00009 #include "DataFormats/ParticleFlowReco/interface/PFBlockElementTrack.h"
00010 #include "DataFormats/ParticleFlowReco/interface/PFBlockElementCluster.h"
00011 #include "DataFormats/ParticleFlowReco/interface/PFRecTrack.h"
00012 #include "DataFormats/ParticleFlowReco/interface/PFCluster.h"
00013 #include "DataFormats/ParticleFlowReco/interface/PFLayer.h"
00014
00015 #include "DataFormats/TrackReco/interface/Track.h"
00016 #include "DataFormats/MuonReco/interface/Muon.h"
00017
00018
00019 #include "DataFormats/Common/interface/OrphanHandle.h"
00020
00021 #include "DataFormats/Provenance/interface/ProductID.h"
00022
00023
00024 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
00025 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h"
00026
00027 #include "Math/PxPyPzM4D.h"
00028 #include "Math/LorentzVector.h"
00029 #include "Math/DisplacementVector3D.h"
00030 #include "Math/SMatrix.h"
00031 #include "TDecompChol.h"
00032
00033 #include "boost/graph/adjacency_matrix.hpp"
00034 #include "boost/graph/graph_utility.hpp"
00035
00036 using namespace std;
00037 using namespace reco;
00038 using namespace boost;
00039
00040 float PFAlgo::maxMvaCut_ = PFCandidate::bigMva_;
00041
00042
00043 typedef std::list< reco::PFBlockRef >::iterator IBR;
00044
00045
00046
00047 PFAlgo::PFAlgo()
00048 : pfCandidates_( new PFCandidateCollection),
00049 nSigmaECAL_(3),
00050 nSigmaHCAL_(3),
00051 clusterRecovery_(false),
00052 PSCut_(999.),
00053 mergedPhotonsMVA_( 0 ),
00054 mvaCut_(PFAlgo::maxMvaCut_),
00055 algo_(1),
00056 debug_(false),
00057 pfele_(0)
00058 {}
00059
00060 PFAlgo::~PFAlgo() {
00061 if (usePFElectrons_) delete pfele_;
00062 if (usePFConversions_) delete pfConversion_;
00063 }
00064
00065
00066 void
00067 PFAlgo::setParameters(double nSigmaECAL,
00068 double nSigmaHCAL,
00069 const shared_ptr<PFEnergyCalibration>& calibration,
00070 const shared_ptr<pftools::PFClusterCalibration>& clusterCalibration,
00071 bool newCalib,
00072 bool clusterRecovery,
00073 double PSCut,
00074 double mvaCut,
00075 const char* mvaWeightFile ) {
00076
00077 nSigmaECAL_ = nSigmaECAL;
00078 nSigmaHCAL_ = nSigmaHCAL;
00079
00080 calibration_ = calibration;
00081 clusterCalibration_ = clusterCalibration;
00082 newCalib_ = newCalib;
00083
00084
00085
00086 clusterRecovery_ = clusterRecovery;
00087
00088 PSCut_=PSCut;
00089 mvaCut_ = mvaCut;
00090
00091 if( mergedPhotonsMVA_ ) delete mergedPhotonsMVA_;
00092 mergedPhotonsMVA_ = new TMVA::Reader();
00093 mergedPhotonsMVA_->AddVariable("eECAL/pTrack", &eECALOverpTrack_);
00094 mergedPhotonsMVA_->AddVariable("chi2ECAL", &chi2ECAL_);
00095 mergedPhotonsMVA_->AddVariable("ptTrack", &ptTrack_);
00096
00097 if( mvaCut < PFAlgo::maxMvaCut_ ) {
00098 FILE * file = fopen(mvaWeightFile, "r");
00099 if (file) {
00100 fclose(file);
00101
00102 mergedPhotonsMVA_->BookMVA( "MVA", mvaWeightFile );
00103 }
00104 else {
00105
00106 string err = "PFAlgo: cannot open weight file '";
00107 err += mvaWeightFile;
00108 err += "'";
00109 throw invalid_argument( err );
00110 }
00111 }
00112 }
00113
00114
00115 void
00116 PFAlgo::setPFEleParameters(double chi2EcalGSF,
00117 double chi2EcalBrem,
00118 double chi2HcalGSF,
00119 double chi2HcalBrem,
00120 double chi2PsGSF,
00121 double chi2PsBrem,
00122 double mvaEleCut,
00123 string mvaWeightFileEleID,
00124 bool usePFElectrons) {
00125 setchi2Values_.push_back(chi2EcalGSF);
00126 setchi2Values_.push_back(chi2EcalBrem);
00127 setchi2Values_.push_back(chi2HcalGSF);
00128 setchi2Values_.push_back(chi2HcalBrem);
00129 setchi2Values_.push_back(chi2PsGSF);
00130 setchi2Values_.push_back(chi2PsBrem);
00131
00132 mvaEleCut_ = mvaEleCut;
00133 usePFElectrons_ = usePFElectrons;
00134 mvaWeightFileEleID_ = mvaWeightFileEleID;
00135 FILE * fileEleID = fopen(mvaWeightFileEleID_.c_str(), "r");
00136 if (fileEleID) {
00137 fclose(fileEleID);
00138 }
00139 else {
00140 string err = "PFAlgo: cannot open weight file '";
00141 err += mvaWeightFileEleID;
00142 err += "'";
00143 throw invalid_argument( err );
00144 }
00145 pfele_= new PFElectronAlgo(setchi2Values_,mvaEleCut_,mvaWeightFileEleID_);
00146 }
00147
00148
00149 void PFAlgo::setPFConversionParameters(bool usePFConversions ) {
00150
00151 usePFConversions_ = usePFConversions;
00152 pfConversion_ = new PFConversionAlgo();
00153
00154
00155 }
00156
00157
00158
00159 void PFAlgo::reconstructParticles( const reco::PFBlockHandle& blockHandle ) {
00160
00161 blockHandle_ = blockHandle;
00162 reconstructParticles( *blockHandle_ );
00163 }
00164
00165
00166
00167 void PFAlgo::reconstructParticles( const reco::PFBlockCollection& blocks ) {
00168
00169
00170 if(pfCandidates_.get() )
00171 pfCandidates_->clear();
00172 else
00173 pfCandidates_.reset( new reco::PFCandidateCollection );
00174
00175
00176
00177 if( debug_ ) {
00178 cout<<"*********************************************************"<<endl;
00179 cout<<"***** Particle flow algorithm *****"<<endl;
00180 cout<<"*********************************************************"<<endl;
00181 }
00182
00183
00184 std::list< reco::PFBlockRef > hcalBlockRefs;
00185 std::list< reco::PFBlockRef > ecalBlockRefs;
00186 std::list< reco::PFBlockRef > otherBlockRefs;
00187
00188 for( unsigned i=0; i<blocks.size(); ++i ) {
00189
00190 reco::PFBlockRef blockref = createBlockRef( blocks, i);
00191
00192 const reco::PFBlock& block = *blockref;
00193 const edm::OwnVector< reco::PFBlockElement >&
00194 elements = block.elements();
00195
00196 bool singleEcalOrHcal = false;
00197 if( elements.size() == 1 ){
00198 if( elements[0].type() == reco::PFBlockElement::ECAL ){
00199 ecalBlockRefs.push_back( blockref );
00200 singleEcalOrHcal = true;
00201 }
00202 if( elements[0].type() == reco::PFBlockElement::HCAL ){
00203 hcalBlockRefs.push_back( blockref );
00204 singleEcalOrHcal = true;
00205 }
00206 }
00207
00208 if(!singleEcalOrHcal) {
00209 otherBlockRefs.push_back( blockref );
00210 }
00211 }
00212
00213 if( debug_ ){
00214 cout<<"# Ecal blocks: "<<ecalBlockRefs.size()
00215 <<", # Hcal blocks: "<<hcalBlockRefs.size()
00216 <<", # Other blocks: "<<otherBlockRefs.size()<<endl;
00217 }
00218
00219
00220
00221
00222
00223
00224 for( IBR io = otherBlockRefs.begin(); io!=otherBlockRefs.end(); ++io) {
00225 processBlock( *io, hcalBlockRefs, ecalBlockRefs );
00226 }
00227
00228
00229
00230
00231 std::list< reco::PFBlockRef > empty;
00232
00233
00234 for( IBR ih = hcalBlockRefs.begin(); ih!=hcalBlockRefs.end(); ++ih) {
00235 processBlock( *ih, empty, empty );
00236 }
00237
00238
00239 for( IBR ie = ecalBlockRefs.begin(); ie!=ecalBlockRefs.end(); ++ie) {
00240 processBlock( *ie, empty, empty );
00241 }
00242 }
00243
00244
00245 void PFAlgo::processBlock( const reco::PFBlockRef& blockref,
00246 std::list<reco::PFBlockRef>& hcalBlockRefs,
00247 std::list<reco::PFBlockRef>& ecalBlockRefs ) {
00248
00249 assert(!blockref.isNull() );
00250 const reco::PFBlock& block = *blockref;
00251
00252 typedef std::multimap<double, unsigned>::iterator IE;
00253
00254 if(debug_) {
00255 cout<<"#########################################################"<<endl;
00256 cout<<"##### Process Block: #####"<<endl;
00257 cout<<"#########################################################"<<endl;
00258 cout<<block<<endl;
00259 }
00260
00261 const edm::OwnVector< reco::PFBlockElement >& elements = block.elements();
00262
00263
00264 PFBlock::LinkData linkData = block.linkData();
00265
00266
00267 vector<bool> active( elements.size(), true );
00268
00269
00270
00271
00272 if (usePFElectrons_) {
00273 if (pfele_->isElectronValidCandidate(blockref,active)){
00274
00275 std::vector<reco::PFCandidate> PFElectCandidates_;
00276 PFElectCandidates_ = pfele_->getElectronCandidates();
00277 for ( std::vector<reco::PFCandidate>::iterator ec = PFElectCandidates_.begin();
00278 ec != PFElectCandidates_.end(); ++ec )
00279 {
00280 pfCandidates_->push_back(*ec);
00281
00282 }
00283
00284
00285 }
00286 }
00287
00288
00289
00290 if (usePFConversions_) {
00291 if (pfConversion_->isConversionValidCandidate(blockref, active )){
00292
00293 std::vector<reco::PFCandidate> PFConversionCandidates = pfConversion_->conversionCandidates();
00294
00295 for ( std::vector<reco::PFCandidate>::iterator iConv = PFConversionCandidates.begin();
00296 iConv != PFConversionCandidates.end(); ++iConv ) {
00297 pfCandidates_->push_back(*iConv);
00298 }
00299 for(unsigned iEle=0; iEle<elements.size(); iEle++) {
00300
00301 }
00302 }
00303 }
00304
00305
00306
00307 if(debug_)
00308 cout<<endl<<"--------------- loop 1 ---------------------"<<endl;
00309
00310
00311
00312
00313
00314
00315
00316
00317 vector<unsigned> hcalIs;
00318 vector<unsigned> ecalIs;
00319 vector<unsigned> trackIs;
00320
00321
00322 for(unsigned iEle=0; iEle<elements.size(); iEle++) {
00323
00324 PFBlockElement::Type type = elements[iEle].type();
00325
00326 if(debug_ && type != PFBlockElement::BREM ) cout<<endl<<elements[iEle];
00327
00328 switch( type ) {
00329 case PFBlockElement::TRACK:
00330 if ( active[iEle] ) {
00331 trackIs.push_back( iEle );
00332 if(debug_) cout<<"TRACK, stored index, continue"<<endl;
00333 }
00334 break;
00335 case PFBlockElement::ECAL:
00336 if ( active[iEle] ) {
00337 ecalIs.push_back( iEle );
00338 if(debug_) cout<<"ECAL, stored index, continue"<<endl;
00339 }
00340 continue;
00341 case PFBlockElement::HCAL:
00342 if ( active[iEle] ) {
00343 hcalIs.push_back( iEle );
00344 if(debug_) cout<<"HCAL, stored index, continue"<<endl;
00345 }
00346
00347 continue;
00348 default:
00349 continue;
00350 }
00351
00352
00353 unsigned iTrack = iEle;
00354 if(debug_) {
00355 cout<<"TRACK"<<endl;
00356 if ( !active[iTrack] ) cout << "Already used by electrons, muons, conversions" << endl;
00357 }
00358
00359
00360
00361 if ( ! active[iTrack] ) continue;
00362
00363 reco::TrackRef trackRef = elements[iTrack].trackRef();
00364 assert( !trackRef.isNull() );
00365
00366
00367
00368
00369 std::multimap<double, unsigned> ecalElems;
00370 block.associatedElements( iTrack, linkData,
00371 ecalElems ,
00372 reco::PFBlockElement::ECAL,
00373 reco::PFBlock::LINKTEST_ALL );
00374
00375 std::multimap<double, unsigned> hcalElems;
00376 block.associatedElements( iTrack, linkData,
00377 hcalElems,
00378 reco::PFBlockElement::HCAL,
00379 reco::PFBlock::LINKTEST_ALL );
00380
00381
00382 std::multimap<double,unsigned> gsfElems;
00383 if (usePFElectrons_ == false) {
00384 block.associatedElements( iTrack, linkData,
00385 gsfElems ,
00386 reco::PFBlockElement::GSF );
00387 }
00388
00389
00390 if(hcalElems.empty() && debug_) {
00391 cout<<"no hcal element connected to track "<<iTrack<<endl;
00392 }
00393
00394 typedef std::multimap<double, unsigned>::iterator IE;
00395
00396
00397
00398 bool ecalFound = false;
00399 bool hcalFound = false;
00400
00401 if(debug_)
00402 cout<<"now looping on elements associated to the track"<<endl;
00403
00404
00405
00406 double ecalEnergy = 0;
00407
00408 unsigned iEcal = 99999;
00409 bool connectedToEcal = false;
00410
00411 for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
00412
00413
00414 unsigned index = ie->second;
00415
00416 PFBlockElement::Type type = elements[index].type();
00417
00418 if(debug_) {
00419 double chi2 = block.chi2(iTrack,index,linkData,reco::PFBlock::LINKTEST_ALL);
00420 cout<<"\telement "<<elements[index]<<" linked with chi2 "<<chi2<<endl;
00421 }
00422
00423 assert( type == PFBlockElement::ECAL );
00424
00425
00426
00427 if ( ! active[index] ) break;
00428
00429 reco::PFClusterRef clusterRef = elements[index].clusterRef();
00430 assert( !clusterRef.isNull() );
00431
00432 if( !ecalFound ) {
00433
00434 if(debug_)
00435 cout<<"\t\tfirst ecal element "<<endl;
00436
00437 ecalFound = true;
00438
00439 if( hcalElems.empty() ) {
00440
00441 if(debug_) {
00442 cout<<"\t\tlocking ecal cluster"<<endl;
00443 }
00444
00445 ecalEnergy = clusterRef->energy();
00446 iEcal = index;
00447 connectedToEcal = true;
00448
00449
00450
00451
00452
00453
00454
00455 }
00456 else {
00457 if(debug_)
00458 cout<<"\t\tat least one hcal element connected to the track."
00459 <<" Sparing Ecal cluster for the hcal loop"<<endl;
00460 }
00461 }
00462 else {
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 if(debug_)
00475 cout<<"\t\tsecondary ecal element "<<endl;
00476 }
00477
00478 }
00479
00480
00481
00482
00483 if( hcalElems.empty() ) {
00484
00485 vector<unsigned> elementIndices;
00486 elementIndices.push_back(iTrack);
00487
00488
00489
00490 active[iTrack] = false;
00491
00492
00493
00494
00495
00496 unsigned tmpi = reconstructTrack( elements[iTrack] );
00497
00498 double calibEcal = ecalEnergy;
00499 double calibHcal = 0.;
00500 double slopeEcal = 1.;
00501 if ( connectedToEcal && active[iEcal] ) {
00502 if ( newCalib_ ) {
00503 clusterCalibration_->
00504 getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
00505 elements[iEcal].clusterRef()->positionREP().Eta(),
00506 elements[iEcal].clusterRef()->positionREP().Phi());
00507 if ( ecalEnergy > 0. ) slopeEcal = calibEcal/ecalEnergy;
00508 } else {
00509 slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
00510 calibEcal *= slopeEcal;
00511 }
00512 }
00513
00514 (*pfCandidates_)[tmpi].setEcalEnergy( calibEcal );
00515 (*pfCandidates_)[tmpi].setHcalEnergy( 0 );
00516 (*pfCandidates_)[tmpi].setPs1Energy( 0 );
00517 (*pfCandidates_)[tmpi].setPs2Energy( 0 );
00518 (*pfCandidates_)[tmpi].addElementInBlock( blockref, iTrack );
00519
00520
00521 if( connectedToEcal && active[iEcal] ) {
00522 reco::PFClusterRef pivotalRef = elements[iEcal].clusterRef();
00523 (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
00524
00525 std::multimap<double, unsigned> sortedTracks;
00526 block.associatedElements( iEcal, linkData,
00527 sortedTracks,
00528 reco::PFBlockElement::TRACK,
00529 reco::PFBlock::LINKTEST_ALL );
00530
00531
00532 if ( sortedTracks.begin()->second == iTrack ) {
00533 double neutralEnergy = calibEcal;
00534
00535
00536 for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
00537 unsigned jTrack = ie->second;
00538
00539
00540
00541 std::multimap<double, unsigned> sortedECAL;
00542 block.associatedElements( jTrack, linkData,
00543 sortedECAL,
00544 reco::PFBlockElement::ECAL,
00545 reco::PFBlock::LINKTEST_ALL );
00546 if ( sortedECAL.begin()->second != iEcal ) continue;
00547
00548
00549
00550 std::multimap<double, unsigned> sortedHCAL;
00551 block.associatedElements( jTrack, linkData,
00552 sortedHCAL,
00553 reco::PFBlockElement::HCAL,
00554 reco::PFBlock::LINKTEST_ALL );
00555 if ( sortedHCAL.size() ) continue;
00556
00557
00558 reco::TrackRef trackRef = elements[jTrack].trackRef();
00559 neutralEnergy -= trackRef->p();
00560
00561 }
00562
00563
00564 active[iEcal] = false;
00565 neutralEnergy /= slopeEcal;
00566 if ( neutralEnergy > 0. ) {
00567 unsigned tmpj = reconstructCluster( *pivotalRef, neutralEnergy );
00568 (*pfCandidates_)[tmpj].setEcalEnergy( neutralEnergy );
00569 (*pfCandidates_)[tmpj].setHcalEnergy( 0. );
00570 (*pfCandidates_)[tmpj].setPs1Energy( -1 );
00571 (*pfCandidates_)[tmpj].setPs2Energy( -1 );
00572 (*pfCandidates_)[tmpj].addElementInBlock(blockref, iEcal);
00573 (*pfCandidates_)[tmpj].addElementInBlock( blockref, iTrack );
00574 }
00575 }
00576 }
00577
00578
00579
00580 if (usePFElectrons_ == false) (*pfCandidates_)[tmpi].set_mva_e_pi(gsfElems.size()>0);
00581
00582
00583 }
00584
00585 for(IE ie = hcalElems.begin(); ie != hcalElems.end(); ++ie ) {
00586
00587
00588 unsigned index = ie->second;
00589
00590 PFBlockElement::Type type = elements[index].type();
00591
00592 if(debug_) {
00593 double chi2 = block.chi2(iTrack,index,linkData,reco::PFBlock::LINKTEST_ALL);
00594 cout<<"\telement "<<elements[index]<<" linked with chi2 "<<chi2<<endl;
00595 }
00596
00597 assert( type == PFBlockElement::HCAL );
00598
00599
00600
00601 if( !hcalFound ) {
00602 if(debug_)
00603 cout<<"\t\tclosest hcal cluster, doing nothing"<<endl;
00604
00605 hcalFound = true;
00606
00607
00608
00609 }
00610 else {
00611
00612 if(debug_)
00613 cout<<"\t\tsecondary hcal cluster. unlinking"<<endl;
00614
00615
00616
00617
00618
00619 block.setLink( iTrack, index, -1, -1, linkData,
00620 PFBlock::LINKTEST_CHI2 );
00621 block.setLink( iTrack, index, -1, -1, linkData,
00622 PFBlock::LINKTEST_RECHIT );
00623 }
00624 }
00625 }
00626
00627
00628
00629 if(debug_) {
00630 cout<<endl;
00631 cout<<endl<<"--------------- loop hcal ---------------------"<<endl;
00632 }
00633
00634
00635
00636
00637
00638
00639
00640 for(unsigned i=0; i<hcalIs.size(); i++) {
00641
00642 unsigned iHcal= hcalIs[i];
00643 PFBlockElement::Type type = elements[iHcal].type();
00644
00645 assert( type == PFBlockElement::HCAL );
00646
00647 if(debug_) cout<<endl<<elements[iHcal]<<endl;
00648
00649 vector<unsigned> elementIndices;
00650 elementIndices.push_back(iHcal);
00651
00652
00653 std::multimap<double, unsigned> sortedTracks;
00654 block.associatedElements( iHcal, linkData,
00655 sortedTracks,
00656 reco::PFBlockElement::TRACK,
00657 reco::PFBlock::LINKTEST_ALL );
00658
00659 std::multimap< unsigned, std::pair<double, unsigned> >
00660 associatedEcals;
00661
00662 PFClusterRef hclusterref = elements[iHcal].clusterRef();
00663 assert(!hclusterref.isNull() );
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 if( sortedTracks.empty() ) {
00674 if(debug_)
00675 cout<<"\tno associated tracks, keep for later"<<endl;
00676 continue;
00677 }
00678
00679
00680
00681
00682
00683
00684
00685 active[iHcal] = false;
00686
00687
00688
00689
00690
00691
00692 if(debug_) cout<<"\t"<<sortedTracks.size()<<" associated tracks:"<<endl;
00693
00694 double totalChargedMomentum = 0;
00695 double sumpError2 = 0.;
00696 double totalEcal = -0.0000000001;
00697 double totalHcal = hclusterref->energy();
00698 vector<double> hcalP;
00699 vector<double> hcalDP;
00700 vector<unsigned> tkIs;
00701 double maxDPovP = -9999.;
00702
00703
00704 std::vector< reco::PFRecTrackRef > associatedTracks;
00705
00706 vector< unsigned > chargedHadronsIndices;
00707 double mergedNeutralHadronEnergy = 0;
00708
00709 for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
00710
00711
00712
00713 unsigned iTrack = ie->second;
00714
00715
00716
00717 if ( !active[iTrack] ) continue;
00718
00719 PFBlockElement::Type type = elements[iTrack].type();
00720 assert( type == reco::PFBlockElement::TRACK );
00721
00722 reco::TrackRef trackRef = elements[iTrack].trackRef();
00723 assert( !trackRef.isNull() );
00724
00725 unsigned tmpi = reconstructTrack( elements[iTrack] );
00726
00727 reco::PFCandidate& currentChargedHadron = (*pfCandidates_)[tmpi];
00728
00729
00730 currentChargedHadron.addElementInBlock( blockref, iTrack );
00731 currentChargedHadron.addElementInBlock( blockref, iHcal );
00732
00733 chargedHadronsIndices.push_back( tmpi );
00734
00735
00736 if (usePFElectrons_ == false) {
00737 std::multimap<double,unsigned> gsfElems;
00738 block.associatedElements( iTrack, linkData,
00739 gsfElems ,
00740 reco::PFBlockElement::GSF );
00741 currentChargedHadron.set_mva_e_pi(gsfElems.size()>0);
00742 }
00743
00744
00745
00746
00747 associatedTracks.push_back( elements[iTrack].trackRefPF() );
00748
00749 if(debug_) cout<<"\t\t"<<elements[iTrack]<<endl;
00750
00751
00752 double trackMomentum = trackRef->p();
00753 totalChargedMomentum += trackMomentum;
00754
00755 double Dp = trackRef->qoverpError()*trackMomentum*trackMomentum;
00756 sumpError2 += Dp*Dp;
00757 hcalP.push_back(trackMomentum);
00758 hcalDP.push_back(Dp);
00759 if (Dp/trackMomentum > maxDPovP) maxDPovP = Dp/trackMomentum;
00760
00761
00762
00763 std::multimap<double, unsigned> sortedEcals;
00764 block.associatedElements( iTrack, linkData,
00765 sortedEcals,
00766 reco::PFBlockElement::ECAL,
00767 reco::PFBlock::LINKTEST_ALL );
00768
00769 if(debug_) cout<<"\t\t\tnumber of Ecal elements linked to this track: "
00770 <<sortedEcals.size()<<endl;
00771
00772 if( !sortedEcals.empty() )
00773 {
00774
00775
00776
00777
00778 for ( IE iec=sortedEcals.begin(); iec!=sortedEcals.end(); ++iec ) {
00779
00780 unsigned iEcal = iec->second;
00781
00782 std::multimap<double, unsigned> sortedTracksEcal;
00783 block.associatedElements( iEcal, linkData,
00784 sortedTracksEcal,
00785 reco::PFBlockElement::TRACK,
00786 reco::PFBlock::LINKTEST_ALL );
00787 unsigned jTrack = sortedTracksEcal.begin()->second;
00788 if ( jTrack != iTrack ) continue;
00789
00790 double chi2Ecal = block.chi2(jTrack,iEcal,linkData,reco::PFBlock::LINKTEST_ALL);
00791 if(debug_) cout<<"\t\t\tclosest: "
00792 <<elements[iEcal]<<endl;
00793
00794 if( active[iEcal] ) {
00795 PFBlockElement::Type type = elements[ iEcal ].type();
00796 assert( type == PFBlockElement::ECAL );
00797 PFClusterRef eclusterref = elements[iEcal].clusterRef();
00798 assert(!eclusterref.isNull() );
00799
00800
00801 totalEcal += eclusterref->energy();
00802
00803
00804
00805 float ecalEnergyCalibrated = eclusterref->energy();
00806 ecalEnergyCalibrated*=calibration_->paramECALplusHCAL_slopeECAL();
00807
00808 currentChargedHadron.setEcalEnergy( ecalEnergyCalibrated );
00809
00810 currentChargedHadron.addElementInBlock( blockref, iEcal );
00811
00812 std::pair<double, unsigned> associatedEcal
00813 = make_pair( chi2Ecal, iEcal );
00814 associatedEcals.insert( make_pair(iTrack, associatedEcal) );
00815 active[iEcal] = false;
00816
00817 if(debug_) cout<<"\t\t\tactive, adding "<<eclusterref->energy()
00818 <<" to ECAL energy, and locking"<<endl;
00819
00820 }
00821 else {
00822 if(debug_) cout<<"\t\tcluster locked"<<endl;
00823 }
00824 break;
00825 }
00826 }
00827
00828 }
00829
00830
00831
00832
00833 double caloEnergy = -1.;
00834 double slopeEcal = 1.0;
00835 double calibEcal = std::max(0.,totalEcal);
00836 double calibHcal = std::max(0.,totalHcal);
00837 if ( newCalib_ ) {
00838
00839
00840
00841
00842
00843 clusterCalibration_->
00844 getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
00845 hclusterref->positionREP().Eta(),
00846 hclusterref->positionREP().Phi());
00847 caloEnergy = calibEcal+calibHcal;
00848 if ( totalEcal > 0.) slopeEcal = calibEcal/totalEcal;
00849 } else {
00850 if( totalEcal>0) {
00851 caloEnergy = calibration_->energyEmHad( totalEcal, totalHcal );
00852 slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
00853 calibEcal = totalEcal * slopeEcal;
00854 } else {
00855 caloEnergy = calibration_->energyHad( totalHcal );
00856 calibEcal = totalEcal;
00857 }
00858 }
00859
00860 assert(caloEnergy>=0);
00861
00862
00863
00864
00865
00866
00867 double Caloresolution = neutralHadronEnergyResolution( totalChargedMomentum );
00868 Caloresolution *= totalChargedMomentum;
00869
00870 double TotalError = sqrt(sumpError2 + Caloresolution*Caloresolution);
00871
00872 if(debug_) {
00873
00874 cout<<"\tCompare Calo Energy to total charged momentum "<<endl;
00875 cout<<"\t\tsum p = "<<totalChargedMomentum<<" +- "<<sqrt(sumpError2)<<endl;
00876 cout<<"\t\tsum ecal = "<<totalEcal<<endl;
00877 cout<<"\t\tsum hcal = "<<totalHcal<<endl;
00878 cout<<"\t\t => Calo Energy = "<<caloEnergy<<" +- "<<Caloresolution<<endl;
00879 cout<<"\t\t => Calo Energy- total charged momentum = "
00880 <<caloEnergy-totalChargedMomentum<<" +- "<<TotalError<<endl;
00881 cout<<endl;
00882 }
00883
00884 double nsigma = nSigmaHCAL_;
00885
00886
00888
00889 if( abs(totalChargedMomentum-caloEnergy)<nsigma*TotalError ) {
00890
00891
00892
00893
00894 if(debug_) {
00895 cout<<"\t\tcase 1: COMPATIBLE "
00896 <<"|Calo Energy- total charged momentum| = "
00897 <<abs(caloEnergy-totalChargedMomentum)
00898 <<" < "<<nsigma<<" x "<<TotalError<<endl;
00899 if (maxDPovP < 0.1 )
00900 cout<<"\t\t\tmax DP/P = "<< maxDPovP
00901 <<" less than 0.1: do nothing "<<endl;
00902 else
00903 cout<<"\t\t\tmax DP/P = "<< maxDPovP
00904 <<" > 0.1: take weighted averages "<<endl;
00905 }
00906
00907
00908 if (maxDPovP > 0.1) {
00909
00910
00911
00912 int nrows = chargedHadronsIndices.size();
00913 TMatrixTSym<double> a (nrows);
00914 TVectorD b (nrows);
00915 TVectorD check(nrows);
00916 double sigma2E = Caloresolution*Caloresolution;
00917 for(int i=0; i<nrows; i++) {
00918 double sigma2i = hcalDP[i]*hcalDP[i];
00919 if (debug_){
00920 cout<<"\t\t\ttrack associated to hcal "<<i
00921 <<" P = "<<hcalP[i]<<" +- "
00922 <<hcalDP[i]<<endl;
00923 }
00924 a(i,i) = 1./sigma2i + 1./sigma2E;
00925 b(i) = hcalP[i]/sigma2i + caloEnergy/sigma2E;
00926 for(int j=0; j<nrows; j++) {
00927 if (i==j) continue;
00928 a(i,j) = 1./sigma2E;
00929 }
00930 }
00931
00932
00933
00934
00935
00936
00937
00938
00939 TDecompChol decomp(a);
00940 bool ok = false;
00941 TVectorD x = decomp.Solve(b, ok);
00942
00943
00944 if (ok) {
00945 for (int i=0; i<nrows; i++){
00946
00947 unsigned ich = chargedHadronsIndices[i];
00948 double rescaleFactor = x(i)/hcalP[i];
00949 (*pfCandidates_)[ich].rescaleMomentum( rescaleFactor );
00950
00951 if(debug_){
00952 cout<<"\t\t\told p "<<hcalP[i]
00953 <<" new p "<<x(i)
00954 <<" rescale "<<rescaleFactor<<endl;
00955 }
00956 }
00957 }
00958 else {
00959 cerr<<"not ok!"<<endl;
00960 assert(0);
00961 }
00962 }
00963 }
00964
00966 else if( caloEnergy > totalChargedMomentum ) {
00967
00968
00969
00970
00971
00972 double eNeutralHadron = caloEnergy - totalChargedMomentum;
00973 double ePhoton = (caloEnergy - totalChargedMomentum) / slopeEcal;
00974
00975 if(debug_) {
00976 if(!sortedTracks.empty() ){
00977 cout<<"\t\tcase 2: NEUTRAL DETECTION "
00978 <<caloEnergy<<" > "<<nsigma<<"x"<<TotalError
00979 <<" + "<<totalChargedMomentum<<endl;
00980 cout<<"\t\tneutral activity detected: "<<endl
00981 <<"\t\t\t photon = "<<ePhoton<<endl
00982 <<"\t\t\tor neutral hadron = "<<eNeutralHadron<<endl;
00983
00984 cout<<"\t\tphoton or hadron ?"<<endl;}
00985
00986 if(sortedTracks.empty() )
00987 cout<<"\t\tno track -> hadron "<<endl;
00988 else
00989 cout<<"\t\t"<<sortedTracks.size()
00990 <<"tracks -> loop and compute mva"<<endl;
00991 }
00992
00993
00994 reco::PFClusterRef maxMvaEcalRef;
00995 reco::PFClusterRef maxPSClusterRef;
00996 double maxMva = -PFCandidate::bigMva_;
00997 bool PSsignature = false;
00998 unsigned maxMvaiEcal= 9999;
00999 unsigned maxPSiEcal= 9999;
01000
01001
01002 for(IE ie = sortedTracks.begin(); ie != sortedTracks.end(); ++ie ) {
01003
01004 unsigned iTrack = ie->second;
01005
01006 PFBlockElement::Type type = elements[iTrack].type();
01007 assert( type == reco::PFBlockElement::TRACK );
01008
01009 reco::TrackRef trackRef = elements[iTrack].trackRef();
01010 assert( !trackRef.isNull() );
01011
01012 std::multimap< unsigned, std::pair<double, unsigned> >::iterator
01013 iae = associatedEcals.find(iTrack);
01014
01015 if( iae == associatedEcals.end() ) continue;
01016
01017 double chi2ECAL = iae->second.first;
01018 unsigned iEcal = iae->second.second;
01019
01020 PFBlockElement::Type typeEcal = elements[iEcal].type();
01021 assert(typeEcal == reco::PFBlockElement::ECAL);
01022
01023 reco::PFClusterRef clusterRef = elements[iEcal].clusterRef();
01024 assert( !clusterRef.isNull() );
01025
01026 chi2ECAL_ = static_cast<float>( chi2ECAL );
01027 ptTrack_ = static_cast<float>( trackRef->pt() );
01028
01029 float pTrack = static_cast<float>( trackRef->p() );
01030 float eECAL = static_cast<float>( clusterRef->energy() );
01031 eECALOverpTrack_ = eECAL / pTrack;
01032
01033 double value = -PFAlgo::maxMvaCut_;
01034 if(mvaCut_ < PFAlgo::maxMvaCut_ ) {
01035 value = mergedPhotonsMVA_->EvaluateMVA( "MVA" );
01036 if( value>maxMva ) {
01037 maxMva = value;
01038 maxMvaEcalRef = clusterRef;
01039 maxMvaiEcal = iEcal;
01040 }
01041 }
01042
01043 if(debug_) {
01044 cout<<"\t\t"<<elements[iTrack]<<endl;
01045 cout<<"\t\t\tassociated ECAL "<<elements[iEcal]<<endl;
01046 cout<<"\t\t\tmva evaluation : "<<endl;
01047 cout<<"\t\t\t\teECALOverpTrack = "<<eECALOverpTrack_<<endl;
01048 cout<<"\t\t\t\tptTrack = "<<ptTrack_<<endl;
01049 cout<<"\t\t\t\tchi2ECAL = "<<chi2ECAL_<<endl;
01050 cout<<"\t\t\t ==> mva = "<<value<<endl;
01051
01052 }
01053
01054 bool PS1found = false;
01055 double PS1energy = -1.;
01056 std::multimap<double, unsigned> sortedPS1;
01057 block.associatedElements( iEcal, linkData,
01058 sortedPS1,
01059 reco::PFBlockElement::PS1 );
01060
01061 if(debug_) cout<<"\t\t\tnumber of PS1 elements linked to this ecal: "
01062 <<sortedPS1.size()<<endl;
01063
01064 if( !sortedPS1.empty() )
01065 {
01066
01067 unsigned iPS1 = sortedPS1.begin()->second;
01068 if(debug_) cout<<"\t\t\tclosest: "
01069 <<elements[iPS1]<<endl;
01070
01071 PFBlockElement::Type type = elements[ iPS1 ].type();
01072 assert( type == PFBlockElement::PS1 );
01073 PFClusterRef PSclusterref = elements[iPS1].clusterRef();
01074 assert(!PSclusterref.isNull() );
01075
01076 PS1energy = PSclusterref->energy();
01077 if (PS1energy > PSCut_) PS1found = true;
01078 }
01079
01080
01081 bool PS2found = false;
01082 double PS2energy = -1.;
01083 std::multimap<double, unsigned> sortedPS2;
01084 block.associatedElements( iEcal, linkData,
01085 sortedPS2,
01086 reco::PFBlockElement::PS2 );
01087
01088 if(debug_) cout<<"\t\t\tnumber of PS2 elements linked to this ecal: "
01089 <<sortedPS2.size()<<endl;
01090
01091 if( !sortedPS2.empty() )
01092 {
01093
01094 unsigned iPS2 = sortedPS2.begin()->second;
01095 if(debug_) cout<<"\t\t\tclosest: "
01096 <<elements[iPS2]<<endl;
01097
01098 PFBlockElement::Type type = elements[ iPS2 ].type();
01099 assert( type == PFBlockElement::PS2 );
01100 PFClusterRef PSclusterref = elements[iPS2].clusterRef();
01101 assert(!PSclusterref.isNull() );
01102
01103 PS2energy = PSclusterref->energy();
01104 if (PS2energy > PSCut_) PS2found = true;
01105
01106 }
01107
01108
01109
01110 if (PSsignature) continue;
01111
01112 PSsignature = PS1found||PS2found;
01113 maxPSClusterRef = clusterRef;
01114 maxPSiEcal = iEcal;
01115 if (debug_) {
01116 cout<<" PS signature "<<PSsignature
01117 <<" PS1 energy "<<PS1energy
01118 <<" PS2 energy "<<PS2energy<<endl;
01119 }
01120
01121 }
01122
01123 std::vector<reco::PFClusterRef> pivotalClusterRef;
01124 std::vector<unsigned> iPivotal;
01125 std::vector<double> particleEnergy, ecalEnergy, hcalEnergy;
01126 vector<unsigned> elementIndices;
01127
01128
01129
01130
01131
01132 if( !maxPSClusterRef.isNull() &&
01133
01134
01135
01136 PSsignature) {
01137 if(debug_) {
01138 cout<<" PS signature is true"
01139 <<", reconstruct a photon"<<endl;
01140 }
01141 particleEnergy.push_back(ePhoton);
01142 ecalEnergy.push_back(ePhoton);
01143 hcalEnergy.push_back(0.);
01144 pivotalClusterRef.push_back(maxPSClusterRef);
01145 iPivotal.push_back(maxPSiEcal);
01146 }
01147 else {
01148 if( !maxMvaEcalRef.isNull() &&
01149 maxMva > mvaCut_) {
01150
01151 if ( ePhoton < totalEcal || eNeutralHadron-calibEcal < 1E-10 ) {
01152 if(debug_) {
01153 cout<<"\t\tmaxMva = "<<maxMva<<">"<< mvaCut_
01154 <<", reconstruct a photon"<<endl;
01155
01156 }
01157
01158
01159
01160
01161
01162 pivotalClusterRef.push_back(maxMvaEcalRef);
01163 particleEnergy.push_back(ePhoton);
01164 ecalEnergy.push_back(ePhoton);
01165 hcalEnergy.push_back(0.);
01166 iPivotal.push_back(maxMvaiEcal);
01167
01168 } else {
01169
01170
01171 pivotalClusterRef.push_back(maxMvaEcalRef);
01172 particleEnergy.push_back(totalEcal);
01173 ecalEnergy.push_back(totalEcal);
01174 hcalEnergy.push_back(0.);
01175 iPivotal.push_back(maxMvaiEcal);
01176
01177
01178 pivotalClusterRef.push_back(hclusterref);
01179 particleEnergy.push_back(eNeutralHadron-calibEcal);
01180 ecalEnergy.push_back(0.);
01181 hcalEnergy.push_back(eNeutralHadron-calibEcal);
01182 iPivotal.push_back(iHcal);
01183
01184 mergedNeutralHadronEnergy = eNeutralHadron-calibEcal;
01185
01186 }
01187
01188 }
01189 else {
01190 if(debug_) {
01191 cout<<"\t\treconstruct a hadron"<<endl;
01192 }
01193
01194
01195 if ( ePhoton < totalEcal || eNeutralHadron-calibEcal <= 1E-10 ) {
01196
01197 pivotalClusterRef.push_back(maxMvaEcalRef);
01198 particleEnergy.push_back(ePhoton);
01199 ecalEnergy.push_back(ePhoton);
01200 hcalEnergy.push_back(0.);
01201 iPivotal.push_back(maxMvaiEcal);
01202
01203 } else {
01204
01205
01206 if ( totalEcal > 0. ) {
01207 pivotalClusterRef.push_back(maxMvaEcalRef);
01208 particleEnergy.push_back(totalEcal);
01209 ecalEnergy.push_back(totalEcal);
01210 hcalEnergy.push_back(0.);
01211 iPivotal.push_back(maxMvaiEcal);
01212 }
01213
01214
01215 pivotalClusterRef.push_back(hclusterref);
01216 particleEnergy.push_back(eNeutralHadron-calibEcal);
01217 ecalEnergy.push_back(0.);
01218 hcalEnergy.push_back(eNeutralHadron-calibEcal);
01219 iPivotal.push_back(iHcal);
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230 mergedNeutralHadronEnergy = eNeutralHadron-calibEcal;
01231 }
01232 }
01233 }
01234
01235
01236
01237
01238
01239
01240 for ( unsigned iPivot=0; iPivot<iPivotal.size(); ++iPivot ) {
01241
01242 if ( particleEnergy[iPivot] < 0. )
01243 std::cout << "ALARM = Negative energy ! "
01244 << particleEnergy[iPivot] << std::endl;
01245
01246 unsigned tmpi = reconstructCluster( *pivotalClusterRef[iPivot],
01247 particleEnergy[iPivot] );
01248
01249 (*pfCandidates_)[tmpi].setEcalEnergy( ecalEnergy[iPivot] );
01250 (*pfCandidates_)[tmpi].setHcalEnergy( hcalEnergy[iPivot] );
01251 (*pfCandidates_)[tmpi].setPs1Energy( -1 );
01252 (*pfCandidates_)[tmpi].setPs2Energy( -1 );
01253 (*pfCandidates_)[tmpi].set_mva_nothing_gamma( maxMva );
01254
01255 (*pfCandidates_)[tmpi].addElementInBlock(blockref, iPivotal[iPivot]);
01256
01257
01258 }
01259
01260 }
01261
01263
01264 else if(clusterRecovery_) {
01265
01266
01267 if(debug_) {
01268 cout<<"\t\tcase 3: CLUSTER RECOVERY "
01269 <<caloEnergy<<" < "
01270 <<totalChargedMomentum<<" - "<<nsigma
01271 <<" x "<<TotalError<<endl;
01272 }
01273
01274 bool investigateOtherBlocks = false;
01275
01276
01277
01278
01279 if( recoveringClusters( totalChargedMomentum,
01280 totalEcal,
01281 totalHcal,
01282 associatedTracks,
01283 blockref,
01284 active ) == KEEP_SEARCHING ){
01285
01286 if( debug_ ){
01287 cout<<"\t\t\tNo satellite cluster found in current block."<<endl;
01288 }
01289 investigateOtherBlocks = true;
01290 }
01291
01292
01293
01294 if( investigateOtherBlocks ){
01295
01296 if( debug_ )
01297 cout<<"\t\t\tInvestigating other blocks now "<<endl;
01298
01299
01300 for( IBR ih = hcalBlockRefs.begin();
01301 ih!=hcalBlockRefs.end();) {
01302
01303 vector<bool> active;
01304 active.push_back(true);
01305 RecoveryStatus recovery =
01306 recoveringClusters( totalChargedMomentum,
01307 totalEcal,
01308 totalHcal,
01309 associatedTracks,
01310 *ih,
01311 active );
01312
01313 if( recovery == DONE ){
01314 if( debug_ )
01315 cout<<"Cluster Recovery is done, stop here"<<endl;
01316 break;
01317 }
01318
01319 if( !active[0] ) {
01320
01321
01322
01323
01324
01325 ih = hcalBlockRefs.erase( ih );
01326 }
01327 else ++ih;
01328
01329
01330 }
01331 }
01332
01333
01334
01335 double slopeEcal = 1.0;
01336 double calibEcal = std::max(0.,totalEcal);
01337 double calibHcal = std::max(0.,totalHcal);
01338 if ( newCalib_ ) {
01339 clusterCalibration_->
01340 getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
01341 hclusterref->positionREP().Eta(),
01342 hclusterref->positionREP().Phi());
01343 caloEnergy = calibEcal+calibHcal;
01344 if ( totalEcal > 0. ) slopeEcal = calibEcal/totalEcal;
01345 } else {
01346 if( totalEcal>0) {
01347 caloEnergy = calibration_->energyEmHad( totalEcal, totalHcal );
01348 slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
01349 calibEcal = totalEcal * slopeEcal;
01350 calibHcal = caloEnergy - calibEcal;
01351 } else {
01352 caloEnergy = calibration_->energyHad( totalHcal );
01353 calibEcal = totalEcal;
01354 calibHcal = caloEnergy - calibEcal;
01355 }
01356 }
01357
01358 }
01359
01360
01361
01362
01363 double totalHcalEnergyCalibrated = calibHcal;
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374 totalHcalEnergyCalibrated -= mergedNeutralHadronEnergy;
01375
01376
01377
01378
01379
01380 double chargedHadronsTotalEnergy = 0;
01381 for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
01382 unsigned index = chargedHadronsIndices[ich];
01383 reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
01384 chargedHadronsTotalEnergy += chargedHadron.energy();
01385 }
01386
01387 for( unsigned ich=0; ich<chargedHadronsIndices.size(); ++ich ) {
01388 unsigned index = chargedHadronsIndices[ich];
01389 reco::PFCandidate& chargedHadron = (*pfCandidates_)[index];
01390 float fraction = chargedHadron.energy()/chargedHadronsTotalEnergy;
01391 chargedHadron.setHcalEnergy( fraction * totalHcalEnergyCalibrated );
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405 }
01406
01407 }
01408
01409
01410
01411 if(debug_) {
01412 cout<<endl;
01413 if(debug_)
01414 cout<<endl
01415 <<"---- loop remaining hcal ------- "<<endl;
01416 }
01417
01418
01419 for(unsigned ihcluster=0; ihcluster<hcalIs.size(); ihcluster++) {
01420 unsigned iHcal = hcalIs[ihcluster];
01421
01422 if(debug_)
01423 cout<<endl<<elements[iHcal]<<" ";
01424
01425
01426 if( !active[iHcal] ) {
01427 if(debug_)
01428 cout<<"not active"<<endl;
01429 continue;
01430 }
01431
01432
01433 std::multimap<double, unsigned> ecalElems;
01434 block.associatedElements( iHcal, linkData,
01435 ecalElems ,
01436 reco::PFBlockElement::ECAL,
01437 reco::PFBlock::LINKTEST_ALL );
01438
01439
01440 float totalEcal = 0.;
01441 for(IE ie = ecalElems.begin(); ie != ecalElems.end(); ++ie ) {
01442
01443 unsigned iEcal = ie->second;
01444 double dist = ie->first;
01445 double chi2 = block.chi2(iHcal,iEcal,linkData,reco::PFBlock::LINKTEST_ALL);
01446 PFBlockElement::Type type = elements[iEcal].type();
01447 assert( type == PFBlockElement::ECAL );
01448
01449
01450 if( !active[iEcal] ) continue;
01451
01452
01453 if ( chi2 > 10. ) continue;
01454
01455
01456 if ( dist > 0.06 ) continue;
01457
01458 if(debug_) {
01459 cout<<"\telement "<<elements[iEcal]<<" linked with chi2/dist "<<chi2<<" / " << dist<<endl;
01460 cout<<"Added to HCAL cluster to form a neutral hadron"<<endl;
01461 }
01462
01463 reco::PFClusterRef eclusterRef = elements[iEcal].clusterRef();
01464 assert( !eclusterRef.isNull() );
01465
01466 totalEcal += eclusterRef->energy();
01467
01468 active[iEcal] = false;
01469
01470 }
01471
01472
01473 PFClusterRef hclusterRef
01474 = elements[iHcal].clusterRef();
01475 assert( !hclusterRef.isNull() );
01476
01477
01478 double totalHcal = hclusterRef->energy();
01479
01480 double caloEnergy = totalHcal;
01481 double slopeEcal = 1.0;
01482 double calibEcal = totalEcal > 0. ? totalEcal : 0.;
01483 double calibHcal = std::max(0.,totalHcal);
01484 if ( newCalib_ ) {
01485 clusterCalibration_->
01486 getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal,
01487 hclusterRef->positionREP().Eta(),
01488 hclusterRef->positionREP().Phi());
01489 if ( calibEcal == 0. ) calibEcal = totalEcal;
01490 if ( calibHcal == 0. ) calibHcal = totalHcal;
01491 caloEnergy = calibEcal+calibHcal;
01492 if ( totalEcal > 0. ) slopeEcal = calibEcal/totalEcal;
01493 } else {
01494 if( totalEcal>0) {
01495 caloEnergy = calibration_->energyEmHad( totalEcal, totalHcal );
01496 slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
01497 calibEcal = totalEcal * slopeEcal;
01498 calibHcal = caloEnergy - calibEcal;
01499 } else if ( hclusterRef->layer() != PFLayer::HCAL_HF ) {
01500 caloEnergy = calibration_->energyHad( totalHcal );
01501 calibEcal = totalEcal;
01502 calibHcal = caloEnergy;
01503 }
01504 }
01505
01506
01507
01508
01509 double particleEnergy = totalEcal + calibHcal;
01510
01511
01512 unsigned tmpi = reconstructCluster( *hclusterRef,
01513 particleEnergy );
01514
01515
01516 (*pfCandidates_)[tmpi].setEcalEnergy( totalEcal );
01517 (*pfCandidates_)[tmpi].setHcalEnergy( calibHcal );
01518 (*pfCandidates_)[tmpi].setPs1Energy( -1 );
01519 (*pfCandidates_)[tmpi].setPs2Energy( -1 );
01520 (*pfCandidates_)[tmpi].addElementInBlock( blockref, iHcal );
01521
01522 }
01523
01524
01525
01526
01527 if(debug_) {
01528 cout<<endl;
01529 if(debug_) cout<<endl<<"---- loop ecal------- "<<endl;
01530 }
01531
01532
01533
01534 for(unsigned i=0; i<ecalIs.size(); i++) {
01535 unsigned iEcal = ecalIs[i];
01536
01537 if(debug_)
01538 cout<<endl<<elements[iEcal]<<" ";
01539
01540 if( ! active[iEcal] ) {
01541 if(debug_)
01542 cout<<"not active"<<endl;
01543 continue;
01544 }
01545
01546 PFBlockElement::Type type = elements[ iEcal ].type();
01547 assert( type == PFBlockElement::ECAL );
01548
01549 PFClusterRef clusterref = elements[iEcal].clusterRef();
01550 assert(!clusterref.isNull() );
01551
01552 active[iEcal] = false;
01553
01554 float ecalEnergy = calibration_->energyEm( clusterref->energy() );
01555 double particleEnergy = ecalEnergy;
01556
01557 unsigned tmpi = reconstructCluster( *clusterref,
01558 particleEnergy );
01559
01560 (*pfCandidates_)[tmpi].setEcalEnergy( ecalEnergy );
01561 (*pfCandidates_)[tmpi].setHcalEnergy( 0 );
01562 (*pfCandidates_)[tmpi].setPs1Energy( -1 );
01563 (*pfCandidates_)[tmpi].setPs2Energy( -1 );
01564 (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEcal );
01565
01566
01567 }
01568
01569
01570 }
01571
01572
01573
01574
01575
01576
01577
01578 unsigned PFAlgo::reconstructTrack( const reco::PFBlockElement& elt ) {
01579
01580 const reco::PFBlockElementTrack* eltTrack
01581 = dynamic_cast<const reco::PFBlockElementTrack*>(&elt);
01582
01583 reco::TrackRef trackRef = eltTrack->trackRef();
01584 const reco::Track& track = *trackRef;
01585
01586 reco::MuonRef muonRef = eltTrack->muonRef();
01587
01588 int charge = track.charge()>0 ? 1 : -1;
01589
01590 double px = track.px();
01591 double py = track.py();
01592 double pz = track.pz();
01593 double energy = track.p();
01594
01595 if( muonRef.isNonnull() ) {
01596
01597 px = muonRef->px();
01598 py = muonRef->py();
01599 pz = muonRef->pz();
01600 energy = muonRef->energy();
01601
01602 }
01603
01604 math::XYZTLorentzVector momentum(px,py,pz,energy);
01605
01606 reco::PFCandidate::ParticleType particleType
01607 = reco::PFCandidate::h;
01608
01609 pfCandidates_->push_back( PFCandidate( charge,
01610 momentum,
01611 particleType ) );
01612
01613 pfCandidates_->back().setVertex( track.vertex() );
01614 pfCandidates_->back().setTrackRef( trackRef );
01615 pfCandidates_->back().setPositionAtECALEntrance( eltTrack->positionAtECALEntrance());
01616
01617
01618
01619 if (muonRef.isNonnull()) {
01620 pfCandidates_->back().setMuonRef( muonRef );
01621
01622
01623 if (muonRef->isGlobalMuon() ) {
01624 particleType = reco::PFCandidate::mu;
01625 pfCandidates_->back().setParticleType( particleType );
01626 if (debug_) cout << "PFAlgo: particle type set to muon" << endl;
01627 }
01628 }
01629
01630
01631 if( particleType != reco::PFCandidate::mu )
01632 if( eltTrack->trackType(reco::PFBlockElement::T_FROM_NUCL)) {
01633 pfCandidates_->back().setFlag( reco::PFCandidate::T_FROM_NUCLINT, true);
01634 pfCandidates_->back().setNuclearRef( eltTrack->nuclearRef() );
01635 }
01636 else if( eltTrack->trackType(reco::PFBlockElement::T_TO_NUCL)) {
01637 pfCandidates_->back().setFlag( reco::PFCandidate::T_TO_NUCLINT, true);
01638 pfCandidates_->back().setNuclearRef( eltTrack->nuclearRef() );
01639 }
01640
01641
01642
01643 if(debug_)
01644 cout<<"** candidate: "<<pfCandidates_->back()<<endl;
01645
01646
01647 return pfCandidates_->size()-1;
01648 }
01649
01650
01651
01652
01653
01654 unsigned PFAlgo::reconstructCluster(const reco::PFCluster& cluster,
01655 double particleEnergy) {
01656
01657 reco::PFCandidate::ParticleType particleType = reco::PFCandidate::X;
01658
01659
01660
01661 ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D<double> , ROOT::Math::DefaultCoordinateSystemTag > clusterPos( cluster.position().X(), cluster.position().Y(),cluster.position().Z() );
01662
01663
01664 clusterPos = clusterPos.Unit();
01665 clusterPos *= particleEnergy;
01666
01667
01668
01669
01670 double mass = 0;
01671 switch( cluster.layer() ) {
01672 case PFLayer::ECAL_BARREL:
01673 case PFLayer::ECAL_ENDCAP:
01674 particleType = PFCandidate::gamma;
01675 break;
01676 case PFLayer::HCAL_BARREL1:
01677 case PFLayer::HCAL_ENDCAP:
01678 particleType = PFCandidate::h0;
01679 break;
01680 case PFLayer::HCAL_HF:
01681 particleType = PFCandidate::h_HF;
01682 break;
01683 default:
01684 assert(0);
01685 }
01686
01687
01688 ROOT::Math::LorentzVector<ROOT::Math::PxPyPzM4D<double> >
01689 momentum( clusterPos.X(), clusterPos.Y(), clusterPos.Z(), mass);
01690
01691 int charge = 0;
01692
01693
01694 math::XYZTLorentzVector tmp;
01695
01696
01697 tmp = momentum;
01698
01699 pfCandidates_->push_back( PFCandidate( charge,
01700 tmp,
01701 particleType ) );
01702
01703 if(debug_)
01704 cout<<"** candidate: "<<pfCandidates_->back()<<endl;
01705
01706
01707 return pfCandidates_->size()-1;
01708
01709 }
01710
01711
01712
01713
01714 double PFAlgo::neutralHadronEnergyResolution( double clusterEnergyHCAL )
01715 const {
01716
01717
01718 return newCalib_ ?
01719 1.40/sqrt(clusterEnergyHCAL) +5.00/clusterEnergyHCAL:
01720 1.50/sqrt(clusterEnergyHCAL) +3.00/clusterEnergyHCAL;
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731 }
01732
01733
01734
01735
01736 ostream& operator<<(ostream& out, const PFAlgo& algo) {
01737 if(!out ) return out;
01738
01739 out<<"====== Particle Flow Algorithm ======= ";
01740 out<<endl;
01741 out<<"nSigmaECAL_ "<<algo.nSigmaECAL_<<endl;
01742 out<<"nSigmaHCAL_ "<<algo.nSigmaHCAL_<<endl;
01743 out<<"mvaCut_ "<<algo.mvaCut_<<endl;
01744 out<<"PSCut_ "<<algo.PSCut_<<endl;
01745 out<<endl;
01746 out<<(*(algo.calibration_))<<endl;
01747 out<<endl;
01748 out<<"reconstructed particles: "<<endl;
01749
01750 const std::auto_ptr< reco::PFCandidateCollection >&
01751 candidates = algo.pfCandidates();
01752
01753 if(!candidates.get() ) {
01754 out<<"candidates already transfered"<<endl;
01755 return out;
01756 }
01757 for(PFCandidateConstIterator ic=algo.pfCandidates_->begin();
01758 ic != algo.pfCandidates_->end(); ic++) {
01759 out<<(*ic)<<endl;
01760 }
01761
01762 return out;
01763 }
01764
01765 PFAlgo::EnergyTest
01766 PFAlgo::energyTest( double energyTrk,
01767 double energyHcal,
01768 double energyEcal,
01769 double eta,
01770 double phi,
01771 double& neutralHadron ) {
01772
01773
01774
01775
01776
01777
01778
01779 double slopeEcal = 1.0;
01780 double calibEcal = std::max(0.,energyEcal);
01781 double calibHcal = std::max(0.,energyHcal);
01782 double eCalib = -1;
01783 if ( newCalib_ ) {
01784 clusterCalibration_->
01785 getCalibratedEnergyEmbedAInHcal(calibEcal, calibHcal, eta, phi);
01786 eCalib = calibEcal+calibHcal;
01787 if ( energyEcal > 0. ) slopeEcal = calibEcal/energyEcal;
01788 } else {
01789 if( energyEcal>0) {
01790 eCalib = calibration_->energyEmHad( energyEcal, energyHcal );
01791 slopeEcal = calibration_->paramECALplusHCAL_slopeECAL();
01792 calibEcal = energyEcal * slopeEcal;
01793 calibHcal = eCalib - calibEcal;
01794 } else {
01795 eCalib = calibration_->energyHad( energyHcal );
01796 calibEcal = energyEcal;
01797 calibHcal = eCalib - calibEcal;
01798 }
01799 }
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809 assert(eCalib>=0);
01810
01811
01812
01813
01814 double reso = neutralHadronEnergyResolution( energyTrk );
01815 reso *= energyTrk;
01816
01817
01818
01822
01823
01824
01825
01826 double lowerlimit = energyTrk - nSigmaHCAL_*reso;
01827 double upperlimit = energyTrk + nSigmaHCAL_*reso;
01828
01829 if( debug_ ) {
01830 cout<<"\t\t\tEnergy test: "
01831 <<"Ecal ="<<energyEcal<<" Hcal="<<energyHcal
01832 <<" ChargedEnergy= "<<energyTrk
01833 <<" Ecalib="<<eCalib
01834 <<" Resolution="<<reso
01835 <<" Interval="
01836 <<lowerlimit<<" "
01837 <<upperlimit<<endl;
01838 }
01839
01840 if( (eCalib >= lowerlimit) &&
01841 (eCalib <= upperlimit) )
01842 return COMPATIBLE;
01843
01844 if( eCalib < lowerlimit )
01845 return NOT_ENOUGH_ENERGY;
01846
01847 if( eCalib > upperlimit ) {
01848 neutralHadron = eCalib - energyTrk - calibEcal + energyEcal;
01849 return TOO_MUCH_ENERGY;
01850 }
01851
01852 return COMPATIBLE;
01853 }
01854
01855
01856 bool PFAlgo::isSatelliteCluster( const reco::PFRecTrack& track,
01857 const PFCluster& cluster ){
01858
01859
01860
01861
01862
01863
01864
01865 bool link = false;
01866
01867 if( cluster.layer() == PFLayer::HCAL_BARREL1 ||
01868 cluster.layer() == PFLayer::HCAL_ENDCAP ) {
01869
01870 const reco::PFTrajectoryPoint& atHCAL
01871 = track.extrapolatedPoint( reco::PFTrajectoryPoint::HCALEntrance );
01872
01873 if( atHCAL.isValid() ){
01874 double tracketa = atHCAL.position().Eta();
01875 double trackphi = atHCAL.position().Phi();
01876 double hcaleta = cluster.positionREP().Eta();
01877 double hcalphi = cluster.positionREP().Phi();
01878
01879
01880 double deta = hcaleta - tracketa;
01881 double dphi = acos(cos(hcalphi - trackphi));
01882 double dr = sqrt(deta*deta + dphi*dphi);
01883
01884 if( debug_ ){
01885 cout<<"\t\t\tSatellite Test "
01886 <<tracketa<<" "<<trackphi<<" "
01887 <<hcaleta<<" "<<hcalphi<<" dr="<<dr
01888 <<endl;
01889 }
01890
01891
01892
01893
01894 if( dr < 0.17 ) link = true;
01895 }
01896
01897 }
01898
01899 return link;
01900 }
01901
01902 PFAlgo::RecoveryStatus
01903 PFAlgo::recoveringClusters( double totalChargedMomentum,
01904 double totalEcal,
01905 double& totalHcal,
01906 const std::vector< reco::PFRecTrackRef >& associatedTracks,
01907 const reco::PFBlockRef& blockref,
01908 vector<bool>& active ) {
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918 if(debug_)
01919 cout<<"\t\t\trecovering clusters"<<endl;
01920
01921
01922 const reco::PFBlock& block
01923 = *blockref;
01924 const edm::OwnVector< reco::PFBlockElement >&
01925 elements_h = block.elements();
01926
01927
01928 assert( active.size() == elements_h.size() );
01929
01930 RecoveryStatus status = KEEP_SEARCHING;
01931
01932 for(unsigned iEle=0; iEle<elements_h.size(); iEle++) {
01933
01934 PFBlockElement::Type type = elements_h[iEle].type();
01935 if( type != PFBlockElement::HCAL ) continue;
01936
01937 if(debug_)
01938 cout<<"\t\t\thcal "<<iEle<<" ";
01939
01940
01941
01942 if( !active[iEle] ) {
01943 if( debug_ ) {
01944 cout<<" not active. skip"<<endl;
01945 }
01946 continue;
01947 }
01948
01949 if( debug_ ) {
01950 cout<<" active. Is it a satellite? "<<endl;
01951 }
01952
01953
01954 const reco::PFClusterRef hclusterref
01955 = elements_h[ iEle ].clusterRef();
01956 assert( !hclusterref.isNull() );
01957
01958 const reco::PFCluster& hcal = *hclusterref;
01959
01960
01961
01962 bool tobeadded = false;
01963 for(unsigned iT=0; iT < associatedTracks.size(); ++iT) {
01964
01965 assert( !associatedTracks[iT].isNull() );
01966
01967 const reco::PFRecTrack& track_h
01968 = *associatedTracks[iT];
01969
01970 if( isSatelliteCluster( track_h,
01971 *hclusterref ) ) {
01972 if( debug_ ) {
01973 cout<<"\t\t\tsatellite of track : "<<iT<<endl;
01974 }
01975 tobeadded = true;
01976 break;
01977 }
01978 }
01979
01980
01981 if( !tobeadded ) continue;
01982
01983 totalHcal += hcal.energy();
01984 double neutralHadron = 0.;
01985 double etaH = hclusterref->positionREP().Eta();
01986 double phiH = hclusterref->positionREP().Phi();
01987 EnergyTest entest = energyTest( totalChargedMomentum,
01988 totalHcal, totalEcal,
01989 etaH, phiH,
01990 neutralHadron);
01991
01992 if( debug_ ){
01993 cout<<"\t\t\tyes, adding hcal energy ("
01994 <<hcal.energy()<<") to totHcal= "
01995 <<totalHcal
01996 <<" test="<<entest<<endl;
01997 }
01998
01999 switch( entest ) {
02000 case COMPATIBLE:
02001
02002 if( debug_ ) cout<<"\t\t\tRecoveryStop"<<endl;
02003 active[iEle]=false;
02004 status = DONE;
02005 break;
02006 case NOT_ENOUGH_ENERGY:
02007
02008 if(debug_) cout<<"\t\t\tRecoveryContinue"<<endl;
02009 active[iEle]=false;
02010 status = KEEP_SEARCHING;
02011 continue;
02012 case TOO_MUCH_ENERGY:
02013
02014
02015 unsigned tmpi = reconstructCluster( *hclusterref,
02016 neutralHadron );
02017
02018
02019
02020 (*pfCandidates_)[tmpi].setEcalEnergy( 0. );
02021 (*pfCandidates_)[tmpi].setHcalEnergy( neutralHadron );
02022 (*pfCandidates_)[tmpi].setPs1Energy( -1 );
02023 (*pfCandidates_)[tmpi].setPs2Energy( -1 );
02024 (*pfCandidates_)[tmpi].addElementInBlock( blockref, iEle );
02025
02026 active[iEle]=false;
02027 status = DONE;
02028 break;
02029 default:
02030 assert(0);
02031
02032 }
02033
02034 }
02035
02036 return status;
02037 }
02038
02039 reco::PFBlockRef
02040 PFAlgo::createBlockRef( const reco::PFBlockCollection& blocks,
02041 unsigned bi ) {
02042
02043 if( blockHandle_.isValid() ) {
02044 return reco::PFBlockRef( blockHandle_, bi );
02045 }
02046 else {
02047 return reco::PFBlockRef( &blocks, bi );
02048 }
02049 }