Belle II Software development
eclLeakageAlgorithm.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/eclLeakageAlgorithm.h>
11
12/* ECL headers. */
13#include <ecl/calibration/tools.h>
14#include <ecl/dbobjects/ECLLeakageCorrections.h>
15
16/* Basf2 headers. */
17#include <framework/database/DBObjPtr.h>
18#include <framework/dataobjects/EventMetaData.h>
19#include <framework/datastore/DataStore.h>
20#include <framework/datastore/StoreObjPtr.h>
21
22/* ROOT headers. */
23#include <TF1.h>
24#include <TFile.h>
25#include <TH1D.h>
26#include <TTree.h>
27
28/* C++ headers. */
29#include <iostream>
30
31using namespace std;
32using namespace Belle2;
33using namespace ECL;
34using namespace Calibration;
35
36/**************************************************************************
37 * eclLeakageAlgorithm analyzes single photon MC to find the eclLeakage payload
38 * After initial setup, the position dependent corrections are found using
39 * photons with good reconstruction.
40 * The correction that depends on the number of crystals has been replaced
41 * by the ECLnOptimal payload.
42 *
43 * Major steps in the process:
44 * 1. Set up (read in parameters and tree, define histogram binning)
45 * 2. Fill and fit histograms of normalized reconstructed energy, one per
46 * thetaID/energy. Novosibirsk fit parameter eta is floated in this fit, then
47 * fixed for fits of data with finer location binning. Peak (i.e. overall correction
48 * for this thetaID/energy) is used to normalize position-dependent correction.
49 * 3. Fill and fit histograms of normalized energy for each location (nominally 29
50 * locations in theta and phi per thetaID) to get the position-dependent correction.
51 * Nominally 69 x 8 x 29 x 3 = 48,024 histograms. 3 = theta, phi next to mech, phi not
52 * next to mech.
53 * 4. Pack payload quantities into vectors and histograms
54 * 5. Fill and fit summary and resolution histograms
55 * 6. Finish; close histogram file and and write payload
56
57 **************************************************************************/
58
59
61//..Function to get starting parameters for the Novo fit
62std::vector<double> eclLeakageFitParameters(TH1F* h, const double& target)
63{
64
65 //..Find the smallest range of bins that contain at least "target" entries
66 double maxIntegral = h->Integral();
67 const int nBins = h->GetNbinsX();
68 int minLo = 1;
69 int minHi = nBins;
70
71 //..Store a vector of integrals over histogram ranges so that I only need to
72 // call h->Integral nBins times, instead of nBins^2.
73 std::vector<double> intVector; // intVector[n] = sum of histogram bins [1,n+1] inclusive
74 intVector.push_back(h->GetBinContent(1));
75 for (int iLo = 2; iLo <= nBins; iLo++) {
76 double nextIntegral = intVector[iLo - 2] + h->GetBinContent(iLo);
77 intVector.push_back(nextIntegral);
78 }
79
80 //..Now just look through all possible bin ranges to find the best one
81 for (int iLo = 2; iLo <= nBins; iLo++) {
82 for (int iHi = iLo; iHi <= nBins; iHi++) {
83
84 //..sum[iLo, iHi] = sum[1, iHi] - sum[1,iLo-1] = intVector[iHi-1] - intVector[iLo-2]
85 double integral = intVector[iHi - 1] - intVector[iLo - 2];
86
87 //..same number of bins, pick the pair with more entries
88 if ((integral > target and (iHi - iLo) < (minHi - minLo)) or
89 (integral > target and (iHi - iLo) == (minHi - minLo) and integral > maxIntegral)
90 ) {
91 minLo = iLo;
92 minHi = iHi;
93 maxIntegral = integral;
94 }
95 }
96 }
97
98 //..Fit parameters are derived (in part) from this range of bins
99 const double lowE = h->GetBinLowEdge(minLo);
100 const double highE = h->GetBinLowEdge(minHi + 1);
101 const double peak = 0.5 * (lowE + highE);
102 const double sigma = 0.4 * (highE - lowE);
103 const double eta = 0.4; // typical value
104 const int nfitBins = (1 + minHi - minLo);
105
106 std::vector<double> parameters;
107 parameters.push_back(peak);
108 parameters.push_back(sigma);
109 parameters.push_back(eta);
110 parameters.push_back(lowE);
111 parameters.push_back(highE);
112 parameters.push_back(nfitBins);
113
114 return parameters;
115}
116
118//..Novosibirsk; H. Ikeda et al. / NIM A 441 (2000) 401-426
119// cppcheck-suppress constParameter ; TF1 fit functions cannot have const parameters
120double eclLeakageNovo(Double_t* x, Double_t* par)
121{
122
123 Double_t peak = par[1];
124 Double_t width = par[2];
125 Double_t sln4 = sqrt(log(4));
126 Double_t y = par[3] * sln4;
127 Double_t tail = -log(y + sqrt(1 + y * y)) / sln4;
128 Double_t qc = 0.;
129
130 if (TMath::Abs(tail) < 1.e-7)
131 qc = 0.5 * TMath::Power(((x[0] - peak) / width), 2);
132 else {
133 double qa = tail * sqrt(log(4.));
134 double qb = sinh(qa) / qa;
135 double qx = (x[0] - peak) / width * qb;
136 double qy = 1. + tail * qx;
137
138 if (qy > 1.E-7)
139 qc = 0.5 * (TMath::Power((log(qy) / tail), 2) + tail * tail);
140 else
141 qc = 15.0;
142 }
143
144 return par[0] * exp(-qc);
145}
146
147
149//..Function to check for bad fits
150// 0 = good, 1 = redo fit, 2 = lowStat, 3 = lowProb, 4 = peakAtLimit, 5 = sigmaAtLimit, 6 = etaAtLimit
151int eclLeakageFitQuality(const double& fitLo, const double& fitHi, const double& fitPeak, const double& fitSigma,
152 const double& fitdEta, const double& fitProb)
153{
154 const double tolerance = 0.02;
155 const double redoFitProb = 1e-5;
156 const double minFitProb = 1e-9;
158 int fitStatus = 0;
159 if (fitProb < redoFitProb) {fitStatus = 1;}
160 if (fitProb < minFitProb) {fitStatus = 3;}
161 double tol = tolerance * (fitHi - fitLo);
162 if (fitPeak < (fitLo + tol) or fitPeak > (fitHi - tol)) {fitStatus = 4;}
163 if (fitSigma<tol or fitSigma>(fitHi - fitLo - tol)) {fitStatus = 5;}
164 double tolEta = tolerance;
165 if (fitdEta < tolEta) {fitStatus = 6;} // just use the tolerance for eta (note that it is eta - limit that is passed)
166 return fitStatus;
167}
168
171{
173 "Generate payload ECLLeakageCorrection from single photon MC recorded by eclLeakageCollectorModule"
174 );
175}
176
177
178
181{
182
183 //====================================================================================
184 //====================================================================================
185 //..Step 1. Set up prior to first loop through data
186 B2INFO("starting eclLeakageAlgorithm");
187
188 //-----------------------------------------------------------------------------------
189 //..Read in histograms created by the collector and fix normalization
190 auto inputParameters = getObjectPtr<TH1F>("inputParameters");
191 int lastBin = inputParameters->GetNbinsX();
192 double scale = inputParameters->GetBinContent(lastBin); // number of times inputParameters was filled
193 for (int ib = 1; ib < lastBin; ib++) {
194 double param = inputParameters->GetBinContent(ib);
195 inputParameters->SetBinContent(ib, param / scale);
196 inputParameters->SetBinError(ib, 0.);
197 }
198
199 //..And write to disk.
200 TFile* histfile = new TFile("eclLeakageAlgorithm.root", "recreate");
201 inputParameters->Write();
202
203 //..Parameters
204 const int nThetaID = 69;
205 const int nLeakReg = 3;
206 const int firstBarrelID = 13;
207 const int lastBarrelID = 58;
208 const int firstUsefulThID = 3;
209 const int lastUsefulThID = 66;
211 const int nPositions = (int)(inputParameters->GetBinContent(1) + 0.001);
212 const int nEnergies = (int)(inputParameters->GetBinContent(2) + 0.001);
213 const int nbinX = nEnergies * nThetaID;
215 const double etaMin = -5.;
216 const double etaMax = 5.;
219 //..Energies
220 auto generatedE = create2Dvector<float>(nLeakReg, nEnergies); // 3 regions forward barrel backward
221
222 int bin = 2; // bin 1 = nPositions, bin 2 = nEnergies, bin 3 = first energy
223 for (int ireg = 0; ireg < nLeakReg; ireg++) {
224 B2INFO("Generated energies for ireg = " << ireg);
225 for (int ie = 0; ie < nEnergies; ie++) {
226 bin++;
227 generatedE[ireg][ie] = inputParameters->GetBinContent(bin);
228 B2INFO(" " << ie << " " << generatedE[ireg][ie] << " GeV");
229 }
230 }
231 B2INFO("Low energy threshold = " << m_lowEnergyThreshold);
232
233 //..Energy per thetaID (in MeV, for use in titles etc)
234 auto iEnergiesMeV = create2Dvector<int>(nEnergies, nThetaID);
235 for (int thID = 0; thID < nThetaID; thID++) {
236 int ireg = 0;
237 if (thID >= firstBarrelID and thID <= lastBarrelID) {
238 ireg = 1;
239 } else if (thID > lastBarrelID) {
240 ireg = 2;
241 }
242 for (int ie = 0; ie < nEnergies; ie++) {
243 iEnergiesMeV[ie][thID] = (int)(1000.*generatedE[ireg][ie] + 0.5);
244 }
245 }
246
247 //-----------------------------------------------------------------------------------
248 //..Bins for eFrac histograms (eFrac = uncorrected reconstructed E / E true)
249 const double eFracLo = 0.4; // low edge of eFrac histograms
250 const double eFracHi = 1.5; // high edge of eFrac histograms
251 auto nEfracBins = create2Dvector<int>(nEnergies, nThetaID);
252 for (int thID = 0; thID < nThetaID; thID++) {
253 B2DEBUG(25, "eFrac nBins for thetaID " << thID);
254 for (int ie = 0; ie < nEnergies; ie++) {
255
256 //..ballpark resolution
257 double res_squared = 0.0001 + 0.064 / iEnergiesMeV[ie][thID];
258
259 //..Convert this to an even integer to get number of bins
260 double binNumOver2 = 3. / sqrt(res_squared);
261 int tempNBin = (int)(binNumOver2 + 0.5);
262 nEfracBins[ie][thID] = 2 * tempNBin;
263 B2DEBUG(25, " ie = " << ie << " E = " << iEnergiesMeV[ie][thID] << " nBins = " << nEfracBins[ie][thID]);
264 }
265 }
266
267 //-----------------------------------------------------------------------------------
268 //..Set up Novosibirsk fit function
269 TString statusString[7] = {"good", "refit", "lowStat", "lowProb", "peakAtLimit", "sigmaAtLimit", "etaAtLimit"};
270 const double fracEnt[2] = {0.683, 0.5}; // fit range includes 68% or 50% of entries
271 const double minEntries = 100.; // don't use fits with fewer entries
272 const double minMaxBin = 50.; // rebin if max bin is below this value
273 const double highMaxBin = 300.; // can float eta if max bin is above this value
274
275 TF1* func = new TF1("eclLeakageNovo", eclLeakageNovo, eFracLo, eFracHi, 4);
276 func->SetParNames("normalization", "peak", "effSigma", "eta");
277 func->SetLineColor(kRed);
278
279 //-----------------------------------------------------------------------------------
280 //..Specify the TTree
281 auto tree = getObjectPtr<TTree>("tree");
282 tree->SetBranchAddress("cellID", &t_cellID);
283 tree->SetBranchAddress("thetaID", &t_thetaID);
284 tree->SetBranchAddress("region", &t_region);
285 tree->SetBranchAddress("thetaBin", &t_thetaBin);
286 tree->SetBranchAddress("phiBin", &t_phiBin);
287 tree->SetBranchAddress("phiMech", &t_phiMech);
288 tree->SetBranchAddress("energyBin", &t_energyBin);
289 tree->SetBranchAddress("nCrys", &t_nCrys);
290 tree->SetBranchAddress("energyFrac", &t_energyFrac);
291 tree->SetBranchAddress("origEnergyFrac", &t_origEnergyFrac);
292 tree->SetBranchAddress("locationError", &t_locationError);
293
294 const int treeEntries = tree->GetEntries();
295 B2INFO("eclLeakageAlgorithm entries = " << treeEntries);
296
297 //-----------------------------------------------------------------------------------
298 //..Get current payload to help validate the new payload
299
300 //..Set event, run, exp number
301 const auto exprun = getRunList();
302 const int iEvt = 1;
303 const int iRun = exprun[0].second;
304 const int iExp = exprun[0].first;
307 evtPtr.registerInDataStore();
309 evtPtr.construct(iEvt, iRun, iExp);
310 DBStore& dbstore = DBStore::Instance();
311 dbstore.update();
312
313 //..Existing payload
314 DBObjPtr<ECLLeakageCorrections> existingCorrections("ECLLeakageCorrections");
315 TH2F existingThetaCorrection = existingCorrections->getThetaCorrections();
316 existingThetaCorrection.SetName("existingThetaCorrection");
317 TH2F existingPhiCorrection = existingCorrections->getPhiCorrections();
318 existingPhiCorrection.SetName("existingPhiCorrection");
319
320 //..Write out the correction histograms
321 histfile->cd();
322 existingThetaCorrection.Write();
323 existingPhiCorrection.Write();
324
325
326 //====================================================================================
327 //====================================================================================
328 //..Step 2. First loop, fill histograms of e/eTrue for each energy and thetaID
329
330 //-----------------------------------------------------------------------------------
331 //..One histogram of e/eTrue per energy per thetaID.
332 // Used to fix eta in subsequent fits, and to get overall correction for that thetaID
333 // (which should be very close to 1).
334 TString name;
335 TString title;
336 auto hELabUncorr = create2Dvector<TH1F*>(nEnergies, nThetaID);
337 for (int thID = firstUsefulThID; thID <= lastUsefulThID; thID++) {
338 TString sthID = std::to_string(thID);
339 for (int ie = 0; ie < nEnergies; ie++) {
340 name = "hELabUncorr_" + std::to_string(ie) + "_" + sthID;
341 title = "eFrac " + to_string(iEnergiesMeV[ie][thID]) + " MeV thetaID " + sthID + ";E/Etrue";
342
343 //..High statistics for these plots; use more bins
344 hELabUncorr[ie][thID] = new TH1F(name, title, 2 * nEfracBins[ie][thID], eFracLo, eFracHi);
345 }
346 }
347
348 //-----------------------------------------------------------------------------------
349 //..Loop over events and store eFrac
350 for (int i = 0; i < treeEntries; i++) {
351 tree->GetEntry(i);
352
353 //..Only events with good reconstruction
354 bool goodReco = t_thetaID >= firstUsefulThID and t_thetaID <= lastUsefulThID and t_energyBin >= 0;
355 if (not goodReco) {continue;}
356
357 //..Fill histogram for full thetaID
358 hELabUncorr[t_energyBin][t_thetaID]->Fill(t_energyFrac);
359 }
360
361 //-----------------------------------------------------------------------------------
362 //..Fit each thetaID/energy histogram to get peak (overall correction) and eta (fixed
363 // in subsequent fits to individual locations).
364 auto peakUncorr = create2Dvector<float>(nEnergies, nThetaID); // store peak from each fit
365 auto etaUncorr = create2Dvector<float>(nEnergies, nThetaID); // store eta from each fit
366
367 std::vector<TString> failedELabUncorr; // names of hists with failed fits
368 std::vector<int> statusELabUncorr; // status of failed fits
369 int payloadStatus = 0; // Overall status of payload determination
370
371 //..Record fit status
372 TH1F* statusOfhELabUncorr = new TH1F("statusOfhELabUncorr",
373 "status of hELabUncorr fits for each thetaID/energy. 0 = good, 1 = redo fit, 2 = lowStat, 3 = lowProb, 4 = peakAtLimit, 5 = sigmaAtLimit",
374 6, 0,
375 6);
376
377
378 //..Fit each histogram
379 for (int thID = firstUsefulThID; thID <= lastUsefulThID; thID++) {
380 TString sthID = std::to_string(thID);
381 for (int ie = 0; ie < nEnergies; ie++) {
382 TH1F* hEnergy = (TH1F*)hELabUncorr[ie][thID];
383 double peak = -1.;
384 double eta = 0.;
385 int fitStatus = 2;
386 double entries = hEnergy->Integral();
387 int nIter = 0; // keep track of attempts to fit this histogram
388 double genE = iEnergiesMeV[ie][thID] / 1000.;
389 bool fitHist = entries > minEntries;
390
391 //..Possibly iterate fit starting from this point
392 while (fitHist) {
393
394 //..Fit parameters
395 double norm = hEnergy->GetMaximum();
396 double target = fracEnt[nIter] * entries; // fit range contains 68% or 50%
397 std::vector<double> startingParameters;// peak, sigma, eta, fitLow, fitHigh, nbins
398 startingParameters = eclLeakageFitParameters(hEnergy, target);
399 func->SetParameters(norm, startingParameters[0], startingParameters[1], startingParameters[2]);
400 func->SetParLimits(1, startingParameters[3], startingParameters[4]);
401 func->SetParLimits(2, 0., startingParameters[4] - startingParameters[3]);
402 func->SetParLimits(3, etaMin, etaMax);
403
404 //..Fit
405 name = hEnergy->GetName();
406 B2DEBUG(40, "Fitting " << name.Data());
407 hEnergy->Fit(func, "LIEQ", "", startingParameters[3], startingParameters[4]);
408 peak = func->GetParameter(1);
409 double effSigma = func->GetParameter(2);
410 eta = func->GetParameter(3);
411 double prob = func->GetProb();
412
413 //..Check fit quality 0 = good, 1 = redo fit, 2 = lowStat, 3 = lowProb,
414 // 4 = peakAtLimit, 5 = sigmaAtLimit, 6 = etaAtLimit
415 double dEta = min((etaMax - eta), (eta - etaMin));
416 fitStatus = eclLeakageFitQuality(startingParameters[3], startingParameters[4], peak, effSigma, dEta, prob);
417
418 //..If the fit probability is low, refit using a smaller range (fracEnt)
419 if ((fitStatus == 1 or fitStatus == 3) and nIter == 0) {
420 nIter++;
421 } else {
422 fitHist = false;
423 }
424 }
425
426 //-----------------------------------------------------------------------------------
427 //..Record failures and fit results.
428 // Mark payload as failed if energy is above low-energy threshold.
429 statusOfhELabUncorr->Fill(fitStatus + 0.000001);
430 if (fitStatus == 2 or fitStatus >= 4) {
431 statusELabUncorr.push_back(fitStatus);
432 failedELabUncorr.push_back(hEnergy->GetName());
433 if (genE > m_lowEnergyThreshold) {
434 payloadStatus = 1; // algorithm failed
435 } else {
436 peak = -1.; // fix up later
437 }
438 }
439 peakUncorr[ie][thID] = peak;
440 etaUncorr[ie][thID] = eta;
441
442 //..Write to disk
443 if (entries > minEntries) {
444 histfile->cd();
445 hELabUncorr[ie][thID]->Write();
446 }
447 }
448 }
449
450 //..Write out summary of fit status
451 histfile->cd();
452 statusOfhELabUncorr->Write();
453
454 //-----------------------------------------------------------------------------------
455 //..Quit now if one of the high-energy fits failed, since we will not get a payload.
456 int nbadFit = statusELabUncorr.size();
457 if (nbadFit > 0) {B2ERROR("hELabUncorr fit failures (one histogram per energy/thetaID):");}
458 for (int ibad = 0; ibad < nbadFit; ibad++) {
459 int badStat = statusELabUncorr[ibad];
460 B2ERROR(" histogram " << failedELabUncorr[ibad].Data() << " status " << badStat << " " << statusString[badStat].Data());
461 }
462 if (payloadStatus != 0) {
463 B2ERROR("ecLeakageAlgorithm: fit to hELabUncorr failed. ");
464 histfile->Close();
465 return c_Failure;
466 }
467
468 //-----------------------------------------------------------------------------------
469 //..Fix up any failed (low-energy) fits by using a neighbouring thetaID
470 for (int thID = firstUsefulThID; thID <= lastUsefulThID; thID++) {
471 for (int ie = 0; ie < nEnergies; ie++) {
472 if (peakUncorr[ie][thID] < 0.) {
473 if (thID > 40) {
474 for (int nextID = thID - 1; thID >= firstUsefulThID; thID--) {
475 if (peakUncorr[ie][nextID] > 0.) {
476 peakUncorr[ie][thID] = peakUncorr[ie][nextID];
477 break;
478 }
479 }
480 } else {
481 for (int nextID = thID + 1; thID <= lastUsefulThID; thID++) {
482 if (peakUncorr[ie][nextID] > 0.) {
483 peakUncorr[ie][thID] = peakUncorr[ie][nextID];
484 break;
485 }
486 }
487 }
488 }
489
490 //..If we were unable to get a successful fit from a neighbour, give up
491 if (peakUncorr[ie][thID] < 0.) {
492 B2ERROR("ecLeakageAlgorithm: unable to correct hELabUncorr for thetaID " << thID << " ie " << ie);
493 histfile->Close();
494 return c_Failure;
495 }
496 }
497 }
498
499 //====================================================================================
500 //====================================================================================
501 //..Step 3. Second loop, fill histograms of e/eTrue as a function of position.
502 // 29 locations in theta, 29 in phi.
503 // Crystals next to mechanical structure in phi are treated separately from
504 // crystals without mechanical structure.
505
506 //-----------------------------------------------------------------------------------
507 //..Histograms to store the energy
508 const int nDir = 3;
509 const TString dirName[nDir] = {"theta", "phiMech", "phiNoMech"};
510
511 auto eFracPosition = create4Dvector<TH1F*>(nEnergies, nThetaID, nDir, nPositions); // the histograms
512
513
514 std::vector<TString> failedeFracPosition; // names of hists with failed fits
515 std::vector<int> statuseFracPosition; // status of failed fits
516
517 for (int thID = firstUsefulThID; thID <= lastUsefulThID; thID++) {
518 TString sthID = std::to_string(thID);
519 for (int ie = 0; ie < nEnergies; ie++) {
520 TString sie = std::to_string(ie);
521 for (int idir = 0; idir < nDir; idir++) {
522 TString sidir = std::to_string(idir);
523 for (int ipos = 0; ipos < nPositions; ipos++) {
524 TString sipos = std::to_string(ipos);
525 name = "eFracPosition_" + sie + "_" + sthID + "_" + sidir + "_" + sipos;
526 title = "eFrac " + to_string(iEnergiesMeV[ie][thID]) + " MeV thetaID " + sthID + " " + dirName[idir] + " pos " + sipos +
527 "; E/Etrue";
528 eFracPosition[ie][thID][idir][ipos] = new TH1F(name, title, nEfracBins[ie][thID], eFracLo, eFracHi);
529 }
530 }
531 }
532 }
533
534 //..And some summary histograms
535 TH1F* statusOfeFracPosition = new TH1F("statusOfeFracPosition",
536 "eFrac fit status: -2 noData, -1 lowE, 0 good, 1 redo fit, 2 lowStat, 3 lowProb, 4 peakAtLimit, 5 sigmaAtLimit", 8, -2,
537 6);
538 TH1F* probOfeFracPosition = new TH1F("probOfeFracPosition", "fit probability of eFrac fits for each position;probability", 100, 0,
539 1);
540 TH1F* maxOfeFracPosition = new TH1F("maxOfeFracPosition", "max entries of eFrac histograms;maximum bin content", 100, 0, 1000);
541
542 //-----------------------------------------------------------------------------------
543 //..Loop over events and store eFrac
544 for (int i = 0; i < treeEntries; i++) {
545 tree->GetEntry(i);
546
547 //..Only events with good reconstruction
548 bool goodReco = t_thetaID >= firstUsefulThID and t_thetaID <= lastUsefulThID and t_energyBin >= 0;
549 if (not goodReco) {continue;}
550
551 //..Theta location (idir = 0)
552 int idir = 0;
553 eFracPosition[t_energyBin][t_thetaID][idir][t_thetaBin]->Fill(t_energyFrac);
554
555 //..phi location. Note that t_phiBin starts at mechanical edge, if there is one.
556 idir = t_phiMech + 1;
557 eFracPosition[t_energyBin][t_thetaID][idir][t_phiBin]->Fill(t_energyFrac);
558 }
559
560 //-----------------------------------------------------------------------------------
561 //..Now fit many many histograms to get the position-dependent corrections
562 auto positionCorrection = create4Dvector<float>(nEnergies, nThetaID, nDir, nPositions);
563 auto positionCorrectionUnc = create4Dvector<float>(nEnergies, nThetaID, nDir, nPositions);
564 int nHistToFit = 0;
565
566
567 //..Temp histogram of position corrections
568 TH1F* thetaCorSummary = new TH1F("thetaCorSummary", "Theta dependent corrections;theta dependent correction", 100, 0.4, 1.4);
569 TH1F* phiCorSummary = new TH1F("phiCorSummary", "Phi dependent corrections;phi dependent correction", 100, 0.4, 1.4);
570
571 for (int thID = firstUsefulThID; thID <= lastUsefulThID; thID++) {
572 for (int ie = 0; ie < nEnergies; ie++) {
573 double genE = iEnergiesMeV[ie][thID] / 1000.;
574 for (int idir = 0; idir < nDir; idir++) {
575 for (int ipos = 0; ipos < nPositions; ipos++) {
576 TH1F* hEnergy = (TH1F*)eFracPosition[ie][thID][idir][ipos];
577 if (hEnergy->Integral() > minEntries) {nHistToFit++;}
578
579 //..Default peak from fit to full thetaID/energy = peakUncorr;
580 // correction = peak / sqrt(peakUncorr) = sqrt(peakUncorr)
581 double correction = sqrt(peakUncorr[ie][thID]);
582 double corrUnc = 0.05; // arbitrary uncertainty
583 double prob = -1.;
584 int fitStatus = 2; // low stats
585 if (genE < m_lowEnergyThreshold) {fitStatus = -1;} // low energy, don't fit, use default peak value
586 if (hEnergy->GetEntries() < 0.5) {fitStatus = -2;} // unused, eg barrel pos=2
587 int nIter = 0; // keep track of attempts to fit this histogram
588 double entries = hEnergy->Integral();
589 bool fitHist = entries > minEntries and genE >= m_lowEnergyThreshold;
590
591 //..Possibly iterate fit starting from this point
592 while (fitHist) {
593 fitHist = false;
594
595 //..Fit parameters
596 double target = fracEnt[nIter] * entries; // fit range contains 68%
597 std::vector<double> startingParameters;// peak, sigma, eta, fitLow, fitHigh, nbins
598 bool findParm = true;
599 while (findParm) {
600 startingParameters = eclLeakageFitParameters(hEnergy, target);
601
602 //..Rebin if stats are low and we have enough DOF
603 if (hEnergy->GetMaximum()<minMaxBin and startingParameters[5]>11.9) {
604 hEnergy->Rebin(2);
605 } else {
606 findParm = false;
607 }
608 }
609 double norm = hEnergy->GetMaximum(); // max bin after rebinning
610 double fitLow = startingParameters[3];
611 double fitHigh = startingParameters[4];
612
613 //..Eta from the fit to the full crystal
614 double etaFix = etaUncorr[ie][thID];
615 func->SetParameters(norm, startingParameters[0], startingParameters[1], etaFix);
616 func->SetParLimits(1, fitLow, fitHigh);
617 func->SetParLimits(2, 0., fitHigh - fitLow);
618
619 //..Fix eta, unless really good statistics
620 if (hEnergy->GetMaximum() < highMaxBin) {
621 func->SetParLimits(3, etaFix, etaFix);
622 } else {
623 func->SetParLimits(3, etaMin, etaMax);
624 }
625
626 //..Fit
627 name = hEnergy->GetName();
628 B2DEBUG(40, "Fitting " << name.Data());
629 hEnergy->Fit(func, "LIEQ", "", fitLow, fitHigh);
630 double peak = func->GetParameter(1);
631 double effSigma = func->GetParameter(2);
632 double eta = func->GetParameter(3);
633 prob = func->GetProb();
634
635 //..Check fit quality 0 = good, 1 = redo fit, 2 = lowStat, 3 = lowProb,
636 // 4 = peakAtLimit, 5 = sigmaAtLimit, 6 = etaAtLimit.
637 double dEta = min((etaMax - eta), (eta - etaMin));
638 fitStatus = eclLeakageFitQuality(fitLow, fitHigh, peak, effSigma, dEta, prob);
639
640 //..If the fit probability is low, refit using a smaller range (fracEnt)
641 if ((fitStatus == 1 or fitStatus == 3) and nIter == 0) {
642 nIter++;
643 fitHist = true;
644
645 // Store correction except for peak or sigma at limit.
646 } else if (fitStatus <= 3) {
647
648 //..Divide by sqrt(peak for full crystal) to get correct average
649 // when multiplying the theta and phi corrections
650 correction = peak / sqrt(peakUncorr[ie][thID]);
651 corrUnc = func->GetParError(1) / sqrt(peakUncorr[ie][thID]);
652 }
653 }
654
655 //..Store the correction for this position
656 positionCorrection[ie][thID][idir][ipos] = correction;
657 positionCorrectionUnc[ie][thID][idir][ipos] = corrUnc;
658 statusOfeFracPosition->Fill(fitStatus + 0.00001);
659 probOfeFracPosition->Fill(prob);
660 maxOfeFracPosition->Fill(hEnergy->GetMaximum());
661
662 //..Summary histogram for successful fits. Note that fitStatus<0 also has prob<0.
663 if (prob > 0 and fitStatus <= 3) {
664 if (idir == 0) {
665 thetaCorSummary->Fill(correction);
666 } else {
667 phiCorSummary->Fill(correction);
668 }
669 }
670
671 //..Record the failed fit details. We may still use the correction.
672 if (fitStatus >= 2) {
673 statuseFracPosition.push_back(fitStatus);
674 failedeFracPosition.push_back(hEnergy->GetName());
675 histfile->cd();
676 hEnergy->Write();
677 }
678 }
679 }
680 }
681 }
682
683 //-----------------------------------------------------------------------------------
684 //..Summarize position fit results
685 B2INFO("eclLeakageAlgorithm: " << nHistToFit << " eFracPosition histograms to fit");
686 nbadFit = statuseFracPosition.size();
687 B2INFO("eFracPosition failed fits: " << nbadFit);
688 for (int ibad = 0; ibad < nbadFit; ibad++) {
689 int badStat = statuseFracPosition[ibad];
690 B2ERROR(" histogram " << failedeFracPosition[ibad].Data() << " status " << badStat << " " << statusString[badStat].Data());
691 }
692
693 //..Write to disk
694 histfile->cd();
695 statusOfeFracPosition->Write();
696 probOfeFracPosition->Write();
697 maxOfeFracPosition->Write();
698 thetaCorSummary->Write();
699 phiCorSummary->Write();
700
701
702 //====================================================================================
703 //====================================================================================
704 //..Step 4. Store quantities needed for the payloads
705
706 //-----------------------------------------------------------------------------------
707 //..First, we need to fix up the thetaID that have been so far missed.
708 // Just copy the values from the first or last thetaID for which corrections were found.
709
710 //..ThetaID before the first useful one
711 for (int thID = firstUsefulThID - 1; thID >= 0; thID--) {
712 for (int ie = 0; ie < nEnergies; ie++) {
713
714 for (int idir = 0; idir < 3; idir++) {
715 for (int ipos = 0; ipos < nPositions; ipos++) {
716 positionCorrection[ie][thID][idir][ipos] = positionCorrection[ie][thID + 1][idir][ipos];
717 positionCorrectionUnc[ie][thID][idir][ipos] = positionCorrectionUnc[ie][thID + 1][idir][ipos];
718 }
719 }
720 }
721 }
722
723 //..ThetaID beyond last useful one
724 for (int thID = lastUsefulThID + 1; thID < nThetaID; thID++) {
725 for (int ie = 0; ie < nEnergies; ie++) {
726
727 for (int idir = 0; idir < 3; idir++) {
728 for (int ipos = 0; ipos < nPositions; ipos++) {
729 positionCorrection[ie][thID][idir][ipos] = positionCorrection[ie][thID - 1][idir][ipos];
730 positionCorrectionUnc[ie][thID][idir][ipos] = positionCorrectionUnc[ie][thID - 1][idir][ipos];
731 }
732 }
733 }
734 }
735
736 //-----------------------------------------------------------------------------------
737 //..std::vectors of generated energies
738 std::vector<float> forwardVector;
739 std::vector<float> barrelVector;
740 std::vector<float> backwardVector;
741 for (int ie = 0; ie < nEnergies; ie++) {
742 forwardVector.push_back(log(generatedE[0][ie]));
743 barrelVector.push_back(log(generatedE[1][ie]));
744 backwardVector.push_back(log(generatedE[2][ie]));
745 }
746
747 //..Store in array format for validation studies
748 float leakLogE[3][12] = {};
749 for (int ie = 0; ie < nEnergies; ie++) {
750 leakLogE[0][ie] = forwardVector[ie];
751 leakLogE[1][ie] = barrelVector[ie];
752 leakLogE[2][ie] = backwardVector[ie];
753 }
754
755 //-----------------------------------------------------------------------------------
756 //..Position dependent corrections
757
758 //..2D histogram of theta-dependent corrections
759 TH2F thetaCorrection("thetaCorrection", "Theta correction vs bin;bin = thetaID + 69*energyBin;local theta bin", nbinX, 0, nbinX,
760 nPositions, 0, nPositions);
761 int ix = 0;
762 for (int ie = 0; ie < nEnergies; ie++) {
763 for (int thID = 0; thID < nThetaID; thID++) {
764 ix++;
765 for (int ipos = 0; ipos < nPositions; ipos++) {
766 int iy = ipos + 1;
767 float correction = positionCorrection[ie][thID][0][ipos];
768 float corrUnc = positionCorrectionUnc[ie][thID][0][ipos];
769 thetaCorrection.SetBinContent(ix, iy, correction);
770 thetaCorrection.SetBinError(ix, iy, corrUnc);
771 }
772 }
773 }
774
775 //..2D histogram of phi-dependent corrections. Twice as many x bins;
776 // one set for crystals next to mechanical structure, one for otherwise.
777 TH2F phiCorrection("phiCorrection", "Phi correction vs bin;bin = thetaID + 69*energyBin;local phi bin", 2 * nbinX, 0, 2 * nbinX,
778 nPositions, 0, nPositions);
779 ix = 0;
780 for (int ie = 0; ie < nEnergies; ie++) {
781 for (int thID = 0; thID < nThetaID; thID++) {
782 ix++;
783 for (int ipos = 0; ipos < nPositions; ipos++) {
784 int iy = ipos + 1;
785
786 //..First set of corrections
787 float correction = positionCorrection[ie][thID][1][ipos];
788 float corrUnc = positionCorrectionUnc[ie][thID][1][ipos];
789 phiCorrection.SetBinContent(ix, iy, correction);
790 phiCorrection.SetBinError(ix, iy, corrUnc);
791
792 //..Second set
793 correction = positionCorrection[ie][thID][2][ipos];
794 corrUnc = positionCorrectionUnc[ie][thID][2][ipos];
795 phiCorrection.SetBinContent(ix + nbinX, iy, correction);
796 phiCorrection.SetBinError(ix + nbinX, iy, corrUnc);
797 }
798 }
799 }
800
801 //-----------------------------------------------------------------------------------
802 //..nCrys dependent corrections; not used since nOptimal was implemented.
803 const int maxN = 21; // maximum number of crystals in a cluster
804 TH2F nCrystalCorrection("nCrystalCorrection", "nCrys correction vs bin;bin = thetaID + 69*energyBin;nCrys", nbinX, 0, nbinX,
805 maxN + 1, 0, maxN + 1);
806
807 ix = 0;
808 for (int ie = 0; ie < nEnergies; ie++) {
809 for (int thID = 0; thID < nThetaID; thID++) {
810 ix++;
811 for (int in = 0; in <= maxN; in++) {
812 int iy = in + 1;
813 float correction = 1.;
814 float corrUnc = 0.;
815 nCrystalCorrection.SetBinContent(ix, iy, correction);
816 nCrystalCorrection.SetBinError(ix, iy, corrUnc);
817 }
818 }
819 }
820
821
822 //====================================================================================
823 //====================================================================================
824 //..Step 5. Diagnostic histograms
825
826 //..Start by storing the payload histograms
827 histfile->cd();
828 thetaCorrection.Write();
829 phiCorrection.Write();
830 nCrystalCorrection.Write();
831
832 //-----------------------------------------------------------------------------------
833 //..One histogram of new and original reconstructed energy after leakage correction
834 // per generated energy per region. Also uncorrected.
835 // The "Corrected no nCrys" and "Corrected measured" are identical, but keep both
836 // for easier comparison with earlier results.
837 const int nResType = 5;
838 const TString resName[nResType] = {"Uncorrected", "Original", "Corrected no nCrys", "Corrected measured", "Corrected true"};
839 const TString regName[nLeakReg] = {"forward", "barrel", "backward"};
840 auto energyResolution = create3Dvector<TH1F*>(nLeakReg, nEnergies, nResType);
841
842 //..Base number of bins on a typical thetaID for each region
843 int thIDReg[nLeakReg];
844 thIDReg[0] = 9;
845 thIDReg[1] = 35;
846 thIDReg[2] = 61;
847
848 for (int ireg = 0; ireg < nLeakReg; ireg++) {
849 for (int ie = 0; ie < nEnergies; ie++) {
850
851 //..Titles and bins for this region and energy
852 TString stireg = std::to_string(ireg);
853 TString stie = std::to_string(ie);
854 TString stieName = std::to_string(iEnergiesMeV[ie][thIDReg[ireg]]);
855 int nbinReg = 20 * nEfracBins[ie][thIDReg[ireg]];
856
857 for (int ires = 0; ires < nResType; ires++) {
858 name = "energyResolution_" + stireg + "_" + stie + "_" + std::to_string(ires);
859 title = resName[ires] + " energy, " + stieName + " MeV, " + regName[ireg] + ";Reconstructed E/Etrue";
860 energyResolution[ireg][ie][ires] = new TH1F(name, title, nbinReg, eFracLo, eFracHi);
861 }
862 }
863 }
864
865 //-----------------------------------------------------------------------------------
866 //..Loop over events and store leakage-corrected energies
867 for (int i = 0; i < treeEntries; i++) {
868 tree->GetEntry(i);
869
870 //..Only events with good reconstruction
871 bool goodReco = t_thetaID >= firstUsefulThID and t_thetaID <= lastUsefulThID and t_energyBin >= 0;
872 if (not goodReco) {continue;}
873
874 //-----------------------------------------------------------------------------------
875 //..Corrections using true energy
876
877 //..Position-dependent leakage corrections using true energy
878 int idir = 0;
879 float thetaPosCor = positionCorrection[t_energyBin][t_thetaID][idir][t_thetaBin];
880
881 idir = t_phiMech + 1;
882 float phiPosCor = positionCorrection[t_energyBin][t_thetaID][idir][t_phiBin];
883 float corrTrue = thetaPosCor * phiPosCor;
884
885 //-----------------------------------------------------------------------------------
886 //..Find correction using measured energy. The correction is a function of corrected
887 // energy, so will need to iterate
888 float corrMeasured = 0.96; // typical correction as starting point
889 for (int iter = 0; iter < 2; iter++) {
890
891
892 //..Energy points that bracket this value
893 float energyRaw = t_energyFrac * generatedE[t_region][t_energyBin];
894 float logEnergy = log(energyRaw / corrMeasured);
895 int ie0 = 0; // lower energy point
896 if (logEnergy < leakLogE[t_region][0]) {
897 ie0 = 0;
898 } else if (logEnergy > leakLogE[t_region][nEnergies - 1]) {
899 ie0 = nEnergies - 2;
900 } else {
901 while (logEnergy > leakLogE[t_region][ie0 + 1]) {ie0++;}
902 }
903
904 //..Corrections from lower and upper energy points
905 float cor0 = positionCorrection[ie0][t_thetaID][0][t_thetaBin] * positionCorrection[ie0][t_thetaID][t_phiMech + 1][t_phiBin];
906 float cor1 = positionCorrection[ie0 + 1][t_thetaID][0][t_thetaBin] * positionCorrection[ie0 + 1][t_thetaID][t_phiMech +
907 1][t_phiBin];
908
909 //..Interpolate in logE
910 corrMeasured = cor0 + (cor1 - cor0) * (logEnergy - leakLogE[t_region][ie0]) / (leakLogE[t_region][ie0 + 1] -
911 leakLogE[t_region][ie0]);
912 }
913
914 //..No longer have a separate case that excludes the nCrys correction
915 float corrNonCrys = corrMeasured;
916
917 //-----------------------------------------------------------------------------------
918 //..Fill the histograms
919 energyResolution[t_region][t_energyBin][0]->Fill(t_energyFrac); // uncorrected
920 energyResolution[t_region][t_energyBin][1]->Fill(t_origEnergyFrac); // original payload
921 energyResolution[t_region][t_energyBin][2]->Fill(t_energyFrac / corrNonCrys); // no nCrys, measured energy
922 energyResolution[t_region][t_energyBin][3]->Fill(t_energyFrac / corrMeasured); // corrected, measured energy
923 energyResolution[t_region][t_energyBin][4]->Fill(t_energyFrac / corrTrue); // corrected, true energy
924 }
925
926 //-----------------------------------------------------------------------------------
927 //..Fit each histogram to find peak, and extract resolution.
928
929 //..Store the peak and resolution values for each histogram
930 auto peakEnergy = create3Dvector<float>(nLeakReg, nEnergies, nResType);
931 auto energyRes = create3Dvector<float>(nLeakReg, nEnergies, nResType);
932
933 //..Loop over the histograms to be fit
934 for (int ireg = 0; ireg < nLeakReg; ireg++) {
935 for (int ie = 0; ie < nEnergies; ie++) {
936
937 //..Base the resolution on the number of entries in the corrected plot for all 4 cases.
938 double entries = energyResolution[ireg][ie][nResType - 1]->Integral();
939 for (int ires = 0; ires < nResType; ires++) {
940 TH1F* hEnergy = (TH1F*)energyResolution[ireg][ie][ires];
941 double peak = -1.;
942 double res68 = 99.; // resolution based on 68.3% of the entries
943 int nIter = 0; // keep track of attempts to fit this histogram
944 bool fitHist = entries > minEntries;
945
946 //..Possibly iterate fit starting from this point
947 while (fitHist) {
948
949 //..Fit parameters
950 double norm = hEnergy->GetMaximum();
951 double target = fracEnt[nIter] * entries; // fit range contains 68.3% or 50%
952 std::vector<double> startingParameters;// peak, sigma, eta, fitLow, fitHigh, nbins
953 startingParameters = eclLeakageFitParameters(hEnergy, target);
954 func->SetParameters(norm, startingParameters[0], startingParameters[1], startingParameters[2]);
955 func->SetParLimits(1, startingParameters[3], startingParameters[4]);
956 func->SetParLimits(2, 0., startingParameters[4] - startingParameters[3]);
957 func->SetParLimits(3, etaMin, etaMax);
958
959 //..First iteration the fitting range contains >68.3% of the histogram integral.
960 if (nIter == 0) {
961
962 //..Find the bin numbers used in the fit
963 int minLo = hEnergy->GetXaxis()->FindBin(startingParameters[3] + 0.0001);
964 int minHi = hEnergy->GetXaxis()->FindBin(startingParameters[4] - 0.0001);
965
966 //..Subtract a partial bin to get to exactly 68.3%
967 double dx = hEnergy->GetBinLowEdge(minLo + 1) - hEnergy->GetBinLowEdge(minLo);
968 double overage = hEnergy->Integral(minLo, minHi) - target;
969 double subLo = overage / hEnergy->GetBinContent(minLo);
970 double subHi = overage / hEnergy->GetBinContent(minHi);
971
972 //..Resolution is half the range that contains 68.3% of the events
973 res68 = 0.5 * dx * (1 + minHi - minLo - max(subLo, subHi));
974 }
975
976 //..Fit
977 name = hEnergy->GetName();
978 B2DEBUG(40, "Fitting " << name.Data());
979 hEnergy->Fit(func, "LIEQ", "", startingParameters[3], startingParameters[4]);
980 peak = func->GetParameter(1);
981 double effSigma = func->GetParameter(2);
982 double eta = func->GetParameter(3);
983 double prob = func->GetProb();
984
985 //..Check fit quality 0 = good, 1 = redo fit, 2 = lowStat, 3 = lowProb,
986 // 4 = peakAtLimit, 5 = sigmaAtLimit, 6 = etaAtLimit
987 double dEta = min((etaMax - eta), (eta - etaMin));
988 int fitStatus = eclLeakageFitQuality(startingParameters[3], startingParameters[4], peak, effSigma, dEta, prob);
989
990 //..If the fit probability is low, refit using a smaller range (fracEnt)
991 if ((fitStatus == 1 or fitStatus == 3) and nIter == 0) {
992 nIter++;
993 } else {
994 fitHist = false;
995 }
996
997 } // end of while
998
999 //..Record peak and resolution
1000 peakEnergy[ireg][ie][ires] = peak;
1001 energyRes[ireg][ie][ires] = res68;
1002
1003 //..And write to disk
1004 histfile->cd();
1005 hEnergy->Write();
1006 }
1007 }
1008 }
1009
1010 //-----------------------------------------------------------------------------------
1011 //..Summarize resolution
1012 int nresBins = nEnergies * nLeakReg * (nResType + 1); // +1 to add an empty bin after each set
1013 TH1F* peakSummary = new TH1F("peakSummary", "Peak E/Etrue for each method, region, energy;Energy energy point", nresBins, 0,
1014 nEnergies);
1015 TH1F* resolutionSummary = new TH1F("resolutionSummary", "Resolution/peak for each method, region, energy;Energy energy point",
1016 nresBins, 0, nEnergies);
1017
1018 B2INFO("Resolution divided by peak for each energy bin and region " << nResType << " ways");
1019 for (int ires = 0; ires < nResType; ires++) {B2INFO(" " << resName[ires]);}
1020 ix = 0;
1021 for (int ie = 0; ie < nEnergies; ie++) {
1022 B2INFO(" energy point " << ie);
1023 for (int ireg = 0; ireg < nLeakReg; ireg++) {
1024 B2INFO(" region " << ireg);
1025 for (int ires = 0; ires < nResType; ires++) {
1026
1027 //..Store in summary histograms
1028 ix++;
1029 peakSummary->SetBinContent(ix, peakEnergy[ireg][ie][ires]);
1030 peakSummary->SetBinError(ix, 0.);
1031 resolutionSummary->SetBinContent(ix, energyRes[ireg][ie][ires] / peakEnergy[ireg][ie][ires]);
1032 resolutionSummary->SetBinError(ix, 0.);
1033
1034 //..Print out as well
1035 B2INFO(" " << ires << " " << energyRes[ireg][ie][ires] / peakEnergy[ireg][ie][ires]);
1036 }
1037 ix++;
1038 }
1039 }
1040
1041 //..Write the summary histograms to disk
1042 histfile->cd();
1043 peakSummary->Write();
1044 resolutionSummary->Write();
1045
1046
1047 //====================================================================================
1048 //====================================================================================
1049 //..Step 6. Finish up.
1050
1051 //-----------------------------------------------------------------------------------
1052 //..Close histogram file
1053 histfile->Close();
1054
1055 //------------------------------------------------------------------------
1056 //..Create and store payload
1057 ECLLeakageCorrections* leakagePayload = new ECLLeakageCorrections();
1058 leakagePayload->setlogEnergiesFwd(forwardVector);
1059 leakagePayload->setlogEnergiesBrl(barrelVector);
1060 leakagePayload->setlogEnergiesBwd(backwardVector);
1061 leakagePayload->setThetaCorrections(thetaCorrection);
1062 leakagePayload->setPhiCorrections(phiCorrection);
1063 leakagePayload->setnCrystalCorrections(nCrystalCorrection);
1064 saveCalibration(leakagePayload, "ECLLeakageCorrections");
1065
1066 B2INFO("eclLeakageAlgorithm: successfully stored payload ECLLeakageCorrections");
1067 return c_OK;
1068}
Base class for calibration algorithms.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
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.
@ c_Failure
Failed =3 in Python.
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
Singleton class to cache database objects.
Definition: DBStore.h:31
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
void setInitializeActive(bool active)
Setter for m_initializeActive.
Definition: DataStore.cc:94
DB object to store leakage corrections, including nCrys dependence
void setThetaCorrections(const TH2F &thetaCorrections)
Set the 2D histogram containing the theta corrections for each thetaID and energy.
void setlogEnergiesBrl(const std::vector< float > &logEnergiesBrl)
Set the vector of energies used to evaluate the leakage corrections in the barrel.
void setnCrystalCorrections(const TH2F &nCrystalCorrections)
Set the 2D histogram containing the nCrys corrections for each thetaID and energy.
void setlogEnergiesFwd(const std::vector< float > &logEnergiesFwd)
Set the vector of energies used to evaluate the leakage corrections in the forward endcap.
void setPhiCorrections(const TH2F &phiCorrections)
Set the 2D histogram containing the phi corrections for each thetaID and energy.
void setlogEnergiesBwd(const std::vector< float > &logEnergiesBwd)
Set the vector of energies used to evaluate the leakage corrections in the backward endcap.
float t_energyFrac
measured energy after nOptimal bias and peak corrections, divided by generated
float t_locationError
reconstructed minus generated position (cm)
int t_energyBin
generated energy point
int t_phiBin
binned location in phi relative to crystal edge
int t_phiMech
mechanical structure next to lower phi (0), upper phi (1), or neither (2)
int t_region
region of photon 0=forward 1=barrel 2=backward
int t_thetaBin
binned location in theta relative to crystal edge
int t_nCrys
number of crystals used to calculate energy
virtual EResult calibrate() override
Run algorithm.
double m_lowEnergyThreshold
Parameters to control fit procedure.
float t_origEnergyFrac
corrected energy at time of generation, divided by generated
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
bool construct(Args &&... params)
Construct an object of type T in this StoreObjPtr, using the provided constructor arguments.
Definition: StoreObjPtr.h:119
static DBStore & Instance()
Instance of a singleton DBStore.
Definition: DBStore.cc:28
void update()
Updates all objects that are outside their interval of validity.
Definition: DBStore.cc:79
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
STL namespace.