12 #include <top/modules/TOPGainEfficiencyMonitor/TOPGainEfficiencyCalculatorModule.h>
52 setDescription(
"Calculate pixel gain and efficiency for a given PMT from 2D histogram of hit timing and pulse charge, "
53 "created by TOPLaserHitSelectorModule.");
56 addParam(
"inputFile", m_inputFile,
"input file name containing 2D histogram", std::string(
""));
57 addParam(
"outputPDFFile", m_outputPDFFile,
"output PDF file to store plots", std::string(
""));
58 addParam(
"targetSlotId", m_targetSlotId,
"TOP module ID in slot number (1-16)", (
short)0);
59 addParam(
"targetPmtId", m_targetPmtId,
"PMT number (1-32)", (
short)0);
60 addParam(
"targetPmtChId", m_targetPmtChId,
"PMT channel number (1-16)", (
short) - 1);
61 addParam(
"hvDiff", m_hvDiff,
"HV difference from nominal HV value", (
short)0);
62 addParam(
"fitHalfWidth", m_fitHalfWidth,
"half fit width for direct laser hit peak in [ns] unit", (
float)1.0);
64 "pulse height (or integrated charge) threshold in fitting its distribution and calculating efficiency", (
float)100.);
65 addParam(
"p0HeightIntegral", m_p0HeightIntegral,
66 "Parameter from p0 + x*p1 function fitting height-integral distribtion.", (
float) - 50.0);
67 addParam(
"p1HeightIntegral", m_p1HeightIntegral,
68 "Parameter from p0 + x*p1 function fitting height-integral distribtion.", (
float)6.0);
69 addParam(
"fracFit", m_fracFit,
"fraction of events to be used in fitting. "
70 "An upper limit of a fit range is given to cover this fraction of events. "
71 "Set negative value to calculate the fraction to exclude only 10 events in tail.", (
float)(-1));
72 addParam(
"initialP0", m_initialP0,
"initial value of the fit parameter p0 divided by histogram entries."
73 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(0.0001));
74 addParam(
"initialP1", m_initialP1,
"initial value of the fit parameter p1."
75 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(1.0));
76 addParam(
"initialP2", m_initialP2,
"initial value of the fit parameter p2."
77 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(1.0));
78 addParam(
"initialX0", m_initialX0,
"initial value of the fit parameter x0 divided by histogram bin width."
79 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(100));
80 addParam(
"pedestalSigma", m_pedestalSigma,
"sigma of pedestal width", (
float)10.);
81 addParam(
"fitoption", m_fitoption,
"fit option likelihood: default chisquare: R", std::string(
"L"));
94 m_tree =
new TTree(
"tree",
"TTree for gain/efficiency monitor summary");
153 "funcFullRangeIntegralUseIntegral/F"));
155 "funcFitRangeIntegralUseIntegral/F"));
157 "histoFitRangeIntegralUseIntegral/F"));
178 bool areGoodParameters =
true;
179 if (m_targetSlotId < 1 || m_targetSlotId > c_NModule) {
180 B2ERROR(
"TOPGainEfficiencyCalculator : invalid slotID : " <<
m_targetSlotId);
181 areGoodParameters =
false;
183 if (m_targetPmtId < 1 || m_targetPmtId > c_NPMTPerModule) {
184 B2ERROR(
"TOPGainEfficiencyCalculator : invalid PMT ID : " <<
m_targetPmtId);
185 areGoodParameters =
false;
188 B2ERROR(
"TOPGainEfficiencyCalculator : pedestal sigma must be non-zero positive value");
189 areGoodParameters =
false;
193 if (areGoodParameters) {
204 DrawResult(
"Height_gain", c_LoadForFitHeight);
209 DrawResult(
"Height_efficiency", c_LoadHitRateHeight);
214 DrawResult(
"Integral_gain", c_LoadForFitIntegral);
225 B2ERROR(
"TOPGainEfficiencyCalculator : fail to open input file \"" <<
m_inputFile <<
"\"");
229 for (
int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
231 std::ostringstream pixelstr;
232 pixelstr << histotype <<
"_"
233 <<
"s" << std::setw(2) << std::setfill(
'0') <<
m_targetSlotId <<
"_PMT"
235 <<
"_" << std::setw(2) << std::setfill(
'0') << (iHisto + 1);
236 std::ostringstream hname;
237 hname <<
"hTime" << pixelstr.str();
245 std::ostringstream hnameProj[2];
246 hnameProj[0] <<
"hTime_" << pixelstr.str();
247 hnameProj[1] <<
"hCharge_" << pixelstr.str();
248 TH1D* hTime = (TH1D*)h2D->ProjectionX(hnameProj[0].str().c_str());
254 TF1* funcLaser =
new TF1(std::string(std::string(
"func_") + hnameProj[1].str()).c_str(),
255 "gaus(0)", fitMin, fitMax);
256 funcLaser->SetParameters(hTime->GetBinContent(hTime->GetXaxis()->FindBin(peakTime)), peakTime,
m_fitHalfWidth);
257 funcLaser->SetParLimits(1, fitMin, fitMax);
258 hTime->Fit(funcLaser,
"Q",
"", fitMin, fitMax);
266 TH1D* hCharge = (TH1D*)h2D->ProjectionY(hnameProj[1].str().c_str(),
267 binNumMin, binNumMax);
273 B2WARNING(
"TOPGainEfficiencyCalculator : no histogram for the number of events with calibration pulses identified in the given input file");
281 int globalAsicId = 0;
282 if (LoadHisto == c_LoadForFitIntegral || LoadHisto == c_LoadHitRateIntegral) threshold =
m_thresholdForIntegral;
284 for (
int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
288 + ((
m_targetPmtId - 1) / c_NPMTPerRow) * c_NPixelPerModule / 2
289 + (iHisto / c_NChannelPerPMTRow) * c_NPixelPerRow + (iHisto % c_NChannelPerPMTRow) + 1;
292 if (LoadHisto == c_LoadForFitHeight) {
301 std::cout <<
" ***** fitting charge distribution for " << hCharge->GetName() <<
" *****" << std::endl;
302 int nBins = hCharge->GetXaxis()->GetNbins();
303 double binWidth = hCharge->GetXaxis()->GetBinUpEdge(1) - hCharge->GetXaxis()->GetBinLowEdge(1);
304 double histoMax = hCharge->GetXaxis()->GetBinUpEdge(nBins);
306 double wholeIntegral = hCharge->Integral(0, hCharge->GetXaxis()->GetNbins() + 1);
308 while (hCharge->Integral(0, hCharge->GetXaxis()->FindBin(
m_fitMax - 0.01 * binWidth)) / wholeIntegral < fitRangeFraction)
310 if (
m_fitMax < threshold + c_NParameterGainFit * binWidth) {
311 B2WARNING(
"TOPGainEfficiencyCalculator : no enough entries for fitting at slot"
313 << std::setw(2) << std::setfill(
'0') <<
m_targetPmtId <<
", Ch"
314 << std::setw(2) << std::setfill(
'0') <<
m_pmtChId);
318 std::ostringstream fname;
319 fname <<
"func_" << (iHisto + 1);
320 TObject*
object = gROOT->FindObject(fname.str().c_str());
321 if (
object)
delete object;
322 TF1* func =
new TF1(fname.str().c_str(),
TOPGainFunc, threshold,
m_fitMax, c_NParameterGainFit);
323 double initGain = TMath::Max(hCharge->GetMean(), 26.1) - 25;
324 double initP1 = TMath::Min(4.0, TMath::Max(10000.*TMath::Power(initGain - 25, -2), 0.01));
325 double initP2 = TMath::Min(0.8 + 0.005 * TMath::Power(initP1, -3), 4.);
326 double initX0 = TMath::Max(initGain * 2 - 150, 10.);
328 double initP1overP2 = initP1 / initP2;
329 double initP0 = hCharge->GetBinContent(hCharge->GetMaximumBin())
330 / (TMath::Power(initP1overP2, initP1overP2) * TMath::Exp(-initP1overP2)) / binWidth;
332 else if (LoadHisto == c_LoadForFitHeight)
333 func->SetParameter(3, 150 + 0.5 * hCharge->GetMean());
334 else if (LoadHisto == c_LoadForFitIntegral)
335 func->SetParameter(3, 1000 + 0.5 * hCharge->GetMean());
341 else func->SetParameter(0,
m_initialP0 * hCharge->GetEntries()*binWidth);
343 func->FixParameter(4, 0);
345 func->SetParName(0,
"#it{p}_{0}");
346 func->SetParName(1,
"#it{p}_{1}");
347 func->SetParName(2,
"#it{p}_{2}");
348 func->SetParName(3,
"#it{x}_{0}");
349 func->SetParName(4,
"pedestal");
350 func->SetParName(5,
"pedestal #sigma");
351 func->SetParLimits(0, 1e-8, 1e8);
352 func->SetParLimits(1, 1e-8, 10);
353 func->SetParLimits(2, 1e-8, 10);
354 func->SetParLimits(3, 1e-8, 1e8);
355 func->SetLineColor(2);
356 func->SetLineWidth(1);
357 TF1* funcFull = NULL;
358 if (LoadHisto == c_LoadForFitHeight or LoadHisto == c_LoadForFitIntegral) {
363 double funcFullMax = histoMax * 2;
364 funcFull =
new TF1((fname.str() +
"_full").c_str(),
TOPGainFunc, (-1)*func->GetParameter(5), funcFullMax, c_NParameterGainFit);
365 for (
int iPar = 0 ; iPar < c_NParameterGainFit ; iPar++)
366 funcFull->SetParameter(iPar, func->GetParameter(iPar));
367 funcFull->SetLineColor(3);
368 funcFull->SetLineWidth(2);
370 double totalWeight = 0;
371 double weightedIntegral = 0;
372 double x = (-1) * func->GetParameter(5);
373 while (x < funcFullMax) {
374 double funcVal = funcFull->Eval(x);
375 totalWeight += funcVal;
376 weightedIntegral += funcVal * x;
381 m_gain = weightedIntegral / totalWeight;
382 m_efficiency = funcFull->Integral(threshold, funcFullMax) / funcFull->Integral((-1) * func->GetParameter(5), funcFullMax);
383 m_p0 = func->GetParameter(0);
384 m_p1 = func->GetParameter(1);
385 m_p2 = func->GetParameter(2);
386 m_x0 = func->GetParameter(3);
392 m_ndf = func->GetNDF();
395 }
else std::cout <<
"*****fitting is skipped***** " << std::endl;
396 int threBin = hCharge->GetXaxis()->FindBin(threshold + 0.01 * binWidth);
397 int fitMaxBin = hCharge->GetXaxis()->FindBin(
m_fitMax - 0.01 * binWidth);
401 for (
int iBin = threBin ; iBin < nBins + 1 ; iBin++) {
402 m_histoMeanAboveThre += (hCharge->GetBinContent(iBin) * hCharge->GetXaxis()->GetBinCenter(iBin));
422 for (
auto itr =
m_branch[LoadHisto].begin(); itr !=
m_branch[LoadHisto].end(); ++itr) {
426 std::cout << std::endl;
429 else m_tree->SetEntries(1);
461 for (
auto itr =
m_branch[LoadHisto].begin(); itr !=
m_branch[LoadHisto].end(); ++itr) {
469 std::ostringstream pdfFilename;
472 pdfFilename <<
"_" <<
"ch" << std::setw(2) << std::setfill(
'0') <<
m_targetPmtChId;
473 pdfFilename <<
".pdf";
475 gStyle->SetFrameFillStyle(0);
476 gStyle->SetFillStyle(0);
477 gStyle->SetStatStyle(0);
478 gStyle->SetOptStat(112210);
479 gStyle->SetOptFit(1110);
480 TCanvas* canvas =
new TCanvas();
481 canvas->SetFillStyle(0);
482 canvas->Print((pdfFilename.str() +
"[").c_str());
484 TLine* line =
new TLine();
485 line->SetLineWidth(1);
486 line->SetLineStyle(1);
487 line->SetLineColor(4);
488 TArrow* arrow =
new TArrow();
489 arrow->SetLineWidth(1);
490 arrow->SetLineStyle(1);
491 arrow->SetLineColor(3);
492 TLatex* latex =
new TLatex();
494 latex->SetTextFont(22);
495 latex->SetTextSize(0.05);
496 latex->SetTextAlign(32);
503 for (
int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
505 if ((iHisto % c_NChannelPerPage) == 0) {
507 canvas->Divide(c_NPlotsPerChannel, c_NChannelPerPage);
511 canvas->cd(3 * (iHisto % c_NChannelPerPage) + 1);
512 gPad->SetFrameFillStyle(0);
513 gPad->SetFillStyle(0);
517 h2D->GetXaxis()->SetTitle(
"hit timing [ns]");
518 h2D->GetYaxis()->SetTitle(
"pulse charge [ADC count]");
522 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + 2);
523 gPad->SetFrameFillStyle(0);
524 gPad->SetFillStyle(0);
529 hTime->SetLineColor(1);
530 hTime->GetXaxis()->SetTitle(
"hit timing [ns]");
531 float binWidth = hTime->GetXaxis()->GetBinUpEdge(1) - hTime->GetXaxis()->GetBinLowEdge(1);
532 std::ostringstream ytitle;
533 ytitle <<
"Entries [/(" << binWidth <<
" ns)]";
534 hTime->GetYaxis()->SetTitle(ytitle.str().c_str());
538 double charge = funcLaser->GetParameter(0);
539 double peakTime = funcLaser->GetParameter(1);
540 float xMin = hTime->GetXaxis()->GetBinLowEdge(hTime->GetXaxis()->FindBin(peakTime - 2 *
m_fitHalfWidth));
541 float xMax = hTime->GetXaxis()->GetBinUpEdge(hTime->GetXaxis()->FindBin(peakTime + 2 *
m_fitHalfWidth));
542 line->DrawLine(xMin, 0.5, xMin, charge * 2.);
543 line->DrawLine(xMax, 0.5, xMax, charge * 2.);
544 arrow->DrawArrow(xMin, charge * 1.5, xMax, charge * 1.5, 0.01,
"<>");
549 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + 3);
550 gPad->SetFrameFillStyle(0);
551 gPad->SetFillStyle(0);
556 hCharge->SetLineColor(1);
557 hCharge->GetXaxis()->SetTitle(
"charge [ADC counts]");
558 float binWidth = hCharge->GetXaxis()->GetBinUpEdge(1) - hCharge->GetXaxis()->GetBinLowEdge(1);
559 std::ostringstream ytitle;
560 ytitle <<
"Entries [/(" << binWidth <<
" ADC counts)]";
561 hCharge->GetYaxis()->SetTitle(ytitle.str().c_str());
566 double charge = hCharge->GetBinContent(hCharge->GetMaximumBin());
567 line->DrawLine(threshold, 0.5, threshold, charge * 2.);
569 if ((
object = gROOT->FindObject(
"dummy")))
delete object;
570 std::ostringstream cut;
571 cut <<
"pmtChId==" << (iHisto + 1);
573 std::ostringstream summarystr[2];
574 if (LoadHisto == c_LoadForFitHeight) {
575 nEntries =
m_tree->Project(
"dummy",
"gain:efficiency", cut.str().c_str());
577 summarystr[0] <<
"gain = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
579 latex->DrawLatex(0.875, 0.34, summarystr[0].str().c_str());
580 summarystr[1] <<
"efficiency = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
581 << (
m_tree->GetV2()[0] * 100) <<
" %";
582 latex->DrawLatex(0.875, 0.29, summarystr[1].str().c_str());
584 }
else if (LoadHisto == c_LoadForFitIntegral) {
585 nEntries =
m_tree->Project(
"dummy",
"gainUseIntegral:efficiencyUseIntegral", cut.str().c_str());
587 summarystr[0] <<
"gain = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
589 latex->DrawLatex(0.875, 0.34, summarystr[0].str().c_str());
590 summarystr[1] <<
"efficiency = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
591 << (
m_tree->GetV2()[0] * 100) <<
" %";
592 latex->DrawLatex(0.875, 0.29, summarystr[1].str().c_str());
597 B2WARNING(
"TOPGainEfficiencyCalculator : mutliple entries with the same channel ID ("
598 <<
m_pmtChId <<
") in the output TTree");
603 if (((iHisto + 1) % c_NChannelPerPage) == 0)
604 canvas->Print(pdfFilename.str().c_str());
606 for (
int iHisto = (c_NChannelPerPMT - 1) % c_NChannelPerPage + 1 ; iHisto < c_NChannelPerPage ; iHisto++) {
607 for (
int iPad = 0 ; iPad < c_NPlotsPerChannel ; iPad++) {
608 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + iPad + 1);
609 gPad->SetFrameFillStyle(0);
610 gPad->SetFillStyle(0);
612 if (((iHisto + 1) % c_NChannelPerPage) == 0)
613 canvas->Print(pdfFilename.str().c_str());
616 canvas->Print((pdfFilename.str() +
"]").c_str());
622 if ((
object = gROOT->FindObject(
"dummy")))
delete object;
630 double pedestal = par[4];
631 double pedestalWidth = par[5];
632 double x = (var[0] - pedestal);
635 double step = pedestalWidth / 100.;
636 double t = TMath::Max(step, x - pedestalWidth * 10);
638 while (t < x + pedestalWidth * 10) {
639 output += TMath::Gaus(x, t, pedestalWidth) * TMath::Power(t / par[3], par[1])
640 * TMath::Exp((-1) * TMath::Power(t / par[3], par[2]));
645 return par[0] * output * step;
650 double histo_xmax = histo->GetXaxis()->GetBinUpEdge(histo->GetXaxis()->GetNbins() - 1);
651 if (xmax > histo_xmax) xmax = histo_xmax;
654 double peakPos = histo->GetXaxis()->GetBinCenter(iBin);
655 double peakCharge = histo->GetBinContent(iBin);
658 double x = histo->GetXaxis()->GetBinCenter(iBin);
661 double binEntry = histo->GetBinContent(iBin);
662 if (binEntry > peakCharge) {
664 peakCharge = binEntry;