CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
PixelThresholdClusterizer.cc
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
20 //----------------------------------------------------------------------------
21 
22 // Our own includes
26 // Geometry
29 //#include "Geometry/CommonTopologies/RectangularPixelTopology.h"
31 
32 // STL
33 #include <stack>
34 #include <vector>
35 #include <iostream>
36 using namespace std;
37 
38 //----------------------------------------------------------------------------
42 //----------------------------------------------------------------------------
45  conf_(conf), bufferAlreadySet(false), theNumOfRows(0), theNumOfCols(0), detid_(0)
46 {
47  // Get thresholds in electrons
48  thePixelThreshold =
49  conf_.getParameter<int>("ChannelThreshold");
50  theSeedThreshold =
51  conf_.getParameter<int>("SeedThreshold");
52  theClusterThreshold =
53  conf_.getParameter<double>("ClusterThreshold");
54  theConversionFactor =
55  conf_.getParameter<int>("VCaltoElectronGain");
56  theOffset =
57  conf_.getParameter<int>("VCaltoElectronOffset");
58  if ( conf_.exists("AdcFullScaleStack") ) theStackADC_=conf_.getParameter<int>("AdcFullScaleStack");
59  else
60  theStackADC_=255;
61  if ( conf_.exists("FirstStackLayer") ) theFirstStack_=conf_.getParameter<int>("FirstStackLayer");
62  else
63  theFirstStack_=5;
64 
65  // Get the constants for the miss-calibration studies
66  doMissCalibrate=conf_.getUntrackedParameter<bool>("MissCalibrate",true);
67  doSplitClusters = conf.getParameter<bool>("SplitClusters");
68  theBuffer.setSize( theNumOfRows, theNumOfCols );
69 }
72 
73 //----------------------------------------------------------------------------
76 //----------------------------------------------------------------------------
78 {
79  // Cache the topology.
80  const PixelTopology & topol = pixDet->specificTopology();
81 
82  // Get the new sizes.
83  int nrows = topol.nrows(); // rows in x
84  int ncols = topol.ncolumns(); // cols in y
85 
86  theNumOfRows = nrows; // Set new sizes
87  theNumOfCols = ncols;
88 
89  if ( nrows > theBuffer.rows() ||
90  ncols > theBuffer.columns() )
91  { // change only when a larger is needed
92  //if( nrows != theNumOfRows || ncols != theNumOfCols ) {
93  //cout << " PixelThresholdClusterizer: pixel buffer redefined to "
94  // << nrows << " * " << ncols << endl;
95  //theNumOfRows = nrows; // Set new sizes
96  //theNumOfCols = ncols;
97  // Resize the buffer
98  theBuffer.setSize(nrows,ncols); // Modify
99  bufferAlreadySet = true;
100  }
101 
102  return true;
103 }
104 //----------------------------------------------------------------------------
110 //----------------------------------------------------------------------------
112  const PixelGeomDetUnit * pixDet,
113  const std::vector<short>& badChannels,
115 
116  DigiIterator begin = input.begin();
117  DigiIterator end = input.end();
118 
119  // Do not bother for empty detectors
120  //if (begin == end) cout << " PixelThresholdClusterizer::clusterizeDetUnit - No digis to clusterize";
121 
122  // Set up the clusterization on this DetId.
123  if ( !setup(pixDet) )
124  return;
125 
126  detid_ = input.detId();
127 
128  // Copy PixelDigis to the buffer array; select the seed pixels
129  // on the way, and store them in theSeeds.
130  copy_to_buffer(begin, end);
131 
132  // At this point we know the number of seeds on this DetUnit, and thus
133  // also the maximal number of possible clusters, so resize theClusters
134  // in order to make vector<>::push_back() efficient.
135  // output.reserve ( theSeeds.size() ); //GPetruc: It is better *not* to reserve, with the new DetSetVector!
136 
137 
138  // Loop over all seeds. TO DO: wouldn't using iterators be faster?
139  // edm::LogError("PixelThresholdClusterizer") << "Starting clusterizing" << endl;
140  for (unsigned int i = 0; i < theSeeds.size(); i++)
141  {
142 
143  // Gavril : The charge of seeds that were already inlcuded in clusters is set to 1 electron
144  // so we don't want to call "make_cluster" for these cases
145  if ( theBuffer(theSeeds[i]) >= theSeedThreshold )
146  { // Is this seed still valid?
147  // Make a cluster around this seed
148  SiPixelCluster cluster = make_cluster( theSeeds[i] , output);
149 
150  // Check if the cluster is above threshold
151  // (TO DO: one is signed, other unsigned, gcc warns...)
152  if ( cluster.charge() >= theClusterThreshold)
153  {
154  // cout << "putting in this cluster" << endl;
155  output.push_back( cluster );
156  }
157  }
158  }
159 
160  // Erase the seeds.
161  theSeeds.clear();
162 
163  // Need to clean unused pixels from the buffer array.
164  clear_buffer(begin, end);
165 
166 }
167 
168 //----------------------------------------------------------------------------
176 //----------------------------------------------------------------------------
178 {
179  for(DigiIterator di = begin; di != end; ++di )
180  {
181  theBuffer.set_adc( di->row(), di->column(), 0 ); // reset pixel adc to 0
182  }
183 }
184 
185 //----------------------------------------------------------------------------
187 //----------------------------------------------------------------------------
189 {
190  for(DigiIterator di = begin; di != end; ++di)
191  {
192  int row = di->row();
193  int col = di->column();
194  int adc = calibrate(di->adc(),col,row); // convert ADC -> electrons
195  if ( adc >= thePixelThreshold)
196  {
197  theBuffer.set_adc( row, col, adc);
198  if ( adc >= theSeedThreshold)
199  {
200  theSeeds.push_back( SiPixelCluster::PixelPos(row,col) );
201  }
202  }
203  }
204 }
205 
206 //----------------------------------------------------------------------------
207 // Calibrate adc counts to electrons
208 //-----------------------------------------------------------------
210 {
211  int electrons = 0;
212  int layer= 0;
213  if (DetId(detid_).subdetId()==1){ layer = PXBDetId(detid_).layer();}
214 
215  if ( doMissCalibrate )
216  {
217  // do not perform calibration if pixel is dead!
218 
219  if ( !theSiPixelGainCalibrationService_->isDead(detid_,col,row) &&
220  !theSiPixelGainCalibrationService_->isNoisy(detid_,col,row) )
221  {
222 
223  // Linear approximation of the TANH response
224  // Pixel(0,0,0)
225  //const float gain = 2.95; // 1 ADC = 2.95 VCALs (1/0.339)
226  //const float pedestal = -83.; // -28/0.339
227  // Roc-0 average
228  //const float gain = 1./0.357; // 1 ADC = 2.80 VCALs
229  //const float pedestal = -28.2 * gain; // -79.
230 
231  float DBgain = theSiPixelGainCalibrationService_->getGain(detid_, col, row);
232  float DBpedestal = theSiPixelGainCalibrationService_->getPedestal(detid_, col, row) * DBgain;
233 
234 
235  // Roc-6 average
236  //const float gain = 1./0.313; // 1 ADC = 3.19 VCALs
237  //const float pedestal = -6.2 * gain; // -19.8
238  //
239  float vcal = adc * DBgain - DBpedestal;
240 
241  // atanh calibration
242  // Roc-6 average
243  //const float p0 = 0.00492;
244  //const float p1 = 1.998;
245  //const float p2 = 90.6;
246  //const float p3 = 134.1;
247  // Roc-6 average
248  //const float p0 = 0.00382;
249  //const float p1 = 0.886;
250  //const float p2 = 112.7;
251  //const float p3 = 113.0;
252  //float vcal = ( atanh( (adc-p3)/p2) + p1)/p0;
253 
254  electrons = int( vcal * theConversionFactor + theOffset);
255  }
256  }
257  else
258  { // No misscalibration in the digitizer
259  // Simple (default) linear gain
260  const float gain = 135.; // 1 ADC = 135 electrons
261  const float pedestal = 0.; //
262  electrons = int(adc * gain + pedestal);
263  if (layer>=theFirstStack_) {
264  if (theStackADC_==1&&adc==1)
265  {
266  electrons = int(255*135); // Arbitrarily use overflow value.
267  }
268  if (theStackADC_>1&&theStackADC_!=255&&adc>=1)
269  {
270  const float gain = 135.; // 1 ADC = 135 electrons
271  electrons = int((adc-1) * gain * 255/float(theStackADC_-1));
272  }
273  }
274  }
275 
276  return electrons;
277 }
278 
279 
280 namespace {
281 
282  struct AccretionCluster {
283  typedef unsigned short UShort;
284  static constexpr UShort MAXSIZE = 256;
285  UShort adc[256];
286  UShort x[256];
287  UShort y[256];
288  UShort xmin=16000;
289  UShort ymin=16000;
290  unsigned int isize=0;
291  unsigned int curr=0;
292 
293  // stack interface (unsafe ok for use below)
294  UShort top() const { return curr;}
295  void pop() { ++curr;}
296  bool empty() { return curr==isize;}
297 
298  bool add(SiPixelCluster::PixelPos const & p, UShort const iadc) {
299  if (isize==MAXSIZE) return false;
300  xmin=std::min(xmin,(unsigned short)(p.row()));
301  ymin=std::min(ymin,(unsigned short)(p.col()));
302  adc[isize]=iadc;
303  x[isize]=p.row();
304  y[isize++]=p.col();
305  return true;
306  }
307  };
308 
309 }
310 
311 //----------------------------------------------------------------------------
313 //----------------------------------------------------------------------------
317 {
318 
319  //First we acquire the seeds for the clusters
320  int seed_adc;
321  stack<SiPixelCluster::PixelPos, vector<SiPixelCluster::PixelPos> > dead_pixel_stack;
322 
323  //The individual modules have been loaded into a buffer.
324  //After each pixel has been considered by the clusterizer, we set the adc count to 1
325  //to mark that we have already considered it.
326  //The only difference between dead/noisy pixels and standard ones is that for dead/noisy pixels,
327  //We consider the charge of the pixel to always be zero.
328 
329  if ( doMissCalibrate &&
330  (theSiPixelGainCalibrationService_->isDead(detid_,pix.col(),pix.row()) ||
331  theSiPixelGainCalibrationService_->isNoisy(detid_,pix.col(),pix.row())) )
332  {
333  seed_adc = 0;
334  theBuffer.set_adc(pix, 1);
335  }
336  else
337  {
338  seed_adc = theBuffer(pix.row(), pix.col());
339  theBuffer.set_adc( pix, 1);
340  }
341 
342  AccretionCluster acluster;
343  acluster.add(pix, seed_adc);
344 
345  //Here we search all pixels adjacent to all pixels in the cluster.
346  bool dead_flag = false;
347  while ( ! acluster.empty())
348  {
349  //This is the standard algorithm to find and add a pixel
350  auto curInd = acluster.top(); acluster.pop();
351  for ( auto r = acluster.x[curInd]-1; r <= acluster.x[curInd]+1; ++r)
352  {
353  for ( auto c = acluster.y[curInd]-1; c <= acluster.y[curInd]+1; ++c)
354  {
355  if ( theBuffer(r,c) >= thePixelThreshold)
356  {
357 
358  SiPixelCluster::PixelPos newpix(r,c);
359  if (!acluster.add( newpix, theBuffer(r,c))) goto endClus;
360  theBuffer.set_adc( newpix, 1);
361  }
362 
363 
364  /* //Commenting out the addition of dead pixels to the cluster until further testing -- dfehling 06/09
365  //Check on the bounds of the module; this is to keep the isDead and isNoisy modules from returning errors
366  else if(r>= 0 && c >= 0 && (r <= (theNumOfRows-1.)) && (c <= (theNumOfCols-1.))){
367  //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.
368  if((theSiPixelGainCalibrationService_->isDead(detid_,c,r) || theSiPixelGainCalibrationService_->isNoisy(detid_,c,r)) && theBuffer(r,c) != 1){
369 
370  //If a pixel is dead or noisy, check to see if we want to split the clusters or not.
371  //Push it into a dead pixel stack in case we want to split the clusters. Otherwise add it to the cluster.
372  //If we are splitting the clusters, we will iterate over the dead pixel stack later.
373 
374  SiPixelCluster::PixelPos newpix(r,c);
375  if(!doSplitClusters){
376 
377  cluster.add(newpix, theBuffer(r,c));}
378  else if(doSplitClusters){
379  dead_pixel_stack.push(newpix);
380  dead_flag = true;}
381 
382  theBuffer.set_adc(newpix, 1);
383  }
384 
385  }
386  */
387 
388 
389 
390  }
391  }
392 
393  } // while accretion
394  endClus:
395  SiPixelCluster cluster(acluster.isize,acluster.adc, acluster.x,acluster.y, acluster.xmin,acluster.ymin);
396  //Here we split the cluster, if the flag to do so is set and we have found a dead or noisy pixel.
397 
398  if (dead_flag && doSplitClusters)
399  {
400  //Set the first cluster equal to the existing cluster.
401  SiPixelCluster first_cluster = cluster;
402  bool have_second_cluster = false;
403  while ( !dead_pixel_stack.empty() )
404  {
405  //consider each found dead pixel
406  SiPixelCluster::PixelPos deadpix = dead_pixel_stack.top(); dead_pixel_stack.pop();
407  theBuffer.set_adc(deadpix, 1);
408 
409  //Clusterize the split cluster using the dead pixel as a seed
410  SiPixelCluster second_cluster = make_cluster(deadpix, output);
411 
412  //If both clusters would normally have been found by the clusterizer, put them into output
413  if ( second_cluster.charge() >= theClusterThreshold &&
414  first_cluster.charge() >= theClusterThreshold )
415  {
416  output.push_back( second_cluster );
417  have_second_cluster = true;
418  }
419 
420  //We also want to keep the merged cluster in data and let the RecHit algorithm decide which set to keep
421  //This loop adds the second cluster to the first.
422  const std::vector<SiPixelCluster::Pixel>& branch_pixels = second_cluster.pixels();
423  for ( unsigned int i = 0; i<branch_pixels.size(); i++)
424  {
425  int temp_x = branch_pixels[i].x;
426  int temp_y = branch_pixels[i].y;
427  int temp_adc = branch_pixels[i].adc;
428  SiPixelCluster::PixelPos newpix(temp_x, temp_y);
429  cluster.add(newpix, temp_adc);}
430  }
431 
432  //Remember to also add the first cluster if we added the second one.
433  if ( first_cluster.charge() >= theClusterThreshold && have_second_cluster)
434  {
435  output.push_back( first_cluster );
436  }
437  }
438 
439  return cluster;
440 }
441 
int adc(sample_type sample)
get the ADC sample (12 bits)
iterator end()
Definition: DetSet.h:61
T getParameter(std::string const &) const
int i
Definition: DBlmapReader.cc:9
float charge() const
void push_back(data_type const &d)
void clusterizeDetUnit(const edm::DetSet< PixelDigi > &input, const PixelGeomDetUnit *pixDet, const std::vector< short > &badChannels, edmNew::DetSetVector< SiPixelCluster >::FastFiller &output)
Cluster pixels. This method operates on a matrix of pixels and finds the largest contiguous cluster a...
PixelThresholdClusterizer(edm::ParameterSet const &conf)
det_id_type detId() const
Definition: DetSet.h:73
SiPixelCluster make_cluster(const SiPixelCluster::PixelPos &pix, edmNew::DetSetVector< SiPixelCluster >::FastFiller &output)
The actual clustering algorithm: group the neighboring pixels around the seed.
virtual int ncolumns() const =0
virtual int nrows() const =0
void add(const std::vector< const T * > &source, std::vector< const T * > &dest)
#define min(a, b)
Definition: mlp_lapack.h:161
unsigned int layer() const
layer id
Definition: PXBDetId.h:35
edm::DetSet< PixelDigi >::const_iterator DigiIterator
#define end
Definition: vmac.h:38
void add(const PixelPos &pix, int adc)
tuple conf
Definition: dbtoconf.py:185
constexpr int col() const
iterator begin()
Definition: DetSet.h:60
Definition: DetId.h:20
void clear_buffer(DigiIterator begin, DigiIterator end)
Clear the internal buffer array.
virtual const PixelTopology & specificTopology() const
Returns a reference to the pixel proxy topology.
Pixel cluster – collection of neighboring pixels above threshold.
#define begin
Definition: vmac.h:31
bool setup(const PixelGeomDetUnit *pixDet)
Private helper methods:
int calibrate(int adc, int col, int row)
Definition: DDAxes.h:10
int col
Definition: cuy.py:1008
void setup(std::vector< TH2F > &depth, std::string name, std::string units="")
constexpr int row() const
const std::vector< Pixel > pixels() const
#define constexpr
void copy_to_buffer(DigiIterator begin, DigiIterator end)
Copy adc counts from PixelDigis into the buffer, identify seeds.