Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-05-22 04:03:20

0001 // Include our own header first
0002 #include "RecoLocalTracker/SiPixelRecHits/interface/PixelCPETemplateReco.h"
0003 
0004 // Geometry services
0005 #include "Geometry/CommonDetUnit/interface/PixelGeomDetUnit.h"
0006 
0007 //#define DEBUG
0008 
0009 // MessageLogger
0010 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0011 
0012 // Magnetic field
0013 #include "MagneticField/Engine/interface/MagneticField.h"
0014 
0015 // The template header files
0016 #include "RecoLocalTracker/SiPixelRecHits/interface/SiPixelTemplateReco.h"
0017 
0018 // Commented for now (3/10/17) until we figure out how to resuscitate 2D template splitter
0019 /// #include "RecoLocalTracker/SiPixelRecHits/interface/SiPixelTemplateSplit.h"
0020 
0021 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0022 
0023 #include <vector>
0024 #include "boost/multi_array.hpp"
0025 
0026 #include <iostream>
0027 
0028 using namespace SiPixelTemplateReco;
0029 //using namespace SiPixelTemplateSplit;
0030 using namespace std;
0031 
0032 namespace {
0033   constexpr float micronsToCm = 1.0e-4;
0034   constexpr int cluster_matrix_size_x = 13;
0035   constexpr int cluster_matrix_size_y = 21;
0036 }  // namespace
0037 
0038 //-----------------------------------------------------------------------------
0039 //  Constructor.
0040 //
0041 //-----------------------------------------------------------------------------
0042 PixelCPETemplateReco::PixelCPETemplateReco(edm::ParameterSet const& conf,
0043                                            const MagneticField* mag,
0044                                            const TrackerGeometry& geom,
0045                                            const TrackerTopology& ttopo,
0046                                            const SiPixelLorentzAngle* lorentzAngle,
0047                                            const std::vector<SiPixelTemplateStore>* templateStore,
0048                                            const SiPixelTemplateDBObject* templateDBobject)
0049     : PixelCPEBase(conf, mag, geom, ttopo, lorentzAngle, nullptr, templateDBobject, nullptr, 1) {
0050   //cout << endl;
0051   //cout << "Constructing PixelCPETemplateReco::PixelCPETemplateReco(...)................................................." << endl;
0052   //cout << endl;
0053 
0054   // Configurable parameters
0055   //DoCosmics_ = conf.getParameter<bool>("DoCosmics"); // Not used in templates
0056   //LoadTemplatesFromDB_ = conf.getParameter<bool>("LoadTemplatesFromDB"); // Moved to Base
0057 
0058   //cout << " PixelCPETemplateReco : (int)LoadTemplatesFromDB_ = " << (int)LoadTemplatesFromDB_ << endl;
0059   //cout << "field_magnitude = " << field_magnitude << endl;
0060 
0061   // configuration parameter to decide between DB or text file template access
0062 
0063   if (LoadTemplatesFromDB_) {
0064     //cout << "PixelCPETemplateReco: Loading templates from database (DB) --------- " << endl;
0065     thePixelTemp_ = templateStore;
0066   } else {
0067     //cout << "PixelCPETemplateReco : Loading templates for barrel and forward from ASCII files ----------" << endl;
0068     barrelTemplateID_ = conf.getParameter<int>("barrelTemplateID");
0069     forwardTemplateID_ = conf.getParameter<int>("forwardTemplateID");
0070     templateDir_ = conf.getParameter<int>("directoryWithTemplates");
0071 
0072     thePixelTemp_ = &thePixelTempCache_;
0073     if (!SiPixelTemplate::pushfile(barrelTemplateID_, thePixelTempCache_, templateDir_))
0074       throw cms::Exception("PixelCPETemplateReco")
0075           << "\nERROR: Template ID " << barrelTemplateID_
0076           << " not loaded correctly from text file. Reconstruction will fail.\n\n";
0077 
0078     if (!SiPixelTemplate::pushfile(forwardTemplateID_, thePixelTempCache_, templateDir_))
0079       throw cms::Exception("PixelCPETemplateReco")
0080           << "\nERROR: Template ID " << forwardTemplateID_
0081           << " not loaded correctly from text file. Reconstruction will fail.\n\n";
0082   }
0083 
0084   speed_ = conf.getParameter<int>("speed");
0085   LogDebug("PixelCPETemplateReco::PixelCPETemplateReco:") << "Template speed = " << speed_ << "\n";
0086 
0087   UseClusterSplitter_ = conf.getParameter<bool>("UseClusterSplitter");
0088 }
0089 
0090 //-----------------------------------------------------------------------------
0091 //  Clean up.
0092 //-----------------------------------------------------------------------------
0093 PixelCPETemplateReco::~PixelCPETemplateReco() {}
0094 
0095 std::unique_ptr<PixelCPEBase::ClusterParam> PixelCPETemplateReco::createClusterParam(const SiPixelCluster& cl) const {
0096   return std::make_unique<ClusterParamTemplate>(cl);
0097 }
0098 
0099 //------------------------------------------------------------------
0100 //  Public methods mandated by the base class.
0101 //------------------------------------------------------------------
0102 
0103 //------------------------------------------------------------------
0104 //  The main call to the template code.
0105 //------------------------------------------------------------------
0106 LocalPoint PixelCPETemplateReco::localPosition(DetParam const& theDetParam, ClusterParam& theClusterParamBase) const {
0107   ClusterParamTemplate& theClusterParam = static_cast<ClusterParamTemplate&>(theClusterParamBase);
0108 
0109   if (!GeomDetEnumerators::isTrackerPixel(theDetParam.thePart))
0110     throw cms::Exception("PixelCPETemplateReco::localPosition :") << "A non-pixel detector type in here?";
0111   //  barrel(false) or forward(true)
0112   const bool fpix = GeomDetEnumerators::isEndcap(theDetParam.thePart);
0113 
0114   int ID = -9999;
0115   if (LoadTemplatesFromDB_) {
0116     int ID0 = templateDBobject_->getTemplateID(theDetParam.theDet->geographicalId());  // just to comapre
0117     ID = theDetParam.detTemplateId;
0118     if (ID0 != ID)
0119       edm::LogError("PixelCPETemplateReco") << " different id" << ID << " " << ID0 << endl;
0120   } else {  // from asci file
0121     if (!fpix)
0122       ID = barrelTemplateID_;  // barrel
0123     else
0124       ID = forwardTemplateID_;  // forward
0125   }
0126   //cout << "PixelCPETemplateReco : ID = " << ID << endl;
0127 
0128   SiPixelTemplate templ(*thePixelTemp_);
0129 
0130   // Preparing to retrieve ADC counts from the SiPixeltheClusterParam.theCluster->  In the cluster,
0131   // we have the following:
0132   //   int minPixelRow(); // Minimum pixel index in the x direction (low edge).
0133   //   int maxPixelRow(); // Maximum pixel index in the x direction (top edge).
0134   //   int minPixelCol(); // Minimum pixel index in the y direction (left edge).
0135   //   int maxPixelCol(); // Maximum pixel index in the y direction (right edge).
0136   // So the pixels from minPixelRow() will go into clust_array_2d[0][*],
0137   // and the pixels from minPixelCol() will go into clust_array_2d[*][0].
0138 
0139   int row_offset = theClusterParam.theCluster->minPixelRow();
0140   int col_offset = theClusterParam.theCluster->minPixelCol();
0141 
0142   // Store the coordinates of the center of the (0,0) pixel of the array that
0143   // gets passed to PixelTempReco1D
0144   // Will add these values to the output of  PixelTempReco1D
0145   float tmp_x = float(row_offset) + 0.5f;
0146   float tmp_y = float(col_offset) + 0.5f;
0147 
0148   // Store these offsets (to be added later) in a LocalPoint after tranforming
0149   // them from measurement units (pixel units) to local coordinates (cm)
0150   //
0151   //
0152 
0153   // In case of template reco failure, these are the lorentz drift corrections
0154   // to be applied
0155   float lorentzshiftX = 0.5f * theDetParam.lorentzShiftInCmX;
0156   float lorentzshiftY = 0.5f * theDetParam.lorentzShiftInCmY;
0157 
0158   // ggiurgiu@jhu.edu 12/09/2010 : update call with trk angles needed for bow/kink corrections
0159   LocalPoint lp;
0160 
0161   if (theClusterParam.with_track_angle)
0162     lp = theDetParam.theTopol->localPosition(MeasurementPoint(tmp_x, tmp_y), theClusterParam.loc_trk_pred);
0163   else {
0164     edm::LogError("PixelCPETemplateReco") << "@SUB = PixelCPETemplateReco::localPosition"
0165                                           << "Should never be here. PixelCPETemplateReco should always be called with "
0166                                              "track angles. This is a bad error !!! ";
0167 
0168     lp = theDetParam.theTopol->localPosition(MeasurementPoint(tmp_x, tmp_y));
0169   }
0170 
0171   // first compute matrix size
0172   int mrow = 0, mcol = 0;
0173   for (int i = 0; i != theClusterParam.theCluster->size(); ++i) {
0174     auto pix = theClusterParam.theCluster->pixel(i);
0175     int irow = int(pix.x);
0176     int icol = int(pix.y);
0177     mrow = std::max(mrow, irow);
0178     mcol = std::max(mcol, icol);
0179   }
0180   mrow -= row_offset;
0181   mrow += 1;
0182   mrow = std::min(mrow, cluster_matrix_size_x);
0183   mcol -= col_offset;
0184   mcol += 1;
0185   mcol = std::min(mcol, cluster_matrix_size_y);
0186   assert(mrow > 0);
0187   assert(mcol > 0);
0188 
0189   float clustMatrix[mrow][mcol];
0190   memset(clustMatrix, 0, sizeof(float) * mrow * mcol);
0191 
0192   // Copy clust's pixels (calibrated in electrons) into clusMatrix;
0193   for (int i = 0; i != theClusterParam.theCluster->size(); ++i) {
0194     auto pix = theClusterParam.theCluster->pixel(i);
0195     int irow = int(pix.x) - row_offset;
0196     int icol = int(pix.y) - col_offset;
0197 
0198     // Gavril : what do we do here if the row/column is larger than cluster_matrix_size_x/cluster_matrix_size_y  ?
0199     // Ignore them for the moment...
0200     if ((irow < mrow) & (icol < mcol))
0201       clustMatrix[irow][icol] = float(pix.adc);
0202   }
0203 
0204   // Make and fill the bool arrays flagging double pixels
0205   bool xdouble[mrow], ydouble[mcol];
0206   // x directions (shorter), rows
0207   for (int irow = 0; irow < mrow; ++irow)
0208     xdouble[irow] = theDetParam.theTopol->isItBigPixelInX(irow + row_offset);
0209 
0210   // y directions (longer), columns
0211   for (int icol = 0; icol < mcol; ++icol)
0212     ydouble[icol] = theDetParam.theTopol->isItBigPixelInY(icol + col_offset);
0213 
0214   SiPixelTemplateReco::ClusMatrix clusterPayload{&clustMatrix[0][0], xdouble, ydouble, mrow, mcol};
0215 
0216   // Output:
0217   float nonsense = -99999.9f;  // nonsense init value
0218   theClusterParam.templXrec_ = theClusterParam.templYrec_ = theClusterParam.templSigmaX_ =
0219       theClusterParam.templSigmaY_ = nonsense;
0220   // If the template recontruction fails, we want to return 1.0 for now
0221   theClusterParam.templProbY_ = theClusterParam.templProbX_ = theClusterParam.templProbQ_ = 1.0f;
0222   theClusterParam.templQbin_ = 0;
0223   // We have a boolean denoting whether the reco failed or not
0224   theClusterParam.hasFilledProb_ = false;
0225 
0226   float templYrec1_ = nonsense;
0227   float templXrec1_ = nonsense;
0228   float templYrec2_ = nonsense;
0229   float templXrec2_ = nonsense;
0230 
0231   // ******************************************************************
0232   // Do it! Use cotalpha_ and cotbeta_ calculated in PixelCPEBase
0233 
0234   float locBz = theDetParam.bz;
0235   float locBx = theDetParam.bx;
0236 
0237   theClusterParam.ierr = PixelTempReco1D(ID,
0238                                          theClusterParam.cotalpha,
0239                                          theClusterParam.cotbeta,
0240                                          locBz,
0241                                          locBx,
0242                                          clusterPayload,
0243                                          templ,
0244                                          theClusterParam.templYrec_,
0245                                          theClusterParam.templSigmaY_,
0246                                          theClusterParam.templProbY_,
0247                                          theClusterParam.templXrec_,
0248                                          theClusterParam.templSigmaX_,
0249                                          theClusterParam.templProbX_,
0250                                          theClusterParam.templQbin_,
0251                                          speed_,
0252                                          theClusterParam.templProbQ_);
0253 
0254   // ******************************************************************
0255 
0256   // Check exit status
0257   if UNLIKELY (theClusterParam.ierr != 0) {
0258     LogDebug("PixelCPETemplateReco::localPosition")
0259         << "reconstruction failed with error " << theClusterParam.ierr << "\n";
0260 
0261     // Template reco has failed, compute position estimates based on cluster center of gravity + Lorentz drift
0262     // Future improvement would be to call generic reco instead
0263 
0264     // ggiurgiu@jhu.edu, 21/09/2010 : trk angles needed to correct for bows/kinks
0265     if (theClusterParam.with_track_angle) {
0266       theClusterParam.templXrec_ =
0267           theDetParam.theTopol->localX(theClusterParam.theCluster->x(), theClusterParam.loc_trk_pred) + lorentzshiftX;
0268       theClusterParam.templYrec_ =
0269           theDetParam.theTopol->localY(theClusterParam.theCluster->y(), theClusterParam.loc_trk_pred) + lorentzshiftY;
0270     } else {
0271       edm::LogError("PixelCPETemplateReco") << "@SUB = PixelCPETemplateReco::localPosition"
0272                                             << "Should never be here. PixelCPETemplateReco should always be called "
0273                                                "with track angles. This is a bad error !!! ";
0274 
0275       theClusterParam.templXrec_ = theDetParam.theTopol->localX(theClusterParam.theCluster->x()) + lorentzshiftX;
0276       theClusterParam.templYrec_ = theDetParam.theTopol->localY(theClusterParam.theCluster->y()) + lorentzshiftY;
0277     }
0278   } else if UNLIKELY (UseClusterSplitter_ && theClusterParam.templQbin_ == 0) {
0279     edm::LogError("PixelCPETemplateReco") << " PixelCPETemplateReco: Qbin = 0 but using cluster splitter, we should "
0280                                              "never be here !!!!!!!!!!!!!!!!!!!!!! \n"
0281                                           << "(int)UseClusterSplitter_ = " << (int)UseClusterSplitter_ << endl;
0282 
0283     //ierr =
0284     //PixelTempSplit( ID, fpix, cotalpha_, cotbeta_,
0285     //      clust_array_2d, ydouble, xdouble,
0286     //      templ,
0287     //      templYrec1_, templYrec2_, templSigmaY_, templProbY_,
0288     //      templXrec1_, templXrec2_, templSigmaX_, templProbX_,
0289     //      templQbin_ );
0290 
0291     // Commented for now (3/10/17) until we figure out how to resuscitate 2D template splitter
0292     ///      std::vector< SiPixelTemplateStore2D > thePixelTemp2D_;
0293     ///SiPixelTemplate2D::pushfile(ID, thePixelTemp2D_);
0294     ///SiPixelTemplate2D templ2D_(thePixelTemp2D_);
0295 
0296     theClusterParam.ierr = -123;
0297     /*
0298        float dchisq;
0299        float templProbQ_;
0300        SiPixelTemplateSplit::PixelTempSplit( ID, theClusterParam.cotalpha, theClusterParam.cotbeta,
0301        clust_array_2d,
0302        ydouble, xdouble,
0303        templ,
0304        templYrec1_, templYrec2_, theClusterParam.templSigmaY_, theClusterParam.templProbY_,
0305        templXrec1_, templXrec2_, theClusterParam.templSigmaX_, theClusterParam.templProbX_,
0306        theClusterParam.templQbin_,
0307        templProbQ_,
0308        true,
0309        dchisq,
0310        templ2D_ );
0311        
0312        */
0313     if (theClusterParam.ierr != 0) {
0314       // Template reco has failed, compute position estimates based on cluster center of gravity + Lorentz drift
0315       // Future improvement would be to call generic reco instead
0316 
0317       // ggiurgiu@jhu.edu, 12/09/2010 : trk angles needed to correct for bows/kinks
0318       if (theClusterParam.with_track_angle) {
0319         theClusterParam.templXrec_ =
0320             theDetParam.theTopol->localX(theClusterParam.theCluster->x(), theClusterParam.loc_trk_pred) + lorentzshiftX;
0321         theClusterParam.templYrec_ =
0322             theDetParam.theTopol->localY(theClusterParam.theCluster->y(), theClusterParam.loc_trk_pred) + lorentzshiftY;
0323       } else {
0324         edm::LogError("PixelCPETemplateReco") << "@SUB = PixelCPETemplateReco::localPosition"
0325                                               << "Should never be here. PixelCPETemplateReco should always be called "
0326                                                  "with track angles. This is a bad error !!! ";
0327         theClusterParam.templXrec_ = theDetParam.theTopol->localX(theClusterParam.theCluster->x()) + lorentzshiftX;
0328         theClusterParam.templYrec_ = theDetParam.theTopol->localY(theClusterParam.theCluster->y()) + lorentzshiftY;
0329       }
0330     } else {
0331       // go from micrometer to centimeter
0332       templXrec1_ *= micronsToCm;
0333       templYrec1_ *= micronsToCm;
0334       templXrec2_ *= micronsToCm;
0335       templYrec2_ *= micronsToCm;
0336 
0337       // go back to the module coordinate system
0338       templXrec1_ += lp.x();
0339       templYrec1_ += lp.y();
0340       templXrec2_ += lp.x();
0341       templYrec2_ += lp.y();
0342 
0343       // calculate distance from each hit to the track and choose the hit closest to the track
0344       float distX1 = std::abs(templXrec1_ - theClusterParam.trk_lp_x);
0345       float distX2 = std::abs(templXrec2_ - theClusterParam.trk_lp_x);
0346       float distY1 = std::abs(templYrec1_ - theClusterParam.trk_lp_y);
0347       float distY2 = std::abs(templYrec2_ - theClusterParam.trk_lp_y);
0348       theClusterParam.templXrec_ = (distX1 < distX2 ? templXrec1_ : templXrec2_);
0349       theClusterParam.templYrec_ = (distY1 < distY2 ? templYrec1_ : templYrec2_);
0350     }
0351   }  // else if ( UseClusterSplitter_ && templQbin_ == 0 )
0352 
0353   else  // apparenly this is the good one!
0354   {
0355     // go from micrometer to centimeter
0356     theClusterParam.templXrec_ *= micronsToCm;
0357     theClusterParam.templYrec_ *= micronsToCm;
0358 
0359     // go back to the module coordinate system
0360     theClusterParam.templXrec_ += lp.x();
0361     theClusterParam.templYrec_ += lp.y();
0362 
0363     // Compute the Alignment Group Corrections [template ID should already be selected from call to reco procedure]
0364     if (doLorentzFromAlignment_) {
0365       // Do only if the lotentzshift has meaningfull numbers
0366       if (theDetParam.lorentzShiftInCmX != 0.0 || theDetParam.lorentzShiftInCmY != 0.0) {
0367         // the LA width/shift returned by templates use (+)
0368         // the LA width/shift produced by PixelCPEBase for positive LA is (-)
0369         // correct this by iserting (-)
0370         //float temp1 = -micronsToCm*templ.lorxwidth();  // old
0371         //float temp2 = -micronsToCm*templ.lorywidth();  // does not incl 1/2
0372         float templateLorbiasCmX = -micronsToCm * templ.lorxbias();  // new
0373         float templateLorbiasCmY = -micronsToCm * templ.lorybias();  //incl. 1/2
0374         // now, correctly, we can use the difference of shifts
0375         //theClusterParam.templXrec_ += 0.5*(theDetParam.lorentzShiftInCmX - templateLorbiasCmX);
0376         //theClusterParam.templYrec_ += 0.5*(theDetParam.lorentzShiftInCmY - templateLorbiasCmY);
0377         theClusterParam.templXrec_ += (0.5 * (theDetParam.lorentzShiftInCmX) - templateLorbiasCmX);
0378         theClusterParam.templYrec_ += (0.5 * (theDetParam.lorentzShiftInCmY) - templateLorbiasCmY);
0379         //cout << "Templates: la lorentz offset = "
0380         //   <<(0.5*(theDetParam.lorentzShiftInCmX)-templateLorbiasCmX)
0381         //   <<" "<<templateLorbiasCmX<<" "<<templateLorbiasCmY
0382         //   <<" "<<temp1<<" "<<temp2
0383         //   <<" "<<theDetParam.lorentzShiftInCmX
0384         //   <<" "<<theDetParam.lorentzShiftInCmY
0385         //   << endl; //dk
0386       }  //else {cout<<" LA is 0, disable offset corrections "<<endl;} //dk
0387     }    //else {cout<<" Do not do LA offset correction "<<endl;} //dk
0388   }
0389 
0390   // Save probabilities and qBin in the quantities given to us by the base class
0391   // (for which there are also inline getters).  &&& templProbX_ etc. should be retired...
0392   theClusterParam.probabilityX_ = theClusterParam.templProbX_;
0393   theClusterParam.probabilityY_ = theClusterParam.templProbY_;
0394   theClusterParam.probabilityQ_ = theClusterParam.templProbQ_;
0395   theClusterParam.qBin_ = theClusterParam.templQbin_;
0396 
0397   if (theClusterParam.ierr == 0)  // always true here
0398     theClusterParam.hasFilledProb_ = true;
0399 
0400   return LocalPoint(theClusterParam.templXrec_, theClusterParam.templYrec_);
0401 }
0402 
0403 //------------------------------------------------------------------
0404 //  localError() relies on localPosition() being called FIRST!!!
0405 //------------------------------------------------------------------
0406 LocalError PixelCPETemplateReco::localError(DetParam const& theDetParam, ClusterParam& theClusterParamBase) const {
0407   ClusterParamTemplate& theClusterParam = static_cast<ClusterParamTemplate&>(theClusterParamBase);
0408 
0409   //cout << endl;
0410   //cout << "Set PixelCPETemplate errors .............................................." << endl;
0411 
0412   //cout << "CPETemplate : " << endl;
0413 
0414   //--- Default is the maximum error used for edge clusters.
0415   //--- (never used, in fact: let comment it out, shut up the complains of the static analyzer, and save a few CPU cycles)
0416   //   const float sig12 = 1./sqrt(12.0);
0417   //   float xerr = theDetParam.thePitchX *sig12;
0418   //   float yerr = theDetParam.thePitchY *sig12;
0419   float xerr, yerr;
0420 
0421   // Check if the errors were already set at the clusters splitting level
0422   if (theClusterParam.theCluster->getSplitClusterErrorX() > 0.0f &&
0423       theClusterParam.theCluster->getSplitClusterErrorX() < clusterSplitMaxError_ &&
0424       theClusterParam.theCluster->getSplitClusterErrorY() > 0.0f &&
0425       theClusterParam.theCluster->getSplitClusterErrorY() < clusterSplitMaxError_) {
0426     xerr = theClusterParam.theCluster->getSplitClusterErrorX() * micronsToCm;
0427     yerr = theClusterParam.theCluster->getSplitClusterErrorY() * micronsToCm;
0428 
0429     //cout << "Errors set at cluster splitting level : " << endl;
0430     //cout << "xerr = " << xerr << endl;
0431     //cout << "yerr = " << yerr << endl;
0432   } else {
0433     // If errors are not split at the cluster splitting level, set the errors here
0434 
0435     //cout  << "Errors are not split at the cluster splitting level, set the errors here : " << endl;
0436 
0437     int maxPixelCol = theClusterParam.theCluster->maxPixelCol();
0438     int maxPixelRow = theClusterParam.theCluster->maxPixelRow();
0439     int minPixelCol = theClusterParam.theCluster->minPixelCol();
0440     int minPixelRow = theClusterParam.theCluster->minPixelRow();
0441 
0442     //--- Are we near either of the edges?
0443     bool edgex =
0444         (theDetParam.theTopol->isItEdgePixelInX(minPixelRow) || theDetParam.theTopol->isItEdgePixelInX(maxPixelRow));
0445     bool edgey =
0446         (theDetParam.theTopol->isItEdgePixelInY(minPixelCol) || theDetParam.theTopol->isItEdgePixelInY(maxPixelCol));
0447 
0448     if (theClusterParam.ierr != 0) {
0449       // If reconstruction fails the hit position is calculated from cluster center of gravity
0450       // corrected in x by average Lorentz drift. Assign huge errors.
0451       //xerr = 10.0 * (float)theClusterParam.theCluster->sizeX() * xerr;
0452       //yerr = 10.0 * (float)theClusterParam.theCluster->sizeX() * yerr;
0453 
0454       if (!GeomDetEnumerators::isTrackerPixel(theDetParam.thePart))
0455         throw cms::Exception("PixelCPETemplateReco::localPosition :") << "A non-pixel detector type in here?";
0456 
0457       // Assign better errors based on the residuals for failed template cases
0458       if (GeomDetEnumerators::isBarrel(theDetParam.thePart)) {
0459         xerr = 55.0f * micronsToCm;
0460         yerr = 36.0f * micronsToCm;
0461       } else {
0462         xerr = 42.0f * micronsToCm;
0463         yerr = 39.0f * micronsToCm;
0464       }
0465 
0466       //cout << "xerr = " << xerr << endl;
0467       //cout << "yerr = " << yerr << endl;
0468 
0469       //return LocalError(xerr*xerr, 0, yerr*yerr);
0470     } else if (edgex || edgey) {
0471       // for edge pixels assign errors according to observed residual RMS
0472       if (edgex && !edgey) {
0473         xerr = xEdgeXError_ * micronsToCm;
0474         yerr = xEdgeYError_ * micronsToCm;
0475       } else if (!edgex && edgey) {
0476         xerr = yEdgeXError_ * micronsToCm;
0477         yerr = yEdgeYError_ * micronsToCm;
0478       } else if (edgex && edgey) {
0479         xerr = bothEdgeXError_ * micronsToCm;
0480         yerr = bothEdgeYError_ * micronsToCm;
0481       } else {
0482         throw cms::Exception(" PixelCPETemplateReco::localError: Something wrong with pixel edge flag !!!");
0483       }
0484 
0485       //cout << "xerr = " << xerr << endl;
0486       //cout << "yerr = " << yerr << endl;
0487     } else {
0488       // &&& need a class const
0489       //const float micronsToCm = 1.0e-4;
0490 
0491       xerr = theClusterParam.templSigmaX_ * micronsToCm;
0492       yerr = theClusterParam.templSigmaY_ * micronsToCm;
0493 
0494       //cout << "xerr = " << xerr << endl;
0495       //cout << "yerr = " << yerr << endl;
0496 
0497       // &&& should also check ierr (saved as class variable) and return
0498       // &&& nonsense (another class static) if the template fit failed.
0499     }
0500 
0501     if (theVerboseLevel > 9) {
0502       LogDebug("PixelCPETemplateReco") << " Sizex = " << theClusterParam.theCluster->sizeX()
0503                                        << " Sizey = " << theClusterParam.theCluster->sizeY() << " Edgex = " << edgex
0504                                        << " Edgey = " << edgey << " ErrX  = " << xerr << " ErrY  = " << yerr;
0505     }
0506 
0507   }  // else
0508 
0509   if (!(xerr > 0.0f))
0510     throw cms::Exception("PixelCPETemplateReco::localError")
0511         << "\nERROR: Negative pixel error xerr = " << xerr << "\n\n";
0512 
0513   if (!(yerr > 0.0f))
0514     throw cms::Exception("PixelCPETemplateReco::localError")
0515         << "\nERROR: Negative pixel error yerr = " << yerr << "\n\n";
0516 
0517   //cout << "Final errors set to: " << endl;
0518   //cout << "xerr = " << xerr << endl;
0519   //cout << "yerr = " << yerr << endl;
0520   //cout << "Out of PixelCPETemplateREco..........................................................................." << endl;
0521   //cout << endl;
0522 
0523   return LocalError(xerr * xerr, 0, yerr * yerr);
0524 }
0525 
0526 void PixelCPETemplateReco::fillPSetDescription(edm::ParameterSetDescription& desc) {
0527   desc.add<int>("barrelTemplateID", 0);
0528   desc.add<int>("forwardTemplateID", 0);
0529   desc.add<int>("directoryWithTemplates", 0);
0530   desc.add<int>("speed", -2);
0531   desc.add<bool>("UseClusterSplitter", false);
0532 }