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 <<
215 ": Replace default gain with average "
228 B2INFO(
"PXD Gain Calibration Successful");
239 const string treename = str(format(
"tree_%1%_%2%_%3%_%4%_%5%") % layerNumber % ladderNumber % sensorNumber % uBin % vBin);
241 vector<double> mc_signals;
243 auto tree_MC = getObjectPtr<TTree>(treename);
244 tree_MC->SetBranchAddress(
"signal", &m_signal);
247 const auto nEntries_MC = tree_MC->GetEntries();
248 for (
int i = 0; i < nEntries_MC; ++i) {
249 tree_MC->GetEntry(i);
251 double noise = gRandom->Gaus(0.0,
noiseSigma);
252 mc_signals.push_back(m_signal + noise);
256 double mcMedian = -1;
258 if (dataMedian <= 0.0) {
259 B2WARNING(
"Retrieved negative charge median from DB for sensor=" << sensorID <<
" uBin=" << uBin <<
" vBin=" << vBin <<
260 ". Set gain to default value (=1.0) as well.");
266 B2FATAL(
"strategy unavailable, use 0 for medians or 1 for landau fit!");
270 if (mcMedian <= 0.0) {
271 B2WARNING(
"Retrieved negative charge median from DB for sensor=" << sensorID <<
" uBin=" << uBin <<
" vBin=" << vBin <<
272 ". Set gain to default value (=1.0) as well.");
277 double gain = dataMedian / mcMedian;
279 B2DEBUG(10,
"Gain from db used in PXDDigitizer is " << gainFromDB);
280 B2DEBUG(10,
"New gain correction derived is " << gain);
281 B2DEBUG(10,
"The total gain we should return is " << gain * gainFromDB);
283 return gain * gainFromDB;
292 auto dbtree = getObjectPtr<TTree>(
"dbtree");
293 dbtree->SetBranchAddress(
"run", &m_run);
294 dbtree->SetBranchAddress(
"exp", &m_exp);
295 dbtree->SetBranchAddress(
"chargeMap", &chargeMapPtr);
296 dbtree->SetBranchAddress(
"gainMap", &gainMapPtr);
303 const auto nEntries = dbtree->GetEntries();
304 for (
int i = 0; i < nEntries; ++i) {
314 return sum / counter;
323 auto dbtree = getObjectPtr<TTree>(
"dbtree");
324 dbtree->SetBranchAddress(
"run", &m_run);
325 dbtree->SetBranchAddress(
"exp", &m_exp);
326 dbtree->SetBranchAddress(
"chargeMap", &chargeMapPtr);
327 dbtree->SetBranchAddress(
"gainMap", &gainMapPtr);
334 const auto nEntries = dbtree->GetEntries();
335 for (
int i = 0; i < nEntries; ++i) {
345 return sum / counter;
351 auto size = signals.size();
356 sort(signals.begin(), signals.end());
358 return (signals[size / 2 - 1] + signals[size / 2]) / 2;
360 return signals[size / 2];
367 auto size = signals.size();
368 if (size == 0)
return 0.0;
371 int max = *max_element(signals.begin(), signals.end());
372 int min = *min_element(signals.begin(), signals.end());
375 TH1D* hist_signals =
new TH1D(
"",
"", max - min, min, max);
376 for (
auto it = signals.begin(); it != signals.end(); ++it) {
377 hist_signals->Fill(*it);
381 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
382 landau->SetParNames(
"MPV",
"sigma",
"scale");
383 landau->SetParameters(100, 1, 1000);
386 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", 0, 350);
387 double MPV = landau->GetParameter(
"MPV");
394 if (status == 0)
return MPV;
396 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)
Retrieve 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)
Retrieve 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.