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
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
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
00058
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
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
00106 m_cableSvc = svc<ICableSvc>(m_cableSvcName,true);
00107
00108
00109 m_simDataSvc = svc<ISimDataSvc>(m_simDataSvcName,true);
00110
00111
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
00155 if(m_enablePrePulse){
00156 if (m_prePulsePdf.size()+1 != m_prePulseEdges.size()) {
00157
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
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
00196 m_simTimeEarliest = pulses->header()->header()->earliest();
00197 m_simTimeLatest = pulses->header()->header()->latest();
00198 TimeStamp headerTime = pulses->header()->header()->timeStamp();
00199
00200
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
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
00241
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
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
00271 TimeStamp vertexTime = (*hcIter)->hc()->header()->header()->timeStamp();
00272
00273
00274
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));
00284 simpulse->setAncestor((*hcIter));
00285 simpulse->setType(PulseType::kPmtHit);
00286 simpulse->setChannelId(elecChannelId);
00287
00288 pulsecon.push_back(simpulse);
00289
00290
00291 if(m_enableAfterPulse){
00292 if( m_enableNonlinearAfterpulse ){
00293
00294 pulsesByPmt[sensDetId].push_back(simpulse);
00295 }else{
00296
00297 if (m_uni() < pmtData->m_afterPulseProb)
00298 pulsecon.push_back(makeAfterPulse(simpulse, *pmtData));
00299 }
00300 }
00301
00302 if (m_uni() < pmtData->m_prePulseProb && m_enablePrePulse){
00303 pulsecon.push_back(makePrePulse(simpulse, *pmtData));
00304 }
00305 }
00306
00307
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
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
00324 int* pulseCount = 0;
00325
00326
00327 std::vector<DayaBay::ElecPulse*>::iterator pulseIter,
00328 pulseEnd = pulseList.end();
00329 if(pulseList.size() > m_linearAfterpulseThreshold){
00330
00331
00332 int numTimeSlots = double(m_simTimeLatest - headerTime)
00333 *Gaudi::Units::second/m_timeInterval + 1;
00334
00335 if(!pulseCount) pulseCount = new int[numTimeSlots];
00336
00337 for(int i=0; i<numTimeSlots; i++) pulseCount[i] = 0;
00338
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
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
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
00360 if(pulseCount) delete [] pulseCount;
00361 }
00362 }
00363 }
00364
00365
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
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
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
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
00451
00452 double current_rand = m_uni();
00453 double afterPulseTime = ConvertPdfRand01(current_rand,m_afterPulsePdf,m_afterPulseEdges);
00454
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
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
00507
00508 int current_bin;
00509 int Nbins = pdf.size();
00510
00511 for (int bin=0;bin<Nbins;bin++) {
00512 if (rand >= (double)(bin/Nbins) && rand < (double)((bin+1)/Nbins)) current_bin = bin;
00513 else current_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
00520
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
00539
00540
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
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