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 <cmath>
00011
00012
00013
00014 using std::vector;
00015
00016
00017 EMShower::EMShower(const RandomEngine* engine,
00018 GammaFunctionGenerator* gamma,
00019 EMECALShowerParametrization* const myParam,
00020 vector<const RawParticle*>* const myPart,
00021 EcalHitMaker * const myGrid,
00022 PreshowerHitMaker * const myPresh)
00023
00024 : theParam(myParam),
00025 thePart(myPart),
00026 theGrid(myGrid),
00027 thePreshower(myPresh),
00028 random(engine),
00029 myGammaGenerator(gamma)
00030 {
00031
00032
00033
00034
00035 stepsCalculated=false;
00036 hasPreshower = myPresh!=NULL;
00037 theECAL = myParam->ecalProperties();
00038 theHCAL = myParam->hcalProperties();
00039 theLayer1 = myParam->layer1Properties();
00040 theLayer2 = myParam->layer2Properties();
00041
00042
00043 double fotos = theECAL->photoStatistics()
00044 * theECAL->lightCollectionEfficiency();
00045
00046 nPart = thePart->size();
00047 totalEnergy = 0.;
00048 globalMaximum = 0.;
00049 double meanDepth=0.;
00050
00051 for ( unsigned int i=0; i<nPart; ++i ) {
00052
00053
00054 Etot.push_back(0.);
00055 E.push_back(((*thePart)[i])->e());
00056 totalEnergy+=E[i];
00057 double lny = std::log ( E[i] / theECAL->criticalEnergy() );
00058
00059
00060 double theMeanT = myParam->meanT(lny);
00061 double theMeanAlpha = myParam->meanAlpha(lny);
00062 double theMeanLnT = myParam->meanLnT(lny);
00063 double theMeanLnAlpha = myParam->meanLnAlpha(lny);
00064 double theSigmaLnT = myParam->sigmaLnT(lny);
00065 double theSigmaLnAlpha = myParam->sigmaLnAlpha(lny);
00066
00067
00068 double theCorrelation = myParam->correlationAlphaT(lny);
00069 double rhop = std::sqrt( (1.+theCorrelation)/2. );
00070 double rhom = std::sqrt( (1.-theCorrelation)/2. );
00071
00072
00073 theNumberOfSpots.push_back(myParam->nSpots(E[i]));
00074
00075
00076
00077
00078 photos.push_back(E[i] * fotos);
00079
00080
00081
00082 double z1=0.;
00083 double z2=0.;
00084 double aa=0.;
00085
00086
00087 while ( aa <= 1. ) {
00088 z1 = random->gaussShoot(0.,1.);
00089 z2 = random->gaussShoot(0.,1.);
00090 aa = std::exp(theMeanLnAlpha + theSigmaLnAlpha * (z1*rhop-z2*rhom));
00091 }
00092
00093 a.push_back(aa);
00094 T.push_back(std::exp(theMeanLnT + theSigmaLnT * (z1*rhop+z2*rhom)));
00095 b.push_back((a[i]-1.)/T[i]);
00096 maximumOfShower.push_back((a[i]-1.)/b[i]);
00097 globalMaximum += maximumOfShower[i]*E[i];
00098 meanDepth += a[i]/b[i]*E[i];
00099
00100
00101 Ti.push_back(
00102 a[i]/b[i] * (std::exp(theMeanLnAlpha)-1.) / std::exp(theMeanLnAlpha));
00103
00104
00105 TSpot.push_back(theParam->meanTSpot(theMeanT));
00106 aSpot.push_back(theParam->meanAlphaSpot(theMeanAlpha));
00107 bSpot.push_back((aSpot[i]-1.)/TSpot[i]);
00108
00109
00110 }
00111
00112
00113
00114
00115
00116
00117
00118 globalMaximum/=totalEnergy;
00119 meanDepth/=totalEnergy;
00120
00121 }
00122
00123 void EMShower::prepareSteps()
00124 {
00125
00126
00127
00128
00129 double dt;
00130 double radlen;
00131 int stps;
00132 int first_Ecal_step=0;
00133 int last_Ecal_step=0;
00134
00135
00136 steps.reserve(20);
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 radlen = -theGrid->x0DepthOffset();
00147
00148
00149 radlen += theGrid->ps1TotalX0();
00150 if ( radlen > 0. ) {
00151 steps.push_back(Step(0,radlen));
00152 radlen = 0.;
00153 }
00154
00155
00156 radlen += theGrid->ps2TotalX0();
00157 if ( radlen > 0. ) {
00158 steps.push_back(Step(1,radlen));
00159 radlen = 0.;
00160 }
00161
00162
00163 radlen += theGrid->ps2eeTotalX0();
00164 if ( radlen > 0.) {
00165 steps.push_back(Step(5,radlen));
00166 radlen = 0.;
00167 }
00168
00169
00170 radlen += theGrid->ecalTotalX0();
00171 if ( radlen > 0. ) {
00172 stps=(int)((radlen+2.5)/5.);
00173
00174 if ( stps == 0 ) stps = 1;
00175 dt = radlen/(double)stps;
00176 Step step(2,dt);
00177 first_Ecal_step=steps.size();
00178 for ( int ist=0; ist<stps; ++ist )
00179 steps.push_back(step);
00180 last_Ecal_step=steps.size()-1;
00181 radlen = 0.;
00182 }
00183
00184
00185
00186
00187 radlen += theGrid->hcalTotalX0();
00188 if ( radlen > 0. ) {
00189 double dtFrontHcal=theGrid->totalX0()-theGrid->hcalTotalX0();
00190
00191 if(dtFrontHcal<30.)
00192 {
00193 dt=30.-dtFrontHcal;
00194 Step step(3,dt);
00195 steps.push_back(step);
00196 }
00197 }
00198
00199 nSteps=steps.size();
00200 if(nSteps==0) return;
00201 double ESliceTot=0.;
00202 double MeanDepth=0.;
00203 depositedEnergy.resize(nSteps);
00204 meanDepth.resize(nSteps);
00205 double t=0.;
00206
00207 int offset=0;
00208 for(unsigned iStep=0;iStep<nSteps;++iStep)
00209 {
00210 ESliceTot=0.;
00211 MeanDepth=0.;
00212 double realTotalEnergy=0;
00213 dt=steps[iStep].second;
00214 t+=dt;
00215 for ( unsigned int i=0; i<nPart; ++i ) {
00216 depositedEnergy[iStep].push_back(deposit(t,a[i],b[i],dt));
00217 ESliceTot +=depositedEnergy[iStep][i];
00218 MeanDepth += deposit(t,a[i]+1.,b[i],dt)/b[i]*a[i];
00219 realTotalEnergy+=depositedEnergy[iStep][i]*E[i];
00220 }
00221
00222 if( ESliceTot > 0. )
00223 MeanDepth/=ESliceTot;
00224 else
00225 MeanDepth=t-dt;
00226
00227 meanDepth[iStep]=MeanDepth;
00228 if(realTotalEnergy<0.001)
00229 {
00230 offset-=1;
00231 }
00232 }
00233
00234 innerDepth=meanDepth[first_Ecal_step];
00235 if(last_Ecal_step+offset>=0)
00236 outerDepth=meanDepth[last_Ecal_step+offset];
00237 else
00238 outerDepth=innerDepth;
00239
00240 stepsCalculated=true;
00241 }
00242
00243 void
00244 EMShower::compute() {
00245
00246 double t = 0.;
00247 double dt = 0.;
00248 if(!stepsCalculated) prepareSteps();
00249
00250
00251
00252 float pstot=0.;
00253 float ps2tot=0.;
00254 float ps1tot=0.;
00255 bool status=false;
00256
00257
00258
00259
00260
00261
00262
00263 for (unsigned iStep=0; iStep<nSteps; ++iStep ) {
00264
00265
00266 dt = steps[iStep].second;
00267
00268
00269
00270
00271 t += dt;
00272
00273
00274 unsigned detector=steps[iStep].first;
00275
00276 bool presh1 = detector==0;
00277 bool presh2 = detector==1;
00278 bool ecal = detector==2;
00279 bool hcal = detector==3;
00280 bool vfcal = detector==4;
00281 bool gap = detector==5;
00282
00283
00284 if ( theHCAL==NULL) hcal=false;
00285
00286
00287 if ( vfcal ) continue;
00288
00289
00290 if( gap ) continue;
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 double tt = t-0.5*dt;
00301
00302 double realTotalEnergy=0.;
00303 for ( unsigned int i=0; i<nPart; ++i ) {
00304 realTotalEnergy += depositedEnergy[iStep][i]*E[i];
00305 }
00306
00307
00308
00309
00310
00311
00312 bool usePreviousGrid=(realTotalEnergy<0.001);
00313
00314
00315
00316
00317
00318 if(iStep>2&&realTotalEnergy<0.000001) continue;
00319
00320 if (ecal && !usePreviousGrid)
00321 {
00322 status=theGrid->getPads(meanDepth[iStep]);
00323 }
00324 if (hcal)
00325 {
00326 status=theHcalHitMaker->setDepth(tt);
00327 }
00328 if((ecal ||hcal) && !status) continue;
00329
00330 bool detailedShowerTail=false;
00331
00332 if(ecal && !usePreviousGrid)
00333 {
00334 detailedShowerTail=(t-dt > theGrid->getX0back());
00335 }
00336
00337
00338 for ( unsigned int i=0; i<nPart; ++i ) {
00339
00340
00341
00342
00343 double dE = (!hcal)? depositedEnergy[iStep][i]:1.-deposit(a[i],b[i],t-dt);
00344
00345
00346 if(dE*E[i]<0.000001) continue;
00347
00348 if(detailedShowerTail)
00349 {
00350 myGammaGenerator->setParameters(floor(a[i]+0.5),b[i],t-dt);
00351 }
00352
00353
00354 double nS = 0;
00355
00356
00357 if (ecal) {
00358
00359 dE = random->poissonShoot(dE*photos[i])/photos[i];
00360 double z0 = random->gaussShoot(0.,1.);
00361 dE *= 1. + z0*theECAL->lightCollectionUniformity();
00362
00363
00364 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00365 * bSpot[i] * dt
00366 / tgamma(aSpot[i]) );
00367
00368
00369 }
00370 else if ( hcal ) {
00371
00372 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00373 * bSpot[i] * dt
00374 / tgamma(aSpot[i]))* theHCAL->spotFraction();
00375 double nSo = nS ;
00376 nS = random->poissonShoot(nS);
00377
00378 if( nSo > 0. && nS/nSo < 10.) dE *= nS/nSo;
00379
00380
00381
00382
00383
00384
00385 }
00386 else if ( presh1 ) {
00387
00388 nS = random->poissonShoot(dE*E[i]*theLayer1->mipsPerGeV());
00389
00390 pstot+=dE*E[i];
00391 ps1tot+=dE*E[i];
00392 dE = nS/(E[i]*theLayer1->mipsPerGeV());
00393
00394
00395
00396
00397
00398 } else if ( presh2 ) {
00399
00400 nS = random->poissonShoot(dE*E[i]*theLayer2->mipsPerGeV());
00401
00402 pstot+=dE*E[i];
00403 ps2tot+=dE*E[i];
00404 dE = nS/(E[i]*theLayer2->mipsPerGeV());
00405
00406
00407
00408
00409 }
00410
00411
00412
00413
00414
00415
00416 double eSpot = (nS>0.) ? dE/nS : 0.;
00417 double SpotEnergy=eSpot*E[i];
00418
00419 if(hasPreshower&&(presh1||presh2)) thePreshower->setSpotEnergy(0.00009);
00420 if(hcal)
00421 {
00422 SpotEnergy*=theHCAL->hOverPi();
00423 theHcalHitMaker->setSpotEnergy(SpotEnergy);
00424 }
00425
00426
00427 int nSpot = (int)(nS+0.5);
00428
00429
00430
00431
00432
00433
00434 double taui = tt/Ti[i];
00435 double proba = theParam->p(taui,E[i]);
00436 double theRC = theParam->rC(taui,E[i]);
00437 double theRT = theParam->rT(taui,E[i]);
00438
00439
00440
00441
00442
00443
00444 double dSpotsCore =
00445 random->gaussShoot(proba*nSpot,std::sqrt(proba*(1.-proba)*nSpot));
00446
00447 if(dSpotsCore<0) dSpotsCore=0;
00448
00449 unsigned nSpots_core = (unsigned)(dSpotsCore+0.5);
00450 unsigned nSpots_tail = ((unsigned)nSpot>nSpots_core) ? nSpot-nSpots_core : 0;
00451
00452 for(unsigned icomp=0;icomp<2;++icomp)
00453 {
00454
00455 double theR=(icomp==0) ? theRC : theRT ;
00456 unsigned ncompspots=(icomp==0) ? nSpots_core : nSpots_tail;
00457
00458 RadialInterval radInterval(theR,ncompspots,SpotEnergy,random);
00459 if(ecal)
00460 {
00461 if(icomp==0)
00462 {
00463 setIntervals(icomp,radInterval);
00464 }
00465 else
00466 {
00467 setIntervals(icomp,radInterval);
00468 }
00469 }
00470 else
00471 {
00472 radInterval.addInterval(100.,1.);
00473 }
00474
00475 radInterval.compute();
00476
00477
00478 unsigned nrad=radInterval.nIntervals();
00479
00480 for(unsigned irad=0;irad<nrad;++irad)
00481 {
00482 double spote=radInterval.getSpotEnergy(irad);
00483 if(ecal) theGrid->setSpotEnergy(spote);
00484 if(hcal) theHcalHitMaker->setSpotEnergy(spote);
00485 unsigned nradspots=radInterval.getNumberOfSpots(irad);
00486 double umin=radInterval.getUmin(irad);
00487 double umax=radInterval.getUmax(irad);
00488
00489 for ( unsigned ispot=0; ispot<nradspots; ++ispot )
00490 {
00491 double z3=random->flatShoot(umin,umax);
00492 double ri=theR * std::sqrt(z3/(1.-z3)) ;
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 double phi = 2.*M_PI*random->flatShoot();
00508
00509
00510
00511
00512 if ( ecal )
00513 {
00514 if(detailedShowerTail)
00515 {
00516
00517 double depth;
00518 do
00519 {
00520 depth=myGammaGenerator->shoot();
00521 }
00522 while(depth>t);
00523 theGrid->addHitDepth(ri,phi,depth);
00524
00525 }
00526 else
00527 theGrid->addHit(ri,phi);
00528 }
00529 else if (hasPreshower&&presh1) thePreshower->addHit(ri,phi,1);
00530 else if (hasPreshower&&presh2) thePreshower->addHit(ri,phi,2);
00531 else if (hcal)
00532 {
00533
00534 theHcalHitMaker->addHit(ri,phi);
00535
00536 }
00537
00538
00539
00540
00541 Etot[i] += spote;
00542 }
00543 }
00544 }
00545
00546
00547
00548 }
00549
00550 }
00551
00552
00553
00554
00555
00556
00557
00558 double Etotal=0.;
00559 for(unsigned i=0;i<nPart;++i)
00560 {
00561
00562 Etotal+=Etot[i];
00563 }
00564
00565
00566
00567 }
00568
00569
00570 double
00571 EMShower::gam(double x, double a) const {
00572
00573 return std::pow(x,a-1.)*std::exp(-x);
00574 }
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606 double
00607 EMShower::deposit(double t, double a, double b, double dt) {
00608 myIncompleteGamma.a().setValue(a);
00609 double b1=b*(t-dt);
00610 double b2=b*t;
00611 double result = 0.;
00612 double rb1=(b1!=0.) ? myIncompleteGamma(b1) : 0.;
00613 double rb2=(b2!=0.) ? myIncompleteGamma(b2) : 0.;
00614 result = (rb2-rb1);
00615 return result;
00616 }
00617
00618
00619 void EMShower::setIntervals(unsigned icomp, RadialInterval& rad)
00620 {
00621
00622 const std::vector<double>& myValues((icomp)?theParam->getTailIntervals():theParam->getCoreIntervals());
00623
00624 unsigned nvals=myValues.size()/2;
00625 for(unsigned iv=0;iv<nvals;++iv)
00626 {
00627
00628 rad.addInterval(myValues[2*iv],myValues[2*iv+1]);
00629 }
00630 }
00631
00632 void EMShower::setPreshower(PreshowerHitMaker * const myPresh)
00633 {
00634 if(myPresh!=NULL)
00635 {
00636 thePreshower = myPresh;
00637 hasPreshower=true;
00638 }
00639 }
00640
00641
00642 void EMShower::setHcal(HcalHitMaker * const myHcal)
00643 {
00644 theHcalHitMaker = myHcal;
00645 }
00646
00647 double
00648 EMShower::deposit( double a, double b, double t) {
00649
00650 myIncompleteGamma.a().setValue(a);
00651 double b2=b*t;
00652 double result = 0.;
00653 if(fabs(b2) < 1.e-9 ) b2 = 1.e-9;
00654 result=myIncompleteGamma(b2);
00655
00656 return result;
00657
00658 }