Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

EmcGlSectorRec.cxx

Go to the documentation of this file.
00001 // Name: EmcGlSectorRec.h
00002 // Author: M. Volkov (RRC KI) Jan 27 2000
00003 // PbGl sector reconstruction
00004 
00005 //INCLUDECHECKER: Removed this line: #include <cmath>
00006 //INCLUDECHECKER: Removed this line: #include "gsl/gsl_math.h"
00007 #include "EmcGlSectorRec.h"
00008 #include "EmcCluster.h"
00009 
00010 // Define and initialize static members
00011 
00012 // Parameters for sigma in Hi2 calculations (p.36-37 v.3)
00013 float EmcGlSectorRec::fgEpar00 = 0.010;
00014 float EmcGlSectorRec::fgEpar0 = 0.01;
00015 float EmcGlSectorRec::fgEpar1 = 0.035;
00016 float EmcGlSectorRec::fgEpar2 = -0.035;
00017 // This is for PPLO mode !!!
00018 float EmcGlSectorRec::fgEpar3 = 0.;
00019 float EmcGlSectorRec::fgEpar4 = 1.0;
00020 
00021 float EmcGlSectorRec::fSin4T = 0.;
00022 
00023 float EmcGlSectorRec::fgConfLevel=0.01;
00024 
00025 // Parameters for sigma calculation in Chi2 analysis
00026 float const EmcGlSectorRec::fgSigEcorr0=2.25e-02;
00027 float const EmcGlSectorRec::fgSigEcorr1=1.43e-02;
00028 float const EmcGlSectorRec::fgSigAcorr0=7.20815e-02;
00029 float const EmcGlSectorRec::fgSigAcorr1=-3.22703e-01;
00030 
00031 // Parameters for threshold calculation in Chi2 analysis
00032 float const EmcGlSectorRec::fgCutEcorr0=2.1e-02;
00033 float const EmcGlSectorRec::fgCutEcorr1=0.009;
00034 
00035 // Parameters for coordinate correction
00036 float const EmcGlSectorRec::fgCoorPar00=0.1584384;
00037 float const EmcGlSectorRec::fgCoorPar01=0.1125;
00038 float const EmcGlSectorRec::fgCoorPar02=4.89856;
00039 float const EmcGlSectorRec::fgCoorPar03=2.42169e-01;
00040 float const EmcGlSectorRec::fgCoorPar10=0.4777;
00041 float const EmcGlSectorRec::fgCoorPar11=4.87463;
00042 float const EmcGlSectorRec::fgCoorPar12=1.23336e-01;
00043 float const EmcGlSectorRec::fgCoorPar20=3.28647;
00044 float const EmcGlSectorRec::fgCoorPar21=6.30741e-01;
00045 
00046 // EmcGlSectorRec member functions
00047 
00048 void 
00049 EmcGlSectorRec::Gamma(int nh, EmcModule* phit, float* pchi, float* pchi0,
00050                       float* pe1, float* px1, float* py1, float* pe2,
00051                       float* px2, float* py2, int &ndf)
00052 {
00053   // Tests for 1 or 2 photon hypothesis by minimizing the chi2.
00054   // If the energy of one of two showers is less then fgMinShowerEnergy 
00055   // they are merged
00056   //
00057   // Returns two shower parameters (pe1,px1,py1,pe2,px2,py2). 
00058   // If one shower hypothesis accepted -> *pe2=0
00059   // *pchi  - chi2 after splitting
00060   // *pchi0 - chi2 before splitting
00061   // ndf contains number of degrees of freedom (not equal to number of cluster
00062   // modules for PbGl).
00063 
00064   float e1, x1, y1, e2, x2, y2;
00065   float chi, chi0, chisave;
00066   int dof;
00067   float d2, xm2;
00068   const float zTG=100;
00069   const float xmcut=0.0015; // (GeV), for overlapping showers separation
00070 
00071   *pe1=0;
00072   *px1=0;
00073   *py1=0;
00074   *pe2=0;
00075   *px2=0;
00076   *py2=0;
00077 
00078   if(nh<=0) return;
00079 
00080   Mom1(nh, phit, &e1, &x1, &y1);
00081   *pe1=e1;     
00082 
00083   if( e1 <= 0 ) return;
00084   
00085   SetProfileParameters(0, e1, x1, y1);
00086 
00087   chisave = *pchi;
00088   chi = *pchi;
00089 
00090   // ClusterChisq parameter list changed MV 28.01.00
00091   chi0 = ClusterChisq(nh, phit, e1, x1, y1, ndf);
00092   dof = ndf; // nh->ndf MV 28.01.00
00093 
00094   // ndf=0 means the cluster's chi2 cannot be found; in this case chi0=0.
00095   if( dof < 1 ) dof=1;
00096   chi = chi0/dof;
00097   
00098   *pchi0 = chi;
00099   *pchi = chi;
00100   *px1 = x1;
00101   *py1 = y1;
00102   
00103   if( e1 <= fgMinShowerEnergy ) return;
00104 
00105   if( chi > chisave ) {
00106     TwoGamma(nh,phit,&chi,&e1,&x1,&y1,&e2,&x2,&y2);
00107     if( e2 > 0 ) {
00108       d2 = ((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))/zTG/zTG;
00109       xm2 = e1*e2*d2;
00110       if( xm2 > 0 ) xm2 = sqrt(xm2);
00111       if( xm2 > xmcut && e1 > fgMinShowerEnergy && e2 > fgMinShowerEnergy) {
00112         *pe1 = e1;
00113         *px1 = x1;
00114         *py1 = y1;
00115         *pe2 = e2;
00116         *px2 = x2;
00117         *py2 = y2;
00118         *pchi = chi;
00119       }
00120     }   
00121   }
00122 }
00123 
00124 float 
00125 EmcGlSectorRec::Chi2Limit(int ndf)
00126 {
00127   // Returns reduced chi2 correcponding to the current CL.
00128 
00129   if(ndf<1) return 0.;
00130   float chi2 = fgChi2Level[EmcCluster::min(ndf,50)-1];
00131   return chi2;
00132 
00133 }
00134 
00135 float 
00136 EmcGlSectorRec::Chi2Correct(float chi2, int ndf)
00137 {
00138 
00139   if(ndf<1) return 0.;
00140   return chi2;
00141 
00142 }
00143 
00144 void 
00145 EmcGlSectorRec::SetProfileParameters(int sectorID, float energy,
00146                                      float x, float y)
00147 {
00148   // z (horizontal) and y (vertical) coordinates wrt sector front face
00149   // reference frame. RF is tied to the module with index 0, i.e. lower left
00150   // corner of sector. z and y are in module units.
00151   // If sectorID<0 only energy-dependent parameters are calculated.
00152 
00153   float vx, vy, vz;
00154   float xVert, yVert, zVert;
00155 
00156   if(sectorID>=0){
00157 
00158     // Vertex coordinates in Sector coordinate system (in cm)
00159     GlobalToSector(fVx, fVy, fVz, &xVert, &yVert, &zVert);
00160     vz = -zVert;
00161     vy = y*fModSizey - yVert;
00162     vx = x*fModSizex - xVert;
00163 
00164     fSinTy=vy/sqrt(vy*vy+vz*vz);
00165     fSinTx=vx/sqrt(vx*vx+vz*vz);
00166 
00167     fSin4T = fabs((2*fSinTy-fSinTx)*(fSinTy-2*fSinTx)*(fSinTy-fSinTx)*(fSinTy-fSinTx));
00168 
00169     //angles in degrees
00170     fTheta=180.0/ M_PI * asin(sqrt(vx*vx+vy*vy)/sqrt(vx*vx+vy*vy+vz*vz));
00171     fPhi=180.0/ M_PI * (M_PI + atan2(vy, vx));
00172 
00173 #if 0
00174     cerr<<"Before 2nd pass"<<endl;
00175     cerr<<"fTheta="<<fTheta<<" ";
00176     cerr<<"fPhi="<<fPhi<<endl;
00177     cerr<<"fVx="<<fVx<<" fVy="<<fVy<<" fVz="<<fVz<<endl;
00178     cerr<<"xVert="<<xVert<<" yVert="<<yVert<<" zVert="<<zVert<<endl;
00179     cerr<<"                      y="<<y*fModSizey<<" x="<<x*fModSizex<<endl;
00180     cerr<<endl;
00181 #endif
00182 
00183     // ==========> Experimental 2nd pass <==========
00184     // As the angles of incidence are calculated based on COG, we have
00185     // a systematic shift in the corrected COG value. For 5 GeV/c electrons 
00186     // at 20 degrees the shift is ~1.5 mm (RMS of Xcorr-Xinc ~8 mm).
00187     // 2nd pass is aimed at eliminating this (small) problem.
00188     
00189     y*=fModSizey; // convert to cm
00190     x*=fModSizex;
00191     float xcorr, ycorr; // corrected values
00192     CorrectPosition(energy, x, y, &xcorr, &ycorr, false);
00193 
00194     // Recalculate angles
00195     vy = ycorr-yVert;
00196     vx = xcorr-xVert;
00197 
00198     fSinTy=vy/sqrt(vy*vy+vz*vz);
00199     fSinTx=vx/sqrt(vx*vx+vz*vz);
00200 
00201     //angles in degrees
00202     fTheta=180.0/ M_PI * asin(sqrt(vx*vx+vy*vy)/sqrt(vx*vx+vy*vy+vz*vz));
00203     fPhi=180.0/ M_PI * (M_PI + atan2(vy, vx));
00204     // ==========> End of experimental 2nd pass <==========
00205 #if 0
00206     cerr<<"After 2nd pass"<<endl;
00207     cerr<<"fTheta="<<fTheta<<" ";
00208     cerr<<"fPhi="<<fPhi<<endl;
00209     cerr<<"fVx="<<fVx<<" fVy="<<fVy<<" fVz="<<fVz<<endl;
00210     cerr<<"xVert="<<xVert<<" yVert="<<yVert<<" zVert="<<zVert<<endl;
00211     cerr<<"                      y="<<y*fModSizey<<" x="<<x*fModSizex<<endl;
00212     cerr<<endl;
00213 #endif
00214   }
00215 
00216   // Calculate coordinate transformation parameters
00217   fShift=ShiftFunc(energy, fTheta);
00218   fExc1=Sigma1Func(energy, fTheta);
00219   fExc2=Sigma2Func(energy, fTheta);
00220   
00221   // Parameters we need to pass to the shape function.
00222   fShapePars[0]=AFunc(energy, fTheta, fPhi);
00223   fShapePars[1]=CFunc(energy, fTheta, fPhi);
00224   fShapePars[2]=DFunc(energy, fTheta, fPhi);
00225   fShapePars[3]=SFunc(energy, fTheta, fPhi);
00226 
00227   // Special threshold for chi2 calculation
00228   fSpecThr=fgCutEcorr0+fgCutEcorr1*energy;
00229   fThrCorr=0;
00230 }
00231 
00232 float 
00233 EmcGlSectorRec::PredictEnergy (float deltaz, float deltay, float energy)
00234 {
00235   // Calculate relative predicted energy deposit in module whose center is at
00236   // deltaz deltay module units from cluster COG.
00237   // If energy<0 no profile parameters change needed.
00238 
00239   if(energy>0) SetProfileParameters(-1, energy, 0., 0.);
00240 
00241   // Rotate coordinates according to phi      
00242   Rotate(fPhi, deltaz, deltay);
00243 
00244   // Shift and squeeze
00245   deltaz-=fShift;
00246   if(deltaz<0.0) deltaz*=fExc1;
00247   else deltaz*=fExc2;
00248 
00249   // Effective distance between this module and center of gravity
00250   float rCG=sqrt(deltaz*deltaz+deltay*deltay);
00251   
00252   // Calculate predicted energy deposit in this module.
00253   float predicted=ShapeFunc(&rCG, fShapePars)+fThrCorr;
00254 
00255   return predicted;
00256 }
00257 
00258 float EmcGlSectorRec::ClusterChisq(int nh, EmcModule* phit, float e, float x,
00259                                 float y, int &ndf)
00260 // Scheme similar to PbSc (modified by AB)
00261 {
00262 
00263   float chi=0;
00264   int nhout = 0;
00265   int ixy, ix, iy;
00266   float et, a, d;
00267   
00268   for( int in=0; in<nh; in++ ) {
00269     et = phit[in].amp;
00270     if( et/e > 0.004 ) {
00271       ixy = phit[in].ich;
00272       iy = ixy/fNx;
00273       ix = ixy - iy*fNx;
00274       a = PredictEnergy(x-ix, y-iy, -1);
00275       d = fgEpar00*fgEpar00 + e*(fgEpar1*a + fgEpar2*a*a + fgEpar3*a*a*a) + 
00276         e*e*fgEpar4*a*(1-a)*fSin4T + e*e*fgEpar0*fgEpar0;
00277       d += 0.30*0.30*e*e*a*a*(1-a); // 5% error 
00278       //      d += 0.25*0.25*e*e*a*a; // 5% error 
00279       a *= e;
00280       chi += (et-a)*(et-a)/d;
00281       nhout++;
00282     }
00283   }
00284 
00285   ndf=nhout; // change needed for PbGl MV 28.01.00
00286   return chi;
00287 
00288 }
00289 
00290 /* Maxim's version
00291 float 
00292 EmcGlSectorRec::ClusterChisq (int nmod, EmcModule* modules,
00293                               float energy, float zcg, float ycg, int &ndf)
00294 {
00295   // Calculate chi2 of cluster consisting of nmod EmcModules whose energy
00296   // and COG coordinates are known. In the case of PbGl we need to recalculate
00297   // COG and energy with special threshold.
00298   
00299   float rowCGChisq; // COG for chi2 calculation
00300   float colCGChisq;
00301   float signal; // signal in module
00302   float rowPos; // z coord. of module
00303   float colPos; // y coord. of module
00304   float bazik=0.0; // Bazik-parameter (chi squared)
00305   float cl=0.0; // confidence level (not outputted)
00306 
00307   // Running sums
00308   float specSum=0.0; // Special energy sum
00309   float sumRowChisq=0.0; // auxiliary sums
00310   float sumColChisq=0.0;
00311   float predSum=0.0; // Sum of predicted energy deposits
00312   ndf=0;
00313 
00314   for(int i=0; i<nmod; i++){
00315     
00316     rowPos=modules[i].ich%fNx;
00317     colPos=modules[i].ich/fNx;
00318     signal=modules[i].amp;
00319 
00320     if(signal>fSpecThr){
00321       
00322       specSum+=signal;
00323       sumRowChisq+=rowPos*signal;
00324       sumColChisq+=colPos*signal;
00325 
00326     }
00327   }
00328 
00329   if(specSum>0.0){
00330     
00331     rowCGChisq=sumRowChisq/specSum;
00332     colCGChisq=sumColChisq/specSum;
00333     
00334   }
00335   else{
00336 
00337     cl=999.999; // Cannot conclude anything about this cluster
00338     ndf=0;
00339     bazik=0.;
00340     return bazik;
00341 
00342   }
00343 
00344   float *predDep=new float[nmod];
00345   float *actDep=new float[nmod];
00346   int *indices=new int[nmod];
00347 
00348   for(int i=0; i<nmod; i++){
00349 
00350     signal=modules[i].amp;
00351 
00352     if(signal>fSpecThr){
00353 
00354       // Retrieve position of the module
00355       rowPos=modules[i].ich%fNx;
00356       colPos=modules[i].ich/fNx;
00357       
00358       float deltaRow=rowCGChisq-rowPos;
00359       float deltaCol=colCGChisq-colPos;
00360 
00361       // Memorize predicted deposit, actual deposit
00362       predDep[ndf]=PredictEnergy(deltaRow, deltaCol, specSum);
00363       actDep[ndf]=signal;
00364       indices[ndf]=i;
00365       
00366       predSum+=predDep[ndf];
00367       
00368       ndf++;
00369       
00370     }
00371   }
00372 
00373   // Renormalization factor
00374   float normFactor=1.0/predSum;
00375 
00376   // Calculate bazik-parameter for selected modules
00377   for(int i=0; i<ndf; i++){
00378 
00379     predDep[i]*=normFactor;
00380     float difference=predDep[i]*specSum-actDep[i];
00381     
00382     // Calculate errors
00383     float sigmaSq=CalcSigma(predDep[i], specSum, fTheta);
00384     
00385     // Calculate bazik parameter
00386     float contrib=difference*difference/sigmaSq;
00387     bazik+=contrib;
00388 
00389   }    
00390   
00391   ndf-=2;
00392   if(ndf>0){
00393 
00394     cl=TMath::Prob(bazik, ndf);
00395 
00396   }
00397   else{
00398 
00399     cl=999.999; // Cannot conclude anything about this cluster
00400     ndf=0;
00401     bazik=0.;
00402 
00403   }
00404 
00405   // Clean up
00406   delete [] predDep;
00407   delete [] actDep;
00408   delete [] indices;
00409 
00410   return bazik;
00411 }
00412 */
00413 
00414 void 
00415 EmcGlSectorRec::CorrectEnergy (float Energy, float x, float y, 
00416                                float* Ecorr)
00417 {
00418   // angular & nonlinearity correction for the cluster energy
00419   // MM 02.11.2000
00420   //
00421   // (x,y) = x & y center of gravity values
00422 
00423     // variables for angular correction of energy
00424 
00425     static float  par_1 = -0.012043;
00426     static float  par_2 = 0.077908;
00427     float  xm,ym;
00428     float  sin_theta;
00429     float  theta_deg;
00430     float  corr_factor_ang;
00431 
00432     // variables for energy nonlinearity correction
00433 
00434     static float  par_a     =  1.0386;     /* corr. funct. par. */
00435     static float  par_b     = -0.041423;   /* corr. funct. par. */
00436     static float  par_c     =  0.006064;   /* corr. funct. par. */
00437     float  log_e;
00438     float  corr_factor_nonl;
00439 
00440     /****************************************/
00441     /* angular correction of cluster energy */
00442     /****************************************/
00443 
00444     // get 1st momenta
00445 
00446     xm = x;
00447     ym = y;
00448 
00449     // get angle for hit
00450 
00451     GetImpactAngle(xm,ym,&sin_theta);
00452     theta_deg = 180.0/ M_PI * asin(sin_theta);
00453 
00454     // correct for perpendicular incident
00455 
00456     corr_factor_ang = par_1*exp(theta_deg*par_2)+1-par_1;
00457 
00458     // correct energy
00459 
00460     // Change energy scale on Klaus Reyger's recommendation
00461     // This has to happen before angular and nonlinearity effects
00462 
00463     //    Energy = 1.11 * Energy;
00464 
00465     // 17-Apr-2001: Additional 3.8% scaling on top of the 11% before (SB)
00466     // Removed to preserve consistency between simulation and real
00467     // data production - correction moved back to calibrator G.D. 02/14/02
00468     //    Energy = 1.15218 * Energy;
00469     
00470     Energy = Energy/corr_factor_ang;
00471 
00472 
00473     /*********************************************/
00474     /* nonlinearity correction of cluster energy */
00475     /*********************************************/
00476 
00477     // precalculate logarithm of cluster energy
00478 
00479     log_e = log(Energy);
00480 
00481     // calculate correction factor for cluster energy
00482 
00483     corr_factor_nonl = par_a + par_b*(log_e)+par_c*(log_e*log_e);
00484 
00485     // calculate corrected cluster energy
00486 
00487     *Ecorr = corr_factor_nonl*Energy;
00488 }
00489 
00490 
00491 void 
00492 EmcGlSectorRec::CorrectECore (float Ecore, float x, float y, 
00493                               float* Ecorr)
00494 {
00495   // Corrects the EM Shower Energy for attenuation in fibers and 
00496   // long energy leakage
00497   //
00498   // (x,y) - impact position (cm)
00499 
00500   *Ecorr = Ecore;
00501 }
00502 
00503 
00504 void 
00505 EmcGlSectorRec::CorrectPosition (float energy, float zcg, float ycg,
00506                                  float* zcgcorr, float* ycgcorr, 
00507                                  bool callSetPar)
00508 {
00509   // Corrects the Shower Center of Gravity for the systematic error due to 
00510   // the limited tower size and angle shift.
00511   // (zcg, ycg) -- CG position in cm,
00512   // (*pzcg, *pycg) -- corrected position in cm.
00513   // callSetPar is used to turn off SetProfileParameters() call when
00514   // CorrectPosition() is called from SetProfileParameters(). This allows
00515   // to avoid infinite recursion.
00516 
00517   float spar[3]; // parameters for s-function
00518 
00519   if(callSetPar)
00520     SetProfileParameters( 0, energy, zcg/GetModSizex(), ycg/GetModSizey() );
00521 
00522   // Correcting z
00523   zcg/=GetModSizex(); // convert from cm to module units
00524   spar[0]=fgCoorPar00+fgCoorPar01*fabs(fSinTx)+
00525     (fgCoorPar02+fgCoorPar03*energy)*fSinTx*fSinTx;
00526   spar[0]*=copysign(1., fSinTx);
00527   spar[1]=fgCoorPar10*fabs(fSinTx)+
00528     (fgCoorPar11+fgCoorPar12*energy)*fSinTx*fSinTx;
00529   spar[1]*=copysign(1., fSinTx);
00530   spar[2]=(fgCoorPar20+fgCoorPar21*log(energy))*fSinTx;
00531 
00532 #if 0
00533   // Experimental for 5 GeV/c 20 deg gammas.
00534   // If we don't distinguish between electrons and gammas, Zrec-Zinc
00535   // distribution becomes shifted approx. 7mm for 5 GeV/c 20 deg. RMS is ~12 mm
00536   // for gammas, ~8 mm for electrons.
00537   spar[0]=1.28090;
00538   spar[0]*=copysign(1., fSinTx);
00539   spar[1]=1.07773;
00540   spar[1]*=copysign(1., fSinTx);
00541   spar[2]=1.65389;
00542   spar[2]*=copysign(1., fSinTx);
00543 #endif
00544 
00545   *zcgcorr=InvScurveFunc(zcg, spar)*GetModSizex();
00546 
00547   // Correcting y
00548   ycg/=GetModSizey(); // convert from cm to module units
00549   spar[0]=fgCoorPar00+fgCoorPar01*fabs(fSinTy)+
00550     (fgCoorPar02+fgCoorPar03*energy)*fSinTy*fSinTy;
00551   spar[0]*=copysign(1., fSinTy);
00552   spar[1]=fgCoorPar10*fabs(fSinTy)+
00553     (fgCoorPar11+fgCoorPar12*energy)*fSinTy*fSinTy;
00554   spar[1]*=copysign(1., fSinTy);
00555   spar[2]=(fgCoorPar20+fgCoorPar21*log(energy))*fSinTy;
00556   *ycgcorr=InvScurveFunc(ycg, spar)*GetModSizey();
00557 }
00558 
00559 void 
00560 EmcGlSectorRec::CalculateErrors (float e, float x, float y, float* pde,
00561                                  float* pdx, float* pdy, float* pdz)
00562 {
00563   // Returns the errors for the reconstructed energy and position 
00564   // (in the hypothesis of EM shower)
00565   // Should be called only just after CorrectPosition !!!
00566 
00567   // NO CALCULATION YET FOR PBGL -- PARAMETERS ARE NOT FOUND!!!
00568 
00569   *pde = 999.999;
00570   *pdx = 999.999;
00571   *pdy = 999.999;
00572   *pdz = 999.999;
00573 }
00574 
00575 void 
00576 EmcGlSectorRec::TwoGamma (int nmod, EmcModule *modules, float *pchi,
00577                           float *pe1, float *pz1, float *py1,
00578                           float *pe2, float *pz2, float *py2)
00579 {
00580   // NO UNFOLDING YET FOR PBGL -- PARAMETERS ARE NOT FOUND!!!
00581 
00582   float e0, z0, y0, zz, yy, zy;
00583 
00584   *pe2=0.;
00585   *pz2=0.;
00586   *py2=0.;
00587 
00588   Momenta(nmod, modules, &e0, &z0, &y0, &zz, &yy, &zy);
00589 
00590   *pe1=e0;
00591   *pz1=z0;
00592   *py1=y0;
00593 }
00594 
00595 float 
00596 EmcGlSectorRec::ShiftFunc (float energy, float angle)
00597 {
00598   // Calculate x coord. shift according to energy and angle.
00599   // Angle in degrees.
00600   
00601   const float par0=-6.06226e+00;
00602   const float par1=-3.49026e-01;
00603 
00604   return (par0+par1*log(energy))*(1.0-cos(angle* M_PI /180.0));
00605 }
00606 
00607 float 
00608 EmcGlSectorRec::Sigma1Func (float energy, float angle)
00609 {
00610   // Calculate 1st transformation factor.
00611   // Angle in degrees.
00612 
00613   const float par0=-1.75549e-02;
00614   const float par1=-1.35630e-03;
00615 
00616   return 1.0+(par0+par1*log(energy))*angle;
00617 }
00618 
00619 float
00620 EmcGlSectorRec::Sigma2Func (float energy, float angle)
00621 {
00622   // Calculate 2nd transformation factor.
00623   // Angle in degrees.
00624 
00625   const float par0=-2.33139e-02;
00626   const float par1=-2.79326e-03;
00627 
00628   return 1.0+(par0+par1*log(energy))*angle;
00629 
00630 }
00631 
00632 float 
00633 EmcGlSectorRec::ShapeFunc (float *x, float *par)
00634 {
00635   // Function describes lateral shower shape for e/m showers.
00636   // x[0] -- (corrected) distance between the module center and the c.g. of the shower.
00637 
00638   float rad=fabs(x[0]);
00639   float value;
00640   
00641   float expr1=exp(-::pow(rad, 1.95)/par[1]);
00642   
00643     float d=par[2];
00644     float s=par[3];
00645     float expr2=d*exp(-rad/s);
00646     value=par[0]*EmcCluster::max(expr1,expr2);
00647   
00648   return value;
00649 }
00650 
00651 float 
00652 EmcGlSectorRec::AFunc (float energy, float angle, float phi)
00653 {
00654   // Calculate 1st parameter for ShapeFunc based on energy and polar
00655   // and azimuthal angles.
00656   // Angle and phi in degrees.
00657 
00658   // Ap0
00659   const float Ap0p0p0=-3.81425e+00;
00660   const float Ap0p0p1=-1.94749e+00;
00661 
00662   float Ap0p0=Ap0p0p0+Ap0p0p1*log(energy);
00663 
00664   const float Ap0p1p0=4.62982e+00;
00665   const float Ap0p1p1=1.94482e+00;
00666 
00667   float Ap0p1=Ap0p1p0+Ap0p1p1*log(energy);
00668 
00669   float Ap0=Ap0p0+Ap0p1*cos(angle* M_PI/180.0);
00670 
00671   // Ap1
00672   const float Ap1p0p0=2.65696e-05;
00673   const float Ap1p0p1=5.56524e-05;
00674 
00675   float Ap1p0=Ap1p0p0+Ap1p0p1*log(energy);
00676 
00677   float Ap1=exp(Ap1p0*::pow(angle, 2.5))-1.0;
00678 
00679   // Ap2
00680   const float Ap2p0p0=1.90663e+01;
00681   const float Ap2p0p1=-2.96820e-02;
00682 
00683   float Ap2p0=Ap2p0p0+Ap2p0p1*log(energy);
00684 
00685   const float Ap2p1p0=1.51973e-04;
00686   const float Ap2p1p1=1.20920e-04;
00687 
00688   float Ap2p1=Ap2p1p0+Ap2p1p1*log(energy);
00689 
00690   float Ap2=Ap2p0+exp(Ap2p1*angle*angle*angle);
00691 
00692   // Final result
00693   float A[3]={Ap0, Ap1, Ap2};
00694 
00695   return PeriodicFunc(&phi, A);
00696 
00697 }
00698 
00699 float 
00700 EmcGlSectorRec::CFunc (float energy, float angle, float phi)
00701 {
00702   // Calculate 2nd parameter for ShapeFunc.
00703   // Angle and phi in degrees.
00704   // Angle and phi are dummy parameters.
00705 
00706 #if 0
00707   const float cp0=3.28956e-01;
00708   const float cp1=-1.08942e-02;
00709 
00710   float c=cp0+cp1*log(energy);
00711 #endif
00712 
00713   const float cp0p0=-4.13339e-03;
00714   const float cp0p1=-6.24275e-03;
00715 
00716   float cp0=cp0p0+cp0p1*log(energy);
00717   
00718   float c=0.34+cp0*::pow(angle, 0.3);
00719   
00720   return c;
00721 
00722 }
00723 
00724 float 
00725 EmcGlSectorRec::DFunc (float energy, float angle, float phi)
00726 {
00727   // Calculate 3rd parameter for ShapeFunc.
00728   // Angle and phi in degrees.
00729   // Angle and phi are dummy parameters.
00730 
00731   const float dp0=1.35528e-01;
00732   const float dp1=-2.43148e-02;
00733 
00734   float d=dp0+dp1*log(energy);
00735 
00736   return d;
00737 
00738 }
00739 
00740 float 
00741 EmcGlSectorRec::SFunc (float energy, float angle, float phi)
00742 {
00743   // Calculate 4th parameter for ShapeFunc.
00744   // Angle and phi in degrees.
00745   // Angle and phi are dummy parameters.
00746 
00747   const float sp0=5.21967e-01;
00748   const float sp1=2.66467e-02;
00749 
00750   float s=sp0+sp1*log(energy);
00751 
00752   return s;
00753 
00754 }
00755 
00756 float 
00757 EmcGlSectorRec::PeriodicFunc (float *x, float *par)
00758 {
00759   // Auxiliary function for calculating of 1st parameter for ShapeFunc.
00760 
00761   float mean;
00762   float var=x[0];
00763   
00764   const float a=45.0;
00765 
00766   if(var!=0.0) mean=a*(fabs(var)/var)*((1+2*abs(int((var-0.00001)/(2*a)))));
00767   else mean=a;
00768   
00769   return par[0]+par[1]*exp(-0.5*(var-mean)*(var-mean)/(par[2]*par[2]));
00770   
00771 }
00772 
00773 float 
00774 EmcGlSectorRec::InvScurveFunc (float cog, float *par)
00775 {
00776   // Dependence between incidence coord. and COG
00777 
00778   float b=par[0];
00779   float d=par[1];
00780   float D=par[2];
00781 
00782   cog-=d;
00783   float translation=cog>0.? int(cog+0.5): int(cog-0.5);
00784   float xinc=translation+
00785     asinh(2.*(cog-translation)*sinh(0.5/b))*b-D+d;
00786 
00787   return xinc;
00788 
00789 }
00790 
00791 void 
00792 EmcGlSectorRec::Rotate (float phi, float &deltaRow, float &deltaCol)
00793 {
00794   // Rotate coordinates according to phi
00795 
00796   float alpha=phi * M_PI / 180.0;
00797   float sina=sin(alpha);
00798   float cosa=cos(alpha);
00799   
00800   float xprime=deltaRow;
00801   float yprime=deltaCol;
00802   
00803   deltaRow=xprime*cosa+yprime*sina;
00804   deltaCol=-xprime*sina+yprime*cosa;
00805 
00806 }
00807 
00808 float 
00809 EmcGlSectorRec::CalcSigma (float predicted, float totSignal, float theta)
00810 {
00811   // Calculate predicted sigma squared for this module based on predicted
00812   // relative energy deposit.
00813 
00814   float sigmaSq; // return value
00815 
00816   // Response in PISA is somewhat different from standard GEANT => forced to
00817   // introduce correction :(
00818   const float pisaCorr=2.;
00819 
00820   sigmaSq=totSignal*fabs(predicted*(0.9-predicted));
00821 
00822   // energy correction
00823   sigmaSq*=(pisaCorr*fgSigEcorr0+fgSigEcorr1*totSignal);
00824 
00825   // Angle-dependent correction
00826   sigmaSq*=1.0+(fgSigAcorr0*exp(fgSigAcorr1*totSignal))*theta;
00827 
00828   return sigmaSq;
00829   
00830 }
00831 
00832 void 
00833 EmcGlSectorRec::getTowerPos(int ix, int iy, 
00834                             float &x, float & y)
00835 {
00836   x = fModSizex * ix+int(ix/6)*0.15;
00837   y = fModSizey * iy+int(iy/6)*0.163;
00838 }
00839 
00841 void   
00842 EmcGlSectorRec::TowersToSector(float xT, float yT, 
00843                                float & xS, float & yS)
00844 {
00845   int   x  = int(xT);
00846   float dx = xT - x;
00847   int   y  = int(yT);
00848   float dy = yT - y;
00849   xS = fModSizex*x + int(xT/6)*0.15  + fModSizex*dx;
00850   yS = fModSizey*y + int(yT/6)*0.163 + fModSizey*dy;
00851 }
00852 
00854 void   
00855 EmcGlSectorRec::TowersToSector(int xT, int yT,   
00856                                float & xS, float & yS)
00857 {
00858   xS = fModSizex*xT + int(xT/6)*0.15;
00859   yS = fModSizey*yT + int(yT/6)*0.163;
00860 }
00861 
00863 void  
00864 EmcGlSectorRec::SectorToTowers(float xS, float yS, 
00865                                int & xT, int & yT)
00866 {
00867   // PbGl
00868   xT = int(((xS-int(xS/24.612)*24.612)+2.0385)/fModSizex) + 6*int(xS/24.612);
00869   yT = int(((yS-int(yS/16.471)*16.471)+2.0385)/fModSizey) + 4*int(yS/16.471);
00870 }
00871 
00872 
00873 
00874 
00875 
00876 
00877 
00878 
00879 
00880 
00881 
00882 

Generated on Sun May 18 03:33:59 2008 for EMCAL Reconstruction by  doxygen 1.3.9.1