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