2 #include <ecl/calibration/eclGammaGammaEAlgorithm.h>
3 #include <ecl/dbobjects/ECLCrystalCalib.h>
17 double eclGammaGammaNovoConst(
double* x,
double* par)
22 double width = par[2];
23 double sln4 = sqrt(log(4));
24 double y = par[3] * sln4;
25 double tail = -log(y + sqrt(1 + y * y)) / sln4;
27 if (TMath::Abs(tail) < 1.e-7) {
28 qc = 0.5 * TMath::Power(((x[0] - peak) / width), 2);
30 double qa = tail * sqrt(log(4.));
31 double qb = sinh(qa) / qa;
32 double qx = (x[0] - peak) / width * qb;
33 double qy = 1. + tail * qx;
36 qc = 0.5 * (TMath::Power((log(qy) / tail), 2) + tail * tail);
40 return par[0] * exp(-qc) + par[4];
48 "Perform energy calibration of ecl crystals by fitting a Novosibirsk function to energy deposited by photons in e+e- --> gamma gamma"
56 const double limitTol = 0.0005;
57 const double minFitLimit = 1e-25;
58 const double minFitProbIter = 1e-8;
59 const double constRatio = 0.5;
60 const double peakMin(0.4), peakMax(2.2);
61 const double peakTol = limitTol * (peakMax - peakMin);
62 const double effSigMin(0.02), effSigMax(0.4);
63 const double effSigTol = limitTol * (effSigMax - effSigMin);
64 const double etaNom(0.41);
65 const double etaMin(0.), etaMax(5.0);
66 const double etaTol = limitTol * (etaMax - etaMin);
67 const double constTol = 0.001;
74 B2INFO(
"eclGammaGammaAlgorithm parameters:");
90 dummy = (TH1F*)gROOT->FindObject(
"IntegralVsCrysID");
91 if (dummy) {
delete dummy;}
92 dummy = (TH1F*)gROOT->FindObject(
"AverageExpECrys");
93 if (dummy) {
delete dummy;}
94 dummy = (TH1F*)gROOT->FindObject(
"AverageElecCalib");
95 if (dummy) {
delete dummy;}
96 dummy = (TH1F*)gROOT->FindObject(
"AverageInitCalib");
97 if (dummy) {
delete dummy;}
101 auto EnVsCrysID = getObjectPtr<TH2F>(
"EnVsCrysID");
102 auto ExpEvsCrys = getObjectPtr<TH1F>(
"ExpEvsCrys");
103 auto ElecCalibvsCrys = getObjectPtr<TH1F>(
"ElecCalibvsCrys");
104 auto InitialCalibvsCrys = getObjectPtr<TH1F>(
"InitialCalibvsCrys");
105 auto CalibEntriesvsCrys = getObjectPtr<TH1F>(
"CalibEntriesvsCrys");
110 TH1F* IntegralVsCrysID =
new TH1F(
"IntegralVsCrysID",
"Integral of EnVsCrysID for each crystal;crystal ID;Entries", 8736, 0, 8736);
111 TH1F* AverageExpECrys =
new TH1F(
"AverageExpECrys",
"Average expected E per crys from collector;Crystal ID;Energy (GeV)", 8736, 0,
113 TH1F* AverageElecCalib =
new TH1F(
"AverageElecCalib",
"Average electronics calib const vs crystal;Crystal ID;Calibration constant",
115 TH1F* AverageInitCalib =
new TH1F(
"AverageInitCalib",
"Average initial calib const vs crystal;Crystal ID;Calibration constant",
118 for (
int crysID = 0; crysID < 8736; crysID++) {
119 TH1D* hEnergy = EnVsCrysID->ProjectionY(
"hEnergy", crysID + 1, crysID + 1);
120 int Integral = hEnergy->Integral();
121 IntegralVsCrysID->SetBinContent(crysID + 1, Integral);
123 double TotEntries = CalibEntriesvsCrys->GetBinContent(crysID + 1);
125 double expectedE = 0.;
126 if (TotEntries > 0.) {expectedE = ExpEvsCrys->GetBinContent(crysID + 1) / TotEntries;}
127 AverageExpECrys->SetBinContent(crysID + 1, expectedE);
129 double calibconst = 0.;
130 if (TotEntries > 0.) {calibconst = ElecCalibvsCrys->GetBinContent(crysID + 1) / TotEntries;}
131 AverageElecCalib->SetBinContent(crysID + 1, calibconst);
134 if (TotEntries > 0.) {calibconst = InitialCalibvsCrys->GetBinContent(crysID + 1) / TotEntries;}
135 AverageInitCalib->SetBinContent(crysID + 1, calibconst);
141 TFile* histfile =
new TFile(fName,
"recreate");
143 IntegralVsCrysID->Write();
144 AverageExpECrys->Write();
145 AverageElecCalib->Write();
146 AverageInitCalib->Write();
151 B2INFO(
"eclGammaGammaEAlgorithm has not been asked to perform fits; copying input histograms and quitting");
158 bool sufficientData =
true;
160 if (IntegralVsCrysID->GetBinContent(crysID + 1) <
m_minEntries) {
161 if (
m_storeConst == 1) {B2INFO(
"eclGammaGammaEAlgorithm: crystal " << crysID <<
" has insufficient statistics: " << IntegralVsCrysID->GetBinContent(crysID + 1) <<
". Requirement is " <<
m_minEntries);}
162 sufficientData =
false;
177 TH1F* CalibVsCrysID =
new TH1F(
"CalibVsCrysID",
"Calibration constant vs crystal ID;crystal ID;counts per GeV", 8736, 0, 8736);
178 TH1F* ExpEnergyperCrys =
new TH1F(
"ExpEnergyperCrys",
"Expected energy per crystal;Crystal ID;Peak energy (GeV)", 8736, 0, 8736);
181 TH1F* PeakVsCrysID =
new TH1F(
"PeakVsCrysID",
"Peak of Novo fit vs crystal ID;crystal ID;Peak normalized energy", 8736, 0, 8736);
182 TH1F* EdgeVsCrysID =
new TH1F(
"EdgeVsCrysID",
"Upper edge of Novo fit vs crystal ID;crystal ID;Maximum normalized energy", 8736, 0,
184 TH1F* effSigVsCrysID =
new TH1F(
"effSigVsCrysID",
"effSigma vs crystal ID;crystal ID;sigma)", 8736, 0, 8736);
185 TH1F* etaVsCrysID =
new TH1F(
"etaVsCrysID",
"eta vs crystal ID;crystal ID;Novo eta parameter", 8736, 0, 8736);
186 TH1F* constVsCrysID =
new TH1F(
"constVsCrysID",
"fit constant vs crystal ID;crystal ID;fit constant", 8736, 0, 8736);
187 TH1F* normVsCrysID =
new TH1F(
"normVsCrysID",
"Novosibirsk normalization vs crystal ID;crystal ID;normalization", 8736, 0, 8736);
188 TH1F* fitLimitVsCrysID =
new TH1F(
"fitLimitVsCrysID",
"fit range lower limit vs crystal ID;crystal ID;upper fit limit", 8736, 0,
190 TH1F* StatusVsCrysID =
new TH1F(
"StatusVsCrysID",
"Fit status vs crystal ID;crystal ID;Fit status", 8736, 0, 8736);
191 TH1F* FitProbVsCrysID =
new TH1F(
"FitProbVsCrysID",
"Fit probability vs crystal id;crystal ID;Fit probability", 8736, 0, 8736);
194 TH1F* hStatus =
new TH1F(
"hStatus",
"Fit status", 25, -5, 20);
195 TH1F* hPeak =
new TH1F(
"hPeak",
"Peaks of normalized energy distributions, successful fits;Peak of Novosibirsk fit", 200, 0.8, 1.2);
196 TH1F* fracPeakUnc =
new TH1F(
"fracPeakUnc",
"Fractional uncertainty on peak uncertainty, successful fits;Uncertainty on peak", 100,
198 TH1F* nIterations =
new TH1F(
"nIterations",
"Number of times histogram was fit;Number of iterations", 20, -0.5, 19.5);
203 bool allFitsOK =
true;
207 TString name =
"Enormalized";
209 TH1D* hEnergy = EnVsCrysID->ProjectionY(name, crysID + 1, crysID + 1);
212 double histMin = hEnergy->GetXaxis()->GetXmin();
213 double histMax = hEnergy->GetXaxis()->GetXmax();
214 TF1* func =
new TF1(
"eclGammaGammaNovoConst", eclGammaGammaNovoConst, histMin, histMax, 5);
215 func->SetParNames(
"normalization",
"peak",
"effSigma",
"eta",
"const");
216 func->SetParLimits(1, peakMin, peakMax);
217 func->SetParLimits(2, effSigMin, effSigMax);
218 func->SetParLimits(3, etaMin, etaMax);
219 func->SetParLimits(4, 0., hEnergy->GetMaximum());
222 hEnergy->GetXaxis()->SetRangeUser(peakMin, peakMax);
223 int maxBin = hEnergy->GetMaximumBin();
224 double peakE = hEnergy->GetBinLowEdge(maxBin);
225 double peakEUnc = 0.;
226 double normalization = hEnergy->GetMaximum();
228 double effSigma = hEnergy->GetRMS();
229 double sigmaUnc = 0.;
230 hEnergy->GetXaxis()->SetRangeUser(histMin, histMax);
233 double fitlow = peakE - effSigma;
234 double fithigh = histMax;
239 double constant = 0.01 * normalization;
240 double constUnc = 0.;
243 double dIter = 0.1 * (histMax - histMin) / hEnergy->GetNbinsX();
245 double fitProbDefault(0.);
246 double lowold(0.), lowoldold(0.);
247 bool fixConst =
false;
249 bool fitHist = IntegralVsCrysID->GetBinContent(crysID + 1) >=
m_minEntries;
256 func->SetParameters(normalization, peakE, effSigma, eta, constant);
257 if (fixConst) { func->FixParameter(4, 0); }
260 hEnergy->Fit(func,
"LIQ",
"", fitlow, fithigh);
263 normalization = func->GetParameter(0);
264 normUnc = func->GetParError(0);
265 peakE = func->GetParameter(1);
266 peakEUnc = func->GetParError(1);
267 effSigma = func->GetParameter(2);
268 sigmaUnc = func->GetParError(2);
269 eta = func->GetParameter(3);
270 etaUnc = func->GetParError(3);
271 constant = func->GetParameter(4);
272 constUnc = func->GetParError(4);
273 fitProbDefault = func->GetProb();
276 double peak = func->Eval(peakE) - constant;
277 double tRatio = (func->Eval(fitlow) - constant) / peak;
278 if (tRatio < m_tRatioMin || tRatio >
m_tRatioMax) {
282 fitlow = func->GetX(targetY, histMin, peakE);
286 if (abs(fitlow - lowoldold) < dIter) {fitlow = 0.5 * (lowold + lowoldold); }
289 if (nIter >
m_maxIterations - 3) {fitlow = 0.33333 * (fitlow + lowold + lowoldold); }
293 if (constant < constTol && !fixConst) {
301 B2DEBUG(10, crysID <<
" " << nIter <<
" " << peakE <<
" " << constant <<
" " << tRatio <<
" " << fitlow);
308 int lowbin = hEnergy->GetXaxis()->FindBin(fitlow);
309 int highbin = hEnergy->GetXaxis()->FindBin(fithigh);
311 if (fixConst) {npar = 4;}
314 double binwidth = hEnergy->GetBinWidth(1);
315 for (
int ib = lowbin; ib <= highbin; ib++) {
316 double xlow = hEnergy->GetBinLowEdge(ib);
317 double yexp = func->Integral(xlow, xlow + binwidth) / binwidth;
320 if (yexp > constTol) {
321 double yobs = hEnergy->GetBinContent(ib);
323 if (yexp < 0.9999 && yobs > yexp) {dnom = yobs;}
324 double dchi2 = (yexp - yobs) * (yexp - yobs) / dnom;
329 fitProb = TMath::Prob(chisq, ndeg);
338 if (normalization < constRatio * constant) {iStatus =
noPeak;}
341 if (fitProb <= minFitLimit || (fitProb < minFitProbIter && iStatus ==
iterations)) {iStatus =
poorFit;}
344 if ((peakE < peakMin + peakTol) || (peakE > peakMax - peakTol)) {iStatus =
atLimit;}
345 if ((effSigma < effSigMin + effSigTol) || (effSigma > effSigMax - effSigTol)) {iStatus =
atLimit;}
346 if ((eta < etaMin + etaTol) || (eta > etaMax - etaTol)) {iStatus =
atLimit;}
349 if (nIter == 0) {iStatus =
notFit;}
353 double upperEdge = peakE;
354 double edgeUnc = peakEUnc;
362 int iLow = hEnergy->GetXaxis()->FindBin(peakE) + 1;
363 int iHigh = hEnergy->GetNbinsX();
365 for (
int ibin = iLow; ibin < iHigh; ibin++) {
366 double xc = hEnergy->GetBinCenter(ibin);
367 if (func->Eval(xc) > targetY) {iLast = ibin;}
369 double xLow = hEnergy->GetBinCenter(iLast);
370 double xHigh = hEnergy->GetBinCenter(iLast + 1);
374 upperEdge = func->GetX(targetY, xLow, xHigh);
377 }
else if (iStatus >
notFit) {
381 int thisBin = hEnergy->GetBinContent(1);
382 for (
int ibin = 2; ibin < hEnergy->GetNbinsX(); ibin++) {
383 int prevBin = thisBin;
384 thisBin = hEnergy->GetBinContent(ibin);
385 if (thisBin > 0 && thisBin + prevBin >= 2) {iLast = ibin;}
387 if (iLast > 0) {upperEdge = hEnergy->GetBinCenter(iLast);}
392 int histbin = crysID + 1;
393 PeakVsCrysID->SetBinContent(histbin, peakE);
394 PeakVsCrysID->SetBinError(histbin, peakEUnc);
395 EdgeVsCrysID->SetBinContent(histbin, upperEdge);
396 EdgeVsCrysID->SetBinError(histbin, edgeUnc);
397 effSigVsCrysID->SetBinContent(histbin, effSigma);
398 effSigVsCrysID->SetBinError(histbin, sigmaUnc);
399 etaVsCrysID->SetBinContent(histbin, eta);
400 etaVsCrysID->SetBinError(histbin, etaUnc);
401 constVsCrysID->SetBinContent(histbin, constant);
402 constVsCrysID->SetBinError(histbin, constUnc);
403 normVsCrysID->SetBinContent(histbin, normalization);
404 normVsCrysID->SetBinError(histbin, normUnc);
405 fitLimitVsCrysID->SetBinContent(histbin, fitlow);
406 fitLimitVsCrysID->SetBinError(histbin, 0);
407 StatusVsCrysID->SetBinContent(histbin, iStatus);
408 StatusVsCrysID->SetBinError(histbin, 0);
409 FitProbVsCrysID->SetBinContent(histbin, fitProb);
410 FitProbVsCrysID->SetBinError(histbin, 0);
413 hStatus->Fill(iStatus);
414 nIterations->Fill(nIter);
417 fracPeakUnc->Fill(peakEUnc / peakE);
421 B2INFO(
"cellID " << crysID + 1 <<
" status = " << iStatus <<
" fit probability = " << fitProb <<
" default prob = " <<
430 for (
int crysID = 0; crysID < 8736; crysID++) {
431 int histbin = crysID + 1;
432 double fitstatus = StatusVsCrysID->GetBinContent(histbin);
433 double upperEdge = EdgeVsCrysID->GetBinContent(histbin);
434 double fracEdgeUnc = EdgeVsCrysID->GetBinError(histbin) / upperEdge;
441 B2INFO(
"eclGammaGammaEAlgorithm: cellID " << histbin <<
" is not a successful fit. Status = " << fitstatus);
448 double inputExpE = abs(AverageExpECrys->GetBinContent(histbin));
449 ExpEnergyperCrys->SetBinContent(histbin, inputExpE * upperEdge);
450 ExpEnergyperCrys->SetBinError(histbin, fracEdgeUnc * inputExpE * upperEdge);
454 double inputCalib = abs(AverageInitCalib->GetBinContent(histbin));
455 CalibVsCrysID->SetBinContent(histbin, inputCalib / upperEdge);
456 CalibVsCrysID->SetBinError(histbin, fracEdgeUnc * inputCalib / upperEdge);
462 bool DBsuccess =
false;
468 std::vector<float> tempE;
469 std::vector<float> tempUnc;
470 for (
int crysID = 0; crysID < 8736; crysID++) {
471 tempE.push_back(ExpEnergyperCrys->GetBinContent(crysID + 1));
472 tempUnc.push_back(ExpEnergyperCrys->GetBinError(crysID + 1));
477 B2INFO(
"eclCosmicEAlgorithm: successfully stored expected energies ECLExpGammaGammaE");
482 std::vector<float> tempCalib;
483 std::vector<float> tempCalibUnc;
484 for (
int crysID = 0; crysID < 8736; crysID++) {
485 tempCalib.push_back(CalibVsCrysID->GetBinContent(crysID + 1));
486 tempCalibUnc.push_back(CalibVsCrysID->GetBinError(crysID + 1));
491 B2INFO(
"eclGammaGammaEAlgorithm: successfully stored ECLCrystalEnergyGammaGamma calibration constants");
498 PeakVsCrysID->Write();
499 EdgeVsCrysID->Write();
500 effSigVsCrysID->Write();
501 etaVsCrysID->Write();
502 constVsCrysID->Write();
503 normVsCrysID->Write();
504 fitLimitVsCrysID->Write();
505 StatusVsCrysID->Write();
506 FitProbVsCrysID->Write();
508 fracPeakUnc->Write();
509 nIterations->Write();
514 ExpEnergyperCrys->Write();
516 CalibVsCrysID->Write();
522 dummy = (TH1F*)gROOT->FindObject(
"PeakVsCrysID");
delete dummy;
523 dummy = (TH1F*)gROOT->FindObject(
"EdgeVsCrysID");
delete dummy;
524 dummy = (TH1F*)gROOT->FindObject(
"effSigVsCrysID");
delete dummy;
525 dummy = (TH1F*)gROOT->FindObject(
"etaVsCrysID");
delete dummy;
526 dummy = (TH1F*)gROOT->FindObject(
"constVsCrysID");
delete dummy;
527 dummy = (TH1F*)gROOT->FindObject(
"normVsCrysID");
delete dummy;
528 dummy = (TH1F*)gROOT->FindObject(
"fitLimitVsCrysID");
delete dummy;
529 dummy = (TH1F*)gROOT->FindObject(
"StatusVsCrysID");
delete dummy;
530 dummy = (TH1F*)gROOT->FindObject(
"FitProbVsCrysID");
delete dummy;
531 dummy = (TH1F*)gROOT->FindObject(
"fracPeakUnc");
delete dummy;
532 dummy = (TH1F*)gROOT->FindObject(
"nIterations");
delete dummy;
533 dummy = (TH1F*)gROOT->FindObject(
"hStatus");
delete dummy;
534 dummy = (TH1F*)gROOT->FindObject(
"ExpEnergyperCrys");
delete dummy;
535 dummy = (TH1F*)gROOT->FindObject(
"CalibVsCrysID");
delete dummy;
541 B2INFO(
"eclGammaGammaEAlgorithm performed fits but was not asked to store contants");
543 }
else if (!DBsuccess) {
544 if (
m_findExpValues) { B2INFO(
"eclGammaGammaEAlgorithm: failed to store expected values"); }
545 else { B2INFO(
"eclGammaGammaEAlgorithm: failed to store calibration constants"); }