Belle II Software  release-08-01-10
TOPCommonT0BFAlgorithm.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/TOPCommonT0BFAlgorithm.h>
10 #include <top/dbobjects/TOPCalCommonT0.h>
11 #include <math.h>
12 #include <TROOT.h>
13 #include <TF1.h>
14 #include <TFile.h>
15 #include <TTree.h>
16 #include <string>
17 
18 using namespace std;
19 
20 namespace Belle2 {
25  namespace TOP {
26 
27  TOPCommonT0BFAlgorithm::TOPCommonT0BFAlgorithm():
28  CalibrationAlgorithm("TOPCommonT0BFCollector")
29  {
30  setDescription("Calibration algorithm for common T0 calibration "
31  "with a fit of bunch finder residuals (method BF)");
32 
33  }
34 
36  {
37  gROOT->SetBatch();
38 
39  // get histogram to fit and check if statistics is sufficient
40 
41  auto h = getHistogram();
42  if (not h) {
43  B2ERROR("TOPCommonT0BFAlgorithm: no histogram to fit");
44  return c_NotEnoughData;
45  }
46 
47  int numEntries = h->GetSumOfWeights();
48  if (numEntries < m_minEntries) {
49  B2ERROR("TOPCommonT0BFAlgorithm: too few entries to fit the histogram");
50  return c_NotEnoughData;
51  }
52 
53  m_bunchTimeSep = h->GetXaxis()->GetXmax() - h->GetXaxis()->GetXmin();
54 
55  // construct file name, open output root file and book output tree
56 
57  const auto& expRun = getRunList();
58  string expNo = to_string(expRun[0].first);
59  while (expNo.length() < 4) expNo.insert(0, "0");
60  string runNo = to_string(expRun[0].second);
61  while (runNo.length() < 5) runNo.insert(0, "0");
62  string outputFileName = "commonT0-e" + expNo + "-r" + runNo + ".root";
63  auto* file = TFile::Open(outputFileName.c_str(), "recreate");
64 
65  auto* tree = new TTree("tree", "common T0 calibration results");
66  tree->Branch<int>("expNum", &m_expNo);
67  tree->Branch<int>("runNum", &m_runNo);
68  tree->Branch<int>("runLast", &m_runLast);
69  tree->Branch<float>("fitted_offset", &m_fittedOffset);
70  tree->Branch<float>("offset", &m_offset);
71  tree->Branch<float>("offsetErr", &m_offsetError);
72  tree->Branch<float>("sigma", &m_sigmaCore);
73  tree->Branch<float>("sigmaTail", &m_sigmaTail);
74  tree->Branch<float>("tailFract", &m_tailFract);
75  tree->Branch<float>("chi2", &m_chi2);
76  tree->Branch<float>("integral", &m_integral);
77  tree->Branch<int>("nEvt", &m_numEvents);
78  tree->Branch<int>("fitStatus", &m_fitStatus);
79 
80  m_expNo = expRun[0].first;
81  m_runNo = expRun[0].second;
82  m_runLast = expRun.back().second;
83 
84  // fit histogram
85 
86  if (numEntries > m_cutoffEntries and m_tailFractInit > 0) {
87  int status = fitDoubleGaus(h);
88  if (status != 0) fitSingleGaus(h);
89  } else {
90  fitSingleGaus(h);
91  }
92  tree->Fill();
93 
94  // write the results and close the file
95 
96  h->Write();
97  file->Write();
98  file->Close();
99 
100  // check the results and return if not good enough
101 
102  if (m_fitStatus != 0 or m_offsetError > m_minError) return c_NotEnoughData;
103 
104  // otherwise create and import payload to DB
105 
106  auto* commonT0 = new TOPCalCommonT0(m_offset, m_offsetError);
107  saveCalibration(commonT0);
108 
109  return c_OK;
110  }
111 
112  std::shared_ptr<TH1F> TOPCommonT0BFAlgorithm::getHistogram()
113  {
114  auto h1a = getObjectPtr<TH1F>("offset_a");
115  auto h1b = getObjectPtr<TH1F>("offset_b");
116  if (not h1a) {
117  B2ERROR("TOPCommonT0BFAlgorithm: histogram 'offset_a' not found");
118  return 0;
119  }
120  if (not h1b) {
121  B2ERROR("TOPCommonT0BFAlgorithm: histogram 'offset_b' not found");
122  return 0;
123  }
124 
125  int halfbins = h1a->GetNbinsX() / 2;
126  if (abs(h1a->GetMaximumBin() - halfbins) < abs(h1b->GetMaximumBin() - halfbins)) {
127  return h1a;
128  } else {
129  return h1b;
130  }
131  }
132 
133  int TOPCommonT0BFAlgorithm::fitSingleGaus(std::shared_ptr<TH1F> h)
134  {
135  double sum = h->GetSumOfWeights();
136  if (sum < 5) return 5;
137  double maxPosition = h->GetBinCenter(h->GetMaximumBin());
138  double binWidth = h->GetBinWidth(1);
139  double xmin = h->GetXaxis()->GetXmin();
140  double xmax = h->GetXaxis()->GetXmax();
141 
142  auto* func = new TF1("func1g",
143  "[0] + [1]/sqrt(2*pi)/[3]*exp(-0.5*((x-[2])/[3])**2)",
144  xmin, xmax);
145  func->SetParameter(0, 0);
146  func->SetParameter(1, sum * binWidth);
147  func->SetParameter(2, maxPosition);
148  func->SetParameter(3, m_sigmaCoreInit);
149 
150  int status = h->Fit(func, "LRSQ");
151 
152  m_fittedOffset = func->GetParameter(2);
154  m_offsetError = func->GetParError(2);
155  m_sigmaCore = func->GetParameter(3);
156  m_sigmaTail = 0;
157  m_tailFract = 0;
158  m_chi2 = func->GetChisquare() / func->GetNDF();
159  m_integral = func->GetParameter(1) / binWidth;
160  m_numEvents = sum;
161  m_fitStatus = status;
162 
163  return status;
164  }
165 
166 
167  int TOPCommonT0BFAlgorithm::fitDoubleGaus(std::shared_ptr<TH1F> h)
168  {
169  double sum = h->GetSumOfWeights();
170  if (sum < 7) return 7;
171  double maxPosition = h->GetBinCenter(h->GetMaximumBin());
172  double binWidth = h->GetBinWidth(1);
173  double xmin = h->GetXaxis()->GetXmin();
174  double xmax = h->GetXaxis()->GetXmax();
175 
176  auto* func = new TF1("func2g",
177  "[0] + [1]*((1-[4])/sqrt(2*pi)/[3]*exp(-0.5*((x-[2])/[3])**2)"
178  "+ [4]/sqrt(2*pi)/[5]*exp(-0.5*((x-[2])/[5])**2))",
179  xmin, xmax);
180  func->SetParameter(0, 0);
181  func->SetParameter(1, sum * binWidth);
182  func->SetParameter(2, maxPosition);
183  func->SetParameter(3, m_sigmaCoreInit);
184  func->SetParameter(4, m_tailFractInit);
185  func->SetParameter(5, m_sigmaTailInit);
186 
187  int status = h->Fit(func, "LRSQ");
188 
189  m_fittedOffset = func->GetParameter(2);
191  m_offsetError = func->GetParError(2);
192  m_sigmaCore = func->GetParameter(3);
193  m_sigmaTail = func->GetParameter(5);
194  m_tailFract = func->GetParameter(4);
195  m_chi2 = func->GetChisquare() / func->GetNDF();
196  m_integral = func->GetParameter(1) / binWidth;
197  m_numEvents = sum;
198  m_fitStatus = status;
199 
200  return status;
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.
Common T0 calibration constant.
int fitDoubleGaus(std::shared_ptr< TH1F > h)
Fit double gaus w/ same mean + constant.
float m_offsetError
error on fitted offset
int m_minEntries
minimal number of histogram entries to perform fit
float m_offset
wrap-around of fitted offset (= common T0)
virtual EResult calibrate() final
algorithm implementation
float m_tailFract
tail fraction (set to 0 for single gauss fit)
int m_numEvents
number of all events in the histogram
int m_cutoffEntries
cutoff entries for single/double gaussian fit
double m_sigmaTailInit
tail gaussian sigma [ns]
double m_minError
minimal commonT0 uncertainty [ns] to declare c_OK
double m_tailFractInit
fraction of tail gaussian
double m_sigmaCoreInit
core gaussian sigma [ns]
float m_integral
number of fitted signal events
float m_sigmaTail
tail gaussian sigma (set to 0 for single gauss fit)
double m_bunchTimeSep
bunch separation in time [ns]
int fitSingleGaus(std::shared_ptr< TH1F > h)
Fit single gaus + constant.
std::shared_ptr< TH1F > getHistogram()
Returns histogram to be fitted.
Abstract base class for different kinds of events.