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) {
137 m_pulseHeight->setParameters(m_slot, m_channel, m_x0, m_p1, m_p2);
138 m_thresholdEffi->setThrEff(m_slot, m_channel, std::min(m_effi, 1.0f), m_xmin);
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();
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
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
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.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
Pulse height parameterizations for all 512 channels of 16 modules.
Class to store the threshold efficiency (i.e.
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_x0
fitted distribution parameter x0 [ADC counts]
int m_numPhot
number of photons (histogram entries)
TOPCalChannelPulseHeight * m_pulseHeight
parametrized PH distributions
std::shared_ptr< T > getObjectPtr(const std::string &name, const std::vector< Calibration::ExpRun > &requestedRuns)
Get calibration data object by name and list of runs, the Merge function will be called to generate t...
commonly used functions
Definition func.h:22
Abstract base class for different kinds of events.
STL namespace.