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;
4140namespace 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
168241void 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