9#include <pxd/calibration/PXDDataMCGainCalibrationAlgorithm.h>
10#include <pxd/dbobjects/PXDClusterChargeMapPar.h>
11#include <pxd/dbobjects/PXDGainMapPar.h>
21#include <boost/format.hpp>
47 void getNumberOfBins(
const std::shared_ptr<TH1I>& histo_ptr,
unsigned short& nBinsU,
unsigned short& nBinsV)
49 set<unsigned short> uBinSet;
50 set<unsigned short> vBinSet;
53 for (
auto histoBin = 1; histoBin <= histo_ptr->GetNbinsX(); histoBin++) {
55 string label = histo_ptr->GetXaxis()->GetBinLabel(histoBin);
58 istringstream stream(label);
60 getline(stream, token,
'_');
61 getline(stream, token,
'_');
62 unsigned short uBin = std::stoi(token);
64 getline(stream, token,
'_');
65 unsigned short vBin = std::stoi(token);
71 if (uBinSet.empty() || vBinSet.empty()) {
72 B2FATAL(
"Not able to determine the grid size. Something is wrong with collected data.");
74 nBinsU = *uBinSet.rbegin() + 1;
75 nBinsV = *vBinSet.rbegin() + 1;
82 set<unsigned short> sensorSet;
85 for (
auto histoBin = 1; histoBin <= histo_ptr->GetNbinsX(); histoBin++) {
87 string label = histo_ptr->GetXaxis()->GetBinLabel(histoBin);
90 istringstream stream(label);
92 getline(stream, token,
'_');
93 VxdID sensorID(token);
94 sensorSet.insert(sensorID.getID());
97 return sensorSet.size();
105 minClusters(5000), noiseSigma(0.6), safetyFactor(2.0), forceContinue(false), strategy(0),
106 doCalibration(false), useChargeHistogram(false), chargePayloadName(
"PXDClusterChargeMapPar")
109 " ------------------------------ PXDDataMCGainCalibrationAlgorithm -----------------------------------\n"
111 " Algorithm for estimating pxd median/MPV cluster charges for different position on sensor in ADU, and optionally calculate gain \n"
112 " ------------------------------------------------------------------------------------------------\n"
122 auto cluster_counter = getObjectPtr<TH1I>(
"PXDClusterCounter");
123 if (!cluster_counter) {
124 B2INFO(
"Not enough Data: cluster counter does not exist ");
129 auto nSensors = getNumberOfSensors(cluster_counter);
132 unsigned short nBinsU = 0;
133 unsigned short nBinsV = 0;
134 getNumberOfBins(cluster_counter, nBinsU, nBinsV);
139 B2INFO(
"Not enough Data: Only " << cluster_counter->GetEntries() <<
" hits were collected but " <<
int(
safetyFactor *
minClusters*
140 nSensors * nBinsU * nBinsV) <<
" needed!");
143 B2INFO(
"Continue despite low statistics: Only " << cluster_counter->GetEntries() <<
" hits were collected but" <<
int(
145 nSensors * nBinsU * nBinsV) <<
" would be desirable!");
149 B2INFO(
"Start calibration using a " << nBinsU <<
"x" << nBinsV <<
" grid per sensor.");
155 set<VxdID> pxdSensors;
160 auto dbtree = getObjectPtr<TTree>(
"dbtree");
161 dbtree->SetBranchAddress(
"run", &m_run);
162 dbtree->SetBranchAddress(
"exp", &m_exp);
163 dbtree->SetBranchAddress(
"chargeMap", &chargeMapPtr);
164 dbtree->SetBranchAddress(
"gainMap", &gainMapPtr);
167 for (
auto histoBin = 1; histoBin <= cluster_counter->GetNbinsX(); histoBin++) {
170 string label = cluster_counter->GetXaxis()->GetBinLabel(histoBin);
173 istringstream stream(label);
175 getline(stream, token,
'_');
176 VxdID sensorID(token);
178 getline(stream, token,
'_');
179 unsigned short uBin = std::stoi(token);
181 getline(stream, token,
'_');
182 unsigned short vBin = std::stoi(token);
185 int numberOfDataHits = cluster_counter->GetBinContent(histoBin);
190 B2INFO(
"start EstimateCharge");
197 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
" U " << uBin <<
" V " << vBin <<
" Charge " << Charge);
205 B2WARNING(
"Retrieved negative charge for data for sensor=" << sensorID <<
" uBin=" << uBin <<
" vBin=" << vBin <<
206 ". Set gain to default value (=1.0).");
210 double mcCharge = chargeMapPtr->
getContent(sensorID.
getID(), uBin, vBin);
212 if (mcCharge <= 0.0) {
213 B2WARNING(
"Retrieved negative charge for MC from DB for sensor=" << sensorID <<
" uBin=" << uBin <<
" vBin=" << vBin <<
214 ". Set gain to default value (=1.0).");
217 Gain = Charge / mcCharge;
218 B2INFO(
"Estimated Gain: sensor " << sensorID.
getID() <<
" U " << uBin <<
" V " << vBin <<
" Gain " << Gain <<
" = " << Charge <<
230 B2WARNING(label <<
": Number of data hits too small for fitting (" << numberOfDataHits <<
" < " <<
minClusters <<
231 "). Use default value of 0 for charge, 1 for gain.");
237 pxdSensors.insert(sensorID);
241 chargeMapPtr =
nullptr;
242 gainMapPtr =
nullptr;
249 B2INFO(
"PXD Cluster Charge Calibration Successful");
258 for (
const auto& sensorID : pxdSensors) {
259 for (
unsigned short vBin = 0; vBin < nBinsV; ++vBin) {
261 unsigned short nGood = 0;
262 unsigned short nBad = 0;
263 for (
unsigned short uBin = 0; uBin < nBinsU; ++uBin) {
264 auto gain = gainMapPar->
getContent(sensorID.getID(), uBin, vBin);
273 B2RESULT(
"Gain calibration on sensor=" << sensorID <<
" and vBin=" << vBin <<
" was successful on " << nGood <<
"/" << nBinsU <<
277 if (nGood > 0 && nBad > 0) {
279 for (
unsigned short uBin = 0; uBin < nBinsU; ++uBin) {
280 auto gain = gainMapPar->
getContent(sensorID.getID(), uBin, vBin);
282 gainMapPar->
setContent(sensorID.getID(), uBin, vBin, meanGain);
283 B2RESULT(
"Gain calibration on sensor=" << sensorID <<
", vBin=" << vBin <<
" uBin " << uBin <<
284 ": Replace default gain with average "
296 B2INFO(
"PXD Gain Calibration Successful");
305 unsigned short histoBin)
310 if (strategy < 0 || strategy > 2) {
311 B2FATAL(
"strategy unavailable, use 0 for medians, 1 for landau fit and 2 for mean!");
320 const string treename = str(format(
"tree_%1%_%2%_%3%_%4%_%5%") % layerNumber % ladderNumber % sensorNumber % uBin % vBin);
322 vector<double> signals;
324 auto tree = getObjectPtr<TTree>(treename);
325 tree->SetBranchAddress(
"signal", &m_signal);
328 const auto nEntries = tree->GetEntries();
331 for (
int i = 0; i < nEntries; i += incr) {
333 double noise = gRandom->Gaus(0.0,
noiseSigma);
334 signals.push_back(m_signal + noise);
339 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
340 <<
") U " << uBin <<
" V " << vBin
341 <<
" Charge " << median);
346 double diff = (landaumpv - median);
348 if (landaumpv > 0.) difff = (landaumpv - median) / landaumpv;
349 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
350 <<
") U " << uBin <<
" V " << vBin
351 <<
" Charge " << landaumpv <<
" Median " << median <<
" diff = " << diff <<
"/" << difff);
355 for (
auto& each : signals)
357 if (signals.size() > 0) mean = mean / signals.size();
363 auto cluster_counter = getObjectPtr<TH2I>(
"PXDClusterCharge");
364 TH1D* hist_signals = cluster_counter->ProjectionY(
"proj", histoBin, histoBin);
368 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
369 <<
") U " << uBin <<
" V " << vBin
370 <<
" Charge " << median);
374 double landaumpv =
FitLandau(hist_signals);
375 double diff = (landaumpv - median);
377 if (landaumpv > 0.) difff = (landaumpv - median) / landaumpv;
378 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
379 <<
") U " << uBin <<
" V " << vBin
380 <<
" Charge " << landaumpv <<
" Median " << median <<
" diff = " << diff <<
"/" << difff);
385 charge = hist_signals->GetMean();
397 auto size = signals.size();
402 sort(signals.begin(), signals.end());
404 return (signals[size / 2 - 1] + signals[size / 2]) / 2;
406 return signals[size / 2];
413 auto size = hist_signals->GetEntries();
415 if (size == 0)
return 0.0;
418 for (
int ibin = 0; ibin < hist_signals->GetNbinsX(); ++ibin) {
419 sum += hist_signals->GetBinContent(ibin + 1);
420 if (sum > size / 2) {
421 return hist_signals->GetBinLowEdge(ibin + 1);
425 B2WARNING(
"Could not find median! using default value 0.0!");
431 auto size = signals.size();
432 if (size == 0)
return 0.0;
435 int max = *max_element(signals.begin(), signals.end());
436 int min = *min_element(signals.begin(), signals.end());
438 if ((max - min) % 2) max--;
439 int nbin = max - min;
442 TH1D* hist_signals =
new TH1D(
"",
"", nbin, min, max);
443 for (
auto it = signals.begin(); it != signals.end(); ++it) {
444 hist_signals->Fill(*it);
448 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
449 landau->SetParNames(
"MPV",
"sigma",
"scale");
450 landau->SetParameters(35, 8, 1000);
451 landau->SetParLimits(0, 0., 80.);
456 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", fitmin, fitmax);
457 double MPV = landau->GetParameter(
"MPV");
459 B2INFO(
"Fit result: " << status <<
" MPV " << MPV <<
" sigma " << landau->GetParameter(
"sigma")
460 <<
" scale " << landau->GetParameter(
"scale") <<
" chi2 " << landau->GetChisquare());
467 if (status == 0)
return MPV;
469 B2WARNING(
"Fit failed! using default value 0.0!");
476 auto size = hist_signals->GetEntries();
477 if (size == 0)
return 0.0;
479 int max = hist_signals->GetBinLowEdge(hist_signals->GetNbinsX() + 1);
480 int min = hist_signals->GetBinLowEdge(1);
483 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
484 landau->SetParNames(
"MPV",
"sigma",
"scale");
485 landau->SetParameters(35, 8, 1000);
486 landau->SetParLimits(0, 0., 80.);
491 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", fitmin, fitmax);
492 double MPV = landau->GetParameter(
"MPV");
494 B2INFO(
"Fit result: " << status <<
" MPV " << MPV <<
" sigma " << landau->GetParameter(
"sigma")
495 <<
" scale " << landau->GetParameter(
"scale") <<
" chi2 " << landau->GetChisquare());
501 if (status == 0)
return MPV;
503 B2WARNING(
"Fit failed! using default value 0.0!");
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.
void setContent(unsigned short sensorID, unsigned short globalID, float value)
Set map content.
bool doCalibration
flag to perform full calibration or only estimate charge: False: only estimate charge,...
double FitLandau(std::vector< double > &signals)
calculate MPV of unsorted signal vector using a Landau fit
double EstimateCharge(VxdID sensorID, unsigned short uBin, unsigned short vBin, unsigned short histoBin)
Estimate median charge form collected clusters on part of PXD.
int minClusters
Minimum number of collected clusters for estimating median charge.
std::string chargePayloadName
Payload name for Cluster Charge.
float noiseSigma
Artificial noise sigma for smearing cluster charge.
bool useChargeHistogram
Flag to use histogram as charge input.
virtual EResult calibrate() override
Run algo on data.
int strategy
strategy to used for gain calibration, 0 for medians, 1 for landau fit
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.
PXDDataMCGainCalibrationAlgorithm()
Constructor set the prefix to PXDDataMCGainCalibrationAlgorithm.
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.