Belle II Software  release-08-01-10
SVDClusterTimeShifterAlgorithm.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 <svd/calibration/SVDClusterTimeShifterAlgorithm.h>
9 
10 #include <svd/dbobjects/SVDClusterTimeShifter.h>
11 
12 #include <TF1.h>
13 #include <TProfile.h>
14 #include "TH1F.h"
15 #include "TH2F.h"
16 #include "TH3F.h"
17 #include "TCanvas.h"
18 #include "TStyle.h"
19 #include "TPaveStats.h"
20 #include <framework/logging/Logger.h>
21 #include <iostream>
22 #include <TString.h>
23 #include <TFitResult.h>
24 
25 using namespace Belle2;
26 
28  CalibrationAlgorithm("SVDClusterTimeShifterCollector")
29  , m_id(str)
30 {
31  setDescription("SVDClusterTimeShifter calibration algorithm");
32 }
33 
35 {
36 
37  gROOT->SetBatch(true);
38 
39  gStyle->SetFillColor(0);
40  gStyle->SetFillStyle(0);
41  gStyle->SetOptStat(0);
42  gStyle->SetOptFit(0);
43 
44  FileStat_t info;
45  int cal_rev = 1;
46  while (gSystem->GetPathInfo(Form("algorithm_svdClusterTimeShifter_%s_output_rev_%d.root", m_timeAlgorithms[0].Data(), cal_rev),
47  info) == 0)
48  cal_rev++;
49 
50  auto payload = new Belle2::SVDClusterTimeShifter(Form("SVDClusterTimeShifter_%s_rev_%d", m_id.data(), cal_rev));
51 
52  // single gaus fit function
53  TF1* fn_singleGaus = new TF1("fn_singleGaus", singleGaus, -50., 50., 4);
54  fn_singleGaus->SetLineColor(kGreen + 2);
55  fn_singleGaus->SetParName(0, "N");
56  fn_singleGaus->SetParName(1, "#mu");
57  fn_singleGaus->SetParName(2, "#sigma");
58  fn_singleGaus->SetParName(3, "C");
59 
60  // double gaus fit function
61  TF1* fn_doubleGaus = new TF1("fn_doubleGaus", doubleGaus, -50., 50., 7);
62  fn_doubleGaus->SetLineColor(kRed + 2);
63  fn_doubleGaus->SetParName(0, "N");
64  fn_doubleGaus->SetParName(1, "f");
65  fn_doubleGaus->SetParName(2, "#mu_{1}");
66  fn_doubleGaus->SetParName(3, "#sigma_{1}");
67  fn_doubleGaus->SetParName(4, "#mu_{2}");
68  fn_doubleGaus->SetParName(5, "#sigma_{2}");
69  fn_doubleGaus->SetParName(6, "C");
70  fn_doubleGaus->SetParLimits(1, 0.01, 0.99);
71  fn_doubleGaus->SetParLimits(3, 0.5, 25.);
72  fn_doubleGaus->SetParLimits(5, 0.5, 25.);
73 
74 
75  auto __hBinToSensorMap__ = getObjectPtr<TH1F>("__hBinToSensorMap__");
76 
77  for (auto alg : m_timeAlgorithms) {
78 
79  B2INFO("Calculating shift for algorithm " << alg);
80 
81  auto __hClusterSizeVsTimeResidual__ = getObjectPtr<TH3F>(("__hClusterSizeVsTimeResidual__" + alg).Data());
82 
83  int nSensors = __hClusterSizeVsTimeResidual__->GetNbinsZ();
84  int maxClsSize = __hClusterSizeVsTimeResidual__->GetNbinsY();
85 
86  // map : shift values
87  std::map< TString, std::vector<double> > shiftValues;
88 
89  // draw shift
90  TH2F* hDrawShift = new TH2F(("hDrawShift_" + alg).Data(),
91  ("Cluster time shift in " + alg).Data(),
92  nSensors, +0.5, nSensors + 0.5, maxClsSize, +0.5, maxClsSize + 0.5);
93  hDrawShift->GetZaxis()->SetTitle("Cluster Time Shift (in ns)");
94  hDrawShift->GetYaxis()->SetTitle("Cluster Size");
95  hDrawShift->GetXaxis()->SetTitle("Sensor");
96 
97  std::unique_ptr<TFile> f(new TFile(Form("algorithm_svdClusterTimeShifter_%s_output_rev_%d.root", alg.Data(), cal_rev), "RECREATE"));
98 
99  TString outPDF = Form("algorithm_svdClusterTimeShifter_%s_output_rev_%d.pdf", alg.Data(), cal_rev);
100  TCanvas c1("c1", "c1", 640, 480);
101  c1.Print(outPDF + "[");
102  TPad onePad("onePad", "onePad", 0, 0, 1, 1, kWhite);
103  onePad.SetFillColor(0);
104  onePad.SetBorderMode(0);
105  onePad.SetBorderSize(2);
106  onePad.SetRightMargin(0.1339713);
107  onePad.SetBottomMargin(0.15);
108  onePad.SetFrameBorderMode(0);
109  onePad.SetFrameBorderMode(0);
110  onePad.SetNumber(1);
111  onePad.Draw();
112 
113  for (int ij = 0; ij < nSensors; ij++) {
114 
115  auto binLabel = __hBinToSensorMap__->GetXaxis()->GetBinLabel(ij + 1);
116  char side;
117  int layer_num, sensor_num;
118  std::sscanf(binLabel, "L%dS%dS%c", &layer_num, &sensor_num, &side);
119 
120  B2INFO("Projecting for Sensor: " << binLabel << " with Bin Number: " << ij + 1);
121 
122  __hClusterSizeVsTimeResidual__->GetZaxis()->SetRange(ij + 1, ij + 1);
123  TH2D* hClusterSizeVsTimeResidual = (TH2D*)__hClusterSizeVsTimeResidual__->Project3D("yxe");
124  hClusterSizeVsTimeResidual->SetName(Form("clusterSizeVsTimeResidual__L%dS%dS%c", layer_num, sensor_num, side));
125  char sidePN = (side == 'U' ? 'P' : 'N');
126  hClusterSizeVsTimeResidual->SetTitle(Form("ClusterSize vs Time Residual in L%d.S%d %c/%c", layer_num, sensor_num, side, sidePN));
127  hClusterSizeVsTimeResidual->SetDirectory(0);
128 
129  for (int clSize = 1; clSize <= maxClsSize; clSize++) {
130 
131  TH1D* hist = (TH1D*)hClusterSizeVsTimeResidual->ProjectionX("tmp", clSize, clSize, "");
132  hist->SetName(Form("clusterTimeResidual__L%dS%dS%c_Sz%d", layer_num, sensor_num, side, clSize));
133  hist->SetTitle(Form("Cluster Time Residual for Size %d in L%d.S%d %c/%c", clSize, layer_num, sensor_num, side, sidePN));
134  hist->SetDirectory(0);
135 
136  B2INFO("Histogram: " << hist->GetName() <<
137  " Entries (n. clusters): " << hist->GetEntries());
138  if (hist->GetEntries() < m_minEntries) {
139  B2INFO("Histogram: " << hist->GetName() <<
140  " Entries (n. clusters): " << hist->GetEntries() <<
141  " Entries required: " << m_minEntries);
142  B2WARNING("Not enough data, adding one run to the collector");
143  delete hDrawShift;
144  c1.Print(outPDF + "]");
145  f->Close();
146  gSystem->Unlink(Form("algorithm_svdClusterTimeShifter_%s_output_rev_%d.root", m_timeAlgorithms[0].Data(), cal_rev));
147  return c_NotEnoughData;
148  }
149 
150  onePad.Clear();
151  onePad.cd();
152  hist->Draw();
153 
154  if (hist->GetMaximum() < 200.) {
155  int rebinValue = 200. / hist->GetMaximum() + 1.;
156  while ((hist->GetNbinsX()) % rebinValue != 0) rebinValue++;
157  hist->Rebin(rebinValue);
158  }
159 
160  int fitCount = 0;
161  bool isSingleGausFitValid, isDoubleGausFitValid;
162  while (fitCount++ < 5) {
163  double histMean = hist->GetMean();
164  double histStd = hist->GetStdDev();
165  fn_singleGaus->SetParameter(0, hist->GetSumOfWeights() * hist->GetBinWidth(1));
166  fn_singleGaus->SetParameter(1, histMean);
167  fn_singleGaus->SetParameter(2, histStd * 0.75);
168  fn_singleGaus->SetParameter(3, 1.);
169  fn_singleGaus->SetParLimits(1, histMean - histStd, histMean + histStd);
170  auto singleGausFitStatus = hist->Fit("fn_singleGaus", "SQ", "",
171  histMean - 2. * histStd, histMean + 2. * histStd);
172  isSingleGausFitValid = singleGausFitStatus->IsValid();
173 
174  fn_doubleGaus->SetParameter(0, hist->GetSumOfWeights() * hist->GetBinWidth(1));
175  fn_doubleGaus->SetParameter(1, 0.95);
176  fn_doubleGaus->SetParameter(2, fn_singleGaus->GetParameter(1));
177  fn_doubleGaus->SetParameter(3, std::fabs(fn_singleGaus->GetParameter(2)));
178  fn_doubleGaus->SetParameter(4, fn_singleGaus->GetParameter(1) - 3.);
179  fn_doubleGaus->SetParameter(5, std::fabs(fn_singleGaus->GetParameter(2)) + 5.);
180  fn_doubleGaus->SetParameter(6, 10.);
181  fn_doubleGaus->SetParLimits(2,
182  fn_doubleGaus->GetParameter(2) - m_maximumAllowedShift,
183  fn_doubleGaus->GetParameter(2) + m_maximumAllowedShift);
184  fn_doubleGaus->SetParLimits(4,
185  fn_doubleGaus->GetParameter(4) - m_maximumAllowedShift,
186  fn_doubleGaus->GetParameter(4) + m_maximumAllowedShift);
187 
188  auto doubleGausFitStatus = hist->Fit("fn_doubleGaus", "SQ+");
189  isDoubleGausFitValid = doubleGausFitStatus->IsValid();
190  if (isDoubleGausFitValid) break;
191  int rebinValue = 2;
192  while ((hist->GetNbinsX()) % rebinValue != 0) rebinValue++;
193  hist->Rebin(rebinValue);
194  }
195 
196  TPaveStats* ptstats = new TPaveStats(0.55, 0.73, 0.85, 0.88, "brNDC");
197  ptstats->SetName("stats1");
198  ptstats->SetBorderSize(1);
199  ptstats->SetFillColor(0);
200  ptstats->SetTextAlign(12);
201  ptstats->SetTextFont(42);
202  ptstats->SetTextColor(kGreen + 2);
203  ptstats->SetOptStat(11);
204  ptstats->SetParent(hist);
205  ptstats->Draw();
206  ptstats->AddText("Single Gaus");
207  for (int npar = 0; npar < (fn_singleGaus->GetNpar()); npar++)
208  ptstats->AddText(TString::Format("%s = %.3f #pm %.4f",
209  fn_singleGaus->GetParName(npar),
210  fn_singleGaus->GetParameter(npar),
211  fn_singleGaus->GetParError(npar)));
212  ptstats = new TPaveStats(0.55, 0.49, 0.85, 0.73, "brNDC");
213  ptstats->SetName("stats2");
214  ptstats->SetBorderSize(1);
215  ptstats->SetFillColor(0);
216  ptstats->SetTextAlign(12);
217  ptstats->SetTextFont(42);
218  ptstats->SetTextColor(kRed + 2);
219  ptstats->SetOptStat(11);
220  ptstats->SetParent(hist);
221  ptstats->Draw();
222  ptstats->AddText("Double Gaus");
223  for (int npar = 0; npar < (fn_doubleGaus->GetNpar()); npar++)
224  ptstats->AddText(TString::Format("%s = %.3f #pm %.4f",
225  fn_doubleGaus->GetParName(npar),
226  fn_doubleGaus->GetParameter(npar),
227  fn_doubleGaus->GetParError(npar)));
228  ptstats = new TPaveStats(0.55, 0.43, 0.85, 0.49, "brNDC");
229  ptstats->SetName("stats3");
230  ptstats->SetBorderSize(1);
231  ptstats->SetFillColor(0);
232  ptstats->SetTextAlign(12);
233  ptstats->SetTextFont(42);
234  ptstats->SetTextColor(kBlue + 2);
235  ptstats->SetOptStat(11);
236  ptstats->SetParent(hist);
237  ptstats->Draw();
238 
239  // setting `fillShiftVal` a higher than `m_maximumAllowedShift`. If both fit statuses are invalid,
240  // then this condition will set shift value to the histogram mean.
241  double fillShiftVal = m_maximumAllowedShift + 1.;
242 
243  if (isDoubleGausFitValid) {
244  fillShiftVal = (fn_doubleGaus->GetParameter(1) > 0.5 ?
245  fn_doubleGaus->GetParameter(2) : fn_doubleGaus->GetParameter(4));
246  ptstats->AddText(TString::Format("#splitline{Shift Value from Double Gaus}{%.3f}", fillShiftVal));
247  } else if (isSingleGausFitValid) {
248  fillShiftVal = fn_singleGaus->GetParameter(1);
249  B2WARNING("Fit failed for " << hist->GetName() <<
250  "; using mean from single gaus fit. ");
251  ptstats->AddText(TString::Format("#splitline{Shift Value from Single Gaus}{%.3f}", fillShiftVal));
252  }
253 
254  if (std::fabs(fillShiftVal) > m_maximumAllowedShift) {
255  B2WARNING("Shift value is more than allowed or fit failed in " <<
256  hist->GetName() << " : " <<
257  shiftValues[binLabel].back() <<
258  "; using mean of the histogram.");
259  fillShiftVal = hist->GetMean();
260  ptstats->AddText(TString::Format("#splitline{Shift Value from Histogram Mean}{%.3f}", fillShiftVal));
261  }
262 
263  shiftValues[binLabel].push_back(1. * int(1000. * fillShiftVal) / 1000.);
264  hDrawShift->SetBinContent(ij + 1, clSize, shiftValues[binLabel].back());
265  hDrawShift->GetXaxis()->SetBinLabel(ij + 1, binLabel);
266 
267  c1.Print(outPDF, TString("Title:") + hist->GetName());
268  f->cd();
269  hist->Write();
270 
271  delete hist;
272  } // loop over cluster size
273 
274  f->cd();
275  hClusterSizeVsTimeResidual->Write();
276  delete hClusterSizeVsTimeResidual;
277  } // loop over sensors
278 
279  for (auto item : shiftValues)
280  payload->setClusterTimeShift(alg, item.first, item.second);
281 
282  onePad.cd();
283  hDrawShift->GetXaxis()->LabelsOption("v");
284  hDrawShift->SetStats(0);
285  hDrawShift->Draw("colz");
286  c1.Print(outPDF, TString("Title:") + hDrawShift->GetName());
287 
288  f->cd();
289  hDrawShift->Write();
290  delete hDrawShift;
291 
292  c1.Print(outPDF + "]");
293  f->Close();
294  } // loop over algorithms
295 
296  saveCalibration(payload, "SVDClusterTimeShifter");
297 
298  return c_OK;
299 }
Base class for calibration algorithms.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
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.
int m_minEntries
Set the minimun number of entries required in the histograms.
std::vector< TString > m_timeAlgorithms
List of time algorithms to calibrate.
std::string m_id
Parameter given to set the UniqueID of the payload.
float m_maximumAllowedShift
Allowed deviation of clsOnTracks histo wrt EventT0 histo.
SVDClusterTimeShifterAlgorithm(const std::string &str)
Constructor set the prefix to SVDTimeCalibrationCollector.
virtual EResult calibrate() override
Run algo on data.
This class store the shift in svd time w.r.t.
double doubleGaus(const double *x, const double *par)
Double gaus function, where N is a normalization constant, f is the fractional contribution of the fi...
double singleGaus(const double *x, const double *par)
Single gaus function, where N is a normalization constant, a is the mean of the Gaus distribution,...
Abstract base class for different kinds of events.