CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SiPixelTemplateReco2D.cc
Go to the documentation of this file.
1 //
2 // SiPixelTemplateReco2D.cc (Version 2.90)
3 // Updated to work with the 2D template generation code
4 // Include all bells and whistles for edge clusters
5 // 2.10 - Add y-lorentz drift to estimate starting point [for FPix]
6 // 2.10 - Remove >1 pixel requirement
7 // 2.20 - Fix major bug, change chi2 scan to 9x5 [YxX]
8 // 2.30 - Allow one pixel clusters, improve cosmetics for increased style points from judges
9 // 2.50 - Add variable cluster shifting to make the position parameter space more symmetric,
10 // also fix potential problems with variable size input clusters and double pixel flags
11 // 2.55 - Fix another double pixel flag problem and a small pseudopixel problem in the edgegflagy = 3 case.
12 // 2.60 - Modify the algorithm to return the point with the best chi2 from the starting point scan when
13 // the iterative procedure does not converge [eg 1 pixel clusters]
14 // 2.70 - Change convergence criterion to require it in both planes [it was either]
15 // 2.80 - Change 3D to 2D
16 // 2.90 - Fix divide by zero for separate 1D convergence branch
17 //
18 //
19 //
20 // Created by Morris Swartz on 7/13/17.
21 //
22 //
23 
24 #ifdef SI_PIXEL_TEMPLATE_STANDALONE
25 #include <math.h>
26 #endif
27 #include <algorithm>
28 #include <vector>
29 #include <utility>
30 #include <iostream>
31 // ROOT::Math has a c++ function that does the probability calc, but only in v5.12 and later
32 #include "TMath.h"
33 #include "Math/DistFunc.h"
34 
35 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
39 #define LOGERROR(x) edm::LogError(x)
40 #define LOGDEBUG(x) LogDebug(x)
41 #define ENDL " "
43 #else
44 #include "SiPixelTemplateReco2D.h"
45 #include "VVIObjF.h"
46 #define LOGERROR(x) std::cout << x << ": "
47 #define LOGDEBUG(x) std::cout << x << ": "
48 #define ENDL std::endl
49 #endif
50 
51 using namespace SiPixelTemplateReco2D;
52 
53 // *************************************************************************************************************************************
82 // *************************************************************************************************************************************
84  float cotalpha,
85  float cotbeta,
86  float locBz,
87  float locBx,
88  int edgeflagy,
89  int edgeflagx,
90  ClusMatrix& cluster,
91  SiPixelTemplate2D& templ2D,
92  float& yrec,
93  float& sigmay,
94  float& xrec,
95  float& sigmax,
96  float& probxy,
97  float& probQ,
98  int& qbin,
99  float& deltay,
100  int& npixels)
101 
102 {
103  // Local variables
104 
105  float template2d[BXM2][BYM2], dpdx2d[2][BXM2][BYM2], fbin[3];
106 
107  // fraction of truncation signal to measure the cluster ends
108  const float fracpix = 0.45f;
109 
110  const int nilist = 9, njlist = 5;
111  const float ilist[nilist] = {0.f, -1.f, -0.75f, -0.5f, -0.25f, 0.25f, 0.5f, 0.75f, 1.f};
112  const float jlist[njlist] = {0.f, -0.5f, -0.25f, 0.25f, 0.50f};
113 
114  // Extract some relevant info from the 2D template
115 
116  if (id >= 0) { // if id < 0, bypass interpolation (used in calibration)
117  if (!templ2D.interpolate(id, cotalpha, cotbeta, locBz, locBx))
118  return 4;
119  }
120  float xsize = templ2D.xsize();
121  float ysize = templ2D.ysize();
122 
123  // Allow Qbin Q/Q_avg fractions to vary to optimize error estimation
124 
125  for (int i = 0; i < 3; ++i) {
126  fbin[i] = templ2D.fbin(i);
127  }
128 
129  float q50 = templ2D.s50();
130  float pseudopix = 0.2f * q50;
131  float pseudopix2 = q50 * q50;
132 
133  // Get charge scaling factor
134 
135  float qscale = templ2D.qscale();
136 
137  // Check that the cluster container is (up to) a 7x21 matrix and matches the dimensions of the double pixel flags
138 
139  int nclusx = cluster.mrow;
140  int nclusy = (int)cluster.mcol;
141  bool* xdouble = cluster.xdouble;
142  bool* ydouble = cluster.ydouble;
143 
144  // First, rescale all pixel charges and compute total charge
145  float qtotal = 0.f;
146  int imin = BYM2, imax = 0, jmin = BXM2, jmax = 0;
147  for (int k = 0; k < nclusx * nclusy; ++k) {
148  cluster.matrix[k] *= qscale;
149  qtotal += cluster.matrix[k];
150  int j = k / nclusy;
151  int i = k - j * nclusy;
152  if (cluster.matrix[k] > 0.f) {
153  if (j < jmin) {
154  jmin = j;
155  }
156  if (j > jmax) {
157  jmax = j;
158  }
159  if (i < imin) {
160  imin = i;
161  }
162  if (i > imax) {
163  imax = i;
164  }
165  }
166  }
167 
168  // Calculate the shifts needed to center the cluster in the buffer
169 
170  int shiftx = THXP1 - (jmin + jmax) / 2;
171  int shifty = THYP1 - (imin + imax) / 2;
172  // Always shift by at least one pixel
173  if (shiftx < 1)
174  shiftx = 1;
175  if (shifty < 1)
176  shifty = 1;
177  // Shift the min maxes too
178  jmin += shiftx;
179  jmax += shiftx;
180  imin += shifty;
181  imax += shifty;
182 
183  // uncertainty and final corrections depend upon total charge bin
184 
185  float fq0 = qtotal / templ2D.qavg();
186 
187  // Next, copy the cluster and double pixel flags into a shifted workspace to
188  // allow for significant zeros [pseudopixels] to be added
189 
190  float clusxy[BXM2][BYM2];
191  for (int j = 0; j < BXM2; ++j) {
192  for (int i = 0; i < BYM2; ++i) {
193  clusxy[j][i] = 0.f;
194  }
195  }
196 
197  const unsigned int NPIXMAX = 200;
198 
199  int indexxy[2][NPIXMAX];
200  float pixel[NPIXMAX];
201  float sigma2[NPIXMAX];
202  float minmax = templ2D.pixmax();
203  float ylow0 = 0.f, yhigh0 = 0.f, xlow0 = 0.f, xhigh0 = 0.f;
204  int npixel = 0;
205  float ysum[BYM2], ye[BYM2 + 1], ypos[BYM2], xpos[BXM2], xe[BXM2 + 1];
206  bool yd[BYM2], xd[BXM2];
207 
208  // Copy double pixel flags to shifted arrays
209 
210  for (int i = 0; i < BYM2; ++i) {
211  ysum[i] = 0.f;
212  yd[i] = false;
213  }
214  for (int j = 0; j < BXM2; ++j) {
215  xd[j] = false;
216  }
217  for (int i = 0; i < nclusy; ++i) {
218  if (ydouble[i]) {
219  int iy = i + shifty;
220  if (iy > -1 && iy < BYM2)
221  yd[iy] = true;
222  }
223  }
224  for (int j = 0; j < nclusx; ++j) {
225  if (xdouble[j]) {
226  int jx = j + shiftx;
227  if (jx > -1 && jx < BXM2)
228  xd[jx] = true;
229  }
230  }
231  // Work out the positions of the rows+columns relative to the lower left edge of pixel[1,1]
232  xe[0] = -xsize;
233  ye[0] = -ysize;
234  for (int i = 0; i < BYM2; ++i) {
235  float ypitch = ysize;
236  if (yd[i]) {
237  ypitch += ysize;
238  }
239  ye[i + 1] = ye[i] + ypitch;
240  ypos[i] = ye[i] + ypitch / 2.;
241  }
242  for (int j = 0; j < BXM2; ++j) {
243  float xpitch = xsize;
244  if (xd[j]) {
245  xpitch += xsize;
246  }
247  xe[j + 1] = xe[j] + xpitch;
248  xpos[j] = xe[j] + xpitch / 2.;
249  }
250  // Shift the cluster center to the central pixel of the array, truncate big signals
251  for (int i = 0; i < nclusy; ++i) {
252  int iy = i + shifty;
253  float maxpix = minmax;
254  if (ydouble[i]) {
255  maxpix *= 2.f;
256  }
257  if (iy > -1 && iy < BYM2) {
258  for (int j = 0; j < nclusx; ++j) {
259  int jx = j + shiftx;
260  if (jx > -1 && jx < BXM2) {
261  if (cluster(j, i) > maxpix) {
262  clusxy[jx][iy] = maxpix;
263  } else {
264  clusxy[jx][iy] = cluster(j, i);
265  }
266  if (clusxy[jx][iy] > 0.f) {
267  ysum[iy] += clusxy[jx][iy];
268  indexxy[0][npixel] = jx;
269  indexxy[1][npixel] = iy;
270  pixel[npixel] = clusxy[jx][iy];
271  ++npixel;
272  }
273  }
274  }
275  }
276  }
277 
278  // Make sure that we find at least one pixel
279  if (npixel < 1) {
280 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
281  throw cms::Exception("DataCorrupt") << "PixelTemplateReco2D::number of pixels above threshold = " << npixel
282  << std::endl;
283 #else
284  std::cout << "PixelTemplateReco2D::number of pixels above threshold = " << npixel << std::endl;
285 #endif
286  return 1;
287  }
288 
289  // Get the shifted coordinates of the cluster ends
290  xlow0 = xe[jmin];
291  xhigh0 = xe[jmax + 1];
292  ylow0 = ye[imin];
293  yhigh0 = ye[imax + 1];
294 
295  // Next, calculate the error^2 [need to know which is the middle y pixel of the cluster]
296 
297  int ypixoff = T2HYP1 - (imin + imax) / 2;
298  for (int k = 0; k < npixel; ++k) {
299  int ypixeff = ypixoff + indexxy[1][k];
300  templ2D.xysigma2(pixel[k], ypixeff, sigma2[k]);
301  }
302 
303  // Next, find the half-height edges of the y-projection and identify any
304  // missing columns to remove from the fit
305 
306  int imisslow = -1, imisshigh = -1, jmisslow = -1, jmisshigh = -1;
307  float ylow = -1.f, yhigh = -1.f;
308  float hmaxpix = fracpix * templ2D.sxymax();
309  for (int i = imin; i <= imax; ++i) {
310  if (ysum[i] > hmaxpix && ysum[i - 1] < hmaxpix && ylow < 0.f) {
311  ylow = ypos[i - 1] + (ypos[i] - ypos[i - 1]) * (hmaxpix - ysum[i - 1]) / (ysum[i] - ysum[i - 1]);
312  }
313  if (ysum[i] < q50) {
314  if (imisslow < 0)
315  imisslow = i;
316  imisshigh = i;
317  }
318  if (ysum[i] > hmaxpix && ysum[i + 1] < hmaxpix) {
319  yhigh = ypos[i] + (ypos[i + 1] - ypos[i]) * (ysum[i] - hmaxpix) / (ysum[i] - ysum[i + 1]);
320  }
321  }
322  if (ylow < 0.f || yhigh < 0.f) {
323  ylow = ylow0;
324  yhigh = yhigh0;
325  }
326 
327  float templeny = templ2D.clsleny();
328  deltay = templeny - (yhigh - ylow) / ysize;
329 
330  // x0 and y0 are best guess seeds for the fit
331 
332  float x0 = 0.5f * (xlow0 + xhigh0) - templ2D.lorxdrift();
333  float y0 = 0.5f * (ylow + yhigh) - templ2D.lorydrift();
334  // float y1 = yhigh - halfy - templ2D.lorydrift();
335  // printf("y0 = %f, y1 = %f \n", y0, y1);
336  // float y0 = 0.5f*(ylow + yhigh);
337 
338  // If there are missing edge columns, set up missing column flags and number
339  // of minimization passes
340 
341  int npass = 1;
342 
343  switch (edgeflagy) {
344  case 0:
345  break;
346  case 1:
347  imisshigh = imin - 1;
348  imisslow = -1;
349  break;
350  case 2:
351  imisshigh = -1;
352  imisslow = imax + 1;
353  break;
354  case 3:
355  imisshigh = imin - 1;
356  imisslow = -1;
357  npass = 2;
358  break;
359  default:
360 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
361  throw cms::Exception("DataCorrupt") << "PixelTemplateReco2D::illegal edgeflagy = " << edgeflagy << std::endl;
362 #else
363  std::cout << "PixelTemplate:2D:illegal edgeflagy = " << edgeflagy << std::endl;
364 #endif
365  }
366 
367  switch (edgeflagx) {
368  case 0:
369  break;
370  case 1:
371  jmisshigh = jmin - 1;
372  jmisslow = -1;
373  break;
374  case 2:
375  jmisshigh = -1;
376  jmisslow = jmax + 1;
377  break;
378  default:
379 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
380  throw cms::Exception("DataCorrupt") << "PixelTemplateReco2D::illegal edgeflagx = " << edgeflagx << std::endl;
381 #else
382  std::cout << "PixelTemplate:2D:illegal edgeflagx = " << edgeflagx << std::endl;
383 #endif
384  }
385 
386  // Define quantities to be saved for each pass
387 
388  float chi2min[2], xerr2[2], yerr2[2];
389  float x2D0[2], y2D0[2], qtfrac0[2];
390  int ipass, tpixel;
391  //int niter0[2];
392 
393  for (ipass = 0; ipass < npass; ++ipass) {
394  if (ipass == 1) {
395  // Now try again if both edges are possible
396 
397  imisshigh = -1;
398  imisslow = imax + 1;
399  // erase pseudo pixels from previous pass
400  for (int k = npixel; k < tpixel; ++k) {
401  int j = indexxy[0][k];
402  int i = indexxy[1][k];
403  clusxy[j][i] = 0.f;
404  }
405  }
406 
407  // Next, add pseudo pixels around the periphery of the cluster
408 
409  tpixel = npixel;
410  for (int k = 0; k < npixel; ++k) {
411  int j = indexxy[0][k];
412  int i = indexxy[1][k];
413  if ((j - 1) != jmisshigh) {
414  if (clusxy[j - 1][i] < pseudopix) {
415  indexxy[0][tpixel] = j - 1;
416  indexxy[1][tpixel] = i;
417  clusxy[j - 1][i] = pseudopix;
418  pixel[tpixel] = pseudopix;
419  sigma2[tpixel] = pseudopix2;
420  ++tpixel;
421  }
422  }
423  if ((j + 1) != jmisslow) {
424  if (clusxy[j + 1][i] < pseudopix) {
425  indexxy[0][tpixel] = j + 1;
426  indexxy[1][tpixel] = i;
427  clusxy[j + 1][i] = pseudopix;
428  pixel[tpixel] = pseudopix;
429  sigma2[tpixel] = pseudopix2;
430  ++tpixel;
431  }
432  }
433  // Don't add them if this is a dead column
434  if ((i + 1) != imisslow) {
435  if ((j - 1) != jmisshigh) {
436  if (clusxy[j - 1][i + 1] < pseudopix) {
437  indexxy[0][tpixel] = j - 1;
438  indexxy[1][tpixel] = i + 1;
439  clusxy[j - 1][i + 1] = pseudopix;
440  pixel[tpixel] = pseudopix;
441  sigma2[tpixel] = pseudopix2;
442  ++tpixel;
443  }
444  }
445  if (clusxy[j][i + 1] < pseudopix) {
446  indexxy[0][tpixel] = j;
447  indexxy[1][tpixel] = i + 1;
448  clusxy[j][i + 1] = pseudopix;
449  pixel[tpixel] = pseudopix;
450  sigma2[tpixel] = pseudopix2;
451  ++tpixel;
452  }
453  if ((j + 1) != jmisslow) {
454  if (clusxy[j + 1][i + 1] < pseudopix) {
455  indexxy[0][tpixel] = j + 1;
456  indexxy[1][tpixel] = i + 1;
457  clusxy[j + 1][i + 1] = pseudopix;
458  pixel[tpixel] = pseudopix;
459  sigma2[tpixel] = pseudopix2;
460  ++tpixel;
461  }
462  }
463  }
464  // Don't add them if this is a dead column
465  if ((i - 1) != imisshigh) {
466  if ((j - 1) != jmisshigh) {
467  if (clusxy[j - 1][i - 1] < pseudopix) {
468  indexxy[0][tpixel] = j - 1;
469  indexxy[1][tpixel] = i - 1;
470  clusxy[j - 1][i - 1] = pseudopix;
471  pixel[tpixel] = pseudopix;
472  sigma2[tpixel] = pseudopix2;
473  ++tpixel;
474  }
475  }
476  if (clusxy[j][i - 1] < pseudopix) {
477  indexxy[0][tpixel] = j;
478  indexxy[1][tpixel] = i - 1;
479  clusxy[j][i - 1] = pseudopix;
480  pixel[tpixel] = pseudopix;
481  sigma2[tpixel] = pseudopix2;
482  ++tpixel;
483  }
484  if ((j + 1) != jmisslow) {
485  if (clusxy[j + 1][i - 1] < pseudopix) {
486  indexxy[0][tpixel] = j + 1;
487  indexxy[1][tpixel] = i - 1;
488  clusxy[j + 1][i - 1] = pseudopix;
489  pixel[tpixel] = pseudopix;
490  sigma2[tpixel] = pseudopix2;
491  ++tpixel;
492  }
493  }
494  }
495  }
496 
497  // Calculate chi2 over a grid of several seeds and choose the smallest
498 
499  chi2min[ipass] = 1000000.f;
500  float chi2, qtemplate, qactive, qtfrac = 0.f, x2D = 0.f, y2D = 0.f;
501  // Scale the y search grid for long clusters [longer than 7 pixels]
502  float ygridscale = 0.271 * cotbeta;
503  if (ygridscale < 1.f)
504  ygridscale = 1.f;
505  for (int is = 0; is < nilist; ++is) {
506  for (int js = 0; js < njlist; ++js) {
507  float xtry = x0 + jlist[js] * xsize;
508  float ytry = y0 + ilist[is] * ygridscale * ysize;
509  chi2 = 0.f;
510  qactive = 0.f;
511  for (int j = 0; j < BXM2; ++j) {
512  for (int i = 0; i < BYM2; ++i) {
513  template2d[j][i] = 0.f;
514  }
515  }
516  templ2D.xytemp(xtry, ytry, yd, xd, template2d, false, dpdx2d, qtemplate);
517  for (int k = 0; k < tpixel; ++k) {
518  int jpix = indexxy[0][k];
519  int ipix = indexxy[1][k];
520  float qtpixel = template2d[jpix][ipix];
521  float pt = pixel[k] - qtpixel;
522  chi2 += pt * pt / sigma2[k];
523  if (k < npixel) {
524  qactive += qtpixel;
525  }
526  }
527  if (chi2 < chi2min[ipass]) {
528  chi2min[ipass] = chi2;
529  x2D = xtry;
530  y2D = ytry;
531  qtfrac = qactive / qtemplate;
532  }
533  }
534  }
535 
536  int niter = 0;
537  float xstep = 1.0f, ystep = 1.0f;
538  float minv11 = 1000.f, minv12 = 1000.f, minv22 = 1000.f;
539  chi2 = chi2min[ipass];
540  while (chi2 <= chi2min[ipass] && niter < 15 && (niter < 2 || (std::abs(xstep) > 0.2 || std::abs(ystep) > 0.2))) {
541  // Remember the present parameters
542  x2D0[ipass] = x2D;
543  y2D0[ipass] = y2D;
544  qtfrac0[ipass] = qtfrac;
545  xerr2[ipass] = minv11;
546  yerr2[ipass] = minv22;
547  chi2min[ipass] = chi2;
548  //niter0[ipass] = niter;
549 
550  // Calculate the initial template which also allows the error calculation for the struck pixels
551 
552  for (int j = 0; j < BXM2; ++j) {
553  for (int i = 0; i < BYM2; ++i) {
554  template2d[j][i] = 0.f;
555  }
556  }
557  templ2D.xytemp(x2D, y2D, yd, xd, template2d, true, dpdx2d, qtemplate);
558 
559  float sumptdt1 = 0., sumptdt2 = 0.;
560  float sumdtdt11 = 0., sumdtdt12 = 0., sumdtdt22 = 0.;
561  chi2 = 0.f;
562  qactive = 0.f;
563  // Loop over all pixels and calculate matrices
564 
565  for (int k = 0; k < tpixel; ++k) {
566  int jpix = indexxy[0][k];
567  int ipix = indexxy[1][k];
568  float qtpixel = template2d[jpix][ipix];
569  float pt = pixel[k] - qtpixel;
570  float dtdx = dpdx2d[0][jpix][ipix];
571  float dtdy = dpdx2d[1][jpix][ipix];
572  chi2 += pt * pt / sigma2[k];
573  sumptdt1 += pt * dtdx / sigma2[k];
574  sumptdt2 += pt * dtdy / sigma2[k];
575  sumdtdt11 += dtdx * dtdx / sigma2[k];
576  sumdtdt12 += dtdx * dtdy / sigma2[k];
577  sumdtdt22 += dtdy * dtdy / sigma2[k];
578  if (k < npixel) {
579  qactive += qtpixel;
580  }
581  }
582 
583  // invert the parameter covariance matrix
584 
585  float D = sumdtdt11 * sumdtdt22 - sumdtdt12 * sumdtdt12;
586 
587  // If the matrix is non-singular invert and solve
588 
589  if (std::abs(D) > 1.e-3) {
590  minv11 = sumdtdt22 / D;
591  minv12 = -sumdtdt12 / D;
592  minv22 = sumdtdt11 / D;
593 
594  qtfrac = qactive / qtemplate;
595 
596  //Calculate the step size
597 
598  xstep = minv11 * sumptdt1 + minv12 * sumptdt2;
599  ystep = minv12 * sumptdt1 + minv22 * sumptdt2;
600 
601  } else {
602  // Assume alternately that ystep = 0 and then xstep = 0
603  if (sumdtdt11 > 0.0001f) {
604  xstep = sumptdt1 / sumdtdt11;
605  } else {
606  xstep = 0.f;
607  }
608  if (sumdtdt22 > 0.0001f) {
609  ystep = sumptdt2 / sumdtdt22;
610  } else {
611  ystep = 0.f;
612  }
613  }
614  xstep *= 0.9f;
615  ystep *= 0.9f;
616  if (std::abs(xstep) > 2. * xsize || std::abs(ystep) > 2. * ysize)
617  break;
618  x2D += xstep;
619  y2D += ystep;
620  ++niter;
621  }
622  }
623 
624  ipass = 0;
625 
626  if (npass > 1) {
627  // two passes, take smaller chisqared
628  if (chi2min[1] < chi2min[0]) {
629  ipass = 1;
630  }
631  }
632 
633  // Correct the charge ratio for missing pixels
634 
635  float fq;
636  if (qtfrac0[ipass] < 0.10f || qtfrac0[ipass] > 1.f) {
637  qtfrac0[ipass] = 1.f;
638  }
639  fq = fq0 / qtfrac0[ipass];
640 
641  // printf("qtfrac0 = %f \n", qtfrac0);
642 
643  if (fq > fbin[0]) {
644  qbin = 0;
645  } else {
646  if (fq > fbin[1]) {
647  qbin = 1;
648  } else {
649  if (fq > fbin[2]) {
650  qbin = 2;
651  } else {
652  qbin = 3;
653  }
654  }
655  }
656 
657  // Get charge related quantities
658 
659  float scalex = templ2D.scalex(qbin);
660  float scaley = templ2D.scaley(qbin);
661  float offsetx = templ2D.offsetx(qbin);
662  float offsety = templ2D.offsety(qbin);
663 
664  // This 2D code has the origin (0,0) at the lower left edge of the input cluster
665  // That is now pixel [shiftx,shifty] and the template reco convention is the middle
666  // of that pixel, so we need to correct
667 
668  xrec = x2D0[ipass] - xpos[shiftx] - offsetx;
669  yrec = y2D0[ipass] - ypos[shifty] - offsety;
670  if (xerr2[ipass] > 0.f) {
671  sigmax = scalex * sqrt(xerr2[ipass]);
672  if (sigmax < 3.f)
673  sigmax = 3.f;
674  } else {
675  sigmax = 10000.f;
676  }
677  if (yerr2[ipass] > 0.f) {
678  sigmay = scaley * sqrt(yerr2[ipass]);
679  if (sigmay < 3.f)
680  sigmay = 3.f;
681  } else {
682  sigmay = 10000.f;
683  }
684  if (id >= 0) { //if id < 0 bypass interpolation (used in calibration)
685  // Do chi2 probability calculation
686  double meanxy = (double)(npixel * templ2D.chi2ppix());
687  double chi2scale = (double)templ2D.chi2scale();
688  if (meanxy < 0.01) {
689  meanxy = 0.01;
690  }
691  double hndof = meanxy / 2.f;
692  double hchi2 = chi2scale * chi2min[ipass] / 2.f;
693  probxy = (float)(1. - TMath::Gamma(hndof, hchi2));
694  // Do the charge probability
695  float mpv = templ2D.mpvvav();
696  float sigmaQ = templ2D.sigmavav();
697  float kappa = templ2D.kappavav();
698  float xvav = (qtotal / qtfrac0[ipass] - mpv) / sigmaQ;
699  float beta2 = 1.f;
700  // VVIObj is a private port of CERNLIB VVIDIS
701  VVIObjF vvidist(kappa, beta2, 1);
702  float prvav = vvidist.fcn(xvav);
703  probQ = 1.f - prvav;
704  } else {
705  probxy = chi2min[ipass];
706  npixels = npixel;
707  probQ = 0.f;
708  }
709 
710  return 0;
711 } // PixelTempReco2D
712 
714  float cotalpha,
715  float cotbeta,
716  float locBz,
717  float locBx,
718  int edgeflagy,
719  int edgeflagx,
720  ClusMatrix& cluster,
721  SiPixelTemplate2D& templ2D,
722  float& yrec,
723  float& sigmay,
724  float& xrec,
725  float& sigmax,
726  float& probxy,
727  float& probQ,
728  int& qbin,
729  float& deltay)
730 
731 {
732  // Local variables
733  int npixels;
735  cotalpha,
736  cotbeta,
737  locBz,
738  locBx,
739  edgeflagy,
740  edgeflagx,
741  cluster,
742  templ2D,
743  yrec,
744  sigmay,
745  xrec,
746  sigmax,
747  probxy,
748  probQ,
749  qbin,
750  deltay,
751  npixels);
752 } // PixelTempReco2D
#define T2HYP1
float xsize()
pixel x-size (microns)
bool xytemp(float xhit, float yhit, bool ydouble[21+2], bool xdouble[13+2], float template2d[13+2][21+2], bool dervatives, float dpdx2d[2][13+2][21+2], float &QTemplate)
float chi2ppix()
average chi^2 per struck pixel
int PixelTempReco2D(int id, float cotalpha, float cotbeta, float locBz, float locBx, int edgeflagy, int edgeflagx, ClusMatrix &cluster, SiPixelTemplate2D &templ, float &yrec, float &sigmay, float &xrec, float &sigmax, float &probxy, float &probQ, int &qbin, float &deltay, int &npixel)
void xysigma2(float qpixel, int index, float &xysig2)
static const int maxpix
const Int_t ysize
float s50()
1/2 of the pixel threshold signal in adc units
float offsetx(int i)
x-offset in 4 charge bins
#define BXM2
T sqrt(T t)
Definition: SSEVec.h:19
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
#define BYM2
float scalex(int i)
x-error scale factor in 4 charge bins
float chi2scale()
scale factor for chi^2 distribution
#define THYP1
float fcn(float x) const
Definition: VVIObjF.cc:141
float lorxdrift()
signed lorentz x-width (microns)
bool interpolate(int id, float cotalpha, float cotbeta, float locBz, float locBx)
for(Iditer=Id.begin();Iditer!=Id.end();Iditer++)
float mpvvav()
most probable Q in Vavilov distribution
DecomposeProduct< arg, typename Div::arg > D
Definition: Factorize.h:141
float kappavav()
kappa parameter in Vavilov distribution
float pixmax()
maximum pixel charge
float lorydrift()
signed lorentz y-width (microns)
float sxymax()
max pixel signal for pixel error calculation
float ysize()
pixel y-size (microns)
float qscale()
charge scaling factor
float qavg()
average cluster charge for this set of track angles
float fbin(int i)
Return lower bound of Qbin definition.
tuple cout
Definition: gather_cfg.py:144
float offsety(int i)
y-offset in 4 charge bins
const Int_t xsize
float clsleny()
cluster y-size
#define THXP1
float sigmavav()
scale factor in Vavilov distribution
float scaley(int i)
y-error scale factor in 4 charge bins