CMS 3D CMS Logo

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