CMS 3D CMS Logo

ConversionProducer.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: ConversionProducer
4 // Class: ConversionProducer
5 //
13 //
14 // Original Authors: Hongliang Liu
15 // Created: Thu Mar 13 17:40:48 CDT 2008
16 //
17 //
18 
19 
20 // system include files
21 #include <memory>
22 #include <map>
23 
24 
30 
35 
38 
39 
41 
44 
48 
51 
58 
59 
60 //Kinematic constraint vertex fitter
70 
71 
72 
74  theVertexFinder_(nullptr)
75 
76 {
77  algoName_ = iConfig.getParameter<std::string>( "AlgorithmName" );
78 
79  src_ =
80  consumes<edm::View<reco::ConversionTrack> >(iConfig.getParameter<edm::InputTag>("src"));
81 
82  maxNumOfTrackInPU_ = iConfig.getParameter<int>("maxNumOfTrackInPU");
83  maxTrackRho_ = iConfig.getParameter<double>("maxTrackRho");
84  maxTrackZ_ = iConfig.getParameter<double>("maxTrackZ");
85 
86  allowTrackBC_ = iConfig.getParameter<bool>("AllowTrackBC");
87  allowD0_ = iConfig.getParameter<bool>("AllowD0");
88  allowDeltaPhi_ = iConfig.getParameter<bool>("AllowDeltaPhi");
89  allowDeltaCot_ = iConfig.getParameter<bool>("AllowDeltaCot");
90  allowMinApproach_ = iConfig.getParameter<bool>("AllowMinApproach");
91  allowOppCharge_ = iConfig.getParameter<bool>("AllowOppCharge");
92 
93  allowVertex_ = iConfig.getParameter<bool>("AllowVertex");
94 
95  bypassPreselGsf_ = iConfig.getParameter<bool>("bypassPreselGsf");
96  bypassPreselEcal_ = iConfig.getParameter<bool>("bypassPreselEcal");
97  bypassPreselEcalEcal_ = iConfig.getParameter<bool>("bypassPreselEcalEcal");
98 
99  deltaEta_ = iConfig.getParameter<double>("deltaEta");
100 
101  halfWayEta_ = iConfig.getParameter<double>("HalfwayEta");//open angle to search track matches with BC
102 
103  d0Cut_ = iConfig.getParameter<double>("d0");
104 
105  usePvtx_ = iConfig.getParameter<bool>("UsePvtx");//if use primary vertices
106 
107  vertexProducer_ =
108  consumes<reco::VertexCollection>(iConfig.getParameter<edm::InputTag>("primaryVertexProducer"));
109 
110 
111  //Track-cluster matching eta and phi cuts
112  dEtaTkBC_ = iConfig.getParameter<double>("dEtaTrackBC");//TODO research on cut endcap/barrel
113  dPhiTkBC_ = iConfig.getParameter<double>("dPhiTrackBC");
114 
116  consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("bcBarrelCollection"));
118  consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("bcEndcapCollection"));
119 
121  consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("scBarrelProducer"));
123  consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("scEndcapProducer"));
124 
125  energyBC_ = iConfig.getParameter<double>("EnergyBC");//BC energy threshold
126  energyTotalBC_ = iConfig.getParameter<double>("EnergyTotalBC");//BC energy threshold
127  minSCEt_ = iConfig.getParameter<double>("minSCEt");//super cluster energy threshold
128  dEtacutForSCmatching_ = iConfig.getParameter<double>("dEtacutForSCmatching");// dEta between conversion momentum direction and SC position
129  dPhicutForSCmatching_ = iConfig.getParameter<double>("dPhicutForSCmatching");// dPhi between conversion momentum direction and SC position
130 
131 
132 
133 
134  //Track cuts on left right track: at least one leg reaches ECAL
135  //Left track: must exist, must reach Ecal and match BC, so loose cut on Chi2 and tight on hits
136  //Right track: not necessary to exist (if allowSingleLeg_), not necessary to reach ECAL or match BC, so tight cut on Chi2 and loose on hits
137  maxChi2Left_ = iConfig.getParameter<double>("MaxChi2Left");
138  maxChi2Right_ = iConfig.getParameter<double>("MaxChi2Right");
139  minHitsLeft_ = iConfig.getParameter<int>("MinHitsLeft");
140  minHitsRight_ = iConfig.getParameter<int>("MinHitsRight");
141 
142  //Track Open angle cut on delta cot(theta) and delta phi
143  deltaCotTheta_ = iConfig.getParameter<double>("DeltaCotTheta");
144  deltaPhi_ = iConfig.getParameter<double>("DeltaPhi");
145  minApproachLow_ = iConfig.getParameter<double>("MinApproachLow");
146  minApproachHigh_ = iConfig.getParameter<double>("MinApproachHigh");
147 
148 
149  // if allow single track collection, by default False
150  allowSingleLeg_ = iConfig.getParameter<bool>("AllowSingleLeg");
151  rightBC_ = iConfig.getParameter<bool>("AllowRightBC");
152 
153  //track inner position dz cut, need RECO
154  dzCut_ = iConfig.getParameter<double>("dz");
155  //track analytical cross cut
156  r_cut = iConfig.getParameter<double>("rCut");
157  vtxChi2_ = iConfig.getParameter<double>("vtxChi2");
158 
159 
160  theVertexFinder_ = new ConversionVertexFinder ( iConfig );
161 
162  thettbuilder_ = nullptr;
163 
164  //output
165  ConvertedPhotonCollection_ = iConfig.getParameter<std::string>("convertedPhotonCollection");
166 
167  produces< reco::ConversionCollection >(ConvertedPhotonCollection_);
168 
169 }
170 
171 
173 {
174 
175  // do anything here that needs to be done at desctruction time
176  // (e.g. close files, deallocate resources etc.)
177  delete theVertexFinder_;
178 }
179 
180 
181 // ------------ method called to produce the data ------------
182 void
184 {
185  using namespace edm;
186 
187  reco::ConversionCollection outputConvPhotonCollection;
188  auto outputConvPhotonCollection_p = std::make_unique<reco::ConversionCollection>();
189 
190  //std::cout << " ConversionProducer::produce " << std::endl;
191  //Read multiple track input collections
192 
193  edm::Handle<edm::View<reco::ConversionTrack> > trackCollectionHandle;
194  iEvent.getByToken(src_,trackCollectionHandle);
195 
196  //build map of ConversionTracks ordered in eta
197  std::multimap<float, edm::Ptr<reco::ConversionTrack> > convTrackMap;
198  for(auto const& t : trackCollectionHandle->ptrs()) convTrackMap.emplace(t->track()->eta(),t);
199 
202  if (usePvtx_){
203  iEvent.getByToken(vertexProducer_, vertexHandle);
204  if (!vertexHandle.isValid()) {
205  edm::LogError("ConversionProducer")
206  << "Error! Can't get the product primary Vertex Collection "<< "\n";
207  usePvtx_ = false;
208  }
209  if (usePvtx_)
210  vertexCollection = *(vertexHandle.product());
211  }
212 
213  edm::ESHandle<TransientTrackBuilder> hTransientTrackBuilder;
214  iSetup.get<TransientTrackRecord>().get("TransientTrackBuilder",hTransientTrackBuilder);
215  thettbuilder_ = hTransientTrackBuilder.product();
216 
217  reco::Vertex the_pvtx;
218  //because the priamry vertex is sorted by quality, the first one is the best
219  if (!vertexCollection.empty())
220  the_pvtx = *(vertexCollection.begin());
221 
222  if (trackCollectionHandle->size()> maxNumOfTrackInPU_){
223  iEvent.put(std::move(outputConvPhotonCollection_p), ConvertedPhotonCollection_);
224  return;
225  }
226 
227 
228  // build Super and Basic cluster geometry map to search in eta bounds for clusters
229  std::multimap<double, reco::CaloClusterPtr> basicClusterPtrs;
230  std::multimap<double, reco::CaloClusterPtr> superClusterPtrs;
231 
232 
233  buildSuperAndBasicClusterGeoMap(iEvent,basicClusterPtrs,superClusterPtrs);
234 
235  buildCollection( iEvent, iSetup, convTrackMap, superClusterPtrs, basicClusterPtrs, the_pvtx, outputConvPhotonCollection);//allow empty basicClusterPtrs
236 
237  outputConvPhotonCollection_p->assign(outputConvPhotonCollection.begin(), outputConvPhotonCollection.end());
238  iEvent.put(std::move(outputConvPhotonCollection_p), ConvertedPhotonCollection_);
239 
240 }
241 
242 
244  std::multimap<double, reco::CaloClusterPtr>& basicClusterPtrs,
245  std::multimap<double, reco::CaloClusterPtr>& superClusterPtrs){
246 
247  // Get the Super Cluster collection in the Barrel
249  iEvent.getByToken(scBarrelProducer_,scBarrelHandle);
250  if (!scBarrelHandle.isValid()) {
251  edm::LogError("ConvertedPhotonProducer")
252  << "Error! Can't get the barrel superclusters!";
253  }
254 
255  // Get the Super Cluster collection in the Endcap
257  iEvent.getByToken(scEndcapProducer_,scEndcapHandle);
258  if (!scEndcapHandle.isValid()) {
259  edm::LogError("ConvertedPhotonProducer")
260  << "Error! Can't get the endcap superclusters!";
261  }
262 
263 
265  edm::Handle<edm::View<reco::CaloCluster> > bcEndcapHandle;//TODO check cluster type if BasicCluster or PFCluster
266 
267  iEvent.getByToken( bcBarrelCollection_, bcBarrelHandle);
268  if (!bcBarrelHandle.isValid()) {
269  edm::LogError("ConvertedPhotonProducer")
270  << "Error! Can't get the barrel basic clusters!";
271  }
272 
273  iEvent.getByToken( bcEndcapCollection_, bcEndcapHandle);
274  if (! bcEndcapHandle.isValid()) {
275  edm::LogError("ConvertedPhotonProducer")
276  << "Error! Can't get the endcap basic clusters!";
277  }
278 
279  if( bcBarrelHandle.isValid() ) {
280  for(auto const& handle : {bcBarrelHandle, bcEndcapHandle} ) {
281  for(auto const& bc : handle->ptrs()) {
282  if(bc->energy() > energyBC_) basicClusterPtrs.emplace(bc->position().eta(), bc);
283  }
284  }
285  }
286 
287  if( scBarrelHandle.isValid() ) {
288  for(auto const& handle : {scBarrelHandle, scEndcapHandle} ) {
289  for(auto const& sc : handle->ptrs()) {
290  if(sc->energy() > minSCEt_) superClusterPtrs.emplace(sc->position().eta(), sc);
291  }
292  }
293  }
294 
295 }
296 
297 
299  const std::multimap<float, edm::Ptr<reco::ConversionTrack> >& allTracks,
300  const std::multimap<double, reco::CaloClusterPtr>& superClusterPtrs,
301  const std::multimap<double, reco::CaloClusterPtr>& basicClusterPtrs,
302  const reco::Vertex& the_pvtx,
303  reco::ConversionCollection & outputConvPhotonCollection){
304 
305 
306  edm::ESHandle<TrackerGeometry> trackerGeomHandle;
307  edm::ESHandle<MagneticField> magFieldHandle;
308  iSetup.get<TrackerDigiGeometryRecord>().get( trackerGeomHandle );
309  iSetup.get<IdealMagneticFieldRecord>().get( magFieldHandle );
310 
311  const TrackerGeometry* trackerGeom = trackerGeomHandle.product();
312  const MagneticField* magField = magFieldHandle.product();
313 
314 // std::vector<math::XYZPointF> trackImpactPosition;
315 // trackImpactPosition.reserve(allTracks.size());//track impact position at ECAL
316 // std::vector<bool> trackValidECAL;//Does this track reach ECAL basic cluster (reach ECAL && match with BC)
317 // trackValidECAL.assign(allTracks.size(), false);
318 //
319 // std::vector<reco::CaloClusterPtr> trackMatchedBC;
320 // reco::CaloClusterPtr empty_bc;
321 // trackMatchedBC.assign(allTracks.size(), empty_bc);//TODO find a better way to avoid copy constructor
322 //
323 // std::vector<int> bcHandleId;//the associated BC handle id, -1 invalid, 0 barrel 1 endcap
324 // bcHandleId.assign(allTracks.size(), -1);
325 
326  // not used std::multimap<double, int> trackInnerEta;//Track innermost state Eta map to TrackRef index, to be used in track pair sorting
327 
328  std::map<edm::Ptr<reco::ConversionTrack>, math::XYZPointF> trackImpactPosition;
329  std::map<edm::Ptr<reco::ConversionTrack>, reco::CaloClusterPtr> trackMatchedBC;
330 
331  ConversionHitChecker hitChecker;
332 
333 
334  //2 propagate all tracks into ECAL, record its eta and phi
335 
336  for (std::multimap<float, edm::Ptr<reco::ConversionTrack> >::const_iterator tk_ref = allTracks.begin(); tk_ref != allTracks.end(); ++tk_ref ){
337  const reco::Track* tk = tk_ref->second->trackRef().get() ;
338 
339 
340  //check impact position then match with BC
341  math::XYZPointF ew;
342  if ( getTrackImpactPosition(tk, trackerGeom, magField, ew) ){
343  trackImpactPosition[tk_ref->second] = ew;
344 
345  reco::CaloClusterPtr closest_bc;//the closest matching BC to track
346 
347  if ( getMatchedBC(basicClusterPtrs, ew, closest_bc) ){
348  trackMatchedBC[tk_ref->second] = closest_bc;
349  }
350  }
351  }
352 
353 
354 
355  //3. pair up tracks:
356  //TODO it is k-Closest pair of point problem
357  //std::cout << " allTracks.size() " << allTracks.size() << std::endl;
358  for(std::multimap<float, edm::Ptr<reco::ConversionTrack> >::const_iterator ll = allTracks.begin(); ll != allTracks.end(); ++ll ) {
359  bool track1HighPurity=true;
360  //std::cout << " Loop on allTracks " << std::endl;
361  const edm::RefToBase<reco::Track> & left = ll->second->trackRef();
362 
363 
364  //TODO: This is a workaround, should be fixed with a proper function in the TTBuilder
365  //(Note that the TrackRef and GsfTrackRef versions of the constructor are needed
366  // to properly get refit tracks in the output vertex)
367  reco::TransientTrack ttk_l;
368  if (dynamic_cast<const reco::GsfTrack*>(left.get())) {
369  ttk_l = thettbuilder_->build(left.castTo<reco::GsfTrackRef>());
370  }
371  else {
372  ttk_l = thettbuilder_->build(left.castTo<reco::TrackRef>());
373  }
374 
376  // if ((allowTrackBC_ && !trackValidECAL[ll-allTracks.begin()]) )//this Left leg should have valid BC
377  // continue;
378 
379 
380  if (the_pvtx.isValid()){
381  if (!(trackD0Cut(left, the_pvtx))) track1HighPurity=false;
382  } else {
383  if (!(trackD0Cut(left))) track1HighPurity=false;
384  }
385 
386  std::vector<int> right_candidates;//store all right legs passed the cut (theta/approach and ref pair)
387  std::vector<double> right_candidate_theta, right_candidate_approach;
388  std::vector<std::pair<bool, reco::Vertex> > vertex_candidates;
389 
390  //inner loop only over tracks between eta and eta + deltaEta of the first track
391  float etasearch = ll->first + deltaEta_;
392  std::multimap<float, edm::Ptr<reco::ConversionTrack> >::const_iterator rr = ll;
393  ++rr;
394  for (; rr != allTracks.lower_bound(etasearch); ++rr ) {
395  bool track2HighPurity = true;
396  bool highPurityPair = true;
397 
398  const edm::RefToBase<reco::Track> & right = rr->second->trackRef();
399 
400 
401  //TODO: This is a workaround, should be fixed with a proper function in the TTBuilder
402  reco::TransientTrack ttk_r;
403  if (dynamic_cast<const reco::GsfTrack*>(right.get())) {
404  ttk_r = thettbuilder_->build(right.castTo<reco::GsfTrackRef>());
405  }
406  else {
407  ttk_r = thettbuilder_->build(right.castTo<reco::TrackRef>());
408  }
409  //std::cout << " This track is " << right->algoName() << std::endl;
410 
411 
412  //all vertexing preselection should go here
413 
414  //check for opposite charge
415  if ( allowOppCharge_ && (left->charge()*right->charge() > 0) )
416  continue; //same sign, reject pair
417 
419  //if ( (allowTrackBC_ && !trackValidECAL[rr-allTracks.begin()] && rightBC_) )// if right track matches ECAL
420  // continue;
421 
422 
423  double approachDist = -999.;
424  //apply preselection to track pair, overriding preselection for gsf+X or ecalseeded+X pairs if so configured
425  bool preselected = preselectTrackPair(ttk_l,ttk_r, approachDist);
426  preselected = preselected || (bypassPreselGsf_ && (left->algo()==reco::TrackBase::gsf || right->algo()==reco::TrackBase::gsf));
429 
430  if (!preselected) {
431  continue;
432  }
433 
434  //do the actual vertex fit
435  reco::Vertex theConversionVertex;//by default it is invalid
436  bool goodVertex = checkVertex(ttk_l, ttk_r, magField, theConversionVertex);
437 
438  //bail as early as possible in case the fit didn't return a good vertex
439  if (!goodVertex) {
440  continue;
441  }
442 
443 
444 
445  //track pair pass the quality cut
446  if ( !( (trackQualityFilter(left, true) && trackQualityFilter(right, false))
447  || (trackQualityFilter(left, false) && trackQualityFilter(right, true)) ) ) {
448  highPurityPair=false;
449  }
450 
451  if (the_pvtx.isValid()){
452  if (!(trackD0Cut(right, the_pvtx))) track2HighPurity=false;
453  } else {
454  if (!(trackD0Cut(right))) track2HighPurity=false;
455  }
456 
457 
458  //if all cuts passed, go ahead to make conversion candidates
459  std::vector<edm::RefToBase<reco::Track> > trackPairRef;
460  trackPairRef.push_back(left);//left track
461  trackPairRef.push_back(right);//right track
462 
463  std::vector<math::XYZVectorF> trackPin;
464  std::vector<math::XYZVectorF> trackPout;
465  std::vector<math::XYZPointF> trackInnPos;
466  std::vector<uint8_t> nHitsBeforeVtx;
467  std::vector<Measurement1DFloat> dlClosestHitToVtx;
468 
469  if (left->extra().isNonnull() && right->extra().isNonnull()){//only available on TrackExtra
470  trackInnPos.push_back( toFConverterP(left->innerPosition()));
471  trackInnPos.push_back( toFConverterP(right->innerPosition()));
472  trackPin.push_back(toFConverterV(left->innerMomentum()));
473  trackPin.push_back(toFConverterV(right->innerMomentum()));
474  trackPout.push_back(toFConverterV(left->outerMomentum()));
475  trackPout.push_back(toFConverterV(right->outerMomentum()));
476  auto leftWrongHits = hitChecker.nHitsBeforeVtx(*left->extra(),theConversionVertex);
477  auto rightWrongHits = hitChecker.nHitsBeforeVtx(*right->extra(),theConversionVertex);
478  nHitsBeforeVtx.push_back(leftWrongHits.first);
479  nHitsBeforeVtx.push_back(rightWrongHits.first);
480  dlClosestHitToVtx.push_back(leftWrongHits.second);
481  dlClosestHitToVtx.push_back(rightWrongHits.second);
482  }
483 
484  uint8_t nSharedHits = hitChecker.nSharedHits(*left.get(),*right.get());
485 
486 
487  //if using kinematic fit, check with chi2 post cut
488  if (theConversionVertex.isValid()){
489  const float chi2Prob = ChiSquaredProbability(theConversionVertex.chi2(), theConversionVertex.ndof());
490  if (chi2Prob<vtxChi2_) highPurityPair=false;
491  }
492 
493  //std::cout << " highPurityPair after vertex cut " << highPurityPair << std::endl;
494  std::vector<math::XYZPointF> trkPositionAtEcal;
495  std::vector<reco::CaloClusterPtr> matchingBC;
496 
497  if (allowTrackBC_){//TODO find out the BC ptrs if not doing matching, otherwise, leave it empty
498  //const int lbc_handle = bcHandleId[ll-allTracks.begin()],
499  // rbc_handle = bcHandleId[rr-allTracks.begin()];
500 
501  std::map<edm::Ptr<reco::ConversionTrack>, math::XYZPointF>::const_iterator trackImpactPositionLeft = trackImpactPosition.find(ll->second);
502  std::map<edm::Ptr<reco::ConversionTrack>, math::XYZPointF>::const_iterator trackImpactPositionRight = trackImpactPosition.find(rr->second);
503  std::map<edm::Ptr<reco::ConversionTrack>, reco::CaloClusterPtr>::const_iterator trackMatchedBCLeft = trackMatchedBC.find(ll->second);
504  std::map<edm::Ptr<reco::ConversionTrack>, reco::CaloClusterPtr>::const_iterator trackMatchedBCRight = trackMatchedBC.find(rr->second);
505 
506  if (trackImpactPositionLeft!=trackImpactPosition.end()) {
507  trkPositionAtEcal.push_back(trackImpactPositionLeft->second);//left track
508  }
509  else {
510  trkPositionAtEcal.push_back(math::XYZPointF());//left track
511  }
512  if (trackImpactPositionRight!=trackImpactPosition.end()) {//second track ECAL position may be invalid
513  trkPositionAtEcal.push_back(trackImpactPositionRight->second);
514  }
515 
516  double total_e_bc = 0.;
517  if (trackMatchedBCLeft!=trackMatchedBC.end()) {
518  matchingBC.push_back(trackMatchedBCLeft->second);//left track
519  total_e_bc += trackMatchedBCLeft->second->energy();
520  }
521  else {
522  matchingBC.push_back( reco::CaloClusterPtr() );//left track
523  }
524  if (trackMatchedBCRight!=trackMatchedBC.end()) {//second track ECAL position may be invalid
525  matchingBC.push_back(trackMatchedBCRight->second);
526  total_e_bc += trackMatchedBCRight->second->energy();
527  }
528 
529  if (total_e_bc<energyTotalBC_) {
530  highPurityPair = false;
531  }
532 
533 
534  }
535  //signature cuts, then check if vertex, then post-selection cuts
536  highPurityPair = highPurityPair && track1HighPurity && track2HighPurity && goodVertex && checkPhi(left, right, trackerGeom, magField, theConversionVertex) ;
537 
538 
540  /*
541  for ( std::vector<edm::RefToBase<reco::Track> >::iterator iTk=trackPairRef.begin(); iTk!=trackPairRef.end(); iTk++) {
542  math::XYZPointF impPos;
543  if ( getTrackImpactPosition(*iTk, trackerGeom, magField, impPos) ) {
544 
545  }
546 
547  }
548  */
549 
550  const float minAppDist = approachDist;
552  float dummy=0;
554  reco::Conversion newCandidate(scPtrVec, trackPairRef, trkPositionAtEcal, theConversionVertex, matchingBC, minAppDist, trackInnPos, trackPin, trackPout, nHitsBeforeVtx, dlClosestHitToVtx, nSharedHits, dummy, algo );
555  // Fill in scPtrVec with the macthing SC
556  if ( matchingSC ( superClusterPtrs, newCandidate, scPtrVec) )
557  newCandidate.setMatchingSuperCluster( scPtrVec);
558 
559 
560  newCandidate.setQuality(reco::Conversion::highPurity, highPurityPair);
561  bool generalTracksOnly = ll->second->isTrackerOnly() && rr->second->isTrackerOnly() && !dynamic_cast<const reco::GsfTrack*>(ll->second->trackRef().get()) && !dynamic_cast<const reco::GsfTrack*>(rr->second->trackRef().get());
562  bool gsfTracksOpenOnly = ll->second->isGsfTrackOpen() && rr->second->isGsfTrackOpen();
563  bool arbitratedEcalSeeded = ll->second->isArbitratedEcalSeeded() && rr->second->isArbitratedEcalSeeded();
564  bool arbitratedMerged = ll->second->isArbitratedMerged() && rr->second->isArbitratedMerged();
565  bool arbitratedMergedEcalGeneral = ll->second->isArbitratedMergedEcalGeneral() && rr->second->isArbitratedMergedEcalGeneral();
566 
567  newCandidate.setQuality(reco::Conversion::generalTracksOnly, generalTracksOnly);
568  newCandidate.setQuality(reco::Conversion::gsfTracksOpenOnly, gsfTracksOpenOnly);
569  newCandidate.setQuality(reco::Conversion::arbitratedEcalSeeded, arbitratedEcalSeeded);
570  newCandidate.setQuality(reco::Conversion::arbitratedMerged, arbitratedMerged);
571  newCandidate.setQuality(reco::Conversion::arbitratedMergedEcalGeneral, arbitratedMergedEcalGeneral);
572 
573  outputConvPhotonCollection.push_back(newCandidate);
574 
575  }
576 
577  }
578 
579 
580 
581 
582 
583 
584 }
585 
586 
587 
588 
589 
590 //
591 // member functions
592 //
593 
595  bool pass = true;
596  if (isLeft){
597  pass = (ref->normalizedChi2() < maxChi2Left_ && ref->found() >= minHitsLeft_);
598  } else {
599  pass = (ref->normalizedChi2() < maxChi2Right_ && ref->found() >= minHitsRight_);
600  }
601 
602  return pass;
603 }
604 
606  //NOTE if not allow d0 cut, always true
607  return ((!allowD0_) || !(ref->d0()*ref->charge()/ref->d0Error()<d0Cut_));
608 }
609 
611  //
612  return ((!allowD0_) || !(-ref->dxy(the_pvtx.position())*ref->charge()/ref->dxyError()<d0Cut_));
613 }
614 
615 
617  const TrackerGeometry* trackerGeom, const MagneticField* magField,
618  math::XYZPointF& ew){
619 
620  PropagatorWithMaterial propag( alongMomentum, 0.000511, magField );
621 
623  new BoundCylinder(129.f, GlobalPoint(0.,0.,0.), TkRotation<float>(),
624  new SimpleCylinderBounds( 129, 129, -320.5, 320.5 ) ) );
625  const float epsilon = 0.001;
626  Surface::RotationType rot; // unit rotation matrix
627  const float barrelRadius = 129.f;
628  const float barrelHalfLength = 270.9f;
629  const float endcapRadius = 171.1f;
630  const float endcapZ = 320.5f;
631  ReferenceCountingPointer<BoundCylinder> theBarrel_(new BoundCylinder(barrelRadius, Surface::PositionType(0,0,0), rot,
632  new SimpleCylinderBounds( barrelRadius-epsilon, barrelRadius+epsilon,
633 -barrelHalfLength, barrelHalfLength)));
634  ReferenceCountingPointer<BoundDisk> theNegativeEtaEndcap_(
635  new BoundDisk( Surface::PositionType( 0, 0, -endcapZ), rot,
636  new SimpleDiskBounds( 0, endcapRadius, -epsilon, epsilon)));
637  ReferenceCountingPointer<BoundDisk> thePositiveEtaEndcap_(
638  new BoundDisk( Surface::PositionType( 0, 0, endcapZ), rot,
639  new SimpleDiskBounds( 0, endcapRadius, -epsilon, epsilon)));
640 
641  //const TrajectoryStateOnSurface myTSOS = trajectoryStateTransform::innerStateOnSurface(*(*ref), *trackerGeom, magField);
642  const TrajectoryStateOnSurface myTSOS = trajectoryStateTransform::outerStateOnSurface(*tk_ref, *trackerGeom, magField);
643  TrajectoryStateOnSurface stateAtECAL;
644  stateAtECAL = propag.propagate(myTSOS, *theBarrel_);
645  if (!stateAtECAL.isValid() || ( stateAtECAL.isValid() && fabs(stateAtECAL.globalPosition().eta() ) >1.479f ) ) {
646  //endcap propagator
647  if (myTSOS.globalPosition().z() > 0.) {
648  stateAtECAL = propag.propagate(myTSOS, *thePositiveEtaEndcap_);
649  } else {
650  stateAtECAL = propag.propagate(myTSOS, *theNegativeEtaEndcap_);
651  }
652  }
653  if (stateAtECAL.isValid()){
654  ew = stateAtECAL.globalPosition();
655  return true;
656  }
657  else
658  return false;
659 }
660 
661 
662 
663 
664 bool ConversionProducer::matchingSC(const std::multimap<double, reco::CaloClusterPtr>& scMap,
665  reco::Conversion& aConv,
666  // reco::CaloClusterPtr& mSC){
668 
669  // double dRMin=999.;
670  double detaMin=999.;
671  double dphiMin=999.;
673  for (std::multimap<double, reco::CaloClusterPtr>::const_iterator scItr = scMap.begin(); scItr != scMap.end(); scItr++) {
674  const reco::CaloClusterPtr& sc = scItr->second;
675  const double delta_phi = reco::deltaPhi( aConv.refittedPairMomentum().phi(), sc->phi());
676  double sceta = sc->eta();
677  double conveta = etaTransformation(aConv.refittedPairMomentum().eta(), aConv.zOfPrimaryVertexFromTracks() );
678  const double delta_eta = fabs(conveta - sceta);
679  if ( fabs(delta_eta) < fabs(detaMin) && fabs(delta_phi) < fabs(dphiMin) ) {
680  detaMin= fabs(delta_eta);
681  dphiMin= fabs(delta_phi);
682  match=sc;
683  }
684  }
685 
686  if ( fabs(detaMin) < dEtacutForSCmatching_ && fabs(dphiMin) < dPhicutForSCmatching_ ) {
687  mSC.push_back(match);
688  return true;
689  } else
690  return false;
691 }
692 
693 bool ConversionProducer::getMatchedBC(const std::multimap<double, reco::CaloClusterPtr>& bcMap,
694  const math::XYZPointF& trackImpactPosition,
695  reco::CaloClusterPtr& closestBC){
696  const double track_eta = trackImpactPosition.eta();
697  const double track_phi = trackImpactPosition.phi();
698 
699  double min_eta = 999., min_phi = 999.;
700  reco::CaloClusterPtr closest_bc;
701  for (std::multimap<double, reco::CaloClusterPtr>::const_iterator bc = bcMap.lower_bound(track_eta - halfWayEta_);
702  bc != bcMap.upper_bound(track_eta + halfWayEta_); ++bc){//use eta map to select possible BC collection then loop in
703  const reco::CaloClusterPtr& ebc = bc->second;
704  const double delta_eta = track_eta-(ebc->position().eta());
705  const double delta_phi = reco::deltaPhi(track_phi, (ebc->position().phi()));
706  if (fabs(delta_eta)<dEtaTkBC_ && fabs(delta_phi)<dPhiTkBC_){
707  if (fabs(min_eta)>fabs(delta_eta) && fabs(min_phi)>fabs(delta_phi)){//take the closest to track BC
708  min_eta = delta_eta;
709  min_phi = delta_phi;
710  closest_bc = bc->second;
711  //TODO check if min_eta>delta_eta but min_phi<delta_phi
712  }
713  }
714  }
715 
716  if (min_eta < 999.){
717  closestBC = closest_bc;
718  return true;
719  } else
720  return false;
721 }
722 
723 
724 
725 
726 
727 
728 //check track open angle of phi at vertex
730  const TrackerGeometry* trackerGeom, const MagneticField* magField,
731  const reco::Vertex& vtx){
732  if (!allowDeltaPhi_)
733  return true;
734  //if track has innermost momentum, check with innermost phi
735  //if track also has valid vertex, propagate to vertex then calculate phi there
736  //if track has no innermost momentum, just return true, because track->phi() makes no sense
737  if (tk_l->extra().isNonnull() && tk_r->extra().isNonnull()){
738  double iphi1 = tk_l->innerMomentum().phi(), iphi2 = tk_r->innerMomentum().phi();
739  if (vtx.isValid()){
740  PropagatorWithMaterial propag( anyDirection, 0.000511, magField );
741 
742  double recoPhoR = vtx.position().Rho();
745  new SimpleCylinderBounds( recoPhoR-0.001, recoPhoR+0.001,
746  -fabs(vtx.position().z()), fabs(vtx.position().z()))));
748  new BoundDisk( Surface::PositionType( 0, 0, vtx.position().z()), rot,
749  new SimpleDiskBounds( 0, recoPhoR, -0.001, 0.001)));
750 
751  const TrajectoryStateOnSurface myTSOS1 = trajectoryStateTransform::innerStateOnSurface(*tk_l, *trackerGeom, magField);
752  const TrajectoryStateOnSurface myTSOS2 = trajectoryStateTransform::innerStateOnSurface(*tk_r, *trackerGeom, magField);
753  TrajectoryStateOnSurface stateAtVtx1, stateAtVtx2;
754  stateAtVtx1 = propag.propagate(myTSOS1, *theBarrel_);
755  if (!stateAtVtx1.isValid() ) {
756  stateAtVtx1 = propag.propagate(myTSOS1, *theDisk_);
757  }
758  if (stateAtVtx1.isValid()){
759  iphi1 = stateAtVtx1.globalDirection().phi();
760  }
761  stateAtVtx2 = propag.propagate(myTSOS2, *theBarrel_);
762  if (!stateAtVtx2.isValid() ) {
763  stateAtVtx2 = propag.propagate(myTSOS2, *theDisk_);
764  }
765  if (stateAtVtx2.isValid()){
766  iphi2 = stateAtVtx2.globalDirection().phi();
767  }
768  }
769  const double dPhi = reco::deltaPhi(iphi1, iphi2);
770  return (fabs(dPhi) < deltaPhi_);
771  } else {
772  return true;
773  }
774 }
775 
777  double& appDist) {
778 
779 
780  double dCotTheta = 1./tan(ttk_l.track().innerMomentum().theta()) - 1./tan(ttk_r.track().innerMomentum().theta());
781  if (allowDeltaCot_ && (std::abs(dCotTheta) > deltaCotTheta_)) {
782  return false;
783  }
784 
785  //non-conversion hypothesis, reject prompt track pairs
786  ClosestApproachInRPhi closest;
788  if (!closest.status()) {
789  return false;
790  }
791 
792  if (closest.crossingPoint().perp() < r_cut) {
793  return false;
794  }
795 
796 
797  //compute tangent point btw tracks (conversion hypothesis)
798  TangentApproachInRPhi tangent;
800  if (!tangent.status()) {
801  return false;
802  }
803 
804  GlobalPoint tangentPoint = tangent.crossingPoint();
805  double rho = tangentPoint.perp();
806 
807  //reject candidates well outside of tracker bounds
808  if (rho > maxTrackRho_) {
809  return false;
810  }
811 
812  if (std::abs(tangentPoint.z()) > maxTrackZ_) {
813  return false;
814  }
815 
816  std::pair<GlobalTrajectoryParameters,GlobalTrajectoryParameters> trajs = tangent.trajectoryParameters();
817 
818  //very large separation in z, no hope
819  if (std::abs(trajs.first.position().z() - trajs.second.position().z()) > dzCut_) {
820  return false;
821  }
822 
823 
824  float minApproach = tangent.perpdist();
825  appDist = minApproach;
826 
827  if (allowMinApproach_ && (minApproach < minApproachLow_ || minApproach > minApproachHigh_) ) {
828  return false;
829  }
830 
831  return true;
832 
833 
834 }
835 
838 
839  const reco::CaloClusterPtr& bc_l = ll.second;//can be null, so check isNonnull()
840  const reco::CaloClusterPtr& bc_r = rr.second;
841 
842  //The cuts should be ordered by considering if takes time and if cuts off many fakes
843  if (allowTrackBC_){
844  //check energy of BC
845  double total_e_bc = 0;
846  if (bc_l.isNonnull()) total_e_bc += bc_l->energy();
847  if (rightBC_)
848  if (bc_r.isNonnull())
849  total_e_bc += bc_r->energy();
850 
851  if (total_e_bc < energyTotalBC_) return false;
852  }
853 
854  return true;
855 }
856 
857 
858 
859 //because reco::vertex uses track ref, so have to keep them
861  const MagneticField* magField,
862  reco::Vertex& the_vertex){
863  bool found = false;
864 
865  std::vector<reco::TransientTrack> pair;
866  pair.push_back(ttk_l);
867  pair.push_back(ttk_r);
868 
869  found = theVertexFinder_->run(pair, the_vertex);
870 
871 
872 
873  return found;
874 }
875 
876 
877 
878 double ConversionProducer::etaTransformation( float EtaParticle , float Zvertex) {
879 
880  //---Definitions
881  const float PI = 3.1415927;
882 
883  //---Definitions for ECAL
884  const float R_ECAL = 136.5;
885  const float Z_Endcap = 328.0;
886  const float etaBarrelEndcap = 1.479;
887 
888  //---ETA correction
889 
890  float Theta = 0.0 ;
891  float ZEcal = R_ECAL*sinh(EtaParticle)+Zvertex;
892 
893  if(ZEcal != 0.0) Theta = atan(R_ECAL/ZEcal);
894  if(Theta<0.0) Theta = Theta+PI ;
895  double ETA = - log(tan(0.5*Theta));
896 
897  if( fabs(ETA) > etaBarrelEndcap )
898  {
899  float Zend = Z_Endcap ;
900  if(EtaParticle<0.0 ) Zend = -Zend ;
901  float Zlen = Zend - Zvertex ;
902  float RR = Zlen/sinh(EtaParticle);
903  Theta = atan(RR/Zend);
904  if(Theta<0.0) Theta = Theta+PI ;
905  ETA = - log(tan(0.5*Theta));
906  }
907  //---Return the result
908  return ETA;
909  //---end
910 }
911 
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:22
value_type const * get() const
Definition: RefToBase.h:234
T getParameter(std::string const &) const
unsigned int maxNumOfTrackInPU_
ConversionVertexFinder * theVertexFinder_
double d0Error() const
error on d0
Definition: TrackBase.h:847
edm::EDGetTokenT< reco::VertexCollection > vertexProducer_
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:125
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:251
TransientVertex run(const std::vector< reco::TransientTrack > &pair)
T perp() const
Definition: PV3DBase.h:72
double d0() const
dxy parameter in perigee convention (d0 = -dxy)
Definition: TrackBase.h:630
bool getTrackImpactPosition(const reco::Track *tk_ref, const TrackerGeometry *trackerGeom, const MagneticField *magField, math::XYZPointF &ew)
const TrackExtraRef & extra() const
reference to "extra" object
Definition: Track.h:194
std::pair< GlobalTrajectoryParameters, GlobalTrajectoryParameters > trajectoryParameters() const
double normalizedChi2() const
chi-squared divided by n.d.o.f. (or chi-squared * 1e6 if n.d.o.f. is zero)
Definition: TrackBase.h:594
TrajectoryStateOnSurface outerStateOnSurface(const reco::Track &tk, const TrackingGeometry &geom, const MagneticField *field, bool withErr=true)
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:517
double dxyError() const
error on dxy
Definition: TrackBase.h:841
void push_back(Ptr< T > const &iPtr)
Definition: PtrVector.h:140
const TransientTrackBuilder * thettbuilder_
void setQuality(ConversionQuality q, bool b)
Definition: Conversion.h:248
bool isValid() const
Tells whether the vertex is valid.
Definition: Vertex.h:68
#define nullptr
Geom::Phi< T > phi() const
Definition: PV3DBase.h:69
Global3DPoint GlobalPoint
Definition: GlobalPoint.h:10
void buildCollection(edm::Event &iEvent, const edm::EventSetup &iSetup, const std::multimap< float, edm::Ptr< reco::ConversionTrack > > &allTracks, const std::multimap< double, reco::CaloClusterPtr > &superClusterPtrs, const std::multimap< double, reco::CaloClusterPtr > &basicClusterPtrs, const reco::Vertex &the_pvtx, reco::ConversionCollection &outputConvPhotonCollection)
reco::TransientTrack build(const reco::Track *p) const
double zOfPrimaryVertexFromTracks(const math::XYZPoint &myBeamSpot=math::XYZPoint()) const
Definition: Conversion.h:146
Cylinder BoundCylinder
Definition: BoundCylinder.h:17
static ConversionAlgorithm algoByName(const std::string &name)
Definition: Conversion.cc:163
void buildSuperAndBasicClusterGeoMap(const edm::Event &, std::multimap< double, reco::CaloClusterPtr > &basicClusterPtrs, std::multimap< double, reco::CaloClusterPtr > &superClusterPtrs)
GlobalPoint globalPosition() const
std::vector< Vertex > VertexCollection
collection of Vertex objects
Definition: VertexFwd.h:9
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< float > > XYZPointF
point in space with cartesian internal representation
Definition: Point3D.h:10
const Point & position() const
position
Definition: Vertex.h:109
math::XYZVectorF refittedPairMomentum() const
Conversion tracks momentum from the tracks refitted with vertex constraint.
Definition: Conversion.cc:248
std::pair< uint8_t, Measurement1DFloat > nHitsBeforeVtx(const reco::TrackExtra &track, const reco::Vertex &vtx, float sigmaTolerance=3.0) const
std::vector< Conversion > ConversionCollection
collectin of Conversion objects
Definition: ConversionFwd.h:9
TrajectoryStateOnSurface innermostMeasurementState() const
bool matchingSC(const std::multimap< double, reco::CaloClusterPtr > &scMap, reco::Conversion &conv, reco::CaloClusterPtrVector &mSC)
const math::XYZPoint & innerPosition() const
position of the innermost hit
Definition: Track.h:57
TrackAlgorithm algo() const
Definition: TrackBase.h:530
#define ETA
int iEvent
Definition: GenABIO.cc:224
bool status() const override
bool calculate(const TrajectoryStateOnSurface &sta, const TrajectoryStateOnSurface &stb) override
math::XYZVectorF toFConverterV(const math::XYZVector &val)
T z() const
Definition: PV3DBase.h:64
Tan< T >::type tan(const T &t)
Definition: Tan.h:22
static float etaBarrelEndcap
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
float energy() const
Energy. Note this is taken from the first SimTrack only.
Definition: SimCluster.h:104
double chi2() const
chi-squares
Definition: Vertex.h:98
double f[11][100]
float ChiSquaredProbability(double chiSquared, double nrDOF)
edm::EDGetTokenT< edm::View< reco::CaloCluster > > scEndcapProducer_
edm::EDGetTokenT< edm::View< reco::CaloCluster > > bcBarrelCollection_
bool isValid() const
Definition: HandleBase.h:74
bool calculate(const TrajectoryStateOnSurface &sta, const TrajectoryStateOnSurface &stb) override
edm::EDGetTokenT< edm::View< reco::CaloCluster > > bcEndcapCollection_
#define PI
Definition: QcdUeDQM.h:36
uint8_t nSharedHits(const reco::Track &trk1, const reco::Track &trk2) const
bool getMatchedBC(const std::multimap< double, reco::CaloClusterPtr > &bcMap, const math::XYZPointF &trackImpactPosition, reco::CaloClusterPtr &closestBC)
double ndof() const
Definition: Vertex.h:105
bool isNonnull() const
Checks for non-null.
Definition: Ptr.h:168
bool checkTrackPair(const std::pair< edm::RefToBase< reco::Track >, reco::CaloClusterPtr > &ll, const std::pair< edm::RefToBase< reco::Track >, reco::CaloClusterPtr > &rr)
bool trackQualityFilter(const edm::RefToBase< reco::Track > &ref, bool isLeft)
const math::XYZVector & outerMomentum() const
momentum vector at the outermost hit position
Definition: Track.h:72
T const * product() const
Definition: Handle.h:74
const Track & track() const
bool trackD0Cut(const edm::RefToBase< reco::Track > &ref)
GlobalPoint crossingPoint() const override
REF castTo() const
Definition: RefToBase.h:289
std::string ConvertedPhotonCollection_
Disk BoundDisk
Definition: BoundDisk.h:62
TrajectoryStateOnSurface propagate(STA const &state, SUR const &surface) const
Definition: Propagator.h:53
T eta() const
Definition: PV3DBase.h:76
edm::EDGetTokenT< edm::View< reco::ConversionTrack > > src_
edm::EDGetTokenT< edm::View< reco::CaloCluster > > scBarrelProducer_
HLT enums.
const math::XYZVector & innerMomentum() const
momentum vector at the innermost hit position
Definition: Track.h:62
unsigned short found() const
Number of valid hits on track.
Definition: Track.h:199
T get() const
Definition: EventSetup.h:71
void produce(edm::Event &, const edm::EventSetup &) override
double etaTransformation(float EtaParticle, float Zvertex)
static float Z_Endcap
int charge() const
track electric charge
Definition: TrackBase.h:600
std::pair< typename Association::data_type::first_type, double > match(Reference key, Association association, bool bestMatchByMaxValue)
Generic matching function.
Definition: Utils.h:10
math::XYZPointF toFConverterP(const math::XYZPoint &val)
bool status() const override
GlobalPoint crossingPoint() const override
bool preselectTrackPair(const reco::TransientTrack &ttk_l, const reco::TransientTrack &ttk_r, double &appDist)
double dxy() const
dxy parameter. (This is the transverse impact parameter w.r.t. to (0,0,0) ONLY if refPoint is close t...
Definition: TrackBase.h:624
T const * product() const
Definition: ESHandle.h:86
static float R_ECAL
void setMatchingSuperCluster(const reco::CaloClusterPtrVector &sc)
Definition: Conversion.h:174
def move(src, dest)
Definition: eostools.py:511
bool checkPhi(const edm::RefToBase< reco::Track > &tk_l, const edm::RefToBase< reco::Track > &tk_r, const TrackerGeometry *trackerGeom, const MagneticField *magField, const reco::Vertex &the_vertex)
GlobalVector globalDirection() const
ConversionProducer(const edm::ParameterSet &)
TrajectoryStateOnSurface innerStateOnSurface(const reco::Track &tk, const TrackingGeometry &geom, const MagneticField *field, bool withErr=true)
float eta() const
Momentum pseudorapidity. Note this is taken from the simtrack before the calorimeter.
Definition: SimCluster.h:148
bool checkVertex(const reco::TransientTrack &ttk_l, const reco::TransientTrack &ttk_r, const MagneticField *magField, reco::Vertex &the_vertex)