File indexing completed on 2024-04-06 12:11:19
0001
0002 #include "FastSimulation/ShowerDevelopment/interface/EMShower.h"
0003 #include "FastSimulation/CaloHitMakers/interface/EcalHitMaker.h"
0004 #include "FastSimulation/CaloHitMakers/interface/PreshowerHitMaker.h"
0005 #include "FastSimulation/CaloHitMakers/interface/HcalHitMaker.h"
0006
0007 #include "FastSimulation/Utilities/interface/RandomEngineAndDistribution.h"
0008 #include "FastSimulation/Utilities/interface/GammaFunctionGenerator.h"
0009
0010 #include <cmath>
0011
0012
0013
0014 using std::vector;
0015
0016 EMShower::EMShower(const RandomEngineAndDistribution* engine,
0017 GammaFunctionGenerator* gamma,
0018 EMECALShowerParametrization* const myParam,
0019 vector<const RawParticle*>* const myPart,
0020 EcalHitMaker* const myGrid,
0021 PreshowerHitMaker* const myPresh,
0022 bool bFixedLength)
0023
0024 : theParam(myParam),
0025 thePart(myPart),
0026 theGrid(myGrid),
0027 thePreshower(myPresh),
0028 random(engine),
0029 myGammaGenerator(gamma),
0030 bFixedLength_(bFixedLength) {
0031
0032
0033
0034 stepsCalculated = false;
0035 hasPreshower = myPresh != nullptr;
0036 theECAL = myParam->ecalProperties();
0037 theHCAL = myParam->hcalProperties();
0038 theLayer1 = myParam->layer1Properties();
0039 theLayer2 = myParam->layer2Properties();
0040
0041 double fotos = theECAL->photoStatistics() * theECAL->lightCollectionEfficiency();
0042
0043 nPart = thePart->size();
0044 totalEnergy = 0.;
0045 globalMaximum = 0.;
0046
0047
0048
0049 for (unsigned int i = 0; i < nPart; ++i) {
0050
0051
0052 Etot.push_back(0.);
0053 E.push_back(((*thePart)[i])->e());
0054 totalEnergy += E[i];
0055
0056 double lny = std::log(E[i] / theECAL->criticalEnergy());
0057
0058
0059 double theMeanT = myParam->meanT(lny);
0060 double theMeanAlpha = myParam->meanAlpha(lny);
0061 double theMeanLnT = myParam->meanLnT(lny);
0062 double theMeanLnAlpha = myParam->meanLnAlpha(lny);
0063 double theSigmaLnT = myParam->sigmaLnT(lny);
0064 double theSigmaLnAlpha = myParam->sigmaLnAlpha(lny);
0065
0066
0067 double theCorrelation = myParam->correlationAlphaT(lny);
0068 double rhop = std::sqrt((1. + theCorrelation) / 2.);
0069 double rhom = std::sqrt((1. - theCorrelation) / 2.);
0070
0071
0072 theNumberOfSpots.push_back(myParam->nSpots(E[i]));
0073
0074
0075
0076
0077 photos.push_back(E[i] * fotos);
0078
0079
0080
0081 double z1 = 0.;
0082 double z2 = 0.;
0083 double aa = 0.;
0084
0085
0086 while (aa <= 1.) {
0087 z1 = random->gaussShoot(0., 1.);
0088 z2 = random->gaussShoot(0., 1.);
0089 aa = std::exp(theMeanLnAlpha + theSigmaLnAlpha * (z1 * rhop - z2 * rhom));
0090 }
0091
0092 a.push_back(aa);
0093 T.push_back(std::exp(theMeanLnT + theSigmaLnT * (z1 * rhop + z2 * rhom)));
0094 b.push_back((a[i] - 1.) / T[i]);
0095 maximumOfShower.push_back((a[i] - 1.) / b[i]);
0096 globalMaximum += maximumOfShower[i] * E[i];
0097
0098
0099
0100 Ti.push_back(a[i] / b[i] * (std::exp(theMeanLnAlpha) - 1.) / std::exp(theMeanLnAlpha));
0101
0102
0103 TSpot.push_back(theParam->meanTSpot(theMeanT));
0104 aSpot.push_back(theParam->meanAlphaSpot(theMeanAlpha));
0105 bSpot.push_back((aSpot[i] - 1.) / TSpot[i]);
0106
0107
0108 }
0109
0110
0111
0112
0113
0114
0115
0116 globalMaximum /= totalEnergy;
0117
0118
0119 }
0120
0121 void EMShower::prepareSteps() {
0122
0123
0124
0125
0126 double dt;
0127 double radlen;
0128 int stps;
0129 int first_Ecal_step = 0;
0130 int last_Ecal_step = 0;
0131
0132
0133 steps.reserve(24);
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 radlen = -theGrid->x0DepthOffset();
0146
0147
0148 radlen += theGrid->ps1TotalX0();
0149 if (radlen > 0.) {
0150 steps.push_back(Step(0, radlen));
0151 radlen = 0.;
0152 }
0153
0154
0155 radlen += theGrid->ps2TotalX0();
0156 if (radlen > 0.) {
0157 steps.push_back(Step(1, radlen));
0158 radlen = 0.;
0159 }
0160
0161
0162 radlen += theGrid->ps2eeTotalX0();
0163 if (radlen > 0.) {
0164 steps.push_back(Step(5, radlen));
0165 radlen = 0.;
0166 }
0167
0168
0169 radlen += theGrid->ecalTotalX0();
0170
0171
0172
0173 if (radlen > 0.) {
0174 if (!bFixedLength_) {
0175 stps = (int)((radlen + 2.5) / 5.);
0176
0177 if (stps == 0)
0178 stps = 1;
0179 dt = radlen / (double)stps;
0180 Step step(2, dt);
0181 first_Ecal_step = steps.size();
0182 for (int ist = 0; ist < stps; ++ist)
0183 steps.push_back(step);
0184 last_Ecal_step = steps.size() - 1;
0185 radlen = 0.;
0186 } else {
0187 dt = 1.0;
0188 stps = static_cast<int>(radlen);
0189 if (stps == 0)
0190 stps = 1;
0191 Step step(2, dt);
0192 first_Ecal_step = steps.size();
0193 for (int ist = 0; ist < stps; ++ist)
0194 steps.push_back(step);
0195 dt = radlen - stps;
0196 if (dt > 0) {
0197 Step stepLast(2, dt);
0198 steps.push_back(stepLast);
0199 }
0200 last_Ecal_step = steps.size() - 1;
0201
0202 radlen = 0.;
0203 }
0204 }
0205
0206
0207
0208
0209 radlen += theGrid->hcalTotalX0();
0210 if (radlen > 0.) {
0211 double dtFrontHcal = theGrid->totalX0() - theGrid->hcalTotalX0();
0212
0213 if (dtFrontHcal < 30.) {
0214 dt = 30. - dtFrontHcal;
0215 Step step(3, dt);
0216 steps.push_back(step);
0217 }
0218 }
0219
0220 nSteps = steps.size();
0221 if (nSteps == 0)
0222 return;
0223 double ESliceTot = 0.;
0224 double MeanDepth = 0.;
0225 depositedEnergy.resize(nSteps);
0226 meanDepth.resize(nSteps);
0227 double t = 0.;
0228
0229 int offset = 0;
0230 for (unsigned iStep = 0; iStep < nSteps; ++iStep) {
0231 ESliceTot = 0.;
0232 MeanDepth = 0.;
0233 double realTotalEnergy = 0;
0234 dt = steps[iStep].second;
0235 t += dt;
0236 for (unsigned int i = 0; i < nPart; ++i) {
0237 depositedEnergy[iStep].push_back(deposit(t, a[i], b[i], dt));
0238 ESliceTot += depositedEnergy[iStep][i];
0239 MeanDepth += deposit(t, a[i] + 1., b[i], dt) / b[i] * a[i];
0240 realTotalEnergy += depositedEnergy[iStep][i] * E[i];
0241 }
0242
0243 if (ESliceTot > 0.)
0244 MeanDepth /= ESliceTot;
0245 else
0246 MeanDepth = t - dt;
0247
0248 meanDepth[iStep] = MeanDepth;
0249 if (realTotalEnergy < 0.001) {
0250 offset -= 1;
0251 }
0252 }
0253
0254 innerDepth = meanDepth[first_Ecal_step];
0255 if (last_Ecal_step + offset >= 0)
0256 outerDepth = meanDepth[last_Ecal_step + offset];
0257 else
0258 outerDepth = innerDepth;
0259
0260 stepsCalculated = true;
0261 }
0262
0263 void EMShower::compute() {
0264 double t = 0.;
0265 double dt = 0.;
0266 if (!stepsCalculated)
0267 prepareSteps();
0268
0269
0270
0271
0272
0273
0274 bool status = false;
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284 for (unsigned iStep = 0; iStep < nSteps; ++iStep) {
0285
0286 dt = steps[iStep].second;
0287
0288
0289
0290
0291 t += dt;
0292
0293
0294 unsigned detector = steps[iStep].first;
0295
0296 bool presh1 = detector == 0;
0297 bool presh2 = detector == 1;
0298 bool ecal = detector == 2;
0299 bool hcal = detector == 3;
0300 bool vfcal = detector == 4;
0301 bool gap = detector == 5;
0302
0303
0304 if (theHCAL == nullptr)
0305 hcal = false;
0306
0307
0308 if (vfcal)
0309 continue;
0310
0311
0312 if (gap)
0313 continue;
0314
0315
0316
0317
0318
0319
0320
0321
0322 double tt = t - 0.5 * dt;
0323
0324 double realTotalEnergy = 0.;
0325 for (unsigned int i = 0; i < nPart; ++i) {
0326 realTotalEnergy += depositedEnergy[iStep][i] * E[i];
0327 }
0328
0329
0330
0331
0332
0333
0334 bool usePreviousGrid = (realTotalEnergy < 0.001);
0335
0336
0337
0338
0339
0340 if (iStep > 2 && realTotalEnergy < 0.000001)
0341 continue;
0342
0343 if (ecal && !usePreviousGrid) {
0344 status = theGrid->getPads(meanDepth[iStep]);
0345 }
0346 if (hcal) {
0347 status = theHcalHitMaker->setDepth(tt);
0348 }
0349 if ((ecal || hcal) && !status)
0350 continue;
0351
0352 bool detailedShowerTail = false;
0353
0354 if (ecal && !usePreviousGrid) {
0355 detailedShowerTail = (t - dt > theGrid->getX0back());
0356 }
0357
0358
0359 for (unsigned int i = 0; i < nPart; ++i) {
0360
0361
0362
0363 double dE = (!hcal) ? depositedEnergy[iStep][i] : 1. - deposit(a[i], b[i], t - dt);
0364
0365
0366 if (dE * E[i] < 0.000001)
0367 continue;
0368
0369 if (ecal && !theECAL->isHom()) {
0370 double mean = dE * E[i];
0371 double sigma = theECAL->resE() * sqrt(mean);
0372
0373
0374
0375
0376
0377
0378
0379 double dE0 = dE;
0380
0381
0382 dE = random->gaussShoot(mean, sigma) / E[i];
0383
0384
0385
0386
0387 if (dE * E[i] < 0.000001)
0388 continue;
0389 photos[i] = photos[i] * dE / dE0;
0390 }
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406 double nS = 0;
0407
0408
0409 if (ecal) {
0410
0411
0412
0413 dE = random->poissonShoot(dE * photos[i]) / photos[i];
0414 double z0 = random->gaussShoot(0., 1.);
0415 dE *= 1. + z0 * theECAL->lightCollectionUniformity();
0416
0417
0418 nS = (theNumberOfSpots[i] * gam(bSpot[i] * tt, aSpot[i]) * bSpot[i] * dt / tgamma(aSpot[i]));
0419
0420
0421 } else if (hcal) {
0422 nS = (theNumberOfSpots[i] * gam(bSpot[i] * tt, aSpot[i]) * bSpot[i] * dt / tgamma(aSpot[i])) *
0423 theHCAL->spotFraction();
0424 double nSo = nS;
0425 nS = random->poissonShoot(nS);
0426
0427 if (nSo > 0. && nS / nSo < 10.)
0428 dE *= nS / nSo;
0429
0430
0431
0432
0433
0434
0435 } else if (presh1) {
0436 nS = random->poissonShoot(dE * E[i] * theLayer1->mipsPerGeV());
0437
0438
0439
0440 dE = nS / (E[i] * theLayer1->mipsPerGeV());
0441
0442
0443
0444
0445
0446 } else if (presh2) {
0447 nS = random->poissonShoot(dE * E[i] * theLayer2->mipsPerGeV());
0448
0449
0450
0451 dE = nS / (E[i] * theLayer2->mipsPerGeV());
0452
0453
0454
0455 }
0456
0457 if (detailedShowerTail)
0458 myGammaGenerator->setParameters(floor(a[i] + 0.5), b[i], t - dt);
0459
0460
0461
0462
0463
0464
0465 double eSpot = (nS > 0.) ? dE / nS : 0.;
0466 double SpotEnergy = eSpot * E[i];
0467
0468 if (hasPreshower && (presh1 || presh2))
0469 thePreshower->setSpotEnergy(0.00009);
0470 if (hcal) {
0471 SpotEnergy *= theHCAL->hOverPi();
0472 theHcalHitMaker->setSpotEnergy(SpotEnergy);
0473 }
0474
0475
0476 int nSpot = (int)(nS + 0.5);
0477
0478
0479
0480
0481
0482 double taui = tt / Ti[i];
0483 double proba = theParam->p(taui, E[i]);
0484 double theRC = theParam->rC(taui, E[i]);
0485 double theRT = theParam->rT(taui, E[i]);
0486
0487
0488
0489
0490
0491
0492 double dSpotsCore = random->gaussShoot(proba * nSpot, std::sqrt(proba * (1. - proba) * nSpot));
0493
0494 if (dSpotsCore < 0)
0495 dSpotsCore = 0;
0496
0497 unsigned nSpots_core = (unsigned)(dSpotsCore + 0.5);
0498 unsigned nSpots_tail = ((unsigned)nSpot > nSpots_core) ? nSpot - nSpots_core : 0;
0499
0500 for (unsigned icomp = 0; icomp < 2; ++icomp) {
0501 double theR = (icomp == 0) ? theRC : theRT;
0502 unsigned ncompspots = (icomp == 0) ? nSpots_core : nSpots_tail;
0503
0504 RadialInterval radInterval(theR, ncompspots, SpotEnergy, random);
0505 if (ecal) {
0506 if (icomp == 0) {
0507 setIntervals(icomp, radInterval);
0508 } else {
0509 setIntervals(icomp, radInterval);
0510 }
0511 } else {
0512 radInterval.addInterval(100., 1.);
0513 }
0514
0515 radInterval.compute();
0516
0517
0518 unsigned nrad = radInterval.nIntervals();
0519
0520 for (unsigned irad = 0; irad < nrad; ++irad) {
0521 double spote = radInterval.getSpotEnergy(irad);
0522 if (ecal)
0523 theGrid->setSpotEnergy(spote);
0524 if (hcal)
0525 theHcalHitMaker->setSpotEnergy(spote);
0526 unsigned nradspots = radInterval.getNumberOfSpots(irad);
0527 double umin = radInterval.getUmin(irad);
0528 double umax = radInterval.getUmax(irad);
0529
0530
0531
0532 for (unsigned ispot = 0; ispot < nradspots; ++ispot) {
0533 double z3 = random->flatShoot(umin, umax);
0534 double ri = theR * std::sqrt(z3 / (1. - z3));
0535
0536
0537 double phi = 2. * M_PI * random->flatShoot();
0538
0539
0540
0541
0542 if (ecal) {
0543 if (detailedShowerTail) {
0544
0545 double depth;
0546 do {
0547 depth = myGammaGenerator->shoot(random);
0548 } while (depth > t);
0549 theGrid->addHitDepth(ri, phi, depth);
0550
0551 } else
0552 theGrid->addHit(ri, phi);
0553 } else if (hasPreshower && presh1)
0554 thePreshower->addHit(ri, phi, 1);
0555 else if (hasPreshower && presh2)
0556 thePreshower->addHit(ri, phi, 2);
0557 else if (hcal) {
0558
0559 theHcalHitMaker->addHit(ri, phi);
0560
0561 }
0562
0563
0564
0565
0566 Etot[i] += spote;
0567 }
0568 }
0569 }
0570
0571
0572
0573 }
0574
0575 }
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597 }
0598
0599 double EMShower::gam(double x, double a) const {
0600
0601 return std::pow(x, a - 1.) * std::exp(-x);
0602 }
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634 double EMShower::deposit(double t, double a, double b, double dt) {
0635 myIncompleteGamma.a().setValue(a);
0636 double b1 = b * (t - dt);
0637 double b2 = b * t;
0638 double result = 0.;
0639 double rb1 = (b1 != 0.) ? myIncompleteGamma(b1) : 0.;
0640 double rb2 = (b2 != 0.) ? myIncompleteGamma(b2) : 0.;
0641 result = (rb2 - rb1);
0642 return result;
0643 }
0644
0645 void EMShower::setIntervals(unsigned icomp, RadialInterval& rad) {
0646
0647 const std::vector<double>& myValues((icomp) ? theParam->getTailIntervals() : theParam->getCoreIntervals());
0648
0649 unsigned nvals = myValues.size() / 2;
0650 for (unsigned iv = 0; iv < nvals; ++iv) {
0651
0652 rad.addInterval(myValues[2 * iv], myValues[2 * iv + 1]);
0653 }
0654 }
0655
0656 void EMShower::setPreshower(PreshowerHitMaker* const myPresh) {
0657 if (myPresh != nullptr) {
0658 thePreshower = myPresh;
0659 hasPreshower = true;
0660 }
0661 }
0662
0663 void EMShower::setHcal(HcalHitMaker* const myHcal) { theHcalHitMaker = myHcal; }
0664
0665 double EMShower::deposit(double a, double b, double t) {
0666
0667 myIncompleteGamma.a().setValue(a);
0668 double b2 = b * t;
0669 double result = 0.;
0670 if (fabs(b2) < 1.e-9)
0671 b2 = 1.e-9;
0672 result = myIncompleteGamma(b2);
0673
0674 return result;
0675 }