CMS 3D CMS Logo

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