Belle II Software  release-08-01-10
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/CDCDedxCosEdgeAlgorithm.h>
15 
16 using namespace Belle2;
17 using 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 
47  getExpRunInfo();
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 //------------------------------------
191 void 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 //------------------------------------
223 void CDCDedxCosEdgeAlgorithm::fitGaussianWRange(TH1D*& temphist, fitstatus& status)
224 {
225  if (temphist->Integral() < 500) { //atleast 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) sucessfull (status = %d)", temphist->GetName(), fs));
248  status = FitOK;
249  }
250  }
251  }
252 }
253 
254 //------------------------------------
255 void 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 //------------------------------------
294 void 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 //------------------------------------
345 void 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 comparision, 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 plotConstants(std::vector< std::vector< double >> &vfinalconst)
function to draw the final calibration constants and comparison with old constants
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 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)
void setHistCosmetics(TH1D &hist, Color_t color, double min, double max, double size)
function to change histogram styles
double m_negMin
min neg cosine angle
void getExpRunInfo()
funtion 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
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 plotHist(std::vector< TH1D * > &hdedx, std::map< int, std::vector< double >> &fPars, std::string type)
funtion to draw dedx histograms for each bin
void createPayload(std::vector< std::vector< double >> &vfinalconst)
function to store new payload after full calibration
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 gaus 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)
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.
Abstract base class for different kinds of events.