Belle II Software development
T0CalibrationAlgorithm.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/T0CalibrationAlgorithm.h>
9#include <calibration/CalibrationAlgorithm.h>
10#include <cdc/dbobjects/CDCTimeZeros.h>
11#include <cdc/dataobjects/WireID.h>
12#include <cdc/geometry/CDCGeometryPar.h>
13
14#include <TError.h>
15#include <TROOT.h>
16#include <TGraphErrors.h>
17#include <TF1.h>
18#include <TFile.h>
19#include <TTree.h>
20#include <TStopwatch.h>
21
22#include <framework/database/DBObjPtr.h>
23#include <framework/logging/Logger.h>
24
25using namespace std;
26using namespace Belle2;
27using namespace CDC;
28
30{
31
33 " -------------------------- T0 Calibration Algorithm -------------------------\n"
34 );
35}
36
38{
39
40 B2INFO("Creating histograms");
41 Float_t x;
42 Float_t t_mea;
43 Float_t t_fit;
44 Float_t ndf;
45 Float_t Pval;
46 UShort_t IWire;
47 UChar_t lay;
48
49 auto tree = getObjectPtr<TTree>("tree");
50 tree->SetBranchAddress("lay", &lay);
51 tree->SetBranchAddress("IWire", &IWire);
52 tree->SetBranchAddress("x_u", &x);
53 tree->SetBranchAddress("t", &t_mea);
54 tree->SetBranchAddress("t_fit", &t_fit);
55 tree->SetBranchAddress("ndf", &ndf);
56 tree->SetBranchAddress("Pval", &Pval);
57
58
59 /* Disable unused branch */
60 std::vector<TString> list_vars = {"lay", "IWire", "x_u", "t", "t_fit", "Pval", "ndf"};
61 tree->SetBranchStatus("*", 0);
62
63 for (TString brname : list_vars) {
64 tree->SetBranchStatus(brname, 1);
65 }
66
67
68 double halfCSize[56];
69
71
72 for (int i = 0; i < 56; ++i) {
73 double R = cdcgeo.senseWireR(i);
74 double nW = cdcgeo.nWiresInLayer(i);
75 halfCSize[i] = M_PI * R / nW;
76 }
77
78 m_hTotal = new TH1F("hTotal", "hTotal", 30, -15, 15);
79
80 //for each channel
81 for (int il = 0; il < 56; il++) {
82 const int nW = cdcgeo.nWiresInLayer(il);
83 for (int ic = 0; ic < nW; ++ic) {
84 m_h1[il][ic] = new TH1F(Form("hdT_L%d_W%d", il, ic), Form("L%d_cell%d", il, ic), 30, -15, 15);
85 }
86 }
87
88 //for each board
89 for (int ib = 0; ib < 300; ++ib) {
90 m_hT0b[ib] = new TH1F(Form("hdT_b%d", ib), Form("boardID_%d", ib), 100, -20, 20);
91 }
92
93 //read data
94 const Long64_t nEntries = tree->GetEntries();
95 B2INFO("Number of entries: " << nEntries);
96 TStopwatch timer;
97 timer.Start();
98 for (Long64_t i = 0; i < nEntries; ++i) {
99 tree->GetEntry(i);
100 double xmax = halfCSize[lay] - 0.1;
101 if ((fabs(x) < m_xmin) || (fabs(x) > xmax)
102 || (ndf < m_ndfmin)
103 || (Pval < m_Pvalmin)) continue; /*select good region*/
104 //each channel
105 m_hTotal->Fill(t_mea - t_fit);
106 m_h1[lay][IWire]->Fill(t_mea - t_fit);
107 //each board
108 int boardID = cdcgeo.getBoardID(WireID(lay, IWire));
109 m_hT0b[boardID]->Fill(t_mea - t_fit);
110 }
111 timer.Stop();
112 B2INFO("Finish making histogram for all channels");
113 B2INFO("Time to fill histograms: " << timer.RealTime() << "s");
114
115}
116
118{
119 B2INFO("Start calibration");
120
121 gROOT->SetBatch(1);
122 gErrorIgnoreLevel = 3001;
123
124 // We are potentially using data from several runs at once during execution
125 // (which may have different DBObject values). So in general you would need to
126 // average them, or apply them to the correct collector data.
127
128 // However since this is the geometry lets assume it is fixed for now.
129 const auto exprun = getRunList()[0];
130 B2INFO("ExpRun used for DB Geometry : " << exprun.first << " " << exprun.second);
131 updateDBObjPtrs(1, exprun.second, exprun.first);
132
133 // CDCGeometryPar basically constructs a ton of objects and other DB objects.
134 // Normally we'd call updateDBObjPtrs to set the values of the requested DB objects.
135 // But in CDCGeometryPar the DB objects get used during the constructor so they must
136 // be set before/during the constructor.
137
138 // Since we are avoiding using the DataStore EventMetaData, we need to pass in
139 // an EventMetaData object to be used when constructing the DB objects.
140
141 B2INFO("Creating CDCGeometryPar object");
143
144 auto hEvtT0 = getObjectPtr<TH1F>("hEventT0");
145 double dEventT0 = hEvtT0->GetMean();
146 createHisto();
147 TH1F* hm_All = new TH1F("hm_All", "mean of #DeltaT distribution for all channels", 500, -10, 10);
148 TH1F* hs_All = new TH1F("hs_All", "#sigma of #DeltaT distribution for all channels", 100, 0, 10);
150
151 TF1* g1 = new TF1("g1", "gaus", -100, 100);
152 g1->SetParLimits(1, -20, 20);
153 vector<double> b, db, Sb, dSb;
154 vector<double> c[56];
155 vector<double> dc[56];
156 vector<double> s[56];
157 vector<double> ds[56];
158
159 B2INFO("Gaus fitting for whole channel");
160 double par[3];
161 m_hTotal->SetDirectory(0);
162 double mean = m_hTotal->GetMean();
163 m_hTotal->Fit("g1", "Q", "", mean - 15, mean + 15);
164 g1->GetParameters(par);
165
166 B2INFO("Gaus fitting for each board");
167 for (int ib = 1; ib < 300; ++ib) {
168 // Set Delta_T0=0 again to make sure there is no strange case
169 // in which T0 might be initialed with a strange value
170 dtb[ib] = 0;
171 err_dtb[ib] = 0;
172
173 if (m_hT0b[ib]->Integral(1, m_hT0b[ib]->GetNbinsX()) < 50) {
174 //set error to large number as a flag of bad value
175 err_dtb[ib] = 50; continue;
176 }
177 mean = m_hT0b[ib]->GetMean();
178 m_hT0b[ib]->SetDirectory(0);
179 m_hT0b[ib]->Fit("g1", "Q", "", mean - 15, mean + 15);
180 g1->GetParameters(par);
181 b.push_back(ib);
182 db.push_back(0.0);
183 Sb.push_back(par[1]);
184 dSb.push_back(g1->GetParError(1));
185 dtb[ib] = par[1] + dEventT0;// add dEvtT0 here
186 err_dtb[ib] = g1->GetParError(1);
187 }
188 B2INFO("Gaus fitting for each cell");
189 for (int ilay = 0; ilay < 56; ++ilay) {
190 const unsigned int nW = cdcgeo.nWiresInLayer(ilay);
191 for (unsigned int iwire = 0; iwire < nW; ++iwire) {
192
193 const int n = m_h1[ilay][iwire]->Integral(1, m_h1[ilay][iwire]->GetNbinsX()) ;
194 B2DEBUG(21, "layer " << ilay << " wire " << iwire << " entries " << n);
195 // Set Delta_T0=0 again to make sure there is no strange case
196 // in which T0 might be initialed with a strange value
197 dt[ilay][iwire] = 0;
198 err_dt[ilay][iwire] = 0;
199
200 if (n < 30) {
201 //set error to large number as a flag of bad value
202 err_dt[ilay][iwire] = 50; continue;
203 }
204
205 mean = m_h1[ilay][iwire]->GetMean();
206 m_h1[ilay][iwire]->SetDirectory(0);
207 m_h1[ilay][iwire]->Fit("g1", "Q", "", mean - 15, mean + 15);
208 g1->GetParameters(par);
209 c[ilay].push_back(iwire);
210 dc[ilay].push_back(0.0);
211 s[ilay].push_back(par[1]);
212 ds[ilay].push_back(g1->GetParError(1));
213
214 dt[ilay][iwire] = par[1] + dEventT0; // add dEvtT0 here;
215 err_dt[ilay][iwire] = g1->GetParError(1);
216 hm_All->Fill(par[1]);// mean of gauss fitting.
217 hs_All->Fill(par[2]); // sigma of gauss fitting.
218 }
219 }
220
221 if (m_storeHisto) {
222 B2INFO("Storing histograms");
223 auto hNDF = getObjectPtr<TH1F>("hNDF");
224 auto hPval = getObjectPtr<TH1F>("hPval");
225 TFile* fout = new TFile(m_histName.c_str(), "RECREATE");
226 fout->cd();
227 TGraphErrors* gr[56];
228 TDirectory* top = gDirectory;
229
230 //store NDF, P-val. EventT0 histogram for monitoring during calibration
231 if (hNDF && hPval && hEvtT0) {
232 hEvtT0->Write();
233 hPval->Write();
234 hNDF->Write();
235 }
236 m_hTotal->Write();
237 hm_All->Write();
238 hs_All->Write();
239 TDirectory* subDir[56];
240 for (int ilay = 0; ilay < 56; ++ilay) {
241 subDir[ilay] = top ->mkdir(Form("lay_%d", ilay));
242 subDir[ilay]->cd();
243 const unsigned int nW = cdcgeo.nWiresInLayer(ilay);
244 for (unsigned int iwire = 0; iwire < nW; ++iwire) {
245 m_h1[ilay][iwire]->Write();
246 }
247 }
248
249 top->cd();
250 TDirectory* corrT0 = top->mkdir("DeltaT0");
251 corrT0->cd();
252
253 if (b.size() > 2) {
254 TGraphErrors* grb = new TGraphErrors(b.size(), &b.at(0), &Sb.at(0), &db.at(0), &dSb.at(0));
255 grb->SetMarkerColor(2);
256 grb->SetMarkerSize(1.0);
257 grb->SetTitle("#DeltaT0;BoardID;#DeltaT0[ns]");
258 grb->SetMaximum(10);
259 grb->SetMinimum(-10);
260 grb->SetName("Board");
261 grb->Write();
262 }
263 for (int sl = 0; sl < 56; ++sl) {
264 if (c[sl].size() < 2) continue;
265 gr[sl] = new TGraphErrors(c[sl].size(), &c[sl].at(0), &s[sl].at(0), &dc[sl].at(0), &ds[sl].at(0));
266 gr[sl]->SetMarkerColor(2);
267 gr[sl]->SetMarkerSize(1.0);
268 gr[sl]->SetTitle(Form("Layer_%d;IWire;#LT t_{mea}-t_{fit} #GT [ns]", sl));
269 gr[sl]->SetMaximum(10);
270 gr[sl]->SetMinimum(-10);
271 gr[sl]->SetName(Form("lay%d", sl));
272 gr[sl]->Write();
273 }
274 fout->Close();
275 }
276 B2INFO("Writing constants...");
277 int Ngood_T0 = write();
278 B2INFO("Checking conversion conditions...");
279 double rms_dT = hm_All->GetRMS();
280 double n_below = hm_All->Integral(0, hm_All->GetXaxis()->FindBin(m_offsetMeanDt - 5 * rms_dT));
281 double n_upper = hm_All->Integral(hm_All->GetXaxis()->FindBin(m_offsetMeanDt + 5 * rms_dT), hm_All->GetXaxis()->GetNbins() - 1);
282 int N_remaining = n_below + n_upper - (14112 - Ngood_T0);
283 if (N_remaining < 0) N_remaining = 0;
284 B2INFO("+ Number of channel which are properly calibrated : " << Ngood_T0);
285 B2INFO("+ Number of channel which still need to be calibrated are: " << N_remaining << "(requirement <" << m_maxBadChannel << ")");
286 B2INFO("+ Median of Delta_T - offset:" << hm_All->GetMean() - m_offsetMeanDt << "(requirement: <" << m_maxMeanDt << ")");
287 B2INFO("+ RMS of Delta_T dist. :" << rms_dT << " (Requirement: <" << m_maxRMSDt << ")");
288
289 if (fabs(hm_All->GetMean() - m_offsetMeanDt) < m_maxMeanDt
290 && fabs(hm_All->GetRMS()) < m_maxRMSDt
291 && N_remaining < m_maxBadChannel) {
292 B2INFO("T0 Calibration Finished:");
293 return c_OK;
294 } else {
295 B2INFO("Need more iteration ...");
296 return c_Iterate;
297 }
298}
299
301{
303 CDCTimeZeros* tz = new CDCTimeZeros();
304
305 TH1F* hT0B[300];
306 for (int ib = 0; ib < 300; ++ib) {
307 hT0B[ib] = new TH1F(Form("hT0B%d", ib), Form("boardID_%d", ib), 9000, 0, 9000);
308 }
309
310 TH1F* hT0_all = new TH1F("hT0_all", "T0 distribution", 9000, 0, 9000);
311 double T0;
312 // get old T0 to calculate T0 mean of each board
313 for (int ilay = 0; ilay < 56; ++ilay) {
314 const unsigned int nW = cdcgeo.nWiresInLayer(ilay);
315 for (unsigned int iwire = 0; iwire < nW; ++iwire) {
316 WireID wireid(ilay, iwire);
317 T0 = cdcgeo.getT0(wireid);
318 hT0_all->Fill(T0);
319 hT0B[cdcgeo.getBoardID(wireid)]->Fill(T0);
320 }
321 }
322
323 //get Nominal T0
324 double T0_average = getMeanT0(hT0_all);
325 if (fabs(T0_average - m_commonT0) > 50) {B2WARNING("Large difference between common T0 (" << m_commonT0 << ") and aveage value" << T0_average);}
326 // get average T0 for each board and also apply T0 correction for T0 of that board
327 double T0B[300];
328 for (int i = 0; i < 300; ++i) {T0B[i] = m_commonT0;}
329
330
331 for (int ib = 1; ib < 300; ++ib) {
332 T0B[ib] = getMeanT0(hT0B[ib]);
333 if (fabs(T0B[ib] - T0_average) > 25) {
334 B2WARNING("T0 of Board " << ib << " (= " << T0B[ib] << ") is too different with common T0: " << T0_average <<
335 "\n It will be replaced by common T0");
336 T0B[ib] = T0_average;
337 continue;
338 }
339 //correct T0 board
340 if (abs(err_dtb[ib]) < 2 && abs(dtb[ib]) < 20) {
341 T0B[ib] -= dtb[ib];
342 }
343 }
344
345 //correct T0 and write
346 double dT;
347 int N_good = 0;
348 for (int ilay = 0; ilay < 56; ++ilay) {
349 const unsigned int nW = cdcgeo.nWiresInLayer(ilay);
350 for (unsigned int iwire = 0; iwire < nW; ++iwire) {
351 WireID wireid(ilay, iwire);
352 int bID = cdcgeo.getBoardID(wireid);
353
354 //get old T0, replace with common T0 of board or average over all channel.
355 T0 = cdcgeo.getT0(wireid);
356 if (fabs(T0 - T0B[bID]) > 25 || fabs(T0 - T0_average) > 25) {
357 B2WARNING("T0 of wireID L-W: " << ilay << "--" << iwire << " (= " << T0
358 << ") is too different with common T0 of board: " << bID << " = " << T0B[bID] <<
359 "\n It will be replaced by common T0 of the Board");
360 T0 = T0B[bID];
361 }
362
363 //select DeltaT
364 dT = 0;
365 if (abs(err_dt[ilay][iwire]) < 2 && abs(dt[ilay][iwire]) < 20) {
366 dT = dt[ilay][iwire];
367 N_good += 1;
368 }
369
370 //export
371 tz->setT0(wireid, T0 - dT);
372 }
373 }
374
375 if (m_textOutput == true) {
377 }
378 saveCalibration(tz, "CDCTimeZeros");
379 return N_good;
380}
382{
383 double mean1 = h1->GetMean();
384 h1->GetXaxis()->SetRangeUser(mean1 - 50, 8000);
385 double mean2 = h1->GetMean();
386 while (fabs(mean1 - mean2) > 0.5) {
387 mean1 = mean2;
388 h1->GetXaxis()->SetRangeUser(mean1 - 50, 8000);
389 mean2 = h1->GetMean();
390 }
391 return mean2;
392
393}
double R
typedef autogenerated by FFTW
Database object for timing offset (t0).
void outputToFile(std::string fileName) const
Output the contents in text file format.
void setT0(unsigned short iCLayer, unsigned short iWire, float t0)
Set t0 in the list.
The Class for CDC Geometry Parameters.
unsigned short getBoardID(const WireID &wID) const
Returns frontend board id. corresponding to the wire id.
float getT0(const WireID &wireID) const
Returns t0 parameter of the specified sense wire.
unsigned nWiresInLayer(int layerId) const
Returns wire numbers in a layer.
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
double senseWireR(int layerId) const
Returns radius of sense wire in each layer.
std::string m_outputT0FileName
output t0 file name for text file
double m_offsetMeanDt
offset dT distribution caused by event timing extraction;
TH1F * m_hTotal
1D histogram of delta T whole channel
double dt[56][385]
dt of each channel
void createHisto()
create histo for each channel
double getMeanT0(TH1F *h1)
calculate mean of the T0 distribution
double m_maxRMSDt
RMS of dT distribution of all channels.
DBObjPtr< CDCGeometry > m_cdcGeo
Geometry of CDC.
double m_commonT0
A common T0 of all channels.
double m_maxMeanDt
Mean of dT distribution of all channels;.
TH1F * m_h1[56][385]
1D histogram for each channel
double err_dt[56][385]
error of dt of each channel
bool m_textOutput
output text file if true
EResult calibrate() override
Run algo on data.
TH1F * m_hT0b[300]
1D histogram for each board
double m_Pvalmin
minimum pvalue required
double err_dtb[300]
error of dt of board
double m_maxBadChannel
Number of channels which has DeltaT0 larger then 0.5.
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_Iterate
Needs iteration =1 in Python.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
Class to identify a wire inside the CDC.
Definition WireID.h:34
std::shared_ptr< T > getObjectPtr(const std::string &name, const std::vector< Calibration::ExpRun > &requestedRuns)
Get calibration data object by name and list of runs, the Merge function will be called to generate t...
Abstract base class for different kinds of events.
STL namespace.