Belle II Software development
TOPGainEfficiencyCalculatorModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9// own include
10#include <top/modules/TOPGainEfficiencyMonitor/TOPGainEfficiencyCalculatorModule.h>
11
12// standard libraries
13#include <iostream>
14#include <sstream>
15#include <iomanip>
16
17// ROOT
18#include <TROOT.h>
19#include <TObject.h>
20#include <TFile.h>
21#include <TF1.h>
22#include <TCanvas.h>
23#include <TStyle.h>
24#include <TAxis.h>
25#include <TLine.h>
26#include <TArrow.h>
27#include <TLatex.h>
28#include <TMath.h>
29
30namespace Belle2 {
35
36 //-----------------------------------------------------------------
38 //-----------------------------------------------------------------
39
40 REG_MODULE(TOPGainEfficiencyCalculator);
41
42
43 //-----------------------------------------------------------------
44 // Implementation
45 //-----------------------------------------------------------------
46
48 {
49 // Set description()
50 setDescription("Calculate pixel gain and efficiency for a given PMT from 2D histogram of hit timing and pulse charge, "
51 "created by TOPLaserHitSelectorModule.");
52
53 // Add parameters
54 addParam("inputFile", m_inputFile, "input file name containing 2D histogram", std::string(""));
55 addParam("outputPDFFile", m_outputPDFFile, "output PDF file to store plots", std::string(""));
56 addParam("targetSlotId", m_targetSlotId, "TOP module ID in slot number (1-16)", (short)0);
57 addParam("targetPmtId", m_targetPmtId, "PMT number (1-32)", (short)0);
58 addParam("targetPmtChId", m_targetPmtChId, "PMT channel number (1-16)", (short) - 1);
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);
61 addParam("threshold", m_threshold,
62 "pulse height (or integrated charge) threshold in fitting its distribution and calculating efficiency", (float)100.);
63 addParam("p0HeightIntegral", m_p0HeightIntegral,
64 "Parameter from p0 + x*p1 function fitting height-integral distribution.", (float) - 50.0);
65 addParam("p1HeightIntegral", m_p1HeightIntegral,
66 "Parameter from p0 + x*p1 function fitting height-integral distribution.", (float)6.0);
67 addParam("fracFit", m_fracFit, "fraction of events to be used in fitting. "
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)); //,(float)0.99);
70 addParam("initialP0", m_initialP0, "initial value of the fit parameter p0 divided by histogram entries."
71 "Set negative value to calculate from histogram information automatically.", (float)(0.0001)); //,(float)1e-6);
72 addParam("initialP1", m_initialP1, "initial value of the fit parameter p1."
73 "Set negative value to calculate from histogram information automatically.", (float)(1.0)); //,(float)1.0);
74 addParam("initialP2", m_initialP2, "initial value of the fit parameter p2."
75 "Set negative value to calculate from histogram information automatically.", (float)(1.0)); //,(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 information automatically.", (float)(100)); //, (float)100.);
78 addParam("pedestalSigma", m_pedestalSigma, "sigma of pedestal width", (float)10.);
79 addParam("fitoption", m_fitoption, "fit option likelihood: default chisquare: R", std::string("L"));
80
81 }
82
83
85 {
86 REG_HISTOGRAM;
87 }
88
90 {
91 m_tree = new TTree("tree", "TTree for gain/efficiency monitor summary");
92 m_branch[0].push_back(m_tree->Branch("slotId", &m_targetSlotId, "slotId/S"));
93 m_branch[0].push_back(m_tree->Branch("pmtId", &m_targetPmtId, "pmtId/S"));
94 m_branch[0].push_back(m_tree->Branch("pixelId", &m_pixelId, "pixelId/S"));
95 m_branch[0].push_back(m_tree->Branch("pmtChId", &m_pmtChId, "pmtChId/S"));
96 m_branch[0].push_back(m_tree->Branch("hvDiff", &m_hvDiff, "hvDiff/S"));
97 m_branch[0].push_back(m_tree->Branch("threshold", &m_threshold, "threshold/F"));
98 m_branch[0].push_back(m_tree->Branch("thresholdForIntegral", &m_thresholdForIntegral, "thresholdForIntegral/F"));
99
100 m_branch[1].push_back(m_tree->Branch("nCalPulse", &m_nCalPulse, "nCalPulse/I"));
101 m_branch[1].push_back(m_tree->Branch("hitTimingForGain", &m_hitTiming, "hitTimingForGain/F"));
102 m_branch[1].push_back(m_tree->Branch("hitTimingSigmaForGain", &m_hitTimingSigma, "hitTimingSigmaForGain/F"));
103 m_branch[1].push_back(m_tree->Branch("nEntriesForGain", &m_nEntries, "nEntriesForGain/I"));
104 m_branch[1].push_back(m_tree->Branch("nOverflowEventsForGain", &m_nOverflowEvents, "nOverflowEventsForGain/I"));
105 m_branch[1].push_back(m_tree->Branch("meanPulseHeightForGain", &m_meanPulseHeight, "meanPulseHeightForGain/F"));
106 m_branch[1].push_back(m_tree->Branch("meanPulseHeightErrorForGain", &m_meanPulseHeightError, "meanPulseHeightErrorForGain/F"));
107 m_branch[1].push_back(m_tree->Branch("fitMaxForGain", &m_fitMax, "fitMaxForGain/F"));
108 m_branch[1].push_back(m_tree->Branch("gain", &m_gain, "gain/F"));
109 m_branch[1].push_back(m_tree->Branch("efficiency", &m_efficiency, "efficiency/F"));
110 m_branch[1].push_back(m_tree->Branch("p0ForGain", &m_p0, "p0ForGain/F"));
111 m_branch[1].push_back(m_tree->Branch("p1ForGain", &m_p1, "p1ForGain/F"));
112 m_branch[1].push_back(m_tree->Branch("p2ForGain", &m_p2, "p2ForGain/F"));
113 m_branch[1].push_back(m_tree->Branch("x0ForGain", &m_x0, "x0ForGain/F"));
114 m_branch[1].push_back(m_tree->Branch("p0ErrorForGain", &m_p0Error, "p0ErrorForGain/F"));
115 m_branch[1].push_back(m_tree->Branch("p1ErrorForGain", &m_p1Error, "p1ErrorForGain/F"));
116 m_branch[1].push_back(m_tree->Branch("p2ErrorForGain", &m_p2Error, "p2ErrorForGain/F"));
117 m_branch[1].push_back(m_tree->Branch("x0ErrorForGain", &m_x0Error, "x0ErrorForGain/F"));
118 m_branch[1].push_back(m_tree->Branch("chisquareForGain", &m_chisquare, "chisquareForGain/F"));
119 m_branch[1].push_back(m_tree->Branch("ndfForGain", &m_ndf, "ndfForGain/I"));
120 m_branch[1].push_back(m_tree->Branch("funcFullRangeIntegralForGain", &m_funcFullRangeIntegral, "funcFullRangeIntegralForGain/F"));
121 m_branch[1].push_back(m_tree->Branch("funcFitRangeIntegralForGain", &m_funcFitRangeIntegral, "funcFitRangeIntegralForGain/F"));
122 m_branch[1].push_back(m_tree->Branch("histoFitRangeIntegralForGain", &m_histoFitRangeIntegral, "histoFitRangeIntegralForGain/F"));
123 m_branch[1].push_back(m_tree->Branch("histoMeanAboveThreForGain", &m_histoMeanAboveThre, "histoMeanAboveThreForGain/F"));
124
125 m_branch[2].push_back(m_tree->Branch("hitTimingForEff", &m_hitTiming, "hitTimingForEff/F"));
126 m_branch[2].push_back(m_tree->Branch("hitTimingSigmaForEff", &m_hitTimingSigma, "hitTimingSigmaForEff/F"));
127 m_branch[2].push_back(m_tree->Branch("nEntriesForEff", &m_nEntries, "nEntriesForEff/I"));
128 m_branch[2].push_back(m_tree->Branch("nOverflowEventsForEff", &m_nOverflowEvents, "nOverflowEventsForEff/I"));
129 m_branch[2].push_back(m_tree->Branch("meanPulseHeightForEff", &m_meanPulseHeight, "meanPulseHeightForEff/F"));
130 m_branch[2].push_back(m_tree->Branch("meanPulseHeightErrorForEff", &m_meanPulseHeightError, "meanPulseHeightErrorForEff/F"));
131 m_branch[2].push_back(m_tree->Branch("histoMeanAboveThreForEff", &m_histoMeanAboveThre, "histoMeanAboveThreForEff/F"));
132
133 m_branch[3].push_back(m_tree->Branch("meanIntegral", &m_meanPulseHeight, "meanIntegral/F"));
134 m_branch[3].push_back(m_tree->Branch("meanIntegralError", &m_meanPulseHeightError, "meanIntegralError/F"));
135 m_branch[3].push_back(m_tree->Branch("nOverflowEventsUseIntegral", &m_nOverflowEvents, "nOverflowEventsUseIntegral/I"));
136 m_branch[3].push_back(m_tree->Branch("fitMaxUseIntegral", &m_fitMax, "fitMaxUseIntegral/F"));
137 m_branch[3].push_back(m_tree->Branch("gainUseIntegral", &m_gain, "gainUseIntegral/F"));
138 m_branch[3].push_back(m_tree->Branch("efficiencyUseIntegral", &m_efficiency, "efficiencyUseIntegral/F"));
139 m_branch[3].push_back(m_tree->Branch("p0UseIntegral", &m_p0, "p0UseIntegral/F"));
140 m_branch[3].push_back(m_tree->Branch("p1UseIntegral", &m_p1, "p1UseIntegral/F"));
141 m_branch[3].push_back(m_tree->Branch("p2UseIntegral", &m_p2, "p2UseIntegral/F"));
142 m_branch[3].push_back(m_tree->Branch("x0UseIntegral", &m_x0, "x0UseIntegral/F"));
143 m_branch[3].push_back(m_tree->Branch("p0ErrorUseIntegral", &m_p0Error, "p0ErrorUseIntegral/F"));
144 m_branch[3].push_back(m_tree->Branch("p1ErrorUseIntegral", &m_p1Error, "p1ErrorUseIntegral/F"));
145 m_branch[3].push_back(m_tree->Branch("p2ErrorUseIntegral", &m_p2Error, "p2ErrorUseIntegral/F"));
146 m_branch[3].push_back(m_tree->Branch("x0ErrorUseIntegral", &m_x0Error, "x0ErrorUseIntegral/F"));
147 m_branch[3].push_back(m_tree->Branch("chisquareUseIntegral", &m_chisquare, "chisquareUseIntegral/F"));
148 m_branch[3].push_back(m_tree->Branch("ndfUseIntegral", &m_ndf, "ndfUseIntegral/I"));
149 m_branch[3].push_back(m_tree->Branch("funcFullRangeIntegralUseIntegral", &m_funcFullRangeIntegral,
150 "funcFullRangeIntegralUseIntegral/F"));
151 m_branch[3].push_back(m_tree->Branch("funcFitRangeIntegralUseIntegral", &m_funcFitRangeIntegral,
152 "funcFitRangeIntegralUseIntegral/F"));
153 m_branch[3].push_back(m_tree->Branch("histoFitRangeIntegralUseIntegral", &m_histoFitRangeIntegral,
154 "histoFitRangeIntegralUseIntegral/F"));
155 m_branch[3].push_back(m_tree->Branch("histoMeanAboveThreUseIntegral", &m_histoMeanAboveThre, "histoMeanAboveThreUseIntegral/F"));
156
157 }
158
160 {
161 //first, check validity of input parameters
162 bool areGoodParameters = true;
164 B2ERROR("TOPGainEfficiencyCalculator : invalid slotID : " << m_targetSlotId);
165 areGoodParameters = false;
166 }
167 if (m_targetPmtId < 1 || m_targetPmtId > c_NPMTPerModule) {
168 B2ERROR("TOPGainEfficiencyCalculator : invalid PMT ID : " << m_targetPmtId);
169 areGoodParameters = false;
170 }
171 if (m_pedestalSigma < 1e-6) {
172 B2ERROR("TOPGainEfficiencyCalculator : pedestal sigma must be non-zero positive value");
173 areGoodParameters = false;
174 }
175
176 //do not proceed to the main process unless all the input parameters are not valid
177 if (areGoodParameters) {
178 if (m_outputPDFFile.size() == 0) {
179 if (m_inputFile.rfind(".") == std::string::npos)
181 else
182 m_outputPDFFile = m_inputFile.substr(0, m_inputFile.rfind("."));
183 }
184
185 //gain run using height distribution
186 LoadHistograms("Height_gain");
187 FitHistograms(c_LoadForFitHeight);
188 DrawResult("Height_gain", c_LoadForFitHeight);
189
190 //efficiency run
191 LoadHistograms("Height_efficiency");
192 FitHistograms(c_LoadHitRateHeight);
193 DrawResult("Height_efficiency", c_LoadHitRateHeight);
194
195 //gain run using integral distribution
196 LoadHistograms("Integral_gain");
197 FitHistograms(c_LoadForFitIntegral);
198 DrawResult("Integral_gain", c_LoadForFitIntegral);
199
200 }
201 }
202
203
204 void TOPGainEfficiencyCalculatorModule::LoadHistograms(const std::string& histotype)
205 {
206
207 TFile* f = new TFile(m_inputFile.c_str());
208 if (!f->IsOpen()) {
209 B2ERROR("TOPGainEfficiencyCalculator : fail to open input file \"" << m_inputFile << "\"");
210 return;
211 }
212
213 for (int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
214 if (m_targetPmtChId != -1 && iHisto + 1 != m_targetPmtChId) continue;
215 std::ostringstream pixelstr;
216 pixelstr << histotype << "_"
217 << "s" << std::setw(2) << std::setfill('0') << m_targetSlotId << "_PMT"
218 << std::setw(2) << std::setfill('0') << m_targetPmtId
219 << "_" << std::setw(2) << std::setfill('0') << (iHisto + 1);
220 std::ostringstream hname;
221 hname << "hTime" << pixelstr.str();
222
223 //first get 2D histogram from a given input (=an output file of TOPLaserHitSelector)
224 m_timeChargeHistogram[iHisto] = static_cast<TH2F*>(f->Get(hname.str().c_str()));
225 TH2F* h2D = m_timeChargeHistogram[iHisto];
226 if (!h2D) continue;
227
228 //create a projection histogram along the x-axis and fit the distribution (hit timing) to get direct laser hit timing
229 std::ostringstream hnameProj[2];
230 hnameProj[0] << "hTime_" << pixelstr.str();
231 hnameProj[1] << "hCharge_" << pixelstr.str();
232 TH1D* hTime = static_cast<TH1D*>(h2D->ProjectionX(hnameProj[0].str().c_str()));
233 m_timeHistogram[iHisto] = hTime;
234 double peakTime = FindPeakForSmallerXThan(hTime, 0);
235 //double peakTime = hTime->GetXaxis()->GetBinCenter(hTime->GetMaximumBin());
236 double fitMin = peakTime - m_fitHalfWidth;
237 double fitMax = peakTime + m_fitHalfWidth;
238 TF1* funcLaser = new TF1(std::string(std::string("func_") + hnameProj[1].str()).c_str(),
239 "gaus(0)", fitMin, fitMax);
240 funcLaser->SetParameters(hTime->GetBinContent(hTime->GetXaxis()->FindBin(peakTime)), peakTime, m_fitHalfWidth);
241 funcLaser->SetParLimits(1, fitMin, fitMax);
242 hTime->Fit(funcLaser, "Q", "", fitMin, fitMax);
243 //if (funcLaser->GetNDF() < 1) continue;
244 m_funcForLaser[iHisto] = funcLaser;
245
246 //if the fitting is successful, create y-projection histogram with timing cut
247 m_hitTiming = funcLaser->GetParameter(1);
248 int binNumMin = hTime->GetXaxis()->FindBin(m_hitTiming - 2 * m_fitHalfWidth);
249 int binNumMax = hTime->GetXaxis()->FindBin(m_hitTiming + 2 * m_fitHalfWidth);
250 TH1D* hCharge = static_cast<TH1D*>(h2D->ProjectionY(hnameProj[1].str().c_str(), binNumMin, binNumMax));
251 m_chargeHistogram[iHisto] = hCharge;
252 }
253
254 m_nCalPulseHistogram = static_cast<TH1F*>(f->Get("hNCalPulse"));
256 B2WARNING("TOPGainEfficiencyCalculator : no histogram for the number of events with calibration pulses identified in the given input file");
258 return;
259 }
260
262 {
263 float threshold = m_threshold;
264 int globalAsicId = 0;
265 if (LoadHisto == c_LoadForFitIntegral || LoadHisto == c_LoadHitRateIntegral) threshold = m_thresholdForIntegral;
266
267 for (int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
268 if (m_targetPmtChId != -1 && iHisto + 1 != m_targetPmtChId) continue;
269
270 m_pixelId = ((m_targetPmtId - 1) % c_NPMTPerRow) * c_NChannelPerPMTRow
271 + ((m_targetPmtId - 1) / c_NPMTPerRow) * c_NPixelPerModule / 2
272 + (iHisto / c_NChannelPerPMTRow) * c_NPixelPerRow + (iHisto % c_NChannelPerPMTRow) + 1;
273 m_pmtChId = (iHisto + 1);
274 globalAsicId = ((m_targetSlotId - 1) * c_NPixelPerModule + (m_pixelId - 1)) / c_NChannelPerAsic;
275 if (LoadHisto == c_LoadForFitHeight) {
276 for (auto itr = m_branch[0].begin(); itr != m_branch[0].end(); ++itr) {
277 (*itr)->Fill();
278 }
279 }
280
281 TH1D* hCharge = m_chargeHistogram[iHisto];
282 if (!hCharge) { DummyFillBranch(LoadHisto); continue;}
283
284 std::cout << " ***** fitting charge distribution for " << hCharge->GetName() << " *****" << std::endl;
285 int nBins = hCharge->GetXaxis()->GetNbins();
286 double binWidth = hCharge->GetXaxis()->GetBinUpEdge(1) - hCharge->GetXaxis()->GetBinLowEdge(1);
287 double histoMax = hCharge->GetXaxis()->GetBinUpEdge(nBins);
288 m_fitMax = threshold;
289 double wholeIntegral = hCharge->Integral(0, hCharge->GetXaxis()->GetNbins() + 1);
290 double fitRangeFraction = (m_fracFit > 0 ? m_fracFit : 1. - 10. / wholeIntegral);
291 while (hCharge->Integral(0, hCharge->GetXaxis()->FindBin(m_fitMax - 0.01 * binWidth)) / wholeIntegral < fitRangeFraction)
292 m_fitMax += binWidth;
293 if (m_fitMax < threshold + static_cast<double>(c_NParameterGainFit) * binWidth) {
294 B2WARNING("TOPGainEfficiencyCalculator : no enough entries for fitting at slot"
295 << std::setw(2) << std::setfill('0') << m_targetSlotId << ", PMT"
296 << std::setw(2) << std::setfill('0') << m_targetPmtId << ", Ch"
297 << std::setw(2) << std::setfill('0') << m_pmtChId);
298 DummyFillBranch(LoadHisto); continue;
299 }
300
301 std::ostringstream fname;
302 fname << "func_" << (iHisto + 1);
303 TObject* object = gROOT->FindObject(fname.str().c_str());
304 if (object) delete object;
305 TF1* func = new TF1(fname.str().c_str(), TOPGainFunc, threshold, m_fitMax, c_NParameterGainFit);
306 double initGain = TMath::Max(hCharge->GetMean(), 26.1) - 25;
307 double initP1 = TMath::Min(4.0, TMath::Max(10000.*TMath::Power(initGain - 25, -2), 0.01));
308 double initP2 = TMath::Min(0.8 + 0.005 * TMath::Power(initP1, -3), 4.);
309 double initX0 = TMath::Max(initGain * 2 - 150, 10.);
310 //if (initP1 > initP2) initX0 = initX0 / 10.
311 double initP1overP2 = initP1 / initP2;
312 double initP0 = hCharge->GetBinContent(hCharge->GetMaximumBin())
313 / (TMath::Power(initP1overP2, initP1overP2) * TMath::Exp(-initP1overP2)) / binWidth;
314 if (m_initialX0 < 0)func->SetParameter(3, initX0);
315 else if (LoadHisto == c_LoadForFitHeight)
316 func->SetParameter(3, 150 + 0.5 * hCharge->GetMean());
317 else if (LoadHisto == c_LoadForFitIntegral)
318 func->SetParameter(3, 1000 + 0.5 * hCharge->GetMean());
319 if (m_initialP2 < 0)func->SetParameter(2, initP2);
320 else func->SetParameter(2, m_initialP2);
321 if (m_initialP1 < 0)func->SetParameter(1, initP1);
322 else func->SetParameter(1, m_initialP1);
323 if (m_initialP0 < 0)func->SetParameter(0, initP0);
324 else func->SetParameter(0, m_initialP0 * hCharge->GetEntries()*binWidth);
325
326 func->FixParameter(4, 0);
327 func->FixParameter(5, m_pedestalSigma);
328 func->SetParName(0, "#it{p}_{0}");
329 func->SetParName(1, "#it{p}_{1}");
330 func->SetParName(2, "#it{p}_{2}");
331 func->SetParName(3, "#it{x}_{0}");
332 func->SetParName(4, "pedestal");
333 func->SetParName(5, "pedestal #sigma");
334 func->SetParLimits(0, 1e-8, 1e8);
335 func->SetParLimits(1, 1e-8, 10);
336 func->SetParLimits(2, 1e-8, 10);
337 func->SetParLimits(3, 1e-8, 1e8);
338 func->SetLineColor(2);
339 func->SetLineWidth(1);
340 TF1* funcFull = NULL;
341 if (LoadHisto == c_LoadForFitHeight or LoadHisto == c_LoadForFitIntegral) {
342 hCharge->Fit(func, m_fitoption.c_str(), "", threshold, m_fitMax);
343
344 if (func->GetNDF() < 2) { DummyFillBranch(LoadHisto); continue;}
345
346 double funcFullMax = histoMax * 2;
347 funcFull = new TF1((fname.str() + "_full").c_str(), TOPGainFunc, (-1)*func->GetParameter(5), funcFullMax, c_NParameterGainFit);
348 for (int iPar = 0 ; iPar < c_NParameterGainFit ; iPar++)
349 funcFull->SetParameter(iPar, func->GetParameter(iPar));
350 funcFull->SetLineColor(3);
351 funcFull->SetLineWidth(2);
352
353 double totalWeight = 0;
354 double weightedIntegral = 0;
355 double x = (-1) * func->GetParameter(5);
356 while (x < funcFullMax) {
357 double funcVal = funcFull->Eval(x);
358 totalWeight += funcVal;
359 weightedIntegral += funcVal * x;
360 x += binWidth / 5.;
361 }
362
363 //fill results to the output TTree
364 m_gain = weightedIntegral / totalWeight;
365 m_efficiency = funcFull->Integral(threshold, funcFullMax) / funcFull->Integral((-1) * func->GetParameter(5), funcFullMax);
366 m_p0 = func->GetParameter(0);
367 m_p1 = func->GetParameter(1);
368 m_p2 = func->GetParameter(2);
369 m_x0 = func->GetParameter(3);
370 m_p0Error = func->GetParError(0);
371 m_p1Error = func->GetParError(1);
372 m_p2Error = func->GetParError(2);
373 m_x0Error = func->GetParError(3);
374 m_chisquare = func->GetChisquare();
375 m_ndf = func->GetNDF();
376 m_funcFullRangeIntegral = funcFull->Integral((-1) * func->GetParameter(5), funcFullMax) / binWidth;
377 m_funcFitRangeIntegral = funcFull->Integral(threshold, m_fitMax) / binWidth;
378 } else std::cout << "*****fitting is skipped***** " << std::endl;
379 int threBin = hCharge->GetXaxis()->FindBin(threshold + 0.01 * binWidth);
380 int fitMaxBin = hCharge->GetXaxis()->FindBin(m_fitMax - 0.01 * binWidth);
381 m_histoFitRangeIntegral = hCharge->Integral(threBin, fitMaxBin);
382
384 for (int iBin = threBin ; iBin < nBins + 1 ; iBin++) {
385 m_histoMeanAboveThre += (hCharge->GetBinContent(iBin) * hCharge->GetXaxis()->GetBinCenter(iBin));
386 }
387 m_histoMeanAboveThre /= hCharge->Integral(threBin, nBins);
388 m_nEntries = hCharge->GetEntries();
389 m_nCalPulse = (m_nCalPulseHistogram ? m_nCalPulseHistogram->GetBinContent(globalAsicId + 1) : -1);
390 m_nOverflowEvents = TMath::FloorNint(hCharge->GetBinContent(nBins + 1));
391 m_meanPulseHeight = hCharge->GetMean();
392 m_meanPulseHeightError = hCharge->GetMeanError();
393 m_hitTiming = 0;
394 m_hitTimingSigma = -1;
395
396 TF1* funcLaser = m_funcForLaser[iHisto];
397 if (m_timeHistogram[iHisto] && funcLaser) {
398 m_hitTiming = funcLaser->GetParameter(1);
399 m_hitTimingSigma = funcLaser->GetParameter(2);
400 }
401
402 m_funcForFitRange[iHisto] = func;
403 m_funcForFullRange[iHisto] = funcFull;
404
405 for (auto itr = m_branch[LoadHisto].begin(); itr != m_branch[LoadHisto].end(); ++itr) {
406 (*itr)->Fill();
407 }
408
409 std::cout << std::endl;
410 }
411 if (m_targetPmtChId == -1) m_tree->SetEntries(c_NChannelPerPMT);
412 else m_tree->SetEntries(1);
413
414 return;
415 }
416
418 {
419 m_fitMax = -1;
420 m_hitTiming = -1;
421 m_hitTimingSigma = -1;
422 m_nEntries = -1;
423 m_nCalPulse = -1;
427 m_gain = -1;
428 m_efficiency = -1;
429 m_p0 = -1;
430 m_p1 = -1;
431 m_p2 = -1;
432 m_x0 = -1;
433 m_p0Error = -1;
434 m_p1Error = -1;
435 m_p2Error = -1;
436 m_x0Error = -1;
437 m_chisquare = -1;
438 m_ndf = -1;
443
444 for (auto itr = m_branch[LoadHisto].begin(); itr != m_branch[LoadHisto].end(); ++itr) {
445 (*itr)->Fill();
446 }
447 }
448
449
450 void TOPGainEfficiencyCalculatorModule::DrawResult(const std::string& histotype, EHistogramType LoadHisto)
451 {
452 std::ostringstream pdfFilename;
453 pdfFilename << m_outputPDFFile << "_" << histotype;
454 if (m_targetPmtChId != -1)
455 pdfFilename << "_" << "ch" << std::setw(2) << std::setfill('0') << m_targetPmtChId;
456 pdfFilename << ".pdf";
457
458 gStyle->SetFrameFillStyle(0);
459 gStyle->SetFillStyle(0);
460 gStyle->SetStatStyle(0);
461 gStyle->SetOptStat(112210);
462 gStyle->SetOptFit(1110);
463 TCanvas* canvas = new TCanvas();
464 canvas->SetFillStyle(0);
465 canvas->Print((pdfFilename.str() + "[").c_str());
466
467 TLine* line = new TLine();
468 line->SetLineWidth(1);
469 line->SetLineStyle(1);
470 line->SetLineColor(4);
471 TArrow* arrow = new TArrow();
472 arrow->SetLineWidth(1);
473 arrow->SetLineStyle(1);
474 arrow->SetLineColor(3);
475 TLatex* latex = new TLatex();
476 latex->SetNDC();
477 latex->SetTextFont(22);
478 latex->SetTextSize(0.05);
479 latex->SetTextAlign(32);
480 TObject* object;
481
482 float threshold;
483 if (LoadHisto == c_LoadForFitIntegral) threshold = m_thresholdForIntegral;
484 else threshold = m_threshold;
485
486 for (int iHisto = 0 ; iHisto < c_NChannelPerPMT ; iHisto++) {
487
488 if ((iHisto % c_NChannelPerPage) == 0) {
489 canvas->Clear();
490 canvas->Divide(c_NPlotsPerChannel, c_NChannelPerPage);
491 }
492
493 //2D (time vs pulse charge) histogram
494 canvas->cd(3 * (iHisto % c_NChannelPerPage) + 1);
495 gPad->SetFrameFillStyle(0);
496 gPad->SetFillStyle(0);
497 TH2F* h2D = m_timeChargeHistogram[iHisto];
498 if (h2D) {
499 h2D->Draw("colz");
500 h2D->GetXaxis()->SetTitle("hit timing [ns]");
501 h2D->GetYaxis()->SetTitle("pulse charge [ADC count]");
502 }
503
504 //timing histogram
505 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + 2);
506 gPad->SetFrameFillStyle(0);
507 gPad->SetFillStyle(0);
508 TH1D* hTime = m_timeHistogram[iHisto];
509 if (hTime) {
510 gPad->SetLogy();
511 hTime->Draw();
512 hTime->SetLineColor(1);
513 hTime->GetXaxis()->SetTitle("hit timing [ns]");
514 float binWidth = hTime->GetXaxis()->GetBinUpEdge(1) - hTime->GetXaxis()->GetBinLowEdge(1);
515 std::ostringstream ytitle;
516 ytitle << "Entries [/(" << binWidth << " ns)]";
517 hTime->GetYaxis()->SetTitle(ytitle.str().c_str());
518
519 TF1* funcLaser = m_funcForLaser[iHisto];
520 if (funcLaser) {
521 double charge = funcLaser->GetParameter(0);
522 double peakTime = funcLaser->GetParameter(1);
523 float xMin = hTime->GetXaxis()->GetBinLowEdge(hTime->GetXaxis()->FindBin(peakTime - 2 * m_fitHalfWidth));
524 float xMax = hTime->GetXaxis()->GetBinUpEdge(hTime->GetXaxis()->FindBin(peakTime + 2 * m_fitHalfWidth));
525 line->DrawLine(xMin, 0.5, xMin, charge * 2.);
526 line->DrawLine(xMax, 0.5, xMax, charge * 2.);
527 arrow->DrawArrow(xMin, charge * 1.5, xMax, charge * 1.5, 0.01, "<>");
528 }
529 }
530
531 //charge histogram with fit result (after timing cut)
532 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + 3);
533 gPad->SetFrameFillStyle(0);
534 gPad->SetFillStyle(0);
535 TH1D* hCharge = m_chargeHistogram[iHisto];
536 if (hCharge) {
537 gPad->SetLogy();
538 hCharge->Draw();
539 hCharge->SetLineColor(1);
540 hCharge->GetXaxis()->SetTitle("charge [ADC counts]");
541 float binWidth = hCharge->GetXaxis()->GetBinUpEdge(1) - hCharge->GetXaxis()->GetBinLowEdge(1);
542 std::ostringstream ytitle;
543 ytitle << "Entries [/(" << binWidth << " ADC counts)]";
544 hCharge->GetYaxis()->SetTitle(ytitle.str().c_str());
545
546 if (m_funcForFitRange[iHisto] && m_funcForFullRange[iHisto]) {
547 m_funcForFullRange[iHisto]->Draw("same");
548 m_funcForFitRange[iHisto]->Draw("same");
549 double charge = hCharge->GetBinContent(hCharge->GetMaximumBin());
550 line->DrawLine(threshold, 0.5, threshold, charge * 2.);
551
552 if ((object = gROOT->FindObject("dummy"))) delete object;
553 std::ostringstream cut;
554 cut << "pmtChId==" << (iHisto + 1);
555 long nEntries = 0;
556 std::ostringstream summarystr[2];
557 if (LoadHisto == c_LoadForFitHeight) {
558 nEntries = m_tree->Project("dummy", "gain:efficiency", cut.str().c_str());
559 if (nEntries == 1) {
560 summarystr[0] << "gain = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
561 << m_tree->GetV1()[0];
562 latex->DrawLatex(0.875, 0.34, summarystr[0].str().c_str());
563 summarystr[1] << "efficiency = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
564 << (m_tree->GetV2()[0] * 100) << " %";
565 latex->DrawLatex(0.875, 0.29, summarystr[1].str().c_str());
566 }
567 } else if (LoadHisto == c_LoadForFitIntegral) {
568 nEntries = m_tree->Project("dummy", "gainUseIntegral:efficiencyUseIntegral", cut.str().c_str());
569 if (nEntries == 1) {
570 summarystr[0] << "gain = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
571 << m_tree->GetV1()[0];
572 latex->DrawLatex(0.875, 0.34, summarystr[0].str().c_str());
573 summarystr[1] << "efficiency = " << std::setiosflags(std::ios::fixed) << std::setprecision(1)
574 << (m_tree->GetV2()[0] * 100) << " %";
575 latex->DrawLatex(0.875, 0.29, summarystr[1].str().c_str());
576 }
577 }
578
579 if (nEntries > 1) {
580 B2WARNING("TOPGainEfficiencyCalculator : multiple entries with the same channel ID ("
581 << m_pmtChId << ") in the output TTree");
582 }
583 }
584 }
585
586 if (((iHisto + 1) % c_NChannelPerPage) == 0)
587 canvas->Print(pdfFilename.str().c_str());
588 }
589 /* not clear what is to be done here (loop condition is always false)... commented out
590 for (int iHisto = (c_NChannelPerPMT - 1) % c_NChannelPerPage + 1 ; iHisto < c_NChannelPerPage ; iHisto++) {
591 for (int iPad = 0 ; iPad < c_NPlotsPerChannel ; iPad++) {
592 canvas->cd(c_NPlotsPerChannel * (iHisto % c_NChannelPerPage) + iPad + 1);
593 gPad->SetFrameFillStyle(0);
594 gPad->SetFillStyle(0);
595 }
596 if (((iHisto + 1) % c_NChannelPerPage) == 0)
597 canvas->Print(pdfFilename.str().c_str());
598 }
599 */
600 canvas->Print((pdfFilename.str() + "]").c_str());
601
602 delete latex;
603 delete arrow;
604 delete line;
605 delete canvas;
606 if ((object = gROOT->FindObject("dummy"))) delete object;
607
608 return;
609 }
610
611 //cppcheck-suppress constParameterCallback
612 double TOPGainEfficiencyCalculatorModule::TOPGainFunc(double* var, double* par)
613 {
614
615 double pedestal = par[4];
616 double pedestalWidth = par[5];
617 double x = (var[0] - pedestal);
618
619 double output = 0;
620 double step = pedestalWidth / 100.;
621 double t = TMath::Max(step, x - pedestalWidth * 10);
622 //double t = TMath::Max( g_xStep, x ); //for test
623 while (t < x + pedestalWidth * 10) {
624 output += TMath::Gaus(x, t, pedestalWidth) * TMath::Power(t / par[3], par[1])
625 * TMath::Exp((-1) * TMath::Power(t / par[3], par[2]));
626 t += step;
627 }
628 // TF1* func = new TF1( "func", "[0]*pow(x-[4],[1])*exp(-pow(x-[4],[2])/[3])",
629
630 return par[0] * output * step;
631 }
632
634 {
635 double histo_xmax = histo->GetXaxis()->GetBinUpEdge(histo->GetXaxis()->GetNbins() - 1);
636 if (xmax > histo_xmax) xmax = histo_xmax;
637
638 int iBin = 1;
639 double peakPos = histo->GetXaxis()->GetBinCenter(iBin);
640 double peakCharge = histo->GetBinContent(iBin);
641 while (true) {
642 iBin++;
643 double x = histo->GetXaxis()->GetBinCenter(iBin);
644 if (x > xmax) break;
645
646 double binEntry = histo->GetBinContent(iBin);
647 if (binEntry > peakCharge) {
648 peakPos = x;
649 peakCharge = binEntry;
650 }
651 }
652
653 return peakPos;
654 }
655
656
657
659} // end Belle2 namespace
HistoModule()
Constructor.
Definition HistoModule.h:32
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
float m_efficiency
calculated efficiency from fitting 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_funcFitRangeIntegral
integral of fit function for a range [threshold, fitMax]
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...
float m_threshold
pulse charge threshold, which defines lower limit of fit region and efficiency calculation
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_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_histoFitRangeIntegral
integral of histogram for a range [threshold, fitMax]
float m_initialP0
initial value of the fit parameter p0
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_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)
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
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
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 &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
static double TOPGainFunc(double *var, double *par)
Fit function of pulse charge (or charge) distribution for channel(pixel)-by-channel gain extraction,...
virtual void initialize() override
Load time vs charge 2D histogram from a given input file (parameter "inputFile") and prepare hit timi...
virtual void terminate() override
Termination action.
void FitHistograms(EHistogramType LoadHisto)
Fit charge (or integrated charged) distribution to calculate gain and efficiency for each channel.
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...
commonly used functions
Definition func.h:22
Abstract base class for different kinds of events.