Belle II Software  release-08-01-10
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 
17 using namespace std;
18 
19 namespace Belle2 {
24  namespace TOP {
25 
26  TOPPulseHeightAlgorithm::TOPPulseHeightAlgorithm():
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) {
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();
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)
EResult
The result of calibration.
@ c_OK
Finished successfuly =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
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.