CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/RecoLocalTracker/SiPixelClusterizer/src/PixelThresholdClusterizer.cc

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00020 //----------------------------------------------------------------------------
00021 
00022 // Our own includes
00023 #include "RecoLocalTracker/SiPixelClusterizer/interface/PixelThresholdClusterizer.h"
00024 #include "RecoLocalTracker/SiPixelClusterizer/interface/SiPixelArrayBuffer.h"
00025 #include "CondFormats/SiPixelObjects/interface/SiPixelGainCalibrationOffline.h"
00026 // Geometry
00027 #include "Geometry/TrackerGeometryBuilder/interface/PixelGeomDetUnit.h"
00028 #include "Geometry/CommonTopologies/interface/PixelTopology.h"
00029 //#include "Geometry/CommonTopologies/RectangularPixelTopology.h"
00030 #include "DataFormats/SiPixelDetId/interface/PXBDetId.h"
00031 
00032 // STL
00033 #include <stack>
00034 #include <vector>
00035 #include <iostream>
00036 using namespace std;
00037 
00038 //----------------------------------------------------------------------------
00042 //----------------------------------------------------------------------------
00043 PixelThresholdClusterizer::PixelThresholdClusterizer
00044   (edm::ParameterSet const& conf) :
00045     conf_(conf), bufferAlreadySet(false), theNumOfRows(0), theNumOfCols(0), detid_(0) 
00046 {
00047   // Get thresholds in electrons
00048   thePixelThreshold   = 
00049     conf_.getParameter<int>("ChannelThreshold");
00050   theSeedThreshold    = 
00051     conf_.getParameter<int>("SeedThreshold");
00052   theClusterThreshold = 
00053     conf_.getParameter<double>("ClusterThreshold");
00054   theConversionFactor = 
00055     conf_.getParameter<int>("VCaltoElectronGain");
00056   theOffset = 
00057     conf_.getParameter<int>("VCaltoElectronOffset");
00058   if ( conf_.exists("AdcFullScaleStack") ) theStackADC_=conf_.getParameter<int>("AdcFullScaleStack");
00059   else 
00060     theStackADC_=255;
00061   if ( conf_.exists("FirstStackLayer") ) theFirstStack_=conf_.getParameter<int>("FirstStackLayer");
00062   else
00063     theFirstStack_=5;
00064   
00065   // Get the constants for the miss-calibration studies
00066   doMissCalibrate=conf_.getUntrackedParameter<bool>("MissCalibrate",true); 
00067   doSplitClusters = conf.getParameter<bool>("SplitClusters");
00068   theBuffer.setSize( theNumOfRows, theNumOfCols );
00069 }
00071 PixelThresholdClusterizer::~PixelThresholdClusterizer() {}
00072 
00073 //----------------------------------------------------------------------------
00076 //----------------------------------------------------------------------------
00077 bool PixelThresholdClusterizer::setup(const PixelGeomDetUnit * pixDet) 
00078 {
00079   // Cache the topology.
00080   const PixelTopology & topol = pixDet->specificTopology();
00081   
00082   // Get the new sizes.
00083   int nrows = topol.nrows();      // rows in x
00084   int ncols = topol.ncolumns();   // cols in y
00085   
00086   theNumOfRows = nrows;  // Set new sizes
00087   theNumOfCols = ncols;
00088   
00089   if ( nrows > theBuffer.rows() || 
00090        ncols > theBuffer.columns() ) 
00091     { // change only when a larger is needed
00092       //if( nrows != theNumOfRows || ncols != theNumOfCols ) {
00093       //cout << " PixelThresholdClusterizer: pixel buffer redefined to " 
00094       // << nrows << " * " << ncols << endl;      
00095       //theNumOfRows = nrows;  // Set new sizes
00096       //theNumOfCols = ncols;
00097       // Resize the buffer
00098       theBuffer.setSize(nrows,ncols);  // Modify
00099       bufferAlreadySet = true;
00100     }
00101   
00102   return true;   
00103 }
00104 //----------------------------------------------------------------------------
00110 //----------------------------------------------------------------------------
00111 void PixelThresholdClusterizer::clusterizeDetUnit( const edm::DetSet<PixelDigi> & input,
00112                                                    const PixelGeomDetUnit * pixDet,
00113                                                    const std::vector<short>& badChannels,
00114                                                    edmNew::DetSetVector<SiPixelCluster>::FastFiller& output) {
00115   
00116   DigiIterator begin = input.begin();
00117   DigiIterator end   = input.end();
00118   
00119   // Do not bother for empty detectors
00120   //if (begin == end) cout << " PixelThresholdClusterizer::clusterizeDetUnit - No digis to clusterize";
00121   
00122   //  Set up the clusterization on this DetId.
00123   if ( !setup(pixDet) ) 
00124     return;
00125   
00126   detid_ = input.detId();
00127   
00128   //  Copy PixelDigis to the buffer array; select the seed pixels
00129   //  on the way, and store them in theSeeds.
00130   copy_to_buffer(begin, end);
00131   
00132   //  At this point we know the number of seeds on this DetUnit, and thus
00133   //  also the maximal number of possible clusters, so resize theClusters
00134   //  in order to make vector<>::push_back() efficient.
00135   // output.reserve ( theSeeds.size() ); //GPetruc: It is better *not* to reserve, with the new DetSetVector!
00136   
00137   
00138   //  Loop over all seeds.  TO DO: wouldn't using iterators be faster?
00139   //  edm::LogError("PixelThresholdClusterizer") <<  "Starting clusterizing" << endl;
00140   for (unsigned int i = 0; i < theSeeds.size(); i++) 
00141     {
00142       
00143       // Gavril : The charge of seeds that were already inlcuded in clusters is set to 1 electron
00144       // so we don't want to call "make_cluster" for these cases 
00145       if ( theBuffer(theSeeds[i]) >= theSeedThreshold ) 
00146         {  // Is this seed still valid?
00147           //  Make a cluster around this seed
00148           SiPixelCluster cluster = make_cluster( theSeeds[i] , output);
00149           
00150           //  Check if the cluster is above threshold  
00151           // (TO DO: one is signed, other unsigned, gcc warns...)
00152           if ( cluster.charge() >= theClusterThreshold) 
00153             {
00154               //        cout << "putting in this cluster" << endl;
00155               output.push_back( cluster );
00156             }
00157         }
00158     }
00159   
00160   // Erase the seeds.
00161   theSeeds.clear();
00162   
00163   //  Need to clean unused pixels from the buffer array.
00164   clear_buffer(begin, end);
00165   
00166 }
00167 
00168 //----------------------------------------------------------------------------
00176 //----------------------------------------------------------------------------
00177 void PixelThresholdClusterizer::clear_buffer( DigiIterator begin, DigiIterator end ) 
00178 {
00179   for(DigiIterator di = begin; di != end; ++di ) 
00180     {
00181       theBuffer.set_adc( di->row(), di->column(), 0 );   // reset pixel adc to 0
00182     }
00183 }
00184 
00185 //----------------------------------------------------------------------------
00187 //----------------------------------------------------------------------------
00188 void PixelThresholdClusterizer::copy_to_buffer( DigiIterator begin, DigiIterator end ) 
00189 {
00190   for(DigiIterator di = begin; di != end; ++di) 
00191     {
00192       int row = di->row();
00193       int col = di->column();
00194       int adc = calibrate(di->adc(),col,row); // convert ADC -> electrons
00195       if ( adc >= thePixelThreshold) 
00196         {
00197           theBuffer.set_adc( row, col, adc);
00198           if ( adc >= theSeedThreshold) 
00199             { 
00200               theSeeds.push_back( SiPixelCluster::PixelPos(row,col) );
00201             }
00202         }
00203     }
00204 }
00205 
00206 //----------------------------------------------------------------------------
00207 // Calibrate adc counts to electrons
00208 //-----------------------------------------------------------------
00209 int PixelThresholdClusterizer::calibrate(int adc, int col, int row) 
00210 {
00211   int electrons = 0;
00212   int layer= 0;
00213   if (DetId(detid_).subdetId()==1){ layer = PXBDetId(detid_).layer();}
00214 
00215   if ( doMissCalibrate ) 
00216     {
00217       // do not perform calibration if pixel is dead!
00218       
00219       if ( !theSiPixelGainCalibrationService_->isDead(detid_,col,row) && 
00220            !theSiPixelGainCalibrationService_->isNoisy(detid_,col,row) )
00221         {
00222           
00223           // Linear approximation of the TANH response
00224           // Pixel(0,0,0)
00225           //const float gain = 2.95; // 1 ADC = 2.95 VCALs (1/0.339)
00226           //const float pedestal = -83.; // -28/0.339
00227           // Roc-0 average
00228           //const float gain = 1./0.357; // 1 ADC = 2.80 VCALs 
00229           //const float pedestal = -28.2 * gain; // -79.
00230           
00231           float DBgain     = theSiPixelGainCalibrationService_->getGain(detid_, col, row);
00232           float DBpedestal = theSiPixelGainCalibrationService_->getPedestal(detid_, col, row) * DBgain;
00233           
00234           
00235           // Roc-6 average
00236           //const float gain = 1./0.313; // 1 ADC = 3.19 VCALs 
00237           //const float pedestal = -6.2 * gain; // -19.8
00238           // 
00239           float vcal = adc * DBgain - DBpedestal;
00240           
00241           // atanh calibration 
00242           // Roc-6 average
00243           //const float p0 = 0.00492;
00244           //const float p1 = 1.998;
00245           //const float p2 = 90.6;
00246           //const float p3 = 134.1; 
00247           // Roc-6 average
00248           //const float p0 = 0.00382;
00249           //const float p1 = 0.886;
00250           //const float p2 = 112.7;
00251           //const float p3 = 113.0; 
00252           //float vcal = ( atanh( (adc-p3)/p2) + p1)/p0;
00253           
00254           electrons = int( vcal * theConversionFactor + theOffset); 
00255         }
00256     }
00257   else 
00258     { // No misscalibration in the digitizer
00259       // Simple (default) linear gain 
00260       const float gain = 135.; // 1 ADC = 135 electrons
00261       const float pedestal = 0.; //
00262       electrons = int(adc * gain + pedestal);
00263       if (layer>=theFirstStack_) {
00264         if (theStackADC_==1&&adc==1)
00265           {
00266             electrons = int(255*135); // Arbitrarily use overflow value.
00267           }
00268         if (theStackADC_>1&&theStackADC_!=255&&adc>=1)
00269           {
00270             const float gain = 135.; // 1 ADC = 135 electrons
00271             electrons = int((adc-1) * gain * 255/float(theStackADC_-1));
00272           }
00273       }
00274     }
00275   
00276   return electrons;
00277 }
00278 
00279 
00280 namespace {
00281 
00282   struct AccretionCluster {
00283     typedef unsigned short UShort;
00284     static constexpr UShort MAXSIZE = 256;
00285     UShort adc[256];
00286     UShort x[256];
00287     UShort y[256];
00288     UShort xmin=16000;
00289     UShort ymin=16000;
00290     unsigned int isize=0;
00291     unsigned int curr=0;
00292 
00293     // stack interface (unsafe ok for use below)
00294     UShort top() const { return curr;}
00295     void pop() { ++curr;}   
00296     bool empty() { return curr==isize;}
00297 
00298     bool add(SiPixelCluster::PixelPos const & p, UShort const iadc) {
00299       if (isize==MAXSIZE) return false;
00300       xmin=std::min(xmin,(unsigned short)(p.row()));
00301       ymin=std::min(ymin,(unsigned short)(p.col()));
00302       adc[isize]=iadc;
00303       x[isize]=p.row();
00304       y[isize++]=p.col();
00305       return true;
00306     }
00307   };
00308 
00309 }
00310 
00311 //----------------------------------------------------------------------------
00313 //----------------------------------------------------------------------------
00314 SiPixelCluster 
00315 PixelThresholdClusterizer::make_cluster( const SiPixelCluster::PixelPos& pix, 
00316                                          edmNew::DetSetVector<SiPixelCluster>::FastFiller& output) 
00317 {
00318   
00319   //First we acquire the seeds for the clusters
00320   int seed_adc;
00321   stack<SiPixelCluster::PixelPos, vector<SiPixelCluster::PixelPos> > dead_pixel_stack;
00322   
00323   //The individual modules have been loaded into a buffer.
00324   //After each pixel has been considered by the clusterizer, we set the adc count to 1
00325   //to mark that we have already considered it.
00326   //The only difference between dead/noisy pixels and standard ones is that for dead/noisy pixels,
00327   //We consider the charge of the pixel to always be zero.
00328 
00329   if ( doMissCalibrate &&
00330        (theSiPixelGainCalibrationService_->isDead(detid_,pix.col(),pix.row()) || 
00331         theSiPixelGainCalibrationService_->isNoisy(detid_,pix.col(),pix.row())) )
00332     {
00333       seed_adc = 0;
00334       theBuffer.set_adc(pix, 1);
00335     }
00336   else
00337     {
00338       seed_adc = theBuffer(pix.row(), pix.col());
00339       theBuffer.set_adc( pix, 1);
00340     }
00341   
00342   AccretionCluster acluster;
00343   acluster.add(pix, seed_adc);
00344   
00345   //Here we search all pixels adjacent to all pixels in the cluster.
00346   bool dead_flag = false;
00347   while ( ! acluster.empty()) 
00348     {
00349       //This is the standard algorithm to find and add a pixel
00350       auto curInd = acluster.top(); acluster.pop();
00351       for ( auto r = acluster.x[curInd]-1; r <= acluster.x[curInd]+1; ++r) 
00352         {
00353           for ( auto c = acluster.y[curInd]-1; c <= acluster.y[curInd]+1; ++c) 
00354             {
00355               if ( theBuffer(r,c) >= thePixelThreshold) 
00356                 {
00357                   
00358                   SiPixelCluster::PixelPos newpix(r,c);
00359                   if (!acluster.add( newpix, theBuffer(r,c))) goto endClus;
00360                   theBuffer.set_adc( newpix, 1);
00361                 }
00362              
00363 
00364               /* //Commenting out the addition of dead pixels to the cluster until further testing -- dfehling 06/09
00365               //Check on the bounds of the module; this is to keep the isDead and isNoisy modules from returning errors 
00366               else if(r>= 0 && c >= 0 && (r <= (theNumOfRows-1.)) && (c <= (theNumOfCols-1.))){ 
00367               //Check for dead/noisy pixels check that the buffer is not -1 (already considered).  Check whether we want to split clusters separated by dead pixels or not.
00368               if((theSiPixelGainCalibrationService_->isDead(detid_,c,r) || theSiPixelGainCalibrationService_->isNoisy(detid_,c,r)) && theBuffer(r,c) != 1){
00369               
00370               //If a pixel is dead or noisy, check to see if we want to split the clusters or not.  
00371               //Push it into a dead pixel stack in case we want to split the clusters.  Otherwise add it to the cluster.
00372               //If we are splitting the clusters, we will iterate over the dead pixel stack later.
00373               
00374               SiPixelCluster::PixelPos newpix(r,c);
00375               if(!doSplitClusters){
00376               
00377               cluster.add(newpix, theBuffer(r,c));}
00378               else if(doSplitClusters){
00379               dead_pixel_stack.push(newpix);
00380               dead_flag = true;}
00381               
00382               theBuffer.set_adc(newpix, 1);
00383               } 
00384               
00385               }
00386               */
00387             
00388 
00389 
00390             }
00391         }
00392       
00393     }  // while accretion
00394  endClus:
00395   SiPixelCluster cluster(acluster.isize,acluster.adc, acluster.x,acluster.y, acluster.xmin,acluster.ymin);
00396   //Here we split the cluster, if the flag to do so is set and we have found a dead or noisy pixel.
00397   
00398   if (dead_flag && doSplitClusters) 
00399     {
00400       //Set the first cluster equal to the existing cluster.
00401       SiPixelCluster first_cluster = cluster;
00402       bool have_second_cluster = false;
00403       while ( !dead_pixel_stack.empty() )
00404         {
00405           //consider each found dead pixel
00406           SiPixelCluster::PixelPos deadpix = dead_pixel_stack.top(); dead_pixel_stack.pop();
00407           theBuffer.set_adc(deadpix, 1);
00408          
00409           //Clusterize the split cluster using the dead pixel as a seed
00410           SiPixelCluster second_cluster = make_cluster(deadpix, output);
00411           
00412           //If both clusters would normally have been found by the clusterizer, put them into output
00413           if ( second_cluster.charge() >= theClusterThreshold && 
00414                first_cluster.charge() >= theClusterThreshold )
00415             {
00416               output.push_back( second_cluster );
00417               have_second_cluster = true;       
00418             }
00419           
00420           //We also want to keep the merged cluster in data and let the RecHit algorithm decide which set to keep
00421           //This loop adds the second cluster to the first.
00422           const std::vector<SiPixelCluster::Pixel>& branch_pixels = second_cluster.pixels();
00423           for ( unsigned int i = 0; i<branch_pixels.size(); i++)
00424             {
00425               int temp_x = branch_pixels[i].x;
00426               int temp_y = branch_pixels[i].y;
00427               int temp_adc = branch_pixels[i].adc;
00428               SiPixelCluster::PixelPos newpix(temp_x, temp_y);
00429               cluster.add(newpix, temp_adc);}
00430         }
00431       
00432       //Remember to also add the first cluster if we added the second one.
00433       if ( first_cluster.charge() >= theClusterThreshold && have_second_cluster) 
00434         {
00435           output.push_back( first_cluster );
00436         }
00437     }
00438   
00439   return cluster;
00440 }
00441