9 #include <ecl/calibration/eclMuMuEAlgorithm.h>
10 #include <ecl/dbobjects/ECLCrystalCalib.h>
23 double eclNovoConst(
double* x,
double* par)
28 double width = par[2];
29 double sln4 = sqrt(log(4));
30 double y = par[3] * sln4;
31 double tail = -log(y + sqrt(1 + y * y)) / sln4;
33 if (TMath::Abs(tail) < 1.e-7) {
34 qc = 0.5 * TMath::Power(((x[0] - peak) / width), 2);
36 double qa = tail * sqrt(log(4.));
37 double qb = sinh(qa) / qa;
38 double qx = (x[0] - peak) / width * qb;
39 double qy = 1. + tail * qx;
42 qc = 0.5 * (TMath::Power((log(qy) / tail), 2) + tail * tail);
46 return par[0] * exp(-qc) + par[4];
50 eclMuMuEAlgorithm::eclMuMuEAlgorithm():
CalibrationAlgorithm(
"eclMuMuECollector"), cellIDLo(1), cellIDHi(8736), minEntries(150),
51 nToRebin(1000), tRatioMin(0.05), tRatioMax(0.40), lowerEdgeThresh(0.10), performFits(true), findExpValues(false), storeConst(0)
54 "Perform energy calibration of ecl crystals by fitting a Novosibirsk function to energy deposited by muons"
62 double limitTol = 0.0005;
63 double minFitLimit = 1e-25;
64 double peakMin(0.4), peakMax(2.2);
65 double peakTol = limitTol * (peakMax - peakMin);
66 double effSigMin(0.02), effSigMax(0.2);
67 double effSigTol = limitTol * (effSigMax - effSigMin);
69 double etaMin(-1.), etaMax(0.);
70 double etaTol = limitTol * (etaMax - etaMin);
77 B2INFO(
"eclMuMuEAlgorithm parameters:");
91 dummy = (TH1F*)gROOT->FindObject(
"IntegralVsCrysID");
92 if (dummy) {
delete dummy;}
93 dummy = (TH1F*)gROOT->FindObject(
"AverageExpECrys");
94 if (dummy) {
delete dummy;}
95 dummy = (TH1F*)gROOT->FindObject(
"AverageElecCalib");
96 if (dummy) {
delete dummy;}
97 dummy = (TH1F*)gROOT->FindObject(
"AverageInitCalib");
98 if (dummy) {
delete dummy;}
102 auto TrkPerCrysID = getObjectPtr<TH1F>(
"TrkPerCrysID");
103 auto EnVsCrysID = getObjectPtr<TH2F>(
"EnVsCrysID");
104 auto ExpEvsCrys = getObjectPtr<TH1F>(
"ExpEvsCrys");
105 auto ElecCalibvsCrys = getObjectPtr<TH1F>(
"ElecCalibvsCrys");
106 auto InitialCalibvsCrys = getObjectPtr<TH1F>(
"InitialCalibvsCrys");
107 auto CalibEntriesvsCrys = getObjectPtr<TH1F>(
"CalibEntriesvsCrys");
108 auto RawDigitAmpvsCrys = getObjectPtr<TH2F>(
"RawDigitAmpvsCrys");
109 auto RawDigitTimevsCrys = getObjectPtr<TH2F>(
"RawDigitTimevsCrys");
110 auto hitCrysVsExtrapolatedCrys = getObjectPtr<TH2F>(
"hitCrysVsExtrapolatedCrys");
115 TH1F* IntegralVsCrysID =
new TH1F(
"IntegralVsCrysID",
"Integral of EnVsCrysID for each crystal;crystal ID;Entries", 8736, 0, 8736);
116 TH1F* AverageExpECrys =
new TH1F(
"AverageExpECrys",
"Average expected E per crys from collector;Crystal ID;Energy (GeV)", 8736, 0,
118 TH1F* AverageElecCalib =
new TH1F(
"AverageElecCalib",
"Average electronics calib const vs crystal;Crystal ID;Calibration constant",
120 TH1F* AverageInitCalib =
new TH1F(
"AverageInitCalib",
"Average initial calib const vs crystal;Crystal ID;Calibration constant",
123 for (
int crysID = 0; crysID < 8736; crysID++) {
124 TH1D* hEnergy = EnVsCrysID->ProjectionY(
"hEnergy", crysID + 1, crysID + 1);
125 int Integral = hEnergy->Integral();
126 IntegralVsCrysID->SetBinContent(crysID + 1, Integral);
128 double TotEntries = CalibEntriesvsCrys->GetBinContent(crysID + 1);
130 double expectedE = 0.;
131 if (TotEntries > 0.) {expectedE = ExpEvsCrys->GetBinContent(crysID + 1) / TotEntries;}
132 AverageExpECrys->SetBinContent(crysID + 1, expectedE);
134 double calibconst = 0.;
135 if (TotEntries > 0.) {calibconst = ElecCalibvsCrys->GetBinContent(crysID + 1) / TotEntries;}
136 AverageElecCalib->SetBinContent(crysID + 1, calibconst);
139 if (TotEntries > 0.) {calibconst = InitialCalibvsCrys->GetBinContent(crysID + 1) / TotEntries;}
140 AverageInitCalib->SetBinContent(crysID + 1, calibconst);
145 TFile* histfile =
new TFile(
"eclMuMuEAlgorithm.root",
"recreate");
146 TrkPerCrysID->Write();
148 IntegralVsCrysID->Write();
149 AverageExpECrys->Write();
150 AverageElecCalib->Write();
151 AverageInitCalib->Write();
152 RawDigitAmpvsCrys->Write();
153 RawDigitTimevsCrys->Write();
154 hitCrysVsExtrapolatedCrys->Write();
159 B2RESULT(
"eclMuMuEAlgorithm has not been asked to perform fits; copying input histograms and quitting");
166 bool sufficientData =
true;
168 if (IntegralVsCrysID->GetBinContent(crysID + 1) <
minEntries) {
169 if (
storeConst == 1) {B2RESULT(
"eclMuMuEAlgorithm: crystal " << crysID <<
" has insufficient statistics: " << IntegralVsCrysID->GetBinContent(crysID + 1) <<
". Requirement is " <<
minEntries);}
170 sufficientData =
false;
185 TH1F* CalibVsCrysID =
new TH1F(
"CalibVsCrysID",
"Calibration constant vs crystal ID;crystal ID;counts per GeV", 8736, 0, 8736);
186 TH1F* ExpEnergyperCrys =
new TH1F(
"ExpEnergyperCrys",
"Expected energy per crystal;Crystal ID;Peak energy (GeV)", 8736, 0, 8736);
189 TH1F* PeakVsCrysID =
new TH1F(
"PeakVsCrysID",
"Peak of Novo fit vs crystal ID;crystal ID;Peak normalized energy", 8736, 0,
191 TH1F* EdgeVsCrysID =
new TH1F(
"EdgeVsCrysID",
"Lower edge of Novo fit vs crystal ID;crystal ID", 8736, 0,
193 TH1F* effSigVsCrysID =
new TH1F(
"effSigVsCrysID",
"effSigma vs crystal ID;crystal ID;sigma)", 8736, 0, 8736);
194 TH1F* etaVsCrysID =
new TH1F(
"etaVsCrysID",
"eta vs crystal ID;crystal ID;Novo eta parameter", 8736, 0, 8736);
195 TH1F* normVsCrysID =
new TH1F(
"normVsCrysID",
"Novosibirsk normalization vs crystal ID;crystal ID;normalization", 8736, 0, 8736);
196 TH1F* lowerLimitVsCrysID =
new TH1F(
"lowerLimitVsCrysID",
"fit range lower limit vs crystal ID;crystal ID;lower fit limit", 8736, 0,
198 TH1F* fitLimitVsCrysID =
new TH1F(
"fitLimitVsCrysID",
"fit range upper limit vs crystal ID;crystal ID;upper fit limit", 8736, 0,
200 TH1F* StatusVsCrysID =
new TH1F(
"StatusVsCrysID",
"Fit status vs crystal ID;crystal ID;Fit status", 8736, 0, 8736);
203 TH1F* hStatus =
new TH1F(
"hStatus",
"Fit status", 25, -5, 20);
204 TH1F* hPeak =
new TH1F(
"hPeak",
"Peaks of normalized energy distributions, successful fits;Peak of Novosibirsk fit", 200, 0.8, 1.2);
205 TH1F* fracPeakUnc =
new TH1F(
"fracPeakUnc",
"Fractional uncertainty on peak uncertainty, successful fits;Uncertainty on peak", 100,
211 bool allFitsOK =
true;
215 TString name =
"Enormalized";
217 TH1D* hEnergy = EnVsCrysID->ProjectionY(name, crysID + 1, crysID + 1);
220 double histMin = hEnergy->GetXaxis()->GetXmin();
221 double histMax = hEnergy->GetXaxis()->GetXmax();
222 TF1* func =
new TF1(
"eclNovoConst", eclNovoConst, histMin, histMax, 5);
223 func->SetParNames(
"normalization",
"peak",
"effSigma",
"eta",
"const");
224 func->SetParLimits(1, peakMin, peakMax);
225 func->SetParLimits(2, effSigMin, effSigMax);
226 func->SetParLimits(3, etaMin, etaMax);
229 double constant = 0.;
230 func->FixParameter(4, constant);
233 if (hEnergy->GetEntries() <
nToRebin) {
235 func->FixParameter(3, etaNom);
239 hEnergy->GetXaxis()->SetRangeUser(peakMin, peakMax);
240 double peak = hEnergy->GetMaximum();
241 int maxBin = hEnergy->GetMaximumBin();
242 double peakE = hEnergy->GetBinLowEdge(maxBin);
243 double peakEUnc = 0.;
244 double normalization = hEnergy->GetMaximum();
246 double effSigma = hEnergy->GetRMS();
247 double sigmaUnc = 0.;
248 hEnergy->GetXaxis()->SetRangeUser(histMin, histMax);
256 double lowerEnEdge = 0.;
261 while (hEnergy->GetBinContent(iLow) > targetY) {iLow--;}
262 double fitlow = hEnergy->GetBinLowEdge(iLow);
266 while (hEnergy->GetBinContent(iHigh) > targetY) {iHigh++;}
267 double fithigh = hEnergy->GetBinLowEdge(iHigh + 1);
271 bool fitHist = IntegralVsCrysID->GetBinContent(crysID + 1) >=
minEntries;
275 func->SetParameters(normalization, peakE, effSigma, eta, constant);
278 hEnergy->Fit(func,
"LIQ",
"", fitlow, fithigh);
279 normalization = func->GetParameter(0);
280 normUnc = func->GetParError(0);
281 peakE = func->GetParameter(1);
282 peakEUnc = func->GetParError(1);
283 effSigma = func->GetParameter(2);
284 sigmaUnc = func->GetParError(2);
285 eta = func->GetParameter(3);
286 etaUnc = func->GetParError(3);
287 fitProb = func->GetProb();
291 peak = func->Eval(peakE);
295 iHigh = hEnergy->GetXaxis()->FindBin(peakE) + 1;
296 iLow = hEnergy->GetXaxis()->FindBin(fitlow);
298 for (
int ibin = iHigh; ibin > iLow; ibin--) {
299 double xc = hEnergy->GetBinCenter(ibin);
300 if (func->Eval(xc) > targetY) {iLast = ibin;}
302 double xHigh = hEnergy->GetBinCenter(iLast);
303 double xLow = hEnergy->GetBinCenter(iLast - 1);
306 if (func->Eval(xLow) < targetY and func->Eval(xHigh) > targetY) {
308 lowerEnEdge = func->GetX(targetY, xLow, xHigh);
320 if (fitProb <= minFitLimit) {iStatus =
poorFit;}
323 if ((peakE < peakMin + peakTol) || (peakE > peakMax - peakTol)) {iStatus =
atLimit;}
324 if ((effSigma < effSigMin + effSigTol) || (effSigma > effSigMax - effSigTol)) {iStatus =
atLimit;}
325 if ((eta < etaMin + etaTol) || (eta > etaMax - etaTol)) {iStatus =
atLimit;}
328 if (!fitHist) {iStatus =
notFit;}
331 int histbin = crysID + 1;
332 PeakVsCrysID->SetBinContent(histbin, peakE);
333 PeakVsCrysID->SetBinError(histbin, peakEUnc);
334 EdgeVsCrysID->SetBinContent(histbin, lowerEnEdge);
335 EdgeVsCrysID->SetBinError(histbin, peakEUnc);
336 effSigVsCrysID->SetBinContent(histbin, effSigma);
337 effSigVsCrysID->SetBinError(histbin, sigmaUnc);
338 etaVsCrysID->SetBinContent(histbin, eta);
339 etaVsCrysID->SetBinError(histbin, etaUnc);
340 normVsCrysID->SetBinContent(histbin, normalization);
341 normVsCrysID->SetBinError(histbin, normUnc);
342 lowerLimitVsCrysID->SetBinContent(histbin, fitlow);
343 lowerLimitVsCrysID->SetBinError(histbin, 0);
344 fitLimitVsCrysID->SetBinContent(histbin, fithigh);
345 fitLimitVsCrysID->SetBinError(histbin, 0);
346 StatusVsCrysID->SetBinContent(histbin, iStatus);
347 StatusVsCrysID->SetBinError(histbin, 0);
350 hStatus->Fill(iStatus);
353 fracPeakUnc->Fill(peakEUnc / peakE);
357 B2INFO(
"cellID " << crysID + 1 <<
" status = " << iStatus <<
" fit probability = " << fitProb);
365 for (
int crysID = 0; crysID < 8736; crysID++) {
366 int histbin = crysID + 1;
367 double fitstatus = StatusVsCrysID->GetBinContent(histbin);
368 double peakE = PeakVsCrysID->GetBinContent(histbin);
369 double edge = EdgeVsCrysID->GetBinContent(histbin);
370 double fracpeakEUnc = PeakVsCrysID->GetBinError(histbin) / peakE;
378 B2RESULT(
"eclMuMuEAlgorithm: cellID " << histbin <<
" is not a successful fit. Status = " << fitstatus);
385 double inputExpE = abs(AverageExpECrys->GetBinContent(histbin));
386 ExpEnergyperCrys->SetBinContent(histbin, inputExpE * edge);
387 ExpEnergyperCrys->SetBinError(histbin, fracpeakEUnc * inputExpE * peakE);
391 double inputCalib = abs(AverageInitCalib->GetBinContent(histbin));
392 CalibVsCrysID->SetBinContent(histbin, inputCalib / edge);
393 CalibVsCrysID->SetBinError(histbin, fracpeakEUnc * inputCalib / peakE);
399 bool DBsuccess =
false;
405 std::vector<float> tempE;
406 std::vector<float> tempUnc;
407 for (
int crysID = 0; crysID < 8736; crysID++) {
408 tempE.push_back(ExpEnergyperCrys->GetBinContent(crysID + 1));
409 tempUnc.push_back(ExpEnergyperCrys->GetBinError(crysID + 1));
414 B2RESULT(
"eclCosmicEAlgorithm: successfully stored expected energies ECLExpMuMuE");
419 std::vector<float> tempCalib;
420 std::vector<float> tempCalibUnc;
421 for (
int crysID = 0; crysID < 8736; crysID++) {
422 tempCalib.push_back(CalibVsCrysID->GetBinContent(crysID + 1));
423 tempCalibUnc.push_back(CalibVsCrysID->GetBinError(crysID + 1));
428 B2RESULT(
"eclMuMuEAlgorithm: successfully stored ECLCrystalEnergyMuMu calibration constants");
435 PeakVsCrysID->Write();
436 EdgeVsCrysID->Write();
437 effSigVsCrysID->Write();
438 etaVsCrysID->Write();
439 normVsCrysID->Write();
440 lowerLimitVsCrysID->Write();
441 fitLimitVsCrysID->Write();
442 StatusVsCrysID->Write();
444 fracPeakUnc->Write();
449 ExpEnergyperCrys->Write();
451 CalibVsCrysID->Write();
457 dummy = (TH1F*)gROOT->FindObject(
"PeakVsCrysID");
delete dummy;
458 dummy = (TH1F*)gROOT->FindObject(
"EdgeVsCrysID");
delete dummy;
459 dummy = (TH1F*)gROOT->FindObject(
"effSigVsCrysID");
delete dummy;
460 dummy = (TH1F*)gROOT->FindObject(
"etaVsCrysID");
delete dummy;
461 dummy = (TH1F*)gROOT->FindObject(
"normVsCrysID");
delete dummy;
462 dummy = (TH1F*)gROOT->FindObject(
"lowerLimitVsCrysID");
delete dummy;
463 dummy = (TH1F*)gROOT->FindObject(
"fitLimitVsCrysID");
delete dummy;
464 dummy = (TH1F*)gROOT->FindObject(
"StatusVsCrysID");
delete dummy;
465 dummy = (TH1F*)gROOT->FindObject(
"fitProbSame");
delete dummy;
466 dummy = (TH1F*)gROOT->FindObject(
"fracPeakUnc");
delete dummy;
467 dummy = (TH1F*)gROOT->FindObject(
"hStatus");
delete dummy;
468 dummy = (TH1F*)gROOT->FindObject(
"ExpEnergyperCrys");
delete dummy;
469 dummy = (TH1F*)gROOT->FindObject(
"CalibVsCrysID");
delete dummy;
475 B2RESULT(
"eclMuMuEAlgorithm performed fits but was not asked to store contants");
477 }
else if (!DBsuccess) {
478 if (
findExpValues) { B2RESULT(
"eclMuMuEAlgorithm: failed to store expected values"); }
479 else { B2RESULT(
"eclMuMuEAlgorithm: failed to store calibration constants"); }
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.
@ c_Failure
Failed =3 in Python.
General DB object to store one calibration number per ECL crystal.
void setCalibVector(const std::vector< float > &CalibConst, const std::vector< float > &CalibConstUnc)
Set vector of constants with uncertainties.
double tRatioMin
entries/peak at low edge of fit must be greater than this
int poorFit
low chi square; fit not useable
int iterations
fit reached max number of iterations, but is useable
int noLowerEdge
could not determine lower edge of fit
int storeConst
controls which values are written to the database.
bool performFits
if false, input histograms are copied to output, but no fits are done.
int cellIDHi
Last cellID to be fit.
double lowerEdgeThresh
Lower edge is where the fit = lowerEdgeThresh * peak value.
int cellIDLo
..Parameters to control Novosibirsk fit to energy deposited in each crystal by mu+mu- events
bool findExpValues
if true, fits are used to find expected energy deposit for each crystal instead of the calibration co...
int minEntries
All crystals to be fit must have at least minEntries events in the fit range.
int notFit
no fit performed
int nToRebin
If fewer entries than this, rebin and fix eta parameter.
virtual EResult calibrate() override
..Run algorithm on events
int atLimit
a parameter is at the limit; fit not useable
double tRatioMax
entries/peak at high edge of fit must be greater than this
Abstract base class for different kinds of events.