Belle II Software development
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 // cppcheck-suppress constParameterCallback ; fit callbacks must keep the signature required by ROOT
53 double fitf(double* x, double* par)
54 {
55
56 double xtoeval = std::fmod(x[0], numberofADCPoints);
57 int whichFitFunctions = x[0] / numberofADCPoints;
58
59 for (int i = 0; i < (int)FitFunctions.size(); i++) {
60 FitFunctions[i]->SetParameter(0, par[i]);
61 FitFunctions[i]->SetParameter(1, par[FitFunctions.size() + i]);
62 FitFunctions[i]->SetParameter(2, par[(2 * FitFunctions.size()) + i]);
63 FitFunctions[i]->FixParameter(3, 0);
64 for (int k = 0; k < 10; k++) {
65 FitFunctions[i]->SetParameter(4 + k, par[(3 * FitFunctions.size()) + k]);
66 }
67 }
68
69 return FitFunctions[whichFitFunctions]->Eval(xtoeval * 0.5);
70 }
71
72}
73
75{
76
77 B2INFO("Reading ECLCrystalCalib payload: eclWaveformTemplateCalibrationC1MaxResLimit");
78 DBObjPtr<ECLCrystalCalib> existingeclWaveformTemplateCalibrationC1MaxResLimit("eclWaveformTemplateCalibrationC1MaxResLimit");
79 auto runs = getRunList();
80 ExpRun chosenRun = runs.front();
81 // After here your DBObjPtrs are correct
82 updateDBObjPtrs(1, chosenRun.second, chosenRun.first);
83
85 gROOT->SetBatch();
86
87 std::vector<double> cellIDArray;
88 std::vector<double> maxResidualArray; // used to quantify fit result
89 std::vector<double> limitResidualArray; // what was final resLimit used
90 std::vector<double> parLimitFactorArray; // what was final parLimitFactorArray used
91
93 TFile* histfile = new TFile(m_outputName.c_str(), "recreate");
94
96 TFile* f_PhotonTemplateOutput = new TFile(Form("PhotonShapes_Low%d_High%d.root", m_firstCellID, m_lastCellID), "RECREATE");
97 TTree* mtree = new TTree("mtree", "");
98 std::vector<double> PhotonWaveformArray(100000);
99 mtree->Branch("PhotonArray", PhotonWaveformArray.data(), "PhotonWaveformArray[100000]/D");
100
102 auto tree = getObjectPtr<TTree>("tree");
103 int CellID;
104 tree->SetBranchAddress("CellID", &CellID);
105 std::vector<int> Waveform(m_NumberofADCPoints);
106 std::vector<int> XValues(m_NumberofADCPoints);
107 for (int i = 0; i < m_NumberofADCPoints; i++) {
108 tree->SetBranchAddress(Form("ADC%d", i), &Waveform[i]);
109 XValues[i] = i;
110 }
111
112 std::time_t t = std::time(0);
113
115 int AttemptCounter = 0;
116
119
122 double ParMin11t[11];
123
125 for (int CellID_i = m_firstCellID; CellID_i <= m_lastCellID; CellID_i++) {
126
128 if (CellID_i > 7776 || CellID_i < 1153) {
129 ParMin11t[0] = 20.3216;
130 ParMin11t[1] = -0.0206266;
131 ParMin11t[2] = 0.313928;
132 ParMin11t[3] = 0.589646;
133 ParMin11t[4] = 0.455526;
134 ParMin11t[5] = 1.03656;
135 ParMin11t[6] = 0.000822467;
136 ParMin11t[7] = 45.1574;
137 ParMin11t[8] = 0.716034;
138 ParMin11t[9] = 0.616753;
139 ParMin11t[10] = 0.0851222;
140 } else {
141 ParMin11t[0] = 24.6176;
142 ParMin11t[1] = 0.00725002;
143 ParMin11t[2] = 0.601578;
144 ParMin11t[3] = 0.491976;
145 ParMin11t[4] = 0.601034;
146 ParMin11t[5] = 0.601684;
147 ParMin11t[6] = -0.0103788;
148 ParMin11t[7] = 2.22615;
149 ParMin11t[8] = 0.671294;
150 ParMin11t[9] = 0.529878;
151 ParMin11t[10] = 0.0757927;
152 }
153
154 double resLimit = 2 * existingeclWaveformTemplateCalibrationC1MaxResLimit->getCalibVector()[CellID_i -
155 1];
156 double resLimitOriginal = resLimit;
157
159 std::vector<int> EntriesToSkip;
160
162 double maxResidual = 1000.0;
163
165 bool PASS = false;
166 while (PASS == false) {
167
169 std::vector<double> xValuesToFit;
170 std::vector<double> yValuesToFit;
171
173 std::vector<double> guessBaseline;
174 std::vector<double> guessAmp;
175 std::vector<double> guessTime;
176
178 std::vector<int> NtupleEntries;
179
180 int counter = 0; // counts entry number in xValuesToFit
181 int counterWaveforms = 0; // counts number of waveforms selected
182
183 for (int i = 0; i < tree->GetEntries(); i++) {
184
186 bool skipEvent = false;
187 for (int k = 0; k < (int)EntriesToSkip.size(); k++) {
188 if (EntriesToSkip[k] == i) skipEvent = true;
189 }
190 if (skipEvent) continue;
191
192 tree->GetEntry(i);
193
194 if (CellID != CellID_i) continue;
195
196 double maxval = 0;
197 double maxIndex = 0;
198 for (int j = 0; j < m_NumberofADCPoints; j++) {
199 xValuesToFit.push_back(counter);
200 yValuesToFit.push_back(Waveform[j]);
201 if (Waveform[j] > maxval) {
202 maxval = Waveform[j];
203 maxIndex = j;
204 }
205 counter++;
206 }
207
209 guessBaseline.push_back(Waveform[0]);
210 guessAmp.push_back(maxval);
211 guessTime.push_back((maxIndex - 4.5) * 0.5);
212
213 NtupleEntries.push_back(i);
214 B2INFO("Entry: " << i);
215
216 counterWaveforms++;
217
218 if (counterWaveforms == m_CollectorLimit) break;
219
220 }
221
223 B2INFO("CellID " << CellID_i << " counterWaveforms = " << counterWaveforms);
224
225 if (counterWaveforms < m_TotalCountsThreshold) {
227 B2INFO("eclWaveformTemplateCalibrationC2Algorithm: warning total entries for cell ID " << CellID_i << " is only: " <<
228 counterWaveforms << " Requirement is : " << m_TotalCountsThreshold);
229 EntriesToSkip.clear();
230 resLimit *= 2;
231 B2INFO("eclWaveformTemplateCalibrationC2Algorithm: warning " << CellID_i << " resLimit is doubled to" << resLimit << " start was "
232 << resLimitOriginal);
233 }
234
235
237 auto gWaveformToFit = new TGraph(xValuesToFit.size(), xValuesToFit.data(), yValuesToFit.data());
238 gWaveformToFit->SetName(Form("gWaveformToFit_%d", int(CellID_i)));
239
241
243 FitFunctions.clear();
244 for (int i = 0; i < counterWaveforms; i++) {
245 FitFunctions.push_back(new TF1(Form("Shp_%d", i), Belle2::ECL::WaveFuncTwoComponent, 0, 30.5, 26));
246 FitFunctions[i]->SetNpx(10000);
247 FitFunctions[i]->FixParameter(3, 0);
248 for (int k = 0; k < 10; k++) {
249 FitFunctions[i]->SetParameter(4 + k, ParMin11t[k + 1]);
250 FitFunctions[i]->FixParameter(10 + 4 + k, ParMin11t[k + 1]);
251 }
252 FitFunctions[i]->FixParameter(24, ParMin11t[0]);
253 FitFunctions[i]->FixParameter(25, 1);
254 }
255
257 TF1* TotalFitFunction = new TF1("TotalFitFunction", fitf, 0, counterWaveforms * m_NumberofADCPoints,
258 (3 * FitFunctions.size()) + 10);
259
261 int FFsize = FitFunctions.size();
262 for (int i = 0; i < FFsize; i++) {
263 TotalFitFunction->SetParameter(i, guessTime[i]);
264 TotalFitFunction->SetParameter(FFsize + i, guessBaseline[i]);
265 TotalFitFunction->SetParameter((2 * FFsize) + i, guessAmp[i]);
266 for (int k = 0; k < 10; k++) {
267 TotalFitFunction->SetParameter((3 * FFsize) + k, ParMin11t[k + 1]);
268 if (m_ParamLimitFactor < 2) {
269 TotalFitFunction->SetParLimits((3 * FFsize) + k, ParMin11t[k + 1] - m_ParamLimitFactor * fabs(ParMin11t[k + 1]),
270 ParMin11t[k + 1] + m_ParamLimitFactor * fabs(ParMin11t[k + 1]));
271 } else {
272 TotalFitFunction->ReleaseParameter((3 * FFsize) + k);
273 }
274 }
275 }
276
278 gWaveformToFit->Fit("TotalFitFunction", "Q M W N 0 R", "", 0, counterWaveforms * m_NumberofADCPoints);
279
281 std::vector<int> FitResultY;
282 std::vector<int> FitResultX;
283 int maxResidualWaveformID = 0; // Used to remove waveforms with potential pile-up outside baseline
284
286 maxResidual = 0.0;
287 double npts = xValuesToFit.size();
288 double maxResidualOld = 0.0;
289 for (int k = 0; k < npts; k++) {
290 double xVal = xValuesToFit[k];
291 double yVal = TotalFitFunction->Eval(xVal);
292 FitResultX.push_back(xVal);
293 FitResultY.push_back(yVal);
294 double diff = fabs(yValuesToFit[k] - yVal);
295 if (diff > maxResidual) {
296 maxResidual = diff;
297 maxResidualWaveformID = (k / m_NumberofADCPoints);
298 maxResidualOld = fabs(yValuesToFit[k] / yVal);
299 }
300 }
301
302 // Checking if fit matches the data.
303 if (maxResidual > resLimit) {
304
305 B2INFO("FAIL: CellID_i " << CellID_i << " maxResidual " << maxResidual << " removing entry: " <<
306 NtupleEntries[maxResidualWaveformID] <<
307 " which was waveform number " << maxResidualWaveformID << " resLimit was " << resLimit << " , resLimit started at " <<
308 resLimitOriginal);
309 B2INFO("Old maxResidual of Data/Fit was " << maxResidualOld);
310
311 B2INFO("Iter Time = " << std::time(0) - t << std::endl);
312 t = std::time(0);
313
314 std::cout << "FAIL: CellID_i " << CellID_i << " maxResidual " << maxResidual << " removing entry: " <<
315 NtupleEntries[maxResidualWaveformID] <<
316 " which was waveform number " << maxResidualWaveformID << " resLimit was " << resLimit << " , resLimit started at " <<
317 resLimitOriginal << std::endl;
318 std::cout << "wave = [";
319 for (int k = 0; k < npts; k++) {
320 std::cout << yValuesToFit[k];
321 if (k < (npts - 1)) {
322 std::cout << ",";
323 } else {
324 std::cout << "]" << std::endl;
325 }
326 }
327 std::cout << "fitRes = [";
328 for (int k = 0; k < npts; k++) {
329 std::cout << TotalFitFunction->Eval(xValuesToFit[k]);
330 if (k < (npts - 1)) {
331 std::cout << ",";
332 } else {
333 std::cout << "]" << std::endl;
334 }
335 }
336
338 EntriesToSkip.push_back(NtupleEntries[maxResidualWaveformID]);
339
340 AttemptCounter++;
341
343 if (counterWaveforms < m_SimutaniousFitLimit) AttemptCounter = m_AttemptLimit;
344
346 if (AttemptCounter == m_AttemptLimit) {
347
349
350 B2INFO("AttemptCounter reach limit: " << AttemptCounter << " counterWaveforms: " << counterWaveforms);
351 B2INFO("Increasing m_ParamLimitFactor to " << m_ParamLimitFactor);
352
354 EntriesToSkip.clear();
355 AttemptCounter = 0;
356
359 resLimit *= m_ResLimitIterator;
360 B2INFO("Increasing resLimit to " << resLimit);
362 }
363 }
364
365 } else {
366
367 B2INFO("PASS: CellID_i " << CellID_i << " maxResidual " << maxResidual << " number of waveforms used was " << counterWaveforms <<
368 " resLimit was " << resLimit);
369
370 PASS = true;
371
372 limitResidualArray.push_back(resLimit);
373 parLimitFactorArray.push_back(m_ParamLimitFactor);
374
376 AttemptCounter = 0;
378
379 auto gFitResult = new TGraph(FitResultX.size(), FitResultX.data(), FitResultY.data());
380 gFitResult->SetName(Form("gFitResult_%d", int(CellID_i)));
381
383 cellIDArray.push_back(CellID_i);
384 maxResidualArray.push_back(maxResidual);
385
387 histfile->cd();
388 gWaveformToFit->Write();
389 gFitResult->Write();
390
392 float tempPhotonPar11[11];
393 tempPhotonPar11[0] = ParMin11t[0];
394 for (unsigned int k = 0; k < 10; k++) tempPhotonPar11[k + 1] = TotalFitFunction->GetParameter((3 * FFsize) + k);
395
397 FitFunctions[0]->SetParameter(0, 0);
398 FitFunctions[0]->SetParameter(1, 0);
399 FitFunctions[0]->SetParameter(2, 1);
400 for (int k = 0; k < 10; k++) {
401 FitFunctions[0]->SetParameter(4 + k, tempPhotonPar11[k + 1]);
402 FitFunctions[0]->SetParameter(10 + 4 + k, tempPhotonPar11[k + 1]);
403 }
404 FitFunctions[0]->FixParameter(24, ParMin11t[0]);
405 FitFunctions[0]->FixParameter(25, 1);
406
408 double MaxVal = -1.0;
409 const double cnpts = 2000;
410 for (int k = 0; k < cnpts; k++) {
411 double xVal = (k * double(m_NumberofADCPoints) / cnpts);
412 double yVal = FitFunctions[0]->Eval(xVal);
413 if (yVal > MaxVal) MaxVal = yVal;
414 }
415 B2INFO("MaxVal " << MaxVal);
416 tempPhotonPar11[0] /= MaxVal;
417 FitFunctions[0]->FixParameter(24, tempPhotonPar11[0]);
418
420 PhotonParameters->setTemplateParameters(CellID_i, tempPhotonPar11, tempPhotonPar11, tempPhotonPar11);
421
423 for (unsigned int k = 0; k < PhotonWaveformArray.size();
424 k++) PhotonWaveformArray[k] = FitFunctions[0]->Eval(((double)k) * (1. / 1000.)) ;
425 mtree->Fill();
426
427 }
428 for (int w = 0; w < (int)FitFunctions.size(); w++) FitFunctions[w]->Delete();
429 TotalFitFunction->Delete() ;
430 gWaveformToFit->Delete();
431 }
432 }
433
435 histfile->cd();
436 auto gmaxResidual = new TGraph(cellIDArray.size(), cellIDArray.data(), maxResidualArray.data());
437 gmaxResidual->SetName("gmaxResidual");
438 auto glimitResidualArray = new TGraph(cellIDArray.size(), cellIDArray.data(), limitResidualArray.data());
439 glimitResidualArray->SetName("glimitResidualArray");
440 auto gparLimitFactorArray = new TGraph(cellIDArray.size(), cellIDArray.data(), parLimitFactorArray.data());
441 gparLimitFactorArray->SetName("gparLimitFactorArray");
442
443 gmaxResidual->Write();
444 glimitResidualArray->Write();
445 gparLimitFactorArray->Write();
446 histfile->Write();
447 histfile->Close();
448 delete histfile;
449
450 f_PhotonTemplateOutput->cd();
451 mtree->Write();
452 f_PhotonTemplateOutput->Write();
453 f_PhotonTemplateOutput->Close();
454 delete f_PhotonTemplateOutput;
455
457 saveCalibration(PhotonParameters, Form("PhotonParameters_CellID%d_CellID%d", m_firstCellID, m_lastCellID));
458 B2INFO("eclWaveformTemplateCalibrationC2Algorithm: successfully stored " << Form("PhotonParameters_CellID%d_CellID%d",
459 m_firstCellID, m_lastCellID) << " constants");
460
461 return c_OK;
462}
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
static 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.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
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.
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.
Struct containing exp number and run number.
Definition Splitter.h:51