CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/RecoLocalTracker/SiPixelRecHits/src/PixelCPEBase.cc

Go to the documentation of this file.
00001 // Move geomCorrection to the concrete class. d.k. 06/06.
00002 // Change drift direction. d.k. 06/06
00003 
00004 // G. Giurgiu (ggiurgiu@pha.jhu.edu), 12/01/06, implemented the function: 
00005 // computeAnglesFromDetPosition(const SiPixelCluster & cl, 
00006 //                              const GeomDetUnit    & det ) const
00007 //                                    09/09/07, replaced assert statements with throw cms::Exception 
00008 //                                              and fix an invalid pointer check in setTheDet function 
00009 //                                    09/21/07, implement caching of Lorentz drift direction
00010 //                                    01/24/09, use atan2 to get the alpha and beta angles
00011 // change to use Lorentz angle from DB Lotte Wilke, Jan. 31st, 2008
00012 // Change to use Generic error & Template calibration from DB - D.Fehling 11/08
00013 
00014 
00015 #include "Geometry/TrackerGeometryBuilder/interface/PixelGeomDetUnit.h"
00016 #include "Geometry/TrackerGeometryBuilder/interface/RectangularPixelTopology.h"
00017 #include "Geometry/TrackerGeometryBuilder/interface/ProxyPixelTopology.h"
00018 
00019 #include "RecoLocalTracker/SiPixelRecHits/interface/PixelCPEBase.h"
00020 
00021 //#define TPDEBUG
00022 #define CORRECT_FOR_BIG_PIXELS
00023 
00024 // MessageLogger
00025 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00026 
00027 // Magnetic field
00028 #include "MagneticField/Engine/interface/MagneticField.h"
00029 
00030 #include "DataFormats/SiPixelDetId/interface/PXBDetId.h"
00031 #include "DataFormats/SiPixelDetId/interface/PXFDetId.h"
00032 #include "DataFormats/SiPixelDetId/interface/PixelSubdetector.h"
00033 
00034 #include <iostream>
00035 
00036 using namespace std;
00037 
00038 const float PI = 3.141593;
00039 const float degsPerRad = 57.29578;
00040 
00041 //-----------------------------------------------------------------------------
00042 //  A fairly boring constructor.  All quantities are DetUnit-dependent, and
00043 //  will be initialized in setTheDet().
00044 //-----------------------------------------------------------------------------
00045 PixelCPEBase::PixelCPEBase(edm::ParameterSet const & conf, const MagneticField *mag, const SiPixelLorentzAngle * lorentzAngle, 
00046                            const SiPixelCPEGenericErrorParm * genErrorParm, const SiPixelTemplateDBObject * templateDBobject)
00047   : theDet(nullptr), theTopol(nullptr), theRecTopol(nullptr), theParam(nullptr), nRecHitsTotal_(0), nRecHitsUsedEdge_(0),
00048     probabilityX_(0.0), probabilityY_(0.0),
00049     probabilityQ_(0.0), qBin_(0),
00050     isOnEdge_(false), hasBadPixels_(false),
00051     spansTwoROCs_(false), hasFilledProb_(false),
00052     loc_trk_pred_(0.0, 0.0, 0.0, 0.0)
00053 {
00054   //--- Lorentz angle tangent per Tesla
00055 
00056   lorentzAngle_ = lorentzAngle;
00057  
00058   //--- Algorithm's verbosity
00059   theVerboseLevel = 
00060     conf.getUntrackedParameter<int>("VerboseLevel",0);
00061   
00062   //-- Magnetic Field
00063   magfield_ = mag;
00064   
00065   //-- Error Parametriaztion from DB for CPE Generic
00066   genErrorParm_ = genErrorParm;
00067   
00068   //-- Template Calibration Object from DB
00069   templateDBobject_ = templateDBobject;
00070   
00071   //-- Switch on/off E.B 
00072   alpha2Order = conf.getParameter<bool>("Alpha2Order");
00073   
00074   //--- A flag that could be used to change the behavior of
00075   //--- clusterProbability() in TSiPixelRecHit (the *transient* one).  
00076   //--- The problem is that the transient hits are made after the CPE runs
00077   //--- and they don't get the access to the PSet, so we pass it via the
00078   //--- CPE itself...
00079   //
00080   clusterProbComputationFlag_ 
00081     = (unsigned int) conf.getParameter<int>("ClusterProbComputationFlag");
00082   
00083 }
00084 
00085 //-----------------------------------------------------------------------------
00086 //  One function to cache the variables common for one DetUnit.
00087 //-----------------------------------------------------------------------------
00088 void
00089 PixelCPEBase::setTheDet( const GeomDetUnit & det, const SiPixelCluster & cluster ) const 
00090 {
00091   if ( theDet == &det )
00092     return;       // we have already seen this det unit
00093   
00094   //--- This is a new det unit, so cache it
00095   theDet = dynamic_cast<const PixelGeomDetUnit*>( &det );
00096 
00097   if ( !theDet ) 
00098     {
00099       throw cms::Exception(" PixelCPEBase::setTheDet : ")
00100             << " Wrong pointer to PixelGeomDetUnit object !!!";
00101     }
00102 
00103   //--- theDet->type() returns a GeomDetType, which implements subDetector()
00104   thePart = theDet->type().subDetector();
00105   switch ( thePart ) 
00106     {
00107     case GeomDetEnumerators::PixelBarrel:
00108       // A barrel!  A barrel!
00109       break;
00110     case GeomDetEnumerators::PixelEndcap:
00111       // A forward!  A forward!
00112       break;
00113     default:
00114       throw cms::Exception("PixelCPEBase::setTheDet :")
00115         << "PixelCPEBase: A non-pixel detector type in here?" ;
00116     }
00117 
00118   //--- The location in of this DetUnit in a cyllindrical coord system (R,Z)
00119   //--- The call goes via BoundSurface, returned by theDet->surface(), but
00120   //--- position() is implemented in GloballyPositioned<> template
00121   //--- ( BoundSurface : Surface : GloballyPositioned<float> )
00122   theDetR = theDet->surface().position().perp();
00123   theDetZ = theDet->surface().position().z();
00124   //--- Define parameters for chargewidth calculation
00125 
00126   //--- bounds() is implemented in BoundSurface itself.
00127   theThickness = theDet->surface().bounds().thickness();
00128 
00129   //--- Cache the topology.
00130   // ggiurgiu@jhu.edu 12/09/2010 : no longer need to dynamyc cast to RectangularPixelTopology
00131   //theTopol
00132   //= dynamic_cast<const RectangularPixelTopology*>( & (theDet->specificTopology()) );
00133 
00134   auto topol = &(theDet->specificTopology());
00135   if unlikely(topol!=theTopol) { // there is ONE topology!)
00136       theTopol=topol;
00137       auto const proxyT = dynamic_cast<const ProxyPixelTopology*>(theTopol);
00138       if (proxyT) theRecTopol = dynamic_cast<const RectangularPixelTopology*>(&(proxyT->specificTopology()));
00139       else theRecTopol = dynamic_cast<const RectangularPixelTopology*>(theTopol);
00140       assert(theRecTopol);
00141       
00142       //---- The geometrical description of one module/plaquette
00143       theNumOfRow = theRecTopol->nrows();      // rows in x
00144       theNumOfCol = theRecTopol->ncolumns();   // cols in y
00145       std::pair<float,float> pitchxy = theRecTopol->pitch();
00146       thePitchX = pitchxy.first;            // pitch along x
00147       thePitchY = pitchxy.second;           // pitch along y
00148     }
00149   
00150   theSign = isFlipped() ? -1 : 1;
00151 
00152 
00153   // will cache if not yest there (need some of the above)
00154   theParam = &param();
00155 
00156   // this "has wrong sign..."
00157   driftDirection_ = (*theParam).drift;
00158  
00159 
00160   //--- The Lorentz shift.
00161   theLShiftX = lorentzShiftX();
00162 
00163   theLShiftY = lorentzShiftY();
00164 
00165   // testing 
00166   if(thePart == GeomDetEnumerators::PixelBarrel) {
00167     //cout<<" lorentz shift "<<theLShiftX<<" "<<theLShiftY<<endl;
00168     theLShiftY=0.;
00169   }
00170 
00171   //--- Geometric Quality Information
00172   int minInX,minInY,maxInX,maxInY=0;
00173   minInX = cluster.minPixelRow();
00174   minInY = cluster.minPixelCol();
00175   maxInX = cluster.maxPixelRow();
00176   maxInY = cluster.maxPixelCol();
00177   
00178   if(theRecTopol->isItEdgePixelInX(minInX) || theRecTopol->isItEdgePixelInX(maxInX) ||
00179      theRecTopol->isItEdgePixelInY(minInY) || theRecTopol->isItEdgePixelInY(maxInY) )  {
00180     isOnEdge_ = true;
00181   }
00182   else isOnEdge_ = false;
00183   
00184   // Bad Pixels have their charge set to 0 in the clusterizer 
00185   hasBadPixels_ = false;
00186   for(unsigned int i=0; i<cluster.pixelADC().size(); ++i) {
00187     if(cluster.pixelADC()[i] == 0) hasBadPixels_ = true;
00188   }
00189   
00190   if(theRecTopol->containsBigPixelInX(minInX,maxInX) ||
00191      theRecTopol->containsBigPixelInY(minInY,maxInY) )  {
00192     spansTwoROCs_ = true;
00193   }
00194   else spansTwoROCs_ = false;
00195   
00196   
00197   if (theVerboseLevel > 1) 
00198     {
00199       LogDebug("PixelCPEBase") << "***** PIXEL LAYOUT *****" 
00200                                << " thePart = " << thePart
00201                                << " theThickness = " << theThickness
00202                                << " thePitchX  = " << thePitchX 
00203                                << " thePitchY  = " << thePitchY 
00204         // << " theOffsetX = " << theOffsetX 
00205         // << " theOffsetY = " << theOffsetY 
00206                                << " theLShiftX  = " << theLShiftX;
00207     }
00208   
00209 }
00210 
00211 
00212 //-----------------------------------------------------------------------------
00213 //  Compute alpha_ and beta_ from the LocalTrajectoryParameters.
00214 //  Note: should become const after both localParameters() become const.
00215 //-----------------------------------------------------------------------------
00216 void PixelCPEBase::
00217 computeAnglesFromTrajectory( const SiPixelCluster & cl,
00218                              const GeomDetUnit    & det, 
00219                              const LocalTrajectoryParameters & ltp) const
00220 {
00221   loc_traj_param_ = ltp;
00222 
00223   LocalVector localDir = ltp.momentum()/ltp.momentum().mag();
00224   
00225   // &&& Or, maybe we need to move to the local frame ???
00226   //  LocalVector localDir( theDet->toLocal(theState.globalDirection()));
00227   //thePart = theDet->type().part();
00228   
00229   float locx = localDir.x();
00230   float locy = localDir.y();
00231   float locz = localDir.z();
00232 
00233   /*
00234     // Danek's definition 
00235     alpha_ = acos(locx/sqrt(locx*locx+locz*locz));
00236     if ( isFlipped() )                    // &&& check for FPIX !!!
00237     alpha_ = PI - alpha_ ;
00238     beta_ = acos(locy/sqrt(locy*locy+locz*locz));
00239   */
00240 
00241   // &&& In the above, why not use atan2() ?
00242   // ggiurgiu@fnal.gov, 01/24/09 :  Use it now.
00243   alpha_ = atan2( locz, locx );
00244   beta_  = atan2( locz, locy );
00245 
00246   cotalpha_ = locx/locz;
00247   cotbeta_  = locy/locz;
00248 
00249   LocalPoint trk_lp = ltp.position();
00250   trk_lp_x = trk_lp.x();
00251   trk_lp_y = trk_lp.y();
00252   
00253   with_track_angle = true;
00254 
00255 
00256   // ggiurgiu@jhu.edu 12/09/2010 : needed to correct for bows/kinks
00257   AlgebraicVector5 vec_trk_parameters = ltp.mixedFormatVector();
00258   //loc_trk_pred = &Topology::LocalTrackPred( vec_trk_parameters );
00259   loc_trk_pred_ = Topology::LocalTrackPred( vec_trk_parameters );
00260   
00261 }
00262 
00263 //-----------------------------------------------------------------------------
00264 //  Estimate theAlpha for barrel, based on the det position.
00265 //  &&& Needs to be consolidated from the above.
00266 //-----------------------------------------------------------------------------
00267 //float 
00268 //PixelCPEBase::estimatedAlphaForBarrel(float centerx) const
00269 //{
00270 //  float tanalpha = theSign * (centerx-theOffsetX) * thePitchX / theDetR;
00271 //  return PI/2.0 - atan(tanalpha);
00272 //}
00273 
00274 
00275 //-----------------------------------------------------------------------------
00276 //  The local position.
00277 // Should do correctly the big pixels.
00278 // who is using this version????
00279 //-----------------------------------------------------------------------------
00280 LocalPoint
00281 PixelCPEBase::localPosition( const SiPixelCluster& cluster, 
00282                              const GeomDetUnit & det) const {
00283   setTheDet( det, cluster );
00284   
00285   float lpx = xpos(cluster);
00286   float lpy = ypos(cluster);
00287   float lxshift = theLShiftX * thePitchX;  // shift in cm
00288   float lyshift = theLShiftY * thePitchY;
00289   LocalPoint cdfsfs(lpx-lxshift, lpy-lyshift);
00290   return cdfsfs;
00291 }
00292 
00293 //-----------------------------------------------------------------------------
00294 //  Seems never used?
00295 //-----------------------------------------------------------------------------
00296 MeasurementPoint 
00297 PixelCPEBase::measurementPosition( const SiPixelCluster& cluster, 
00298                                    const GeomDetUnit & det) const {
00299 
00300   LocalPoint lp = localPosition(cluster,det);
00301 
00302   // ggiurgiu@jhu.edu 12/09/2010 : trk angles needed for bow/kink correction
00303 
00304   if ( with_track_angle )
00305     return theTopol->measurementPosition( lp, Topology::LocalTrackAngles( loc_traj_param_.dxdz(), loc_traj_param_.dydz() ) );
00306   else 
00307     return theTopol->measurementPosition( lp );
00308 
00309 }
00310 
00311 
00312 //-----------------------------------------------------------------------------
00313 //  Once we have the position, feed it to the topology to give us
00314 //  the error.  
00315 //  &&& APPARENTLY THIS METHOD IS NOT BEING USED ??? (Delete it?)
00316 //-----------------------------------------------------------------------------
00317 MeasurementError  
00318 PixelCPEBase::measurementError( const SiPixelCluster& cluster, const GeomDetUnit & det) const 
00319 {
00320   LocalPoint lp( localPosition(cluster, det) );
00321   LocalError le( localError(   cluster, det) );
00322 
00323   // ggiurgiu@jhu.edu 12/09/2010 : trk angles needed for bow/kink correction
00324   if ( with_track_angle )
00325     return theTopol->measurementError( lp, le, Topology::LocalTrackAngles( loc_traj_param_.dxdz(), loc_traj_param_.dydz() ) );
00326   else 
00327     return theTopol->measurementError( lp, le );
00328 }
00329 
00330 //-----------------------------------------------------------------------------
00331 //  Compute alpha_ and beta_ from the position of this DetUnit.
00332 //  &&& DOES NOT WORK FOR NOW. d.k. 6/06
00333 // The angles from dets are calculated internaly in the PixelCPEInitial class
00334 //-----------------------------------------------------------------------------
00335 // G. Giurgiu, 12/01/06 : implement the function
00336 void PixelCPEBase::
00337 computeAnglesFromDetPosition(const SiPixelCluster & cl, 
00338                              const GeomDetUnit    & det ) const
00339 {
00340   //--- This is a new det unit, so cache it
00341   theDet = dynamic_cast<const PixelGeomDetUnit*>( &det );
00342   if ( ! theDet ) 
00343     {
00344       throw cms::Exception("PixelCPEBase::computeAngleFromDetPosition")
00345         << " Wrong pointer to pixel detector !!!" << endl;
00346     
00347     }
00348 
00349   // get cluster center of gravity (of charge)
00350   float xcenter = cl.x();
00351   float ycenter = cl.y();
00352   
00353   // get the cluster position in local coordinates (cm)
00354 
00355   // ggiurgiu@jhu.edu 12/09/2010 : This function is called without track info, therefore there are no track 
00356   // angles to provide here. Call the default localPosition (without track info)
00357   LocalPoint lp = theTopol->localPosition( MeasurementPoint(xcenter, ycenter) );
00358 
00359 
00360   // get the cluster position in global coordinates (cm)
00361   GlobalPoint gp = theDet->surface().toGlobal( lp );
00362   float gp_mod = sqrt( gp.x()*gp.x() + gp.y()*gp.y() + gp.z()*gp.z() );
00363 
00364   // normalize
00365   float gpx = gp.x()/gp_mod;
00366   float gpy = gp.y()/gp_mod;
00367   float gpz = gp.z()/gp_mod;
00368 
00369   // make a global vector out of the global point; this vector will point from the 
00370   // origin of the detector to the cluster
00371   GlobalVector gv(gpx, gpy, gpz);
00372 
00373   // make local unit vector along local X axis
00374   const Local3DVector lvx(1.0, 0.0, 0.0);
00375 
00376   // get the unit X vector in global coordinates/
00377   GlobalVector gvx = theDet->surface().toGlobal( lvx );
00378 
00379   // make local unit vector along local Y axis
00380   const Local3DVector lvy(0.0, 1.0, 0.0);
00381 
00382   // get the unit Y vector in global coordinates
00383   GlobalVector gvy = theDet->surface().toGlobal( lvy );
00384    
00385   // make local unit vector along local Z axis
00386   const Local3DVector lvz(0.0, 0.0, 1.0);
00387 
00388   // get the unit Z vector in global coordinates
00389   GlobalVector gvz = theDet->surface().toGlobal( lvz );
00390     
00391   // calculate the components of gv (the unit vector pointing to the cluster) 
00392   // in the local coordinate system given by the basis {gvx, gvy, gvz}
00393   // note that both gv and the basis {gvx, gvy, gvz} are given in global coordinates
00394   float gv_dot_gvx = gv.x()*gvx.x() + gv.y()*gvx.y() + gv.z()*gvx.z();
00395   float gv_dot_gvy = gv.x()*gvy.x() + gv.y()*gvy.y() + gv.z()*gvy.z();
00396   float gv_dot_gvz = gv.x()*gvz.x() + gv.y()*gvz.y() + gv.z()*gvz.z();
00397 
00398 
00399   /* all the above is equivalent to  
00400      const Local3DPoint origin =   theDet->surface().toLocal(GlobalPoint(0,0,0)); // can be computed once...
00401      auto gvx = lp.x()-origin.x();
00402      auto gvy = lp.y()-origin.y();
00403      auto gvz = -origin.z();
00404   *  normalization not required as only ratio used... 
00405   */
00406 
00407 
00408   // calculate angles
00409   alpha_ = atan2( gv_dot_gvz, gv_dot_gvx );
00410   beta_  = atan2( gv_dot_gvz, gv_dot_gvy );
00411 
00412   cotalpha_ = gv_dot_gvx / gv_dot_gvz;
00413   cotbeta_  = gv_dot_gvy / gv_dot_gvz;
00414 
00415   with_track_angle = false;
00416 }
00417 
00418 
00419 
00420 //-----------------------------------------------------------------------------
00421 // The isFlipped() is a silly way to determine which detectors are inverted.
00422 // In the barrel for every 2nd ladder the E field direction is in the
00423 // global r direction (points outside from the z axis), every other
00424 // ladder has the E field inside. Something similar is in the 
00425 // forward disks (2 sides of the blade). This has to be recognised
00426 // because the charge sharing effect is different.
00427 //
00428 // The isFliped does it by looking and the relation of the local (z always
00429 // in the E direction) to global coordinates. There is probably a much 
00430 // better way.
00431 //-----------------------------------------------------------------------------
00432 bool PixelCPEBase::isFlipped() const 
00433 {
00434   // Check the relative position of the local +/- z in global coordinates.
00435   float tmp1 = theDet->surface().toGlobal(Local3DPoint(0.,0.,0.)).perp2();
00436   float tmp2 = theDet->surface().toGlobal(Local3DPoint(0.,0.,1.)).perp2();
00437   //cout << " 1: " << tmp1 << " 2: " << tmp2 << endl;
00438   if ( tmp2<tmp1 ) return true;
00439   else return false;    
00440 }
00441 
00442 PixelCPEBase::Param const & PixelCPEBase::param() const {
00443   Param & p = m_Params[ theDet->geographicalId().rawId() ];
00444   if unlikely ( p.bz<-1.e10f  ) { 
00445       LocalVector Bfield = theDet->surface().toLocal(magfield_->inTesla(theDet->surface().position()));
00446       p.drift = driftDirection(Bfield );
00447       p.bz = Bfield.z();
00448     }
00449   return p;
00450 }
00451 
00452 
00453 //-----------------------------------------------------------------------------
00454 // HALF OF the Lorentz shift (so for the full shift multiply by 2), and
00455 // in the units of pitch.  (So note these are neither local nor measurement
00456 // units!)
00457 //-----------------------------------------------------------------------------
00458 float PixelCPEBase::lorentzShiftX() const 
00459 {
00460   LocalVector dir = getDrift();
00461 
00462   // max shift in cm 
00463   float xdrift = dir.x()/dir.z() * theThickness;  
00464   // express the shift in units of pitch, 
00465   // divide by 2 to get the average correction
00466   float lshift = xdrift / (thePitchX*2.); 
00467     
00468   return lshift;  
00469   
00470 
00471 }
00472 
00473 float PixelCPEBase::lorentzShiftY() const 
00474 {
00475  
00476   LocalVector dir = getDrift();
00477   
00478   float ydrift = dir.y()/dir.z() * theThickness;
00479   float lshift = ydrift / (thePitchY * 2.f);
00480   return lshift; 
00481   
00482 
00483 }
00484 
00485 
00486 //-----------------------------------------------------------------------------
00487 //  Drift direction.
00488 //  Works OK for barrel and forward.
00489 //  The formulas used for dir_x,y,z have to be exactly the same as the ones
00490 //  used in the digitizer (SiPixelDigitizerAlgorithm.cc).
00491 //  Assumption: setTheDet() has been called already.
00492 //
00493 //  Petar (2/23/07): uhm, actually, there is a bug in the sign for both X and Y!
00494 //  (The signs have been fixed in SiPixelDigitizer, but not in here.)
00495 //-----------------------------------------------------------------------------
00496 LocalVector 
00497 PixelCPEBase::driftDirection( GlobalVector bfield ) const {
00498 
00499   Frame detFrame(theDet->surface().position(), theDet->surface().rotation());
00500   LocalVector Bfield = detFrame.toLocal(bfield);
00501   return driftDirection(Bfield);
00502   
00503 }
00504 
00505 LocalVector 
00506 PixelCPEBase::driftDirection( LocalVector Bfield ) const {
00507   
00508   if(lorentzAngle_ == 0){
00509     throw cms::Exception("invalidPointer") << "[PixelCPEBase::driftDirection] zero pointer to lorentz angle record ";
00510   }
00511   double langle = lorentzAngle_->getLorentzAngle(theDet->geographicalId().rawId());
00512   float alpha2;
00513   if (alpha2Order) {
00514     alpha2 = langle*langle;
00515   } else {
00516     alpha2 = 0.0;
00517   }
00518   // &&& dir_x should have a "-" and dir_y a "+"
00519   // **********************************************************************
00520   // Our convention is the following:
00521   // +x is defined by the direction of the Lorentz drift!
00522   // +z is defined by the direction of E field (so electrons always go into -z!)
00523   // +y is defined by +x and +z, and it turns out to be always opposite to the +B field.
00524   // **********************************************************************
00525   
00526   float dir_x =  ( langle * Bfield.y() + alpha2* Bfield.z()* Bfield.x() );
00527   float dir_y = -( langle * Bfield.x() - alpha2* Bfield.z()* Bfield.y() );
00528   float dir_z = -( 1.f + alpha2* Bfield.z()*Bfield.z() );
00529   double scale = 1.f/std::abs( dir_z );  // same as 1 + alpha2*Bfield.z()*Bfield.z()
00530   LocalVector  dd(dir_x*scale, dir_y*scale, -1.f );  // last is -1 !
00531   if ( theVerboseLevel > 9 ) 
00532     LogDebug("PixelCPEBase") << " The drift direction in local coordinate is " 
00533                              << dd   ;
00534         
00535   return dd;
00536 }
00537 
00538 //-----------------------------------------------------------------------------
00539 //  One-shot computation of the driftDirection and both lorentz shifts
00540 //-----------------------------------------------------------------------------
00541 void
00542 PixelCPEBase::computeLorentzShifts() const 
00543 {
00544   // this "has wrong sign..."  so "corrected below
00545    driftDirection_ = getDrift();
00546  
00547  // Max shift (at the other side of the sensor) in cm 
00548   lorentzShiftInCmX_ = -driftDirection_.x()/driftDirection_.z() * theThickness;  // &&& redundant
00549   // Express the shift in units of pitch, 
00550   lorentzShiftX_ = lorentzShiftInCmX_ / thePitchX ; 
00551    
00552   // Max shift (at the other side of the sensor) in cm 
00553   lorentzShiftInCmY_ = -driftDirection_.y()/driftDirection_.z() * theThickness;  // &&& redundant
00554   // Express the shift in units of pitch, 
00555   lorentzShiftY_ = lorentzShiftInCmY_ / thePitchY;
00556 
00557 
00558   if ( theVerboseLevel > 9 ) {
00559     LogDebug("PixelCPEBase") << " The drift direction in local coordinate is " 
00560                              << driftDirection_    ;
00561     
00562   }
00563 }
00564 
00565 //-----------------------------------------------------------------------------
00570 //-----------------------------------------------------------------------------
00571 SiPixelRecHitQuality::QualWordType 
00572 PixelCPEBase::rawQualityWord() const
00573 {
00574   SiPixelRecHitQuality::QualWordType qualWord(0);
00575   
00576   SiPixelRecHitQuality::thePacking.setProbabilityXY ( probabilityXY() ,
00577                                                       qualWord );
00578   
00579   SiPixelRecHitQuality::thePacking.setProbabilityQ  ( probabilityQ_ , 
00580                                                       qualWord );
00581   
00582   SiPixelRecHitQuality::thePacking.setQBin          ( (int)qBin_, 
00583                                                       qualWord );
00584   
00585   SiPixelRecHitQuality::thePacking.setIsOnEdge      ( isOnEdge_,
00586                                                       qualWord );
00587   
00588   SiPixelRecHitQuality::thePacking.setHasBadPixels  ( hasBadPixels_,
00589                                                       qualWord );
00590   
00591   SiPixelRecHitQuality::thePacking.setSpansTwoROCs  ( spansTwoROCs_,
00592                                                       qualWord );
00593   
00594   SiPixelRecHitQuality::thePacking.setHasFilledProb ( hasFilledProb_,
00595                                                       qualWord );
00596   
00597   return qualWord;
00598 }