CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/FastSimulation/Calorimetry/src/HCALResponse.cc

Go to the documentation of this file.
00001 //FastSimulation headers
00002 #include "FastSimulation/Calorimetry/interface/HCALResponse.h"
00003 #include "FastSimulation/Utilities/interface/RandomEngine.h"
00004 #include "FastSimulation/Utilities/interface/DoubleCrystalBallGenerator.h"
00005 
00006 // CMSSW Headers
00007 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00009 
00010 #include <iostream>
00011 #include <vector>
00012 #include <string>
00013 #include <math.h>
00014 
00015 using namespace edm;
00016 
00017 HCALResponse::HCALResponse(const edm::ParameterSet& pset, const RandomEngine* engine) :  random(engine), cball(random) {
00018   //switches
00019   debug = pset.getParameter<bool>("debug");
00020   usemip = pset.getParameter<bool>("usemip");
00021 
00022 //values for "old" response parameterizations
00023 //--------------------------------------------------------------------
00024   RespPar[HCAL][0][0] = pset.getParameter<double>("HadronBarrelResolution_Stochastic");
00025   RespPar[HCAL][0][1] = pset.getParameter<double>("HadronBarrelResolution_Constant");
00026   RespPar[HCAL][0][2] = pset.getParameter<double>("HadronBarrelResolution_Noise");
00027 
00028   RespPar[HCAL][1][0] = pset.getParameter<double>("HadronEndcapResolution_Stochastic");
00029   RespPar[HCAL][1][1] = pset.getParameter<double>("HadronEndcapResolution_Constant");
00030   RespPar[HCAL][1][2] = pset.getParameter<double>("HadronEndcapResolution_Noise");
00031 
00032   RespPar[VFCAL][0][0] = pset.getParameter<double>("HadronForwardResolution_Stochastic");
00033   RespPar[VFCAL][0][1] = pset.getParameter<double>("HadronForwardResolution_Constant");
00034   RespPar[VFCAL][0][2] = pset.getParameter<double>("HadronForwardResolution_Noise");
00035 
00036   RespPar[VFCAL][1][0] = pset.getParameter<double>("ElectronForwardResolution_Stochastic");
00037   RespPar[VFCAL][1][1] = pset.getParameter<double>("ElectronForwardResolution_Constant");
00038   RespPar[VFCAL][1][2] = pset.getParameter<double>("ElectronForwardResolution_Noise");
00039 
00040   eResponseScale[0] = pset.getParameter<double>("eResponseScaleHB");  
00041   eResponseScale[1] = pset.getParameter<double>("eResponseScaleHE");
00042   eResponseScale[2] = pset.getParameter<double>("eResponseScaleHF");
00043 
00044   eResponsePlateau[0] = pset.getParameter<double>("eResponsePlateauHB");
00045   eResponsePlateau[1] = pset.getParameter<double>("eResponsePlateauHE");
00046   eResponsePlateau[2] = pset.getParameter<double>("eResponsePlateauHF");
00047 
00048   eResponseExponent = pset.getParameter<double>("eResponseExponent");
00049   eResponseCoefficient = pset.getParameter<double>("eResponseCoefficient");
00050   
00051 //pion parameters
00052 //--------------------------------------------------------------------
00053   //energy values
00054   maxHDe[0] = pset.getParameter<int>("maxHBe");
00055   maxHDe[1] = pset.getParameter<int>("maxHEe");
00056   maxHDe[2] = pset.getParameter<int>("maxHFe");
00057   eGridHD[0] = pset.getParameter<vec1>("eGridHB");
00058   eGridHD[1] = pset.getParameter<vec1>("eGridHE");
00059   eGridHD[2] = pset.getParameter<vec1>("eGridHF");
00060   
00061   //region eta indices calculated from eta values
00062   etaStep = pset.getParameter<double>("etaStep");
00063   //eta boundaries
00064   HDeta[0] = abs((int)(pset.getParameter<double>("HBeta") / etaStep));
00065   HDeta[1] = abs((int)(pset.getParameter<double>("HEeta") / etaStep));
00066   HDeta[2] = abs((int)(pset.getParameter<double>("HFeta") / etaStep));
00067   HDeta[3] = abs((int)(pset.getParameter<double>("maxHDeta") / etaStep)); //add 1 because this is the max index
00068   //eta ranges
00069   maxHDetas[0] = HDeta[1] - HDeta[0];
00070   maxHDetas[1] = HDeta[2] - HDeta[1];
00071   maxHDetas[2] = HDeta[3] - HDeta[2];
00072   
00073   //parameter info
00074   nPar = pset.getParameter<int>("nPar");
00075   parNames = pset.getParameter<std::vector<std::string> >("parNames");
00076   std::string detNames[] = {"_HB","_HE","_HF"};
00077   std::string mipNames[] = {"_mip","_nomip",""};
00078   
00079   //setup parameters (5D vector)
00080   parameters = vec5(nPar,vec4(3,vec3(3)));
00081   for(int p = 0; p < nPar; p++){ //loop over parameters
00082     for(int m = 0; m < 3; m++){ //loop over mip, nomip, total
00083           for(int d = 0; d < 3; d++){ //loop over dets: HB, HE, HF
00084             //get from python
00085                 std::string pname = parNames[p] + detNames[d] + mipNames[m];
00086                 vec1 tmp = pset.getParameter<vec1>(pname);
00087           
00088             //resize vector for energy range of det d
00089             parameters[p][m][d].resize(maxHDe[d]);
00090                 
00091                 for(int i = 0; i < maxHDe[d]; i++){ //loop over energy for det d
00092                   //resize vector for eta range of det d
00093                   parameters[p][m][d][i].resize(maxHDetas[d]);
00094                   
00095                   for(int j = 0; j < maxHDetas[d]; j++){ //loop over eta for det d
00096                     //fill in parameters vector from python
00097                         parameters[p][m][d][i][j] = tmp[i*maxHDetas[d] + j];
00098                   }
00099                 }
00100           }
00101         }
00102   }
00103 
00104 // MUON probability histos for bin size = 0.25 GeV (0-10 GeV, 40 bins)
00105 //--------------------------------------------------------------------
00106   muStep  = pset.getParameter<double>("muStep");
00107   maxMUe = pset.getParameter<int>("maxMUe");
00108   maxMUeta = pset.getParameter<int>("maxMUeta");
00109   maxMUbin = pset.getParameter<int>("maxMUbin");
00110   eGridMU = pset.getParameter<vec1>("eGridMU");
00111   etaGridMU = pset.getParameter<vec1>("etaGridMU");
00112   vec1 _responseMU[2] = {pset.getParameter<vec1>("responseMUBarrel"),pset.getParameter<vec1>("responseMUEndcap")};
00113   
00114   //get muon region eta indices from the eta grid
00115   double _barrelMUeta = pset.getParameter<double>("barrelMUeta");
00116   double _endcapMUeta = pset.getParameter<double>("endcapMUeta");
00117   barrelMUeta = endcapMUeta = maxMUeta;
00118   for(int i = 0; i < maxMUeta; i++) {
00119     if(fabs(_barrelMUeta) <= etaGridMU[i]) { barrelMUeta = i; break; }      
00120   }
00121   for(int i = 0; i < maxMUeta; i++) {
00122     if(fabs(_endcapMUeta) <= etaGridMU[i]) { endcapMUeta = i; break; }      
00123   }
00124   int maxMUetas[] = {endcapMUeta - barrelMUeta, maxMUeta - endcapMUeta};
00125   
00126   //initialize 3D vector
00127   responseMU = vec3(maxMUe,vec2(maxMUeta,vec1(maxMUbin,0)));
00128   
00129   //fill in 3D vector
00130   //(complementary cumulative distribution functions, from normalized response distributions)
00131   int loc, eta_loc;
00132   loc = eta_loc = -1;
00133   for(int i = 0; i < maxMUe; i++){
00134     for(int j = 0; j < maxMUeta; j++){
00135           //check location - barrel, endcap, or forward
00136           if(j==barrelMUeta) {loc = 0; eta_loc = barrelMUeta;}
00137           else if(j==endcapMUeta) {loc = 1; eta_loc = endcapMUeta;}
00138           
00139           for(int k = 0; k < maxMUbin; k++){
00140             responseMU[i][j][k] = _responseMU[loc][i*maxMUetas[loc]*maxMUbin + (j-eta_loc)*maxMUbin + k];
00141                 
00142                 if(debug) {
00143             //cout.width(6);
00144             LogInfo("FastCalorimetry") << " responseMU " << i << " " << j << " " << k  << " = " 
00145                                       << responseMU[i][j][k] << std::endl;
00146             }
00147           }
00148         }
00149   }
00150 
00151 // values for EM response in HF
00152 //--------------------------------------------------------------------
00153   maxEMe = pset.getParameter<int>("maxEMe");
00154   maxEMeta = maxHDetas[2];
00155   respFactorEM = pset.getParameter<double>("respFactorEM");
00156   eGridEM = pset.getParameter<vec1>("eGridEM");
00157  
00158   // e-gamma mean response and sigma in HF 
00159   vec1 _meanEM = pset.getParameter<vec1>("meanEM");
00160   vec1 _sigmaEM = pset.getParameter<vec1>("sigmaEM");
00161 
00162   //fill in 2D vectors (w/ correction factor applied)
00163   meanEM = vec2(maxEMe,vec1(maxEMeta,0));
00164   sigmaEM = vec2(maxEMe,vec1(maxEMeta,0));
00165   for(int i = 0; i < maxEMe; i++){
00166     for(int j = 0; j < maxEMeta; j++){
00167           meanEM[i][j] = respFactorEM * _meanEM[i*maxEMeta + j];
00168           sigmaEM[i][j] = respFactorEM * _sigmaEM[i*maxEMeta + j];
00169         }
00170   }
00171 
00172 }
00173 
00174  
00175 double HCALResponse::responseHCAL(int _mip, double energy, double eta, int partype){
00176   int ieta = abs((int)(eta / etaStep)) ;
00177   int ie = -1;
00178 
00179   int mip;
00180   if(usemip) mip = _mip;
00181   else mip = 2; //ignore mip, use only overall (mip + nomip) parameters
00182 
00183   double mean = 0;
00184   
00185   // e/gamma in HF
00186   if(partype == 0) {
00187     //check eta
00188     ieta -= HDeta[2];  // HF starts at ieta=30 till ieta=51 
00189                  // but resp.vector from index=0 through 20
00190     if(ieta >= maxEMeta ) ieta = maxEMeta-1;
00191     else if(ieta < 0) ieta = 0;
00192  
00193     //find energy range
00194     for (int i = 0; i < maxEMe; i++) {
00195       if(energy < eGridEM[i])  {
00196             if(i == 0) ie = 0; // less than minimal - back extrapolation with the 1st interval  
00197         else  ie = i-1;
00198         break;
00199       }
00200     }
00201     if(ie == -1) ie = maxEMe - 2; // more than maximum - extrapolation with last interval
00202         
00203         //do smearing
00204     mean = interEM(energy, ie, ieta);
00205   }
00206   
00207   // hadrons
00208   else if(partype == 1) {
00209       //check eta and det
00210           int det = getDet(ieta);
00211           int deta = ieta - HDeta[det];
00212       if(deta >= maxHDetas[det]) deta = maxHDetas[det] - 1;
00213       else if(deta < 0 ) deta = 0;
00214           
00215           //find energy range
00216       for (int i = 0; i < maxHDe[det]; i++) {
00217             if(energy < eGridHD[det][i])  {
00218               if(i == 0) ie = 0; // less than minimal - back extrapolation with the 1st interval
00219               else  ie = i-1;
00220               break;
00221             }   
00222       }
00223       if(ie == -1) ie = maxHDe[det] - 2; // more than maximum - extrapolation with last interval
00224       
00225           //do smearing
00226       mean = interHD(mip, energy, ie, deta, det);
00227   }
00228 
00229   
00230   // muons
00231   else if(partype == 2) { 
00232     //check eta
00233     ieta = maxMUeta;
00234     for(int i = 0; i < maxMUeta; i++) {
00235       if(fabs(eta) < etaGridMU[i]) {
00236             ieta = i;  
00237             break;
00238       }      
00239     }
00240     if(ieta < 0) ieta = 0;
00241         
00242     if(ieta < maxMUeta) {  // HB-HE
00243           //find energy range
00244       for (int i = 0; i < maxMUe; i++) {
00245             if(energy < eGridMU[i])  {
00246               if(i == 0) ie = 0; // less than minimal - back extrapolation with the 1st interval
00247               else  ie = i-1;
00248               break;
00249             }
00250       }
00251           if(ie == -1) ie = maxMUe - 2; // more than maximum - extrapolation with last interval
00252           
00253           //do smearing
00254       mean = interMU(energy, ie, ieta);
00255           if(mean > energy) mean = energy;
00256     }
00257   }
00258 
00259   // debugging
00260   if(debug) {
00261     //  cout.width(6);
00262     LogInfo("FastCalorimetry") << std::endl
00263                                 << " HCALResponse::responseHCAL, partype = " <<  partype 
00264                                 << " E, eta = " << energy << " " << eta  
00265                                 << "  mean = " << mean << std::endl;
00266   }  
00267   
00268   return mean;
00269 }
00270 
00271 double HCALResponse::interMU(double e, int ie, int ieta) {
00272   double x = random->flatShoot();
00273 
00274   int bin1 = maxMUbin;
00275   for(int i = 0; i < maxMUbin; i++) {
00276     if(x > responseMU[ie][ieta][i]) {
00277       bin1 = i-1;
00278       break;
00279     }
00280   }
00281   int bin2 = maxMUbin;
00282   for(int i = 0; i < maxMUbin; i++) {
00283     if(x > responseMU[ie+1][ieta][i]) {
00284       bin2 = i-1;
00285       break;
00286     }
00287   }
00288    
00289   double x1 = eGridMU[ie];
00290   double x2 = eGridMU[ie+1];
00291   double y1 = (bin1 + random->flatShoot()) * muStep;   
00292   double y2 = (bin2 + random->flatShoot()) * muStep;   
00293 
00294   if(debug) {
00295     //  cout.width(6);
00296     LogInfo("FastCalorimetry") << std::endl
00297                                 << " HCALResponse::interMU  " << std::endl
00298                                 << " x, x1-x2, y1-y2 = " 
00299                                 << e << ", " << x1 <<"-" << x2 << " " << y1 <<"-" << y2 << std::endl; 
00300   
00301   }
00302 
00303   //linear interpolation
00304   double mean = (y1*(x2-e) + y2*(e-x1))/(x2-x1);
00305 
00306   if(debug) {
00307     //cout.width(6);
00308     LogInfo("FastCalorimetry") << std::endl
00309                                 << " HCALResponse::interMU " << std::endl
00310                                 << " e, ie, ieta = " << e << " " << ie << " " << ieta << std::endl
00311                                 << " response  = " << mean << std::endl; 
00312   }
00313 
00314   return mean;
00315 }
00316 
00317 double HCALResponse::interHD(int mip, double e, int ie, int ieta, int det) {
00318   double y1, y2;
00319 
00320   double x1 = eGridHD[det][ie];
00321   double x2 = eGridHD[det][ie+1];
00322   
00323   vec1 pars(nPar,0);
00324 
00325   //calculate all parameters
00326   for(int p = 0; p < nPar; p++){
00327         y1 = parameters[p][mip][det][ie][ieta];
00328         y2 = parameters[p][mip][det][ie+1][ieta];
00329 
00330         //par-specific checks
00331         double custom = 0;
00332         bool use_custom = false;
00333         
00334         //do not let mu or sigma get extrapolated below zero for low energies
00335         //especially important for HF since extrapolation is used for E < 15 GeV
00336         if((p==0 || p==1) && e < x1){
00337                 double tmp = (y1*x2-y2*x1)/(x2-x1); //extrapolate down to e=0
00338                 if(tmp<0) { //require mu,sigma > 0 for E > 0
00339                         custom = y1*e/x1;
00340                         use_custom = true;
00341                 }
00342         }
00343         //tail parameters have lower bounds - never extrapolate down
00344         else if((p==2 || p==3 || p==4 || p==5)){
00345                 if(e < x1 && y1 < y2){
00346                         custom = y1;
00347                         use_custom = true;
00348                 }
00349                 else if(e > x2 && y2 < y1){
00350                         custom = y2;
00351                         use_custom = true;
00352                 }
00353         }
00354         
00355         //linear interpolation
00356         if(use_custom) pars[p] = custom;
00357         else pars[p] = (y1*(x2-e) + y2*(e-x1))/(x2-x1);
00358   }
00359   
00360   //random smearing
00361   double mean = 0;
00362   if(nPar==6) mean = cballShootNoNegative(pars[0],pars[1],pars[2],pars[3],pars[4],pars[5]);
00363   else if(nPar==2) mean = gaussShootNoNegative(pars[0],pars[1]); //gaussian fallback
00364 
00365   return mean;
00366 }
00367 
00368 
00369 double HCALResponse::interEM(double e, int ie, int ieta) {
00370   double y1 = meanEM[ie][ieta]; 
00371   double y2 = meanEM[ie+1][ieta]; 
00372   double x1 = eGridEM[ie];
00373   double x2 = eGridEM[ie+1];
00374   
00375   if(debug) {
00376     //  cout.width(6);
00377     LogInfo("FastCalorimetry") << std::endl
00378                                 << " HCALResponse::interEM mean " << std::endl
00379                                 << " x, x1-x2, y1-y2 = " 
00380                                 << e << ", " << x1 <<"-" << x2 << " " << y1 <<"-" << y2 << std::endl;
00381   }
00382 
00383   //linear interpolation
00384   double mean = (y1*(x2-e) + y2*(e-x1))/(x2-x1);     
00385   
00386   y1 = sigmaEM[ie][ieta]; 
00387   y2 = sigmaEM[ie+1][ieta]; 
00388   
00389   if(debug) {
00390     //  cout.width(6);
00391     LogInfo("FastCalorimetry") << std::endl
00392                                 << " HCALResponse::interEM sigma" << std::endl
00393                                 << " x, x1-x2, y1-y2 = " 
00394                                 << e << ", " << x1 <<"-" << x2 << " " << y1 <<"-" << y2 << std::endl;
00395   }
00396 
00397   //linear interpolation
00398   double sigma = (y1*(x2-e) + y2*(e-x1))/(x2-x1);
00399   
00400   //random smearing
00401   double rndm = gaussShootNoNegative(mean,sigma);
00402   
00403   return rndm;
00404 }
00405 
00406 // Old parameterization of the calo response to hadrons
00407 double HCALResponse::getHCALEnergyResponse(double e, int hit){
00408   //response
00409   double s = eResponseScale[hit];
00410   double n = eResponseExponent;
00411   double p = eResponsePlateau[hit];
00412   double c = eResponseCoefficient;
00413 
00414   double response = e * p / (1+c*exp(n * log(s/e)));
00415 
00416   if(response<0.) response = 0.;
00417 
00418   //resolution
00419   double resolution;
00420   if(hit==hcforward) 
00421     resolution = e *sqrt( RespPar[VFCAL][1][0]*RespPar[VFCAL][1][0] / e + RespPar[VFCAL][1][1]*RespPar[VFCAL][1][1] );
00422   else
00423     resolution = e * sqrt( RespPar[HCAL][hit][0]*RespPar[HCAL][hit][0]/(e) + RespPar[HCAL][hit][1]*RespPar[HCAL][hit][1] );   
00424   
00425   //random smearing
00426   double rndm = gaussShootNoNegative(response,resolution);
00427   
00428   return rndm;
00429 }
00430 
00431 //find subdet and eta offset
00432 int HCALResponse::getDet(int ieta){
00433         int d;
00434         for(d = 0; d < 2; d++){
00435                 if(ieta < HDeta[d+1]){
00436                         break;
00437                 }
00438         }
00439         return d;
00440 }
00441 
00442 // Remove (most) hits with negative energies
00443 double HCALResponse::gaussShootNoNegative(double e, double sigma) {
00444   double out = random->gaussShoot(e,sigma);
00445   if (e >= 0.) {
00446     while (out < 0.) out = random->gaussShoot(e,sigma);
00447   }
00448   //else give up on re-trying, otherwise too much time can be lost before emeas comes out positive
00449 
00450   return out;
00451 }
00452 
00453 // Remove (most) hits with negative energies
00454 double HCALResponse::cballShootNoNegative(double mu, double sigma, double aL, double nL, double aR, double nR) {
00455   double out = cball.shoot(mu,sigma,aL,nL,aR,nR);
00456   if (mu >= 0.) {
00457     while (out < 0.) out = cball.shoot(mu,sigma,aL,nL,aR,nR);
00458   }
00459   //else give up on re-trying, otherwise too much time can be lost before emeas comes out positive
00460 
00461   return out;
00462 }