10#include <ecl/calibration/eclee5x5Algorithm.h>
13#include <ecl/dataobjects/ECLElementNumbers.h>
14#include <ecl/dbobjects/ECLCrystalCalib.h>
22#include <TMatrixDSym.h>
33 "Perform energy calibration of ecl crystals by analyzing energy in 25-crystal sums from Bhabha events"
42 dummy = (TH1F*)gROOT->FindObject(
"AverageExpECrys");
43 if (dummy) {
delete dummy;}
44 dummy = (TH1F*)gROOT->FindObject(
"AverageElecCalib");
45 if (dummy) {
delete dummy;}
46 dummy = (TH1F*)gROOT->FindObject(
"AverageInitCalib");
47 if (dummy) {
delete dummy;}
48 dummy = (TH1F*)gROOT->FindObject(
"meanEnvsCrysID");
49 if (dummy) {
delete dummy;}
56 B2INFO(
"eclee5x5Algorithm parameters:");
72 auto EnVsCrysID = getObjectPtr<TH2F>(
"EnVsCrysID");
73 auto RvsCrysID = getObjectPtr<TH1F>(
"RvsCrysID");
74 auto NRvsCrysID = getObjectPtr<TH1F>(
"NRvsCrysID");
75 auto Qmatrix = getObjectPtr<TH2F>(
"Qmatrix");
76 auto ElecCalibvsCrys = getObjectPtr<TH1F>(
"ElecCalibvsCrys");
77 auto ExpEvsCrys = getObjectPtr<TH1F>(
"ExpEvsCrys");
78 auto InitialCalibvsCrys = getObjectPtr<TH1F>(
"InitialCalibvsCrys");
79 auto CalibEntriesvsCrys = getObjectPtr<TH1F>(
"CalibEntriesvsCrys");
80 auto EntriesvsCrys = getObjectPtr<TH1F>(
"EntriesvsCrys");
81 auto dPhivsThetaID = getObjectPtr<TH2F>(
"dPhivsThetaID");
86 TH1F* AverageExpECrys =
new TH1F(
"AverageExpECrys",
"Average expected E per crys from collector;Crystal ID;Energy (GeV)",
89 TH1F* AverageElecCalib =
new TH1F(
"AverageElecCalib",
"Average electronics calib const vs crystal;Crystal ID;Calibration constant",
91 TH1F* AverageInitCalib =
new TH1F(
"AverageInitCalib",
"Average initial calib const vs crystal;Crystal ID;Calibration constant",
93 TH1F* meanEnvsCrysID =
new TH1F(
"meanEnvsCrysID",
"Mean normalized energy vs crystal;CrystalID;E/Eexp",
97 double TotEntries = CalibEntriesvsCrys->GetBinContent(cellID);
98 if (TotEntries > 0.) {
99 AverageElecCalib->SetBinContent(cellID, ElecCalibvsCrys->GetBinContent(cellID) / TotEntries);
100 AverageExpECrys->SetBinContent(cellID, ExpEvsCrys->GetBinContent(cellID) / TotEntries);
101 AverageInitCalib->SetBinContent(cellID, InitialCalibvsCrys->GetBinContent(cellID) / TotEntries);
104 TH1D* En = EnVsCrysID->ProjectionY(
"En", cellID, cellID);
105 meanEnvsCrysID->SetBinContent(cellID, En->GetMean());
106 meanEnvsCrysID->SetBinError(cellID, En->GetStdDev());
112 TFile* histfile =
new TFile(fName,
"recreate");
117 AverageElecCalib->Write();
118 AverageExpECrys->Write();
119 AverageInitCalib->Write();
120 EntriesvsCrys->Write();
121 dPhivsThetaID->Write();
122 meanEnvsCrysID->Write();
127 B2INFO(
"eclee5x5Algorithm has not been asked to find constants; copying input histograms and quitting");
137 if (AverageInitCalib->GetBinContent(cellID) > 0.) {
138 if (EntriesvsCrys->GetBinContent(cellID) <
m_minEntries) {
140 B2INFO(
"eclee5x5Algorithm: insufficient data for cellID = " << cellID <<
" " << EntriesvsCrys->GetBinContent(cellID) <<
" entries");
154 bool foundConst =
false;
155 TH1F* gVsCrysID =
new TH1F(
"gVsCrysID",
"Ratio of new to old calibration vs crystal ID;crystal ID;vector g",
157 TH1F* CalibVsCrysID =
new TH1F(
"CalibVsCrysID",
"Calibration constant vs crystal ID;crystal ID;counts per GeV",
159 TH1F* ExpEnergyperCrys =
new TH1F(
"ExpEnergyperCrys",
"Expected energy per crystal;Crystal ID;Energy in 25 crystal sum (GeV)",
162 TString title =
"dPhi cut per crystal " +
m_payloadName +
";Crystal ID;dPhi requirement (deg)";
169 float mean = meanEnvsCrysID->GetBinContent(cellID);
170 float stdDev = meanEnvsCrysID->GetBinError(cellID);
171 float inputE = AverageExpECrys->GetBinContent(cellID);
172 if (mean > 0. and stdDev > 0.) {
173 ExpEnergyperCrys->SetBinContent(cellID, mean * abs(inputE));
174 ExpEnergyperCrys->SetBinError(cellID, stdDev * abs(inputE));
176 ExpEnergyperCrys->SetBinContent(cellID, inputE);
177 ExpEnergyperCrys->SetBinError(cellID, 0.05 * inputE);
184 std::vector<float> tempCalib;
185 std::vector<float> tempCalibStdDev;
188 tempCalib.push_back(ExpEnergyperCrys->GetBinContent(cellID));
189 tempCalibStdDev.push_back(ExpEnergyperCrys->GetBinError(cellID));
194 B2INFO(
"eclee5x5Algorithm: successfully stored expected energies ECLExpee5x5E");
205 vectorR[ix - 1] = RvsCrysID->GetBinContent(ix);
207 matrixQ[ix - 1][iy - 1] = Qmatrix->GetBinContent(ix, iy);
212 int nNotCalibrated = 0;
214 if (NRvsCrysID->GetBinContent(cellID) < 0.5) {
216 matrixQ[cellID - 1][othercell - 1] = 0.;
217 matrixQ[othercell - 1][cellID - 1] = 0.;
219 matrixQ[cellID - 1][cellID - 1] = 1.;
220 vectorR[cellID - 1] = -1.;
224 B2INFO(
"eclee5x5Algorithm: " << nNotCalibrated <<
" crystals will not be calibrated. ");
227 TDecompLU lu(matrixQ);
229 TVectorD vectorg = lu.Solve(vectorR, solved);
235 gVsCrysID->SetBinContent(cellID, vectorg[cellID - 1]);
236 gVsCrysID->SetBinError(cellID, 0.);
237 float newCalib = vectorg[cellID - 1] * abs(AverageInitCalib->GetBinContent(cellID));
238 CalibVsCrysID->SetBinContent(cellID, newCalib);
239 CalibVsCrysID->SetBinError(cellID, 0.);
241 if (vectorg[cellID - 1] < 0. and NRvsCrysID->GetBinContent(cellID) > 0.) {foundConst =
false;}
247 std::vector<float> tempCalib;
248 std::vector<float> tempCalibStdDev;
251 tempCalib.push_back(CalibVsCrysID->GetBinContent(cellID));
252 tempCalibStdDev.push_back(CalibVsCrysID->GetBinError(cellID));
257 B2INFO(
"eclee5x5Algorithm: successfully stored calibration ECLCrystalEnergyee5x5");
265 float dPhiCenter[69] = {};
266 float dPhiHalfWidth[69] = {};
269 const int nbins = dPhivsThetaID->GetNbinsX();
270 for (
int ib = 1; ib <= nbins; ib++) {
271 TH1D* proj = dPhivsThetaID->ProjectionY(
"proj", ib, ib);
272 if (proj->Integral() < 100) {
continue;}
273 int thetaID = (int)dPhivsThetaID->GetXaxis()->GetBinCenter(ib);
274 if (firstID == 0) { firstID = thetaID; }
288 double peak = proj->GetMaximum();
289 int nPhiBins = proj->GetNbinsX();
293 }
while (proj->GetBinContent(binLo) <
m_fracLo * peak and binLo < nPhiBins);
294 double xfitLo = proj->GetBinLowEdge(binLo);
298 int binHi = proj->GetXaxis()->FindBin(175.01);
301 }
while (proj->GetBinContent(binHi)<fracHi* peak and binHi>1);
302 double xfitHi = proj->GetBinLowEdge(binHi + 1);
305 int peakBin = proj->GetMaximumBin();
306 if (binLo >= peakBin or binHi <= peakBin) {
307 B2ERROR(
"Flawed dPhi fit range for thetaID = " << thetaID <<
" peakBin = " << peakBin <<
" binLo = " << binLo <<
"binHi = " <<
312 proj->Fit(
"gaus",
"",
"", xfitLo, xfitHi);
315 TF1* fitGaus = proj->GetFunction(
"gaus");
316 float mean = fitGaus->GetParameter(1);
317 float sigma = fitGaus->GetParameter(2);
318 float dPhiLo = mean -
m_nsigLo * sigma;
319 float dPhiHi = mean + nsigHi * sigma;
320 dPhiCenter[thetaID] = 0.5 * (dPhiLo + dPhiHi);
321 dPhiHalfWidth[thetaID] = 0.5 * (dPhiHi - dPhiLo);
325 for (
int thetaID = 0; thetaID < firstID; thetaID++) {
326 dPhiCenter[thetaID] = dPhiCenter[firstID];
327 dPhiHalfWidth[thetaID] = dPhiHalfWidth[firstID];
329 for (
int thetaID = lastID + 1; thetaID < 69; thetaID++) {
330 dPhiCenter[thetaID] = dPhiCenter[lastID];
331 dPhiHalfWidth[thetaID] = dPhiHalfWidth[lastID];
337 std::vector<float> tempCalib;
338 std::vector<float> tempCalibWidth;
342 for (
int thetaID = 0; thetaID < 69; thetaID++) {
344 tempCalib.at(crysID) = dPhiCenter[thetaID];
345 tempCalibWidth.at(crysID) = dPhiHalfWidth[thetaID];
346 dPhiperCrys->SetBinContent(crysID + 1, dPhiCenter[thetaID]);
347 dPhiperCrys->SetBinError(crysID + 1, dPhiHalfWidth[thetaID]);
358 B2INFO(
"eclee5x5Algorithm: successfully stored calibration " <<
m_payloadName);
364 B2ERROR(
"eclee5x5Algorithm: invalid payload name: m_payloadName = " <<
m_payloadName);
371 ExpEnergyperCrys->Write();
374 CalibVsCrysID->Write();
376 dPhiperCrys->Write();
380 dummy = (TH1F*)gROOT->FindObject(
"gVsCrysID");
delete dummy;
381 dummy = (TH1F*)gROOT->FindObject(
"CalibVsCrysID");
delete dummy;
382 dummy = (TH1F*)gROOT->FindObject(
"ExpEnergyperCrys");
delete dummy;
383 dummy = (TH1F*)gROOT->FindObject(
"dPhiperCrys");
delete dummy;
389 B2INFO(
"eclee5x5Algorithm successfully found constants but was not asked to store them");
391 B2INFO(
"eclee5x5Algorithm was not asked to store constants, and did not succeed in finding them");
394 }
else if (!foundConst) {
396 B2INFO(
"eclee5x5Algorithm: failed to store expected values");
398 B2INFO(
"eclee5x5Algorithm: failed to store calibration constants");
400 B2INFO(
"eclee5x5Algorithm: failed to find dPhi* selection criteria");
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 successfully =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.
Class to get the neighbours for a given cell id.
short int getCrystalsPerRing(const short int thetaid) const
return number of crystals in a given theta ring
int m_minEntries
all crystals to be calibrated must have this many entries
double m_fracHiASym
or fracHiASym*peak, at low values of thetaID
eclee5x5Algorithm()
..Constructor
double m_fracLo
start dPhi fit where data is > fraclo*peak
double m_nsigHiASym
or mean+nsigHiASym*sigma at low thetaID
double m_nsigLo
dPhi region is mean - nsigLo*sigma
std::string m_payloadName
Name of the payload to be stored.
ECL::ECLNeighbours * m_eclNeighbours5x5
Neighbours, used to get nCrys per ring.
std::string m_outputName
..Parameters to control job to find energy calibration using Bhabhas
bool m_storeConst
write payload to localdb if true
int m_lastLoThetaID
use asymmetric dPhi range for thetaID<= this value
virtual EResult calibrate() override
..Run algorithm on events
double m_fracHiSym
end dPhi fit where data is > fracHiSym*peak
double m_nsigHiSym
to mean + nsigHiSym*sigma
const int c_NCrystals
Number of crystals.
Abstract base class for different kinds of events.