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
00035 theShowino->initialize(showerType, energy, globalTime, charge,
00036 position, momentum, theBField);
00037
00038 }
00039
00040 void GflashHadronShowerProfile::hadronicParameterization()
00041 {
00042
00043
00044
00045
00046
00047
00048
00049
00050 double showerDepthR50 = 0.0;
00051 bool firstHcalHit = true;
00052
00053
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
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
00079 theShowino->updateShowino(deltaStep);
00080
00081
00082 double heightProfile = 0.;
00083 double deltaEnergy = 0.;
00084
00085 whichCalor = Gflash::getCalorimeterNumber(theShowino->getPosition());
00086
00087
00088 if(whichCalor == Gflash::kNULL ) continue;
00089
00090 heightProfile = longitudinalProfile();
00091
00092
00093 if(heightProfile < 1.00e-08 ) continue;
00094
00095
00096 deltaEnergy = heightProfile*Gflash::divisionStep*energyScale[whichCalor];
00097 theShowino->addEnergyDeposited(deltaEnergy);
00098
00099
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
00107
00108 if((whichCalor==Gflash::kHB || whichCalor==Gflash::kHE) && firstHcalHit) {
00109 firstHcalHit = false;
00110
00111 showerDepthR50 = Gflash::divisionStep;
00112 }
00113
00114
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
00125
00126 double incrementPath = theShowino->getPathLength()
00127 + (deltaStep/nSpotsInStep)*(ispot+0.5 - 0.5*nSpotsInStep);
00128
00129
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 }
00146 }
00147
00148
00149
00150 if(theShowino->getEnergy()> Gflash::MinEnergyCutOffForHO &&
00151 fabs(theShowino->getPositionAtShower().pseudoRapidity()) < Gflash::EtaMax[Gflash::kHO] &&
00152 theGflashHcalOuter) {
00153
00154
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
00160
00161 if( r0 < nonzeroProb && leftoverE > 0.0) {
00162
00163
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
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
00188 theShowino->updateShowino(deltaStep);
00189
00190
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
00212
00213
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
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 }
00239 }
00240 }
00241 }
00242
00243
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
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
00278 double rnunif = CLHEP::HepUniformRand();
00279 double rxPDF = std::sqrt(rnunif/(1.-rnunif));
00280 double rShower = lateralArm*rxPDF;
00281
00282
00283 rShower = std::min(Gflash::maxLateralArmforR50,rShower);
00284
00285
00286 double azimuthalAngle = CLHEP::twopi*CLHEP::HepUniformRand();
00287
00288
00289 Gflash3Vector position = point.getPosition() +
00290 rShower*std::cos(azimuthalAngle)*point.getOrthogonalUnitVector() +
00291 rShower*std::sin(azimuthalAngle)*point.getCrossUnitVector();
00292
00293
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
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
00313
00314
00315
00316
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
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
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
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
00425
00426
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
00456
00457
00458 numberOfSpots = std::max(500,static_cast<int> (nmean+nsigma* CLHEP::RandGaussQ::shoot()));
00459
00460
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
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 }