CMS 3D CMS Logo

SteppingHelixPropagator.cc

Go to the documentation of this file.
00001 
00013 //
00014 // Original Author:  Vyacheslav Krutelyov
00015 //         Created:  Fri Mar  3 16:01:24 CST 2006
00016 // $Id: SteppingHelixPropagator.cc,v 1.60 2008/12/04 00:27:02 slava77 Exp $
00017 //
00018 //
00019 
00020 
00021 #include "MagneticField/Engine/interface/MagneticField.h"
00022 #include "MagneticField/VolumeBasedEngine/interface/VolumeBasedMagneticField.h"
00023 #include "MagneticField/VolumeGeometry/interface/MagVolume.h"
00024 #include "MagneticField/Interpolation/interface/MFGrid.h"
00025 
00026 #include "Utilities/Timing/interface/TimingReport.h"
00027 
00028 #include "DataFormats/GeometrySurface/interface/Cylinder.h"
00029 #include "DataFormats/GeometrySurface/interface/Plane.h"
00030 #include "DataFormats/GeometrySurface/interface/Cone.h"
00031 
00032 #include "TrackingTools/GeomPropagators/interface/PropagationExceptions.h"
00033 
00034 #include "TrackPropagation/SteppingHelixPropagator/interface/SteppingHelixPropagator.h"
00035 
00036 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00037 
00038 #include <sstream>
00039 #include <typeinfo>
00040 
00041 SteppingHelixPropagator::SteppingHelixPropagator() :
00042   Propagator(anyDirection)
00043 {
00044   field_ = 0;
00045 }
00046 
00047 SteppingHelixPropagator::SteppingHelixPropagator(const MagneticField* field, 
00048                                                  PropagationDirection dir):
00049   Propagator(dir),
00050   unit66_(AlgebraicMatrixID())
00051 {
00052   field_ = field;
00053   vbField_ = dynamic_cast<const VolumeBasedMagneticField*>(field_);
00054   covRot_ = AlgebraicMatrix66();
00055   dCTransform_ = unit66_;
00056   debug_ = false;
00057   noMaterialMode_ = false;
00058   noErrorPropagation_ = false;
00059   applyRadX0Correction_ = true;
00060   useMagVolumes_ = true;
00061   useIsYokeFlag_ = true;
00062   useMatVolumes_ = true;
00063   useInTeslaFromMagField_ = false; //overrides behavior only if true
00064   returnTangentPlane_ = true;
00065   sendLogWarning_ = false;
00066   useTuningForL2Speed_ = false;
00067   for (int i = 0; i <= MAX_POINTS; i++){
00068     svBuf_[i].cov = AlgebraicSymMatrix66();
00069     svBuf_[i].matDCov = AlgebraicSymMatrix66();
00070     svBuf_[i].isComplete = true;
00071     svBuf_[i].isValid_ = true;
00072     svBuf_[i].hasErrorPropagated_ = !noErrorPropagation_;
00073   }
00074   defaultStep_ = 5.;
00075 
00076   ecShiftPos_ = 0;
00077   ecShiftNeg_ = 0;
00078 
00079 }
00080 
00081 TrajectoryStateOnSurface 
00082 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, const Plane& pDest) const {
00083   return propagateWithPath(ftsStart, pDest).first;
00084 }
00085 
00086 TrajectoryStateOnSurface 
00087 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, const Cylinder& cDest) const
00088 {
00089   return propagateWithPath(ftsStart, cDest).first;
00090 }
00091 
00092 FreeTrajectoryState
00093 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, const GlobalPoint& pDest) const
00094 {
00095   return propagateWithPath(ftsStart, pDest).first;
00096 }
00097 
00098 FreeTrajectoryState
00099 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, 
00100                                    const GlobalPoint& pDest1, const GlobalPoint& pDest2) const
00101 {
00102   return propagateWithPath(ftsStart, pDest1, pDest2).first;
00103 }
00104 
00105 FreeTrajectoryState
00106 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, 
00107                                    const reco::BeamSpot& beamSpot) const
00108 {
00109   return propagateWithPath(ftsStart, beamSpot).first;
00110 }
00111 
00112 
00113 std::pair<TrajectoryStateOnSurface, double> 
00114 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart, 
00115                                            const Plane& pDest) const {
00116 
00117   setIState(SteppingHelixStateInfo(ftsStart));
00118 
00119   const StateInfo& svCurrent = propagate(svBuf_[0], pDest);
00120 
00121   return TsosPP(svCurrent.getStateOnSurface(pDest), svCurrent.path());
00122 }
00123 
00124 std::pair<TrajectoryStateOnSurface, double> 
00125 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart, 
00126                                            const Cylinder& cDest) const {
00127 
00128   setIState(SteppingHelixStateInfo(ftsStart));
00129 
00130   const StateInfo& svCurrent = propagate(svBuf_[0], cDest);
00131 
00132   return TsosPP(svCurrent.getStateOnSurface(cDest, returnTangentPlane_), svCurrent.path());
00133 }
00134 
00135 
00136 std::pair<FreeTrajectoryState, double> 
00137 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart, 
00138                                            const GlobalPoint& pDest) const {
00139   setIState(SteppingHelixStateInfo(ftsStart));
00140 
00141   const StateInfo& svCurrent = propagate(svBuf_[0], pDest);
00142 
00143   FreeTrajectoryState ftsDest;
00144   svCurrent.getFreeState(ftsDest);
00145 
00146   return FtsPP(ftsDest, svCurrent.path());
00147 }
00148 
00149 std::pair<FreeTrajectoryState, double> 
00150 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart, 
00151                                            const GlobalPoint& pDest1, const GlobalPoint& pDest2) const {
00152 
00153   if ((pDest1-pDest2).mag() < 1e-10){
00154     if (sendLogWarning_){
00155       edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: the points should be at a bigger distance"
00156                                                 <<std::endl;
00157     }
00158     return FtsPP();
00159   }
00160   setIState(SteppingHelixStateInfo(ftsStart));
00161   
00162   const StateInfo& svCurrent = propagate(svBuf_[0], pDest1, pDest2);
00163 
00164   FreeTrajectoryState ftsDest;
00165   svCurrent.getFreeState(ftsDest);
00166 
00167   return FtsPP(ftsDest, svCurrent.path());
00168 }
00169 
00170 
00171 std::pair<FreeTrajectoryState, double>  
00172 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart,  
00173                                            const reco::BeamSpot& beamSpot) const {
00174   GlobalPoint pDest1(beamSpot.x0(), beamSpot.y0(), beamSpot.z0());
00175   GlobalPoint pDest2(pDest1.x() + beamSpot.dxdz()*1e3, 
00176                      pDest1.y() + beamSpot.dydz()*1e3,
00177                      pDest1.z() + 1e3);
00178   return propagateWithPath(ftsStart, pDest1, pDest2);
00179 }
00180 
00181 const SteppingHelixStateInfo&
00182 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart, 
00183                                    const Surface& sDest) const {
00184   
00185   if (! sStart.isValid()){
00186     if (sendLogWarning_){
00187       edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
00188                                                 <<std::endl;
00189     }
00190     return invalidState_;
00191   }
00192 
00193   const Plane* pDest = dynamic_cast<const Plane*>(&sDest);
00194   if (pDest != 0) return propagate(sStart, *pDest);
00195 
00196   const Cylinder* cDest = dynamic_cast<const Cylinder*>(&sDest);
00197   if (cDest != 0) return propagate(sStart, *cDest);
00198 
00199   throw PropagationException("The surface is neither Cylinder nor Plane");
00200 
00201 }
00202 
00203 const SteppingHelixStateInfo&
00204 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart, 
00205                                    const Plane& pDest) const {
00206   
00207   if (! sStart.isValid()){
00208     if (sendLogWarning_){
00209       edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
00210                                                 <<std::endl;
00211     }    
00212     return invalidState_;
00213   }
00214   setIState(sStart);
00215   
00216   GlobalPoint rPlane = pDest.position();
00217   GlobalVector nPlane(pDest.rotation().zx(), pDest.rotation().zy(), pDest.rotation().zz());
00218 
00219   double pars[6] = { pDest.position().x(), pDest.position().y(), pDest.position().z(),
00220                      pDest.rotation().zx(), pDest.rotation().zy(), pDest.rotation().zz() };
00221   
00222   propagate(PLANE_DT, pars);
00223   
00224   //(re)set it before leaving: dir =1 (-1) if path increased (decreased) and 0 if it didn't change
00225   //need to implement this somewhere else as a separate function
00226   double lDir = 0;
00227   if (sStart.path() < svBuf_[cIndex_(nPoints_-1)].path()) lDir = 1.;
00228   if (sStart.path() > svBuf_[cIndex_(nPoints_-1)].path()) lDir = -1.;
00229   svBuf_[cIndex_(nPoints_-1)].dir = lDir;
00230   return svBuf_[cIndex_(nPoints_-1)];
00231 }
00232 
00233 const SteppingHelixStateInfo&
00234 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart, 
00235                                    const Cylinder& cDest) const {
00236   
00237   if (! sStart.isValid()){
00238     if (sendLogWarning_){
00239       edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
00240                                                 <<std::endl;
00241     }    
00242     return invalidState_;
00243   }
00244   setIState(sStart);
00245   
00246   double pars[6] = {0,0,0,0,0,0};
00247   pars[RADIUS_P] = cDest.radius();
00248 
00249   
00250   propagate(RADIUS_DT, pars);
00251   
00252   //(re)set it before leaving: dir =1 (-1) if path increased (decreased) and 0 if it didn't change
00253   //need to implement this somewhere else as a separate function
00254   double lDir = 0;
00255   if (sStart.path() < svBuf_[cIndex_(nPoints_-1)].path()) lDir = 1.;
00256   if (sStart.path() > svBuf_[cIndex_(nPoints_-1)].path()) lDir = -1.;
00257   svBuf_[cIndex_(nPoints_-1)].dir = lDir;
00258   return svBuf_[cIndex_(nPoints_-1)];
00259 }
00260 
00261 const SteppingHelixStateInfo&
00262 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart, 
00263                                    const GlobalPoint& pDest) const {
00264   
00265   if (! sStart.isValid()){
00266     if (sendLogWarning_){
00267       edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
00268                                                 <<std::endl;
00269     }    
00270     return invalidState_;
00271   }
00272   setIState(sStart);
00273   
00274   double pars[6] = {pDest.x(), pDest.y(), pDest.z(), 0, 0, 0};
00275 
00276   
00277   propagate(POINT_PCA_DT, pars);
00278   
00279   return svBuf_[cIndex_(nPoints_-1)];
00280 }
00281 
00282 const SteppingHelixStateInfo&
00283 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart, 
00284                                    const GlobalPoint& pDest1, const GlobalPoint& pDest2) const {
00285   
00286   if ((pDest1-pDest2).mag() < 1e-10 || !sStart.isValid()){
00287     if (sendLogWarning_){
00288       if ((pDest1-pDest2).mag() < 1e-10)
00289         edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: points are too close"
00290                                                   <<std::endl;
00291       if (!sStart.isValid())
00292         edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
00293                                                   <<std::endl;
00294     }
00295     return invalidState_;
00296   }
00297   setIState(sStart);
00298   
00299   double pars[6] = {pDest1.x(), pDest1.y(), pDest1.z(),
00300                     pDest2.x(), pDest2.y(), pDest2.z()};
00301   
00302   propagate(LINE_PCA_DT, pars);
00303   
00304   return svBuf_[cIndex_(nPoints_-1)];
00305 }
00306 
00307 void SteppingHelixPropagator::setIState(const SteppingHelixStateInfo& sStart) const {
00308   nPoints_ = 0;
00309   svBuf_[cIndex_(nPoints_)] = sStart; //do this anyways to have a fresh start
00310   if (sStart.isComplete ) {
00311     svBuf_[cIndex_(nPoints_)] = sStart;
00312     nPoints_++;
00313   } else {
00314     loadState(svBuf_[cIndex_(nPoints_)], sStart.p3, sStart.r3, sStart.q, sStart.cov,
00315               propagationDirection());
00316     nPoints_++;
00317   }
00318   svBuf_[cIndex_(0)].hasErrorPropagated_ = sStart.hasErrorPropagated_ & !noErrorPropagation_;
00319 }
00320 
00321 SteppingHelixPropagator::Result 
00322 SteppingHelixPropagator::propagate(SteppingHelixPropagator::DestType type, 
00323                                    const double pars[6], double epsilon)  const{
00324 
00325   static const std::string metname = "SteppingHelixPropagator";
00326   StateInfo* svCurrent = &svBuf_[cIndex_(nPoints_-1)];
00327 
00328   //check if it's going to work at all
00329   double tanDist = 0;
00330   double dist = 0;
00331   PropagationDirection refDirection = anyDirection;
00332   Result result = refToDest(type, (*svCurrent), pars, dist, tanDist, refDirection);
00333 
00334   if (result != SteppingHelixStateInfo::OK || fabs(dist) > 1e6){
00335     svCurrent->status_ = result;
00336     if (fabs(dist) > 1e6) svCurrent->status_ = SteppingHelixStateInfo::INACC;
00337     svCurrent->isValid_ = false;
00338     svCurrent->field = field_;
00339     if (sendLogWarning_){
00340       edm::LogWarning(metname)<<" Failed after first refToDest check with status "
00341                               <<SteppingHelixStateInfo::ResultName[result]
00342                               <<std::endl;
00343     }
00344     return result;
00345   }
00346 
00347   result = SteppingHelixStateInfo::UNDEFINED;
00348   bool makeNextStep = true;
00349   double dStep = defaultStep_;
00350   PropagationDirection dir,oldDir;
00351   dir = propagationDirection(); 
00352   oldDir = dir;
00353   int nOsc = 0;
00354 
00355   double distMag = 1e12;
00356   double tanDistMag = 1e12;
00357 
00358   double distMat = 1e12;
00359   double tanDistMat = 1e12;
00360 
00361   double tanDistNextCheck = -0.1;//just need a negative start val
00362   double tanDistMagNextCheck = -0.1;
00363   double tanDistMatNextCheck = -0.1;
00364   double oldDStep = 0;
00365   PropagationDirection oldRefDirection = propagationDirection();
00366 
00367   Result resultToMat = SteppingHelixStateInfo::UNDEFINED;
00368   Result resultToMag = SteppingHelixStateInfo::UNDEFINED;
00369 
00370   bool isFirstStep = true;
00371   bool expectNewMagVolume = false;
00372 
00373   int loopCount = 0;
00374   while (makeNextStep){
00375     dStep = defaultStep_;
00376     svCurrent = &svBuf_[cIndex_(nPoints_-1)];
00377     double curZ = svCurrent->r3.z();
00378     double curR = svCurrent->r3.perp();
00379     if ( fabs(curZ) < 440 && curR < 260) dStep = defaultStep_*2;
00380 
00381     //more such ifs might be scattered around
00382     //even though dStep is large, it will still make stops at each volume boundary
00383     if (useTuningForL2Speed_){
00384       dStep = 100.;
00385       if (! useIsYokeFlag_ && fabs(curZ) < 667 && curR > 380 && curR < 850){
00386         dStep = 5*(1+0.2*svCurrent->p3.mag());
00387       }
00388     }
00389 
00390     //    refDirection = propagationDirection();
00391 
00392     tanDistNextCheck -= oldDStep;
00393     tanDistMagNextCheck -= oldDStep;
00394     tanDistMatNextCheck -= oldDStep;
00395     
00396     if (tanDistNextCheck < 0){
00397       //use pre-computed values if it's the first step
00398       if (! isFirstStep) refToDest(type, (*svCurrent), pars, dist, tanDist, refDirection);
00399       // constrain allowed path for a tangential approach
00400       if (fabs(tanDist/dist) > 4) tanDist *= fabs(dist/tanDist*4.);
00401 
00402       tanDistNextCheck = fabs(tanDist)*0.5 - 0.5; //need a better guess (to-do)
00403       //reasonable limit
00404       if (tanDistNextCheck >  defaultStep_*20. ) tanDistNextCheck = defaultStep_*20.;
00405       oldRefDirection = refDirection;
00406     } else {
00407       tanDist  = tanDist > 0. ? tanDist - oldDStep : tanDist + oldDStep; 
00408       refDirection = oldRefDirection;
00409       if (debug_) LogTrace(metname)<<"Skipped refToDest: guess tanDist = "<<tanDist
00410                                    <<" next check at "<<tanDistNextCheck<<std::endl;
00411     }
00413     double fastSkipDist = fabs(dist) > fabs(tanDist) ? tanDist : dist;
00414 
00415     if (propagationDirection() == anyDirection){
00416       dir = refDirection;
00417     } else {
00418       dir = propagationDirection();
00419       if (fabs(tanDist)<0.1 && refDirection != dir ){
00420         //how did it get here?  nOsc++;
00421         dir = refDirection;
00422         if (debug_) LogTrace(metname)<<"NOTE: overstepped last time: switch direction (can do it if within 1 mm)"<<std::endl;
00423       }
00424     }    
00425 
00426     if (useMagVolumes_ && ! (fabs(dist) < fabs(epsilon))){//need to know the general direction
00427       if (tanDistMagNextCheck < 0){
00428         resultToMag = refToMagVolume((*svCurrent), dir, distMag, tanDistMag, fabs(fastSkipDist), expectNewMagVolume);
00429         // constrain allowed path for a tangential approach
00430         if (fabs(tanDistMag/distMag) > 4) tanDistMag *= fabs(distMag/tanDistMag*4.);
00431 
00432         tanDistMagNextCheck = fabs(tanDistMag)*0.5-0.5; //need a better guess (to-do)
00433         //reasonable limit; "turn off" checking if bounds are further than the destination
00434         if (tanDistMagNextCheck >  defaultStep_*20. 
00435             || fabs(dist) < fabs(distMag)
00436             || resultToMag ==SteppingHelixStateInfo::INACC) 
00437           tanDistMagNextCheck  = defaultStep_*20 > fabs(fastSkipDist) ? fabs(fastSkipDist) : defaultStep_*20;;  
00438         if (resultToMag != SteppingHelixStateInfo::INACC 
00439             && resultToMag != SteppingHelixStateInfo::OK) tanDistMagNextCheck = -1;
00440       } else {
00441         //      resultToMag = SteppingHelixStateInfo::OK;
00442         tanDistMag  = tanDistMag > 0. ? tanDistMag - oldDStep : tanDistMag + oldDStep; 
00443         if (debug_) LogTrace(metname)<<"Skipped refToMag: guess tanDistMag = "<<tanDistMag
00444                                      <<" next check at "<<tanDistMagNextCheck;
00445       }
00446     }
00447 
00448     if (useMatVolumes_ && ! (fabs(dist) < fabs(epsilon))){//need to know the general direction
00449       if (tanDistMatNextCheck < 0){
00450         resultToMat = refToMatVolume((*svCurrent), dir, distMat, tanDistMat, fabs(fastSkipDist));
00451         // constrain allowed path for a tangential approach
00452         if (fabs(tanDistMat/distMat) > 4) tanDistMat *= fabs(distMat/tanDistMat*4.);
00453 
00454         tanDistMatNextCheck = fabs(tanDistMat)*0.5-0.5; //need a better guess (to-do)
00455         //reasonable limit; "turn off" checking if bounds are further than the destination
00456         if (tanDistMatNextCheck >  defaultStep_*20. 
00457             || fabs(dist) < fabs(distMat)
00458             || resultToMat ==SteppingHelixStateInfo::INACC ) 
00459           tanDistMatNextCheck = defaultStep_*20 > fabs(fastSkipDist) ? fabs(fastSkipDist) : defaultStep_*20;
00460         if (resultToMat != SteppingHelixStateInfo::INACC 
00461             && resultToMat != SteppingHelixStateInfo::OK) tanDistMatNextCheck = -1;
00462       } else {
00463         //      resultToMat = SteppingHelixStateInfo::OK;
00464         tanDistMat  = tanDistMat > 0. ? tanDistMat - oldDStep : tanDistMat + oldDStep; 
00465         if (debug_) LogTrace(metname)<<"Skipped refToMat: guess tanDistMat = "<<tanDistMat
00466                                      <<" next check at "<<tanDistMatNextCheck;
00467       }
00468     }
00469 
00470     double rDotP = svCurrent->r3.dot(svCurrent->p3);
00471     if ((fabs(curZ) > 1.5e3 || curR >800.) 
00472         && ((dir == alongMomentum && rDotP > 0) 
00473             || (dir == oppositeToMomentum && rDotP < 0) )
00474         ){
00475       dStep = fabs(tanDist) -1e-12;
00476     }
00477     double tanDistMin = fabs(tanDist);
00478     if (tanDistMin > fabs(tanDistMag)+0.05 && 
00479         (resultToMag == SteppingHelixStateInfo::OK || resultToMag == SteppingHelixStateInfo::WRONG_VOLUME)){
00480       tanDistMin = fabs(tanDistMag)+0.05;     //try to step into the next volume
00481       expectNewMagVolume = true;
00482     } else expectNewMagVolume = false;
00483 
00484     if (tanDistMin > fabs(tanDistMat)+0.05 && resultToMat == SteppingHelixStateInfo::OK){
00485       tanDistMin = fabs(tanDistMat)+0.05;     //try to step into the next volume
00486       if (expectNewMagVolume) expectNewMagVolume = false;
00487     }
00488 
00489     if (tanDistMin*fabs(svCurrent->dEdx) > 0.5*svCurrent->p3.mag()){
00490       tanDistMin = 0.5*svCurrent->p3.mag()/fabs(svCurrent->dEdx);
00491       if (expectNewMagVolume) expectNewMagVolume = false;
00492     }
00493 
00494 
00495 
00496     double tanDistMinLazy = fabs(tanDistMin);
00497     if ((type == POINT_PCA_DT || type == LINE_PCA_DT)
00498         && fabs(tanDist) < 2.*fabs(tanDistMin) ){
00499       //being lazy here; the best is to take into account the curvature
00500       tanDistMinLazy = fabs(tanDistMin)*0.5;
00501     }
00502  
00503     if (fabs(tanDistMinLazy) < dStep){
00504       dStep = fabs(tanDistMinLazy); 
00505     }
00506 
00507     //keep this path length for the next step
00508     oldDStep = dStep;
00509 
00510     if (dStep > 1e-10 && ! (fabs(dist) < fabs(epsilon))){
00511       StateInfo* svNext = &svBuf_[cIndex_(nPoints_)];
00512       makeAtomStep((*svCurrent), (*svNext), dStep, dir, HEL_AS_F);
00513 //       if (useMatVolumes_ && expectNewMagVolume 
00514 //        && svCurrent->magVol == svNext->magVol){
00515 //      double tmpDist=0;
00516 //      double tmpDistMag = 0;
00517 //      if (refToMagVolume((*svNext), dir, tmpDist, tmpDistMag, fabs(dist)) != SteppingHelixStateInfo::OK){
00518 //      //the point appears to be outside, but findVolume claims the opposite
00519 //        dStep += 0.05*fabs(tanDistMag/distMag); oldDStep = dStep; //do it again with a bigger step
00520 //        if (debug_) LogTrace(metname)
00521 //          <<"Failed to get into new mag volume: will try with new bigger step "<<dStep<<std::endl;
00522 //        makeAtomStep((*svCurrent), (*svNext), dStep, dir, HEL_AS_F);    
00523 //      }
00524 //       }
00525       nPoints_++;    svCurrent = &svBuf_[cIndex_(nPoints_-1)];
00526       if (oldDir != dir){
00527         nOsc++;
00528         tanDistNextCheck = -1;//check dist after osc
00529         tanDistMagNextCheck = -1;
00530         tanDistMatNextCheck = -1;
00531       }
00532       oldDir = dir;
00533     }
00534 
00535     if (nOsc>1 && fabs(dStep)>epsilon){
00536       if (debug_) LogTrace(metname)<<"Ooops"<<std::endl;
00537     }
00538 
00539     if (fabs(dist) < fabs(epsilon)  ) result = SteppingHelixStateInfo::OK;
00540 
00541     if ((type == POINT_PCA_DT || type == LINE_PCA_DT )
00542         && fabs(dStep) < fabs(epsilon)  ){
00543       //now check if it's not a branch point (peek ahead at 1 cm)
00544       double nextDist = 0;
00545       double nextTanDist = 0;
00546       PropagationDirection nextRefDirection = anyDirection;
00547       StateInfo* svNext = &svBuf_[cIndex_(nPoints_)];
00548       makeAtomStep((*svCurrent), (*svNext), 1., dir, HEL_AS_F);
00549       nPoints_++;     svCurrent = &svBuf_[cIndex_(nPoints_-1)];
00550       refToDest(type, (*svCurrent), pars, nextDist, nextTanDist, nextRefDirection);
00551       if ( fabs(nextDist) > fabs(dist)){
00552         nPoints_--;      svCurrent = &svBuf_[cIndex_(nPoints_-1)];
00553         result = SteppingHelixStateInfo::OK;
00554         if (debug_){
00555           LogTrace(metname)<<"Found real local minimum in PCA"<<std::endl;
00556         }
00557       } else {
00558         //keep this trial point and continue
00559         dStep = defaultStep_;
00560         if (debug_){
00561           LogTrace(metname)<<"Found branch point in PCA"<<std::endl;
00562         }
00563       }
00564     }
00565 
00566     if (nPoints_ > MAX_STEPS*1./defaultStep_  || loopCount > MAX_STEPS*100
00567         || nOsc > 6 ) result = SteppingHelixStateInfo::FAULT;
00568 
00569     if (svCurrent->p3.mag() < 0.1 ) result = SteppingHelixStateInfo::RANGEOUT;
00570 
00571     curZ = svCurrent->r3.z();
00572     curR = svCurrent->r3.perp();
00573     if ( curR > 20000 || fabs(curZ) > 20000 ) result = SteppingHelixStateInfo::INACC;
00574 
00575     makeNextStep = result == SteppingHelixStateInfo::UNDEFINED;
00576     svCurrent->status_ = result;
00577     svCurrent->isValid_ = (result == SteppingHelixStateInfo::OK || makeNextStep );
00578     svCurrent->field = field_;
00579 
00580     isFirstStep = false;
00581     loopCount++;
00582   }
00583 
00584   if (sendLogWarning_ && result != SteppingHelixStateInfo::OK){
00585     edm::LogWarning(metname)<<" Propagation failed with status "
00586                             <<SteppingHelixStateInfo::ResultName[result]
00587                             <<std::endl;
00588     if (result == SteppingHelixStateInfo::RANGEOUT)
00589       edm::LogWarning(metname)<<" Momentum at last point is too low (<0.1) p_last = "
00590                               <<svCurrent->p3.mag()
00591                               <<std::endl;
00592     if (result == SteppingHelixStateInfo::INACC)
00593       edm::LogWarning(metname)<<" Went too far: the last point is at "<<svCurrent->r3
00594                               <<std::endl;
00595     if (result == SteppingHelixStateInfo::FAULT && nOsc > 6)
00596       edm::LogWarning(metname)<<" Infinite loop condidtion detected: going in cycles. Break after 6 cycles"
00597                               <<std::endl;
00598     if (result == SteppingHelixStateInfo::FAULT && nPoints_ > MAX_STEPS*1./defaultStep_)
00599       edm::LogWarning(metname)<<" Tired to go farther. Made too many steps: more than "
00600                               <<MAX_STEPS*1./defaultStep_
00601                               <<std::endl;
00602     
00603   }
00604 
00605   if (debug_){
00606     switch (type) {
00607     case RADIUS_DT:
00608       LogTrace(metname)<<"going to radius "<<pars[RADIUS_P]<<std::endl;
00609       break;
00610     case Z_DT:
00611       LogTrace(metname)<<"going to z "<<pars[Z_P]<<std::endl;
00612       break;
00613     case PATHL_DT:
00614       LogTrace(metname)<<"going to pathL "<<pars[PATHL_P]<<std::endl;
00615       break;
00616     case PLANE_DT:
00617       {
00618         Point rPlane(pars[0], pars[1], pars[2]);
00619         Vector nPlane(pars[3], pars[4], pars[5]);
00620         LogTrace(metname)<<"going to plane r0:"<<rPlane<<" n:"<<nPlane<<std::endl;
00621       }
00622       break;
00623     case POINT_PCA_DT:
00624       {
00625         Point rDest(pars[0], pars[1], pars[2]);
00626         LogTrace(metname)<<"going to PCA to point "<<rDest<<std::endl;
00627       }
00628       break;
00629     case LINE_PCA_DT:
00630       {
00631         Point rDest1(pars[0], pars[1], pars[2]);
00632         Point rDest2(pars[3], pars[4], pars[5]);
00633         LogTrace(metname)<<"going to PCA to line "<<rDest1<<" - "<<rDest2<<std::endl;
00634       }
00635       break;
00636     default:
00637       LogTrace(metname)<<"going to NOT IMPLEMENTED"<<std::endl;
00638       break;
00639     }
00640     LogTrace(metname)<<"Made "<<nPoints_-1<<" steps and stopped at(cur step) "<<svCurrent->r3<<" nOsc "<<nOsc<<std::endl;
00641   }
00642   
00643   return result;
00644 }
00645   
00646 void SteppingHelixPropagator::loadState(SteppingHelixPropagator::StateInfo& svCurrent, 
00647                                         const SteppingHelixPropagator::Vector& p3, 
00648                                         const SteppingHelixPropagator::Point& r3, int charge,
00649                                         const AlgebraicSymMatrix66& cov, PropagationDirection dir) const{
00650   static const std::string metname = "SteppingHelixPropagator";
00651 
00652   svCurrent.q = charge;
00653   svCurrent.p3 = p3;
00654   svCurrent.r3 = r3;
00655   svCurrent.dir = dir == alongMomentum ? 1.: -1.;
00656 
00657   svCurrent.path_ = 0; // this could've held the initial path
00658   svCurrent.radPath_ = 0;
00659 
00660   GlobalPoint gPointNegZ(svCurrent.r3.x(), svCurrent.r3.y(), -fabs(svCurrent.r3.z()));
00661   GlobalPoint gPointNorZ(svCurrent.r3.x(), svCurrent.r3.y(), svCurrent.r3.z());
00662 
00663   GlobalVector bf;
00664   // = field_->inTesla(gPoint);
00665   if (useMagVolumes_){
00666     if (vbField_ ){
00667       if (vbField_->isZSymmetric()){
00668         svCurrent.magVol = vbField_->findVolume(gPointNegZ);
00669       } else {
00670         svCurrent.magVol = vbField_->findVolume(gPointNorZ);
00671       }
00672       if (useIsYokeFlag_){
00673         double curRad = svCurrent.r3.perp();
00674         if (curRad > 380 && curRad < 850 && fabs(svCurrent.r3.z()) < 667){
00675           svCurrent.isYokeVol = isYokeVolume(svCurrent.magVol);
00676         } else {
00677           svCurrent.isYokeVol = false;
00678         }
00679       }
00680     } else {
00681       edm::LogWarning(metname)<<"Failed to cast into VolumeBasedMagneticField: fall back to the default behavior"<<std::endl;
00682       svCurrent.magVol = 0;
00683     }
00684     if (debug_){
00685       LogTrace(metname)<<"Got volume at "<<svCurrent.magVol<<std::endl;
00686     }
00687   }
00688   
00689   if (useMagVolumes_ && svCurrent.magVol != 0 && ! useInTeslaFromMagField_){
00690     if (vbField_->isZSymmetric()){
00691       bf = svCurrent.magVol->inTesla(gPointNegZ);
00692     } else {
00693       bf = svCurrent.magVol->inTesla(gPointNorZ);
00694     }
00695     if (r3.z() > 0 && vbField_->isZSymmetric() ){
00696       svCurrent.bf.set(-bf.x(), -bf.y(), bf.z());
00697     } else {
00698       svCurrent.bf.set(bf.x(), bf.y(), bf.z());
00699     }
00700   } else {
00701     GlobalPoint gPoint(r3.x(), r3.y(), r3.z());
00702     bf = field_->inTesla(gPoint);
00703     svCurrent.bf.set(bf.x(), bf.y(), bf.z());
00704   }
00705   if (svCurrent.bf.mag() < 1e-6) svCurrent.bf.set(0., 0., 1e-6);
00706 
00707 
00708 
00709   double dEdXPrime = 0;
00710   double dEdx = 0;
00711   double radX0 = 0;
00712   MatBounds rzLims;
00713   dEdx = getDeDx(svCurrent, dEdXPrime, radX0, rzLims);
00714   svCurrent.dEdx = dEdx;    svCurrent.dEdXPrime = dEdXPrime;
00715   svCurrent.radX0 = radX0;
00716   svCurrent.rzLims = rzLims;
00717 
00718   svCurrent.cov =cov;
00719 
00720   svCurrent.isComplete = true;
00721   svCurrent.isValid_ = true;
00722 
00723   if (debug_){
00724     LogTrace(metname)<<"Loaded at  path: "<<svCurrent.path()<<" radPath: "<<svCurrent.radPath()
00725                      <<" p3 "<<" pt: "<<svCurrent.p3.perp()<<" phi: "<<svCurrent.p3.phi()
00726                      <<" eta: "<<svCurrent.p3.eta()
00727                      <<" "<<svCurrent.p3
00728                      <<" r3: "<<svCurrent.r3
00729                      <<" bField: "<<svCurrent.bf.mag()
00730                      <<std::endl;
00731     LogTrace(metname)<<"Input Covariance in Global RF "<<cov<<std::endl;
00732   }
00733 }
00734 
00735 void SteppingHelixPropagator::getNextState(const SteppingHelixPropagator::StateInfo& svPrevious, 
00736                                            SteppingHelixPropagator::StateInfo& svNext,
00737                                            double dP, const SteppingHelixPropagator::Vector& tau,
00738                                            const SteppingHelixPropagator::Vector& drVec, double dS, double dX0,
00739                                            const AlgebraicMatrix66& dCovTransform) const{
00740   static const std::string metname = "SteppingHelixPropagator";
00741   svNext.q = svPrevious.q;
00742   svNext.dir = dS > 0.0 ? 1.: -1.; 
00743   svNext.p3 = tau;  svNext.p3*=(svPrevious.p3.mag() - svNext.dir*fabs(dP));
00744 
00745   svNext.r3 = svPrevious.r3; svNext.r3 += drVec;
00746 
00747   svNext.path_ = svPrevious.path() + dS;
00748   svNext.radPath_ = svPrevious.radPath() + dX0;
00749 
00750   GlobalPoint gPointNegZ(svNext.r3.x(), svNext.r3.y(), -fabs(svNext.r3.z()));
00751   GlobalPoint gPointNorZ(svNext.r3.x(), svNext.r3.y(), svNext.r3.z());
00752 
00753   GlobalVector bf; 
00754 
00755   if (useMagVolumes_){
00756     if (vbField_ != 0){
00757        if (vbField_->isZSymmetric()){
00758          svNext.magVol = vbField_->findVolume(gPointNegZ);
00759        } else {
00760          svNext.magVol = vbField_->findVolume(gPointNorZ);
00761        }
00762       if (useIsYokeFlag_){
00763         double curRad = svNext.r3.perp();
00764         if (curRad > 380 && curRad < 850 && fabs(svNext.r3.z()) < 667){
00765           svNext.isYokeVol = isYokeVolume(svNext.magVol);
00766         } else {
00767           svNext.isYokeVol = false;
00768         }
00769       }
00770     } else {
00771       LogTrace(metname)<<"Failed to cast into VolumeBasedMagneticField"<<std::endl;
00772       svNext.magVol = 0;
00773     }
00774     if (debug_){
00775       LogTrace(metname)<<"Got volume at "<<svNext.magVol<<std::endl;
00776     }
00777   }
00778 
00779   if (useMagVolumes_ && svNext.magVol != 0 && ! useInTeslaFromMagField_){
00780     if (vbField_->isZSymmetric()){
00781       bf = svNext.magVol->inTesla(gPointNegZ);
00782     } else {
00783       bf = svNext.magVol->inTesla(gPointNorZ);
00784     }
00785     if (svNext.r3.z() > 0  && vbField_->isZSymmetric() ){
00786       svNext.bf.set(-bf.x(), -bf.y(), bf.z());
00787     } else {
00788       svNext.bf.set(bf.x(), bf.y(), bf.z());
00789     }
00790   } else {
00791     GlobalPoint gPoint(svNext.r3.x(), svNext.r3.y(), svNext.r3.z());
00792     bf = field_->inTesla(gPoint);
00793     svNext.bf.set(bf.x(), bf.y(), bf.z());
00794   }
00795   if (svNext.bf.mag() < 1e-6) svNext.bf.set(0., 0., 1e-6);
00796   
00797   
00798   double dEdXPrime = 0;
00799   double dEdx = 0;
00800   double radX0 = 0;
00801   MatBounds rzLims;
00802   dEdx = getDeDx(svNext, dEdXPrime, radX0, rzLims);
00803   svNext.dEdx = dEdx;    svNext.dEdXPrime = dEdXPrime;
00804   svNext.radX0 = radX0;
00805   svNext.rzLims = rzLims;
00806 
00807   //update Emat only if it's valid
00808   svNext.hasErrorPropagated_ = svPrevious.hasErrorPropagated_;
00809   if (svPrevious.hasErrorPropagated_){
00810     //    svNext.cov = ROOT::Math::Similarity(dCovTransform, svPrevious.cov);
00811     AlgebraicMatrix66 tmp = dCovTransform*svPrevious.cov;
00812     ROOT::Math::AssignSym::Evaluate(svNext.cov, tmp*ROOT::Math::Transpose(dCovTransform));
00813 
00814     svNext.cov += svPrevious.matDCov;
00815   } else {
00816     //could skip dragging along the unprop. cov later .. now
00817     // svNext.cov = svPrevious.cov;
00818   }
00819 
00820   if (debug_){
00821     LogTrace(metname)<<"Now at  path: "<<svNext.path()<<" radPath: "<<svNext.radPath()
00822                      <<" p3 "<<" pt: "<<svNext.p3.perp()<<" phi: "<<svNext.p3.phi()
00823                      <<" eta: "<<svNext.p3.eta()
00824                      <<" "<<svNext.p3
00825                      <<" r3: "<<svNext.r3
00826                      <<" dPhi: "<<acos(svNext.p3.unit().dot(svPrevious.p3.unit()))
00827                      <<" bField: "<<svNext.bf.mag()
00828                      <<" dedx: "<<svNext.dEdx
00829                      <<std::endl;
00830     LogTrace(metname)<<"New Covariance "<<svNext.cov<<std::endl;
00831     LogTrace(metname)<<"Transf by dCovTransform "<<dCovTransform<<std::endl;
00832   }
00833 }
00834 
00835 void SteppingHelixPropagator::setRep(SteppingHelixPropagator::Basis& rep, 
00836                                      const SteppingHelixPropagator::Vector& tau) const{
00837   Vector zRep(0., 0., 1.);
00838   rep.lX = tau;
00839   rep.lY = zRep.cross(tau); rep.lY *= 1./tau.perp();
00840   rep.lZ = rep.lX.cross(rep.lY);
00841 }
00842 
00843 bool SteppingHelixPropagator::makeAtomStep(SteppingHelixPropagator::StateInfo& svCurrent,
00844                                            SteppingHelixPropagator::StateInfo& svNext,
00845                                            double dS, 
00846                                            PropagationDirection dir, 
00847                                            SteppingHelixPropagator::Fancy fancy) const{
00848   static const std::string metname = "SteppingHelixPropagator";
00849   if (debug_){
00850     LogTrace(metname)<<"Make atom step "<<svCurrent.path()<<" with step "<<dS<<" in direction "<<dir<<std::endl;
00851   }
00852 
00853   double dP = 0;
00854   Vector tau = svCurrent.p3; tau *= 1./tau.mag();
00855   Vector tauNext(tau);
00856   Vector drVec;
00857 
00858   dS = dir == alongMomentum ? fabs(dS) : -fabs(dS);
00859 
00860 
00861   double radX0 = 1e24;
00862 
00863   switch (fancy){
00864   case HEL_AS_F:
00865   case HEL_ALL_F:{
00866     double p0 = svCurrent.p3.mag();
00867     double b0 = svCurrent.bf.mag();
00868 
00869     //get to the mid-point first
00870     double phi = 0.0029979*svCurrent.q*b0/p0*dS/2.;
00871     bool phiSmall = fabs(phi) < 3e-8;
00872 
00873     double cosPhi = cos(phi);
00874     double sinPhi = sin(phi);
00875 
00876     double oneLessCosPhi = 1.-cosPhi;
00877     double oneLessCosPhiOPhi = oneLessCosPhi/phi;
00878     double sinPhiOPhi = sinPhi/phi;
00879     double phiLessSinPhiOPhi = 1 - sinPhiOPhi;
00880     if (phiSmall){
00881       oneLessCosPhi = 0.5*phi*phi;//*(1.- phi*phi/12.);
00882       oneLessCosPhiOPhi = 0.5*phi;//*(1.- phi*phi/12.);
00883       sinPhiOPhi = 1. - phi*phi/6.;
00884       phiLessSinPhiOPhi = phi*phi/6.;//*(1. - phi*phi/20.);
00885     }
00886 
00887     Vector bHat = svCurrent.bf; bHat *= 1./bHat.mag();
00888     Vector btVec(bHat.cross(tau));
00889     Vector bbtVec(bHat.cross(btVec));
00890 
00891     //don't need it here    tauNext = tau + bbtVec*oneLessCosPhi - btVec*sinPhi;
00892     drVec = tau; drVec += bbtVec*phiLessSinPhiOPhi; drVec -= btVec*oneLessCosPhiOPhi;
00893     drVec *= dS/2.;
00894 
00895     double dEdx = svCurrent.dEdx;
00896     double dEdXPrime = svCurrent.dEdXPrime;
00897     radX0 = svCurrent.radX0;
00898     dP = dEdx*dS;
00899 
00900     //improve with above values:
00901     drVec += svCurrent.r3;
00902     GlobalVector bfGV;
00903     Vector bf; //(bfGV.x(), bfGV.y(), bfGV.z());
00904     // = svCurrent.magVol->inTesla(GlobalPoint(drVec.x(), drVec.y(), -fabs(drVec.z())));
00905     if (useMagVolumes_ && svCurrent.magVol != 0 && ! useInTeslaFromMagField_){
00906       // this negative-z business will break at some point
00907       if (vbField_->isZSymmetric()){
00908         bfGV = svCurrent.magVol->inTesla(GlobalPoint(drVec.x(), drVec.y(), -fabs(drVec.z())));
00909       } else {
00910         bfGV = svCurrent.magVol->inTesla(GlobalPoint(drVec.x(), drVec.y(), drVec.z()));
00911       }
00912       if (drVec.z() > 0 && vbField_->isZSymmetric()){
00913         bf.set(-bfGV.x(), -bfGV.y(), bfGV.z());
00914       } else {
00915         bf.set(bfGV.x(), bfGV.y(), bfGV.z());
00916       }
00917     } else {
00918       bfGV = field_->inTesla(GlobalPoint(drVec.x(), drVec.y(), drVec.z()));
00919       bf.set(bfGV.x(), bfGV.y(), bfGV.z());
00920     }
00921     b0 = bf.mag();
00922     if (b0 < 1e-6) {
00923       b0 = 1e-6;
00924       bf.set(0., 0., 1e-6);
00925     }
00926     if (debug_){
00927       LogTrace(metname)<<"Improved b "<<b0
00928                        <<" at r3 "<<drVec<<std::endl;
00929     }
00930 
00931     if (fabs((b0-svCurrent.bf.mag())*dS) > 1){
00932       //missed the mag volume boundary?
00933       if (debug_){
00934         LogTrace(metname)<<"Large bf*dS change "<<fabs((b0-svCurrent.bf.mag())*dS)
00935                          <<" --> recalc dedx"<<std::endl;
00936       }
00937       svNext.r3 = drVec;
00938       svNext.bf = bf;
00939       svNext.p3 = svCurrent.p3;
00940       svNext.isYokeVol = svCurrent.isYokeVol;
00941       MatBounds rzTmp;
00942       dEdx = getDeDx(svNext, dEdXPrime, radX0, rzTmp);
00943       dP = dEdx*dS;      
00944       if (debug_){
00945         LogTrace(metname)<<"New dEdX= "<<dEdx
00946                          <<" dP= "<<dP
00947                          <<" for p0 "<<p0<<std::endl;
00948       }
00949     }
00950     //p0 is mid-way and b0 from mid-point
00951     p0 += dP/2.; p0 = p0 < 1e-2 ? 1e-2 : p0;
00952 
00953     phi = 0.0029979*svCurrent.q*b0/p0*dS;
00954     phiSmall = fabs(phi) < 3e-8;
00955 
00956     if (phiSmall){
00957       sinPhi = phi;
00958       cosPhi = 1. -phi*phi/2;
00959       oneLessCosPhi = 0.5*phi*phi;//*(1.- phi*phi/12.); //<-- ~below double-precision for phi<3e-8
00960       oneLessCosPhiOPhi = 0.5*phi;//*(1.- phi*phi/12.);
00961       sinPhiOPhi = 1. - phi*phi/6.;
00962       phiLessSinPhiOPhi = phi*phi/6.;//*(1. - phi*phi/20.);
00963     }else {
00964       cosPhi = cos(phi); 
00965       sinPhi = sin(phi);
00966       oneLessCosPhi = 1.-cosPhi;
00967       oneLessCosPhiOPhi = oneLessCosPhi/phi;
00968       sinPhiOPhi = sinPhi/phi;
00969       phiLessSinPhiOPhi = 1. - sinPhiOPhi;
00970     }
00971 
00972     bHat = bf; bHat *= 1./bHat.mag();
00973     btVec = bHat.cross(tau);
00974     bbtVec = bHat.cross(btVec);
00975 
00976     tauNext = tau; tauNext += bbtVec*oneLessCosPhi; tauNext -= btVec*sinPhi;
00977     drVec = tau; drVec += bbtVec*phiLessSinPhiOPhi; drVec -= btVec*oneLessCosPhiOPhi;
00978     drVec *= dS;
00979     
00980     
00981     if (svCurrent.hasErrorPropagated_){
00982       double theta02 = 14.e-3/p0*sqrt(fabs(dS)/radX0); // .. drop log term (this is non-additive)
00983       theta02 *=theta02;
00984       if (applyRadX0Correction_){
00985         // this provides the integrand for theta^2
00986         // if summed up along the path, should result in 
00987         // theta_total^2 = Int_0^x0{ f(x)dX} = (13.6/p0)^2*x0*(1+0.036*ln(x0+1))
00988         // x0+1 above is to make the result infrared safe.
00989         double x0 = fabs(svCurrent.radPath());
00990         double dX0 = fabs(dS)/radX0;
00991         double alphaX0 = 13.6e-3/p0; alphaX0 *= alphaX0;
00992         double betaX0 = 0.038;
00993         theta02 = dX0*alphaX0*(1+betaX0*log(x0+1))*(1 + betaX0*log(x0+1) + 2.*betaX0*x0/(x0+1) );
00994       }
00995       
00996       double epsilonP0 = 1.+ dP/p0;
00997       double omegaP0 = -dP/p0 + dS*dEdXPrime;      
00998       
00999 
01000       double dsp = dS/p0;
01001 
01002       Vector tbtVec(tau.cross(btVec));
01003 
01004       dCTransform_ = unit66_;
01005       //make everything in global
01006       //case I: no "spatial" derivatives |--> dCtr({1,2,3,4,5,6}{1,2,3}) = 0    
01007       dCTransform_(0,3) = dsp*(bHat.x()*tbtVec.x() 
01008                                + cosPhi*tau.x()*bbtVec.x()
01009                                + ((1.-bHat.x()*bHat.x()) + phi*tau.x()*btVec.x())*sinPhiOPhi);
01010 
01011       dCTransform_(0,4) = dsp*(bHat.z()*oneLessCosPhiOPhi + bHat.x()*tbtVec.y()
01012                                + cosPhi*tau.y()*bbtVec.x() 
01013                                + (-bHat.x()*bHat.y() + phi*tau.y()*btVec.x())*sinPhiOPhi);
01014       dCTransform_(0,5) = dsp*(-bHat.y()*oneLessCosPhiOPhi + bHat.x()*tbtVec.z()
01015                                + cosPhi*tau.z()*bbtVec.x()
01016                                + (-bHat.x()*bHat.z() + phi*tau.z()*btVec.x())*sinPhiOPhi);
01017 
01018       dCTransform_(1,3) = dsp*(-bHat.z()*oneLessCosPhiOPhi + bHat.y()*tbtVec.x()
01019                                + cosPhi*tau.x()*bbtVec.y()
01020                                + (-bHat.x()*bHat.y() + phi*tau.x()*btVec.y())*sinPhiOPhi);
01021       dCTransform_(1,4) = dsp*(bHat.y()*tbtVec.y() 
01022                                + cosPhi*tau.y()*bbtVec.y()
01023                                + ((1.-bHat.y()*bHat.y()) + phi*tau.y()*btVec.y())*sinPhiOPhi);
01024       dCTransform_(1,5) = dsp*(bHat.x()*oneLessCosPhiOPhi + bHat.y()*tbtVec.z()
01025                                + cosPhi*tau.z()*bbtVec.y() 
01026                                + (-bHat.y()*bHat.z() + phi*tau.z()*btVec.y())*sinPhiOPhi);
01027 
01028       dCTransform_(2,3) = dsp*(bHat.y()*oneLessCosPhiOPhi + bHat.z()*tbtVec.x()
01029                                + cosPhi*tau.x()*bbtVec.z() 
01030                                + (-bHat.x()*bHat.z() + phi*tau.x()*btVec.z())*sinPhiOPhi);
01031       dCTransform_(2,4) = dsp*(-bHat.x()*oneLessCosPhiOPhi + bHat.z()*tbtVec.y()
01032                                + cosPhi*tau.y()*bbtVec.z()
01033                                + (-bHat.y()*bHat.z() + phi*tau.y()*btVec.z())*sinPhiOPhi);
01034       dCTransform_(2,5) = dsp*(bHat.z()*tbtVec.z() 
01035                                + cosPhi*tau.z()*bbtVec.z()
01036                                + ((1.-bHat.z()*bHat.z()) + phi*tau.z()*btVec.z())*sinPhiOPhi);
01037 
01038 
01039       dCTransform_(3,3) = epsilonP0*(1. - oneLessCosPhi*(1.-bHat.x()*bHat.x())
01040                                      + phi*tau.x()*(cosPhi*btVec.x() - sinPhi*bbtVec.x()))
01041         + omegaP0*tau.x()*tauNext.x();
01042       dCTransform_(3,4) = epsilonP0*(bHat.x()*bHat.y()*oneLessCosPhi + bHat.z()*sinPhi
01043                                      + phi*tau.y()*(cosPhi*btVec.x() - sinPhi*bbtVec.x()))
01044         + omegaP0*tau.y()*tauNext.x();
01045       dCTransform_(3,5) = epsilonP0*(bHat.x()*bHat.z()*oneLessCosPhi - bHat.y()*sinPhi
01046                                      + phi*tau.z()*(cosPhi*btVec.x() - sinPhi*bbtVec.x()))
01047         + omegaP0*tau.z()*tauNext.x();
01048 
01049       dCTransform_(4,3) = epsilonP0*(bHat.x()*bHat.y()*oneLessCosPhi - bHat.z()*sinPhi
01050                                      + phi*tau.x()*(cosPhi*btVec.y() - sinPhi*bbtVec.y()))
01051         + omegaP0*tau.x()*tauNext.y();
01052       dCTransform_(4,4) = epsilonP0*(1. - oneLessCosPhi*(1.-bHat.y()*bHat.y())
01053                                      + phi*tau.y()*(cosPhi*btVec.y() - sinPhi*bbtVec.y()))
01054         + omegaP0*tau.y()*tauNext.y();
01055       dCTransform_(4,5) = epsilonP0*(bHat.y()*bHat.z()*oneLessCosPhi + bHat.x()*sinPhi
01056                                      + phi*tau.z()*(cosPhi*btVec.y() - sinPhi*bbtVec.y()))
01057         + omegaP0*tau.z()*tauNext.y();
01058     
01059       dCTransform_(5,3) = epsilonP0*(bHat.x()*bHat.z()*oneLessCosPhi + bHat.y()*sinPhi
01060                                      + phi*tau.x()*(cosPhi*btVec.z() - sinPhi*bbtVec.z()))
01061         + omegaP0*tau.x()*tauNext.z();
01062       dCTransform_(5,4) = epsilonP0*(bHat.y()*bHat.z()*oneLessCosPhi - bHat.x()*sinPhi
01063                                      + phi*tau.y()*(cosPhi*btVec.z() - sinPhi*bbtVec.z()))
01064         + omegaP0*tau.y()*tauNext.z();
01065       dCTransform_(5,5) = epsilonP0*(1. - oneLessCosPhi*(1.-bHat.z()*bHat.z())
01066                                      + phi*tau.z()*(cosPhi*btVec.z() - sinPhi*bbtVec.z()))
01067         + omegaP0*tau.z()*tauNext.z();
01068     
01069 
01070       Basis rep; setRep(rep, tauNext);
01071       //mind the sign of dS and dP (dS*dP < 0 allways)
01072       //covariance should grow no matter which direction you propagate
01073       //==> take abs values.
01074       //reset not needed: fill all below  svCurrent.matDCov *= 0.;
01075       double mulRR = theta02*dS*dS/3.;
01076       double mulRP = theta02*fabs(dS)*p0/2.;
01077       double mulPP = theta02*p0*p0;
01078       double losPP = dP*dP*1.6/fabs(dS)*(1.0 + p0*1e-3);
01079       //another guess .. makes sense for 1 cm steps 2./dS == 2 [cm] / dS [cm] at low pt
01080       //double it by 1TeV
01081       //not gaussian anyways
01082       // derived from the fact that sigma_p/eLoss ~ 0.08 after ~ 200 steps
01083 
01084       //symmetric RR part
01085       svCurrent.matDCov(0,0) = mulRR*(rep.lY.x()*rep.lY.x() + rep.lZ.x()*rep.lZ.x());
01086       svCurrent.matDCov(0,1) = mulRR*(rep.lY.x()*rep.lY.y() + rep.lZ.x()*rep.lZ.y());
01087       svCurrent.matDCov(0,2) = mulRR*(rep.lY.x()*rep.lY.z() + rep.lZ.x()*rep.lZ.z());
01088       svCurrent.matDCov(1,1) = mulRR*(rep.lY.y()*rep.lY.y() + rep.lZ.y()*rep.lZ.y());
01089       svCurrent.matDCov(1,2) = mulRR*(rep.lY.y()*rep.lY.z() + rep.lZ.y()*rep.lZ.z());
01090       svCurrent.matDCov(2,2) = mulRR*(rep.lY.z()*rep.lY.z() + rep.lZ.z()*rep.lZ.z());
01091 
01092       //symmetric PP part
01093       svCurrent.matDCov(3,3) = mulPP*(rep.lY.x()*rep.lY.x() + rep.lZ.x()*rep.lZ.x())
01094         + losPP*rep.lX.x()*rep.lX.x();
01095       svCurrent.matDCov(3,4) = mulPP*(rep.lY.x()*rep.lY.y() + rep.lZ.x()*rep.lZ.y())
01096         + losPP*rep.lX.x()*rep.lX.y();
01097       svCurrent.matDCov(3,5) = mulPP*(rep.lY.x()*rep.lY.z() + rep.lZ.x()*rep.lZ.z())
01098         + losPP*rep.lX.x()*rep.lX.z();
01099       svCurrent.matDCov(4,4) = mulPP*(rep.lY.y()*rep.lY.y() + rep.lZ.y()*rep.lZ.y())
01100         + losPP*rep.lX.y()*rep.lX.y();
01101       svCurrent.matDCov(4,5) = mulPP*(rep.lY.y()*rep.lY.z() + rep.lZ.y()*rep.lZ.z())
01102         + losPP*rep.lX.y()*rep.lX.z();
01103       svCurrent.matDCov(5,5) = mulPP*(rep.lY.z()*rep.lY.z() + rep.lZ.z()*rep.lZ.z())
01104         + losPP*rep.lX.z()*rep.lX.z();
01105 
01106       //still symmetric but fill 9 elements
01107       svCurrent.matDCov(0,3) = mulRP*(rep.lY.x()*rep.lY.x() + rep.lZ.x()*rep.lZ.x());
01108       svCurrent.matDCov(0,4) = mulRP*(rep.lY.x()*rep.lY.y() + rep.lZ.x()*rep.lZ.y());
01109       svCurrent.matDCov(0,5) = mulRP*(rep.lY.x()*rep.lY.z() + rep.lZ.x()*rep.lZ.z());
01110       svCurrent.matDCov(1,3) = mulRP*(rep.lY.x()*rep.lY.y() + rep.lZ.x()*rep.lZ.y());
01111       svCurrent.matDCov(1,4) = mulRP*(rep.lY.y()*rep.lY.y() + rep.lZ.y()*rep.lZ.y());
01112       svCurrent.matDCov(1,5) = mulRP*(rep.lY.y()*rep.lY.z() + rep.lZ.y()*rep.lZ.z());
01113       svCurrent.matDCov(2,3) = mulRP*(rep.lY.x()*rep.lY.z() + rep.lZ.x()*rep.lZ.z());
01114       svCurrent.matDCov(2,4) = mulRP*(rep.lY.y()*rep.lY.z() + rep.lZ.y()*rep.lZ.z());
01115       svCurrent.matDCov(2,5) = mulRP*(rep.lY.z()*rep.lY.z() + rep.lZ.z()*rep.lZ.z());
01116       
01117     }
01118     break;
01119   }
01120     //   case POL_1_F:
01121     //   case POL_2_F:
01122     //   case POL_M_F:
01123     //     break;
01124   default:
01125     break;
01126   }
01127 
01128   double pMag = svCurrent.p3.mag();
01129 
01130   if (dir == oppositeToMomentum) dP = fabs(dP);
01131   else if( dP < 0) { //the case of negative dP
01132     dP = -dP > pMag ? -pMag+1e-5 : dP;
01133   }
01134   
01135   getNextState(svCurrent, svNext, dP, tauNext, drVec, dS, dS/radX0,
01136                dCTransform_);
01137   return true;
01138 }
01139 
01140 double SteppingHelixPropagator::getDeDx(const SteppingHelixPropagator::StateInfo& sv, 
01141                                         double& dEdXPrime, double& radX0,
01142                                         MatBounds& rzLims) const{
01143   radX0 = 1.e24;
01144   dEdXPrime = 0.;
01145   rzLims = MatBounds();
01146   if (noMaterialMode_) return 0;
01147 
01148   double dEdx = 0.;
01149 
01150   double lR = sv.r3.perp();
01151   double lZ = fabs(sv.r3.z());
01152 
01153   //assume "Iron" .. seems to be quite the same for brass/iron/PbW04
01154   //good for Fe within 3% for 0.2 GeV to 10PeV
01155   double p0 = sv.p3.mag();
01156 
01157   //0.065 (PDG) --> 0.044 to better match with MPV
01158   double dEdX_mat = -(11.4 + 0.96*fabs(log(p0*2.8)) + 0.033*p0*(1.0 - pow(p0, -0.33)) )*1e-3; 
01159   //in GeV/cm .. 0.8 to get closer to the median or MPV
01160   double dEdX_HCal = 0.95*dEdX_mat; //extracted from sim
01161   double dEdX_ECal = 0.45*dEdX_mat;
01162   double dEdX_coil = 0.35*dEdX_mat; //extracted from sim .. closer to 40% in fact
01163   double dEdX_Fe =   dEdX_mat;
01164   double dEdX_MCh =  0.053*dEdX_mat; //chambers on average
01165   double dEdX_Trk =  0.0114*dEdX_mat;
01166   double dEdX_Air =  2E-4*dEdX_mat;
01167   double dEdX_Vac =  0.0;
01168 
01169   double radX0_HCal = 1.44/0.8; //guessing
01170   double radX0_ECal = 0.89/0.7;
01171   double radX0_coil = 4.; //
01172   double radX0_Fe =   1.76;
01173   double radX0_MCh =  1e3; //
01174   double radX0_Trk =  320.;
01175   double radX0_Air =  3.e4;
01176   double radX0_Vac =  3.e9; //"big" number for vacuum
01177 
01178 
01179   //not all the boundaries are set below: this will be a default
01180   if (! (lR < 380 && lZ < 785)){
01181     if (lZ > 785 ) rzLims = MatBounds(0, 1e4, 785, 1e4);
01182     if (lZ < 785 ) rzLims = MatBounds(380, 1e4, 0, 785);
01183   }
01184 
01185   //this def makes sense assuming we don't jump into endcap volume from the other z-side in one step
01186   //also, it is a positive shift only (at least for now): can't move ec further into the detector
01187   double ecShift = sv.r3.z() > 0 ? fabs(ecShiftPos_) : fabs(ecShiftNeg_); 
01188 
01189   //this should roughly figure out where things are 
01190   //(numbers taken from Fig1.1.2 TDR and from geom xmls)
01191   if (lR < 2.9){ //inside beampipe
01192     dEdx = dEdX_Vac; radX0 = radX0_Vac;
01193     rzLims = MatBounds(0, 2.9, 0, 1E4);
01194   }
01195   else if (lR < 129){
01196     if (lZ < 294){ 
01197       rzLims = MatBounds(2.9, 129, 0, 294); //tracker boundaries
01198       dEdx = dEdX_Trk; radX0 = radX0_Trk; 
01199       //somewhat empirical formula that ~ matches the average if going from 0,0,0
01200       //assuming "uniform" tracker material
01201       //doesn't really track material layer to layer
01202       double lEtaDet = fabs(sv.r3.eta());
01203       double scaleRadX = lEtaDet > 1.5 ? 0.7724 : sin(2.*atan(exp(-0.5*lEtaDet)));
01204       scaleRadX *= scaleRadX;
01205       if (lEtaDet > 2 && lZ > 20) scaleRadX *= (lEtaDet-1.);
01206       if (lEtaDet > 2.5 && lZ > 20) scaleRadX *= (lEtaDet-1.);
01207       radX0 *= scaleRadX;
01208     }
01209     //endcap part begins here
01210     else if ( lZ < 294 + ecShift ){
01211       //gap in front of EE here, piece inside 2.9<R<129
01212       rzLims = MatBounds(2.9, 129, 294, 294 + ecShift); 
01213       dEdx = dEdX_Air; radX0 = radX0_Air;
01214     }
01215     else if (lZ < 372 + ecShift){ 
01216       rzLims = MatBounds(2.9, 129, 294 + ecShift, 372 + ecShift); //EE here, piece inside 2.9<R<129
01217       dEdx = dEdX_ECal; radX0 = radX0_ECal; 
01218     }//EE averaged out over a larger space
01219     else if (lZ < 398 + ecShift){
01220       rzLims = MatBounds(2.9, 129, 372 + ecShift, 398 + ecShift); //whatever goes behind EE 2.9<R<129 is air up to Z=398
01221       dEdx = dEdX_HCal*0.05; radX0 = radX0_Air; 
01222     }//betw EE and HE
01223     else if (lZ < 555 + ecShift){ 
01224       rzLims = MatBounds(2.9, 129, 398 + ecShift, 555 + ecShift); //HE piece 2.9<R<129; 
01225       dEdx = dEdX_HCal*0.96; radX0 = radX0_HCal/0.96; 
01226     } //HE calor abit less dense
01227     else {
01228       //      rzLims = MatBounds(2.9, 129, 555, 785);
01229       // set the boundaries first: they serve as stop-points here
01230       // the material is set below
01231       if (lZ < 568  + ecShift) rzLims = MatBounds(2.9, 129, 555 + ecShift, 568 + ecShift); //a piece of HE support R<129, 555<Z<568
01232       else if (lZ < 625 + ecShift){
01233         if (lR < 85 + ecShift) rzLims = MatBounds(2.9, 85, 568 + ecShift, 625 + ecShift); 
01234         else rzLims = MatBounds(85, 129, 568 + ecShift, 625 + ecShift);
01235       } else if (lZ < 785 + ecShift) rzLims = MatBounds(2.9, 129, 625 + ecShift, 785 + ecShift);
01236       else if (lZ < 1500 + ecShift)  rzLims = MatBounds(2.9, 129, 785 + ecShift, 1500 + ecShift);
01237       else rzLims = MatBounds(2.9, 129, 1500 + ecShift, 1E4);
01238 
01239       //iron .. don't care about no material in front of HF (too forward)
01240       if (! (lZ > 568 + ecShift && lZ < 625 + ecShift && lR > 85 ) // HE support 
01241           && ! (lZ > 785 + ecShift && lZ < 850 + ecShift && lR > 118)) {dEdx = dEdX_Fe; radX0 = radX0_Fe; }
01242       else  { dEdx = dEdX_MCh; radX0 = radX0_MCh; } //ME at eta > 2.2
01243     }
01244   }
01245   else if (lR < 287){
01246     if (lZ < 372 + ecShift && lR < 177){ // 129<<R<177
01247       if (lZ < 304) rzLims = MatBounds(129, 177, 0, 304); //EB  129<<R<177 0<Z<304
01248       else if (lZ < 343){ // 129<<R<177 304<Z<343
01249         if (lR < 135 ) rzLims = MatBounds(129, 135, 304, 343);// tk piece 129<<R<135 304<Z<343
01250         else if (lR < 172 ){ //
01251           if (lZ < 311 ) rzLims = MatBounds(135, 172, 304, 311);
01252           else rzLims = MatBounds(135, 172, 311, 343);
01253         } else {
01254           if (lZ < 328) rzLims = MatBounds(172, 177, 304, 328);
01255           else rzLims = MatBounds(172, 177, 328, 343);
01256         }
01257       }
01258       else if ( lZ < 343 + ecShift){
01259         rzLims = MatBounds(129, 177, 343, 343 + ecShift); //gap
01260       }
01261       else {
01262         if (lR < 156 ) rzLims = MatBounds(129, 156, 343 + ecShift, 372 + ecShift);
01263         else if ( (lZ - 343 - ecShift) > (lR - 156)*1.38 ) 
01264           rzLims = MatBounds(156, 177, 127.72 + ecShift, 372 + ecShift, atan(1.38), 0);
01265         else rzLims = MatBounds(156, 177, 343 + ecShift, 127.72 + ecShift, 0, atan(1.38));
01266       }
01267 
01268       if (!(lR > 135 && lZ <343 + ecShift && lZ > 304 )
01269           && ! (lR > 156 && lZ < 372 + ecShift  && lZ > 343 + ecShift  && ((lZ-343. - ecShift )< (lR-156.)*1.38)))
01270         {
01271           //the crystals are the same length, but they are not 100% of material
01272           double cosThetaEquiv = 0.8/sqrt(1.+lZ*lZ/lR/lR) + 0.2;
01273           if (lZ > 343) cosThetaEquiv = 1.;
01274           dEdx = dEdX_ECal*cosThetaEquiv; radX0 = radX0_ECal/cosThetaEquiv; 
01275         } //EB
01276       else { 
01277         if ( (lZ > 304 && lZ < 328 && lR < 177 && lR > 135) 
01278              && ! (lZ > 311 && lR < 172) ) {dEdx = dEdX_Fe; radX0 = radX0_Fe; } //Tk_Support
01279         else if ( lZ > 343 && lZ < 343 + ecShift) { dEdx = dEdX_Air; radX0 = radX0_Air; }
01280         else {dEdx = dEdX_ECal*0.2; radX0 = radX0_Air;} //cables go here <-- will be abit too dense for ecShift > 0
01281       }
01282     }
01283     else if (lZ < 554 + ecShift){ // 129<R<177 372<Z<554  AND 177<R<287 0<Z<554
01284       if (lR < 177){ //  129<R<177 372<Z<554
01285         if ( lZ > 372 + ecShift && lZ < 398 + ecShift )rzLims = MatBounds(129, 177, 372 + ecShift, 398 + ecShift); // EE 129<R<177 372<Z<398
01286         else if (lZ < 548 + ecShift) rzLims = MatBounds(129, 177, 398 + ecShift, 548 + ecShift); // HE 129<R<177 398<Z<548
01287         else rzLims = MatBounds(129, 177, 548 + ecShift, 554 + ecShift); // HE gap 129<R<177 548<Z<554
01288       }
01289       else if (lR < 193){ // 177<R<193 0<Z<554
01290         if ((lZ - 307) < (lR - 177.)*1.739) rzLims = MatBounds(177, 193, 0, -0.803, 0, atan(1.739));
01291         else if ( lZ < 389)  rzLims = MatBounds(177, 193, -0.803, 389, atan(1.739), 0.);
01292         else if ( lZ < 389 + ecShift)  rzLims = MatBounds(177, 193, 389, 389 + ecShift); // air insert
01293         else if ( lZ < 548 + ecShift ) rzLims = MatBounds(177, 193, 389 + ecShift, 548 + ecShift);// HE 177<R<193 389<Z<548
01294         else rzLims = MatBounds(177, 193, 548 + ecShift, 554 + ecShift); // HE gap 177<R<193 548<Z<554
01295       }
01296       else if (lR < 264){ // 193<R<264 0<Z<554
01297         double anApex = 375.7278 - 193./1.327; // 230.28695599096
01298         if ( (lZ - 375.7278) < (lR - 193.)/1.327) rzLims = MatBounds(193, 264, 0, anApex, 0, atan(1./1.327)); //HB
01299         else if ( (lZ - 392.7278 ) < (lR - 193.)/1.327) 
01300           rzLims = MatBounds(193, 264, anApex, anApex+17., atan(1./1.327), atan(1./1.327)); // HB-HE gap
01301         else if ( (lZ - 392.7278 - ecShift ) < (lR - 193.)/1.327) 
01302           rzLims = MatBounds(193, 264, anApex+17., anApex+17. + ecShift, atan(1./1.327), atan(1./1.327)); // HB-HE gap air insert
01303         // HE (372,193)-(517,193)-(517,264)-(417.8,264)
01304         else if ( lZ < 517 + ecShift ) rzLims = MatBounds(193, 264, anApex+17. + ecShift, 517 + ecShift, atan(1./1.327), 0);
01305         else if (lZ < 548 + ecShift){ // HE+gap 193<R<264 517<Z<548
01306           if (lR < 246 ) rzLims = MatBounds(193, 246, 517 + ecShift, 548 + ecShift); // HE 193<R<246 517<Z<548
01307           else rzLims = MatBounds(246, 264, 517 + ecShift, 548 + ecShift); // HE gap 246<R<264 517<Z<548
01308         } 
01309         else rzLims = MatBounds(193, 264, 548 + ecShift, 554 + ecShift); // HE gap  193<R<246 548<Z<554
01310       }
01311       else if ( lR < 275){ // 264<R<275 0<Z<554
01312         if (lZ < 433) rzLims = MatBounds(264, 275, 0, 433); //HB
01313         else if (lZ < 554 ) rzLims = MatBounds(264, 275, 433, 554); // HE gap 264<R<275 433<Z<554
01314         else rzLims = MatBounds(264, 275, 554, 554 + ecShift); // HE gap 264<R<275 554<Z<554 air insert
01315       }
01316       else { // 275<R<287 0<Z<554
01317         if (lZ < 402) rzLims = MatBounds(275, 287, 0, 402);// HB 275<R<287 0<Z<402
01318         else if (lZ < 554) rzLims = MatBounds(275, 287, 402, 554);//  //HE gap 275<R<287 402<Z<554
01319         else rzLims = MatBounds(275, 287, 554, 554 + ecShift); //HE gap 275<R<287 554<Z<554 air insert
01320       }
01321 
01322       if ((lZ < 433 || lR < 264) && (lZ < 402 || lR < 275) && (lZ < 517 + ecShift || lR < 246) //notches
01323           //I should've made HE and HF different .. now need to shorten HE to match
01324           && lZ < 548 + ecShift
01325           && ! (lZ < 389 + ecShift && lZ > 335 && lR < 193 ) //not a gap EB-EE 129<R<193
01326           && ! (lZ > 307 && lZ < 335 && lR < 193 && ((lZ - 307) > (lR - 177.)*1.739)) //not a gap 
01327           && ! (lR < 177 && lZ < 398 + ecShift) //under the HE nose
01328           && ! (lR < 264 && lR > 193 && fabs(441.5+0.5*ecShift - lZ + (lR - 269.)/1.327) < (8.5 + ecShift*0.5)) ) //not a gap
01329         { dEdx = dEdX_HCal; radX0 = radX0_HCal; //hcal
01330         }
01331       else if( (lR < 193 && lZ > 389 && lZ < 389 + ecShift ) || (lR > 264 && lR < 287 && lZ > 554 && lZ < 554 + ecShift)
01332                ||(lR < 264 && lR > 193 && fabs(441.5+8.5+0.5*ecShift - lZ + (lR - 269.)/1.327) < ecShift*0.5) )  {
01333         dEdx = dEdX_Air; radX0 = radX0_Air; 
01334       }
01335       else {dEdx = dEdX_HCal*0.05; radX0 = radX0_Air; }//endcap gap
01336     }
01337     //the rest is a tube of endcap volume  129<R<251 554<Z<largeValue
01338     else if (lZ < 564 + ecShift){ // 129<R<287  554<Z<564
01339       if (lR < 251) {
01340         rzLims = MatBounds(129, 251, 554 + ecShift, 564 + ecShift);  // HE support 129<R<251  554<Z<564    
01341         dEdx = dEdX_Fe; radX0 = radX0_Fe; 
01342       }//HE support
01343       else { 
01344         rzLims = MatBounds(251, 287, 554 + ecShift, 564 + ecShift); //HE/ME gap 251<R<287  554<Z<564    
01345         dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01346       }
01347     }
01348     else if (lZ < 625 + ecShift){ // ME/1/1 129<R<287  564<Z<625
01349       rzLims = MatBounds(129, 287, 564 + ecShift, 625 + ecShift);      
01350       dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01351     }
01352     else if (lZ < 785 + ecShift){ //129<R<287  625<Z<785
01353       if (lR < 275) rzLims = MatBounds(129, 275, 625 + ecShift, 785 + ecShift); //YE/1 129<R<275 625<Z<785
01354       else { // 275<R<287  625<Z<785
01355         if (lZ < 720 + ecShift) rzLims = MatBounds(275, 287, 625 + ecShift, 720 + ecShift); // ME/1/2 275<R<287  625<Z<720
01356         else rzLims = MatBounds(275, 287, 720 + ecShift, 785 + ecShift); // YE/1 275<R<287  720<Z<785
01357       }
01358       if (! (lR > 275 && lZ < 720 + ecShift)) { dEdx = dEdX_Fe; radX0 = radX0_Fe; }//iron
01359       else { dEdx = dEdX_MCh; radX0 = radX0_MCh; }
01360     }
01361     else if (lZ < 850 + ecShift){
01362       rzLims = MatBounds(129, 287, 785 + ecShift, 850 + ecShift);
01363       dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01364     }
01365     else if (lZ < 910 + ecShift){
01366       rzLims = MatBounds(129, 287, 850 + ecShift, 910 + ecShift);
01367       dEdx = dEdX_Fe; radX0 = radX0_Fe; 
01368     }//iron
01369     else if (lZ < 975 + ecShift){
01370       rzLims = MatBounds(129, 287, 910 + ecShift, 975 + ecShift);
01371       dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01372     }
01373     else if (lZ < 1000 + ecShift){
01374       rzLims = MatBounds(129, 287, 975 + ecShift, 1000 + ecShift);
01375       dEdx = dEdX_Fe; radX0 = radX0_Fe; 
01376     }//iron
01377     else if (lZ < 1063 + ecShift){
01378       rzLims = MatBounds(129, 287, 1000 + ecShift, 1063 + ecShift);
01379       dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01380     }
01381     else if ( lZ < 1073 + ecShift){
01382       rzLims = MatBounds(129, 287, 1063 + ecShift, 1073 + ecShift);
01383       dEdx = dEdX_Fe; radX0 = radX0_Fe; 
01384     }
01385     else if (lZ < 1E4 )  { 
01386       rzLims = MatBounds(129, 287, 1073 + ecShift, 1E4);
01387       dEdx = dEdX_Air; radX0 = radX0_Air;
01388     }
01389     else { 
01390       
01391       dEdx = dEdX_Air; radX0 = radX0_Air;
01392     }
01393   }
01394   else if (lR <380 && lZ < 667){
01395     if (lZ < 630){
01396       if (lR < 315) rzLims = MatBounds(287, 315, 0, 630); 
01397       else if (lR < 341 ) rzLims = MatBounds(315, 341, 0, 630); //b-field ~linear rapid fall here
01398       else rzLims = MatBounds(341, 380, 0, 630);      
01399     } else rzLims = MatBounds(287, 380, 630, 667);  
01400 
01401     if (lZ < 630) { dEdx = dEdX_coil; radX0 = radX0_coil; }//a guess for the solenoid average
01402     else {dEdx = dEdX_Air; radX0 = radX0_Air; }//endcap gap
01403   }
01404   else {
01405     if (lZ < 667) {
01406       if (lR < 850){
01407         bool isIron = false;
01408         //sanity check in addition to flags
01409         if (useIsYokeFlag_ && useMagVolumes_ && sv.magVol != 0){
01410           isIron = sv.isYokeVol;
01411         } else {
01412           double bMag = sv.bf.mag();
01413           isIron = (bMag > 0.75 && ! (lZ > 500 && lR <500 && bMag < 1.15)
01414                     && ! (lZ < 450 && lR > 420 && bMag < 1.15 ) );
01415         }
01416         //tell the material stepper where mat bounds are
01417         rzLims = MatBounds(380, 850, 0, 667);
01418         if (isIron) { dEdx = dEdX_Fe; radX0 = radX0_Fe; }//iron
01419         else { dEdx = dEdX_MCh; radX0 = radX0_MCh; }
01420       } else {
01421         rzLims = MatBounds(850, 1E4, 0, 667);
01422         dEdx = dEdX_Air; radX0 = radX0_Air; 
01423       }
01424     } 
01425     else if (lR > 750 ){
01426       rzLims = MatBounds(750, 1E4, 667, 1E4);
01427       dEdx = dEdX_Air; radX0 = radX0_Air; 
01428     }
01429     else if (lZ < 667 + ecShift){
01430       rzLims = MatBounds(287, 750, 667, 667 + ecShift);
01431       dEdx = dEdX_Air; radX0 = radX0_Air;       
01432     }
01433     //the rest is endcap piece with 287<R<750 Z>667
01434     else if (lZ < 724 + ecShift){
01435       if (lR < 380 ) rzLims = MatBounds(287, 380, 667 + ecShift, 724 + ecShift); 
01436       else rzLims = MatBounds(380, 750, 667 + ecShift, 724 + ecShift); 
01437       dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01438     }
01439     else if (lZ < 785 + ecShift){
01440       if (lR < 380 ) rzLims = MatBounds(287, 380, 724 + ecShift, 785 + ecShift); 
01441       else rzLims = MatBounds(380, 750, 724 + ecShift, 785 + ecShift); 
01442       dEdx = dEdX_Fe; radX0 = radX0_Fe; 
01443     }//iron
01444     else if (lZ < 850 + ecShift){
01445       rzLims = MatBounds(287, 750, 785 + ecShift, 850 + ecShift); 
01446       dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01447     }
01448     else if (lZ < 910 + ecShift){
01449       rzLims = MatBounds(287, 750, 850 + ecShift, 910 + ecShift); 
01450       dEdx = dEdX_Fe; radX0 = radX0_Fe; 
01451     }//iron
01452     else if (lZ < 975 + ecShift){
01453       rzLims = MatBounds(287, 750, 910 + ecShift, 975 + ecShift); 
01454       dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01455     }
01456     else if (lZ < 1000 + ecShift){
01457       rzLims = MatBounds(287, 750, 975 + ecShift, 1000 + ecShift); 
01458       dEdx = dEdX_Fe; radX0 = radX0_Fe; 
01459     }//iron
01460     else if (lZ < 1063 + ecShift){
01461       if (lR < 360){
01462         rzLims = MatBounds(287, 360, 1000 + ecShift, 1063 + ecShift);
01463         dEdx = dEdX_MCh; radX0 = radX0_MCh; 
01464       } 
01465       //put empty air where me4/2 should be (future)
01466       else {
01467         rzLims = MatBounds(360, 750, 1000 + ecShift, 1063 + ecShift);
01468         dEdx = dEdX_Air; radX0 = radX0_Air;
01469       }
01470     }
01471     else if ( lZ < 1073 + ecShift){
01472       rzLims = MatBounds(287, 750, 1063 + ecShift, 1073 + ecShift);
01473       //this plate does not exist: air
01474       dEdx = dEdX_Air; radX0 = radX0_Air; 
01475     }
01476     else if (lZ < 1E4 )  { 
01477       rzLims = MatBounds(287, 750, 1073 + ecShift, 1E4);
01478       dEdx = dEdX_Air; radX0 = radX0_Air;
01479     }
01480     else {dEdx = dEdX_Air; radX0 = radX0_Air; }//air
01481   }
01482   
01483   dEdXPrime = dEdx == 0 ? 0 : -dEdx/dEdX_mat*(0.96/p0 + 0.033 - 0.022*pow(p0, -0.33))*1e-3; //== d(dEdX)/dp
01484 
01485   return dEdx;
01486 }
01487 
01488 
01489 int SteppingHelixPropagator::cIndex_(int ind) const{
01490   int result = ind%MAX_POINTS;  
01491   if (ind != 0 && result == 0){
01492     result = MAX_POINTS;
01493   }
01494   return result;
01495 }
01496 
01497 SteppingHelixPropagator::Result
01498 SteppingHelixPropagator::refToDest(SteppingHelixPropagator::DestType dest, 
01499                                    const SteppingHelixPropagator::StateInfo& sv,
01500                                    const double pars[6], 
01501                                    double& dist, double& tanDist, 
01502                                    PropagationDirection& refDirection,
01503                                    double fastSkipDist) const{
01504   static const std::string metname = "SteppingHelixPropagator";
01505   Result result = SteppingHelixStateInfo::NOT_IMPLEMENTED;
01506   double curZ = sv.r3.z();
01507   double curR = sv.r3.perp();
01508 
01509   switch (dest){
01510   case RADIUS_DT:
01511     {
01512       double cosDPhiPR = cos((sv.r3.deltaPhi(sv.p3)));
01513       dist = pars[RADIUS_P] - curR;
01514       refDirection = dist*cosDPhiPR > 0 ?
01515         alongMomentum : oppositeToMomentum;
01516       if (fabs(dist) > fastSkipDist){
01517         result = SteppingHelixStateInfo::INACC;
01518         break;
01519       }
01520       tanDist = dist/sv.p3.perp()*sv.p3.mag();      
01521       result = SteppingHelixStateInfo::OK;
01522     }
01523     break;
01524   case Z_DT:
01525     {
01526       dist = pars[Z_P] - curZ;
01527       refDirection = sv.p3.z()*dist > 0. ?
01528         alongMomentum : oppositeToMomentum;
01529       if (fabs(dist) > fastSkipDist){
01530         result = SteppingHelixStateInfo::INACC;
01531         break;
01532       }
01533       tanDist = dist/sv.p3.z()*sv.p3.mag();
01534       result = SteppingHelixStateInfo::OK;
01535     }
01536     break;
01537   case PLANE_DT:
01538     {
01539       Point rPlane(pars[0], pars[1], pars[2]);
01540       Vector nPlane(pars[3], pars[4], pars[5]);
01541       
01542       double dRDotN = (sv.r3 - rPlane).dot(nPlane);
01543       
01544       dist = fabs(dRDotN);
01545       double p0 = sv.p3.mag();
01546       double tN = sv.p3.dot(nPlane)/p0;
01547       refDirection = tN*dRDotN < 0. ?
01548         alongMomentum : oppositeToMomentum;
01549       if (fabs(dist) > fastSkipDist){
01550         result = SteppingHelixStateInfo::INACC;
01551         break;
01552       }
01553       double b0 = sv.bf.mag();
01554       if (fabs(tN)>1e-24) tanDist = -dRDotN/tN;
01555       if (fabs(tanDist) > 1e4) tanDist = 1e4;
01556       if (b0>1.5e-6){
01557         double kVal = 0.0029979*sv.q/p0*b0;
01558         double aVal = tanDist*kVal;
01559         Vector lVec = sv.bf.cross(sv.p3); lVec *= 1./b0/p0;
01560         double bVal = lVec.dot(nPlane)/tN;
01561         if (fabs(aVal*bVal)< 0.3){
01562           double cVal = - sv.bf.cross(lVec).dot(nPlane)/b0/tN; //1- bHat_n*bHat_tau/tau_n;
01563           double tanDCorr = bVal/2. + (bVal*bVal/2. + cVal/6)*aVal; 
01564           tanDCorr *= aVal;
01565           //+ (-bVal/24. + 0.625*bVal*bVal*bVal + 5./12.*bVal*cVal)*aVal*aVal*aVal
01566           if (debug_) LogTrace(metname)<<tanDist<<" vs "<<tanDist*(1.+tanDCorr)<<" corr "<<tanDist*tanDCorr<<std::endl;
01567           tanDist *= (1.+tanDCorr);
01568         } else {
01569           if (debug_) LogTrace(metname)<<"ABVal "<< fabs(aVal*bVal)
01570                                        <<" = "<<aVal<<" * "<<bVal<<" too large:: will not converge"<<std::endl;
01571         }
01572       }
01573       result = SteppingHelixStateInfo::OK;
01574     }
01575     break;
01576   case CONE_DT:
01577     {
01578       //assumes the cone axis/vertex is along z
01579       Point cVertex(pars[0], pars[1], pars[2]);
01580       Vector relV3 = sv.r3 - cVertex;
01581       double theta(pars[3]);
01582       if (cVertex.perp() < 1e-5){
01583         double sinDTheta = sin(theta-relV3.theta());
01584         double cosDTheta = cos(theta-relV3.theta());
01585         bool isInside = sin(theta) > sin(relV3.theta()) 
01586           && cos(theta)*cos(relV3.theta()) > 0;
01587         dist = isInside || cosDTheta > 0 ? 
01588           relV3.mag()*sinDTheta : relV3.mag();
01589         double normPhi = isInside ? 
01590           Geom::pi() + relV3.phi() : relV3.phi();
01591         double normTheta = theta > Geom::pi()/2. ?
01592           ( isInside ? 1.5*Geom::pi()  - theta : theta - Geom::pi()/2. )
01593           : ( isInside ? Geom::pi()/2. - theta : theta + Geom::pi()/2 );
01594         //this is a normVector from the cone to the point
01595         Vector norm; norm.setRThetaPhi(fabs(dist), normTheta, normPhi);
01596         double sineConeP = sin(theta - sv.p3.theta());
01597 
01598         double sinSolid = norm.dot(sv.p3)/fabs(dist)/sv.p3.mag();
01599         tanDist = fabs(sinSolid) > fabs(sineConeP) ? dist/fabs(sinSolid) : dist/fabs(sineConeP);
01600 
01601 
01602         refDirection = sinSolid > 0 ?
01603           oppositeToMomentum : alongMomentum;
01604         if (debug_){
01605           LogTrace(metname)<<"Cone pars: theta "<<theta
01606                            <<" normTheta "<<norm.theta()
01607                            <<" p3Theta "<<sv.p3.theta()
01608                            <<" sinD: "<< sineConeP
01609                            <<" sinSolid "<<sinSolid;
01610         }
01611         if (fabs(dist) > fastSkipDist){
01612           result = SteppingHelixStateInfo::INACC;
01613           break;
01614         }
01615         if (debug_){
01616           LogTrace(metname)<<"refToDest:toCone the point is "
01617                            <<(isInside? "in" : "out")<<"side the cone"
01618                            <<std::endl;
01619         }
01620       }
01621       result = SteppingHelixStateInfo::OK;
01622     }
01623     break;
01624     //   case CYLINDER_DT:
01625     //     break;
01626   case PATHL_DT:
01627     {
01628       double curS = fabs(sv.path());
01629       dist = pars[PATHL_P] - curS;
01630       refDirection = pars[PATHL_P] > 0 ? 
01631         alongMomentum : oppositeToMomentum;
01632       if (fabs(dist) > fastSkipDist){
01633         result = SteppingHelixStateInfo::INACC;
01634         break;
01635       }
01636       tanDist = dist;
01637       result = SteppingHelixStateInfo::OK;
01638     }
01639     break;
01640   case POINT_PCA_DT:
01641     {
01642       Point pDest(pars[0], pars[1], pars[2]);
01643       dist = (sv.r3 - pDest).mag()+ 1e-24;//add a small number to avoid 1/0
01644       tanDist = (sv.r3.dot(sv.p3) - pDest.dot(sv.p3))/sv.p3.mag();
01645       //account for bending in magnetic field (quite approximate)
01646       double b0 = sv.bf.mag();
01647       if (b0>1.5e-6){
01648         double p0 = sv.p3.mag();
01649         double kVal = 0.0029979*sv.q/p0*b0;
01650         double aVal = fabs(dist*kVal);
01651         tanDist *= 1./(1.+ aVal);
01652         if (debug_) LogTrace(metname)<<"corrected by aVal "<<aVal<<" to "<<tanDist;
01653       }
01654       refDirection = tanDist < 0 ?
01655         alongMomentum : oppositeToMomentum;
01656       result = SteppingHelixStateInfo::OK;
01657     }
01658     break;
01659   case LINE_PCA_DT:
01660     {
01661       Point rLine(pars[0], pars[1], pars[2]);
01662       Vector dLine(pars[3], pars[4], pars[5]);
01663       dLine = (dLine - rLine);
01664       dLine *= 1./dLine.mag(); if (debug_) LogTrace(metname)<<"dLine "<<dLine;
01665 
01666       Vector dR = sv.r3 - rLine;
01667       Vector dRPerp = dR - dLine*(dR.dot(dLine)); if (debug_) LogTrace(metname)<<"dRperp "<<dRPerp;
01668       dist = dRPerp.mag() + 1e-24;//add a small number to avoid 1/0
01669       tanDist = dRPerp.dot(sv.p3)/sv.p3.mag();
01670       //angle wrt line
01671       double cosAlpha = dLine.dot(sv.p3)/sv.p3.mag();
01672       tanDist *= fabs(1./sqrt(fabs(1.-cosAlpha*cosAlpha)+1e-96));
01673       //correct for dPhi in magnetic field: this isn't made quite right here 
01674       //(the angle between the line and the trajectory plane is neglected .. conservative)
01675       double b0 = sv.bf.mag();
01676       if (b0>1.5e-6){
01677         double p0 = sv.p3.mag();
01678         double kVal = 0.0029979*sv.q/p0*b0;
01679         double aVal = fabs(dist*kVal);
01680         tanDist *= 1./(1.+ aVal);
01681         if (debug_) LogTrace(metname)<<"corrected by aVal "<<aVal<<" to "<<tanDist;
01682       }
01683       refDirection = tanDist < 0 ?
01684         alongMomentum : oppositeToMomentum;
01685       result = SteppingHelixStateInfo::OK;
01686     }
01687     break;
01688   default:
01689     {
01690       //some large number
01691       dist = 1e12;
01692       tanDist = 1e12;
01693       refDirection = anyDirection;
01694       result = SteppingHelixStateInfo::NOT_IMPLEMENTED;
01695     }
01696     break;
01697   }
01698 
01699   double tanDistConstrained = tanDist;
01700   if (fabs(tanDist/dist) > 4) tanDistConstrained *= fabs(dist/tanDist*4.);
01701 
01702   if (debug_){
01703     LogTrace(metname)<<"refToDest input: dest"<<dest<<" pars[]: ";
01704     for (int i = 0; i < 6; i++){
01705       LogTrace(metname)<<", "<<i<<" "<<pars[i];
01706     }
01707     LogTrace(metname)<<std::endl;
01708     LogTrace(metname)<<"refToDest output: "
01709                      <<"\t dist" << dist
01710                      <<"\t tanDist "<< tanDist      
01711                      <<"\t tanDistConstr "<< tanDistConstrained      
01712                      <<"\t refDirection "<< refDirection
01713                      <<std::endl;
01714   }
01715   tanDist = tanDistConstrained;
01716 
01717   return result;
01718 }
01719 
01720 SteppingHelixPropagator::Result
01721 SteppingHelixPropagator::refToMagVolume(const SteppingHelixPropagator::StateInfo& sv,
01722                                         PropagationDirection dir,
01723                                         double& dist, double& tanDist,
01724                                         double fastSkipDist, bool expectNewMagVolume) const{
01725 
01726   static const std::string metname = "SteppingHelixPropagator";
01727   Result result = SteppingHelixStateInfo::NOT_IMPLEMENTED;
01728   const MagVolume* cVol = sv.magVol;
01729 
01730   if (cVol == 0) return result;
01731   const std::vector<VolumeSide>& cVolFaces(cVol->faces());
01732 
01733   double distToFace[6] = {0,0,0,0,0,0};
01734   double tanDistToFace[6] = {0,0,0,0,0,0};
01735   PropagationDirection refDirectionToFace[6];
01736   Result resultToFace[6];
01737   int iFDest = -1;
01738   int iDistMin = -1;
01739   
01740   uint iFDestSorted[6] = {0,0,0,0,0,0};
01741   uint nDestSorted =0;
01742   uint nearParallels = 0;
01743 
01744   if (debug_){
01745     LogTrace(metname)<<"Trying volume "<<DDSolidShapesName::name(cVol->shapeType())
01746                      <<" with "<<cVolFaces.size()<<" faces"<<std::endl;
01747   }
01748 
01749   for (uint iFace = 0; iFace < cVolFaces.size(); iFace++){
01750     if (iFace > 5){
01751       LogTrace(metname)<<"Too many faces"<<std::endl;
01752     }
01753     if (debug_){
01754       LogTrace(metname)<<"Start with face "<<iFace<<std::endl;
01755     }
01756 //     const Plane* cPlane = dynamic_cast<const Plane*>(&cVolFaces[iFace].surface());
01757 //     const Cylinder* cCyl = dynamic_cast<const Cylinder*>(&cVolFaces[iFace].surface());
01758 //     const Cone* cCone = dynamic_cast<const Cone*>(&cVolFaces[iFace].surface());
01759     const Surface* cPlane = 0; //only need to know the loc->glob transform
01760     const Cylinder* cCyl = 0;
01761     const Cone* cCone = 0;
01762     if (typeid(cVolFaces[iFace].surface()) == typeid(const Plane&)){
01763       cPlane = &cVolFaces[iFace].surface();
01764     } else if (typeid(cVolFaces[iFace].surface()) == typeid(const Cylinder&)){
01765       cCyl = dynamic_cast<const Cylinder*>(&cVolFaces[iFace].surface());
01766     } else if (typeid(cVolFaces[iFace].surface()) == typeid(const Cone&)){
01767       cCone = dynamic_cast<const Cone*>(&cVolFaces[iFace].surface());
01768     } else {
01769       edm::LogWarning(metname)<<"Could not cast a volume side surface to a known type"<<std::endl;
01770     }
01771     
01772     if (debug_){
01773       if (cPlane!=0) LogTrace(metname)<<"The face is a plane at "<<cPlane<<std::endl;
01774       if (cCyl!=0) LogTrace(metname)<<"The face is a cylinder at "<<cCyl<<std::endl;
01775     }
01776 
01777     double pars[6] = {0,0,0,0,0,0};
01778     DestType dType = UNDEFINED_DT;
01779     if (cPlane != 0){
01780       GlobalPoint rPlane = cPlane->position();
01781       // = cPlane->toGlobal(LocalVector(0,0,1.)); nPlane = nPlane.unit();
01782       GlobalVector nPlane(cPlane->rotation().zx(), cPlane->rotation().zy(), cPlane->rotation().zz());
01783       
01784       if (sv.r3.z() < 0 || !vbField_->isZSymmetric() ){
01785         pars[0] = rPlane.x(); pars[1] = rPlane.y(); pars[2] = rPlane.z();
01786         pars[3] = nPlane.x(); pars[4] = nPlane.y(); pars[5] = nPlane.z();
01787       } else {
01788         pars[0] = rPlane.x(); pars[1] = rPlane.y(); pars[2] = -rPlane.z();
01789         pars[3] = nPlane.x(); pars[4] = nPlane.y(); pars[5] = -nPlane.z();
01790       }
01791       dType = PLANE_DT;
01792     } else if (cCyl != 0){
01793       if (debug_){
01794         LogTrace(metname)<<"Cylinder at "<<cCyl->position()
01795                          <<" rorated by "<<cCyl->rotation()
01796                          <<std::endl;
01797       }
01798       pars[RADIUS_P] = cCyl->radius();
01799       dType = RADIUS_DT;
01800     } else if (cCone != 0){
01801       if (debug_){
01802         LogTrace(metname)<<"Cone at "<<cCone->position()
01803                          <<" rorated by "<<cCone->rotation()
01804                          <<" vertex at "<<cCone->vertex()
01805                          <<" angle of "<<cCone->openingAngle()
01806                          <<std::endl;
01807       }
01808       if (sv.r3.z() < 0 || !vbField_->isZSymmetric()){
01809         pars[0] = cCone->vertex().x(); pars[1] = cCone->vertex().y(); 
01810         pars[2] = cCone->vertex().z();
01811         pars[3] = cCone->openingAngle();
01812       } else {
01813         pars[0] = cCone->vertex().x(); pars[1] = cCone->vertex().y(); 
01814         pars[2] = -cCone->vertex().z();
01815         pars[3] = Geom::pi() - cCone->openingAngle();
01816       }
01817       dType = CONE_DT;
01818     } else {
01819       LogTrace(metname)<<"Unknown surface"<<std::endl;
01820       resultToFace[iFace] = SteppingHelixStateInfo::UNDEFINED;
01821       continue;
01822     }
01823     resultToFace[iFace] = 
01824       refToDest(dType, sv, pars, 
01825                 distToFace[iFace], tanDistToFace[iFace], refDirectionToFace[iFace], fastSkipDist);    
01826     
01827     
01828     if (resultToFace[iFace] != SteppingHelixStateInfo::OK){
01829       if (resultToFace[iFace] == SteppingHelixStateInfo::INACC) result = SteppingHelixStateInfo::INACC;
01830     }
01831 
01832 
01833       
01834     //keep those in right direction for later use
01835     if (resultToFace[iFace] == SteppingHelixStateInfo::OK){
01836       bool isNearParallel = fabs(distToFace[iFace]/tanDistToFace[iFace]/tanDistToFace[iFace]) < 0.1/sv.p3.mag()
01837         && fabs(distToFace[iFace]/tanDistToFace[iFace]) < 0.05;
01838       if (refDirectionToFace[iFace] == dir || isNearParallel){
01839         if (isNearParallel) nearParallels++;
01840         iFDestSorted[nDestSorted] = iFace;
01841         nDestSorted++;
01842       }
01843     }
01844     
01845     //pick a shortest distance here (right dir only for now)
01846     if (refDirectionToFace[iFace] == dir){
01847       if (iDistMin == -1) iDistMin = iFace;
01848       else if (fabs(distToFace[iFace]) < fabs(distToFace[iDistMin])) iDistMin = iFace;
01849     }
01850     if (debug_) 
01851       LogTrace(metname)<<cVol<<" "<<iFace<<" "
01852                        <<tanDistToFace[iFace]<<" "<<distToFace[iFace]<<" "<<refDirectionToFace[iFace]<<" "<<dir<<std::endl;
01853     
01854   }
01855   
01856   for (uint i = 0;i<nDestSorted; ++i){
01857     uint iMax = nDestSorted-i-1;
01858     for (uint j=0;j<nDestSorted-i; ++j){
01859       if (fabs(tanDistToFace[iFDestSorted[j]]) > fabs(tanDistToFace[iFDestSorted[iMax]]) ){
01860         iMax = j;
01861       }
01862     }
01863     uint iTmp = iFDestSorted[nDestSorted-i-1];
01864     iFDestSorted[nDestSorted-i-1] = iFDestSorted[iMax];
01865     iFDestSorted[iMax] = iTmp;
01866   }
01867 
01868   if (debug_){
01869     for (uint i=0;i<nDestSorted;++i){
01870       LogTrace(metname)<<cVol<<" "<<i<<" "<<iFDestSorted[i]<<" "<<tanDistToFace[iFDestSorted[i]]<<std::endl;
01871     }
01872   }
01873 
01874   //now go from the shortest to the largest distance hoping to get a point in the volume.
01875   //other than in case of a near-parallel travel this should stop after the first try
01876   for (uint i=0; i<nDestSorted;++i){
01877     iFDest = iFDestSorted[i];
01878 
01879     double sign = dir == alongMomentum ? 1. : -1.;
01880     Point gPointEst(sv.r3);
01881     Vector lDelta(sv.p3); lDelta *= 1./sv.p3.mag()*sign*fabs(distToFace[iFDest]);
01882     gPointEst += lDelta;
01883     if (debug_){
01884       LogTrace(metname)<<"Linear est point "<<gPointEst
01885                        <<" for iFace "<<iFDest<<std::endl;
01886     }
01887     GlobalPoint gPointEstNegZ(gPointEst.x(), gPointEst.y(), -fabs(gPointEst.z()));
01888     GlobalPoint gPointEstNorZ(gPointEst.x(), gPointEst.y(), gPointEst.z() );
01889     if (  (vbField_->isZSymmetric() && cVol->inside(gPointEstNegZ))
01890           || ( !vbField_->isZSymmetric() && cVol->inside(gPointEstNorZ) )  ){
01891       if (debug_){
01892         LogTrace(metname)<<"The point is inside the volume"<<std::endl;
01893       }
01894       
01895       result = SteppingHelixStateInfo::OK;
01896       dist = distToFace[iFDest];
01897       tanDist = tanDistToFace[iFDest];
01898       if (debug_){
01899         LogTrace(metname)<<"Got a point near closest boundary -- face "<<iFDest<<std::endl;
01900       }
01901       break;
01902     }
01903   }
01904   
01905   if (result != SteppingHelixStateInfo::OK && expectNewMagVolume){
01906     double sign = dir == alongMomentum ? 1. : -1.;
01907 
01908     //check if it's a wrong volume situation
01909     if (nDestSorted-nearParallels > 0 ) result = SteppingHelixStateInfo::WRONG_VOLUME;
01910     else {
01911       //get here if all faces in the corr direction were skipped
01912       Point gPointEst(sv.r3);
01913       double lDist = fabs(distToFace[iDistMin]);
01914       if (lDist > fastSkipDist) lDist = fastSkipDist;
01915       Vector lDelta(sv.p3); lDelta *= 1./sv.p3.mag()*sign*lDist;
01916       gPointEst += lDelta;
01917       if (debug_){
01918         LogTrace(metname)<<"Linear est point to shortest dist "<<gPointEst
01919                          <<" for iFace "<<iDistMin<<" at distance "<<lDist*sign<<std::endl;
01920       }
01921       GlobalPoint gPointEstNegZ(gPointEst.x(), gPointEst.y(), -fabs(gPointEst.z()));
01922       GlobalPoint gPointEstNorZ(gPointEst.x(), gPointEst.y(), gPointEst.z() );
01923       if (  (vbField_->isZSymmetric() && cVol->inside(gPointEstNegZ))
01924           || ( !vbField_->isZSymmetric() && cVol->inside(gPointEstNorZ) ) ){
01925         if (debug_){
01926           LogTrace(metname)<<"The point is inside the volume"<<std::endl;
01927         }
01928         
01929       }else {
01930         result = SteppingHelixStateInfo::WRONG_VOLUME;
01931       }
01932     }
01933     
01934     if (result == SteppingHelixStateInfo::WRONG_VOLUME){
01935       dist = sign*0.05;
01936       tanDist = dist*1.01;
01937       if( debug_){
01938         LogTrace(metname)<<"Wrong volume located: return small dist, tandist"<<std::endl;
01939       }
01940     }
01941   }
01942 
01943   if (result == SteppingHelixStateInfo::INACC){
01944     if (debug_) LogTrace(metname)<<"All faces are too far"<<std::endl;
01945   } else if (result == SteppingHelixStateInfo::WRONG_VOLUME){
01946     if (debug_) LogTrace(metname)<<"Appear to be in a wrong volume"<<std::endl;
01947   } else if (result != SteppingHelixStateInfo::OK){
01948     if (debug_) LogTrace(metname)<<"Something else went wrong"<<std::endl;
01949   }
01950 
01951   
01952   return result;
01953 }
01954 
01955 
01956 SteppingHelixPropagator::Result
01957 SteppingHelixPropagator::refToMatVolume(const SteppingHelixPropagator::StateInfo& sv,
01958                                         PropagationDirection dir,
01959                                         double& dist, double& tanDist,
01960                                         double fastSkipDist) const{
01961 
01962   static const std::string metname = "SteppingHelixPropagator";
01963   Result result = SteppingHelixStateInfo::NOT_IMPLEMENTED;
01964 
01965   double parLim[6] = {sv.rzLims.rMin, sv.rzLims.rMax, 
01966                       sv.rzLims.zMin, sv.rzLims.zMax, 
01967                       sv.rzLims.th1, sv.rzLims.th2 };
01968 
01969   double distToFace[4] = {0,0,0,0};
01970   double tanDistToFace[4] = {0,0,0,0};
01971   PropagationDirection refDirectionToFace[4];
01972   Result resultToFace[4];
01973   int iFDest = -1;
01974   
01975   for (uint iFace = 0; iFace < 4; iFace++){
01976     if (debug_){
01977       LogTrace(metname)<<"Start with mat face "<<iFace<<std::endl;
01978     }
01979 
01980     double pars[6] = {0,0,0,0,0,0};
01981     DestType dType = UNDEFINED_DT;
01982     if (iFace > 1){
01983       if (fabs(parLim[iFace+2])< 1e-6){//plane
01984         if (sv.r3.z() < 0){
01985           pars[0] = 0; pars[1] = 0; pars[2] = -parLim[iFace];
01986           pars[3] = 0; pars[4] = 0; pars[5] = 1;
01987         } else {
01988           pars[0] = 0; pars[1] = 0; pars[2] = parLim[iFace];
01989           pars[3] = 0; pars[4] = 0; pars[5] = 1;
01990         }
01991         dType = PLANE_DT;
01992       } else {
01993         if (sv.r3.z() > 0){
01994           pars[0] = 0; pars[1] = 0; 
01995           pars[2] = parLim[iFace];
01996           pars[3] = Geom::pi()/2. - parLim[iFace+2];
01997         } else {
01998           pars[0] = 0; pars[1] = 0; 
01999           pars[2] = - parLim[iFace];
02000           pars[3] = Geom::pi()/2. + parLim[iFace+2];
02001         }
02002         dType = CONE_DT;        
02003       }
02004     } else {
02005       pars[RADIUS_P] = parLim[iFace];
02006       dType = RADIUS_DT;
02007     }
02008 
02009     resultToFace[iFace] = 
02010       refToDest(dType, sv, pars, 
02011                 distToFace[iFace], tanDistToFace[iFace], refDirectionToFace[iFace], fastSkipDist);
02012     
02013     if (resultToFace[iFace] != SteppingHelixStateInfo::OK){
02014       if (resultToFace[iFace] == SteppingHelixStateInfo::INACC) result = SteppingHelixStateInfo::INACC;
02015       continue;
02016     }
02017     if (refDirectionToFace[iFace] == dir || fabs(distToFace[iFace]/tanDistToFace[iFace]) < 2e-2){
02018       double sign = dir == alongMomentum ? 1. : -1.;
02019       Point gPointEst(sv.r3);
02020       Vector lDelta(sv.p3); lDelta *= sign*fabs(distToFace[iFace])/sv.p3.mag();
02021       gPointEst += lDelta;
02022       if (debug_){
02023         LogTrace(metname)<<"Linear est point "<<gPointEst
02024                          <<std::endl;
02025       }
02026       double lZ = fabs(gPointEst.z());
02027       double lR = gPointEst.perp();
02028       if ( (lZ - parLim[2]) > lR*tan(parLim[4]) 
02029            && (lZ - parLim[3]) < lR*tan(parLim[5])  
02030            && lR > parLim[0] && lR < parLim[1]){
02031         if (debug_){
02032           LogTrace(metname)<<"The point is inside the volume"<<std::endl;
02033         }
02034         //OK, guessed a point still inside the volume
02035         if (iFDest == -1){
02036           iFDest = iFace;
02037         } else {
02038           if (fabs(tanDistToFace[iFDest]) > fabs(tanDistToFace[iFace])){
02039             iFDest = iFace;
02040           }
02041         }
02042       } else {
02043         if (debug_){
02044           LogTrace(metname)<<"The point is NOT inside the volume"<<std::endl;
02045         }
02046       }
02047     }
02048 
02049   }
02050   if (iFDest != -1){
02051     result = SteppingHelixStateInfo::OK;
02052     dist = distToFace[iFDest];
02053     tanDist = tanDistToFace[iFDest];
02054     if (debug_){
02055       LogTrace(metname)<<"Got a point near closest boundary -- face "<<iFDest<<std::endl;
02056     }
02057   } else {
02058     if (debug_){
02059       LogTrace(metname)<<"Failed to find a dest point inside the volume"<<std::endl;
02060     }
02061   }
02062 
02063   return result;
02064 }
02065 
02066 
02067 bool SteppingHelixPropagator::isYokeVolume(const MagVolume* vol) const {
02068   static const std::string metname = "SteppingHelixPropagator";
02069   if (vol == 0) return false;
02070   const MFGrid* mGrid = reinterpret_cast<const MFGrid*>(vol->provider());
02071   std::vector<int> dims(mGrid->dimensions());
02072   
02073   LocalVector lVCen(mGrid->nodeValue(dims[0]/2, dims[1]/2, dims[2]/2));
02074   LocalVector lVZLeft(mGrid->nodeValue(dims[0]/2, dims[1]/2, dims[2]/5));
02075   LocalVector lVZRight(mGrid->nodeValue(dims[0]/2, dims[1]/2, (dims[2]*4)/5));
02076 
02077   double mag2VCen = lVCen.mag2();
02078   double mag2VZLeft = lVZLeft.mag2();
02079   double mag2VZRight = lVZRight.mag2();
02080 
02081   bool result = false;
02082   if (mag2VCen > 0.6 && mag2VZLeft > 0.6 && mag2VZRight > 0.6){
02083     if (debug_) LogTrace(metname)<<"Volume is magnetic, located at "<<vol->position()<<std::endl;    
02084     result = true;
02085   } else {
02086     if (debug_) LogTrace(metname)<<"Volume is not magnetic, located at "<<vol->position()<<std::endl;
02087   }
02088 
02089   return result;
02090 }

Generated on Tue Jun 9 17:48:43 2009 for CMSSW by  doxygen 1.5.4