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 for delta histogram updates", 30000.);
51 addParam("MessageThreshold", m_MessageThreshold,
52 "Max number of messages to show up in channel occupancy plots", 12);
53 addParam("HistogramDirectoryName", m_histogramDirectoryName, "Name of histogram directory", std::string("KLM"));
54
56 m_2DHitsLine.SetLineColor(kRed);
57 m_2DHitsLine.SetLineWidth(3);
58 m_2DHitsLine.SetLineStyle(2); // dashed
59 m_PlaneLine.SetLineColor(kMagenta);
60 m_PlaneLine.SetLineWidth(1);
61 m_PlaneLine.SetLineStyle(2); // dashed
62 m_PlaneText.SetTextAlign(22); // centered, middle
63 m_PlaneText.SetTextColor(kMagenta);
64 m_PlaneText.SetTextFont(42); // Helvetica regular
65 m_PlaneText.SetTextSize(0.02); // 2% of TPad's full height
66}
67
68
70{
72
74 B2FATAL("The threshold used for hot channels is larger than the one for masked channels."
75 << LogVar("Threshold for hot channels", m_ThresholdForHot)
76 << LogVar("Threshold for masked channels", m_ThresholdForMasked));
77
78 // register plots for delta histogramming
79 addDeltaPar(m_histogramDirectoryName, "time_rpc", HistDelta::c_Entries, m_minEntries, 1);
80 addDeltaPar(m_histogramDirectoryName, "time_scintillator_bklm", HistDelta::c_Entries, m_minEntries, 1);
81 addDeltaPar(m_histogramDirectoryName, "time_scintillator_eklm", HistDelta::c_Entries, m_minEntries, 1);
82
83 addDeltaPar(m_histogramDirectoryName, "feStatus_bklm_scintillator_layers_0", HistDelta::c_Entries, m_minEntries, 1);
84 addDeltaPar(m_histogramDirectoryName, "feStatus_bklm_scintillator_layers_1", HistDelta::c_Entries, m_minEntries, 1);
85 addDeltaPar(m_histogramDirectoryName, "feStatus_eklm_plane_0", HistDelta::c_Entries, m_minEntries, 1);
86 addDeltaPar(m_histogramDirectoryName, "feStatus_eklm_plane_1", HistDelta::c_Entries, m_minEntries, 1);
87
88 //register EPICS PVs
89 registerEpicsPV("KLM:MaskedChannels", "MaskedChannels");
90 registerEpicsPV("KLM:DeadBarrelModules", "DeadBarrelModules");
91 registerEpicsPV("KLM:DeadEndcapModules", "DeadEndcapModules");
92
93 gROOT->cd();
94 std::string c_masked_channels_name = m_histogramDirectoryName + "/c_masked_channels";
95 m_c_masked_channels = new TCanvas((c_masked_channels_name).c_str());
96 std::string c_fe_bklm_ratio_name = m_histogramDirectoryName + "/c_fe_bklm_ratio";
97 m_c_fe_bklm_ratio = new TCanvas((c_fe_bklm_ratio_name).c_str());
98 std::string c_fe_eklm_ratio_name = m_histogramDirectoryName + "/c_fe_eklm_ratio";
99 m_c_fe_eklm_ratio = new TCanvas((c_fe_eklm_ratio_name).c_str());
100 // Feature extraction status histogram for BKLM
101 int bklmSectors = BKLMElementNumbers::getMaximalSectorGlobalNumber(); // 16
102 int eklmPlanes = EKLMElementNumbers::getMaximalPlaneGlobalNumber(); // 208
103 //BKLM
104 std::string fe_bklm_ratio_name = m_histogramDirectoryName + "/fe_bklm_ratio";
105 m_fe_bklm_ratio = new TH1F((fe_bklm_ratio_name).c_str(),
106 "FE Ratio in BKLM",
107 bklmSectors * 2, 0.5, 0.5 + bklmSectors * 2);
108 m_fe_bklm_ratio->GetXaxis()->SetTitle("Scintillator Layer number");
109 m_fe_bklm_ratio->SetStats(false);
110 m_fe_bklm_ratio->SetOption("HIST");
111 //EKLM
112 std::string fe_eklm_ratio_name = m_histogramDirectoryName + "/fe_eklm_ratio";
113 m_fe_eklm_ratio = new TH1F((fe_eklm_ratio_name).c_str(),
114 "FE Ratio in EKLM",
115 eklmPlanes, 0.5, 0.5 + eklmPlanes);
116 m_fe_eklm_ratio->GetXaxis()->SetTitle("Plane number");
117 m_fe_eklm_ratio->SetStats(false);
118 m_fe_eklm_ratio->SetOption("HIST");
119 /* Masked channels per sector. */
120 KLMSectorNumber totalSectors = m_SectorArrayIndex->getNElements();
121 m_MaskedChannelsHist = new TH1F("masked_channels", "Number of masked channels per sector",
122 totalSectors, -0.5, totalSectors - 0.5);
123
124 std::string str;
126 for (KLMChannelIndex& klmSector : klmIndex) {
127 std::string label = m_ElementNumbers->getSectorDAQName(klmSector.getSubdetector(), klmSector.getSection(), klmSector.getSector());
128 KLMSectorNumber sector = klmSector.getKLMSectorNumber();
129 KLMSectorNumber sectorIndex = m_SectorArrayIndex->getIndex(sector);
130 m_MaskedChannelsHist->GetXaxis()->SetBinLabel(sectorIndex + 1, label.c_str());
131 int nHistograms;
132 if (klmSector.getSubdetector() == KLMElementNumbers::c_BKLM)
133 nHistograms = 2;
134 else
135 nHistograms = 3;
136 for (int j = 0; j < nHistograms; j++) {
137 str = "strip_hits_subdetector_" +
138 std::to_string(klmSector.getSubdetector()) +
139 "_section_" + std::to_string(klmSector.getSection()) +
140 "_sector_" + std::to_string(klmSector.getSector()) +
141 "_" + std::to_string(j);
142 addDeltaPar(m_histogramDirectoryName, str, HistDelta::c_Entries, m_minEntries, 1);
143
144 }
145 }
146
147}
148
152
154{
155 if (!m_ElectronicsMap.isValid())
156 B2FATAL("No KLM electronics map.");
159 m_DeadBarrelModules.clear();
160 m_DeadEndcapModules.clear();
161 m_MaskedChannels.clear();
162
163 m_IsNullRun = (getRunType() == "null");
164}
165
167{
168 int hist_max_bin; double max_position;
169 TH1* time_rpc = findHist(m_histogramDirectoryName + "/time_rpc");
170 if (time_rpc) {
171 hist_max_bin = time_rpc->GetMaximumBin();
172 max_position = time_rpc->GetXaxis()->GetBinCenter(hist_max_bin);
173 m_monObj->setVariable("RPC_Time_Peak", max_position);
174 }
175
176 TH1* time_scint_bklm = findHist(m_histogramDirectoryName + "/time_scintillator_bklm");
177 if (time_scint_bklm) {
178 hist_max_bin = time_scint_bklm->GetMaximumBin();
179 max_position = time_scint_bklm->GetXaxis()->GetBinCenter(hist_max_bin);
180 m_monObj->setVariable("BKLM_Scint_Time_Peak", max_position);
181 }
182
183 TH1* time_scint_eklm = findHist(m_histogramDirectoryName + "/time_scintillator_eklm");
184 if (time_scint_eklm) {
185 hist_max_bin = time_scint_eklm->GetMaximumBin();
186 max_position = time_scint_eklm->GetXaxis()->GetBinCenter(hist_max_bin);
187 m_monObj->setVariable("EKLM_Scint_Time_Peak", max_position);
188 }
189}
190
192{
194 B2WARNING("Either DAQ/Nevent is not found or Nevent = 0.");
195 /* Set the minimal number of processed events to 0 if we can't determine the processed events. */
197 }
199}
200
201void DQMHistAnalysisKLMModule::deltaDrawer(TH1* delta, TH1* histogram, TCanvas* canvas)
202{
203 if (delta != nullptr) {
204 Double_t scale = (Double_t) histogram->Integral(); //want delta and histo to have same norm
205
206 // delta != nullptr should take care of whether update condition is met.
207 delta->SetLineColor(kBlackBody); //random choice of not green or blue
208 delta->SetLineStyle(4);
209 delta->DrawNormalized("SAME", scale); //normalize delta to histo
210 canvas->Modified();
211 canvas->Update();
212 }
213}
214
216 int subdetector, int section, int sector, int index,
217 TH1* histogram, TH1* delta, TCanvas* canvas, TLatex& latex)
218{
219 double x = 0.15;
220 double y = 0.85;
221 int i, n;
222 std::map<KLMModuleNumber, double> moduleHitMap;
223 std::map<KLMModuleNumber, double>::iterator it;
224 double average = 0;
225 int channelSubdetector, channelSection, channelSector;
226 int layer, plane, strip;
227 std::string str;
228 canvas->Clear();
229 canvas->cd();
230 histogram->SetStats(false);
231 canvas->SetLogy(0); //initialize to start without logscale
232 histogram->Draw();
233 deltaDrawer(delta, histogram, canvas); //draw normalized delta on top
234 n = histogram->GetXaxis()->GetNbins();
235
236 /* call reference histograms from base class*/
237 TH1* ref_histogram = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
238 if (ref_histogram) {ref_histogram->Draw("hist,same");}
239 float ref_average = 0;
240
241 if (ref_histogram != nullptr) {
242 for (i = 1; i <= n; i++) {
243 double nHitsPerModuleRef = ref_histogram->GetBinContent(i);
244 ref_average = ref_average + nHitsPerModuleRef;
245 }
246 }
247
248 for (i = 1; i <= n; i++) {
249 KLMChannelNumber channelIndex = std::round(histogram->GetBinCenter(i));
250 KLMChannelNumber channelNumber =
251 m_ChannelArrayIndex->getNumber(channelIndex);
252 double nHitsPerModule = histogram->GetBinContent(i);
253 average = average + nHitsPerModule;
254 m_ElementNumbers->channelNumberToElementNumbers(
255 channelNumber, &channelSubdetector, &channelSection, &channelSector,
256 &layer, &plane, &strip);
257 if ((channelSubdetector != subdetector) ||
258 (channelSection != section) ||
259 (channelSector != sector))
260 B2FATAL("Inconsistent element numbers.");
261 KLMModuleNumber module = m_ElementNumbers->moduleNumber(
262 subdetector, section, sector, layer);
263 it = moduleHitMap.find(module);
264 if (it == moduleHitMap.end()) {
265 moduleHitMap.insert(std::pair<KLMModuleNumber, double>(
266 module, nHitsPerModule));
267 } else {
268 it->second += nHitsPerModule;
269 }
270 }
271 unsigned int activeModuleChannels = 0;
272 int message_counter = 0;
273 for (it = moduleHitMap.begin(); it != moduleHitMap.end(); ++it) {
274 KLMModuleNumber moduleNumber = it->first;
275 if (it->second != 0) {
276 activeModuleChannels += m_ElementNumbers->getNChannelsModule(moduleNumber);
277 continue;
278 }
279 m_ElementNumbers->moduleNumberToElementNumbers(
280 moduleNumber, &channelSubdetector, &channelSection, &channelSector, &layer);
281 /* Channel with plane = 1, strip = 1 exists for any BKLM or EKLM module. */
282 KLMChannelNumber channel =
283 m_ElementNumbers->channelNumber(
284 channelSubdetector, channelSection, channelSector, layer, 1, 1);
285 const KLMElectronicsChannel* electronicsChannel =
286 m_ElectronicsMap->getElectronicsChannel(channel);
287 if (electronicsChannel == nullptr)
288 B2FATAL("Incomplete KLM electronics map.");
289 str = "No data from lane " + std::to_string(electronicsChannel->getLane());
290 latex.DrawLatexNDC(x, y, str.c_str());
291 y -= 0.05;
292 message_counter++;
293 /* Store the module number, used later in processPlaneHistogram
294 * to color the canvas with red and to raise up an alarm. */
295 if (channelSubdetector == KLMElementNumbers::c_BKLM) {
296 std::vector<KLMModuleNumber>::iterator ite =
297 std::find(m_DeadBarrelModules.begin(),
299 moduleNumber);
300 if (ite == m_DeadBarrelModules.end())
301 m_DeadBarrelModules.push_back(moduleNumber);
302 } else {
303 std::vector<KLMModuleNumber>::iterator ite = std::find(m_DeadEndcapModules.begin(),
305 moduleNumber);
306 if (ite == m_DeadEndcapModules.end())
307 m_DeadEndcapModules.push_back(moduleNumber);
308 }
309 }
310 if (activeModuleChannels == 0)
311 return;
312 average /= activeModuleChannels;
313 ref_average /= activeModuleChannels;
314
315 for (i = 1; i <= n; ++i) {
316 KLMChannelNumber channelIndex = std::round(histogram->GetBinCenter(i));
317 KLMChannelNumber channelNumber =
318 m_ChannelArrayIndex->getNumber(channelIndex);
319 double nHits = histogram->GetBinContent(i);
320 m_ElementNumbers->channelNumberToElementNumbers(
321 channelNumber, &channelSubdetector, &channelSection, &channelSector,
322 &layer, &plane, &strip);
323 std::string channelStatus = "Normal";
324 if ((nHits > average * m_ThresholdForMasked) && (nHits > m_MinHitsForFlagging)) {
325 channelStatus = "Masked";
326 std::vector<KLMModuleNumber>::iterator ite =
327 std::find(m_MaskedChannels.begin(),
328 m_MaskedChannels.end(),
329 channelNumber);
330 if (ite == m_MaskedChannels.end())
331 m_MaskedChannels.push_back(channelNumber);
332 B2DEBUG(20, "KLM@MaskMe " << channelNumber);
333 } else if ((nHits > average * m_ThresholdForHot) && (nHits > m_MinHitsForFlagging)) {
334 channelStatus = "Hot";
335 }
336 if (channelStatus != "Normal") {
337 const KLMElectronicsChannel* electronicsChannel =
338 m_ElectronicsMap->getElectronicsChannel(channelNumber);
339 if (electronicsChannel == nullptr)
340 B2FATAL("Incomplete BKLM electronics map.");
341 if (channelStatus == "Masked") {
342 histogram->SetBinContent(i, 0);
343 if (delta != nullptr)
344 delta->SetBinContent(i, 0);
345 }
346 str = channelStatus + " channel: ";
347 // lane, axis, channel
348 str += ("L" + std::to_string(electronicsChannel->getLane()) +
349 " A" + std::to_string(electronicsChannel->getAxis()) +
350 " Ch" + std::to_string(electronicsChannel->getChannel()));
351 message_counter++;
352 if (message_counter <= m_MessageThreshold) {
353 latex.DrawLatexNDC(x, y, str.c_str());
354 y -= 0.05;
355 }
356 }
357 }
358 if (message_counter > m_MessageThreshold) {
359 std::string verbose_message = " more messages";
360 verbose_message = std::to_string(message_counter - m_MessageThreshold) + verbose_message;
361 latex.DrawLatexNDC(x, y, verbose_message.c_str());
362 }
363
364
365 // for hot/masked channels, log scale plots (reference and main)
366 if (histogram->GetMaximum()*n > histogram->Integral()*m_ThresholdForLog && average * activeModuleChannels > m_MinHitsForFlagging) {
367 histogram->SetMinimum(1);
368 canvas->SetLogy();
369 } else if (ref_histogram != nullptr) {
370 if (ref_histogram->GetMaximum()*n > ref_histogram->Integral()*m_ThresholdForLog
371 && ref_average * activeModuleChannels > m_MinHitsForFlagging) {
372 histogram->SetMinimum(1);
373 canvas->SetLogy();
374 } else
375 canvas->SetLogy(0);
376 } else
377 canvas->SetLogy(0);
378
379 canvas->Modified();
380 canvas->Update();
381
382 /* Drawing dividing lines */
383 int divisions;
384 int bin = 1;
385 double xLine;
386 // drawing lines for BKLM sectors
387 if (subdetector == 1) {
388 int shift;
389 if (index == 0) {
390 divisions = 7;
391 shift = 1;
392 } else {
395 }
396 for (int k = 0; k < divisions; k++) {
397 xLine = (histogram->GetXaxis()->GetBinLowEdge(bin) - canvas->GetX1()) / (canvas->GetX2() - canvas->GetX1());
398 m_PlaneLine.DrawLineNDC(xLine, 0.1, xLine, 0.9);
399 bin += BKLMElementNumbers::getNStrips(section, sector, k + shift, 0)
400 + BKLMElementNumbers::getNStrips(section, sector, k + shift, 1);
401 }
402 } else { // drawing lines for EKLM sectors
403 if ((section == 2) && (index == 0 || index == 1))
404 divisions = 5;
405 else
406 divisions = 4;
407 for (int k = 0; k < divisions; k++) {
408 xLine = (histogram->GetXaxis()->GetBinLowEdge(bin) - canvas->GetX1()) / (canvas->GetX2() - canvas->GetX1());
409 m_PlaneLine.DrawLineNDC(xLine, 0.1, xLine, 0.9);
411 }
412 }
413 canvas->Modified();
414 canvas->Update();
415
416}
417
419 KLMSectionNumber section, TH2F* histogram, TCanvas* canvas)
420{
421 canvas->Clear();
422 canvas->cd();
423 histogram->SetStats(false);
424 histogram->Draw("COLZ");
425 /* Draw the lines only for the backward layers. */
427 m_2DHitsLine.DrawLine(-110, 80, -110, 190);
428 m_2DHitsLine.DrawLine(-110, 190, 110, 190);
429 m_2DHitsLine.DrawLine(110, 80, 110, 190);
430 m_2DHitsLine.DrawLine(-110, 80, 110, 80);
431 }
432 canvas->Modified();
433 canvas->Update();
434}
435
437 const std::string& histName)
438{
439 TH1* histogram = findHist(m_histogramDirectoryName + "/" + histName);
440 if (histogram == nullptr) {
441 B2WARNING("KLM DQM histogram " + m_histogramDirectoryName + "/" << histName << " is not found.");
442 return;
443 }
444
445 TCanvas* canvas = findCanvas(m_histogramDirectoryName + "/c_" + histName);
446 if (canvas == nullptr) {
447 B2WARNING("KLM DQM histogram canvas " + m_histogramDirectoryName + "/c_" << histName << " is not found.");
448 return;
449 }
450
451 else {
452 canvas->Clear();
453 canvas->cd();
454 histogram->Draw();
455 /* calling on delta histogram*/
456 TH1* delta = getDelta(m_histogramDirectoryName, histName);
457 UpdateCanvas(canvas->GetName(), delta != nullptr); //keeping this for testing purposes
458 if (delta != nullptr) {
459 B2INFO("DQMHistAnalysisKLM: Time Delta Entries is " << delta->GetEntries());
460 deltaDrawer(delta, histogram, canvas);
461 }
462 //reference check
463 TH1* ref = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
464 if (ref) {ref->Draw("hist,same");}
465 }
466}
467
469 TH1* histogram, TCanvas* canvas)
470{
471 histogram->Clear();
472 canvas->Clear();
473 canvas->cd();
474 if (m_MaskedChannels.size() > 0) {
475 int channelSubdetector, channelSection, channelSector;
476 int layer, plane, strip;
477 for (KLMChannelNumber channel : m_MaskedChannels) {
478 m_ElementNumbers->channelNumberToElementNumbers(
479 channel, &channelSubdetector, &channelSection, &channelSector,
480 &layer, &plane, &strip);
481 KLMSectorNumber sectorNumber;
482 if (channelSubdetector == KLMElementNumbers::c_BKLM)
483 sectorNumber = m_ElementNumbers->sectorNumberBKLM(channelSection, channelSector);
484 else
485 sectorNumber = m_ElementNumbers->sectorNumberEKLM(channelSection, channelSector);
486 KLMSectorNumber sectorIndex = m_SectorArrayIndex->getIndex(sectorNumber);
487 histogram->Fill(sectorIndex);
488 }
489 }
490 histogram->SetStats(false);
491 histogram->SetTitle("Number of masked channels per sector");
492 histogram->Draw();
493 canvas->Modified();
494 canvas->Update();
495}
496
498 const std::string& histName, TLatex* latex = nullptr, TH1* histogram = nullptr)
499{
500 // If no histogram is provided, try to retrieve it by name
501 if (!histogram) {
502 histogram = findHist(m_histogramDirectoryName + "/" + histName);
503 if (!histogram) {
504 B2WARNING("KLM DQM histogram " + m_histogramDirectoryName + "/" << histName << " is not found.");
505 return;
506 }
507 }
508
509 TCanvas* canvas = findCanvas(m_histogramDirectoryName + "/c_" + histName);
510 if (!canvas) {
511 B2WARNING("KLM DQM histogram canvas " + m_histogramDirectoryName + "/c_" << histName << " is not found.");
512 return;
513 }
514 // Set up the canvas
515 canvas->Clear();
516 canvas->cd();
517 histogram->SetStats(false);
518 histogram->Draw();
519
520 // Overlay reference histogram if available
521 TH1* ref = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
522 if (ref) {
523 ref->Draw("hist,same");
524 }
525
526 // Define variables for text and alarm positioning
527 double xAlarm = 0.15, yAlarm = 0.8;
528 int message_counter = 0;
529 std::string name;
530
531 // Determine if histogram is BKLM or EKLM and process accordingly
532 bool isBKLM = histName.find("bklm") != std::string::npos;
533
534 // Check if "fe" is in histName to adjust maximalLayer
535 bool isFE = histName.find("fe") != std::string::npos;
536
537 if (isBKLM) {
538 // Use a different maximalLayer if "fe" is found in the name
539 const int maximalLayer = isFE ? BKLMElementNumbers::getMaximalSectorGlobalNumber() / 8 :
541
542 for (int sector = 0; sector < BKLMElementNumbers::getMaximalSectorGlobalNumber(); ++sector) {
543 int bin = maximalLayer * sector + 1;
544 double xLine = histogram->GetXaxis()->GetBinLowEdge(bin);
545 double xText = histogram->GetXaxis()->GetBinLowEdge(bin + maximalLayer / 2);
546 double yText = gPad->GetUymin() + 0.98 * (gPad->GetUymax() - gPad->GetUymin());
547
548 if (sector > 0) {
549 m_PlaneLine.DrawLine(xLine, gPad->GetUymin(), xLine, gPad->GetUymax());
550 }
551
552 name = (sector < BKLMElementNumbers::getMaximalSectorNumber() ? "BB" : "BF") +
553 std::to_string(sector % BKLMElementNumbers::getMaximalSectorNumber());
554 m_PlaneText.DrawText(xText, yText, name.c_str());
555 }
556 // Only update canvas status if latex is provided
557 if (latex) {
558 updateCanvasStatus(canvas, m_DeadBarrelModules, latex, message_counter, xAlarm, yAlarm);
559 }
560 } else {
561 const double maximalLayer = EKLMElementNumbers::getMaximalLayerGlobalNumber();
563
564 for (int layerGlobal = 1; layerGlobal <= maximalLayer; ++layerGlobal) {
565 int bin = maxPlane * layerGlobal + 1;
566 double xLine = histogram->GetXaxis()->GetBinLowEdge(bin);
567 double xText = histogram->GetXaxis()->GetBinLowEdge(bin - maxPlane / 2);
568 double yText = gPad->GetUymin() + 0.98 * (gPad->GetUymax() - gPad->GetUymin());
569
570 if (layerGlobal < maximalLayer) {
571 m_PlaneLine.DrawLine(xLine, gPad->GetUymin(), xLine, gPad->GetUymax());
572 }
573
574 int section, layer;
575 m_EklmElementNumbers->layerNumberToElementNumbers(layerGlobal, &section, &layer);
576 name = (section == EKLMElementNumbers::c_BackwardSection ? "B" : "F") + std::to_string(layer);
577 m_PlaneText.DrawText(xText, yText, name.c_str());
578 }
579
580 // Only update canvas status if latex is provided
581 if (latex) {
582 updateCanvasStatus(canvas, m_DeadEndcapModules, latex, message_counter, xAlarm, yAlarm);
583 }
584 }
585
586 // Display additional message if message threshold exceeded
587 if (latex && message_counter > m_MessageThreshold) {
588 std::string verbose_string = std::to_string(message_counter - m_MessageThreshold) + " more messages";
589 latex->DrawLatexNDC(xAlarm, yAlarm, verbose_string.c_str());
590 }
591
592 canvas->Modified();
593 canvas->Update();
594}
595
596// Helper function to update canvas status based on dead modules
598 TCanvas* canvas, const std::vector<KLMModuleNumber>& deadModules,
599 TLatex* latex, int& message_counter, double xAlarm, double yAlarm)
600{
601 if (deadModules.empty()) {
604 for (const KLMModuleNumber& module : deadModules) {
605 int moduleSubdetector, moduleSection, moduleSector, moduleLayer;
606 m_ElementNumbers->moduleNumberToElementNumbers(module, &moduleSubdetector, &moduleSection, &moduleSector, &moduleLayer);
607
608 std::string alarm = "No data from " + m_ElementNumbers->getSectorDAQName(moduleSubdetector, moduleSection, moduleSector)
609 + ", layer " + std::to_string(moduleLayer);
610 message_counter++;
611 if (message_counter <= m_MessageThreshold) {
612 latex->DrawLatexNDC(xAlarm, yAlarm, alarm.c_str());
613 yAlarm -= 0.05;
614 }
615 }
616 if (!m_IsNullRun) {
618 }
619 } else {
621 }
622}
623
624
626 const std::string& histName, TLatex& latex)
627{
628 // Internally call the main function with a pointer to TLatex
629 processPlaneHistogram(histName, &latex, nullptr);
630}
631
632void DQMHistAnalysisKLMModule::processFEHistogram(TH1* feHist, const std::string& histName, TCanvas* canvas)
633{
634 if (!feHist) {
635 B2WARNING("processFEHistogram: feHist is null, exiting function.");
636 return;
637 }
638 if (!canvas) {
639 B2WARNING("processFEHistogram: canvas is null, cannot draw histograms.");
640 return;
641 }
642
643 /* Obtain plots necessary for FE Ratio plots */
644 auto* numerator = findHist(m_histogramDirectoryName + "/" + histName + "_0");
645 auto* denominator = findHist(m_histogramDirectoryName + "/" + histName + "_1");
646 /* Check if fe histograms exist*/
647 if (numerator == nullptr || denominator == nullptr) {
648 B2INFO("processFEHistogram: Histograms needed for FE Ratio computation are not found");
649 return;
650 }
651
652 feHist->Reset();
653 std::unique_ptr<TH1> feClone(static_cast<TH1*>(feHist->Clone())); // Clone feHist
654
655 canvas->cd();
656
657 if (denominator != nullptr && numerator != nullptr) {
658 // Clone numerator and denominator into unique_ptrs to ensure they are deleted automatically
659 auto tempNumerator = std::unique_ptr<TH1>(static_cast<TH1*>(numerator->Clone()));
660 auto tempSum = std::unique_ptr<TH1>(static_cast<TH1*>(denominator->Clone()));
661
662 // Add numerator to denominator to get the sum (denominator + numerator)
663 tempSum->Add(numerator);
664
665 // Divide numerator by (denominator + numerator) and store result in feHist
666 feHist->Divide(tempNumerator.get(), tempSum.get(), 1.0, 1.0, "B");
667 feHist->Draw();
668
669 // Reference check
670 TH1* ref = findRefHist(feHist->GetName(), ERefScaling::c_RefScaleNone);
671 if (ref) {
672 ref->Draw("hist,same");
673 B2INFO("processFEHistogram: Found and drew reference histogram.");
674 } else {
675 B2WARNING("processFEHistogram: Reference histogram not found.");
676 }
677
678 canvas->Modified();
679 canvas->Update();
680 B2INFO("processFEHistogram: Updated canvas after first draw.");
681
682 /* Delta component */
683 // Use the latest available deltas, not only "updated in the same event".
684 auto deltaDenom = getDelta(m_histogramDirectoryName, histName + "_1", 0, false);
685 auto deltaNumer = getDelta(m_histogramDirectoryName, histName + "_0", 0, false);
686
687 UpdateCanvas(canvas->GetName(), (feHist != nullptr));
688 if (deltaNumer != nullptr && deltaDenom != nullptr) {
689 B2INFO("DQMHistAnalysisKLM: FE Ratio Delta Num/Denom Entries is "
690 << deltaNumer->GetEntries() << "/" << deltaDenom->GetEntries());
691
692 // Clone deltaNumer and deltaDenom into unique_ptrs to create the delta sum
693 auto deltaTempNumerator = std::unique_ptr<TH1>(static_cast<TH1*>(deltaNumer->Clone()));
694 auto deltaTempSum = std::unique_ptr<TH1>(static_cast<TH1*>(deltaDenom->Clone()));
695
696 // Add delta numerator and denominator
697 deltaTempSum->Add(deltaNumer);
698
699 // Divide deltaNumer by (deltaDenom + deltaNumer) and store in feClone
700 feClone->Divide(deltaTempNumerator.get(), deltaTempSum.get(), 1.0, 1.0, "B");
701 feClone->SetLineColor(kOrange);
702 feClone->DrawCopy("SAME");
703
704 canvas->Modified();
705 canvas->Update();
706 } else {
707 B2WARNING("processFEHistogram: Delta numerator or denominator not found.");
708 }
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.
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.