Belle II Software  release-08-01-10
TimeWalkCalibration.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/TimeWalkCalibration.h>
9 #include <cdc/dbobjects/CDCTimeWalks.h>
10 #include <cdc/geometry/CDCGeometryPar.h>
11 #include <cdc/dataobjects/WireID.h>
12 
13 #include <TF1.h>
14 #include <TFile.h>
15 #include <TChain.h>
16 #include <TDirectory.h>
17 #include <TROOT.h>
18 #include <framework/utilities/FileSystem.h>
19 #include <framework/database/DBImportObjPtr.h>
20 #include <framework/database/DBObjPtr.h>
21 #include <framework/database/IntervalOfValidity.h>
22 #include <framework/logging/Logger.h>
23 
24 using namespace std;
25 using namespace Belle2;
26 using namespace CDC;
27 
28 TimeWalkCalibration::TimeWalkCalibration()
29 {
30  // setDescription("CDC Time Walk Calibration");
31 }
32 void TimeWalkCalibration::CreateHisto()
33 {
34  double x;
35  double t_mea;
36  double w;
37  double t_fit;
38  double ndf;
39  double Pval;
40  unsigned short adc;
41  // int board;
42  int IWire;
43  int lay;
44 
45  // auto& tree = getObject<TTree>("cdcCalib");
46  TChain* tree = new TChain("tree");
47  tree->Add(m_InputRootFileName.c_str());
48 
49  tree->SetBranchAddress("lay", &lay);
50  tree->SetBranchAddress("IWire", &IWire);
51  tree->SetBranchAddress("x_u", &x);
52  tree->SetBranchAddress("t", &t_mea);
53  tree->SetBranchAddress("t_fit", &t_fit);
54  tree->SetBranchAddress("weight", &w);
55  tree->SetBranchAddress("ndf", &ndf);
56  tree->SetBranchAddress("Pval", &Pval);
57  tree->SetBranchAddress("adc", &adc);
58 
59  /* Disable unused branch */
60  std::vector<TString> list_vars = {"lay", "IWire", "x_u", "t", "t_fit", "weight", "Pval", "ndf", "adc"};
61  tree->SetBranchStatus("*", 0);
62 
63  for (TString brname : list_vars) {
64  tree->SetBranchStatus(brname, 1);
65  }
66 
67 
68  static CDCGeometryPar& cdcgeo = CDCGeometryPar::Instance();
69  double halfCSize[56];
70  for (int i = 0; i < 56; ++i) {
71  double R = cdcgeo.senseWireR(i);
72  double nW = cdcgeo.nWiresInLayer(i);
73  halfCSize[i] = M_PI * R / nW;
74  }
75  int nEntries = tree->GetEntries();
76  B2INFO("Number of entry: " << nEntries);
77  //Histogram of each board
78  for (int i = 0; i < 300; ++i) {
79  m_h2[i] = new TH2D(Form("board_%d", i), Form("board_%d", i), 50, 0., 500, 60, -30, 30);
80  }
81 
82  //read data
83  for (int i = 0; i < nEntries; ++i) {
84  tree->GetEntry(i);
85  double xmax = halfCSize[lay] - 0.12;
86  if ((fabs(x) < m_xmin) || (fabs(x) > xmax)
87  || (ndf < m_ndfmin)
88  || (Pval < m_Pvalmin)) continue; /*select good region*/
89 
90  m_h2[cdcgeo.getBoardID(WireID(lay, IWire))]->Fill(adc, fabs(t_mea) - fabs(t_fit));
91  }
92  B2INFO("Reading data and filling histogram are done");
93 }
94 
95 bool TimeWalkCalibration::calibrate()
96 {
97  gROOT->SetBatch(1);
98  readTW();
99  CreateHisto();
100  TF1* fold = nullptr;
101  if (m_twParamMode_old == 0)
102  fold = new TF1("fold", "[0]/sqrt(x)", 0, 500);
103  else if (m_twParamMode_old == 1)
104  fold = new TF1("fold", "[0]*exp(-1*[1]*x)", 0, 500);
105  else
106  B2FATAL("Mode " << m_twParamMode_new << " haven't implemented yet.");
107 
108  B2INFO("Old time walk formular: ");
109  fold->Print();
110  B2INFO("Time walk mode new: " << m_twParamMode_new << " with " << m_nTwParams_new << " parameters");
111  // double p3, p1;
112  m_tw_new[0].resize(m_nTwParams_new, 0.0); //for board 0, no available
113  for (int ib = 1; ib < 300; ++ib) {
114  m_flag[ib] = 1;
115  B2DEBUG(199, "Board ID:" << ib);
116  m_h2[ib]->SetDirectory(0);
117 
118  // ignore if histogram is low statistic
119  if (m_h2[ib]->GetEntries() < 500) { m_flag[ib] = 0; continue;}
120  // do slide fit
121  m_h2[ib]->FitSlicesY(0, 1, -1, 10);
122  TString name = m_h2[ib]->GetName();
123  TString hm_name = name + "_1";
124  m_h1[ib] = (TH1D*)gDirectory->Get(hm_name);
125  if (!m_h1[ib]) {m_flag[ib] = 0; continue;}
126  m_h1[ib]->SetDirectory(0);
127 
128  //if number of poist after slide fit quite low, ignore
129  if (m_h1[ib]->GetEntries() < 5) {
130  m_flag[ib] = 0;
131  B2WARNING("Low statistic, number of points after slice fit: " << m_h1[ib]->GetEntries());
132  continue;
133  }
134 
135  // Add previous correction to this
136  for (int p = 0; p < m_nTwParams_old; ++p) {
137  fold->SetParameter(p, m_tw_old[ib][p]);
138  }
139  m_h1[ib]->Add(fold);
140  if (m_twParamMode_new == 0) {
141  TF1* func = new TF1("func", "[0]+[1]/sqrt(x)", 0, 500);
142  func->SetParameters(-4, 28);
143  m_h1[ib]->Fit("func", "MQ", "", 20, 150);
144  }//fit for mode 0
145  else if (m_twParamMode_new == 1) {
146  fitToExponentialFunc(m_h1[ib]);//do fitting for mode 1
147  } else {
148  B2FATAL("Mode " << m_twParamMode_new << " is not available, please check again");
149  }
150 
151  // read fitted parameters
152  TF1* f1 = m_h1[ib]->GetFunction("func");
153  if (!f1) { m_flag[ib] = 0; continue;}
154  m_constTerm[ib] = f1->GetParameter(0);
155  m_tw_new[ib].resize(m_nTwParams_new, 0.0);
156  for (int i = 1; i <= m_nTwParams_new; ++i) {
157  m_tw_new[ib][i - 1] = f1->GetParameter(i);
158  }
159  B2DEBUG(199, "Prob of fitting:" << f1->GetProb());
160  B2DEBUG(199, "Fitting Param 0-1:" << f1->GetParameter(0) << " - " << f1->GetParameter(1));
161  }
162  //Write histogram to file
163  if (m_storeHisto) {
164  B2INFO("Storing histogram");
165  TFile* fhist = new TFile("tw_histo.root", "recreate");
166  TDirectory* old = gDirectory;
167  TDirectory* h1D = old->mkdir("h1D");
168  TDirectory* h2D = old->mkdir("h2D");
169  h1D->cd();
170  for (int ib = 1; ib < 300; ++ib) {
171  if (!m_h1[ib] || m_flag[ib] != 1) continue;
172  m_h1[ib]->SetDirectory(0);
173  if (m_h1[ib]->GetEntries() < 5) continue;
174 
175  m_h1[ib]->SetMinimum(-5);
176  m_h1[ib]->SetMaximum(15);
177  m_h1[ib]->Write();
178  }
179  B2DEBUG(199, "Store 2D histogram");
180  h2D->cd();
181  for (int ib = 1; ib < 300; ++ib) {
182  if (m_h2[ib]) {
183  m_h2[ib]->SetDirectory(0);
184  m_h2[ib]->Write();
185  }
186  }
187  fhist->Close();
188  B2INFO("All hitograms were stored");
189  }
190  Write();
191  updateT0();
192  return true;
193 }
194 void TimeWalkCalibration::Write()
195 {
196  B2INFO("Store calibrated time walk parameters");
197  int nfailure(-1);//for no exist board; board 0;
198  // CDCTimeWalks* dbTw = new CDCTimeWalks();
200  dbTw.construct();
201 
202  for (int ib = 0; ib < 300; ++ib) {
203  // If fitting fail and new mode is same as previous input mode. use old param
204  if (m_flag[ib] != 1) {
205  nfailure += 1;
206  if (m_twParamMode_old == m_twParamMode_new) {
207  dbTw->setTimeWalkParams(ib, m_tw_old[ib]);
208  } else {
209  //and even calibrated fail but mode is different from previous.
210  //in this case, param is zero
211  m_tw_new[ib].resize(m_nTwParams_new, 0.0);
212  dbTw->setTimeWalkParams(ib, m_tw_new[ib]);
213  }
214  } else {
215  //Use new param if board is successfuly calibrated
216  dbTw->setTimeWalkParams(ib, m_tw_new[ib]);
217  }
218  }
219  dbTw->setTwParamMode(m_twParamMode_new);
220  dbTw->outputToFile(m_outputTWFileName);
221  if (m_useDB) {
222  IntervalOfValidity iov(m_firstExperiment, m_firstRun,
223  m_lastExperiment, m_lastRun);
224  dbTw.import(iov);
225  }
226 
227  B2RESULT("Failure to calibrate time-walk for " << nfailure << " board");
228  B2RESULT("Time-walk coeff. table wrote to " << m_outputTWFileName.c_str());
229 }
230 void TimeWalkCalibration::updateT0()
231 {
232  B2INFO("Add constant term into T0 database");
233  static CDCGeometryPar& cdcgeo = CDCGeometryPar::Instance();
234  ofstream ofs(m_outputT0FileName.c_str());
235  DBImportObjPtr<CDCTimeZeros> tz;// = new CDCTimeZeros();
236  tz.construct();
237  double T0;
238  //correct T0 and write
239  for (int ilay = 0; ilay < 56; ++ilay) {
240  for (unsigned int iwire = 0; iwire < cdcgeo.nWiresInLayer(ilay); ++iwire) {
241  WireID wireid(ilay, iwire);
242  int bID = cdcgeo.getBoardID(wireid);
243  T0 = cdcgeo.getT0(wireid);
244  if (m_flag[bID] == 1) {
245  ofs << ilay << "\t" << iwire << "\t" << T0 - m_constTerm[bID] << std::endl;
246  if (m_useDB)
247  tz->setT0(wireid, T0 - m_constTerm[bID]);
248  } else {
249  ofs << ilay << "\t" << iwire << "\t" << T0 << std::endl;
250  if (m_useDB)
251  tz->setT0(wireid, T0 - m_constTerm[bID]);
252  }
253  }
254  }
255  ofs.close();
256  if (m_useDB) {
257  IntervalOfValidity iov(m_firstExperiment, m_firstRun,
258  m_lastExperiment, m_lastRun);
259  tz.import(iov);
260  }
261  B2RESULT("updated constant term of tw correction to T0 constant.");
262 }
263 void TimeWalkCalibration::fitToExponentialFunc(TH1D* h1)
264 {
265  h1->SetDirectory(0);
266  int max = h1->GetMaximumBin();
267  double maxX = h1->GetBinCenter(max);
268  double maxY = h1->GetBinContent(max);
269  B2DEBUG(199, "Max: id - x - y : " << max << " " << maxX << " " << maxY);
270 
271  //search for p0
272  double p0 = -1;
273  h1->Fit("pol0", "MQE", "", maxX + 125, 500);
274  if (h1->GetFunction("pol0")) {
275  p0 = h1->GetFunction("pol0")->GetParameter(0);
276  }
277  //create histo = old-p0;
278  // fit with expo function to find intial parameters
279  TH1D* hshift = new TH1D("hshift", "shift", h1->GetNbinsX(), 0, 500);
280  hshift->SetDirectory(0);
281  for (int i = 0; i <= h1->GetNbinsX(); ++i) {
282  hshift->SetBinContent(i, h1->GetBinContent(i) - p0);
283  }
284  hshift->Fit("expo", "MQE", "", 0, 400);
285  double p1 = maxY + p0;
286  double p2 = -0.04;
287  if (hshift->GetFunction("expo")) {
288  p1 = exp(hshift->GetFunction("expo")->GetParameter(0));
289  p2 = hshift->GetFunction("expo")->GetParameter(1);
290  }
291 
292  // fit with function
293  TF1* func = new TF1("func", "[0]+ [1]*exp(-1*[2]*x)", 0, 500);
294  func->SetParameters(p0, p1, -1 * p2);
295  func->SetParLimits(0, -5, 5);
296  func->SetParLimits(1, -5, 500);
297  func->SetParLimits(2, -0.01, 0.1);
298  h1->Fit("func", "MQE", "", 10, 400);
299 }
300 void TimeWalkCalibration::readTW()
301 {
302  if (m_useDB) {
304  m_twParamMode_old = oldDB->getTwParamMode();
305  for (int ib = 0; ib < 300; ++ib) {
306  m_tw_old[ib] = oldDB->getTimeWalkParams(ib);
307  }
308  } else {
309  //For text mode
310  std::string fileName1 = "/data/cdc" + m_InputTWFileName;
311  std::string fileName = FileSystem::findFile(fileName1);
312  ifstream ifs;
313  if (fileName == "") {
314  fileName = FileSystem::findFile(m_InputTWFileName);
315  }
316  if (fileName == "") {
317  B2FATAL("CDCGeometryPar: " << fileName1 << " not exist!");
318  } else {
319  B2INFO("Time Walk Calibration: open " << fileName);
320  ifs.open(fileName.c_str());
321  if (!ifs) B2FATAL("CDCGeometryPar: cannot open " << fileName1 << " !");
322  }
323 
324  unsigned short iBoard(0);
325  int nRead(0);
326  double dumy(0.);// dumy2(0.), dumy3(0.);
327  ifs >> m_twParamMode_old >> m_nTwParams_old;
328  while (ifs >> iBoard) {
329  m_tw_old[iBoard].resize(m_nTwParams_old);
330  for (int i = 0; i < m_nTwParams_old; ++i) {
331  ifs >> dumy;
332  m_tw_old[iBoard][i] = dumy;
333  }
334  ++nRead;
335  }
336  if (nRead - 1 != 299) B2FATAL("#lines read-in (=" << nRead << ") is not equal #boards 299 !");
337  ifs.close();
338  B2INFO("TW from database: mode = " << m_twParamMode_old << " with " << m_nTwParams_old << " parameters");
339  }
340 }
double R
typedef autogenerated by FFTW
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.
double senseWireR(int layerId) const
Returns radius of sense wire in each layer.
bool import(const IntervalOfValidity &iov)
Import the object to database.
Definition: DBImportBase.cc:36
Class for importing a single object to the database.
void construct(Args &&... params)
Construct an object of type T in this DBImportObjPtr using the provided constructor arguments.
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
A class that describes the interval of experiments/runs for which an object in the database is valid.
Class to identify a wire inside the CDC.
Definition: WireID.h:34
Abstract base class for different kinds of events.