Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:27:10

0001 /** \class SETSeedFinder
0002     I. Bloch, E. James, S. Stoynev
0003  */
0004 
0005 #include "RecoMuon/MuonSeedGenerator/src/SETSeedFinder.h"
0006 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0007 #include "FWCore/Framework/interface/Event.h"
0008 #include "RecoMuon/TrackingTools/interface/MuonPatternRecoDumper.h"
0009 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0010 #include "TrackingTools/DetLayers/interface/DetLayer.h"
0011 #include "Geometry/CommonDetUnit/interface/GeomDet.h"
0012 #include "DataFormats/MuonDetId/interface/MuonSubdetId.h"
0013 #include "DataFormats/MuonDetId/interface/CSCDetId.h"
0014 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h"
0015 
0016 #include "TMath.h"
0017 
0018 using namespace edm;
0019 using namespace std;
0020 
0021 const string metname = "Muon|RecoMuon|SETMuonSeedFinder";
0022 
0023 SETSeedFinder::SETSeedFinder(const ParameterSet& parameterSet) : MuonSeedVFinder() {
0024   // Parameter set for the Builder
0025   ParameterSet trajectoryBuilderParameters = parameterSet.getParameter<ParameterSet>("SETTrajBuilderParameters");
0026   apply_prePruning = trajectoryBuilderParameters.getParameter<bool>("Apply_prePruning");
0027   // load pT seed parameters
0028   thePtExtractor = new MuonSeedPtExtractor(trajectoryBuilderParameters);
0029 }
0030 
0031 void SETSeedFinder::seeds(const MuonRecHitContainer& cluster, std::vector<TrajectorySeed>& result) {}
0032 
0033 // there is an existing sorter somewhere in the CMSSW code (I think) - delete that
0034 namespace {
0035   struct sorter {
0036     sorter() {}
0037     bool operator()(MuonTransientTrackingRecHit::MuonRecHitPointer const& hit_1,
0038                     MuonTransientTrackingRecHit::MuonRecHitPointer const& hit_2) const {
0039       return (hit_1->globalPosition().mag2() < hit_2->globalPosition().mag2());
0040     }
0041   };  // smaller first
0042   const sorter sortSegRadius;
0043 }  // namespace
0044 
0045 std::vector<SETSeedFinder::MuonRecHitContainer> SETSeedFinder::sortByLayer(MuonRecHitContainer& cluster) const {
0046   stable_sort(cluster.begin(), cluster.end(), sortSegRadius);
0047   //---- group hits in detector layers (if in same layer); the idea is that
0048   //---- some hits could not belong to a track simultaneously - these will be in a
0049   //---- group; two hits from one and the same group will not go to the same track
0050   std::vector<MuonRecHitContainer> MuonRecHitContainer_perLayer;
0051   if (!cluster.empty()) {
0052     int iHit = 0;
0053     MuonRecHitContainer hitsInThisLayer;
0054     hitsInThisLayer.push_back(cluster[iHit]);
0055     DetId detId = cluster[iHit]->hit()->geographicalId();
0056     const GeomDet* geomDet = theService->trackingGeometry()->idToDet(detId);
0057     while (iHit < int(cluster.size()) - 1) {
0058       DetId detId_2 = cluster[iHit + 1]->hit()->geographicalId();
0059       const GlobalPoint gp_nextHit = cluster[iHit + 1]->globalPosition();
0060 
0061       // this is the distance of the "second" hit to the "first" detector (containing the "first hit")
0062       float distanceToDetector = fabs(geomDet->surface().localZ(gp_nextHit));
0063 
0064       //---- hits from DT and CSC  could be very close in angle but incosistent with
0065       //---- belonging to a common track (and these are different surfaces);
0066       //---- also DT (and CSC now - 090822) hits from a station (in a pre-cluster) should be always in a group together;
0067       //---- take this into account and put such hits in a group together
0068 
0069       bool specialCase = false;
0070       if (detId.subdetId() == MuonSubdetId::DT && detId_2.subdetId() == MuonSubdetId::DT) {
0071         DTChamberId dtCh(detId);
0072         DTChamberId dtCh_2(detId_2);
0073         specialCase = (dtCh.station() == dtCh_2.station());
0074       } else if (detId.subdetId() == MuonSubdetId::CSC && detId_2.subdetId() == MuonSubdetId::CSC) {
0075         CSCDetId cscCh(detId);
0076         CSCDetId cscCh_2(detId_2);
0077         specialCase = (cscCh.station() == cscCh_2.station() && cscCh.ring() == cscCh_2.ring());
0078       }
0079 
0080       if (distanceToDetector < 0.001 || true == specialCase) {  // hardcoded value - remove!
0081         hitsInThisLayer.push_back(cluster[iHit + 1]);
0082       } else {
0083         specialCase = false;
0084         if (((cluster[iHit]->isDT() && cluster[iHit + 1]->isCSC()) ||
0085              (cluster[iHit]->isCSC() && cluster[iHit + 1]->isDT())) &&
0086             //---- what is the minimal distance between a DT and a CSC hit belonging
0087             //---- to a common track? (well, with "reasonable" errors; put 10 cm for now)
0088             fabs(cluster[iHit + 1]->globalPosition().mag() - cluster[iHit]->globalPosition().mag()) < 10.) {
0089           hitsInThisLayer.push_back(cluster[iHit + 1]);
0090           // change to Stoyan - now we also update the detID here... give it a try. IBL 080905
0091           detId = cluster[iHit + 1]->hit()->geographicalId();
0092           geomDet = theService->trackingGeometry()->idToDet(detId);
0093         } else if (!specialCase) {
0094           //---- put the group of hits in the vector (containing the groups of hits)
0095           //---- and continue with next layer (group)
0096           MuonRecHitContainer_perLayer.push_back(hitsInThisLayer);
0097           hitsInThisLayer.clear();
0098           hitsInThisLayer.push_back(cluster[iHit + 1]);
0099           detId = cluster[iHit + 1]->hit()->geographicalId();
0100           geomDet = theService->trackingGeometry()->idToDet(detId);
0101         }
0102       }
0103       ++iHit;
0104     }
0105     MuonRecHitContainer_perLayer.push_back(hitsInThisLayer);
0106   }
0107   return MuonRecHitContainer_perLayer;
0108 }
0109 //
0110 void SETSeedFinder::limitCombinatorics(std::vector<MuonRecHitContainer>& MuonRecHitContainer_perLayer) {
0111   const int maximumNumberOfCombinations = 1000000;
0112   unsigned nLayers = MuonRecHitContainer_perLayer.size();
0113   if (1 == nLayers) {
0114     return;
0115   }
0116   // maximal number of (segment) layers would be upto ~12; see next function
0117   // below is just a quick fix for a rare "overflow"
0118   if (MuonRecHitContainer_perLayer.size() > 15) {
0119     MuonRecHitContainer_perLayer.resize(1);
0120     return;
0121   }
0122 
0123   std::vector<double> sizeOfLayer(nLayers);
0124   //std::cout<<" nLayers = "<<nLayers<<std::endl;
0125   double nAllCombinations = 1.;
0126   for (unsigned int i = 0; i < nLayers; ++i) {
0127     //std::cout<<" i = "<<i<<" size = "<<MuonRecHitContainer_perLayer.at(i).size()<<std::endl;
0128     sizeOfLayer.at(i) = MuonRecHitContainer_perLayer.at(i).size();
0129     nAllCombinations *= MuonRecHitContainer_perLayer.at(i).size();
0130   }
0131   //std::cout<<"nAllCombinations = "<<nAllCombinations<<std::endl;
0132   //---- Erase most busy detector layers until we get less than maximumNumberOfCombinations combinations
0133   while (nAllCombinations > float(maximumNumberOfCombinations)) {
0134     std::vector<double>::iterator maxEl_it = max_element(sizeOfLayer.begin(), sizeOfLayer.end());
0135     int maxEl = maxEl_it - sizeOfLayer.begin();
0136     nAllCombinations /= MuonRecHitContainer_perLayer.at(maxEl).size();
0137     MuonRecHitContainer_perLayer.erase(MuonRecHitContainer_perLayer.begin() + maxEl);
0138     sizeOfLayer.erase(sizeOfLayer.begin() + maxEl);
0139   }
0140   return;
0141 }
0142 //
0143 std::vector<SETSeedFinder::MuonRecHitContainer> SETSeedFinder::findAllValidSets(
0144     const std::vector<SETSeedFinder::MuonRecHitContainer>& MuonRecHitContainer_perLayer) {
0145   std::vector<MuonRecHitContainer> allValidSets;
0146   // build all possible combinations (i.e valid sets; the algorithm name is after this feature -
0147   // SET algorithm)
0148   //
0149   // ugly... use recursive function?!
0150   // or implement Ingo's suggestion (a la ST)
0151   unsigned nLayers = MuonRecHitContainer_perLayer.size();
0152   if (1 == nLayers) {
0153     return allValidSets;
0154   }
0155   MuonRecHitContainer validSet;
0156   unsigned int iPos0 = 0;
0157   std::vector<unsigned int> iLayer(12);  // could there be more than 11 layers?
0158   std::vector<unsigned int> size(12);
0159   if (iPos0 < nLayers) {
0160     size.at(iPos0) = MuonRecHitContainer_perLayer.at(iPos0).size();
0161     for (iLayer[iPos0] = 0; iLayer[iPos0] < size[iPos0]; ++iLayer[iPos0]) {
0162       validSet.clear();
0163       validSet.push_back(MuonRecHitContainer_perLayer[iPos0][iLayer[iPos0]]);
0164       unsigned int iPos1 = 1;
0165       if (iPos1 < nLayers) {
0166         size.at(iPos1) = MuonRecHitContainer_perLayer.at(iPos1).size();
0167         for (iLayer[iPos1] = 0; iLayer[iPos1] < size[iPos1]; ++iLayer[iPos1]) {
0168           validSet.resize(iPos1);
0169           validSet.push_back(MuonRecHitContainer_perLayer[iPos1][iLayer[iPos1]]);
0170           unsigned int iPos2 = 2;
0171           if (iPos2 < nLayers) {
0172             size.at(iPos2) = MuonRecHitContainer_perLayer.at(iPos2).size();
0173             for (iLayer[iPos2] = 0; iLayer[iPos2] < size[iPos2]; ++iLayer[iPos2]) {
0174               validSet.resize(iPos2);
0175               validSet.push_back(MuonRecHitContainer_perLayer[iPos2][iLayer[iPos2]]);
0176               unsigned int iPos3 = 3;
0177               if (iPos3 < nLayers) {
0178                 size.at(iPos3) = MuonRecHitContainer_perLayer.at(iPos3).size();
0179                 for (iLayer[iPos3] = 0; iLayer[iPos3] < size[iPos3]; ++iLayer[iPos3]) {
0180                   validSet.resize(iPos3);
0181                   validSet.push_back(MuonRecHitContainer_perLayer[iPos3][iLayer[iPos3]]);
0182                   unsigned int iPos4 = 4;
0183                   if (iPos4 < nLayers) {
0184                     size.at(iPos4) = MuonRecHitContainer_perLayer.at(iPos4).size();
0185                     for (iLayer[iPos4] = 0; iLayer[iPos4] < size[iPos4]; ++iLayer[iPos4]) {
0186                       validSet.resize(iPos4);
0187                       validSet.push_back(MuonRecHitContainer_perLayer[iPos4][iLayer[iPos4]]);
0188                       unsigned int iPos5 = 5;
0189                       if (iPos5 < nLayers) {
0190                         size.at(iPos5) = MuonRecHitContainer_perLayer.at(iPos5).size();
0191                         for (iLayer[iPos5] = 0; iLayer[iPos5] < size[iPos5]; ++iLayer[iPos5]) {
0192                           validSet.resize(iPos5);
0193                           validSet.push_back(MuonRecHitContainer_perLayer[iPos5][iLayer[iPos5]]);
0194                           unsigned int iPos6 = 6;
0195                           if (iPos6 < nLayers) {
0196                             size.at(iPos6) = MuonRecHitContainer_perLayer.at(iPos6).size();
0197                             for (iLayer[iPos6] = 0; iLayer[iPos6] < size[iPos6]; ++iLayer[iPos6]) {
0198                               validSet.resize(iPos6);
0199                               validSet.push_back(MuonRecHitContainer_perLayer[iPos6][iLayer[iPos6]]);
0200                               unsigned int iPos7 = 7;
0201                               if (iPos7 < nLayers) {
0202                                 size.at(iPos7) = MuonRecHitContainer_perLayer.at(iPos7).size();
0203                                 for (iLayer[iPos7] = 0; iLayer[iPos7] < size[iPos7]; ++iLayer[iPos7]) {
0204                                   validSet.resize(iPos7);
0205                                   validSet.push_back(MuonRecHitContainer_perLayer[iPos7][iLayer[iPos7]]);
0206                                   unsigned int iPos8 = 8;
0207                                   if (iPos8 < nLayers) {
0208                                     size.at(iPos8) = MuonRecHitContainer_perLayer.at(iPos8).size();
0209                                     for (iLayer[iPos8] = 0; iLayer[iPos8] < size[iPos8]; ++iLayer[iPos8]) {
0210                                       validSet.resize(iPos8);
0211                                       validSet.push_back(MuonRecHitContainer_perLayer[iPos8][iLayer[iPos8]]);
0212                                       unsigned int iPos9 = 9;
0213                                       if (iPos9 < nLayers) {
0214                                         size.at(iPos9) = MuonRecHitContainer_perLayer.at(iPos9).size();
0215                                         for (iLayer[iPos9] = 0; iLayer[iPos9] < size[iPos9]; ++iLayer[iPos9]) {
0216                                           validSet.resize(iPos9);
0217                                           validSet.push_back(MuonRecHitContainer_perLayer[iPos9][iLayer[iPos9]]);
0218                                           unsigned int iPos10 = 10;
0219                                           if (iPos10 < nLayers) {
0220                                             size.at(iPos10) = MuonRecHitContainer_perLayer.at(iPos10).size();
0221                                             for (iLayer[iPos10] = 0; iLayer[iPos10] < size[iPos10]; ++iLayer[iPos10]) {
0222                                               validSet.resize(iPos10);
0223                                               validSet.push_back(MuonRecHitContainer_perLayer[iPos10][iLayer[iPos10]]);
0224                                               unsigned int iPos11 = 11;  // more?
0225                                               if (iPos11 < nLayers) {
0226                                                 size.at(iPos11) = MuonRecHitContainer_perLayer.at(iPos11).size();
0227                                                 for (iLayer[iPos11] = 0; iLayer[iPos11] < size[iPos11];
0228                                                      ++iLayer[iPos11]) {
0229                                                 }
0230                                               } else {
0231                                                 allValidSets.push_back(validSet);
0232                                               }
0233                                             }
0234                                           } else {
0235                                             allValidSets.push_back(validSet);
0236                                           }
0237                                         }
0238                                       } else {
0239                                         allValidSets.push_back(validSet);
0240                                       }
0241                                     }
0242                                   } else {
0243                                     allValidSets.push_back(validSet);
0244                                   }
0245                                 }
0246                               } else {
0247                                 allValidSets.push_back(validSet);
0248                               }
0249                             }
0250                           } else {
0251                             allValidSets.push_back(validSet);
0252                           }
0253                         }
0254                       } else {
0255                         allValidSets.push_back(validSet);
0256                       }
0257                     }
0258                   } else {
0259                     allValidSets.push_back(validSet);
0260                   }
0261                 }
0262               } else {
0263                 allValidSets.push_back(validSet);
0264               }
0265             }
0266           } else {
0267             allValidSets.push_back(validSet);
0268           }
0269         }
0270       } else {
0271         allValidSets.push_back(validSet);
0272       }
0273     }
0274   } else {
0275     allValidSets.push_back(validSet);
0276   }
0277   return allValidSets;
0278 }
0279 
0280 std::pair<int, int>  // or <bool, bool>
0281 SETSeedFinder::checkAngleDeviation(double dPhi_1, double dPhi_2) const {
0282   // Two conditions:
0283   // a) deviations should be only to one side (above some absolute value cut to avoid
0284   //    material effects; this should be refined)
0285   // b) deviatiation in preceding steps should be bigger due to higher magnetic field
0286   //    (again - a minimal value cut should be in place; this also should account for
0287   //     the small (Z) distances in overlaping CSC chambers)
0288 
0289   double mult = dPhi_1 * dPhi_2;
0290   int signVal = 1;
0291   if (fabs(dPhi_1) < fabs(dPhi_2)) {
0292     signVal = -1;
0293   }
0294   int signMult = -1;
0295   if (mult > 0)
0296     signMult = 1;
0297   std::pair<int, int> sign;
0298   sign = make_pair(signVal, signMult);
0299 
0300   return sign;
0301 }
0302 
0303 void SETSeedFinder::validSetsPrePruning(std::vector<SETSeedFinder::MuonRecHitContainer>& allValidSets) {
0304   //---- this actually is a pre-pruning; it does not include any fit information;
0305   //---- it is intended to remove only very "wild" segments from a set;
0306   //---- no "good" segment is to be lost (otherwise - widen the parameters)
0307 
0308   for (unsigned int iSet = 0; iSet < allValidSets.size(); ++iSet) {
0309     pre_prune(allValidSets[iSet]);
0310   }
0311 }
0312 
0313 void SETSeedFinder::pre_prune(SETSeedFinder::MuonRecHitContainer& validSet) const {
0314   unsigned nHits = validSet.size();
0315   if (nHits > 3) {  // to decide we need at least 4 measurements
0316     // any information could be used to make a decision for pruning
0317     // maybe dPhi (delta Phi) is enough
0318     std::vector<double> dPhi;
0319     double dPhi_tmp;
0320     bool wildCandidate;
0321     int pruneHit_tmp;
0322 
0323     for (unsigned int iHit = 1; iHit < nHits; ++iHit) {
0324       dPhi_tmp = validSet[iHit]->globalPosition().phi() - validSet[iHit - 1]->globalPosition().phi();
0325       dPhi.push_back(dPhi_tmp);
0326     }
0327     std::vector<int> pruneHit;
0328     //---- loop over all the hits in a set
0329 
0330     for (unsigned int iHit = 0; iHit < nHits; ++iHit) {
0331       double dPHI_MIN = 0.02;  //?? hardcoded - remove it
0332       if (iHit) {
0333         // if we have to remove the very first hit (iHit == 0) then
0334         // we'll probably be in trouble already
0335         wildCandidate = false;
0336         // actually 2D is bad only if not r-phi... Should I refine it?
0337         // a hit is a candidate for pruning only if dPhi > dPHI_MIN;
0338         // pruning decision is based on combination of hits characteristics
0339         if (4 == validSet[iHit - 1]->dimension() && 4 == validSet[iHit]->dimension() &&
0340             fabs(validSet[iHit]->globalPosition().phi() - validSet[iHit - 1]->globalPosition().phi()) > dPHI_MIN) {
0341           wildCandidate = true;
0342         }
0343         pruneHit_tmp = -1;
0344         if (wildCandidate) {
0345           // OK - this couple doesn't look good (and is from 4D segments); proceed...
0346           if (1 == iHit) {  // the first  and the last hits are special case
0347             if (4 == validSet[iHit + 1]->dimension() && 4 == validSet[iHit + 2]->dimension()) {  //4D?
0348               // is the picture better if we remove the second hit?
0349               dPhi_tmp = validSet[iHit + 1]->globalPosition().phi() - validSet[iHit - 1]->globalPosition().phi();
0350               // is the deviation what we expect (sign, not magnitude)?
0351               std::pair<int, int> sign = checkAngleDeviation(dPhi_tmp, dPhi[2]);
0352               if (1 == sign.first && 1 == sign.second) {
0353                 pruneHit_tmp = iHit;  // mark the hit 1 for removing
0354               }
0355             }
0356           } else if (iHit > 1 && iHit < validSet.size() - 1) {
0357             if (4 == validSet[0]->dimension() &&  // we rely on the first (most important) couple
0358                 4 == validSet[1]->dimension() && pruneHit.back() != int(iHit - 1) &&
0359                 pruneHit.back() != 1) {  // check if hits are already marked
0360               // decide which of the two hits should be removed (if any; preferably the outer one i.e.
0361               // iHit rather than iHit-1); here - check what we get by removing iHit
0362               dPhi_tmp = validSet[iHit + 1]->globalPosition().phi() - validSet[iHit - 1]->globalPosition().phi();
0363               // first couple is most important anyway so again compare to it
0364               std::pair<int, int> sign = checkAngleDeviation(dPhi[0], dPhi_tmp);
0365               if (1 == sign.first && 1 == sign.second) {
0366                 pruneHit_tmp = iHit;  // mark the hit iHit for removing
0367               } else {                // iHit is not to be removed; proceed...
0368                 // what if we remove (iHit - 1) instead of iHit?
0369                 dPhi_tmp = validSet[iHit + 1]->globalPosition().phi() - validSet[iHit]->globalPosition().phi();
0370                 std::pair<int, int> sign = checkAngleDeviation(dPhi[0], dPhi_tmp);
0371                 if (1 == sign.first && 1 == sign.second) {
0372                   pruneHit_tmp = iHit - 1;  // mark the hit (iHit -1) for removing
0373                 }
0374               }
0375             }
0376           } else {
0377             // the last hit: if picture is not good - remove it
0378             if (pruneHit.size() > 1 && pruneHit[pruneHit.size() - 1] < 0 && pruneHit[pruneHit.size() - 2] < 0) {
0379               std::pair<int, int> sign = checkAngleDeviation(dPhi[dPhi.size() - 2], dPhi[dPhi.size() - 1]);
0380               if (-1 == sign.first && -1 == sign.second) {  // here logic is a bit twisted
0381                 pruneHit_tmp = iHit;                        // mark the last hit for removing
0382               }
0383             }
0384           }
0385         }
0386         pruneHit.push_back(pruneHit_tmp);
0387       }
0388     }
0389     // }
0390     // actual pruning
0391     for (unsigned int iHit = 1; iHit < nHits; ++iHit) {
0392       int count = 0;
0393       if (pruneHit[iHit - 1] > 0) {
0394         validSet.erase(validSet.begin() + pruneHit[iHit - 1] - count);
0395         ++count;
0396       }
0397     }
0398   }
0399 }
0400 
0401 std::vector<SeedCandidate> SETSeedFinder::fillSeedCandidates(std::vector<MuonRecHitContainer>& allValidSets) {
0402   //---- we have the valid sets constructed; transform the information in an
0403   //---- apropriate form; meanwhile - estimate the momentum for a given set
0404 
0405   // RPCs should not be used (no parametrization)
0406   std::vector<SeedCandidate> seedCandidates_inCluster;
0407   // calculate and fill the inputs needed
0408   // loop over all valid sets
0409   for (unsigned int iSet = 0; iSet < allValidSets.size(); ++iSet) {
0410     //
0411     //std::cout<<"  This is SET number : "<<iSet<<std::endl;
0412     //for(unsigned int iHit = 0;iHit<allValidSets[iSet].size();++iHit){
0413     //std::cout<<"   measurements in the SET:  iHit = "<<iHit<<" pos = "<<allValidSets[iSet][iHit]->globalPosition()<<
0414     //" dim = "<<allValidSets[iSet][iHit]->dimension()<<std::endl;
0415     //}
0416 
0417     CLHEP::Hep3Vector momEstimate;
0418     int chargeEstimate;
0419     estimateMomentum(allValidSets[iSet], momEstimate, chargeEstimate);
0420     MuonRecHitContainer MuonRecHitContainer_theSet_prep;
0421     // currently hardcoded - will be in proper loop of course:
0422 
0423     SeedCandidate seedCandidates_inCluster_prep;
0424     seedCandidates_inCluster_prep.theSet = allValidSets[iSet];
0425     seedCandidates_inCluster_prep.momentum = momEstimate;
0426     seedCandidates_inCluster_prep.charge = chargeEstimate;
0427     seedCandidates_inCluster.push_back(seedCandidates_inCluster_prep);
0428     // END estimateMomentum
0429   }
0430   return seedCandidates_inCluster;
0431 }
0432 
0433 void SETSeedFinder::estimateMomentum(const MuonRecHitContainer& validSet,
0434                                      CLHEP::Hep3Vector& momEstimate,
0435                                      int& charge) const {
0436   int firstMeasurement = -1;
0437   int lastMeasurement = -1;
0438 
0439   // don't use 2D measurements for momentum estimation
0440 
0441   //if( 4==allValidSets[iSet].front()->dimension() &&
0442   //(allValidSets[iSet].front()->isCSC() || allValidSets[iSet].front()->isDT())){
0443   //firstMeasurement = 0;
0444   //}
0445   //else{
0446   // which is the "first" hit (4D)?
0447   for (unsigned int iMeas = 0; iMeas < validSet.size(); ++iMeas) {
0448     if (4 == validSet[iMeas]->dimension() && (validSet[iMeas]->isCSC() || validSet[iMeas]->isDT())) {
0449       firstMeasurement = iMeas;
0450       break;
0451     }
0452   }
0453   //}
0454 
0455   std::vector<double> momentum_estimate;
0456   double pT = 0.;
0457   MuonTransientTrackingRecHit::ConstMuonRecHitPointer firstHit;
0458   MuonTransientTrackingRecHit::ConstMuonRecHitPointer secondHit;
0459   // which is the second hit?
0460   for (int loop = 0; loop < 2; ++loop) {  // it is actually not used; to be removed
0461     // this is the last measurement
0462     if (!loop) {  // this is what is used currently
0463       // 23.04.09 : it becomes a problem with introduction of ME42 chambers -
0464       // the initial pT parametrization is incorrect for them
0465       for (int iMeas = validSet.size() - 1; iMeas > -1; --iMeas) {
0466         if (4 == validSet[iMeas]->dimension() && (validSet[iMeas]->isCSC() || validSet[iMeas]->isDT()) &&
0467             // below is a fix saying "don't use ME4 chambers for initial pT estimation";
0468             // not using ME41 should not be a big loss too (and is more "symmetric" solution)
0469             fabs(validSet[iMeas]->globalPosition().z()) < 1000.) {
0470           lastMeasurement = iMeas;
0471           break;
0472         }
0473       }
0474     } else {
0475       // this is the second measurement
0476       for (unsigned int iMeas = 1; iMeas < validSet.size(); ++iMeas) {
0477         if (4 == validSet[iMeas]->dimension() && (validSet[iMeas]->isCSC() || validSet[iMeas]->isDT())) {
0478           lastMeasurement = iMeas;
0479           break;
0480         }
0481       }
0482     }
0483     // only 2D measurements (it should have been already abandoned)
0484     if (-1 == lastMeasurement && -1 == firstMeasurement) {
0485       firstMeasurement = 0;
0486       lastMeasurement = validSet.size() - 1;
0487     }
0488     // because of the ME42 above lastMeasurement could be -1
0489     else if (-1 == lastMeasurement) {
0490       lastMeasurement = firstMeasurement;
0491     } else if (-1 == firstMeasurement) {
0492       firstMeasurement = lastMeasurement;
0493     }
0494 
0495     firstHit = validSet[firstMeasurement];
0496     secondHit = validSet[lastMeasurement];
0497     if (firstHit->isRPC() && secondHit->isRPC()) {  // remove all RPCs from here?
0498       momentum_estimate.push_back(300.);
0499       momentum_estimate.push_back(300.);
0500     } else {
0501       if (firstHit->isRPC()) {
0502         firstHit = secondHit;
0503       } else if (secondHit->isRPC()) {
0504         secondHit = firstHit;
0505       }
0506       //---- estimate pT given two hits
0507       //std::cout<<"   hits for initial pT estimate: first -> dim = "<<firstHit->dimension()<<" pos = "<<firstHit->globalPosition()<<
0508       //" , second -> "<<" dim = "<<secondHit->dimension()<<" pos = "<<secondHit->globalPosition()<<std::endl;
0509       //---- pT throws exception if hits are MB4
0510       // (no coding for them - 2D hits in the outer station)
0511       if (2 == firstHit->dimension() && 2 == secondHit->dimension()) {
0512         momentum_estimate.push_back(999999999.);
0513         momentum_estimate.push_back(999999999.);
0514       } else {
0515         momentum_estimate = thePtExtractor->pT_extract(firstHit, secondHit);
0516       }
0517     }
0518     pT = fabs(momentum_estimate[0]);
0519     if (true || pT > 40.) {  //it is skipped; we have to look at least into number of hits in the chamber actually...
0520       // and then decide which segment to use
0521       // use the last measurement, otherwise use the second; this is to be investigated
0522       break;
0523     }
0524   }
0525 
0526   const float pT_min = 1.99;  // many hardcoded - remove them!
0527   if (pT > 3000.) {
0528     pT = 3000.;
0529   } else if (pT < pT_min) {
0530     if (pT > 0) {
0531       pT = pT_min;
0532     } else if (pT > (-1) * pT_min) {
0533       pT = (-1) * pT_min;
0534     } else if (pT < -3000.) {
0535       pT = -3000;
0536     }
0537   }
0538   //std::cout<<"  THE pT from the parametrization: "<<momentum_estimate[0]<<std::endl;
0539   // estimate the charge of the track candidate from the delta phi of two segments:
0540   //int charge      = dPhi > 0 ? 1 : -1; // what we want is: dphi < 0 => charge = -1
0541   charge = momentum_estimate[0] > 0 ? 1 : -1;
0542 
0543   // we have the pT - get the 3D momentum estimate as well
0544 
0545   // this is already final info:
0546   double xHit = validSet[firstMeasurement]->globalPosition().x();
0547   double yHit = validSet[firstMeasurement]->globalPosition().y();
0548   double rHit = TMath::Sqrt(pow(xHit, 2) + pow(yHit, 2));
0549 
0550   double thetaInner = validSet[firstMeasurement]->globalPosition().theta();
0551   // if some of the segments is missing r-phi measurement then we should
0552   // use only the 4D phi estimate (also use 4D eta estimate only)
0553   // the direction is not so important (it will be corrected)
0554 
0555   double rTrack = (pT / (0.3 * 3.8)) * 100.;  //times 100 for conversion to cm!
0556 
0557   double par = -1. * (2. / charge) * (TMath::ASin(rHit / (2 * rTrack)));
0558   double sinPar = TMath::Sin(par);
0559   double cosPar = TMath::Cos(par);
0560 
0561   // calculate phi at coordinate origin (0,0,0).
0562   double sinPhiH = 1. / (2. * charge * rTrack) * (xHit + ((sinPar) / (cosPar - 1.)) * yHit);
0563   double cosPhiH = -1. / (2. * charge * rTrack) * (((sinPar) / (1. - cosPar)) * xHit + yHit);
0564 
0565   // finally set the return vector
0566 
0567   // try out the reco info:
0568   // should used into to theta directly here (rather than tan(atan2(...)))
0569   momEstimate = CLHEP::Hep3Vector(pT * cosPhiH, pT * sinPhiH, pT / TMath::Tan(thetaInner));
0570   //Hep3Vector momEstimate(6.97961,      5.89732,     -50.0855);
0571   const float minMomenum = 5.;  //hardcoded - remove it! same in SETFilter
0572   if (momEstimate.mag() < minMomenum) {
0573     int sign = (pT < 0.) ? -1 : 1;
0574     pT = sign * (fabs(pT) + 1);
0575     CLHEP::Hep3Vector momEstimate2(pT * cosPhiH, pT * sinPhiH, pT / TMath::Tan(thetaInner));
0576     momEstimate = momEstimate2;
0577     if (momEstimate.mag() < minMomenum) {
0578       pT = sign * (fabs(pT) + 1);
0579       CLHEP::Hep3Vector momEstimate3(pT * cosPhiH, pT * sinPhiH, pT / TMath::Tan(thetaInner));
0580       momEstimate = momEstimate3;
0581       if (momEstimate.mag() < minMomenum) {
0582         pT = sign * (fabs(pT) + 1);
0583         CLHEP::Hep3Vector momEstimate4(pT * cosPhiH, pT * sinPhiH, pT / TMath::Tan(thetaInner));
0584         momEstimate = momEstimate4;
0585       }
0586     }
0587   }
0588 }
0589 
0590 TrajectorySeed SETSeedFinder::makeSeed(const TrajectoryStateOnSurface& firstTSOS,
0591                                        const TransientTrackingRecHit::ConstRecHitContainer& hits) const {
0592   edm::OwnVector<TrackingRecHit> recHitsContainer;
0593   for (unsigned int iHit = 0; iHit < hits.size(); ++iHit) {
0594     recHitsContainer.push_back(hits.at(iHit)->hit()->clone());
0595   }
0596   PropagationDirection dir = oppositeToMomentum;
0597   if (useSegmentsInTrajectory) {
0598     dir = alongMomentum;  // why forward (for rechits) later?
0599   }
0600 
0601   PTrajectoryStateOnDet const& seedTSOS =
0602       trajectoryStateTransform::persistentState(firstTSOS, hits.at(0)->geographicalId().rawId());
0603   TrajectorySeed seed(seedTSOS, recHitsContainer, dir);
0604 
0605   //MuonPatternRecoDumper debug;
0606   //std::cout<<" firstTSOS = "<<debug.dumpTSOS(firstTSOS)<<std::endl;
0607   //std::cout<<" iTraj = ???"<<" hits = "<<range.second-range.first<<std::endl;
0608   //std::cout<<" nhits = "<<hits.size()<<std::endl;
0609   //for(unsigned int iRH=0;iRH<hits.size();++iRH){
0610   //std::cout<<" RH = "<<iRH+1<<" globPos = "<<hits.at(iRH)->globalPosition()<<std::endl;
0611   //}
0612   return seed;
0613 }