Belle II Software  release-08-01-10
XTCalibrationAlgorithm.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 #include <cdc/calibration/XTCalibrationAlgorithm.h>
9 #include <cdc/calibration/XTFunction.h>
10 #include <cdc/geometry/CDCGeometryPar.h>
11 #include <cdc/dbobjects/CDCXtRelations.h>
12 
13 #include <TError.h>
14 #include <TStopwatch.h>
15 #include <TROOT.h>
16 #include <TProfile.h>
17 #include <TF1.h>
18 #include <TFile.h>
19 #include <TTree.h>
20 
21 #include <iostream>
22 #include <memory>
23 
24 #include <framework/database/DBObjPtr.h>
25 
26 using namespace std;
27 using namespace Belle2;
28 using namespace CDC;
29 
30 typedef std::array<float, 3> array3;
31 XTCalibrationAlgorithm::XTCalibrationAlgorithm() : CalibrationAlgorithm("CDCCalibrationCollector")
32 {
34  " -------------------------- XT Calibration Algorithm -------------------------\n"
35  );
36 }
37 
39 {
40 
41  B2INFO("create and fill histo");
42  /*Create histogram*/
43  for (int i = 0; i < 56; ++i) {
44  for (int lr = 0; lr < 2; ++lr) {
45  for (int al = 0; al < m_nAlphaBins; ++al) {
46  for (int th = 0; th < m_nThetaBins; ++th) {
47  m_hProf[i][lr][al][th] = new TProfile(Form("m_hProf%d_%d_%d_%d", i, lr, al, th),
48  Form("(L=%d)-(lr=%d)-(#alpha=%3.0f)-(#theta=%3.0f); Drift time (ns);Drift Length (cm)",
49  i, lr, m_iAlpha[al], m_iTheta[th]), 210, -20, 600, 0, 1.2, "i");
50  m_hist2d[i][lr][al][th] = new TH2F(Form("h%d_%d_%d_%d", i, lr, al, th),
51  Form("(L=%d)-(lr=%d)-(#alpha=%3.0f)-(#theta=%3.0f); Drift time (ns);Drift Length (cm)",
52  i, lr, m_iAlpha[al], m_iTheta[th]), 210, -20, 600, 110, 0, 1.2);
53  if (lr == 1)
54  m_hist2dDraw[i][al][th] = new TH2F(Form("h_draw%d_%d_%d", i, al, th),
55  Form("(L=%d)-(#alpha=%3.0f)-(#theta=%3.0f); Drift time (ns);Drift Length (cm)",
56  i, m_iAlpha[al], m_iTheta[th]), 210, -20, 600, 220, -1.2, 1.2);
57  }
58  }
59  }
60  }
61 
62  /* Read data and make histo*/
63 
64  auto tree = getObjectPtr<TTree>("tree");
65 
66  UChar_t lay;
67  Float_t dt;
68  Float_t dx;
69  Float_t Pval, alpha, theta;
70  Float_t ndf;
71 
72  tree->SetBranchAddress("lay", &lay);
73  tree->SetBranchAddress("t", &dt);
74  tree->SetBranchAddress("x_u", &dx);
75  tree->SetBranchAddress("alpha", &alpha);
76  tree->SetBranchAddress("theta", &theta);
77  tree->SetBranchAddress("Pval", &Pval);
78  tree->SetBranchAddress("ndf", &ndf);
79 
80  /* Disable unused branch */
81  std::vector<TString> list_vars = {"lay", "t", "x_u", "alpha", "theta", "Pval", "ndf"};
82  tree->SetBranchStatus("*", 0);
83 
84  for (TString brname : list_vars) {
85  tree->SetBranchStatus(brname, 1);
86  }
87 
88 
89  int al = 0;
90  int th = 0;
91  TStopwatch time;
92  time.Start();
93  const Long64_t nEntries = tree->GetEntries();
94  B2INFO("Number of entries " << nEntries);
95  for (Long64_t i = 0; i < nEntries; ++i) {
96  tree->GetEntry(i);
97 
98  if (Pval < m_minPval || ndf < m_minNdf) continue;
99 
100  for (int k = 0; k < m_nAlphaBins; ++k) {
101  if (alpha < m_upperAlpha[k]) {
102  al = k;
103  break;
104  }
105  }
106  for (int j = 0; j < m_nThetaBins; ++j) {
107  if (theta < m_upperTheta[j]) {
108  th = j;
109  break;
110  }
111  }
112  int lr = dx > 0 ? c_Right : c_Left;
113  if (m_LRseparate) {
114  m_hProf[lay][lr][al][th]->Fill(dt, abs(dx));
115  m_hist2d[lay][lr][al][th]->Fill(dt, abs(dx));
116  } else {
117  m_hProf[lay][0][al][th]->Fill(dt, abs(dx));
118  m_hist2d[lay][0][al][th]->Fill(dt, abs(dx));
119  m_hProf[lay][1][al][th]->Fill(dt, abs(dx));
120  m_hist2d[lay][1][al][th]->Fill(dt, abs(dx));
121  }
122  m_hist2dDraw[lay][al][th]->Fill(dt, dx);
123  }
124  time.Stop();
125  B2INFO("Time to fill histograms: " << time.RealTime() << "s");
126  // time.Print();
127 }
128 
130 {
131  gROOT->SetBatch(1);
132  gPrintViaErrorHandler = true; // Suppress huge log output from TMinuit
133  gErrorIgnoreLevel = 3001;
134  B2INFO("Start calibration");
135 
136 
137  const auto exprun = getRunList()[0];
138  B2INFO("ExpRun used for DB Geometry : " << exprun.first << " " << exprun.second);
139  updateDBObjPtrs(1, exprun.second, exprun.first);
140  B2INFO("Creating CDCGeometryPar object");
142 
143  prepare();
144  createHisto();
145 
146  B2INFO("Start Fitting");
147  std::unique_ptr<XTFunction> xt;
148  for (int l = 0; l < 56; ++l) {
149  for (int lr = 0; lr < 2; ++lr) {
150  for (int al = 0; al < m_nAlphaBins; ++al) {
151  for (int th = 0; th < m_nThetaBins; ++th) {
152  if (m_hist2d[l][lr][al][th]->GetEntries() < m_minEntriesRequired) {
153  m_fitStatus[l][lr][al][th] = FitStatus::c_lowStat;
154  continue;
155  }
156  double p0, p1, tmin;
157  TF1* fpol1;
158  if (m_useSliceFit) {
159  m_hist2d[l][lr][al][th]->FitSlicesY(0, 0, -1, 5);
160  m_hist2d_1[l][lr][al][th] = (TH1F*)gDirectory->Get(Form("h%d_%d_%d_%d_1", l, lr, al, th));
161  if (!m_hist2d_1[l][lr][al][th]) {
162  m_fitStatus[l][lr][al][th] = FitStatus::c_lowStat;
163  B2WARNING("Error, not found results of slices fit");
164  continue;
165  }
166  m_hist2d_1[l][lr][al][th]->Fit("pol1", "Q", "", 30, 60);
167  fpol1 = (TF1*)m_hProf[l][lr][al][th]->GetFunction("pol1");
168  } else {
169  /*Set Error for low statistic bin*/
170  for (int n = 0; n < m_hProf[l][lr][al][th]->GetNbinsX(); ++n) {
171  if (m_hProf[l][lr][al][th]->GetBinEntries(n) < 5 && m_hProf[l][lr][al][th]->GetBinEntries(n) > 1) {
172  m_hProf[l][lr][al][th]->SetBinError(n, 0.3 / m_hProf[l][lr][al][th]->GetBinEntries(n));
173  }
174  }
175  m_hProf[l][lr][al][th]->Fit("pol1", "Q", "", 30, 60);
176  fpol1 = (TF1*)m_hProf[l][lr][al][th]->GetFunction("pol1");
177  }
178 
179  if (fpol1) {
180  //determine tmin in fitting
181  p0 = fpol1->GetParameter(0);
182  p1 = fpol1->GetParameter(1);
183  tmin = -1 * p0 / p1 + 15;
184  } else {
185  p0 = 0;
186  p1 = 0.005;
187  tmin = 12;
188  }
189 
190  // B2INFO("layer " << l << ", lr " << lr << ", alpha " << m_iAlpha[al] << ", theta " << m_iTheta[th]);
191  if (m_useSliceFit) { // if slice fit results exist.
192  xt.reset(new XTFunction(m_hist2d_1[l][lr][al][th], m_xtMode));
193  } else { // from TProfile.
194  xt.reset(new XTFunction(m_hProf[l][lr][al][th], m_xtMode));
195  }
196 
197  if (m_bField) {
198  int ial_old = 0;
199  int ith_old = 0;
200  for (int k = 0; k < m_nAlphaBins; ++k) {
201  if (m_iAlpha[al] < m_upperAlpha[k]) {
202  ial_old = k;
203  break;
204  }
205  }
206  for (int j = 0; j < m_nThetaBins; ++j) {
207  if (m_iTheta[th] < m_upperTheta[j]) {
208  ith_old = j;
209  break;
210  }
211  }
212 
213  double p6 = m_xtPrior[l][lr][ial_old][ith_old][6];
214  if (p6 > 400) {
215  p6 = 400;
216  }
217 
218  if (m_xtMode == m_xtModePrior) {
219  xt->setXTParams(m_xtPrior[l][lr][ial_old][ith_old]);
220  xt->setP6(p6);
221  } else {
222  xt->setXTParams(p0, p1, 0., 0., 0., 0., p6, m_xtPrior[l][lr][ial_old][ith_old][7]);
223  }
224  xt->setFitRange(tmin, p6 + 100);
225  } else {
226  xt->setXTParams(p0, p1, 0., 0., 0., 0., m_par6[l], 0.0001);
227  xt->setFitRange(tmin, m_par6[l] + 100);
228  }
229  xt->setDebug(m_debug);
230  xt->setBField(m_bField);
231  xt->fitXT();
232  if (xt->isValid() == false) {
233  B2WARNING("Empty xt");
234  m_fitStatus[l][lr][al][th] = c_fitFailure;
235  continue;
236  }
237  if (xt->getFitStatus() != 1) {
238  B2WARNING("Fit failed");
239  m_fitStatus[l][lr][al][th] = c_fitFailure;
240  continue;
241  }
242  if (xt->validate() == true) {
243  m_fitStatus[l][lr][al][th] = xt->getFitStatus();
244  m_xtFunc[l][lr][al][th] = (TF1*)xt->getXTFunction();
245 
246  if (m_useSliceFit) {
247  m_hist2d_1[l][lr][al][th] = (TH1F*)xt->getFittedHisto();
248  } else {
249  m_hProf[l][lr][al][th] = (TProfile*)xt->getFittedHisto();
250  }
251  } else {
252  m_fitStatus[l][lr][al][th] = c_fitFailure;
253  }
254  }
255  }
256  }
257  }
258  sanitaryCheck();
259  write();
260  storeHisto();
261  return checkConvergence();
262 }
263 
265 {
266  const double tMax = 500; // max drift time (nsec)
267  for (int l = 0; l < 56; ++l) {
268  for (int lr = 0; lr < 2; ++lr) {
269  for (int al = 0; al < m_nAlphaBins; ++al) {
270  for (int th = 0; th < m_nThetaBins; ++th) {
271  if (m_fitStatus[l][lr][al][th] == FitStatus::c_OK) {
272  TF1* fun = m_xtFunc[l][lr][al][th];
273  double y = fun->Eval(tMax);
274  if (y < 0) {
275  B2INFO("Strange XT function l " << l << " lr " << lr << " alpha " << al << " theta " << th
276  << ", replaced by initial one");
277  fun->SetParameters(m_xtPrior[l][lr][al][th]);
278  }
279  }
280  }
281  }
282  }
283  }
284 }
286 {
287 
288  const int nTotal = 56 * 2 * m_nAlphaBins * m_nThetaBins;
289  int nFitCompleted = 0;
290  for (int l = 0; l < 56; ++l) {
291  for (int lr = 0; lr < 2; ++lr) {
292  for (int al = 0; al < m_nAlphaBins; ++al) {
293  for (int th = 0; th < m_nThetaBins; ++th) {
294  if (m_fitStatus[l][lr][al][th] == FitStatus::c_OK) {
295  nFitCompleted++;
296  }
297  }
298  }
299  }
300  }
301 
302  if (static_cast<double>(nFitCompleted) / nTotal < m_threshold) {
303  B2WARNING("Less than " << m_threshold * 100 << " % of XTs were fitted.");
304  return c_NotEnoughData;
305  }
306  return c_OK;
307 }
308 
310 {
311  B2INFO("Prepare calibration of XT");
312  const double rad2deg = 180 / M_PI;
313 
315  m_nAlphaBins = dbXT->getNoOfAlphaBins();
316  m_nThetaBins = dbXT->getNoOfThetaBins();
317  for (unsigned short i = 0; i < m_nAlphaBins; ++i) {
318  array3 alpha = dbXT->getAlphaBin(i);
319  m_lowerAlpha[i] = alpha[0] * rad2deg;
320  m_upperAlpha[i] = alpha[1] * rad2deg;
321  m_iAlpha[i] = alpha[2] * rad2deg;
322  }
323 
324  for (unsigned short i = 0; i < m_nThetaBins; ++i) {
325  array3 theta = dbXT->getThetaBin(i);
326  m_lowerTheta[i] = theta[0] * rad2deg;
327  m_upperTheta[i] = theta[1] * rad2deg;
328  m_iTheta[i] = theta[2] * rad2deg;
329  }
330 
331  m_xtModePrior = dbXT->getXtParamMode();
332  if (!(m_xtModePrior == c_Chebyshev || m_xtModePrior == c_Polynomial)) {
333  B2FATAL("Function type before calibration is wrong " << m_xtModePrior);
334  }
335 
336  B2INFO("Number of alpha bins " << m_nAlphaBins);
337  B2INFO("Number of theta bins " << m_nThetaBins);
338  B2INFO("Function type " << m_xtMode);
339 
340  for (unsigned short iCL = 0; iCL < 56; ++iCL) {
341  for (unsigned short iLR = 0; iLR < 2; ++iLR) {
342  for (unsigned short iA = 0; iA < m_nAlphaBins; ++iA) {
343  for (unsigned short iT = 0; iT < m_nThetaBins; ++iT) {
344  const std::vector<float> params = dbXT->getXtParams(iCL, iLR, iA, iT);
345  unsigned short np = params.size();
346  for (unsigned short i = 0; i < np; ++i) {
347  m_xtPrior[iCL][iLR][iA][iT][i] = params[i];
348  }
349  }
350  }
351  }
352  }
353 }
354 
356 {
357  B2INFO("write calibrated XT");
358  double par[8];
359 
360 
361  int nfitted = 0;
362  int nfailure = 0;
363 
364  //
365  // Save to the localDB
366  //
367 
368  CDCXtRelations* xtRel = new CDCXtRelations();
369  const float deg2rad = static_cast<float>(Unit::deg);
370 
371  for (int i = 0; i < m_nAlphaBins; ++i) {
372  std::array<float, 3> alpha3 = {m_lowerAlpha[i]* deg2rad,
373  m_upperAlpha[i]* deg2rad,
374  m_iAlpha[i]* deg2rad
375  };
376  xtRel->setAlphaBin(alpha3);
377  }
378 
379  for (int i = 0; i < m_nThetaBins; ++i) {
380  std::array<float, 3> theta3 = {m_lowerTheta[i]* deg2rad,
381  m_upperTheta[i]* deg2rad,
382  m_iTheta[i]* deg2rad
383  };
384  xtRel->setThetaBin(theta3);
385  }
386 
387  xtRel->setXtParamMode(m_xtMode);
388 
389  for (int th = 0; th < m_nThetaBins; ++th) {
390  for (int al = 0; al < m_nAlphaBins; ++al) {
391  for (int l = 0; l < 56; ++l) {
392  for (int lr = 0; lr < 2; ++lr) {
393  if (m_fitStatus[l][lr][al][th] != FitStatus::c_OK) {
394  nfailure += 1;
395  B2DEBUG(21, "fit failure status = " << m_fitStatus[l][lr][al][th]);
396  B2DEBUG(21, "layer " << l << ", r " << lr << ", alpha " << m_iAlpha[al] << ", theta " << m_iTheta[th]);
397  B2DEBUG(21, "number of event: " << m_hProf[l][lr][al][th]->GetEntries());
398  if (m_fitStatus[l][lr][al][th] != FitStatus::c_lowStat) {
399  if (m_xtFunc[l][lr][al][th]) {
400  B2DEBUG(21, "Probability of fit: " << m_xtFunc[l][lr][al][th]->GetProb());
401  }
402  }
403  // If fit is failed
404  // and mode of input xt (prior) is same as output, previous xt is used.
405  if (m_xtMode == m_xtModePrior) {
406  for (int i = 0; i < 8; ++i) {
407  par[i] = m_xtPrior[l][lr][al][th][i];
408  }
409  } else {
410  B2FATAL("XT mode before/after calibration is different!");
411  }
412 
413  } else {
414  if (par[1] < 0) { // if negative c1, privious xt is kept.
415  for (int i = 0; i < 8; ++i) {
416  par[i] = m_xtPrior[l][lr][al][th][i];
417  }
418  } else {
419  m_xtFunc[l][lr][al][th]->GetParameters(par);
420  nfitted += 1;
421  }
422  }
423  std::vector<float> xtbuff;
424  for (int i = 0; i < 8; ++i) {
425  xtbuff.push_back(par[i]);
426  }
427  xtRel->setXtParams(l, lr, al, th, xtbuff);
428  }//lr
429  }//layer
430  }//alpha
431  }//theta
432 
433  if (m_textOutput == true) {
435  }
436 
437  saveCalibration(xtRel, "CDCXtRelations");
438 
439  B2RESULT("Total number of xt fit: " << m_nAlphaBins * m_nThetaBins * 2 * 56);
440  B2RESULT("Successfully Fitted: " << nfitted);
441  B2RESULT("Failure Fit: " << nfailure);
442 
443 }
444 
446 {
447 
448  auto hNDF = getObjectPtr<TH1F>("hNDF");
449  auto hPval = getObjectPtr<TH1F>("hPval");
450  auto hEvtT0 = getObjectPtr<TH1F>("hEventT0");
451  B2INFO("saving histograms");
452  TFile* fout = new TFile(m_histName.c_str(), "RECREATE");
453  TDirectory* top = gDirectory;
454  //store NDF, P-val. EventT0 histogram for monitoring during calibration
455  if (hNDF && hPval && hEvtT0) {
456  hEvtT0->Write();
457  hPval->Write();
458  hNDF->Write();
459  }
460  // for each layer
461 
462  TDirectory* Direct[56];
463  int nhisto = 0;
464  for (int l = 0; l < 56; ++l) {
465  top->cd();
466  Direct[l] = gDirectory->mkdir(Form("lay_%d", l));
467  Direct[l]->cd();
468  for (int th = 0; th < m_nThetaBins; ++th) {
469  for (int al = 0; al < m_nAlphaBins; ++al) {
470  m_hist2dDraw[l][al][th]->Write();
471  for (int lr = 0; lr < 2; ++lr) {
472  m_hist2d[l][lr][al][th]->Write();
473  if (m_fitStatus[l][lr][al][th] != 1) continue;
474  if (m_useSliceFit) {
475  if (m_hist2d_1[l][lr][al][th]) {
476  m_hist2d_1[l][lr][al][th]->Write();
477  nhisto += 1;
478  }
479  } else {
480  m_hProf[l][lr][al][th]->Write();
481  nhisto += 1;
482  }
483  }
484  }
485  }
486  }
487  top->cd();
488 
489  fout->Close();
490  B2RESULT(" " << nhisto << " histograms was stored.");
491 }
492 
Database object for xt-relations.
void setThetaBin(const array3 &theta)
Set theta-angle bin (rad)
void outputToFile(std::string fileName) const
Output the contents in test file format.
void setXtParamMode(unsigned short mode)
Set xt parameterization mode.
void setXtParams(const XtID xtID, const std::vector< float > &params)
Set xt parameters for the specified id.
void setAlphaBin(const array3 &alpha)
Set alpha-angle bin (rad)
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
void storeHisto()
Store histogram to file.
void prepare()
Prepare the calibration of XT.
void sanitaryCheck()
Check if there are any wrong xt functions.
double m_par6[56]
boundary parameter for fitting, semi-experiment number
float m_lowerTheta[7]
Lower boundays of theta bins.
double m_xtPrior[56][2][18][7][8]
paremeters of XT before calibration
TF1 * m_xtFunc[56][2][20][10]
XTFunction.
double m_threshold
minimal requirement for the fraction of fitted results
bool m_LRseparate
Separate LR in calibration or mix.
void createHisto()
Create histogram for calibration.
int m_minEntriesRequired
minimum number of hit per hitosgram.
int m_fitStatus[56][2][20][10]
Fit flag.
TH2F * m_hist2d[56][2][20][10]
2D histo of xt
double m_minPval
minimum pvalue required
TProfile * m_hProf[56][2][20][10]
Profile xt histo.
float m_iAlpha[18]
Represented alpha in alpha bins.
float m_lowerAlpha[18]
Lower boundays of alpha bins.
DBObjPtr< CDCGeometry > m_cdcGeo
Geometry of CDC.
bool m_useSliceFit
Use slice fit or profile.
void write()
Store calibrated constand.
float m_upperAlpha[18]
Upper boundays of alpha bins.
bool m_textOutput
output text file if true
EResult calibrate() override
Run algo on data.
EResult checkConvergence()
Check the convergence of XT fit.
int m_xtModePrior
Mode of xt before calibration; 0 is polynomial;1 is Chebyshev.
TH2F * m_hist2dDraw[56][20][10]
2d histo for draw
float m_upperTheta[7]
Upper boundays of theta bins.
int m_xtMode
Mode of xt; 0 is polynomial;1 is Chebyshev.
TH1F * m_hist2d_1[56][2][20][10]
1D xt histo, results of slice fit
std::string m_outputFileName
Output xt filename.
float m_iTheta[7]
Represented theta in theta bins.
Class to perform fitting for each xt function.
Definition: XTFunction.h:69
Base class for calibration algorithms.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
void updateDBObjPtrs(const unsigned int event, const int run, const int experiment)
Updates any DBObjPtrs by calling update(event) for DBStore.
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.
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
static const double deg
degree to radians
Definition: Unit.h:109
Abstract base class for different kinds of events.