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
00025
00026
00027
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
00069
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
00098 m_detector = DayaBay::Detector(m_detectorName);
00099
00100
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
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
00134 return StatusCode::SUCCESS;
00135 }
00136
00137
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
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
00162
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
00175 unsigned int connector = channel->channelId().connector();
00176 if(connector % 2 == 0){
00177
00178 m_bottomCalibTdcOffset += channel->tdc(0);
00179 m_bottomCalibNTdcs++;
00180 }else{
00181
00182 m_topCalibTdcOffset += channel->tdc(0);
00183 m_topCalibNTdcs++;
00184 }
00185 }
00186 }
00187 m_nEvents++;
00188 return StatusCode::SUCCESS;
00189 }
00190
00191
00192 if(m_nEvents == m_maxTdcCalibEvents){
00193
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
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
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
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
00253 double flashQDisc = 1 - m_flashDeltaAdc[chanCount]/m_adcSum;
00254 if(flashQDisc > m_flasherThreshold){
00255
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
00276 flashDisc += m_logLikelihood[int(timeResidual-m_minDt)];
00277 nHit++;
00278 }
00279 }
00280 if(nHit>0){
00281 flashDisc /= (nHit*m_logLikelihood[0]);
00282 }
00283
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
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
00335 info() << "Init Dist A" << endreq;
00336 double lightspeed = 300.;
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
00358 const DayaBay::AdPmtSensor& pmtId2 = *pmtIdIter2;
00359
00360
00361 if(pmtId2.ring()==0 && pmtId2.column()>6) continue;
00362 const DayaBay::FeeChannelId& channel2 = m_cableSvc->feeChannelId(pmtId2,
00363 svcMode);
00364
00365
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
00379 m_distance[chanIdx1][chanIdx2] = distance / lightspeed;
00380
00381 }
00382
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
00394 histograms = new TH1*[MAXHISTS];
00395 for(int i=0; i<MAXHISTS; i++) histograms[i] = 0;
00396 m_shortCuts[run] = histograms;
00397 }else{
00398
00399 histograms = histIter->second;
00400 }
00401
00402 TH1* hist =
00403 histograms[board * NCONNECTORS * NHISTOGRAMS
00404 + connector * NHISTOGRAMS
00405 + histogram];
00406 if(!hist){
00407
00408 std::string histName;
00409 if(detector.detectorId()){
00410 if(board){
00411
00412 switch(histogram){
00413 case FLASHERQVST:
00414
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
00428 switch(histogram){
00429 case FLASHERRINGVSCOLUMN:
00430
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
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
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
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