Belle II Software development
PXDChargeCalibrationAlgorithm.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <pxd/calibration/PXDChargeCalibrationAlgorithm.h>
10#include <pxd/dbobjects/PXDClusterChargeMapPar.h>
11
12#include <string>
13#include <algorithm>
14#include <set>
15
16#include <sstream>
17#include <iostream>
18
19#include <boost/format.hpp>
20
21//ROOT
22#include <TRandom.h>
23#include <TH1I.h>
24#include <TF1.h>
25
26
27using namespace std;
28using boost::format;
29using namespace Belle2;
30
31
32// Anonymous namespace for data objects used by PXDChargeCalibrationAlgorithm class
33namespace {
34
36 int m_signal;
37
39 void getNumberOfBins(const std::shared_ptr<TH1I>& histo_ptr, unsigned short& nBinsU, unsigned short& nBinsV)
40 {
41 set<unsigned short> uBinSet;
42 set<unsigned short> vBinSet;
43
44 // Loop over all bins of input histo
45 for (auto histoBin = 1; histoBin <= histo_ptr->GetXaxis()->GetNbins(); histoBin++) {
46 // The bin label contains the vxdid, uBin and vBin
47 string label = histo_ptr->GetXaxis()->GetBinLabel(histoBin);
48
49 // Parse label string format to read sensorID, uBin and vBin
50 istringstream stream(label);
51 string token;
52 getline(stream, token, '_');
53 getline(stream, token, '_');
54 unsigned short uBin = std::stoi(token);
55
56 getline(stream, token, '_');
57 unsigned short vBin = std::stoi(token);
58
59 uBinSet.insert(uBin);
60 vBinSet.insert(vBin);
61 }
62
63 if (uBinSet.empty() || vBinSet.empty()) {
64 B2FATAL("Not able to determine the grid size. Something is wrong with collected data.");
65 } else {
66 nBinsU = *uBinSet.rbegin() + 1;
67 nBinsV = *vBinSet.rbegin() + 1;
68 }
69 }
70
72 unsigned short getNumberOfSensors(const std::shared_ptr<TH1I>& histo_ptr)
73 {
74 set<unsigned short> sensorSet;
75
76 // Loop over all bins of input histo
77 for (auto histoBin = 1; histoBin <= histo_ptr->GetXaxis()->GetNbins(); histoBin++) {
78 // The bin label contains the vxdid, uBin and vBin
79 string label = histo_ptr->GetXaxis()->GetBinLabel(histoBin);
80
81 // Parse label string format to read sensorID, uBin and vBin
82 istringstream stream(label);
83 string token;
84 getline(stream, token, '_');
85 VxdID sensorID(token);
86 sensorSet.insert(sensorID.getID());
87 }
88
89 return sensorSet.size();
90 }
91
92}
93
94
96 CalibrationAlgorithm("PXDClusterChargeCollector"),
97 minClusters(5000), noiseSigma(0.6), safetyFactor(2.0), forceContinue(false), strategy(0)
98{
100 " ------------------------------ PXDChargeCalibrationAlgorithm -----------------------------------\n"
101 " \n"
102 " Algorithm for estimating pxd median/MPV cluster charges for different position on sensor in ADU \n"
103 " ------------------------------------------------------------------------------------------------\n"
104 );
105}
106
107
108
109
111{
112
113 // Get counter histogram
114 auto cluster_counter = getObjectPtr<TH1I>("PXDClusterCounter");
115
116 // Extract number of sensors from counter histograms
117 auto nSensors = getNumberOfSensors(cluster_counter);
118
119 // Extract the number of grid bins from counter histograms
120 unsigned short nBinsU = 0;
121 unsigned short nBinsV = 0;
122 getNumberOfBins(cluster_counter, nBinsU, nBinsV);
123
124 // Check that we have collected enough Data
125 if (cluster_counter->GetEntries() < int(safetyFactor * minClusters * nSensors * nBinsU * nBinsV)) {
126 if (not forceContinue) {
127 B2INFO("Not enough Data: Only " << cluster_counter->GetEntries() << " hits were collected but " << int(safetyFactor * minClusters*
128 nSensors * nBinsU * nBinsV) << " needed!");
129 return c_NotEnoughData;
130 } else {
131 B2INFO("Continue despite low statistics: Only " << cluster_counter->GetEntries() << " hits were collected but" << int(
133 nSensors * nBinsU * nBinsV) << " would be desirable!");
134 }
135 }
136
137 B2INFO("Start calibration using a " << nBinsU << "x" << nBinsV << " grid per sensor.");
138
139 // This is the PXD charge calibration payload for conditions DB
140 PXDClusterChargeMapPar* chargeMapPar = new PXDClusterChargeMapPar(nBinsU, nBinsV);
141
142 // Loop over all bins of input histo
143 for (auto histoBin = 1; histoBin <= cluster_counter->GetXaxis()->GetNbins(); histoBin++) {
144 // The bin label contains the vxdid, uBin and vBin
145 string label = cluster_counter->GetXaxis()->GetBinLabel(histoBin);
146
147 // Parse label string format to read sensorID, uBin and vBin
148 istringstream stream(label);
149 string token;
150 getline(stream, token, '_');
151 VxdID sensorID(token);
152
153 getline(stream, token, '_');
154 unsigned short uBin = std::stoi(token);
155
156 getline(stream, token, '_');
157 unsigned short vBin = std::stoi(token);
158
159 // Read back the counters for number of collected clusters
160 int numberOfDataHits = cluster_counter->GetBinContent(histoBin);
161
162 // Only perform fitting, when enough data is available
163 if (numberOfDataHits >= minClusters) {
164
165 // Compute the median cluster charge for the part of PXD
166 auto Charge = EstimateCharge(sensorID, uBin, vBin);
167
168 // Store the charge
169 chargeMapPar->setContent(sensorID.getID(), uBin, vBin, Charge);
170 } else {
171 B2WARNING(label << ": Number of data hits too small for fitting (" << numberOfDataHits << " < " << minClusters <<
172 "). Use default value of 0.");
173 chargeMapPar->setContent(sensorID.getID(), uBin, vBin, 0.0);
174 }
175 }
176
177 // Save the charge map to database. Note that this will set the database object name to the same as the collector but you
178 // are free to change it.
179 saveCalibration(chargeMapPar, "PXDClusterChargeMapPar");
180
181 B2INFO("PXD Cluster Charge Calibration Successful");
182 return c_OK;
183}
184
185
186double PXDChargeCalibrationAlgorithm::EstimateCharge(VxdID sensorID, unsigned short uBin, unsigned short vBin)
187{
188
189 // Construct a tree name for requested part of PXD
190 auto layerNumber = sensorID.getLayerNumber();
191 auto ladderNumber = sensorID.getLadderNumber();
192 auto sensorNumber = sensorID.getSensorNumber();
193 const string treename = str(format("tree_%1%_%2%_%3%_%4%_%5%") % layerNumber % ladderNumber % sensorNumber % uBin % vBin);
194 // Vector with cluster signals from collected data
195 vector<double> signals;
196
197 // Fill data_signal vector from input data
198 auto tree = getObjectPtr<TTree>(treename);
199 tree->SetBranchAddress("signal", &m_signal);
200
201 // Loop over tree
202 const auto nEntries = tree->GetEntries();
203 for (int i = 0; i < nEntries; ++i) {
204 tree->GetEntry(i);
205
206 double noise = gRandom->Gaus(0.0, noiseSigma);
207 signals.push_back(m_signal + noise);
208 }
209 if (strategy == 0) return CalculateMedian(signals);
210 if (strategy == 1) return FitLandau(signals);
211 else {
212 B2FATAL("strategy unavailable, use 0 for medians or 1 for landau fit!");
213 }
214}
215
216
218{
219 auto size = signals.size();
220
221 if (size == 0) {
222 return 0.0; // Undefined, really.
223 } else {
224 sort(signals.begin(), signals.end());
225 if (size % 2 == 0) {
226 return (signals[size / 2 - 1] + signals[size / 2]) / 2;
227 } else {
228 return signals[size / 2];
229 }
230 }
231}
232
233double PXDChargeCalibrationAlgorithm::FitLandau(vector<double>& signals)
234{
235 auto size = signals.size();
236 if (size == 0) return 0.0; // Undefined, really.
237
238 // get max and min values of vector
239 int max = *max_element(signals.begin(), signals.end());
240 int min = *min_element(signals.begin(), signals.end());
241
242
243 // create histogram to hold signals and fill it
244 TH1D* hist_signals = new TH1D("", "", max - min, min, max);
245 for (auto it = signals.begin(); it != signals.end(); ++it) {
246 hist_signals->Fill(*it);
247 }
248
249 // create fit function
250 TF1* landau = new TF1("landau", "TMath::Landau(x,[0],[1])*[2]", min, max);
251 landau->SetParNames("MPV", "sigma", "scale");
252 landau->SetParameters(100, 1, 1000);
253
254 //do fit and get results, fit range restricted to exclude low charge peak
255 Int_t status = hist_signals->Fit("landau", "Lq", "", 30, 350);
256 double MPV = landau->GetParameter("MPV");
257
258 // clean up
259 delete hist_signals;
260 delete landau;
261
262 // check fit status
263 if (status == 0) return MPV;
264 else {
265 B2WARNING("Fit failed! using default value 0.0!");
266 return 0.0;
267 }
268}
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.
double EstimateCharge(VxdID sensorID, unsigned short uBin, unsigned short vBin)
Estimate median charge form collected clusters on part of PXD.
double FitLandau(std::vector< double > &signals)
calculate MPV of unsorted signal vector using a Landau fit
PXDChargeCalibrationAlgorithm()
Constructor set the prefix to PXDChargeCalibrationAlgorithm.
int minClusters
Minimum number of collected clusters for estimating median charge.
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
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 cluster charge calibrations.
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.
Definition: VxdID.h:33
baseType getID() const
Get the unique id.
Definition: VxdID.h:94
baseType getSensorNumber() const
Get the sensor id.
Definition: VxdID.h:100
baseType getLadderNumber() const
Get the ladder id.
Definition: VxdID.h:98
baseType getLayerNumber() const
Get the layer id.
Definition: VxdID.h:96
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.
STL namespace.