Belle II Software  release-08-00-10
DQMHistAnalysisTOP.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 #include <dqm/analysis/modules/DQMHistAnalysisTOP.h>
10 #include <boost/format.hpp>
11 #include <boost/algorithm/string.hpp>
12 #include <TClass.h>
13 #include <TF1.h>
14 #include <TROOT.h>
15 #include <TStyle.h>
16 #include <TProfile.h>
17 #include <TString.h>
18 #include <map>
19 
20 using namespace std;
21 using namespace Belle2;
22 using boost::format;
23 
24 //-----------------------------------------------------------------
25 // Register the Module
26 //-----------------------------------------------------------------
27 REG_MODULE(DQMHistAnalysisTOP);
28 
29 //-----------------------------------------------------------------
30 // Implementation
31 //-----------------------------------------------------------------
32 
33 DQMHistAnalysisTOPModule::DQMHistAnalysisTOPModule(): DQMHistAnalysisModule()
34 {
35  // Set description
36  setDescription("Histogram analysis module for TOP DQM.");
37 
38  // Add parameters
39  addParam("asicWindowsBand", m_asicWindowsBand,
40  "lower and upper bin of a band denoting good windows", m_asicWindowsBand);
41  addParam("asicWindowsAlarmLevels", m_asicWindowsAlarmLevels,
42  "alarm levels for the fraction of windows outside the band (yellow, red)", m_asicWindowsAlarmLevels);
43  addParam("eventMonitorAlarmLevels", m_eventMonitorAlarmLevels,
44  "alarm levels for the fraction of desynchronized digits (yellow, red)", m_eventMonitorAlarmLevels);
45  addParam("junkHitsAlarmLevels", m_junkHitsAlarmLevels,
46  "alarm levels for the fraction of junk hits (yellow, red)", m_junkHitsAlarmLevels);
47  addParam("deadChannelsAlarmLevels", m_deadChannelsAlarmLevels,
48  "alarm levels for the fraction of dead + hot channels (yellow, red)", m_deadChannelsAlarmLevels);
49  addParam("backgroundAlarmLevels", m_backgroundAlarmLevels,
50  "alarm levels for background rates [MHz/PMT] (yellow, red)", m_backgroundAlarmLevels);
51  addParam("photonYieldsAlarmLevels", m_photonYieldsAlarmLevels,
52  "alarm levels for the number of photons per track (red, yellow)", m_photonYieldsAlarmLevels);
53  addParam("excludedBoardstacks", m_excludedBoardstacks,
54  "boarstacks to be excluded from alarming. Names are given like '5c', '13d' etc.", m_excludedBoardstacks);
55  addParam("pvPrefix", m_pvPrefix, "Epics PV prefix", std::string("TOP:"));
56 
57  B2DEBUG(20, "DQMHistAnalysisTOP: Constructor done.");
58 }
59 
60 
62 
63 
65 {
66 
67  // check module parameters
68 
69  if (m_asicWindowsBand.size() != 2) B2ERROR("Parameter list 'asicWindowsBand' must contain two numbers");
70  if (m_asicWindowsAlarmLevels.size() != 2) B2ERROR("Parameter list 'asicWindowsAlarmLevels' must contain two numbers");
71  if (m_eventMonitorAlarmLevels.size() != 2) B2ERROR("Parameter list 'eventMonitorAlarmLevels' must contain two numbers");
72  if (m_junkHitsAlarmLevels.size() != 2) B2ERROR("Parameter list 'junkHitsAlarmLevels' must contain two numbers");
73  if (m_deadChannelsAlarmLevels.size() != 2) B2ERROR("Parameter list 'deadChannelsAlarmLevels' must contain two numbers");
74  if (m_backgroundAlarmLevels.size() != 2) B2ERROR("Parameter list 'backgroundAlarmLevels' must contain two numbers");
75  if (m_photonYieldsAlarmLevels.size() != 2) B2ERROR("Parameter list 'photonYieldsAlarmLevels' must contain two numbers");
76 
77  // make a map of boardstack names to ID's
78 
79  int id = 1;
80  for (int slot = 1; slot <= 16; slot++) {
81  string slotstr = to_string(slot);
82  for (std::string bs : {"a", "b", "c", "d"}) {
83  m_bsmap[slotstr + bs] = id;
84  id++;
85  }
86  }
87 
88  // parse excluded boardstacks
89 
91 
92  // MiraBelle monitoring
93 
95 
96  // Epics used to pass values to shifter's page (output only)
97 
98  registerEpicsPV(m_pvPrefix + "badBoardstacks", "badBoardstacks");
99  registerEpicsPV(m_pvPrefix + "badCarriers", "badCarriers");
100  registerEpicsPV(m_pvPrefix + "badAsics", "badAsics");
101  registerEpicsPV(m_pvPrefix + "badPMTs", "badPMTs");
102  registerEpicsPV(m_pvPrefix + "numExcludedBS", "numExcludedBS");
103 
104  // Epics used to get limits from configuration file - override module parameters (input only)
105 
106  registerEpicsPV(m_pvPrefix + "asicWindowsBand", "asicWindowsBand");
107  registerEpicsPV(m_pvPrefix + "asicWindowsAlarmLevels", "asicWindowsAlarmLevels");
108  registerEpicsPV(m_pvPrefix + "eventMonitorAlarmLevels", "eventMonitorAlarmLevels");
109  registerEpicsPV(m_pvPrefix + "junkHitsAlarmLevels", "junkHitsAlarmLevels");
110  registerEpicsPV(m_pvPrefix + "deadChannelsAlarmLevels", "deadChannelsAlarmLevels");
111  registerEpicsPV(m_pvPrefix + "backgroundAlarmLevels", "backgroundAlarmLevels");
112  registerEpicsPV(m_pvPrefix + "photonYieldsAlarmLevels", "photonYieldsAlarmLevels");
113  registerEpicsPV(m_pvPrefix + "excludedBoardstacks", "excludedBoardstacks");
114 
115  updateEpicsPVs(5.0);
116 
117  // new canvases, histograms and graphic primitives
118 
119  gROOT->cd();
120 
121  m_c_photonYields = new TCanvas("TOP/c_photonYields", "c_photonYields");
122  m_c_backgroundRates = new TCanvas("TOP/c_backgroundRates", "c_backgroundRates");
123 
124  m_deadFraction = new TH1F("TOP/deadFraction", "Fraction of dead channels", 16, 0.5, 16.5);
125  m_deadFraction->SetXTitle("slot number");
126  m_deadFraction->SetYTitle("fraction");
127  m_hotFraction = new TH1F("TOP/hotFraction", "Fraction of hot channels", 16, 0.5, 16.5);
128  m_hotFraction->SetXTitle("slot number");
129  m_hotFraction->SetYTitle("fraction");
130  m_activeFraction = new TH1F("TOP/activeFraction", "Fraction of active channels", 16, 0.5, 16.5);
131  m_activeFraction->SetXTitle("slot number");
132  m_activeFraction->SetYTitle("fraction");
133  m_c_deadAndHot = new TCanvas("TOP/c_deadAndHotChannels", "c_deadAndHotChannels");
134 
135  m_junkFraction = new TH1F("TOP/junkFraction", "Fraction of junk hits per boardstack", 64, 0.5, 16.5);
136  m_junkFraction->SetXTitle("slot number");
137  m_junkFraction->SetYTitle("fraction");
138  m_c_junkFraction = new TCanvas("TOP/c_junkFraction", "c_junkFraction");
139 
140  m_text1 = new TPaveText(1, 435, 12, 500, "NB");
141  m_text1->SetFillColorAlpha(kWhite, 0);
142  m_text1->SetBorderSize(0);
143  m_text2 = new TPaveText(0.55, 0.8, 0.85, 0.89, "NDC");
144  m_text2->SetFillColorAlpha(kWhite, 0);
145  m_text2->SetBorderSize(0);
146  m_text3 = new TPaveText(0.47, 0.8, 0.85, 0.89, "NDC");
147  m_text3->SetFillColorAlpha(kWhite, 0);
148  m_text3->SetBorderSize(0);
149 
150  for (int slot = 1; slot < 16; slot++) {
151  auto* line = new TLine(slot + 0.5, 0, slot + 0.5, 1);
152  line->SetLineWidth(1);
153  line->SetLineStyle(2);
154  m_verticalLines.push_back(line);
155  }
156 
157  setAlarmLines();
158 
159  B2DEBUG(20, "DQMHistAnalysisTOP: initialized.");
160 }
161 
162 
164 {
165  auto* h = findHist("DQMInfo/rtype");
166  std::string title = h ? h->GetTitle() : "";
167  m_IsNullRun = (title == "null");
168 
169  updateLimits();
170 
171  B2DEBUG(20, "DQMHistAnalysisTOP: beginRun called.");
172 }
173 
174 
176 {
177  bool zeroSupp = gStyle->GetHistMinimumZero();
178  gStyle->SetHistMinimumZero(true);
179 
180  // Update window_vs_slot canvas w/ alarming
182 
183  // Update event desynchronization monitor w/ alarming
185 
186  // Fraction of dead and hot channels
187  const auto* activeFraction = makeDeadAndHotFractionsPlot();
188 
189  // Photon yields and background rates, corrected for dead and hot channels
190  makePhotonYieldsAndBGRatePlots(activeFraction);
191 
192  // Fractions of junk hits
194 
195  // Set z-axis range to 3 times the average for good hits, 30 times the average for junk hits
196  setZAxisRange("TOP/good_hits_xy_", 3);
197  setZAxisRange("TOP/bad_hits_xy_", 30);
198  setZAxisRange("TOP/good_hits_asics_", 3);
199  setZAxisRange("TOP/bad_hits_asics_", 30);
200 
201  // Background subtracted time distributions
202  makeBGSubtractedTimimgPlot("goodHitTimes");
203  for (int slot = 1; slot <= 16; slot++) {
204  makeBGSubtractedTimimgPlot("good_timing_" + to_string(slot));
205  }
206 
207  // Set Epics variables
209 
210  gStyle->SetHistMinimumZero(zeroSupp);
211 }
212 
213 
215 {
216  // add MiraBelle monitoring
217 
218  setMiraBelleVariables("RateBadRaw_slot", m_windowFractions);
219  m_monObj->setVariable("RateBadRaw_all", m_totalWindowFraction);
220  setMiraBelleVariables("PhotonsPerTrack_slot", m_photonYields);
221  setMiraBelleVariables("BackgroundRate_slot", m_backgroundRates);
222  setMiraBelleVariables("ActiveChannelFraction_slot", m_activeFraction);
223 
224  B2DEBUG(20, "DQMHistAnalysisTOP : endRun called");
225 }
226 
227 
229 {
230  B2DEBUG(20, "terminate called");
231 }
232 
233 
235 {
236  m_totalWindowFraction = 0; // used also for MiraBelle
237  m_windowFractions = nullptr; // used also for MiraBelle
238  int alarmState = c_Gray;
239  m_text1->Clear();
240 
241  auto* hraw = (TH2F*) findHist("TOP/window_vs_slot");
242  if (hraw) {
243  auto* px = hraw->ProjectionX("tmp_px");
244  auto* band = hraw->ProjectionX("TOP/windowFractions", m_asicWindowsBand[0], m_asicWindowsBand[1]);
245  band->Add(px, band, 1, -1);
246  double total = px->Integral();
247  m_totalWindowFraction = (total != 0) ? band->Integral() / total : 0;
248  band->Divide(band, px);
249  m_windowFractions = band;
250  if (total > 0) {
252  m_text1->AddText(Form("Fraction outside red lines: %.2f %%", m_totalWindowFraction * 100.0));
253  }
254  delete px;
255  }
256 
257  auto* canvas = findCanvas("TOP/c_window_vs_slot");
258  if (canvas) {
259  canvas->cd();
260  m_text1->Draw();
261  for (auto* line : m_asicWindowsBandLines) line->Draw();
262  canvas->Pad()->SetFrameFillColor(10);
263  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
264  canvas->Modified();
265  }
266 }
267 
268 
270 {
271  int alarmState = c_Gray;
272  m_text2->Clear();
273 
274  auto* evtMonitor = (TH1F*) findHist("TOP/BoolEvtMonitor");
275  if (evtMonitor) {
276  double totalEvts = evtMonitor->Integral();
277  double badEvts = evtMonitor->GetBinContent(2);
278  if (totalEvts > 0) {
279  double badRatio = badEvts / totalEvts;
280  alarmState = getAlarmState(badRatio, m_eventMonitorAlarmLevels);
281  m_text2->AddText(Form("Fraction: %.4f %%", badRatio * 100.0));
282  }
283  }
284 
285  auto* canvas = findCanvas("TOP/c_BoolEvtMonitor");
286  if (canvas) {
287  canvas->cd();
288  m_text2->Draw();
289  canvas->Pad()->SetFrameFillColor(10);
290  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
291  canvas->Modified();
292  }
293 }
294 
295 
297 {
298  m_deadFraction->Reset();
299  m_hotFraction->Reset();
300  m_activeFraction->Reset();
301  double inactiveFract = 0; // max inactive channel fraction when some boardstacks are excluded from alarming
302 
303  for (int slot = 1; slot <= 16; slot++) {
304  auto* h = (TH1F*) findHist("TOP/good_channel_hits_" + std::to_string(slot));
305  if (not h) continue;
306  double mean = 0;
307  int n = 0;
308  for (int chan = 0; chan < h->GetNbinsX(); chan++) {
309  double y = h->GetBinContent(chan + 1);
310  if (y > 0) {
311  mean += y;
312  n++;
313  }
314  }
315  if (n > 0) mean /= n;
316  double deadCut = mean / 10;
317  double hotCut = mean * 10;
318  double deadFract = 0;
319  double hotFract = 0;
320  double deadFractIncl = 0;
321  double hotFractIncl = 0;
322  for (int chan = 0; chan < h->GetNbinsX(); chan++) {
323  double y = h->GetBinContent(chan + 1);
324  int bs = chan / 128 + (slot - 1) * 4;
325  bool included = m_includedBoardstacks[bs];
326  if (y <= deadCut) {
327  deadFract += 1;
328  if (included) deadFractIncl += 1;
329  } else if (y > hotCut) {
330  hotFract += 1;
331  if (included) hotFractIncl += 1;
332  }
333  }
334  deadFract /= h->GetNbinsX();
335  hotFract /= h->GetNbinsX();
336  m_deadFraction->SetBinContent(slot, deadFract);
337  m_hotFraction->SetBinContent(slot, hotFract);
338  m_activeFraction->SetBinContent(slot, 1 - deadFract - hotFract);
339  inactiveFract = std::max(inactiveFract, (deadFractIncl + hotFractIncl) / h->GetNbinsX());
340  }
341 
342  int alarmState = c_Gray;
343  if (m_activeFraction->Integral() > 0) {
344  alarmState = getAlarmState(1 - m_activeFraction->GetMinimum(), m_deadChannelsAlarmLevels);
345  if (alarmState == 3) alarmState = std::max(getAlarmState(inactiveFract, m_deadChannelsAlarmLevels), 2);
346  }
347 
348  m_deadFraction->SetFillColor(1);
349  m_deadFraction->GetXaxis()->SetNdivisions(16);
350 
351  m_hotFraction->SetFillColor(2);
352  m_hotFraction->GetXaxis()->SetNdivisions(16);
353 
354  m_activeFraction->SetFillColor(0);
355  m_activeFraction->GetXaxis()->SetNdivisions(16);
356 
357  auto* canvas = m_c_deadAndHot;
358  canvas->Clear();
359  canvas->cd();
360  canvas->Pad()->SetFrameFillColor(10);
361  if (not m_stack) {
362  m_stack = new THStack("TOP/stack", "Fraction of dead and hot channels");
363  m_stack->Add(m_deadFraction);
364  m_stack->Add(m_hotFraction);
366  }
367  m_stack->Draw();
368 
369  for (auto* line : m_deadChannelsAlarmLines) line->Draw("same");
370 
371  if (not m_legend) {
372  m_legend = new TLegend(0.8, 0.87, 0.99, 0.99);
373  m_legend->AddEntry(m_hotFraction, "hot");
374  m_legend->AddEntry(m_deadFraction, "dead");
375  }
376  m_legend->Draw("same");
377 
378  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
379  canvas->Modified();
380 
381  return m_activeFraction;
382 }
383 
384 
386 {
387  for (auto* canvas : {m_c_photonYields, m_c_backgroundRates}) {
388  canvas->Clear();
389  canvas->Pad()->SetFrameFillColor(10);
390  canvas->Pad()->SetFillColor(getAlarmColor(c_Gray));
391  canvas->Modified();
392  }
393 
394  auto* signalHits = (TProfile*) findHist("TOP/signalHits");
395  if (not signalHits) return;
396 
397  auto* backgroundHits = (TProfile*) findHist("TOP/backgroundHits");
398  if (not backgroundHits) return;
399 
400  m_photonYields = signalHits->ProjectionX("TOP/photonYields");
401  m_backgroundRates = backgroundHits->ProjectionX("TOP/backgroundRates");
402  auto* activeFract = (TH1F*) activeFraction->Clone("tmp");
403  for (int i = 1; i <= activeFract->GetNbinsX(); i++) activeFract->SetBinError(i, 0);
404 
406  m_photonYields->Divide(m_photonYields, activeFract);
407 
408  int alarmState = c_Gray;
409  if (signalHits->GetEntries() > 0 and activeFraction->Integral() > 0) {
410  double hmin = 1000;
411  for (int i = 1; i <= m_photonYields->GetNbinsX(); i++) {
412  hmin = std::min(hmin, m_photonYields->GetBinContent(i) + 3 * m_photonYields->GetBinError(i));
413  }
414  alarmState = getAlarmState(hmin, m_photonYieldsAlarmLevels, false);
415  }
416 
417  m_photonYields->SetTitle("Number of photons per track");
418  m_photonYields->SetYTitle("photons per track");
419  m_photonYields->SetMarkerStyle(24);
420  m_photonYields->GetXaxis()->SetNdivisions(16);
421 
422  auto* canvas = m_c_photonYields;
423  canvas->cd();
424  m_photonYields->SetMinimum(0);
425  m_photonYields->Draw();
426  for (auto* line : m_photonYieldsAlarmLines) line->Draw("same");
427  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
428  canvas->Modified();
429 
430  m_backgroundRates->Scale(1.0 / 50.0e-3 / 32); // measured in 50 ns window, 32 PMT's ==> rate in MHz/PMT
431  m_backgroundRates->Divide(m_backgroundRates, activeFract);
432 
433  alarmState = c_Gray;
434  m_text3->Clear();
435  if (backgroundHits->GetEntries() > 0 and activeFraction->Integral() > 0) {
436  int status = m_backgroundRates->Fit("pol0", "Q0");
437  if (status == 0) {
438  auto* fun = m_backgroundRates->GetFunction("pol0");
439  if (fun) {
440  double average = fun->GetParameter(0);
441  double error = fun->GetParError(0);
442  alarmState = getAlarmState(average - 3 * error, m_backgroundAlarmLevels);
443  m_text3->AddText(Form("Average: %.2f MHz/PMT", average));
444  }
445  }
446  }
447 
448  m_backgroundRates->SetTitle("Background rates");
449  m_backgroundRates->SetYTitle("background rate [MHz/PMT]");
450  m_backgroundRates->SetMarkerStyle(24);
451  m_backgroundRates->GetXaxis()->SetNdivisions(16);
452 
453  canvas = m_c_backgroundRates;
454  canvas->cd();
455  m_backgroundRates->SetMinimum(0);
456  m_backgroundRates->Draw();
457  for (auto* line : m_backgroundAlarmLines) line->Draw("same");
458  m_text3->Draw();
459  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
460  canvas->Modified();
461 
462  delete activeFract;
463 }
464 
465 
467 {
468  m_junkFraction->Reset();
469  auto* allHits = (TH1D*) m_junkFraction->Clone("tmp");
470  for (int slot = 1; slot <= 16; slot++) {
471  auto* good = (TH1F*) findHist("TOP/good_channel_hits_" + std::to_string(slot));
472  if (not good) continue;
473  auto* bad = (TH1F*) findHist("TOP/bad_channel_hits_" + std::to_string(slot));
474  if (not bad) continue;
475  for (int i = 0; i < 512; i++) {
476  int bs = i / 128;
477  allHits->Fill(slot + bs / 4. - 0.5, good->GetBinContent(i + 1) + bad->GetBinContent(i + 1));
478  m_junkFraction->Fill(slot + bs / 4. - 0.5, bad->GetBinContent(i + 1));
479  }
480  }
481 
482  m_junkFraction->Divide(m_junkFraction, allHits, 1, 1, "B");
483 
484  int alarmState = c_Gray;
485  if (allHits->Integral() > 0) {
486  alarmState = getAlarmState(m_junkFraction->GetMaximum(), m_junkHitsAlarmLevels);
487  if (alarmState == 3) {
488  double hmax = 0;
489  for (size_t i = 0; i < m_includedBoardstacks.size(); i++) {
490  if (m_includedBoardstacks[i]) hmax = std::max(hmax, m_junkFraction->GetBinContent(i + 1));
491  }
492  alarmState = std::max(getAlarmState(hmax, m_junkHitsAlarmLevels), 2);
493  }
494  }
495  delete allHits;
496 
497  auto* canvas = m_c_junkFraction;
498  canvas->Clear();
499  canvas->cd();
500  canvas->Pad()->SetFrameFillColor(10);
501  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
502  m_junkFraction->SetMarkerStyle(24);
503  m_junkFraction->GetXaxis()->SetNdivisions(16);
504  m_junkFraction->GetYaxis()->SetRangeUser(0, 1); // Note: m_junkFraction->GetMaximum() will now give 1 and not the histogram maximum!
505  m_junkFraction->Draw();
506  for (auto* line : m_verticalLines) line->Draw("same");
507  for (auto* line : m_junkHitsAlarmLines) line->Draw("same");
508  canvas->Modified();
509 }
510 
511 
512 void DQMHistAnalysisTOPModule::setZAxisRange(const std::string& name, double scale)
513 {
514  double totalHits = 0;
515  std::vector<TH2F*> histos;
516  for (int slot = 1; slot <= 16; slot++) {
517  TH2F* h = (TH2F*) findHist(name + std::to_string(slot));
518  if (not h) continue;
519  histos.push_back(h);
520  totalHits += h->Integral();
521  }
522  if (histos.empty()) return;
523  double average = totalHits / 512 / histos.size(); // per pixel or asic channel
524 
525  for (auto* h : histos) h->GetZaxis()->SetRangeUser(0, std::max(average * scale, 1.0));
526 }
527 
528 
530 {
531  auto* canvas = findCanvas("TOP/c_" + name);
532  if (not canvas) return;
533 
534  auto* h = (TH1F*) findHist("TOP/" + name);
535  if (not h) return;
536 
537  auto* hb = (TH1F*) findHist("TOP/" + name + "BG");
538  if (not hb) return;
539 
540  // use the content of bins at t < 0 to scale the background
541 
542  int i0 = h->GetXaxis()->FindBin(0.); // bin at t = 0
543  double s = h->Integral(1, i0);
544  if (s == 0) return;
545  double sb = hb->Integral(1, i0);
546  if (sb == 0) return;
547  h->Add(h, hb, 1, -s / sb);
548  TString title = TString(h->GetTitle()) + " (BG subtracted)";
549  h->SetTitle(title);
550 
551  canvas->Clear();
552  canvas->cd();
553  h->Draw();
554  canvas->Modified();
555 }
556 
557 
558 void DQMHistAnalysisTOPModule::setMiraBelleVariables(const std::string& variableName, const TH1* histogram)
559 {
560  for (int slot = 1; slot <= 16; slot++) {
561  auto vname = variableName + std::to_string(slot);
562  double value = histogram ? histogram->GetBinContent(slot) : 0;
563  m_monObj->setVariable(vname, value);
564 
565  B2DEBUG(20, vname << " " << value);
566  }
567 }
568 
569 
570 int DQMHistAnalysisTOPModule::getAlarmState(double value, const std::vector<double>& alarmLevels, bool bigRed) const
571 {
572  if (m_IsNullRun) return c_Gray;
573 
574  if (bigRed) {
575  if (value < alarmLevels[0]) return c_Green;
576  else if (value < alarmLevels[1]) return c_Yellow;
577  else return c_Red;
578  } else {
579  if (value < alarmLevels[0]) return c_Red;
580  else if (value < alarmLevels[1]) return c_Yellow;
581  else return c_Green;
582  }
583 }
584 
585 
586 void DQMHistAnalysisTOPModule::setAlarmLines(const std::vector<double>& alarmLevels, double xmin, double xmax,
587  std::vector<TLine*>& alarmLines, bool bigRed)
588 {
589  std::vector<int> colors = {kOrange, kRed};
590  if (not bigRed) std::reverse(colors.begin(), colors.end());
591  for (size_t i = 0; i < std::min(colors.size(), alarmLevels.size()); i++) {
592  if (i < alarmLines.size()) {
593  auto* line = alarmLines[i];
594  line->SetX1(xmin);
595  line->SetX2(xmax);
596  line->SetY1(alarmLevels[i]);
597  line->SetY2(alarmLevels[i]);
598  } else {
599  auto* line = new TLine(xmin, alarmLevels[i], xmax, alarmLevels[i]);
600  line->SetLineWidth(2);
601  line->SetLineStyle(2);
602  line->SetLineColor(colors[i]);
603  alarmLines.push_back(line);
604  }
605  }
606 }
607 
608 
610 {
611  for (auto y : m_asicWindowsBand) {
612  auto* line = new TLine(0.5, y, 16.5, y);
613  line->SetLineWidth(2);
614  line->SetLineColor(kRed);
615  m_asicWindowsBandLines.push_back(line);
616  }
617 
622 }
623 
624 
626 {
627  double mean = 0;
628  int n = 0;
629  for (int col = 1; col <= h->GetNbinsX(); col++) {
630  for (int row = 1; row <= h->GetNbinsY(); row++) {
631  double y = h->GetBinContent(col, row);
632  if (y > 0) {
633  mean += y;
634  n++;
635  }
636  }
637  }
638  if (n > 0) mean /= n;
639  return mean;
640 }
641 
642 
644 {
645  int badBoardstacks = 0;
646  int badCarriers = 0;
647  int badAsics = 0;
648  for (int slot = 1; slot <= 16; slot++) {
649  std::string hname = "TOP/good_hits_asics_" + to_string(slot);
650  auto* h = (TH2F*) findHist(hname);
651  if (not h) continue;
652 
653  double mean = getMean(h);
654  double deadCut = mean / 10;
655  double hotCut = mean * 10;
656  std::vector<int> asics(64, 0);
657  std::vector<int> carriers(16, 0);
658  std::vector<int> boardstacks(4, 0);
659  for (int asic = 0; asic < 64; asic++) {
660  int carrier = asic / 4;
661  int boardstack = carrier / 4;
662  for (int chan = 0; chan < 8; chan++) {
663  double y = h->GetBinContent(asic + 1, chan + 1);
664  if (y > deadCut and y < hotCut) {
665  asics[asic]++;
666  carriers[carrier]++;
667  boardstacks[boardstack]++;
668  }
669  }
670  }
671  for (int n : asics) if (n == 0) badAsics++;
672  for (int n : carriers) if (n == 0) badCarriers++;
673  for (int n : boardstacks) if (n == 0) badBoardstacks++;
674  }
675  badAsics -= badCarriers * 4;
676  badCarriers -= badBoardstacks * 4;
677 
678  int badPMTs = 0;
679  for (int slot = 1; slot <= 16; slot++) {
680  std::string hname = "TOP/good_hits_xy_" + to_string(slot);
681  auto* h = (TH2F*) findHist(hname);
682  if (not h) continue;
683 
684  double mean = getMean(h);
685  double deadCut = mean / 10;
686  double hotCut = mean * 10;
687  std::vector<int> pmts(32, 0);
688  for (int row = 0; row < 8; row++) {
689  for (int col = 0; col < 64; col++) {
690  int pmt = col / 4 + (row / 4) * 16;
691  double y = h->GetBinContent(col + 1, row + 1);
692  if (y > deadCut and y < hotCut) pmts[pmt]++;
693  }
694  }
695  for (int n : pmts) if (n == 0) badPMTs++;
696  }
697  badPMTs -= badBoardstacks * 8;
698 
699  setEpicsPV("badBoardstacks", badBoardstacks);
700  setEpicsPV("badCarriers", badCarriers);
701  setEpicsPV("badAsics", badAsics);
702  setEpicsPV("badPMTs", badPMTs);
703  int numBS = 0;
704  for (auto included : m_includedBoardstacks) if (not included) numBS++;
705  setEpicsPV("numExcludedBS", numBS);
706  updateEpicsPVs(5.0);
707 
708  B2DEBUG(20, "badBoardstacks: " << badBoardstacks);
709  B2DEBUG(20, "badCarriers: " << badCarriers);
710  B2DEBUG(20, "badAsics: " << badAsics);
711  B2DEBUG(20, "badPMTs: " << badPMTs);
712  B2DEBUG(20, "excludedBS: " << numBS);
713 }
714 
716 {
717  double unused = 0;
718 
719  double yLo = m_asicWindowsBand[0];
720  double yHi = m_asicWindowsBand[1];
721  requestLimitsFromEpicsPVs("asicWindowsBand", yLo, unused, unused, yHi);
722  m_asicWindowsBand[0] = yLo;
723  m_asicWindowsBand[1] = yHi;
724 
725  requestLimitsFromEpicsPVs("asicWindowsAlarmLevels", unused, unused, m_asicWindowsAlarmLevels[0], m_asicWindowsAlarmLevels[1]);
726  requestLimitsFromEpicsPVs("eventMonitorAlarmLevels", unused, unused, m_eventMonitorAlarmLevels[0], m_eventMonitorAlarmLevels[1]);
727  requestLimitsFromEpicsPVs("junkHitsAlarmLevels", unused, unused, m_junkHitsAlarmLevels[0], m_junkHitsAlarmLevels[1]);
728  requestLimitsFromEpicsPVs("deadChannelsAlarmLevels", unused, unused, m_deadChannelsAlarmLevels[0], m_deadChannelsAlarmLevels[1]);
729  requestLimitsFromEpicsPVs("backgroundAlarmLevels", unused, unused, m_backgroundAlarmLevels[0], m_backgroundAlarmLevels[1]);
730  requestLimitsFromEpicsPVs("photonYieldsAlarmLevels", m_photonYieldsAlarmLevels[0], m_photonYieldsAlarmLevels[1], unused, unused);
731 
732  setAlarmLines();
733 
734  bool status = false;
735  std::string excludedBS = getEpicsStringPV("excludedBoardstacks", status);
736 
737  if (status) {
738  m_excludedBoardstacks.clear();
739  std::string name;
740  for (auto c : excludedBS) {
741  if (isspace(c)) continue;
742  else if (ispunct(c)) {
743  if (not name.empty()) {
744  m_excludedBoardstacks.push_back(name);
745  name.clear();
746  }
747  } else name.push_back(c);
748  }
749  if (not name.empty()) {
750  m_excludedBoardstacks.push_back(name);
751  }
753  }
754 
755  B2DEBUG(20, "asicWindowsBand: [" << m_asicWindowsBand[0] << ", " << m_asicWindowsBand[1] << "]");
756  B2DEBUG(20, "asicWindowsAlarmLevels: [" << m_asicWindowsAlarmLevels[0] << ", " << m_asicWindowsAlarmLevels[1] << "]");
757  B2DEBUG(20, "eventMonitorAlarmLevels: [" << m_eventMonitorAlarmLevels[0] << ", " << m_eventMonitorAlarmLevels[1] << "]");
758  B2DEBUG(20, "junkHitsAlarmLevels: [" << m_junkHitsAlarmLevels[0] << ", " << m_junkHitsAlarmLevels[1] << "]");
759  B2DEBUG(20, "deadChannelsAlarmLevels: [" << m_deadChannelsAlarmLevels[0] << ", " << m_deadChannelsAlarmLevels[1] << "]");
760  B2DEBUG(20, "backgroundAlarmLevels: [" << m_backgroundAlarmLevels[0] << ", " << m_backgroundAlarmLevels[1] << "]");
761  B2DEBUG(20, "photonYieldsAlarmLevels: [" << m_photonYieldsAlarmLevels[0] << ", " << m_photonYieldsAlarmLevels[1] << "]");
762  std::string ss;
763  for (const auto& s : m_excludedBoardstacks) ss += "'" + s + "', ";
764  if (ss.size() > 2) {ss.pop_back(); ss.pop_back();}
765  B2DEBUG(20, "excludedBoardstacks: [" << ss << "]");
766 
767 }
768 
769 void DQMHistAnalysisTOPModule::setIncludedBoardstacks(const std::vector<std::string>& excludedBoardstacks)
770 {
771  m_includedBoardstacks.clear();
772  m_includedBoardstacks.resize(64, true);
773 
774  for (const auto& bsname : excludedBoardstacks) {
775  int id = m_bsmap[bsname];
776  if (id > 0) m_includedBoardstacks[id - 1] = false;
777  else B2ERROR("Invalid boardstack name: " << bsname);
778  }
779 }
The base class for the histogram analysis module.
TCanvas * findCanvas(TString cname)
Find canvas by name.
void updateEpicsPVs(float timeout)
Update all EPICS PV (flush to network)
int registerEpicsPV(std::string pvname, std::string keyname="", bool update_pvs=true)
EPICS related Functions.
static TH1 * findHist(const std::string &histname, bool onlyIfUpdated=false)
Get histogram from list (no other search).
std::string getEpicsStringPV(std::string keyname, bool &status)
Read value from a EPICS PV.
void setEpicsPV(std::string keyname, double value)
Write value to a EPICS PV.
static MonitoringObject * getMonitoringObject(const std::string &histname)
Get MonitoringObject with given name (new object is created if non-existing)
bool requestLimitsFromEpicsPVs(chid id, double &lowerAlarm, double &lowerWarn, double &upperWarn, double &upperAlarm)
Get Alarm Limits from EPICS PV.
void updateEventMonitorCanvas()
Updates canvas of event desynchronization monitor w/ alarming.
std::vector< int > m_asicWindowsBand
lower and upper bin of a band denoting good windows
void setZAxisRange(const std::string &name, double scale)
Sets z-axis range of 2D histograms.
TCanvas * m_c_photonYields
Canvas: photon yields per slot.
void initialize() override final
Initializer.
std::vector< double > m_deadChannelsAlarmLevels
alarm levels for the fraction of dead + hot channels
std::vector< double > m_asicWindowsAlarmLevels
alarm levels for fraction of windows outside the band
TPaveText * m_text2
text to be written to event desynchonization monitor
TCanvas * m_c_junkFraction
Canvas: fraction of junk hits per boardstack.
THStack * m_stack
stack for drawing dead, hot and active channel fractions
const TH1F * makeDeadAndHotFractionsPlot()
Makes a plot of dead and hot channel fractions per slot.
TPaveText * m_text3
text to be written to background rates
std::vector< TLine * > m_deadChannelsAlarmLines
lines representing alarm levels
TPaveText * m_text1
text to be written to window_vs_slot
std::vector< TLine * > m_photonYieldsAlarmLines
lines representing alarm levels
std::vector< bool > m_includedBoardstacks
boardstacks included in alarming
std::vector< TLine * > m_verticalLines
vertical lines splitting slots
std::string m_pvPrefix
Epics PV prefix.
TH1D * m_photonYields
photon yields per slot (corrected for active channels)
TH1D * m_backgroundRates
background rates per slot
MonitoringObject * m_monObj
MiraBelle monitoring object.
TCanvas * m_c_backgroundRates
Canvas: background rates per slot.
std::vector< double > m_eventMonitorAlarmLevels
alarm levels for fraction of desynchronized digits
void terminate() override final
This method is called at the end of the event processing.
void setAlarmLines()
Sets all alarm lines.
TH1F * m_activeFraction
fraction of active channels per slot
int getAlarmColor(unsigned alarmState) const
Converts alarm state to color.
void event() override final
This method is called for each event.
std::vector< double > m_photonYieldsAlarmLevels
alarm levels for the number of photons per track
std::vector< TLine * > m_junkHitsAlarmLines
lines representing alarm levels
void setIncludedBoardstacks(const std::vector< std::string > &excludedBoardstacks)
Sets flags for boardstacks to be included in alarming.
TH1F * m_deadFraction
fraction of dead channels per slot
TH1F * m_hotFraction
fraction of hot channels per slot
void makeBGSubtractedTimimgPlot(const std::string &name)
Makes background subtracted time distribution plot.
std::vector< std::string > m_excludedBoardstacks
list of boarstacks to be excluded from alarming
void makePhotonYieldsAndBGRatePlots(const TH1F *activeFraction)
Make plots of dead-and-hot-channel corrected photon yields and BG rates per slot.
TH1F * m_junkFraction
fraction of junk hits per boardstack
double getMean(const TH2 *h)
Returns histogram mean by excluding bins with zero content.
void endRun() override final
This method is called if the current run ends.
int getAlarmState(double value, const std::vector< double > &alarmLevels, bool bigRed=true) const
Returns alarm state.
std::vector< TLine * > m_asicWindowsBandLines
lines denoting a band of good windows
void makeJunkFractionPlot()
Makes a plot of fractions of junk hits per boardstack.
double m_totalWindowFraction
total fraction of windows outside the band
void beginRun() override final
Called when entering a new run.
TLegend * m_legend
legend for dead and hot channels
TCanvas * m_c_deadAndHot
Canvas: fractin of dead and hot channels.
std::vector< TLine * > m_backgroundAlarmLines
lines representing alarm levels
void updateWindowVsSlotCanvas()
Updates canvas of window_vs_slot w/ alarming.
std::map< std::string, int > m_bsmap
a map of boardstack names to ID's
std::vector< double > m_backgroundAlarmLevels
alarm levels for background rates [MHz/PMT]
void setEpicsVariables()
Calculates and sets epics variables.
std::vector< double > m_junkHitsAlarmLevels
alarm levels for the fraction of junk hits
TH1D * m_windowFractions
fraction of windows outside the band denoting good windows, per slot
bool m_IsNullRun
Run type flag for null runs.
void updateLimits()
Updates limits defined by module parameters using EpicsPVs.
void setMiraBelleVariables(const std::string &variableName, const TH1 *histogram)
Sets MiraBelle variables from the histogram with bins corresponding to slot numbers.
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setVariable(const std::string &var, float val, float upErr=-1., float dwErr=-1)
set value to float variable (new variable is made if not yet existing)
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:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.