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();
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"
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;
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)
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;
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);
357 for (
const auto& each : signals)
359 if (signals.size() > 0) mean = mean / signals.size();
366 TH1D* hist_signals = cluster_counter->ProjectionY(
"proj", histoBin, histoBin);
370 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
371 <<
") U " << uBin <<
" V " << vBin
372 <<
" Charge " << median);
376 double landaumpv =
FitLandau(hist_signals);
377 double diff = (landaumpv - median);
379 if (landaumpv > 0.) difff = (landaumpv - median) / landaumpv;
380 B2INFO(
"EstimateCharge: sensor " << sensorID.
getID() <<
"(" << layerNumber <<
"," << ladderNumber <<
"," << sensorNumber
381 <<
") U " << uBin <<
" V " << vBin
382 <<
" Charge " << landaumpv <<
" Median " << median <<
" diff = " << diff <<
"/" << difff);
389 charge = hist_signals->GetMean();
401 auto size = signals.size();
406 sort(signals.begin(), signals.end());
408 return (signals[size / 2 - 1] + signals[size / 2]) / 2;
410 return signals[size / 2];
417 auto size = hist_signals->GetEntries();
419 if (size == 0)
return 0.0;
422 for (
int ibin = 0; ibin < hist_signals->GetNbinsX(); ++ibin) {
423 sum += hist_signals->GetBinContent(ibin + 1);
424 if (sum > size / 2) {
425 return hist_signals->GetBinLowEdge(ibin + 1);
429 B2WARNING(
"Could not find median! using default value 0.0!");
435 auto size = signals.size();
436 if (size == 0)
return 0.0;
439 int max = *max_element(signals.begin(), signals.end());
440 int min = *min_element(signals.begin(), signals.end());
442 if ((max - min) % 2) max--;
443 int nbin = max - min;
446 TH1D* hist_signals =
new TH1D(
"",
"", nbin, min, max);
447 for (
auto it = signals.begin(); it != signals.end(); ++it) {
448 hist_signals->Fill(*it);
452 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
453 landau->SetParNames(
"MPV",
"sigma",
"scale");
454 landau->SetParameters(35, 8, 1000);
455 landau->SetParLimits(0, 0., 80.);
460 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", fitmin, fitmax);
461 double MPV = landau->GetParameter(
"MPV");
463 B2INFO(
"Fit result: " << status <<
" MPV " << MPV <<
" sigma " << landau->GetParameter(
"sigma")
464 <<
" scale " << landau->GetParameter(
"scale") <<
" chi2 " << landau->GetChisquare());
471 if (status == 0)
return MPV;
473 B2WARNING(
"Fit failed! using default value 0.0!");
480 auto size = hist_signals->GetEntries();
481 if (size == 0)
return 0.0;
483 int max = hist_signals->GetBinLowEdge(hist_signals->GetNbinsX() + 1);
484 int min = hist_signals->GetBinLowEdge(1);
487 TF1* landau =
new TF1(
"landau",
"TMath::Landau(x,[0],[1])*[2]", min, max);
488 landau->SetParNames(
"MPV",
"sigma",
"scale");
489 landau->SetParameters(35, 8, 1000);
490 landau->SetParLimits(0, 0., 80.);
495 Int_t status = hist_signals->Fit(
"landau",
"Lq",
"", fitmin, fitmax);
496 double MPV = landau->GetParameter(
"MPV");
498 B2INFO(
"Fit result: " << status <<
" MPV " << MPV <<
" sigma " << landau->GetParameter(
"sigma")
499 <<
" scale " << landau->GetParameter(
"scale") <<
" chi2 " << landau->GetChisquare());
505 if (status == 0)
return MPV;
507 B2WARNING(
"Fit failed! using default value 0.0!");
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.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
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,...
static 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.
static 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.
std::shared_ptr< T > getObjectPtr(const std::string &name, const std::vector< Calibration::ExpRun > &requestedRuns)
Get calibration data object by name and list of runs, the Merge function will be called to generate t...
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.