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
00059 Gflash::CalorimeterNumber whichCalor = Gflash::kNULL;
00060
00061 theGflashHitList.clear();
00062
00063 GflashHit aHit;
00064
00065 while(stepLengthLeft > 0.0) {
00066
00067
00068 if ( stepLengthLeft < Gflash::divisionStep ) {
00069 deltaStep = stepLengthLeft;
00070 stepLengthLeft = 0.0;
00071 }
00072 else {
00073 deltaStep = Gflash::divisionStep;
00074 stepLengthLeft -= deltaStep;
00075 }
00076
00077 showerDepth += deltaStep;
00078 showerDepthR50 += deltaStep;
00079
00080
00081 theShowino->updateShowino(deltaStep);
00082
00083
00084 double heightProfile = 0.;
00085 double deltaEnergy = 0.;
00086
00087 whichCalor = Gflash::getCalorimeterNumber(theShowino->getPosition());
00088
00089
00090 if(whichCalor == Gflash::kNULL ) continue;
00091
00092 heightProfile = longitudinalProfile();
00093
00094
00095 if(heightProfile < 1.00e-08 ) continue;
00096
00097
00098 deltaEnergy = heightProfile*Gflash::divisionStep*energyScale[whichCalor];
00099 theShowino->addEnergyDeposited(deltaEnergy);
00100
00101
00102 double hadronicFraction = 1.0;
00103 double fluctuatedEnergy = deltaEnergy;
00104
00105 int nSpotsInStep = std::max(1,static_cast<int>(getNumberOfSpots(whichCalor)*(deltaEnergy/energyScale[whichCalor]) ));
00106 double sampleSpotEnergy = hadronicFraction*fluctuatedEnergy/nSpotsInStep;
00107
00108
00109
00110 if((whichCalor==Gflash::kHB || whichCalor==Gflash::kHE) && firstHcalHit) {
00111 firstHcalHit = false;
00112
00113 showerDepthR50 = Gflash::divisionStep;
00114 }
00115
00116
00117 double R50 = medianLateralArm(showerDepthR50,whichCalor);
00118
00119 double hitEnergy = sampleSpotEnergy*CLHEP::GeV;
00120 double hitTime = theShowino->getGlobalTime()*CLHEP::nanosecond;
00121
00122 Gflash::CalorimeterNumber hitCalor = Gflash::kNULL;
00123
00124 for (int ispot = 0 ; ispot < nSpotsInStep ; ispot++) {
00125
00126
00127
00128 double incrementPath = theShowino->getPathLength()
00129 + (deltaStep/nSpotsInStep)*(ispot+0.5 - 0.5*nSpotsInStep);
00130
00131
00132 GflashTrajectoryPoint trajectoryPoint;
00133 theShowino->getHelix()->getGflashTrajectoryPoint(trajectoryPoint,incrementPath);
00134
00135 Gflash3Vector hitPosition = locateHitPosition(trajectoryPoint,R50);
00136
00137 hitCalor = Gflash::getCalorimeterNumber(hitPosition);
00138
00139 if( hitCalor == Gflash::kNULL) continue;
00140
00141 hitPosition *= CLHEP::cm;
00142
00143 aHit.setTime(hitTime);
00144 aHit.setEnergy(hitEnergy);
00145 aHit.setPosition(hitPosition);
00146 theGflashHitList.push_back(aHit);
00147
00148 }
00149 }
00150
00151
00152
00153 if(theShowino->getEnergy()> Gflash::MinEnergyCutOffForHO &&
00154 fabs(theShowino->getPositionAtShower().pseudoRapidity()) < Gflash::EtaMax[Gflash::kHO] &&
00155 theGflashHcalOuter) {
00156
00157
00158 double nonzeroProb = 0.7*fTanh(theShowino->getEnergy(),Gflash::ho_nonzero);
00159 double r0 = CLHEP::HepUniformRand();
00160 double leftoverE = theShowino->getEnergy() - theShowino->getEnergyDeposited();
00161
00162
00163
00164 if( r0 < nonzeroProb && leftoverE > 0.0) {
00165
00166
00167 double pathLength = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmin[Gflash::kHO]-10);
00168 stepLengthLeft = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHO]+10) - pathLength;
00169 showerDepth = pathLength - theShowino->getPathLengthAtShower();
00170
00171 theShowino->setPathLength(pathLength);
00172
00173 double pathLengthx = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHO]);
00174 double pathLengthy = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHB]);
00175
00176 while(stepLengthLeft > 0.0) {
00177
00178
00179 if ( stepLengthLeft < Gflash::divisionStep ) {
00180 deltaStep = stepLengthLeft;
00181 stepLengthLeft = 0.0;
00182 }
00183 else {
00184 deltaStep = Gflash::divisionStep;
00185 stepLengthLeft -= deltaStep;
00186 }
00187
00188 showerDepth += deltaStep;
00189
00190
00191 theShowino->updateShowino(deltaStep);
00192
00193
00194 double heightProfile = 0.;
00195 double deltaEnergy = 0.;
00196
00197 double hoScale = leftoverE*(pathLengthx-pathLengthy)/(pathLengthx- theShowino->getPathLengthAtShower());
00198 double refDepth = theShowino->getPathLength()
00199 - theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHB]);
00200
00201 if( refDepth > 0) {
00202 heightProfile = hoProfile(theShowino->getPathLength(),refDepth);
00203 deltaEnergy = heightProfile*Gflash::divisionStep*hoScale;
00204 }
00205
00206 int nSpotsInStep = std::max(50,static_cast<int>((160.+40* CLHEP::RandGaussQ::shoot())*std::log(theShowino->getEnergy())+50.));
00207
00208 double hoFraction = 1.00;
00209 double poissonProb = CLHEP::RandPoissonQ::shoot(1.0);
00210
00211 double fluctuatedEnergy = deltaEnergy*poissonProb;
00212 double sampleSpotEnergy = hoFraction*fluctuatedEnergy/nSpotsInStep;
00213
00214
00215
00216
00217 double R50 = medianLateralArm(showerDepth,Gflash::kHB);
00218
00219 double hitEnergy = sampleSpotEnergy*CLHEP::GeV;
00220 double hitTime = theShowino->getGlobalTime()*CLHEP::nanosecond;
00221
00222 for (int ispot = 0 ; ispot < nSpotsInStep ; ispot++) {
00223
00224 double incrementPath = theShowino->getPathLength()
00225 + (deltaStep/nSpotsInStep)*(ispot+0.5 - 0.5*nSpotsInStep);
00226
00227
00228 GflashTrajectoryPoint trajectoryPoint;
00229 theShowino->getHelix()->getGflashTrajectoryPoint(trajectoryPoint,incrementPath);
00230
00231 Gflash3Vector hitPosition = locateHitPosition(trajectoryPoint,R50);
00232 hitPosition *= CLHEP::cm;
00233
00234 if(std::fabs(hitPosition.getZ()/CLHEP::cm) > Gflash::Zmax[Gflash::kHO] ) continue;
00235
00236 aHit.setTime(hitTime);
00237 aHit.setEnergy(hitEnergy);
00238 aHit.setPosition(hitPosition);
00239 theGflashHitList.push_back(aHit);
00240
00241 }
00242 }
00243 }
00244 }
00245
00246
00247
00248 }
00249
00250 void GflashHadronShowerProfile::loadParameters()
00251 {
00252 edm::LogInfo("SimGeneralGFlash") << "GflashHadronShowerProfile::loadParameters() "
00253 << "should be implimented for each particle type";
00254 }
00255
00256 double GflashHadronShowerProfile::medianLateralArm(double showerDepthR50, Gflash::CalorimeterNumber kCalor)
00257 {
00258 double lateralArm = 0.0;
00259 if(kCalor != Gflash::kNULL) {
00260
00261 double showerDepthR50X = std::min(showerDepthR50/22.4, Gflash::maxShowerDepthforR50);
00262 double R50 = lateralPar[kCalor][0] + std::max(0.0,lateralPar[kCalor][1]) * showerDepthR50X;
00263 double varinanceR50 = std::pow((lateralPar[kCalor][2] + lateralPar[kCalor][3] * showerDepthR50X) * R50, 2);
00264
00265
00266
00267 if(R50>0) {
00268 double sigmaSq = std::log(varinanceR50/(R50*R50)+1.0);
00269 double sigmaR50 = std::sqrt(sigmaSq);
00270 double meanR50 = std::log(R50) - (sigmaSq/2.);
00271
00272 lateralArm = std::exp(meanR50 + sigmaR50* CLHEP::RandGaussQ::shoot());
00273 }
00274 }
00275 return lateralArm;
00276 }
00277
00278 Gflash3Vector GflashHadronShowerProfile::locateHitPosition(GflashTrajectoryPoint& point, double lateralArm)
00279 {
00280
00281 double rnunif = CLHEP::HepUniformRand();
00282 double rxPDF = std::sqrt(rnunif/(1.-rnunif));
00283 double rShower = lateralArm*rxPDF;
00284
00285
00286 rShower = std::min(Gflash::maxLateralArmforR50,rShower);
00287
00288
00289 double azimuthalAngle = CLHEP::twopi*CLHEP::HepUniformRand();
00290
00291
00292 Gflash3Vector position = point.getPosition() +
00293 rShower*std::cos(azimuthalAngle)*point.getOrthogonalUnitVector() +
00294 rShower*std::sin(azimuthalAngle)*point.getCrossUnitVector();
00295
00296
00297 if(theHisto->getStoreFlag()) {
00298 theHisto->rshower->Fill(rShower);
00299 theHisto->lateralx->Fill(rShower*std::cos(azimuthalAngle));
00300 theHisto->lateraly->Fill(rShower*std::sin(azimuthalAngle));
00301 }
00302 return position;
00303 }
00304
00305
00306 double GflashHadronShowerProfile::longitudinalProfile() {
00307
00308 double heightProfile = 0.0;
00309
00310 Gflash3Vector pos = theShowino->getPosition();
00311 int showerType = theShowino->getShowerType();
00312 double showerDepth = theShowino->getDepth();
00313 double transDepth = theShowino->getStepLengthToHcal();
00314
00315
00316
00317
00318
00319
00320
00321 Gflash::CalorimeterNumber whichCalor = Gflash::getCalorimeterNumber(pos);
00322
00323 if(showerType == 0 || showerType == 4 ) {
00324 double shiftDepth = theShowino->getPathLengthOnEcal() - theShowino->getPathLengthAtShower();
00325 if(shiftDepth > 0 ) {
00326 heightProfile = twoGammaProfile(longEcal,showerDepth-shiftDepth,whichCalor);
00327 }
00328 else {
00329 heightProfile = 0.;
00330
00331 }
00332 }
00333 else if(showerType == 1 || showerType == 5 ) {
00334 if(whichCalor == Gflash::kESPM || whichCalor == Gflash::kENCA ) {
00335 heightProfile = twoGammaProfile(longEcal,showerDepth,whichCalor);
00336 }
00337 else if(whichCalor == Gflash::kHB || whichCalor == Gflash::kHE) {
00338 heightProfile = twoGammaProfile(longHcal,showerDepth-transDepth,whichCalor);
00339 }
00340 else heightProfile = 0.;
00341 }
00342 else if (showerType == 2 || showerType == 6 ) {
00343
00344 if((showerDepth - transDepth) > 0.0) {
00345 heightProfile = twoGammaProfile(longHcal,showerDepth-transDepth,Gflash::kHB);
00346 }
00347 else heightProfile = 0.;
00348 }
00349 else if (showerType == 3 || showerType == 7 ) {
00350
00351 heightProfile = twoGammaProfile(longHcal,showerDepth,Gflash::kHB);
00352 }
00353
00354 return heightProfile;
00355 }
00356
00357 double GflashHadronShowerProfile::hoProfile(double pathLength, double refDepth) {
00358
00359 double heightProfile = 0;
00360
00361 GflashTrajectoryPoint tempPoint;
00362 theShowino->getHelix()->getGflashTrajectoryPoint(tempPoint,pathLength);
00363
00364 double dint = 1.4*Gflash::intLength[Gflash::kHO]*std::sin(tempPoint.getPosition().getTheta());
00365 heightProfile = std::exp(-1.0*refDepth/dint);
00366
00367 return heightProfile;
00368 }
00369
00370 void GflashHadronShowerProfile::getFluctuationVector(double *lowTriangle, double *correlationVector) {
00371
00372 const int dim = Gflash::NPar;
00373
00374 double **xr = new double *[dim];
00375 double **xrho = new double *[dim];
00376
00377 for(int j=0;j<dim;j++) {
00378 xr[j] = new double [dim];
00379 xrho[j] = new double [dim];
00380 }
00381
00382 for(int i = 0; i < dim; i++) {
00383 for(int j = 0; j < i+1 ; j++) {
00384 if(j==i) xrho[i][j] = 1.0;
00385 else {
00386 xrho[i][j] = lowTriangle[i*(i-1)/2 + j];
00387 xrho[j][i] = xrho[i][j];
00388 }
00389 }
00390 }
00391
00392 doCholeskyReduction(xrho,xr,dim);
00393
00394 for(int i = 0 ; i < dim ; i++) {
00395 for (int j = 0 ; j < i+1 ; j++){
00396 correlationVector[i*(i+1)/2 + j] = xr[i][j];
00397 }
00398 }
00399
00400 for(int j=0;j<dim;j++) delete [] xr[j];
00401 delete [] xr;
00402 for(int j=0;j<dim;j++) delete [] xrho[j];
00403 delete [] xrho;
00404 }
00405
00406 void GflashHadronShowerProfile::doCholeskyReduction(double **vv, double **cc, const int ndim) {
00407
00408 double sumCjkSquare;
00409 double vjjLess;
00410 double sumCikjk;
00411
00412 cc[0][0] = std::sqrt(vv[0][0]);
00413
00414 for(int j=1 ; j < ndim ; j++) {
00415 cc[j][0] = vv[j][0]/cc[0][0];
00416 }
00417
00418 for(int j=1 ; j < ndim ; j++) {
00419
00420 sumCjkSquare = 0.0;
00421 for (int k=0 ; k < j ; k++) sumCjkSquare += cc[j][k]*cc[j][k];
00422
00423 vjjLess = vv[j][j] - sumCjkSquare;
00424
00425
00426 cc[j][j] = std::sqrt(std::fabs(vjjLess));
00427
00428 for (int i=j+1 ; i < ndim ; i++) {
00429 sumCikjk = 0.;
00430 for(int k=0 ; k < j ; k++) sumCikjk += cc[i][k]*cc[j][k];
00431 cc[i][j] = (vv[i][j] - sumCikjk)/cc[j][j];
00432 }
00433 }
00434 }
00435
00436 int GflashHadronShowerProfile::getNumberOfSpots(Gflash::CalorimeterNumber kCalor) {
00437
00438
00439
00440
00441 double einc = theShowino->getEnergy();
00442 int showerType = theShowino->getShowerType();
00443
00444 int numberOfSpots = 0;
00445 double nmean = 0.0;
00446 double nsigma = 0.0;
00447
00448 if(showerType == 0 || showerType == 1 || showerType == 4 || showerType == 5 ) {
00449 if(kCalor == Gflash::kESPM || kCalor == Gflash::kENCA) {
00450 nmean = 10000 + 5000*log(einc);
00451 nsigma = 1000;
00452 }
00453 if(kCalor == Gflash::kHB || kCalor == Gflash::kHE) {
00454 nmean = 5000 + 2500*log(einc);
00455 nsigma = 500;
00456 }
00457 }
00458 else if (showerType == 2 || showerType == 3 || showerType == 6 || showerType == 7 ) {
00459 if(kCalor == Gflash::kHB || kCalor == Gflash::kHE) {
00460 nmean = 5000 + 2500*log(einc);
00461 nsigma = 500;
00462 }
00463 else {
00464 nmean = 10000;
00465 nsigma = 1000;
00466 }
00467 }
00468
00469
00470
00471 numberOfSpots = std::max(500,static_cast<int> (nmean+nsigma* CLHEP::RandGaussQ::shoot()));
00472
00473
00474
00475 if( kCalor == Gflash::kESPM || kCalor == Gflash::kENCA) {
00476 numberOfSpots = static_cast<int>(numberOfSpots/100);
00477 }
00478 else {
00479 numberOfSpots = static_cast<int>(numberOfSpots/3.0);
00480 }
00481
00482 return numberOfSpots;
00483 }
00484
00485 double GflashHadronShowerProfile::fTanh(double einc, const double *par) {
00486 double func = 0.0;
00487 if(einc>0.0) func = par[0]+par[1]*std::tanh(par[2]*(std::log(einc)-par[3])) + par[4]*std::log(einc);
00488 return func;
00489 }
00490
00491 double GflashHadronShowerProfile::fLnE1(double einc, const double *par) {
00492 double func = 0.0;
00493 if(einc>0.0) func = par[0]+par[1]*std::log(einc);
00494 return func;
00495 }
00496
00497 double GflashHadronShowerProfile::depthScale(double ssp, double ssp0, double length) {
00498 double func = 0.0;
00499 if(length>0.0) func = std::pow((ssp-ssp0)/length,2.0);
00500 return func;
00501 }
00502
00503 double GflashHadronShowerProfile::gammaProfile(double alpha, double beta, double showerDepth, double lengthUnit) {
00504 double gamma = 0.0;
00505
00506 if(showerDepth>0.0) {
00507 Genfun::LogGamma lgam;
00508 double x = showerDepth*(beta/lengthUnit);
00509 gamma = (beta/lengthUnit)*std::pow(x,alpha-1.0)*std::exp(-x)/std::exp(lgam(alpha));
00510 }
00511 return gamma;
00512 }
00513
00514 double GflashHadronShowerProfile::twoGammaProfile(double *longPar, double depth, Gflash::CalorimeterNumber kIndex) {
00515 double twoGamma = 0.0;
00516
00517 longPar[0] = std::min(1.0,longPar[0]);
00518 longPar[0] = std::max(0.0,longPar[0]);
00519
00520 if(longPar[3] > 4.0 || longPar[4] > 4.0) {
00521 double rfactor = 2.0/std::max(longPar[3],longPar[4]);
00522 longPar[3] = rfactor*(longPar[3]+1.0);
00523 longPar[4] *= rfactor;
00524 }
00525
00526 twoGamma = longPar[0]*gammaProfile(exp(longPar[1]),exp(longPar[2]),depth,Gflash::radLength[kIndex])
00527 +(1-longPar[0])*gammaProfile(exp(longPar[3]),exp(longPar[4]),depth,Gflash::intLength[kIndex]);
00528 return twoGamma;
00529 }