10#include <top/modules/TOPGainEfficiencyMonitor/TOPGainEfficiencyCalculatorModule.h>
50 setDescription(
"Calculate pixel gain and efficiency for a given PMT from 2D histogram of hit timing and pulse charge, "
51 "created by TOPLaserHitSelectorModule.");
54 addParam(
"inputFile",
m_inputFile,
"input file name containing 2D histogram", std::string(
""));
59 addParam(
"hvDiff",
m_hvDiff,
"HV difference from nominal HV value", (
short)0);
60 addParam(
"fitHalfWidth",
m_fitHalfWidth,
"half fit width for direct laser hit peak in [ns] unit", (
float)1.0);
62 "pulse height (or integrated charge) threshold in fitting its distribution and calculating efficiency", (
float)100.);
64 "Parameter from p0 + x*p1 function fitting height-integral distribtion.", (
float) - 50.0);
66 "Parameter from p0 + x*p1 function fitting height-integral distribtion.", (
float)6.0);
68 "An upper limit of a fit range is given to cover this fraction of events. "
69 "Set negative value to calculate the fraction to exclude only 10 events in tail.", (
float)(-1));
70 addParam(
"initialP0",
m_initialP0,
"initial value of the fit parameter p0 divided by histogram entries."
71 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(0.0001));
73 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(1.0));
75 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(1.0));
76 addParam(
"initialX0",
m_initialX0,
"initial value of the fit parameter x0 divided by histogram bin width."
77 "Set negative value to calculate from histogram inforamtion automatically.", (
float)(100));
79 addParam(
"fitoption",
m_fitoption,
"fit option likelihood: default chisquare: R", std::string(
"L"));
92 m_tree =
new TTree(
"tree",
"TTree for gain/efficiency monitor summary");
151 "funcFullRangeIntegralUseIntegral/F"));
153 "funcFitRangeIntegralUseIntegral/F"));
155 "histoFitRangeIntegralUseIntegral/F"));
176 bool areGoodParameters =
true;
177 if (m_targetSlotId < 1 || m_targetSlotId > c_NModule) {
178 B2ERROR(
"TOPGainEfficiencyCalculator : invalid slotID : " <<
m_targetSlotId);
179 areGoodParameters =
false;
181 if (m_targetPmtId < 1 || m_targetPmtId > c_NPMTPerModule) {
182 B2ERROR(
"TOPGainEfficiencyCalculator : invalid PMT ID : " <<
m_targetPmtId);
183 areGoodParameters =
false;
186 B2ERROR(
"TOPGainEfficiencyCalculator : pedestal sigma must be non-zero positive value");
187 areGoodParameters =
false;
191 if (areGoodParameters) {
202 DrawResult(
"Height_gain", c_LoadForFitHeight);
207 DrawResult(
"Height_efficiency", c_LoadHitRateHeight);
212 DrawResult(
"Integral_gain", c_LoadForFitIntegral);
223 B2ERROR(
"TOPGainEfficiencyCalculator : fail to open input file \"" <<
m_inputFile <<
"\"");
227 for (
int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
229 std::ostringstream pixelstr;
230 pixelstr << histotype <<
"_"
231 <<
"s" << std::setw(2) << std::setfill(
'0') <<
m_targetSlotId <<
"_PMT"
233 <<
"_" << std::setw(2) << std::setfill(
'0') << (iHisto + 1);
234 std::ostringstream hname;
235 hname <<
"hTime" << pixelstr.str();
243 std::ostringstream hnameProj[2];
244 hnameProj[0] <<
"hTime_" << pixelstr.str();
245 hnameProj[1] <<
"hCharge_" << pixelstr.str();
246 TH1D* hTime = (TH1D*)h2D->ProjectionX(hnameProj[0].str().c_str());
252 TF1* funcLaser =
new TF1(std::string(std::string(
"func_") + hnameProj[1].str()).c_str(),
253 "gaus(0)", fitMin, fitMax);
254 funcLaser->SetParameters(hTime->GetBinContent(hTime->GetXaxis()->FindBin(peakTime)), peakTime,
m_fitHalfWidth);
255 funcLaser->SetParLimits(1, fitMin, fitMax);
256 hTime->Fit(funcLaser,
"Q",
"", fitMin, fitMax);
264 TH1D* hCharge = (TH1D*)h2D->ProjectionY(hnameProj[1].str().c_str(),
265 binNumMin, binNumMax);
271 B2WARNING(
"TOPGainEfficiencyCalculator : no histogram for the number of events with calibration pulses identified in the given input file");
279 int globalAsicId = 0;
280 if (LoadHisto == c_LoadForFitIntegral || LoadHisto == c_LoadHitRateIntegral) threshold =
m_thresholdForIntegral;
282 for (
int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
286 + ((
m_targetPmtId - 1) / c_NPMTPerRow) * c_NPixelPerModule / 2
287 + (iHisto / c_NChannelPerPMTRow) * c_NPixelPerRow + (iHisto % c_NChannelPerPMTRow) + 1;
290 if (LoadHisto == c_LoadForFitHeight) {
299 std::cout <<
" ***** fitting charge distribution for " << hCharge->GetName() <<
" *****" << std::endl;
300 int nBins = hCharge->GetXaxis()->GetNbins();
301 double binWidth = hCharge->GetXaxis()->GetBinUpEdge(1) - hCharge->GetXaxis()->GetBinLowEdge(1);
302 double histoMax = hCharge->GetXaxis()->GetBinUpEdge(nBins);
304 double wholeIntegral = hCharge->Integral(0, hCharge->GetXaxis()->GetNbins() + 1);
306 while (hCharge->Integral(0, hCharge->GetXaxis()->FindBin(
m_fitMax - 0.01 * binWidth)) / wholeIntegral < fitRangeFraction)
308 if (
m_fitMax < threshold +
static_cast<double>(c_NParameterGainFit) * binWidth) {
309 B2WARNING(
"TOPGainEfficiencyCalculator : no enough entries for fitting at slot"
311 << std::setw(2) << std::setfill(
'0') <<
m_targetPmtId <<
", Ch"
312 << std::setw(2) << std::setfill(
'0') <<
m_pmtChId);
316 std::ostringstream fname;
317 fname <<
"func_" << (iHisto + 1);
318 TObject*
object = gROOT->FindObject(fname.str().c_str());
319 if (
object)
delete object;
320 TF1* func =
new TF1(fname.str().c_str(),
TOPGainFunc, threshold,
m_fitMax, c_NParameterGainFit);
321 double initGain = TMath::Max(hCharge->GetMean(), 26.1) - 25;
322 double initP1 = TMath::Min(4.0, TMath::Max(10000.*TMath::Power(initGain - 25, -2), 0.01));
323 double initP2 = TMath::Min(0.8 + 0.005 * TMath::Power(initP1, -3), 4.);
324 double initX0 = TMath::Max(initGain * 2 - 150, 10.);
326 double initP1overP2 = initP1 / initP2;
327 double initP0 = hCharge->GetBinContent(hCharge->GetMaximumBin())
328 / (TMath::Power(initP1overP2, initP1overP2) * TMath::Exp(-initP1overP2)) / binWidth;
330 else if (LoadHisto == c_LoadForFitHeight)
331 func->SetParameter(3, 150 + 0.5 * hCharge->GetMean());
332 else if (LoadHisto == c_LoadForFitIntegral)
333 func->SetParameter(3, 1000 + 0.5 * hCharge->GetMean());
339 else func->SetParameter(0,
m_initialP0 * hCharge->GetEntries()*binWidth);
341 func->FixParameter(4, 0);
343 func->SetParName(0,
"#it{p}_{0}");
344 func->SetParName(1,
"#it{p}_{1}");
345 func->SetParName(2,
"#it{p}_{2}");
346 func->SetParName(3,
"#it{x}_{0}");
347 func->SetParName(4,
"pedestal");
348 func->SetParName(5,
"pedestal #sigma");
349 func->SetParLimits(0, 1e-8, 1e8);
350 func->SetParLimits(1, 1e-8, 10);
351 func->SetParLimits(2, 1e-8, 10);
352 func->SetParLimits(3, 1e-8, 1e8);
353 func->SetLineColor(2);
354 func->SetLineWidth(1);
355 TF1* funcFull = NULL;
356 if (LoadHisto == c_LoadForFitHeight or LoadHisto == c_LoadForFitIntegral) {
361 double funcFullMax = histoMax * 2;
362 funcFull =
new TF1((fname.str() +
"_full").c_str(),
TOPGainFunc, (-1)*func->GetParameter(5), funcFullMax, c_NParameterGainFit);
363 for (
int iPar = 0 ; iPar < c_NParameterGainFit ; iPar++)
364 funcFull->SetParameter(iPar, func->GetParameter(iPar));
365 funcFull->SetLineColor(3);
366 funcFull->SetLineWidth(2);
368 double totalWeight = 0;
369 double weightedIntegral = 0;
370 double x = (-1) * func->GetParameter(5);
371 while (x < funcFullMax) {
372 double funcVal = funcFull->Eval(x);
373 totalWeight += funcVal;
374 weightedIntegral += funcVal * x;
379 m_gain = weightedIntegral / totalWeight;
380 m_efficiency = funcFull->Integral(threshold, funcFullMax) / funcFull->Integral((-1) * func->GetParameter(5), funcFullMax);
381 m_p0 = func->GetParameter(0);
382 m_p1 = func->GetParameter(1);
383 m_p2 = func->GetParameter(2);
384 m_x0 = func->GetParameter(3);
390 m_ndf = func->GetNDF();
393 }
else std::cout <<
"*****fitting is skipped***** " << std::endl;
394 int threBin = hCharge->GetXaxis()->FindBin(threshold + 0.01 * binWidth);
395 int fitMaxBin = hCharge->GetXaxis()->FindBin(
m_fitMax - 0.01 * binWidth);
399 for (
int iBin = threBin ; iBin < nBins + 1 ; iBin++) {
400 m_histoMeanAboveThre += (hCharge->GetBinContent(iBin) * hCharge->GetXaxis()->GetBinCenter(iBin));
420 for (
auto itr =
m_branch[LoadHisto].begin(); itr !=
m_branch[LoadHisto].end(); ++itr) {
424 std::cout << std::endl;
427 else m_tree->SetEntries(1);
459 for (
auto itr =
m_branch[LoadHisto].begin(); itr !=
m_branch[LoadHisto].end(); ++itr) {
467 std::ostringstream pdfFilename;
470 pdfFilename <<
"_" <<
"ch" << std::setw(2) << std::setfill(
'0') <<
m_targetPmtChId;
471 pdfFilename <<
".pdf";
473 gStyle->SetFrameFillStyle(0);
474 gStyle->SetFillStyle(0);
475 gStyle->SetStatStyle(0);
476 gStyle->SetOptStat(112210);
477 gStyle->SetOptFit(1110);
478 TCanvas* canvas =
new TCanvas();
479 canvas->SetFillStyle(0);
480 canvas->Print((pdfFilename.str() +
"[").c_str());
482 TLine* line =
new TLine();
483 line->SetLineWidth(1);
484 line->SetLineStyle(1);
485 line->SetLineColor(4);
486 TArrow* arrow =
new TArrow();
487 arrow->SetLineWidth(1);
488 arrow->SetLineStyle(1);
489 arrow->SetLineColor(3);
490 TLatex* latex =
new TLatex();
492 latex->SetTextFont(22);
493 latex->SetTextSize(0.05);
494 latex->SetTextAlign(32);
501 for (
int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
503 if ((iHisto % c_NChannelPerPage) == 0) {
505 canvas->Divide(c_NPlotsPerChannel, c_NChannelPerPage);
509 canvas->cd(3 * (iHisto % c_NChannelPerPage) + 1);
510 gPad->SetFrameFillStyle(0);
511 gPad->SetFillStyle(0);
515 h2D->GetXaxis()->SetTitle(
"hit timing [ns]");
516 h2D->GetYaxis()->SetTitle(
"pulse charge [ADC count]");
520 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + 2);
521 gPad->SetFrameFillStyle(0);
522 gPad->SetFillStyle(0);
527 hTime->SetLineColor(1);
528 hTime->GetXaxis()->SetTitle(
"hit timing [ns]");
529 float binWidth = hTime->GetXaxis()->GetBinUpEdge(1) - hTime->GetXaxis()->GetBinLowEdge(1);
530 std::ostringstream ytitle;
531 ytitle <<
"Entries [/(" << binWidth <<
" ns)]";
532 hTime->GetYaxis()->SetTitle(ytitle.str().c_str());
536 double charge = funcLaser->GetParameter(0);
537 double peakTime = funcLaser->GetParameter(1);
538 float xMin = hTime->GetXaxis()->GetBinLowEdge(hTime->GetXaxis()->FindBin(peakTime - 2 *
m_fitHalfWidth));
539 float xMax = hTime->GetXaxis()->GetBinUpEdge(hTime->GetXaxis()->FindBin(peakTime + 2 *
m_fitHalfWidth));
540 line->DrawLine(xMin, 0.5, xMin, charge * 2.);
541 line->DrawLine(xMax, 0.5, xMax, charge * 2.);
542 arrow->DrawArrow(xMin, charge * 1.5, xMax, charge * 1.5, 0.01,
"<>");
547 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + 3);
548 gPad->SetFrameFillStyle(0);
549 gPad->SetFillStyle(0);
554 hCharge->SetLineColor(1);
555 hCharge->GetXaxis()->SetTitle(
"charge [ADC counts]");
556 float binWidth = hCharge->GetXaxis()->GetBinUpEdge(1) - hCharge->GetXaxis()->GetBinLowEdge(1);
557 std::ostringstream ytitle;
558 ytitle <<
"Entries [/(" << binWidth <<
" ADC counts)]";
559 hCharge->GetYaxis()->SetTitle(ytitle.str().c_str());
564 double charge = hCharge->GetBinContent(hCharge->GetMaximumBin());
565 line->DrawLine(threshold, 0.5, threshold, charge * 2.);
567 if ((
object = gROOT->FindObject(
"dummy")))
delete object;
568 std::ostringstream cut;
569 cut <<
"pmtChId==" << (iHisto + 1);
571 std::ostringstream summarystr[2];
572 if (LoadHisto == c_LoadForFitHeight) {
573 nEntries =
m_tree->Project(
"dummy",
"gain:efficiency", cut.str().c_str());
575 summarystr[0] <<
"gain = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
577 latex->DrawLatex(0.875, 0.34, summarystr[0].str().c_str());
578 summarystr[1] <<
"efficiency = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
579 << (
m_tree->GetV2()[0] * 100) <<
" %";
580 latex->DrawLatex(0.875, 0.29, summarystr[1].str().c_str());
582 }
else if (LoadHisto == c_LoadForFitIntegral) {
583 nEntries =
m_tree->Project(
"dummy",
"gainUseIntegral:efficiencyUseIntegral", cut.str().c_str());
585 summarystr[0] <<
"gain = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
587 latex->DrawLatex(0.875, 0.34, summarystr[0].str().c_str());
588 summarystr[1] <<
"efficiency = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
589 << (
m_tree->GetV2()[0] * 100) <<
" %";
590 latex->DrawLatex(0.875, 0.29, summarystr[1].str().c_str());
595 B2WARNING(
"TOPGainEfficiencyCalculator : mutliple entries with the same channel ID ("
596 <<
m_pmtChId <<
") in the output TTree");
601 if (((iHisto + 1) % c_NChannelPerPage) == 0)
602 canvas->Print(pdfFilename.str().c_str());
604 for (
int iHisto = (c_NChannelPerPMT - 1) % c_NChannelPerPage + 1 ; iHisto < c_NChannelPerPage ; iHisto++) {
605 for (
int iPad = 0 ; iPad < c_NPlotsPerChannel ; iPad++) {
606 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + iPad + 1);
607 gPad->SetFrameFillStyle(0);
608 gPad->SetFillStyle(0);
610 if (((iHisto + 1) % c_NChannelPerPage) == 0)
611 canvas->Print(pdfFilename.str().c_str());
614 canvas->Print((pdfFilename.str() +
"]").c_str());
620 if ((
object = gROOT->FindObject(
"dummy")))
delete object;
628 double pedestal = par[4];
629 double pedestalWidth = par[5];
630 double x = (var[0] - pedestal);
633 double step = pedestalWidth / 100.;
634 double t = TMath::Max(step, x - pedestalWidth * 10);
636 while (t < x + pedestalWidth * 10) {
637 output += TMath::Gaus(x, t, pedestalWidth) * TMath::Power(t / par[3], par[1])
638 * TMath::Exp((-1) * TMath::Power(t / par[3], par[2]));
643 return par[0] * output * step;
648 double histo_xmax = histo->GetXaxis()->GetBinUpEdge(histo->GetXaxis()->GetNbins() - 1);
649 if (xmax > histo_xmax) xmax = histo_xmax;
652 double peakPos = histo->GetXaxis()->GetBinCenter(iBin);
653 double peakCharge = histo->GetBinContent(iBin);
656 double x = histo->GetXaxis()->GetBinCenter(iBin);
659 double binEntry = histo->GetBinContent(iBin);
660 if (binEntry > peakCharge) {
662 peakCharge = binEntry;
HistoModule.h is supposed to be used instead of Module.h for the modules with histogram definitions t...
void setDescription(const std::string &description)
Sets the description of the module.
float m_efficiency
calculated efficiency from fitting of pulse charge distribution
int m_nEntries
entries of pulse charge distribution
float m_initialX0
initial value of the fit parameter x0
float m_p1HeightIntegral
Parameter from p0 + x*p1 function that fits height-integral distribution.
float m_pedestalSigma
sigma of pedestal
float m_funcFitRangeIntegral
integral of fit function for a range [threshold, fitMax]
TTree * m_tree
ntuple to store summary
float m_p2Error
fit error of p2
float m_p1Error
fit error of p1
float m_thresholdForIntegral
pulse integral threshold, which defines lower limit of fit region and efficiency calculation
TF1 * m_funcForFitRange[c_NChannelPerPMT]
array of TF1 pointer to store fit function for pulse charge distribution, defined only for fit region
TH2F * m_timeChargeHistogram[c_NChannelPerPMT]
2D histogram of hit timing and pulse charge (or charge), taken from an output file of TOPLaserHitSele...
short m_targetPmtId
PMT ID.
float m_threshold
pulse charge threshold, which defines lower limit of fit region and efficiency calculation
short m_pmtChId
PMT channel ID.
float m_fitMax
upper limit of fit region for pulse charge distribution, determined based on m_fracFit value
float m_gain
calculated gain from fitting of pulse charge distribution
std::vector< TBranch * > m_branch[4]
ntuple to store summary of gain using height distribution.
float m_p1
fit result of p1
float m_fitHalfWidth
half fit width for direct laser hit peak in [ns] unit
int m_nCalPulse
the number of events with calibration pulse(s) identified
float m_initialP2
initial value of the fit parameter p2
float m_funcFullRangeIntegral
integral of fit function for its full range
float m_p2
fit result of p2
short m_targetPmtChId
PMT channel ID.
float m_histoFitRangeIntegral
integral of histogram for a range [threshold, fitMax]
float m_initialP0
initial value of the fit parameter p0
short m_targetSlotId
slot ID
float m_meanPulseHeight
histogram mean of pulse height distribution
float m_hitTimingSigma
Gaussian fit sigma for a peak of laser direct photons in hit timing distribution.
short m_pixelId
pixel ID, calculated from PMT ID and PMT channel ID
float m_p0
fit result of p0
float m_p0HeightIntegral
Parameter from p0 + x*p1 function that fits height-integral distribution.
float m_fracFit
fraction of events which are covered by an area [0,m_fitMax]
std::string m_inputFile
input file containing timing vs charge 2D histograms (output of TOPLaserHitSelector)
float m_x0
fit result of x0
float m_p0Error
fit error of p0
std::string m_fitoption
charge histograms fitting option.
float m_meanPulseHeightError
histogram mean error of pulse height distribution
std::string m_outputPDFFile
output PDF file to store plots of 2D histogram, timing, and charge distribution for each channel
EHistogramType
enum for LoadHistograms switch.
float m_x0Error
fit error of x0
short m_hvDiff
HV difference from nominal HV value.
TF1 * m_funcForFullRange[c_NChannelPerPMT]
array of TF1 pointer to store fit function for pulse charge distribution, defined only for full range...
TF1 * m_funcForLaser[c_NChannelPerPMT]
array of TF1 pointer to store fit function for hit timing distribution
float m_initialP1
initial value of the fit parameter p1
TH1D * m_chargeHistogram[c_NChannelPerPMT]
pulse charge distribution, extracted from m_timeChargeHistogram as a projection along its y-axis with...
float m_histoMeanAboveThre
mean of histogram above threshold, ignore overflow bin
float m_hitTiming
timing of laser direct photon hits, given by Gaussian fit mean
float m_chisquare
chi2 of fitting
TH1F * m_nCalPulseHistogram
histogram to store the number of events with calibration pulse(s) identified for each asic (1,...
int m_nOverflowEvents
the number of events outside histogram range
TH1D * m_timeHistogram[c_NChannelPerPMT]
hit timing distribution, extracted from m_timeChargeHistogram as a projection along its x-axis.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
TOPGainEfficiencyCalculatorModule()
Constructor.
static double TOPGainFunc(double *var, double *par)
Fit function of pulse charge (or charnge) distribution for channel(pixel)-by-channel gain extraction,...
virtual void initialize() override
Load time vs charge 2D histogram from a given input file (paramter "inputFile") and prepare hit timin...
virtual void event() override
This will be empty as the all the processes are done in beginRun() function thus input file can be a ...
virtual void endRun() override
Draw plots to show fitting results for each channel and save them into a given PDF file (outputPDFFil...
virtual void terminate() override
Termination action.
virtual ~TOPGainEfficiencyCalculatorModule()
Destructor.
void FitHistograms(EHistogramType LoadHisto)
Fit charge (or integrated charged) distribution to calculate gain and efficiency for each channel.
virtual void beginRun() override
The main processes, fitting charge distribution and calculating gain/efficiency, are done in this fun...
static double FindPeakForSmallerXThan(TH1 *histo, double xmax=0)
Find peak and return its position for a limited range of x (x smaller than the given value (xmax))
void DrawResult(const std::string &histotype, EHistogramType LoadHisto)
Draw results of gain/efficiency calculation for each channel to a given output file.
void LoadHistograms(const std::string &histotype)
Load 2D histograms from a given input file (output of TOPLaserHitSelector) and create timing and char...
void DummyFillBranch(EHistogramType LoadHisto)
Fill Dummy for Branch.
virtual void defineHisto() override
Define TTree branches to store fit results for each channel This TTree is saved in an output file giv...
Abstract base class for different kinds of events.