CMS 3D CMS Logo

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