| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

EsPmtEffectPulseTool.cc

Go to the documentation of this file.
00001 #include "EsPmtEffectPulseTool.h"
00002 
00003 #include "Event/SimHit.h"
00004 #include "Event/ElecPulse.h"
00005 #include "Event/ElecRpcPulse.h"
00006 #include "Event/SimTrackReference.h"
00007 #include "Event/SimTrack.h"
00008 
00009 #include "Conventions/PulseType.h"
00010 
00011 #include "GaudiKernel/SystemOfUnits.h"
00012 #include "GaudiKernel/PhysicalConstants.h"
00013 
00014 #include <math.h>
00015 
00016 
00017 // DWL: After-pulse timing distribution
00018 
00019 #define NUM_BINS_DIST 96
00020 
00021 static double afterPusleTimingDist[NUM_BINS_DIST] = {0.0000000, 0.0012950, 0.0030194, 0.0064297, 0.0142225,
00022                                                      0.0247712, 0.0417949, 0.0696709, 0.1063259, 0.1485606,
00023                                                      0.1957973, 0.2465997, 0.2957179, 0.3401377, 0.3798086,
00024                                                      0.4135611, 0.4437462, 0.4702155, 0.4928434, 0.5123140,
00025                                                      0.5289294, 0.5432514, 0.5556360, 0.5664919, 0.5758642,
00026                                                      0.5843533, 0.5920903, 0.5990121, 0.6052796, 0.6111246,
00027                                                      0.6165560, 0.6215807, 0.6261028, 0.6304032, 0.6346304,
00028                                                      0.6387545, 0.6425872, 0.6465577, 0.6500606, 0.6534989,
00029                                                      0.6568080, 0.6602148, 0.6635239, 0.6667457, 0.6700025, 
00030                                                      0.6737148, 0.6780693, 0.6829002, 0.6879599, 0.6935379, 
00031                                                      0.6994667, 0.7058650, 0.7121394, 0.7187122, 0.7255085, 
00032                                                      0.7324600, 0.7394151, 0.7467314, 0.7546551, 0.7630884, 
00033                                                      0.7718917, 0.7816427, 0.7914601, 0.8023700, 0.8137512, 
00034                                                      0.8255861, 0.8375781, 0.8498354, 0.8621276, 0.8741685, 
00035                                                      0.8855410, 0.8962833, 0.9061268, 0.9156126, 0.9243357, 
00036                                                      0.9320726, 0.9392022, 0.9459897, 0.9519587, 0.9574180, 
00037                                                      0.9623468, 0.9667851, 0.9708308, 0.9744296, 0.9777980, 
00038                                                      0.9807231, 0.9835296, 0.9861040, 0.9885404, 0.9906504, 
00039                                                      0.9926209, 0.9943923, 0.9959998, 0.9974658, 0.9987678, 
00040                                                      1.0000000};
00041 
00042 
00043 using namespace CLHEP;
00044 
00045 EsPmtEffectPulseTool::EsPmtEffectPulseTool(const std::string& type,
00046                                            const std::string& name, 
00047                                            const IInterface* parent)
00048     : GaudiTool(type,name,parent)
00049     , m_cableSvc(0)
00050     , m_simDataSvc(0)
00051     , m_simTimeEarliest(0)
00052     , m_simTimeLatest(0)
00053 {
00054   // Initialization
00055   m_prePulsePdf.clear();     m_prePulsePdf.push_back(1);
00056   m_prePulseEdges.clear();   m_prePulseEdges.push_back(-50.0*ns);  m_prePulseEdges.push_back(0.0*ns);
00057   //  m_afterPulsePdf.clear();   m_afterPulsePdf.push_back(1);
00058   //  m_afterPulseEdges.clear(); m_afterPulseEdges.push_back(0.0*ns); m_afterPulseEdges.push_back(10.0e3*ns);
00059   m_afterPulsePdf.clear();
00060   m_afterPulseEdges.clear();
00061 
00062   for(int ii=0; ii < NUM_BINS_DIST; ii++) {
00063     m_afterPulsePdf.push_back(afterPusleTimingDist[ii]);
00064     m_afterPulseEdges.push_back(ii*100.+500.);
00065   }
00066 
00067   debug() << "time(ns) Afterpulse PDF (integrated) " <<endreq;
00068   for(int numLine=0; numLine < NUM_BINS_DIST; numLine++)
00069     debug() << m_afterPulseEdges[numLine] << ",   " << m_afterPulsePdf[numLine] << endreq;
00070   //    std::cout << m_afterPulseEdges[numLine] << ",   " << m_afterPulsePdf[numLine] << std::endl;
00071 
00072   declareInterface< IEsPulseTool >(this) ;   
00073   declareProperty("CableSvcName",m_cableSvcName="StaticCableSvc",
00074                   "Name of service to map between detector, hardware, and electronic IDs");
00075   declareProperty("SimDataSvcName",m_simDataSvcName="StaticSimDataSvc",
00076                   "Name of service to provide pmt properties for simulation");
00077   declareProperty("EnablePrePulse",m_enablePrePulse=true,"Switch on/off prepulse simulation");
00078   declareProperty("EnableAfterPulse",m_enableAfterPulse=true,"Switch on/off afterpulse simulation");
00079   declareProperty("PrePulsePdf",m_prePulsePdf,"User-defined PDF for timing distribution of pre-pulse");
00080   declareProperty("PrePulsePdfEdges",m_prePulseEdges,"Bin edges of PrePulsePdf"); 
00081   declareProperty("AfterPulseAmpMode",m_afterPulseAmpMode="SinglePE","Mode for afterpulse amplitude distribution");
00082   declareProperty("DarkPulseAmpMode",m_darkPulseAmpMode="SinglePE","Mode for dark pulse amplitude distribution");
00083   declareProperty("AfterPulsePdf",m_afterPulsePdf,"User-defined PDF for timing distribution of after-pulse");
00084   declareProperty("AfterPulsePdfEdges",m_afterPulseEdges,"Bin edges of AfterPulsePdf");
00085   declareProperty("AfterPulseTimeInterval", m_timeInterval=20*ns, 
00086                   "PMT hit counting window size");
00087   declareProperty("EnableNonlinearAfterpulse", m_enableNonlinearAfterpulse=true,
00088                   "Enable nonlinear suppression of afterpulsing.");
00089   declareProperty("LinearAfterpulseThreshold", m_linearAfterpulseThreshold=400,
00090                   "Upper limit of linear afterpulsing in number of PE.");
00091 
00092 
00093   declareProperty("EnableVeryLongTimeSuppression",m_enableVeryLongTimeSuppression=false,
00094                   "Enable suppression of hit times in the far future");
00095   declareProperty("VeryLongTime",m_veryLongTime=3e7*s,
00096                   "Definition of very long time for hit time suppression");
00097   declareProperty("ExpWeight", m_expWeight=0,"Weight of the exponential contribution to the spe response function");
00098   declareProperty("SpeExpDecay", m_speExpDecay=0.5,"Decay time of the exponential contribution to the spe response function");
00099 }
00100 
00101 EsPmtEffectPulseTool::~EsPmtEffectPulseTool(){}
00102 
00103 StatusCode EsPmtEffectPulseTool::initialize()
00104 {
00105   // Get Cable Service
00106   m_cableSvc = svc<ICableSvc>(m_cableSvcName,true);
00107 
00108   // Get PMT simulation input data service
00109   m_simDataSvc = svc<ISimDataSvc>(m_simDataSvcName,true);
00110 
00111   // Random number service
00112   IRndmGenSvc *rgs = 0;
00113   if (service("RndmGenSvc",rgs,true).isFailure()) {
00114     fatal() << "Failed to get random service" << endreq;
00115     return StatusCode::FAILURE;        
00116   }
00117   
00118   StatusCode sc;
00119   sc = m_uni.initialize(rgs, Rndm::Flat(0,1));
00120   if (sc.isFailure()) {
00121     fatal() << "Failed to initialize uniform random numbers" << endreq;
00122     return StatusCode::FAILURE;
00123   }
00124   sc = m_gauss.initialize(rgs, Rndm::Gauss(0,1));
00125   if (sc.isFailure()) {
00126     fatal() << "Failed to initialize gaussian random numbers" << endreq;
00127     return StatusCode::FAILURE;
00128   }
00129   sc = m_exp.initialize(rgs, Rndm::Exponential(m_speExpDecay));
00130   if (sc.isFailure()) {
00131     fatal() << "Failed to initialize exponential random numbers" << endreq;
00132     return StatusCode::FAILURE;
00133   }
00134   if(m_enablePrePulse){
00135     info() << "Prepulse simulation enabled" << endreq;
00136     sc = m_randPrePulseTime.initialize(rgs, Rndm::DefinedPdf(m_prePulsePdf,0));
00137     if (sc.isFailure()) {
00138       fatal() << "Failed to initialize random numbers for timing distribution" << endreq;
00139       return StatusCode::FAILURE;
00140     }
00141   }
00142   else info() << "Prepulse simulation disabled" << endreq;
00143   
00144   if(m_enableAfterPulse){
00145     info() << "Afterpulse simulation enabled" << endreq;
00146     sc = m_randAfterPulseTime.initialize(rgs, Rndm::DefinedPdf(m_afterPulsePdf,0));
00147     if (sc.isFailure()) {
00148       fatal() << "Failed to initialize random numbers for timing distribution" << endreq;
00149       return StatusCode::FAILURE;
00150     }
00151   }
00152   else info() << "Afterpulse simulation disabled" << endreq;
00153   
00154   // Check user input for user-defined PDFs
00155   if(m_enablePrePulse){
00156     if (m_prePulsePdf.size()+1   != m_prePulseEdges.size()) { 
00157         // ||   m_afterPulsePdf.size()+1 != m_afterPulseEdges.size() ) {
00158       fatal() << "There should be 1 more number of bin edges than bins when defining pdf" << endreq;
00159       return StatusCode::FAILURE; 
00160     }
00161   }
00162 
00163   // DWL: Check user input for user-defined PMT hit counting time interval
00164   if (m_timeInterval <= 0) {
00165     fatal() << "PMT hit couting time interval should be great than zero !" << endreq;
00166     return StatusCode::FAILURE;
00167   }
00168   if(m_enableAfterPulse){
00169     if ((m_afterPulseAmpMode != "SinglePE") && (m_afterPulseAmpMode != "PDF")) {
00170       fatal() << "Not a recognized afterpulse amplitude distribution mode" << endreq;
00171       return StatusCode::FAILURE;
00172     }
00173     if (m_afterPulseAmpMode == "SinglePE") debug() << "Assume single p.e. amplitude for afterpulses" << endreq; 
00174     if (m_afterPulseAmpMode == "PDF" || m_darkPulseAmpMode == "PDF") {
00175       debug() << "Set up amplitude PDF for afterpulses" << endreq; 
00176       m_afterPulseAmpPdf.clear();
00177       m_afterPulseAmpEdges.clear();
00178       getAfterPulseAmpPdf(m_afterPulseAmpPdf);
00179       getAfterPulseAmpEdges(m_afterPulseAmpEdges);
00180     }  
00181   }
00182   return StatusCode::SUCCESS;
00183 }
00184 
00185 StatusCode EsPmtEffectPulseTool::finalize()
00186 {
00187   return StatusCode::SUCCESS;
00188 }
00189 
00190 StatusCode EsPmtEffectPulseTool::generatePulses(DayaBay::SimHitCollection* hits,
00191                                                 DayaBay::ElecPulseCollection* pulses)
00192 {    
00193   debug() << "running generatePulses()" << endreq; 
00194 
00195   // Define simulation time window
00196   m_simTimeEarliest = pulses->header()->header()->earliest();
00197   m_simTimeLatest   = pulses->header()->header()->latest();
00198   TimeStamp headerTime = pulses->header()->header()->timeStamp();
00199 
00200   // Maintain a list of primary pulses for each PMT
00201   std::map<DayaBay::DetectorSensor, 
00202            std::vector<DayaBay::ElecPulse*> > pulsesByPmt;
00203   std::map<DayaBay::DetectorSensor, 
00204            std::vector<DayaBay::ElecPulse*> >::iterator pulsePmtIter, 
00205            pulsePmtEnd; 
00206 
00207   const DayaBay::SimHitCollection::hit_container& htcon = hits->collection();
00208   DayaBay::SimHitCollection::hit_container::const_iterator hcIter, 
00209     hcDone = htcon.end();
00210   DayaBay::ElecPulseCollection::PulseContainer& pulsecon = pulses->pulses();
00211 
00212   // Context, ServiceMode for this data
00213   Context context(pulses->detector().site(), SimFlag::kMC, 
00214                   pulses->header()->header()->timeStamp(),
00215                   pulses->detector().detectorId());
00216   int task = 0;
00217   ServiceMode svcMode(context, task);
00218 
00219   debug() << "Processing " << htcon.size() << " simulated hits from detector " 
00220           << hits->detector() << endreq; 
00221 
00222 
00223   for (hcIter=htcon.begin(); hcIter != hcDone; ++hcIter) {
00224 
00225     DayaBay::DetectorSensor sensDetId((*hcIter)->sensDetId());
00226 
00227     if (sensDetId.isAD()) {
00228         DayaBay::AdPmtSensor pmtid(sensDetId.fullPackedData());
00229         if (pmtid.bogus()) {
00230             warning() << "Got bogus AD PMT: " << pmtid << endreq;
00231         }
00232     }
00233     else {
00234         DayaBay::PoolPmtSensor pmtid(sensDetId.fullPackedData());
00235         if (pmtid.bogus()) {
00236             warning() << "Got bogus Pool PMT: " << pmtid << endreq;
00237         }
00238     }
00239 
00240     //temporarily ignore very long time hit to avoid program break
00241     //if((*hcIter)->hitTime() > 1e7) {
00242     if((*hcIter)->hitTime() > m_veryLongTime ) {
00243         warning() << "Skipping very long hit time of " << (*hcIter)->hitTime() 
00244                   << " in PMT " << sensDetId << endreq;
00245         continue;
00246     }
00247 
00248     verbose() << "Requesting pmtData for " << sensDetId << endreq;
00249     const DayaBay::PmtSimData* pmtData = 
00250       m_simDataSvc->pmtSimData(sensDetId, svcMode);
00251     if(!pmtData){
00252       warning() << "No Simulation input properties for PMT: " << sensDetId 
00253                 << " Ignoring..." << endreq;
00254       continue;
00255     }
00256     // Ignore SimHit due to efficiency?
00257     if (m_uni() > pmtData->m_efficiency) continue;
00258 
00259 
00260     const DayaBay::ElecChannelId& elecChannelId = m_cableSvc->elecChannelId( 
00261                                                                      sensDetId,
00262                                                                      svcMode);
00263     if(elecChannelId.fullPackedData() == 0){
00264       warning() << "PMT: " << sensDetId 
00265                 << " is not connected in cable map.  Ignoring..." << endreq;
00266       continue;
00267     }
00268     DayaBay::ElecPulse* simpulse = new DayaBay::ElecPmtPulse();
00269 
00270     // Primary vertex time (absolute, in seconds)
00271     TimeStamp vertexTime = (*hcIter)->hc()->header()->header()->timeStamp();
00272     // Need to subtract ElecHeader time (absolute, in seconds) to get 
00273     // pulse time wrt ElecHeader
00274     // Set pulse time, include transit time (nanoseconds)
00275     double transitTime = m_gauss() * pmtData->m_timeSpread 
00276       + pmtData->m_timeOffset;
00277     double headerOffset = double(vertexTime - headerTime)*Gaudi::Units::second;
00278     double pulseHitTime = headerOffset + (*hcIter)->hitTime() + transitTime;
00279 
00280     simpulse->setTime(pulseHitTime);
00281 
00282     simpulse->setAmplitude(PulseAmp((*hcIter)->weight(),pmtData->m_gain,
00283                                     pmtData->m_sigmaGain));  // Include SPE effects, relative gain
00284     simpulse->setAncestor((*hcIter));
00285     simpulse->setType(PulseType::kPmtHit);
00286     simpulse->setChannelId(elecChannelId);
00287 
00288     pulsecon.push_back(simpulse);
00289 
00290     // PMT pulse counting
00291     if(m_enableAfterPulse){
00292       if( m_enableNonlinearAfterpulse ){
00293         // Add pulse to the list for this PMT
00294         pulsesByPmt[sensDetId].push_back(simpulse);
00295       }else{
00296         // Immediatly add linear afterpulsing
00297         if (m_uni() < pmtData->m_afterPulseProb) 
00298           pulsecon.push_back(makeAfterPulse(simpulse, *pmtData));
00299       }
00300     }
00301     // Include pre-pulse?
00302     if (m_uni() < pmtData->m_prePulseProb && m_enablePrePulse){
00303       pulsecon.push_back(makePrePulse(simpulse, *pmtData));
00304     }
00305   } 
00306 
00307   // Add afterpulses in nonlinear mode
00308   if(m_enableAfterPulse){
00309     if( m_enableNonlinearAfterpulse){
00310       pulsePmtEnd = pulsesByPmt.end(); 
00311       for(pulsePmtIter = pulsesByPmt.begin();pulsePmtIter != pulsePmtEnd;pulsePmtIter++){
00312         const DayaBay::DetectorSensor& sensDetId = pulsePmtIter->first;
00313         std::vector<DayaBay::ElecPulse*>& pulseList = pulsePmtIter->second;
00314         // Get PMT properties
00315         const DayaBay::PmtSimData* pmtData = 
00316           m_simDataSvc->pmtSimData(sensDetId, svcMode);
00317         if(!pmtData){
00318           error() << "Nonlinear: No Simulation input properties for PMT: "
00319                   << sensDetId << endreq;
00320           return StatusCode::FAILURE;
00321         }
00322   
00323         // Prepare a handle for memory buffer
00324         int* pulseCount = 0;
00325   
00326         // Process hits to make afterpulses
00327         std::vector<DayaBay::ElecPulse*>::iterator pulseIter, 
00328           pulseEnd = pulseList.end();
00329         if(pulseList.size() > m_linearAfterpulseThreshold){
00330           // Add Nonlinear afterpulsing
00331           // Step 1: assemble pulse counts in a specified time window
00332           int numTimeSlots = double(m_simTimeLatest - headerTime)
00333             *Gaudi::Units::second/m_timeInterval + 1;
00334           // allocate memory only if needed
00335           if(!pulseCount) pulseCount = new int[numTimeSlots];
00336           // Clear memory buffer
00337           for(int i=0; i<numTimeSlots; i++) pulseCount[i] = 0;
00338           // Loop once to create pulse counts
00339           for(pulseIter=pulseList.begin(); pulseIter != pulseEnd; pulseIter++){
00340             int hitTimeSlot = int((*pulseIter)->time()/m_timeInterval);
00341             int pulseNo = int((*pulseIter)->amplitude()+0.5);
00342             pulseCount[hitTimeSlot] += pulseNo;
00343           }
00344           // Loop again to create afterpulses
00345           for(pulseIter=pulseList.begin(); pulseIter != pulseEnd; pulseIter++){
00346             int hitTimeSlot = int((*pulseIter)->time()/m_timeInterval);
00347             double nonlinearProb = pmtData->m_afterPulseProb/0.0164
00348               *NumAfterPulse(pulseCount[hitTimeSlot]) / pulseCount[hitTimeSlot];
00349             if (m_uni() < nonlinearProb) 
00350               pulsecon.push_back(makeAfterPulse(*pulseIter, *pmtData));
00351           }
00352         }else{
00353           // Add Linear afterpulsing
00354           for(pulseIter=pulseList.begin(); pulseIter != pulseEnd; pulseIter++){
00355             if (m_uni() < pmtData->m_afterPulseProb) 
00356               pulsecon.push_back(makeAfterPulse(*pulseIter, *pmtData));
00357           }
00358         }
00359         // Free memory buffer if it was used
00360         if(pulseCount) delete [] pulseCount;
00361       }
00362     }
00363   }
00364   // Process dark pulses
00365   // Get list of all detector sensors
00366   debug() << "Adding dark hits" << endreq; 
00367   
00368   const std::vector<DayaBay::DetectorSensor>& detSensors = 
00369     m_cableSvc->sensors( svcMode );
00370 
00371   for (size_t idet = 0; idet < detSensors.size(); ++idet) {
00372       DayaBay::DetectorSensor detSens = detSensors[idet];      
00373       if (detSens.isAD() ) {
00374           DayaBay::AdPmtSensor pmtid(detSens.fullPackedData());
00375           if (pmtid.bogus()) {
00376               warning() << "bogus AD PMT id: " << pmtid << endreq;
00377           }
00378       }
00379       else {
00380           DayaBay::PoolPmtSensor pmtid(detSens.fullPackedData());
00381           if (pmtid.bogus()) {
00382               warning() << "bogus Pool PMT id: " << pmtid << endreq;
00383           }
00384       }
00385   }
00386 
00387 
00388   for (unsigned int idet=0; idet < detSensors.size(); ++idet) {
00389     // Skip this detector sensor if not in detector of ElecPulseCollection/SimHitCollection
00390     DayaBay::DetectorSensor detSens = detSensors[idet];
00391 
00392     if (detSens.detName() != pulses->detector().detName()) continue;
00393 
00394     const DayaBay::ElecChannelId& channelId = m_cableSvc->elecChannelId( 
00395                                                                  detSens,
00396                                                                  svcMode);
00397 
00398     const DayaBay::PmtSimData* pmtData = 
00399       m_simDataSvc->pmtSimData(detSens, svcMode);
00400     if(!pmtData){
00401         error() << "No Simulation input properties for PMT #" << idet
00402                 << ": id = " << detSens
00403                 << " svcMode = " << svcMode
00404                 << endreq;
00405         return StatusCode::FAILURE;
00406     }
00407     // Generate Poisson-distributed number around mean number of dark hits in simulation time window
00408     int Ndark = PoissonRand(pmtData->m_darkRate
00409                             *double(m_simTimeLatest-m_simTimeEarliest)
00410                             *Gaudi::Units::second);
00411     verbose() << "Adding " << Ndark << " dark hits on pmt " 
00412             << detSens << " with dark rate " << pmtData->m_darkRate
00413             << " and dt " 
00414             << double(m_simTimeLatest-m_simTimeEarliest)*Gaudi::Units::second 
00415             << endreq;
00416     for (int dummy = 0; dummy < Ndark; ++dummy) {
00417       pulsecon.push_back(makeDarkPulse(channelId, *pmtData));
00418     }
00419   }
00420   
00421   debug() << "Adding " << pulsecon.size() << " pulses to detector " 
00422           << pulses->detector() << endreq; 
00423   return StatusCode::SUCCESS;
00424 }
00425 
00426 DayaBay::ElecPulse* EsPmtEffectPulseTool::makePrePulse(
00427                                           DayaBay::ElecPulse* simpulse,
00428                                           const DayaBay::PmtSimData& pmtData) {
00429   DayaBay::ElecPulse* prepulse = new DayaBay::ElecPmtPulse();
00430 
00431   // Time offset from main pulse based on time PDF of pre-pulses
00432   double current_rand = m_randPrePulseTime();
00433   double prePulseTime = ConvertPdfRand(current_rand,m_prePulsePdf,m_prePulseEdges);
00434 
00435   prepulse->setTime(simpulse->time() + prePulseTime);
00436   prepulse->setAmplitude(PulseAmp(simpulse->amplitude(), pmtData.m_gain,
00437                                   pmtData.m_sigmaGain));
00438   prepulse->setAncestor(simpulse->ancestor());
00439   prepulse->setType(PulseType::kPrePulse);
00440   prepulse->setChannelId(simpulse->channelId());
00441   
00442   return prepulse;
00443 }
00444 
00445 DayaBay::ElecPulse* EsPmtEffectPulseTool::makeAfterPulse(
00446                                           DayaBay::ElecPulse* simpulse,
00447                                           const DayaBay::PmtSimData& pmtData) {
00448   DayaBay::ElecPulse* afterpulse = new DayaBay::ElecPmtPulse();
00449 
00450   // Time offset from main pulse based on time PDF of after-pulses
00451   // double current_rand = m_randAfterPulseTime();
00452   double current_rand = m_uni();
00453   double afterPulseTime = ConvertPdfRand01(current_rand,m_afterPulsePdf,m_afterPulseEdges);
00454   //  std::cout << "current_rand = " << current_rand  << ", time = " << afterPulseTime << std::endl;
00455 
00456   afterpulse->setTime(simpulse->time() + afterPulseTime); 
00457   if(m_afterPulseAmpMode == "SinglePE") 
00458     afterpulse->setAmplitude(PulseAmp(simpulse->amplitude(), pmtData.m_gain, pmtData.m_sigmaGain));
00459   if(m_afterPulseAmpMode == "PDF"){
00460     current_rand = m_uni();
00461     double amplitude = ConvertPdfRand01(current_rand, m_afterPulseAmpPdf, m_afterPulseAmpEdges);
00462     afterpulse->setAmplitude(PulseAmp(amplitude, pmtData.m_gain, pmtData.m_sigmaGain));
00463   }
00464   afterpulse->setAncestor(simpulse->ancestor()); 
00465   afterpulse->setType(PulseType::kAfterPulse);
00466   afterpulse->setChannelId(simpulse->channelId());
00467   
00468   return afterpulse;
00469 }
00470 
00471 DayaBay::ElecPulse* EsPmtEffectPulseTool::makeDarkPulse(
00472                                         const DayaBay::ElecChannelId& channelId,
00473                                         const DayaBay::PmtSimData& pmtData) {
00474   DayaBay::ElecPulse* darkpulse = new DayaBay::ElecPmtPulse();
00475   double darkPulseTime
00476     = m_uni()*double(m_simTimeLatest-m_simTimeEarliest)*Gaudi::Units::second;
00477 
00478   darkpulse->setTime(darkPulseTime);
00479   if(m_darkPulseAmpMode == "SinglePE") darkpulse->setAmplitude(PulseAmp(1.0, pmtData.m_gain, pmtData.m_sigmaGain));
00480   if(m_darkPulseAmpMode == "PDF"){
00481     double current_rand = m_uni();
00482     double amplitude = ConvertPdfRand01(current_rand, m_afterPulseAmpPdf, m_afterPulseAmpEdges);
00483     darkpulse->setAmplitude(PulseAmp(amplitude, pmtData.m_gain, pmtData.m_sigmaGain));
00484   }
00485   darkpulse->setAncestor(0);
00486   darkpulse->setType(PulseType::kDarkPulse);
00487   darkpulse->setChannelId(channelId);
00488   
00489   return darkpulse;
00490 }
00491 
00492 float EsPmtEffectPulseTool::PulseAmp(float weight, float gain, float sigmaGain){
00493 
00494   // Include relative gain
00495   float randW = m_uni();
00496   if (randW > m_expWeight ){
00497     return m_gauss() * sigmaGain + gain;
00498   }
00499   else {
00500     return (m_exp() + m_speCutoff) * gain;
00501   }
00502 }
00503 
00504 
00505 double EsPmtEffectPulseTool::ConvertPdfRand(double rand, std::vector<double> pdf, std::vector<double> edges) {
00506   // Defined PDF returns random number in [0,1] distributed according to user-defined histogram.
00507   // It assumes even bin sizes, so accomodate uneven bin sizes for generality.
00508   int current_bin;
00509   int Nbins = pdf.size();
00510 
00511   for (int bin=0;bin<Nbins;bin++) { // find which bin rand is in
00512     if (rand >= (double)(bin/Nbins) && rand < (double)((bin+1)/Nbins)) current_bin = bin;
00513     else current_bin = Nbins-1;     // else rand=1, so current_bin is last bin (Nbins-1)
00514   }
00515   return edges[current_bin] + (rand*Nbins - current_bin)*(edges[current_bin+1]-edges[current_bin]);
00516 }
00517 
00518 double EsPmtEffectPulseTool::ConvertPdfRand01(double rand, std::vector<double> pdf, std::vector<double> edges) {
00519   // Defined PDF returns random number in [0,1] distributed according to user-defined histogram.
00520   // It assumes even bin sizes, so accomodate uneven bin sizes for generality.
00521   int current_bin;
00522   int Nbins = pdf.size();
00523 
00524   for(int bin=0; bin<Nbins; bin++) {
00525     if(rand >= pdf[bin] && rand < pdf[bin+1]) {
00526       current_bin = bin;
00527       break;
00528     }
00529     else
00530       current_bin = Nbins-1;
00531   }
00532 
00533   return edges[current_bin] + (rand-pdf[current_bin])*(edges[current_bin+1]-edges[current_bin])
00534     /(pdf[current_bin+1]-pdf[current_bin]);
00535 }
00536 
00537 int EsPmtEffectPulseTool::PoissonRand(double mean) {
00538   // Using source code from ROOT's TRandom::Poisson
00539   // Note: ROOT uses different algorithms depending on the mean, but mean is small 
00540   //       for our purposes, so use algorithm for mean<25
00541  
00542   int n;
00543   if (mean <= 0) return 0;
00544 
00545   double expmean = exp(-mean);
00546   double pir = 1;
00547   n = -1;
00548   while(1) {
00549     n++;
00550     pir *= m_uni();
00551     if (pir <= expmean) break;
00552   }
00553   return n;
00554 }
00555 
00556 
00557 double EsPmtEffectPulseTool::NumAfterPulse(const int numPmtHit) {
00558   // Get number of after-pulses per PMT pulse based on the number of PMT hits
00559 
00560   double cnt;
00561 
00562   if (numPmtHit <= 400)
00563     cnt = 0.016 * numPmtHit;
00564   else if (numPmtHit <= 2500)
00565     cnt = -1.307853 + 0.02666278 * numPmtHit - 0.2001321e-4 * pow(numPmtHit, 2)
00566                +0.7330343e-8 * pow(numPmtHit, 3) - 0.102098e-11 * pow(numPmtHit, 4);
00567   else
00568     cnt = 15.;
00569 
00570   return cnt;
00571 }
00572 
00573 void EsPmtEffectPulseTool::getAfterPulseAmpEdges(std::vector<double>& edges){
00574   edges.push_back(0.5);edges.push_back(0.7);edges.push_back(0.9);edges.push_back(1.1);
00575   edges.push_back(1.3);edges.push_back(1.5);edges.push_back(1.7);edges.push_back(1.9);
00576   edges.push_back(2.1);edges.push_back(2.3);edges.push_back(2.5);edges.push_back(2.7);
00577   edges.push_back(3.05);edges.push_back(3.4);edges.push_back(3.75);edges.push_back(4.1);
00578   edges.push_back(4.6);edges.push_back(5.1);edges.push_back(5.6);edges.push_back(6.1);
00579   edges.push_back(7.1);edges.push_back(8.1);edges.push_back(9.1);edges.push_back(10.1);
00580   edges.push_back(11.1);edges.push_back(13.1);edges.push_back(15.1);edges.push_back(17.1);
00581   edges.push_back(19.1);edges.push_back(21.1);edges.push_back(23.1);edges.push_back(25.1);
00582   edges.push_back(27.1);edges.push_back(29.1);edges.push_back(31.1);edges.push_back(35.1);
00583   edges.push_back(39.1);edges.push_back(43.1);edges.push_back(47.1);edges.push_back(51.1);
00584   edges.push_back(55.1);edges.push_back(59.1);edges.push_back(63.1);edges.push_back(67.1);
00585   edges.push_back(71.1);edges.push_back(75.1);edges.push_back(79.1);edges.push_back(83.1);
00586   edges.push_back(87.1);edges.push_back(91.1);edges.push_back(95.1);edges.push_back(100);
00587 }
00588 
00589 void EsPmtEffectPulseTool::getAfterPulseAmpPdf(std::vector<double>& pdf){
00590   pdf.push_back(0);pdf.push_back(0.0219574);pdf.push_back(0.0931247);pdf.push_back(0.179757);
00591   pdf.push_back(0.264803);pdf.push_back(0.342568);pdf.push_back(0.411712);pdf.push_back(0.472498);
00592   pdf.push_back(0.525729);pdf.push_back(0.572335);pdf.push_back(0.613205);pdf.push_back(0.649137);
00593   pdf.push_back(0.702162);pdf.push_back(0.745131);pdf.push_back(0.780295);pdf.push_back(0.809341);
00594   pdf.push_back(0.842677);pdf.push_back(0.868769);pdf.push_back(0.889482);pdf.push_back(0.906131);
00595   pdf.push_back(0.930777);pdf.push_back(0.947671);pdf.push_back(0.95962);pdf.push_back(0.968294);
00596   pdf.push_back(0.974731);pdf.push_back(0.983341);pdf.push_back(0.988564);pdf.push_back(0.99189);
00597   pdf.push_back(0.994094);pdf.push_back(0.995601);pdf.push_back(0.996661);pdf.push_back(0.997423);
00598   pdf.push_back(0.997983);pdf.push_back(0.998401);pdf.push_back(0.998717);pdf.push_back(0.999151);
00599   pdf.push_back(0.999418);pdf.push_back(0.999591);pdf.push_back(0.999705);pdf.push_back(0.999783);
00600   pdf.push_back(0.999838);pdf.push_back(0.999876);pdf.push_back(0.999905);pdf.push_back(0.999926);
00601   pdf.push_back(0.999941);pdf.push_back(0.999953);pdf.push_back(0.999962);pdf.push_back(0.999969);
00602   pdf.push_back(0.999975);pdf.push_back(0.999979);pdf.push_back(0.999983);pdf.push_back(1.0);
00603 }
00604 
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 20:49:26 2011 for ElecSim by doxygen 1.4.7