CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch13/src/RecoEgamma/EgammaPhotonProducers/src/TrackerOnlyConversionProducer.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:    TrackerOnlyConversionProducer
00004 // Class:      TrackerOnlyConversionProducer
00005 //
00013 //
00014 // Original Author:  Hongliang Liu
00015 //         Created:  Thu Mar 13 17:40:48 CDT 2008
00016 // $Id: TrackerOnlyConversionProducer.cc,v 1.40.4.1 2011/01/26 20:12:45 nancy Exp $
00017 //
00018 //
00019 
00020 
00021 // system include files
00022 #include <memory>
00023 #include <map>
00024 
00025 
00026 #include "RecoEgamma/EgammaPhotonProducers/interface/TrackerOnlyConversionProducer.h"
00027 #include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
00028 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h"
00029 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateOnSurface.h"
00030 #include "DataFormats/TrajectoryState/interface/PTrajectoryStateOnDet.h"
00031 
00032 #include "TrackingTools/GeomPropagators/interface/AnalyticalPropagator.h"
00033 #include "TrackingTools/MaterialEffects/interface/PropagatorWithMaterial.h"
00034 #include "DataFormats/TrackingRecHit/interface/TrackingRecHit.h"
00035 #include "DataFormats/EcalDetId/interface/EcalSubdetector.h"
00036 
00037 #include "TrackingTools/TransientTrack/interface/TrackTransientTrack.h"
00038 #include "DataFormats/EgammaTrackReco/interface/ConversionTrack.h"
00039 
00040 
00041 #include "DataFormats/VertexReco/interface/Vertex.h"
00042 #include "DataFormats/VertexReco/interface/VertexFwd.h"
00043 #include "DataFormats/GsfTrackReco/interface/GsfTrack.h"
00044 #include "DataFormats/GsfTrackReco/interface/GsfTrackFwd.h"
00045 
00046 #include "TrackingTools/TransientTrack/interface/TransientTrackBuilder.h"
00047 #include "TrackingTools/Records/interface/TransientTrackRecord.h"
00048 #include "TrackingTools/TransientTrack/interface/TransientTrack.h"
00049 
00050 #include "TrackingTools/PatternTools/interface/ClosestApproachInRPhi.h"
00051 #include "TrackingTools/PatternTools/interface/TwoTrackMinimumDistance.h"
00052 
00053 #include "CommonTools/Statistics/interface/ChiSquaredProbability.h"
00054 #include "DataFormats/Math/interface/deltaPhi.h"
00055 #include "RecoEgamma/EgammaPhotonAlgos/interface/ConversionVertexFinder.h"
00056 #include "TrackingTools/PatternTools/interface/Trajectory.h"
00057 #include "RecoEgamma/EgammaPhotonAlgos/interface/TangentApproachInRPhi.h"
00058 #include "RecoEgamma/EgammaPhotonAlgos/interface/ConversionHitChecker.h"
00059 
00060 
00061 //Kinematic constraint vertex fitter
00062 #include "RecoVertex/KinematicFitPrimitives/interface/ParticleMass.h"
00063 #include "RecoVertex/KinematicFitPrimitives/interface/MultiTrackKinematicConstraint.h"
00064 #include <RecoVertex/KinematicFitPrimitives/interface/KinematicParticleFactoryFromTransientTrack.h>
00065 #include "RecoVertex/KinematicFit/interface/KinematicConstrainedVertexFitter.h"
00066 #include "RecoVertex/KinematicFit/interface/TwoTrackMassKinematicConstraint.h"
00067 #include "RecoVertex/KinematicFit/interface/KinematicParticleVertexFitter.h"
00068 #include "RecoVertex/KinematicFit/interface/KinematicParticleFitter.h"
00069 #include "RecoVertex/KinematicFit/interface/MassKinematicConstraint.h"
00070 #include "RecoVertex/KinematicFit/interface/ColinearityKinematicConstraint.h"
00071 
00072 
00073 
00074 TrackerOnlyConversionProducer::TrackerOnlyConversionProducer(const edm::ParameterSet& iConfig):
00075  theVertexFinder_(0)
00076 
00077 {
00078     algoName_ = iConfig.getParameter<std::string>( "AlgorithmName" );
00079 
00080     src_ = iConfig.getParameter<edm::InputTag>("src");
00081     maxNumOfTrackInPU_ = iConfig.getParameter<int>("maxNumOfTrackInPU");
00082     allowTrackBC_ = iConfig.getParameter<bool>("AllowTrackBC");
00083     allowD0_ = iConfig.getParameter<bool>("AllowD0");
00084     allowDeltaPhi_ = iConfig.getParameter<bool>("AllowDeltaPhi");
00085     allowDeltaCot_ = iConfig.getParameter<bool>("AllowDeltaCot");
00086     allowMinApproach_ = iConfig.getParameter<bool>("AllowMinApproach");
00087     allowOppCharge_ = iConfig.getParameter<bool>("AllowOppCharge");
00088 
00089     allowVertex_ = iConfig.getParameter<bool>("AllowVertex");
00090 
00091     halfWayEta_ = iConfig.getParameter<double>("HalfwayEta");//open angle to search track matches with BC
00092 
00093     if (allowD0_)
00094         d0Cut_ = iConfig.getParameter<double>("d0");
00095     
00096     usePvtx_ = iConfig.getParameter<bool>("UsePvtx");//if use primary vertices
00097 
00098     if (usePvtx_){
00099         vertexProducer_   = iConfig.getParameter<std::string>("primaryVertexProducer");
00100     }
00101 
00102     if (allowTrackBC_) {
00103         //Track-cluster matching eta and phi cuts
00104         dEtaTkBC_ = iConfig.getParameter<double>("dEtaTrackBC");//TODO research on cut endcap/barrel
00105         dPhiTkBC_ = iConfig.getParameter<double>("dPhiTrackBC");
00106 
00107         bcBarrelCollection_     = iConfig.getParameter<edm::InputTag>("bcBarrelCollection");
00108         bcEndcapCollection_     = iConfig.getParameter<edm::InputTag>("bcEndcapCollection");
00109 
00110         energyBC_ = iConfig.getParameter<double>("EnergyBC");//BC energy cut
00111         energyTotalBC_ = iConfig.getParameter<double>("EnergyTotalBC");//BC energy cut
00112 
00113     }
00114 
00115     //Track cuts on left right track: at least one leg reaches ECAL
00116     //Left track: must exist, must reach Ecal and match BC, so loose cut on Chi2 and tight on hits
00117     //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
00118     maxChi2Left_ =  iConfig.getParameter<double>("MaxChi2Left");
00119     maxChi2Right_ =  iConfig.getParameter<double>("MaxChi2Right");
00120     minHitsLeft_ = iConfig.getParameter<int>("MinHitsLeft");
00121     minHitsRight_ = iConfig.getParameter<int>("MinHitsRight");
00122 
00123     //Track Open angle cut on delta cot(theta) and delta phi
00124     if (allowDeltaCot_)
00125         deltaCotTheta_ = iConfig.getParameter<double>("DeltaCotTheta");
00126     if (allowDeltaPhi_)
00127         deltaPhi_ = iConfig.getParameter<double>("DeltaPhi");
00128     if (allowMinApproach_){
00129         minApproachLow_ = iConfig.getParameter<double>("MinApproachLow");
00130         minApproachHigh_ = iConfig.getParameter<double>("MinApproachHigh");
00131     }
00132 
00133     // if allow single track collection, by default False
00134     allowSingleLeg_ = iConfig.getParameter<bool>("AllowSingleLeg");
00135     rightBC_ = iConfig.getParameter<bool>("AllowRightBC");
00136 
00137     //track inner position dz cut, need RECO
00138     dzCut_ = iConfig.getParameter<double>("dz");
00139     //track analytical cross cut
00140     r_cut = iConfig.getParameter<double>("rCut");
00141     vtxChi2_ = iConfig.getParameter<double>("vtxChi2");
00142 
00143 
00144     theVertexFinder_ = new ConversionVertexFinder ( iConfig );
00145 
00146     thettbuilder_ = 0;
00147 
00148     //output
00149     ConvertedPhotonCollection_     = iConfig.getParameter<std::string>("convertedPhotonCollection");
00150 
00151     produces< reco::ConversionCollection >(ConvertedPhotonCollection_);
00152 
00153 }
00154 
00155 
00156 TrackerOnlyConversionProducer::~TrackerOnlyConversionProducer()
00157 {
00158 
00159    // do anything here that needs to be done at desctruction time
00160    // (e.g. close files, deallocate resources etc.)
00161   delete theVertexFinder_;
00162 }
00163 
00164 
00165 // ------------ method called to produce the data  ------------
00166     void
00167 TrackerOnlyConversionProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup)
00168 {
00169     using namespace edm;
00170 
00171     reco::ConversionCollection outputConvPhotonCollection;
00172     std::auto_ptr<reco::ConversionCollection> outputConvPhotonCollection_p(new reco::ConversionCollection);
00173 
00174     //std::cout << " TrackerOnlyConversionProducer::produce " << std::endl;
00175     //Read multiple track input collections
00176 
00177     edm::Handle<reco::ConversionTrackCollection> trackCollectionHandle;
00178     iEvent.getByLabel(src_,trackCollectionHandle);    
00179     
00180     edm::Handle<edm::View<reco::CaloCluster> > bcBarrelHandle;//TODO error handling if no collection found
00181     edm::Handle<edm::View<reco::CaloCluster> > bcEndcapHandle;//TODO check cluster type if BasicCluster or PFCluster
00182     if (allowTrackBC_){
00183         iEvent.getByLabel( bcBarrelCollection_, bcBarrelHandle);
00184         iEvent.getByLabel( bcEndcapCollection_, bcEndcapHandle);
00185     }
00186 
00187     edm::Handle<reco::VertexCollection> vertexHandle;
00188     reco::VertexCollection vertexCollection;
00189     if (usePvtx_){
00190         iEvent.getByLabel(vertexProducer_, vertexHandle);
00191         if (!vertexHandle.isValid()) {
00192             edm::LogError("TrackerOnlyConversionProducer") << "Error! Can't get the product primary Vertex Collection "<< "\n";
00193             usePvtx_ = false;
00194         }
00195         if (usePvtx_)
00196             vertexCollection = *(vertexHandle.product());
00197     }
00198 
00199     edm::ESHandle<TransientTrackBuilder> hTransientTrackBuilder;
00200     iSetup.get<TransientTrackRecord>().get("TransientTrackBuilder",hTransientTrackBuilder);
00201     thettbuilder_ = hTransientTrackBuilder.product();
00202 
00203     reco::Vertex the_pvtx;
00204     //because the priamry vertex is sorted by quality, the first one is the best
00205     if (!vertexCollection.empty())
00206         the_pvtx = *(vertexCollection.begin());
00207 
00208     if (trackCollectionHandle->size()> maxNumOfTrackInPU_ ){
00209         iEvent.put( outputConvPhotonCollection_p, ConvertedPhotonCollection_);
00210         return;
00211     }
00212 
00213     //2. select track by propagating
00214     //2.0 build Basic cluster geometry map to search in eta bounds for clusters
00215     std::multimap<double, reco::CaloClusterPtr> basicClusterPtrs;
00216     edm::Handle<edm::View<reco::CaloCluster> > bcHandle = bcBarrelHandle;
00217 
00218     if (allowTrackBC_){
00219         for (unsigned jj = 0; jj < 2; ++jj ){
00220             for (unsigned ii = 0; ii < bcHandle->size(); ++ii ) {
00221                 if (bcHandle->ptrAt(ii)->energy()>energyBC_)
00222                     basicClusterPtrs.insert(std::make_pair(bcHandle->ptrAt(ii)->position().eta(), bcHandle->ptrAt(ii)));
00223             }
00224             bcHandle = bcEndcapHandle;
00225         }
00226     }
00227 
00228     buildCollection( iEvent, iSetup, *trackCollectionHandle.product(), basicClusterPtrs, the_pvtx, outputConvPhotonCollection);//allow empty basicClusterPtrs
00229 
00230     outputConvPhotonCollection_p->assign(outputConvPhotonCollection.begin(), outputConvPhotonCollection.end());
00231     iEvent.put( outputConvPhotonCollection_p, ConvertedPhotonCollection_);
00232 
00233 }
00234 
00235 
00236 
00237 
00238 void TrackerOnlyConversionProducer::buildCollection(edm::Event& iEvent, const edm::EventSetup& iSetup,
00239                                                     const reco::ConversionTrackCollection& allTracks,
00240                                                     const std::multimap<double, reco::CaloClusterPtr>& basicClusterPtrs,
00241                                                     const reco::Vertex& the_pvtx,
00242                                                     reco::ConversionCollection & outputConvPhotonCollection){
00243 
00244   
00245   edm::ESHandle<TrackerGeometry> trackerGeomHandle;
00246   edm::ESHandle<MagneticField> magFieldHandle;
00247   iSetup.get<TrackerDigiGeometryRecord>().get( trackerGeomHandle );
00248   iSetup.get<IdealMagneticFieldRecord>().get( magFieldHandle );
00249   
00250     const TrackerGeometry* trackerGeom = trackerGeomHandle.product();
00251     const MagneticField* magField = magFieldHandle.product();;
00252 
00253     std::vector<math::XYZPoint> trackImpactPosition;
00254     trackImpactPosition.reserve(allTracks.size());//track impact position at ECAL
00255     std::vector<bool> trackValidECAL;//Does this track reach ECAL basic cluster (reach ECAL && match with BC)
00256     trackValidECAL.assign(allTracks.size(), false);
00257 
00258     std::vector<reco::CaloClusterPtr> trackMatchedBC;
00259     reco::CaloClusterPtr empty_bc;
00260     trackMatchedBC.assign(allTracks.size(), empty_bc);//TODO find a better way to avoid copy constructor
00261 
00262     std::vector<int> bcHandleId;//the associated BC handle id, -1 invalid, 0 barrel 1 endcap
00263     bcHandleId.assign(allTracks.size(), -1);
00264 
00265     std::multimap<double, int> trackInnerEta;//Track innermost state Eta map to TrackRef index, to be used in track pair sorting
00266 
00267 
00268     ConversionHitChecker hitChecker;
00269 
00270     
00271     //2 propagate all tracks into ECAL, record its eta and phi
00272     for (reco::ConversionTrackCollection::const_iterator tk_ref = allTracks.begin(); tk_ref != allTracks.end(); ++tk_ref ){
00273       const reco::Track* tk = tk_ref->trackRef().get()  ;
00274 
00275         //map TrackRef to Eta
00276       trackInnerEta.insert(std::make_pair(tk->innerMomentum().eta(), tk_ref-allTracks.begin()));
00277       
00278       if (allowTrackBC_){
00279         //check impact position then match with BC
00280             math::XYZPoint ew;
00281             if ( getTrackImpactPosition(tk, trackerGeom, magField, ew) ){
00282                 trackImpactPosition.push_back(ew);
00283 
00284                 reco::CaloClusterPtr closest_bc;//the closest matching BC to track
00285 
00286                 if ( getMatchedBC(basicClusterPtrs, ew, closest_bc) ){
00287                     trackMatchedBC[tk_ref-allTracks.begin()] = closest_bc;
00288                     trackValidECAL[tk_ref-allTracks.begin()] = true;
00289                     bcHandleId[tk_ref-allTracks.begin()] = (fabs(closest_bc->position().eta())>1.479)?1:0;
00290                 }
00291             } else {
00292                 trackImpactPosition.push_back(ew);
00293                 continue;
00294             }
00295 
00296         }
00297     }
00298 
00299 
00300 
00301 
00302     //3. pair up : to select one track from matched EBC, and select the other track to fit cot theta and phi open angle cut
00303     //TODO it is k-Closest pair of point problem
00304     //std::cout << " allTracks.size() " <<  allTracks.size() << std::endl;
00305     for(reco::ConversionTrackCollection::const_iterator ll = allTracks.begin(); ll != allTracks.end(); ++ ll ) {
00306       bool track1HighPurity=true;
00307       //std::cout << " Loop on allTracks " << std::endl;
00308       const  edm::RefToBase<reco::Track> & left = ll->trackRef();
00309       
00310       //TODO: This is a workaround, should be fixed with a proper function in the TTBuilder
00311       //(Note that the TrackRef and GsfTrackRef versions of the constructor are needed
00312       // to properly get refit tracks in the output vertex)
00313       reco::TransientTrack ttk_l;
00314       if (dynamic_cast<const reco::GsfTrack*>(left.get())) {
00315         ttk_l = thettbuilder_->build(left.castTo<reco::GsfTrackRef>());
00316       }
00317       else {
00318         ttk_l = thettbuilder_->build(left.castTo<reco::TrackRef>());
00319       }
00320       
00321 
00322       if ((allowTrackBC_ && !trackValidECAL[ll-allTracks.begin()]) )//this Left leg should have valid BC
00323         continue;
00324       
00325       if (the_pvtx.isValid()){
00326         if (!(trackD0Cut(left, the_pvtx)))   track1HighPurity=false;
00327       } else {
00328         if (!(trackD0Cut(left)))  track1HighPurity=false;
00329       }
00330 
00331       std::vector<int> right_candidates;//store all right legs passed the cut (theta/approach and ref pair)
00332       std::vector<double> right_candidate_theta, right_candidate_approach;
00333       std::vector<std::pair<bool, reco::Vertex> > vertex_candidates;
00334 
00335 
00336       for (reco::ConversionTrackCollection::const_iterator rr = ll+1; rr != allTracks.end(); ++ rr ) {
00337           bool track2HighPurity = true;
00338           bool highPurityPair = true;
00339           
00340           const  edm::RefToBase<reco::Track> & right = rr->trackRef();
00341        
00342           //TODO: This is a workaround, should be fixed with a proper function in the TTBuilder
00343           reco::TransientTrack ttk_r;
00344           if (dynamic_cast<const reco::GsfTrack*>(right.get())) {
00345             ttk_r = thettbuilder_->build(right.castTo<reco::GsfTrackRef>());
00346           }
00347           else {
00348             ttk_r = thettbuilder_->build(right.castTo<reco::TrackRef>());
00349           }
00350           //std::cout << " This track is " <<  right->algoName() << std::endl;
00351 
00352           
00353           //all vertexing preselection should go here
00354 
00355           //check for opposite charge
00356           if (  allowOppCharge_ && (left->charge()*right->charge() > 0) )  
00357             continue; //same sign, reject pair
00358 
00359           if ( (allowTrackBC_ && !trackValidECAL[rr-allTracks.begin()] && rightBC_) )// if right track matches ECAL
00360             continue;
00361           
00362           
00363           double approachDist = -999.;
00364           //apply preselection to track pair, unless one or both tracks are gsf
00365           if (!preselectTrackPair(ttk_l,ttk_r, approachDist) && left->algo()!=29 && right->algo()!=29) {
00366             continue;
00367           }
00368                     
00369           //do the actual vertex fit
00370           reco::Vertex theConversionVertex;//by default it is invalid          
00371           bool goodVertex = checkVertex(ttk_l, ttk_r, magField, theConversionVertex);
00372           
00373           //bail as early as possible in case the fit didn't return a good vertex
00374           if (!goodVertex) {
00375             continue;
00376           }
00377 
00378           
00379           
00380           //track pair pass the quality cut
00381           if (   !( (trackQualityFilter(left, true) && trackQualityFilter(right, false))
00382                   || (trackQualityFilter(left, false) && trackQualityFilter(right, true)) ) ) {
00383             highPurityPair=false;
00384           }
00385 
00386           if (the_pvtx.isValid()){
00387               if (!(trackD0Cut(right, the_pvtx))) track2HighPurity=false; 
00388           } else {
00389               if (!(trackD0Cut(right))) track2HighPurity=false; 
00390           }
00391 
00392 
00393           const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr> the_left  = std::make_pair(left, trackMatchedBC[ll-allTracks.begin()]);
00394           const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr> the_right = std::make_pair(right, trackMatchedBC[rr-allTracks.begin()]);
00395 
00396           
00397          
00398           //signature cuts, then check if vertex, then post-selection cuts
00399           highPurityPair=  highPurityPair && track1HighPurity &&  track2HighPurity && checkTrackPair(the_left, the_right) ;
00400           highPurityPair = highPurityPair && goodVertex && checkPhi(left, right, trackerGeom, magField, theConversionVertex) ;
00401 
00402           //if all cuts passed, go ahead to make conversion candidates
00403           std::vector<edm::RefToBase<reco::Track> > trackPairRef;
00404           trackPairRef.push_back(left);//left track
00405           trackPairRef.push_back(right);//right track
00406 
00407           std::vector<math::XYZVector> trackPin;
00408           std::vector<math::XYZVector> trackPout;
00409           std::vector<math::XYZPoint> trackInnPos;
00410           std::vector<uint8_t> nHitsBeforeVtx;
00411           std::vector<Measurement1DFloat> dlClosestHitToVtx;
00412 
00413           if (left->extra().isNonnull() && right->extra().isNonnull()){//only available on TrackExtra
00414             trackInnPos.push_back(  left->innerPosition());
00415             trackInnPos.push_back(  right->innerPosition());
00416             trackPin.push_back(left->innerMomentum());
00417             trackPin.push_back(right->innerMomentum());
00418             trackPout.push_back(left->outerMomentum());
00419             trackPout.push_back(right->outerMomentum());
00420           }
00421           
00422           if (ll->trajRef().isNonnull() && rr->trajRef().isNonnull()) {
00423             std::pair<uint8_t,Measurement1DFloat> leftWrongHits = hitChecker.nHitsBeforeVtx(*ll->trajRef().get(),theConversionVertex);
00424             std::pair<uint8_t,Measurement1DFloat> rightWrongHits = hitChecker.nHitsBeforeVtx(*rr->trajRef().get(),theConversionVertex);
00425             nHitsBeforeVtx.push_back(leftWrongHits.first);
00426             nHitsBeforeVtx.push_back(rightWrongHits.first);
00427             dlClosestHitToVtx.push_back(leftWrongHits.second);
00428             dlClosestHitToVtx.push_back(rightWrongHits.second);            
00429           }
00430           
00431           uint8_t nSharedHits = hitChecker.nSharedHits(*left.get(),*right.get());
00432 
00433           reco::CaloClusterPtrVector scPtrVec;
00434           //if using kinematic fit, check with chi2 post cut
00435           if (theConversionVertex.isValid()){
00436             const float chi2Prob = ChiSquaredProbability(theConversionVertex.chi2(), theConversionVertex.ndof());
00437             if (chi2Prob<vtxChi2_)  highPurityPair=false;
00438           }
00439 
00440           //std::cout << "  highPurityPair after vertex cut " <<  highPurityPair << std::endl;
00441           std::vector<math::XYZPoint> trkPositionAtEcal;
00442           std::vector<reco::CaloClusterPtr> matchingBC;
00443 
00444           if (allowTrackBC_){//TODO find out the BC ptrs if not doing matching, otherwise, leave it empty
00445               const int lbc_handle = bcHandleId[ll-allTracks.begin()],
00446                     rbc_handle = bcHandleId[rr-allTracks.begin()];
00447 
00448               trkPositionAtEcal.push_back(trackImpactPosition[ll-allTracks.begin()]);//left track
00449               if (trackValidECAL[rr-allTracks.begin()])//second track ECAL position may be invalid
00450                   trkPositionAtEcal.push_back(trackImpactPosition[rr-allTracks.begin()]);
00451 
00452               matchingBC.push_back(trackMatchedBC[ll-allTracks.begin()]);//left track
00453               scPtrVec.push_back(trackMatchedBC[ll-allTracks.begin()]);//left track
00454               if (trackValidECAL[rr-allTracks.begin()]){//second track ECAL position may be invalid
00455                   matchingBC.push_back(trackMatchedBC[rr-allTracks.begin()]);
00456                   if (!(trackMatchedBC[rr-allTracks.begin()] == trackMatchedBC[ll-allTracks.begin()])//avoid 1 bc 2 tk
00457                           && lbc_handle == rbc_handle )//avoid ptr from different collection
00458                       scPtrVec.push_back(trackMatchedBC[rr-allTracks.begin()]);
00459               }
00460           }
00461           const float minAppDist = approachDist;
00462 
00463           reco::Conversion::ConversionAlgorithm algo = reco::Conversion::algoByName(algoName_);
00464           float dummy=0;
00465           reco::Conversion  newCandidate(scPtrVec,  trackPairRef, trkPositionAtEcal, theConversionVertex, matchingBC, minAppDist,  trackInnPos, trackPin, trackPout, nHitsBeforeVtx, dlClosestHitToVtx, nSharedHits, dummy, algo );
00466           newCandidate.setQuality(reco::Conversion::highPurity,  highPurityPair);
00467           
00468           bool generalTracksOnly = ll->isTrackerOnly() && rr->isTrackerOnly() && !dynamic_cast<const reco::GsfTrack*>(ll->trackRef().get()) && !dynamic_cast<const reco::GsfTrack*>(rr->trackRef().get());
00469           bool arbitratedEcalSeeded = ll->isArbitratedEcalSeeded() && rr->isArbitratedEcalSeeded();
00470           bool arbitratedMerged = ll->isArbitratedMerged() && rr->isArbitratedMerged();
00471           bool arbitratedMergedEcalGeneral = ll->isArbitratedMergedEcalGeneral() && rr->isArbitratedMergedEcalGeneral();          
00472           
00473           newCandidate.setQuality(reco::Conversion::generalTracksOnly,  generalTracksOnly);
00474           newCandidate.setQuality(reco::Conversion::arbitratedEcalSeeded,  arbitratedEcalSeeded);
00475           newCandidate.setQuality(reco::Conversion::arbitratedMerged,  arbitratedMerged);
00476           newCandidate.setQuality(reco::Conversion::arbitratedMergedEcalGeneral,  arbitratedMergedEcalGeneral);          
00477           
00478           outputConvPhotonCollection.push_back(newCandidate);
00479 
00480       }
00481       
00482   }
00483 
00484 
00485 
00486 
00487 
00488 
00489 }
00490 
00491 
00492 
00493 
00494 
00495 //
00496 // member functions
00497 //
00498 
00499 inline bool TrackerOnlyConversionProducer::trackQualityFilter(const  edm::RefToBase<reco::Track>&   ref, bool isLeft){
00500     bool pass = true;
00501     if (isLeft){
00502         pass = (ref->normalizedChi2() < maxChi2Left_ && ref->found() >= minHitsLeft_);
00503     } else {
00504         pass = (ref->normalizedChi2() < maxChi2Right_ && ref->found() >= minHitsRight_);
00505     }
00506 
00507     return pass;
00508 }
00509 
00510 inline bool TrackerOnlyConversionProducer::trackD0Cut(const  edm::RefToBase<reco::Track>&  ref){
00511     //NOTE if not allow d0 cut, always true
00512     return ((!allowD0_) || !(ref->d0()*ref->charge()/ref->d0Error()<d0Cut_));
00513 }
00514 
00515 inline bool TrackerOnlyConversionProducer::trackD0Cut(const edm::RefToBase<reco::Track>&  ref, const reco::Vertex& the_pvtx){
00516     //
00517     return ((!allowD0_) || !(-ref->dxy(the_pvtx.position())*ref->charge()/ref->dxyError()<d0Cut_));
00518 }
00519 
00520 
00521 bool TrackerOnlyConversionProducer::getTrackImpactPosition(const reco::Track* tk_ref,
00522         const TrackerGeometry* trackerGeom, const MagneticField* magField,
00523         math::XYZPoint& ew){
00524 
00525     PropagatorWithMaterial propag( alongMomentum, 0.000511, magField );
00526     TrajectoryStateTransform transformer;
00527     ReferenceCountingPointer<Surface> ecalWall(
00528             new  BoundCylinder( GlobalPoint(0.,0.,0.), TkRotation<float>(),
00529                 SimpleCylinderBounds( 129, 129, -320.5, 320.5 ) ) );
00530     const float epsilon = 0.001;
00531     Surface::RotationType rot; // unit rotation matrix
00532     const float barrelRadius = 129.f;
00533     const float barrelHalfLength = 270.9f;
00534     const float endcapRadius = 171.1f;
00535     const float endcapZ = 320.5f;
00536     ReferenceCountingPointer<BoundCylinder>  theBarrel_(new BoundCylinder( Surface::PositionType(0,0,0), rot,
00537                 SimpleCylinderBounds( barrelRadius-epsilon, barrelRadius+epsilon, -barrelHalfLength, barrelHalfLength)));
00538     ReferenceCountingPointer<BoundDisk>      theNegativeEtaEndcap_(
00539             new BoundDisk( Surface::PositionType( 0, 0, -endcapZ), rot,
00540                 SimpleDiskBounds( 0, endcapRadius, -epsilon, epsilon)));
00541     ReferenceCountingPointer<BoundDisk>      thePositiveEtaEndcap_(
00542             new BoundDisk( Surface::PositionType( 0, 0, endcapZ), rot,
00543                 SimpleDiskBounds( 0, endcapRadius, -epsilon, epsilon)));
00544 
00545     //const TrajectoryStateOnSurface myTSOS = transformer.innerStateOnSurface(*(*ref), *trackerGeom, magField);
00546     const TrajectoryStateOnSurface myTSOS = transformer.outerStateOnSurface(*tk_ref, *trackerGeom, magField);
00547     TrajectoryStateOnSurface  stateAtECAL;
00548     stateAtECAL = propag.propagate(myTSOS, *theBarrel_);
00549     if (!stateAtECAL.isValid() || ( stateAtECAL.isValid() && fabs(stateAtECAL.globalPosition().eta() ) >1.479 )  ) {
00550         //endcap propagator
00551         if (myTSOS.globalPosition().eta() > 0.) {
00552             stateAtECAL = propag.propagate(myTSOS, *thePositiveEtaEndcap_);
00553         } else {
00554             stateAtECAL = propag.propagate(myTSOS, *theNegativeEtaEndcap_);
00555         }
00556     }       
00557     if (stateAtECAL.isValid()){
00558         ew = stateAtECAL.globalPosition();
00559         return true;
00560     }
00561     else
00562         return false;
00563 }
00564 
00565 bool TrackerOnlyConversionProducer::getMatchedBC(const std::multimap<double, reco::CaloClusterPtr>& bcMap, 
00566         const math::XYZPoint& trackImpactPosition,
00567         reco::CaloClusterPtr& closestBC){
00568     const double track_eta = trackImpactPosition.eta();
00569     const double track_phi = trackImpactPosition.phi();
00570 
00571     double min_eta = 999., min_phi = 999.;
00572     reco::CaloClusterPtr closest_bc;
00573     for (std::multimap<double, reco::CaloClusterPtr>::const_iterator bc = bcMap.lower_bound(track_eta - halfWayEta_);
00574             bc != bcMap.upper_bound(track_eta + halfWayEta_); ++bc){//use eta map to select possible BC collection then loop in
00575         const reco::CaloClusterPtr& ebc = bc->second;
00576         const double delta_eta = track_eta-(ebc->position().eta());
00577         const double delta_phi = reco::deltaPhi(track_phi, (ebc->position().phi()));
00578         if (fabs(delta_eta)<dEtaTkBC_ && fabs(delta_phi)<dPhiTkBC_){
00579             if (fabs(min_eta)>fabs(delta_eta) && fabs(min_phi)>fabs(delta_phi)){//take the closest to track BC
00580                 min_eta = delta_eta;
00581                 min_phi = delta_phi;
00582                 closest_bc = bc->second;
00583                 //TODO check if min_eta>delta_eta but min_phi<delta_phi
00584             }
00585         }
00586     }
00587 
00588     if (min_eta < 999.){
00589         closestBC = closest_bc;
00590         return true;
00591     } else
00592         return false;
00593 }
00594 
00595 bool TrackerOnlyConversionProducer::getMatchedBC(const reco::CaloClusterPtrVector& bcMap,
00596         const math::XYZPoint& trackImpactPosition,
00597         reco::CaloClusterPtr& closestBC){
00598     const double track_eta = trackImpactPosition.eta();
00599     const double track_phi = trackImpactPosition.phi();
00600 
00601     double min_eta = 999., min_phi = 999.;
00602     reco::CaloClusterPtr closest_bc;
00603     for (reco::CaloClusterPtrVector::const_iterator bc = bcMap.begin();
00604             bc != bcMap.end(); ++bc){//use eta map to select possible BC collection then loop in
00605         const reco::CaloClusterPtr& ebc = (*bc);
00606         const double delta_eta = track_eta-(ebc->position().eta());
00607         const double delta_phi = reco::deltaPhi(track_phi, (ebc->position().phi()));
00608         if (fabs(delta_eta)<dEtaTkBC_ && fabs(delta_phi)<dPhiTkBC_){
00609             if (fabs(min_eta)>fabs(delta_eta) && fabs(min_phi)>fabs(delta_phi)){//take the closest to track BC
00610                 min_eta = delta_eta;
00611                 min_phi = delta_phi;
00612                 closest_bc = ebc;
00613                 //TODO check if min_eta>delta_eta but min_phi<delta_phi
00614             }
00615         }
00616     }
00617 
00618     if (min_eta < 999.){
00619         closestBC = closest_bc;
00620         return true;
00621     } else
00622         return false;
00623 }
00624 
00625 //check track open angle of phi at vertex
00626 bool TrackerOnlyConversionProducer::checkPhi(const edm::RefToBase<reco::Track>& tk_l, const edm::RefToBase<reco::Track>& tk_r,
00627         const TrackerGeometry* trackerGeom, const MagneticField* magField,
00628         const reco::Vertex& vtx){
00629     if (!allowDeltaPhi_)
00630         return true;
00631     //if track has innermost momentum, check with innermost phi
00632     //if track also has valid vertex, propagate to vertex then calculate phi there
00633     //if track has no innermost momentum, just return true, because track->phi() makes no sense
00634     if (tk_l->extra().isNonnull() && tk_r->extra().isNonnull()){
00635         double iphi1 = tk_l->innerMomentum().phi(), iphi2 = tk_r->innerMomentum().phi();
00636         if (vtx.isValid()){
00637             PropagatorWithMaterial propag( anyDirection, 0.000511, magField );
00638             TrajectoryStateTransform transformer;
00639             double recoPhoR = vtx.position().Rho();
00640             Surface::RotationType rot;
00641             ReferenceCountingPointer<BoundCylinder>  theBarrel_(new BoundCylinder( Surface::PositionType(0,0,0), rot,
00642                         SimpleCylinderBounds( recoPhoR-0.001, recoPhoR+0.001, -fabs(vtx.position().z()), fabs(vtx.position().z()))));
00643             ReferenceCountingPointer<BoundDisk>      theDisk_(
00644                     new BoundDisk( Surface::PositionType( 0, 0, vtx.position().z()), rot,
00645                         SimpleDiskBounds( 0, recoPhoR, -0.001, 0.001)));
00646 
00647             const TrajectoryStateOnSurface myTSOS1 = transformer.innerStateOnSurface(*tk_l, *trackerGeom, magField);
00648             const TrajectoryStateOnSurface myTSOS2 = transformer.innerStateOnSurface(*tk_r, *trackerGeom, magField);
00649             TrajectoryStateOnSurface  stateAtVtx1, stateAtVtx2;
00650             stateAtVtx1 = propag.propagate(myTSOS1, *theBarrel_);
00651             if (!stateAtVtx1.isValid() ) {
00652                 stateAtVtx1 = propag.propagate(myTSOS1, *theDisk_);
00653             }
00654             if (stateAtVtx1.isValid()){
00655                 iphi1 = stateAtVtx1.globalDirection().phi();
00656             }
00657             stateAtVtx2 = propag.propagate(myTSOS2, *theBarrel_);
00658             if (!stateAtVtx2.isValid() ) {
00659                 stateAtVtx2 = propag.propagate(myTSOS2, *theDisk_);
00660             }
00661             if (stateAtVtx2.isValid()){
00662                 iphi2 = stateAtVtx2.globalDirection().phi();
00663             }
00664         }
00665         const double dPhi = reco::deltaPhi(iphi1, iphi2);
00666         return (fabs(dPhi) < deltaPhi_);
00667     } else {
00668         return true;
00669     }
00670 }
00671 
00672 bool TrackerOnlyConversionProducer::preselectTrackPair(const reco::TransientTrack &ttk_l, const reco::TransientTrack &ttk_r,
00673              double& appDist) {
00674   
00675 
00676   double dCotTheta =  1./tan(ttk_l.track().innerMomentum().theta()) - 1./tan(ttk_r.track().innerMomentum().theta());
00677   if (allowDeltaCot_ && (std::abs(dCotTheta) > deltaCotTheta_)) {
00678     return false;
00679   }
00680   
00681   //non-conversion hypothesis, reject prompt track pairs
00682   ClosestApproachInRPhi closest;
00683   closest.calculate(ttk_l.innermostMeasurementState(),ttk_r.innermostMeasurementState());
00684   if (!closest.status()) {
00685     return false;
00686   }
00687   
00688   if (closest.crossingPoint().perp() < r_cut) {
00689     return false;
00690   }
00691 
00692   
00693   //compute tangent point btw tracks (conversion hypothesis)
00694   TangentApproachInRPhi tangent;
00695   tangent.calculate(ttk_l.innermostMeasurementState(),ttk_r.innermostMeasurementState());
00696   if (!tangent.status()) {
00697     return false;
00698   }
00699   
00700   GlobalPoint tangentPoint = tangent.crossingPoint();
00701   double rho = tangentPoint.perp();
00702   
00703   //reject candidates well outside of tracker bounds
00704   if (rho > 120.0) {
00705     return false;
00706   }
00707   
00708   if (std::abs(tangentPoint.z()) > 300.0) {
00709     return false;
00710   }
00711   
00712   std::pair<GlobalTrajectoryParameters,GlobalTrajectoryParameters> trajs = tangent.trajectoryParameters();
00713   
00714   //very large separation in z, no hope
00715   if (std::abs(trajs.first.position().z() - trajs.second.position().z()) > dzCut_) {
00716     return false;
00717   }
00718   
00719   
00720   float minApproach = tangent.perpdist();
00721   appDist = minApproach;
00722   
00723   if (allowMinApproach_ && (minApproach < minApproachLow_ || minApproach > minApproachHigh_) ) {
00724     return false;
00725   }
00726   
00727   return true;
00728   
00729   
00730 }
00731 
00732 bool TrackerOnlyConversionProducer::checkTrackPair(const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr>& ll, 
00733         const std::pair<edm::RefToBase<reco::Track>, reco::CaloClusterPtr>& rr){
00734 
00735      const reco::CaloClusterPtr& bc_l = ll.second;//can be null, so check isNonnull()
00736     const reco::CaloClusterPtr& bc_r = rr.second;
00737     
00738     //The cuts should be ordered by considering if takes time and if cuts off many fakes
00739     if (allowTrackBC_){
00740         //check energy of BC
00741         double total_e_bc = 0;
00742         if (bc_l.isNonnull()) total_e_bc += bc_l->energy();
00743         if (rightBC_) 
00744             if (bc_r.isNonnull())
00745                 total_e_bc += bc_r->energy();
00746 
00747         if (total_e_bc < energyTotalBC_) return false;
00748     }
00749 
00750     return true;
00751 }
00752 
00753 
00754 
00755 //because reco::vertex uses track ref, so have to keep them
00756 bool TrackerOnlyConversionProducer::checkVertex(const reco::TransientTrack &ttk_l, const reco::TransientTrack &ttk_r, 
00757         const MagneticField* magField,
00758         reco::Vertex& the_vertex){
00759     bool found = false;
00760 
00761     std::vector<reco::TransientTrack>  pair;
00762     pair.push_back(ttk_l);
00763     pair.push_back(ttk_r);
00764    
00765     found = theVertexFinder_->run(pair, the_vertex);
00766 
00767 
00768 
00769     return found;
00770 }
00771 
00772