CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
SiPixelTemplateSplit.cc
Go to the documentation of this file.
1 //
2 // SiPixelTemplateSplit.cc (Version 1.05)
3 //
4 // Procedure to fit two templates (same angle hypotheses) to a single cluster
5 // Return two x- and two y-coordinates for the cluster
6 //
7 // Created by Morris Swartz on 04/10/08.
8 // Copyright 2008 __TheJohnsHopkinsUniversity__. All rights reserved.
9 //
10 // Incorporate "cluster repair" to handle dead pixels
11 // Take truncation size from new pixmax information
12 // Change to allow template sizes to be changed at compile time
13 // Move interpolation range error to LogDebug
14 // Add qbin = 5 and change 1-pixel probability to use new template info
15 // Add floor for probabilities (no exact zeros)
16 //
17 
18 #include <math.h>
19 #include <algorithm>
20 #include <vector>
21 #include <iostream>
22 // ROOT::Math has a c++ function that does the probability calc, but only in v5.12 and later
23 //#include "Math/DistFunc.h"
24 #include "TMath.h"
25 // Use current version of gsl instead of ROOT::Math
26 //#include <gsl/gsl_cdf.h>
27 
28 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
31 #define LOGERROR(x) edm::LogError(x)
32 #define LOGDEBUG(x) LogDebug(x)
33 static int theVerboseLevel = 2;
34 #define ENDL " "
35 #else
36 #include "SiPixelTemplateSplit.h"
37 //static int theVerboseLevel = {2};
38 #define LOGERROR(x) std::cout << x << ": "
39 #define LOGDEBUG(x) std::cout << x << ": "
40 #define ENDL std::endl
41 #endif
42 
43 using namespace SiPixelTemplateReco;
44 
45 // *************************************************************************************************************************************
69 // *************************************************************************************************************************************
70 int SiPixelTemplateReco::PixelTempSplit(int id, bool fpix, float cotalpha, float cotbeta, array_2d cluster,
71  std::vector<bool> ydouble, std::vector<bool> xdouble,
72  SiPixelTemplate& templ,
73  float& yrec1, float& yrec2, float& sigmay, float& proby,
74  float& xrec1, float& xrec2, float& sigmax, float& probx, int& qbin, bool deadpix, std::vector<std::pair<int, int> > zeropix)
75 
76 {
77  // Local variables
78  static int i, j, k, minbin, binq, midpix, fypix, nypix, lypix, logypx;
79  static int fxpix, nxpix, lxpix, logxpx, shifty, shiftx, nyzero[TYSIZE];
80  static int nclusx, nclusy;
81  static int nybin, ycbin, nxbin, xcbin, minbinj, minbink;
82  static float sythr, sxthr, delta, sigma, sigavg, pseudopix, qscale;
83  static float ss2, ssa, sa2, rat, fq, qtotal, qpixel;
84  static float originx, originy, bias, maxpix, minmax;
85  static double chi2x, meanx, chi2y, meany, chi2ymin, chi2xmin, chi21max;
86  static double hchi2, hndof;
87  static float ysum[BYSIZE], xsum[BXSIZE], ysort[BYSIZE], xsort[BXSIZE];
88  static float ysig2[BYSIZE], xsig2[BXSIZE];
89  static bool yd[BYSIZE], xd[BXSIZE], anyyd, anyxd;
90  const float ysize={150.}, xsize={100.}, sqrt2={2.};
91  const float probmin={1.110223e-16};
92 // const float sqrt2={1.41421356};
93 
94 // The minimum chi2 for a valid one pixel cluster = pseudopixel contribution only
95 
96  const double mean1pix={0.100}, chi21min={0.160};
97 
98 // First, interpolate the template needed to analyze this cluster
99 // check to see of the track direction is in the physical range of the loaded template
100 
101  if(!templ.interpolate(id, fpix, cotalpha, cotbeta)) {
102  LOGDEBUG("SiPixelTemplateReco") << "input cluster direction cot(alpha) = " << cotalpha << ", cot(beta) = " << cotbeta << " is not within the acceptance of fpix = "
103  << fpix << ", template ID = " << id << ", no reconstruction performed" << ENDL;
104  return 20;
105  }
106 
107 // Define size of pseudopixel
108 
109  pseudopix = templ.s50();
110 
111 // Get charge scaling factor
112 
113  qscale = templ.qscale();
114 
115 // Check that the cluster container is (up to) a 7x21 matrix and matches the dimensions of the double pixel flags
116 
117  if(cluster.num_dimensions() != 2) {
118  LOGERROR("SiPixelTemplateReco") << "input cluster container (BOOST Multiarray) has wrong number of dimensions" << ENDL;
119  return 3;
120  }
121  nclusx = (int)cluster.shape()[0];
122  nclusy = (int)cluster.shape()[1];
123  if(nclusx != (int)xdouble.size()) {
124  LOGERROR("SiPixelTemplateReco") << "input cluster container x-size is not equal to double pixel flag container size" << ENDL;
125  return 4;
126  }
127  if(nclusy != (int)ydouble.size()) {
128  LOGERROR("SiPixelTemplateReco") << "input cluster container y-size is not equal to double pixel flag container size" << ENDL;
129  return 5;
130  }
131 
132 // enforce maximum size
133 
134  if(nclusx > TXSIZE) {nclusx = TXSIZE;}
135  if(nclusy > TYSIZE) {nclusy = TYSIZE;}
136 
137 // First, rescale all pixel charges
138 
139  for(i=0; i<nclusy; ++i) {
140  for(j=0; j<nclusx; ++j) {
141  if(cluster[j][i] > 0) {cluster[j][i] *= qscale;}
142  }
143  }
144 
145 // Next, sum the total charge and "decapitate" big pixels
146 
147  qtotal = 0.;
148  minmax = 2.*templ.pixmax();
149  for(i=0; i<nclusy; ++i) {
150  maxpix = minmax;
151  if(ydouble[i]) {maxpix *=2.;}
152  for(j=0; j<nclusx; ++j) {
153  qtotal += cluster[j][i];
154  if(cluster[j][i] > maxpix) {cluster[j][i] = maxpix;}
155  }
156  }
157 
158 // Do the cluster repair here
159 
160  if(deadpix) {
161  fypix = BYM3; lypix = -1;
162  for(i=0; i<nclusy; ++i) {
163  ysum[i] = 0.; nyzero[i] = 0;
164 // Do preliminary cluster projection in y
165  for(j=0; j<nclusx; ++j) {
166  ysum[i] += cluster[j][i];
167  }
168  if(ysum[i] > 0.) {
169 // identify ends of cluster to determine what the missing charge should be
170  if(i < fypix) {fypix = i;}
171  if(i > lypix) {lypix = i;}
172  }
173  }
174 
175 // Now loop over dead pixel list and "fix" everything
176 
177 //First see if the cluster ends are redefined and that we have only one dead pixel per column
178 
179  std::vector<std::pair<int, int> >::const_iterator zeroIter = zeropix.begin(), zeroEnd = zeropix.end();
180  for ( ; zeroIter != zeroEnd; ++zeroIter ) {
181  i = zeroIter->second;
182  if(i<0 || i>TYSIZE-1) {LOGERROR("SiPixelTemplateReco") << "dead pixel column y-index " << i << ", no reconstruction performed" << ENDL;
183  return 11;}
184 
185 // count the number of dead pixels in each column
186  ++nyzero[i];
187 // allow them to redefine the cluster ends
188  if(i < fypix) {fypix = i;}
189  if(i > lypix) {lypix = i;}
190  }
191 
192  nypix = lypix-fypix+1;
193 
194 // Now adjust the charge in the dead pixels to sum to 0.5*truncation value in the end columns and the truncation value in the interior columns
195 
196  for (zeroIter = zeropix.begin(); zeroIter != zeroEnd; ++zeroIter ) {
197  i = zeroIter->second; j = zeroIter->first;
198  if(j<0 || j>TXSIZE-1) {LOGERROR("SiPixelTemplateReco") << "dead pixel column x-index " << j << ", no reconstruction performed" << ENDL;
199  return 12;}
200  if((i == fypix || i == lypix) && nypix > 1) {maxpix = templ.symax()/2.;} else {maxpix = templ.symax();}
201  if(ydouble[i]) {maxpix *=2.;}
202  if(nyzero[i] > 0 && nyzero[i] < 3) {qpixel = (maxpix - ysum[i])/(float)nyzero[i];} else {qpixel = 1.;}
203  if(qpixel < 1.) {qpixel = 1.;}
204  cluster[j][i] = qpixel;
205 // Adjust the total cluster charge to reflect the charge of the "repaired" cluster
206  qtotal += qpixel;
207  }
208 // End of cluster repair section
209  }
210 
211 // Next, make y-projection of the cluster and copy the double pixel flags into a 25 element container
212 
213  for(i=0; i<BYSIZE; ++i) { ysum[i] = 0.; yd[i] = false;}
214  k=0;
215  anyyd = false;
216  for(i=0; i<nclusy; ++i) {
217  for(j=0; j<nclusx; ++j) {
218  ysum[k] += cluster[j][i];
219  }
220 
221 // If this is a double pixel, put 1/2 of the charge in 2 consective single pixels
222 
223  if(ydouble[i]) {
224  ysum[k] /= 2.;
225  ysum[k+1] = ysum[k];
226  yd[k] = true;
227  yd[k+1] = false;
228  k=k+2;
229  anyyd = true;
230  } else {
231  yd[k] = false;
232  ++k;
233  }
234  if(k > BYM1) {break;}
235  }
236 
237 // Next, make x-projection of the cluster and copy the double pixel flags into an 11 element container
238 
239  for(i=0; i<BXSIZE; ++i) { xsum[i] = 0.; xd[i] = false;}
240  k=0;
241  anyxd = false;
242  for(j=0; j<nclusx; ++j) {
243  for(i=0; i<nclusy; ++i) {
244  xsum[k] += cluster[j][i];
245  }
246 
247 // If this is a double pixel, put 1/2 of the charge in 2 consective single pixels
248 
249  if(xdouble[j]) {
250  xsum[k] /= 2.;
251  xsum[k+1] = xsum[k];
252  xd[k]=true;
253  xd[k+1]=false;
254  k=k+2;
255  anyxd = true;
256  } else {
257  xd[k]=false;
258  ++k;
259  }
260  if(k > BXM1) {break;}
261  }
262 
263 // next, identify the y-cluster ends, count total pixels, nypix, and logical pixels, logypx
264 
265  fypix=-1;
266  nypix=0;
267  lypix=0;
268  logypx=0;
269  for(i=0; i<BYSIZE; ++i) {
270  if(ysum[i] > 0.) {
271  if(fypix == -1) {fypix = i;}
272  if(!yd[i]) {
273  ysort[logypx] = ysum[i];
274  ++logypx;
275  }
276  ++nypix;
277  lypix = i;
278  }
279  }
280 
281 // Make sure cluster is continuous
282 
283  if((lypix-fypix+1) != nypix || nypix == 0) {
284  LOGDEBUG("SiPixelTemplateReco") << "y-length of pixel cluster doesn't agree with number of pixels above threshold" << ENDL;
285  if (theVerboseLevel > 2) {
286  LOGDEBUG("SiPixelTemplateReco") << "ysum[] = ";
287  for(i=0; i<BYSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << ysum[i] << ", ";}
288  LOGDEBUG("SiPixelTemplateReco") << ysum[BYSIZE-1] << ENDL;
289  }
290 
291  return 1;
292  }
293 
294 // If cluster is longer than max template size, technique fails
295 
296  if(nypix > TYSIZE) {
297  LOGDEBUG("SiPixelTemplateReco") << "y-length of pixel cluster is larger than maximum template size" << ENDL;
298  if (theVerboseLevel > 2) {
299  LOGDEBUG("SiPixelTemplateReco") << "ysum[] = ";
300  for(i=0; i<BYSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << ysum[i] << ", ";}
301  LOGDEBUG("SiPixelTemplateReco") << ysum[BYSIZE-1] << ENDL;
302  }
303 
304  return 6;
305  }
306 
307 // next, center the cluster on pixel 12 if necessary
308 
309  midpix = (fypix+lypix)/2;
310  shifty = BHY - midpix;
311  if(shifty > 0) {
312  for(i=lypix; i>=fypix; --i) {
313  ysum[i+shifty] = ysum[i];
314  ysum[i] = 0.;
315  yd[i+shifty] = yd[i];
316  yd[i] = false;
317  }
318  } else if (shifty < 0) {
319  for(i=fypix; i<=lypix; ++i) {
320  ysum[i+shifty] = ysum[i];
321  ysum[i] = 0.;
322  yd[i+shifty] = yd[i];
323  yd[i] = false;
324  }
325  }
326  lypix +=shifty;
327  fypix +=shifty;
328 
329 // If the cluster boundaries are OK, add pesudopixels, otherwise quit
330 
331  if(fypix > 1 && fypix < BYM2) {
332  ysum[fypix-1] = pseudopix;
333  ysum[fypix-2] = 0.2*pseudopix;
334  } else {return 8;}
335  if(lypix > 1 && lypix < BYM2) {
336  ysum[lypix+1] = pseudopix;
337  ysum[lypix+2] = 0.2*pseudopix;
338  } else {return 8;}
339 
340 // finally, determine if pixel[0] is a double pixel and make an origin correction if it is
341 
342  if(ydouble[0]) {
343  originy = -0.5;
344  } else {
345  originy = 0.;
346  }
347 
348 // next, identify the x-cluster ends, count total pixels, nxpix, and logical pixels, logxpx
349 
350  fxpix=-1;
351  nxpix=0;
352  lxpix=0;
353  logxpx=0;
354  for(i=0; i<BXSIZE; ++i) {
355  if(xsum[i] > 0.) {
356  if(fxpix == -1) {fxpix = i;}
357  if(!xd[i]) {
358  xsort[logxpx] = xsum[i];
359  ++logxpx;
360  }
361  ++nxpix;
362  lxpix = i;
363  }
364  }
365 
366 // Make sure cluster is continuous
367 
368  if((lxpix-fxpix+1) != nxpix) {
369 
370  LOGDEBUG("SiPixelTemplateReco") << "x-length of pixel cluster doesn't agree with number of pixels above threshold" << ENDL;
371  if (theVerboseLevel > 2) {
372  LOGDEBUG("SiPixelTemplateReco") << "xsum[] = ";
373  for(i=0; i<BXSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << xsum[i] << ", ";}
374  LOGDEBUG("SiPixelTemplateReco") << ysum[BXSIZE-1] << ENDL;
375  }
376 
377  return 2;
378  }
379 
380 // If cluster is longer than max template size, technique fails
381 
382  if(nxpix > TXSIZE) {
383 
384  LOGDEBUG("SiPixelTemplateReco") << "x-length of pixel cluster is larger than maximum template size" << ENDL;
385  if (theVerboseLevel > 2) {
386  LOGDEBUG("SiPixelTemplateReco") << "xsum[] = ";
387  for(i=0; i<BXSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << xsum[i] << ", ";}
388  LOGDEBUG("SiPixelTemplateReco") << ysum[BXSIZE-1] << ENDL;
389  }
390 
391  return 7;
392  }
393 
394 // next, center the cluster on pixel 5 if necessary
395 
396  midpix = (fxpix+lxpix)/2;
397  shiftx = BHX - midpix;
398  if(shiftx > 0) {
399  for(i=lxpix; i>=fxpix; --i) {
400  xsum[i+shiftx] = xsum[i];
401  xsum[i] = 0.;
402  xd[i+shiftx] = xd[i];
403  xd[i] = false;
404  }
405  } else if (shiftx < 0) {
406  for(i=fxpix; i<=lxpix; ++i) {
407  xsum[i+shiftx] = xsum[i];
408  xsum[i] = 0.;
409  xd[i+shiftx] = xd[i];
410  xd[i] = false;
411  }
412  }
413  lxpix +=shiftx;
414  fxpix +=shiftx;
415 
416 // If the cluster boundaries are OK, add pesudopixels, otherwise quit
417 
418  if(fxpix > 1 && fxpix <BXM2) {
419  xsum[fxpix-1] = pseudopix;
420  xsum[fxpix-2] = 0.2*pseudopix;
421  } else {return 9;}
422  if(lxpix > 1 && lxpix < BXM2) {
423  xsum[lxpix+1] = pseudopix;
424  xsum[lxpix+2] = 0.2*pseudopix;
425  } else {return 9;}
426 
427 // finally, determine if pixel[0] is a double pixel and make an origin correction if it is
428 
429  if(xdouble[0]) {
430  originx = -0.5;
431  } else {
432  originx = 0.;
433  }
434 
435 // uncertainty and final corrections depend upon total charge bin
436 
437  fq = qtotal/templ.qavg();
438  if(fq > 3.0) {
439  binq=0;
440  } else {
441  if(fq > 2.0) {
442  binq=1;
443  } else {
444  if(fq > 1.70) {
445  binq=2;
446  } else {
447  binq=3;
448  }
449  }
450  }
451 
452 // Return the charge bin via the parameter list unless the charge is too small (then flag it)
453 
454  qbin = binq;
455  if(!deadpix && qtotal < 1.9*templ.qmin()) {qbin = 5;} else {
456  if(!deadpix && qtotal < 1.9*templ.qmin(1)) {qbin = 4;}
457  }
458 
459  if (theVerboseLevel > 9) {
460  LOGDEBUG("SiPixelTemplateReco") <<
461  "ID = " << id << " FPix = " << fpix <<
462  " cot(alpha) = " << cotalpha << " cot(beta) = " << cotbeta <<
463  " nclusx = " << nclusx << " nclusy = " << nclusy << ENDL;
464  }
465 
466 
467 // Next, generate the 3d y- and x-templates
468 
469  array_3d ytemp;
470  templ.ytemp3d(nypix, ytemp);
471 
472  array_3d xtemp;
473  templ.xtemp3d(nxpix, xtemp);
474 
475 // Do the y-reconstruction first
476 
477 // retrieve the number of y-bins
478 
479  nybin = ytemp.shape()[0]; ycbin = nybin/2;
480 
481 // Modify the template if double pixels are present
482 
483  if(nypix > logypx) {
484  i=fypix;
485  while(i < lypix) {
486  if(yd[i] && !yd[i+1]) {
487  for(j=0; j<nybin; ++j) {
488  for(k=0; k<=j; ++k) {
489 
490 // Sum the adjacent cells and put the average signal in both
491 
492  sigavg = (ytemp[j][k][i] + ytemp[j][k][i+1])/2.;
493  ytemp[j][k][i] = sigavg;
494  ytemp[j][k][i+1] = sigavg;
495  }
496  }
497  i += 2;
498  } else {
499  ++i;
500  }
501  }
502  }
503 
504 // Define the maximum signal to allow before de-weighting a pixel
505 
506  sythr = 2.1*(templ.symax());
507 
508 // Make sure that there will be at least two pixels that are not de-weighted
509 
510  std::sort(&ysort[0], &ysort[logypx]);
511  if(logypx == 1) {sythr = 1.01*ysort[0];} else {
512  if (ysort[1] > sythr) { sythr = 1.01*ysort[1]; }
513  }
514 
515 // Evaluate pixel-by-pixel uncertainties (weights) for the templ analysis
516 
517  for(i=0; i<BYSIZE; ++i) { ysig2[i] = 0.;}
518  templ.ysigma2(fypix, lypix, sythr, ysum, ysig2);
519 
520 // Find the template bin that minimizes the Chi^2
521 
522  chi2ymin = 1.e15;
523  minbinj = -1;
524  minbink = -1;
525  for(j=0; j<nybin; ++j) {
526  for(k=0; k<=j; ++k) {
527  ss2 = 0.;
528  ssa = 0.;
529  sa2 = 0.;
530  for(i=fypix-2; i<=lypix+2; ++i) {
531  ss2 += ysum[i]*ysum[i]/ysig2[i];
532  ssa += ysum[i]*ytemp[j][k][i]/ysig2[i];
533  sa2 += ytemp[j][k][i]*ytemp[j][k][i]/ysig2[i];
534  }
535  rat=ssa/ss2;
536  if(rat <= 0.) {LOGERROR("SiPixelTemplateReco") << "illegal chi2ymin normalization = " << rat << ENDL; rat = 1.;}
537  chi2y=ss2-2.*ssa/rat+sa2/(rat*rat);
538  if(chi2y < chi2ymin) {
539  chi2ymin = chi2y;
540  minbinj = j;
541  minbink = k;
542  }
543  }
544  }
545 
546  if (theVerboseLevel > 9) {
547  LOGDEBUG("SiPixelTemplateReco") <<
548  "minbins " << minbinj << "," << minbink << " chi2ymin = " << chi2ymin << ENDL;
549  }
550 
551 // Do not apply final template pass to 1-pixel clusters (use calibrated offset)
552 
553  if(logypx == 1) {
554 
555  if(nypix ==1) {
556  delta = templ.dyone();
557  sigma = templ.syone();
558  } else {
559  delta = templ.dytwo();
560  sigma = templ.sytwo();
561  }
562 
563  yrec1 = 0.5*(fypix+lypix-2*shifty+2.*originy)*ysize-delta;
564  yrec2 = yrec1;
565 
566  if(sigma <= 0.) {
567  sigmay = 43.3;
568  } else {
569  sigmay = sigma;
570  }
571 
572 // Do probability calculation for one-pixel clusters
573 
574  chi21max = fmax(chi21min, (double)templ.chi2yminone());
575  chi2ymin -=chi21max;
576  if(chi2ymin < 0.) {chi2ymin = 0.;}
577  // proby = gsl_cdf_chisq_Q(chi2ymin, mean1pix);
578  meany = fmax(mean1pix, (double)templ.chi2yavgone());
579  hchi2 = chi2ymin/2.; hndof = meany/2.;
580  proby = 1. - TMath::Gamma(hndof, hchi2);
581 
582  } else {
583 
584 // For cluster > 1 pix, use chi^2 minimm to recontruct the two y-positions
585 
586 // at small eta, the templates won't actually work on two pixel y-clusters so just return the pixel centers
587 
588  if(logypx == 2 && fabsf(cotbeta) < 0.25) {
589  switch(nypix) {
590  case 2:
591 // Both pixels are small
592  yrec1 = (fypix-shifty+originy)*ysize;
593  yrec2 = (lypix-shifty+originy)*ysize;
594  sigmay = 43.3;
595  break;
596  case 3:
597 // One big pixel and one small pixel
598  if(yd[fypix]) {
599  yrec1 = (fypix+0.5-shifty+originy)*ysize;
600  yrec2 = (lypix-shifty+originy)*ysize;
601  sigmay = 43.3;
602  } else {
603  yrec1 = (fypix-shifty+originy)*ysize;
604  yrec2 = (lypix-0.5-shifty+originy)*ysize;
605  sigmay = 65.;
606  }
607  break;
608  case 4:
609 // Two big pixels
610  yrec1 = (fypix+0.5-shifty+originy)*ysize;
611  yrec2 = (lypix-0.5-shifty+originy)*ysize;
612  sigmay = 86.6;
613  break;
614  default:
615 // Something is screwy ...
616  LOGERROR("SiPixelTemplateReco") << "weird problem: logical y-pixels = " << logypx << ", total ysize in normal pixels = " << nypix << ENDL;
617  return 10;
618  }
619  } else {
620 
621 // uncertainty and final correction depend upon charge bin
622 
623  bias = templ.yavgc2m(binq);
624  yrec1 = (0.125*(minbink-ycbin)+BHY-(float)shifty+originy)*ysize - bias;
625  yrec2 = (0.125*(minbinj-ycbin)+BHY-(float)shifty+originy)*ysize - bias;
626  sigmay = sqrt2*templ.yrmsc2m(binq);
627 
628  }
629 
630 // Do goodness of fit test in y
631 
632  if(chi2ymin < 0.0) {chi2ymin = 0.0;}
633  meany = 2.*templ.chi2yavg(binq);
634  if(meany < 0.01) {meany = 0.01;}
635 // gsl function that calculates the chi^2 tail prob for non-integral dof
636 // proby = gsl_cdf_chisq_Q(chi2y, meany);
637 // proby = ROOT::Math::chisquared_cdf_c(chi2y, meany);
638  hchi2 = chi2ymin/2.; hndof = meany/2.;
639  proby = 1. - TMath::Gamma(hndof, hchi2);
640  }
641 
642 // Do the x-reconstruction next
643 
644 // retrieve the number of x-bins
645 
646  nxbin = xtemp.shape()[0]; xcbin = nxbin/2;
647 
648 // Modify the template if double pixels are present
649 
650  if(nxpix > logxpx) {
651  i=fxpix;
652  while(i < lxpix) {
653  if(xd[i] && !xd[i+1]) {
654  for(j=0; j<nxbin; ++j) {
655  for(k=0; k<=j; ++k) {
656 
657 // Sum the adjacent cells and put the average signal in both
658 
659  sigavg = (xtemp[j][k][i] + xtemp[j][k][i+1])/2.;
660  xtemp[j][k][i] = sigavg;
661  xtemp[j][k][i+1] = sigavg;
662  }
663  }
664  i += 2;
665  } else {
666  ++i;
667  }
668  }
669  }
670 
671 // Define the maximum signal to allow before de-weighting a pixel
672 
673  sxthr = 2.1*templ.sxmax();
674 
675 // Make sure that there will be at least two pixels that are not de-weighted
676  std::sort(&xsort[0], &xsort[logxpx]);
677  if(logxpx == 1) {sxthr = 1.01*xsort[0];} else {
678  if (xsort[1] > sxthr) { sxthr = 1.01*xsort[1]; }
679  }
680 
681 // Evaluate pixel-by-pixel uncertainties (weights) for the templ analysis
682 
683  for(i=0; i<BYSIZE; ++i) { xsig2[i] = 0.; }
684  templ.xsigma2(fxpix, lxpix, sxthr, xsum, xsig2);
685 
686 // Find the template bin that minimizes the Chi^2
687 
688  chi2xmin = 1.e15;
689  minbinj = -1;
690  minbink = -1;
691  for(j=0; j<nxbin; ++j) {
692  for(k=0; k<=j; ++k) {
693  ss2 = 0.;
694  ssa = 0.;
695  sa2 = 0.;
696  for(i=fxpix-2; i<=lxpix+2; ++i) {
697  ss2 += xsum[i]*xsum[i]/xsig2[i];
698  ssa += xsum[i]*xtemp[j][k][i]/xsig2[i];
699  sa2 += xtemp[j][k][i]*xtemp[j][k][i]/xsig2[i];
700  }
701  rat=ssa/ss2;
702  if(rat <= 0.) {LOGERROR("SiPixelTemplateReco") << "illegal chi2ymin normalization = " << rat << ENDL; rat = 1.;}
703  chi2x=ss2-2.*ssa/rat+sa2/(rat*rat);
704  if(chi2x < chi2xmin) {
705  chi2xmin = chi2x;
706  minbinj = j;
707  minbink = k;
708  }
709  }
710  }
711 
712  if (theVerboseLevel > 9) {
713  LOGDEBUG("SiPixelTemplateReco") <<
714  "minbin " << minbin << " chi2xmin = " << chi2xmin << ENDL;
715  }
716 
717 // Do not apply final template pass to 1-pixel clusters (use calibrated offset)
718 
719  if(logxpx == 1) {
720 
721  if(nxpix ==1) {
722  delta = templ.dxone();
723  sigma = templ.sxone();
724  } else {
725  delta = templ.dxtwo();
726  sigma = templ.sxtwo();
727  }
728  xrec1 = 0.5*(fxpix+lxpix-2*shiftx+2.*originx)*xsize-delta;
729  xrec2 = xrec1;
730  if(sigma <= 0.) {
731  sigmax = 28.9;
732  } else {
733  sigmax = sigma;
734  }
735 
736 // Do probability calculation for one-pixel clusters
737 
738  chi21max = fmax(chi21min, (double)templ.chi2xminone());
739  chi2xmin -=chi21max;
740  if(chi2xmin < 0.) {chi2xmin = 0.;}
741  meanx = fmax(mean1pix, (double)templ.chi2xavgone());
742  hchi2 = chi2xmin/2.; hndof = meanx/2.;
743  probx = 1. - TMath::Gamma(hndof, hchi2);
744 
745  } else {
746 
747 // For cluster > 1 pix, use chi^2 minimm to recontruct the two x-positions
748 
749 // uncertainty and final correction depend upon charge bin
750 
751  bias = templ.xavgc2m(binq);
752  k = std::min(minbink, minbinj);
753  j = std::max(minbink, minbinj);
754  xrec1 = (0.125*(minbink-xcbin)+BHX-(float)shiftx+originx)*xsize - bias;
755  xrec2 = (0.125*(minbinj-xcbin)+BHX-(float)shiftx+originx)*xsize - bias;
756  sigmax = sqrt2*templ.xrmsc2m(binq);
757 
758 // Do goodness of fit test in y
759 
760  if(chi2xmin < 0.0) {chi2xmin = 0.0;}
761  meanx = 2.*templ.chi2xavg(binq);
762  if(meanx < 0.01) {meanx = 0.01;}
763  hchi2 = chi2xmin/2.; hndof = meanx/2.;
764  probx = 1. - TMath::Gamma(hndof, hchi2);
765  }
766 
767  // Don't return exact zeros for the probability
768 
769  if(proby < probmin) {proby = probmin;}
770  if(probx < probmin) {probx = probmin;}
771 
772  return 0;
773 } // PixelTempSplit
774 
775 
776 // *************************************************************************************************************************************
798 // *************************************************************************************************************************************
799 
800 int SiPixelTemplateReco::PixelTempSplit(int id, bool fpix, float cotalpha, float cotbeta, array_2d cluster,
801  std::vector<bool> ydouble, std::vector<bool> xdouble,
802  SiPixelTemplate& templ,
803  float& yrec1, float& yrec2, float& sigmay, float& proby,
804  float& xrec1, float& xrec2, float& sigmax, float& probx, int& qbin)
805 {
806  // Local variables
807  const bool deadpix = false;
808  std::vector<std::pair<int, int> > zeropix;
809 
810  return SiPixelTemplateReco::PixelTempSplit(id, fpix, cotalpha, cotbeta, cluster, ydouble, xdouble, templ,
811  yrec1, yrec2, sigmay, proby, xrec1, xrec2, sigmax, probx, qbin, deadpix, zeropix);
812 
813 } // PixelTempSplit
float yrmsc2m(int i)
1st pass chi2 min search: average y-rms of reconstruction binned in 4 charge bins ...
dbl * delta
Definition: mlp_gen.cc:36
int i
Definition: DBlmapReader.cc:9
#define BXSIZE
float chi2xminone()
//!&lt; minimum of x chi^2 for 1 pixel clusters
void ytemp3d(int nypix, array_3d &ytemplate)
static int theVerboseLevel
float symax()
average pixel signal for y-projection of cluster
#define BYSIZE
#define TXSIZE
#define LOGERROR(x)
#define BXM1
float qmin()
minimum cluster charge for valid hit (keeps 99.9% of simulated hits)
#define min(a, b)
Definition: mlp_lapack.h:161
float xavgc2m(int i)
1st pass chi2 min search: average x-bias of reconstruction binned in 4 charge bins ...
float sytwo()
rms for one double-pixel y-clusters
#define ENDL
float chi2yminone()
//!&lt; minimum of y chi^2 for 1 pixel clusters
bool interpolate(int id, float cotalpha, float cotbeta, float locBz)
float sxone()
rms for one pixel x-clusters
#define BYM1
#define BXM2
boost::multi_array< float, 2 > array_2d
float qscale()
charge scaling factor
float dxone()
mean offset/correction for one pixel x-clusters
void xtemp3d(int nxpix, array_3d &xtemplate)
const T & max(const T &a, const T &b)
float chi2yavg(int i)
average y chi^2 in 4 charge bins
#define BHX
boost::multi_array< float, 3 > array_3d
int j
Definition: DBlmapReader.cc:9
#define LOGDEBUG(x)
#define BYM2
float sxtwo()
rms for one double-pixel x-clusters
#define BYM3
float dytwo()
mean offset/correction for one double-pixel y-clusters
float s50()
1/2 of the pixel threshold signal in electrons
int k[5][pyjets_maxn]
float yavgc2m(int i)
1st pass chi2 min search: average y-bias of reconstruction binned in 4 charge bins ...
#define TYSIZE
static const int maxpix
float syone()
rms for one pixel y-clusters
float chi2yavgone()
//!&lt; average y chi^2 for 1 pixel clusters
float qavg()
average cluster charge for this set of track angles
#define BHY
float sxmax()
average pixel signal for x-projection of cluster
void xsigma2(int fxpix, int lxpix, float sxthr, float xsum[BXSIZE], float xsig2[BXSIZE])
float chi2xavgone()
//!&lt; average x chi^2 for 1 pixel clusters
float pixmax()
maximum pixel charge
void ysigma2(int fypix, int lypix, float sythr, float ysum[BYSIZE], float ysig2[BYSIZE])
dbl * Gamma
Definition: mlp_gen.cc:38
float chi2xavg(int i)
averaage x chi^2 in 4 charge bins
int PixelTempSplit(int id, bool fpix, float cotalpha, float cotbeta, array_2d cluster, std::vector< bool > ydouble, std::vector< bool > xdouble, SiPixelTemplate &templ, float &yrec1, float &yrec2, float &sigmay, float &proby, float &xrec1, float &xrec2, float &sigmax, float &probx, int &qbin, bool deadpix, std::vector< std::pair< int, int > > zeropix)
float dyone()
mean offset/correction for one pixel y-clusters
float dxtwo()
mean offset/correction for one double-pixel x-clusters
float xrmsc2m(int i)
1st pass chi2 min search: average x-rms of reconstruction binned in 4 charge bins ...