Belle II Software  release-08-01-10
eclNOptimalAlgorithm.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/eclNOptimalAlgorithm.h>
11 
12 /* ECL headers. */
13 #include <ecl/calibration/tools.h>
14 #include <ecl/dataobjects/ECLElementNumbers.h>
15 #include <ecl/dbobjects/ECLnOptimal.h>
16 
17 /* Basf2 headers. */
18 #include <framework/database/DBObjPtr.h>
19 #include <framework/database/DBStore.h>
20 #include <framework/dataobjects/EventMetaData.h>
21 #include <framework/datastore/DataStore.h>
22 #include <framework/datastore/StoreObjPtr.h>
23 
24 /* ROOT headers. */
25 #include <TF1.h>
26 #include <TH2F.h>
27 #include <TMath.h>
28 #include <TROOT.h>
29 
30 using namespace std;
31 using namespace Belle2;
32 using namespace ECL;
33 using namespace Calibration;
34 
35 //-----------------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------------
37 //..Structure
38 // 1. Setup
39 // - from collector histograms, read in job parameters and group number for each crystal
40 // - get the existing payload, which we will use as the starting point for nOptimal
41 // - write out histograms from collector and from the existing payload
42 //
43 // 2. Create histograms to store many items from many fits
44 //
45 // 3. Loop over each energy and group to find the optimal number of crystals
46 // - start by checking the current value of nOptimal, then check smaller and larger
47 // values of number of summed crystals. For value, find:
48 // - peak contained energy divided by generated energy by fitting the histogram
49 // range that includes 50% of events;
50 // - corresponding bias = sum of ECLCalDigits minus mc true energy;
51 // - resolution = one-half of minimum range that includes 68.3% of events
52 // - after finding the value of nOptimal with best resolution, also find the
53 // resolution for the current reconstruction.
54 // - store everything in diagnostic histograms.
55 //
56 // 4. Having found nOptimal for that group/energy, find the bias and peak fractional
57 // contained energy for adjacent energies. This enables energy interpolation
58 // when the payloads are used.
59 //
60 // 5. Generate and store the actual payload
61 
62 
63 //-----------------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------------
65 //..Some helper functions
66 
67 //-----------------------------------------------------------------------------------
68 //..Fit the minimum range of bins that contain the specified number of events.
69 std::vector<int> eclNOptimalFitRange(TH1D* h, const double& fraction)
70 {
71  const double target = fraction * h->GetEntries();
72  const int nBins = h->GetNbinsX();
73 
74  //..Start at the histogram maximum
75  int iLo = h->GetMaximumBin();
76  int iHi = iLo;
77  double sum = h->Integral(iLo, iHi);
78 
79  //..Add one bin at a time
80  while (sum < target and (iLo > 1 or iHi < nBins)) {
81  double nextLo = 0.;
82  if (iLo > 1) {nextLo = h->GetBinContent(iLo - 1);}
83  double nextHi = 0.;
84  if (iHi < nBins) {nextHi = h->GetBinContent(iHi + 1);}
85  if (nextLo > nextHi) {
86  sum += nextLo;
87  iLo--;
88  } else {
89  sum += nextHi;
90  iHi++;
91  }
92  }
93 
94  std::vector<int> iBins;
95  iBins.push_back(iLo);
96  iBins.push_back(iHi);
97  return iBins;
98 
99 }
100 
101 //-----------------------------------------------------------------------------------
102 //..Resolution is the minimum range that contains 68.3% of entries
103 double eclNOptimalResolution(TH1D* h, int& iLo75, int& iHi75)
104 {
105 
106  //..Search among the bin range that contains 75% of events for the smallest
107  // range that contains at least 68.3%. If more than one, pick the one with
108  // the most events.
109  const int nBins = h->GetNbinsX();
110  const double target = 0.683 * h->GetEntries();
111 
112  //..Copy the histogram contents for speed of access
113  // Recall that the first histogram bin is 1, not 0.
114  std::vector<double> intVector;
115  intVector.push_back(h->GetBinContent(1));
116  for (int iL = 2; iL <= nBins; iL++) {
117  double nextIntegral = intVector[iL - 2] + h->GetBinContent(iL);
118  intVector.push_back(nextIntegral);
119  }
120 
121  //..Now search all possible ranges
122  int iLo = iLo75;
123  int iHi = iHi75;
124  double maxIntegral = intVector[iHi - 1] - intVector[iLo - 2];
125  for (int iL = iLo75; iL <= iHi75; iL++) {
126  for (int iH = iL; iH <= iHi75; iH++) {
127 
128  // sum[iL, iH] = sum[1, iH] - sum[1,iL-1] = intVector[iH-1] - intVector[iL-2]
129  double integral = intVector[iH - 1] - intVector[iL - 2];
130  if ((integral > target and (iH - iL) < (iHi - iLo)) or
131  (integral > target and (iH - iL) == (iHi - iLo) and integral > maxIntegral)
132  ) {
133  iLo = iL;
134  iHi = iH;
135  maxIntegral = integral;
136  }
137  }
138  }
139 
140  //..Refine the range to exactly 68.3% by subtracting a fraction of the first or last bin.
141  // Use fit to estimate distribution of events across the bin.
142  const double overage = h->Integral(iLo, iHi) - target;
143  const double dx = (h->GetXaxis()->GetXmax() - h->GetXaxis()->GetXmin()) / nBins;
144 
145  //..Fraction of the first bin we could exclude
146  double xLow = h->GetBinLowEdge(iLo);
147  double fracEntriesToExcludeLo = overage / h->GetBinContent(iLo);
148  double fracBinToExcludeLo = fracEntriesToExcludeLo;
149 
150  //..Use the slope from the fit extrapolated to this point unless it is 0
151  TF1* func = (TF1*)h->GetFunction("eclNOptimalNovo");
152  double f0 = func->Eval(xLow);
153  double f1 = func->Eval(xLow + dx);
154  if (abs(f1 - f0) > 1.) {
155  fracBinToExcludeLo = (sqrt(f0 * f0 + fracEntriesToExcludeLo * (f1 * f1 - f0 * f0)) - f0) / (f1 - f0);
156  }
157 
158  //..Last bin. In this case, we want the integral from the low edge of the bin to
159  // be the fraction of events to keep in the range, not the fraction to exclude.
160  double xHigh = h->GetBinLowEdge(iHi + 1);
161  f0 = func->Eval(xHigh - dx);
162  f1 = func->Eval(xHigh);
163  double fracEntriesToExcludeHi = overage / h->GetBinContent(iHi);
164  double fracEntriesToInclude = 1. - fracEntriesToExcludeHi;
165  double fracBinToInclude = fracEntriesToInclude;
166  if (abs(f1 - f0) > 1.) {
167  fracBinToInclude = (sqrt(f0 * f0 + fracEntriesToInclude * (f1 * f1 - f0 * f0)) - f0) / (f1 - f0);
168  }
169  double fracBinToExcludeHi = 1. - fracBinToInclude;
170 
171  //..Exclude the first bin or last bin fraction, whichever gives better resolution
172  double rangeBins = 1 + iHi - iLo - max(fracBinToExcludeLo, fracBinToExcludeHi);
173  return 0.5 * dx * rangeBins;
174 
175 }
176 
177 //--------------------------------------------------------------------
178 //..Novosibirsk; H. Ikeda et al. / NIM A 441 (2000) 401-426
179 double eclNOptimalNovo(const double* x, const double* par)
180 {
181 
182  double peak = par[1];
183  double width = par[2];
184  double sln4 = sqrt(log(4));
185  double y = par[3] * sln4;
186  double tail = -log(y + sqrt(1 + y * y)) / sln4;
187  double qc = 0.;
188 
189  if (TMath::Abs(tail) < 1.e-7)
190  qc = 0.5 * TMath::Power(((x[0] - peak) / width), 2);
191  else {
192  double qa = tail * sqrt(log(4.));
193  double qb = sinh(qa) / qa;
194  double qx = (x[0] - peak) / width * qb;
195  double qy = 1. + tail * qx;
196 
197  if (qy > 1.E-7)
198  qc = 0.5 * (TMath::Power((log(qy) / tail), 2) + tail * tail);
199  else
200  qc = 15.0;
201  }
202 
203  return par[0] * exp(-qc);
204 }
205 
206 //-----------------------------------------------------------------------------------
207 //-------------------------------------------------------------------------------
208 //..Constructor
209 
210 eclNOptimalAlgorithm::eclNOptimalAlgorithm(): CalibrationAlgorithm("eclNOptimalCollector")
211 {
213  "Use single gamma MC to find the optimal number of crystals to sum for cluster energy"
214  );
215 }
216 
217 //-------------------------------------------------------------------------------
218 //..Calibrate
220 {
221 
222  //-----------------------------------------------------------------------------------
223  //-----------------------------------------------------------------------------------
224  //..Algorithm set up
225 
226  //..Get started
227  B2INFO("Starting eclNOptimalAlgorithm");
228  gROOT->SetBatch();
229 
230  //-----------------------------------------------------------------------------------
231  //..Read in parameter histograms created by the collector and fix normalization
232  auto inputParameters = getObjectPtr<TH1F>("inputParameters");
233  const int lastBin = inputParameters->GetNbinsX();
234  const double scale = inputParameters->GetBinContent(lastBin); // number of times inputParameters was filled
235  for (int ib = 1; ib < lastBin; ib++) {
236  double param = inputParameters->GetBinContent(ib);
237  inputParameters->SetBinContent(ib, param / scale);
238  inputParameters->SetBinError(ib, 0.);
239  }
240 
241  //..Also read in and normalize group number for each cellID
242  auto groupNumberOfEachCellID = getObjectPtr<TH1F>("groupNumberOfEachCellID");
243  for (int ic = 1; ic <= ECLElementNumbers::c_NCrystals; ic++) {
244  const double groupNum = groupNumberOfEachCellID->GetBinContent(ic);
245  groupNumberOfEachCellID->SetBinContent(ic, groupNum / scale);
246  groupNumberOfEachCellID->SetBinError(ic, 0.);
247  }
248 
249  //..Couple of diagnostic histograms
250  auto entriesPerThetaIdEnergy = getObjectPtr<TH2F>("entriesPerThetaIdEnergy");
251  auto mcEnergyDiff = getObjectPtr<TH2F>("mcEnergyDiff");
252 
253  //..Write these to disk.
254  TFile* histFile = new TFile("eclNOptimalAlgorithm.root", "recreate");
255  inputParameters->Write();
256  groupNumberOfEachCellID->Write();
257  entriesPerThetaIdEnergy->Write();
258  mcEnergyDiff->Write();
259 
260  //-----------------------------------------------------------------------------------
261  //..Parameters from the inputParameters histogram
262  const int nCrystalGroups = (int)(inputParameters->GetBinContent(1) + 0.5);
263  const int nEnergies = (int)(inputParameters->GetBinContent(2) + 0.5);
264  const int nLeakReg = 3; // 3 regions forward barrel backward
265  auto generatedE = create2Dvector<float>(nLeakReg, nEnergies);
266  int bin = 2; // bin 1 = nCrystalGroups, bin 2 = nEnergies, bin 3 = first energy
267  for (int ireg = 0; ireg < nLeakReg; ireg++) {
268  for (int ie = 0; ie < nEnergies; ie++) {
269  bin++;
270  generatedE[ireg][ie] = inputParameters->GetBinContent(bin);
271  }
272  }
273  B2INFO("nCrystalGroups = " << nCrystalGroups);
274 
275  //-----------------------------------------------------------------------------------
276  //..Experiment and run number, for reading existing payload from database
277  const auto exprun = getRunList();
278  const int iExp = exprun[0].first;
279  const int iRun = exprun[0].second;
280  B2INFO("Experiment, run = " << iExp << ", " << iRun);
281 
283  // simulate the initialize() phase where we can register objects in the DataStore
285  evtPtr.registerInDataStore();
287  // now construct the event metadata
288  evtPtr.construct(1, iRun, iExp);
289  // and update the database contents
290  DBStore& dbstore = DBStore::Instance();
291  dbstore.update();
292  // this is only needed it the payload might be intra-run dependent,
293  // that is if it might change during one run as well
294  dbstore.updateEvent();
295 
296  //-----------------------------------------------------------------------------------
297  //..Get existing payload
298  B2INFO("eclNOptimalAlgorithm: reading previous payload");
299  DBObjPtr<ECLnOptimal> existingECLnOptimal;
300  std::vector<float> eUpperBoundariesFwdPrev = existingECLnOptimal->getUpperBoundariesFwd();
301  std::vector<float> eUpperBoundariesBrlPrev = existingECLnOptimal->getUpperBoundariesBrl();
302  std::vector<float> eUpperBoundariesBwdPrev = existingECLnOptimal->getUpperBoundariesBwd();
303  TH2F nOptimal2DPrev = existingECLnOptimal->getNOptimal();
304  nOptimal2DPrev.SetName("nOptimal2DPrev");
305 
306  const int nPrevE = eUpperBoundariesFwdPrev.size();
307  B2INFO("Energy upper boundaries from previous payload for each region");
308  for (int ie = 0; ie < nPrevE; ie++) {
309  B2INFO(" " << ie << " " << eUpperBoundariesFwdPrev[ie] << " " << eUpperBoundariesBrlPrev[ie] << " " << eUpperBoundariesBwdPrev[ie]);
310  }
311 
312  //..Write out
313  histFile->cd();
314  nOptimal2DPrev.Write();
315 
316  //-----------------------------------------------------------------------------------
317  //..Use existing payload to get the initial nOptimal value for each group
318  std::vector< std::vector<int> > initialNOptimal;
319  initialNOptimal.resize(nCrystalGroups, std::vector<int>(nEnergies, 0));
320 
321  //..Couple of histograms of relevant quantities
322  TH2F* nInitialPerGroup = new TH2F("nInitialPerGroup", "initial nCrys, energy point vs group number;group;energy point",
323  nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
324  TH2F* generatedEPerGroup = new TH2F("generatedEPerGroup", "Generated energy, energy point vs group number;group;energy point",
325  nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
326  TH1F* firstCellIDPerGroup = new TH1F("firstCellIDPerGroup", "First cellID of group;group", nCrystalGroups, 0., nCrystalGroups);
327  TH1F* nCrystalsPerGroup = new TH1F("nCrystalsPerGroup", "Number of crystals per group;group", nCrystalGroups, 0., nCrystalGroups);
328  std::vector<int> crystalsPerGroup;
329  crystalsPerGroup.resize(nCrystalGroups, 0);
330 
331  const int nCrystalsTotal = ECLElementNumbers::c_NCrystals;
332  for (int cellID = 1; cellID <= nCrystalsTotal; cellID++) {
333 
334  //..Group number of this cellID
335  int iGroup = (int)(0.5 + groupNumberOfEachCellID->GetBinContent(cellID));
336 
337  //..Energy boundaries of previous payload, which depend on the ECL region
338  std::vector<float> eUpperBoundariesPrev = eUpperBoundariesBrlPrev;
339  int iRegion = 1; // barrel
340  if (ECLElementNumbers::isForward(cellID)) {
341  eUpperBoundariesPrev = eUpperBoundariesFwdPrev;
342  iRegion = 0;
343  } else if (ECLElementNumbers::isBackward(cellID)) {
344  eUpperBoundariesPrev = eUpperBoundariesBwdPrev;
345  iRegion = 2;
346  }
347 
348  //..For each test energy, get the nOptimal for this cellID from previous payload.
349  // iEnergy is the energy bin of the previous payload, which is equal to ie if
350  // the test energies have not changed.
351  for (int ie = 0; ie < nEnergies; ie++) {
352  float energy = generatedE[iRegion][ie];
353  int iEnergy = 0;
354  while (energy > eUpperBoundariesPrev[iEnergy]) {iEnergy++;}
355  initialNOptimal[iGroup][ie] = (int)(0.5 + nOptimal2DPrev.GetBinContent(iGroup + 1, iEnergy + 1));
356  if (ie != iEnergy) {
357  B2INFO("ie iEnergy mismatch: cellID " << cellID << " ie " << ie << " iEnergy " << iEnergy);
358  }
359 
360  //..Store in diagnostic histograms
361  generatedEPerGroup->SetBinContent(iGroup + 1, ie + 1, energy);
362  nInitialPerGroup->SetBinContent(iGroup + 1, ie + 1, initialNOptimal[iGroup][ie]);
363  }
364 
365  //..Count crystals in this group
366  if (crystalsPerGroup[iGroup] == 0) {
367  firstCellIDPerGroup->SetBinContent(iGroup + 1, cellID);
368  firstCellIDPerGroup->SetBinError(iGroup + 1, 0.);
369  }
370  crystalsPerGroup[iGroup]++;
371  }
372 
373  //..Write out these histograms
374  for (int ig = 0; ig < nCrystalGroups; ig++) {
375  nCrystalsPerGroup->SetBinContent(ig + 1, crystalsPerGroup[ig]);
376  nCrystalsPerGroup->SetBinError(ig + 1, 0.);
377  }
378  histFile->cd();
379  nInitialPerGroup->Write();
380  generatedEPerGroup->Write();
381  firstCellIDPerGroup->Write();
382  nCrystalsPerGroup->Write();
383  B2INFO("Wrote initial diagnostic histograms");
384 
385  //-----------------------------------------------------------------------------------
386  //..Write out all the 2D histograms
387  for (int ig = 0; ig < nCrystalGroups; ig++) {
388  for (int ie = 0; ie < nEnergies; ie++) {
389  std::string name = "eSum_" + std::to_string(ig) + "_" + std::to_string(ie);
390  auto eSum = getObjectPtr<TH2F>(name);
391  name = "biasSum_" + std::to_string(ig) + "_" + std::to_string(ie);
392  auto biasSum = getObjectPtr<TH2F>(name);
393  histFile->cd();
394  eSum->Write();
395  biasSum->Write();
396  }
397  }
398  B2INFO("Wrote eSum and biasSum histograms");
399 
400  //-----------------------------------------------------------------------------------
401  //-----------------------------------------------------------------------------------
402  //..Find nOptimal and corresponding bias for each group/energy point
403 
404  //..Histograms to store fit results
405  TH2F* nOptimalPerGroup = new TH2F("nOptimalPerGroup", "nOptimal;group;energy point", nCrystalGroups, 0., nCrystalGroups, nEnergies,
406  0., nEnergies);
407  TH2F* changeInNOptimal = new TH2F("changeInNOptimal", "nOptimal minus nInitial;group;energy point", nCrystalGroups, 0.,
408  nCrystalGroups, nEnergies, 0., nEnergies);
409  TH2F* binsInFit = new TH2F("binsInFit", "Number of bins used in Novo fit, energy point vs group number;group;energy point",
410  nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
411  TH2F* maxEntriesPerHist = new TH2F("maxEntriesPerHist",
412  "Max entries in histogram bin, energy point vs group number;group;energy point", nCrystalGroups, 0., nCrystalGroups, nEnergies, 0.,
413  nEnergies);
414  TH2F* peakPerGroup = new TH2F("peakPerGroup", "peak energy, energy point vs group number;group;energy point", nCrystalGroups, 0.,
415  nCrystalGroups, nEnergies, 0., nEnergies);
416  TH2F* effSigmaPerGroup = new TH2F("effSigmaPerGroup", "fit effective sigma, energy point vs group number;group;energy point",
417  nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
418  TH2F* etaPerGroup = new TH2F("etaPerGroup", "fit eta, energy point vs group number;group;energy point", nCrystalGroups, 0.,
419  nCrystalGroups, nEnergies, 0., nEnergies);
420  TH2F* fitProbPerGroup = new TH2F("fitProbPerGroup", "fit probability, energy point vs group number;group;energy point",
421  nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
422  TH2F* resolutionPerGroup = new TH2F("resolutionPerGroup", "resolution/(peak-bias), energy point vs group number;group;energy point",
423  nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
424  TH2F* fracContainedEPerGroup = new TH2F("fracContainedEPerGroup",
425  "peak fraction of energy contained in nOpt crystals;group;energy point", nCrystalGroups, 0., nCrystalGroups, nEnergies, 0.,
426  nEnergies);
427 
428  TH2F* biasPerGroup = new TH2F("biasPerGroup", "bias (GeV), energy point vs group number;group;energy point", nCrystalGroups, 0.,
429  nCrystalGroups, nEnergies, 0., nEnergies);
430  TH2F* sigmaBiasPerGroup = new TH2F("sigmaBiasPerGroup", "sigma bias (GeV), energy point vs group number;group;energy point",
431  nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
432 
433  TH2F* existingResolutionPerGroup = new TH2F("existingResolutionPerGroup",
434  "existing resolution/peak, energy point vs group number;group;energy point", nCrystalGroups, 0., nCrystalGroups, nEnergies, 0.,
435  nEnergies);
436 
437  //-----------------------------------------------------------------------------------
438  //..Loop over all groups and energy points
439 
440  //..Fit function Novosibirsk (xmin, xmax, nparameters)
441  TF1* func = new TF1("eclNOptimalNovo", eclNOptimalNovo, 0.4, 1.4, 4);
442  func->SetLineColor(kRed);
443 
444  for (int ig = 0; ig < nCrystalGroups; ig++) {
445  for (int ie = 0; ie < nEnergies; ie++) {
446 
447  //..Read in the energy sum vs nCrys for the group and energy point
448  std::string name = "eSum_" + std::to_string(ig) + "_" + std::to_string(ie);
449  auto eSum = getObjectPtr<TH2F>(name);
450 
451  //..Also the corresponding bias histgram
452  std::string biasName = "biasSum_" + std::to_string(ig) + "_" + std::to_string(ie);
453  auto biasSum = getObjectPtr<TH2F>(biasName);
454 
455  //..And the generated energy
456  const double genEnergy = generatedEPerGroup->GetBinContent(ig + 1, ie + 1);
457 
458  //-----------------------------------------------------------------------------------
459  //..Extract the eSum distributions for various nCrys (=nCrysSumToFit) and fit them
460  // to find the best resolution.
461  const int nCrysBins = eSum->GetNbinsX();
462  const int nCrysMax = nCrysBins - 1; // the last bin is eSum for existing reco
463 
464  //..Items to be found and stored in the following while loop
465  TH1D* eSumOpt{nullptr}; // 1D projection with the best resolution
466  int nFitBins = 0; // keep track of how many bins are included in the fit
467  double bestFractionalResolution = 999.;
468  double existingFractionalResolution = 999.;
469  double biasForNOpt = 0.; // bias from backgrounds for optimal nCrys
470  double biasSigmaForNOpt = 0.; // sigma bias
471  int nOpt = 0;
472 
473  //..Start with the previous optimal value, then try fewer, if possible, then
474  // try more, if possible. End by finding the resolution for the
475  // reconstruction used to produce the single photon MC samples.
476  const int initialnCrysSumToFit = initialNOptimal[ig][ie];
477  int nCrysSumToFit = initialnCrysSumToFit;
478  while (nCrysSumToFit > 0) {
479 
480  TH1D* hEnergy = (TH1D*)eSum->ProjectionY("hEnergy", nCrysSumToFit, nCrysSumToFit);
481  TString newName = name + "_" + std::to_string(nCrysSumToFit);
482  hEnergy->SetName(newName);
483 
484  //------------------------------------------------------------------------------
485  //..Check stats, and rebin as required
486  const double minESumEntries = 800.;
487  if (hEnergy->GetEntries() < minESumEntries) {
488  B2INFO("Insuffient entries in eSum: " << hEnergy->GetEntries() << " for group " << ig << " energy point " << ie);
489  histFile->Close();
490  B2INFO("closed histFile; quitting");
491  return c_NotEnoughData;
492  }
493 
494  //..Rebin if the maximum bin has too few entries
495  const double minPeakValue = 300.;
496  while (hEnergy->GetMaximum() < minPeakValue) {hEnergy->Rebin(2);}
497 
498  //------------------------------------------------------------------------------
499  //..Find 50% range for Novo fit to find peak value. Rebin if there are too many bins
500  double fitFraction = 0.5;
501  int iLo = 1;
502  int iHi = hEnergy->GetNbinsX();
503  const int maxBinsToFit = 59;
504  while ((iHi - iLo) > maxBinsToFit) {
505  std::vector<int> iBins = eclNOptimalFitRange(hEnergy, fitFraction);
506  iLo = iBins[0];
507  iHi = iBins[1];
508  if ((iHi - iLo) > maxBinsToFit) {hEnergy->Rebin(2);}
509  }
510 
511  //..Fit range
512  const int nBinsX = hEnergy->GetNbinsX();
513  const double fitlow = hEnergy->GetBinLowEdge(iLo);
514  const double fithigh = hEnergy->GetBinLowEdge(iHi + 1);
515  double sum = hEnergy->Integral(iLo, iHi);
516  B2INFO("group " << ig << " ie " << ie << " name " << name << " newName " << newName << " nBinsX " << nBinsX << " 50% target: " <<
517  fitFraction * hEnergy->GetEntries() << " iLo: " << iLo << " iHi: " << iHi << " sum: " << sum);
518 
519  //------------------------------------------------------------------------------
520  //..Set up the fit. Initial values
521  double normalization = hEnergy->GetMaximum();
522  const int iMax = hEnergy->GetMaximumBin();
523  double peak = hEnergy->GetBinLowEdge(iMax);
524  double effSigma = 0.5 * (fithigh - fitlow);
525  double eta = 0.4; // typical value for good fits
526 
527  func->SetParameters(normalization, peak, effSigma, eta);
528  func->SetParNames("normalization", "peak", "effSigma", "eta");
529 
530  //..Parameter ranges
531  func->SetParLimits(1, fitlow, fithigh);
532  func->SetParLimits(2, 0., 2.*effSigma);
533  func->SetParLimits(3, -1, 3);
534 
535  //..If there is only one crystal, fix eta to a special value
536  if (nCrysSumToFit == 1) {
537  const double etaForOneCrystal = 0.95;
538  func->SetParameter(3, etaForOneCrystal);
539  func->SetParLimits(3, etaForOneCrystal, etaForOneCrystal);
540  }
541 
542  //..Fit
543  hEnergy->Fit(func, "LIEQ", "", fitlow, fithigh);
544 
545  //------------------------------------------------------------------------------
546  //..Find the bias = sum of CalDigits minus sum of MC truth for this nCrys
547  // Bias is the mid point of the minimum range that contains 68.3% of events
548  double bias = 0.;
549  double biasSigma = 0.;
550  if (nCrysSumToFit < nCrysBins) {
551  TH1D* hBias = (TH1D*)biasSum->ProjectionY("hBias", nCrysSumToFit, nCrysSumToFit);
552  fitFraction = 0.683;
553  std::vector<int> jBins = eclNOptimalFitRange(hBias, fitFraction);
554  const double lowEdge = hBias->GetBinLowEdge(jBins[0]);
555  const double highEdge = hBias->GetBinLowEdge(jBins[1] + 1);
556  bias = 0.5 * (lowEdge + highEdge);
557  biasSigma = 0.5 * (highEdge - lowEdge);
558  }
559 
560  //------------------------------------------------------------------------------
561  //..Resolution is half the smallest range that contains 68.3% of events.
562  // Speed up the process by only looking among the range that contains 75%.
563  fitFraction = 0.75;
564  std::vector<int> iBins = eclNOptimalFitRange(hEnergy, fitFraction);
565  const double resolution = eclNOptimalResolution(hEnergy, iBins[0], iBins[1]);
566 
567  //..Correct for the bias from background when calculating fractional resolution.
568  // Note that variable resolution = (E_hi - E_lo)/E_gen is dimensionless,
569  // variable peak = E_peak/E_gen is dimensionless, but variable bias has units GeV
570  peak = func->GetParameter(1);
571  const double fractionalResolution = resolution / (peak - bias / genEnergy);
572 
573  //..Record information if this is the best resolution (and is not the existing
574  // resolution case).
575  if (fractionalResolution < bestFractionalResolution and nCrysSumToFit != nCrysBins) {
576  bestFractionalResolution = fractionalResolution;
577  nOpt = nCrysSumToFit;
578  eSumOpt = hEnergy;
579  nFitBins = 1 + iHi - iLo;
580  biasForNOpt = bias;
581  biasSigmaForNOpt = biasSigma;
582  } else if (nCrysSumToFit == nCrysBins) {
583  existingFractionalResolution = fractionalResolution;
584  }
585 
586  //------------------------------------------------------------------------------
587  //..Logic to decide what to do next
588 
589  //..keep checking different N until resolution is this much worse than best value
590  const double resTolerance = 1.05;
591  if (nCrysSumToFit == initialnCrysSumToFit) {
592 
593  //..After testing the previous nOptimal, try one fewer if possible
594  if (nCrysSumToFit > 1) {
595  nCrysSumToFit--;
596  } else {
597  nCrysSumToFit++;
598  }
599  } else if (nCrysSumToFit < initialnCrysSumToFit) {
600 
601  //..Trying fewer crystals. If this is the best so far, try one
602  // fewer, if possible. Otherwise, try more crystals.
603  if (fractionalResolution < resTolerance* bestFractionalResolution and nCrysSumToFit > 1) {
604  nCrysSumToFit--;
605  } else if (initialnCrysSumToFit != nCrysMax) {
606  nCrysSumToFit = initialnCrysSumToFit + 1;
607  } else {
608  nCrysSumToFit = nCrysBins;
609  }
610  } else if (nCrysSumToFit < nCrysBins) { // nCrysSumToFit is always > initialnCrysSumToFit
611 
612  //..Trying more crystals. If this is the best, try one more, if
613  // possible. Otherwise, do the current reconstruction case (nCrysSumToFit = nCrysBins)
614  if (fractionalResolution < resTolerance * bestFractionalResolution and nCrysSumToFit < nCrysMax) {
615  nCrysSumToFit++;
616  } else {
617  nCrysSumToFit = nCrysBins;
618  }
619  } else if (nCrysSumToFit == nCrysBins) {
620 
621  //..This is the current resolution case, so we are done
622  nCrysSumToFit = 0;
623  }
624 
625  } // while(nCrysSumToFit > 0)
626  B2INFO(" ig: " << ig << " ie: " << ie << " initial nOpt: " << initialnCrysSumToFit << " final nOpt: " << nOpt);
627 
628  //-----------------------------------------------------------------------------------
629  //..Store everything in diagnostic histograms
630 
631  //..Extract the function from the nOptimal histogram
632  TF1* funcOpt = (TF1*)eSumOpt->GetFunction("eclNOptimalNovo");
633 
634  nOptimalPerGroup->SetBinContent(ig + 1, ie + 1, nOpt);
635 
636  changeInNOptimal->SetBinContent(ig + 1, ie + 1, nOpt - initialnCrysSumToFit);
637  changeInNOptimal->SetBinError(ig + 1, ie + 1, 0.);
638 
639  biasPerGroup->SetBinContent(ig + 1, ie + 1, biasForNOpt);
640  biasPerGroup->SetBinError(ig + 1, ie + 1, 0.);
641 
642  sigmaBiasPerGroup->SetBinContent(ig + 1, ie + 1, biasSigmaForNOpt);
643  sigmaBiasPerGroup->SetBinError(ig + 1, ie + 1, 0.);
644 
645  binsInFit->SetBinContent(ig + 1, ie + 1, nFitBins);
646  binsInFit->SetBinError(ig + 1, ie + 1, 0.);
647 
648  maxEntriesPerHist->SetBinContent(ig + 1, ie + 1, eSumOpt->GetMaximum());
649  maxEntriesPerHist->SetBinError(ig + 1, ie + 1, 0.);
650 
651  const double peakOpt = funcOpt->GetParameter(1);
652  const double peakOptUnc = funcOpt->GetParError(1);
653  peakPerGroup->SetBinContent(ig + 1, ie + 1, peakOpt);
654  peakPerGroup->SetBinError(ig + 1, ie + 1, peakOptUnc);
655 
656  const double genE = generatedEPerGroup->GetBinContent(ig + 1, ie + 1);
657  const double peakCor = peakOpt - biasForNOpt / genE;
658  fracContainedEPerGroup->SetBinContent(ig + 1, ie + 1, peakCor);
659  fracContainedEPerGroup->SetBinError(ig + 1, ie + 1, peakOptUnc);
660 
661  effSigmaPerGroup->SetBinContent(ig + 1, ie + 1, funcOpt->GetParameter(2));
662  effSigmaPerGroup->SetBinError(ig + 1, ie + 1, funcOpt->GetParError(2));
663 
664  etaPerGroup->SetBinContent(ig + 1, ie + 1, funcOpt->GetParameter(3));
665  etaPerGroup->SetBinError(ig + 1, ie + 1, funcOpt->GetParError(3));
666 
667  fitProbPerGroup->SetBinContent(ig + 1, ie + 1, funcOpt->GetProb());
668  fitProbPerGroup->SetBinError(ig + 1, ie + 1, 0.);
669 
670  resolutionPerGroup->SetBinContent(ig + 1, ie + 1, bestFractionalResolution);
671  resolutionPerGroup->SetBinError(ig + 1, ie + 1, 0.);
672 
673  existingResolutionPerGroup->SetBinContent(ig + 1, ie + 1, existingFractionalResolution);
674  existingResolutionPerGroup->SetBinError(ig + 1, ie + 1, 0.);
675 
676  //..Write out to disk
677  histFile->cd();
678  eSumOpt->Write();
679 
680  }
681  }
682 
683  //-----------------------------------------------------------------------------------
684  //..Write out fit summary histograms
685  histFile->cd();
686  changeInNOptimal->Write();
687  biasPerGroup->Write();
688  sigmaBiasPerGroup->Write();
689  binsInFit->Write();
690  maxEntriesPerHist->Write();
691  peakPerGroup->Write();
692  effSigmaPerGroup->Write();
693  etaPerGroup->Write();
694  fitProbPerGroup->Write();
695  resolutionPerGroup->Write();
696  existingResolutionPerGroup->Write();
697  fracContainedEPerGroup->Write();
698 
699  B2INFO("Wrote fit summary histograms");
700 
701  //-----------------------------------------------------------------------------------
702  //-----------------------------------------------------------------------------------
703  //..Find bias and fraction contained energy in nOpt crystals for the energy bins
704  // adjacent to each of the group / energy points.
705 
706  //..Histograms to store results
707  TH2F* fracContainedAdjacent[2];
708  TH2F* biasAdjacent[2];
709  const TString updown[2] = {"lower", "higher"};
710  for (int ia = 0; ia < 2; ia++) {
711  TString name = "fracContainedAdjacent_" + std::to_string(ia);
712  TString title = "peak fraction of energy contained in nOpt crystals, " + updown[ia] + " E;group;energy point";
713  fracContainedAdjacent[ia] = new TH2F(name, title, nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
714 
715  name = "biasAdjacent_" + std::to_string(ia);
716  title = "bias (GeV) in nOpt crystals, " + updown[ia] + " E;group;energy point";
717  biasAdjacent[ia] = new TH2F(name, title, nCrystalGroups, 0., nCrystalGroups, nEnergies, 0., nEnergies);
718  }
719 
720  //-----------------------------------------------------------------------------------
721  //..Loop over all groups and energy points
722  for (int ig = 0; ig < nCrystalGroups; ig++) {
723  for (int ie = 0; ie < nEnergies; ie++) {
724 
725  //..nOpt for this point
726  const int nOpt = nOptimalPerGroup->GetBinContent(ig + 1, ie + 1);
727 
728  //-----------------------------------------------------------------------------------
729  //..Two adjacent energy points
730  for (int ia = 0; ia < 2; ia++) {
731  const int ieAdj = ie + 2 * ia - 1; // ie +/- 1
732  double eFracPeakAdj = fracContainedEPerGroup->GetBinContent(ig + 1, ie + 1);
733  double biasAdj = biasPerGroup->GetBinContent(ig + 1, ie + 1);
734 
735  //..Need this to be a valid energy point to do anything more
736  if (ieAdj >= 0 and ieAdj < nEnergies) {
737 
738  //----------------------------------------------------------------------------
739  //..Find the bias
740  std::string biasName = "biasSum_" + std::to_string(ig) + "_" + std::to_string(ieAdj);
741  auto biasSum = getObjectPtr<TH2F>(biasName);
742  TH1D* hBias = (TH1D*)biasSum->ProjectionY("hBias", nOpt, nOpt);
743 
744  //..Bias is the mid-point of the range containing 68.3% of events
745  double fitFraction = 0.683;
746  std::vector<int> jBins = eclNOptimalFitRange(hBias, fitFraction);
747  const double lowEdge = hBias->GetBinLowEdge(jBins[0]);
748  const double highEdge = hBias->GetBinLowEdge(jBins[1] + 1);
749  biasAdj = 0.5 * (lowEdge + highEdge);
750 
751  //----------------------------------------------------------------------------
752  //..Get the eSum distribution to be fit
753  std::string name = "eSum_" + std::to_string(ig) + "_" + std::to_string(ieAdj);
754  auto eSum = getObjectPtr<TH2F>(name);
755  TH1D* hEnergy = (TH1D*)eSum->ProjectionY("hEnergy", nOpt, nOpt);
756  TString newName = name + "_" + std::to_string(nOpt);
757  hEnergy->SetName(newName);
758 
759  B2INFO("fit adj ig = " << ig << " ie = " << ie << " ia = " << ia << " " << newName << " " << " entries = " << hEnergy->GetEntries()
760  << " GetMaxiumum = " << hEnergy->GetMaximum());
761 
762  //..Rebin if the maximum bin has too few entries
763  const double minPeakValue = 300.;
764  while (hEnergy->GetMaximum() < minPeakValue) {hEnergy->Rebin(2);}
765 
766  //..Find 50% range for Novo fit. Rebin if there are too many bins
767  fitFraction = 0.5;
768  int iLo = 1;
769  int iHi = hEnergy->GetNbinsX();
770  const int maxBinsToFit = 59;
771  while ((iHi - iLo) > maxBinsToFit) {
772  std::vector<int> iBins = eclNOptimalFitRange(hEnergy, fitFraction);
773  iLo = iBins[0];
774  iHi = iBins[1];
775  if ((iHi - iLo) > maxBinsToFit) {hEnergy->Rebin(2);}
776  }
777 
778  //..Fit parameters
779  const double fitlow = hEnergy->GetBinLowEdge(iLo);
780  const double fithigh = hEnergy->GetBinLowEdge(iHi + 1);
781  double normalization = hEnergy->GetMaximum();
782  const int iMax = hEnergy->GetMaximumBin();
783  double peak = hEnergy->GetBinLowEdge(iMax);
784  double effSigma = 0.5 * (fithigh - fitlow);
785  double eta = 0.4; // typical value for good fits
786 
787  func->SetParameters(normalization, peak, effSigma, eta);
788  func->SetParNames("normalization", "peak", "effSigma", "eta");
789 
790  //..Parameter ranges
791  func->SetParLimits(1, fitlow, fithigh);
792  func->SetParLimits(2, 0., 2.*effSigma);
793  func->SetParLimits(3, -1, 3);
794 
795  //..If there is only one crystal, fix eta to a special value
796  if (nOpt == 1) {
797  const double etaForOneCrystal = 0.95;
798  func->SetParameter(3, etaForOneCrystal);
799  func->SetParLimits(3, etaForOneCrystal, etaForOneCrystal);
800  }
801 
802  //..Fit
803  hEnergy->Fit(func, "LIEQ", "", fitlow, fithigh);
804 
805  //..Fraction of contained energy = peak of fit corrected for bias
806  const double peakAdj = func->GetParameter(1);
807  const double genE = generatedEPerGroup->GetBinContent(ig + 1, ieAdj + 1);
808  eFracPeakAdj = peakAdj - biasAdj / genE;
809  }
810 
811  //..Store
812  fracContainedAdjacent[ia]->SetBinContent(ig + 1, ie + 1, eFracPeakAdj);
813  biasAdjacent[ia]->SetBinContent(ig + 1, ie + 1, biasAdj);
814  } // loop over adjacent energy points
815 
816  B2INFO(" ig " << ig << " ie " << ie << " eFrac (3): "
817  << fracContainedAdjacent[0]->GetBinContent(ig + 1, ie + 1) << " "
818  << fracContainedEPerGroup->GetBinContent(ig + 1, ie + 1) << " "
819  << fracContainedAdjacent[1]->GetBinContent(ig + 1, ie + 1)
820  << " biases (3): "
821  << biasAdjacent[0]->GetBinContent(ig + 1, ie + 1) << " "
822  << biasPerGroup->GetBinContent(ig + 1, ie + 1) << " "
823  << biasAdjacent[1]->GetBinContent(ig + 1, ie + 1)
824  );
825  } // loop over ie
826  } // loop over ig
827 
828  //-----------------------------------------------------------------------------------
829  //..Write out histograms with results for adjacent energy points
830  histFile->cd();
831  fracContainedAdjacent[0]->Write();
832  fracContainedAdjacent[1]->Write();
833  biasAdjacent[0]->Write();
834  biasAdjacent[1]->Write();
835 
836  B2INFO("Wrote adjacent energy point summary histograms");
837 
838 
839  //-----------------------------------------------------------------------------------
840  //-----------------------------------------------------------------------------------
841  //..Prepare the payload contents
842  //..Upper energy boundaries are the mid-point of the log energies
843  auto boundaryE = create2Dvector<float>(nLeakReg, nEnergies);
844  for (int ireg = 0; ireg < nLeakReg; ireg++) {
845  B2INFO("Generated energies and boundaries for region = " << ireg);
846  for (int ie = 0; ie < nEnergies - 1; ie++) {
847  double logE0 = log(generatedE[ireg][ie]);
848  double logE1 = log(generatedE[ireg][ie + 1]);
849  double logBoundary = 0.5 * (logE0 + logE1);
850  boundaryE[ireg][ie] = exp(logBoundary);
851  B2INFO(" " << ie << " " << generatedE[ireg][ie] << " " << boundaryE[ireg][ie] << " GeV");
852  }
853 
854  //..Last boundary is an arbitrarily large number
855  boundaryE[ireg][nEnergies - 1] = 9999.;
856  B2INFO(" " << nEnergies - 1 << " " << generatedE[ireg][nEnergies - 1] << " " << boundaryE[ireg][nEnergies - 1] << " GeV");
857  }
858 
859  //..Group number of each cellID
860  std::vector<int> groupNumber;
861  for (int cellID = 1; cellID <= ECLElementNumbers::c_NCrystals; cellID++) {
862  const int iGroup = (int)(0.5 + groupNumberOfEachCellID->GetBinContent(cellID));
863  groupNumber.push_back(iGroup);
864  }
865 
866  //..Copy results for each group into the payload histogram
867  TH2F nOptimal2D("nOptimal2D", "Optimal nCrys, energy bin vs group number", nCrystalGroups, 0, nCrystalGroups, nEnergies, 0.,
868  nEnergies);
869  for (int ig = 0; ig < nCrystalGroups; ig++) {
870  for (int ie = 0; ie < nEnergies; ie++) {
871  double nOpt = nOptimalPerGroup->GetBinContent(ig + 1, ie + 1);
872  nOptimal2D.SetBinContent(ig + 1, ie + 1, nOpt);
873  }
874  }
875 
876  //..2D histograms for peak and bias corrections.
877  // Note that these have 3 x bins per group = nominal energy plus adjacent energies.
878  TH2F peakFracEnergy("peakFracEnergy", "peak contained energy over generated E, energy bin vs group number", 3 * nCrystalGroups, 0,
879  nCrystalGroups, nEnergies, 0., nEnergies);
880  TH2F bias("bias", "median bias (GeV), energy bin vs group number", 3 * nCrystalGroups, 0, nCrystalGroups, nEnergies, 0., nEnergies);
881  TH2F logPeakEnergy("logPeakEnergy", "log peak Energy (GeV), energy bin vs group number", 3 * nCrystalGroups, 0, nCrystalGroups,
882  nEnergies, 0., nEnergies);
883  for (int ig = 0; ig < nCrystalGroups; ig++) {
884  for (int ie = 0; ie < nEnergies; ie++) {
885  const int iy = ie + 1;
886  const int ix = 1 + 3 * ig; // three bins per group in payload histograms
887 
888  //..Peak fractional energy and log peak contained energy (GeV)
889 
890  //..Nominal ig and and ie
891  double peakAdj = fracContainedEPerGroup->GetBinContent(ig + 1, ie + 1);
892  const double genE = generatedEPerGroup->GetBinContent(ig + 1, ie + 1);
893  double logE = log(genE * peakAdj);
894 
895  peakFracEnergy.SetBinContent(ix, iy, peakAdj);
896  logPeakEnergy.SetBinContent(ix, iy, logE);
897 
898  //..Lower E adjacent point
899  double peakAdj0 = peakAdj;
900  double logE0 = logE;
901  if (ie > 1) {
902  peakAdj0 = fracContainedAdjacent[0]->GetBinContent(ig + 1, ie + 1);
903  const double genE0 = generatedEPerGroup->GetBinContent(ig + 1, ie);
904  logE0 = log(genE0 * peakAdj0);
905  }
906 
907  peakFracEnergy.SetBinContent(ix + 1, iy, peakAdj0);
908  logPeakEnergy.SetBinContent(ix + 1, iy, logE0);
909 
910  //..Higher E adjacent point
911  double peakAdj1 = peakAdj;
912  double logE1 = logE;
913  if (ie < nEnergies - 1) {
914  peakAdj1 = fracContainedAdjacent[1]->GetBinContent(ig + 1, ie + 1);
915  const double genE1 = generatedEPerGroup->GetBinContent(ig + 1, ie + 2);
916  logE1 = log(genE1 * peakAdj1);
917  }
918 
919  peakFracEnergy.SetBinContent(ix + 2, iy, peakAdj1);
920  logPeakEnergy.SetBinContent(ix + 2, iy, logE1);
921 
922  //..Bias
923  double medianBias = biasPerGroup->GetBinContent(ig + 1, ie + 1);
924  bias.SetBinContent(ix, iy, medianBias);
925  medianBias = biasAdjacent[0]->GetBinContent(ig + 1, ie + 1);
926  bias.SetBinContent(ix + 1, iy, medianBias);
927  medianBias = biasAdjacent[1]->GetBinContent(ig + 1, ie + 1);
928  bias.SetBinContent(ix + 2, iy, medianBias);
929  }
930  }
931 
932  //..Store the histograms
933  histFile->cd();
934  nOptimal2D.Write();
935  peakFracEnergy.Write();
936  logPeakEnergy.Write();
937  bias.Write();
938  histFile->Close();
939 
940  //-----------------------------------------------------------------------------------
941  //..The payload itself
942  ECLnOptimal* optimalNCrys = new ECLnOptimal();
943 
944  //..Energy boundaries
945  for (int ireg = 0; ireg < nLeakReg; ireg++) {
946  std::vector<float> eUpperBoundaries;
947  for (int ie = 0; ie < nEnergies; ie++) {eUpperBoundaries.push_back(boundaryE[ireg][ie]);}
948  if (ireg == 0) {
949  optimalNCrys->setUpperBoundariesFwd(eUpperBoundaries);
950  } else if (ireg == 1) {
951  optimalNCrys->setUpperBoundariesBrl(eUpperBoundaries);
952  } else {
953  optimalNCrys->setUpperBoundariesBwd(eUpperBoundaries);
954  }
955  }
956 
957  //..Group number of each cellID
958  optimalNCrys->setGroupNumber(groupNumber);
959 
960  //..nOptimal histogram
961  optimalNCrys->setNOptimal(nOptimal2D);
962 
963  //..Peak and bias correction histograms
964  optimalNCrys->setPeakFracEnergy(peakFracEnergy);
965  optimalNCrys->setBias(bias);
966  optimalNCrys->setLogPeakEnergy(logPeakEnergy);
967 
968  //..Save the calibration
969  saveCalibration(optimalNCrys, "ECLnOptimal");
970  B2RESULT("eclNOptimalAlgorithm: successfully stored payload ECLnOptimal");
971 
972  //..Done
973  return c_OK;
974 }
975 
976 
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_NotEnoughData
Needs more data =2 in Python.
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
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
virtual EResult calibrate() override
..Run algorithm on events
DB object to store the optimal number of crystals to be used in a cluster energy sum,...
Definition: ECLnOptimal.h:23
void setNOptimal(const TH2F &nOptimal)
Set the 2D histogram of nOptimal.
Definition: ECLnOptimal.h:92
void setLogPeakEnergy(const TH2F &logPeakEnergy)
Set the 2D histogram of log of peak contained energy in GeV.
Definition: ECLnOptimal.h:101
void setGroupNumber(const std::vector< int > &groupNumber)
Set the vector of group numbers for each crystal.
Definition: ECLnOptimal.h:89
void setUpperBoundariesFwd(const std::vector< float > &eUpperBoundariesFwd)
Set vector of energies that specify energy ranges in the forward endcap.
Definition: ECLnOptimal.h:80
void setBias(const TH2F &bias)
Set the 2D histogram of beam background bias (reconstructed - true) (GeV)
Definition: ECLnOptimal.h:98
void setUpperBoundariesBrl(const std::vector< float > &eUpperBoundariesBrl)
Set vector of energies that specify energy ranges in the barrel.
Definition: ECLnOptimal.h:83
void setUpperBoundariesBwd(const std::vector< float > &eUpperBoundariesBwd)
Set vector of energies that specify energy ranges in the backward endcap.
Definition: ECLnOptimal.h:86
void setPeakFracEnergy(const TH2F &peakFracEnergy)
Set the 2D histogram of peak fractional contained energy.
Definition: ECLnOptimal.h:95
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 updateEvent()
Updates all intra-run dependent objects.
Definition: DBStore.cc:142
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
const int c_NCrystals
Number of crystals.
bool isBackward(int cellId)
Check whether the crystal is in backward ECL.
bool isForward(int cellId)
Check whether the crystal is in forward ECL.
Abstract base class for different kinds of events.