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 steps.reserve(20);
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 radlen = -theGrid->x0DepthOffset();
00146
00147
00148 radlen += theGrid->ps1TotalX0();
00149 if ( radlen > 0. ) {
00150 steps.push_back(Step(0,radlen));
00151 radlen = 0.;
00152 }
00153
00154
00155 radlen += theGrid->ps2TotalX0();
00156 if ( radlen > 0. ) {
00157 steps.push_back(Step(1,radlen));
00158 radlen = 0.;
00159 }
00160
00161
00162 radlen += theGrid->ecalTotalX0();
00163 if ( radlen > 0. ) {
00164 stps=(int)((radlen+2.5)/5.);
00165
00166 if ( stps == 0 ) stps = 1;
00167 dt = radlen/(double)stps;
00168 Step step(2,dt);
00169 first_Ecal_step=steps.size();
00170 for ( int ist=0; ist<stps; ++ist )
00171 steps.push_back(step);
00172 last_Ecal_step=steps.size()-1;
00173 radlen = 0.;
00174 }
00175
00176
00177 radlen += theGrid->hcalTotalX0();
00178 if ( radlen > 0. ) {
00179 double dtFrontHcal=theGrid->totalX0()-theGrid->hcalTotalX0();
00180
00181 if(dtFrontHcal<30.)
00182 {
00183 dt=30.-dtFrontHcal;
00184 Step step(3,dt);
00185 steps.push_back(step);
00186 }
00187 }
00188
00189 nSteps=steps.size();
00190 if(nSteps==0) return;
00191 double ESliceTot=0.;
00192 double MeanDepth=0.;
00193 depositedEnergy.resize(nSteps);
00194 meanDepth.resize(nSteps);
00195 double t=0.;
00196
00197 int offset=0;
00198 for(unsigned iStep=0;iStep<nSteps;++iStep)
00199 {
00200 ESliceTot=0.;
00201 MeanDepth=0.;
00202 double realTotalEnergy=0;
00203 dt=steps[iStep].second;
00204 t+=dt;
00205 for ( unsigned int i=0; i<nPart; ++i ) {
00206
00207 depositedEnergy[iStep].push_back(deposit(t,a[i],b[i],dt));
00208 ESliceTot +=depositedEnergy[iStep][i];
00209 MeanDepth += deposit(t,a[i]+1.,b[i],dt)/b[i]*a[i];
00210 realTotalEnergy+=depositedEnergy[iStep][i]*E[i];
00211 }
00212 MeanDepth/=ESliceTot;
00213 meanDepth[iStep]=MeanDepth;
00214 if(realTotalEnergy<0.001)
00215 {
00216 offset-=1;
00217 }
00218 }
00219
00220 innerDepth=meanDepth[first_Ecal_step];
00221 if(last_Ecal_step+offset>=0)
00222 outerDepth=meanDepth[last_Ecal_step+offset];
00223 else
00224 outerDepth=innerDepth;
00225
00226 stepsCalculated=true;
00227 }
00228
00229 void
00230 EMShower::compute() {
00231
00232 double t = 0.;
00233 double dt = 0.;
00234 if(!stepsCalculated) prepareSteps();
00235
00236
00237
00238
00239 bool status=false;
00240
00241
00242
00243
00244
00245
00246
00247
00248 for (unsigned iStep=0; iStep<nSteps; ++iStep ) {
00249
00250
00251 dt = steps[iStep].second;
00252
00253
00254 t += dt;
00255
00256
00257 unsigned detector=steps[iStep].first;
00258 bool presh1 = detector==0;
00259 bool presh2 = detector==1;
00260 bool ecal = detector==2;
00261 bool hcal = detector==3;
00262 bool vfcal = detector==4;
00263
00264
00265 if ( theHCAL==NULL) hcal=false;
00266
00267
00268 if ( vfcal ) continue;
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 double tt = t-0.5*dt;
00279
00280 double realTotalEnergy=0.;
00281 for ( unsigned int i=0; i<nPart; ++i ) {
00282 realTotalEnergy += depositedEnergy[iStep][i]*E[i];
00283 }
00284
00285
00286
00287
00288
00289
00290 bool usePreviousGrid=(realTotalEnergy<0.001);
00291
00292
00293
00294
00295
00296 if(iStep>2&&realTotalEnergy<0.000001) continue;
00297
00298 if (ecal && !usePreviousGrid)
00299 {
00300 status=theGrid->getPads(meanDepth[iStep]);
00301 }
00302 if (hcal)
00303 {
00304 status=theHcalHitMaker->setDepth(tt);
00305 }
00306 if((ecal ||hcal) && !status) continue;
00307
00308 bool detailedShowerTail=false;
00309
00310 if(ecal && !usePreviousGrid)
00311 {
00312 detailedShowerTail=(t-dt > theGrid->getX0back());
00313 }
00314
00315
00316 for ( unsigned int i=0; i<nPart; ++i ) {
00317
00318
00319
00320
00321 double dE = (!hcal)? depositedEnergy[iStep][i]:1.-deposit(a[i],b[i],t-dt);
00322
00323
00324 if(dE*E[i]<0.000001) continue;
00325
00326 if(detailedShowerTail)
00327 {
00328 myGammaGenerator->setParameters(floor(a[i]+0.5),b[i],t-dt);
00329 }
00330
00331
00332 double nS = 0;
00333
00334
00335 if (ecal) {
00336
00337 dE = random->poissonShoot(dE*photos[i])/photos[i];
00338 double z0 = random->gaussShoot(0.,1.);
00339 dE *= 1. + z0*theECAL->lightCollectionUniformity();
00340
00341
00342 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00343 * bSpot[i] * dt
00344 / tgamma(aSpot[i]) );
00345
00346
00347 }
00348 else if ( hcal ) {
00349 nS = ( theNumberOfSpots[i] * gam(bSpot[i]*tt,aSpot[i])
00350 * bSpot[i] * dt
00351 / tgamma(aSpot[i]))* theHCAL->spotFraction();
00352 double nSo = nS ;
00353
00354 nS = random->poissonShoot(nS);
00355 dE *= nS/nSo;
00356
00357
00358
00359
00360
00361 }
00362 else if ( presh1 ) {
00363
00364 nS = random->poissonShoot(dE*E[i]*theLayer1->mipsPerGeV());
00365 dE = nS/(E[i]*theLayer1->mipsPerGeV());
00366
00367
00368
00369
00370 } else if ( presh2 ) {
00371
00372 nS = random->poissonShoot(dE*E[i]*theLayer2->mipsPerGeV());
00373 dE = nS/(E[i]*theLayer2->mipsPerGeV());
00374
00375
00376
00377 }
00378
00379
00380
00381
00382
00383
00384 double eSpot = (nS>0.) ? dE/nS : 0.;
00385 double SpotEnergy=eSpot*E[i];
00386
00387 if(hasPreshower&&(presh1||presh2)) thePreshower->setSpotEnergy(0.00009);
00388 if(hcal)
00389 {
00390 SpotEnergy*=theHCAL->hOverPi();
00391 theHcalHitMaker->setSpotEnergy(SpotEnergy);
00392 }
00393
00394
00395 int nSpot = (int)(nS+0.5);
00396
00397
00398
00399
00400
00401
00402 double taui = tt/Ti[i];
00403 double proba = theParam->p(taui,E[i]);
00404 double theRC = theParam->rC(taui,E[i]);
00405 double theRT = theParam->rT(taui,E[i]);
00406
00407
00408
00409
00410
00411
00412 double dSpotsCore =
00413 random->gaussShoot(proba*nSpot,std::sqrt(proba*(1.-proba)*nSpot));
00414
00415 if(dSpotsCore<0) dSpotsCore=0;
00416
00417 unsigned nSpots_core = (unsigned)(dSpotsCore+0.5);
00418 unsigned nSpots_tail = ((unsigned)nSpot>nSpots_core) ? nSpot-nSpots_core : 0;
00419
00420 for(unsigned icomp=0;icomp<2;++icomp)
00421 {
00422
00423 double theR=(icomp==0) ? theRC : theRT ;
00424 unsigned ncompspots=(icomp==0) ? nSpots_core : nSpots_tail;
00425
00426 RadialInterval radInterval(theR,ncompspots,SpotEnergy,random);
00427 if(ecal)
00428 {
00429 if(icomp==0)
00430 {
00431 setIntervals(icomp,radInterval);
00432 }
00433 else
00434 {
00435 setIntervals(icomp,radInterval);
00436 }
00437 }
00438 else
00439 {
00440 radInterval.addInterval(100.,1.);
00441 }
00442
00443 radInterval.compute();
00444
00445
00446 unsigned nrad=radInterval.nIntervals();
00447
00448 for(unsigned irad=0;irad<nrad;++irad)
00449 {
00450 double spote=radInterval.getSpotEnergy(irad);
00451 if(ecal) theGrid->setSpotEnergy(spote);
00452 if(hcal) theHcalHitMaker->setSpotEnergy(spote);
00453 unsigned nradspots=radInterval.getNumberOfSpots(irad);
00454 double umin=radInterval.getUmin(irad);
00455 double umax=radInterval.getUmax(irad);
00456
00457 for ( unsigned ispot=0; ispot<nradspots; ++ispot )
00458 {
00459 double z3=random->flatShoot(umin,umax);
00460 double ri=theR * std::sqrt(z3/(1.-z3)) ;
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 double phi = 2.*M_PI*random->flatShoot();
00476
00477
00478
00479
00480 if ( ecal )
00481 {
00482 if(detailedShowerTail)
00483 {
00484
00485 double depth;
00486 do
00487 {
00488 depth=myGammaGenerator->shoot();
00489 }
00490 while(depth>t);
00491 theGrid->addHitDepth(ri,phi,depth);
00492
00493 }
00494 else
00495 theGrid->addHit(ri,phi);
00496 }
00497 else if (hasPreshower&&presh1) thePreshower->addHit(ri,phi,1);
00498 else if (hasPreshower&&presh2) thePreshower->addHit(ri,phi,2);
00499 else if (hcal)
00500 {
00501
00502 theHcalHitMaker->addHit(ri,phi);
00503
00504 }
00505
00506
00507
00508
00509 Etot[i] += spote;
00510 }
00511 }
00512 }
00513
00514
00515
00516 }
00517
00518 }
00519
00520
00521
00522
00523
00524
00525
00526 double Etotal=0.;
00527 for(unsigned i=0;i<nPart;++i)
00528 {
00529
00530 Etotal+=Etot[i];
00531 }
00532
00533 }
00534
00535
00536 double
00537 EMShower::gam(double x, double a) const {
00538
00539 return std::pow(x,a-1.)*std::exp(-x);
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 double
00573 EMShower::deposit(double t, double a, double b, double dt) {
00574 myIncompleteGamma.a().setValue(a);
00575 double b1=b*(t-dt);
00576 double b2=b*t;
00577 return (myIncompleteGamma(b2)-myIncompleteGamma(b1));
00578 }
00579
00580
00581 void EMShower::setIntervals(unsigned icomp, RadialInterval& rad)
00582 {
00583
00584 const std::vector<double>& myValues((icomp)?theParam->getTailIntervals():theParam->getCoreIntervals());
00585
00586 unsigned nvals=myValues.size()/2;
00587 for(unsigned iv=0;iv<nvals;++iv)
00588 {
00589
00590 rad.addInterval(myValues[2*iv],myValues[2*iv+1]);
00591 }
00592 }
00593
00594 void EMShower::setPreshower(PreshowerHitMaker * const myPresh)
00595 {
00596 if(myPresh!=NULL)
00597 {
00598 thePreshower = myPresh;
00599 hasPreshower=true;
00600 }
00601 }
00602
00603
00604 void EMShower::setHcal(HcalHitMaker * const myHcal)
00605 {
00606 theHcalHitMaker = myHcal;
00607 }
00608
00609 double
00610 EMShower::deposit( double a, double b, double t) {
00611
00612 myIncompleteGamma.a().setValue(a);
00613 double b2=b*t;
00614 double result=myIncompleteGamma(b2);
00615
00616 return result;
00617 }