9#include <pxd/calibration/PXDGainCalibrationAlgorithm.h>
10#include <pxd/dbobjects/PXDGainMapPar.h>
11#include <pxd/dbobjects/PXDClusterChargeMapPar.h>
20#include <boost/format.hpp>
43 void getNumberOfBins(
const std::shared_ptr<TH1I>& histo_ptr,
unsigned short& nBinsU,
unsigned short& nBinsV)
45 set<unsigned short> uBinSet;
46 set<unsigned short> vBinSet;
49 for (
auto histoBin = 1; histoBin <= histo_ptr->GetXaxis()->GetNbins(); histoBin++) {
51 string label = histo_ptr->GetXaxis()->GetBinLabel(histoBin);
54 istringstream stream(label);
56 getline(stream, token,
'_');
57 getline(stream, token,
'_');
58 unsigned short uBin = std::stoi(token);
60 getline(stream, token,
'_');
61 unsigned short vBin = std::stoi(token);
67 if (uBinSet.empty() || vBinSet.empty()) {
68 B2FATAL(
"Not able to determine the grid size. Something is wrong with collected data.");
70 nBinsU = *uBinSet.rbegin() + 1;
71 nBinsV = *vBinSet.rbegin() + 1;
78 set<unsigned short> sensorSet;
81 for (
auto histoBin = 1; histoBin <= histo_ptr->GetXaxis()->GetNbins(); histoBin++) {
83 string label = histo_ptr->GetXaxis()->GetBinLabel(histoBin);
86 istringstream stream(label);
88 getline(stream, token,
'_');
89 VxdID sensorID(token);
90 sensorSet.insert(sensorID.getID());
92 return sensorSet.size();
101 minClusters(1000), noiseSigma(0.6), safetyFactor(2.0), forceContinue(false), strategy(0)
104 " -------------------------- PXDGainCalibrationAlgorithm ---------------------------------\n"
106 " Algorithm for estimating pxd gains (conversion factor from charge to ADU) \n"
107 " ----------------------------------------------------------------------------------------\n"
118 auto cluster_counter = getObjectPtr<TH1I>(
"PXDClusterCounter");
121 auto nSensors = getNumberOfSensors(cluster_counter);
124 unsigned short nBinsU = 0;
125 unsigned short nBinsV = 0;
126 getNumberOfBins(cluster_counter, nBinsU, nBinsV);
131 B2WARNING(
"Not enough Data: Only " << cluster_counter->GetEntries() <<
" hits were collected but " <<
int(
133 nSensors * nBinsU * nBinsV) <<
" needed!");
136 B2WARNING(
"Continue despite low statistics: Only " << cluster_counter->GetEntries() <<
" hits were collected but" <<
int(
138 nSensors * nBinsU * nBinsV) <<
" would be desirable!");
142 B2INFO(
"Start calibration using a " << nBinsU <<
"x" << nBinsV <<
" grid per sensor.");
143 B2INFO(
"Number of collected clusters is " << cluster_counter->GetEntries());
147 set<VxdID> pxdSensors;
150 for (
auto histoBin = 1; histoBin <= cluster_counter->GetXaxis()->GetNbins(); histoBin++) {
152 string label = cluster_counter->GetXaxis()->GetBinLabel(histoBin);
155 istringstream stream(label);
157 getline(stream, token,
'_');
158 VxdID sensorID(token);
160 getline(stream, token,
'_');
161 unsigned short uBin = std::stoi(token);
163 getline(stream, token,
'_');
164 unsigned short vBin = std::stoi(token);
167 int numberOfHits = cluster_counter->GetBinContent(histoBin);
178 B2WARNING(label <<
": Number of mc hits too small for fitting (" << numberOfHits <<
" < " <<
minClusters <<
179 "). Use default gain.");
182 pxdSensors.insert(sensorID);
189 for (
const auto& sensorID : pxdSensors) {
190 for (
unsigned short vBin = 0; vBin < nBinsV; ++vBin) {
192 unsigned short nGood = 0;
193 unsigned short nBad = 0;
194 for (
unsigned short uBin = 0; uBin < nBinsU; ++uBin) {
195 auto gain = gainMapPar->
getContent(sensorID.getID(), uBin, vBin);
204 B2RESULT(
"Gain calibration on sensor=" << sensorID <<
" and vBin=" << vBin <<
" was successful on " << nGood <<
"/" << nBinsU <<
208 if (nGood > 0 && nBad > 0) {
210 for (
unsigned short uBin = 0; uBin < nBinsU; ++uBin) {
211 auto gain = gainMapPar->
getContent(sensorID.getID(), uBin, vBin);
213 gainMapPar->
setContent(sensorID.getID(), uBin, vBin, meanGain);
214 B2RESULT(
"Gain calibration on sensor=" << sensorID <<
", vBin=" << vBin <<
" uBin " << uBin <<
": Replace default gain wih average "
227 B2INFO(
"PXD Gain Calibration Successful");
238 const string treename = str(format(
"tree_%1%_%2%_%3%_%4%_%5%") % layerNumber % ladderNumber % sensorNumber % uBin % vBin);
240 vector<double> mc_signals;
242 auto tree_MC = getObjectPtr<TTree>(treename);
243 tree_MC->SetBranchAddress(
"signal", &m_signal);
246 const auto nEntries_MC = tree_MC->GetEntries();
247 for (
int i = 0; i < nEntries_MC; ++i) {
248 tree_MC->GetEntry(i);
250 double noise = gRandom->Gaus(0.0,
noiseSigma);
251 mc_signals.push_back(m_signal + noise);
255 double mcMedian = -1;
257 if (dataMedian <= 0.0) {
258 B2WARNING(
"Retrieved negative charge median from DB for sensor=" << sensorID <<
" uBin=" << uBin <<
" vBin=" << vBin <<
259 ". Set gain to default value (=1.0) as well.");
265 B2FATAL(
"strategy unavailable, use 0 for medians or 1 for landau fit!");
269 if (mcMedian <= 0.0) {
270 B2WARNING(
"Retrieved negative charge median from DB for sensor=" << sensorID <<
" uBin=" << uBin <<
" vBin=" << vBin <<
271 ". Set gain to default value (=1.0) as well.");
276 double gain = dataMedian / mcMedian;
278 B2DEBUG(10,
"Gain from db used in PXDDigitizer is " << gainFromDB);
279 B2DEBUG(10,
"New gain correction derived is " << gain);
280 B2DEBUG(10,
"The total gain we should return is " << gain * gainFromDB);
282 return gain * gainFromDB;
291 auto dbtree = getObjectPtr<TTree>(
"dbtree");
292 dbtree->SetBranchAddress(
"run", &m_run);
293 dbtree->SetBranchAddress(
"exp", &m_exp);
294 dbtree->SetBranchAddress(
"chargeMap", &chargeMapPtr);
295 dbtree->SetBranchAddress(
"gainMap", &gainMapPtr);
302 const auto nEntries = dbtree->GetEntries();
303 for (
int i = 0; i < nEntries; ++i) {
313 return sum / counter;
322 auto dbtree = getObjectPtr<TTree>(
"dbtree");
323 dbtree->SetBranchAddress(
"run", &m_run);
324 dbtree->SetBranchAddress(
"exp", &m_exp);
325 dbtree->SetBranchAddress(
"chargeMap", &chargeMapPtr);
326 dbtree->SetBranchAddress(
"gainMap", &gainMapPtr);
333 const auto nEntries = dbtree->GetEntries();
334 for (
int i = 0; i < nEntries; ++i) {
344 return sum / counter;
350 auto size = signals.size();
355 sort(signals.begin(), signals.end());
357 return (signals[size / 2 - 1] + signals[size / 2]) / 2;
359 return signals[size / 2];
366 auto size = signals.size();
367 if (size == 0)
return 0.0;
370 int max = *max_element(signals.begin(), signals.end());
371 int min = *min_element(signals.begin(), signals.end());
374 TH1D* hist_signals =
new TH1D(
"",
"", max - min, min, max);
375 for (
auto it = signals.begin(); it != signals.end(); ++it) {
376 hist_signals->Fill(*it);
380 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
381 landau->SetParNames(
"MPV",
"sigma",
"scale");
382 landau->SetParameters(100, 1, 1000);
385 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", 0, 350);
386 double MPV = landau->GetParameter(
"MPV");
393 if (status == 0)
return MPV;
395 B2WARNING(
"Fit failed!. using default value.");
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.
The payload class for PXD cluster charge calibrations.
float getContent(unsigned short sensorID, unsigned short globalID) const
Get content.
double EstimateGain(VxdID sensorID, unsigned short uBin, unsigned short vBin)
Estimate gain as ratio of medians from MC and data for a part of PXD.
double FitLandau(std::vector< double > &signals)
Calculate MPV from signal vector using a landau fit.
double GetCurrentGainFromDB(VxdID sensorID, unsigned short uBin, unsigned short vBin)
Retrive current gain value from pulled in data base payload.
PXDGainCalibrationAlgorithm()
Constructor set the prefix to PXDGainCalibrationAlgorithm.
int minClusters
Minimum number of collected clusters for estimating gains.
float noiseSigma
Artificial noise sigma for smearing cluster charge.
virtual EResult calibrate() override
Run algo on data.
int strategy
strategy to used for gain calibration, 0 for medians, 1 for landau fit
double GetChargeMedianFromDB(VxdID sensorID, unsigned short uBin, unsigned short vBin)
Retrive charge median value from pulled in data base payload.
float safetyFactor
Safety factor for determining whether the collected number of clusters is enough.
double CalculateMedian(std::vector< double > &signals)
Calculate a median from unsorted signal vector. The input vector gets sorted.
bool forceContinue
Force continue in low statistics runs instead of returning c_NotEnoughData.
The payload class for PXD gain corrections.
float getContent(unsigned short sensorID, unsigned short globalID) const
Get content.
void setContent(unsigned short sensorID, unsigned short globalID, float value)
Set map content.
Class to uniquely identify a any structure of the PXD and SVD.
baseType getID() const
Get the unique id.
baseType getSensorNumber() const
Get the sensor id.
baseType getLadderNumber() const
Get the ladder id.
baseType getLayerNumber() const
Get the layer id.
unsigned short getNumberOfSensors(const std::shared_ptr< TH1I > &histo_ptr)
Helper function to extract number of sensors from counter histogram labels.
void getNumberOfBins(const std::shared_ptr< TH1I > &histo_ptr, unsigned short &nBinsU, unsigned short &nBinsV)
Helper function to extract number of bins along u side and v side from counter histogram labels.
Abstract base class for different kinds of events.