Belle II Software development
CDCDedxCosEdgeAlgorithm.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 <TF1.h>
10#include <TCanvas.h>
11#include <TH1I.h>
12#include <TLegend.h>
13
14#include <reconstruction/calibration/CDCdEdx/CDCDedxCosEdgeAlgorithm.h>
15
16using namespace Belle2;
17using namespace std;
18
19//-----------------------------------------------------------------
20// Implementation
21//-----------------------------------------------------------------
23 CalibrationAlgorithm("CDCDedxElectronCollector"),
24 m_isMakePlots(true),
25 m_isMerge(true),
26 m_sigLim(2.5),
27 m_npBins(20),
28 m_negMin(-0.870),
29 m_negMax(-0.850),
30 m_posMin(0.950),
31 m_posMax(0.960),
32 m_dedxBins(600),
33 m_dedxMin(0.0),
34 m_dedxMax(3.0),
35 m_suffix("")
36{
37 // Set module properties
38 setDescription("A calibration algorithm for CDC dE/dx electron cos(theta) dependence");
39}
40
41//-----------------------------------------------------------------
42// Run the calibration
43//-----------------------------------------------------------------
45{
46
48
49 // Get data objects
50 auto ttree = getObjectPtr<TTree>("tree");
51 if (ttree->GetEntries() < 100) return c_NotEnoughData;
52
53 double dedx, costh; int charge;
54 ttree->SetBranchAddress("dedx", &dedx);
55 ttree->SetBranchAddress("costh", &costh);
56 ttree->SetBranchAddress("charge", &charge);
57
58 // make histograms to store dE/dx values in bins of cos(theta)
59 vector<TH1D*> hdedx_negi, hdedx_posi;
60
61 const double bwnegi = (m_negMax - m_negMin) / m_npBins;
62 const double bwposi = (m_posMax - m_posMin) / m_npBins;
63
64 for (unsigned int i = 0; i < m_npBins; ++i) {
65
66 double mincos = i * bwposi + m_posMin;
67 double maxcos = mincos + bwposi;
68 string title = Form("costh: %0.04f, %0.04f(%s)", mincos, maxcos, m_suffix.data());
69 hdedx_posi.push_back(new TH1D(Form("hdedx_posi%d_%s", i, m_suffix.data()), "", m_dedxBins, m_dedxMin, m_dedxMax));
70 hdedx_posi[i]->SetTitle(Form("%s;dedx;entries", title.data()));
71
72 mincos = i * bwnegi + m_negMin;
73 maxcos = mincos + bwnegi;
74 title = Form("costh: %0.04f, %0.04f(%s)", mincos, maxcos, m_suffix.data());
75 hdedx_negi.push_back(new TH1D(Form("hdedx_negi%d_%s", i, m_suffix.data()), "", m_dedxBins, m_dedxMin, m_dedxMax));
76 hdedx_negi[i]->SetTitle(Form("%s;dedx;entries", title.data()));
77 }
78
79 int icosbin = -99.;
80 for (int i = 0; i < ttree->GetEntries(); ++i) {
81
82 ttree->GetEvent(i);
83
84 //if track is a junk
85 if (dedx <= 0 || charge == 0) continue;
86 if (costh > -0.850 && costh < 0.950) continue;
87
88 if (costh > 0) {
89 icosbin = int((costh - m_posMin) / bwposi);
90 hdedx_posi[icosbin]->Fill(dedx);
91 } else if (costh < 0) {
92 icosbin = int((costh - m_negMin) / bwnegi);
93 hdedx_negi[icosbin]->Fill(dedx);
94 }
95 }
96
97 map<int, vector<double>> vneg_fitpars;
98 map<int, vector<double>> vpos_fitpars;
99
100 vector<double> vneg_const, vpos_const;
101 vector<vector<double>> vfinal_const;
102
103 for (unsigned int i = 0; i < m_npBins; ++i) {
104
105 fitstatus status;
106
107 //Fit dedx in negative cos bins
108 fitGaussianWRange(hdedx_negi[i], status);
109 if (status != FitOK) {
110 vneg_fitpars[0].push_back(1.0);
111 vneg_fitpars[1].push_back(0.0);
112 vneg_fitpars[2].push_back(0.0);
113 vneg_fitpars[3].push_back(0.0);
114 hdedx_negi[i]->SetTitle(Form("%s, Fit(%d)", hdedx_negi[i]->GetTitle(), status));
115 } else {
116 vneg_fitpars[0].push_back(hdedx_negi[i]->GetFunction("gaus")->GetParameter(1));
117 vneg_fitpars[1].push_back(hdedx_negi[i]->GetFunction("gaus")->GetParError(1));
118 vneg_fitpars[2].push_back(hdedx_negi[i]->GetFunction("gaus")->GetParameter(2));
119 vneg_fitpars[3].push_back(hdedx_negi[i]->GetFunction("gaus")->GetParError(2));
120 }
121
122 vneg_const.push_back(vneg_fitpars[0][i]);
123
124 //Fit dedx in positive cos bins
125 fitGaussianWRange(hdedx_posi[i], status);
126 if (status != FitOK) {
127 vpos_fitpars[0].push_back(1.0);
128 vpos_fitpars[1].push_back(0.0);
129 vpos_fitpars[2].push_back(0.0);
130 vpos_fitpars[3].push_back(0.0);
131 hdedx_posi[i]->SetTitle(Form("%s, Fit(%d)", hdedx_posi[i]->GetTitle(), status));
132 } else {
133 vpos_fitpars[0].push_back(hdedx_posi[i]->GetFunction("gaus")->GetParameter(1));
134 vpos_fitpars[1].push_back(hdedx_posi[i]->GetFunction("gaus")->GetParError(1));
135 vpos_fitpars[2].push_back(hdedx_posi[i]->GetFunction("gaus")->GetParameter(2));
136 vpos_fitpars[3].push_back(hdedx_posi[i]->GetFunction("gaus")->GetParError(2));
137 }
138
139 vpos_const.push_back(vpos_fitpars[0][i]);
140 }
141
142 vfinal_const.push_back(vneg_const);
143 vfinal_const.push_back(vpos_const);
144
145 createPayload(vfinal_const);
146
147 if (m_isMakePlots) {
148
149 //1. draw dedx dist of individual bins
150 plotHist(hdedx_posi, vpos_fitpars, "pos");
151 plotHist(hdedx_negi, vneg_fitpars, "neg");
152
153 //2. plot relative const or fit parameters
154 plotFitPars(vneg_fitpars, vpos_fitpars);
155
156 //3. compare new/old calibration constants
157 plotConstants(vfinal_const);
158
159 //4. plot statistics related plots here
160 plotStats();
161 }
162
163 m_suffix.clear();
164 return c_OK;
165}
166
167
168//------------------------------------
170{
171 int cruns = 0;
172 for (auto expRun : getRunList()) {
173 if (cruns == 0)B2INFO("CDCDedxCosEdge: start exp " << expRun.first << " and run " << expRun.second << "");
174 cruns++;
175 }
176
177 const auto erStart = getRunList()[0];
178 int estart = erStart.first;
179 int rstart = erStart.second;
180
181 const auto erEnd = getRunList()[cruns - 1];
182 int rend = erEnd.second;
183
184 updateDBObjPtrs(1, rstart, estart);
185
186 if (m_suffix.length() > 0) m_suffix = Form("%s_e%d_r%dr%d", m_suffix.data(), estart, rstart, rend);
187 else m_suffix = Form("e%d_r%dr%d", estart, rstart, rend);
188}
189
190//------------------------------------
191void CDCDedxCosEdgeAlgorithm::createPayload(vector<vector<double>>& vfinalconst)
192{
193 if (m_isMerge) {
194 if (m_DBCosineCor->getSize(-1) != int(m_npBins) || m_DBCosineCor->getSize(1) != int(m_npBins))
195 B2FATAL("CDCDedxCosEdgeAlgorithm: Can't merge paylaods with different size");
196
197 for (unsigned int ibin = 0; ibin < m_npBins; ibin++) {
198
199 //costh < 0
200 double prevg = m_DBCosineCor->getMean(-1, ibin);
201 double relg = vfinalconst[0].at(ibin);
202 double newg = prevg * relg;
203 B2INFO("CosEdge Const (<0), bin# " << ibin << ", rel " << relg << ", previous " << prevg << ", merged " << newg);
204 vfinalconst[0].at(ibin) *= (double)m_DBCosineCor->getMean(-1, ibin);
205 vfinalconst[0].at(ibin) /= (0.5 * (vfinalconst[0].at(m_npBins - 1) + vfinalconst[0].at(m_npBins - 2)));
206
207 //costh > 0
208 prevg = m_DBCosineCor->getMean(1, ibin);
209 relg = vfinalconst[1].at(ibin);
210 newg = prevg * relg;
211 B2INFO("CosEdge Const (>0), bin# " << ibin << ", rel " << relg << ", previous " << prevg << ", merged " << newg);
212 vfinalconst[1].at(ibin) *= (double)m_DBCosineCor->getMean(1, ibin);
213 vfinalconst[1].at(ibin) /= (0.5 * (vfinalconst[1].at(0) + vfinalconst[1].at(1)));
214 }
215 }
216
217 B2INFO("CDCDedxCosineEdge calibration done");
218 CDCDedxCosineEdge* gain = new CDCDedxCosineEdge(vfinalconst);
219 saveCalibration(gain, "CDCDedxCosineEdge");
220}
221
222//------------------------------------
223void CDCDedxCosEdgeAlgorithm::fitGaussianWRange(TH1D*& temphist, fitstatus& status)
224{
225 if (temphist->Integral() < 500) { //at least 1k bhabha events
226 B2INFO(Form("\t insufficient fit stats (%0.00f) for (%s)", temphist->Integral(), temphist->GetName()));
227 status = LowStats;
228 return;
229 } else {
230 temphist->GetXaxis()->SetRange(temphist->FindFirstBinAbove(0, 1), temphist->FindLastBinAbove(0, 1));
231 int fs = temphist->Fit("gaus", "QR");
232 if (fs != 0) {
233 B2INFO(Form("\tFit (round 1) for hist (%s) failed (status = %d)", temphist->GetName(), fs));
234 status = FitFailed;
235 return;
236 } else {
237 double fdEdxMean = temphist->GetFunction("gaus")->GetParameter(1);
238 double width = temphist->GetFunction("gaus")->GetParameter(2);
239 temphist->GetXaxis()->SetRangeUser(fdEdxMean - 5.0 * width, fdEdxMean + 5.0 * width);
240 fs = temphist->Fit("gaus", "QR", "", fdEdxMean - m_sigLim * width, fdEdxMean + m_sigLim * width);
241 if (fs != 0) {
242 B2INFO(Form("\tFit (round 2) for hist (%s) failed (status = %d)", temphist->GetName(), fs));
243 status = FitFailed;
244 return;
245 } else {
246 temphist->GetXaxis()->SetRangeUser(fdEdxMean - 5.0 * width, fdEdxMean + 5.0 * width);
247 B2INFO(Form("\tFit for hist (%s) successful (status = %d)", temphist->GetName(), fs));
248 status = FitOK;
249 }
250 }
251 }
252}
253
254//------------------------------------
255void CDCDedxCosEdgeAlgorithm::plotHist(vector<TH1D*>& hdedx, map<int, vector<double>>& vpars,
256 string type)
257{
258 TCanvas ctmp("ctmp", "ctmp", 1200, 1200);
259 ctmp.Divide(5, 4);
260
261 stringstream psname;
262 psname << Form("cdcdedx_cosedgecal_fits_%s_%s.pdf[", type.data(), m_suffix.data());
263 ctmp.Print(psname.str().c_str());
264 psname.str("");
265 psname << Form("cdcdedx_cosedgecal_fits_%s_%s.pdf", type.data(), m_suffix.data());
266
267 for (unsigned int i = 0; i < m_npBins; ++i) {
268
269 ctmp.cd(i % 20 + 1); // each canvas is 2x2
270 hdedx[i]->SetStats(0);
271 hdedx[i]->SetFillColor(kAzure - 9);
272 hdedx[i]->DrawCopy();
273
274 TPaveText* pt = new TPaveText(0.5, 0.73, 0.8, 0.89, "NBNDC");
275 setTextCosmetics(pt, 0.04258064);
276 pt->AddText(Form("#mu_{fit}: %0.03f#pm%0.03f", vpars[0][i], vpars[1][i]));
277 pt->AddText(Form("#sigma_{fit}: %0.03f#pm%0.03f", vpars[2][i], vpars[3][i]));
278 pt->Draw("same");
279
280 if ((i + 1) % 20 == 0 || (i + 1) == m_npBins) {
281 ctmp.Print(psname.str().c_str());
282 ctmp.Clear("D");
283 }
284
285 delete hdedx[i];
286 }
287
288 psname.str("");
289 psname << Form("cdcdedx_cosedgecal_fits_%s_%s.pdf]", type.data(), m_suffix.data());
290 ctmp.Print(psname.str().c_str());
291}
292
293//------------------------------------
294void CDCDedxCosEdgeAlgorithm::plotFitPars(map<int, vector<double>>& vneg_fitpars,
295 map<int, vector<double>>& vpos_fitpars)
296{
297 // For qa pars
298 TCanvas cQa("cQa", "cQa", 1200, 1200);
299 cQa.Divide(2, 2);
300
301 double min[2] = {0.85, 0.04};
302 double max[2] = {1.05, 0.3};
303
304 string vars[2] = {"#mu_{fit}", "#sigma_{fit}"};
305 string side[2] = {"pcos", "ncos"};
306
307 for (int is = 0; is < 2; is++) {
308
309 double minp = m_negMin, maxp = m_negMax;
310 if (is == 0) {
311 minp = m_posMin;
312 maxp = m_posMax;
313 }
314
315 for (int iv = 0; iv < 2; iv++) {
316
317 string hname = Form("hpar_%s_%s_%s", vars[iv].data(), side[is].data(), m_suffix.data());
318
319 TH1D htemp(Form("%s", hname.data()), "", m_npBins, minp, maxp);
320 htemp.SetTitle(Form("Constant (%s), cos#theta:(%0.02f, %0.02f);cos(#theta);const", vars[iv].data(), minp, maxp));
321
322 for (unsigned int ib = 0; ib < m_npBins; ib++) {
323 if (is == 0) {
324 htemp.SetBinContent(ib + 1, vpos_fitpars[2 * iv][ib]);
325 htemp.SetBinError(ib + 1, vpos_fitpars[2 * iv + 1][ib]);
326 } else {
327 htemp.SetBinContent(ib + 1, vneg_fitpars[2 * iv][ib]);
328 htemp.SetBinError(ib + 1, vneg_fitpars[2 * iv + 1][ib]);
329 }
330 }
331
332 setHistCosmetics(htemp, iv * 2 + 2, min[iv], max[iv], 0.025);
333
334 cQa.cd(2 * iv + 1 + is); //1,3,2,4
335 gPad->SetGridx(1);
336 gPad->SetGridy(1);
337 htemp.DrawCopy("");
338 }
339 }
340 cQa.SaveAs(Form("cdcdedx_cosedgecal_relconst_%s.pdf", m_suffix.data()));
341 cQa.SaveAs(Form("cdcdedx_cosedgecal_relconst_%s.root", m_suffix.data()));
342}
343
344//------------------------------------
345void CDCDedxCosEdgeAlgorithm::plotConstants(vector<vector<double>>& vfinalconst)
346{
347
348 TCanvas ctmp_const("ctmp_const", "ctmp_const", 900, 450);
349 ctmp_const.Divide(2, 1);
350
351 for (int i = 0; i < 2; i++) {
352
353 double min = m_negMin, max = m_negMax;
354 if (i == 1) {
355 min = m_posMin;
356 max = m_posMax;
357 }
358
359 TH1D holdconst(Form("holdconst%d_%s", i, m_suffix.data()), "", m_npBins, min, max);
360 holdconst.SetTitle(Form("constant comparison, cos#theta:(%0.02f, %0.02f);cos(#theta);const", min, max));
361
362 TH1D hnewconst(Form("hnewconst%d_%s", i, m_suffix.data()), "", m_npBins, min, max);
363
364 int iside = 2 * i - 1; //-1 or +1 for neg and pos cosine side
365 for (int ibin = 0; ibin < m_DBCosineCor->getSize(iside); ibin++) {
366 holdconst.SetBinContent(ibin + 1, (double)m_DBCosineCor->getMean(iside, ibin));
367 hnewconst.SetBinContent(ibin + 1, vfinalconst[i].at(ibin));
368 }
369
370 ctmp_const.cd(i + 1);
371 gPad->SetGridx(1);
372 gPad->SetGridy(1);
373
374 setHistCosmetics(holdconst, kBlack, 0.0, 1.10, 0.025);
375 holdconst.DrawCopy("");
376
377 setHistCosmetics(hnewconst, kRed, 0.0, 1.10, 0.025);
378 hnewconst.DrawCopy("same");
379
380 TPaveText* pt = new TPaveText(0.47, 0.73, 0.77, 0.89, "NBNDC");
381 setTextCosmetics(pt, 0.02258064);
382
383 TText* told = pt->AddText("old const");
384 told->SetTextColor(kBlack);
385 TText* tnew = pt->AddText("new const");
386 tnew->SetTextColor(kRed);
387 pt->Draw("same");
388
389 }
390
391 ctmp_const.SaveAs(Form("cdcdedx_cosedgecal_constcomp_%s.pdf", m_suffix.data()));
392 ctmp_const.SaveAs(Form("cdcdedx_cosedgecal_constcomp_%s.root", m_suffix.data()));
393}
394
395//------------------------------------
397{
398
399 TCanvas cstats("cstats", "cstats", 1000, 500);
400 cstats.SetBatch(kTRUE);
401 cstats.Divide(2, 1);
402
403 cstats.cd(1);
404 auto hestats = getObjectPtr<TH1I>("hestats");
405 if (hestats) {
406 hestats->SetName(Form("hestats_%s", m_suffix.data()));
407 hestats->SetStats(0);
408 hestats->DrawCopy("");
409 }
410
411 cstats.cd(2);
412 auto htstats = getObjectPtr<TH1I>("htstats");
413 if (htstats) {
414 htstats->SetName(Form("htstats_%s", m_suffix.data()));
415 htstats->SetStats(0);
416 htstats->DrawCopy("");
417 }
418 cstats.Print(Form("cdcdedx_cosedgecal_stats_%s.pdf", m_suffix.data()));
419}
void plotFitPars(std::map< int, std::vector< double > > &fPars_Neg, std::map< int, std::vector< double > > &fPars_Pos)
function to draw the fit parameters (relative gains and resolutions)
CDCDedxCosEdgeAlgorithm()
Constructor: Sets the description, the properties and the parameters of the algorithm.
bool m_isMerge
merge payload if calculated relative
void plotStats()
function to draw the stats plots
void setHistCosmetics(TH1D &hist, Color_t color, double min, double max, double size)
function to change histogram styles
void plotHist(std::vector< TH1D * > &hdedx, std::map< int, std::vector< double > > &fPars, std::string type)
function to draw dedx histograms for each bin
double m_negMin
min neg cosine angle
void getExpRunInfo()
function to get info about current exp and run
DBObjPtr< CDCDedxCosineEdge > m_DBCosineCor
CoseEdge correction DB object.
unsigned int m_npBins
number of bins across cosine range
void createPayload(std::vector< std::vector< double > > &vfinalconst)
function to store new payload after full calibration
std::string m_suffix
suffix for better plot naming
void setTextCosmetics(TPaveText *pt, double size)
function to change text styles
double m_posMax
max pos cosine angle
int m_dedxBins
number of bins for dedx histogram
void plotConstants(std::vector< std::vector< double > > &vfinalconst)
function to draw the final calibration constants and comparison with old constants
double m_posMin
min pos cosine angle
virtual EResult calibrate() override
Cosine edge algorithm.
double m_sigLim
gaussian fit sigma limit
void fitGaussianWRange(TH1D *&temphist, fitstatus &status)
function to perform gauss fit for given histogram
double m_negMax
max neg cosine angle
dE/dx special large cosine calibration to fix bending shoulder at large costh
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 successfully =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
Abstract base class for different kinds of events.
STL namespace.