Belle II Software development
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
26using namespace std;
27using namespace Belle2;
28using namespace CDC;
29
30typedef std::array<float, 3> array3;
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 }
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)
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 successfuly =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
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.
STL namespace.