CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch9/src/SimGeneral/GFlash/src/GflashHadronShowerProfile.cc

Go to the documentation of this file.
00001 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00002 
00003 #include "SimGeneral/GFlash/interface/GflashHadronShowerProfile.h"
00004 #include "SimGeneral/GFlash/interface/GflashTrajectoryPoint.h"
00005 #include "SimGeneral/GFlash/interface/GflashHit.h"
00006 
00007 #include <CLHEP/GenericFunctions/IncompleteGamma.hh>
00008 #include <CLHEP/GenericFunctions/LogGamma.hh>
00009 #include <CLHEP/Units/PhysicalConstants.h>
00010 #include <CLHEP/Units/SystemOfUnits.h>
00011 #include <CLHEP/Random/Randomize.h>
00012 #include <CLHEP/Random/RandGaussQ.h>
00013 #include <CLHEP/Random/RandPoissonQ.h>
00014 
00015 #include <math.h>
00016 
00017 GflashHadronShowerProfile::GflashHadronShowerProfile(edm::ParameterSet parSet) : theParSet(parSet)
00018 {
00019   theBField = parSet.getParameter<double>("bField");
00020   theGflashHcalOuter = parSet.getParameter<bool>("GflashHcalOuter");
00021 
00022   theShowino = new GflashShowino();
00023   theHisto = GflashHistogram::instance();
00024 }
00025 
00026 GflashHadronShowerProfile::~GflashHadronShowerProfile() 
00027 {
00028   if(theShowino) delete theShowino;
00029 }
00030 
00031 void GflashHadronShowerProfile::initialize(int showerType, double energy, double globalTime,double charge, 
00032                                            Gflash3Vector &position,Gflash3Vector &momentum) { 
00033 
00034   //initialize GflashShowino for this track
00035   theShowino->initialize(showerType, energy, globalTime, charge, 
00036                          position, momentum, theBField);
00037 
00038 }
00039 
00040 void GflashHadronShowerProfile::hadronicParameterization()
00041 {
00042   // The skeleton of this method is based on the fortran code gfshow.F originally written  
00043   // by S. Peters and G. Grindhammer (also see NIM A290 (1990) 469-488), but longitudinal
00044   // parameterizations of hadron showers are significantly modified for the CMS calorimeter  
00045 
00046   // unit convention: energy in [GeV] and length in [cm]
00047   // intrinsic properties of hadronic showers (lateral shower profile)
00048   
00049   // The step size of showino along the helix trajectory in cm unit
00050   double showerDepthR50 = 0.0;
00051   bool firstHcalHit = true;
00052 
00053   //initial valuses that will be changed as the shower developes
00054   double stepLengthLeft = theShowino->getStepLengthToOut();
00055 
00056   double deltaStep = 0.0;
00057   double showerDepth = 0.0;
00058   Gflash::CalorimeterNumber whichCalor = Gflash::kNULL;
00059 
00060   theGflashHitList.clear();
00061   GflashHit aHit;
00062 
00063   while(stepLengthLeft > 0.0) {
00064 
00065     // update shower depth and stepLengthLeft
00066     if ( stepLengthLeft < Gflash::divisionStep ) {
00067       deltaStep = stepLengthLeft;
00068       stepLengthLeft  = 0.0;
00069     }
00070     else {
00071       deltaStep = Gflash::divisionStep;
00072       stepLengthLeft -= deltaStep;
00073     }
00074 
00075     showerDepth += deltaStep;
00076     showerDepthR50 += deltaStep;
00077 
00078     //update GflashShowino
00079     theShowino->updateShowino(deltaStep);
00080 
00081     //evaluate energy in this deltaStep along the longitudinal shower profile
00082     double heightProfile = 0.; 
00083     double deltaEnergy = 0.;
00084 
00085     whichCalor = Gflash::getCalorimeterNumber(theShowino->getPosition());
00086 
00087     //skip if Showino is outside envelopes
00088     if(whichCalor == Gflash::kNULL ) continue;
00089 
00090     heightProfile = longitudinalProfile();
00091 
00092     //skip if the delta energy for this step will be very small
00093     if(heightProfile < 1.00e-08 ) continue;
00094 
00095     //get energy deposition for this step 
00096     deltaEnergy =  heightProfile*Gflash::divisionStep*energyScale[whichCalor];    
00097     theShowino->addEnergyDeposited(deltaEnergy);
00098 
00099     //apply sampling fluctuation if showino is inside the sampling calorimeter
00100     double hadronicFraction = 1.0;
00101     double fluctuatedEnergy = deltaEnergy;
00102 
00103     int nSpotsInStep = std::max(1,static_cast<int>(getNumberOfSpots(whichCalor)*(deltaEnergy/energyScale[whichCalor]) ));
00104     double sampleSpotEnergy = hadronicFraction*fluctuatedEnergy/nSpotsInStep;
00105 
00106     // Lateral shape and fluctuations
00107 
00108     if((whichCalor==Gflash::kHB || whichCalor==Gflash::kHE) && firstHcalHit) {
00109       firstHcalHit = false;
00110       //reset the showerDepth used in the lateral parameterization inside Hcal
00111       showerDepthR50 = Gflash::divisionStep;
00112     }
00113 
00114     //evaluate the fluctuated median of the lateral distribution, R50
00115     double R50 = medianLateralArm(showerDepthR50,whichCalor);
00116 
00117     double hitEnergy = sampleSpotEnergy*CLHEP::GeV;
00118     double hitTime = theShowino->getGlobalTime()*CLHEP::nanosecond;
00119 
00120     Gflash::CalorimeterNumber hitCalor = Gflash::kNULL;
00121 
00122     for (int ispot = 0 ;  ispot < nSpotsInStep ; ispot++) {
00123         
00124       // Compute global position of generated spots with taking into account magnetic field
00125       // Divide deltaStep into nSpotsInStep and give a spot a global position
00126       double incrementPath = theShowino->getPathLength() 
00127         + (deltaStep/nSpotsInStep)*(ispot+0.5 - 0.5*nSpotsInStep);
00128         
00129       // trajectoryPoint give a spot an imaginary point along the shower development
00130       GflashTrajectoryPoint trajectoryPoint;
00131       theShowino->getHelix()->getGflashTrajectoryPoint(trajectoryPoint,incrementPath);
00132         
00133       Gflash3Vector hitPosition = locateHitPosition(trajectoryPoint,R50);   
00134         
00135       hitCalor = Gflash::getCalorimeterNumber(hitPosition);       
00136       if( hitCalor == Gflash::kNULL) continue;
00137 
00138       hitPosition *= CLHEP::cm;
00139 
00140       aHit.setTime(hitTime);
00141       aHit.setEnergy(hitEnergy);
00142       aHit.setPosition(hitPosition);
00143       theGflashHitList.push_back(aHit);
00144         
00145     } // end of for spot iteration
00146   } // end of while for longitudinal integration
00147 
00148   //HO parameterization
00149 
00150   if(theShowino->getEnergy()> Gflash::MinEnergyCutOffForHO &&
00151      fabs(theShowino->getPositionAtShower().pseudoRapidity()) < Gflash::EtaMax[Gflash::kHO] && 
00152      theGflashHcalOuter) {
00153     
00154     //non zero ho fraction to simulate based on geant4
00155     double nonzeroProb = 0.7*fTanh(theShowino->getEnergy(),Gflash::ho_nonzero);
00156     double r0 = CLHEP::HepUniformRand();
00157     double leftoverE =  theShowino->getEnergy() - theShowino->getEnergyDeposited();
00158 
00159     //@@@ nonzeroProb is not random - need further correlation for non-zero HO energy
00160 
00161     if( r0 < nonzeroProb && leftoverE > 0.0) {
00162             
00163       //starting path Length and stepLengthLeft
00164       double pathLength = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmin[Gflash::kHO]-10);
00165       stepLengthLeft = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHO]+10) - pathLength;
00166       showerDepth = pathLength - theShowino->getPathLengthAtShower();
00167       
00168       theShowino->setPathLength(pathLength);
00169       
00170       double pathLengthx = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHO]);
00171       double pathLengthy = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHB]);
00172       
00173       while(stepLengthLeft > 0.0) {
00174         
00175         // update shower depth and stepLengthLeft
00176         if ( stepLengthLeft < Gflash::divisionStep ) {
00177           deltaStep = stepLengthLeft;
00178           stepLengthLeft  = 0.0;
00179         }
00180         else {
00181           deltaStep = Gflash::divisionStep;
00182           stepLengthLeft -= deltaStep;
00183         }
00184         
00185         showerDepth += deltaStep;
00186         
00187         //update GflashShowino
00188         theShowino->updateShowino(deltaStep);
00189         
00190         //evaluate energy in this deltaStep along the longitudinal shower profile
00191         double heightProfile = 0.; 
00192         double deltaEnergy = 0.;
00193         
00194         double hoScale  = leftoverE*(pathLengthx-pathLengthy)/(pathLengthx- theShowino->getPathLengthAtShower());
00195         double refDepth = theShowino->getPathLength() 
00196           - theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHB]);
00197         
00198         if( refDepth > 0) {
00199           heightProfile = hoProfile(theShowino->getPathLength(),refDepth);
00200           deltaEnergy = heightProfile*Gflash::divisionStep*hoScale;
00201         }
00202         
00203         int nSpotsInStep = std::max(50,static_cast<int>((160.+40* CLHEP::RandGaussQ::shoot())*std::log(theShowino->getEnergy())+50.));
00204         
00205         double hoFraction = 1.00;
00206         double poissonProb = CLHEP::RandPoissonQ::shoot(1.0);
00207         
00208         double fluctuatedEnergy = deltaEnergy*poissonProb;
00209         double sampleSpotEnergy = hoFraction*fluctuatedEnergy/nSpotsInStep;
00210         
00211         // Lateral shape and fluctuations
00212         
00213         //evaluate the fluctuated median of the lateral distribution, R50
00214         double R50 = medianLateralArm(showerDepth,Gflash::kHB);
00215 
00216         double hitEnergy = sampleSpotEnergy*CLHEP::GeV;
00217         double hitTime = theShowino->getGlobalTime()*CLHEP::nanosecond;
00218         
00219         for (int ispot = 0 ;  ispot < nSpotsInStep ; ispot++) {
00220           
00221           double incrementPath = theShowino->getPathLength() 
00222             + (deltaStep/nSpotsInStep)*(ispot+0.5 - 0.5*nSpotsInStep);
00223           
00224           // trajectoryPoint give a spot an imaginary point along the shower development
00225           GflashTrajectoryPoint trajectoryPoint;
00226           theShowino->getHelix()->getGflashTrajectoryPoint(trajectoryPoint,incrementPath);
00227           
00228           Gflash3Vector hitPosition = locateHitPosition(trajectoryPoint,R50);   
00229           hitPosition *= CLHEP::cm;
00230 
00231           if(std::fabs(hitPosition.getZ()/CLHEP::cm) > Gflash::Zmax[Gflash::kHO] ) continue;
00232 
00233           aHit.setTime(hitTime);
00234           aHit.setEnergy(hitEnergy);
00235           aHit.setPosition(hitPosition);
00236           theGflashHitList.push_back(aHit);
00237           
00238         } // end of for HO spot iteration
00239       } // end of while for HO longitudinal integration
00240     }
00241   }
00242 
00243   //  delete theGflashNavigator;
00244 
00245 }
00246 
00247 void GflashHadronShowerProfile::loadParameters()
00248 {
00249   edm::LogInfo("SimGeneralGFlash") << "GflashHadronShowerProfile::loadParameters() "
00250                                    << "should be implimented for each particle type";
00251 }
00252 
00253 double GflashHadronShowerProfile::medianLateralArm(double showerDepthR50, Gflash::CalorimeterNumber kCalor) 
00254 {
00255   double lateralArm = 0.0;
00256   if(kCalor != Gflash::kNULL) {
00257     
00258     double showerDepthR50X = std::min(showerDepthR50/22.4, Gflash::maxShowerDepthforR50);
00259     double R50          = lateralPar[kCalor][0] + std::max(0.0,lateralPar[kCalor][1]) * showerDepthR50X;
00260     double varinanceR50 = std::pow((lateralPar[kCalor][2] + lateralPar[kCalor][3] * showerDepthR50X) * R50, 2);
00261     
00262     // Simulation of lognormal distribution
00263     
00264     if(R50>0) {
00265       double sigmaSq  = std::log(varinanceR50/(R50*R50)+1.0);
00266       double sigmaR50 = std::sqrt(sigmaSq);
00267       double meanR50  = std::log(R50) - (sigmaSq/2.);
00268       
00269       lateralArm = std::exp(meanR50 + sigmaR50* CLHEP::RandGaussQ::shoot());
00270     }
00271   }
00272   return lateralArm;
00273 }
00274 
00275 Gflash3Vector GflashHadronShowerProfile::locateHitPosition(GflashTrajectoryPoint& point, double lateralArm) 
00276 {
00277   // Smearing in r according to f(r)= 2.*r*R50**2/(r**2+R50**2)**2
00278   double rnunif = CLHEP::HepUniformRand();
00279   double rxPDF = std::sqrt(rnunif/(1.-rnunif));
00280   double rShower = lateralArm*rxPDF;
00281   
00282   //rShower within maxLateralArmforR50
00283   rShower = std::min(Gflash::maxLateralArmforR50,rShower);
00284 
00285   // Uniform smearing in phi
00286   double azimuthalAngle = CLHEP::twopi*CLHEP::HepUniformRand(); 
00287 
00288   // actual spot position by adding a radial vector to a trajectoryPoint
00289   Gflash3Vector position = point.getPosition() +
00290     rShower*std::cos(azimuthalAngle)*point.getOrthogonalUnitVector() +
00291     rShower*std::sin(azimuthalAngle)*point.getCrossUnitVector();
00292   
00293   //@@@debugging histograms
00294   if(theHisto->getStoreFlag()) {
00295     theHisto->rshower->Fill(rShower);
00296     theHisto->lateralx->Fill(rShower*std::cos(azimuthalAngle));
00297     theHisto->lateraly->Fill(rShower*std::sin(azimuthalAngle));
00298   }
00299   return position;
00300 }
00301 
00302 //double GflashHadronShowerProfile::longitudinalProfile(double showerDepth, double pathLength) {
00303 double GflashHadronShowerProfile::longitudinalProfile() {
00304 
00305   double heightProfile = 0.0;
00306 
00307   Gflash3Vector pos = theShowino->getPosition();
00308   int showerType = theShowino->getShowerType();
00309   double showerDepth = theShowino->getDepth();
00310   double transDepth = theShowino->getStepLengthToHcal();
00311 
00312   // Energy in a delta step (dz) = (energy to deposite)*[Gamma(z+dz)-Gamma(z)]*dz
00313   // where the incomplete Gamma function gives an intergrate probability of the longitudinal 
00314   // shower up to the shower depth (z).
00315   // Instead, we use approximated energy; energy in dz = (energy to deposite)*gamma(z)*dz
00316   // where gamma is the Gamma-distributed probability function
00317 
00318   Gflash::CalorimeterNumber whichCalor = Gflash::getCalorimeterNumber(pos);
00319 
00320   if(showerType == 0 || showerType == 1 || showerType == 4 || showerType == 5 ) {
00321     if(whichCalor == Gflash::kESPM || whichCalor == Gflash::kENCA ) {
00322       heightProfile = twoGammaProfile(longEcal,showerDepth,whichCalor);
00323     }
00324     else if(whichCalor == Gflash::kHB || whichCalor == Gflash::kHE) {
00325       heightProfile = twoGammaProfile(longHcal,showerDepth-transDepth,whichCalor);
00326     }
00327     else  heightProfile = 0.;
00328   }  
00329   else if (showerType == 2 || showerType == 6 ) {
00330     //two gammas between crystal and Hcal
00331     if((showerDepth - transDepth) > 0.0) {
00332       heightProfile = twoGammaProfile(longHcal,showerDepth-transDepth,Gflash::kHB);
00333     }
00334     else heightProfile = 0.;
00335   }
00336   else if (showerType == 3 || showerType == 7 ) {
00337     //two gammas inside Hcal
00338     heightProfile = twoGammaProfile(longHcal,showerDepth,Gflash::kHB);
00339   }
00340 
00341   return heightProfile;
00342 }
00343 
00344 double GflashHadronShowerProfile::hoProfile(double pathLength, double refDepth) {
00345 
00346   double heightProfile = 0;
00347 
00348   GflashTrajectoryPoint tempPoint;
00349   theShowino->getHelix()->getGflashTrajectoryPoint(tempPoint,pathLength);
00350 
00351   double dint = 1.4*Gflash::intLength[Gflash::kHO]*std::sin(tempPoint.getPosition().getTheta());
00352   heightProfile = std::exp(-1.0*refDepth/dint);
00353 
00354   return heightProfile;
00355 }
00356 
00357 void GflashHadronShowerProfile::getFluctuationVector(double *lowTriangle, double *correlationVector) {
00358 
00359     const int dim = Gflash::NPar;
00360 
00361     double **xr   = new double *[dim];
00362     double **xrho = new double *[dim];
00363     
00364     for(int j=0;j<dim;j++) {
00365       xr[j]   = new double [dim];
00366       xrho[j] = new double [dim];
00367     }
00368     
00369     for(int i = 0; i < dim; i++) {
00370       for(int j = 0; j < i+1 ; j++) {
00371         if(j==i) xrho[i][j] = 1.0;
00372         else {
00373           xrho[i][j] = lowTriangle[i*(i-1)/2 + j];
00374           xrho[j][i] = xrho[i][j];
00375         }
00376       }
00377     }
00378 
00379     doCholeskyReduction(xrho,xr,dim);
00380 
00381     for(int i = 0 ; i < dim ; i++) {
00382       for (int j = 0 ; j < i+1 ; j++){
00383         correlationVector[i*(i+1)/2 + j] = xr[i][j];
00384       }
00385     }
00386 
00387     for(int j=0;j<dim;j++) delete [] xr[j];
00388     delete [] xr;
00389     for(int j=0;j<dim;j++) delete [] xrho[j];
00390     delete [] xrho;
00391 }
00392 
00393 void GflashHadronShowerProfile::doCholeskyReduction(double **vv, double **cc, const int ndim) {
00394 
00395   double sumCjkSquare;
00396   double vjjLess;
00397   double sumCikjk;
00398 
00399   cc[0][0] = std::sqrt(vv[0][0]);
00400 
00401   for(int j=1 ; j < ndim ; j++) {
00402     cc[j][0] = vv[j][0]/cc[0][0];
00403   }
00404 
00405   for(int j=1 ; j < ndim ; j++) {
00406 
00407     sumCjkSquare = 0.0;
00408     for (int k=0 ; k < j ; k++) sumCjkSquare += cc[j][k]*cc[j][k];
00409 
00410     vjjLess =  vv[j][j] - sumCjkSquare;
00411 
00412     //check for the case that vjjLess is negative
00413     cc[j][j] = std::sqrt(std::fabs(vjjLess));
00414 
00415     for (int i=j+1 ; i < ndim ; i++) {
00416       sumCikjk = 0.;
00417       for(int k=0 ; k < j ; k++) sumCikjk += cc[i][k]*cc[j][k];
00418       cc[i][j] = (vv[i][j] - sumCikjk)/cc[j][j];
00419     }
00420   }
00421 }
00422 
00423 int GflashHadronShowerProfile::getNumberOfSpots(Gflash::CalorimeterNumber kCalor) {
00424   //generator number of spots: energy dependent Gamma distribution of Nspots based on Geant4
00425   //replacing old parameterization of H1,
00426   //int numberOfSpots = std::max( 50, static_cast<int>(80.*std::log(einc)+50.));
00427 
00428   double einc = theShowino->getEnergy();
00429   int showerType = theShowino->getShowerType();
00430 
00431   int numberOfSpots = 0;
00432   double nmean  = 0.0;
00433   double nsigma = 0.0;
00434 
00435   if(showerType == 0 || showerType == 1 || showerType == 4 || showerType == 5 ) {
00436     if(kCalor == Gflash::kESPM || kCalor == Gflash::kENCA) {
00437       nmean = 10000 + 5000*log(einc);
00438       nsigma = 1000;
00439     }
00440     if(kCalor == Gflash::kHB || kCalor == Gflash::kHE) {
00441       nmean =  5000 + 2500*log(einc);
00442       nsigma =  500;
00443     }
00444   }
00445   else if (showerType == 2 || showerType == 3 || showerType == 6 || showerType == 7 ) {
00446     if(kCalor == Gflash::kHB || kCalor == Gflash::kHE) {
00447       nmean =  5000 + 2500*log(einc);
00448       nsigma =  500;
00449     }
00450     else {
00451       nmean = 10000;
00452       nsigma = 1000;
00453     }
00454   }
00455   //@@@need correlation and individual fluctuation on alphaNspots and betaNspots here:
00456   //evaluating covariance should be straight forward since the distribution is 'one' Gamma
00457 
00458   numberOfSpots = std::max(500,static_cast<int> (nmean+nsigma* CLHEP::RandGaussQ::shoot()));
00459 
00460   //until we optimize the reduction scale in the number of Nspots
00461       
00462   if( kCalor == Gflash::kESPM ||  kCalor == Gflash::kENCA) {
00463     numberOfSpots = static_cast<int>(numberOfSpots/100);
00464   }
00465   else {
00466     numberOfSpots = static_cast<int>(numberOfSpots/3.0);
00467   }
00468 
00469   return numberOfSpots;
00470 }
00471 
00472 double GflashHadronShowerProfile::fTanh(double einc, const double *par) {
00473   double func = 0.0;
00474   if(einc>0.0) func = par[0]+par[1]*std::tanh(par[2]*(std::log(einc)-par[3]));
00475   return func;
00476 }
00477 
00478 double GflashHadronShowerProfile::fLnE1(double einc, const double *par) {
00479   double func = 0.0;
00480   if(einc>0.0) func = par[0]+par[1]*std::log(einc);
00481   return func;
00482 }
00483 
00484 double GflashHadronShowerProfile::depthScale(double ssp, double ssp0, double length) {
00485   double func = 0.0;
00486   if(length>0.0) func = std::pow((ssp-ssp0)/length,2.0);
00487   return func;
00488 }
00489 
00490 double GflashHadronShowerProfile::gammaProfile(double alpha, double beta, double showerDepth, double lengthUnit) {
00491   double gamma = 0.0;
00492   //  if(alpha > 0 && beta > 0 && lengthUnit > 0) {
00493   if(showerDepth>0.0) {
00494     Genfun::LogGamma lgam;
00495     double x = showerDepth*(beta/lengthUnit);
00496     gamma = (beta/lengthUnit)*std::pow(x,alpha-1.0)*std::exp(-x)/std::exp(lgam(alpha));
00497   }
00498   return gamma;
00499 }
00500  
00501 double GflashHadronShowerProfile::twoGammaProfile(double *longPar, double depth, Gflash::CalorimeterNumber kIndex) {
00502   double twoGamma = 0.0;
00503 
00504   longPar[0] = std::min(1.0,longPar[0]);
00505   if(longPar[3] > 4.0 || longPar[4] > 4.0) {
00506     double rfactor = 2.0/std::max(longPar[3],longPar[4]);
00507     longPar[3] = rfactor*(longPar[3]+1.0);  
00508     longPar[4] *= rfactor;  
00509   }
00510 
00511   twoGamma  = longPar[0]*gammaProfile(exp(longPar[1]),exp(longPar[2]),depth,Gflash::radLength[kIndex])
00512          +(1-longPar[0])*gammaProfile(exp(longPar[3]),exp(longPar[4]),depth,Gflash::intLength[kIndex]);
00513   return twoGamma;
00514 }