Belle II Software development
DQMHistAnalysisKLM.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/* Own header. */
10#include <dqm/analysis/modules/DQMHistAnalysisKLM.h>
11
12/* Basf2 headers. */
13#include <klm/dataobjects/KLMChannelIndex.h>
14
15/* ROOT headers. */
16#include <TClass.h>
17#include <TROOT.h>
18#include <TStyle.h>
19
20/* C++ headers. */
21#include <algorithm>
22
23using namespace Belle2;
24
25REG_MODULE(DQMHistAnalysisKLM);
26
30 m_IsNullRun{false},
33 m_ElementNumbers{&(KLMElementNumbers::Instance())},
35{
36 setDescription("Module used to analyze KLM DQM histograms.");
37 addParam("ThresholdForMasked", m_ThresholdForMasked,
38 "Threshold X for masked channels: if a channel has an occupancy X times larger than the average, it will be masked.", 100);
39 addParam("ThresholdForHot", m_ThresholdForHot,
40 "Threshold Y for hot channels: if a channel has an occupancy Y times larger than the average, it will be marked as hot (but not masked).",
41 10);
42 addParam("ThresholdForLog", m_ThresholdForLog,
43 "Threshold Z for log scale view: if a channel has an occupancy Z times larger than the average, canvas shifts to log scale.",
44 20);
45 addParam("MinHitsForFlagging", m_MinHitsForFlagging, "Minimal number of hits in a channel required to flag it as 'Masked' or 'Hot'",
46 50);
47 addParam("MinProcessedEventsForMessages", m_MinProcessedEventsForMessagesInput,
48 "Minimal number of processed events required to print error messages", 10000.);
49 addParam("MinEntries", m_minEntries,
50 "Minimal number of entries for delta histogram updates", 30000.);
51 addParam("MinEvents", m_minEvents,
52 "Minimal number of processed events for delta histogram updates", 30000.);
53 addParam("MessageThreshold", m_MessageThreshold,
54 "Max number of messages to show up in channel occupancy plots", 12);
55 addParam("HistogramDirectoryName", m_histogramDirectoryName, "Name of histogram directory", std::string("KLM"));
56
58 m_2DHitsLine.SetLineColor(kRed);
59 m_2DHitsLine.SetLineWidth(3);
60 m_2DHitsLine.SetLineStyle(2); // dashed
61 m_PlaneLine.SetLineColor(kMagenta);
62 m_PlaneLine.SetLineWidth(1);
63 m_PlaneLine.SetLineStyle(2); // dashed
64 m_PlaneText.SetTextAlign(22); // centered, middle
65 m_PlaneText.SetTextColor(kMagenta);
66 m_PlaneText.SetTextFont(42); // Helvetica regular
67 m_PlaneText.SetTextSize(0.02); // 2% of TPad's full height
68}
69
70
72{
74
76 B2FATAL("The threshold used for hot channels is larger than the one for masked channels."
77 << LogVar("Threshold for hot channels", m_ThresholdForHot)
78 << LogVar("Threshold for masked channels", m_ThresholdForMasked));
79
80 // register plots for delta histogramming
81 addDeltaPar(m_histogramDirectoryName, "time_rpc", HistDelta::c_Entries, m_minEntries, 1);
82 addDeltaPar(m_histogramDirectoryName, "time_scintillator_bklm", HistDelta::c_Entries, m_minEntries, 1);
83 addDeltaPar(m_histogramDirectoryName, "time_scintillator_eklm", HistDelta::c_Entries, m_minEntries, 1);
84
85 // The FE ratio via pair: in c_Entries one fills far more slowly than other,
86 // leaving the pair out of sync and now use c_Events to update over the same event window.
87 addDeltaPar(m_histogramDirectoryName, "feStatus_bklm_scintillator_layers_0", HistDelta::c_Events, m_minEvents, 1);
88 addDeltaPar(m_histogramDirectoryName, "feStatus_bklm_scintillator_layers_1", HistDelta::c_Events, m_minEvents, 1);
89 addDeltaPar(m_histogramDirectoryName, "feStatus_eklm_plane_0", HistDelta::c_Events, m_minEvents, 1);
90 addDeltaPar(m_histogramDirectoryName, "feStatus_eklm_plane_1", HistDelta::c_Events, m_minEvents, 1);
91
92 //register EPICS PVs
93 registerEpicsPV("KLM:MaskedChannels", "MaskedChannels");
94 registerEpicsPV("KLM:DeadBarrelModules", "DeadBarrelModules");
95 registerEpicsPV("KLM:DeadEndcapModules", "DeadEndcapModules");
96
97 gROOT->cd();
98 std::string c_masked_channels_name = m_histogramDirectoryName + "/c_masked_channels";
99 m_c_masked_channels = new TCanvas((c_masked_channels_name).c_str());
100 std::string c_fe_bklm_ratio_name = m_histogramDirectoryName + "/c_fe_bklm_ratio";
101 m_c_fe_bklm_ratio = new TCanvas((c_fe_bklm_ratio_name).c_str());
102 std::string c_fe_eklm_ratio_name = m_histogramDirectoryName + "/c_fe_eklm_ratio";
103 m_c_fe_eklm_ratio = new TCanvas((c_fe_eklm_ratio_name).c_str());
104 // Feature extraction status histogram for BKLM
105 int bklmSectors = BKLMElementNumbers::getMaximalSectorGlobalNumber(); // 16
106 int eklmPlanes = EKLMElementNumbers::getMaximalPlaneGlobalNumber(); // 208
107 //BKLM
108 std::string fe_bklm_ratio_name = m_histogramDirectoryName + "/fe_bklm_ratio";
109 m_fe_bklm_ratio = new TH1F((fe_bklm_ratio_name).c_str(),
110 "FE Ratio in BKLM",
111 bklmSectors * 2, 0.5, 0.5 + bklmSectors * 2);
112 m_fe_bklm_ratio->GetXaxis()->SetTitle("Scintillator Layer number");
113 m_fe_bklm_ratio->SetStats(false);
114 m_fe_bklm_ratio->SetOption("HIST");
115 //EKLM
116 std::string fe_eklm_ratio_name = m_histogramDirectoryName + "/fe_eklm_ratio";
117 m_fe_eklm_ratio = new TH1F((fe_eklm_ratio_name).c_str(),
118 "FE Ratio in EKLM",
119 eklmPlanes, 0.5, 0.5 + eklmPlanes);
120 m_fe_eklm_ratio->GetXaxis()->SetTitle("Plane number");
121 m_fe_eklm_ratio->SetStats(false);
122 m_fe_eklm_ratio->SetOption("HIST");
123 /* Masked channels per sector. */
124 KLMSectorNumber totalSectors = m_SectorArrayIndex->getNElements();
125 m_MaskedChannelsHist = new TH1F("masked_channels", "Number of masked channels per sector",
126 totalSectors, -0.5, totalSectors - 0.5);
127
128 std::string str;
130 for (KLMChannelIndex& klmSector : klmIndex) {
131 std::string label = m_ElementNumbers->getSectorDAQName(klmSector.getSubdetector(), klmSector.getSection(), klmSector.getSector());
132 KLMSectorNumber sector = klmSector.getKLMSectorNumber();
133 KLMSectorNumber sectorIndex = m_SectorArrayIndex->getIndex(sector);
134 m_MaskedChannelsHist->GetXaxis()->SetBinLabel(sectorIndex + 1, label.c_str());
135 int nHistograms;
136 if (klmSector.getSubdetector() == KLMElementNumbers::c_BKLM)
137 nHistograms = 2;
138 else
139 nHistograms = 3;
140 for (int j = 0; j < nHistograms; j++) {
141 str = "strip_hits_subdetector_" +
142 std::to_string(klmSector.getSubdetector()) +
143 "_section_" + std::to_string(klmSector.getSection()) +
144 "_sector_" + std::to_string(klmSector.getSector()) +
145 "_" + std::to_string(j);
146 addDeltaPar(m_histogramDirectoryName, str, HistDelta::c_Entries, m_minEntries, 1);
147
148 }
149 }
150
151}
152
156
158{
159 if (!m_ElectronicsMap.isValid())
160 B2FATAL("No KLM electronics map.");
163 m_DeadBarrelModules.clear();
164 m_DeadEndcapModules.clear();
165 m_MaskedChannels.clear();
166
167 m_IsNullRun = (getRunType() == "null");
168}
169
171{
172 int hist_max_bin; double max_position;
173 TH1* time_rpc = findHist(m_histogramDirectoryName + "/time_rpc");
174 if (time_rpc) {
175 hist_max_bin = time_rpc->GetMaximumBin();
176 max_position = time_rpc->GetXaxis()->GetBinCenter(hist_max_bin);
177 m_monObj->setVariable("RPC_Time_Peak", max_position);
178 }
179
180 TH1* time_scint_bklm = findHist(m_histogramDirectoryName + "/time_scintillator_bklm");
181 if (time_scint_bklm) {
182 hist_max_bin = time_scint_bklm->GetMaximumBin();
183 max_position = time_scint_bklm->GetXaxis()->GetBinCenter(hist_max_bin);
184 m_monObj->setVariable("BKLM_Scint_Time_Peak", max_position);
185 }
186
187 TH1* time_scint_eklm = findHist(m_histogramDirectoryName + "/time_scintillator_eklm");
188 if (time_scint_eklm) {
189 hist_max_bin = time_scint_eklm->GetMaximumBin();
190 max_position = time_scint_eklm->GetXaxis()->GetBinCenter(hist_max_bin);
191 m_monObj->setVariable("EKLM_Scint_Time_Peak", max_position);
192 }
193}
194
196{
198 B2WARNING("Either DAQ/Nevent is not found or Nevent = 0.");
199 /* Set the minimal number of processed events to 0 if we can't determine the processed events. */
201 }
203}
204
205void DQMHistAnalysisKLMModule::deltaDrawer(TH1* delta, TH1* histogram, TCanvas* canvas)
206{
207 if (delta != nullptr) {
208 Double_t scale = (Double_t) histogram->Integral(); //want delta and histo to have same norm
209
210 // delta != nullptr should take care of whether update condition is met.
211 delta->SetLineColor(kBlackBody); //random choice of not green or blue
212 delta->SetLineStyle(4);
213 delta->DrawNormalized("SAME", scale); //normalize delta to histo
214 canvas->Modified();
215 canvas->Update();
216 }
217}
218
220 int subdetector, int section, int sector, int index,
221 TH1* histogram, TH1* delta, TCanvas* canvas, TLatex& latex)
222{
223 double x = 0.15;
224 double y = 0.85;
225 int i, n;
226 std::map<KLMModuleNumber, double> moduleHitMap;
227 std::map<KLMModuleNumber, double>::iterator it;
228 double average = 0;
229 int channelSubdetector, channelSection, channelSector;
230 int layer, plane, strip;
231 std::string str;
232 canvas->Clear();
233 canvas->cd();
234 histogram->SetStats(false);
235 canvas->SetLogy(0); //initialize to start without logscale
236 histogram->Draw();
237 deltaDrawer(delta, histogram, canvas); //draw normalized delta on top
238 n = histogram->GetXaxis()->GetNbins();
239
240 /* call reference histograms from base class*/
241 TH1* ref_histogram = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
242 if (ref_histogram) {ref_histogram->Draw("hist,same");}
243 float ref_average = 0;
244
245 if (ref_histogram != nullptr) {
246 for (i = 1; i <= n; i++) {
247 double nHitsPerModuleRef = ref_histogram->GetBinContent(i);
248 ref_average = ref_average + nHitsPerModuleRef;
249 }
250 }
251
252 for (i = 1; i <= n; i++) {
253 KLMChannelNumber channelIndex = std::round(histogram->GetBinCenter(i));
254 KLMChannelNumber channelNumber =
255 m_ChannelArrayIndex->getNumber(channelIndex);
256 double nHitsPerModule = histogram->GetBinContent(i);
257 average = average + nHitsPerModule;
258 m_ElementNumbers->channelNumberToElementNumbers(
259 channelNumber, &channelSubdetector, &channelSection, &channelSector,
260 &layer, &plane, &strip);
261 if ((channelSubdetector != subdetector) ||
262 (channelSection != section) ||
263 (channelSector != sector))
264 B2FATAL("Inconsistent element numbers.");
265 KLMModuleNumber module = m_ElementNumbers->moduleNumber(
266 subdetector, section, sector, layer);
267 it = moduleHitMap.find(module);
268 if (it == moduleHitMap.end()) {
269 moduleHitMap.insert(std::pair<KLMModuleNumber, double>(
270 module, nHitsPerModule));
271 } else {
272 it->second += nHitsPerModule;
273 }
274 }
275 unsigned int activeModuleChannels = 0;
276 int message_counter = 0;
277 for (it = moduleHitMap.begin(); it != moduleHitMap.end(); ++it) {
278 KLMModuleNumber moduleNumber = it->first;
279 if (it->second != 0) {
280 activeModuleChannels += m_ElementNumbers->getNChannelsModule(moduleNumber);
281 continue;
282 }
283 m_ElementNumbers->moduleNumberToElementNumbers(
284 moduleNumber, &channelSubdetector, &channelSection, &channelSector, &layer);
285 /* Channel with plane = 1, strip = 1 exists for any BKLM or EKLM module. */
286 KLMChannelNumber channel =
287 m_ElementNumbers->channelNumber(
288 channelSubdetector, channelSection, channelSector, layer, 1, 1);
289 const KLMElectronicsChannel* electronicsChannel =
290 m_ElectronicsMap->getElectronicsChannel(channel);
291 if (electronicsChannel == nullptr)
292 B2FATAL("Incomplete KLM electronics map.");
293 str = "No data from lane " + std::to_string(electronicsChannel->getLane());
294 latex.DrawLatexNDC(x, y, str.c_str());
295 y -= 0.05;
296 message_counter++;
297 /* Store the module number, used later in processPlaneHistogram
298 * to color the canvas with red and to raise up an alarm. */
299 if (channelSubdetector == KLMElementNumbers::c_BKLM) {
300 std::vector<KLMModuleNumber>::iterator ite =
301 std::find(m_DeadBarrelModules.begin(),
303 moduleNumber);
304 if (ite == m_DeadBarrelModules.end())
305 m_DeadBarrelModules.push_back(moduleNumber);
306 } else {
307 std::vector<KLMModuleNumber>::iterator ite = std::find(m_DeadEndcapModules.begin(),
309 moduleNumber);
310 if (ite == m_DeadEndcapModules.end())
311 m_DeadEndcapModules.push_back(moduleNumber);
312 }
313 }
314 if (activeModuleChannels == 0)
315 return;
316 average /= activeModuleChannels;
317 ref_average /= activeModuleChannels;
318
319 for (i = 1; i <= n; ++i) {
320 KLMChannelNumber channelIndex = std::round(histogram->GetBinCenter(i));
321 KLMChannelNumber channelNumber =
322 m_ChannelArrayIndex->getNumber(channelIndex);
323 double nHits = histogram->GetBinContent(i);
324 m_ElementNumbers->channelNumberToElementNumbers(
325 channelNumber, &channelSubdetector, &channelSection, &channelSector,
326 &layer, &plane, &strip);
327 std::string channelStatus = "Normal";
328 if ((nHits > average * m_ThresholdForMasked) && (nHits > m_MinHitsForFlagging)) {
329 channelStatus = "Masked";
330 std::vector<KLMModuleNumber>::iterator ite =
331 std::find(m_MaskedChannels.begin(),
332 m_MaskedChannels.end(),
333 channelNumber);
334 if (ite == m_MaskedChannels.end())
335 m_MaskedChannels.push_back(channelNumber);
336 B2DEBUG(20, "KLM@MaskMe " << channelNumber);
337 } else if ((nHits > average * m_ThresholdForHot) && (nHits > m_MinHitsForFlagging)) {
338 channelStatus = "Hot";
339 }
340 if (channelStatus != "Normal") {
341 const KLMElectronicsChannel* electronicsChannel =
342 m_ElectronicsMap->getElectronicsChannel(channelNumber);
343 if (electronicsChannel == nullptr)
344 B2FATAL("Incomplete BKLM electronics map.");
345 if (channelStatus == "Masked") {
346 histogram->SetBinContent(i, 0);
347 if (delta != nullptr)
348 delta->SetBinContent(i, 0);
349 }
350 str = channelStatus + " channel: ";
351 // lane, axis, channel
352 str += ("L" + std::to_string(electronicsChannel->getLane()) +
353 " A" + std::to_string(electronicsChannel->getAxis()) +
354 " Ch" + std::to_string(electronicsChannel->getChannel()));
355 message_counter++;
356 if (message_counter <= m_MessageThreshold) {
357 latex.DrawLatexNDC(x, y, str.c_str());
358 y -= 0.05;
359 }
360 }
361 }
362 if (message_counter > m_MessageThreshold) {
363 std::string verbose_message = " more messages";
364 verbose_message = std::to_string(message_counter - m_MessageThreshold) + verbose_message;
365 latex.DrawLatexNDC(x, y, verbose_message.c_str());
366 }
367
368
369 // for hot/masked channels, log scale plots (reference and main)
370 if (histogram->GetMaximum()*n > histogram->Integral()*m_ThresholdForLog && average * activeModuleChannels > m_MinHitsForFlagging) {
371 histogram->SetMinimum(1);
372 canvas->SetLogy();
373 } else if (ref_histogram != nullptr) {
374 if (ref_histogram->GetMaximum()*n > ref_histogram->Integral()*m_ThresholdForLog
375 && ref_average * activeModuleChannels > m_MinHitsForFlagging) {
376 histogram->SetMinimum(1);
377 canvas->SetLogy();
378 } else
379 canvas->SetLogy(0);
380 } else
381 canvas->SetLogy(0);
382
383 canvas->Modified();
384 canvas->Update();
385
386 /* Drawing dividing lines */
387 int divisions;
388 int bin = 1;
389 double xLine;
390 // drawing lines for BKLM sectors
391 if (subdetector == 1) {
392 int shift;
393 if (index == 0) {
394 divisions = 7;
395 shift = 1;
396 } else {
399 }
400 for (int k = 0; k < divisions; k++) {
401 xLine = (histogram->GetXaxis()->GetBinLowEdge(bin) - canvas->GetX1()) / (canvas->GetX2() - canvas->GetX1());
402 m_PlaneLine.DrawLineNDC(xLine, 0.1, xLine, 0.9);
403 bin += BKLMElementNumbers::getNStrips(section, sector, k + shift, 0)
404 + BKLMElementNumbers::getNStrips(section, sector, k + shift, 1);
405 }
406 } else { // drawing lines for EKLM sectors
407 if ((section == 2) && (index == 0 || index == 1))
408 divisions = 5;
409 else
410 divisions = 4;
411 for (int k = 0; k < divisions; k++) {
412 xLine = (histogram->GetXaxis()->GetBinLowEdge(bin) - canvas->GetX1()) / (canvas->GetX2() - canvas->GetX1());
413 m_PlaneLine.DrawLineNDC(xLine, 0.1, xLine, 0.9);
415 }
416 }
417 canvas->Modified();
418 canvas->Update();
419
420}
421
423 KLMSectionNumber section, TH2F* histogram, TCanvas* canvas)
424{
425 canvas->Clear();
426 canvas->cd();
427 histogram->SetStats(false);
428 histogram->Draw("COLZ");
429 /* Draw the lines only for the backward layers. */
431 m_2DHitsLine.DrawLine(-110, 80, -110, 190);
432 m_2DHitsLine.DrawLine(-110, 190, 110, 190);
433 m_2DHitsLine.DrawLine(110, 80, 110, 190);
434 m_2DHitsLine.DrawLine(-110, 80, 110, 80);
435 }
436 canvas->Modified();
437 canvas->Update();
438}
439
441 const std::string& histName)
442{
443 TH1* histogram = findHist(m_histogramDirectoryName + "/" + histName);
444 if (histogram == nullptr) {
445 B2WARNING("KLM DQM histogram " + m_histogramDirectoryName + "/" << histName << " is not found.");
446 return;
447 }
448
449 TCanvas* canvas = findCanvas(m_histogramDirectoryName + "/c_" + histName);
450 if (canvas == nullptr) {
451 B2WARNING("KLM DQM histogram canvas " + m_histogramDirectoryName + "/c_" << histName << " is not found.");
452 return;
453 }
454
455 else {
456 canvas->Clear();
457 canvas->cd();
458 histogram->Draw();
459 /* calling on delta histogram*/
460 TH1* delta = getDelta(m_histogramDirectoryName, histName);
461 UpdateCanvas(canvas->GetName(), delta != nullptr); //keeping this for testing purposes
462 if (delta != nullptr) {
463 B2INFO("DQMHistAnalysisKLM: Time Delta Entries is " << delta->GetEntries());
464 deltaDrawer(delta, histogram, canvas);
465 }
466 //reference check
467 TH1* ref = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
468 if (ref) {ref->Draw("hist,same");}
469 }
470}
471
473 TH1* histogram, TCanvas* canvas)
474{
475 histogram->Clear();
476 canvas->Clear();
477 canvas->cd();
478 if (m_MaskedChannels.size() > 0) {
479 int channelSubdetector, channelSection, channelSector;
480 int layer, plane, strip;
481 for (KLMChannelNumber channel : m_MaskedChannels) {
482 m_ElementNumbers->channelNumberToElementNumbers(
483 channel, &channelSubdetector, &channelSection, &channelSector,
484 &layer, &plane, &strip);
485 KLMSectorNumber sectorNumber;
486 if (channelSubdetector == KLMElementNumbers::c_BKLM)
487 sectorNumber = m_ElementNumbers->sectorNumberBKLM(channelSection, channelSector);
488 else
489 sectorNumber = m_ElementNumbers->sectorNumberEKLM(channelSection, channelSector);
490 KLMSectorNumber sectorIndex = m_SectorArrayIndex->getIndex(sectorNumber);
491 histogram->Fill(sectorIndex);
492 }
493 }
494 histogram->SetStats(false);
495 histogram->SetTitle("Number of masked channels per sector");
496 histogram->Draw();
497 canvas->Modified();
498 canvas->Update();
499}
500
502 const std::string& histName, TLatex* latex = nullptr, TH1* histogram = nullptr)
503{
504 // If no histogram is provided, try to retrieve it by name
505 if (!histogram) {
506 histogram = findHist(m_histogramDirectoryName + "/" + histName);
507 if (!histogram) {
508 B2WARNING("KLM DQM histogram " + m_histogramDirectoryName + "/" << histName << " is not found.");
509 return;
510 }
511 }
512
513 TCanvas* canvas = findCanvas(m_histogramDirectoryName + "/c_" + histName);
514 if (!canvas) {
515 B2WARNING("KLM DQM histogram canvas " + m_histogramDirectoryName + "/c_" << histName << " is not found.");
516 return;
517 }
518 // Set up the canvas
519 canvas->Clear();
520 canvas->cd();
521 histogram->SetStats(false);
522 histogram->Draw();
523
524 // Overlay reference histogram if available
525 TH1* ref = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
526 if (ref) {
527 ref->Draw("hist,same");
528 }
529
530 // Define variables for text and alarm positioning
531 double xAlarm = 0.15, yAlarm = 0.8;
532 int message_counter = 0;
533 std::string name;
534
535 // Determine if histogram is BKLM or EKLM and process accordingly
536 bool isBKLM = histName.find("bklm") != std::string::npos;
537
538 // Check if "fe" is in histName to adjust maximalLayer
539 bool isFE = histName.find("fe") != std::string::npos;
540
541 if (isBKLM) {
542 // Use a different maximalLayer if "fe" is found in the name
543 const int maximalLayer = isFE ? BKLMElementNumbers::getMaximalSectorGlobalNumber() / 8 :
545
546 for (int sector = 0; sector < BKLMElementNumbers::getMaximalSectorGlobalNumber(); ++sector) {
547 int bin = maximalLayer * sector + 1;
548 double xLine = histogram->GetXaxis()->GetBinLowEdge(bin);
549 double xText = histogram->GetXaxis()->GetBinLowEdge(bin + maximalLayer / 2);
550 double yText = gPad->GetUymin() + 0.98 * (gPad->GetUymax() - gPad->GetUymin());
551
552 if (sector > 0) {
553 m_PlaneLine.DrawLine(xLine, gPad->GetUymin(), xLine, gPad->GetUymax());
554 }
555
556 name = (sector < BKLMElementNumbers::getMaximalSectorNumber() ? "BB" : "BF") +
557 std::to_string(sector % BKLMElementNumbers::getMaximalSectorNumber());
558 m_PlaneText.DrawText(xText, yText, name.c_str());
559 }
560 // Only update canvas status if latex is provided
561 if (latex) {
562 updateCanvasStatus(canvas, m_DeadBarrelModules, latex, message_counter, xAlarm, yAlarm);
563 }
564 } else {
565 const double maximalLayer = EKLMElementNumbers::getMaximalLayerGlobalNumber();
567
568 for (int layerGlobal = 1; layerGlobal <= maximalLayer; ++layerGlobal) {
569 int bin = maxPlane * layerGlobal + 1;
570 double xLine = histogram->GetXaxis()->GetBinLowEdge(bin);
571 double xText = histogram->GetXaxis()->GetBinLowEdge(bin - maxPlane / 2);
572 double yText = gPad->GetUymin() + 0.98 * (gPad->GetUymax() - gPad->GetUymin());
573
574 if (layerGlobal < maximalLayer) {
575 m_PlaneLine.DrawLine(xLine, gPad->GetUymin(), xLine, gPad->GetUymax());
576 }
577
578 int section, layer;
579 m_EklmElementNumbers->layerNumberToElementNumbers(layerGlobal, &section, &layer);
580 name = (section == EKLMElementNumbers::c_BackwardSection ? "B" : "F") + std::to_string(layer);
581 m_PlaneText.DrawText(xText, yText, name.c_str());
582 }
583
584 // Only update canvas status if latex is provided
585 if (latex) {
586 updateCanvasStatus(canvas, m_DeadEndcapModules, latex, message_counter, xAlarm, yAlarm);
587 }
588 }
589
590 // Display additional message if message threshold exceeded
591 if (latex && message_counter > m_MessageThreshold) {
592 std::string verbose_string = std::to_string(message_counter - m_MessageThreshold) + " more messages";
593 latex->DrawLatexNDC(xAlarm, yAlarm, verbose_string.c_str());
594 }
595
596 canvas->Modified();
597 canvas->Update();
598}
599
600// Helper function to update canvas status based on dead modules
602 TCanvas* canvas, const std::vector<KLMModuleNumber>& deadModules,
603 TLatex* latex, int& message_counter, double xAlarm, double yAlarm)
604{
605 if (deadModules.empty()) {
608 for (const KLMModuleNumber& module : deadModules) {
609 int moduleSubdetector, moduleSection, moduleSector, moduleLayer;
610 m_ElementNumbers->moduleNumberToElementNumbers(module, &moduleSubdetector, &moduleSection, &moduleSector, &moduleLayer);
611
612 std::string alarm = "No data from " + m_ElementNumbers->getSectorDAQName(moduleSubdetector, moduleSection, moduleSector)
613 + ", layer " + std::to_string(moduleLayer);
614 message_counter++;
615 if (message_counter <= m_MessageThreshold) {
616 latex->DrawLatexNDC(xAlarm, yAlarm, alarm.c_str());
617 yAlarm -= 0.05;
618 }
619 }
620 if (!m_IsNullRun) {
622 }
623 } else {
625 }
626}
627
628
630 const std::string& histName, TLatex& latex)
631{
632 // Internally call the main function with a pointer to TLatex
633 processPlaneHistogram(histName, &latex, nullptr);
634}
635
636void DQMHistAnalysisKLMModule::processFEHistogram(TH1* feHist, const std::string& histName, TCanvas* canvas)
637{
638 if (!feHist) {
639 B2WARNING("processFEHistogram: feHist is null, exiting function.");
640 return;
641 }
642 if (!canvas) {
643 B2WARNING("processFEHistogram: canvas is null, cannot draw histograms.");
644 return;
645 }
646
647 /* Obtain plots necessary for FE Ratio plots */
648 auto* numerator = findHist(m_histogramDirectoryName + "/" + histName + "_0");
649 auto* denominator = findHist(m_histogramDirectoryName + "/" + histName + "_1");
650
651 feHist->Reset();
652 std::unique_ptr<TH1> feClone(static_cast<TH1*>(feHist->Clone())); // Clone feHist
653
654 canvas->cd();
655
656 if (denominator != nullptr && numerator != nullptr) {
657 // Clone numerator and denominator into unique_ptrs to ensure they are deleted automatically
658 auto tempNumerator = std::unique_ptr<TH1>(static_cast<TH1*>(numerator->Clone()));
659 auto tempSum = std::unique_ptr<TH1>(static_cast<TH1*>(denominator->Clone()));
660
661 // Add numerator to denominator to get the sum (denominator + numerator)
662 tempSum->Add(numerator);
663
664 // Divide numerator by (denominator + numerator) and store result in feHist
665 feHist->Divide(tempNumerator.get(), tempSum.get(), 1.0, 1.0, "B");
666 feHist->Draw();
667
668 // Reference check
669 TH1* ref = findRefHist(feHist->GetName(), ERefScaling::c_RefScaleNone);
670 if (ref) {
671 ref->Draw("hist,same");
672 B2INFO("processFEHistogram: Found and drew reference histogram.");
673 } else {
674 B2WARNING("processFEHistogram: Reference histogram not found.");
675 }
676
677 canvas->Modified();
678 canvas->Update();
679 B2INFO("processFEHistogram: Updated canvas after first draw.");
680
681 /* Delta component */
682 // Use the latest available deltas, not only "updated in the same event".
683 auto deltaDenom = getDelta(m_histogramDirectoryName, histName + "_1", 0, false);
684 auto deltaNumer = getDelta(m_histogramDirectoryName, histName + "_0", 0, false);
685
686 UpdateCanvas(canvas->GetName(), (feHist != nullptr));
687 if (deltaNumer != nullptr && deltaDenom != nullptr) {
688 B2INFO("DQMHistAnalysisKLM: FE Ratio Delta Num/Denom Entries is "
689 << deltaNumer->GetEntries() << "/" << deltaDenom->GetEntries());
690
691 // Clone deltaNumer and deltaDenom into unique_ptrs to create the delta sum
692 auto deltaTempNumerator = std::unique_ptr<TH1>(static_cast<TH1*>(deltaNumer->Clone()));
693 auto deltaTempSum = std::unique_ptr<TH1>(static_cast<TH1*>(deltaDenom->Clone()));
694
695 // Add delta numerator and denominator
696 deltaTempSum->Add(deltaNumer);
697
698 // Divide deltaNumer by (deltaDenom + deltaNumer) and store in feClone
699 feClone->Divide(deltaTempNumerator.get(), deltaTempSum.get(), 1.0, 1.0, "B");
700 feClone->SetLineColor(kOrange);
701 feClone->DrawCopy("SAME");
702
703 canvas->Modified();
704 canvas->Update();
705 }
706 // If the deltas are not available yet (e.g. before the first MinEvents window
707 // has closed), silently skip drawing the delta overlay, consistent with the
708 // other histogram handlers (e.g. processTimeHistogram).
709 } else {
710 B2WARNING("processFEHistogram: Skipped histogram processing due to missing numerator/denominator.");
711 }
712}
713
715{
716 /* If KLM is not included, stop here and return. */
717 TH1* daqInclusion = findHist(m_histogramDirectoryName + "/daq_inclusion");
718 if (not(daqInclusion == nullptr)) {
719 int isKlmIncluded = daqInclusion->GetBinContent(daqInclusion->GetXaxis()->FindBin("Yes"));
720 if (isKlmIncluded == 0)
721 return;
722 }
723 /* Make sure that the vectors are cleared at each DQM refresh. */
724 m_DeadBarrelModules.clear();
725 m_DeadEndcapModules.clear();
726 m_MaskedChannels.clear();
728 std::string str, histogramName, canvasName;
729 TLatex latex;
730 latex.SetTextColor(kRed);
731 latex.SetTextAlign(11);
733 // gathering relevant info for analyseChannelHitHistogram
734 for (KLMChannelIndex& klmSector : klmIndex) {
735 int nHistograms;
736 if (klmSector.getSubdetector() == KLMElementNumbers::c_BKLM)
737 nHistograms = 2;
738 else
739 nHistograms = 3;
740 for (int j = 0; j < nHistograms; j++) {
741 str = "strip_hits_subdetector_" +
742 std::to_string(klmSector.getSubdetector()) +
743 "_section_" + std::to_string(klmSector.getSection()) +
744 "_sector_" + std::to_string(klmSector.getSector()) +
745 "_" + std::to_string(j);
746 histogramName = m_histogramDirectoryName + "/" + str;
747 canvasName = m_histogramDirectoryName + "/c_" + str;
748 TH1* histogram = findHist(histogramName);
749 //get delta histogram (should we work with a clone instead?)
750 auto delta = getDelta("", histogramName);
751
752 if (histogram == nullptr) {
753 B2WARNING("KLM DQM histogram " << histogramName << " is not found.");
754 continue;
755 }
756 TCanvas* canvas = findCanvas(canvasName);
757 if (canvas == nullptr) {
758 B2WARNING("KLM DQM histogram canvas " << canvasName << " is not found.");
759 continue;
760 }
761 // Add this canvas that it is time to update
762 // not sure if this is interfering with the generation of some features
763 // after testing, switch condition back to delta != nullptr || histogram != nullptr
764 UpdateCanvas(canvas->GetName(), true);
766 klmSector.getSubdetector(), klmSector.getSection(),
767 klmSector.getSector(), j, histogram, delta, canvas, latex);
768
769 }
770 }
771 /* Temporary change the color palette. */
772 gStyle->SetPalette(kLightTemperature);
774 for (KLMChannelIndex& klmSection : klmIndex) {
775 KLMSubdetectorNumber subdetector = klmSection.getSubdetector();
776 if (subdetector == KLMElementNumbers::c_EKLM) {
777 KLMSubdetectorNumber section = klmSection.getSection();
778 int maximalLayerNumber = m_EklmElementNumbers->getMaximalDetectorLayerNumber(section);
779 for (int j = 1; j <= maximalLayerNumber; ++j) {
780 str = "spatial_2d_hits_subdetector_" + std::to_string(subdetector) +
781 "_section_" + std::to_string(section) +
782 "_layer_" + std::to_string(j);
783 histogramName = m_histogramDirectoryName + "/" + str;
784 canvasName = m_histogramDirectoryName + "/c_" + str;
785 TH2F* histogram = static_cast<TH2F*>(findHist(histogramName));
786 if (histogram == nullptr) {
787 B2ERROR("KLM DQM histogram " << histogramName << " is not found.");
788 continue;
789 }
790 TCanvas* canvas = findCanvas(canvasName);
791 if (canvas == nullptr) {
792 B2ERROR("KLM DQM histogram canvas " << canvasName << " is not found.");
793 continue;
794 }
795 processSpatial2DHitEndcapHistogram(section, histogram, canvas);
796 }
797 }
798 }
799
800 /* Reset the color palette to the default one. */
801 gStyle->SetPalette(kBird);
803 latex.SetTextColor(kBlue);
804 processPlaneHistogram("plane_bklm_phi", latex);
805 processPlaneHistogram("plane_bklm_z", latex);
806 processPlaneHistogram("plane_eklm", latex);
807
808 processFEHistogram(m_fe_bklm_ratio, "feStatus_bklm_scintillator_layers", m_c_fe_bklm_ratio);
810 processPlaneHistogram("fe_bklm_ratio", nullptr, m_fe_bklm_ratio);
811 processPlaneHistogram("fe_eklm_ratio", nullptr, m_fe_eklm_ratio);
812
813
814 processTimeHistogram("time_rpc");
815 processTimeHistogram("time_scintillator_bklm");
816 processTimeHistogram("time_scintillator_eklm");
817
818 B2DEBUG(20, "Updating EPICS PVs for DQMHistAnalysisKLM");
819 // only update PVs if there's enough statistics and datasize != 0
820 // Check if it's a null run, if so, don't update EPICS PVs
821 if (m_IsNullRun) {
822 B2INFO("DQMHistAnalysisKLM: Null run detected. No PV Update.");
823 return;
824 }
825 auto* daqDataSize = findHist("DAQ/KLMDataSize");
826 double meanDAQDataSize = 0.;
827 if (daqDataSize != nullptr) {
828 meanDAQDataSize = daqDataSize->GetMean();
829 } else
830 B2WARNING("DQMHistAnalysisKLM: Cannot find KLMDataSize");
831 if ((daqDataSize != nullptr) and (meanDAQDataSize != 0.)) {
833 setEpicsPV("MaskedChannels", (double)m_MaskedChannels.size());
834 setEpicsPV("DeadBarrelModules", (double)m_DeadBarrelModules.size());
835 setEpicsPV("DeadEndcapModules", (double)m_DeadEndcapModules.size());
836 B2DEBUG(20, "DQMHistAnalysisKLM: MaskedChannels " << m_MaskedChannels.size());
837 B2DEBUG(20, "DQMHistAnalysisKLM: DeadBarrelModules " << m_DeadBarrelModules.size());
838 B2DEBUG(20, "DQMHistAnalysisKLM: DeadEndcapModules " << m_DeadEndcapModules.size());
839 }
840 } else
841 B2INFO("DQMHistAnalysisKLM: KLM Not included. No PV Update. ");
842
843
844}
static constexpr int getMaximalLayerNumber()
Get maximal layer number (1-based).
static constexpr int getMaximalSectorNumber()
Get maximal sector number (1-based).
static constexpr int getMaximalSectorGlobalNumber()
Get maximal sector global number.
static int getNStrips(int section, int sector, int layer, int plane)
Get number of strips.
TLine m_PlaneLine
TLine for boundary in plane histograms.
void processFEHistogram(TH1 *feHist, const std::string &histName, TCanvas *canvas)
Process histogram containing the efficiencies.
double m_ProcessedEvents
Number of processed events.
void initialize() override final
Initializer.
int m_MessageThreshold
Message Threshold for expert pots.
void updateCanvasStatus(TCanvas *canvas, const std::vector< KLMModuleNumber > &deadModules, TLatex *latex, int &message_counter, double xAlarm, double yAlarm)
Helper function to update the canvas status based on dead modules.
void processPlaneHistogram(const std::string &histName, TLatex *latex, TH1 *histogram)
Process histogram containing the number of hits in plane.
TH1 * m_fe_eklm_ratio
Histogram for EKLM plane events fraction w/ FE.
int m_ThresholdForLog
Threshold for log scale.
double m_minEntries
Minimal number of entries for delta histogram update.
TCanvas * m_c_fe_eklm_ratio
Canvas for EKLM plane events fraction w/ FE.
int m_MinHitsForFlagging
Minimal number of hits for flagging.
const KLMElementNumbers * m_ElementNumbers
KLM element numbers.
const EKLMElementNumbers * m_EklmElementNumbers
EKLM element numbers.
double m_minEvents
Minimal number of processed events for delta histogram update.
void fillMaskedChannelsHistogram(TH1 *histogram, TCanvas *canvas)
Fill histogram containing masked channels per sector.
void processSpatial2DHitEndcapHistogram(uint16_t section, TH2F *histogram, TCanvas *canvas)
Process spatial 2D hits histograms for endcap.
MonitoringObject * m_monObj
Monitoring object.
void deltaDrawer(TH1 *delta, TH1 *histogram, TCanvas *canvas)
Scales and draws desired delta histogram for current canvas.
void processTimeHistogram(const std::string &histName)
Process histogram containing the hit times.
std::vector< uint16_t > m_MaskedChannels
Vector of masked channels.
void terminate() override final
This method is called at the end of the event processing.
void event() override final
This method is called for each event.
TCanvas * m_c_fe_bklm_ratio
Canvas for BKLM plane events fraction w/ FE.
int m_ThresholdForHot
Threshold for hot channels.
TH1 * m_fe_bklm_ratio
Histogram for BKLM plane events fraction w/ FE.
std::vector< uint16_t > m_DeadBarrelModules
Vector of dead barrel modules.
std::string m_histogramDirectoryName
Name of histogram directory.
double m_MinProcessedEventsForMessagesInput
Input parameter for minimal number of processed events for error messages.
TText m_PlaneText
TText for names in plane histograms.
DBObjPtr< KLMElectronicsMap > m_ElectronicsMap
Electronics map.
void endRun() override final
This method is called if the current run ends.
TH1 * m_MaskedChannelsHist
Histogram for masked channels per sector.
int m_ThresholdForMasked
Threshold for masked channels.
const KLMSectorArrayIndex * m_SectorArrayIndex
KLM sector array index.
void beginRun() override final
Called when entering a new run.
double m_MinProcessedEventsForMessages
Minimal number of processed events for error messages.
std::vector< uint16_t > m_DeadEndcapModules
Vector of dead endcap modules.
double getProcessedEvents()
Get number of processed events.
TLine m_2DHitsLine
TLine for background region in 2d hits histograms.
const KLMChannelArrayIndex * m_ChannelArrayIndex
KLM channel array index.
bool m_IsNullRun
Run type flag for null runs.
void analyseChannelHitHistogram(int subdetector, int section, int sector, int index, TH1 *histogram, TH1 *delta, TCanvas *canvas, TLatex &latex)
Analyse channel hit histogram.
TCanvas * m_c_masked_channels
Canvas for masked channels per sector summary.
static TCanvas * findCanvas(TString cname)
Find canvas by name.
static TH1 * findRefHist(const std::string &histname, ERefScaling scaling=ERefScaling::c_RefScaleNone, const TH1 *hist=nullptr)
Get referencehistogram from list (no other search).
int registerEpicsPV(const std::string &pvname, const std::string &keyname="")
EPICS related Functions.
static MonitoringObject * getMonitoringObject(const std::string &name)
Get MonitoringObject with given name (new object is created if non-existing)
static void addDeltaPar(const std::string &dirname, const std::string &histname, HistDelta::EDeltaType t, int p, unsigned int a=1)
Add Delta histogram parameters.
static void colorizeCanvas(TCanvas *canvas, EStatus status)
Helper function for Canvas colorization.
static TH1 * findHist(const std::string &histname, bool onlyIfUpdated=false)
Get histogram from list (no other search).
static void UpdateCanvas(const std::string &name, bool updated=true)
Mark canvas as updated (or not)
static const std::string & getRunType(void)
Get the list of the reference histograms.
TH1 * getDelta(const std::string &fullname, int n=0, bool onlyIfUpdated=true)
Get Delta histogram.
DQMHistAnalysisModule()
Constructor / Destructor.
@ c_StatusTooFew
Not enough entries/event to judge.
@ c_StatusError
Analysis result: Severe issue found.
@ c_StatusGood
Analysis result: Good.
@ c_RefScaleEntries
to number of entries (integral)
static int getEventProcessed(void)
Get the number of processed events.
void setEpicsPV(const std::string &keyname, double value)
Write value to a EPICS PV.
static constexpr int getNStripsSector()
Get number of strips in a sector.
static constexpr int getMaximalLayerGlobalNumber()
Get maximal detector layer global number.
static constexpr int getMaximalPlaneGlobalNumber()
Get maximal plane global number.
static constexpr int getMaximalSectorNumber()
Get maximal sector number.
static constexpr int getMaximalPlaneNumber()
Get maximal plane number.
KLM channel index.
void setIndexLevel(enum IndexLevel indexLevel)
Set index level.
KLM sector array index.
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
Class to store variables with their name which were sent to the logging service.
TH2 * moduleHitMap(TH1 *hitMap, int moduleID)
Make hit map in HAPD view (12*12 channels).
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
uint16_t KLMSectorNumber
Sector number.
uint16_t KLMChannelNumber
Channel number.
uint16_t KLMSubdetectorNumber
Subdetector number.
uint16_t KLMModuleNumber
Module number.
uint16_t KLMSectionNumber
Section number.
Abstract base class for different kinds of events.