SimPmtM64Oxford Class Reference

#include <SimPmtM64Oxford.h>

Inheritance diagram for SimPmtM64Oxford:

SimPmtM64Full SimPmtM64 SimPmt List of all members.

Public Member Functions

 SimPmtM64Oxford (PlexPixelSpotId tube, VldContext context, TRandom *random=NULL)
virtual ~SimPmtM64Oxford ()
virtual void Reset (const VldContext &context)
virtual void SimulateCharges ()
virtual void SimulatePmt ()
virtual void Config (Registry &config)

Protected Member Functions

virtual Float_t GenChargeFromPE (Int_t pixel, Int_t spot, Float_t pe)
virtual UInt_t SimFirstDynodes (Int_t pixel, Int_t nPe)
virtual UInt_t SimLaterDynodes (Int_t pixel, Int_t neToD3)
virtual Bool_t CalStageGains ()
virtual void SimulateAnodeEffects ()
virtual Float_t GenNonlinearCharge (Int_t pixel, Float_t inCharge)

Static Protected Attributes

static Bool_t fsPmtDoChargeSmear = true

Private Attributes

Bool_t fStagesBuilt
Double_t fStageGains [65][13]
Double_t fSkippingGain [65]
Bool_t fOneSpot
VldContext fLastVldContext

Static Private Attributes

static const Double_t gkDefaultStageGains [13]
static const Double_t gkDefaultSecEmmRatio = 4.5
static const Double_t gkNLWindowBefore = 1.8056 * Munits::ns
static const Double_t gkNLWindowAfter = 0.9841 * Munits::ns
static Double_t fsDynodeSkipRate = 0.00
static Double_t fsNLThreshold = 5
static Double_t fsNonlinearityScale = 1.5

Detailed Description

Definition at line 14 of file SimPmtM64Oxford.h.


Constructor & Destructor Documentation

SimPmtM64Oxford::SimPmtM64Oxford ( PlexPixelSpotId  tube,
VldContext  context,
TRandom *  random = NULL 
)

Definition at line 38 of file SimPmtM64Oxford.cxx.

References Msg::kFatal, Msg::kWarning, and MSG.

00040                                                   : 
00041   SimPmtM64Full(tube,context,random)
00042 {
00043   // check if multiple spots are active on the tube (probably 
00044   // fNSpots == 1) i'm trusting that, at the very least, fNSpots is
00045   //  always  non-zero & positive
00046   fOneSpot = true;
00047 
00048   fStagesBuilt = false;
00049       
00050   if (fNSpots != 1) {
00051     fOneSpot = false;
00052     MSG("DetSim",Msg::kWarning) << "This PMT has " << fNSpots 
00053                                 << " spots! Ready for a rough ride?" 
00054                                 << endl;
00055   }
00056 
00057   //Do some safty checks... hopefully i'll rewrite sensitive bits 
00058   //with vectors, then we shouldn't need this. But for now: 
00059   if (fNPixels > 64) {
00060     //were in big trouble... there pixel arrays going out of bounds
00061     MSG("DetSim",Msg::kFatal) << "Too many pixels! /n"
00062                               << "Cant continue without memory carnage!"
00063                               << endl;
00064     assert(0);  //Die in dishonor
00065   }
00066   
00067   
00068   Reset(context);
00069 
00070 }

virtual SimPmtM64Oxford::~SimPmtM64Oxford (  )  [inline, virtual]

Definition at line 21 of file SimPmtM64Oxford.h.

00021 {};


Member Function Documentation

Bool_t SimPmtM64Oxford::CalStageGains (  )  [protected, virtual]

Definition at line 122 of file SimPmtM64Oxford.cxx.

References SimPmt::fNPixels, SimPmt::fNSpots, fOneSpot, fSkippingGain, fStageGains, SimPmt::GetGainAndWidth(), gkDefaultSecEmmRatio, gkDefaultStageGains, Msg::kInfo, and MSG.

Referenced by Reset().

00123 {
00124   Bool_t success = false;
00125 
00126   //Calculate the default total Gain 
00127   Double_t DefaultTubeGain = 1;  
00128   for (Int_t i = 1; i <= 12; i++) {
00129     DefaultTubeGain *= gkDefaultStageGains[i];
00130   }
00131 
00132   
00133   for (Int_t pix = 1 ; pix <= fNPixels ; pix++){
00134     
00135     //Initialise the stage gains for each pixels
00136     for (Int_t i = 0; i <= 12; i++) {
00137       fStageGains[pix][i] = gkDefaultStageGains[i];
00138     } 
00139     
00140     //Get the gain and width from the database 
00141     Double_t thisPixelGain = 0;
00142     Double_t thisPixelWidth = 0;
00143     
00144     if ( fOneSpot ) {  
00145       
00146       success = GetGainAndWidth(pix, 1, thisPixelGain, thisPixelWidth);
00147       //cout << "pixel: " << pix << endl;
00148       //cout << "Gain set to " << thisPixelGain << endl;
00149       //cout << "Width set to " << thisPixelWidth << endl;;
00150     }  
00151 
00152     else{      
00153       //Sum over active spots
00154       //  as far as i know, there should only ever be one active spot.
00155       Double_t tempGain = 0;
00156       Double_t tempWidth = 0;
00157       Int_t nActiveSpots = 0;
00158       
00159       for (Int_t spotit = 1; spotit <= fNSpots; spotit++){
00160         GetGainAndWidth(pix, spotit, tempGain, tempWidth);
00161         if (( tempGain > 0 ) && ( tempWidth > 0 )){
00162           thisPixelGain += tempGain;
00163           thisPixelWidth += tempWidth;
00164           nActiveSpots++;
00165         } //if (spot is okay)
00166       }  //for (spots)
00167       
00168       thisPixelGain /= nActiveSpots;
00169       thisPixelWidth /= nActiveSpots;
00170       
00171     }  // >1 spots (else)
00172 
00173     // Truncate gains to 3 * 10^6 (should be much less)
00174     if (thisPixelGain > 3e6){
00175       MSG("DetSim",Msg::kInfo  ) << "Huge gain in DB: " << thisPixelGain 
00176                                  << "\tTruncating to 3e6" << endl;
00177       thisPixelGain = 3e6; 
00178     }
00179     //Calculate secondary emission (amplification at D1) correction
00180     //here we are modeling variation in the width of the 1pe peak 
00181     //as being entirely due to an variation in the first stage gain
00182   
00183     //first compute true (as opposed to effective) SecEmmRatio
00184     //See NuMi NOTE-Scint-934 for details
00185     
00186     Double_t secEmmCrtn = 1;
00187     Double_t effSecEmmRatio = 1/( thisPixelWidth*thisPixelWidth );   //(rho)
00188     
00189     //quick(er) method (accurate to ~0.6%, which is plenty)
00190     //secEmmCrtn = ( (effSecEmmRatio + 0.25) / (gkDefaultSecEmmRatio + 0.25) );
00191 
00192     //cout << "recal : "<< secEmmCrtn <<endl;
00193     
00194     //full, slow(er) method
00195     secEmmCrtn = effSecEmmRatio * ( 1. + sqrt( 1. + 1./effSecEmmRatio ) );
00196     secEmmCrtn /= gkDefaultSecEmmRatio * (1. + sqrt(1.+1./gkDefaultSecEmmRatio ) );
00197     //cout << "full recal : "<< secEmmCrtn <<endl;
00198 
00199     fStageGains[pix][1] *= secEmmCrtn; 
00200 
00201     //do inverse correction to other stages to renormalise gain
00202 
00203     secEmmCrtn = pow(secEmmCrtn, 1./11.); 
00204     
00205     //cout << "inv recal = "<< 1./secEmmCrtn << endl;
00206 
00207     for(Int_t i = 2; i <= 12; i++){
00208       fStageGains[pix][i] /= secEmmCrtn;
00209     } //for (dynodes 2->12)
00210    
00211     //calculate skipping gain 
00212     // using g(skip) = ( g(1)^(1/beta) + g(2)^(1/beta) )^beta
00213     // with beta = 0.890199
00214     
00215     const Double_t beta = 0.890199;  //Measured at test stand
00216 
00217       //cout << "D1 :" <<  fStageGains[pix][1] << endl;
00218       //cout << "D2 :" <<  fStageGains[pix][2] << endl;
00219 
00220     fSkippingGain[pix] = pow( fStageGains[pix][1], 1./ beta )
00221       + pow( fStageGains[pix][2], 1./ beta );
00222 
00223     //cout << "skipping gain :" << fSkippingGain[pix] << endl;
00224 
00225     fSkippingGain[pix] = pow( fSkippingGain[pix], beta ); 
00226 
00227     //cout << "skipping gain " << fSkippingGain[pix] << endl;
00228 
00229 
00230     //Re-calculate pixel gain
00231 
00232     Double_t gainRatio = 0;
00233     gainRatio = thisPixelGain / DefaultTubeGain ;
00234     //cout << "gainratio " << gainRatio << endl;
00235     
00236     gainRatio = pow(gainRatio, 1./12.);
00237     
00238     //apply correction
00239     
00240     for (Int_t i = 0; i <= 12; i++) {
00241       fStageGains[pix][i] *= gainRatio;
00242     } 
00243 
00244    
00245     //Fix the Dynode skipping gains  
00246     fSkippingGain[pix] =  fSkippingGain[pix] * gainRatio * gainRatio;
00247     
00248   } //for (pix)
00249   
00250   return success;
00251 }

void SimPmtM64Oxford::Config ( Registry config  )  [virtual]

Reimplemented from SimPmtM64Full.

Definition at line 635 of file SimPmtM64Oxford.cxx.

References SimPmtM64Full::Config(), fsDynodeSkipRate, fsNLThreshold, fsNonlinearityScale, fsPmtDoChargeSmear, SimPmt::fsPmtDoNonlinearity, and Registry::Get().

00636 {
00637   double dtmp;
00638   int itmp;
00639   if(config.Get("pmtDoChargeSmear",itmp)) fsPmtDoChargeSmear = itmp;
00640   if(config.Get("pmtM64DynodeSkipRate",dtmp)) fsDynodeSkipRate = dtmp;
00641   if(config.Get("pmtM64NLThreshold",dtmp)) fsNLThreshold = dtmp;
00642   if(config.Get("pmtM64NonlinearityScale",dtmp)) fsNonlinearityScale =dtmp;
00643 
00644   SimPmtM64Full::Config(config);
00645 
00646   // A non linearity scale of zero is equivalent to no nonlinearity,
00647   // so turn it off now because it would also cause a FPE.
00648   // this is quicker than checking each time we go past.  
00649   if (0 == fsNonlinearityScale) fsPmtDoNonlinearity = 0;
00650 }

Float_t SimPmtM64Oxford::GenChargeFromPE ( Int_t  pixel,
Int_t  spot,
Float_t  pe 
) [protected, virtual]

Reimplemented from SimPmtM64.

Definition at line 255 of file SimPmtM64Oxford.cxx.

References Munits::e_SI, Msg::kError, Msg::kInfo, MSG, SimFirstDynodes(), and SimLaterDynodes().

Referenced by SimulateCharges().

00257 {
00258   if (spot != 1) {
00259     MSG("DetSim",Msg::kError) << "Amplifiying a pe in spot "<< spot 
00260                               << "! This is okay... /n"
00261                               << "But Non-linearity will fail" 
00262                               << endl;
00263   } // spot != 1
00264 
00265   if (pe <= 0) return 0;  
00266   
00267   Int_t nPe = (Int_t) pe;
00268 
00269   if (nPe > 1200){
00270     //Scream like a baby
00271     MSG("DetSim",Msg::kInfo  ) << "BIG pulse seen: " << nPe 
00272                                << " photoelectons."
00273                                << "\tTruncating to 1200" << endl;
00274     nPe = 1200;
00275   }
00276   //this process is divided into two stages: 
00277   //the first dynodes, where individual photons count
00278   //the later dynodes, where we don't notice individual photons
00279   
00280   
00281   UInt_t neFromD2 = SimFirstDynodes(pixel, nPe);
00282   UInt_t neToAnode = SimLaterDynodes(pixel, neFromD2);
00283   
00284   return neToAnode * Munits::e_SI;
00285 
00286 }

Float_t SimPmtM64Oxford::GenNonlinearCharge ( Int_t  pixel,
Float_t  inCharge 
) [protected, virtual]

Reimplemented from SimPmtM64.

Definition at line 569 of file SimPmtM64Oxford.cxx.

References Munits::e_SI, fsNLThreshold, and fsNonlinearityScale.

Referenced by SimulateAnodeEffects().

00571 {
00572   //Debug
00573   //if (fsNonlinearityScale == 0) {cout << "fsnls: exactly 0" << endl;}
00574   //else {cout << "fsnls: " << fsNonlinearityScale << endl;} 
00575 
00576   //Note on Tuning parameters: threshold(fsNLThreshold) and dGdQ
00577  
00578   //Threshold in terms of (approx) number of pes in window.
00579   //For pulses similar in shape to the oxford test stand, and a ~3ns window
00580   //the non-linearity `turns on' for pulses sizes (in pe) of ~7 times
00581   //this threshold.
00582   
00583   //dGdQ is the (Default) rate at which the gain drops off at threshold
00584   //increasing fsNonlinearityScale -> NL turns on more quickly
00585 
00586   Float_t scaleNL = 1.;
00587   const Float_t qInPe = linCharge / (1e6 * Munits::e_SI);  
00588 
00589   const Float_t dGdQ = 3.9e-3; //Best tune from Test Stand  
00590 
00591   //Exponential drop off model:
00592   if (qInPe > fsNLThreshold) {
00593     const Float_t alpha = 2 * dGdQ * fsNonlinearityScale;  
00594     //makes everything  easier to read. 
00595     
00596     scaleNL = 1 - TMath::Exp( -alpha * (qInPe - fsNLThreshold) );
00597     scaleNL /= alpha * ( qInPe - fsNLThreshold );  
00598 
00599   }  // if (above threshold)
00600 
00601 return linCharge * scaleNL;
00602   
00603 }

void SimPmtM64Oxford::Reset ( const VldContext context  )  [virtual]

Reimplemented from SimPmtM64.

Definition at line 108 of file SimPmtM64Oxford.cxx.

References CalStageGains(), SimPmt::fsRebuildGainMap, fStagesBuilt, and SimPmtM64::Reset().

00109 {
00110   //Do the inherited M64 reset stuff
00111   SimPmtM64::Reset(context);
00112   
00113   //Reset the gains
00114   if((!fStagesBuilt)||fsRebuildGainMap) {
00115     CalStageGains();
00116     fStagesBuilt = true;
00117   }
00118 }

UInt_t SimPmtM64Oxford::SimFirstDynodes ( Int_t  pixel,
Int_t  nPe 
) [protected, virtual]

Definition at line 291 of file SimPmtM64Oxford.cxx.

References SimPmt::fRandom, fsDynodeSkipRate, fSkippingGain, and fStageGains.

Referenced by GenChargeFromPE().

00292 {
00293   //bah. maybe i have to burn random numbers in a binomial to 
00294   //do this transparently
00295   //i'm pretty sure this does the same thing though 
00296 
00297   //Simulate 'skipping' path
00298   Float_t meanSkipping = nPe * fsDynodeSkipRate;
00299   UInt_t neThatSkip = 
00300     fRandom->Poisson( meanSkipping * fSkippingGain[pixel] );
00301   
00302   //simulate 'normal' path
00303   Float_t meanElectrons = 6.5;
00304   UInt_t neFromPrevDynode = nPe ;  //values for saftey
00305 
00306   //at dynode 1
00307   meanElectrons = fStageGains[pixel][1] * nPe * (1 - fsDynodeSkipRate);
00308   neFromPrevDynode = (UInt_t) fRandom->PoissonD(meanElectrons);
00309 
00310   //& at dynode 2
00311   meanElectrons = fStageGains[pixel][2] * neFromPrevDynode;
00312   neFromPrevDynode = (UInt_t) fRandom->PoissonD(meanElectrons);
00313                               
00314   //add in skipping electrons
00315   neFromPrevDynode += neThatSkip;
00316 
00317   return neFromPrevDynode;
00318 }

UInt_t SimPmtM64Oxford::SimLaterDynodes ( Int_t  pixel,
Int_t  neToD3 
) [protected, virtual]

Definition at line 323 of file SimPmtM64Oxford.cxx.

References SimPmt::fRandom, and fStageGains.

Referenced by GenChargeFromPE().

00324 {
00325 //   Int_t switchPoint = 6;
00326 //   //Change this if you want. It must be >= 3  and <= 12 
00327 //   //speed = low, accuracy = high (recommend >5)
00328 
00329 
00330 //   //At this dynode, switch from simulating each dynode individually
00331 //   // to simulating everything in one go.
00332 //   //It only works for Gaussian statistics!
00333 //   //The main speed issue is with generating Poisson statisics,
00334 //   //so bigger speed increases can be acheived by switching 
00335 //   //at or before dynode 5. But this nessicerily gives bigger errors.
00336 //   //There's no such thing as a free lunch!
00337 
00338 //   //saftey net: switchPoint MUST stay within these bounds.
00339 //   if (switchPoint < 3) switchPoint = 3;  
00340 //   if (switchPoint > 12) switchPoint = 12;  
00341  
00342 //   Float_t meanElectrons = 29.3;  //Value is just for saftey
00343 //   UInt_t neFromPrevDynode = neToD3;
00344   
00345 //   for (Int_t i = 3; i < switchPoint ; i++) {
00346 //     meanElectrons = fStageGains[pixel][i] * (Float_t) neFromPrevDynode;
00347 //     neFromPrevDynode = fRandom->Poisson(meanElectrons);
00348 //    }
00349 
00350 //   //calculate gaussian mean & width. 
00351 //   // see NuMI note 661 for detail relating to the `extraWidth' calculation
00352   
00353 //   Float_t extraWidth = 1;
00354 //   Float_t gausGain = fStageGains[pixel][switchPoint];
00355   
00356 //   for (Int_t i = (switchPoint + 1) ; i <= 12; i++ ) {
00357 //     extraWidth = 1. + ( extraWidth * fStageGains[pixel][i] ); 
00358 //     gausGain *= fStageGains[pixel][i];
00359 //   }
00360   
00361 //   //do gaussian amplification
00362 
00363 //   Float_t gausMean = neFromPrevDynode * gausGain;
00364 //   Float_t gausWidth = sqrt(gausMean * extraWidth);
00365   
00366 //   neFromPrevDynode = UInt_t(fRandom->Gaus(0,1) *gausWidth + gausMean + 0.5 );
00367   
00368 //..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  
00369   //  If you want to do everything properly this does the job:
00370 
00371   Float_t meanElectrons = 29.3;  //Value is just for saftey
00372   UInt_t neFromPrevDynode = neToD3;
00373   for (Int_t i = 3; i <= 12; i++) {
00374     meanElectrons = fStageGains[pixel][i] * (Float_t) neFromPrevDynode;
00375     neFromPrevDynode = (UInt_t) fRandom->PoissonD(meanElectrons);
00376   }
00377   
00378   return neFromPrevDynode;
00379 }

void SimPmtM64Oxford::SimulateAnodeEffects (  )  [protected, virtual]

Definition at line 382 of file SimPmtM64Oxford.cxx.

References SimPixelTimeBucket::AddCharge(), SimPmtM64::BucketToStartTime(), SimPmtM64::BucketToStopTime(), Munits::fC, SimPixelTimeBucket::fCharge, SimPmt::fNPixels, SimPmt::fNSpots, fOneSpot, fsPmtDoChargeSmear, SimPmt::fsPmtDoNonlinearity, SimPixelTimeBucket::fTime, GenNonlinearCharge(), SimPmt::GetBucket(), SimPixelTimeBucket::GetCharge(), SimPmtTimeBucket::GetPixelBucket(), gkNLWindowAfter, gkNLWindowBefore, Msg::kError, DigiSignal::kLeakFromNextBucket, DigiSignal::kLeakFromPrevBucket, Msg::kVerbose, MSG, SimPmtM64Full::NextBucketFraction(), SimPmtM64Full::PrevBucketFraction(), and SimPixelTimeBucket::SetTruthBit().

Referenced by SimulatePmt().

00383 {
00384   //Saftey check: 
00385   //if there are several spots active then there will be problems  
00386   Int_t activeSpot = 1; //the only spot considered in NL corrections
00387 
00388   if (!fOneSpot) {
00389     MSG("DetSim",Msg::kError  ) << "This tube has" << fNSpots 
00390                                 << " spots active! Only PEs in spot " 
00391                                 << activeSpot << " will be considered."
00392                                 << endl;
00393   } 
00394 
00395   // This uses the time structure of the pe lists to calculate the
00396   // amount of charge active in the pmt in a window near each pe.
00397   // this is used to calculate a non linearity correction, which is 
00398   // subtracted from the pixel bucket charge.
00399 
00400   // The charge is then smeared into nearby buckets using a charge pulse
00401   // shape t^3 exp[-1.6*t]. 
00402 
00403   // make something to store the pe non-linearity digests
00404   typedef std::vector<PeNLDigest_t> AllPePixelList_t;
00405   
00406   std::vector<AllPePixelList_t> allPeList(fNPixels + 1);  
00407   // zeroth element is empty, so that AllPeList[n] corresponds to 
00408   // pixel # n, using pixels numbered 1 -> 64 ( NOT 0 ->63 )
00409 
00410   // Iterate over all time buckets 
00411   // in each time bucket: add DigiPE summaries to the lists 
00412   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00413     Int_t bucketId = it.BucketId();
00414     SimPmtTimeBucket& pmtBucket = it.Bucket();
00415     
00416     // iterate over pixels 
00417     for(Int_t pix = 1 ; pix <= fNPixels ; pix++) {
00418       SimPixelTimeBucket& pixelBucket = pmtBucket.GetPixelBucket(pix);
00419         Float_t q = 0.;
00420         if ( pixelBucket.GetTotalPEXtalk() ) {
00421            q = pixelBucket.GetCharge(); 
00422            q /= pixelBucket.GetTotalPEXtalk(); 
00423         }
00424 
00425       //get the pe list associated with this pixel in this time bucket 
00426       SimPixelTimeBucket::PeList_t& peInThisBkt 
00427         = pixelBucket.GetDigiPEXtalk(activeSpot);  
00428       // spot issues... And this time, i cant iterate over spots because
00429       // that wouldn't be time ordered!
00430       
00431       SimPixelTimeBucket::PeList_t::iterator peItr 
00432         = peInThisBkt.begin();
00433       
00434       for (  ; peItr != peInThisBkt.end() ; peItr++ ) {
00435         
00436         //make a pe summary
00437         PeNLDigest_t peInfo(bucketId, peItr->first, q);
00438         //cout << peInfo.fBucketNo << endl;
00439   
00440         //store it in the relevent vector
00441         allPeList[pix].push_back(peInfo); 
00442 
00443       } //for (pes)
00444     } //for (pixels)
00445   } //for (pmt time buckets)
00446   
00447   MSG("DetSim",Msg::kVerbose) << "Constructed pe list for non-linearity"
00448                               << endl;
00449 
00450 
00451   // Now we have nice long lists of pe's spanning all time buckets
00452   // lets nonlinear-ise!
00453   
00454   // iterate over pixels
00455   for(Int_t pix = 1 ; pix <= fNPixels ; pix++) {
00456     
00457     // iterate over pes
00458     AllPePixelList_t::iterator currPeItr = allPeList[pix].begin();
00459     for (  ; currPeItr != allPeList[pix].end() ; ++currPeItr) {
00460 
00461       //Get the bucketId and some references.
00462       //Need these for Nonlinearity & charge smearing
00463       Int_t bucketId = currPeItr->fBucketNo;
00464       SimPmtTimeBucket& pmtBkt = GetBucket(bucketId);
00465       SimPixelTimeBucket& pixelBucket = pmtBkt.GetPixelBucket(pix);
00466       
00467       Double_t chargeRatio = 1; //if no nonlinearity
00468 
00469       
00470       if (fsPmtDoNonlinearity){ 
00471         //Non-linearity
00472         // count up how much charge is nearby
00473         Float_t peTime = currPeItr->fTime; 
00474         Float_t nearbyCharge = 0;
00475         AllPePixelList_t::iterator  nearbyPeItr = currPeItr;
00476         Float_t dt = 0;
00477         
00478         // look back
00479         while ( nearbyPeItr != allPeList[pix].begin() ) {
00480           --nearbyPeItr;
00481           dt = peTime - nearbyPeItr->fTime;
00482           if ( dt > gkNLWindowBefore ) break;
00483           nearbyCharge += nearbyPeItr->fCharge;
00484           
00485         } //while (past pes)
00486         
00487         //look forward, include current pe
00488         nearbyPeItr = currPeItr;
00489         
00490         while (nearbyPeItr != allPeList[pix].end() ) {
00491           dt = nearbyPeItr->fTime - peTime;
00492           if ( dt > gkNLWindowAfter ) break;
00493           nearbyCharge += nearbyPeItr->fCharge;
00494           ++nearbyPeItr;
00495         }  //while (future pes)
00496         
00497         
00498         // calculate NL correction based on this amount
00499         // newCharge is the nonlinearised charge for all the pes in
00500         // the window, we want it for just one.
00501         if (nearbyCharge){
00502           // because it is possable have pes but no charge
00503           // (no seconday emission at some stage)
00504           chargeRatio = GenNonlinearCharge( pix, nearbyCharge );
00505           chargeRatio /= nearbyCharge;
00506         }       
00507                 
00508         // use this correction to reduce the charge in this bucket
00509         Float_t deltaq = (chargeRatio - 1) * currPeItr->fCharge;
00510         pixelBucket.AddCharge(deltaq);
00511       
00512       } // if (fsDoNonlinearity) 
00513 
00514 
00515 
00516       if (fsPmtDoChargeSmear){
00517         //Smear the charge about
00518         
00519         // "This smushes charge into the next and previous QIE buckets.  
00520         // It's assumed that digiPE occours at the peak of the pulse, 
00521         // which has a shape of t^3 exp(-t*1.6). 
00522         // Some of the charge gets put into the next and previous buckets.
00523         // Note that the truth info is lost: you will now get digits with 
00524         // no signal info... but that's the way it goes, I'm afraid."
00525         
00526         Float_t startTime = BucketToStartTime(bucketId);
00527         Float_t stopTime = BucketToStopTime(bucketId);
00528         
00529         SimPmtTimeBucket& nextPmtBucket = GetBucket(bucketId + 1);
00530         SimPixelTimeBucket& nextPixBucket = nextPmtBucket.GetPixelBucket(pix);
00531         SimPmtTimeBucket& prevPmtBucket = GetBucket(bucketId - 1); 
00532         SimPixelTimeBucket& prevPixBucket = prevPmtBucket.GetPixelBucket(pix);
00533         
00534         //How much into the adjacent buckets?
00535         Float_t qNext = currPeItr->fCharge * chargeRatio;
00536         qNext *= NextBucketFraction ( stopTime - currPeItr->fTime );
00537         Float_t qPrev = currPeItr->fCharge * chargeRatio;
00538         qPrev *= PrevBucketFraction ( currPeItr->fTime - startTime );
00539         
00540         //cout << "Time from boundary = " << (currPeItr->fTime - startTime) * 1e9 <<endl;
00541         
00542         //Add charge to next bucket, and set truth bits if there is a 
00543         //non-trivial amount.
00544         nextPixBucket.AddCharge(qNext);
00545         if ( qNext > 1.0 * Munits::fC ) {
00546           nextPixBucket.SetTruthBit(DigiSignal::kLeakFromPrevBucket);
00547         }
00548         
00549         //Add charge to previous bucket, and set truth bits if there is a 
00550         //non-trivial amount.
00551         prevPixBucket.AddCharge(qPrev);
00552         if ( qPrev > 1.0 * Munits::fC ) {
00553           prevPixBucket.SetTruthBit(DigiSignal::kLeakFromNextBucket);
00554         }
00555         
00556         //remove the same amount of charge from the current bucket
00557         pixelBucket.AddCharge( -(qPrev + qNext) ); 
00558       
00559       } // if (fsDoChargeSmear)
00560     } // for (pes)
00561   } // for (pixels)
00562   
00563   MSG("Detsim",Msg::kVerbose) << "Nonlinearity and Charge smearing done"
00564                               << endl;
00565     
00566 }

void SimPmtM64Oxford::SimulateCharges (  )  [virtual]

Reimplemented from SimPmtM64Full.

Definition at line 606 of file SimPmtM64Oxford.cxx.

References SimPmt::fNPixels, SimPmt::fNSpots, SimPmt::fTotalCharge, and GenChargeFromPE().

Referenced by SimulatePmt().

00607 {
00608   fTotalCharge =0;
00609   
00610   //cout << "PMT total pe " << GetTotalPe() << endl; 
00611 
00612   //Iterate over all time buckets. 
00613   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00614     SimPmtTimeBucket& pmtBucket = it.Bucket();
00615 
00616     //Iterate over pixels
00617     for(Int_t pix = 1 ; pix <= fNPixels ; pix++) {
00618       SimPixelTimeBucket& pixelBucket = pmtBucket.GetPixelBucket(pix);
00619       Float_t nPe = pixelBucket.GetTotalPEXtalk();
00620       
00621       //Generate a charge in the pixel bucket
00622       //iterate over spots (...)
00623       for (Int_t spot = 1 ; spot <= fNSpots ; spot++){
00624         Float_t q = GenChargeFromPE( pix, spot, nPe );
00625         //cout << "Anode charge = " << q << endl;
00626         pixelBucket.AddCharge(q);
00627         fTotalCharge += q;
00628       } //for (spots)
00629     } //for (pixels)
00630   } // for (pmt time buckets)
00631 }

void SimPmtM64Oxford::SimulatePmt (  )  [virtual]

Reimplemented from SimPmt.

Definition at line 654 of file SimPmtM64Oxford.cxx.

References SimPmt::CopyPEtoPEXtalk(), SimPmt::fsPmtDoChargeCrosstalk, fsPmtDoChargeSmear, SimPmt::fsPmtDoDarkNoise, SimPmt::fsPmtDoNonlinearity, SimPmt::fsPmtDoOpticalCrosstalk, SimulateAnodeEffects(), SimPmt::SimulateChargeCrosstalk(), SimulateCharges(), SimPmt::SimulateDarkNoise(), and SimPmtM64::SimulateOpticalXtalk().

00655 {
00656   //
00657   // Reimplemented from SimPmt. Nonlinearity and Charge smearing are both done
00658   // in a new function SimulateAnodeEffects.
00659   //
00660   //cout << "*************************************************************" << endl;
00661   // cout << "        Start simulation." << endl;
00662   //cout << "*************************************************************" << endl;
00663   //Print();
00664   
00665   if(fsPmtDoOpticalCrosstalk) SimulateOpticalXtalk();     // Move single PEs around for crosstalk
00666   else CopyPEtoPEXtalk();  // A null operation.
00667   
00668   //cout << "*************************************************************" << endl;
00669   // cout << "        After Optical." << endl;
00670   //cout << "*************************************************************" << endl;
00671   //Print();
00672   
00673   SimulateCharges();                                 // Simulate the dynode chain to get anode charge.
00674   
00675   //cout << "*************************************************************" << endl;
00676   //cout << "        After Charges." << endl;
00677   //cout << "*************************************************************" << endl;
00678   //Print();
00679   
00680   if(fsPmtDoDarkNoise)        SimulateDarkNoise();        // Add some charge to some pixels by dark noise.
00681   if(fsPmtDoChargeSmear ||
00682      fsPmtDoNonlinearity   )     SimulateAnodeEffects();     // Apply the nonlinearity
00683   if(fsPmtDoChargeCrosstalk)  SimulateChargeCrosstalk();  // Crosstalk some charge around.
00684   //cout << "*************************************************************" << endl;
00685   //cout << "        Final." << endl;
00686   //cout << "*************************************************************" << endl;
00687   //Print();
00688  }


Member Data Documentation

VldContext SimPmtM64Oxford::fLastVldContext [private]

Definition at line 62 of file SimPmtM64Oxford.h.

Bool_t SimPmtM64Oxford::fOneSpot [private]

Definition at line 58 of file SimPmtM64Oxford.h.

Referenced by CalStageGains(), and SimulateAnodeEffects().

Double_t SimPmtM64Oxford::fsDynodeSkipRate = 0.00 [static, private]

Definition at line 50 of file SimPmtM64Oxford.h.

Referenced by Config(), and SimFirstDynodes().

Double_t SimPmtM64Oxford::fSkippingGain[65] [private]

Definition at line 57 of file SimPmtM64Oxford.h.

Referenced by CalStageGains(), and SimFirstDynodes().

Double_t SimPmtM64Oxford::fsNLThreshold = 5 [static, private]

Definition at line 51 of file SimPmtM64Oxford.h.

Referenced by Config(), and GenNonlinearCharge().

Double_t SimPmtM64Oxford::fsNonlinearityScale = 1.5 [static, private]

Definition at line 52 of file SimPmtM64Oxford.h.

Referenced by Config(), and GenNonlinearCharge().

Bool_t SimPmtM64Oxford::fsPmtDoChargeSmear = true [static, protected]

Definition at line 40 of file SimPmtM64Oxford.h.

Referenced by Config(), SimulateAnodeEffects(), and SimulatePmt().

Double_t SimPmtM64Oxford::fStageGains[65][13] [private]

Definition at line 56 of file SimPmtM64Oxford.h.

Referenced by CalStageGains(), SimFirstDynodes(), and SimLaterDynodes().

Bool_t SimPmtM64Oxford::fStagesBuilt [private]

Definition at line 55 of file SimPmtM64Oxford.h.

Referenced by Reset().

const Double_t SimPmtM64Oxford::gkDefaultSecEmmRatio = 4.5 [static, private]

Definition at line 44 of file SimPmtM64Oxford.h.

Referenced by CalStageGains().

const Double_t SimPmtM64Oxford::gkDefaultStageGains [static, private]

Initial value:

 {0, 6.5397, 4.5583, 4.5583,
                                                          2.4593,  2.4593, 2.4593,
                                                          2.4593,  2.4593, 2.4593,
                                                          2.4593,  2.4593, 4.5583}

Definition at line 43 of file SimPmtM64Oxford.h.

Referenced by CalStageGains().

const Double_t SimPmtM64Oxford::gkNLWindowAfter = 0.9841 * Munits::ns [static, private]

Definition at line 48 of file SimPmtM64Oxford.h.

Referenced by SimulateAnodeEffects().

const Double_t SimPmtM64Oxford::gkNLWindowBefore = 1.8056 * Munits::ns [static, private]

Definition at line 47 of file SimPmtM64Oxford.h.

Referenced by SimulateAnodeEffects().


The documentation for this class was generated from the following files:
Generated on Mon Sep 1 00:52:45 2014 for loon by  doxygen 1.4.7