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

In This Package:

FlasherIdTool.cc

Go to the documentation of this file.
00001 #include "FlasherIdTool.h"
00002 
00003 #include "StatisticsSvc/IStatisticsSvc.h"
00004 #include "Event/ReadoutHeader.h"
00005 #include "Event/DaqCrate.h"
00006 #include "Event/DaqPmtCrate.h"
00007 #include "Event/DaqPmtChannel.h"
00008 #include "Conventions/Electronics.h"
00009 
00010 #include "DataSvc/ICableSvc.h"
00011 #include "DetHelpers/IPmtGeomInfoSvc.h"
00012 #include "CLHEP/Vector/ThreeVector.h"
00013 
00014 #include "TH2.h"
00015 #include "TMath.h"
00016 #include "TList.h"
00017 #include "TTree.h"
00018 
00019 #include <sstream>
00020 
00021 
00022 char timeFormat[] = "#splitline{%H:%M:%S}{%b %d %Y}";
00023 
00024 // Another frustrating feature of ROOT: timezones are a pain.
00025 // It doesn't matter if you set the china local time here,
00026 // it will always be drawn in the local time of the
00027 // machine which draws the histogram. :(
00028 
00029 FlasherIdTool::FlasherIdTool(const std::string& type,
00030                              const std::string& name, 
00031                              const IInterface* parent) 
00032   : GaudiTool(type,name,parent),
00033     m_statsSvc(0),
00034     m_cableSvc(0),
00035     m_pmtInfoSvc(0),
00036     m_firstTriggerTime(0),
00037     m_detector(Site::kSAB, DetectorId::kAD1),
00038     m_nEvents(0),
00039     m_maxTdcCalibEvents(1000),
00040     m_topCalibTdcOffset(0),
00041     m_topCalibNTdcs(0),
00042     m_bottomCalibTdcOffset(0),
00043     m_bottomCalibNTdcs(0),
00044     m_nChannels(0),
00045     m_minDt(-MAXDT/2.)
00046 {
00047   declareInterface<IReadoutProcessor>(this);
00048   declareProperty("FlasherThreshold", m_flasherThreshold=0.4, 
00049                   "Threshold for flasher discrimination");
00050   declareProperty("Detector", m_detectorName="SABAD1", 
00051                   "Detector to process with this tool");
00052 
00053   for(unsigned int board=0; board<NBOARDS; board++){
00054     m_boardTdcOffset[board]=0;
00055     m_boardNTdcs[board]=0;
00056   }
00057   unsigned int maxChanIdx = NBOARDS*NCONNECTORS;
00058   for(unsigned int chanIdx=0; chanIdx<maxChanIdx; chanIdx++){
00059     m_flashBoard[chanIdx]=0;
00060     m_flashConnector[chanIdx]=0;
00061     m_flashDeltaAdc[chanIdx]=0;
00062     m_flashTdc[chanIdx]=0;
00063     for(unsigned int chanIdx2=0; chanIdx2<maxChanIdx; chanIdx2++){
00064       m_distance[chanIdx][chanIdx2]=0;
00065     }
00066   }
00067 
00068   // Pre-calculate log-likelihood for dt
00069   // Use distribution that roughly approximates data
00070   double levyScale = 50.;
00071   double bgScale = 0.01;
00072   double probability[MAXDT];
00073   double maxProb=0;
00074   double sqrt2pi = TMath::Sqrt(2*TMath::Pi());
00075   for(unsigned int idx=0; idx < MAXDT; idx++){
00076     double levyX0 = 25.;
00077     double dt = (m_minDt + idx + levyX0)/levyScale;
00078     probability[idx] = bgScale;
00079     if(dt>0){
00080       probability[idx] += (1-bgScale)*(TMath::Exp(-0.5/dt)
00081                                        /(sqrt2pi*TMath::Power(dt,1.5)));
00082     }
00083     if(probability[idx]>maxProb) maxProb = probability[idx];
00084   }
00085   for(unsigned int idx=0; idx < MAXDT; idx++){
00086     m_logLikelihood[idx] = -2*TMath::Log( probability[idx]/maxProb );
00087     debug() << m_logLikelihood[idx] << endreq;
00088   }
00089 }
00090 
00091 FlasherIdTool::~FlasherIdTool()
00092 {
00093 }
00094 
00095 StatusCode FlasherIdTool::initialize()
00096 {
00097   // Initialize the tool
00098   m_detector = DayaBay::Detector(m_detectorName);
00099 
00100   // Initialize the necessary services
00101   StatusCode sc = this->service("StatisticsSvc",m_statsSvc,true);
00102   if(sc.isFailure()){
00103     error() << "Failed to get StatisticsSvc" << endreq;
00104     return sc;
00105   }
00106 
00107   sc = this->service("StaticCableSvc",m_cableSvc,true);
00108   if(sc.isFailure()){
00109     error() << "Failed to get CableSvc" << endreq;
00110     return sc;
00111   }
00112 
00113   sc = this->service("PmtGeomInfoSvc",m_pmtInfoSvc,true);
00114   if(sc.isFailure()){
00115     error() << "Failed to get PmtGeomInfoSvc" << endreq;
00116     return sc;
00117   }
00118 
00119   return sc;
00120 }
00121 
00122 StatusCode FlasherIdTool::process(const DayaBay::ReadoutHeader* readoutHeader)
00123 {
00124   // Check this readout for possible PMT flashers
00125   //
00126   const DayaBay::DaqCrate* daqCrate = readoutHeader->daqCrate();
00127   if(!daqCrate){
00128     error() << "Failed to get daq readout from header" << endreq;
00129     return StatusCode::FAILURE;
00130   }
00131 
00132   if(!daqCrate->detector().isAD() || daqCrate->detector()!=m_detector){
00133     // Not the detector we want, continue
00134     return StatusCode::SUCCESS;
00135   }
00136 
00137   // Convert to PMT crate readout
00138   const DayaBay::DaqPmtCrate* pmtCrate = daqCrate->asPmtCrate();
00139 
00140   if(!m_firstTriggerTime){
00141     m_firstTriggerTime = new TimeStamp(daqCrate->triggerTime());
00142     StatusCode sc = this->initializeDistanceTable(readoutHeader->context());
00143     if(!sc.isSuccess()) return sc;
00144   }
00145 
00146   // Find histograms
00147   int runNumber = daqCrate->runNumber();
00148   const DayaBay::Detector& detector = daqCrate->detector();
00149 
00150   TH2F* flasherRingVsColumn = 0;
00151 
00152   const std::vector<DayaBay::DaqPmtChannel*>& channels = pmtCrate->channelReadouts();
00153   
00154   std::vector<DayaBay::DaqPmtChannel*>::const_iterator channelIter, 
00155     channelEnd = channels.end();
00156 
00157   TimeStamp dtTriggerTime = daqCrate->triggerTime();
00158   dtTriggerTime.Subtract(m_lastTriggerTime);
00159   m_dt = dtTriggerTime.GetSeconds();
00160 
00161   // Stage 1: Collect TDC offset data for each board
00162   //  2" calib PMTs need an additional correction due to top/bottom cable length
00163   if( m_nEvents < m_maxTdcCalibEvents ){
00164     for(channelIter = channels.begin();
00165         channelIter!=channelEnd; 
00166         channelIter++){ 
00167       const DayaBay::DaqPmtChannel* channel = *channelIter;      
00168       if( channel->hitCount() < 1 ) continue;
00169       unsigned int board = channel->channelId().board();
00170       if( board!=17 ){
00171         m_boardTdcOffset[board] += channel->tdc(0);
00172         m_boardNTdcs[board]++;
00173       }else{
00174         // Deal with 2" calib PMT
00175         unsigned int connector = channel->channelId().connector();
00176         if(connector % 2 == 0){
00177           // Even PMTs on bottom
00178           m_bottomCalibTdcOffset += channel->tdc(0);
00179           m_bottomCalibNTdcs++;
00180         }else{
00181           // Odd PMTs on top
00182           m_topCalibTdcOffset += channel->tdc(0);
00183           m_topCalibNTdcs++;
00184         } 
00185       } 
00186     }
00187     m_nEvents++;
00188     return StatusCode::SUCCESS;
00189   }
00190 
00191   // Stage 2: Calculate current board TDC offset
00192   if(m_nEvents == m_maxTdcCalibEvents){
00193     // Calculate current TDC offsets
00194     for(unsigned int boardIdx = 0; boardIdx<NBOARDS; boardIdx++){
00195       if(m_boardNTdcs[boardIdx]>0){
00196         m_boardTdcOffset[boardIdx] /= m_boardNTdcs[boardIdx];
00197       }
00198     }
00199     if(m_topCalibNTdcs>0){
00200       m_topCalibTdcOffset /= m_topCalibNTdcs;
00201     }
00202     if(m_bottomCalibNTdcs>0){
00203       m_bottomCalibTdcOffset /= m_bottomCalibNTdcs;
00204     }
00205   }
00206 
00207   // Stage 3: Find first hit on each channel
00208   unsigned int nChan = 0;
00209   m_adcSum=0;
00210   for(channelIter = channels.begin(); channelIter!=channelEnd; channelIter++) { 
00211     const DayaBay::DaqPmtChannel* channel = *channelIter;
00212     if( channel->hitCount() <1 ){
00213       continue;
00214     }   
00215     int board = channel->channelId().board();
00216     int connector = channel->channelId().connector();
00217 
00218     // Loop over hits, find first hit on channel
00219     unsigned int earliestTdc = channel->tdc( 0 );
00220     unsigned int adc = channel->adc( 0 );
00221     float preAdc = channel->preAdcAvg( 0 );
00222     bool isHighGainAdc = channel->isHighGainAdc( 0 );
00223     for(unsigned int hitIdx=1; hitIdx<channel->hitCount(); hitIdx++){
00224       if( channel->tdc( hitIdx ) > earliestTdc ){
00225         earliestTdc = channel->tdc( hitIdx );
00226         adc = channel->adc( hitIdx );
00227         preAdc = channel->preAdcAvg( hitIdx );
00228         isHighGainAdc = channel->isHighGainAdc( hitIdx );
00229       }
00230     }
00231     unsigned int chanIdx = this->channelIndex(board,connector);
00232     m_flashTdc[nChan] = earliestTdc - this->tdcOffset(board, connector);
00233     m_flashDeltaAdc[nChan] = adc-preAdc;
00234     if(!isHighGainAdc){
00235       m_flashDeltaAdc[nChan]*=19;
00236     }
00237     m_flashBoard[nChan] = board;
00238     m_flashConnector[nChan] = connector;
00239     m_flashRing[nChan] = m_ring[chanIdx];
00240     m_flashColumn[nChan] = m_column[chanIdx];
00241     m_adcSum += m_flashDeltaAdc[nChan];
00242     nChan++;
00243   }
00244 
00245   //Stage 4: calculate flasher discriminator for each PMT that was hit
00246   double tdcToNs = -(25./16.);
00247   double sqrt2 = sqrt(2.);
00248   for( unsigned int chanCount=0; chanCount<nChan; chanCount++ ){
00249     unsigned int flashBoard = m_flashBoard[chanCount];
00250     unsigned int flashConnector = m_flashConnector[chanCount];
00251     unsigned int flashChanIdx = this->channelIndex(flashBoard, flashConnector);
00252     // First check Q-discriminator
00253     double flashQDisc = 1 - m_flashDeltaAdc[chanCount]/m_adcSum;
00254     if(flashQDisc > m_flasherThreshold){
00255       // Skip this channel if Q-discriminator is already too high
00256       continue;
00257     }
00258     double flashDisc = 0;
00259     double flashTdc = m_flashTdc[chanCount];
00260     int nHit = 0;
00261     for(channelIter = channels.begin(); channelIter!=channelEnd;
00262         channelIter++) { 
00263       const DayaBay::DaqPmtChannel* channel = *channelIter;
00264       if( channel->hitCount() < 1 ) continue;
00265       int board = channel->channelId().board();
00266       int connector = channel->channelId().connector();
00267       unsigned int targetChanIdx = this->channelIndex(board, connector);
00268       if(targetChanIdx==flashChanIdx) continue;
00269       double tdcOff = this->tdcOffset(board, connector);
00270       for(unsigned int hitIdx=0; hitIdx<channel->hitCount(); hitIdx++){
00271         double tdcCorr = channel->tdc(hitIdx) - tdcOff;
00272         double dtHit = (tdcCorr - flashTdc) * tdcToNs;
00273         double timeResidual = (dtHit - m_distance[flashChanIdx][targetChanIdx]) 
00274           - this->transitTime(flashBoard);
00275         // Use integer ns resolution on likelihood to improve speed
00276         flashDisc += m_logLikelihood[int(timeResidual-m_minDt)];
00277         nHit++;
00278       }
00279     }
00280     if(nHit>0){
00281       flashDisc /= (nHit*m_logLikelihood[0]);
00282     }
00283     // Record flasher likelihood
00284     m_flashLikelihood[chanCount] = sqrt(flashDisc*flashDisc 
00285                                         + flashQDisc*flashQDisc)/sqrt2;
00286     if(m_flashLikelihood[chanCount] < m_flasherThreshold){
00287       TH2F* flasherQVsT = 
00288         dynamic_cast<TH2F*>(this->getOrMakeHist(runNumber,
00289                                                 detector,
00290                                                 flashBoard,
00291                                                 flashConnector, 
00292                                                 FLASHERQVST));
00293       flasherQVsT->Fill(flashDisc,flashQDisc);
00294       if(!flasherRingVsColumn){
00295         flasherRingVsColumn = 
00296           dynamic_cast<TH2F*>(this->getOrMakeHist(runNumber,
00297                                                   detector,
00298                                                   0, 0, 
00299                                                   FLASHERRINGVSCOLUMN));
00300       }
00301       flasherRingVsColumn->Fill(m_flashColumn[chanCount],
00302                                 m_flashRing[chanCount]);
00303     }
00304   }
00305 
00306   m_nChannels = nChan;
00307 
00308   m_lastTriggerTime = daqCrate->triggerTime();
00309 
00310   m_nEvents++;
00311   return StatusCode::SUCCESS;
00312 }
00313 
00314 StatusCode FlasherIdTool::finalize()
00315 {
00316   // Clean-up histogram shortcuts
00317   std::map<int,TH1**>::iterator histIter, histEnd = m_shortCuts.end();
00318   for(histIter = m_shortCuts.begin(); histIter!=histEnd; histIter++){
00319     delete [] (histIter->second);
00320     histIter->second = 0;
00321   }
00322   if( m_statsSvc ) m_statsSvc->release();
00323   if(m_firstTriggerTime){
00324     delete m_firstTriggerTime;
00325     m_firstTriggerTime = 0;
00326   }
00327   return StatusCode::SUCCESS;
00328 }
00329 
00331 
00332 StatusCode FlasherIdTool::initializeDistanceTable(const Context& context)
00333 {
00334   // Pre-calculate PMT-to-PMT distances
00335   info() << "Init Dist A" << endreq;
00336   double lightspeed = 300.; // mm/ns
00337   ServiceMode svcMode(context,0);
00338   const std::vector<DayaBay::AdPmtSensor>& adPmts = 
00339     m_cableSvc->adPmtSensors(svcMode);
00340   std::vector<DayaBay::AdPmtSensor>::const_iterator pmtIdIter1, pmtIdIter2, 
00341     pmtIdEnd = adPmts.end();
00342   for(pmtIdIter1 = adPmts.begin(); pmtIdIter1!=pmtIdEnd; pmtIdIter1++){
00343     info() << "Init Dist b" << endreq;
00344     const DayaBay::AdPmtSensor& pmtId1 = *pmtIdIter1;
00345     info() << "  ring/column: " << pmtId1.ring() << "  " 
00346            << pmtId1.column() << endreq;
00347     if(pmtId1.ring()==0 && pmtId1.column()>6) continue;
00348     const DayaBay::FeeChannelId& channel1 = m_cableSvc->feeChannelId(pmtId1, 
00349                                                                      svcMode);
00350     unsigned int chanIdx1 = this->channelIndex(channel1.board(),
00351                                                channel1.connector());
00352     m_ring[chanIdx1] = pmtId1.ring();
00353     m_column[chanIdx1] = pmtId1.column();
00354     const CLHEP::Hep3Vector& pmtPos1 
00355       = m_pmtInfoSvc->get(pmtId1.fullPackedData())->localPosition();    
00356     for(pmtIdIter2 = adPmts.begin(); pmtIdIter2!=pmtIdEnd; pmtIdIter2++){
00357       //info() << "Init Dist c" << endreq;
00358       const DayaBay::AdPmtSensor& pmtId2 = *pmtIdIter2;
00359       //info() << "  ring/column: " << pmtId2.ring() << "  " 
00360       //     << pmtId2.column() << endreq;
00361       if(pmtId2.ring()==0 && pmtId2.column()>6) continue;
00362       const DayaBay::FeeChannelId& channel2 = m_cableSvc->feeChannelId(pmtId2,
00363                                                                        svcMode);
00364       //info() << "  board/connector: " << channel2.board() << "  " 
00365       //             << channel2.connector() << endreq;
00366       unsigned int chanIdx2 = this->channelIndex(channel2.board(),
00367                                                  channel2.connector());
00368       const CLHEP::Hep3Vector& pmtPos2 
00369         = m_pmtInfoSvc->get(pmtId2.fullPackedData())->localPosition();
00370       double distance = 0;
00371       double dr = pmtPos1.x()-pmtPos2.x();
00372       distance += dr*dr;
00373       dr = pmtPos1.y()-pmtPos2.y();
00374       distance += dr*dr;
00375       dr = pmtPos1.z()-pmtPos2.z();
00376       distance += dr*dr;
00377       distance = TMath::Sqrt(distance);
00378       //info() << "  distance " << distance << endreq;
00379       m_distance[chanIdx1][chanIdx2] = distance / lightspeed;
00380       //info() << "  done " << endreq;
00381     }
00382     //info() << "Init Dist d" << endreq;
00383   }
00384   return StatusCode::SUCCESS;
00385 }
00386 
00387 TH1* FlasherIdTool::getOrMakeHist(int run, const DayaBay::Detector& detector,
00388                                   int board, int connector, int histogram)
00389 {
00390   std::map<int,TH1**>::iterator histIter = m_shortCuts.find(run);
00391   TH1** histograms = 0;
00392   if( histIter == m_shortCuts.end() ){
00393     // Initialize histogram shortcuts
00394     histograms = new TH1*[MAXHISTS];
00395     for(int i=0; i<MAXHISTS; i++) histograms[i] = 0;
00396     m_shortCuts[run] = histograms;
00397   }else{
00398     // Found run
00399     histograms = histIter->second;
00400   }
00401   
00402   TH1* hist = 
00403     histograms[board * NCONNECTORS * NHISTOGRAMS
00404                + connector * NHISTOGRAMS
00405                + histogram];
00406   if(!hist){
00407     // Make this histogram
00408     std::string histName;
00409     if(detector.detectorId()){
00410       if(board){
00411         // Make channel histograms
00412         switch(histogram){
00413         case FLASHERQVST:
00414           // Plot flasher charge vs. time discriminator
00415           histName = "flasherQVsT";
00416           hist = new TH2F(histName.c_str(),
00417                           "Flasher Q vs. T Discriminator",
00418                           200,0,1,200,0,1);
00419           hist->GetXaxis()->SetTitle("T-discriminator");
00420           hist->GetYaxis()->SetTitle("Q-discriminator");
00421           break;
00422         default:
00423           error() << "Unknown Histogram: " << histogram << endreq;
00424           return 0;
00425         }
00426       }else{
00427         // Make detector histogram
00428         switch(histogram){
00429         case FLASHERRINGVSCOLUMN:
00430           // Plot flasher ring vs. column
00431           histName = "flasherRingVsColumn";
00432           hist = new TH2F(histName.c_str(),
00433                           "Flasher Ring vs. Column",
00434                           49,0.25,24.75,19,-0.75,8.75);
00435           hist->GetXaxis()->SetTitle("PMT Column");
00436           hist->GetYaxis()->SetTitle("PMT Ring");
00437           hist->SetStats(0);              
00438           break;
00439         default:
00440           error() << "Unknown Histogram: " << histogram << endreq;
00441           return 0;
00442         }
00443       }
00444     }
00445     info() << "Making histogram: " << histName << endreq;
00446     m_statsSvc->put( this->getPath(run, detector.detName().c_str(), board, 
00447                                    connector, histName.c_str()), 
00448                      hist );
00449     histograms[board * NCONNECTORS * NHISTOGRAMS
00450                + connector * NHISTOGRAMS
00451                + histogram] = hist;
00452   }
00453 
00454   return hist;
00455 }
00456 
00457 unsigned int FlasherIdTool::channelIndex(unsigned int board, 
00458                                          unsigned int connector)
00459 {
00460   // Return a counting index for channels
00461   return board * NCONNECTORS + connector;
00462 }
00463 
00464 double FlasherIdTool::tdcOffset(int board, int connector)
00465 {
00466   double tdcOffset = m_boardTdcOffset[board];
00467   if(board==17){
00468     if(connector %2 == 0){
00469       tdcOffset = m_bottomCalibTdcOffset;
00470     }else{
00471       tdcOffset = m_topCalibTdcOffset;
00472     }
00473   }
00474   return tdcOffset;
00475 }
00476 
00477 double FlasherIdTool::transitTime(unsigned int board) 
00478 {
00479   // Return transit time
00480   if(board==17) return 29.;
00481   return 55.;
00482 }
00483 
00484 std::string FlasherIdTool::getPath(int run, const char* detectorName,
00485                                    int board, int connector, 
00486                                    const char* histName)
00487 {
00488   // Construct histogram path in statistics service
00489   std::stringstream path;
00490   path << "/file1/diagnostics/run_" << std::setfill('0') << std::setw(7) 
00491        << run;
00492   if(detectorName){
00493     path << "/detector_" << detectorName;
00494     if(board){
00495       path << "/channel_board" << std::setfill('0') << std::setw(2) 
00496            << board << "_connector" << std::setfill('0') << std::setw(2)
00497            << connector;
00498     }
00499   }
00500   path << "/" << histName;
00501   return path.str();
00502 }
00503 
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 20:25:59 2011 for FlasherId by doxygen 1.4.7