00001 #include "RollingGain.h"
00002 #include "Event/Readout.h"
00003 #include "Event/CalibReadout.h"
00004 #include "Event/CalibReadoutPmtCrate.h"
00005 #include "Event/CalibReadoutPmtChannel.h"
00006 #include "Event/RunData.h"
00007 #include "DataSvc/ICableSvc.h"
00008 #include "DataSvc/ICalibDataSvc.h"
00009 #include "Event/RawEventHeader.h"
00010 #include <math.h>
00011 #include <fstream>
00012 #include "TMath.h"
00013
00014 RollingGain::RollingGain(const std::string& name, ISvcLocator* pSvcLocator):
00015 GaudiAlgorithm(name, pSvcLocator)
00016 {
00017 declareProperty("FileName", m_fileName = "AdcFit.root", "Root file name");
00018 declareProperty("FitPeriod", m_fitPeriod = 30*60, "Fit period in second, Default is 30 minutes");
00019 declareProperty("Fix", m_Fix = 0, "a temp fix for 40M noise");
00020 }
00021
00022 RollingGain::~RollingGain()
00023 {
00024 }
00025
00026 double RollingGain::poisson(double u, int n){
00027 return pow(u,n)*exp(-u)/TMath::Gamma(n+1);
00028 }
00029
00030 double RollingGain::gn(double x,double n, double q0, double sigma0,
00031 double q1, double sigma1){
00032 double sigman = sqrt(sigma0*sigma0+n*sigma1*sigma1);
00033 double xn = x-q0-n*q1;
00034 double tmp = pow(xn,2)/(2*sigman*sigman);
00035 return exp(-tmp)/(sigman*sqrt(2*TMath::Pi()));
00036 }
00037
00038 double RollingGain::NIMmodel(double* xpar,double* par){
00039 double x = xpar[0];
00040 double norm = par[0];
00041 double q0 = par[1];
00042 double sigma0 = par[2];
00043 double q1 = par[3];
00044 double sigma1 = par[4];
00045 double w = par[5];
00046 double a = par[6];
00047 double u = par[7];
00048 int nmin = 1;
00049 int nmax = 6;
00050
00051 double total = 0;
00052 for(int i=nmin; i<nmax; i++){
00053 int n = i;
00054 double tmp = poisson(u,n);
00055 double tmp2 = gn(x,n,q0,sigma0,q1,sigma1);
00056 double qn = q0+n*q1;
00057 double sigman = sqrt(sigma0*sigma0+n*sigma1*sigma1);
00058
00059 double tmp3 = exp(-a*(x-qn-a*sigman*sigman/2.))*a/2.;
00060 double tmp4 = TMath::Erf(fabs(q0-qn-a*sigman*sigman)/(sigman*sqrt(2.)));
00061 double sign = 1.0;
00062 if((x-qn-sigman*sigman*a)<0) sign = -1.0;
00063 tmp4 += sign*TMath::Erf(fabs(x-qn-sigman*sigman*a)/(sigman*sqrt(2.)));
00064 tmp3 *= tmp4;
00065
00066 double result = tmp*((1-w)*tmp2+w*tmp3);
00067 total += result;
00068 }
00069 return total*norm;
00070 }
00071
00072 double RollingGain::Pedestal(double* xpar,double* par){
00073 double x = xpar[0];
00074 double norm = par[0];
00075 double q0 = par[1];
00076 double sigma0 = par[2];
00077 double w = par[3];
00078 double a = par[4];
00079
00080 double tmp = exp(-pow(x-q0,2)/(2*pow(sigma0,2)));
00081 double result = (1-w)*tmp/(sigma0*sqrt(2*TMath::Pi()));
00082 if(x>q0) result += w*a*exp(-a*(x-q0));
00083
00084 return result*norm;
00085 }
00086
00087 void RollingGain::Fit(){
00088 ostringstream tmp;
00089 tmp <<setw(2) <<setfill('0') << m_NStop;
00090 string filename = "pmtDataTable_"+tmp.str()+".txt";
00091 FILE* outfile = fopen(filename.c_str(), "w+");
00092
00093 fprintf(outfile, "# First Trigger time: (TrigSecond, TrigNanoSec) = (%d,%d).\n", m_FirstTrigSecond, m_FirstTrigNanoSec);
00094 fprintf(outfile, "# Last Trigger time: (TrigSecond, TrigNanoSec) = (%d,%d).\n", m_LastTrigSecond, m_LastTrigNanoSec);
00095 fprintf(outfile, "# [pmtID] [description] [status] [nhits] [fitStat] [chi2ndf] [speHigh] [gainErr] [sigmaSpe] [speLow] [timeOffset] [timeSpread] [efficiency] [prePulse] [afterPulse] [darkRate] [darkRateErr] [preAdc] [preAdcErr]\n");
00096
00097 m_rootfile->cd();
00098 string newdir = tmp.str();
00099 m_rootfile->mkdir(newdir.c_str());
00100 m_rootfile->cd(newdir.c_str());
00101
00102 m_masterfile = fopen("Master.pmtCalibMap.txt", "a");
00103 TimeStamp lastT1(m_LastTrigSecond,m_LastTrigNanoSec+1);
00104 fprintf(m_masterfile, "0000000 0000000 %4.0d %4.0d %10.0d %10.0d %10.0d %10.0d %s\n",
00105 m_site, m_simFlag, m_FirstTrigSecond,m_FirstTrigNanoSec,(int)lastT1.GetSec(),lastT1.GetNanoSec(),filename.c_str());
00106 fclose(m_masterfile);
00107
00108 m_StartTime = m_FirstTrigSecond + m_FirstTrigNanoSec*1e-9;
00109 m_EndTime = m_LastTrigSecond + m_LastTrigNanoSec*1e-9;
00110
00111 map<int,PmtProp>::iterator it,idend=m_PmtPropMap.end();
00112 for(it=m_PmtPropMap.begin(); it!=idend; it++) {
00113 PmtProp& curr = it->second;
00114
00115
00116 double tlength = m_NTrigger*100*1.5625*1e-9;
00117 curr.DarkRateErr = sqrt(curr.DarkRate)/tlength;
00118 curr.DarkRate = curr.DarkRate/tlength;
00119
00120 if( curr.h_PreAdc->GetEntries() == 0 ) {
00121
00122 curr.Status=PmtCalibData::kUnknown;
00123 } else if ( (curr.h_PreAdc->GetEntries() > 0 &&
00124 curr.h_PreAdc->GetEntries() < 100) ||
00125 (curr.h_Adc->GetEntries() > 0 &&
00126 curr.h_Adc->GetEntries() < 100) ) {
00127 curr.Status = PmtCalibData::kBadEfficiency;
00128 curr.NHits = curr.h_Adc->GetEntries();
00129 } else {
00130
00131 ostringstream tmp3;
00132 tmp3<<setw(2)<<setfill('0')<< m_NStop;
00133 string histname = "PreAdc_"+curr.PmtLabel+"_"+tmp3.str();
00134 string histname2 = "Adc_"+curr.PmtLabel+"_"+tmp3.str();
00135
00136 double pedarea = curr.h_PreAdc->GetEntries();
00137 double pedmean = curr.h_PreAdc->GetMean();
00138 double pedsigm = curr.h_PreAdc->GetRMS();
00139 f1->SetParameters(pedarea,pedmean,pedsigm);
00140 f1->SetRange(pedmean-3*pedsigm,pedmean+3*pedsigm);
00141 int status1 = curr.h_PreAdc->Fit("f1","R");
00142
00143 double q0 = f1->GetParameter(1);
00144 double q0err = f1->GetParError(1);
00145 double sigma0 = f1->GetParameter(2);
00146
00147
00148 if(f1->GetChisquare()/f1->GetNDF()>10 || status1!=0){
00149 warning()<< "Batch "<<tmp3.str()<<" bad pedestal fit for PMT: "
00150 << curr.PmtLabel <<endreq;;
00151 q0 = curr.h_PreAdc->GetMean();
00152 q0err = 0;
00153 sigma0 = 1.9;
00154 curr.Status |= PmtCalibData::kBadPedestal;
00155 }
00156 curr.Pedestal = q0;
00157
00158
00159
00160
00161 q0 = 0;
00162 sigma0 = 0;
00163
00164 double AreaGuess, Q1MeanGuess, Q1SigmaGuess;
00165 AreaGuess = curr.h_Adc->GetEntries();
00166 Q1MeanGuess = curr.h_Adc->GetMean();
00167 Q1SigmaGuess = curr.h_Adc->GetRMS();
00168
00169 f2->SetParameters(AreaGuess*10, 0, 0, Q1MeanGuess, Q1SigmaGuess, 0.01, 0.03, 0.1);
00170 f2->SetParNames("N","Q_{0}","#sigma_{0}","Q_{1}","#sigma_{1}","w","#alpha","#mu");
00171
00172 f2->FixParameter(1,q0);
00173 f2->FixParameter(2,sigma0);
00174 f2->FixParameter(5,0.);
00175 f2->FixParameter(6,0.);
00176
00177
00178
00179 f2->SetRange(q0+sigma0, q0+Q1MeanGuess+5*Q1SigmaGuess);
00180 int status2 = curr.h_Adc->Fit("f2","R");
00181
00182 double q1 = f2->GetParameter(3);
00183 double sigma1 = f2->GetParameter(4);
00184 double q1err = f2->GetParError(3);
00185 double sigma1err = f2->GetParError(4);
00186 double avechi2 = f2->GetChisquare()/f2->GetNDF();
00187 if(sigma1<0) sigma1 = -sigma1;
00188 if( status2!=0 || avechi2>10 || q1<10 || q1>80){
00189 warning()<<"Batch "<<tmp3.str()<<" bad gain fit for PMT: "<<
00190 curr.PmtLabel<<", try a simple Gaussian fit." <<endreq;
00191
00192 double adcmean = curr.h_Adc->GetMean();
00193 f1->SetParameters(AreaGuess,adcmean,7.);
00194 f1->SetRange(adcmean-10, adcmean+12);
00195 status2 = curr.h_Adc->Fit("f1","R");
00196
00197 q1 = f1->GetParameter(1)-q0;
00198 sigma1 = f1->GetParameter(2);
00199 q1err = f1->GetParError(1);
00200 sigma1err = f1->GetParError(2);
00201 avechi2 = f1->GetChisquare()/f1->GetNDF();
00202 if(status2!=0 || avechi2>10 || q1<10 || q1>80){
00203 warning()<< "Batch "<<tmp3.str()<<" gaussian fit for PMT: "
00204 << curr.PmtLabel
00205 << " is not good either. Set the gain to 0." <<endreq;
00206 q1 = 0; sigma1 = 0; q1err = 0; sigma1err = 0;
00207 }
00208 }
00209
00210
00211 curr.PedestalErr = q0err;
00212 curr.Gain = q1;
00213 curr.Sigma = sigma1;
00214 curr.GainErr = q1err;
00215 curr.SigmaErr = sigma1err;
00216 curr.NHits = AreaGuess;
00217 curr.FitStatus = status2;
00218 curr.Chi2 = avechi2;
00219 if( curr.FitStatus!=0 || curr.Chi2>10 || curr.Gain<10 || curr.Gain>80 ) {
00220 curr.Status |= PmtCalibData::kBadGain;
00221 }
00222 if( curr.Sigma/curr.Gain > 1 ) {
00223 curr.Status |= PmtCalibData::kBadGainWidth;
00224 }
00225 if( curr.Status == PmtCalibData::kUnknown) {
00226 curr.Status = PmtCalibData::kGood;
00227 }
00228 }
00229
00231
00232 if(curr.h_Adc->GetEntries()>0){
00233 fprintf(outfile, "%d %s %2d %6d %2d %6.2f %8.3f %8.3f %7.3f %.1f %.1f %.1f %.1f %.1f %.1f %9.1f %9.1f %8.3f %8.3f\n",
00234 curr.PmtId, curr.PmtLabel.c_str(), curr.Status, curr.NHits, curr.FitStatus,
00235 curr.Chi2, curr.Gain, curr.GainErr, curr.Sigma, curr.Gain/19 ,0.,0.,0.,0.,0.,curr.DarkRate, curr.DarkRateErr, curr.Pedestal, curr.PedestalErr);
00236
00237 curr.h_PreAdc->Write();
00238 curr.h_Adc->Write();
00239 curr.h_Tdc->Write();
00240 }
00241 }
00242
00243
00244 fclose(outfile);
00245 }
00246
00247 int RollingGain::InitPmtProp(const ServiceMode& svc)
00248 {
00249
00250 const vector<AdPmtSensor>& adPmts = m_cableSvc->adPmtSensors(svc);
00251 const vector<PoolPmtSensor>& poolPmts = m_cableSvc->poolPmtSensors(svc);
00252
00253 PmtProp defPmtProp;
00254 defPmtProp.h_Adc=0;
00255 defPmtProp.h_Tdc=0;
00256 defPmtProp.h_PreAdc=0;
00257 defPmtProp.Pedestal=0;
00258 defPmtProp.PedestalErr=0;
00259 defPmtProp.DarkRate=0;
00260 defPmtProp.DarkRateErr=0;
00261 defPmtProp.Gain=0;
00262 defPmtProp.GainErr=0;
00263 defPmtProp.Sigma=0;
00264 defPmtProp.SigmaErr=0;
00265 defPmtProp.Status=PmtCalibData::kUnknown;
00266 defPmtProp.NHits=0;
00267 defPmtProp.FitStatus=-1;
00268 defPmtProp.Chi2=-1;
00269 defPmtProp.PmtLabel="";
00270 defPmtProp.PmtId=0;
00271
00272 m_PmtPropMap.clear();
00273
00274 for( unsigned int ct=0; ct<adPmts.size(); ct++ ) {
00275 AdPmtSensor sensor = adPmts[ct];
00276 int id = sensor.fullPackedData();
00277 m_PmtPropMap[id] = defPmtProp;
00278
00279 ostringstream sring, scolumn;
00280 sring<<setw(2)<<setfill('0')<<sensor.ring();
00281 scolumn<<setw(2)<<setfill('0')<<sensor.column();
00282 string label = sensor.detName()+"_R"+sring.str()+"_C"+scolumn.str();
00283
00284 string hname = "h_Adc_"+label;
00285 string hname2 = "h_PreAdc_"+label;
00286 string hname3 = "h_Tdc_"+label;
00287 m_PmtPropMap[id].h_Adc = new TH1F(hname.c_str(),hname.c_str(),350,-50,300);
00288 m_PmtPropMap[id].h_PreAdc = new TH1F(hname2.c_str(),hname2.c_str(),350,-50,300);
00289 m_PmtPropMap[id].h_Tdc = new TH1F(hname3.c_str(),hname3.c_str(),400,400,1200);
00290 m_PmtPropMap[id].PmtLabel=label;
00291 m_PmtPropMap[id].PmtId=id;
00292 }
00293
00294 for( unsigned int ct=0; ct<poolPmts.size(); ct++ ) {
00295 PoolPmtSensor sensor = poolPmts[ct];
00296 int id = sensor.fullPackedData();
00297 m_PmtPropMap[id] = defPmtProp;
00298
00299 ostringstream swall, sspot,sfacing;
00300 swall<<setw(2)<<setfill('0')<<sensor.wallNumber();
00301 sspot<<setw(2)<<setfill('0')<<sensor.wallSpot();
00302 sfacing<<setw(2)<<setfill('0')<<sensor.inwardFacing();
00303 string label = sensor.detName()+"_W"+swall.str()+"_S"+sspot.str()+"_F"+sfacing.str();
00304
00305 string hname = "h_Adc_"+label;
00306 string hname2 = "h_PreAdc_"+label;
00307 string hname3 = "h_Tdc_"+label;
00308 m_PmtPropMap[id].h_Adc = new TH1F(hname.c_str(),hname.c_str(),350,-50,300);
00309 m_PmtPropMap[id].h_PreAdc = new TH1F(hname2.c_str(),hname2.c_str(),350,-50,300);
00310 m_PmtPropMap[id].h_Tdc = new TH1F(hname3.c_str(),hname3.c_str(),400,400,1200);
00311 m_PmtPropMap[id].PmtLabel=label;
00312 m_PmtPropMap[id].PmtId=id;
00313 }
00314
00315
00316
00317
00318
00319
00320 ResetPmtProp();
00321
00322 m_NStop = 1;
00323 m_startrun = -1;
00324 m_currentrun = -1;
00325
00326 return 1;
00327 }
00328
00329 int RollingGain::ResetPmtProp()
00330 {
00331 map<int,PmtProp>::iterator it,idend=m_PmtPropMap.end();
00332 for(it=m_PmtPropMap.begin(); it!=idend; it++) {
00333 PmtProp& curr = it->second;
00334 curr.h_Adc->Reset();
00335 curr.h_PreAdc->Reset();
00336 curr.h_Tdc->Reset();
00337 curr.Pedestal=0;
00338 curr.PedestalErr=0;
00339 curr.DarkRate=0;
00340 curr.DarkRateErr=0;
00341 curr.Gain=0;
00342 curr.GainErr=0;
00343 curr.Sigma=0;
00344 curr.SigmaErr=0;
00345 curr.Status=PmtCalibData::kUnknown;
00346 curr.NHits=0;
00347 curr.FitStatus=-1;
00348 curr.Chi2=-1;
00349 }
00350
00351 m_NTrigger = 0;
00352 m_startrun = -1;
00353
00354 return 1;
00355 }
00356
00357 StatusCode RollingGain::initialize()
00358 {
00359 StatusCode sc;
00360 sc = this->GaudiAlgorithm::initialize();
00361 if( sc.isFailure() ) {
00362 error() << "Base class initialization error" << endreq;
00363 return sc;
00364 }
00365
00367 sc = service("RunDataSvc",m_runDataSvc);
00368 if( sc.isFailure() ) {
00369 error() << "Can't get RunDataSvc" << endreq;
00370 return sc;
00371 }
00372
00374 sc = service("StaticCableSvc",m_cableSvc);
00375 if( sc.isFailure() ) {
00376 error() << "Can't get StaticCableSvc" << endreq;
00377 return sc;
00378 }
00379
00380 f1 = new TF1("f1","gaus",20,250);
00381
00382 f2 = new TF1("f2",NIMmodel,20,300,8);
00383
00384 m_rootfile = new TFile(m_fileName.c_str(),"recreate");
00385
00386
00387
00388 m_masterfile = fopen("Master.pmtCalibMap.txt", "a");
00389 fprintf(m_masterfile, "# [StartRun] [EndRun] [Sites] [SimFlag] [StartTimeSec] [StartTimeNanoSec] [EndTimeSec] [EndTimeNanoSec] [map file]\n");
00390 fclose(m_masterfile);
00391
00392 return sc;
00393 }
00394
00395 StatusCode RollingGain::execute()
00396 {
00397 debug()<<"RollingGain executing ... "<<endreq;
00398
00399 StatusCode sc;
00400
00402
00403
00404
00405
00406
00407
00408
00409
00410
00412 ReadoutHeader* readoutHdr = get<ReadoutHeader>( ReadoutHeader::defaultLocation() );
00413 if(!readoutHdr) {
00414 error()<<"Failed to get readout header"<<endreq;
00415 return StatusCode::FAILURE;
00416 }
00417
00418 const DaqCrate* daqCrate = readoutHdr->daqCrate();
00419 if(!daqCrate) {
00420 error()<<"Failed to get daqCrate from header"<<endreq;
00421 return StatusCode::FAILURE;
00422 }
00423
00424 TimeStamp trigTime = daqCrate->triggerTime();
00425 m_currentTime = trigTime.GetSeconds();
00426
00427 static bool first = true;
00428 if( first ) {
00429 first = false;
00431 Context ctx = readoutHdr->context();
00432 m_site=ctx.GetSite();
00433 m_simFlag=ctx.GetSimFlag();
00434 ctx.SetSite(Site::kAll);
00435 ctx.SetDetId(DetectorId::kAll);
00436 ServiceMode svc(ctx,0);
00437
00438 InitPmtProp(svc);
00439
00440 m_prevTrigTime = trigTime.GetSeconds();
00441 m_lastFitTime = trigTime.GetSeconds();
00442 }
00443
00445 if( !(daqCrate->detector().isAD() ||
00446 daqCrate->detector().isWaterShield()) ) {
00447 return StatusCode::SUCCESS;
00448 }
00449
00450 const DaqPmtCrate* pmtCrate = daqCrate->asPmtCrate();
00451 if (!pmtCrate) {
00452 error()<<"Failed to get DaqPmtCrate"<<endreq;
00453 return StatusCode::FAILURE;
00454 }
00455 m_NTrigger++;
00456
00457
00458
00459 m_LastTrigSecond = trigTime.GetSec();
00460 m_LastTrigNanoSec = trigTime.GetNanoSec();
00461 if(m_NTrigger==1){
00462 m_FirstTrigSecond = trigTime.GetSec();
00463 m_FirstTrigNanoSec = trigTime.GetNanoSec();
00464 }
00465
00466 Detector det = pmtCrate->detector();
00467 ServiceMode svcMode( readoutHdr->context(),0 );
00468
00469
00471
00472
00473
00475 const DaqPmtCrate::PmtChannelPtrList& channels = pmtCrate->pmtChannelReadouts();
00476 DaqPmtCrate::PmtChannelPtrList::const_iterator ci, ci_end = channels.end();
00477
00478 for(ci = channels.begin(); ci!=ci_end; ci++) {
00479 const DaqPmtChannel* channel = *ci;
00480 FeeChannelId channelId = channel->channelId();
00481
00482
00483 unsigned int multi = channel->hitCount();
00484
00485 AdPmtSensor pmtId = m_cableSvc->adPmtSensor( channelId, svcMode );
00486 int id = pmtId.fullPackedData();
00487 PmtProp& curPmt = m_PmtPropMap[id];
00488
00489 for(unsigned int nr = 0; nr<multi; ++nr) {
00490 int tdc = channel->tdc(nr);
00491 int adc = channel->adc(nr);
00492 float preAdc = channel->preAdcAvg(nr);
00493 int gain = channel->isHighGainAdc(nr);
00494
00495 curPmt.h_Tdc->Fill(tdc);
00496
00497 if(tdc>1070 && tdc<1170){
00498 curPmt.DarkRate++;
00499 }
00500
00501 if( multi==1 &&
00502 tdc>1070 &&
00503 gain==FeeGain::kHigh &&
00504 m_currentTime - m_prevTrigTime > 20e-6
00505 ) {
00506 if(m_Fix){
00507 int residue = (tdc-15)%16;
00508 if(residue>4){
00509 curPmt.h_Adc->Fill(adc-preAdc);
00510 curPmt.h_PreAdc->Fill(preAdc);
00511 }
00512 }
00513 else{
00514 curPmt.h_Adc->Fill(adc-preAdc);
00515 curPmt.h_PreAdc->Fill(preAdc);
00516 }
00517 }
00518 }
00519 }
00520
00521
00522
00523 if(m_currentTime - m_lastFitTime > m_fitPeriod) {
00524
00525 Fit();
00526
00527 ResetPmtProp();
00528 m_NStop++;
00529 m_lastFitTime = m_currentTime;
00530 }
00531
00532 m_prevTrigTime = m_currentTime;
00533
00534 return StatusCode::SUCCESS;
00535 }
00536
00537 StatusCode RollingGain::finalize()
00538 {
00539
00540 Fit();
00541
00542 map<int,PmtProp>::iterator it,idend=m_PmtPropMap.end();
00543 for(it=m_PmtPropMap.begin(); it!=idend; it++) {
00544 PmtProp& curr = it->second;
00545 delete curr.h_Adc;
00546 delete curr.h_PreAdc;
00547 delete curr.h_Tdc;
00548 }
00549
00550 m_rootfile->Write();
00551 m_rootfile->Close();
00552
00553 delete f1;
00554 delete f2;
00555
00556 delete m_rootfile;
00557
00558 StatusCode sc;
00559 sc = this->GaudiAlgorithm::finalize();
00560 return sc;
00561 }
00562
00563