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", 50000.);
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_fe_bklm_ratio_name = m_histogramDirectoryName + "/c_fe_bklm_ratio";
95 m_c_fe_bklm_ratio = new TCanvas((c_fe_bklm_ratio_name).c_str());
96 std::string c_fe_eklm_ratio_name = m_histogramDirectoryName + "/c_fe_eklm_ratio";
97 m_c_fe_eklm_ratio = new TCanvas((c_fe_eklm_ratio_name).c_str());
98 // Feature extraction status histogram for BKLM
100 int eklmPlanes = EKLMElementNumbers::getMaximalPlaneGlobalNumber(); // 208
101 //BKLM
102 std::string fe_bklm_ratio_name = m_histogramDirectoryName + "/fe_bklm_ratio";
103 m_fe_bklm_ratio = new TH1F((fe_bklm_ratio_name).c_str(),
104 "FE Ratio in BKLM",
105 bklmSectors * 2, 0.5, 0.5 + bklmSectors * 2);
106 m_fe_bklm_ratio->GetXaxis()->SetTitle("Scintillator Layer number");
107 m_fe_bklm_ratio->SetStats(false);
108 m_fe_bklm_ratio->SetOption("HIST");
109 //EKLM
110 std::string fe_eklm_ratio_name = m_histogramDirectoryName + "/fe_eklm_ratio";
111 m_fe_eklm_ratio = new TH1F((fe_eklm_ratio_name).c_str(),
112 "FE Ratio in EKLM",
113 eklmPlanes, 0.5, 0.5 + eklmPlanes);
114 m_fe_eklm_ratio->GetXaxis()->SetTitle("Plane number");
115 m_fe_eklm_ratio->SetStats(false);
116 m_fe_eklm_ratio->SetOption("HIST");
117
118 std::string str;
120 for (KLMChannelIndex& klmSector : klmIndex) {
121 int nHistograms;
122 if (klmSector.getSubdetector() == KLMElementNumbers::c_BKLM)
123 nHistograms = 2;
124 else
125 nHistograms = 3;
126 for (int j = 0; j < nHistograms; j++) {
127 str = "strip_hits_subdetector_" +
128 std::to_string(klmSector.getSubdetector()) +
129 "_section_" + std::to_string(klmSector.getSection()) +
130 "_sector_" + std::to_string(klmSector.getSector()) +
131 "_" + std::to_string(j);
132 addDeltaPar(m_histogramDirectoryName, str, HistDelta::c_Entries, m_minEntries, 1);
133
134 }
135 }
136
137}
138
142
144{
145 if (!m_ElectronicsMap.isValid())
146 B2FATAL("No KLM electronics map.");
149 m_DeadBarrelModules.clear();
150 m_DeadEndcapModules.clear();
151 m_MaskedChannels.clear();
152
153 m_IsNullRun = (getRunType() == "null");
154}
155
157{
158 int hist_max_bin; double max_position;
159 TH1* time_rpc = findHist(m_histogramDirectoryName + "/time_rpc");
160 if (time_rpc) {
161 hist_max_bin = time_rpc->GetMaximumBin();
162 max_position = time_rpc->GetXaxis()->GetBinCenter(hist_max_bin);
163 m_monObj->setVariable("RPC_Time_Peak", max_position);
164 }
165
166 TH1* time_scint_bklm = findHist(m_histogramDirectoryName + "/time_scintillator_bklm");
167 if (time_scint_bklm) {
168 hist_max_bin = time_scint_bklm->GetMaximumBin();
169 max_position = time_scint_bklm->GetXaxis()->GetBinCenter(hist_max_bin);
170 m_monObj->setVariable("BKLM_Scint_Time_Peak", max_position);
171 }
172
173 TH1* time_scint_eklm = findHist(m_histogramDirectoryName + "/time_scintillator_eklm");
174 if (time_scint_eklm) {
175 hist_max_bin = time_scint_eklm->GetMaximumBin();
176 max_position = time_scint_eklm->GetXaxis()->GetBinCenter(hist_max_bin);
177 m_monObj->setVariable("EKLM_Scint_Time_Peak", max_position);
178 }
179}
180
182{
184 B2WARNING("Either DAQ/Nevent is not found or Nevent = 0.");
185 /* Set the minimal number of processed events to 0 if we can't determine the processed events. */
187 }
189}
190
191void DQMHistAnalysisKLMModule::deltaDrawer(TH1* delta, TH1* histogram, TCanvas* canvas)
192{
193 if (delta != nullptr) {
194 Double_t scale = (Double_t) histogram->Integral(); //want delta and histo to have same norm
195
196 // delta != nullptr should take care of whether update condition is met.
197 delta->SetLineColor(kBlackBody); //random choice of not green or blue
198 delta->SetLineStyle(4);
199 delta->DrawNormalized("SAME", scale); //normalize delta to histo
200 canvas->Modified();
201 canvas->Update();
202 }
203}
204
206 int subdetector, int section, int sector, int index,
207 TH1* histogram, TH1* delta, TCanvas* canvas, TLatex& latex)
208{
209 double x = 0.15;
210 double y = 0.85;
211 int i, n;
212 std::map<KLMModuleNumber, double> moduleHitMap;
213 std::map<KLMModuleNumber, double>::iterator it;
214 double average = 0;
215 int channelSubdetector, channelSection, channelSector;
216 int layer, plane, strip;
217 std::string str;
218 canvas->Clear();
219 canvas->cd();
220 histogram->SetStats(false);
221 canvas->SetLogy(0); //initialize to start without logscale
222 histogram->Draw();
223 deltaDrawer(delta, histogram, canvas); //draw normalized delta on top
224 n = histogram->GetXaxis()->GetNbins();
225
226 /* call reference histograms from base class*/
227 TH1* ref_histogram = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
228 if (ref_histogram) {ref_histogram->Draw("hist,same");}
229 float ref_average = 0;
230
231 if (ref_histogram != nullptr) {
232 for (i = 1; i <= n; i++) {
233 double nHitsPerModuleRef = ref_histogram->GetBinContent(i);
234 ref_average = ref_average + nHitsPerModuleRef;
235 }
236 }
237
238 for (i = 1; i <= n; i++) {
239 KLMChannelNumber channelIndex = std::round(histogram->GetBinCenter(i));
240 KLMChannelNumber channelNumber =
241 m_ChannelArrayIndex->getNumber(channelIndex);
242 double nHitsPerModule = histogram->GetBinContent(i);
243 average = average + nHitsPerModule;
244 m_ElementNumbers->channelNumberToElementNumbers(
245 channelNumber, &channelSubdetector, &channelSection, &channelSector,
246 &layer, &plane, &strip);
247 if ((channelSubdetector != subdetector) ||
248 (channelSection != section) ||
249 (channelSector != sector))
250 B2FATAL("Inconsistent element numbers.");
251 KLMModuleNumber module = m_ElementNumbers->moduleNumber(
252 subdetector, section, sector, layer);
253 it = moduleHitMap.find(module);
254 if (it == moduleHitMap.end()) {
255 moduleHitMap.insert(std::pair<KLMModuleNumber, double>(
256 module, nHitsPerModule));
257 } else {
258 it->second += nHitsPerModule;
259 }
260 }
261 unsigned int activeModuleChannels = 0;
262 int message_counter = 0;
263 for (it = moduleHitMap.begin(); it != moduleHitMap.end(); ++it) {
264 KLMModuleNumber moduleNumber = it->first;
265 if (it->second != 0) {
266 activeModuleChannels += m_ElementNumbers->getNChannelsModule(moduleNumber);
267 continue;
268 }
269 m_ElementNumbers->moduleNumberToElementNumbers(
270 moduleNumber, &channelSubdetector, &channelSection, &channelSector, &layer);
271 /* Channel with plane = 1, strip = 1 exists for any BKLM or EKLM module. */
272 KLMChannelNumber channel =
273 m_ElementNumbers->channelNumber(
274 channelSubdetector, channelSection, channelSector, layer, 1, 1);
275 const KLMElectronicsChannel* electronicsChannel =
276 m_ElectronicsMap->getElectronicsChannel(channel);
277 if (electronicsChannel == nullptr)
278 B2FATAL("Incomplete KLM electronics map.");
279 str = "No data from lane " + std::to_string(electronicsChannel->getLane());
280 latex.DrawLatexNDC(x, y, str.c_str());
281 y -= 0.05;
282 message_counter++;
283 /* Store the module number, used later in processPlaneHistogram
284 * to color the canvas with red and to raise up an alarm. */
285 if (channelSubdetector == KLMElementNumbers::c_BKLM) {
286 std::vector<KLMModuleNumber>::iterator ite =
287 std::find(m_DeadBarrelModules.begin(),
289 moduleNumber);
290 if (ite == m_DeadBarrelModules.end())
291 m_DeadBarrelModules.push_back(moduleNumber);
292 } else {
293 std::vector<KLMModuleNumber>::iterator ite = std::find(m_DeadEndcapModules.begin(),
295 moduleNumber);
296 if (ite == m_DeadEndcapModules.end())
297 m_DeadEndcapModules.push_back(moduleNumber);
298 }
299 }
300 if (activeModuleChannels == 0)
301 return;
302 average /= activeModuleChannels;
303 ref_average /= activeModuleChannels;
304
305 for (i = 1; i <= n; ++i) {
306 KLMChannelNumber channelIndex = std::round(histogram->GetBinCenter(i));
307 KLMChannelNumber channelNumber =
308 m_ChannelArrayIndex->getNumber(channelIndex);
309 double nHits = histogram->GetBinContent(i);
310 m_ElementNumbers->channelNumberToElementNumbers(
311 channelNumber, &channelSubdetector, &channelSection, &channelSector,
312 &layer, &plane, &strip);
313 std::string channelStatus = "Normal";
314 if ((nHits > average * m_ThresholdForMasked) && (nHits > m_MinHitsForFlagging)) {
315 channelStatus = "Masked";
316 std::vector<KLMModuleNumber>::iterator ite =
317 std::find(m_MaskedChannels.begin(),
318 m_MaskedChannels.end(),
319 channelNumber);
320 if (ite == m_MaskedChannels.end())
321 m_MaskedChannels.push_back(channelNumber);
322 B2DEBUG(20, "KLM@MaskMe " << channelNumber);
323 } else if ((nHits > average * m_ThresholdForHot) && (nHits > m_MinHitsForFlagging)) {
324 channelStatus = "Hot";
325 }
326 if (channelStatus != "Normal") {
327 const KLMElectronicsChannel* electronicsChannel =
328 m_ElectronicsMap->getElectronicsChannel(channelNumber);
329 if (electronicsChannel == nullptr)
330 B2FATAL("Incomplete BKLM electronics map.");
331 if (channelStatus == "Masked") {
332 histogram->SetBinContent(i, 0);
333 if (delta != nullptr)
334 delta->SetBinContent(i, 0);
335 }
336 str = channelStatus + " channel: ";
337 // lane, axis, channel
338 str += ("L" + std::to_string(electronicsChannel->getLane()) +
339 " A" + std::to_string(electronicsChannel->getAxis()) +
340 " Ch" + std::to_string(electronicsChannel->getChannel()));
341 message_counter++;
342 if (message_counter <= m_MessageThreshold) {
343 latex.DrawLatexNDC(x, y, str.c_str());
344 y -= 0.05;
345 }
346 }
347 }
348 if (message_counter > m_MessageThreshold) {
349 std::string verbose_message = " more messages";
350 verbose_message = std::to_string(message_counter - m_MessageThreshold) + verbose_message;
351 latex.DrawLatexNDC(x, y, verbose_message.c_str());
352 }
353
354
355 // for hot/masked channels, log scale plots (reference and main)
356 if (histogram->GetMaximum()*n > histogram->Integral()*m_ThresholdForLog && average * activeModuleChannels > m_MinHitsForFlagging) {
357 histogram->SetMinimum(1);
358 canvas->SetLogy();
359 } else if (ref_histogram != nullptr) {
360 if (ref_histogram->GetMaximum()*n > ref_histogram->Integral()*m_ThresholdForLog
361 && ref_average * activeModuleChannels > m_MinHitsForFlagging) {
362 histogram->SetMinimum(1);
363 canvas->SetLogy();
364 } else
365 canvas->SetLogy(0);
366 } else
367 canvas->SetLogy(0);
368
369 canvas->Modified();
370 canvas->Update();
371
372 /* Drawing dividing lines */
373 int divisions;
374 int bin = 1;
375 double xLine;
376 // drawing lines for BKLM sectors
377 if (subdetector == 1) {
378 int shift;
379 if (index == 0) {
380 divisions = 7;
381 shift = 1;
382 } else {
385 }
386 for (int k = 0; k < divisions; k++) {
387 xLine = (histogram->GetXaxis()->GetBinLowEdge(bin) - canvas->GetX1()) / (canvas->GetX2() - canvas->GetX1());
388 m_PlaneLine.DrawLineNDC(xLine, 0.1, xLine, 0.9);
389 bin += BKLMElementNumbers::getNStrips(section, sector, k + shift, 0)
390 + BKLMElementNumbers::getNStrips(section, sector, k + shift, 1);
391 }
392 } else { // drawing lines for EKLM sectors
393 if ((section == 2) && (index == 0 || index == 1))
394 divisions = 5;
395 else
396 divisions = 4;
397 for (int k = 0; k < divisions; k++) {
398 xLine = (histogram->GetXaxis()->GetBinLowEdge(bin) - canvas->GetX1()) / (canvas->GetX2() - canvas->GetX1());
399 m_PlaneLine.DrawLineNDC(xLine, 0.1, xLine, 0.9);
401 }
402 }
403 canvas->Modified();
404 canvas->Update();
405
406}
407
409 KLMSectionNumber section, TH2F* histogram, TCanvas* canvas)
410{
411 canvas->Clear();
412 canvas->cd();
413 histogram->SetStats(false);
414 histogram->Draw("COLZ");
415 /* Draw the lines only for the backward layers. */
417 m_2DHitsLine.DrawLine(-110, 80, -110, 190);
418 m_2DHitsLine.DrawLine(-110, 190, 110, 190);
419 m_2DHitsLine.DrawLine(110, 80, 110, 190);
420 m_2DHitsLine.DrawLine(-110, 80, 110, 80);
421 }
422 canvas->Modified();
423 canvas->Update();
424}
425
427 const std::string& histName)
428{
429 TH1* histogram = findHist(m_histogramDirectoryName + "/" + histName);
430 if (histogram == nullptr) {
431 B2WARNING("KLM DQM histogram " + m_histogramDirectoryName + "/" << histName << " is not found.");
432 return;
433 }
434
435 TCanvas* canvas = findCanvas(m_histogramDirectoryName + "/c_" + histName);
436 if (canvas == nullptr) {
437 B2WARNING("KLM DQM histogram canvas " + m_histogramDirectoryName + "/c_" << histName << " is not found.");
438 return;
439 }
440
441 else {
442 canvas->Clear();
443 canvas->cd();
444 histogram->Draw();
445 /* calling on delta histogram*/
446 TH1* delta = getDelta(m_histogramDirectoryName, histName);
447 UpdateCanvas(canvas->GetName(), delta != nullptr); //keeping this for testing purposes
448 if (delta != nullptr) {
449 B2INFO("DQMHistAnalysisKLM: Time Delta Entries is " << delta->GetEntries());
450 deltaDrawer(delta, histogram, canvas);
451 }
452 //reference check
453 TH1* ref = findRefHist(histogram->GetName(), ERefScaling::c_RefScaleEntries, histogram);
454 if (ref) {ref->Draw("hist,same");}
455 }
456}
457
459 const std::string& histName)
460{
461 TH1* histogram = findHist(m_histogramDirectoryName + "/" + histName);
462 if (histogram == nullptr) {
463 B2WARNING("KLM DQM histogram " + m_histogramDirectoryName + "/" << histName << " is not found.");
464 return;
465 }
466 TCanvas* canvas = findCanvas(m_histogramDirectoryName + "/c_" + histName);
467 if (canvas == nullptr) {
468 B2WARNING("KLM DQM histogram canvas " + m_histogramDirectoryName + "/c_" << histName << " is not found.");
469 return;
470 }
471
472 histogram->Clear();
473 canvas->Clear();
474 canvas->cd();
475 if (m_MaskedChannels.size() > 0) {
476 int channelSubdetector, channelSection, channelSector;
477 int layer, plane, strip;
478 for (KLMChannelNumber channel : m_MaskedChannels) {
479 m_ElementNumbers->channelNumberToElementNumbers(
480 channel, &channelSubdetector, &channelSection, &channelSector,
481 &layer, &plane, &strip);
482 KLMSectorNumber sectorNumber;
483 if (channelSubdetector == KLMElementNumbers::c_BKLM)
484 sectorNumber = m_ElementNumbers->sectorNumberBKLM(channelSection, channelSector);
485 else
486 sectorNumber = m_ElementNumbers->sectorNumberEKLM(channelSection, channelSector);
487 KLMSectorNumber sectorIndex = m_SectorArrayIndex->getIndex(sectorNumber);
488 histogram->Fill(sectorIndex);
489 }
490 }
491 histogram->SetStats(false);
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, TH1* denominator, TH1* numerator, 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 feHist->Reset();
644 std::unique_ptr<TH1> feClone(static_cast<TH1*>(feHist->Clone())); // Clone feHist
645
646 canvas->cd();
647
648 if (denominator != nullptr && numerator != nullptr) {
649 // Clone numerator and denominator into unique_ptrs to ensure they are deleted automatically
650 auto tempNumerator = std::unique_ptr<TH1>(static_cast<TH1*>(numerator->Clone()));
651 auto tempSum = std::unique_ptr<TH1>(static_cast<TH1*>(denominator->Clone()));
652
653 // Add numerator to denominator to get the sum (denominator + numerator)
654 tempSum->Add(numerator);
655
656 // Divide numerator by (denominator + numerator) and store result in feHist
657 feHist->Divide(tempNumerator.get(), tempSum.get(), 1.0, 1.0, "B");
658 feHist->Draw();
659
660 // Reference check
661 TH1* ref = findRefHist(feHist->GetName(), ERefScaling::c_RefScaleNone);
662 if (ref) {
663 ref->Draw("hist,same");
664 B2INFO("processFEHistogram: Found and drew reference histogram.");
665 } else {
666 B2WARNING("processFEHistogram: Reference histogram not found.");
667 }
668
669 canvas->Modified();
670 canvas->Update();
671 B2INFO("processFEHistogram: Updated canvas after first draw.");
672
673 /* Delta component */
674 auto deltaDenom = getDelta("", denominator->GetName());
675 auto deltaNumer = getDelta("", numerator->GetName());
676
677 UpdateCanvas(canvas->GetName(), (feHist != nullptr));
678 if ((deltaNumer != nullptr) && (deltaDenom != nullptr)) {
679 B2INFO("DQMHistAnalysisKLM: FE Ratio Delta Num/Denom Entries is "
680 << deltaNumer->GetEntries() << "/" << deltaDenom->GetEntries());
681
682 // Clone deltaNumer and deltaDenom into unique_ptrs to create the delta sum
683 auto deltaTempNumerator = std::unique_ptr<TH1>(static_cast<TH1*>(deltaNumer->Clone()));
684 auto deltaTempSum = std::unique_ptr<TH1>(static_cast<TH1*>(deltaDenom->Clone()));
685
686 // Add delta numerator and denominator
687 deltaTempSum->Add(deltaNumer);
688
689 // Divide deltaNumer by (deltaDenom + deltaNumer) and store in feClone
690 feClone->Divide(deltaTempNumerator.get(), deltaTempSum.get(), 1.0, 1.0, "B");
691 feClone->SetLineColor(kOrange);
692 feClone->DrawCopy("SAME");
693
694 canvas->Modified();
695 canvas->Update();
696 } else {
697 B2WARNING("processFEHistogram: Delta numerator or denominator not found.");
698 }
699 } else {
700 B2WARNING("processFEHistogram: Skipped histogram processing due to missing numerator/denominator.");
701 }
702}
703
705{
706 /* If KLM is not included, stop here and return. */
707 TH1* daqInclusion = findHist(m_histogramDirectoryName + "/daq_inclusion");
708 if (not(daqInclusion == nullptr)) {
709 int isKlmIncluded = daqInclusion->GetBinContent(daqInclusion->GetXaxis()->FindBin("Yes"));
710 if (isKlmIncluded == 0)
711 return;
712 }
713 /* Make sure that the vectors are cleared at each DQM refresh. */
714 m_DeadBarrelModules.clear();
715 m_DeadEndcapModules.clear();
716 m_MaskedChannels.clear();
718 std::string str, histogramName, canvasName;
719 TLatex latex;
720 latex.SetTextColor(kRed);
721 latex.SetTextAlign(11);
723 // gathering relevant info for analyseChannelHitHistogram
724 for (KLMChannelIndex& klmSector : klmIndex) {
725 int nHistograms;
726 if (klmSector.getSubdetector() == KLMElementNumbers::c_BKLM)
727 nHistograms = 2;
728 else
729 nHistograms = 3;
730 for (int j = 0; j < nHistograms; j++) {
731 str = "strip_hits_subdetector_" +
732 std::to_string(klmSector.getSubdetector()) +
733 "_section_" + std::to_string(klmSector.getSection()) +
734 "_sector_" + std::to_string(klmSector.getSector()) +
735 "_" + std::to_string(j);
736 histogramName = m_histogramDirectoryName + "/" + str;
737 canvasName = m_histogramDirectoryName + "/c_" + str;
738 TH1* histogram = findHist(histogramName);
739 //get delta histogram (should we work with a clone instead?)
740 auto delta = getDelta("", histogramName);
741
742 if (histogram == nullptr) {
743 B2WARNING("KLM DQM histogram " << histogramName << " is not found.");
744 continue;
745 }
746 TCanvas* canvas = findCanvas(canvasName);
747 if (canvas == nullptr) {
748 B2WARNING("KLM DQM histogram canvas " << canvasName << " is not found.");
749 continue;
750 }
751 // Add this canvas that it is time to update
752 // not sure if this is interfering with the generation of some features
753 // after testing, switch condition back to delta != nullptr || histogram != nullptr
754 UpdateCanvas(canvas->GetName(), true);
756 klmSector.getSubdetector(), klmSector.getSection(),
757 klmSector.getSector(), j, histogram, delta, canvas, latex);
758
759 }
760 }
761 /* Temporary change the color palette. */
762 gStyle->SetPalette(kLightTemperature);
764 for (KLMChannelIndex& klmSection : klmIndex) {
765 KLMSubdetectorNumber subdetector = klmSection.getSubdetector();
766 if (subdetector == KLMElementNumbers::c_EKLM) {
767 KLMSubdetectorNumber section = klmSection.getSection();
768 int maximalLayerNumber = m_EklmElementNumbers->getMaximalDetectorLayerNumber(section);
769 for (int j = 1; j <= maximalLayerNumber; ++j) {
770 str = "spatial_2d_hits_subdetector_" + std::to_string(subdetector) +
771 "_section_" + std::to_string(section) +
772 "_layer_" + std::to_string(j);
773 histogramName = m_histogramDirectoryName + "/" + str;
774 canvasName = m_histogramDirectoryName + "/c_" + str;
775 TH2F* histogram = static_cast<TH2F*>(findHist(histogramName));
776 if (histogram == nullptr) {
777 B2ERROR("KLM DQM histogram " << histogramName << " is not found.");
778 continue;
779 }
780 TCanvas* canvas = findCanvas(canvasName);
781 if (canvas == nullptr) {
782 B2ERROR("KLM DQM histogram canvas " << canvasName << " is not found.");
783 continue;
784 }
785 processSpatial2DHitEndcapHistogram(section, histogram, canvas);
786 }
787 }
788 }
789 /* Obtain plots necessary for FE Ratio plots */
790 TH1F* feStatus_bklm_scintillator_0 = (TH1F*)findHist(m_histogramDirectoryName + "/feStatus_bklm_scintillator_layers_0");
791 TH1F* feStatus_bklm_scintillator_1 = (TH1F*)findHist(m_histogramDirectoryName + "/feStatus_bklm_scintillator_layers_1");
792
793 TH1F* feStatus_eklm_plane_0 = (TH1F*)findHist(m_histogramDirectoryName + "/feStatus_eklm_plane_0");
794 TH1F* feStatus_eklm_plane_1 = (TH1F*)findHist(m_histogramDirectoryName + "/feStatus_eklm_plane_1");
795 /* Check if fe histograms exist*/
796 if ((feStatus_bklm_scintillator_0 == nullptr || feStatus_bklm_scintillator_1 == nullptr)) {
797 B2INFO("Histograms needed for BKLM feature extraction computation are not found");
798 }
799
800 if ((feStatus_eklm_plane_0 == nullptr || feStatus_eklm_plane_1 == nullptr)) {
801 B2INFO("Histograms needed for EKLM feature extraction computation are not found");
802 }
803 /* Reset the color palette to the default one. */
804 gStyle->SetPalette(kBird);
805 fillMaskedChannelsHistogram("masked_channels");
806 latex.SetTextColor(kBlue);
807 processPlaneHistogram("plane_bklm_phi", latex);
808 processPlaneHistogram("plane_bklm_z", latex);
809 processPlaneHistogram("plane_eklm", latex);
810
811 processFEHistogram(m_fe_bklm_ratio, feStatus_bklm_scintillator_1, feStatus_bklm_scintillator_0, m_c_fe_bklm_ratio);
812 processFEHistogram(m_fe_eklm_ratio, feStatus_eklm_plane_1, feStatus_eklm_plane_0, m_c_fe_eklm_ratio);
813 processPlaneHistogram("fe_bklm_ratio", nullptr, m_fe_bklm_ratio);
814 processPlaneHistogram("fe_eklm_ratio", nullptr, m_fe_eklm_ratio);
815
816
817 processTimeHistogram("time_rpc");
818 processTimeHistogram("time_scintillator_bklm");
819 processTimeHistogram("time_scintillator_eklm");
820
821 B2DEBUG(20, "Updating EPICS PVs for DQMHistAnalysisKLM");
822 // only update PVs if there's enough statistics and datasize != 0
823 // Check if it's a null run, if so, don't update EPICS PVs
824 if (m_IsNullRun) {
825 B2INFO("DQMHistAnalysisKLM: Null run detected. No PV Update.");
826 return;
827 }
828 auto* daqDataSize = findHist("DAQ/KLMDataSize");
829 double meanDAQDataSize = 0.;
830 if (daqDataSize != nullptr) {
831 meanDAQDataSize = daqDataSize->GetMean();
832 } else
833 B2WARNING("DQMHistAnalysisKLM: Cannot find KLMDataSize");
834 if ((daqDataSize != nullptr) and (meanDAQDataSize != 0.)) {
836 setEpicsPV("MaskedChannels", (double)m_MaskedChannels.size());
837 setEpicsPV("DeadBarrelModules", (double)m_DeadBarrelModules.size());
838 setEpicsPV("DeadEndcapModules", (double)m_DeadEndcapModules.size());
839 B2DEBUG(20, "DQMHistAnalysisKLM: MaskedChannels " << m_MaskedChannels.size());
840 B2DEBUG(20, "DQMHistAnalysisKLM: DeadBarrelModules " << m_DeadBarrelModules.size());
841 B2DEBUG(20, "DQMHistAnalysisKLM: DeadEndcapModules " << m_DeadEndcapModules.size());
842 }
843 } else
844 B2INFO("DQMHistAnalysisKLM: KLM Not included. No PV Update. ");
845
846
847}
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.
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 processSpatial2DHitEndcapHistogram(uint16_t section, TH2F *histogram, TCanvas *canvas)
Process spatial 2D hits histograms for endcap.
MonitoringObject * m_monObj
Monitoring object.
void processFEHistogram(TH1 *feHist, TH1 *denominator, TH1 *numerator, TCanvas *canvas)
Process histogram containing the efficiencies.
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.
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.
void fillMaskedChannelsHistogram(const std::string &histName)
Fill histogram containing masked channels per sector.
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).
static MonitoringObject * getMonitoringObject(const std::string &name)
Get MonitoringObject with given name (new object is created if non-existing)
void addDeltaPar(const std::string &dirname, const std::string &histname, HistDelta::EDeltaType t, int p, unsigned int a=1)
Add Delta histogram parameters.
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 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.
void setEpicsPV(std::string keyname, double value)
Write value to a EPICS PV.
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.
int registerEpicsPV(std::string pvname, std::string keyname="")
EPICS related Functions.
void UpdateCanvas(std::string name, bool updated=true)
Mark canvas as updated (or not)
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.