Belle II Software development
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
25using 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 successfully =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 singleGaus(const double *x, const double *par)
Single gaus function, where N is a normalization constant, a is the mean of the Gaus distribution,...
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...
Abstract base class for different kinds of events.