Belle II Software  release-08-01-08
eclWaveformTemplateCalibrationC2Algorithm.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 /* Own header. */
10 #include <ecl/calibration/eclWaveformTemplateCalibrationC2Algorithm.h>
11 
12 /* ECL headers. */
13 #include <ecl/dataobjects/ECLElementNumbers.h>
14 #include <ecl/digitization/OfflineFitFunction.h>
15 #include <ecl/dbobjects/ECLDigitWaveformParameters.h>
16 #include <ecl/dbobjects/ECLCrystalCalib.h>
17 
18 /* Basf2 headers. */
19 #include <framework/database/DBObjPtr.h>
20 
21 /* ROOT headers. */
22 #include <TFile.h>
23 #include <TGraph.h>
24 #include <TTree.h>
25 #include <TF1.h>
26 
27 /* C++ headers. */
28 #include <ctime>
29 
30 using namespace std;
31 using namespace Belle2;
32 using namespace ECL;
33 using namespace Calibration;
34 
36 eclWaveformTemplateCalibrationC2Algorithm::eclWaveformTemplateCalibrationC2Algorithm():
37  CalibrationAlgorithm("eclWaveformTemplateCalibrationC2Collector")
38 {
40  "Perform the photon template shape calibration using waveforms from high energy crystals from e+e- --> gamma gamma events"
41  );
42 
43 }
44 
45 
46 namespace {
47 
48  // Used to perform simultaneous fits of multiple waveforms
49  std::vector<TF1*> FitFunctions;
50  const double numberofADCPoints = 31.0;
51 
52  double fitf(double* x, double* par)
53  {
54 
55  double xtoeval = std::fmod(x[0], numberofADCPoints);
56  int whichFitFunctions = x[0] / numberofADCPoints;
57 
58  for (int i = 0; i < (int)FitFunctions.size(); i++) {
59  FitFunctions[i]->SetParameter(0, par[i]);
60  FitFunctions[i]->SetParameter(1, par[FitFunctions.size() + i]);
61  FitFunctions[i]->SetParameter(2, par[(2 * FitFunctions.size()) + i]);
62  FitFunctions[i]->FixParameter(3, 0);
63  for (int k = 0; k < 10; k++) {
64  FitFunctions[i]->SetParameter(4 + k, par[(3 * FitFunctions.size()) + k]);
65  }
66  }
67 
68  return FitFunctions[whichFitFunctions]->Eval(xtoeval * 0.5);
69  }
70 
71 }
72 
74 {
75 
76  B2INFO("Reading ECLCrystalCalib payload: eclWaveformTemplateCalibrationC1MaxResLimit");
77  DBObjPtr<ECLCrystalCalib> existingeclWaveformTemplateCalibrationC1MaxResLimit("eclWaveformTemplateCalibrationC1MaxResLimit");
78  auto runs = getRunList();
79  ExpRun chosenRun = runs.front();
80  // After here your DBObjPtrs are correct
81  updateDBObjPtrs(1, chosenRun.second, chosenRun.first);
82 
84  gROOT->SetBatch();
85 
86  std::vector<double> cellIDArray;
87  std::vector<double> maxResidualArray; // used to quantify fit result
88  std::vector<double> limitResidualArray; // what was final resLimit used
89  std::vector<double> parLimitFactorArray; // what was final parLimitFactorArray used
90 
92  TFile* histfile = new TFile(m_outputName.c_str(), "recreate");
93 
95  TFile* f_PhotonTemplateOutput = new TFile(Form("PhotonShapes_Low%d_High%d.root", m_firstCellID, m_lastCellID), "RECREATE");
96  TTree* mtree = new TTree("mtree", "");
97  std::vector<double> PhotonWaveformArray(100000);
98  mtree->Branch("PhotonArray", PhotonWaveformArray.data(), "PhotonWaveformArray[100000]/D");
99 
101  auto tree = getObjectPtr<TTree>("tree");
102  int CellID;
103  tree->SetBranchAddress("CellID", &CellID);
104  std::vector<int> Waveform(m_NumberofADCPoints);
105  std::vector<int> XValues(m_NumberofADCPoints);
106  for (int i = 0; i < m_NumberofADCPoints; i++) {
107  tree->SetBranchAddress(Form("ADC%d", i), &Waveform[i]);
108  XValues[i] = i;
109  }
110 
111  std::time_t t = std::time(0);
112 
114  int AttemptCounter = 0;
115 
117  ECLDigitWaveformParameters* PhotonParameters = new ECLDigitWaveformParameters();
118 
121  double ParMin11t[11];
122 
124  for (int CellID_i = m_firstCellID; CellID_i <= m_lastCellID; CellID_i++) {
125 
127  if (CellID_i > 7776 || CellID_i < 1153) {
128  ParMin11t[0] = 20.3216;
129  ParMin11t[1] = -0.0206266;
130  ParMin11t[2] = 0.313928;
131  ParMin11t[3] = 0.589646;
132  ParMin11t[4] = 0.455526;
133  ParMin11t[5] = 1.03656;
134  ParMin11t[6] = 0.000822467;
135  ParMin11t[7] = 45.1574;
136  ParMin11t[8] = 0.716034;
137  ParMin11t[9] = 0.616753;
138  ParMin11t[10] = 0.0851222;
139  } else {
140  ParMin11t[0] = 24.6176;
141  ParMin11t[1] = 0.00725002;
142  ParMin11t[2] = 0.601578;
143  ParMin11t[3] = 0.491976;
144  ParMin11t[4] = 0.601034;
145  ParMin11t[5] = 0.601684;
146  ParMin11t[6] = -0.0103788;
147  ParMin11t[7] = 2.22615;
148  ParMin11t[8] = 0.671294;
149  ParMin11t[9] = 0.529878;
150  ParMin11t[10] = 0.0757927;
151  }
152 
153  double resLimit = 2 * existingeclWaveformTemplateCalibrationC1MaxResLimit->getCalibVector()[CellID_i -
154  1];
155  double resLimitOriginal = resLimit;
156 
158  std::vector<int> EntriesToSkip;
159 
161  double maxResidual = 1000.0;
162 
164  bool PASS = false;
165  while (PASS == false) {
166 
168  std::vector<double> xValuesToFit;
169  std::vector<double> yValuesToFit;
170 
172  std::vector<double> guessBaseline;
173  std::vector<double> guessAmp;
174  std::vector<double> guessTime;
175 
177  std::vector<int> NtupleEntries;
178 
179  int counter = 0; // counts entry number in xValuesToFit
180  int counterWaveforms = 0; // counts numver of waveforms selected
181 
182  for (int i = 0; i < tree->GetEntries(); i++) {
183 
185  bool skipEvent = false;
186  for (int k = 0; k < (int)EntriesToSkip.size(); k++) {
187  if (EntriesToSkip[k] == i) skipEvent = true;
188  }
189  if (skipEvent) continue;
190 
191  tree->GetEntry(i);
192 
193  if (CellID != CellID_i) continue;
194 
195  double maxval = 0;
196  double maxIndex = 0;
197  for (int j = 0; j < m_NumberofADCPoints; j++) {
198  xValuesToFit.push_back(counter);
199  yValuesToFit.push_back(Waveform[j]);
200  if (Waveform[j] > maxval) {
201  maxval = Waveform[j];
202  maxIndex = j;
203  }
204  counter++;
205  }
206 
208  guessBaseline.push_back(Waveform[0]);
209  guessAmp.push_back(maxval);
210  guessTime.push_back((maxIndex - 4.5) * 0.5);
212  NtupleEntries.push_back(i);
213  B2INFO("Entry: " << i);
214 
215  counterWaveforms++;
216 
217  if (counterWaveforms == m_CollectorLimit) break;
218 
219  }
220 
222  B2INFO("CellID " << CellID_i << " counterWaveforms = " << counterWaveforms);
223 
224  if (counterWaveforms < m_TotalCountsThreshold) {
225  B2INFO("eclWaveformTemplateCalibrationC2Algorithm: warning total entries for cell ID " << CellID_i << " is only: " <<
226  counterWaveforms <<
227  " Requirement is : " << m_TotalCountsThreshold);
229  return c_NotEnoughData;
230  }
231 
232 
234  auto gWaveformToFit = new TGraph(xValuesToFit.size(), xValuesToFit.data(), yValuesToFit.data());
235  gWaveformToFit->SetName(Form("gWaveformToFit_%d", int(CellID_i)));
236 
240  FitFunctions.clear();
241  for (int i = 0; i < counterWaveforms; i++) {
242  FitFunctions.push_back(new TF1(Form("Shp_%d", i), Belle2::ECL::WaveFuncTwoComponent, 0, 30.5, 26));
243  FitFunctions[i]->SetNpx(10000);
244  FitFunctions[i]->FixParameter(3, 0);
245  for (int k = 0; k < 10; k++) {
246  FitFunctions[i]->SetParameter(4 + k, ParMin11t[k + 1]);
247  FitFunctions[i]->FixParameter(10 + 4 + k, ParMin11t[k + 1]);
248  }
249  FitFunctions[i]->FixParameter(24, ParMin11t[0]);
250  FitFunctions[i]->FixParameter(25, 1);
251  }
252 
254  TF1* TotalFitFunction = new TF1("TotalFitFunction", fitf, 0, counterWaveforms * m_NumberofADCPoints,
255  (3 * FitFunctions.size()) + 10);
256 
258  int FFsize = FitFunctions.size();
259  for (int i = 0; i < FFsize; i++) {
260  TotalFitFunction->SetParameter(i, guessTime[i]);
261  TotalFitFunction->SetParameter(FFsize + i, guessBaseline[i]);
262  TotalFitFunction->SetParameter((2 * FFsize) + i, guessAmp[i]);
263  for (int k = 0; k < 10; k++) {
264  TotalFitFunction->SetParameter((3 * FFsize) + k, ParMin11t[k + 1]);
265  if (m_ParamLimitFactor < 2) {
266  TotalFitFunction->SetParLimits((3 * FFsize) + k, ParMin11t[k + 1] - m_ParamLimitFactor * fabs(ParMin11t[k + 1]),
267  ParMin11t[k + 1] + m_ParamLimitFactor * fabs(ParMin11t[k + 1]));
268  } else {
269  TotalFitFunction->ReleaseParameter((3 * FFsize) + k);
270  }
271  }
272  }
273 
275  gWaveformToFit->Fit("TotalFitFunction", "Q M W N 0 R", "", 0, counterWaveforms * m_NumberofADCPoints);
276 
278  std::vector<int> FitResultY;
279  std::vector<int> FitResultX;
280  int maxResidualWaveformID = 0; // Used to remove waveforms with potential pile-up outside baseline
281 
283  maxResidual = 0.0;
284  double npts = xValuesToFit.size();
285  double maxResidualOld = 0.0;
286  for (int k = 0; k < npts; k++) {
287  double xVal = xValuesToFit[k];
288  double yVal = TotalFitFunction->Eval(xVal);
289  FitResultX.push_back(xVal);
290  FitResultY.push_back(yVal);
291  double diff = fabs(yValuesToFit[k] - yVal);
292  if (diff > maxResidual) {
293  maxResidual = diff;
294  maxResidualWaveformID = (k / m_NumberofADCPoints);
295  maxResidualOld = fabs(yValuesToFit[k] / yVal);
296  }
297  }
298 
299  // Checking if fit matches the data.
300  if (maxResidual > resLimit) {
301 
302  B2INFO("FAIL: CellID_i " << CellID_i << " maxResidual " << maxResidual << " removing entry: " <<
303  NtupleEntries[maxResidualWaveformID] <<
304  " which was waveform number " << maxResidualWaveformID << " resLimit was " << resLimit << " , resLimit started at " <<
305  resLimitOriginal);
306  B2INFO("Old maxResidual of Data/Fit was " << maxResidualOld);
307 
308  B2INFO("Iter Time = " << std::time(0) - t << std::endl);
309  t = std::time(0);
310 
311  std::cout << "FAIL: CellID_i " << CellID_i << " maxResidual " << maxResidual << " removing entry: " <<
312  NtupleEntries[maxResidualWaveformID] <<
313  " which was waveform number " << maxResidualWaveformID << " resLimit was " << resLimit << " , resLimit started at " <<
314  resLimitOriginal << std::endl;
315  std::cout << "wave = [";
316  for (int k = 0; k < npts; k++) {
317  std::cout << yValuesToFit[k];
318  if (k < (npts - 1)) {
319  std::cout << ",";
320  } else {
321  std::cout << "]" << std::endl;
322  }
323  }
324  std::cout << "fitRes = [";
325  for (int k = 0; k < npts; k++) {
326  std::cout << TotalFitFunction->Eval(xValuesToFit[k]);
327  if (k < (npts - 1)) {
328  std::cout << ",";
329  } else {
330  std::cout << "]" << std::endl;
331  }
332  }
333 
335  EntriesToSkip.push_back(NtupleEntries[maxResidualWaveformID]);
336 
337  AttemptCounter++;
338 
340  if (counterWaveforms < m_SimutaniousFitLimit) AttemptCounter = m_AttemptLimit;
341 
343  if (AttemptCounter == m_AttemptLimit) {
344 
346 
347  B2INFO("AttemptCounter reach limit: " << AttemptCounter << " counterWaveforms: " << counterWaveforms);
348  B2INFO("Increasing m_ParamLimitFactor to " << m_ParamLimitFactor);
349 
351  EntriesToSkip.clear();
352  AttemptCounter = 0;
353 
356  resLimit *= m_ResLimitIterator;
357  B2INFO("Increasing resLimit to " << resLimit);
359  }
360  }
361 
362  } else {
363 
364  B2INFO("PASS: CellID_i " << CellID_i << " maxResidual " << maxResidual << " number of waveforms used was " << counterWaveforms <<
365  " resLimit was " << resLimit);
366 
367  PASS = true;
368 
369  limitResidualArray.push_back(resLimit);
370  parLimitFactorArray.push_back(m_ParamLimitFactor);
371 
373  AttemptCounter = 0;
375 
376  auto gFitResult = new TGraph(FitResultX.size(), FitResultX.data(), FitResultY.data());
377  gFitResult->SetName(Form("gFitResult_%d", int(CellID_i)));
378 
380  cellIDArray.push_back(CellID_i);
381  maxResidualArray.push_back(maxResidual);
382 
384  histfile->cd();
385  gWaveformToFit->Write();
386  gFitResult->Write();
387 
389  float tempPhotonPar11[11];
390  tempPhotonPar11[0] = ParMin11t[0];
391  for (unsigned int k = 0; k < 10; k++) tempPhotonPar11[k + 1] = TotalFitFunction->GetParameter((3 * FFsize) + k);
392 
394  FitFunctions[0]->SetParameter(0, 0);
395  FitFunctions[0]->SetParameter(1, 0);
396  FitFunctions[0]->SetParameter(2, 1);
397  for (int k = 0; k < 10; k++) {
398  FitFunctions[0]->SetParameter(4 + k, tempPhotonPar11[k + 1]);
399  FitFunctions[0]->SetParameter(10 + 4 + k, tempPhotonPar11[k + 1]);
400  }
401  FitFunctions[0]->FixParameter(24, ParMin11t[0]);
402  FitFunctions[0]->FixParameter(25, 1);
403 
405  double MaxVal = -1.0;
406  const double cnpts = 2000;
407  for (int k = 0; k < cnpts; k++) {
408  double xVal = (k * double(m_NumberofADCPoints) / cnpts);
409  double yVal = FitFunctions[0]->Eval(xVal);
410  if (yVal > MaxVal) MaxVal = yVal;
411  }
412  B2INFO("MaxVal " << MaxVal);
413  tempPhotonPar11[0] /= MaxVal;
414  FitFunctions[0]->FixParameter(24, tempPhotonPar11[0]);
415 
417  PhotonParameters->setTemplateParameters(CellID_i, tempPhotonPar11, tempPhotonPar11, tempPhotonPar11);
418 
420  for (unsigned int k = 0; k < PhotonWaveformArray.size();
421  k++) PhotonWaveformArray[k] = FitFunctions[0]->Eval(((double)k) * (1. / 1000.)) ;
422  mtree->Fill();
423 
424  }
425  for (int w = 0; w < (int)FitFunctions.size(); w++) FitFunctions[w]->Delete();
426  TotalFitFunction->Delete() ;
427  gWaveformToFit->Delete();
428  }
429  }
430 
432  histfile->cd();
433  auto gmaxResidual = new TGraph(cellIDArray.size(), cellIDArray.data(), maxResidualArray.data());
434  gmaxResidual->SetName("gmaxResidual");
435  auto glimitResidualArray = new TGraph(cellIDArray.size(), cellIDArray.data(), limitResidualArray.data());
436  glimitResidualArray->SetName("glimitResidualArray");
437  auto gparLimitFactorArray = new TGraph(cellIDArray.size(), cellIDArray.data(), parLimitFactorArray.data());
438  gparLimitFactorArray->SetName("gparLimitFactorArray");
439 
440  gmaxResidual->Write();
441  glimitResidualArray->Write();
442  gparLimitFactorArray->Write();
443  histfile->Write();
444  histfile->Close();
445  delete histfile;
446 
447  f_PhotonTemplateOutput->cd();
448  mtree->Write();
449  f_PhotonTemplateOutput->Write();
450  f_PhotonTemplateOutput->Close();
451  delete f_PhotonTemplateOutput;
452 
454  saveCalibration(PhotonParameters, Form("PhotonParameters_CellID%d_CellID%d", m_firstCellID, m_lastCellID));
455  B2INFO("eclWaveformTemplateCalibrationC2Algorithm: successfully stored " << Form("PhotonParameters_CellID%d_CellID%d",
456  m_firstCellID, m_lastCellID) << " constants");
457 
458  return c_OK;
459 }
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.
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
DB object to store photon, hadron and diode shape parameters.
void setTemplateParameters(int cellID, const float photonInput[11], const float hadronInput[11], const float diodeInput[11])
Set photon, hadron and diode template parameters for crystal.
int m_AttemptLimit
Number of attempts before increasing parameter limits or resLimt.
double m_ParamLimitFactor
Factor to determine parameter limits in fit.
const int m_SimutaniousFitLimit
Min number waveforms required for simultaneous fit.
const int m_TotalCountsThreshold
Min number waveforms required per crystal.
Abstract base class for different kinds of events.
Struct containing exp number and run number.
Definition: Splitter.h:51