00001
00002 #include "FastSimulation/ShowerDevelopment/interface/EMShower.h"
00003 #include "FastSimulation/CaloHitMakers/interface/EcalHitMaker.h"
00004 #include "FastSimulation/CaloHitMakers/interface/PreshowerHitMaker.h"
00005 #include "FastSimulation/CaloHitMakers/interface/HcalHitMaker.h"
00006
00007 #include "FastSimulation/Utilities/interface/RandomEngine.h"
00008 #include "FastSimulation/Utilities/interface/GammaFunctionGenerator.h"
00009
00010 #include "DQMServices/Core/interface/DQMStore.h"
00011 #include "DQMServices/Core/interface/MonitorElement.h"
00012
00013
00014 #include <cmath>
00015
00016
00017
00018 using std::vector;
00019
00020
00021 EMShower::EMShower(const RandomEngine* engine,
00022 GammaFunctionGenerator* gamma,
00023 EMECALShowerParametrization* const myParam,
00024 vector<const RawParticle*>* const myPart,
00025 DQMStore * const dbeIn,
00026 EcalHitMaker * const myGrid,
00027 PreshowerHitMaker * const myPresh,
00028 bool bFixedLength)
00029
00030 : theParam(myParam),
00031 thePart(myPart),
00032 theGrid(myGrid),
00033 thePreshower(myPresh),
00034 random(engine),
00035 myGammaGenerator(gamma),
00036 bFixedLength_(bFixedLength)
00037 {
00038
00039
00040
00041
00042 stepsCalculated=false;
00043 hasPreshower = myPresh!=NULL;
00044 theECAL = myParam->ecalProperties();
00045 theHCAL = myParam->hcalProperties();
00046 theLayer1 = myParam->layer1Properties();
00047 theLayer2 = myParam->layer2Properties();
00048
00049
00050 double fotos = theECAL->photoStatistics()
00051 * theECAL->lightCollectionEfficiency();
00052
00053 dbe = dbeIn;
00054
00055 nPart = thePart->size();
00056 totalEnergy = 0.;
00057 globalMaximum = 0.;
00058 double meanDepth=0.;
00059
00060
00061 if (dbe) {
00062 dbe->cd();
00063 if (!dbe->get("EMShower/NumberOfParticles")) {}
00064 else {
00065 dbe->get("EMShower/NumberOfParticles")->Fill(nPart);
00066 }
00067 }
00068
00069
00070 for ( unsigned int i=0; i<nPart; ++i ) {
00071
00072
00073 Etot.push_back(0.);
00074 E.push_back(((*thePart)[i])->e());
00075 totalEnergy+=E[i];
00076
00077
00078
00079 if (dbe) {
00080 dbe->cd();
00081 if (!dbe->get("EMShower/ParticlesEnergy")) {}
00082 else {
00083 dbe->get("EMShower/ParticlesEnergy")->Fill(log10(E[i]));
00084 }
00085 }
00086
00087
00088
00089
00090
00091
00092
00093 double lny = std::log ( E[i] / theECAL->criticalEnergy() );
00094
00095
00096 double theMeanT = myParam->meanT(lny);
00097 double theMeanAlpha = myParam->meanAlpha(lny);
00098 double theMeanLnT = myParam->meanLnT(lny);
00099 double theMeanLnAlpha = myParam->meanLnAlpha(lny);
00100 double theSigmaLnT = myParam->sigmaLnT(lny);
00101 double theSigmaLnAlpha = myParam->sigmaLnAlpha(lny);
00102
00103
00104
00105 double theCorrelation = myParam->correlationAlphaT(lny);
00106 double rhop = std::sqrt( (1.+theCorrelation)/2. );
00107 double rhom = std::sqrt( (1.-theCorrelation)/2. );
00108
00109
00110 theNumberOfSpots.push_back(myParam->nSpots(E[i]));
00111
00112
00113
00114
00115 photos.push_back(E[i] * fotos);
00116
00117
00118
00119 double z1=0.;
00120 double z2=0.;
00121 double aa=0.;
00122
00123
00124 while ( aa <= 1. ) {
00125 z1 = random->gaussShoot(0.,1.);
00126 z2 = random->gaussShoot(0.,1.);
00127 aa = std::exp(theMeanLnAlpha + theSigmaLnAlpha * (z1*rhop-z2*rhom));
00128 }
00129
00130 a.push_back(aa);
00131 T.push_back(std::exp(theMeanLnT + theSigmaLnT * (z1*rhop+z2*rhom)));
00132 b.push_back((a[i]-1.)/T[i]);
00133 maximumOfShower.push_back((a[i]-1.)/b[i]);
00134 globalMaximum += maximumOfShower[i]*E[i];
00135 meanDepth += a[i]/b[i]*E[i];
00136
00137
00138 Ti.push_back(
00139 a[i]/b[i] * (std::exp(theMeanLnAlpha)-1.) / std::exp(theMeanLnAlpha));
00140
00141
00142 TSpot.push_back(theParam->meanTSpot(theMeanT));
00143 aSpot.push_back(theParam->meanAlphaSpot(theMeanAlpha));
00144 bSpot.push_back((aSpot[i]-1.)/TSpot[i]);
00145
00146
00147 }
00148
00149
00150
00151
00152
00153
00154
00155 globalMaximum/=totalEnergy;
00156 meanDepth/=totalEnergy;
00157
00158 }
00159
00160 void EMShower::prepareSteps()
00161 {
00162
00163
00164
00165
00166 double dt;
00167 double radlen;
00168 int stps;
00169 int first_Ecal_step=0;
00170 int last_Ecal_step=0;
00171
00172
00173 steps.reserve(24);
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 radlen = -theGrid->x0DepthOffset();
00186
00187
00188 radlen += theGrid->ps1TotalX0();
00189 if ( radlen > 0. ) {
00190 steps.push_back(Step(0,radlen));
00191 radlen = 0.;
00192 }
00193
00194
00195 radlen += theGrid->ps2TotalX0();
00196 if ( radlen > 0. ) {
00197 steps.push_back(Step(1,radlen));
00198 radlen = 0.;
00199 }
00200
00201
00202 radlen += theGrid->ps2eeTotalX0();
00203 if ( radlen > 0.) {
00204 steps.push_back(Step(5,radlen));
00205 radlen = 0.;
00206 }
00207
00208
00209 radlen += theGrid->ecalTotalX0();
00210
00211
00212
00213 if ( radlen > 0. ) {
00214
00215 if (!bFixedLength_){
00216 stps=(int)((radlen+2.5)/5.);
00217
00218 if ( stps == 0 ) stps = 1;
00219 dt = radlen/(double)stps;
00220 Step step(2,dt);
00221 first_Ecal_step=steps.size();
00222 for ( int ist=0; ist<stps; ++ist )
00223 steps.push_back(step);
00224 last_Ecal_step=steps.size()-1;
00225 radlen = 0.;
00226 } else {
00227 dt = 1.0;
00228 stps = static_cast<int>(radlen);
00229 if (stps == 0) stps = 1;
00230 Step step(2,dt);
00231 first_Ecal_step=steps.size();
00232 for ( int ist=0; ist<stps; ++ist ) steps.push_back(step);
00233 dt = radlen-stps;
00234 if (dt>0) {
00235 Step stepLast (2,dt);
00236 steps.push_back(stepLast);
00237 }
00238 last_Ecal_step=steps.size()-1;
00239
00240 radlen = 0.;
00241
00242 }
00243 }
00244
00245
00246
00247
00248 radlen += theGrid->hcalTotalX0();
00249 if ( radlen > 0. ) {
00250 double dtFrontHcal=theGrid->totalX0()-theGrid->hcalTotalX0();
00251
00252 if(dtFrontHcal<30.)
00253 {
00254 dt=30.-dtFrontHcal;
00255 Step step(3,dt);
00256 steps.push_back(step);
00257 }
00258 }
00259
00260 nSteps=steps.size();
00261 if(nSteps==0) return;
00262 double ESliceTot=0.;
00263 double MeanDepth=0.;
00264 depositedEnergy.resize(nSteps);
00265 meanDepth.resize(nSteps);
00266 double t=0.;
00267
00268 int offset=0;
00269 for(unsigned iStep=0;iStep<nSteps;++iStep)
00270 {
00271 ESliceTot=0.;
00272 MeanDepth=0.;
00273 double realTotalEnergy=0;
00274 dt=steps[iStep].second;
00275 t+=dt;
00276 for ( unsigned int i=0; i<nPart; ++i ) {
00277 depositedEnergy[iStep].push_back(deposit(t,a[i],b[i],dt));
00278 ESliceTot +=depositedEnergy[iStep][i];
00279 MeanDepth += deposit(t,a[i]+1.,b[i],dt)/b[i]*a[i];
00280 realTotalEnergy+=depositedEnergy[iStep][i]*E[i];
00281 }
00282
00283 if( ESliceTot > 0. )
00284 MeanDepth/=ESliceTot;
00285 else
00286 MeanDepth=t-dt;
00287
00288 meanDepth[iStep]=MeanDepth;
00289 if(realTotalEnergy<0.001)
00290 {
00291 offset-=1;
00292 }
00293 }
00294
00295 innerDepth=meanDepth[first_Ecal_step];
00296 if(last_Ecal_step+offset>=0)
00297 outerDepth=meanDepth[last_Ecal_step+offset];
00298 else
00299 outerDepth=innerDepth;
00300
00301 stepsCalculated=true;
00302 }
00303
00304 void
00305 EMShower::compute() {
00306
00307 double samplingWidth = theECAL->da() + theECAL->dp();
00308 double theECALX0 = theECAL->radLenIncm();
00309
00310
00311
00312
00313
00314
00315
00316 double t = 0.;
00317 double dt = 0.;
00318 if(!stepsCalculated) prepareSteps();
00319
00320
00321
00322 float pstot=0.;
00323 float ps2tot=0.;
00324 float ps1tot=0.;
00325 bool status=false;
00326
00327
00328
00329
00330
00331
00332
00333 double totECalc = 0;
00334
00335
00336
00337 for (unsigned iStep=0; iStep<nSteps; ++iStep ) {
00338
00339
00340 dt = steps[iStep].second;
00341
00342
00343
00344
00345 t += dt;
00346
00347
00348 unsigned detector=steps[iStep].first;
00349
00350 bool presh1 = detector==0;
00351 bool presh2 = detector==1;
00352 bool ecal = detector==2;
00353 bool hcal = detector==3;
00354 bool vfcal = detector==4;
00355 bool gap = detector==5;
00356
00357
00358 if ( theHCAL==NULL) hcal=false;
00359
00360
00361 if ( vfcal ) continue;
00362
00363
00364 if( gap ) continue;
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 double tt = t-0.5*dt;
00375
00376 double realTotalEnergy=0.;
00377 for ( unsigned int i=0; i<nPart; ++i ) {
00378 realTotalEnergy += depositedEnergy[iStep][i]*E[i];
00379 }
00380
00381
00382
00383
00384
00385
00386 bool usePreviousGrid=(realTotalEnergy<0.001);
00387
00388
00389
00390
00391
00392 if(iStep>2&&realTotalEnergy<0.000001) continue;
00393
00394 if (ecal && !usePreviousGrid)
00395 {
00396 status=theGrid->getPads(meanDepth[iStep]);
00397 }
00398 if (hcal)
00399 {
00400 status=theHcalHitMaker->setDepth(tt);
00401 }
00402 if((ecal || hcal) && !status) continue;
00403
00404 bool detailedShowerTail=false;
00405
00406 if(ecal && !usePreviousGrid)
00407 {
00408 detailedShowerTail=(t-dt > theGrid->getX0back());
00409 }
00410
00411
00412 for ( unsigned int i=0; i<nPart; ++i ) {
00413
00414
00415
00416
00417 double dE = (!hcal)? depositedEnergy[iStep][i]:1.-deposit(a[i],b[i],t-dt);
00418
00419
00420 if(dE*E[i]<0.000001) continue;
00421
00422
00423 if (ecal && !theECAL->isHom()) {
00424 double mean = dE*E[i];
00425 double sigma = theECAL->resE()*sqrt(mean);
00426
00427
00428
00429
00430
00431
00432
00433 double dE0 = dE;
00434
00435
00436 dE = random->gaussShoot(mean, sigma)/E[i];
00437
00438
00439
00440
00441 if (dE*E[i] < 0.000001) continue;
00442 photos[i] = photos[i]*dE/dE0;
00443
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 totECalc +=dE;
00460
00461 if (dbe && fabs(dt-1.)< 1e-5 && ecal) {
00462 dbe->cd();
00463 if (!dbe->get("EMShower/LongitudinalShape")) {}
00464 else {
00465 double dx = 1.;
00466
00467 dbe->get("EMShower/LongitudinalShape")->Fill(t, dE/dx);
00468
00469 double step = theECALX0/samplingWidth;
00470 double binMin = abs((t-1)*step)+1;
00471 double binMax = abs(t*step)+1;
00472 double dBins = binMax-binMin;
00473
00474
00475
00476
00477
00478
00479
00480 if ( dBins < 1) {
00481 dbe->get("EMShower/LongitudinalShapeLayers")->Fill(binMin, dE/dx);
00482
00483 }
00484 else {
00485
00486
00487 double w1 = (binMin + 1 - (t-1)*step - 1)/step;
00488 double w2 = 1./step;
00489 double w3 = (t*step+1-binMax)/step;
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 dbe->get("EMShower/LongitudinalShapeLayers")->Fill(binMin, dE/dx*w1);
00502
00503
00504 for (int iBin = 1; iBin < dBins; iBin++){
00505
00506 dbe->get("EMShower/LongitudinalShapeLayers")->Fill(binMin+iBin, dE/dx*w2);
00507
00508 }
00509
00510
00511 dbe->get("EMShower/LongitudinalShapeLayers")->Fill(binMax, dE/dx*w3);
00512
00513
00514 }
00515
00516
00517 }
00518
00519
00520 }
00521
00522
00523 double nS = 0;
00524
00525
00526 if (ecal) {
00527
00528
00529
00530
00531
00532
00533 dE = random->poissonShoot(dE*photos[i])/photos[i];
00534 double z0 = random->gaussShoot(0.,1.);
00535 dE *= 1. + z0*theECAL->lightCollectionUniformity();
00536
00537
00538 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00539 * bSpot[i] * dt
00540 / tgamma(aSpot[i]) );
00541
00542
00543 }
00544 else if ( hcal ) {
00545
00546 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00547 * bSpot[i] * dt
00548 / tgamma(aSpot[i]))* theHCAL->spotFraction();
00549 double nSo = nS ;
00550 nS = random->poissonShoot(nS);
00551
00552 if( nSo > 0. && nS/nSo < 10.) dE *= nS/nSo;
00553
00554
00555
00556
00557
00558
00559 }
00560 else if ( presh1 ) {
00561
00562 nS = random->poissonShoot(dE*E[i]*theLayer1->mipsPerGeV());
00563
00564 pstot+=dE*E[i];
00565 ps1tot+=dE*E[i];
00566 dE = nS/(E[i]*theLayer1->mipsPerGeV());
00567
00568
00569
00570
00571
00572 } else if ( presh2 ) {
00573
00574 nS = random->poissonShoot(dE*E[i]*theLayer2->mipsPerGeV());
00575
00576 pstot+=dE*E[i];
00577 ps2tot+=dE*E[i];
00578 dE = nS/(E[i]*theLayer2->mipsPerGeV());
00579
00580
00581
00582
00583 }
00584
00585 if(detailedShowerTail)
00586 myGammaGenerator->setParameters(floor(a[i]+0.5),b[i],t-dt);
00587
00588
00589
00590
00591
00592
00593
00594
00595 double eSpot = (nS>0.) ? dE/nS : 0.;
00596 double SpotEnergy=eSpot*E[i];
00597
00598 if(hasPreshower&&(presh1||presh2)) thePreshower->setSpotEnergy(0.00009);
00599 if(hcal)
00600 {
00601 SpotEnergy*=theHCAL->hOverPi();
00602 theHcalHitMaker->setSpotEnergy(SpotEnergy);
00603 }
00604
00605
00606 int nSpot = (int)(nS+0.5);
00607
00608
00609
00610
00611
00612
00613 double taui = tt/Ti[i];
00614 double proba = theParam->p(taui,E[i]);
00615 double theRC = theParam->rC(taui,E[i]);
00616 double theRT = theParam->rT(taui,E[i]);
00617
00618
00619
00620
00621
00622
00623 double dSpotsCore =
00624 random->gaussShoot(proba*nSpot,std::sqrt(proba*(1.-proba)*nSpot));
00625
00626 if(dSpotsCore<0) dSpotsCore=0;
00627
00628 unsigned nSpots_core = (unsigned)(dSpotsCore+0.5);
00629 unsigned nSpots_tail = ((unsigned)nSpot>nSpots_core) ? nSpot-nSpots_core : 0;
00630
00631 for(unsigned icomp=0;icomp<2;++icomp)
00632 {
00633
00634 double theR=(icomp==0) ? theRC : theRT ;
00635 unsigned ncompspots=(icomp==0) ? nSpots_core : nSpots_tail;
00636
00637 RadialInterval radInterval(theR,ncompspots,SpotEnergy,random);
00638 if(ecal)
00639 {
00640 if(icomp==0)
00641 {
00642 setIntervals(icomp,radInterval);
00643 }
00644 else
00645 {
00646 setIntervals(icomp,radInterval);
00647 }
00648 }
00649 else
00650 {
00651 radInterval.addInterval(100.,1.);
00652 }
00653
00654 radInterval.compute();
00655
00656
00657 unsigned nrad=radInterval.nIntervals();
00658
00659 for(unsigned irad=0;irad<nrad;++irad)
00660 {
00661 double spote=radInterval.getSpotEnergy(irad);
00662 if(ecal) theGrid->setSpotEnergy(spote);
00663 if(hcal) theHcalHitMaker->setSpotEnergy(spote);
00664 unsigned nradspots=radInterval.getNumberOfSpots(irad);
00665 double umin=radInterval.getUmin(irad);
00666 double umax=radInterval.getUmax(irad);
00667
00668
00669
00670 for ( unsigned ispot=0; ispot<nradspots; ++ispot )
00671 {
00672 double z3=random->flatShoot(umin,umax);
00673 double ri=theR * std::sqrt(z3/(1.-z3)) ;
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 if (dbe && fabs(dt-1.)< 1e-5 && ecal) {
00688 dbe->cd();
00689 if (!dbe->get("EMShower/TransverseShape")) {}
00690 else {
00691 double drho = 0.1;
00692 double dx = 1;
00693
00694 dbe->get("EMShower/TransverseShape")->Fill(ri,1/E[i]*spote/drho);
00695 dbe->get("EMShower/ShapeRhoZ")->Fill(ri, t, 1/E[i]*spote/(drho*dx));
00696 }
00697 } else {
00698
00699 }
00700
00701
00702
00703 double phi = 2.*M_PI*random->flatShoot();
00704
00705
00706
00707
00708 if ( ecal )
00709 {
00710 if(detailedShowerTail)
00711 {
00712
00713 double depth;
00714 do
00715 {
00716 depth=myGammaGenerator->shoot();
00717 }
00718 while(depth>t);
00719 theGrid->addHitDepth(ri,phi,depth);
00720
00721 }
00722 else
00723 theGrid->addHit(ri,phi);
00724 }
00725 else if (hasPreshower&&presh1) thePreshower->addHit(ri,phi,1);
00726 else if (hasPreshower&&presh2) thePreshower->addHit(ri,phi,2);
00727 else if (hcal)
00728 {
00729
00730 theHcalHitMaker->addHit(ri,phi);
00731
00732 }
00733
00734
00735
00736
00737 Etot[i] += spote;
00738 }
00739 }
00740 }
00741
00742
00743
00744 }
00745
00746 }
00747
00748
00749
00750
00751
00752
00753
00754 double Etotal=0.;
00755 for(unsigned i=0;i<nPart;++i)
00756 {
00757
00758 Etotal+=Etot[i];
00759 }
00760
00761
00762
00763
00764
00765
00766
00767 }
00768
00769
00770 double
00771 EMShower::gam(double x, double a) const {
00772
00773 return std::pow(x,a-1.)*std::exp(-x);
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 double
00807 EMShower::deposit(double t, double a, double b, double dt) {
00808 myIncompleteGamma.a().setValue(a);
00809 double b1=b*(t-dt);
00810 double b2=b*t;
00811 double result = 0.;
00812 double rb1=(b1!=0.) ? myIncompleteGamma(b1) : 0.;
00813 double rb2=(b2!=0.) ? myIncompleteGamma(b2) : 0.;
00814 result = (rb2-rb1);
00815 return result;
00816 }
00817
00818
00819 void EMShower::setIntervals(unsigned icomp, RadialInterval& rad)
00820 {
00821
00822 const std::vector<double>& myValues((icomp)?theParam->getTailIntervals():theParam->getCoreIntervals());
00823
00824 unsigned nvals=myValues.size()/2;
00825 for(unsigned iv=0;iv<nvals;++iv)
00826 {
00827
00828 rad.addInterval(myValues[2*iv],myValues[2*iv+1]);
00829 }
00830 }
00831
00832 void EMShower::setPreshower(PreshowerHitMaker * const myPresh)
00833 {
00834 if(myPresh!=NULL)
00835 {
00836 thePreshower = myPresh;
00837 hasPreshower=true;
00838 }
00839 }
00840
00841
00842 void EMShower::setHcal(HcalHitMaker * const myHcal)
00843 {
00844 theHcalHitMaker = myHcal;
00845 }
00846
00847 double
00848 EMShower::deposit( double a, double b, double t) {
00849
00850 myIncompleteGamma.a().setValue(a);
00851 double b2=b*t;
00852 double result = 0.;
00853 if(fabs(b2) < 1.e-9 ) b2 = 1.e-9;
00854 result=myIncompleteGamma(b2);
00855
00856 return result;
00857
00858 }