CMS 3D CMS Logo

PixelThresholdClusterizer.cc
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
20 //----------------------------------------------------------------------------
21 
22 // Our own includes
24 #include "SiPixelArrayBuffer.h"
26 // Geometry
29 //#include "Geometry/CommonTopologies/RectangularPixelTopology.h"
31 
32 // STL
33 #include <stack>
34 #include <vector>
35 #include <iostream>
36 #include <atomic>
37 using namespace std;
38 
39 //----------------------------------------------------------------------------
43 //----------------------------------------------------------------------------
45  (edm::ParameterSet const& conf) :
46  bufferAlreadySet(false),
47  // Get thresholds in electrons
48  thePixelThreshold( conf.getParameter<int>("ChannelThreshold") ),
49  theSeedThreshold( conf.getParameter<int>("SeedThreshold") ),
50  theClusterThreshold( conf.getParameter<double>("ClusterThreshold") ),
51  theConversionFactor( conf.getParameter<int>("VCaltoElectronGain") ),
52  theOffset( conf.getParameter<int>("VCaltoElectronOffset") ),
53  theStackADC_( conf.exists("AdcFullScaleStack") ? conf.getParameter<int>("AdcFullScaleStack") : 255 ),
54  theFirstStack_( conf.exists("FirstStackLayer") ? conf.getParameter<int>("FirstStackLayer") : 5 ),
55  theElectronPerADCGain_( conf.exists("ElectronPerADCGain") ? conf.getParameter<double>("ElectronPerADCGain") : 135. ),
56  theNumOfRows(0), theNumOfCols(0), detid_(0),
57  // Get the constants for the miss-calibration studies
58  doMissCalibrate( conf.getUntrackedParameter<bool>("MissCalibrate",true) ),
59  doSplitClusters( conf.getParameter<bool>("SplitClusters") )
60 {
61  theBuffer.setSize( theNumOfRows, theNumOfCols );
62 }
65 
66 //----------------------------------------------------------------------------
69 //----------------------------------------------------------------------------
71 {
72  // Cache the topology.
73  const PixelTopology & topol = pixDet->specificTopology();
74 
75  // Get the new sizes.
76  int nrows = topol.nrows(); // rows in x
77  int ncols = topol.ncolumns(); // cols in y
78 
79  theNumOfRows = nrows; // Set new sizes
80  theNumOfCols = ncols;
81 
82  if ( nrows > theBuffer.rows() ||
83  ncols > theBuffer.columns() )
84  { // change only when a larger is needed
85  //if( nrows != theNumOfRows || ncols != theNumOfCols ) {
86  //cout << " PixelThresholdClusterizer: pixel buffer redefined to "
87  // << nrows << " * " << ncols << endl;
88  //theNumOfRows = nrows; // Set new sizes
89  //theNumOfCols = ncols;
90  // Resize the buffer
91  theBuffer.setSize(nrows,ncols); // Modify
92  bufferAlreadySet = true;
93  }
94 
95  return true;
96 }
97 //----------------------------------------------------------------------------
103 //----------------------------------------------------------------------------
104 template<typename T>
106  const PixelGeomDetUnit * pixDet,
107  const std::vector<short>& badChannels,
109 
110  typename T::const_iterator begin = input.begin();
111  typename T::const_iterator end = input.end();
112 
113  // Do not bother for empty detectors
114  //if (begin == end) cout << " PixelThresholdClusterizer::clusterizeDetUnit - No digis to clusterize";
115 
116  // Set up the clusterization on this DetId.
117  if ( !setup(pixDet) )
118  return;
119 
120  detid_ = input.detId();
121 
122  // Copy PixelDigis to the buffer array; select the seed pixels
123  // on the way, and store them in theSeeds.
124  copy_to_buffer(begin, end);
125 
126  assert(output.empty());
127  // Loop over all seeds. TO DO: wouldn't using iterators be faster?
128  // edm::LogError("PixelThresholdClusterizer") << "Starting clusterizing" << endl;
129  for (unsigned int i = 0; i < theSeeds.size(); i++)
130  {
131 
132  // Gavril : The charge of seeds that were already inlcuded in clusters is set to 1 electron
133  // so we don't want to call "make_cluster" for these cases
134  if ( theBuffer(theSeeds[i]) >= theSeedThreshold )
135  { // Is this seed still valid?
136  // Make a cluster around this seed
137  SiPixelCluster && cluster = make_cluster( theSeeds[i] , output);
138 
139  // Check if the cluster is above threshold
140  // (TO DO: one is signed, other unsigned, gcc warns...)
141  if ( cluster.charge() >= theClusterThreshold)
142  {
143  // std::cout << "putting in this cluster " << i << " " << cluster.charge() << " " << cluster.pixelADC().size() << endl;
144  // sort by row (x)
145  output.push_back( std::move(cluster) );
146  std::push_heap(output.begin(),output.end(),[](SiPixelCluster const & cl1,SiPixelCluster const & cl2) { return cl1.minPixelRow() < cl2.minPixelRow();});
147  }
148  }
149  }
150  // sort by row (x) maybe sorting the seed would suffice....
151  std::sort_heap(output.begin(),output.end(),[](SiPixelCluster const & cl1,SiPixelCluster const & cl2) { return cl1.minPixelRow() < cl2.minPixelRow();});
152 
153  // Erase the seeds.
154  theSeeds.clear();
155 
156  // Need to clean unused pixels from the buffer array.
157  clear_buffer(begin, end);
158 
159 }
160 
161 //----------------------------------------------------------------------------
169 //----------------------------------------------------------------------------
171 {
172  for(DigiIterator di = begin; di != end; ++di )
173  {
174  theBuffer.set_adc( di->row(), di->column(), 0 ); // reset pixel adc to 0
175  }
176 }
177 
179 {
180  for(ClusterIterator ci = begin; ci != end; ++ci )
181  {
182  for(int i = 0; i < ci->size(); ++i)
183  {
184  const SiPixelCluster::Pixel pixel = ci->pixel(i);
185 
186  theBuffer.set_adc( pixel.x, pixel.y, 0 ); // reset pixel adc to 0
187  }
188  }
189 }
190 
191 //----------------------------------------------------------------------------
193 //----------------------------------------------------------------------------
195 {
196 #ifdef PIXELREGRESSION
197  static std::atomic<int> s_ic=0;
198  in ic = ++s_ic;
199  if (ic==1) {
200  // std::cout << (doMissCalibrate ? "VI from db" : "VI linear") << std::endl;
201  }
202 #endif
203  int electron[end-begin];
204  memset(electron, 0, sizeof(electron));
205  if ( doMissCalibrate ) {
206  (*theSiPixelGainCalibrationService_).calibrate(detid_,begin,end,theConversionFactor, theOffset,electron);
207  } else {
208  int layer = (DetId(detid_).subdetId()==1) ? PXBDetId(detid_).layer() : 0;
209  int i=0;
210  for(DigiIterator di = begin; di != end; ++di) {
211  auto adc = di->adc();
212  const float gain = theElectronPerADCGain_; // default: 1 ADC = 135 electrons
213  const float pedestal = 0.; //
214  electron[i] = int(adc * gain + pedestal);
215  if (layer>=theFirstStack_) {
216  if (theStackADC_==1&&adc==1) {
217  electron[i] = int(255*135); // Arbitrarily use overflow value.
218  }
219  if (theStackADC_>1&&theStackADC_!=255&&adc>=1){
220  const float gain = theElectronPerADCGain_; // default: 1 ADC = 135 electrons
221  electron[i] = int((adc-1) * gain * 255/float(theStackADC_-1));
222  }
223  }
224  ++i;
225  }
226  assert(i==(end-begin));
227  }
228 
229  int i=0;
230 #ifdef PIXELREGRESSION
231  static std::atomic<int> eqD=0;
232 #endif
233  for(DigiIterator di = begin; di != end; ++di) {
234  int row = di->row();
235  int col = di->column();
236  int adc = electron[i++];
237 #ifdef PIXELREGRESSION
238  int adcOld = calibrate(di->adc(),col,row);
239  //assert(adc==adcOld);
240  if (adc!=adcOld) std::cout << "VI " << eqD <<' '<< ic <<' '<< end-begin <<' '<< i <<' '<< di->adc() <<' ' << adc <<' '<< adcOld << std::endl; else ++eqD;
241 #endif
242  if ( adc >= thePixelThreshold) {
243  theBuffer.set_adc( row, col, adc);
244  if ( adc >= theSeedThreshold) theSeeds.push_back( SiPixelCluster::PixelPos(row,col) );
245  }
246  }
247  assert(i==(end-begin));
248 
249 }
250 
252 {
253  // loop over clusters
254  for(ClusterIterator ci = begin; ci != end; ++ci) {
255  // loop over pixels
256  for(int i = 0; i < ci->size(); ++i) {
257  const SiPixelCluster::Pixel pixel = ci->pixel(i);
258 
259  int row = pixel.x;
260  int col = pixel.y;
261  int adc = pixel.adc;
262  if ( adc >= thePixelThreshold) {
263  theBuffer.add_adc( row, col, adc);
264  if ( adc >= theSeedThreshold) theSeeds.push_back( SiPixelCluster::PixelPos(row,col) );
265  }
266  }
267  }
268 }
269 
270 //----------------------------------------------------------------------------
271 // Calibrate adc counts to electrons
272 //-----------------------------------------------------------------
274 {
275  int electrons = 0;
276  int layer= 0;
277  if (DetId(detid_).subdetId()==1){ layer = PXBDetId(detid_).layer();}
278 
279  if ( doMissCalibrate )
280  {
281  // do not perform calibration if pixel is dead!
282 
283  if ( !theSiPixelGainCalibrationService_->isDead(detid_,col,row) &&
284  !theSiPixelGainCalibrationService_->isNoisy(detid_,col,row) )
285  {
286 
287  // Linear approximation of the TANH response
288  // Pixel(0,0,0)
289  //const float gain = 2.95; // 1 ADC = 2.95 VCALs (1/0.339)
290  //const float pedestal = -83.; // -28/0.339
291  // Roc-0 average
292  //const float gain = 1./0.357; // 1 ADC = 2.80 VCALs
293  //const float pedestal = -28.2 * gain; // -79.
294 
295  float DBgain = theSiPixelGainCalibrationService_->getGain(detid_, col, row);
296  float DBpedestal = theSiPixelGainCalibrationService_->getPedestal(detid_, col, row) * DBgain;
297 
298 
299  // Roc-6 average
300  //const float gain = 1./0.313; // 1 ADC = 3.19 VCALs
301  //const float pedestal = -6.2 * gain; // -19.8
302  //
303  float vcal = adc * DBgain - DBpedestal;
304 
305  // atanh calibration
306  // Roc-6 average
307  //const float p0 = 0.00492;
308  //const float p1 = 1.998;
309  //const float p2 = 90.6;
310  //const float p3 = 134.1;
311  // Roc-6 average
312  //const float p0 = 0.00382;
313  //const float p1 = 0.886;
314  //const float p2 = 112.7;
315  //const float p3 = 113.0;
316  //float vcal = ( atanh( (adc-p3)/p2) + p1)/p0;
317 
318  electrons = int( vcal * theConversionFactor + theOffset);
319  }
320  }
321  else
322  { // No misscalibration in the digitizer
323  // Simple (default) linear gain
324  const float gain = theElectronPerADCGain_; // default: 1 ADC = 135 electrons
325  const float pedestal = 0.; //
326  electrons = int(adc * gain + pedestal);
327  if (layer>=theFirstStack_) {
328  if (theStackADC_==1&&adc==1)
329  {
330  electrons = int(255*135); // Arbitrarily use overflow value.
331  }
332  if (theStackADC_>1&&theStackADC_!=255&&adc>=1)
333  {
334  const float gain = theElectronPerADCGain_; // default: 1 ADC = 135 electrons
335  electrons = int((adc-1) * gain * 255/float(theStackADC_-1));
336  }
337  }
338  }
339 
340  return electrons;
341 }
342 
343 //----------------------------------------------------------------------------
345 //----------------------------------------------------------------------------
349 {
350 
351  //First we acquire the seeds for the clusters
352  int seed_adc;
353  stack<SiPixelCluster::PixelPos, vector<SiPixelCluster::PixelPos> > dead_pixel_stack;
354 
355  //The individual modules have been loaded into a buffer.
356  //After each pixel has been considered by the clusterizer, we set the adc count to 1
357  //to mark that we have already considered it.
358  //The only difference between dead/noisy pixels and standard ones is that for dead/noisy pixels,
359  //We consider the charge of the pixel to always be zero.
360 
361  /* this is not possible as dead and noisy pixel cannot make it into a seed...
362  if ( doMissCalibrate &&
363  (theSiPixelGainCalibrationService_->isDead(detid_,pix.col(),pix.row()) ||
364  theSiPixelGainCalibrationService_->isNoisy(detid_,pix.col(),pix.row())) )
365  {
366  std::cout << "IMPOSSIBLE" << std::endl;
367  seed_adc = 0;
368  theBuffer.set_adc(pix, 1);
369  }
370  else {
371  */
372  seed_adc = theBuffer(pix.row(), pix.col());
373  theBuffer.set_adc( pix, 1);
374  // }
375 
376  AccretionCluster acluster;
377  acluster.add(pix, seed_adc);
378 
379  //Here we search all pixels adjacent to all pixels in the cluster.
380  bool dead_flag = false;
381  while ( ! acluster.empty())
382  {
383  //This is the standard algorithm to find and add a pixel
384  auto curInd = acluster.top(); acluster.pop();
385  for ( auto c = std::max(0,int(acluster.y[curInd])-1); c < std::min(int(acluster.y[curInd])+2,theBuffer.columns()) ; ++c) {
386  for ( auto r = std::max(0,int(acluster.x[curInd])-1); r < std::min(int(acluster.x[curInd])+2,theBuffer.rows()); ++r) {
387  if ( theBuffer(r,c) >= thePixelThreshold) {
388  SiPixelCluster::PixelPos newpix(r,c);
389  if (!acluster.add( newpix, theBuffer(r,c))) goto endClus;
390  theBuffer.set_adc( newpix, 1);
391  }
392 
393 
394  /* //Commenting out the addition of dead pixels to the cluster until further testing -- dfehling 06/09
395  //Check on the bounds of the module; this is to keep the isDead and isNoisy modules from returning errors
396  else if(r>= 0 && c >= 0 && (r <= (theNumOfRows-1.)) && (c <= (theNumOfCols-1.))){
397  //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.
398  if((theSiPixelGainCalibrationService_->isDead(detid_,c,r) || theSiPixelGainCalibrationService_->isNoisy(detid_,c,r)) && theBuffer(r,c) != 1){
399 
400  //If a pixel is dead or noisy, check to see if we want to split the clusters or not.
401  //Push it into a dead pixel stack in case we want to split the clusters. Otherwise add it to the cluster.
402  //If we are splitting the clusters, we will iterate over the dead pixel stack later.
403 
404  SiPixelCluster::PixelPos newpix(r,c);
405  if(!doSplitClusters){
406 
407  cluster.add(newpix, theBuffer(r,c));}
408  else if(doSplitClusters){
409  dead_pixel_stack.push(newpix);
410  dead_flag = true;}
411 
412  theBuffer.set_adc(newpix, 1);
413  }
414 
415  }
416  */
417 
418 
419 
420  }
421  }
422 
423  } // while accretion
424  endClus:
425  SiPixelCluster cluster(acluster.isize,acluster.adc, acluster.x,acluster.y, acluster.xmin,acluster.ymin);
426  //Here we split the cluster, if the flag to do so is set and we have found a dead or noisy pixel.
427 
428  if (dead_flag && doSplitClusters)
429  {
430  //Set the first cluster equal to the existing cluster.
431  SiPixelCluster first_cluster = cluster;
432  bool have_second_cluster = false;
433  while ( !dead_pixel_stack.empty() )
434  {
435  //consider each found dead pixel
436  SiPixelCluster::PixelPos deadpix = dead_pixel_stack.top(); dead_pixel_stack.pop();
437  theBuffer.set_adc(deadpix, 1);
438 
439  //Clusterize the split cluster using the dead pixel as a seed
440  SiPixelCluster second_cluster = make_cluster(deadpix, output);
441 
442  //If both clusters would normally have been found by the clusterizer, put them into output
443  if ( second_cluster.charge() >= theClusterThreshold &&
444  first_cluster.charge() >= theClusterThreshold )
445  {
446  output.push_back( second_cluster );
447  have_second_cluster = true;
448  }
449 
450  //We also want to keep the merged cluster in data and let the RecHit algorithm decide which set to keep
451  //This loop adds the second cluster to the first.
452  const std::vector<SiPixelCluster::Pixel>& branch_pixels = second_cluster.pixels();
453  for ( unsigned int i = 0; i<branch_pixels.size(); i++)
454  {
455  int temp_x = branch_pixels[i].x;
456  int temp_y = branch_pixels[i].y;
457  int temp_adc = branch_pixels[i].adc;
458  SiPixelCluster::PixelPos newpix(temp_x, temp_y);
459  cluster.add(newpix, temp_adc);}
460  }
461 
462  //Remember to also add the first cluster if we added the second one.
463  if ( first_cluster.charge() >= theClusterThreshold && have_second_cluster)
464  {
465  output.push_back( first_cluster );
466  std::push_heap(output.begin(),output.end(),[](SiPixelCluster const & cl1,SiPixelCluster const & cl2) { return cl1.minPixelRow() < cl2.minPixelRow();});
467  }
468  }
469 
470  return cluster;
471 }
472 
int adc(sample_type sample)
get the ADC sample (12 bits)
T getParameter(std::string const &) const
T getUntrackedParameter(std::string const &, T const &) const
void push_back(data_type const &d)
virtual int nrows() const =0
PixelThresholdClusterizer(edm::ParameterSet const &conf)
SiPixelCluster make_cluster(const SiPixelCluster::PixelPos &pix, edmNew::DetSetVector< SiPixelCluster >::FastFiller &output)
The actual clustering algorithm: group the neighboring pixels around the seed.
bool exists(std::string const &parameterName) const
checks if a parameter exists
def setup(process, global_tag, zero_tesla=False)
Definition: GeneralSetup.py:1
int charge() const
unsigned int layer() const
layer id
Definition: PXBDetId.h:35
static std::string const input
Definition: EdmProvDump.cc:44
void clusterizeDetUnitT(const T &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...
int minPixelRow() const
edm::DetSet< PixelDigi >::const_iterator DigiIterator
#define end
Definition: vmac.h:37
void add(const PixelPos &pix, int adc)
T min(T a, T b)
Definition: MathUtil.h:58
int subdetId() const
get the contents of the subdetector field (not cast into any detector&#39;s numbering enum) ...
Definition: DetId.h:37
bool add(SiPixelCluster::PixelPos const &p, UShort const iadc)
constexpr int col() const
Definition: DetId.h:18
edmNew::DetSet< SiPixelCluster >::const_iterator ClusterIterator
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:30
virtual int ncolumns() const =0
col
Definition: cuy.py:1008
bool setup(const PixelGeomDetUnit *pixDet)
Private helper methods:
int calibrate(int adc, int col, int row)
long double T
constexpr int row() const
def move(src, dest)
Definition: eostools.py:510
const std::vector< Pixel > pixels() const
void copy_to_buffer(DigiIterator begin, DigiIterator end)
Copy adc counts from PixelDigis into the buffer, identify seeds.