00001 #include "RecoEgamma/EgammaTools/interface/ConversionFinder.h"
00002 #include "DataFormats/Math/interface/deltaR.h"
00003 #include "DataFormats/GsfTrackReco/interface/GsfTrack.h"
00004 #include "DataFormats/GsfTrackReco/interface/GsfTrackFwd.h"
00005 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00006 #include "TMath.h"
00007
00008 typedef math::XYZTLorentzVector LorentzVector;
00009
00010 bool ConversionFinder::isFromConversion
00011 ( const ConversionInfo & convInfo, double maxAbsDist, double maxAbsDcot )
00012 {
00013 if ( (std::abs(convInfo.dist())<maxAbsDist) && (std::abs(convInfo.dcot())<maxAbsDcot) )
00014 return true ;
00015 return false ;
00016 }
00017
00018
00019 ConversionFinder::ConversionFinder() {}
00020
00021
00022 ConversionFinder::~ConversionFinder() {}
00023
00024
00025 ConversionInfo ConversionFinder::getConversionInfo(const reco::GsfElectron& gsfElectron,
00026 const edm::Handle<reco::TrackCollection>& ctftracks_h,
00027 const edm::Handle<reco::GsfTrackCollection>& gsftracks_h,
00028 const double bFieldAtOrigin,
00029 const double minFracSharedHits) {
00030
00031 std::vector<ConversionInfo> temp = getConversionInfos(*gsfElectron.core(),ctftracks_h,gsftracks_h,bFieldAtOrigin,minFracSharedHits) ;
00032 return findBestConversionMatch(temp);
00033
00034 }
00035
00036 ConversionInfo ConversionFinder::getConversionInfo(const reco::GsfElectronCore& gsfElectron,
00037 const edm::Handle<reco::TrackCollection>& ctftracks_h,
00038 const edm::Handle<reco::GsfTrackCollection>& gsftracks_h,
00039 const double bFieldAtOrigin,
00040 const double minFracSharedHits) {
00041
00042 std::vector<ConversionInfo> temp = getConversionInfos(gsfElectron,ctftracks_h,gsftracks_h,bFieldAtOrigin,minFracSharedHits) ;
00043 return findBestConversionMatch(temp);
00044
00045 }
00046
00047
00048
00049 std::vector<ConversionInfo> ConversionFinder::getConversionInfos(const reco::GsfElectronCore& gsfElectron,
00050 const edm::Handle<reco::TrackCollection>& ctftracks_h,
00051 const edm::Handle<reco::GsfTrackCollection>& gsftracks_h,
00052 const double bFieldAtOrigin,
00053 const double minFracSharedHits) {
00054
00055
00056
00057 using namespace reco;
00058 using namespace std;
00059 using namespace edm;
00060
00061
00062
00063 const TrackCollection *ctftracks = ctftracks_h.product();
00064 const GsfTrackCollection *gsftracks = gsftracks_h.product();
00065
00066
00067
00068 const reco::TrackRef el_ctftrack = gsfElectron.ctfTrack();
00069 const reco::GsfTrackRef el_gsftrack = gsfElectron.gsfTrack();
00070
00071
00072 if(el_ctftrack.isNonnull() && el_ctftrack.id() != ctftracks_h.id())
00073 throw cms::Exception("ConversionFinderError") << "ProductID of ctf track collection does not match ProductID of electron's CTF track! \n";
00074 if(el_gsftrack.isNonnull() && el_gsftrack.id() != gsftracks_h.id())
00075 throw cms::Exception("ConversionFinderError") << "ProductID of gsf track collection does not match ProductID of electron's GSF track! \n";
00076
00077
00078 LorentzVector el_ctftrack_p4;
00079 if(el_ctftrack.isNonnull() && gsfElectron.ctfGsfOverlap() > minFracSharedHits)
00080 el_ctftrack_p4 = LorentzVector(el_ctftrack->px(), el_ctftrack->py(), el_ctftrack->pz(), el_ctftrack->p());
00081 LorentzVector el_gsftrack_p4(el_gsftrack->px(), el_gsftrack->py(), el_gsftrack->pz(), el_gsftrack->p());
00082
00083
00084
00085 int ctfidx = -999.;
00086 int gsfidx = -999.;
00087 if(el_ctftrack.isNonnull() && gsfElectron.ctfGsfOverlap() > minFracSharedHits)
00088 ctfidx = static_cast<int>(el_ctftrack.key());
00089
00090 gsfidx = static_cast<int>(el_gsftrack.key());
00091
00092
00093
00094 vector<ConversionInfo> v_candidatePartners;
00095
00096 int ctftk_i = 0;
00097 int gsftk_i = 0;
00098
00099
00100
00101 for(TrackCollection::const_iterator ctftk = ctftracks->begin();
00102 ctftk != ctftracks->end(); ctftk++, ctftk_i++) {
00103
00104 if((ctftk_i == ctfidx))
00105 continue;
00106
00107
00108 LorentzVector ctftk_p4 = LorentzVector(ctftk->px(), ctftk->py(), ctftk->pz(), ctftk->p());
00109
00110
00111 if(ctftk->ptError()/ctftk->pt() > 0.05)
00112 continue;
00113 if(ctftk->numberOfValidHits() < 5)
00114 continue;
00115
00116 if(el_ctftrack.isNonnull() &&
00117 gsfElectron.ctfGsfOverlap() > minFracSharedHits &&
00118 fabs(ctftk_p4.Pt() - el_ctftrack->pt())/el_ctftrack->pt() < 0.2)
00119 continue;
00120
00121
00122
00123 if(el_ctftrack.isNonnull() && gsfElectron.ctfGsfOverlap() > minFracSharedHits &&
00124 deltaR(el_ctftrack_p4, ctftk_p4) < 0.5 &&
00125 (el_ctftrack->charge() + ctftk->charge() == 0) ) {
00126
00127 ConversionInfo convInfo = getConversionInfo((const reco::Track*)(el_ctftrack.get()), &(*ctftk), bFieldAtOrigin);
00128
00129
00130
00131 int deltaMissingHits = ctftk->trackerExpectedHitsInner().numberOfHits() - el_ctftrack->trackerExpectedHitsInner().numberOfHits();
00132 convInfo = ConversionInfo(convInfo.dist(),
00133 convInfo.dcot(),
00134 convInfo.radiusOfConversion(),
00135 convInfo.pointOfConversion(),
00136 TrackRef(ctftracks_h, ctftk_i),
00137 GsfTrackRef() ,
00138 deltaMissingHits,
00139 0);
00140
00141 v_candidatePartners.push_back(convInfo);
00142
00143 }
00144
00145
00146
00147 if(deltaR(el_gsftrack_p4, ctftk_p4) < 0.5 &&
00148 (el_gsftrack->charge() + ctftk->charge() == 0) &&
00149 el_gsftrack->ptError()/el_gsftrack->pt() < 0.25) {
00150
00151 int deltaMissingHits = ctftk->trackerExpectedHitsInner().numberOfHits() - el_gsftrack->trackerExpectedHitsInner().numberOfHits();
00152 ConversionInfo convInfo = getConversionInfo((const reco::Track*)(el_gsftrack.get()), &(*ctftk), bFieldAtOrigin);
00153 convInfo = ConversionInfo(convInfo.dist(),
00154 convInfo.dcot(),
00155 convInfo.radiusOfConversion(),
00156 convInfo.pointOfConversion(),
00157 TrackRef(ctftracks_h, ctftk_i),
00158 GsfTrackRef(),
00159 deltaMissingHits,
00160 1);
00161
00162 v_candidatePartners.push_back(convInfo);
00163 }
00164
00165 }
00166
00167
00168
00169 for(GsfTrackCollection::const_iterator gsftk = gsftracks->begin();
00170 gsftk != gsftracks->end(); gsftk++, gsftk_i++) {
00171
00172
00173 if(gsfidx == gsftk_i)
00174 continue;
00175
00176 LorentzVector gsftk_p4 = LorentzVector(gsftk->px(), gsftk->py(), gsftk->pz(), gsftk->p());
00177
00178
00179 if(gsftk->ptError()/gsftk->pt() > 0.5)
00180 continue;
00181 if(gsftk->numberOfValidHits() < 5)
00182 continue;
00183
00184 if(fabs(gsftk->pt() - el_gsftrack->pt())/el_gsftrack->pt() < 0.25)
00185 continue;
00186
00187
00188
00189
00190 if(el_ctftrack.isNonnull() && gsfElectron.ctfGsfOverlap() > minFracSharedHits &&
00191 deltaR(el_ctftrack_p4, gsftk_p4) < 0.5 &&
00192 (el_ctftrack->charge() + gsftk->charge() == 0)) {
00193
00194 int deltaMissingHits = gsftk->trackerExpectedHitsInner().numberOfHits() - el_ctftrack->trackerExpectedHitsInner().numberOfHits();
00195 ConversionInfo convInfo = getConversionInfo((const reco::Track*)(el_ctftrack.get()), (const reco::Track*)(&(*gsftk)), bFieldAtOrigin);
00196
00197 convInfo = ConversionInfo(convInfo.dist(),
00198 convInfo.dcot(),
00199 convInfo.radiusOfConversion(),
00200 convInfo.pointOfConversion(),
00201 TrackRef(),
00202 GsfTrackRef(gsftracks_h, gsftk_i),
00203 deltaMissingHits,
00204 2);
00205 v_candidatePartners.push_back(convInfo);
00206
00207 }
00208
00209
00210 if(deltaR(el_gsftrack_p4, gsftk_p4) < 0.5 &&
00211 (el_gsftrack->charge() + gsftk->charge() == 0) &&
00212 (el_gsftrack->ptError()/el_gsftrack_p4.pt() < 0.5)) {
00213 ConversionInfo convInfo = getConversionInfo((const reco::Track*)(el_gsftrack.get()), (const reco::Track*)(&(*gsftk)), bFieldAtOrigin);
00214
00215
00216 int deltaMissingHits = gsftk->trackerExpectedHitsInner().numberOfHits() - el_gsftrack->trackerExpectedHitsInner().numberOfHits();
00217 convInfo = ConversionInfo(convInfo.dist(),
00218 convInfo.dcot(),
00219 convInfo.radiusOfConversion(),
00220 convInfo.pointOfConversion(),
00221 TrackRef(),
00222 GsfTrackRef(gsftracks_h, gsftk_i),
00223 deltaMissingHits,
00224 3);
00225
00226 v_candidatePartners.push_back(convInfo);
00227 }
00228 }
00229
00230
00231 return v_candidatePartners;
00232
00233 }
00234
00235
00236
00237 ConversionInfo ConversionFinder::getConversionInfo(const reco::Track *el_track,
00238 const reco::Track *candPartnerTk,
00239 const double bFieldAtOrigin) {
00240
00241 using namespace reco;
00242
00243
00244 LorentzVector el_tk_p4(el_track->px(), el_track->py(), el_track->pz(), el_track->p());
00245 double elCurvature = -0.3*bFieldAtOrigin*(el_track->charge()/el_tk_p4.pt())/100.;
00246 double rEl = fabs(1./elCurvature);
00247 double xEl = -1*(1./elCurvature - el_track->d0())*sin(el_tk_p4.phi());
00248 double yEl = (1./elCurvature - el_track->d0())*cos(el_tk_p4.phi());
00249
00250
00251 LorentzVector cand_p4 = LorentzVector(candPartnerTk->px(), candPartnerTk->py(),candPartnerTk->pz(), candPartnerTk->p());
00252 double candCurvature = -0.3*bFieldAtOrigin*(candPartnerTk->charge()/cand_p4.pt())/100.;
00253 double rCand = fabs(1./candCurvature);
00254 double xCand = -1*(1./candCurvature - candPartnerTk->d0())*sin(cand_p4.phi());
00255 double yCand = (1./candCurvature - candPartnerTk->d0())*cos(cand_p4.phi());
00256
00257 double d = sqrt(pow(xEl-xCand, 2) + pow(yEl-yCand , 2));
00258 double dist = d - (rEl + rCand);
00259 double dcot = 1./tan(el_tk_p4.theta()) - 1./tan(cand_p4.theta());
00260
00261
00262 double xa1 = xEl + (xCand-xEl) * rEl/d;
00263 double xa2 = xCand + (xEl-xCand) * rCand/d;
00264 double ya1 = yEl + (yCand-yEl) * rEl/d;
00265 double ya2 = yCand + (yEl-yCand) * rCand/d;
00266
00267 double x=.5*(xa1+xa2);
00268 double y=.5*(ya1+ya2);
00269 double rconv = sqrt(pow(x,2) + pow(y,2));
00270 double z = el_track->dz() + rEl*el_track->pz()*TMath::ACos(1-pow(rconv,2)/(2.*pow(rEl,2)))/el_track->pt();
00271
00272 math::XYZPoint convPoint(x, y, z);
00273
00274
00275 float tempsign = el_track->px()*x + el_track->py()*y;
00276 tempsign = tempsign/fabs(tempsign);
00277 rconv = tempsign*rconv;
00278
00279
00280 return ConversionInfo(dist, dcot, rconv, convPoint, TrackRef(), GsfTrackRef(), -9999, -9999);
00281
00282 }
00283
00284
00285 const reco::Track* ConversionFinder::getElectronTrack(const reco::GsfElectron& electron, const float minFracSharedHits) {
00286
00287 if(electron.closestCtfTrackRef().isNonnull() &&
00288 electron.shFracInnerHits() > minFracSharedHits)
00289 return (const reco::Track*)electron.closestCtfTrackRef().get();
00290
00291 return (const reco::Track*)(electron.gsfTrack().get());
00292 }
00293
00294
00295
00296
00297
00298
00299 ConversionInfo ConversionFinder::arbitrateConversionPartnersbyR(const std::vector<ConversionInfo>& v_convCandidates) {
00300
00301 if(v_convCandidates.size() == 1)
00302 return v_convCandidates.at(0);
00303
00304 ConversionInfo arbitratedConvInfo = v_convCandidates.at(0);
00305 double R = sqrt(pow(arbitratedConvInfo.dist(),2) + pow(arbitratedConvInfo.dcot(),2));
00306
00307 for(unsigned int i = 1; i < v_convCandidates.size(); i++) {
00308 ConversionInfo temp = v_convCandidates.at(i);
00309 double temp_R = sqrt(pow(temp.dist(),2) + pow(temp.dcot(),2));
00310 if(temp_R < R) {
00311 R = temp_R;
00312 arbitratedConvInfo = temp;
00313 }
00314
00315 }
00316
00317 return arbitratedConvInfo;
00318
00319 }
00320
00321
00322 ConversionInfo ConversionFinder::findBestConversionMatch(const std::vector<ConversionInfo>& v_convCandidates)
00323 {
00324 using namespace std;
00325
00326 if(v_convCandidates.size() == 0)
00327 return ConversionInfo(-9999.,-9999.,-9999.,
00328 math::XYZPoint(-9999.,-9999.,-9999),
00329 reco::TrackRef(), reco::GsfTrackRef(),
00330 -9999, -9999);
00331
00332
00333 if(v_convCandidates.size() == 1)
00334 return v_convCandidates.at(0);
00335
00336 vector<ConversionInfo> v_0;
00337 vector<ConversionInfo> v_1;
00338 vector<ConversionInfo> v_2;
00339 vector<ConversionInfo> v_3;
00340
00341 for(unsigned int i = 1; i < v_convCandidates.size(); i++) {
00342 ConversionInfo temp = v_convCandidates.at(i);
00343
00344 if(temp.flag() == 0) {
00345 bool isConv = false;
00346 if(fabs(temp.dist()) < 0.02 &&
00347 fabs(temp.dcot()) < 0.02 &&
00348 temp.deltaMissingHits() < 3 &&
00349 temp.radiusOfConversion() > -2)
00350 isConv = true;
00351 if(sqrt(pow(temp.dist(),2) + pow(temp.dcot(),2)) < 0.05 &&
00352 temp.deltaMissingHits() < 2 &&
00353 temp.radiusOfConversion() > -2)
00354 isConv = true;
00355
00356 if(isConv)
00357 v_0.push_back(temp);
00358 }
00359
00360 if(temp.flag() == 1) {
00361
00362 if(sqrt(pow(temp.dist(),2) + pow(temp.dcot(),2)) < 0.05 &&
00363 temp.deltaMissingHits() < 2 &&
00364 temp.radiusOfConversion() > -2)
00365 v_1.push_back(temp);
00366 }
00367 if(temp.flag() == 2) {
00368
00369 if(sqrt(pow(temp.dist(),2) + pow(temp.dcot()*temp.dcot(),2)) < 0.05 &&
00370 temp.deltaMissingHits() < 2 &&
00371 temp.radiusOfConversion() > -2)
00372 v_2.push_back(temp);
00373
00374 }
00375 if(temp.flag() == 3) {
00376
00377 if(sqrt(temp.dist()*temp.dist() + temp.dcot()*temp.dcot()) < 0.05
00378 && temp.deltaMissingHits() < 2
00379 && temp.radiusOfConversion() > -2)
00380 v_3.push_back(temp);
00381
00382 }
00383
00384 }
00385
00386
00387
00388
00389
00390 if(v_0.size() > 0)
00391 return arbitrateConversionPartnersbyR(v_0);
00392
00393 if(v_1.size() > 0)
00394 return arbitrateConversionPartnersbyR(v_1);
00395
00396 if(v_2.size() > 0)
00397 return arbitrateConversionPartnersbyR(v_2);
00398
00399 if(v_3.size() > 0)
00400 return arbitrateConversionPartnersbyR(v_3);
00401
00402
00403
00404
00405
00406 return arbitrateConversionPartnersbyR(v_convCandidates);
00407
00408 }
00409
00410
00411
00412
00413
00414
00415
00416
00417 std::pair<double, double> ConversionFinder::getConversionInfo(LorentzVector trk1_p4,
00418 int trk1_q, float trk1_d0,
00419 LorentzVector trk2_p4,
00420 int trk2_q, float trk2_d0,
00421 float bFieldAtOrigin) {
00422
00423
00424 double tk1Curvature = -0.3*bFieldAtOrigin*(trk1_q/trk1_p4.pt())/100.;
00425 double rTk1 = fabs(1./tk1Curvature);
00426 double xTk1 = -1.*(1./tk1Curvature - trk1_d0)*sin(trk1_p4.phi());
00427 double yTk1 = (1./tk1Curvature - trk1_d0)*cos(trk1_p4.phi());
00428
00429
00430 double tk2Curvature = -0.3*bFieldAtOrigin*(trk2_q/trk2_p4.pt())/100.;
00431 double rTk2 = fabs(1./tk2Curvature);
00432 double xTk2 = -1.*(1./tk2Curvature - trk2_d0)*sin(trk2_p4.phi());
00433 double yTk2 = (1./tk2Curvature - trk2_d0)*cos(trk2_p4.phi());
00434
00435
00436 double dist = sqrt(pow(xTk1-xTk2, 2) + pow(yTk1-yTk2 , 2));
00437 dist = dist - (rTk1 + rTk2);
00438
00439 double dcot = 1./tan(trk1_p4.theta()) - 1./tan(trk2_p4.theta());
00440
00441 return std::make_pair(dist, dcot);
00442
00443 }
00444
00445
00446
00447 ConversionInfo ConversionFinder::getConversionInfo(const reco::GsfElectron& gsfElectron,
00448 const edm::Handle<reco::TrackCollection>& track_h,
00449 const double bFieldAtOrigin,
00450 const double minFracSharedHits) {
00451
00452
00453 using namespace reco;
00454 using namespace std;
00455 using namespace edm;
00456
00457
00458 const TrackCollection *ctftracks = track_h.product();
00459 const reco::TrackRef el_ctftrack = gsfElectron.closestCtfTrackRef();
00460 int ctfidx = -999.;
00461 int flag = -9999.;
00462 if(el_ctftrack.isNonnull() && gsfElectron.shFracInnerHits() > minFracSharedHits) {
00463 ctfidx = static_cast<int>(el_ctftrack.key());
00464 flag = 0;
00465 } else
00466 flag = 1;
00467
00468
00469
00470
00471
00472
00473
00474 const reco::Track* el_track = getElectronTrack(gsfElectron, minFracSharedHits);
00475 LorentzVector el_tk_p4(el_track->px(), el_track->py(), el_track->pz(), el_track->p());
00476
00477
00478 int tk_i = 0;
00479 double mindcot = 9999.;
00480
00481 TrackRef candCtfTrackRef = TrackRef() ;
00482
00483
00484 for(TrackCollection::const_iterator tk = ctftracks->begin();
00485 tk != ctftracks->end(); tk++, tk_i++) {
00486
00487 if((tk_i == ctfidx))
00488 continue;
00489
00490 LorentzVector tk_p4 = LorentzVector(tk->px(), tk->py(),tk->pz(), tk->p());
00491
00492
00493 double dR = deltaR(el_tk_p4, tk_p4);
00494 if(dR>0.5)
00495 continue;
00496
00497
00498
00499 if(tk->charge() + el_track->charge() != 0)
00500 continue;
00501
00502 double dcot = fabs(1./tan(tk_p4.theta()) - 1./tan(el_tk_p4.theta()));
00503 if(dcot < mindcot) {
00504 mindcot = dcot;
00505 candCtfTrackRef = reco::TrackRef(track_h, tk_i);
00506 }
00507 }
00508
00509
00510 if(!candCtfTrackRef.isNonnull())
00511 return ConversionInfo(-9999.,-9999.,-9999.,
00512 math::XYZPoint(-9999.,-9999.,-9999),
00513 reco::TrackRef(), reco::GsfTrackRef(),
00514 -9999, -9999);
00515
00516
00517
00518
00519 double elCurvature = -0.3*bFieldAtOrigin*(el_track->charge()/el_tk_p4.pt())/100.;
00520 double rEl = fabs(1./elCurvature);
00521 double xEl = -1*(1./elCurvature - el_track->d0())*sin(el_tk_p4.phi());
00522 double yEl = (1./elCurvature - el_track->d0())*cos(el_tk_p4.phi());
00523
00524
00525 LorentzVector cand_p4 = LorentzVector(candCtfTrackRef->px(), candCtfTrackRef->py(),candCtfTrackRef->pz(), candCtfTrackRef->p());
00526 double candCurvature = -0.3*bFieldAtOrigin*(candCtfTrackRef->charge()/cand_p4.pt())/100.;
00527 double rCand = fabs(1./candCurvature);
00528 double xCand = -1*(1./candCurvature - candCtfTrackRef->d0())*sin(cand_p4.phi());
00529 double yCand = (1./candCurvature - candCtfTrackRef->d0())*cos(cand_p4.phi());
00530
00531 double d = sqrt(pow(xEl-xCand, 2) + pow(yEl-yCand , 2));
00532 double dist = d - (rEl + rCand);
00533 double dcot = 1./tan(el_tk_p4.theta()) - 1./tan(cand_p4.theta());
00534
00535
00536 double xa1 = xEl + (xCand-xEl) * rEl/d;
00537 double xa2 = xCand + (xEl-xCand) * rCand/d;
00538 double ya1 = yEl + (yCand-yEl) * rEl/d;
00539 double ya2 = yCand + (yEl-yCand) * rCand/d;
00540
00541 double x=.5*(xa1+xa2);
00542 double y=.5*(ya1+ya2);
00543 double rconv = sqrt(pow(x,2) + pow(y,2));
00544 double z = el_track->dz() + rEl*el_track->pz()*TMath::ACos(1-pow(rconv,2)/(2.*pow(rEl,2)))/el_track->pt();
00545
00546 math::XYZPoint convPoint(x, y, z);
00547
00548
00549 float tempsign = el_track->px()*x + el_track->py()*y;
00550 tempsign = tempsign/fabs(tempsign);
00551 rconv = tempsign*rconv;
00552
00553 int deltaMissingHits = -9999;
00554 deltaMissingHits = candCtfTrackRef->trackerExpectedHitsInner().numberOfHits() - el_track->trackerExpectedHitsInner().numberOfHits();
00555 return ConversionInfo(dist, dcot, rconv, convPoint, candCtfTrackRef, GsfTrackRef(), deltaMissingHits, flag);
00556
00557 }
00558
00559