9#include <pxd/calibration/PXDHotPixelMaskCalibrationAlgorithm.h>
10#include <pxd/dbobjects/PXDMaskedPixelPar.h>
11#include <pxd/dbobjects/PXDDeadPixelPar.h>
12#include <pxd/dbobjects/PXDOccupancyInfoPar.h>
13#include <vxd/dataobjects/VxdID.h>
15#include <boost/format.hpp>
33 " -------------------------- PXDHotPixelMak Calibration Algorithm ------------------------\n"
35 " Algorithm which masks hot pixels with too large occupancy and dead pixels w/o no hits. \n"
36 " ----------------------------------------------------------------------------------------\n"
47 TDirectory* currentDir = gDirectory;
51 std::string fileName = (this->
getPrefix()) +
"debug.root";
52 B2INFO(
"Creating file " << fileName);
53 m_file = std::make_shared<TFile>(fileName.c_str(),
"RECREATE");
57 string iov_str = str(format(
"E%1%_R%2%_E%3%_R%4%") % expRuns.front().first
58 % expRuns.front().second % expRuns.back().first % expRuns.back().second);
59 m_file->mkdir(iov_str.c_str());
60 m_file->cd(iov_str.c_str());
66 auto nevents = collector_pxdhits->GetEntries();
68 for (
auto sensBin = 1; sensBin <= collector_pxdhitcounts->GetXaxis()->GetNbins(); sensBin++) {
69 string sensorDescr = collector_pxdhitcounts->GetXaxis()->GetBinLabel(sensBin);
70 VxdID id(sensorDescr);
73 string name = str(format(
"PXD_%1%_PixelHitmap") %
id.
getID());
75 if (collector_pxdhitmap ==
nullptr) {
78 TH1I* debugHisto =
new TH1I(*collector_pxdhitmap);
80 debugHisto->SetBinContent(debugHisto->GetNbinsX() + 1, nevents);
86 if (expRuns.back() == expRunsAll.back()) {
87 B2INFO(
"Reached Final ExpRun: (" << expRuns.back().first <<
", " << expRuns.back().second <<
")");
101 if (!collector_pxdhits) {
109 auto nevents = collector_pxdhits->GetEntries();
112 B2INFO(
"Not enough data: Only " << nevents <<
" events were collected!");
115 B2WARNING(
"Not enough data: Only " << nevents <<
" events were collected! The masking continuous but the mask may be empty.");
119 B2RESULT(
"Found total of " << nevents <<
" events in collected data.");
122 unsigned long long int nPXDHits = 0;
124 for (
auto sensBin = 1; sensBin <= collector_pxdhitcounts->GetXaxis()->GetNbins(); sensBin++) {
126 string sensorDescr = collector_pxdhitcounts->GetXaxis()->GetBinLabel(sensBin);
127 VxdID id(sensorDescr);
131 unsigned long long int nSensorHits = collector_pxdhitcounts->GetBinContent(sensBin);
132 nPXDHits += nSensorHits;
134 B2RESULT(
"Number of hits for sensor sensor=" <<
id <<
" is " << nSensorHits);
139 if (nPXDHits < minPXDHits) {
141 B2INFO(
"Not enough data: Only " << nPXDHits <<
" raw hits were collected!");
144 B2WARNING(
"Not enough data: Only " << nPXDHits <<
" raw hits were collected! The masking continuous but the mask may be empty.");
148 B2RESULT(
"Found total of " << nPXDHits <<
" raw hits in collected data.");
151 for (
auto sensBin = 1; sensBin <= collector_pxdhitcounts->GetXaxis()->GetNbins(); sensBin++) {
153 string sensorDescr = collector_pxdhitcounts->GetXaxis()->GetBinLabel(sensBin);
154 VxdID id(sensorDescr);
159 string name = str(format(
"PXD_%1%_PixelHitmap") %
id.
getID());
163 if (collector_pxdhitmap ==
nullptr)
continue;
166 int nBins = collector_pxdhitmap->GetXaxis()->GetNbins();
168 vector<double> hitVec(nBins);
170 for (
auto bin = 1; bin <= nBins; bin++) {
171 hitVec[bin - 1] = (double) collector_pxdhitmap->GetBinContent(bin);
173 double medianNumberOfHits;
174 TMath::Quantiles(nBins, 1, &hitVec[0], &medianNumberOfHits, &prob, kFALSE);
175 if (medianNumberOfHits <= 0) {
176 B2WARNING(
"Median number of hits per senor is smaller <1. Raise median to 1 instead.");
177 medianNumberOfHits = 1;
179 B2RESULT(
"Median of hits is " << medianNumberOfHits <<
" for sensor " <<
id);
186 if (medianNumberOfHits <
minHits) {
188 B2INFO(
"Not enough data: Median number of his is only " << medianNumberOfHits <<
"!");
191 B2WARNING(
"Not enough data: Median number of hits is only " << medianNumberOfHits <<
192 "! The masking continuous but the mask may be empty.");
210 for (
auto sensBin = 1; sensBin <= collector_pxdhitcounts->GetXaxis()->GetNbins(); sensBin++) {
212 string sensorDescr = collector_pxdhitcounts->GetXaxis()->GetBinLabel(sensBin);
213 VxdID id(sensorDescr);
216 int nSensorHits = collector_pxdhitcounts->GetBinContent(sensBin);
217 if (nSensorHits == 0) {
223 string name = str(format(
"PXD_%1%_PixelHitmap") %
id.
getID());
225 if (collector_pxdhitmap ==
nullptr) {
226 B2WARNING(
"Cannot find PixelHitmap although there should be hits. This is strange!");
231 int nBins = collector_pxdhitmap->GetXaxis()->GetNbins();
234 if (medianNumberOfHits >=
minHits) {
238 vector<int> hitsAlongDrain(
c_nDrains, 0);
243 B2RESULT(
"Pixel hit threshold for dead rows is " << inefficientPixelHitThr <<
" for sensor " <<
id);
245 for (
auto bin = 1; bin <= nBins; bin++) {
250 int drainID = uCell * 4 + vCell % 4;
251 int nhits = collector_pxdhitmap->GetBinContent(bin);
252 hitsAlongDrain[drainID] += nhits;
253 hitsAlongRow[vCell] += nhits;
255 nDeadAlongRow[vCell] += 1;
259 B2INFO(
"Entering masking of dead rows ...");
260 for (
auto vCell = 0; vCell <
c_nVCells; vCell++) {
262 int nhits = hitsAlongRow[vCell];
263 int nDeadPixels = nDeadAlongRow[vCell];
267 B2RESULT(
"Dead row with vCell=" << vCell <<
" on sensor " <<
id);
273 B2INFO(
"Entering masking of dead drains ...");
274 for (
auto drainID = 0; drainID <
c_nDrains; drainID++) {
276 int nhits = hitsAlongDrain[drainID];
280 B2RESULT(
"Dead drain line at drainID=" << drainID <<
" on sensor " <<
id);
285 B2INFO(
"Entering masking of single dead pixels ...");
286 for (
auto bin = 1; bin <= nBins; bin++) {
288 int nhits = collector_pxdhitmap->GetBinContent(bin);
292 int drainID = uCell * 4 + vCell % 4;
294 if (nhits == 0 && !deadPixelsPar->
isDeadRow(
id.getID(), vCell) && !deadPixelsPar->
isDeadDrain(
id.getID(), drainID)) {
297 B2RESULT(
"Dead single pixel with ucell=" << uCell <<
", vcell=" << vCell <<
" on sensor " <<
id);
305 vector<float> unmaskedHitsAlongDrain(
c_nDrains, 0);
306 vector<int> unmaskedCellsAlongDrain(
c_nDrains, 0);
309 vector<float> unmaskedHitsAlongRow(
c_nVCells, 0);
310 vector<int> unmaskedCellsAlongRow(
c_nVCells, 0);
314 B2RESULT(
"Pixel hit threshold is " << pixelHitThr <<
" for sensor " <<
id);
317 for (
auto bin = 1; bin <= nBins; bin++) {
322 int drainID = uCell * 4 + vCell % 4;
325 float nhits = collector_pxdhitmap->GetBinContent(bin);
328 if (nhits > pixelHitThr) {
332 B2RESULT(
"Masking single pixel with ucell=" << uCell <<
", vcell=" << vCell <<
" on sensor " <<
id);
338 ++unmaskedCellsAlongDrain[drainID];
339 unmaskedHitsAlongDrain[drainID] += nhits;
340 ++unmaskedCellsAlongRow[vCell];
341 unmaskedHitsAlongRow[vCell] += nhits;
347 B2RESULT(
"Drain hit threshold is " << drainHitThr <<
" for sensor " <<
id);
349 for (
auto drainID = 0; drainID <
c_nDrains; drainID++) {
350 if (unmaskedCellsAlongDrain[drainID] > 0) {
352 float nhits = unmaskedHitsAlongDrain[drainID] / unmaskedCellsAlongDrain[drainID];
354 if (nhits > drainHitThr) {
355 for (
auto iGate = 0; iGate < 192; iGate++) {
356 int uCell = drainID / 4;
357 int vCell = drainID % 4 + iGate * 4;
360 B2RESULT(
"Masking drain line with drainID=" << drainID <<
" on sensor " <<
id);
368 B2RESULT(
"Row hit threshold is " << rowHitThr <<
" for sensor " <<
id);
370 for (
auto vCell = 0; vCell <
c_nVCells; vCell++) {
371 if (unmaskedCellsAlongRow[vCell] > 0) {
373 float nhits = unmaskedHitsAlongRow[vCell] / unmaskedCellsAlongRow[vCell];
375 if (nhits > rowHitThr) {
376 for (
auto uCell = 0; uCell <
c_nUCells; uCell++)
379 B2RESULT(
"Masking complete row with vCell=" << vCell <<
" on sensor " <<
id);
389 int numberOfUnmaskedHits = 0;
391 for (
auto bin = 1; bin <= nBins; bin++) {
395 if (maskedPixelsPar->
pixelOK(
id.getID(), pixID)) {
396 numberOfUnmaskedHits += collector_pxdhitmap->GetBinContent(bin);
401 float meanOccupancyAfterMasking = (float)numberOfUnmaskedHits / nevents /
c_nVCells /
c_nUCells;
402 B2RESULT(
"Hotpixel filtered occupancy sensor=" <<
id <<
" is " << meanOccupancyAfterMasking);
408 auto id = elem.first;
409 auto singles = elem.second;
410 B2RESULT(
"SensorID " <<
VxdID(
id) <<
" has filtered occupancy of " << occupancyInfoPar->
getOccupancy(
id));
411 B2RESULT(
"SensorID " <<
VxdID(
id) <<
" has fraction of masked pixels of " << (
float)singles.size() / (
c_nVCells *
c_nUCells));
423 B2INFO(
"PXDHotPixelMask Calibration Successful");
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
std::vector< Calibration::ExpRun > getRunListFromAllData() const
Get the complete list of runs from inspection of collected data.
void setDescription(const std::string &description)
Set algorithm description (in constructor)
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
std::string getPrefix() const
Get the prefix used for getting calibration data.
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 telling which PXD pixel is dead (=Readout system does not receive signals)
void maskSensor(unsigned short sensorID)
Mask sensor.
void maskRow(unsigned short sensorID, unsigned int vCellID)
Mask single row.
void maskSinglePixel(unsigned short sensorID, unsigned int pixID)
Mask single pixel.
void maskDrain(unsigned short sensorID, unsigned int drainID)
Mask single drain.
bool isDeadDrain(unsigned short sensorID, unsigned int drainID) const
Check whether a drain is dead.
bool isDeadRow(unsigned short sensorID, unsigned int vCellID) const
Check whether a row is dead.
float inefficientPixelMultiplier
The occupancy threshold for inefficient (or dead) pixels is the median occupancy x inefficientPixelMu...
bool maskRows
Mask hot rows with too high average occupancy after single pixel masking.
int minEvents
Minimum number of collected events.
std::map< VxdID, double > m_medianOfHitsMap
map of VxdID to median hits of each sensor
float drainMultiplier
The occupancy threshold for masking hot drains is the median occupancy x drainMultiplier.
int minInefficientPixels
The minimum number of inefficient (or dead) pixels per row to define an inefficient row.
const unsigned short c_nDrains
Number of drain lines of Belle II PXD sensors.
bool maskDrains
Mask hot drain lines with too high average occupancy after single pixel masking.
const unsigned short c_nVCells
Number of vCells of Belle II PXD sensors.
int m_debugHisto
Set if a debugging histogram should be created in the algorithm output directory.
float pixelMultiplier
The occupancy threshold for masking hot single pixels is the median occupancy x pixelMultiplier.
const unsigned short c_nUCells
Number of uCells of Belle II PXD sensors.
std::shared_ptr< TFile > m_file
Pointer for TFile.
PXDHotPixelMaskCalibrationAlgorithm()
Constructor set the prefix to PXDHotPixelMaskCalibrationAlgorithm.
float rowMultiplier
The occupancy threshold for masking hot rows is the median occupancy x rowMultiplier.
virtual EResult calibrate() override
Run algo on data.
bool forceContinueMasking
Force continue masking in almost empty runs instead of returning c_NotEnoughData.
int minHits
Minimum median number of hits per pixel needed for dead pixel masking.
std::string deadPixelPayloadName
Payload name for PXDDeadPixelPar used for more defective pixels from damaged gates.
void createDebugHistogram()
Perform debug histogram file creation.
The payload telling which PXD pixel to mask (ignore)
bool pixelOK(unsigned short sensorID, unsigned int pixID) const
Check whether a pixel on a given sensor is OK or not.
const std::unordered_map< unsigned short, MaskedSinglePixelsSet > & getMaskedPixelMap() const
Return unordered_map with all masked single pixels in PXD.
void maskSinglePixel(unsigned short sensorID, unsigned int pixID)
Mask single pixel.
The payload collecting some meta information from running the masking algorithm.
void setOccupancy(unsigned short sensorID, float occupancy)
Set occupancy.
void setNumberOfEvents(int nEvents)
Set number of events used for occupancy estimation.
float getOccupancy(unsigned short sensorID) const
Get occupancy.
Class to uniquely identify a any structure of the PXD and SVD.
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...
int getID(const std::vector< double > &breaks, double t)
get id of the time point t
Abstract base class for different kinds of events.