Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

SimPmt.cxx

Go to the documentation of this file.
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; // true = pixel number 1-16 instead of 0-15
00019 Double_t SimPmt::fsVaGain;               // VA ADC->charge decalibration
00020 Double_t SimPmt::fsQieDacCharge;         // QIE ADC->charge decalibration
00021 Bool_t   SimPmt::fsRebuildGainMap = true;       // Rebuild the dynode chain each event, or keep it constant. Should change if gains change.
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   // Clear all data in this object.
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   // Add a DigiPE to the PMT.
00075   //
00076 
00077   if(!digipe) return;
00078 
00079   double time = digipe->GetTime();
00080   // First, find what bucket it goes into.
00081   int bucket = this->TimeToBucket(time);
00082   
00083   // Put the DigiPE in the bucket.
00084   // This bit of hocus-pocus does several things:
00085   // - makes the bucket if it doesn't exist.
00086   // - Translates the pixel and spot numbers to the range 1..N
00087   int pix =  GetPixelNumber(digipe->GetPixelSpotId());
00088   int spot = GetSpotNumber(digipe->GetPixelSpotId());
00089   GetBucket(bucket).AddDigiPE(digipe, pix, spot);
00090 
00091   // In addition, set the dynode time.
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   //  Get signal PE on pixel, spot at time bucket.
00102   //  Use spot = 0 to get total of all spots.
00103   // 
00104   if(spot == 0 ) {
00105     // Get total.
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   //  Get signal PE on pixel, spot at time bucket.
00116   //  Use spot = 0 to get total of all spots.
00117   // 
00118   if(spot == 0 ) {
00119     // Get total.
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   //  Get charge (in couloms) on pixel, at time bucket.
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   //  Get charge (in coulombs) on pixel, at time bucket.
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   // Iterate over all time buckets.
00162   
00163   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00164     SimPmtTimeBucket& pmttb = it.Bucket();
00165     // Iterate over pixels.
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   // Iterate over all time buckets.
00186   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00187     SimPmtTimeBucket& pmttb = it.Bucket();
00188     // Iterate over pixels.
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   // Iterate over all time buckets.
00208   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00209     SimPmtTimeBucket& pmttb = it.Bucket();
00210     // Iterate over pixels.
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   // For the usual compilers:
00242   //return  exp(-lambda + x*log(lambda)-lgamma(x+1.0));
00243 
00244   // For ROOT:
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   // Sanity check
00263   if(lambda<=0) return 0;
00264 
00265   // If lambda is large enough, just use a gaussian.
00266   if (lambda > 88) {
00267       return fRandom->Gaus(0,1)*TMath::Sqrt(lambda) + lambda;
00268   }
00269 
00270   // rp is an integer, chosen at random from the poisson dist'n.  
00271   // rp is the nearest integer to the REAL random number we want.  
00272   Float_t rp = fRandom->Poisson(lambda);
00273   
00274   // Now choose a random number between rp-0.5 and rp+0.5.
00275 
00276   Float_t ri = TMath::Nint(rp); // Just in case it's NOT an integer.
00277   Float_t a = ri - 0.5;
00278   Float_t b = ri + 0.5;
00279 
00280   // Find the maximum value of f() (where f is the gen poisson f'n) in
00281   // this range.  If the range contains lambda, the max is lambda.
00282   Float_t fmax;
00283   if((lambda>a)&&(lambda<b)) {
00284     fmax = GenPoisson(lambda,lambda);
00285   } else {
00286     // Find f(a) and f(b);
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   // Now, pick (weighted) number between (a,b]
00294   while(true) {
00295     Float_t x = fRandom->Rndm();
00296     x = x + a;   
00297     // i.e.  x = a + x*(b-a), but (b-a) =1;
00298     // x is a random number (non weighted) in (a,b]
00299 
00300     Float_t f = GenPoisson(lambda,x);
00301 
00302     // r is the probability that this number is good.
00303     // Note we chose r in the range (0,fmax), not (0,1).
00304     // This keeps us from haveing to re-pick in areas
00305     // where the function is small.
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   // Set the fractional width.
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   // convert into gain units (i.e. unitless)
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 // Simulate.
00352 
00353 void SimPmt::SimulatePmt(void)
00354 {
00355   //
00356   // This routine, it's override, and it's helpers do the actual
00357   // job of simulating everything there is to simulate in the PMT.
00358 
00359   if(fsPmtDoOpticalCrosstalk) SimulateOpticalXtalk();     // Move single PEs around for crosstalk
00360   else CopyPEtoPEXtalk();  // A null operation.
00361   SimulateCharges();                                 // Simulate the dynode chain to get anode charge.
00362   if(fsPmtDoDarkNoise)        SimulateDarkNoise();        // Add some charge to some pixels by dark noise.
00363   if(fsPmtDoNonlinearity)     SimulateNonlinearity();     // Apply the nonlinearity
00364   if(fsPmtDoChargeCrosstalk)  SimulateChargeCrosstalk();  // Crosstalk some charge around.
00365 }
00366 
00367 
00368 void SimPmt::SimulateAfterpulsing()
00369 {
00370   //
00371   // Creates extra PE, and adds them at delayed times.
00372   //
00373 
00374   if(fSimAfterpulseModel==0) return;
00375 
00376   // Iterate over all time buckets.
00377   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00378     SimPmtTimeBucket& pmttb = it.Bucket();
00379 
00380     // Iterate over pixels
00381     for(Int_t injPix = 1; injPix <= fNPixels; injPix++) {      
00382       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(injPix);
00383       
00384       // Iterate over all spots
00385       for(Int_t injSpot = 1; injSpot <= fNSpots; injSpot++ ) { 
00386         Float_t npe = pixtb.GetPE(injSpot);
00387         
00388         if(npe>0) {
00389           // Do this the easy, sloppy way: roll a number for every PE.
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             // Don't afterpulse the afterpulsing...? Might be correct to do so.
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);      // Add to simulation.
00408               fCreatedDigiPEs.push_back(newpe); // Add to ownership.
00409             }
00410           }
00411           
00412         }
00413       }
00414     }
00415   }
00416 }
00417 
00418 void SimPmt::SimulateOpticalXtalk()
00419 {
00420   //
00421   // Puts extra PE into pixels they don't belong.
00422   //
00423  
00424   // Hack!
00425   // This can be uncommented to make a big dump file of the crosstalk.
00426   //static ofstream ofile("xtalk.dat");
00427 
00428   // Iterate over all time buckets.
00429   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00430     SimPmtTimeBucket& pmttb = it.Bucket();
00431 
00432     // Iterate over the talked-to pixel
00433     for(Int_t xpix = 1; xpix<=fNPixels; xpix++) {  
00434       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(xpix);
00435   
00436       // Iterate over talking pixels.
00437       for(Int_t injPix = 1; injPix <= fNPixels; injPix++) {      
00438         if(injPix!=xpix) {
00439           SimPixelTimeBucket& pixtb_inj = pmttb.GetPixelBucket(injPix);
00440 
00441           // Iterate over all talking spots
00442           for(Int_t injSpot = 1; injSpot <= fNSpots; injSpot++ ) { 
00443             if( pixtb_inj.GetPE(injSpot) > 0) { // There is charge in this spot.
00444               
00445               Float_t pe = GenOpticalCrosstalk(injPix, // Injected pixel
00446                                                injSpot,  // Injected spot
00447                                                xpix,     // xtalk pixel
00448                                                pixtb_inj.GetPE(injSpot) ); // number pe.
00449               
00450               // Debugging hack continued.
00451               //ofile << injPix << "\t"  << injSpot << "\t" 
00452               //            << xpix << "\t" << pixtb_inj.GetPE(injSpot) << "\t" << pe << endl;
00453               if(pe>0){
00454                 // Choose a spot at random:
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           } // Itr over inj spot
00464           
00465         } // Itr over inj pixel
00466       } 
00467     }  // itr over xtalk pixel
00468 
00469     // Now we're done with all pixels in the bucket.
00470   } // it over buckets
00471   // whew!
00472 
00473   // Copy whatever didn't crosstalk.
00474   CopyPEtoPEXtalk();
00475 }
00476 
00477 void SimPmt::SimulateCharges()
00478 {
00479   fTotalCharge = 0;
00480   // Iterate over all time buckets.
00481   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00482     SimPmtTimeBucket& pmttb = it.Bucket();
00483 
00484     // Iterate over pixels.
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             // This bit of magic provides the Int_trinsic
00493             // width of the 1 PE peak in a nice way.
00494             Float_t charge = GenChargeFromPE(pix,spot, pixtb.GetPEXtalk(spot));
00495             pixtb.AddCharge(charge);
00496           } // spots
00497           fTotalCharge += pixtb.GetCharge();
00498           pmttb.AddTotalCharge(pixtb.GetCharge());
00499       } // pixels
00500   } // buckets.
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   // Simulate nonlinearity.
00525   // No algorithm yet.
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   // Simulates charge crosstalk.
00546   //
00547   // Currently just a simple fraction.
00548 
00549   // (Static for speed's sake.)
00550   static float sCharge[101]; // We have no PMT type with more than 64 pixels.
00551   assert(fNPixels<100);
00552 
00553   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00554     SimPmtTimeBucket& pmttb = it.Bucket();
00555     
00556     // Store old charges. 
00557     for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00558       sCharge[pix] = pmttb.GetPixelBucket(pix).GetCharge();
00559     }
00560 
00561     // Do crosstalk.
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         // Set truth bit for significant charge only.
00569         if(xcharge>1.0*Munits::fC) 
00570           thePixel.SetTruthBit(DigiSignal::kCrosstalk);
00571 
00572       }
00573     }
00574   }
00575 }
00576 
00577 
00579 // Actual Computation.
00580 
00581 
00582 
00583 Float_t SimPmt::GenChargeFromPE( Int_t pixel, Int_t spot, Float_t pe )
00584 {
00585   //
00586   // Does a single charge simulation.
00587   //
00588   
00589   // First version, by Nathaniel.
00590   // Uses the generalized poisson to get the job done.
00591 
00592   if(pe<=0) return 0;
00593 
00594   // The secondary emmission ratio is directly related to the width of the 1pe peak.
00595   Float_t secemm = GetPixelSecondaryEmmisionRatio(pixel,spot);
00596 
00597   // Choose a random number from the spectrum with a peak at the number of expected 2nary pes.
00598   Float_t mean2ndaryPe = pe * secemm;
00599   Float_t secondary_pe = RandomGenPoisson(mean2ndaryPe);
00600 
00601   // convert this into charge.
00602   return (secondary_pe / secemm)
00603     * GetPixelGain(pixel,spot)                   // Gain of pixel
00604     * 1.6e2;                                     // Convert 10^6 e -> fempto Coulombs  
00605 
00606 }
00607 
00608 Float_t SimPmt::GenDarkNoiseCharge( Int_t /* pixel */, 
00609                                     Float_t /* timeWindow */ )
00610 {
00611   //
00612   // Dark noise simulation.
00613   //
00614   // Return the charge (in coulombs) that results from opening an integration gate of duration timeWindow (in Muints).
00615   // (This should return zero most of the time).
00616   //
00617   
00618   // No simulation yet.
00619   return 0; 
00620 }
00621 
00622 
00623 Float_t SimPmt::GenNonlinearCharge( Int_t /* pixel */,
00624                                     Float_t inCharge) 
00625 {
00626   //
00627   // Nonlinearity Simulation.
00628   //
00629   // Given a charge on the anode, this routine applies
00630   // the nonlinearity for the PMT to give a new output charge.
00631   // 
00632   // For a completely linear response, return inCharge.
00633   
00634   return inCharge; 
00635 }
00636 
00637 Float_t SimPmt::GenOpticalCrosstalk( Int_t /* injPixel */,
00638                                      Int_t /* injSpot */,
00639                                      Int_t /* xtalkPixel */,
00640                                      Float_t /* injPE */ ) 
00641 {
00642   // 
00643   // Optical crosstalk simulation.
00644   //
00645   // If injPE photoelectrons of light are injected into injPixel and injSpot,
00646   // this routine returns the number of the photoelectrons that will leak into
00647   // the xtalkPixel.  Note that this should probably be a random integer..
00648   //
00649   
00650   // Return 0 for no crosstalk.
00651   
00652   return 0; 
00653 
00654 }
00655 
00656 Float_t SimPmt::GenElectricalCrosstalk( Int_t /* injPixel */,                                   
00657                                         Int_t /* xtalkPixel */,
00658                                         Float_t /* injCharge */ ) 
00659 {
00660   //
00661   // Electrical crosstalk simulation.
00662   //
00663   // If inCharge femtoCoulombs of charge are seen on the anode of injPixel, then
00664   // this returns the quantity of charge that will be leaked to xtalkPixel.
00665   // This may be a random quantity, or a fixed fraction, depending on the model.
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   // Moves DigiPe from one pixel to another 
00679   // for use with optical crosstalk.
00680 
00681   // For efficiency.
00682   if(npe<=0) return;
00683 
00684   // Sanity check.
00685   // This can happen most likely for a single PE for which the 'mean' crosstalk is maybe 0.2%.
00686   // This gives a non-zero chance to get a poisson number of 2. 
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)); // Set to max.
00690   }
00691 
00692   // Get the PE lists.
00693   SimPixelTimeBucket::PeList_t &fromPeList = fromPixel.GetDigiPE(fromSpot);
00694   SimPixelTimeBucket::PeList_t &toPeList =   toPixel.GetDigiPEXtalk(toSpot);
00695 
00696 
00697   // Even more sanity check.. COULD happen.
00698   // Happens most likely for a single PE on the pixel, which gets cross-talked
00699   // away to two neighboring pixels. The odds of this happening are about
00700   // one chance in 10,000, but there are an awful lot of pixels in an event.
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   // For each moved pe
00710   for(UInt_t i=0; i<npe; i++) {
00711     // Pick a pe to move:
00712     Int_t whichPe = fRandom->Integer(fromPeList.size());
00713 
00714     // Go find it.
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()) { // Even more sanity checks.
00720       toPeList.insert(*it); // Move it.
00721       toPixel.AddPEXtalk(toSpot,1); // Update number
00722       
00723       fromPeList.erase(it);    // Get rid of old copy: it's gone.
00724     }
00725   }
00726 }
00727 
00728 void SimPmt::CopyPEtoPEXtalk(void)
00729 {
00730   // Iterate over all time buckets.
00731   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00732     SimPmtTimeBucket& pmttb = it.Bucket();
00733 
00734     // Iterate over pixels.
00735     for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00736       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00737       
00738       // Iterate over spots.
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 // Configuration.
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 

Generated on Fri Mar 28 15:39:51 2008 for loon by  doxygen 1.3.9.1