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 double theCorrelation = myParam->correlationAlphaT(lny);
00105 double rhop = std::sqrt( (1.+theCorrelation)/2. );
00106 double rhom = std::sqrt( (1.-theCorrelation)/2. );
00107
00108
00109 theNumberOfSpots.push_back(myParam->nSpots(E[i]));
00110
00111
00112
00113
00114 photos.push_back(E[i] * fotos);
00115
00116
00117
00118 double z1=0.;
00119 double z2=0.;
00120 double aa=0.;
00121
00122
00123 while ( aa <= 1. ) {
00124 z1 = random->gaussShoot(0.,1.);
00125 z2 = random->gaussShoot(0.,1.);
00126 aa = std::exp(theMeanLnAlpha + theSigmaLnAlpha * (z1*rhop-z2*rhom));
00127 }
00128
00129 a.push_back(aa);
00130 T.push_back(std::exp(theMeanLnT + theSigmaLnT * (z1*rhop+z2*rhom)));
00131 b.push_back((a[i]-1.)/T[i]);
00132 maximumOfShower.push_back((a[i]-1.)/b[i]);
00133 globalMaximum += maximumOfShower[i]*E[i];
00134 meanDepth += a[i]/b[i]*E[i];
00135
00136
00137 Ti.push_back(
00138 a[i]/b[i] * (std::exp(theMeanLnAlpha)-1.) / std::exp(theMeanLnAlpha));
00139
00140
00141 TSpot.push_back(theParam->meanTSpot(theMeanT));
00142 aSpot.push_back(theParam->meanAlphaSpot(theMeanAlpha));
00143 bSpot.push_back((aSpot[i]-1.)/TSpot[i]);
00144
00145
00146 }
00147
00148
00149
00150
00151
00152
00153
00154 globalMaximum/=totalEnergy;
00155 meanDepth/=totalEnergy;
00156
00157 }
00158
00159 void EMShower::prepareSteps()
00160 {
00161
00162
00163
00164
00165 double dt;
00166 double radlen;
00167 int stps;
00168 int first_Ecal_step=0;
00169 int last_Ecal_step=0;
00170
00171
00172 steps.reserve(24);
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 radlen = -theGrid->x0DepthOffset();
00185
00186
00187 radlen += theGrid->ps1TotalX0();
00188 if ( radlen > 0. ) {
00189 steps.push_back(Step(0,radlen));
00190 radlen = 0.;
00191 }
00192
00193
00194 radlen += theGrid->ps2TotalX0();
00195 if ( radlen > 0. ) {
00196 steps.push_back(Step(1,radlen));
00197 radlen = 0.;
00198 }
00199
00200
00201 radlen += theGrid->ps2eeTotalX0();
00202 if ( radlen > 0.) {
00203 steps.push_back(Step(5,radlen));
00204 radlen = 0.;
00205 }
00206
00207
00208 radlen += theGrid->ecalTotalX0();
00209
00210 if ( radlen > 0. ) {
00211
00212 if (!bFixedLength_){
00213 stps=(int)((radlen+2.5)/5.);
00214
00215 if ( stps == 0 ) stps = 1;
00216 dt = radlen/(double)stps;
00217 Step step(2,dt);
00218 first_Ecal_step=steps.size();
00219 for ( int ist=0; ist<stps; ++ist )
00220 steps.push_back(step);
00221 last_Ecal_step=steps.size()-1;
00222 radlen = 0.;
00223 } else {
00224 dt = 1.0;
00225 stps = static_cast<int>(radlen);
00226 if (stps == 0) stps = 1;
00227 Step step(2,dt);
00228 first_Ecal_step=steps.size();
00229 for ( int ist=0; ist<stps; ++ist ) steps.push_back(step);
00230 dt = radlen-stps;
00231 if (dt>0) {
00232 Step stepLast (2,dt);
00233 steps.push_back(stepLast);
00234 }
00235 last_Ecal_step=steps.size()-1;
00236
00237 radlen = 0.;
00238
00239 }
00240 }
00241
00242
00243
00244
00245 radlen += theGrid->hcalTotalX0();
00246 if ( radlen > 0. ) {
00247 double dtFrontHcal=theGrid->totalX0()-theGrid->hcalTotalX0();
00248
00249 if(dtFrontHcal<30.)
00250 {
00251 dt=30.-dtFrontHcal;
00252 Step step(3,dt);
00253 steps.push_back(step);
00254 }
00255 }
00256
00257 nSteps=steps.size();
00258 if(nSteps==0) return;
00259 double ESliceTot=0.;
00260 double MeanDepth=0.;
00261 depositedEnergy.resize(nSteps);
00262 meanDepth.resize(nSteps);
00263 double t=0.;
00264
00265 int offset=0;
00266 for(unsigned iStep=0;iStep<nSteps;++iStep)
00267 {
00268 ESliceTot=0.;
00269 MeanDepth=0.;
00270 double realTotalEnergy=0;
00271 dt=steps[iStep].second;
00272 t+=dt;
00273 for ( unsigned int i=0; i<nPart; ++i ) {
00274 depositedEnergy[iStep].push_back(deposit(t,a[i],b[i],dt));
00275 ESliceTot +=depositedEnergy[iStep][i];
00276 MeanDepth += deposit(t,a[i]+1.,b[i],dt)/b[i]*a[i];
00277 realTotalEnergy+=depositedEnergy[iStep][i]*E[i];
00278 }
00279
00280 if( ESliceTot > 0. )
00281 MeanDepth/=ESliceTot;
00282 else
00283 MeanDepth=t-dt;
00284
00285 meanDepth[iStep]=MeanDepth;
00286 if(realTotalEnergy<0.001)
00287 {
00288 offset-=1;
00289 }
00290 }
00291
00292 innerDepth=meanDepth[first_Ecal_step];
00293 if(last_Ecal_step+offset>=0)
00294 outerDepth=meanDepth[last_Ecal_step+offset];
00295 else
00296 outerDepth=innerDepth;
00297
00298 stepsCalculated=true;
00299 }
00300
00301 void
00302 EMShower::compute() {
00303
00304 double t = 0.;
00305 double dt = 0.;
00306 if(!stepsCalculated) prepareSteps();
00307
00308
00309
00310 float pstot=0.;
00311 float ps2tot=0.;
00312 float ps1tot=0.;
00313 bool status=false;
00314
00315
00316
00317
00318
00319
00320
00321 double totECalc = 0;
00322
00323
00324
00325 for (unsigned iStep=0; iStep<nSteps; ++iStep ) {
00326
00327
00328 dt = steps[iStep].second;
00329
00330
00331
00332
00333 t += dt;
00334
00335
00336 unsigned detector=steps[iStep].first;
00337
00338 bool presh1 = detector==0;
00339 bool presh2 = detector==1;
00340 bool ecal = detector==2;
00341 bool hcal = detector==3;
00342 bool vfcal = detector==4;
00343 bool gap = detector==5;
00344
00345
00346 if ( theHCAL==NULL) hcal=false;
00347
00348
00349 if ( vfcal ) continue;
00350
00351
00352 if( gap ) continue;
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 double tt = t-0.5*dt;
00363
00364 double realTotalEnergy=0.;
00365 for ( unsigned int i=0; i<nPart; ++i ) {
00366 realTotalEnergy += depositedEnergy[iStep][i]*E[i];
00367 }
00368
00369
00370
00371
00372
00373
00374 bool usePreviousGrid=(realTotalEnergy<0.001);
00375
00376
00377
00378
00379
00380 if(iStep>2&&realTotalEnergy<0.000001) continue;
00381
00382 if (ecal && !usePreviousGrid)
00383 {
00384 status=theGrid->getPads(meanDepth[iStep]);
00385 }
00386 if (hcal)
00387 {
00388 status=theHcalHitMaker->setDepth(tt);
00389 }
00390 if((ecal || hcal) && !status) continue;
00391
00392 bool detailedShowerTail=false;
00393
00394 if(ecal && !usePreviousGrid)
00395 {
00396 detailedShowerTail=(t-dt > theGrid->getX0back());
00397 }
00398
00399
00400 for ( unsigned int i=0; i<nPart; ++i ) {
00401
00402
00403
00404
00405 double dE = (!hcal)? depositedEnergy[iStep][i]:1.-deposit(a[i],b[i],t-dt);
00406
00407 totECalc +=dE;
00408
00409 if (dbe && fabs(dt-1.)< 1e-5 && ecal) {
00410 dbe->cd();
00411 if (!dbe->get("EMShower/LongitudinalShape")) {}
00412 else {
00413 double dx = 1.;
00414
00415 dbe->get("EMShower/LongitudinalShape")->Fill(t, dE/dx);
00416 }
00417
00418
00419 }
00420
00421
00422
00423
00424 if(dE*E[i]<0.000001) continue;
00425
00426 if(detailedShowerTail)
00427 {
00428 myGammaGenerator->setParameters(floor(a[i]+0.5),b[i],t-dt);
00429 }
00430
00431
00432 double nS = 0;
00433
00434
00435 if (ecal) {
00436
00437 dE = random->poissonShoot(dE*photos[i])/photos[i];
00438 double z0 = random->gaussShoot(0.,1.);
00439 dE *= 1. + z0*theECAL->lightCollectionUniformity();
00440
00441
00442 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00443 * bSpot[i] * dt
00444 / tgamma(aSpot[i]) );
00445
00446
00447 }
00448 else if ( hcal ) {
00449
00450 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00451 * bSpot[i] * dt
00452 / tgamma(aSpot[i]))* theHCAL->spotFraction();
00453 double nSo = nS ;
00454 nS = random->poissonShoot(nS);
00455
00456 if( nSo > 0. && nS/nSo < 10.) dE *= nS/nSo;
00457
00458
00459
00460
00461
00462
00463 }
00464 else if ( presh1 ) {
00465
00466 nS = random->poissonShoot(dE*E[i]*theLayer1->mipsPerGeV());
00467
00468 pstot+=dE*E[i];
00469 ps1tot+=dE*E[i];
00470 dE = nS/(E[i]*theLayer1->mipsPerGeV());
00471
00472
00473
00474
00475
00476 } else if ( presh2 ) {
00477
00478 nS = random->poissonShoot(dE*E[i]*theLayer2->mipsPerGeV());
00479
00480 pstot+=dE*E[i];
00481 ps2tot+=dE*E[i];
00482 dE = nS/(E[i]*theLayer2->mipsPerGeV());
00483
00484
00485
00486
00487 }
00488
00489
00490
00491
00492
00493
00494 double eSpot = (nS>0.) ? dE/nS : 0.;
00495 double SpotEnergy=eSpot*E[i];
00496
00497 if(hasPreshower&&(presh1||presh2)) thePreshower->setSpotEnergy(0.00009);
00498 if(hcal)
00499 {
00500 SpotEnergy*=theHCAL->hOverPi();
00501 theHcalHitMaker->setSpotEnergy(SpotEnergy);
00502 }
00503
00504
00505 int nSpot = (int)(nS+0.5);
00506
00507
00508
00509
00510
00511
00512 double taui = tt/Ti[i];
00513 double proba = theParam->p(taui,E[i]);
00514 double theRC = theParam->rC(taui,E[i]);
00515 double theRT = theParam->rT(taui,E[i]);
00516
00517
00518
00519
00520
00521
00522 double dSpotsCore =
00523 random->gaussShoot(proba*nSpot,std::sqrt(proba*(1.-proba)*nSpot));
00524
00525 if(dSpotsCore<0) dSpotsCore=0;
00526
00527 unsigned nSpots_core = (unsigned)(dSpotsCore+0.5);
00528 unsigned nSpots_tail = ((unsigned)nSpot>nSpots_core) ? nSpot-nSpots_core : 0;
00529
00530 for(unsigned icomp=0;icomp<2;++icomp)
00531 {
00532
00533 double theR=(icomp==0) ? theRC : theRT ;
00534 unsigned ncompspots=(icomp==0) ? nSpots_core : nSpots_tail;
00535
00536 RadialInterval radInterval(theR,ncompspots,SpotEnergy,random);
00537 if(ecal)
00538 {
00539 if(icomp==0)
00540 {
00541 setIntervals(icomp,radInterval);
00542 }
00543 else
00544 {
00545 setIntervals(icomp,radInterval);
00546 }
00547 }
00548 else
00549 {
00550 radInterval.addInterval(100.,1.);
00551 }
00552
00553 radInterval.compute();
00554
00555
00556 unsigned nrad=radInterval.nIntervals();
00557
00558 for(unsigned irad=0;irad<nrad;++irad)
00559 {
00560 double spote=radInterval.getSpotEnergy(irad);
00561 if(ecal) theGrid->setSpotEnergy(spote);
00562 if(hcal) theHcalHitMaker->setSpotEnergy(spote);
00563 unsigned nradspots=radInterval.getNumberOfSpots(irad);
00564 double umin=radInterval.getUmin(irad);
00565 double umax=radInterval.getUmax(irad);
00566
00567
00568
00569 for ( unsigned ispot=0; ispot<nradspots; ++ispot )
00570 {
00571 double z3=random->flatShoot(umin,umax);
00572 double ri=theR * std::sqrt(z3/(1.-z3)) ;
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 if (dbe && fabs(dt-1.)< 1e-5 && ecal) {
00587 dbe->cd();
00588 if (!dbe->get("EMShower/TransverseShape")) {}
00589 else {
00590 double drho = 0.1;
00591 double dx = 1;
00592
00593 dbe->get("EMShower/TransverseShape")->Fill(ri,1/E[i]*spote/drho);
00594 dbe->get("EMShower/ShapeRhoZ")->Fill(ri, t, 1/E[i]*spote/(drho*dx));
00595 }
00596 } else {
00597
00598 }
00599
00600
00601
00602 double phi = 2.*M_PI*random->flatShoot();
00603
00604
00605
00606
00607 if ( ecal )
00608 {
00609 if(detailedShowerTail)
00610 {
00611
00612 double depth;
00613 do
00614 {
00615 depth=myGammaGenerator->shoot();
00616 }
00617 while(depth>t);
00618 theGrid->addHitDepth(ri,phi,depth);
00619
00620 }
00621 else
00622 theGrid->addHit(ri,phi);
00623 }
00624 else if (hasPreshower&&presh1) thePreshower->addHit(ri,phi,1);
00625 else if (hasPreshower&&presh2) thePreshower->addHit(ri,phi,2);
00626 else if (hcal)
00627 {
00628
00629 theHcalHitMaker->addHit(ri,phi);
00630
00631 }
00632
00633
00634
00635
00636 Etot[i] += spote;
00637 }
00638 }
00639 }
00640
00641
00642
00643 }
00644
00645 }
00646
00647
00648
00649
00650
00651
00652
00653 double Etotal=0.;
00654 for(unsigned i=0;i<nPart;++i)
00655 {
00656
00657 Etotal+=Etot[i];
00658 }
00659
00660
00661
00662
00663
00664
00665
00666 }
00667
00668
00669 double
00670 EMShower::gam(double x, double a) const {
00671
00672 return std::pow(x,a-1.)*std::exp(-x);
00673 }
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 double
00706 EMShower::deposit(double t, double a, double b, double dt) {
00707 myIncompleteGamma.a().setValue(a);
00708 double b1=b*(t-dt);
00709 double b2=b*t;
00710 double result = 0.;
00711 double rb1=(b1!=0.) ? myIncompleteGamma(b1) : 0.;
00712 double rb2=(b2!=0.) ? myIncompleteGamma(b2) : 0.;
00713 result = (rb2-rb1);
00714 return result;
00715 }
00716
00717
00718 void EMShower::setIntervals(unsigned icomp, RadialInterval& rad)
00719 {
00720
00721 const std::vector<double>& myValues((icomp)?theParam->getTailIntervals():theParam->getCoreIntervals());
00722
00723 unsigned nvals=myValues.size()/2;
00724 for(unsigned iv=0;iv<nvals;++iv)
00725 {
00726
00727 rad.addInterval(myValues[2*iv],myValues[2*iv+1]);
00728 }
00729 }
00730
00731 void EMShower::setPreshower(PreshowerHitMaker * const myPresh)
00732 {
00733 if(myPresh!=NULL)
00734 {
00735 thePreshower = myPresh;
00736 hasPreshower=true;
00737 }
00738 }
00739
00740
00741 void EMShower::setHcal(HcalHitMaker * const myHcal)
00742 {
00743 theHcalHitMaker = myHcal;
00744 }
00745
00746 double
00747 EMShower::deposit( double a, double b, double t) {
00748
00749 myIncompleteGamma.a().setValue(a);
00750 double b2=b*t;
00751 double result = 0.;
00752 if(fabs(b2) < 1.e-9 ) b2 = 1.e-9;
00753 result=myIncompleteGamma(b2);
00754
00755 return result;
00756
00757 }