Belle II Software  release-06-00-14
LaserCalibratorFit.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/modules/TOPLaserCalibrator/LaserCalibratorFit.h>
10 
11 #include <framework/logging/Logger.h>
12 
13 #include <Math/PdfFuncMathCore.h>
14 #include <Math/MinimizerOptions.h>
15 #include <TFile.h>
16 #include <TTree.h>
17 
18 namespace Belle2 {
23  namespace TOP {
24 //Crystal Ball function
25  double fcnCB(double* x, double* par)
26  {
27  double m1 = par[1];
28  double s1 = par[2];
29  double a1 = par[3];
30  double n1 = par[4];
31  double f1 = ROOT::Math::crystalball_pdf(x[0], a1, n1, s1, m1);
32  return par[0] * f1;
33  }
34 
35 //double Crystal Ball function
36  double fcnCB2(double* x, double* par)
37  {
38  double m1 = par[1];
39  double s1 = par[2];
40  double a1 = par[3];
41  double n1 = par[4];
42  double m2 = m1 - par[6];
43  double s2 = par[7];
44  double a2 = par[8];
45  double n2 = par[9];
46 
47  double f1 = ROOT::Math::crystalball_pdf(x[0], a1, n1, s1, m1);
48  double f2 = ROOT::Math::crystalball_pdf(x[0], a2, n2, s2, m2);
49  return par[0] * f1 + par[5] * f2;
50  }
51 
53  m_moduleID(moduleID)
54  {
55  }
56 
58  {
59  for (auto f : m_func) {
60  delete f;
61  }
62  m_func.clear();
63 
64  for (auto h : m_hist) {
65  delete h;
66  }
67  m_hist.clear();
68  }
69 
70 //initial TF1 of all channels in one slot
71  void LaserCalibratorFit::setHist(const std::vector<TH1F*>& hist)
72  {
73  m_hist = hist;
74  for (unsigned i = 0; i < hist.size(); i++) {
75  m_func.push_back(0);
76  m_maxpos.push_back(0);
77  m_maxpos_error.push_back(0);
78  }
79  }
80 
81  double LaserCalibratorFit::getFitChisq(unsigned channel)
82  {
83  if (m_func[channel]) {
84  return m_func[channel]->GetChisquare();
85  } else {
86  return -9;
87  };
88  }
89 
90  int LaserCalibratorFit::fitChannel(unsigned channel)
91  {
92  if (channel > m_hist.size()) {
93  B2WARNING("Wrong channel!");
94  return 0;
95  }
96  if (!m_hist[channel]) {
97  B2WARNING("No Evts. in channel " << channel);
98  return 0;
99  }
100  //require at least 10 evts for each fit
101  if (m_hist[channel]->GetEntries() < 10) {
102  B2WARNING("Too little Evts. for fitting (Evts. < 10)!");
103  return 0;
104  }
105  m_hist[channel]->SetAxisRange(m_xmin, m_xmax);
106  m_maxpos[channel] = m_hist[channel]->GetXaxis()->GetBinCenter(m_hist[channel]->GetMaximumBin());
107  m_hist[channel]->SetAxisRange(m_maxpos[channel] - 1.5, m_maxpos[channel] + 2);
108  m_maxpos_error[channel] = m_hist[channel]->GetXaxis()->GetBinWidth(m_hist[channel]->GetMaximumBin()); // Error = bin width ?
109  if (m_fitMethod == "gauss" || m_fitMethod == "gaus") {
110  m_func[channel] = makeGFit(channel);
111  } else if (m_fitMethod == "cb") {
112  m_func[channel] = makeCBFit(channel);
113  } else if (m_fitMethod == "cb2") {
114  m_func[channel] = makeCB2Fit(channel, 0);
115  } else {
116  B2WARNING("No matched fit method!");
117  return 0;
118  }
119 
120  return 1;
121  }
122 
123  void LaserCalibratorFit::writeFile(const std::string& outfile)
124  {
125  auto file = new TFile(outfile.c_str(), "RECREATE");
126  auto otree = new TTree("fits", "fitted times");
127 
128  unsigned channel = 0;
129  double maxpos = 0;
130 
131  otree->Branch("maxpos", &maxpos, "maxpos/D");
132 
133  if (m_fitMethod == "gauss") {
134  double parms[3];
135  double parmErrs[3];
136  otree->Branch("channel", &channel, "channel/I");
137  otree->Branch("norm", &(parms[0]), "norm/D");
138  otree->Branch("time", &(parms[1]), "time/D");
139  otree->Branch("reso", &(parms[2]), "reso/D");
140  otree->Branch("normErr", &(parmErrs[0]), "normErr/D");
141  otree->Branch("timeErr", &(parmErrs[1]), "timeErr/D");
142  otree->Branch("resoErr", &(parmErrs[2]), "resoErr/D");
143 
144  for (auto& f : m_func) {
145  maxpos = m_maxpos[channel];
146  if (f) {
147  f->GetParameters(parms);
148  for (int iPar = 0; iPar < 3; iPar++)
149  parmErrs[iPar] = f->GetParError(iPar);
150  otree->Fill();
151  channel++;
152  }
153  }
154  } else if (m_fitMethod == "cb2") {
155  double parms[8];
156  double parmErrs[8];
157 
158  double time2 = 0;
159  otree->Branch("channel", &channel, "channel/I");
160  otree->Branch("norm1", &(parms[0]), "norm1/D");
161  otree->Branch("time1", &(parms[1]), "time1/D");
162  otree->Branch("reso1", &(parms[2]), "reso1/D");
163  otree->Branch("alpha_CB", &(parms[3]), "alpha_CB/D");
164  otree->Branch("n_CB", &(parms[4]), "n_CB/D");
165  otree->Branch("norm2", &(parms[5]), "norm2/D");
166  otree->Branch("dt12", &(parms[6]), "dt12/D");
167  otree->Branch("reso2", &(parms[7]), "reso2/D");
168  otree->Branch("time2", &time2, "time2/D");
169 
170  otree->Branch("norm1Err", &(parmErrs[0]), "norm1Err/D");
171  otree->Branch("time1Err", &(parmErrs[1]), "time1Err/D");
172  otree->Branch("reso1Err", &(parmErrs[2]), "reso1Err/D");
173  otree->Branch("alpha_CBErr", &(parmErrs[3]), "alpha_CBErr/D");
174  otree->Branch("n_CBErr", &(parmErrs[4]), "n_CBErr/D");
175  otree->Branch("norm2Err", &(parmErrs[5]), "norm2Err/D");
176  otree->Branch("dt12Err", &(parmErrs[6]), "dt12Err/D");
177  otree->Branch("reso2Err", &(parmErrs[7]), "reso2Err/D");
178 
179 
180  for (auto& f : m_func) {
181  maxpos = m_maxpos[channel];
182  if (f) {
183  f->GetParameters(parms);
184  for (int iPar = 0; iPar < 8; iPar++)
185  parmErrs[iPar] = f->GetParError(iPar);
186  otree->Fill();
187  channel++;
188  }
189  }
190  } else if (m_fitMethod == "cb") {
191  double parms[5];
192  double parmErrs[5];
193 
194  otree->Branch("channel", &channel, "channel/I");
195  otree->Branch("norm", &(parms[0]), "norm/D");
196  otree->Branch("time", &(parms[1]), "time/D");
197  otree->Branch("reso", &(parms[2]), "reso/D");
198  otree->Branch("alpha_CB", &(parms[3]), "alpha_CB/D");
199  otree->Branch("n_CB", &(parms[4]), "n_CB/D");
200 
201  otree->Branch("normErr", &(parmErrs[0]), "normErr/D");
202  otree->Branch("timeErr", &(parmErrs[1]), "timeErr/D");
203  otree->Branch("resoErr", &(parmErrs[2]), "resoErr/D");
204  otree->Branch("alpha_CBErr", &(parmErrs[3]), "alpha_CBErr/D");
205  otree->Branch("n_CBErr", &(parmErrs[4]), "n_CBErr/D");
206 
207  for (auto& f : m_func) {
208  maxpos = m_maxpos[channel];
209  if (f) {
210  f->GetParameters(parms);
211  for (int iPar = 0; iPar < 5; iPar++)
212  parmErrs[iPar] = f->GetParError(iPar);
213  otree->Fill();
214  channel++;
215  }
216  }
217  } else {
218  B2WARNING("Nothing be written to files!");
219  return;
220  }
221  for (auto& h : m_hist) {
222  if (h && h->GetEntries() >= 10) {
223  h->Write();
224  }
225  }
226  otree->Write();
227  delete otree;
228  file->Close();
229  delete file;
230  }
231 
232 // single Gaussian fit
233  TF1* LaserCalibratorFit::makeGFit(unsigned channel)
234  {
235  TH1F* h = m_hist[channel];
236  double m = h->GetMean();
237  double w = h->GetRMS();
238  h->Fit("gaus", "Q", "", m - 2.*w, m + 4.*w);
239  double parms[3];
240  TF1* func = h->GetFunction("gaus");
241  func->GetParameters(parms);
242  func->SetNpx(1000);
243  h->Fit("gaus", "Q", "", m - w, m + w);
244  func = h->GetFunction("gaus");
245  m_fitT = parms[1];
246  m_fitTErr = func->GetParError(1);
247  return func;
248  }
249 
250 // single Crystal Ball fit
251  TF1* LaserCalibratorFit::makeCBFit(unsigned channel)
252  {
253  TH1F* h = m_hist[channel];
254  auto func = new TF1("fcnCB", fcnCB, m_xmin, m_xmax, 5);
255 
256  double parms[5];
257  parms[0] = 1;
258  parms[1] = h->GetMean();
259  parms[2] = h->GetRMS();
260  parms[3] = -0.5;
261  parms[4] = 4;
262 
263  func->SetParameters(parms);
264  func->SetNpx(1000);
265 
266  func->SetParName(0, "norm");
267  func->SetParName(1, "time");
268  func->SetParName(2, "sigma");
269  func->SetParName(3, "alpha_CB");
270  func->SetParName(4, "n_CB");
271 
272  //func->SetParLimits(1,par[1]-0.2,par[1]+0.2);
273  //func->SetParLimits(2,par[2]-0.02,par[2]+0.08);
274  func->SetParLimits(3, -5, 0);
275  func->SetParLimits(4, 0, 10);
276 
277  h->Fit(func, "Q", "");
278  if (fabs(m_maxpos[channel] - parms[1]) < parms[2]) {
279  m_fitT = parms[1];
280  m_fitTErr = func->GetParError(1);
281  } else {
282  m_fitT = m_maxpos[channel];
283  m_fitTErr = m_maxpos_error[channel];
284  }
285  return func;
286  }
287 
288 // double Crystal Ball fit
289  TF1* LaserCalibratorFit::makeCB2Fit(unsigned channel, bool minOut)
290  {
291  TH1F* h = m_hist[channel];
292  auto func = new TF1("fcnCB2", fcnCB2, m_xmin, m_xmax, 8);
293 
294  double vdt[8] = {0.272, 0.242, 0.208, 0.178, 0.113, 0.082, 0.0485, 0.017}; //input para. from MC study, need further studies
295  double parms[8];
296  //the input para. need further studies
297  parms[0] = 1;
298  parms[1] = 0.6;
299  parms[2] = 0.1;
300  parms[3] = -0.5;
301  parms[4] = 4;
302  parms[5] = 1;
303  parms[6] = vdt[(channel) / 64]; //refers to a typical time separation of two main peaks
304  //parms[6] = 0.3;
305  parms[7] = 0.1;
306 
307  func->SetParameters(parms);
308  func->SetNpx(1000);
309 
310  func->SetParName(0, "norm1");
311  func->SetParName(1, "time1");
312  func->SetParName(2, "sigma1");
313  func->SetParName(3, "alpha1_CB");
314  func->SetParName(4, "n1_CB");
315  func->SetParName(5, "norm2");
316  func->SetParName(6, "dt12");
317  func->SetParName(7, "sigma2");
318  func->SetParName(8, "alpha2_CB");
319  func->SetParName(9, "n2_CB");
320 
321  func->SetParLimits(1, parms[1] - 0.25, parms[1] + 0.15);
322  //func->SetParLimits(2,par[2]-0.02,par[2]+0.08);
323  func->SetParLimits(3, -5, 0);
324  func->SetParLimits(4, 0, 10);
325  func->SetParLimits(6, parms[6] * 0.7, parms[6] * 1.5);
326  func->SetParLimits(8, -5, 0);
327  func->SetParLimits(9, 0, 10);
328 
329  ROOT::Math::MinimizerOptions::SetDefaultMaxFunctionCalls(50000); //set to a large number for a test
330  if (minOut) {
331  h->Fit(func, "Q", "");
332  } else {
333  h->Fit(func);
334  }
335  m_fitT = parms[1];
336  m_fitTErr = func->GetParError(1);
337  return func;
338  }
339  } // TOP namespace
341 }// Belle2 namespace
TF1 * makeCB2Fit(unsigned channel, bool minOut)
Fit process using double Crystal Ball fuction.
void setHist(const std::vector< TH1F * > &hist)
set time hist of all channels in one moduleID
std::vector< TH1F * > m_hist
time hist of 512 channels
TF1 * makeCBFit(unsigned channel)
Fit process using single Crystal Ball fuction.
std::vector< TF1 * > m_func
fitting function
double m_fitTErr
error on the mean position estimated by the fit
LaserCalibratorFit(unsigned moduleID)
Constructor.
double m_xmax
fitting upper-edge
std::vector< double > m_maxpos_error
error on the center positon of hist max bin
int fitChannel(unsigned channel)
fit for a specific channel
void writeFile(const std::string &outfile)
write fit result to a root file
double m_fitT
mean position after fit
std::string m_fitMethod
fitting method
TF1 * makeGFit(unsigned channel)
Fit process using single gaussian function.
std::vector< double > m_maxpos
center positon of hist max bin
double getFitChisq(unsigned channel)
get chi^2 in the fit
Abstract base class for different kinds of events.