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.31 2008/11/18 17:31:02 rhatcher 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 //Added by G. Pawloski to scale Adjacent and Diagonal separately
00018 Double_t SimPmt::fsPmtScaleAdjacentChargeCrosstalk = 1.0;
00019 Double_t SimPmt::fsPmtScaleDiagonalChargeCrosstalk = 1.0;
00020 Double_t SimPmt::fsPmtScaleAdjacentOpticalCrosstalk = 1.0;
00021 Double_t SimPmt::fsPmtScaleDiagonalOpticalCrosstalk = 1.0;
00022 Bool_t   SimPmt::fsPmtApplyGainDrift     = true;
00023 Bool_t   SimPmt::fsPmtHamamatsuPixelNumbering = false; // true = pixel number 1-16 instead of 0-15
00024 Double_t SimPmt::fsVaGain;               // VA ADC->charge decalibration
00025 Double_t SimPmt::fsQieDacCharge;         // QIE ADC->charge decalibration
00026 Bool_t   SimPmt::fsRebuildGainMap = true;       // Rebuild the dynode chain each event, or keep it constant. Should change if gains change.
00027 
00028 SimPmt::SimPmt ( PlexPixelSpotId tube, 
00029                  VldContext context, 
00030                  TRandom* random,
00031                  Int_t nPixels, Int_t nSpots 
00032                  )
00033   : fNPixels(nPixels),
00034     fNSpots(nSpots),
00035     fTube(tube),
00036     fContext(context),
00037     fRandom(random),
00038     fSimAfterpulseModel(0)
00039 {
00040   if(random == NULL) fRandom = gRandom;
00041  
00042   SimPmt::Reset(context);
00043 }
00044 
00045 
00046 SimPmt::~SimPmt()
00047 {
00048   BucketMap_t::iterator itr(fTimeBuckets.begin()),itrEnd(fTimeBuckets.end());
00049   for (; itr != itrEnd; ++itr) 
00050     delete itr->second; 
00051   fTimeBuckets.clear();
00052 
00053   UInt_t n= fCreatedDigiPEs.size();
00054   for(UInt_t i=0;i<n;i++) delete fCreatedDigiPEs[i];
00055 }
00056 
00057 void SimPmt::Reset(const VldContext& newContext)
00058 {
00059   //
00060   // Clear all data in this object.
00061   //
00062   MSG("DetSim",Msg::kVerbose) << "SimPmt::Reset() " << fTube.AsString() << endl;
00063   fContext = newContext;
00064   fTotalCharge = 0;
00065   fDynodeTime = kPmtTime_Never;
00066   BucketMap_t::iterator itr(fTimeBuckets.begin()),itrEnd(fTimeBuckets.end());
00067   for (; itr != itrEnd; ++itr) 
00068     delete itr->second; 
00069   fTimeBuckets.clear();
00070   UInt_t num= fCreatedDigiPEs.size();
00071   for(UInt_t i=0;i<num;i++) delete fCreatedDigiPEs[i];
00072 }
00073 
00074 
00075 
00076 void SimPmt::AddDigiPE( const DigiPE* digipe )
00077 {
00078   //
00079   // Add a DigiPE to the PMT.
00080   //
00081 
00082   if(!digipe) return;
00083 
00084   double time = digipe->GetTime();
00085   // First, find what bucket it goes into.
00086   int bucket = this->TimeToBucket(time);
00087   
00088   // Put the DigiPE in the bucket.
00089   // This bit of hocus-pocus does several things:
00090   // - makes the bucket if it doesn't exist.
00091   // - Translates the pixel and spot numbers to the range 1..N
00092   int pix =  GetPixelNumber(digipe->GetPixelSpotId());
00093   int spot = GetSpotNumber(digipe->GetPixelSpotId());
00094   GetBucket(bucket).AddDigiPE(digipe, pix, spot);
00095 
00096   // In addition, set the dynode time.
00097   GetBucket(bucket).SetDynodeTime(time);
00098   if(time<fDynodeTime) fDynodeTime = time;
00099 }
00100 
00101 
00102 
00103 Float_t SimPmt::GetPe( int pixel, int spot, int bucket ) const
00104 {
00105   // 
00106   //  Get signal PE on pixel, spot at time bucket.
00107   //  Use spot = 0 to get total of all spots.
00108   // 
00109   if(spot == 0 ) {
00110     // Get total.
00111     return GetBucket(bucket).GetPixelBucket(pixel).GetTotalPE();
00112   }
00113 
00114   return GetBucket(bucket).GetPixelBucket(pixel).GetPE(spot);
00115 }
00116 
00117 Float_t SimPmt::GetPeXtalk( int pixel, int spot, int bucket ) const
00118 {
00119   // 
00120   //  Get signal PE on pixel, spot at time bucket.
00121   //  Use spot = 0 to get total of all spots.
00122   // 
00123   if(spot == 0 ) {
00124     // Get total.
00125     return GetBucket(bucket).GetPixelBucket(pixel).GetTotalPEXtalk();
00126   }
00127 
00128   return GetBucket(bucket).GetPixelBucket(pixel).GetPEXtalk(spot);
00129 }
00130 
00131 
00132 
00133 Float_t SimPmt::GetCharge( int pixel, int bucket ) const
00134 {
00135   // 
00136   //  Get charge (in couloms) on pixel, at time bucket.
00137   // 
00138 
00139   return GetBucket(bucket).GetPixelBucket(pixel).GetCharge();
00140 }
00141 
00142 
00143 Float_t SimPmt::GetTime( int pixel, int bucket ) const
00144 {
00145   // 
00146   //  Get charge (in coulombs) on pixel, at time bucket.
00147   // 
00148 
00149   return GetBucket(bucket).GetPixelBucket(pixel).GetTime();
00150 }
00151 
00152 DigiSignal* SimPmt::CreateSignal( int pixel, int bucket ) const
00153 {
00154   return GetBucket(bucket).GetPixelBucket(pixel).CreateSignal();
00155 }
00156 
00157 
00158 Int_t SimPmt::GetTotalHitPixels( Bool_t with_xtalk ) const
00159 {
00164   int tot = 0;
00165   int tot_xtalk = 0;
00166   // Iterate over all time buckets.
00167   
00168   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00169     SimPmtTimeBucket& pmttb = it.Bucket();
00170     // Iterate over pixels.
00171       for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00172           SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00173 
00174           if(pixtb.GetTotalPE() >0)     tot++;   
00175           if(pixtb.GetTotalPEXtalk() >0) tot_xtalk++;
00176       }
00177   }         
00178   if(with_xtalk) return tot_xtalk;
00179   return tot;
00180 }
00181 
00182 Float_t SimPmt::GetTotalPe( void ) const 
00183 {
00187   
00188   Float_t tot = 0;
00189   
00190   // Iterate over all time buckets.
00191   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00192     SimPmtTimeBucket& pmttb = it.Bucket();
00193     // Iterate over pixels.
00194       for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00195           SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00196           
00197           tot += pixtb.GetTotalPE();
00198       }
00199   }         
00200 
00201   return tot;
00202 }
00203 
00204 Float_t SimPmt::GetTotalCharge( void ) const 
00205 {
00209   
00210   Float_t tot = 0;
00211   
00212   // Iterate over all time buckets.
00213   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00214     SimPmtTimeBucket& pmttb = it.Bucket();
00215     // Iterate over pixels.
00216       for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00217           SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00218           
00219           tot += pixtb.GetCharge();
00220       }
00221   }         
00222 
00223   return tot;
00224 }
00225 
00226 
00227 
00228 
00229 
00230 Float_t SimPmt::GenPoisson( Float_t lambda, Float_t x )
00231 {
00245 
00246   // For the usual compilers:
00247   //return  exp(-lambda + x*log(lambda)-lgamma(x+1.0));
00248 
00249   // For ROOT:
00250   return  exp(-lambda + x*log(lambda)-TMath::LnGamma(x+1.0));
00251 }
00252 
00253 
00254 Float_t SimPmt::RandomGenPoisson( Float_t lambda )
00255 {
00266 
00267   // Sanity check
00268   if(lambda<=0) return 0;
00269 
00270   // If lambda is large enough, just use a gaussian.
00271   if (lambda > 88) {
00272       return fRandom->Gaus(0,1)*TMath::Sqrt(lambda) + lambda;
00273   }
00274 
00275   // rp is an integer, chosen at random from the poisson dist'n.  
00276   // rp is the nearest integer to the REAL random number we want.  
00277   Float_t rp = fRandom->Poisson(lambda);
00278   
00279   // Now choose a random number between rp-0.5 and rp+0.5.
00280 
00281   Float_t ri = TMath::Nint(rp); // Just in case it's NOT an integer.
00282   Float_t a = ri - 0.5;
00283   Float_t b = ri + 0.5;
00284 
00285   // Find the maximum value of f() (where f is the gen poisson f'n) in
00286   // this range.  If the range contains lambda, the max is lambda.
00287   Float_t fmax;
00288   if((lambda>a)&&(lambda<b)) {
00289     fmax = GenPoisson(lambda,lambda);
00290   } else {
00291     // Find f(a) and f(b);
00292     Float_t fa = GenPoisson(lambda,a);
00293     Float_t fb = GenPoisson(lambda,b);
00294     if(fa>fb) fmax = fa;
00295     else      fmax = fb;
00296   }
00297 
00298   // Now, pick (weighted) number between (a,b]
00299   while(true) {
00300     Float_t x = fRandom->Rndm();
00301     x = x + a;   
00302     // i.e.  x = a + x*(b-a), but (b-a) =1;
00303     // x is a random number (non weighted) in (a,b]
00304 
00305     Float_t f = GenPoisson(lambda,x);
00306 
00307     // r is the probability that this number is good.
00308     // Note we chose r in the range (0,fmax), not (0,1).
00309     // This keeps us from haveing to re-pick in areas
00310     // where the function is small.
00311     Float_t r = fRandom->Rndm();
00312     r = r*fmax;
00313 
00314     if(r < f) return x;
00315   }
00316 }
00317 
00318 
00319 Bool_t SimPmt::GetGainAndWidth(int pixel, int spot, Double_t& outGain, Double_t &outWidth)
00320 {
00324 
00325   PlexPixelSpotId psid = GetPixelSpotId(pixel,spot);
00326   FloatErr adcgain, adcwidth;
00327   Calibrator::Instance().DecalGainAndWidth(adcgain,adcwidth,psid);
00328 
00329   // Set the fractional width.
00330   outWidth =adcwidth/adcgain;
00331   
00332   float driftedGain = adcgain;
00333   if(fsPmtApplyGainDrift) {
00334     PlexHandle plex(fContext);
00335     PlexStripEndId seid = plex.GetStripEndId(psid);
00336     if(seid.IsValid()) {
00337       driftedGain = Calibrator::Instance().GetDriftCorrected(adcgain,seid);
00338       if(driftedGain != adcgain)
00339         MSG("DetSim",Msg::kDebug) << "Drifted gain on " << psid.AsString() 
00340                                   << " " << seid.AsString() 
00341                                   << " by " << driftedGain/adcgain << endl;      
00342     }
00343   }
00344   
00345   // convert into gain units (i.e. unitless)
00346   float elecgain = 1.0/fsVaGain;
00347   if(GetTubeId().GetElecType()==ElecType::kQIE) elecgain = fsQieDacCharge;
00348   outGain = driftedGain * elecgain / Munits::e_SI;
00349 
00350    return true;
00351 }
00352 
00353 
00355 // Simulate.
00357 
00358 void SimPmt::SimulatePmt(void)
00359 {
00360   //
00361   // This routine, it's override, and it's helpers do the actual
00362   // job of simulating everything there is to simulate in the PMT.
00363 
00364   if(fsPmtDoOpticalCrosstalk) SimulateOpticalXtalk();     // Move single PEs around for crosstalk
00365   else CopyPEtoPEXtalk();  // A null operation.
00366   SimulateCharges();                                 // Simulate the dynode chain to get anode charge.
00367   if(fsPmtDoDarkNoise)        SimulateDarkNoise();        // Add some charge to some pixels by dark noise.
00368   if(fsPmtDoNonlinearity)     SimulateNonlinearity();     // Apply the nonlinearity
00369   if(fsPmtDoChargeCrosstalk)  SimulateChargeCrosstalk();  // Crosstalk some charge around.
00370 }
00371 
00372 
00373 void SimPmt::SimulateAfterpulsing()
00374 {
00375   //
00376   // Creates extra PE, and adds them at delayed times.
00377   //
00378 
00379   if(fSimAfterpulseModel==0) return;
00380 
00381   // Iterate over all time buckets.
00382   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00383     SimPmtTimeBucket& pmttb = it.Bucket();
00384 
00385     // Iterate over pixels
00386     for(Int_t injPix = 1; injPix <= fNPixels; injPix++) {      
00387       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(injPix);
00388       
00389       // Iterate over all spots
00390       for(Int_t injSpot = 1; injSpot <= fNSpots; injSpot++ ) { 
00391         Float_t npe = pixtb.GetPE(injSpot);
00392         
00393         if(npe>0) {
00394           // Do this the easy, sloppy way: roll a number for every PE.
00395           SimPixelTimeBucket::PeList_t pelist = pixtb.GetDigiPE(injSpot);
00396           SimPixelTimeBucket::PeList_t::iterator it = pelist.begin();
00397           SimPixelTimeBucket::PeList_t::iterator end = pelist.end();
00398           for( ; it!=end; it++ ) {
00399             const DigiPE* sourcePe = it->second;
00400             // Don't afterpulse the afterpulsing...? Might be correct to do so.
00401             if(sourcePe->IsAfterpulse()) continue;
00402             
00403             Float_t prob = fSimAfterpulseModel->ComputeAfterpulseProb(sourcePe->GetPixelSpotId(),npe);
00404             if(fRandom->Uniform() < prob) {
00405               PlexPixelSpotId outpsid;
00406               Double_t outtime;
00407               fSimAfterpulseModel->ComputeAfterpulsePixelAndTime(
00408                                                                  sourcePe->GetPixelSpotId(),
00409                                                                  sourcePe->GetTime(),
00410                                                                  outpsid, outtime );
00411               DigiPE* newpe = new DigiPE(outtime, outpsid, DigiSignal::kAfterpulse );
00412               this->AddDigiPE(newpe);      // Add to simulation.
00413               fCreatedDigiPEs.push_back(newpe); // Add to ownership.
00414             }
00415           }
00416           
00417         }
00418       }
00419     }
00420   }
00421 }
00422 
00423 void SimPmt::SimulateOpticalXtalk()
00424 {
00425   //
00426   // Puts extra PE into pixels they don't belong.
00427   //
00428  
00429   // Hack!
00430   // This can be uncommented to make a big dump file of the crosstalk.
00431   //static ofstream ofile("xtalk.dat");
00432 
00433   // Iterate over all time buckets.
00434   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00435     SimPmtTimeBucket& pmttb = it.Bucket();
00436 
00437     // Iterate over the talked-to pixel
00438     for(Int_t xpix = 1; xpix<=fNPixels; xpix++) {  
00439       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(xpix);
00440   
00441       // Iterate over talking pixels.
00442       for(Int_t injPix = 1; injPix <= fNPixels; injPix++) {      
00443         if(injPix!=xpix) {
00444           SimPixelTimeBucket& pixtb_inj = pmttb.GetPixelBucket(injPix);
00445 
00446           // Iterate over all talking spots
00447           for(Int_t injSpot = 1; injSpot <= fNSpots; injSpot++ ) { 
00448             if( pixtb_inj.GetPE(injSpot) > 0) { // There is charge in this spot.
00449               
00450               Float_t pe = GenOpticalCrosstalk(injPix, // Injected pixel
00451                                                injSpot,  // Injected spot
00452                                                xpix,     // xtalk pixel
00453                                                pixtb_inj.GetPE(injSpot) ); // number pe.
00454               
00455               // Debugging hack continued.
00456               //ofile << injPix << "\t"  << injSpot << "\t" 
00457               //            << xpix << "\t" << pixtb_inj.GetPE(injSpot) << "\t" << pe << endl;
00458               if(pe>0){
00459                 // Choose a spot at random:
00460                 Int_t toSpot = fRandom->Integer(fNSpots)+1;
00461                 MoveOpticalPE(TMath::Nint(pe),
00462                               pixtb_inj,injSpot,
00463                               pixtb,    toSpot );
00464 
00465                 pixtb.SetTruthBit(DigiSignal::kCrosstalkOptical);
00466               }
00467             }
00468           } // Itr over inj spot
00469           
00470         } // Itr over inj pixel
00471       } 
00472     }  // itr over xtalk pixel
00473 
00474     // Now we're done with all pixels in the bucket.
00475   } // it over buckets
00476   // whew!
00477 
00478   // Copy whatever didn't crosstalk.
00479   CopyPEtoPEXtalk();
00480 }
00481 
00482 void SimPmt::SimulateCharges()
00483 {
00484   fTotalCharge = 0;
00485   // Iterate over all time buckets.
00486   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00487     SimPmtTimeBucket& pmttb = it.Bucket();
00488 
00489     // Iterate over pixels.
00490       for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00491           SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00492           
00493           pixtb.SetCharge(0);
00494           
00495           for(Int_t spot = 1; spot <= fNSpots; spot++) {
00496             
00497             // This bit of magic provides the Int_trinsic
00498             // width of the 1 PE peak in a nice way.
00499             Float_t charge = GenChargeFromPE(pix,spot, pixtb.GetPEXtalk(spot));
00500             pixtb.AddCharge(charge);
00501           } // spots
00502           fTotalCharge += pixtb.GetCharge();
00503           pmttb.AddTotalCharge(pixtb.GetCharge());
00504       } // pixels
00505   } // buckets.
00506 }
00507 
00508 
00509 void SimPmt::SimulateDarkNoise()
00510 {
00511   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00512     Int_t ibucket = it.BucketId();
00513     SimPmtTimeBucket& pmttb = it.Bucket();
00514     
00515     for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00516       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00517       
00518       Float_t darkcharge = GenDarkNoiseCharge( pix, GetBucketDuration(ibucket) );
00519       pixtb.AddCharge(darkcharge);
00520     }
00521   }
00522   
00523 }
00524 
00525 
00526 void SimPmt::SimulateNonlinearity()
00527 {
00528   // 
00529   // Simulate nonlinearity.
00530   // No algorithm yet.
00531   //
00532   
00533   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00534     SimPmtTimeBucket& pmttb = it.Bucket();
00535     
00536     for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00537       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00538       
00539       Float_t nonlin = GenNonlinearCharge( pix, pixtb.GetCharge() );
00540       pixtb.SetCharge(nonlin);
00541       
00542      }
00543    }
00544 }
00545 
00546 
00547 void SimPmt::SimulateChargeCrosstalk()
00548 {
00549   //
00550   // Simulates charge crosstalk.
00551   //
00552   // Currently just a simple fraction.
00553 
00554   // (Static for speed's sake.)
00555   static float sCharge[101]; // We have no PMT type with more than 64 pixels.
00556   assert(fNPixels<100);
00557 
00558   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00559     SimPmtTimeBucket& pmttb = it.Bucket();
00560     
00561     // Store old charges. 
00562     for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00563       sCharge[pix] = pmttb.GetPixelBucket(pix).GetCharge();
00564     }
00565 
00566     // Do crosstalk.
00567     for( Int_t xpix = 1; xpix <= fNPixels; xpix++ ) {
00568       for( Int_t injPix = 1; injPix <=fNPixels; injPix++ ) {
00569         
00570         SimPixelTimeBucket& thePixel =  pmttb.GetPixelBucket(xpix);
00571         Float_t xcharge = GenElectricalCrosstalk( injPix, xpix, sCharge[injPix] );
00572         thePixel.AddCharge(xcharge);
00573         // Set truth bit for significant charge only.
00574         if(xcharge>1.0*Munits::fC) 
00575           thePixel.SetTruthBit(DigiSignal::kCrosstalk);
00576 
00577       }
00578     }
00579   }
00580 }
00581 
00582 
00584 // Actual Computation.
00585 
00586 
00587 
00588 Float_t SimPmt::GenChargeFromPE( Int_t pixel, Int_t spot, Float_t pe )
00589 {
00590   //
00591   // Does a single charge simulation.
00592   //
00593   
00594   // First version, by Nathaniel.
00595   // Uses the generalized poisson to get the job done.
00596 
00597   if(pe<=0) return 0;
00598 
00599   // The secondary emmission ratio is directly related to the width of the 1pe peak.
00600   Float_t secemm = GetPixelSecondaryEmmisionRatio(pixel,spot);
00601 
00602   // Choose a random number from the spectrum with a peak at the number of expected 2nary pes.
00603   Float_t mean2ndaryPe = pe * secemm;
00604   Float_t secondary_pe = RandomGenPoisson(mean2ndaryPe);
00605 
00606   // convert this into charge.
00607   return (secondary_pe / secemm)
00608     * GetPixelGain(pixel,spot)                   // Gain of pixel
00609     * 1.6e2;                                     // Convert 10^6 e -> fempto Coulombs  
00610 
00611 }
00612 
00613 Float_t SimPmt::GenDarkNoiseCharge( Int_t /* pixel */, 
00614                                     Float_t /* timeWindow */ )
00615 {
00616   //
00617   // Dark noise simulation.
00618   //
00619   // Return the charge (in coulombs) that results from opening an integration gate of duration timeWindow (in Munits).
00620   // (This should return zero most of the time).
00621   //
00622   
00623   // No simulation yet.
00624   return 0; 
00625 }
00626 
00627 
00628 Float_t SimPmt::GenNonlinearCharge( Int_t /* pixel */,
00629                                     Float_t inCharge) 
00630 {
00631   //
00632   // Nonlinearity Simulation.
00633   //
00634   // Given a charge on the anode, this routine applies
00635   // the nonlinearity for the PMT to give a new output charge.
00636   // 
00637   // For a completely linear response, return inCharge.
00638   
00639   return inCharge; 
00640 }
00641 
00642 Float_t SimPmt::GenOpticalCrosstalk( Int_t /* injPixel */,
00643                                      Int_t /* injSpot */,
00644                                      Int_t /* xtalkPixel */,
00645                                      Float_t /* injPE */ ) 
00646 {
00647   // 
00648   // Optical crosstalk simulation.
00649   //
00650   // If injPE photoelectrons of light are injected into injPixel and injSpot,
00651   // this routine returns the number of the photoelectrons that will leak into
00652   // the xtalkPixel.  Note that this should probably be a random integer..
00653   //
00654   
00655   // Return 0 for no crosstalk.
00656   
00657   return 0; 
00658 
00659 }
00660 
00661 Float_t SimPmt::GenElectricalCrosstalk( Int_t /* injPixel */,                                   
00662                                         Int_t /* xtalkPixel */,
00663                                         Float_t /* injCharge */ ) 
00664 {
00665   //
00666   // Electrical crosstalk simulation.
00667   //
00668   // If inCharge femtoCoulombs of charge are seen on the anode of injPixel, then
00669   // this returns the quantity of charge that will be leaked to xtalkPixel.
00670   // This may be a random quantity, or a fixed fraction, depending on the model.
00671 
00672  return 0; 
00673 }
00674 
00675 
00676 void SimPmt::MoveOpticalPE( UInt_t npe,
00677                             SimPixelTimeBucket& fromPixel,
00678                             Int_t               fromSpot,
00679                             SimPixelTimeBucket& toPixel,
00680                             Int_t               toSpot)
00681 {
00682   //
00683   // Moves DigiPe from one pixel to another 
00684   // for use with optical crosstalk.
00685 
00686   // For efficiency.
00687   if(npe<=0) return;
00688 
00689   // Sanity check.
00690   // This can happen most likely for a single PE for which the 'mean' crosstalk is maybe 0.2%.
00691   // This gives a non-zero chance to get a poisson number of 2. 
00692   if(fromPixel.GetPE(fromSpot)<npe) {
00693     MSG("DetSim",Msg::kDebug) << "SimPmt::MoveOpticalPe() Optical crosstalk is bigger than injected light!" << endl;
00694     npe = (UInt_t)(fromPixel.GetPE(fromSpot)); // Set to max.
00695   }
00696 
00697   // Get the PE lists.
00698   SimPixelTimeBucket::PeList_t &fromPeList = fromPixel.GetDigiPE(fromSpot);
00699   SimPixelTimeBucket::PeList_t &toPeList =   toPixel.GetDigiPEXtalk(toSpot);
00700 
00701 
00702   // Even more sanity check.. COULD happen.
00703   // Happens most likely for a single PE on the pixel, which gets cross-talked
00704   // away to two neighboring pixels. The odds of this happening are about
00705   // one chance in 10,000, but there are an awful lot of pixels in an event.
00706   if(fromPeList.size() < npe) {
00707     MSG("DetSim",Msg::kDebug) << "SimPmt::MoveOpticalPe() Too much crosstalk! " 
00708                                 << fromPeList.size() << "pe available, " 
00709                                 << npe << " crosstalk requested." << endl;
00710     npe = fromPeList.size();
00711   }
00712   
00713 
00714   // For each moved pe
00715   for(UInt_t i=0; i<npe; i++) {
00716     // Pick a pe to move:
00717     Int_t whichPe = fRandom->Integer(fromPeList.size());
00718 
00719     // Go find it.
00720     SimPixelTimeBucket::PeList_t::iterator it;
00721     it=fromPeList.begin();
00722     for(int i=0;i<whichPe;i++) ++it;
00723 
00724     if(it!=fromPeList.end()) { // Even more sanity checks.
00725       toPeList.insert(*it); // Move it.
00726       toPixel.AddPEXtalk(toSpot,1); // Update number
00727       
00728       fromPeList.erase(it);    // Get rid of old copy: it's gone.
00729     }
00730   }
00731 }
00732 
00733 void SimPmt::CopyPEtoPEXtalk(void)
00734 {
00735   // Iterate over all time buckets.
00736   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00737     SimPmtTimeBucket& pmttb = it.Bucket();
00738 
00739     // Iterate over pixels.
00740     for(Int_t pix = 1; pix <= fNPixels; pix++) {      
00741       SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(pix);
00742       
00743       // Iterate over spots.
00744       for(Int_t spot = 1; spot<= fNSpots; spot++) {
00745         SimPixelTimeBucket::PeList_t &fromPeList = pixtb.GetDigiPE(spot);
00746         SimPixelTimeBucket::PeList_t &toPeList =   pixtb.GetDigiPEXtalk(spot);
00747 
00748         pixtb.AddPEXtalk(spot,(Float_t)(fromPeList.size()));
00749         toPeList.insert(fromPeList.begin(),fromPeList.end());   
00750       }
00751     }
00752   }
00753 }
00754 
00756 // Configuration.
00757 void SimPmt::Config( Registry& config )
00758 {
00759   Int_t tbool;
00760   if(config.Get("pmtDoOpticalCrosstalk",tbool)) fsPmtDoOpticalCrosstalk = tbool;
00761   if(config.Get("pmtDoChargeCrosstalk",tbool))  fsPmtDoChargeCrosstalk = tbool;
00762   if(config.Get("pmtDoNonlinearity",tbool))     fsPmtDoNonlinearity = tbool;
00763   if(config.Get("pmtDoDarkNoise",tbool))        fsPmtDoDarkNoise = tbool;
00764   if(config.Get("pmtApplyGainDrift",tbool))     fsPmtApplyGainDrift = tbool;
00765 
00766   config.Get("pmtScaleOpticalCrosstalk",fsPmtScaleOpticalCrosstalk);
00767   config.Get("pmtScaleChargeCrosstalk", fsPmtScaleChargeCrosstalk);
00768   //Added by G. Pawloski to scale Adjacent and Diagonal separately
00769   config.Get("pmtScaleAdjacentChargeCrosstalk", fsPmtScaleAdjacentChargeCrosstalk);
00770   config.Get("pmtScaleDiagonalChargeCrosstalk", fsPmtScaleDiagonalChargeCrosstalk);
00771   config.Get("pmtScaleAdjacentOpticalCrosstalk", fsPmtScaleAdjacentOpticalCrosstalk);
00772   config.Get("pmtScaleDiagonalOpticalCrosstalk", fsPmtScaleDiagonalOpticalCrosstalk);
00773 
00774   config.Get("vaGain",fsVaGain);
00775   config.Get("qieDacCharge",fsQieDacCharge);
00776 
00777   if(config.Get("pmtRebuildGainMap",tbool)) fsRebuildGainMap = tbool;
00778 
00779   if(config.Get("pmtHamamatsuPixelNumbering",tbool))  fsPmtHamamatsuPixelNumbering = tbool;
00780 
00781 }
00782 
00783 void SimPmt::PrintConfig(Option_t*)
00784 {
00785   printf("SimPmt Config: pmtDoOpticalCrosstalk    %s\n",fsPmtDoOpticalCrosstalk?"true":"false");
00786   printf("               pmtDoChargeCrosstalk     %s\n",fsPmtDoChargeCrosstalk?"true":"false");
00787   printf("               pmtDoNonlinearity        %s\n",fsPmtDoNonlinearity?"true":"false");
00788   printf("               pmtDoDarkNoise           %s\n",fsPmtDoDarkNoise?"true":"false");
00789   printf("               pmtScaleOpticalCrosstalk %f\n",fsPmtScaleOpticalCrosstalk);
00790   printf("               pmtScaleChargeCrosstalk  %f\n",fsPmtScaleChargeCrosstalk );
00791   //Added by G. Pawloski to scale Adjacent and Diagonal separately
00792   printf("               pmtScaleAdjacentChargeCrosstalk  %f\n",fsPmtScaleAdjacentChargeCrosstalk );
00793   printf("               pmtScaleDiagonalChargeCrosstalk  %f\n",fsPmtScaleDiagonalChargeCrosstalk );
00794   printf("               pmtScaleAdjacentOpticalCrosstalk  %f\n",fsPmtScaleAdjacentOpticalCrosstalk );
00795   printf("               pmtScaleDiagonalOpticalCrosstalk  %f\n",fsPmtScaleDiagonalOpticalCrosstalk );
00796   printf("               pmtApplyGainDrift        %s\n",fsPmtApplyGainDrift?"true":"false" ); 
00797   printf("               pmtHamamatsuPixelNumbering %s\n",fsPmtHamamatsuPixelNumbering?"true":"false");
00798   printf("               vaGain                   %f ADC/fC\n",fsVaGain*Munits::fC);
00799   printf("               qieDacCharge             %f fC/DAC\n",fsQieDacCharge/Munits::fC);
00800   printf("               pmtRebuildGainMap        %s\n",fsRebuildGainMap?"true":"false");
00801 }
00802 

Generated on Mon Feb 15 11:07:37 2010 for loon by  doxygen 1.3.9.1