File indexing completed on 2024-04-06 12:24:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include "CommonTools/Statistics/interface/ChiSquaredProbability.h"
0020 #include "DataFormats/CaloRecHit/interface/CaloCluster.h"
0021 #include "DataFormats/EcalDetId/interface/EcalSubdetector.h"
0022 #include "DataFormats/EgammaCandidates/interface/Conversion.h"
0023 #include "DataFormats/EgammaCandidates/interface/Photon.h"
0024 #include "DataFormats/EgammaTrackReco/interface/ConversionTrack.h"
0025 #include "DataFormats/GeometrySurface/interface/BoundCylinder.h"
0026 #include "DataFormats/GeometrySurface/interface/BoundDisk.h"
0027 #include "DataFormats/GeometrySurface/interface/ReferenceCounted.h"
0028 #include "DataFormats/GeometrySurface/interface/SimpleCylinderBounds.h"
0029 #include "DataFormats/GeometrySurface/interface/SimpleDiskBounds.h"
0030 #include "DataFormats/GsfTrackReco/interface/GsfTrack.h"
0031 #include "DataFormats/GsfTrackReco/interface/GsfTrackFwd.h"
0032 #include "DataFormats/Math/interface/deltaPhi.h"
0033 #include "DataFormats/TrackReco/interface/Track.h"
0034 #include "DataFormats/TrackingRecHit/interface/TrackingRecHit.h"
0035 #include "DataFormats/TrajectoryState/interface/PTrajectoryStateOnDet.h"
0036 #include "DataFormats/VertexReco/interface/Vertex.h"
0037 #include "FWCore/Framework/interface/ESHandle.h"
0038 #include "FWCore/Framework/interface/Event.h"
0039 #include "FWCore/Framework/interface/stream/EDProducer.h"
0040 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0041 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0042 #include "FWCore/Utilities/interface/ESGetToken.h"
0043 #include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
0044 #include "Geometry/CommonDetUnit/interface/GeomDet.h"
0045 #include "Geometry/Records/interface/TrackerDigiGeometryRecord.h"
0046 #include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
0047 #include "MagneticField/Engine/interface/MagneticField.h"
0048 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
0049 #include "RecoEgamma/EgammaPhotonAlgos/interface/ConversionHitChecker.h"
0050 #include "RecoEgamma/EgammaPhotonAlgos/interface/ConversionVertexFinder.h"
0051 #include "RecoEgamma/EgammaPhotonAlgos/interface/TangentApproachInRPhi.h"
0052 #include "TrackingTools/MaterialEffects/interface/PropagatorWithMaterial.h"
0053 #include "TrackingTools/PatternTools/interface/ClosestApproachInRPhi.h"
0054 #include "TrackingTools/PatternTools/interface/Trajectory.h"
0055 #include "TrackingTools/Records/interface/TransientTrackRecord.h"
0056 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateOnSurface.h"
0057 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h"
0058 #include "TrackingTools/TransientTrack/interface/TrackTransientTrack.h"
0059 #include "TrackingTools/TransientTrack/interface/TransientTrack.h"
0060 #include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
0061
0062 #include <map>
0063 #include <memory>
0064
0065 class ConversionProducer : public edm::stream::EDProducer<> {
0066 public:
0067 explicit ConversionProducer(const edm::ParameterSet&);
0068
0069 private:
0070 void produce(edm::Event&, const edm::EventSetup&) override;
0071
0072 void buildSuperAndBasicClusterGeoMap(const edm::Event&,
0073 std::multimap<double, reco::CaloClusterPtr>& basicClusterPtrs,
0074 std::multimap<double, reco::CaloClusterPtr>& superClusterPtrs);
0075
0076
0077 std::string algoName_;
0078
0079 typedef math::XYZPointF Point;
0080 typedef std::vector<Point> PointCollection;
0081
0082 edm::EDGetTokenT<edm::View<reco::ConversionTrack> > src_;
0083
0084 edm::EDGetTokenT<edm::View<reco::CaloCluster> > scBarrelProducer_;
0085 edm::EDGetTokenT<edm::View<reco::CaloCluster> > scEndcapProducer_;
0086 edm::EDGetTokenT<edm::View<reco::CaloCluster> > bcBarrelCollection_;
0087 edm::EDGetTokenT<edm::View<reco::CaloCluster> > bcEndcapCollection_;
0088 std::string ConvertedPhotonCollection_;
0089
0090 edm::ESGetToken<TransientTrackBuilder, TransientTrackRecord> transientTrackBuilder_;
0091 edm::ESGetToken<TrackerGeometry, TrackerDigiGeometryRecord> trackerGeometry_;
0092 edm::ESGetToken<MagneticField, IdealMagneticFieldRecord> magneticField_;
0093
0094 bool allowD0_, allowDeltaPhi_, allowTrackBC_, allowDeltaCot_, allowMinApproach_, allowOppCharge_, allowVertex_;
0095
0096 bool bypassPreselGsf_, bypassPreselEcal_, bypassPreselEcalEcal_;
0097
0098 bool usePvtx_;
0099 edm::EDGetTokenT<reco::VertexCollection> vertexProducer_;
0100 ConversionVertexFinder vertexFinder_;
0101
0102 const TransientTrackBuilder* thettbuilder_;
0103
0104 double deltaEta_;
0105
0106 double halfWayEta_, halfWayPhi_;
0107 unsigned int maxNumOfTrackInPU_;
0108 double maxTrackZ_;
0109 double maxTrackRho_;
0110 double minSCEt_;
0111 double dEtacutForSCmatching_;
0112 double dPhicutForSCmatching_;
0113 double energyBC_;
0114 double energyTotalBC_;
0115 double d0Cut_;
0116 double dzCut_;
0117 double dEtaTkBC_, dPhiTkBC_;
0118
0119 double maxChi2Left_, maxChi2Right_;
0120 double minHitsLeft_, minHitsRight_;
0121
0122 double deltaCotTheta_, deltaPhi_, minApproachLow_,
0123 minApproachHigh_;
0124
0125 double r_cut;
0126 double vtxChi2_;
0127
0128 bool allowSingleLeg_;
0129 bool rightBC_;
0130
0131 void buildCollection(edm::Event& iEvent,
0132 const edm::EventSetup& iSetup,
0133 const std::multimap<float, edm::Ptr<reco::ConversionTrack> >& allTracks,
0134 const std::multimap<double, reco::CaloClusterPtr>& superClusterPtrs,
0135 const std::multimap<double, reco::CaloClusterPtr>& basicClusterPtrs,
0136 const reco::Vertex& the_pvtx,
0137 reco::ConversionCollection& outputConvPhotonCollection);
0138
0139
0140 inline bool trackQualityFilter(const edm::RefToBase<reco::Track>& ref, bool isLeft);
0141 inline bool trackD0Cut(const edm::RefToBase<reco::Track>& ref);
0142 inline bool trackD0Cut(const edm::RefToBase<reco::Track>& ref, const reco::Vertex& the_pvtx);
0143
0144
0145 bool getTrackImpactPosition(const reco::Track* tk_ref,
0146 TrackerGeometry const& trackerGeom,
0147 MagneticField const& magField,
0148 math::XYZPointF& ew);
0149
0150
0151
0152
0153
0154 bool preselectTrackPair(const reco::TransientTrack& ttk_l, const reco::TransientTrack& ttk_r, double& appDist);
0155
0156
0157 bool checkTrackPair(const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr>& ll,
0158 const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr>& rr);
0159
0160
0161 inline bool checkVertex(const reco::TransientTrack& ttk_l,
0162 const reco::TransientTrack& ttk_r,
0163 MagneticField const& magField,
0164 reco::Vertex& the_vertex) {
0165 return vertexFinder_.run({ttk_l, ttk_r}, the_vertex);
0166 }
0167
0168 bool checkPhi(const edm::RefToBase<reco::Track>& tk_l,
0169 const edm::RefToBase<reco::Track>& tk_r,
0170 TrackerGeometry const& trackerGeom,
0171 MagneticField const& magField,
0172 const reco::Vertex& the_vertex);
0173
0174
0175 bool getMatchedBC(const std::multimap<double, reco::CaloClusterPtr>& bcMap,
0176 const math::XYZPointF& trackImpactPosition,
0177 reco::CaloClusterPtr& closestBC);
0178
0179
0180 bool matchingSC(const std::multimap<double, reco::CaloClusterPtr>& scMap,
0181 reco::Conversion& conv,
0182 reco::CaloClusterPtrVector& mSC);
0183
0184 double etaTransformation(float EtaParticle, float Zvertex);
0185
0186 math::XYZPointF toFConverterP(const math::XYZPoint& val) { return math::XYZPointF(val.x(), val.y(), val.z()); }
0187
0188 math::XYZVectorF toFConverterV(const math::XYZVector& val) { return math::XYZVectorF(val.x(), val.y(), val.z()); }
0189 };
0190
0191 #include "FWCore/Framework/interface/MakerMacros.h"
0192 DEFINE_FWK_MODULE(ConversionProducer);
0193
0194 inline const GeomDet* recHitDet(const TrackingRecHit& hit, const TrackingGeometry* geom) {
0195 return geom->idToDet(hit.geographicalId());
0196 }
0197
0198 inline const BoundPlane& recHitSurface(const TrackingRecHit& hit, const TrackingGeometry* geom) {
0199 return recHitDet(hit, geom)->surface();
0200 }
0201
0202 inline LocalVector toLocal(const reco::Track::Vector& v, const Surface& s) {
0203 return s.toLocal(GlobalVector(v.x(), v.y(), v.z()));
0204 }
0205
0206 ConversionProducer::ConversionProducer(const edm::ParameterSet& iConfig) : vertexFinder_{iConfig} {
0207 algoName_ = iConfig.getParameter<std::string>("AlgorithmName");
0208
0209 src_ = consumes<edm::View<reco::ConversionTrack> >(iConfig.getParameter<edm::InputTag>("src"));
0210
0211 maxNumOfTrackInPU_ = iConfig.getParameter<int>("maxNumOfTrackInPU");
0212 maxTrackRho_ = iConfig.getParameter<double>("maxTrackRho");
0213 maxTrackZ_ = iConfig.getParameter<double>("maxTrackZ");
0214
0215 allowTrackBC_ = iConfig.getParameter<bool>("AllowTrackBC");
0216 allowD0_ = iConfig.getParameter<bool>("AllowD0");
0217 allowDeltaPhi_ = iConfig.getParameter<bool>("AllowDeltaPhi");
0218 allowDeltaCot_ = iConfig.getParameter<bool>("AllowDeltaCot");
0219 allowMinApproach_ = iConfig.getParameter<bool>("AllowMinApproach");
0220 allowOppCharge_ = iConfig.getParameter<bool>("AllowOppCharge");
0221
0222 allowVertex_ = iConfig.getParameter<bool>("AllowVertex");
0223
0224 bypassPreselGsf_ = iConfig.getParameter<bool>("bypassPreselGsf");
0225 bypassPreselEcal_ = iConfig.getParameter<bool>("bypassPreselEcal");
0226 bypassPreselEcalEcal_ = iConfig.getParameter<bool>("bypassPreselEcalEcal");
0227
0228 deltaEta_ = iConfig.getParameter<double>("deltaEta");
0229
0230 halfWayEta_ = iConfig.getParameter<double>("HalfwayEta");
0231
0232 d0Cut_ = iConfig.getParameter<double>("d0");
0233
0234 usePvtx_ = iConfig.getParameter<bool>("UsePvtx");
0235
0236 vertexProducer_ = consumes<reco::VertexCollection>(iConfig.getParameter<edm::InputTag>("primaryVertexProducer"));
0237
0238 transientTrackBuilder_ = esConsumes(edm::ESInputTag("", "TransientTrackBuilder"));
0239 trackerGeometry_ = esConsumes();
0240 magneticField_ = esConsumes();
0241
0242
0243 dEtaTkBC_ = iConfig.getParameter<double>("dEtaTrackBC");
0244 dPhiTkBC_ = iConfig.getParameter<double>("dPhiTrackBC");
0245
0246 bcBarrelCollection_ =
0247 consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("bcBarrelCollection"));
0248 bcEndcapCollection_ =
0249 consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("bcEndcapCollection"));
0250
0251 scBarrelProducer_ = consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("scBarrelProducer"));
0252 scEndcapProducer_ = consumes<edm::View<reco::CaloCluster> >(iConfig.getParameter<edm::InputTag>("scEndcapProducer"));
0253
0254 energyBC_ = iConfig.getParameter<double>("EnergyBC");
0255 energyTotalBC_ = iConfig.getParameter<double>("EnergyTotalBC");
0256 minSCEt_ = iConfig.getParameter<double>("minSCEt");
0257 dEtacutForSCmatching_ = iConfig.getParameter<double>(
0258 "dEtacutForSCmatching");
0259 dPhicutForSCmatching_ = iConfig.getParameter<double>(
0260 "dPhicutForSCmatching");
0261
0262
0263
0264
0265 maxChi2Left_ = iConfig.getParameter<double>("MaxChi2Left");
0266 maxChi2Right_ = iConfig.getParameter<double>("MaxChi2Right");
0267 minHitsLeft_ = iConfig.getParameter<int>("MinHitsLeft");
0268 minHitsRight_ = iConfig.getParameter<int>("MinHitsRight");
0269
0270
0271 deltaCotTheta_ = iConfig.getParameter<double>("DeltaCotTheta");
0272 deltaPhi_ = iConfig.getParameter<double>("DeltaPhi");
0273 minApproachLow_ = iConfig.getParameter<double>("MinApproachLow");
0274 minApproachHigh_ = iConfig.getParameter<double>("MinApproachHigh");
0275
0276
0277 allowSingleLeg_ = iConfig.getParameter<bool>("AllowSingleLeg");
0278 rightBC_ = iConfig.getParameter<bool>("AllowRightBC");
0279
0280
0281 dzCut_ = iConfig.getParameter<double>("dz");
0282
0283 r_cut = iConfig.getParameter<double>("rCut");
0284 vtxChi2_ = iConfig.getParameter<double>("vtxChi2");
0285
0286 thettbuilder_ = nullptr;
0287
0288
0289 ConvertedPhotonCollection_ = iConfig.getParameter<std::string>("convertedPhotonCollection");
0290
0291 produces<reco::ConversionCollection>(ConvertedPhotonCollection_);
0292 }
0293
0294
0295 void ConversionProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0296 using namespace edm;
0297
0298 reco::ConversionCollection outputConvPhotonCollection;
0299 auto outputConvPhotonCollection_p = std::make_unique<reco::ConversionCollection>();
0300
0301
0302
0303
0304 edm::Handle<edm::View<reco::ConversionTrack> > trackCollectionHandle;
0305 iEvent.getByToken(src_, trackCollectionHandle);
0306
0307
0308 std::multimap<float, edm::Ptr<reco::ConversionTrack> > convTrackMap;
0309 for (auto const& t : trackCollectionHandle->ptrs())
0310 convTrackMap.emplace(t->track()->eta(), t);
0311
0312 edm::Handle<reco::VertexCollection> vertexHandle;
0313 reco::VertexCollection vertexCollection;
0314 if (usePvtx_) {
0315 iEvent.getByToken(vertexProducer_, vertexHandle);
0316 if (!vertexHandle.isValid()) {
0317 edm::LogError("ConversionProducer") << "Error! Can't get the product primary Vertex Collection "
0318 << "\n";
0319 usePvtx_ = false;
0320 }
0321 if (usePvtx_)
0322 vertexCollection = *(vertexHandle.product());
0323 }
0324
0325 thettbuilder_ = &iSetup.getData(transientTrackBuilder_);
0326
0327 reco::Vertex the_pvtx;
0328
0329 if (!vertexCollection.empty())
0330 the_pvtx = *(vertexCollection.begin());
0331
0332 if (trackCollectionHandle->size() > maxNumOfTrackInPU_) {
0333 iEvent.put(std::move(outputConvPhotonCollection_p), ConvertedPhotonCollection_);
0334 return;
0335 }
0336
0337
0338 std::multimap<double, reco::CaloClusterPtr> basicClusterPtrs;
0339 std::multimap<double, reco::CaloClusterPtr> superClusterPtrs;
0340
0341 buildSuperAndBasicClusterGeoMap(iEvent, basicClusterPtrs, superClusterPtrs);
0342
0343 buildCollection(iEvent,
0344 iSetup,
0345 convTrackMap,
0346 superClusterPtrs,
0347 basicClusterPtrs,
0348 the_pvtx,
0349 outputConvPhotonCollection);
0350
0351 outputConvPhotonCollection_p->assign(outputConvPhotonCollection.begin(), outputConvPhotonCollection.end());
0352 iEvent.put(std::move(outputConvPhotonCollection_p), ConvertedPhotonCollection_);
0353 }
0354
0355 void ConversionProducer::buildSuperAndBasicClusterGeoMap(const edm::Event& iEvent,
0356 std::multimap<double, reco::CaloClusterPtr>& basicClusterPtrs,
0357 std::multimap<double, reco::CaloClusterPtr>& superClusterPtrs) {
0358
0359 edm::Handle<edm::View<reco::CaloCluster> > scBarrelHandle;
0360 iEvent.getByToken(scBarrelProducer_, scBarrelHandle);
0361 if (!scBarrelHandle.isValid()) {
0362 edm::LogError("ConvertedPhotonProducer") << "Error! Can't get the barrel superclusters!";
0363 }
0364
0365
0366 edm::Handle<edm::View<reco::CaloCluster> > scEndcapHandle;
0367 iEvent.getByToken(scEndcapProducer_, scEndcapHandle);
0368 if (!scEndcapHandle.isValid()) {
0369 edm::LogError("ConvertedPhotonProducer") << "Error! Can't get the endcap superclusters!";
0370 }
0371
0372 edm::Handle<edm::View<reco::CaloCluster> > bcBarrelHandle;
0373 edm::Handle<edm::View<reco::CaloCluster> > bcEndcapHandle;
0374
0375 iEvent.getByToken(bcBarrelCollection_, bcBarrelHandle);
0376 if (!bcBarrelHandle.isValid()) {
0377 edm::LogError("ConvertedPhotonProducer") << "Error! Can't get the barrel basic clusters!";
0378 }
0379
0380 iEvent.getByToken(bcEndcapCollection_, bcEndcapHandle);
0381 if (!bcEndcapHandle.isValid()) {
0382 edm::LogError("ConvertedPhotonProducer") << "Error! Can't get the endcap basic clusters!";
0383 }
0384
0385 if (bcBarrelHandle.isValid()) {
0386 for (auto const& handle : {bcBarrelHandle, bcEndcapHandle}) {
0387 for (auto const& bc : handle->ptrs()) {
0388 if (bc->energy() > energyBC_)
0389 basicClusterPtrs.emplace(bc->position().eta(), bc);
0390 }
0391 }
0392 }
0393
0394 if (scBarrelHandle.isValid()) {
0395 for (auto const& handle : {scBarrelHandle, scEndcapHandle}) {
0396 for (auto const& sc : handle->ptrs()) {
0397 if (sc->energy() > minSCEt_)
0398 superClusterPtrs.emplace(sc->position().eta(), sc);
0399 }
0400 }
0401 }
0402 }
0403
0404 void ConversionProducer::buildCollection(edm::Event& iEvent,
0405 const edm::EventSetup& iSetup,
0406 const std::multimap<float, edm::Ptr<reco::ConversionTrack> >& allTracks,
0407 const std::multimap<double, reco::CaloClusterPtr>& superClusterPtrs,
0408 const std::multimap<double, reco::CaloClusterPtr>& basicClusterPtrs,
0409 const reco::Vertex& the_pvtx,
0410 reco::ConversionCollection& outputConvPhotonCollection) {
0411 TrackerGeometry const& trackerGeom = iSetup.getData(trackerGeometry_);
0412 MagneticField const& magField = iSetup.getData(magneticField_);
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428 std::map<edm::Ptr<reco::ConversionTrack>, math::XYZPointF> trackImpactPosition;
0429 std::map<edm::Ptr<reco::ConversionTrack>, reco::CaloClusterPtr> trackMatchedBC;
0430
0431 ConversionHitChecker hitChecker;
0432
0433
0434
0435 for (auto const& tk_ref : allTracks) {
0436 const reco::Track* tk = tk_ref.second->trackRef().get();
0437
0438
0439 math::XYZPointF ew;
0440 if (getTrackImpactPosition(tk, trackerGeom, magField, ew)) {
0441 trackImpactPosition[tk_ref.second] = ew;
0442
0443 reco::CaloClusterPtr closest_bc;
0444
0445 if (getMatchedBC(basicClusterPtrs, ew, closest_bc)) {
0446 trackMatchedBC[tk_ref.second] = closest_bc;
0447 }
0448 }
0449 }
0450
0451
0452
0453
0454 for (auto ll = allTracks.begin(); ll != allTracks.end(); ++ll) {
0455 bool track1HighPurity = true;
0456
0457 const edm::RefToBase<reco::Track>& left = ll->second->trackRef();
0458
0459
0460
0461
0462 reco::TransientTrack ttk_l;
0463 if (dynamic_cast<const reco::GsfTrack*>(left.get())) {
0464 ttk_l = thettbuilder_->build(left.castTo<reco::GsfTrackRef>());
0465 } else {
0466 ttk_l = thettbuilder_->build(left.castTo<reco::TrackRef>());
0467 }
0468
0469
0470
0471
0472
0473 if (the_pvtx.isValid()) {
0474 if (!(trackD0Cut(left, the_pvtx)))
0475 track1HighPurity = false;
0476 } else {
0477 if (!(trackD0Cut(left)))
0478 track1HighPurity = false;
0479 }
0480
0481 std::vector<int> right_candidates;
0482 std::vector<double> right_candidate_theta, right_candidate_approach;
0483 std::vector<std::pair<bool, reco::Vertex> > vertex_candidates;
0484
0485
0486 float etasearch = ll->first + deltaEta_;
0487 std::multimap<float, edm::Ptr<reco::ConversionTrack> >::const_iterator rr = ll;
0488 ++rr;
0489 for (; rr != allTracks.lower_bound(etasearch); ++rr) {
0490 bool track2HighPurity = true;
0491 bool highPurityPair = true;
0492
0493 const edm::RefToBase<reco::Track>& right = rr->second->trackRef();
0494
0495
0496 reco::TransientTrack ttk_r;
0497 if (dynamic_cast<const reco::GsfTrack*>(right.get())) {
0498 ttk_r = thettbuilder_->build(right.castTo<reco::GsfTrackRef>());
0499 } else {
0500 ttk_r = thettbuilder_->build(right.castTo<reco::TrackRef>());
0501 }
0502
0503
0504
0505
0506
0507 if (allowOppCharge_ && (left->charge() * right->charge() > 0))
0508 continue;
0509
0510
0511
0512
0513
0514 double approachDist = -999.;
0515
0516 bool preselected = preselectTrackPair(ttk_l, ttk_r, approachDist);
0517 preselected = preselected || (bypassPreselGsf_ &&
0518 (left->algo() == reco::TrackBase::gsf || right->algo() == reco::TrackBase::gsf));
0519 preselected = preselected || (bypassPreselEcal_ && (left->algo() == reco::TrackBase::outInEcalSeededConv ||
0520 right->algo() == reco::TrackBase::outInEcalSeededConv ||
0521 left->algo() == reco::TrackBase::inOutEcalSeededConv ||
0522 right->algo() == reco::TrackBase::inOutEcalSeededConv));
0523 preselected = preselected || (bypassPreselEcalEcal_ &&
0524 (left->algo() == reco::TrackBase::outInEcalSeededConv ||
0525 left->algo() == reco::TrackBase::inOutEcalSeededConv) &&
0526 (right->algo() == reco::TrackBase::outInEcalSeededConv ||
0527 right->algo() == reco::TrackBase::inOutEcalSeededConv));
0528
0529 if (!preselected) {
0530 continue;
0531 }
0532
0533
0534 reco::Vertex theConversionVertex;
0535 bool goodVertex = checkVertex(ttk_l, ttk_r, magField, theConversionVertex);
0536
0537
0538 if (!goodVertex) {
0539 continue;
0540 }
0541
0542
0543 if (!((trackQualityFilter(left, true) && trackQualityFilter(right, false)) ||
0544 (trackQualityFilter(left, false) && trackQualityFilter(right, true)))) {
0545 highPurityPair = false;
0546 }
0547
0548 if (the_pvtx.isValid()) {
0549 if (!(trackD0Cut(right, the_pvtx)))
0550 track2HighPurity = false;
0551 } else {
0552 if (!(trackD0Cut(right)))
0553 track2HighPurity = false;
0554 }
0555
0556
0557 std::vector<edm::RefToBase<reco::Track> > trackPairRef;
0558 trackPairRef.push_back(left);
0559 trackPairRef.push_back(right);
0560
0561 std::vector<math::XYZVectorF> trackPin;
0562 std::vector<math::XYZVectorF> trackPout;
0563 std::vector<math::XYZPointF> trackInnPos;
0564 std::vector<uint8_t> nHitsBeforeVtx;
0565 std::vector<Measurement1DFloat> dlClosestHitToVtx;
0566
0567 if (left->extra().isNonnull() && right->extra().isNonnull()) {
0568 trackInnPos.push_back(toFConverterP(left->innerPosition()));
0569 trackInnPos.push_back(toFConverterP(right->innerPosition()));
0570 trackPin.push_back(toFConverterV(left->innerMomentum()));
0571 trackPin.push_back(toFConverterV(right->innerMomentum()));
0572 trackPout.push_back(toFConverterV(left->outerMomentum()));
0573 trackPout.push_back(toFConverterV(right->outerMomentum()));
0574 auto leftWrongHits = hitChecker.nHitsBeforeVtx(*left->extra(), theConversionVertex);
0575 auto rightWrongHits = hitChecker.nHitsBeforeVtx(*right->extra(), theConversionVertex);
0576 nHitsBeforeVtx.push_back(leftWrongHits.first);
0577 nHitsBeforeVtx.push_back(rightWrongHits.first);
0578 dlClosestHitToVtx.push_back(leftWrongHits.second);
0579 dlClosestHitToVtx.push_back(rightWrongHits.second);
0580 }
0581
0582 uint8_t nSharedHits = hitChecker.nSharedHits(*left.get(), *right.get());
0583
0584
0585 if (theConversionVertex.isValid()) {
0586 const float chi2Prob = ChiSquaredProbability(theConversionVertex.chi2(), theConversionVertex.ndof());
0587 if (chi2Prob < vtxChi2_)
0588 highPurityPair = false;
0589 }
0590
0591
0592 std::vector<math::XYZPointF> trkPositionAtEcal;
0593 std::vector<reco::CaloClusterPtr> matchingBC;
0594
0595 if (allowTrackBC_) {
0596
0597
0598
0599 std::map<edm::Ptr<reco::ConversionTrack>, math::XYZPointF>::const_iterator trackImpactPositionLeft =
0600 trackImpactPosition.find(ll->second);
0601 std::map<edm::Ptr<reco::ConversionTrack>, math::XYZPointF>::const_iterator trackImpactPositionRight =
0602 trackImpactPosition.find(rr->second);
0603 std::map<edm::Ptr<reco::ConversionTrack>, reco::CaloClusterPtr>::const_iterator trackMatchedBCLeft =
0604 trackMatchedBC.find(ll->second);
0605 std::map<edm::Ptr<reco::ConversionTrack>, reco::CaloClusterPtr>::const_iterator trackMatchedBCRight =
0606 trackMatchedBC.find(rr->second);
0607
0608 if (trackImpactPositionLeft != trackImpactPosition.end()) {
0609 trkPositionAtEcal.push_back(trackImpactPositionLeft->second);
0610 } else {
0611 trkPositionAtEcal.push_back(math::XYZPointF());
0612 }
0613 if (trackImpactPositionRight != trackImpactPosition.end()) {
0614 trkPositionAtEcal.push_back(trackImpactPositionRight->second);
0615 }
0616
0617 double total_e_bc = 0.;
0618 if (trackMatchedBCLeft != trackMatchedBC.end()) {
0619 matchingBC.push_back(trackMatchedBCLeft->second);
0620 total_e_bc += trackMatchedBCLeft->second->energy();
0621 } else {
0622 matchingBC.push_back(reco::CaloClusterPtr());
0623 }
0624 if (trackMatchedBCRight != trackMatchedBC.end()) {
0625 matchingBC.push_back(trackMatchedBCRight->second);
0626 total_e_bc += trackMatchedBCRight->second->energy();
0627 }
0628
0629 if (total_e_bc < energyTotalBC_) {
0630 highPurityPair = false;
0631 }
0632 }
0633
0634 highPurityPair = highPurityPair && track1HighPurity && track2HighPurity && goodVertex &&
0635 checkPhi(left, right, trackerGeom, magField, theConversionVertex);
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648 const float minAppDist = approachDist;
0649 reco::Conversion::ConversionAlgorithm algo = reco::Conversion::algoByName(algoName_);
0650 float dummy = 0;
0651 reco::CaloClusterPtrVector scPtrVec;
0652 reco::Conversion newCandidate(scPtrVec,
0653 trackPairRef,
0654 trkPositionAtEcal,
0655 theConversionVertex,
0656 matchingBC,
0657 minAppDist,
0658 trackInnPos,
0659 trackPin,
0660 trackPout,
0661 nHitsBeforeVtx,
0662 dlClosestHitToVtx,
0663 nSharedHits,
0664 dummy,
0665 algo);
0666
0667 if (matchingSC(superClusterPtrs, newCandidate, scPtrVec))
0668 newCandidate.setMatchingSuperCluster(scPtrVec);
0669
0670 newCandidate.setQuality(reco::Conversion::highPurity, highPurityPair);
0671 bool generalTracksOnly = ll->second->isTrackerOnly() && rr->second->isTrackerOnly() &&
0672 !dynamic_cast<const reco::GsfTrack*>(ll->second->trackRef().get()) &&
0673 !dynamic_cast<const reco::GsfTrack*>(rr->second->trackRef().get());
0674 bool gsfTracksOpenOnly = ll->second->isGsfTrackOpen() && rr->second->isGsfTrackOpen();
0675 bool arbitratedEcalSeeded = ll->second->isArbitratedEcalSeeded() && rr->second->isArbitratedEcalSeeded();
0676 bool arbitratedMerged = ll->second->isArbitratedMerged() && rr->second->isArbitratedMerged();
0677 bool arbitratedMergedEcalGeneral =
0678 ll->second->isArbitratedMergedEcalGeneral() && rr->second->isArbitratedMergedEcalGeneral();
0679
0680 newCandidate.setQuality(reco::Conversion::generalTracksOnly, generalTracksOnly);
0681 newCandidate.setQuality(reco::Conversion::gsfTracksOpenOnly, gsfTracksOpenOnly);
0682 newCandidate.setQuality(reco::Conversion::arbitratedEcalSeeded, arbitratedEcalSeeded);
0683 newCandidate.setQuality(reco::Conversion::arbitratedMerged, arbitratedMerged);
0684 newCandidate.setQuality(reco::Conversion::arbitratedMergedEcalGeneral, arbitratedMergedEcalGeneral);
0685
0686 outputConvPhotonCollection.push_back(newCandidate);
0687 }
0688 }
0689 }
0690
0691
0692
0693
0694
0695 inline bool ConversionProducer::trackQualityFilter(const edm::RefToBase<reco::Track>& ref, bool isLeft) {
0696 bool pass = true;
0697 if (isLeft) {
0698 pass = (ref->normalizedChi2() < maxChi2Left_ && ref->found() >= minHitsLeft_);
0699 } else {
0700 pass = (ref->normalizedChi2() < maxChi2Right_ && ref->found() >= minHitsRight_);
0701 }
0702
0703 return pass;
0704 }
0705
0706 inline bool ConversionProducer::trackD0Cut(const edm::RefToBase<reco::Track>& ref) {
0707
0708 return ((!allowD0_) || !(ref->d0() * ref->charge() / ref->d0Error() < d0Cut_));
0709 }
0710
0711 inline bool ConversionProducer::trackD0Cut(const edm::RefToBase<reco::Track>& ref, const reco::Vertex& the_pvtx) {
0712
0713 return ((!allowD0_) || !(-ref->dxy(the_pvtx.position()) * ref->charge() / ref->dxyError() < d0Cut_));
0714 }
0715
0716 bool ConversionProducer::getTrackImpactPosition(const reco::Track* tk_ref,
0717 TrackerGeometry const& trackerGeom,
0718 MagneticField const& magField,
0719 math::XYZPointF& ew) {
0720 PropagatorWithMaterial propag(alongMomentum, 0.000511, &magField);
0721
0722 ReferenceCountingPointer<Surface> ecalWall(new BoundCylinder(
0723 129.f, GlobalPoint(0., 0., 0.), TkRotation<float>(), new SimpleCylinderBounds(129, 129, -320.5, 320.5)));
0724 constexpr float epsilon = 0.001;
0725 Surface::RotationType rot;
0726 constexpr float barrelRadius = 129.f;
0727 constexpr float barrelHalfLength = 270.9f;
0728 constexpr float endcapRadius = 171.1f;
0729 constexpr float endcapZ = 320.5f;
0730 ReferenceCountingPointer<BoundCylinder> theBarrel_(new BoundCylinder(
0731 barrelRadius,
0732 Surface::PositionType(0, 0, 0),
0733 rot,
0734 new SimpleCylinderBounds(barrelRadius - epsilon, barrelRadius + epsilon, -barrelHalfLength, barrelHalfLength)));
0735 ReferenceCountingPointer<BoundDisk> theNegativeEtaEndcap_(new BoundDisk(
0736 Surface::PositionType(0, 0, -endcapZ), rot, new SimpleDiskBounds(0, endcapRadius, -epsilon, epsilon)));
0737 ReferenceCountingPointer<BoundDisk> thePositiveEtaEndcap_(new BoundDisk(
0738 Surface::PositionType(0, 0, endcapZ), rot, new SimpleDiskBounds(0, endcapRadius, -epsilon, epsilon)));
0739
0740
0741 const auto myTSOS = trajectoryStateTransform::outerStateOnSurface(*tk_ref, trackerGeom, &magField);
0742 TrajectoryStateOnSurface stateAtECAL;
0743 stateAtECAL = propag.propagate(myTSOS, *theBarrel_);
0744 if (!stateAtECAL.isValid() || (stateAtECAL.isValid() && fabs(stateAtECAL.globalPosition().eta()) > 1.479f)) {
0745
0746 if (myTSOS.globalPosition().z() > 0.) {
0747 stateAtECAL = propag.propagate(myTSOS, *thePositiveEtaEndcap_);
0748 } else {
0749 stateAtECAL = propag.propagate(myTSOS, *theNegativeEtaEndcap_);
0750 }
0751 }
0752 if (stateAtECAL.isValid()) {
0753 ew = stateAtECAL.globalPosition();
0754 return true;
0755 } else
0756 return false;
0757 }
0758
0759 bool ConversionProducer::matchingSC(const std::multimap<double, reco::CaloClusterPtr>& scMap,
0760 reco::Conversion& aConv,
0761
0762 reco::CaloClusterPtrVector& mSC) {
0763
0764 double detaMin = 999.;
0765 double dphiMin = 999.;
0766 reco::CaloClusterPtr match;
0767 for (std::multimap<double, reco::CaloClusterPtr>::const_iterator scItr = scMap.begin(); scItr != scMap.end();
0768 scItr++) {
0769 const reco::CaloClusterPtr& sc = scItr->second;
0770 const double delta_phi = reco::deltaPhi(aConv.refittedPairMomentum().phi(), sc->phi());
0771 double sceta = sc->eta();
0772 double conveta = etaTransformation(aConv.refittedPairMomentum().eta(), aConv.zOfPrimaryVertexFromTracks());
0773 const double delta_eta = fabs(conveta - sceta);
0774 if (fabs(delta_eta) < fabs(detaMin) && fabs(delta_phi) < fabs(dphiMin)) {
0775 detaMin = fabs(delta_eta);
0776 dphiMin = fabs(delta_phi);
0777 match = sc;
0778 }
0779 }
0780
0781 if (fabs(detaMin) < dEtacutForSCmatching_ && fabs(dphiMin) < dPhicutForSCmatching_) {
0782 mSC.push_back(match);
0783 return true;
0784 } else
0785 return false;
0786 }
0787
0788 bool ConversionProducer::getMatchedBC(const std::multimap<double, reco::CaloClusterPtr>& bcMap,
0789 const math::XYZPointF& trackImpactPosition,
0790 reco::CaloClusterPtr& closestBC) {
0791 const double track_eta = trackImpactPosition.eta();
0792 const double track_phi = trackImpactPosition.phi();
0793
0794 double min_eta = 999., min_phi = 999.;
0795 reco::CaloClusterPtr closest_bc;
0796 for (std::multimap<double, reco::CaloClusterPtr>::const_iterator bc = bcMap.lower_bound(track_eta - halfWayEta_);
0797 bc != bcMap.upper_bound(track_eta + halfWayEta_);
0798 ++bc) {
0799 const reco::CaloClusterPtr& ebc = bc->second;
0800 const double delta_eta = track_eta - (ebc->position().eta());
0801 const double delta_phi = reco::deltaPhi(track_phi, (ebc->position().phi()));
0802 if (fabs(delta_eta) < dEtaTkBC_ && fabs(delta_phi) < dPhiTkBC_) {
0803 if (fabs(min_eta) > fabs(delta_eta) && fabs(min_phi) > fabs(delta_phi)) {
0804 min_eta = delta_eta;
0805 min_phi = delta_phi;
0806 closest_bc = bc->second;
0807
0808 }
0809 }
0810 }
0811
0812 if (min_eta < 999.) {
0813 closestBC = closest_bc;
0814 return true;
0815 } else
0816 return false;
0817 }
0818
0819
0820 bool ConversionProducer::checkPhi(const edm::RefToBase<reco::Track>& tk_l,
0821 const edm::RefToBase<reco::Track>& tk_r,
0822 TrackerGeometry const& trackerGeom,
0823 MagneticField const& magField,
0824 const reco::Vertex& vtx) {
0825 if (!allowDeltaPhi_)
0826 return true;
0827
0828
0829
0830 if (tk_l->extra().isNonnull() && tk_r->extra().isNonnull()) {
0831 double iphi1 = tk_l->innerMomentum().phi(), iphi2 = tk_r->innerMomentum().phi();
0832 if (vtx.isValid()) {
0833 PropagatorWithMaterial propag(anyDirection, 0.000511, &magField);
0834
0835 double recoPhoR = vtx.position().Rho();
0836 Surface::RotationType rot;
0837 ReferenceCountingPointer<BoundCylinder> theBarrel_(new BoundCylinder(
0838 recoPhoR,
0839 Surface::PositionType(0, 0, 0),
0840 rot,
0841 new SimpleCylinderBounds(
0842 recoPhoR - 0.001, recoPhoR + 0.001, -fabs(vtx.position().z()), fabs(vtx.position().z()))));
0843 ReferenceCountingPointer<BoundDisk> theDisk_(new BoundDisk(
0844 Surface::PositionType(0, 0, vtx.position().z()), rot, new SimpleDiskBounds(0, recoPhoR, -0.001, 0.001)));
0845
0846 const auto myTSOS1 = trajectoryStateTransform::innerStateOnSurface(*tk_l, trackerGeom, &magField);
0847 const auto myTSOS2 = trajectoryStateTransform::innerStateOnSurface(*tk_r, trackerGeom, &magField);
0848 TrajectoryStateOnSurface stateAtVtx1, stateAtVtx2;
0849 stateAtVtx1 = propag.propagate(myTSOS1, *theBarrel_);
0850 if (!stateAtVtx1.isValid()) {
0851 stateAtVtx1 = propag.propagate(myTSOS1, *theDisk_);
0852 }
0853 if (stateAtVtx1.isValid()) {
0854 iphi1 = stateAtVtx1.globalDirection().phi();
0855 }
0856 stateAtVtx2 = propag.propagate(myTSOS2, *theBarrel_);
0857 if (!stateAtVtx2.isValid()) {
0858 stateAtVtx2 = propag.propagate(myTSOS2, *theDisk_);
0859 }
0860 if (stateAtVtx2.isValid()) {
0861 iphi2 = stateAtVtx2.globalDirection().phi();
0862 }
0863 }
0864 const double dPhi = reco::deltaPhi(iphi1, iphi2);
0865 return (fabs(dPhi) < deltaPhi_);
0866 } else {
0867 return true;
0868 }
0869 }
0870
0871 bool ConversionProducer::preselectTrackPair(const reco::TransientTrack& ttk_l,
0872 const reco::TransientTrack& ttk_r,
0873 double& appDist) {
0874 double dCotTheta = 1. / tan(ttk_l.track().innerMomentum().theta()) - 1. / tan(ttk_r.track().innerMomentum().theta());
0875 if (allowDeltaCot_ && (std::abs(dCotTheta) > deltaCotTheta_)) {
0876 return false;
0877 }
0878
0879
0880 ClosestApproachInRPhi closest;
0881 closest.calculate(ttk_l.innermostMeasurementState(), ttk_r.innermostMeasurementState());
0882 if (!closest.status()) {
0883 return false;
0884 }
0885
0886 if (closest.crossingPoint().perp() < r_cut) {
0887 return false;
0888 }
0889
0890
0891 TangentApproachInRPhi tangent;
0892 tangent.calculate(ttk_l.innermostMeasurementState(), ttk_r.innermostMeasurementState());
0893 if (!tangent.status()) {
0894 return false;
0895 }
0896
0897 GlobalPoint tangentPoint = tangent.crossingPoint();
0898 double rho = tangentPoint.perp();
0899
0900
0901 if (rho > maxTrackRho_) {
0902 return false;
0903 }
0904
0905 if (std::abs(tangentPoint.z()) > maxTrackZ_) {
0906 return false;
0907 }
0908
0909 std::pair<GlobalTrajectoryParameters, GlobalTrajectoryParameters> trajs = tangent.trajectoryParameters();
0910
0911
0912 if (std::abs(trajs.first.position().z() - trajs.second.position().z()) > dzCut_) {
0913 return false;
0914 }
0915
0916 float minApproach = tangent.perpdist();
0917 appDist = minApproach;
0918
0919 if (allowMinApproach_ && (minApproach < minApproachLow_ || minApproach > minApproachHigh_)) {
0920 return false;
0921 }
0922
0923 return true;
0924 }
0925
0926 bool ConversionProducer::checkTrackPair(const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr>& ll,
0927 const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr>& rr) {
0928 const reco::CaloClusterPtr& bc_l = ll.second;
0929 const reco::CaloClusterPtr& bc_r = rr.second;
0930
0931
0932 if (allowTrackBC_) {
0933
0934 double total_e_bc = 0;
0935 if (bc_l.isNonnull())
0936 total_e_bc += bc_l->energy();
0937 if (rightBC_)
0938 if (bc_r.isNonnull())
0939 total_e_bc += bc_r->energy();
0940
0941 if (total_e_bc < energyTotalBC_)
0942 return false;
0943 }
0944
0945 return true;
0946 }
0947
0948 double ConversionProducer::etaTransformation(float EtaParticle, float Zvertex) {
0949
0950 const float PI = 3.1415927;
0951
0952
0953 const float R_ECAL = 136.5;
0954 const float Z_Endcap = 328.0;
0955 const float etaBarrelEndcap = 1.479;
0956
0957
0958
0959 float Theta = 0.0;
0960 float ZEcal = R_ECAL * sinh(EtaParticle) + Zvertex;
0961
0962 if (ZEcal != 0.0)
0963 Theta = atan(R_ECAL / ZEcal);
0964 if (Theta < 0.0)
0965 Theta = Theta + PI;
0966 double ETA = -log(tan(0.5 * Theta));
0967
0968 if (fabs(ETA) > etaBarrelEndcap) {
0969 float Zend = Z_Endcap;
0970 if (EtaParticle < 0.0)
0971 Zend = -Zend;
0972 float Zlen = Zend - Zvertex;
0973 float RR = Zlen / sinh(EtaParticle);
0974 Theta = atan(RR / Zend);
0975 if (Theta < 0.0)
0976 Theta = Theta + PI;
0977 ETA = -log(tan(0.5 * Theta));
0978 }
0979
0980 return ETA;
0981
0982 }