Belle II Software release-09-00-00
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
30using namespace std;
31using namespace Belle2;
32using namespace ECL;
33using namespace Calibration;
34
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
46namespace {
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
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)
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 successfuly =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
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.
STL namespace.
Struct containing exp number and run number.
Definition: Splitter.h:51