Skip to content

Commit e60899c

Browse files
sweyh99Sierra Weyhmiller
andauthored
[EMCAL-529] Change NumPatchesPerFastORCheck to nsigma over mean checker (#2330)
* [EMCAL-529] Change NumPatchesPerFastORCheck to nsigma over mean checker Determine if a FastOR is noisy by how many sigma it is over the mean FastOR noise level Remove from the list of noisy FastORs any neighboring FastORs to the noisiest ones * [EMCAL-529] Changed to linear loops instead of nested loops --------- Co-authored-by: Sierra Weyhmiller <sierra.lisa.weyhmiller@cern.ch>
1 parent 6018214 commit e60899c

2 files changed

Lines changed: 170 additions & 71 deletions

File tree

Modules/EMCAL/include/EMCAL/NumPatchesPerFastORCheck.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,35 @@ class NumPatchesPerFastORCheck : public o2::quality_control::checker::CheckInter
6464
}
6565
};
6666

67+
struct FastORNoiseLevel {
68+
int mCounts;
69+
int mFastORID;
70+
int mPosGlobalPhi;
71+
int mPosGlobalEta;
72+
bool mRejected;
73+
74+
bool operator==(const FastORNoiseLevel& other) const
75+
{
76+
return (mCounts == other.mCounts && mFastORID == other.mFastORID);
77+
}
78+
79+
bool operator<(const FastORNoiseLevel& other) const
80+
{
81+
if (mCounts == other.mCounts) {
82+
return mFastORID < other.mFastORID;
83+
}
84+
return mCounts < other.mCounts;
85+
}
86+
};
87+
6788
private:
6889
/************************************************
6990
* threshold cuts *
7091
************************************************/
7192

72-
float mBadThresholdNumPatchesPerFastOR = 4.; ///< Bad Threshold used in the Number of Patches Per FastOR check
73-
float mMediumThresholdNumPatchesPerFastOR = 2.; ///< Bad Threshold used in the Number of Patches Per FastOR check
74-
float mSigmaTSpectrum = 0.1; ///< TSpectrum parameter sigma
75-
float mThreshTSpectrum = 0.01; ///< TSpectrum parameter threshold
76-
int mLogLevelIL = 0; ///< Log level on InfoLogger
93+
float mBadSigmaNumPatchesPerFastOR = 5.; ///< Number of sigmas used in the Number of Patches Per FastOR fastORs outside of mean bad check
94+
float mMedSigmaNumPatchesPerFastOR = 3.; ///< Number of sigmas used in the Number of Patches Per FastOR fastORs outside of mean medium check
95+
int mLogLevelIL = 0; ///< Log level on InfoLogger
7796

7897
o2::emcal::Geometry* mGeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); ///< Geometry for mapping position between SM and full EMCAL
7998
std::unique_ptr<o2::emcal::TriggerMappingV2> mTriggerMapping = std::make_unique<o2::emcal::TriggerMappingV2>(mGeometry); ///!<! Trigger mapping

Modules/EMCAL/src/NumPatchesPerFastORCheck.cxx

Lines changed: 146 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include <TRobustEstimator.h>
3232
#include <TMath.h>
3333
#include <ROOT/TSeq.hxx>
34-
#include <TSpectrum.h>
3534
#include <iostream>
3635
#include <vector>
3736
#include <sstream>
@@ -41,43 +40,31 @@ using namespace std;
4140
namespace o2::quality_control_modules::emcal
4241
{
4342

44-
void NumPatchesPerFastORCheck::configure()
43+
bool compareDescending(const NumPatchesPerFastORCheck::FastORNoiseLevel& noise1, const NumPatchesPerFastORCheck::FastORNoiseLevel& noise2)
4544
{
46-
// configure threshold-based checkers for bad quality
47-
auto nBadThresholdNumPatchesPerFastOR = mCustomParameters.find("BadThresholdNumPatchesPerFastOR");
48-
if (nBadThresholdNumPatchesPerFastOR != mCustomParameters.end()) {
49-
try {
50-
mBadThresholdNumPatchesPerFastOR = std::stof(nBadThresholdNumPatchesPerFastOR->second);
51-
} catch (std::exception& e) {
52-
ILOG(Error, Support) << "Value " << nBadThresholdNumPatchesPerFastOR->second.data() << " not a float" << ENDM;
53-
}
54-
}
55-
56-
auto nMediumThresholdNumPatchesPerFastOR = mCustomParameters.find("MediumThresholdNumPatchesPerFastOR");
57-
if (nMediumThresholdNumPatchesPerFastOR != mCustomParameters.end()) {
58-
try {
59-
mMediumThresholdNumPatchesPerFastOR = std::stof(nMediumThresholdNumPatchesPerFastOR->second);
60-
} catch (std::exception& e) {
61-
ILOG(Error, Support) << "Value " << nMediumThresholdNumPatchesPerFastOR->second.data() << " not a float" << ENDM;
62-
}
45+
if (noise1.mCounts == noise2.mCounts) {
46+
return noise1.mFastORID > noise2.mFastORID; // Sort by mFastORID in descending order if mCounts are equal
6347
}
48+
return noise1.mCounts > noise2.mCounts; // Used to sort by count in descending order
49+
}
6450

65-
// configure TSpectrum parameters
66-
auto nSigmaTSpectrum = mCustomParameters.find("TSpecSigma");
67-
if (nSigmaTSpectrum != mCustomParameters.end()) {
51+
void NumPatchesPerFastORCheck::configure()
52+
{
53+
// configure nsigma-based checkers
54+
auto nBadSigmaNumPatchesPerFastOR = mCustomParameters.find("BadSigmaNumPatchesPerFastOR");
55+
if (nBadSigmaNumPatchesPerFastOR != mCustomParameters.end()) {
6856
try {
69-
mSigmaTSpectrum = std::stof(nSigmaTSpectrum->second);
57+
mBadSigmaNumPatchesPerFastOR = std::stof(nBadSigmaNumPatchesPerFastOR->second);
7058
} catch (std::exception& e) {
71-
ILOG(Error, Support) << "Value " << nSigmaTSpectrum->second.data() << " not a float" << ENDM;
59+
ILOG(Error, Support) << "Value " << nBadSigmaNumPatchesPerFastOR->second << " not a float" << ENDM;
7260
}
7361
}
74-
75-
auto nThreshTSpectrum = mCustomParameters.find("TSpecThresh");
76-
if (nThreshTSpectrum != mCustomParameters.end()) {
62+
auto nMedSigmaNumPatchesPerFastOR = mCustomParameters.find("MedSigmaNumPatchesPerFastOR");
63+
if (nMedSigmaNumPatchesPerFastOR != mCustomParameters.end()) {
7764
try {
78-
mThreshTSpectrum = std::stof(nThreshTSpectrum->second);
65+
mMedSigmaNumPatchesPerFastOR = std::stof(nMedSigmaNumPatchesPerFastOR->second);
7966
} catch (std::exception& e) {
80-
ILOG(Error, Support) << "Value " << nThreshTSpectrum->second.data() << " not a float" << ENDM;
67+
ILOG(Error, Support) << "Value " << nMedSigmaNumPatchesPerFastOR->second << " not a float" << ENDM;
8168
}
8269
}
8370

@@ -96,13 +83,21 @@ Quality NumPatchesPerFastORCheck::check(std::map<std::string, std::shared_ptr<Mo
9683
auto mo = moMap->begin()->second;
9784
Quality result = Quality::Good;
9885
mNoisyTRUPositions.clear();
86+
mHighCountTRUPositions.clear();
9987
std::stringstream messagebuilder;
10088

89+
std::vector<FastORNoiseLevel> candBadFastORs;
90+
std::vector<FastORNoiseLevel> finalBadFastORs;
91+
std::vector<FastORNoiseLevel> candMedFastORs;
92+
std::vector<FastORNoiseLevel> finalMedFastORs;
93+
10194
if (mo->getName() == "NumberOfPatchesWithFastOR") {
10295
auto* h = dynamic_cast<TH1*>(mo->getObject());
10396
if (h->GetEntries() == 0) {
10497
result = Quality::Medium;
10598
} else {
99+
100+
// Determine the threshold for bad and medium FastOR candidates
106101
std::vector<double> smcounts;
107102
for (auto ib : ROOT::TSeqI(0, h->GetXaxis()->GetNbins())) {
108103
auto countSM = h->GetBinContent(ib + 1);
@@ -117,43 +112,121 @@ Quality NumPatchesPerFastORCheck::check(std::map<std::string, std::shared_ptr<Mo
117112
double mean, sigma;
118113
meanfinder.EvaluateUni(smcounts.size(), smcounts.data(), mean, sigma);
119114

120-
TSpectrum peakfinder;
121-
Int_t nfound = peakfinder.Search(h, mSigmaTSpectrum, "nobackground", mThreshTSpectrum); // Search for peaks //CHANGE - make config?
122-
Double_t* xpeaks = peakfinder.GetPositionX();
123-
Double_t* ypeaks = peakfinder.GetPositionY();
124-
std::sort(ypeaks, ypeaks + nfound, std::greater<double>()); // sort peaks in descending order to easy pick the y value of max peak
125-
double thresholdBad = mBadThresholdNumPatchesPerFastOR * mean,
126-
thresholdMedium = mMediumThresholdNumPatchesPerFastOR * mean;
127-
128-
for (Int_t n_peak = 0; n_peak < nfound; n_peak++) {
129-
Int_t bin = h->GetXaxis()->FindBin(xpeaks[n_peak]);
130-
Double_t peak_val = h->GetBinContent(bin);
131-
132-
if (peak_val > thresholdBad || peak_val > thresholdMedium) {
133-
Double_t peak_pos = h->GetXaxis()->GetBinCenter(bin);
134-
auto [truID, fastorTRU] = mTriggerMapping->getTRUFromAbsFastORIndex(peak_pos);
135-
auto [truID1, posEta, posPhi] = mTriggerMapping->getPositionInTRUFromAbsFastORIndex(peak_pos);
136-
FastORNoiseInfo obj{ static_cast<int>(truID), static_cast<int>(fastorTRU), static_cast<int>(posPhi), static_cast<int>(posEta) };
137-
if (peak_val > thresholdBad) {
138-
result = Quality::Bad;
139-
std::string errorMessage = "TRU " + std::to_string(truID) + " has a noisy FastOR at position " + std::to_string(fastorTRU) + " (eta " + std::to_string(posEta) + ", phi " + std::to_string(posPhi) + ") in TRU.";
140-
messagebuilder << errorMessage << std::endl;
141-
if (mLogLevelIL > 1) {
142-
ILOG(Error, Support) << errorMessage << ENDM;
115+
double thresholdBad = mean + mBadSigmaNumPatchesPerFastOR * sigma,
116+
thresholdMedium = mean + mMedSigmaNumPatchesPerFastOR * sigma;
117+
118+
// Find the noisy FastOR candidates
119+
for (auto ib : ROOT::TSeqI(0, h->GetXaxis()->GetNbins())) {
120+
if (h->GetBinContent(ib + 1) > thresholdMedium) {
121+
if (result != Quality::Bad) {
122+
result = Quality::Medium;
123+
}
124+
auto [posEta, posPhi] = mTriggerMapping->getPositionInEMCALFromAbsFastORIndex(h->GetXaxis()->GetBinCenter(ib + 1));
125+
FastORNoiseLevel cand{ static_cast<int>(h->GetBinContent(ib + 1)), static_cast<int>(h->GetXaxis()->GetBinCenter(ib + 1)), static_cast<int>(posPhi), static_cast<int>(posEta), false };
126+
candMedFastORs.push_back(cand);
127+
}
128+
if (h->GetBinContent(ib + 1) > thresholdBad) {
129+
result = Quality::Bad;
130+
auto [posEta, posPhi] = mTriggerMapping->getPositionInEMCALFromAbsFastORIndex(h->GetXaxis()->GetBinCenter(ib + 1));
131+
FastORNoiseLevel cand{ static_cast<int>(h->GetBinContent(ib + 1)), static_cast<int>(h->GetXaxis()->GetBinCenter(ib + 1)), static_cast<int>(posPhi), static_cast<int>(posEta), false };
132+
candBadFastORs.push_back(cand);
133+
}
134+
}
135+
136+
// Sort the noisy FastOR candidates in descending counts order
137+
std::sort(candBadFastORs.begin(), candBadFastORs.end(), compareDescending);
138+
std::sort(candMedFastORs.begin(), candMedFastORs.end(), compareDescending);
139+
140+
// Array to store whether eta,phi position should be removed
141+
const int rows = 48; // eta 0-47
142+
const int cols = 104; // phi 0-103
143+
bool bad_ignore[rows][cols] = { false };
144+
bool med_ignore[rows][cols] = { false };
145+
146+
// Loop over the candidate Bad FastORs to find the smaller nearby FastORs
147+
for (std::vector<FastORNoiseLevel>::iterator i = candBadFastORs.begin(); i != candBadFastORs.end(); i++) {
148+
149+
if (i->mRejected) {
150+
continue;
151+
}
152+
153+
// Check at the begining if the element's phi eta should be ignored and if so set rejected = true and skip it.
154+
int high_posEta = i->mPosGlobalEta;
155+
int high_posPhi = i->mPosGlobalPhi;
156+
157+
if (bad_ignore[high_posEta][high_posPhi] == true) {
158+
i->mRejected = true;
159+
continue;
160+
}
161+
162+
// Ignore what is near the current highest FastOR
163+
for (int eta = high_posEta - 1; eta <= high_posEta + 1; eta++) {
164+
for (int phi = high_posPhi - 1; phi <= high_posPhi + 1; phi++) {
165+
if (eta >= 0 && eta < rows && phi >= 0 && phi < cols && !(eta == high_posEta && phi == high_posPhi)) {
166+
bad_ignore[eta][phi] = true;
143167
}
144-
mNoisyTRUPositions.insert(obj);
145-
} else if (peak_val > thresholdMedium) {
146-
if (result != Quality::Bad) {
147-
result = Quality::Medium;
148-
std::string errorMessage = "TRU " + std::to_string(truID) + " has a high rate in FastOR at position " + std::to_string(fastorTRU) + " (eta " + std::to_string(posEta) + ", phi " + std::to_string(posPhi) + ") in TRU.";
149-
messagebuilder << errorMessage << std::endl;
150-
if (mLogLevelIL > 2) {
151-
ILOG(Warning, Support) << errorMessage << ENDM;
152-
}
153-
mHighCountTRUPositions.insert(obj);
168+
}
169+
}
170+
171+
// Save the final bad FastORs
172+
FastORNoiseLevel final{ i->mCounts, i->mFastORID, i->mPosGlobalPhi, i->mPosGlobalEta, i->mRejected };
173+
finalBadFastORs.push_back(final);
174+
}
175+
176+
// Save the positions of the final Bad FastORs and display the error message
177+
for (std::vector<FastORNoiseLevel>::iterator itFinal = finalBadFastORs.begin(); itFinal != finalBadFastORs.end(); itFinal++) {
178+
auto [truID, fastorTRU] = mTriggerMapping->getTRUFromAbsFastORIndex(itFinal->mFastORID);
179+
auto [truID1, posEta, posPhi] = mTriggerMapping->getPositionInTRUFromAbsFastORIndex(itFinal->mFastORID);
180+
FastORNoiseInfo obj{ static_cast<int>(truID), static_cast<int>(fastorTRU), static_cast<int>(posPhi), static_cast<int>(posEta) };
181+
std::string errorMessage = "TRU " + std::to_string(truID) + " has a noisy FastOR at position " + std::to_string(fastorTRU) + " (eta " + std::to_string(posEta) + ", phi " + std::to_string(posPhi) + ") in TRU.";
182+
messagebuilder << errorMessage << std::endl;
183+
if (mLogLevelIL > 1) {
184+
ILOG(Error, Support) << errorMessage << ENDM;
185+
}
186+
mNoisyTRUPositions.insert(obj);
187+
}
188+
189+
// Loop over the candidate Med FastORs to find the smaller nearby FastORs
190+
for (std::vector<FastORNoiseLevel>::iterator i = candMedFastORs.begin(); i != candMedFastORs.end(); i++) {
191+
192+
if (i->mRejected) {
193+
continue;
194+
}
195+
196+
// Check at the begining if the element's phi eta should be ignored and if so set rejected = true and skip it.
197+
int high_posEta = i->mPosGlobalEta;
198+
int high_posPhi = i->mPosGlobalPhi;
199+
200+
if (med_ignore[high_posEta][high_posPhi] == true) {
201+
i->mRejected = true;
202+
continue;
203+
}
204+
205+
// Ignore what is near the current highest FastOR
206+
for (int eta = high_posEta - 1; eta <= high_posEta + 1; eta++) {
207+
for (int phi = high_posPhi - 1; phi <= high_posPhi + 1; phi++) {
208+
if (eta >= 0 && eta < rows && phi >= 0 && phi < cols && !(eta == high_posEta && phi == high_posPhi)) {
209+
med_ignore[eta][phi] = true;
154210
}
155211
}
156212
}
213+
214+
// Save the final med FastORs
215+
FastORNoiseLevel final{ i->mCounts, i->mFastORID, i->mPosGlobalPhi, i->mPosGlobalEta, i->mRejected };
216+
finalMedFastORs.push_back(final);
217+
}
218+
219+
// Save the positions of the final Med FastORs and display the error message
220+
for (std::vector<FastORNoiseLevel>::iterator itFinal = finalMedFastORs.begin(); itFinal != finalMedFastORs.end(); itFinal++) {
221+
auto [truID, fastorTRU] = mTriggerMapping->getTRUFromAbsFastORIndex(itFinal->mFastORID);
222+
auto [truID1, posEta, posPhi] = mTriggerMapping->getPositionInTRUFromAbsFastORIndex(itFinal->mFastORID);
223+
FastORNoiseInfo obj{ static_cast<int>(truID), static_cast<int>(fastorTRU), static_cast<int>(posPhi), static_cast<int>(posEta) };
224+
std::string errorMessage = "TRU " + std::to_string(truID) + " has a high rate in FastOR at position " + std::to_string(fastorTRU) + " (eta " + std::to_string(posEta) + ", phi " + std::to_string(posPhi) + ") in TRU.";
225+
messagebuilder << errorMessage << std::endl;
226+
if (mLogLevelIL > 2) {
227+
ILOG(Warning, Support) << errorMessage << ENDM;
228+
}
229+
mHighCountTRUPositions.insert(obj);
157230
}
158231
}
159232
}
@@ -167,10 +240,17 @@ std::string NumPatchesPerFastORCheck::getAcceptedType() { return "TH1"; }
167240

168241
void NumPatchesPerFastORCheck::beautify(std::shared_ptr<MonitorObject> mo, Quality checkResult)
169242
{
170-
// To do - good message
171243
if (mo->getName() == "NumberOfPatchesWithFastOR") {
172244
auto* h = dynamic_cast<TH1*>(mo->getObject());
173-
if (checkResult == Quality::Bad) {
245+
if (checkResult == Quality::Good) {
246+
TPaveText* msg = new TPaveText(0.12, 0.84, 0.88, 0.94, "NDC");
247+
h->GetListOfFunctions()->Add(msg);
248+
msg->SetName(Form("%s_msg", mo->GetName()));
249+
msg->Clear();
250+
msg->AddText("Data OK: No Outlier Noisy FastORs");
251+
msg->SetFillColor(kGreen);
252+
msg->Draw();
253+
} else if (checkResult == Quality::Bad) {
174254
TLatex* msg;
175255
msg = new TLatex(0.15, 0.84, "#color[2]{Error: Noisy TRU(s)}");
176256
msg->SetNDC();
@@ -197,7 +277,7 @@ void NumPatchesPerFastORCheck::beautify(std::shared_ptr<MonitorObject> mo, Quali
197277
}
198278
for (const auto& noiseinfo : mHighCountTRUPositions) {
199279
stringstream errorMessageIndiv;
200-
errorMessageIndiv << "Position " << noiseinfo.mFastORIndex << " (eta " << noiseinfo.mPosEta << ", phi " << noiseinfo.mPosPhi << ") in TRU " << noiseinfo.mTRUIndex << " has high counts" << std::endl;
280+
errorMessageIndiv << "Position " << noiseinfo.mFastORIndex << " (eta " << noiseinfo.mPosEta << ", phi " << noiseinfo.mPosPhi << ") in TRU " << noiseinfo.mTRUIndex << " has high counts." << std::endl;
201281
msg = new TLatex(0.15, 0.8 - iErr / 25., errorMessageIndiv.str().c_str());
202282
msg->SetNDC();
203283
msg->SetTextSize(16);
@@ -221,7 +301,7 @@ void NumPatchesPerFastORCheck::beautify(std::shared_ptr<MonitorObject> mo, Quali
221301
int iErr = 0;
222302
for (const auto& noiseinfo : mHighCountTRUPositions) {
223303
stringstream errorMessageIndiv;
224-
errorMessageIndiv << "Position " << noiseinfo.mFastORIndex << " (eta " << noiseinfo.mPosEta << ", phi " << noiseinfo.mPosPhi << ") in TRU " << noiseinfo.mTRUIndex << " has high counts" << std::endl;
304+
errorMessageIndiv << "Position " << noiseinfo.mFastORIndex << " (eta " << noiseinfo.mPosEta << ", phi " << noiseinfo.mPosPhi << ") in TRU " << noiseinfo.mTRUIndex << " has high counts." << std::endl;
225305
msg = new TLatex(0.15, 0.8 - iErr / 25., errorMessageIndiv.str().c_str());
226306
msg->SetNDC();
227307
msg->SetTextSize(16);

0 commit comments

Comments
 (0)