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 <<
": Replace default gain wih average "
295 B2INFO(
"PXD Gain Calibration Successful");
304 unsigned short histoBin)
309 if (strategy < 0 || strategy > 2) {
310 B2FATAL(
"strategy unavailable, use 0 for medians, 1 for landau fit and 2 for mean!");
319 const string treename = str(format(
"tree_%1%_%2%_%3%_%4%_%5%") % layerNumber % ladderNumber % sensorNumber % uBin % vBin);
321 vector<double> signals;
323 auto tree = getObjectPtr<TTree>(treename);
324 tree->SetBranchAddress(
"signal", &m_signal);
327 const auto nEntries = tree->GetEntries();
330 for (
int i = 0; i < nEntries; i += incr) {
332 double noise = gRandom->Gaus(0.0,
noiseSigma);
333 signals.push_back(m_signal + noise);
338 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
339 <<
") U " << uBin <<
" V " << vBin
340 <<
" Charge " << median);
345 double diff = (landaumpv - median);
347 if (landaumpv > 0.) difff = (landaumpv - median) / landaumpv;
348 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
349 <<
") U " << uBin <<
" V " << vBin
350 <<
" Charge " << landaumpv <<
" Median " << median <<
" diff = " << diff <<
"/" << difff);
354 for (
auto& each : signals)
356 if (signals.size() > 0) mean = mean / signals.size();
362 auto cluster_counter = getObjectPtr<TH2I>(
"PXDClusterCharge");
363 TH1D* hist_signals = cluster_counter->ProjectionY(
"proj", histoBin, histoBin);
367 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
368 <<
") U " << uBin <<
" V " << vBin
369 <<
" Charge " << median);
373 double landaumpv =
FitLandau(hist_signals);
374 double diff = (landaumpv - median);
376 if (landaumpv > 0.) difff = (landaumpv - median) / landaumpv;
377 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
378 <<
") U " << uBin <<
" V " << vBin
379 <<
" Charge " << landaumpv <<
" Median " << median <<
" diff = " << diff <<
"/" << difff);
384 charge = hist_signals->GetMean();
396 auto size = signals.size();
401 sort(signals.begin(), signals.end());
403 return (signals[size / 2 - 1] + signals[size / 2]) / 2;
405 return signals[size / 2];
412 auto size = hist_signals->GetEntries();
414 if (size == 0)
return 0.0;
417 for (
int ibin = 0; ibin < hist_signals->GetNbinsX(); ++ibin) {
418 sum += hist_signals->GetBinContent(ibin + 1);
419 if (sum > size / 2) {
420 return hist_signals->GetBinLowEdge(ibin + 1);
424 B2WARNING(
"Could not find median! using default value 0.0!");
430 auto size = signals.size();
431 if (size == 0)
return 0.0;
434 int max = *max_element(signals.begin(), signals.end());
435 int min = *min_element(signals.begin(), signals.end());
437 if ((max - min) % 2) max--;
438 int nbin = max - min;
441 TH1D* hist_signals =
new TH1D(
"",
"", nbin, min, max);
442 for (
auto it = signals.begin(); it != signals.end(); ++it) {
443 hist_signals->Fill(*it);
447 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
448 landau->SetParNames(
"MPV",
"sigma",
"scale");
449 landau->SetParameters(35, 8, 1000);
450 landau->SetParLimits(0, 0., 80.);
455 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", fitmin, fitmax);
456 double MPV = landau->GetParameter(
"MPV");
458 B2INFO(
"Fit result: " << status <<
" MPV " << MPV <<
" sigma " << landau->GetParameter(
"sigma")
459 <<
" scale " << landau->GetParameter(
"scale") <<
" chi2 " << landau->GetChisquare());
466 if (status == 0)
return MPV;
468 B2WARNING(
"Fit failed! using default value 0.0!");
475 auto size = hist_signals->GetEntries();
476 if (size == 0)
return 0.0;
478 int max = hist_signals->GetBinLowEdge(hist_signals->GetNbinsX() + 1);
479 int min = hist_signals->GetBinLowEdge(1);
482 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
483 landau->SetParNames(
"MPV",
"sigma",
"scale");
484 landau->SetParameters(35, 8, 1000);
485 landau->SetParLimits(0, 0., 80.);
490 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", fitmin, fitmax);
491 double MPV = landau->GetParameter(
"MPV");
493 B2INFO(
"Fit result: " << status <<
" MPV " << MPV <<
" sigma " << landau->GetParameter(
"sigma")
494 <<
" scale " << landau->GetParameter(
"scale") <<
" chi2 " << landau->GetChisquare());
500 if (status == 0)
return MPV;
502 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 esitmate 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.