00001 #include "SimPmt.h"
00002 #include "Calibrator/Calibrator.h"
00003 #include "MessageService/MsgService.h"
00004 #include "SimAfterpulseModel.h"
00005 #include <fstream>
00006
00007 CVSID("$Id: SimPmt.cxx,v 1.29 2005/10/27 18:55:47 tagg Exp $");
00008 ClassImp(SimPmt)
00009
00010
00011 Bool_t SimPmt::fsPmtDoOpticalCrosstalk = true;
00012 Bool_t SimPmt::fsPmtDoChargeCrosstalk = true;
00013 Bool_t SimPmt::fsPmtDoNonlinearity = true;
00014 Bool_t SimPmt::fsPmtDoDarkNoise = true;
00015 Double_t SimPmt::fsPmtScaleOpticalCrosstalk = 1.0;
00016 Double_t SimPmt::fsPmtScaleChargeCrosstalk = 1.0;
00017 Bool_t SimPmt::fsPmtApplyGainDrift = true;
00018 Bool_t SimPmt::fsPmtHamamatsuPixelNumbering = false;
00019 Double_t SimPmt::fsVaGain;
00020 Double_t SimPmt::fsQieDacCharge;
00021 Bool_t SimPmt::fsRebuildGainMap = true;
00022
00023 SimPmt::SimPmt ( PlexPixelSpotId tube,
00024 VldContext context,
00025 TRandom* random,
00026 Int_t nPixels, Int_t nSpots
00027 )
00028 : fNPixels(nPixels),
00029 fNSpots(nSpots),
00030 fTube(tube),
00031 fContext(context),
00032 fRandom(random),
00033 fSimAfterpulseModel(0)
00034 {
00035 if(random == NULL) fRandom = gRandom;
00036
00037 SimPmt::Reset(context);
00038 }
00039
00040
00041 SimPmt::~SimPmt()
00042 {
00043 BucketMap_t::iterator itr(fTimeBuckets.begin()),itrEnd(fTimeBuckets.end());
00044 for (; itr != itrEnd; ++itr)
00045 delete itr->second;
00046 fTimeBuckets.clear();
00047
00048 UInt_t n= fCreatedDigiPEs.size();
00049 for(UInt_t i=0;i<n;i++) delete fCreatedDigiPEs[i];
00050 }
00051
00052 void SimPmt::Reset(const VldContext& newContext)
00053 {
00054
00055
00056
00057 MSG("DetSim",Msg::kVerbose) << "SimPmt::Reset() " << fTube.AsString() << endl;
00058 fContext = newContext;
00059 fTotalCharge = 0;
00060 fDynodeTime = kPmtTime_Never;
00061 BucketMap_t::iterator itr(fTimeBuckets.begin()),itrEnd(fTimeBuckets.end());
00062 for (; itr != itrEnd; ++itr)
00063 delete itr->second;
00064 fTimeBuckets.clear();
00065 UInt_t num= fCreatedDigiPEs.size();
00066 for(UInt_t i=0;i<num;i++) delete fCreatedDigiPEs[i];
00067 }
00068
00069
00070
00071 void SimPmt::AddDigiPE( const DigiPE* digipe )
00072 {
00073
00074
00075
00076
00077 if(!digipe) return;
00078
00079 double time = digipe->GetTime();
00080
00081 int bucket = this->TimeToBucket(time);
00082
00083
00084
00085
00086
00087 int pix = GetPixelNumber(digipe->GetPixelSpotId());
00088 int spot = GetSpotNumber(digipe->GetPixelSpotId());
00089 GetBucket(bucket).AddDigiPE(digipe, pix, spot);
00090
00091
00092 GetBucket(bucket).SetDynodeTime(time);
00093 if(time<fDynodeTime) fDynodeTime = time;
00094 }
00095
00096
00097
00098 Float_t SimPmt::GetPe( int pixel, int spot, int bucket ) const
00099 {
00100
00101
00102
00103
00104 if(spot == 0 ) {
00105
00106 return GetBucket(bucket).GetPixelBucket(pixel).GetTotalPE();
00107 }
00108
00109 return GetBucket(bucket).GetPixelBucket(pixel).GetPE(spot);
00110 }
00111
00112 Float_t SimPmt::GetPeXtalk( int pixel, int spot, int bucket ) const
00113 {
00114
00115
00116
00117
00118 if(spot == 0 ) {
00119
00120 return GetBucket(bucket).GetPixelBucket(pixel).GetTotalPEXtalk();
00121 }
00122
00123 return GetBucket(bucket).GetPixelBucket(pixel).GetPEXtalk(spot);
00124 }
00125
00126
00127
00128 Float_t SimPmt::GetCharge( int pixel, int bucket ) const
00129 {
00130
00131
00132
00133
00134 return GetBucket(bucket).GetPixelBucket(pixel).GetCharge();
00135 }
00136
00137
00138 Float_t SimPmt::GetTime( int pixel, int bucket ) const
00139 {
00140
00141
00142
00143
00144 return GetBucket(bucket).GetPixelBucket(pixel).GetTime();
00145 }
00146
00147 DigiSignal* SimPmt::CreateSignal( int pixel, int bucket ) const
00148 {
00149 return GetBucket(bucket).GetPixelBucket(pixel).CreateSignal();
00150 }
00151
00152
00153 Int_t SimPmt::GetTotalHitPixels( Bool_t with_xtalk ) const
00154 {
00159 int tot = 0;
00160 int tot_xtalk = 0;
00161
00162
00163 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00164 SimPmtTimeBucket& pmttb = it.Bucket();
00165
00166 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00167 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00168
00169 if(pixtb.GetTotalPE() >0) tot++;
00170 if(pixtb.GetTotalPEXtalk() >0) tot_xtalk++;
00171 }
00172 }
00173 if(with_xtalk) return tot_xtalk;
00174 return tot;
00175 }
00176
00177 Float_t SimPmt::GetTotalPe( void ) const
00178 {
00182
00183 Float_t tot = 0;
00184
00185
00186 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00187 SimPmtTimeBucket& pmttb = it.Bucket();
00188
00189 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00190 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00191
00192 tot += pixtb.GetTotalPE();
00193 }
00194 }
00195
00196 return tot;
00197 }
00198
00199 Float_t SimPmt::GetTotalCharge( void ) const
00200 {
00204
00205 Float_t tot = 0;
00206
00207
00208 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00209 SimPmtTimeBucket& pmttb = it.Bucket();
00210
00211 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00212 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00213
00214 tot += pixtb.GetCharge();
00215 }
00216 }
00217
00218 return tot;
00219 }
00220
00221
00222
00223
00224
00225 Float_t SimPmt::GenPoisson( Float_t lambda, Float_t x )
00226 {
00240
00241
00242
00243
00244
00245 return exp(-lambda + x*log(lambda)-TMath::LnGamma(x+1.0));
00246 }
00247
00248
00249 Float_t SimPmt::RandomGenPoisson( Float_t lambda )
00250 {
00261
00262
00263 if(lambda<=0) return 0;
00264
00265
00266 if (lambda > 88) {
00267 return fRandom->Gaus(0,1)*TMath::Sqrt(lambda) + lambda;
00268 }
00269
00270
00271
00272 Float_t rp = fRandom->Poisson(lambda);
00273
00274
00275
00276 Float_t ri = TMath::Nint(rp);
00277 Float_t a = ri - 0.5;
00278 Float_t b = ri + 0.5;
00279
00280
00281
00282 Float_t fmax;
00283 if((lambda>a)&&(lambda<b)) {
00284 fmax = GenPoisson(lambda,lambda);
00285 } else {
00286
00287 Float_t fa = GenPoisson(lambda,a);
00288 Float_t fb = GenPoisson(lambda,b);
00289 if(fa>fb) fmax = fa;
00290 else fmax = fb;
00291 }
00292
00293
00294 while(true) {
00295 Float_t x = fRandom->Rndm();
00296 x = x + a;
00297
00298
00299
00300 Float_t f = GenPoisson(lambda,x);
00301
00302
00303
00304
00305
00306 Float_t r = fRandom->Rndm();
00307 r = r*fmax;
00308
00309 if(r < f) return x;
00310 }
00311 }
00312
00313
00314 Bool_t SimPmt::GetGainAndWidth(int pixel, int spot, Double_t& outGain, Double_t &outWidth)
00315 {
00319
00320 PlexPixelSpotId psid = GetPixelSpotId(pixel,spot);
00321 FloatErr adcgain, adcwidth;
00322 Calibrator::Instance().DecalGainAndWidth(adcgain,adcwidth,psid);
00323
00324
00325 outWidth =adcwidth/adcgain;
00326
00327 float driftedGain = adcgain;
00328 if(fsPmtApplyGainDrift) {
00329 PlexHandle plex(fContext);
00330 PlexStripEndId seid = plex.GetStripEndId(psid);
00331 if(seid.IsValid()) {
00332 driftedGain = Calibrator::Instance().GetDriftCorrected(adcgain,seid);
00333 if(driftedGain != adcgain)
00334 MSG("DetSim",Msg::kDebug) << "Drifted gain on " << psid.AsString()
00335 << " " << seid.AsString()
00336 << " by " << driftedGain/adcgain << endl;
00337 }
00338 }
00339
00340
00341 float elecgain = 1.0/fsVaGain;
00342 if(GetTubeId().GetElecType()==ElecType::kQIE) elecgain = fsQieDacCharge;
00343 outGain = driftedGain * elecgain / Munits::e_SI;
00344
00345 return true;
00346 }
00347
00348
00350
00352
00353 void SimPmt::SimulatePmt(void)
00354 {
00355
00356
00357
00358
00359 if(fsPmtDoOpticalCrosstalk) SimulateOpticalXtalk();
00360 else CopyPEtoPEXtalk();
00361 SimulateCharges();
00362 if(fsPmtDoDarkNoise) SimulateDarkNoise();
00363 if(fsPmtDoNonlinearity) SimulateNonlinearity();
00364 if(fsPmtDoChargeCrosstalk) SimulateChargeCrosstalk();
00365 }
00366
00367
00368 void SimPmt::SimulateAfterpulsing()
00369 {
00370
00371
00372
00373
00374 if(fSimAfterpulseModel==0) return;
00375
00376
00377 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00378 SimPmtTimeBucket& pmttb = it.Bucket();
00379
00380
00381 for(Int_t injPix = 1; injPix <= fNPixels; injPix++) {
00382 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(injPix);
00383
00384
00385 for(Int_t injSpot = 1; injSpot <= fNSpots; injSpot++ ) {
00386 Float_t npe = pixtb.GetPE(injSpot);
00387
00388 if(npe>0) {
00389
00390 SimPixelTimeBucket::PeList_t pelist = pixtb.GetDigiPE(injSpot);
00391 SimPixelTimeBucket::PeList_t::iterator it = pelist.begin();
00392 SimPixelTimeBucket::PeList_t::iterator end = pelist.end();
00393 for( ; it!=end; it++ ) {
00394 const DigiPE* sourcePe = it->second;
00395
00396 if(sourcePe->IsAfterpulse()) continue;
00397
00398 Float_t prob = fSimAfterpulseModel->ComputeAfterpulseProb(sourcePe->GetPixelSpotId(),npe);
00399 if(fRandom->Uniform() < prob) {
00400 PlexPixelSpotId outpsid;
00401 Double_t outtime;
00402 fSimAfterpulseModel->ComputeAfterpulsePixelAndTime(
00403 sourcePe->GetPixelSpotId(),
00404 sourcePe->GetTime(),
00405 outpsid, outtime );
00406 DigiPE* newpe = new DigiPE(outtime, outpsid, DigiSignal::kAfterpulse );
00407 this->AddDigiPE(newpe);
00408 fCreatedDigiPEs.push_back(newpe);
00409 }
00410 }
00411
00412 }
00413 }
00414 }
00415 }
00416 }
00417
00418 void SimPmt::SimulateOpticalXtalk()
00419 {
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00430 SimPmtTimeBucket& pmttb = it.Bucket();
00431
00432
00433 for(Int_t xpix = 1; xpix<=fNPixels; xpix++) {
00434 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(xpix);
00435
00436
00437 for(Int_t injPix = 1; injPix <= fNPixels; injPix++) {
00438 if(injPix!=xpix) {
00439 SimPixelTimeBucket& pixtb_inj = pmttb.GetPixelBucket(injPix);
00440
00441
00442 for(Int_t injSpot = 1; injSpot <= fNSpots; injSpot++ ) {
00443 if( pixtb_inj.GetPE(injSpot) > 0) {
00444
00445 Float_t pe = GenOpticalCrosstalk(injPix,
00446 injSpot,
00447 xpix,
00448 pixtb_inj.GetPE(injSpot) );
00449
00450
00451
00452
00453 if(pe>0){
00454
00455 Int_t toSpot = fRandom->Integer(fNSpots)+1;
00456 MoveOpticalPE(TMath::Nint(pe),
00457 pixtb_inj,injSpot,
00458 pixtb, toSpot );
00459
00460 pixtb.SetTruthBit(DigiSignal::kCrosstalkOptical);
00461 }
00462 }
00463 }
00464
00465 }
00466 }
00467 }
00468
00469
00470 }
00471
00472
00473
00474 CopyPEtoPEXtalk();
00475 }
00476
00477 void SimPmt::SimulateCharges()
00478 {
00479 fTotalCharge = 0;
00480
00481 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00482 SimPmtTimeBucket& pmttb = it.Bucket();
00483
00484
00485 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00486 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00487
00488 pixtb.SetCharge(0);
00489
00490 for(Int_t spot = 1; spot <= fNSpots; spot++) {
00491
00492
00493
00494 Float_t charge = GenChargeFromPE(pix,spot, pixtb.GetPEXtalk(spot));
00495 pixtb.AddCharge(charge);
00496 }
00497 fTotalCharge += pixtb.GetCharge();
00498 pmttb.AddTotalCharge(pixtb.GetCharge());
00499 }
00500 }
00501 }
00502
00503
00504 void SimPmt::SimulateDarkNoise()
00505 {
00506 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00507 Int_t ibucket = it.BucketId();
00508 SimPmtTimeBucket& pmttb = it.Bucket();
00509
00510 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00511 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00512
00513 Float_t darkcharge = GenDarkNoiseCharge( pix, GetBucketDuration(ibucket) );
00514 pixtb.AddCharge(darkcharge);
00515 }
00516 }
00517
00518 }
00519
00520
00521 void SimPmt::SimulateNonlinearity()
00522 {
00523
00524
00525
00526
00527
00528 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00529 SimPmtTimeBucket& pmttb = it.Bucket();
00530
00531 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00532 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00533
00534 Float_t nonlin = GenNonlinearCharge( pix, pixtb.GetCharge() );
00535 pixtb.SetCharge(nonlin);
00536
00537 }
00538 }
00539 }
00540
00541
00542 void SimPmt::SimulateChargeCrosstalk()
00543 {
00544
00545
00546
00547
00548
00549
00550 static float sCharge[101];
00551 assert(fNPixels<100);
00552
00553 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00554 SimPmtTimeBucket& pmttb = it.Bucket();
00555
00556
00557 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00558 sCharge[pix] = pmttb.GetPixelBucket(pix).GetCharge();
00559 }
00560
00561
00562 for( Int_t xpix = 1; xpix <= fNPixels; xpix++ ) {
00563 for( Int_t injPix = 1; injPix <=fNPixels; injPix++ ) {
00564
00565 SimPixelTimeBucket& thePixel = pmttb.GetPixelBucket(xpix);
00566 Float_t xcharge = GenElectricalCrosstalk( injPix, xpix, sCharge[injPix] );
00567 thePixel.AddCharge(xcharge);
00568
00569 if(xcharge>1.0*Munits::fC)
00570 thePixel.SetTruthBit(DigiSignal::kCrosstalk);
00571
00572 }
00573 }
00574 }
00575 }
00576
00577
00579
00580
00581
00582
00583 Float_t SimPmt::GenChargeFromPE( Int_t pixel, Int_t spot, Float_t pe )
00584 {
00585
00586
00587
00588
00589
00590
00591
00592 if(pe<=0) return 0;
00593
00594
00595 Float_t secemm = GetPixelSecondaryEmmisionRatio(pixel,spot);
00596
00597
00598 Float_t mean2ndaryPe = pe * secemm;
00599 Float_t secondary_pe = RandomGenPoisson(mean2ndaryPe);
00600
00601
00602 return (secondary_pe / secemm)
00603 * GetPixelGain(pixel,spot)
00604 * 1.6e2;
00605
00606 }
00607
00608 Float_t SimPmt::GenDarkNoiseCharge( Int_t ,
00609 Float_t )
00610 {
00611
00612
00613
00614
00615
00616
00617
00618
00619 return 0;
00620 }
00621
00622
00623 Float_t SimPmt::GenNonlinearCharge( Int_t ,
00624 Float_t inCharge)
00625 {
00626
00627
00628
00629
00630
00631
00632
00633
00634 return inCharge;
00635 }
00636
00637 Float_t SimPmt::GenOpticalCrosstalk( Int_t ,
00638 Int_t ,
00639 Int_t ,
00640 Float_t )
00641 {
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652 return 0;
00653
00654 }
00655
00656 Float_t SimPmt::GenElectricalCrosstalk( Int_t ,
00657 Int_t ,
00658 Float_t )
00659 {
00660
00661
00662
00663
00664
00665
00666
00667 return 0;
00668 }
00669
00670
00671 void SimPmt::MoveOpticalPE( UInt_t npe,
00672 SimPixelTimeBucket& fromPixel,
00673 Int_t fromSpot,
00674 SimPixelTimeBucket& toPixel,
00675 Int_t toSpot)
00676 {
00677
00678
00679
00680
00681
00682 if(npe<=0) return;
00683
00684
00685
00686
00687 if(fromPixel.GetPE(fromSpot)<npe) {
00688 MSG("DetSim",Msg::kDebug) << "SimPmt::MoveOpticalPe() Optical crosstalk is bigger than injected light!" << endl;
00689 npe = (UInt_t)(fromPixel.GetPE(fromSpot));
00690 }
00691
00692
00693 SimPixelTimeBucket::PeList_t &fromPeList = fromPixel.GetDigiPE(fromSpot);
00694 SimPixelTimeBucket::PeList_t &toPeList = toPixel.GetDigiPEXtalk(toSpot);
00695
00696
00697
00698
00699
00700
00701 if(fromPeList.size() < npe) {
00702 MSG("DetSim",Msg::kDebug) << "SimPmt::MoveOpticalPe() Too much crosstalk! "
00703 << fromPeList.size() << "pe available, "
00704 << npe << " crosstalk requested." << endl;
00705 npe = fromPeList.size();
00706 }
00707
00708
00709
00710 for(UInt_t i=0; i<npe; i++) {
00711
00712 Int_t whichPe = fRandom->Integer(fromPeList.size());
00713
00714
00715 SimPixelTimeBucket::PeList_t::iterator it;
00716 it=fromPeList.begin();
00717 for(int i=0;i<whichPe;i++) ++it;
00718
00719 if(it!=fromPeList.end()) {
00720 toPeList.insert(*it);
00721 toPixel.AddPEXtalk(toSpot,1);
00722
00723 fromPeList.erase(it);
00724 }
00725 }
00726 }
00727
00728 void SimPmt::CopyPEtoPEXtalk(void)
00729 {
00730
00731 for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00732 SimPmtTimeBucket& pmttb = it.Bucket();
00733
00734
00735 for(Int_t pix = 1; pix <= fNPixels; pix++) {
00736 SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00737
00738
00739 for(Int_t spot = 1; spot<= fNSpots; spot++) {
00740 SimPixelTimeBucket::PeList_t &fromPeList = pixtb.GetDigiPE(spot);
00741 SimPixelTimeBucket::PeList_t &toPeList = pixtb.GetDigiPEXtalk(spot);
00742
00743 pixtb.AddPEXtalk(spot,(Float_t)(fromPeList.size()));
00744 toPeList.insert(fromPeList.begin(),fromPeList.end());
00745 }
00746 }
00747 }
00748 }
00749
00751
00752 void SimPmt::Config( Registry& config )
00753 {
00754 Int_t tbool;
00755 if(config.Get("pmtDoOpticalCrosstalk",tbool)) fsPmtDoOpticalCrosstalk = tbool;
00756 if(config.Get("pmtDoChargeCrosstalk",tbool)) fsPmtDoChargeCrosstalk = tbool;
00757 if(config.Get("pmtDoNonlinearity",tbool)) fsPmtDoNonlinearity = tbool;
00758 if(config.Get("pmtDoDarkNoise",tbool)) fsPmtDoDarkNoise = tbool;
00759 if(config.Get("pmtApplyGainDrift",tbool)) fsPmtApplyGainDrift = tbool;
00760
00761 config.Get("pmtScaleOpticalCrosstalk",fsPmtScaleOpticalCrosstalk);
00762 config.Get("pmtScaleChargeCrosstalk", fsPmtScaleChargeCrosstalk);
00763
00764 config.Get("vaGain",fsVaGain);
00765 config.Get("qieDacCharge",fsQieDacCharge);
00766
00767 if(config.Get("pmtRebuildGainMap",tbool)) fsRebuildGainMap = tbool;
00768
00769 if(config.Get("pmtHamamatsuPixelNumbering",tbool)) fsPmtHamamatsuPixelNumbering = tbool;
00770
00771 }
00772
00773 void SimPmt::PrintConfig(Option_t*)
00774 {
00775 printf("SimPmt Config: pmtDoOpticalCrosstalk %s\n",fsPmtDoOpticalCrosstalk?"true":"false");
00776 printf(" pmtDoChargeCrosstalk %s\n",fsPmtDoChargeCrosstalk?"true":"false");
00777 printf(" pmtDoNonlinearity %s\n",fsPmtDoNonlinearity?"true":"false");
00778 printf(" pmtDoDarkNoise %s\n",fsPmtDoDarkNoise?"true":"false");
00779 printf(" pmtScaleOpticalCrosstalk %f\n",fsPmtScaleOpticalCrosstalk);
00780 printf(" pmtScaleChargeCrosstalk %f\n",fsPmtScaleChargeCrosstalk );
00781 printf(" pmtApplyGainDrift %s\n",fsPmtApplyGainDrift?"true":"false" );
00782 printf(" pmtHamamatsuPixelNumbering %s\n",fsPmtHamamatsuPixelNumbering?"true":"false");
00783 printf(" vaGain %f ADC/fC\n",fsVaGain*Munits::fC);
00784 printf(" qieDacCharge %f fC/DAC\n",fsQieDacCharge/Munits::fC);
00785 printf(" pmtRebuildGainMap %s\n",fsRebuildGainMap?"true":"false");
00786 }
00787