CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/RecoLocalTracker/SiPixelRecHits/src/SiPixelTemplateReco.cc

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