Belle II Software development
TOPPulseHeightAlgorithm.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#include <top/calibration/TOPPulseHeightAlgorithm.h>
10#include "TROOT.h"
11#include <TDirectory.h>
12#include <TF1.h>
13#include <TMath.h>
14#include <string>
15#include <algorithm>
16
17using namespace std;
18
19namespace Belle2 {
24 namespace TOP {
25
27 CalibrationAlgorithm("TOPPulseHeightCollector")
28 {
29 setDescription("Calibration algorithm for pulse-height and threshold efficiency calibration");
30 }
31
33 {
34 gROOT->SetBatch();
35
36 // construct file name, open output root file and book output tree
37
38 const auto& expRun = getRunList();
39 string expNo = to_string(expRun[0].first);
40 while (expNo.length() < 4) expNo.insert(0, "0");
41 string runNo = to_string(expRun[0].second);
42 while (runNo.length() < 5) runNo.insert(0, "0");
43 string outputFileName = "pulseHeight-e" + expNo + "-r" + runNo + ".root";
44 m_file = TFile::Open(outputFileName.c_str(), "recreate");
45
46 m_tree = new TTree("tree", "pulse-height calibration results");
47 m_tree->Branch<int>("slot", &m_slot);
48 m_tree->Branch<unsigned>("channel", &m_channel);
49 m_tree->Branch<int>("numPhot", &m_numPhot);
50 m_tree->Branch<float>("x0", &m_x0);
51 m_tree->Branch<float>("p1", &m_p1);
52 m_tree->Branch<float>("p2", &m_p2);
53 m_tree->Branch<float>("x0err", &m_x0err);
54 m_tree->Branch<float>("p1err", &m_p1err);
55 m_tree->Branch<float>("p2err", &m_p2err);
56 m_tree->Branch<float>("effi", &m_effi);
57 m_tree->Branch<float>("meanHist", &m_meanHist);
58 m_tree->Branch<float>("meanFunc", &m_meanFunc);
59 m_tree->Branch<float>("chi2", &m_chi2);
60 m_tree->Branch<int>("ndf", &m_ndf);
61 m_tree->Branch<int>("fitStatus", &m_fitStatus);
62 m_tree->Branch<bool>("good", &m_good);
63
64 // write-out control histograms
65
66 auto h1a = getObjectPtr<TH1F>("time");
67 if (h1a) h1a->Write();
68 auto h1b = getObjectPtr<TH1F>("time_sel");
69 if (h1b) h1b->Write();
70 auto h2a = getObjectPtr<TH2F>("ph_vs_width");
71 if (h2a) h2a->Write();
72 auto h2b = getObjectPtr<TH2F>("ph_vs_width_sel");
73 if (h2b) h2b->Write();
74
75 // create payloads for storing results
76
79
80 // fit histograms
81
82 TDirectory* oldDir = gDirectory;
83 int nsucc = 0;
84 for (int slot = 1; slot <= 16; slot++) {
85 m_slot = slot;
86 string name = "ph_slot_" + to_string(slot);
87 auto h = getObjectPtr<TH2F>(name);
88 if (not h) continue;
89
90 name = "slot_" + to_string(slot);
91 oldDir->mkdir(name.c_str())->cd();
92 h->Write();
93
94 int n = fitChannels(h);
95 B2INFO("slot " << slot << ": " << n << "/512 channels successfully fitted");
96 nsucc += n;
97 }
98
99 // write the results and close the file
100
101 m_file->Write();
102 m_file->Close();
103
104 // check the results and return if fraction of well fitted too small
105
106 if (nsucc / 8192.0 < m_minCalibrated) {
107 delete m_pulseHeight;
108 delete m_thresholdEffi;
109 return c_NotEnoughData;
110 }
111
112 // otherwise import payloads to DB
113
116
117 return c_OK;
118 }
119
120
121 int TOPPulseHeightAlgorithm::fitChannels(std::shared_ptr<TH2F> h2d)
122 {
123 int n = 0;
124
125 for (int ch = 0; ch < h2d->GetNbinsX(); ch++) {
126 m_channel = ch;
127 string chan = to_string(ch);
128 while (chan.length() < 3) chan.insert(0, "0");
129 string name = "chan_" + chan;
130 auto* h = h2d->ProjectionY(name.c_str(), ch + 1, ch + 1);
131 string title = "slot " + to_string(m_slot) + " channel " + to_string(ch);
132 h->SetTitle(title.c_str());
133
134 auto status = fitPulseHeight(h);
135
136 if (status == 0 and m_good) {
139 n++;
140 }
141 }
142
143 return n;
144 }
145
146
148 {
149 m_numPhot = h->GetSumOfWeights();
150 if (m_numPhot < std::max(m_minEntries, 5)) return -1;
151
152 double xmin = h->GetXaxis()->GetXmin();
153 double xmax = h->GetXaxis()->GetXmax();
154
155 auto* func = new TF1("func", "[0]*x/[1]*exp(-pow(x/[1],[2]))", xmin, xmax);
156
157 double p2 = 1.0;
158 m_meanHist = h->GetMean();
159 double x0 = m_meanHist / 3; // for p2 = 1 only
160 func->SetParameter(0, m_numPhot / x0); // for p2 = 1 only
161 func->SetParameter(1, x0);
162 func->SetParameter(2, p2);
163
164 int status = h->Fit(func, "LRSQ", "", m_xmin, xmax);
165
166 m_x0 = func->GetParameter(1);
167 m_p1 = 1.0;
168 m_p2 = func->GetParameter(2);
169 m_x0err = func->GetParError(1);
170 m_p1err = 0;
171 m_p2err = func->GetParError(2);
172 m_chi2 = func->GetChisquare();
173 m_effi = getEfficiency(h, func);
174 m_meanFunc = TMath::Gamma((m_p1 + 2) / m_p2) / TMath::Gamma((m_p1 + 1) / m_p2) * m_x0;
175 m_fitStatus = status;
176 m_good = (m_chi2 / m_ndf < 10 and m_p2 > 0.5 and m_p2 < 5);
177 m_tree->Fill();
178
179 return status;
180 }
181
182
183 double TOPPulseHeightAlgorithm::getEfficiency(TH1D* h, TF1* func)
184 {
185 double fbelow = 0;
186 double fabove = 0;
187 double count = 0;
188 m_ndf = -func->GetNumberFreeParameters();
189 for (int i = 0; i < h->GetNbinsX(); i++) {
190 double x = h->GetBinCenter(i + 1);
191 if (x > m_xmin) {
192 fabove += func->Eval(x);
193 count += h->GetBinContent(i);
194 if (h->GetBinContent(i) > 0) m_ndf++;
195 } else {
196 fbelow += func->Eval(x);
197 }
198 }
199 double integral = (fbelow + fabove) * count / fabove;
200 return h->GetSumOfWeights() / integral;
201 }
202
203
204 } // end namespace TOP
206} // end namespace Belle2
Base class for calibration algorithms.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
void setDescription(const std::string &description)
Set algorithm description (in constructor)
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
EResult
The result of calibration.
@ c_OK
Finished successfully =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
Pulse height parameterizations for all 512 channels of 16 modules.
void setParameters(int moduleID, unsigned channel, double x0, double p1, double p2)
Sets calibration for a single channel and switches status to calibrated.
Class to store the threshold efficiency (i.e.
void setThrEff(int moduleID, unsigned channel, float ThrEff, short offlineThreshold)
Sets the threshold efficiency and correspolding threshold for a single channel and switches status to...
int fitChannels(std::shared_ptr< TH2F > h)
Fit pulse-height distributions of a single module.
int m_minEntries
minimal number of histogram entries to perform fit
double m_xmin
fit range lower limit [ADC counts]
double getEfficiency(TH1D *h, TF1 *func)
Calculate and return threshold efficiency.
int fitPulseHeight(TH1D *h)
Fit pulse-height distribution of a single channel with P(x) = (x/x0)^p1 * exp(-(x/x0)^p2) and p1 = 1.
virtual EResult calibrate() final
algorithm implementation
TOPCalChannelThresholdEff * m_thresholdEffi
threshold efficiencies
float m_p1
fitted distribution parameter p1
float m_meanFunc
fitted distribution mean value
float m_p2
fitted distribution parameter p2
float m_x0err
error on x0 [ADC counts]
float m_x0
fitted distribution parameter x0 [ADC counts]
int m_numPhot
number of photons (histogram entries)
TOPCalChannelPulseHeight * m_pulseHeight
parametrized PH distributions
Abstract base class for different kinds of events.
STL namespace.