Belle II Software  release-08-01-10
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 
31 using namespace std;
32 using namespace Belle2;
33 using namespace ECL;
34 using 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
62 std::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
120 double 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
151 int 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 
170 eclLeakageAlgorithm::eclLeakageAlgorithm(): CalibrationAlgorithm("eclLeakageCollector")
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)
EResult
The result of calibration.
@ c_OK
Finished successfuly =0 in Python.
@ c_Failure
Failed =3 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
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.