Belle II Software  release-08-01-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  registerEpicsPV(m_pvPrefix + "histoAlarmState", "histoAlarmState"); // to pass overall state to central alarm overview panel
104 
105  // Epics used to get limits from configuration file - override module parameters (input only)
106 
107  registerEpicsPV(m_pvPrefix + "asicWindowsBand", "asicWindowsBand");
108  registerEpicsPV(m_pvPrefix + "asicWindowsAlarmLevels", "asicWindowsAlarmLevels");
109  registerEpicsPV(m_pvPrefix + "eventMonitorAlarmLevels", "eventMonitorAlarmLevels");
110  registerEpicsPV(m_pvPrefix + "junkHitsAlarmLevels", "junkHitsAlarmLevels");
111  registerEpicsPV(m_pvPrefix + "deadChannelsAlarmLevels", "deadChannelsAlarmLevels");
112  registerEpicsPV(m_pvPrefix + "backgroundAlarmLevels", "backgroundAlarmLevels");
113  registerEpicsPV(m_pvPrefix + "photonYieldsAlarmLevels", "photonYieldsAlarmLevels");
114  registerEpicsPV(m_pvPrefix + "excludedBoardstacks", "excludedBoardstacks");
115 
116  updateEpicsPVs(5.0);
117 
118  // new canvases, histograms and graphic primitives
119 
120  gROOT->cd();
121 
122  m_c_photonYields = new TCanvas("TOP/c_photonYields", "c_photonYields");
123  m_c_backgroundRates = new TCanvas("TOP/c_backgroundRates", "c_backgroundRates");
124 
125  m_deadFraction = new TH1F("TOP/deadFraction", "Fraction of dead channels", 16, 0.5, 16.5);
126  m_deadFraction->SetXTitle("slot number");
127  m_deadFraction->SetYTitle("fraction");
128  m_hotFraction = new TH1F("TOP/hotFraction", "Fraction of hot channels", 16, 0.5, 16.5);
129  m_hotFraction->SetXTitle("slot number");
130  m_hotFraction->SetYTitle("fraction");
131  m_activeFraction = new TH1F("TOP/activeFraction", "Fraction of active channels", 16, 0.5, 16.5);
132  m_activeFraction->SetXTitle("slot number");
133  m_activeFraction->SetYTitle("fraction");
134  m_c_deadAndHot = new TCanvas("TOP/c_deadAndHotChannels", "c_deadAndHotChannels");
135 
136  m_junkFraction = new TH1F("TOP/junkFraction", "Fraction of junk hits per boardstack", 64, 0.5, 16.5);
137  m_junkFraction->SetXTitle("slot number");
138  m_junkFraction->SetYTitle("fraction");
139  m_c_junkFraction = new TCanvas("TOP/c_junkFraction", "c_junkFraction");
140 
141  m_text1 = new TPaveText(1, 435, 12, 500, "NB");
142  m_text1->SetFillColorAlpha(kWhite, 0);
143  m_text1->SetBorderSize(0);
144  m_text2 = new TPaveText(0.55, 0.8, 0.85, 0.89, "NDC");
145  m_text2->SetFillColorAlpha(kWhite, 0);
146  m_text2->SetBorderSize(0);
147  m_text3 = new TPaveText(0.47, 0.8, 0.85, 0.89, "NDC");
148  m_text3->SetFillColorAlpha(kWhite, 0);
149  m_text3->SetBorderSize(0);
150 
151  for (int slot = 1; slot < 16; slot++) {
152  auto* line = new TLine(slot + 0.5, 0, slot + 0.5, 1);
153  line->SetLineWidth(1);
154  line->SetLineStyle(2);
155  m_verticalLines.push_back(line);
156  }
157 
158  setAlarmLines();
159 
160  B2DEBUG(20, "DQMHistAnalysisTOP: initialized.");
161 }
162 
163 
165 {
166  auto* h = findHist("DQMInfo/rtype");
167  std::string title = h ? h->GetTitle() : "";
168  m_IsNullRun = (title == "null");
169 
170  B2DEBUG(20, "DQMHistAnalysisTOP: beginRun called.");
171 }
172 
173 
175 {
176  bool zeroSupp = gStyle->GetHistMinimumZero();
177  gStyle->SetHistMinimumZero(true);
178 
179  // update alarm levels and other parameters from EpicsPVs
180  updateLimits();
181 
182  // reset overall alarm state
183  m_alarmStateOverall = c_Gray;
184 
185  // Update window_vs_slot canvas w/ alarming
187 
188  // Update event desynchronization monitor w/ alarming
190 
191  // Fraction of dead and hot channels
192  const auto* activeFraction = makeDeadAndHotFractionsPlot();
193 
194  // Photon yields and background rates, corrected for dead and hot channels
195  makePhotonYieldsAndBGRatePlots(activeFraction);
196 
197  // Fractions of junk hits
199 
200  // Set z-axis range to 3 times the average for good hits, 30 times the average for junk hits
201  setZAxisRange("TOP/good_hits_xy_", 3);
202  setZAxisRange("TOP/bad_hits_xy_", 30);
203  setZAxisRange("TOP/good_hits_asics_", 3);
204  setZAxisRange("TOP/bad_hits_asics_", 30);
205 
206  // Background subtracted time distributions
207  auto* trackHits = (TH2F*) findHist("TOP/trackHits");
208  makeBGSubtractedTimimgPlot("goodHitTimes", trackHits, 0);
209  for (int slot = 1; slot <= 16; slot++) {
210  makeBGSubtractedTimimgPlot("good_timing_" + to_string(slot), trackHits, slot);
211  }
212 
213  // Set Epics variables
215 
216  gStyle->SetHistMinimumZero(zeroSupp);
217 }
218 
219 
221 {
222  // add MiraBelle monitoring
223 
224  setMiraBelleVariables("RateBadRaw_slot", m_windowFractions);
225  m_monObj->setVariable("RateBadRaw_all", m_totalWindowFraction);
226  setMiraBelleVariables("PhotonsPerTrack_slot", m_photonYields);
227  setMiraBelleVariables("BackgroundRate_slot", m_backgroundRates);
228  setMiraBelleVariables("ActiveChannelFraction_slot", m_activeFraction);
229 
230  B2DEBUG(20, "DQMHistAnalysisTOP : endRun called");
231 }
232 
233 
235 {
236  B2DEBUG(20, "terminate called");
237 }
238 
239 
241 {
242  m_totalWindowFraction = 0; // used also for MiraBelle
243  m_windowFractions = nullptr; // used also for MiraBelle
244  int alarmState = c_Gray;
245  m_text1->Clear();
246 
247  auto* hraw = (TH2F*) findHist("TOP/window_vs_slot");
248  if (hraw) {
249  auto* px = hraw->ProjectionX("tmp_px");
250  auto* band = hraw->ProjectionX("TOP/windowFractions", m_asicWindowsBand[0], m_asicWindowsBand[1]);
251  band->Add(px, band, 1, -1);
252  double total = px->Integral();
253  m_totalWindowFraction = (total != 0) ? band->Integral() / total : 0;
254  band->Divide(band, px);
255  m_windowFractions = band;
256  if (total > 0) {
258  m_text1->AddText(Form("Fraction outside red lines: %.2f %%", m_totalWindowFraction * 100.0));
259  }
260  delete px;
261  }
262 
263  m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
264 
265  auto* canvas = findCanvas("TOP/c_window_vs_slot");
266  if (canvas) {
267  canvas->cd();
268  m_text1->Draw();
269  for (auto* line : m_asicWindowsBandLines) line->Draw();
270  canvas->Pad()->SetFrameFillColor(10);
271  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
272  canvas->Modified();
273  }
274 }
275 
276 
278 {
279  int alarmState = c_Gray;
280  m_text2->Clear();
281 
282  auto* evtMonitor = (TH1F*) findHist("TOP/BoolEvtMonitor");
283  if (evtMonitor) {
284  double totalEvts = evtMonitor->Integral();
285  double badEvts = evtMonitor->GetBinContent(2);
286  if (totalEvts > 0) {
287  double badRatio = badEvts / totalEvts;
288  alarmState = getAlarmState(badRatio, m_eventMonitorAlarmLevels);
289  m_text2->AddText(Form("Fraction: %.4f %%", badRatio * 100.0));
290  }
291  }
292 
293  m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
294 
295  auto* canvas = findCanvas("TOP/c_BoolEvtMonitor");
296  if (canvas) {
297  canvas->cd();
298  m_text2->Draw();
299  canvas->Pad()->SetFrameFillColor(10);
300  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
301  canvas->Modified();
302  }
303 }
304 
305 
307 {
308  m_deadFraction->Reset();
309  m_hotFraction->Reset();
310  m_activeFraction->Reset();
311  double inactiveFract = 0; // max inactive channel fraction when some boardstacks are excluded from alarming
312 
313  for (int slot = 1; slot <= 16; slot++) {
314  auto* h = (TH1F*) findHist("TOP/good_channel_hits_" + std::to_string(slot));
315  if (not h) continue;
316  double mean = 0;
317  int n = 0;
318  for (int chan = 0; chan < h->GetNbinsX(); chan++) {
319  double y = h->GetBinContent(chan + 1);
320  if (y > 0) {
321  mean += y;
322  n++;
323  }
324  }
325  if (n > 0) mean /= n;
326  double deadCut = mean / 10;
327  double hotCut = mean * 10;
328  double deadFract = 0;
329  double hotFract = 0;
330  double deadFractIncl = 0;
331  double hotFractIncl = 0;
332  for (int chan = 0; chan < h->GetNbinsX(); chan++) {
333  double y = h->GetBinContent(chan + 1);
334  int bs = chan / 128 + (slot - 1) * 4;
335  bool included = m_includedBoardstacks[bs];
336  if (y <= deadCut) {
337  deadFract += 1;
338  if (included) deadFractIncl += 1;
339  } else if (y > hotCut) {
340  hotFract += 1;
341  if (included) hotFractIncl += 1;
342  }
343  }
344  deadFract /= h->GetNbinsX();
345  hotFract /= h->GetNbinsX();
346  m_deadFraction->SetBinContent(slot, deadFract);
347  m_hotFraction->SetBinContent(slot, hotFract);
348  m_activeFraction->SetBinContent(slot, 1 - deadFract - hotFract);
349  inactiveFract = std::max(inactiveFract, (deadFractIncl + hotFractIncl) / h->GetNbinsX());
350  }
351 
352  int alarmState = c_Gray;
353  if (m_activeFraction->Integral() > 0) {
354  alarmState = getAlarmState(1 - m_activeFraction->GetMinimum(), m_deadChannelsAlarmLevels);
355  if (alarmState == c_Red) alarmState = std::max(getAlarmState(inactiveFract, m_deadChannelsAlarmLevels), static_cast<int>(c_Yellow));
356  }
357 
358  m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
359 
360  m_deadFraction->SetFillColor(1);
361  m_deadFraction->GetXaxis()->SetNdivisions(16);
362 
363  m_hotFraction->SetFillColor(2);
364  m_hotFraction->GetXaxis()->SetNdivisions(16);
365 
366  m_activeFraction->SetFillColor(0);
367  m_activeFraction->GetXaxis()->SetNdivisions(16);
368 
369  auto* canvas = m_c_deadAndHot;
370  canvas->Clear();
371  canvas->cd();
372  canvas->Pad()->SetFrameFillColor(10);
373  if (not m_stack) {
374  m_stack = new THStack("TOP/stack", "Fraction of dead and hot channels");
375  m_stack->Add(m_deadFraction);
376  m_stack->Add(m_hotFraction);
378  }
379  m_stack->Draw();
380 
381  for (auto* line : m_deadChannelsAlarmLines) line->Draw("same");
382 
383  if (not m_legend) {
384  m_legend = new TLegend(0.8, 0.87, 0.99, 0.99);
385  m_legend->AddEntry(m_hotFraction, "hot");
386  m_legend->AddEntry(m_deadFraction, "dead");
387  }
388  m_legend->Draw("same");
389 
390  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
391  canvas->Modified();
392 
393  return m_activeFraction;
394 }
395 
396 
398 {
399  for (auto* canvas : {m_c_photonYields, m_c_backgroundRates}) {
400  canvas->Clear();
401  canvas->Pad()->SetFrameFillColor(10);
402  canvas->Pad()->SetFillColor(getAlarmColor(c_Gray));
403  canvas->Modified();
404  }
405 
406  auto* signalHits = (TProfile*) findHist("TOP/signalHits");
407  if (not signalHits) return;
408 
409  auto* backgroundHits = (TProfile*) findHist("TOP/backgroundHits");
410  if (not backgroundHits) return;
411 
412  m_photonYields = signalHits->ProjectionX("TOP/photonYields");
413  m_backgroundRates = backgroundHits->ProjectionX("TOP/backgroundRates");
414  auto* activeFract = (TH1F*) activeFraction->Clone("tmp");
415  for (int i = 1; i <= activeFract->GetNbinsX(); i++) activeFract->SetBinError(i, 0);
416 
418  m_photonYields->Divide(m_photonYields, activeFract);
419 
420  int alarmState = c_Gray;
421  if (signalHits->GetEntries() > 0 and activeFraction->Integral() > 0) {
422  double hmin = 1000;
423  for (int i = 1; i <= m_photonYields->GetNbinsX(); i++) {
424  if (signalHits->GetBinEntries(i) < 10) continue;
425  hmin = std::min(hmin, m_photonYields->GetBinContent(i) + 3 * m_photonYields->GetBinError(i));
426  }
427  if (hmin < 1000) alarmState = getAlarmState(hmin, m_photonYieldsAlarmLevels, false);
428  }
429  m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
430 
431  m_photonYields->SetTitle("Number of photons per track");
432  m_photonYields->SetYTitle("photons per track");
433  m_photonYields->SetMarkerStyle(24);
434  m_photonYields->GetXaxis()->SetNdivisions(16);
435 
436  auto* canvas = m_c_photonYields;
437  canvas->cd();
438  m_photonYields->SetMinimum(0);
439  m_photonYields->Draw();
440  for (auto* line : m_photonYieldsAlarmLines) line->Draw("same");
441  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
442  canvas->Modified();
443 
444  m_backgroundRates->Scale(1.0 / 50.0e-3 / 32); // measured in 50 ns window, 32 PMT's ==> rate in MHz/PMT
445  m_backgroundRates->Divide(m_backgroundRates, activeFract);
446 
447  alarmState = c_Gray;
448  m_text3->Clear();
449  if (backgroundHits->GetEntries() > 100 and activeFraction->Integral() > 0) {
450  int status = m_backgroundRates->Fit("pol0", "Q0");
451  if (status == 0) {
452  auto* fun = m_backgroundRates->GetFunction("pol0");
453  if (fun) {
454  double average = fun->GetParameter(0);
455  double error = fun->GetParError(0);
456  alarmState = getAlarmState(average - 3 * error, m_backgroundAlarmLevels);
457  m_text3->AddText(Form("Average: %.2f MHz/PMT", average));
458  }
459  }
460  }
461  m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
462 
463  m_backgroundRates->SetTitle("Background rates");
464  m_backgroundRates->SetYTitle("background rate [MHz/PMT]");
465  m_backgroundRates->SetMarkerStyle(24);
466  m_backgroundRates->GetXaxis()->SetNdivisions(16);
467 
468  canvas = m_c_backgroundRates;
469  canvas->cd();
470  m_backgroundRates->SetMinimum(0);
471  m_backgroundRates->Draw();
472  for (auto* line : m_backgroundAlarmLines) line->Draw("same");
473  m_text3->Draw();
474  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
475  canvas->Modified();
476 
477  delete activeFract;
478 }
479 
480 
482 {
483  m_junkFraction->Reset();
484  auto* allHits = (TH1D*) m_junkFraction->Clone("tmp");
485  for (int slot = 1; slot <= 16; slot++) {
486  auto* good = (TH1F*) findHist("TOP/good_channel_hits_" + std::to_string(slot));
487  if (not good) continue;
488  auto* bad = (TH1F*) findHist("TOP/bad_channel_hits_" + std::to_string(slot));
489  if (not bad) continue;
490  for (int i = 0; i < 512; i++) {
491  int bs = i / 128;
492  allHits->Fill(slot + bs / 4. - 0.5, good->GetBinContent(i + 1) + bad->GetBinContent(i + 1));
493  m_junkFraction->Fill(slot + bs / 4. - 0.5, bad->GetBinContent(i + 1));
494  }
495  }
496 
497  m_junkFraction->Divide(m_junkFraction, allHits, 1, 1, "B");
498 
499  int alarmState = c_Gray;
500  if (allHits->Integral() > 0) {
501  alarmState = getAlarmState(m_junkFraction->GetMaximum(), m_junkHitsAlarmLevels);
502  if (alarmState == c_Red) {
503  double hmax = 0;
504  for (size_t i = 0; i < m_includedBoardstacks.size(); i++) {
505  if (m_includedBoardstacks[i]) hmax = std::max(hmax, m_junkFraction->GetBinContent(i + 1));
506  }
507  alarmState = std::max(getAlarmState(hmax, m_junkHitsAlarmLevels), static_cast<int>(c_Yellow));
508  }
509  }
510  delete allHits;
511  m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
512 
513  auto* canvas = m_c_junkFraction;
514  canvas->Clear();
515  canvas->cd();
516  canvas->Pad()->SetFrameFillColor(10);
517  canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
518  m_junkFraction->SetMarkerStyle(24);
519  m_junkFraction->GetXaxis()->SetNdivisions(16);
520  m_junkFraction->GetYaxis()->SetRangeUser(0, 1); // Note: m_junkFraction->GetMaximum() will now give 1 and not the histogram maximum!
521  m_junkFraction->Draw();
522  for (auto* line : m_verticalLines) line->Draw("same");
523  for (auto* line : m_junkHitsAlarmLines) line->Draw("same");
524  canvas->Modified();
525 }
526 
527 
528 void DQMHistAnalysisTOPModule::setZAxisRange(const std::string& name, double scale)
529 {
530  double totalHits = 0;
531  std::vector<TH2F*> histos;
532  for (int slot = 1; slot <= 16; slot++) {
533  TH2F* h = (TH2F*) findHist(name + std::to_string(slot));
534  if (not h) continue;
535  histos.push_back(h);
536  totalHits += h->Integral();
537  }
538  if (histos.empty()) return;
539  double average = totalHits / 512 / histos.size(); // per pixel or asic channel
540 
541  for (auto* h : histos) h->GetZaxis()->SetRangeUser(0, std::max(average * scale, 1.0));
542 }
543 
544 
545 void DQMHistAnalysisTOPModule::makeBGSubtractedTimimgPlot(const std::string& name, const TH2F* trackHits, int slot)
546 {
547  auto* canvas = findCanvas("TOP/c_" + name);
548  if (not canvas) return;
549 
550  auto* h = (TH1F*) findHist("TOP/" + name);
551  if (not h) return;
552 
553  auto* hb = (TH1F*) findHist("TOP/" + name + "BG");
554  if (not hb) return;
555 
556  if (trackHits) {
557  // use the ratio of events w/ and w/o track in the slot to scale the background
558  double s = (slot == 0) ? trackHits->Integral(1, 16, 2, 2) : trackHits->GetBinContent(slot, 2);
559  if (s == 0) return;
560  double sb = (slot == 0) ? trackHits->Integral(1, 16, 1, 1) : trackHits->GetBinContent(slot, 1);
561  if (sb == 0) return;
562  h->Add(h, hb, 1, -s / sb);
563  } else {
564  // use the content of bins at t < 0 to scale the background
565  int i0 = h->GetXaxis()->FindBin(0.); // bin at t = 0
566  double s = h->Integral(1, i0);
567  if (s == 0) return;
568  double sb = hb->Integral(1, i0);
569  if (sb == 0) return;
570  if (s / sb > 1) return; // this can happen due to low statistics and is not reliable
571  h->Add(h, hb, 1, -s / sb);
572  }
573 
574  TString title = TString(h->GetTitle()) + " (BG subtracted)";
575  h->SetTitle(title);
576 
577  canvas->Clear();
578  canvas->cd();
579  h->Draw();
580  canvas->Modified();
581 }
582 
583 
584 void DQMHistAnalysisTOPModule::setMiraBelleVariables(const std::string& variableName, const TH1* histogram)
585 {
586  for (int slot = 1; slot <= 16; slot++) {
587  auto vname = variableName + std::to_string(slot);
588  double value = histogram ? histogram->GetBinContent(slot) : 0;
589  m_monObj->setVariable(vname, value);
590 
591  B2DEBUG(20, vname << " " << value);
592  }
593 }
594 
595 
596 int DQMHistAnalysisTOPModule::getAlarmState(double value, const std::vector<double>& alarmLevels, bool bigRed) const
597 {
598  if (m_IsNullRun) return c_Gray;
599 
600  if (bigRed) {
601  if (value < alarmLevels[0]) return c_Green;
602  else if (value < alarmLevels[1]) return c_Yellow;
603  else return c_Red;
604  } else {
605  if (value < alarmLevels[0]) return c_Red;
606  else if (value < alarmLevels[1]) return c_Yellow;
607  else return c_Green;
608  }
609 }
610 
611 
612 void DQMHistAnalysisTOPModule::setAlarmLines(const std::vector<double>& alarmLevels, double xmin, double xmax,
613  std::vector<TLine*>& alarmLines, bool bigRed)
614 {
615  std::vector<int> colors = {kOrange, kRed};
616  if (not bigRed) std::reverse(colors.begin(), colors.end());
617  for (size_t i = 0; i < std::min(colors.size(), alarmLevels.size()); i++) {
618  if (i < alarmLines.size()) {
619  auto* line = alarmLines[i];
620  line->SetX1(xmin);
621  line->SetX2(xmax);
622  line->SetY1(alarmLevels[i]);
623  line->SetY2(alarmLevels[i]);
624  } else {
625  auto* line = new TLine(xmin, alarmLevels[i], xmax, alarmLevels[i]);
626  line->SetLineWidth(2);
627  line->SetLineStyle(2);
628  line->SetLineColor(colors[i]);
629  alarmLines.push_back(line);
630  }
631  }
632 }
633 
634 
636 {
637  for (auto y : m_asicWindowsBand) {
638  auto* line = new TLine(0.5, y, 16.5, y);
639  line->SetLineWidth(2);
640  line->SetLineColor(kRed);
641  m_asicWindowsBandLines.push_back(line);
642  }
643 
648 }
649 
650 
652 {
653  double mean = 0;
654  int n = 0;
655  for (int col = 1; col <= h->GetNbinsX(); col++) {
656  for (int row = 1; row <= h->GetNbinsY(); row++) {
657  double y = h->GetBinContent(col, row);
658  if (y > 0) {
659  mean += y;
660  n++;
661  }
662  }
663  }
664  if (n > 0) mean /= n;
665  return mean;
666 }
667 
668 
670 {
671  int badBoardstacks = 0;
672  int badCarriers = 0;
673  int badAsics = 0;
674  for (int slot = 1; slot <= 16; slot++) {
675  std::string hname = "TOP/good_hits_asics_" + to_string(slot);
676  auto* h = (TH2F*) findHist(hname);
677  if (not h) continue;
678 
679  double mean = getMean(h);
680  double deadCut = mean / 10;
681  double hotCut = mean * 10;
682  std::vector<int> asics(64, 0);
683  std::vector<int> carriers(16, 0);
684  std::vector<int> boardstacks(4, 0);
685  for (int asic = 0; asic < 64; asic++) {
686  int carrier = asic / 4;
687  int boardstack = carrier / 4;
688  for (int chan = 0; chan < 8; chan++) {
689  double y = h->GetBinContent(asic + 1, chan + 1);
690  if (y > deadCut and y < hotCut) {
691  asics[asic]++;
692  carriers[carrier]++;
693  boardstacks[boardstack]++;
694  }
695  }
696  }
697  for (int n : asics) if (n == 0) badAsics++;
698  for (int n : carriers) if (n == 0) badCarriers++;
699  for (int n : boardstacks) if (n == 0) badBoardstacks++;
700  }
701  badAsics -= badCarriers * 4;
702  badCarriers -= badBoardstacks * 4;
703 
704  int badPMTs = 0;
705  for (int slot = 1; slot <= 16; slot++) {
706  std::string hname = "TOP/good_hits_xy_" + to_string(slot);
707  auto* h = (TH2F*) findHist(hname);
708  if (not h) continue;
709 
710  double mean = getMean(h);
711  double deadCut = mean / 10;
712  double hotCut = mean * 10;
713  std::vector<int> pmts(32, 0);
714  for (int row = 0; row < 8; row++) {
715  for (int col = 0; col < 64; col++) {
716  int pmt = col / 4 + (row / 4) * 16;
717  double y = h->GetBinContent(col + 1, row + 1);
718  if (y > deadCut and y < hotCut) pmts[pmt]++;
719  }
720  }
721  for (int n : pmts) if (n == 0) badPMTs++;
722  }
723  badPMTs -= badBoardstacks * 8;
724 
725  setEpicsPV("badBoardstacks", badBoardstacks);
726  setEpicsPV("badCarriers", badCarriers);
727  setEpicsPV("badAsics", badAsics);
728  setEpicsPV("badPMTs", badPMTs);
729  int numBS = 0;
730  for (auto included : m_includedBoardstacks) if (not included) numBS++;
731  setEpicsPV("numExcludedBS", numBS);
733  updateEpicsPVs(5.0);
734 
735  B2DEBUG(20, "badBoardstacks: " << badBoardstacks);
736  B2DEBUG(20, "badCarriers: " << badCarriers);
737  B2DEBUG(20, "badAsics: " << badAsics);
738  B2DEBUG(20, "badPMTs: " << badPMTs);
739  B2DEBUG(20, "excludedBS: " << numBS);
740  B2DEBUG(20, "histoAlarmState: " << getOffcialAlarmStatus(m_alarmStateOverall));
741 }
742 
744 {
745  double unused = 0;
746 
747  double yLo = m_asicWindowsBand[0];
748  double yHi = m_asicWindowsBand[1];
749  requestLimitsFromEpicsPVs("asicWindowsBand", yLo, unused, unused, yHi);
750  m_asicWindowsBand[0] = yLo;
751  m_asicWindowsBand[1] = yHi;
752 
753  requestLimitsFromEpicsPVs("asicWindowsAlarmLevels", unused, unused, m_asicWindowsAlarmLevels[0], m_asicWindowsAlarmLevels[1]);
754  requestLimitsFromEpicsPVs("eventMonitorAlarmLevels", unused, unused, m_eventMonitorAlarmLevels[0], m_eventMonitorAlarmLevels[1]);
755  requestLimitsFromEpicsPVs("junkHitsAlarmLevels", unused, unused, m_junkHitsAlarmLevels[0], m_junkHitsAlarmLevels[1]);
756  requestLimitsFromEpicsPVs("deadChannelsAlarmLevels", unused, unused, m_deadChannelsAlarmLevels[0], m_deadChannelsAlarmLevels[1]);
757  requestLimitsFromEpicsPVs("backgroundAlarmLevels", unused, unused, m_backgroundAlarmLevels[0], m_backgroundAlarmLevels[1]);
758  requestLimitsFromEpicsPVs("photonYieldsAlarmLevels", m_photonYieldsAlarmLevels[0], m_photonYieldsAlarmLevels[1], unused, unused);
759 
760  setAlarmLines();
761 
762  bool status = false;
763  std::string excludedBS = getEpicsStringPV("excludedBoardstacks", status);
764 
765  if (status) {
766  m_excludedBoardstacks.clear();
767  std::string name;
768  for (auto c : excludedBS) {
769  if (isspace(c)) continue;
770  else if (ispunct(c)) {
771  if (not name.empty()) {
772  m_excludedBoardstacks.push_back(name);
773  name.clear();
774  }
775  } else name.push_back(c);
776  }
777  if (not name.empty()) {
778  m_excludedBoardstacks.push_back(name);
779  }
781  }
782 
783  B2DEBUG(20, "asicWindowsBand: [" << m_asicWindowsBand[0] << ", " << m_asicWindowsBand[1] << "]");
784  B2DEBUG(20, "asicWindowsAlarmLevels: [" << m_asicWindowsAlarmLevels[0] << ", " << m_asicWindowsAlarmLevels[1] << "]");
785  B2DEBUG(20, "eventMonitorAlarmLevels: [" << m_eventMonitorAlarmLevels[0] << ", " << m_eventMonitorAlarmLevels[1] << "]");
786  B2DEBUG(20, "junkHitsAlarmLevels: [" << m_junkHitsAlarmLevels[0] << ", " << m_junkHitsAlarmLevels[1] << "]");
787  B2DEBUG(20, "deadChannelsAlarmLevels: [" << m_deadChannelsAlarmLevels[0] << ", " << m_deadChannelsAlarmLevels[1] << "]");
788  B2DEBUG(20, "backgroundAlarmLevels: [" << m_backgroundAlarmLevels[0] << ", " << m_backgroundAlarmLevels[1] << "]");
789  B2DEBUG(20, "photonYieldsAlarmLevels: [" << m_photonYieldsAlarmLevels[0] << ", " << m_photonYieldsAlarmLevels[1] << "]");
790  std::string ss;
791  for (const auto& s : m_excludedBoardstacks) ss += "'" + s + "', ";
792  if (ss.size() > 2) {ss.pop_back(); ss.pop_back();}
793  B2DEBUG(20, "excludedBoardstacks: [" << ss << "]");
794 
795 }
796 
797 void DQMHistAnalysisTOPModule::setIncludedBoardstacks(const std::vector<std::string>& excludedBoardstacks)
798 {
799  m_includedBoardstacks.clear();
800  m_includedBoardstacks.resize(64, true);
801 
802  for (const auto& bsname : excludedBoardstacks) {
803  int id = m_bsmap[bsname];
804  if (id > 0) m_includedBoardstacks[id - 1] = false;
805  else B2ERROR("Invalid boardstack name: " << bsname);
806  }
807 }
The base class for the histogram analysis module.
TCanvas * findCanvas(TString cname)
Find canvas by name.
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.
int updateEpicsPVs(float timeout)
Update all EPICS PV (flush to network)
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
int m_alarmStateOverall
overall alarm state of histograms to be sent by EpicsPV
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
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.
void makeBGSubtractedTimimgPlot(const std::string &name, const TH2F *trackHits, int slot)
Makes background subtracted time distribution plot.
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.
int getOffcialAlarmStatus(unsigned alarmState) const
Converts alarm state to official status (see EStatus of the base class)
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.