CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_4_5_patch3/src/RecoLocalTracker/SiPixelRecHits/plugins/SiPixelTemplateReco.cc

Go to the documentation of this file.
00001 //
00002 //  SiPixelTemplateReco.cc (Version 8.11)
00003 //
00004 //  Add goodness-of-fit to algorithm, include single pixel clusters in chi2 calculation
00005 //  Try "decapitation" of large single pixels
00006 //  Add correction for (Q_F-Q_L)/(Q_F+Q_L) bias
00007 //  Add cot(beta) reflection to reduce y-entries and more sophisticated x-interpolation
00008 //  Fix small double pixel bug with decapitation (2.41 5-Mar-2007).
00009 //  Fix pseudopixel bug causing possible memory overwrite (2.42 12-Mar-2007)
00010 //  Adjust template binning to span 3 (or 4) central pixels and implement improved (faster) chi2min search
00011 //  Replace internal containers with static arrays
00012 //  Add external threshold to calls to ysigma2 and xsigma2, use sorted signal heights to guarrantee min clust size = 2
00013 //  Use denser search over larger bin range for clusters with big pixels.
00014 //  Use single calls to template object to load template arrays (had been many)
00015 //  Add speed switch to trade-off speed and robustness
00016 //  Add qmin and re-define qbin to flag low-q clusters
00017 //  Add qscale to match charge scales
00018 //  Return error if no pixels in cluster
00019 //  Replace 4 cout's with LogError's
00020 //  Add LogDebug I/O to report various common errors
00021 //  Incorporate "cluster repair" to handle dead pixels
00022 //  Take truncation size from new pixmax information
00023 //  Change to allow template sizes to be changed at compile time
00024 //  Move interpolation range error to LogDebug
00025 //  Add qbin = 5 and change 1-pixel probability to use new template info
00026 //  Add floor for probabilities (no exact zeros)
00027 //  Replace asserts with exceptions in CMSSW
00028 //  Change calling sequence to handle cot(beta)<0 for FPix cosmics
00029 //
00030 //  V7.00 - Decouple BPix and FPix information into separate templates
00031 //  Pass all containers by alias to prevent excessive cpu-usage (V7.01)
00032 //  Slightly modify search bin range to avoid problem with single pixel clusters + large Lorentz drift (V7.02)
00033 //
00034 //  V8.00 - Add 2D probabilities, take pixel sizes from the template
00035 //  V8.05 - Shift 2-D cluster to center on the buffer
00036 //  V8.06 - Add locBz to the 2-D template (causes failover to the simple template when the cotbeta-locBz correlation is incorrect ... ie for non-IP tracks)
00037 //        - include minimum value for prob2D (1.e-30)
00038 //  V8.07 - Tune 2-d probability: consider only pixels above threshold and use threshold value for zero signal pixels (non-zero template)
00039 //  V8.10 - Remove 2-d probability for ineffectiveness and replace with simple cluster charge probability
00040 //  V8.11 - Change probQ to upper tail probability always (rather than two-sided tail probability)
00041 //
00042 //
00043 //  Created by Morris Swartz on 10/27/06.
00044 //  Copyright 2006 __TheJohnsHopkinsUniversity__. All rights reserved.
00045 //
00046 //
00047 
00048 #include <math.h>
00049 #include <algorithm>
00050 #include <vector>
00051 #include <utility>
00052 #include <iostream>
00053 // ROOT::Math has a c++ function that does the probability calc, but only in v5.12 and later
00054 #include "TMath.h"
00055 #include "Math/DistFunc.h"
00056 // Use current version of gsl instead of ROOT::Math
00057 //#include <gsl/gsl_cdf.h>
00058 
00059 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
00060 #include "SiPixelTemplateReco.h"
00061 #include "VVIObj.h"
00062 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00063 #define LOGERROR(x) edm::LogError(x)
00064 #define LOGDEBUG(x) LogDebug(x)
00065 static int theVerboseLevel = 2;
00066 #define ENDL " "
00067 #include "FWCore/Utilities/interface/Exception.h"
00068 #else
00069 #include "SiPixelTemplateReco.h"
00070 #include "VVIObj.h"
00071 //static int theVerboseLevel = {2};
00072 #define LOGERROR(x) std::cout << x << ": "
00073 #define LOGDEBUG(x) std::cout << x << ": "
00074 #define ENDL std::endl
00075 #endif
00076 
00077 using namespace SiPixelTemplateReco;
00078 
00079 // *************************************************************************************************************************************
00119 // *************************************************************************************************************************************
00120 int SiPixelTemplateReco::PixelTempReco2D(int id, float cotalpha, float cotbeta, float locBz, array_2d& clust, 
00121                     std::vector<bool>& ydouble, std::vector<bool>& xdouble, 
00122                     SiPixelTemplate& templ, 
00123                     float& yrec, float& sigmay, float& proby, float& xrec, float& sigmax, float& probx, int& qbin, int speed, bool deadpix, std::vector<std::pair<int, int> >& zeropix,
00124                          float& probQ)
00125                         
00126 {
00127     // Local variables 
00128   int i, j, k, minbin, binl, binh, binq, midpix, fypix, nypix, lypix, logypx;
00129   int fxpix, nxpix, lxpix, logxpx, shifty, shiftx, nyzero[TYSIZE];
00130   int nclusx, nclusy;
00131   int deltaj, jmin, jmax, fxbin, lxbin, fybin, lybin, djy, djx;
00132   int fypix2D, lypix2D, fxpix2D, lxpix2D;
00133   float sythr, sxthr, rnorm, delta, sigma, sigavg, pseudopix, qscale, q50;
00134   float ss2, ssa, sa2, ssba, saba, sba2, rat, fq, qtotal, qpixel;
00135   float originx, originy, qfy, qly, qfx, qlx, bias, maxpix, minmax;
00136   double chi2x, meanx, chi2y, meany, chi2ymin, chi2xmin, chi21max;
00137   double hchi2, hndof, prvav, mpv, sigmaQ, kappa, xvav, beta2;
00138   float ytemp[41][BYSIZE], xtemp[41][BXSIZE], ysum[BYSIZE], xsum[BXSIZE], ysort[BYSIZE], xsort[BXSIZE];
00139   float chi2ybin[41], chi2xbin[41], ysig2[BYSIZE], xsig2[BXSIZE];
00140   float yw2[BYSIZE], xw2[BXSIZE],  ysw[BYSIZE], xsw[BXSIZE];
00141   bool yd[BYSIZE], xd[BXSIZE], anyyd, anyxd, calc_probQ, use_VVIObj;
00142   float ysize, xsize;
00143   const float probmin={1.110223e-16};
00144   const float probQmin={1.e-5};
00145         
00146 // The minimum chi2 for a valid one pixel cluster = pseudopixel contribution only
00147 
00148   const double mean1pix={0.100}, chi21min={0.160};
00149   
00150   // First, interpolate the template needed to analyze this cluster     
00151   // check to see of the track direction is in the physical range of the loaded template
00152   
00153   if(!templ.interpolate(id, cotalpha, cotbeta, locBz)) {
00154     if (theVerboseLevel > 2) {LOGDEBUG("SiPixelTemplateReco") << "input cluster direction cot(alpha) = " << cotalpha << ", cot(beta) = " << cotbeta<< ", local B_z = " << locBz << ", template ID = " << id << ", no reconstruction performed" << ENDL;}        
00155     return 20;
00156   }
00157   
00158   // Make a local copy of the cluster container so that we can muck with it
00159   
00160   array_2d cluster = clust;
00161   
00162   // Check to see if Q probability is selected
00163   
00164   calc_probQ = false;
00165   use_VVIObj = false;
00166   if(speed < 0) {
00167     calc_probQ = true;
00168     if(speed < -1) use_VVIObj = true;
00169     speed = 0;
00170   }
00171   
00172   if(speed > 3) {
00173     calc_probQ = true;
00174     if(speed < 5) use_VVIObj = true;
00175     speed = 3;
00176   }
00177   
00178   // Get pixel dimensions from the template (to allow multiple detectors in the future)
00179   
00180   xsize = templ.xsize();
00181   ysize = templ.ysize();
00182   
00183   // Define size of pseudopixel
00184   
00185   q50 = templ.s50();
00186   pseudopix = 0.2*q50;
00187   
00188   // Get charge scaling factor
00189   
00190   qscale = templ.qscale();
00191   
00192   // Check that the cluster container is (up to) a 7x21 matrix and matches the dimensions of the double pixel flags
00193   
00194   if(cluster.num_dimensions() != 2) {
00195     LOGERROR("SiPixelTemplateReco") << "input cluster container (BOOST Multiarray) has wrong number of dimensions" << ENDL;     
00196     return 3;
00197   }
00198   nclusx = (int)cluster.shape()[0];
00199   nclusy = (int)cluster.shape()[1];
00200   if(nclusx != (int)xdouble.size()) {
00201     LOGERROR("SiPixelTemplateReco") << "input cluster container x-size is not equal to double pixel flag container size" << ENDL;       
00202     return 4;
00203   }
00204   if(nclusy != (int)ydouble.size()) {
00205     LOGERROR("SiPixelTemplateReco") << "input cluster container y-size is not equal to double pixel flag container size" << ENDL;       
00206     return 5;
00207   }
00208   
00209   // enforce maximum size       
00210   
00211   if(nclusx > TXSIZE) {nclusx = TXSIZE;}
00212   if(nclusy > TYSIZE) {nclusy = TYSIZE;}
00213   
00214   // First, rescale all pixel charges       
00215   
00216   for(j=0; j<nclusx; ++j) 
00217     for(i=0; i<nclusy; ++i) 
00218       if(cluster[j][i] > 0) {cluster[j][i] *= qscale;}
00219     
00220   
00221   // Next, sum the total charge and "decapitate" big pixels         
00222   
00223   qtotal = 0.;
00224   minmax = templ.pixmax();
00225   for(i=0; i<nclusy; ++i) {
00226     maxpix = minmax;
00227     if(ydouble[i]) {maxpix *=2.;}
00228     for(j=0; j<nclusx; ++j) {
00229       qtotal += cluster[j][i];
00230       if(cluster[j][i] > maxpix) {cluster[j][i] = maxpix;}
00231     }
00232   }
00233   
00234   // Do the cluster repair here 
00235   
00236   if(deadpix) {
00237     fypix = BYM3; lypix = -1;
00238     for(i=0; i<nclusy; ++i) {
00239       ysum[i] = 0.; nyzero[i] = 0;
00240       // Do preliminary cluster projection in y
00241       for(j=0; j<nclusx; ++j) {
00242         ysum[i] += cluster[j][i];
00243       }
00244       if(ysum[i] > 0.) {
00245         // identify ends of cluster to determine what the missing charge should be
00246         if(i < fypix) {fypix = i;}
00247         if(i > lypix) {lypix = i;}
00248       }
00249     }
00250     
00251     // Now loop over dead pixel list and "fix" everything       
00252     
00253     //First see if the cluster ends are redefined and that we have only one dead pixel per column
00254     
00255     std::vector<std::pair<int, int> >::const_iterator zeroIter = zeropix.begin(), zeroEnd = zeropix.end();
00256     for ( ; zeroIter != zeroEnd; ++zeroIter ) {
00257       i = zeroIter->second;
00258       if(i<0 || i>TYSIZE-1) {LOGERROR("SiPixelTemplateReco") << "dead pixel column y-index " << i << ", no reconstruction performed" << ENDL;   
00259         return 11;}
00260       
00261       // count the number of dead pixels in each column
00262       ++nyzero[i];
00263       // allow them to redefine the cluster ends
00264       if(i < fypix) {fypix = i;}
00265       if(i > lypix) {lypix = i;}
00266     }
00267     
00268     nypix = lypix-fypix+1;
00269     
00270     // 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
00271     
00272     for (zeroIter = zeropix.begin(); zeroIter != zeroEnd; ++zeroIter ) {           
00273       i = zeroIter->second; j = zeroIter->first;
00274       if(j<0 || j>TXSIZE-1) {LOGERROR("SiPixelTemplateReco") << "dead pixel column x-index " << j << ", no reconstruction performed" << ENDL;   
00275         return 12;}
00276       if((i == fypix || i == lypix) && nypix > 1) {maxpix = templ.symax()/2.;} else {maxpix = templ.symax();}
00277       if(ydouble[i]) {maxpix *=2.;}
00278       if(nyzero[i] > 0 && nyzero[i] < 3) {qpixel = (maxpix - ysum[i])/(float)nyzero[i];} else {qpixel = 1.;}
00279       if(qpixel < 1.) {qpixel = 1.;}
00280       cluster[j][i] = qpixel;
00281       // Adjust the total cluster charge to reflect the charge of the "repaired" cluster
00282       qtotal += qpixel;
00283     }
00284     // End of cluster repair section
00285   } 
00286   
00287   // Next, make y-projection of the cluster and copy the double pixel flags into a 25 element container         
00288   
00289   for(i=0; i<BYSIZE; ++i) { ysum[i] = 0.; yd[i] = false;}
00290   k=0;
00291   anyyd = false;
00292   for(i=0; i<nclusy; ++i) {
00293     for(j=0; j<nclusx; ++j) {
00294       ysum[k] += cluster[j][i];
00295     }
00296     
00297     // If this is a double pixel, put 1/2 of the charge in 2 consective single pixels  
00298     
00299     if(ydouble[i]) {
00300       ysum[k] /= 2.;
00301       ysum[k+1] = ysum[k];
00302       yd[k] = true;
00303       yd[k+1] = false;
00304       k=k+2;
00305       anyyd = true;
00306     } else {
00307       yd[k] = false;
00308       ++k;
00309     }
00310     if(k > BYM1) {break;}
00311   }
00312   
00313   // Next, make x-projection of the cluster and copy the double pixel flags into an 11 element container         
00314   
00315   for(i=0; i<BXSIZE; ++i) { xsum[i] = 0.; xd[i] = false;}
00316   k=0;
00317   anyxd = false;
00318   for(j=0; j<nclusx; ++j) {
00319     for(i=0; i<nclusy; ++i) {
00320       xsum[k] += cluster[j][i];
00321     }
00322     
00323     // If this is a double pixel, put 1/2 of the charge in 2 consective single pixels  
00324     
00325     if(xdouble[j]) {
00326       xsum[k] /= 2.;
00327       xsum[k+1] = xsum[k];
00328       xd[k]=true;
00329       xd[k+1]=false;
00330       k=k+2;
00331       anyxd = true;
00332     } else {
00333       xd[k]=false;
00334       ++k;
00335     }
00336     if(k > BXM1) {break;}
00337   }
00338   
00339   // next, identify the y-cluster ends, count total pixels, nypix, and logical pixels, logypx   
00340   
00341   fypix=-1;
00342   nypix=0;
00343   lypix=0;
00344   logypx=0;
00345   for(i=0; i<BYSIZE; ++i) {
00346     if(ysum[i] > 0.) {
00347       if(fypix == -1) {fypix = i;}
00348       if(!yd[i]) {
00349         ysort[logypx] = ysum[i];
00350         ++logypx;
00351       }
00352       ++nypix;
00353       lypix = i;
00354     }
00355   }
00356   
00357   //    dlengthy = (float)nypix - templ.clsleny();
00358   
00359   // Make sure cluster is continuous
00360   
00361   if((lypix-fypix+1) != nypix || nypix == 0) { 
00362     LOGDEBUG("SiPixelTemplateReco") << "y-length of pixel cluster doesn't agree with number of pixels above threshold" << ENDL;
00363     if (theVerboseLevel > 2) {
00364       LOGDEBUG("SiPixelTemplateReco") << "ysum[] = ";
00365       for(i=0; i<BYSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << ysum[i] << ", ";}           
00366       LOGDEBUG("SiPixelTemplateReco") << ysum[BYSIZE-1] << ENDL;
00367     }
00368     
00369     return 1; 
00370   }
00371   
00372   // If cluster is longer than max template size, technique fails
00373   
00374   if(nypix > TYSIZE) { 
00375     LOGDEBUG("SiPixelTemplateReco") << "y-length of pixel cluster is larger than maximum template size" << ENDL;
00376     if (theVerboseLevel > 2) {
00377       LOGDEBUG("SiPixelTemplateReco") << "ysum[] = ";
00378       for(i=0; i<BYSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << ysum[i] << ", ";}           
00379       LOGDEBUG("SiPixelTemplateReco") << ysum[BYSIZE-1] << ENDL;
00380     }
00381     
00382     return 6; 
00383   }
00384   
00385   // Remember these numbers for later
00386   
00387   fypix2D = fypix;
00388   lypix2D = lypix;
00389   
00390   // next, center the cluster on pixel 12 if necessary   
00391   
00392   midpix = (fypix+lypix)/2;
00393   shifty = BHY - midpix;
00394   if(shifty > 0) {
00395     for(i=lypix; i>=fypix; --i) {
00396       ysum[i+shifty] = ysum[i];
00397       ysum[i] = 0.;
00398       yd[i+shifty] = yd[i];
00399       yd[i] = false;
00400     }
00401   } else if (shifty < 0) {
00402     for(i=fypix; i<=lypix; ++i) {
00403       ysum[i+shifty] = ysum[i];
00404       ysum[i] = 0.;
00405       yd[i+shifty] = yd[i];
00406       yd[i] = false;
00407     }
00408   }
00409   lypix +=shifty;
00410   fypix +=shifty;
00411   
00412   // If the cluster boundaries are OK, add pesudopixels, otherwise quit
00413   
00414   if(fypix > 1 && fypix < BYM2) {
00415     ysum[fypix-1] = pseudopix;
00416     ysum[fypix-2] = pseudopix;
00417   } else {return 8;}
00418   if(lypix > 1 && lypix < BYM2) {
00419     ysum[lypix+1] = pseudopix;  
00420     ysum[lypix+2] = pseudopix;
00421   } else {return 8;}
00422   
00423   // finally, determine if pixel[0] is a double pixel and make an origin correction if it is   
00424   
00425   if(ydouble[0]) {
00426     originy = -0.5;
00427   } else {
00428     originy = 0.;
00429   }
00430   
00431   // next, identify the x-cluster ends, count total pixels, nxpix, and logical pixels, logxpx   
00432   
00433   fxpix=-1;
00434   nxpix=0;
00435   lxpix=0;
00436   logxpx=0;
00437   for(i=0; i<BXSIZE; ++i) {
00438     if(xsum[i] > 0.) {
00439       if(fxpix == -1) {fxpix = i;}
00440       if(!xd[i]) {
00441         xsort[logxpx] = xsum[i];
00442         ++logxpx;
00443       }
00444       ++nxpix;
00445       lxpix = i;
00446     }
00447   }
00448   
00449   //    dlengthx = (float)nxpix - templ.clslenx();
00450   
00451   // Make sure cluster is continuous
00452   
00453   if((lxpix-fxpix+1) != nxpix) { 
00454     
00455     LOGDEBUG("SiPixelTemplateReco") << "x-length of pixel cluster doesn't agree with number of pixels above threshold" << ENDL;
00456     if (theVerboseLevel > 2) {
00457       LOGDEBUG("SiPixelTemplateReco") << "xsum[] = ";
00458       for(i=0; i<BXSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << xsum[i] << ", ";}           
00459       LOGDEBUG("SiPixelTemplateReco") << ysum[BXSIZE-1] << ENDL;
00460     }
00461     
00462     return 2; 
00463   }
00464   
00465   // If cluster is longer than max template size, technique fails
00466   
00467   if(nxpix > TXSIZE) { 
00468     
00469     LOGDEBUG("SiPixelTemplateReco") << "x-length of pixel cluster is larger than maximum template size" << ENDL;
00470     if (theVerboseLevel > 2) {
00471       LOGDEBUG("SiPixelTemplateReco") << "xsum[] = ";
00472       for(i=0; i<BXSIZE-1; ++i) {LOGDEBUG("SiPixelTemplateReco") << xsum[i] << ", ";}           
00473       LOGDEBUG("SiPixelTemplateReco") << ysum[BXSIZE-1] << ENDL;
00474     }
00475     
00476     return 7; 
00477   }
00478   
00479   // Remember these numbers for later
00480   
00481   fxpix2D = fxpix;
00482   lxpix2D = lxpix;
00483   
00484   // next, center the cluster on pixel 5 if necessary   
00485   
00486   midpix = (fxpix+lxpix)/2;
00487   shiftx = BHX - midpix;
00488   if(shiftx > 0) {
00489     for(i=lxpix; i>=fxpix; --i) {
00490       xsum[i+shiftx] = xsum[i];
00491       xsum[i] = 0.;
00492       xd[i+shiftx] = xd[i];
00493       xd[i] = false;
00494     }
00495   } else if (shiftx < 0) {
00496     for(i=fxpix; i<=lxpix; ++i) {
00497       xsum[i+shiftx] = xsum[i];
00498       xsum[i] = 0.;
00499       xd[i+shiftx] = xd[i];
00500       xd[i] = false;
00501     }
00502   }
00503   lxpix +=shiftx;
00504   fxpix +=shiftx;
00505   
00506   // If the cluster boundaries are OK, add pesudopixels, otherwise quit
00507   
00508   if(fxpix > 1 && fxpix < BXM2) {
00509     xsum[fxpix-1] = pseudopix;
00510     xsum[fxpix-2] = pseudopix;
00511   } else {return 9;}
00512   if(lxpix > 1 && lxpix < BXM2) {
00513     xsum[lxpix+1] = pseudopix;
00514     xsum[lxpix+2] = pseudopix;
00515   } else {return 9;}
00516   
00517   // finally, determine if pixel[0] is a double pixel and make an origin correction if it is   
00518   
00519   if(xdouble[0]) {
00520     originx = -0.5;
00521   } else {
00522     originx = 0.;
00523   }
00524   
00525   // uncertainty and final corrections depend upon total charge bin        
00526   
00527   fq = qtotal/templ.qavg();
00528   if(fq > 1.5) {
00529     binq=0;
00530   } else {
00531     if(fq > 1.0) {
00532       binq=1;
00533     } else {
00534       if(fq > 0.85) {
00535         binq=2;
00536       } else {
00537         binq=3;
00538       }
00539     }
00540   }
00541   
00542   // Return the charge bin via the parameter list unless the charge is too small (then flag it)
00543   
00544   qbin = binq;
00545   if(!deadpix && qtotal < 0.95*templ.qmin()) {qbin = 5;} else {
00546     if(!deadpix && qtotal < 0.95*templ.qmin(1)) {qbin = 4;}
00547   }
00548   if (theVerboseLevel > 9) {
00549     LOGDEBUG("SiPixelTemplateReco") <<
00550       "ID = " << id <<  
00551       " cot(alpha) = " << cotalpha << " cot(beta) = " << cotbeta << 
00552       " nclusx = " << nclusx << " nclusy = " << nclusy << ENDL;
00553   }
00554   
00555   
00556   // Next, copy the y- and x-templates to local arrays
00557   
00558   // First, decide on chi^2 min search parameters
00559   
00560 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
00561   if(speed < 0 || speed > 3) {
00562     throw cms::Exception("DataCorrupt") << "SiPixelTemplateReco::PixelTempReco2D called with illegal speed = " << speed << std::endl;
00563   }
00564 #else
00565   assert(speed >= 0 && speed < 4);
00566 #endif
00567   fybin = 2; lybin = 38; fxbin = 2; lxbin = 38; djy = 1; djx = 1;
00568   if(speed > 0) {
00569     fybin = 8; lybin = 32;
00570     if(yd[fypix]) {fybin = 4; lybin = 36;}
00571     if(lypix > fypix) {
00572       if(yd[lypix-1]) {fybin = 4; lybin = 36;}
00573     }
00574     fxbin = 8; lxbin = 32;
00575     if(xd[fxpix]) {fxbin = 4; lxbin = 36;}
00576     if(lxpix > fxpix) {
00577       if(xd[lxpix-1]) {fxbin = 4; lxbin = 36;}
00578     }
00579   }
00580   
00581   if(speed > 1) { 
00582     djy = 2; djx = 2;
00583     if(speed > 2) {
00584       if(!anyyd) {djy = 4;}
00585       if(!anyxd) {djx = 4;}
00586     }
00587   }
00588   
00589   if (theVerboseLevel > 9) {
00590     LOGDEBUG("SiPixelTemplateReco") <<
00591       "fypix " << fypix << " lypix = " << lypix << 
00592       " fybin = " << fybin << " lybin = " << lybin << 
00593       " djy = " << djy << " logypx = " << logypx << ENDL;
00594     LOGDEBUG("SiPixelTemplateReco") <<
00595       "fxpix " << fxpix << " lxpix = " << lxpix << 
00596       " fxbin = " << fxbin << " lxbin = " << lxbin << 
00597       " djx = " << djx << " logxpx = " << logxpx << ENDL;
00598   }
00599   
00600   // Now do the copies
00601   
00602   templ.ytemp(fybin, lybin, ytemp);
00603   
00604   templ.xtemp(fxbin, lxbin, xtemp);
00605   
00606   // Do the y-reconstruction first 
00607   
00608   // Apply the first-pass template algorithm to all clusters
00609   
00610   // Modify the template if double pixels are present   
00611   
00612   if(nypix > logypx) {
00613     i=fypix;
00614     while(i < lypix) {
00615       if(yd[i] && !yd[i+1]) {
00616         for(j=fybin; j<=lybin; ++j) {
00617           
00618           // Sum the adjacent cells and put the average signal in both   
00619           
00620           sigavg = (ytemp[j][i] +  ytemp[j][i+1])/2.;
00621           ytemp[j][i] = sigavg;
00622           ytemp[j][i+1] = sigavg;
00623         }
00624         i += 2;
00625       } else {
00626         ++i;
00627       }
00628     }
00629   }     
00630   
00631   // Define the maximum signal to allow before de-weighting a pixel 
00632   
00633   sythr = 1.1*(templ.symax());
00634   
00635   // Make sure that there will be at least two pixels that are not de-weighted 
00636   
00637   std::sort(&ysort[0], &ysort[logypx]);
00638   if(logypx == 1) {sythr = 1.01f*ysort[0];} else {
00639     if (ysort[1] > sythr) { sythr = 1.01f*ysort[1]; }
00640   }
00641   
00642   // Evaluate pixel-by-pixel uncertainties (weights) for the templ analysis 
00643   
00644   // for(i=0; i<BYSIZE; ++i) { ysig2[i] = 0.;}
00645   templ.ysigma2(fypix, lypix, sythr, ysum, ysig2);
00646   
00647   // Find the template bin that minimizes the Chi^2 
00648   
00649   chi2ymin = 1.e15;
00650   for(i=fybin; i<=lybin; ++i) { 
00651     chi2ybin[i] = -1.e15f;
00652   }
00653   ss2 = 0.f;
00654   for(i=fypix-2; i<=lypix+2; ++i) {
00655     yw2[i] = 1.f/ysig2[i];
00656     ysw[i] = ysum[i]*yw2[i];
00657     ss2 += ysum[i]*ysw[i];
00658   }
00659   minbin = -1;
00660   deltaj = djy;
00661   jmin = fybin;
00662   jmax = lybin;
00663   while(deltaj > 0) {
00664     for(j=jmin; j<=jmax; j+=deltaj) {
00665       if(chi2ybin[j] < -100.f) {
00666         ssa = 0.f;
00667         sa2 = 0.f;
00668         for(i=fypix-2; i<=lypix+2; ++i) {
00669           ssa += ysw[i]*ytemp[j][i];
00670           sa2 += ytemp[j][i]*ytemp[j][i]*yw2[i];
00671         }
00672         rat=ssa/ss2;
00673         if(rat <= 0.f) {LOGERROR("SiPixelTemplateReco") << "illegal chi2ymin normalization (1) = " << rat << ENDL; rat = 1.;}
00674         chi2ybin[j]=ss2-2.f*ssa/rat+sa2/(rat*rat);
00675       }
00676       if(chi2ybin[j] < chi2ymin) {
00677         chi2ymin = chi2ybin[j];
00678         minbin = j;
00679       }
00680     } 
00681     deltaj /= 2;
00682     if(minbin > fybin) {jmin = minbin - deltaj;} else {jmin = fybin;}
00683     if(minbin < lybin) {jmax = minbin + deltaj;} else {jmax = lybin;}
00684   }
00685   
00686   if (theVerboseLevel > 9) {
00687     LOGDEBUG("SiPixelTemplateReco") <<
00688       "minbin " << minbin << " chi2ymin = " << chi2ymin << ENDL;
00689   }
00690   
00691   // Do not apply final template pass to 1-pixel clusters (use calibrated offset) 
00692   
00693   if(logypx == 1) {
00694     
00695     if(nypix ==1) {
00696       delta = templ.dyone();
00697       sigma = templ.syone();
00698     } else {
00699       delta = templ.dytwo();
00700       sigma = templ.sytwo();
00701     }
00702     
00703     yrec = 0.5f*(fypix+lypix-2*shifty+2.f*originy)*ysize-delta;
00704     if(sigma <= 0.) {
00705       sigmay = 43.3f;
00706     } else {
00707       sigmay = sigma;
00708     }
00709     
00710     // Do probability calculation for one-pixel clusters
00711     
00712     chi21max = fmax(chi21min, (double)templ.chi2yminone());
00713     chi2ymin -=chi21max;
00714     if(chi2ymin < 0.) {chi2ymin = 0.;}
00715     //     proby = gsl_cdf_chisq_Q(chi2ymin, mean1pix);
00716     meany = fmax(mean1pix, (double)templ.chi2yavgone());
00717     hchi2 = chi2ymin/2.; hndof = meany/2.;
00718     proby = 1. - TMath::Gamma(hndof, hchi2);
00719     
00720   } else {
00721     
00722     // For cluster > 1 pix, make the second, interpolating pass with the templates 
00723     
00724     binl = minbin - 1;
00725     binh = binl + 2;
00726     if(binl < fybin) { binl = fybin;}
00727     if(binh > lybin) { binh = lybin;}     
00728     ssa = 0.;
00729     sa2 = 0.;
00730     ssba = 0.;
00731     saba = 0.;
00732     sba2 = 0.;
00733     for(i=fypix-2; i<=lypix+2; ++i) {
00734       ssa += ysw[i]*ytemp[binl][i];
00735       sa2 += ytemp[binl][i]*ytemp[binl][i]*yw2[i];
00736       ssba += ysw[i]*(ytemp[binh][i] - ytemp[binl][i]);
00737       saba += ytemp[binl][i]*(ytemp[binh][i] - ytemp[binl][i])*yw2[i];
00738       sba2 += (ytemp[binh][i] - ytemp[binl][i])*(ytemp[binh][i] - ytemp[binl][i])*yw2[i];
00739     }
00740     
00741     // rat is the fraction of the "distance" from template a to template b         
00742     
00743     rat=(ssba*ssa-ss2*saba)/(ss2*sba2-ssba*ssba);
00744     if(rat < 0.) {rat=0.;}
00745     if(rat > 1.) {rat=1.0;}
00746     rnorm = (ssa+rat*ssba)/ss2;
00747     
00748     // Calculate the charges in the first and last pixels
00749     
00750     qfy = ysum[fypix];
00751     if(yd[fypix]) {qfy+=ysum[fypix+1];}
00752     if(logypx > 1) {
00753       qly=ysum[lypix];
00754       if(yd[lypix-1]) {qly+=ysum[lypix-1];}
00755     } else {
00756       qly = qfy;
00757     }
00758     
00759     //  Now calculate the mean bias correction and uncertainties
00760     
00761     float qyfrac = (qfy-qly)/(qfy+qly);
00762     bias = templ.yflcorr(binq,qyfrac)+templ.yavg(binq);
00763     
00764     // uncertainty and final correction depend upon charge bin     
00765     
00766     yrec = (0.125f*binl+BHY-2.5f+rat*(binh-binl)*0.125f-(float)shifty+originy)*ysize - bias;
00767     sigmay = templ.yrms(binq);
00768     
00769     // Do goodness of fit test in y  
00770     
00771     if(rnorm <= 0.) {LOGERROR("SiPixelTemplateReco") << "illegal chi2y normalization (2) = " << rnorm << ENDL; rnorm = 1.;}
00772     chi2y=ss2-2./rnorm*ssa-2./rnorm*rat*ssba+(sa2+2.*rat*saba+rat*rat*sba2)/(rnorm*rnorm)-templ.chi2ymin(binq);
00773     if(chi2y < 0.0) {chi2y = 0.0;}
00774     meany = templ.chi2yavg(binq);
00775     if(meany < 0.01) {meany = 0.01;}
00776     // gsl function that calculates the chi^2 tail prob for non-integral dof
00777     //     proby = gsl_cdf_chisq_Q(chi2y, meany);
00778     //     proby = ROOT::Math::chisquared_cdf_c(chi2y, meany);
00779     hchi2 = chi2y/2.; hndof = meany/2.;
00780     proby = 1. - TMath::Gamma(hndof, hchi2);
00781   }
00782   
00783   // Do the x-reconstruction next 
00784   
00785   // Apply the first-pass template algorithm to all clusters
00786   
00787   // Modify the template if double pixels are present 
00788   
00789   if(nxpix > logxpx) {
00790     i=fxpix;
00791     while(i < lxpix) {
00792       if(xd[i] && !xd[i+1]) {
00793         for(j=fxbin; j<=lxbin; ++j) {
00794           
00795           // Sum the adjacent cells and put the average signal in both   
00796           
00797           sigavg = (xtemp[j][i] +  xtemp[j][i+1])/2.;
00798           xtemp[j][i] = sigavg;
00799           xtemp[j][i+1] = sigavg;
00800         }
00801         i += 2;
00802       } else {
00803         ++i;
00804       }
00805     }
00806   }       
00807   
00808   // Define the maximum signal to allow before de-weighting a pixel 
00809   
00810   sxthr = 1.1f*templ.sxmax();
00811   
00812   // Make sure that there will be at least two pixels that are not de-weighted 
00813   std::sort(&xsort[0], &xsort[logxpx]);
00814   if(logxpx == 1) {sxthr = 1.01f*xsort[0];} else {
00815     if (xsort[1] > sxthr) { sxthr = 1.01f*xsort[1]; }
00816   }
00817   
00818   // Evaluate pixel-by-pixel uncertainties (weights) for the templ analysis 
00819   
00820   // for(i=0; i<BXSIZE; ++i) { xsig2[i] = 0.; }
00821   templ.xsigma2(fxpix, lxpix, sxthr, xsum, xsig2);
00822   
00823   // Find the template bin that minimizes the Chi^2 
00824   
00825   chi2xmin = 1.e15;
00826   for(i=fxbin; i<=lxbin; ++i) { chi2xbin[i] = -1.e15f;}
00827   ss2 = 0.f;
00828   for(i=fxpix-2; i<=lxpix+2; ++i) {
00829     xw2[i] = 1.f/xsig2[i];
00830     xsw[i] = xsum[i]*xw2[i];
00831     ss2 += xsum[i]*xsw[i];
00832   }
00833     
00834   minbin = -1;
00835   deltaj = djx;
00836   jmin = fxbin;
00837   jmax = lxbin;
00838   while(deltaj > 0) {
00839     for(j=jmin; j<=jmax; j+=deltaj) {
00840       if(chi2xbin[j] < -100.f) {
00841         ssa = 0.f;
00842         sa2 = 0.f;
00843         for(i=fxpix-2; i<=lxpix+2; ++i) {
00844           ssa += xsw[i]*xtemp[j][i];
00845           sa2 += xtemp[j][i]*xtemp[j][i]*xw2[i];
00846         }
00847         rat=ssa/ss2;
00848         if(rat <= 0.f) {LOGERROR("SiPixelTemplateReco") << "illegal chi2xmin normalization (1) = " << rat << ENDL; rat = 1.;}
00849         chi2xbin[j]=ss2-2.f*ssa/rat+sa2/(rat*rat);
00850       }
00851       if(chi2xbin[j] < chi2xmin) {
00852         chi2xmin = chi2xbin[j];
00853         minbin = j;
00854       }
00855     } 
00856     deltaj /= 2;
00857     if(minbin > fxbin) {jmin = minbin - deltaj;} else {jmin = fxbin;}
00858     if(minbin < lxbin) {jmax = minbin + deltaj;} else {jmax = lxbin;}
00859   }
00860   
00861   if (theVerboseLevel > 9) {
00862     LOGDEBUG("SiPixelTemplateReco") <<
00863       "minbin " << minbin << " chi2xmin = " << chi2xmin << ENDL;
00864   }
00865   
00866   // Do not apply final template pass to 1-pixel clusters (use calibrated offset)
00867   
00868   if(logxpx == 1) {
00869     
00870     if(nxpix ==1) {
00871       delta = templ.dxone();
00872       sigma = templ.sxone();
00873     } else {
00874       delta = templ.dxtwo();
00875       sigma = templ.sxtwo();
00876     }
00877     xrec = 0.5*(fxpix+lxpix-2*shiftx+2.*originx)*xsize-delta;
00878     if(sigma <= 0.) {
00879       sigmax = 28.9;
00880     } else {
00881       sigmax = sigma;
00882     }
00883     
00884     // Do probability calculation for one-pixel clusters
00885     
00886     chi21max = fmax(chi21min, (double)templ.chi2xminone());
00887     chi2xmin -=chi21max;
00888     if(chi2xmin < 0.) {chi2xmin = 0.;}
00889     meanx = fmax(mean1pix, (double)templ.chi2xavgone());
00890     hchi2 = chi2xmin/2.; hndof = meanx/2.;
00891     probx = 1. - TMath::Gamma(hndof, hchi2);
00892     
00893   } else {
00894     
00895     // Now make the second, interpolating pass with the templates 
00896     
00897     binl = minbin - 1;
00898     binh = binl + 2;
00899     if(binl < fxbin) { binl = fxbin;}
00900     if(binh > lxbin) { binh = lxbin;}     
00901     ssa = 0.;
00902     sa2 = 0.;
00903     ssba = 0.;
00904     saba = 0.;
00905     sba2 = 0.;
00906     for(i=fxpix-2; i<=lxpix+2; ++i) {
00907       ssa += xsw[i]*xtemp[binl][i];
00908       sa2 += xtemp[binl][i]*xtemp[binl][i]*xw2[i];
00909       ssba += xsw[i]*(xtemp[binh][i] - xtemp[binl][i]);
00910       saba += xtemp[binl][i]*(xtemp[binh][i] - xtemp[binl][i])*xw2[i];
00911       sba2 += (xtemp[binh][i] - xtemp[binl][i])*(xtemp[binh][i] - xtemp[binl][i])*xw2[i];
00912     }
00913     
00914     // rat is the fraction of the "distance" from template a to template b         
00915     
00916     rat=(ssba*ssa-ss2*saba)/(ss2*sba2-ssba*ssba);
00917     if(rat < 0.f) {rat=0.f;}
00918     if(rat > 1.f) {rat=1.0f;}
00919     rnorm = (ssa+rat*ssba)/ss2;
00920     
00921     // Calculate the charges in the first and last pixels
00922     
00923     qfx = xsum[fxpix];
00924     if(xd[fxpix]) {qfx+=xsum[fxpix+1];}
00925     if(logxpx > 1) {
00926       qlx=xsum[lxpix];
00927       if(xd[lxpix-1]) {qlx+=xsum[lxpix-1];}
00928     } else {
00929       qlx = qfx;
00930     }
00931     
00932     //  Now calculate the mean bias correction and uncertainties
00933     
00934     float qxfrac = (qfx-qlx)/(qfx+qlx);
00935     bias = templ.xflcorr(binq,qxfrac)+templ.xavg(binq);
00936     
00937     // uncertainty and final correction depend upon charge bin     
00938     
00939     xrec = (0.125f*binl+BHX-2.5f+rat*(binh-binl)*0.125f-(float)shiftx+originx)*xsize - bias;
00940     sigmax = templ.xrms(binq);
00941     
00942     // Do goodness of fit test in x  
00943     
00944     if(rnorm <= 0.) {LOGERROR("SiPixelTemplateReco") << "illegal chi2x normalization (2) = " << rnorm << ENDL; rnorm = 1.;}
00945     chi2x=ss2-2./rnorm*ssa-2./rnorm*rat*ssba+(sa2+2.*rat*saba+rat*rat*sba2)/(rnorm*rnorm)-templ.chi2xmin(binq);
00946     if(chi2x < 0.0) {chi2x = 0.0;}
00947     meanx = templ.chi2xavg(binq);
00948     if(meanx < 0.01) {meanx = 0.01;}
00949     // gsl function that calculates the chi^2 tail prob for non-integral dof
00950     //     probx = gsl_cdf_chisq_Q(chi2x, meanx);
00951     //     probx = ROOT::Math::chisquared_cdf_c(chi2x, meanx, trx0);
00952     hchi2 = chi2x/2.; hndof = meanx/2.;
00953     probx = 1. - TMath::Gamma(hndof, hchi2);
00954   }
00955   
00956   //  Don't return exact zeros for the probability
00957   
00958   if(proby < probmin) {proby = probmin;}
00959   if(probx < probmin) {probx = probmin;}
00960   
00961   //  Decide whether to generate a cluster charge probability
00962   
00963   if(calc_probQ) {
00964     
00965     // Calculate the Vavilov probability that the cluster charge is OK
00966     
00967     templ.vavilov_pars(mpv, sigmaQ, kappa);
00968 #ifndef SI_PIXEL_TEMPLATE_STANDALONE
00969     if((sigmaQ <=0.) || (mpv <= 0.) || (kappa < 0.01) || (kappa > 9.9)) {
00970       throw cms::Exception("DataCorrupt") << "SiPixelTemplateReco::Vavilov parameters mpv/sigmaQ/kappa = " << mpv << "/" << sigmaQ << "/" << kappa << std::endl;
00971     }
00972 #else
00973     assert((sigmaQ > 0.) && (mpv > 0.) && (kappa > 0.01) && (kappa < 10.));
00974 #endif
00975     xvav = ((double)qtotal-mpv)/sigmaQ;
00976     beta2 = 1.;
00977     if(use_VVIObj) {                    
00978       //  VVIObj is a private port of CERNLIB VVIDIS
00979       VVIObj vvidist(kappa, beta2, 1);
00980       prvav = vvidist.fcn(xvav);
00981 
00982      // std::cout << "vav: " << kappa << " " << xvav << " " << prvav
00983      //          << " " << TMath::VavilovI(xvav, kappa, beta2) << std::endl; 
00984 
00985     } else {
00986       //  Use faster but less accurate TMath Vavilov distribution function
00987       prvav = TMath::VavilovI(xvav, kappa, beta2);
00988     }
00989     //  Change to upper tail probability
00990     //          if(prvav > 0.5) prvav = 1. - prvav;
00991     //          probQ = (float)(2.*prvav);
00992     probQ = 1. - prvav;
00993     if(probQ < probQmin) {probQ = probQmin;}
00994   } else {
00995     probQ = -1;
00996   }
00997   
00998   return 0;
00999 } // PixelTempReco2D 
01000 
01001 // *************************************************************************************************************************************
01002 //  Overload parameter list for compatibility with older versions
01029 // *************************************************************************************************************************************
01030 int SiPixelTemplateReco::PixelTempReco2D(int id, float cotalpha, float cotbeta, float locBz, array_2d& cluster, 
01031                     std::vector<bool>& ydouble, std::vector<bool>& xdouble, 
01032                     SiPixelTemplate& templ, 
01033                     float& yrec, float& sigmay, float& proby, float& xrec, float& sigmax, float& probx, int& qbin, int speed,
01034                          float& probQ)
01035                         
01036 {
01037     // Local variables 
01038         const bool deadpix = false;
01039         std::vector<std::pair<int, int> > zeropix;
01040     
01041         return SiPixelTemplateReco::PixelTempReco2D(id, cotalpha, cotbeta, locBz, cluster, ydouble, xdouble, templ, 
01042                 yrec, sigmay, proby, xrec, sigmax, probx, qbin, speed, deadpix, zeropix, probQ);
01043 
01044 } // PixelTempReco2D
01045 
01046 // *************************************************************************************************************************************
01047 //  Overload parameter list for compatibility with older versions
01073 // *************************************************************************************************************************************
01074 int SiPixelTemplateReco::PixelTempReco2D(int id, float cotalpha, float cotbeta, array_2d& cluster, 
01075                                                                                  std::vector<bool>& ydouble, std::vector<bool>& xdouble, 
01076                                                                                  SiPixelTemplate& templ, 
01077                                                                                  float& yrec, float& sigmay, float& proby, float& xrec, float& sigmax, float& probx, int& qbin, int speed,
01078                                                                                  float& probQ)
01079 
01080 {
01081     // Local variables 
01082         const bool deadpix = false;
01083         std::vector<std::pair<int, int> > zeropix;
01084         float locBz = -1.;
01085         if(cotbeta < 0.) {locBz = -locBz;}
01086     
01087         return SiPixelTemplateReco::PixelTempReco2D(id, cotalpha, cotbeta, locBz, cluster, ydouble, xdouble, templ, 
01088                                                                                                 yrec, sigmay, proby, xrec, sigmax, probx, qbin, speed, deadpix, zeropix, probQ);
01089         
01090 } // PixelTempReco2D
01091 
01092 
01093 // *************************************************************************************************************************************
01094 //  Overload parameter list for compatibility with older versions
01117 // *************************************************************************************************************************************
01118 int SiPixelTemplateReco::PixelTempReco2D(int id, float cotalpha, float cotbeta, array_2d& cluster, 
01119                                                                                                           std::vector<bool>& ydouble, std::vector<bool>& xdouble, 
01120                                                                                                           SiPixelTemplate& templ, 
01121                                                                                                           float& yrec, float& sigmay, float& proby, float& xrec, float& sigmax, float& probx, int& qbin, int speed)
01122 
01123 {
01124         // Local variables 
01125         const bool deadpix = false;
01126         std::vector<std::pair<int, int> > zeropix;
01127         float locBz = -1.;
01128         if(cotbeta < 0.) {locBz = -locBz;}
01129         float probQ;
01130         if(speed < 0) speed = 0;
01131    if(speed > 3) speed = 3;
01132         
01133         return SiPixelTemplateReco::PixelTempReco2D(id, cotalpha, cotbeta, locBz, cluster, ydouble, xdouble, templ, 
01134                                                                                                                           yrec, sigmay, proby, xrec, sigmax, probx, qbin, speed, deadpix, zeropix, probQ);
01135         
01136 } // PixelTempReco2D