Belle II Software development
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 <TProfile2D.h>
18#include <TString.h>
19#include <TMath.h>
20#include <map>
21
22using namespace std;
23using namespace Belle2;
24using boost::format;
25
26//-----------------------------------------------------------------
27// Register the Module
28//-----------------------------------------------------------------
29REG_MODULE(DQMHistAnalysisTOP);
30
31//-----------------------------------------------------------------
32// Implementation
33//-----------------------------------------------------------------
34
36{
37 // Set description
38 setDescription("Histogram analysis module for TOP DQM.");
39
40 // Add parameters
41 addParam("asicWindowsBand", m_asicWindowsBand,
42 "lower and upper bin of a band denoting good windows", m_asicWindowsBand);
43 addParam("asicWindowsAlarmLevels", m_asicWindowsAlarmLevels,
44 "alarm levels for the fraction of windows outside the band (yellow, red)", m_asicWindowsAlarmLevels);
45 addParam("windowMedianAlarmLevels", m_windowMedianAlarmLevels,
46 "alarm levels for the window_vs_slot medians (yellow, red)", m_windowMedianAlarmLevels);
47 addParam("eventMonitorAlarmLevels", m_eventMonitorAlarmLevels,
48 "alarm levels for the fraction of desynchronized digits (yellow, red)", m_eventMonitorAlarmLevels);
49 addParam("unpackerErrAlarmLevels", m_unpackerErrAlarmLevels,
50 "alarm levels for the fraction of unpacker errors (yellow, red)", m_unpackerErrAlarmLevels);
51 addParam("junkHitsAlarmLevels", m_junkHitsAlarmLevels,
52 "alarm levels for the fraction of junk hits (yellow, red)", m_junkHitsAlarmLevels);
53 addParam("deadChannelsAlarmLevels", m_deadChannelsAlarmLevels,
54 "alarm levels for the fraction of dead + hot channels (yellow, red)", m_deadChannelsAlarmLevels);
55 addParam("backgroundAlarmLevels", m_backgroundAlarmLevels,
56 "alarm levels for background rates [MHz/PMT] (yellow, red)", m_backgroundAlarmLevels);
57 addParam("photonYieldsAlarmLevels", m_photonYieldsAlarmLevels,
58 "alarm levels for the number of photons per track (red, yellow)", m_photonYieldsAlarmLevels);
59 addParam("excludedBoardstacks", m_excludedBoardstacks,
60 "boarstacks to be excluded from alarming. Names are given like '5c', '13d' etc.", m_excludedBoardstacks);
61 addParam("pvPrefix", m_pvPrefix, "Epics PV prefix", std::string("TOP:"));
62 addParam("injectionBGAlarmLevels", m_injectionBGAlarmLevels,
63 "alarm levels for injection background (in % of events)", m_injectionBGAlarmLevels);
64 addParam("timingAlarmLevels", m_timingAlarmLevels,
65 "alarm levels for time distribution (residual fraction w.r.t reference plot)", m_timingAlarmLevels);
66 addParam("eventT0MeanAlarmLevels", m_eventT0MeanAlarmLevels,
67 "alarm levels for mean of event T0 [ns]", m_eventT0MeanAlarmLevels);
68 addParam("eventT0RmsAlarmLevels", m_eventT0RmsAlarmLevels,
69 "alarm levels for r.m.s. of event T0 [ns]", m_eventT0RmsAlarmLevels);
70 addParam("offsetMeanAlarmLevels", m_offsetMeanAlarmLevels,
71 "alarm levels for mean of bunch offset [ns]", m_offsetMeanAlarmLevels);
72 addParam("offsetRmsAlarmLevels", m_offsetRmsAlarmLevels,
73 "alarm levels for r.m.s. of bunch offset [ns]", m_offsetRmsAlarmLevels);
74
75 B2DEBUG(20, "DQMHistAnalysisTOP: Constructor done.");
76}
77
78
80{
81
82 // check module parameters
83
84 if (m_asicWindowsBand.size() != 2) B2ERROR("Parameter list 'asicWindowsBand' must contain two numbers");
85 if (m_asicWindowsAlarmLevels.size() != 2) B2ERROR("Parameter list 'asicWindowsAlarmLevels' must contain two numbers");
86 if (m_windowMedianAlarmLevels.size() != 2) B2ERROR("Parameter list 'windowMedianAlarmLevels' must contain two numbers");
87 if (m_eventMonitorAlarmLevels.size() != 2) B2ERROR("Parameter list 'eventMonitorAlarmLevels' must contain two numbers");
88 if (m_unpackerErrAlarmLevels.size() != 2) B2ERROR("Parameter list 'unpackerErrAlarmLevels' must contain two numbers");
89 if (m_junkHitsAlarmLevels.size() != 2) B2ERROR("Parameter list 'junkHitsAlarmLevels' must contain two numbers");
90 if (m_deadChannelsAlarmLevels.size() != 2) B2ERROR("Parameter list 'deadChannelsAlarmLevels' must contain two numbers");
91 if (m_backgroundAlarmLevels.size() != 2) B2ERROR("Parameter list 'backgroundAlarmLevels' must contain two numbers");
92 if (m_photonYieldsAlarmLevels.size() != 2) B2ERROR("Parameter list 'photonYieldsAlarmLevels' must contain two numbers");
93 if (m_injectionBGAlarmLevels.size() != 2) B2ERROR("Parameter list 'injectionBGAlarmLevels' must contain two numbers");
94 if (m_timingAlarmLevels.size() != 2) B2ERROR("Parameter list 'timingAlarmLevels' must contain two numbers");
95 if (m_eventT0MeanAlarmLevels.size() != 2) B2ERROR("Parameter list 'eventT0MeanAlarmLevels' must contain two numbers");
96 if (m_eventT0RmsAlarmLevels.size() != 2) B2ERROR("Parameter list 'eventT0RmsAlarmLevels' must contain two numbers");
97 if (m_offsetMeanAlarmLevels.size() != 2) B2ERROR("Parameter list 'offsetMeanAlarmLevels' must contain two numbers");
98 if (m_offsetRmsAlarmLevels.size() != 2) B2ERROR("Parameter list 'offsetRmsAlarmLevels' must contain two numbers");
99
100 // make a map of boardstack names to ID's
101
102 int id = 1;
103 for (int slot = 1; slot <= 16; slot++) {
104 string slotstr = to_string(slot);
105 for (std::string bs : {"a", "b", "c", "d"}) {
106 m_bsmap[slotstr + bs] = id;
107 id++;
108 }
109 }
110
111 // parse excluded boardstacks
112
114
115 // MiraBelle monitoring
116
118
119 // Epics used to pass values to shifter's page (output only)
120
121 registerEpicsPV(m_pvPrefix + "badBoardstacks", "badBoardstacks");
122 registerEpicsPV(m_pvPrefix + "badCarriers", "badCarriers");
123 registerEpicsPV(m_pvPrefix + "badAsics", "badAsics");
124 registerEpicsPV(m_pvPrefix + "badPMTs", "badPMTs");
125 registerEpicsPV(m_pvPrefix + "numExcludedBS", "numExcludedBS");
126 registerEpicsPV(m_pvPrefix + "histoAlarmState", "histoAlarmState"); // to pass overall state to central alarm overview panel
127
128 // Epics used to get limits from configuration file - override module parameters (input only)
129
130 registerEpicsPV(m_pvPrefix + "asicWindowsBand", "asicWindowsBand");
131 registerEpicsPV(m_pvPrefix + "asicWindowsAlarmLevels", "asicWindowsAlarmLevels");
132 registerEpicsPV(m_pvPrefix + "windowMedian", "windowMedian"); // also output
133 registerEpicsPV(m_pvPrefix + "eventMonitorAlarmLevels", "eventMonitorAlarmLevels");
134 registerEpicsPV(m_pvPrefix + "unpackerErrAlarmLevels", "unpackerErrAlarmLevels");
135 registerEpicsPV(m_pvPrefix + "junkHitsAlarmLevels", "junkHitsAlarmLevels");
136 registerEpicsPV(m_pvPrefix + "deadChannelsAlarmLevels", "deadChannelsAlarmLevels");
137 registerEpicsPV(m_pvPrefix + "backgroundAlarmLevels", "backgroundAlarmLevels"); // also output
138 registerEpicsPV(m_pvPrefix + "photonYieldsAlarmLevels", "photonYieldsAlarmLevels");
139 registerEpicsPV(m_pvPrefix + "excludedBoardstacks", "excludedBoardstacks");
140
141 registerEpicsPV(m_pvPrefix + "injectionBGAlarmLevels", "injectionBGAlarmLevels"); // also output
142 registerEpicsPV(m_pvPrefix + "timingAlarmLevels", "timingAlarmLevels");
143 registerEpicsPV(m_pvPrefix + "eventT0MeanAlarmLevels", "eventT0MeanAlarmLevels");
144 registerEpicsPV(m_pvPrefix + "eventT0RmsAlarmLevels", "eventT0RmsAlarmLevels");
145 registerEpicsPV(m_pvPrefix + "offsetMeanAlarmLevels", "offsetMeanAlarmLevels");
146 registerEpicsPV(m_pvPrefix + "offsetRmsAlarmLevels", "offsetRmsAlarmLevels");
147
148 // new canvases, histograms and graphic primitives
149
150 gROOT->cd();
151
152 m_c_evtMonitorFract = new TCanvas("TOP/c_evtMonitorFract", "c_evtMonitorFract");
153 m_windowMedian = new TH1F("TOP/windowMedian", "Asic windows (medians); slot number; median", 64, 1, 17);
154 m_windowMedian->SetFillColor(9);
155 m_windowMedian->GetXaxis()->SetNdivisions(16);
156 m_windowMedian->GetXaxis()->CenterLabels();
157 m_windowMedian->SetMinimum(0);
158 m_c_windowMedian = new TCanvas("TOP/c_windowMedian", "c_windowMedian");
159 m_c_photonYields = new TCanvas("TOP/c_photonYields", "c_photonYields");
160 m_c_backgroundRates = new TCanvas("TOP/c_backgroundRates", "c_backgroundRates");
161
162 m_deadFraction = new TH1F("TOP/deadFraction", "Fraction of dead channels in included boardstacks", 16, 0.5, 16.5);
163 m_deadFraction->SetXTitle("slot number");
164 m_deadFraction->SetYTitle("fraction");
165 m_hotFraction = new TH1F("TOP/hotFraction", "Fraction of hot channels in included boardstacks", 16, 0.5, 16.5);
166 m_hotFraction->SetXTitle("slot number");
167 m_hotFraction->SetYTitle("fraction");
168 m_excludedFraction = new TH1F("TOP/excludedFraction", "Fraction of hot and dead channels in excluded bordstacks", 16, 0.5, 16.5);
169 m_excludedFraction->SetXTitle("slot number");
170 m_excludedFraction->SetYTitle("fraction");
171 m_activeFraction = new TH1F("TOP/activeFraction", "Fraction of active channels", 16, 0.5, 16.5);
172 m_activeFraction->SetXTitle("slot number");
173 m_activeFraction->SetYTitle("fraction");
174 m_c_deadAndHot = new TCanvas("TOP/c_deadAndHotChannels", "c_deadAndHotChannels");
175
176 m_junkFraction = new TH1F("TOP/junkFraction", "Fraction of junk hits per boardstack", 64, 1, 17);
177 m_junkFraction->SetXTitle("slot number");
178 m_junkFraction->SetYTitle("fraction");
179 m_junkFraction->GetXaxis()->SetNdivisions(16);
180 m_junkFraction->GetXaxis()->CenterLabels();
181 // note: titles are intentionally the same since this one is plotted first
182 m_excludedBSHisto = new TH1F("TOP/excludedBSHisto", "Fraction of junk hits per boardstack", 64, 1, 17);
183 m_excludedBSHisto->SetXTitle("slot number");
184 m_excludedBSHisto->SetYTitle("fraction");
185 m_excludedBSHisto->GetXaxis()->SetNdivisions(16);
186 m_excludedBSHisto->GetXaxis()->CenterLabels();
187 m_c_junkFraction = new TCanvas("TOP/c_junkFraction", "c_junkFraction");
188
189 for (int slot = 1; slot <= 16; slot++) {
190 string hname = "TOP/pmtHitRates_" + to_string(slot);
191 string htitle = "PMT hits per event for slot #" + to_string(slot);
192 auto* h = new TH1F(hname.c_str(), htitle.c_str(), 32, 0.5, 32.5);
193 h->SetXTitle("PMT number");
194 h->SetYTitle("Number of good hits per event");
195 m_pmtHitRates.push_back(h);
196 string cname = "TOP/c_pmtHitRates_" + to_string(slot);
197 string ctitle = "c_pmtHitRates_" + to_string(slot);
198 m_c_pmtHitRates.push_back(new TCanvas(cname.c_str(), ctitle.c_str()));
199 }
200
201 for (std::string name : {
202 "nhitInjLER", "nhitInjHER", "nhitInjLERcut", "nhitInjHERcut",
203 "eventInjLER", "eventInjHER", "eventInjLERcut", "eventInjHERcut"
204 }) {
205 for (std::string proj : {"_px", "_py"}) {
206 std::string cname = "TOP/c_" + name + proj;
207 m_c_injBGs[cname] = new TCanvas(cname.c_str(), (name + proj).c_str());
208 }
209 }
210
211 m_c_skipProcFlagFract = new TCanvas("TOP/c_skipProcFlagFract", "c_skipProcFlagFract");
212 m_c_injVetoFlagFract = new TCanvas("TOP/c_injVetoFlagFract", "c_injVetoFlagFract");
213
214 m_text1 = new TPaveText(0.125, 0.8, 0.675, 0.88, "NDC");
215 m_text1->SetFillColorAlpha(kWhite, 0);
216 m_text1->SetBorderSize(0);
217 m_text2 = new TPaveText(0.55, 0.8, 0.85, 0.89, "NDC");
218 m_text2->SetFillColorAlpha(kWhite, 0);
219 m_text2->SetBorderSize(0);
220 m_text3 = new TPaveText(0.47, 0.8, 0.85, 0.89, "NDC");
221 m_text3->SetFillColorAlpha(kWhite, 0);
222 m_text3->SetBorderSize(0);
223 m_text4 = new TPaveText(0.125, 0.8, 0.675, 0.88, "NDC");
224 m_text4->SetFillColorAlpha(kWhite, 0);
225 m_text4->SetBorderSize(0);
226
228
229 B2DEBUG(20, "DQMHistAnalysisTOP: initialized.");
230}
231
232
234{
235 m_mirabelleVariables.clear();
236
237 B2DEBUG(20, "DQMHistAnalysisTOP: beginRun called.");
238}
239
240
242{
243 // get type of the run (TODO: to be replaced with base class function when fixed)
244 auto* rtype = findHist("DQMInfo/rtype");
245 m_runType = rtype ? rtype->GetTitle() : "";
246 m_IsNullRun = (m_runType == "null");
247
248 // get number of events processed with TOPDQM module
249 auto* goodHitsPerEvent = findHist("TOP/goodHitsPerEventAll");
250 m_numEvents = goodHitsPerEvent ? goodHitsPerEvent->GetEntries() : 0;
251
252 bool zeroSupp = gStyle->GetHistMinimumZero();
253 gStyle->SetHistMinimumZero(true);
254
255 // update alarm levels and other parameters from EpicsPVs
256 updateLimits();
257
258 // reset overall alarm state
259 m_alarmStateOverall = c_Gray;
260
261 // Update window_vs_slot canvas w/ alarming
263
264 // Update window_vs_slot median canvas w/ alarming
266
267 // Update event desynchronization monitor w/ alarming
269
270 // Update unpacker errors w/ alarming
272
273 // Update number of good hits per event w/ alarming (injection BG)
275
276 // Update event T0 w/ alarming
278
279 // Update bunch offset w/ alarming
281
282 // Fraction of dead and hot channels
283 const auto* activeFraction = makeDeadAndHotFractionsPlot();
284
285 // Photon yields and background rates, corrected for dead and hot channels
286 makePhotonYieldsAndBGRatePlots(activeFraction);
287
288 // Fractions of junk hits
290
291 // Set z-axis range to 3 times the average for good hits, 30 times the average for junk hits
292 setZAxisRange("TOP/good_hits_xy_", 3);
293 setZAxisRange("TOP/bad_hits_xy_", 30);
294 setZAxisRange("TOP/good_hits_asics_", 3);
295 setZAxisRange("TOP/bad_hits_asics_", 30);
296
297 // Background subtracted time distributions (only for physics runs)
298 if (m_runType == "physics") {
299 const auto* trackHits = static_cast<TH2F*>(findHist("TOP/trackHits"));
300 makeBGSubtractedTimingPlot("goodHitTimes", trackHits, 0);
301 for (int slot = 1; slot <= 16; slot++) {
302 makeBGSubtractedTimingPlot("good_timing_" + to_string(slot), trackHits, slot);
303 }
304 }
305
306 // Update timing plot w/ alarming
308
309 // PMT hit rates
311
312 // Injection BG
314
315 // normalize histogram for injection veto flags check
316 auto* injVetoFlagDiff = static_cast<TH1F*>(findHist("TOP/injVetoFlagDiff"));
317 if (injVetoFlagDiff) injVetoFlagDiff->Scale(1 / injVetoFlagDiff->Integral(), "nosw2");
318
319 // make flag fraction plots
322
323 // set gridx in some canvases
324 setGridX("TOP/c_injVetoFlag");
325 setGridX("TOP/c_skipProcFlag");
326 setGridX("TOP/c_PSBypassMode");
327 setGridX("TOP/c_unpackErr");
328
329 // Set Epics variables
331
332 gStyle->SetHistMinimumZero(zeroSupp);
333}
334
335
337{
338 // add MiraBelle monitoring
339
340 for (const auto& var : m_mirabelleVariables) {
341 m_monObj->setVariable(var.first, var.second);
342 B2DEBUG(20, var.first << " " << var.second);
343 }
344
345 B2DEBUG(20, "DQMHistAnalysisTOP : endRun called");
346}
347
348
350{
351 B2DEBUG(20, "terminate called");
352}
353
354
356{
357 int alarmState = c_Gray;
358 m_text1->Clear();
359
360 auto* hraw = static_cast<TH2F*>(findHist("TOP/window_vs_slot"));
361 if (hraw) {
362 auto* px = hraw->ProjectionX("tmp_px");
363 auto* band = hraw->ProjectionX("tmp_band", m_asicWindowsBand[0], m_asicWindowsBand[1]);
364 if (px->GetNbinsX() == 64) {
365 band->Rebin(4); // binned in slots for MiraBelle
366 px->Rebin(4); // binned in slots for MiraBelle
367 }
368 band->Add(px, band, 1, -1);
369 double total = px->Integral();
370 double totalWindowFraction = (total != 0) ? band->Integral() / total : 0;
371 band->Divide(band, px);
372 setMiraBelleVariables("RateBadRaw_slot", band);
373 m_mirabelleVariables["RateBadRaw_all"] = totalWindowFraction;
374 if (total > 0) {
375 alarmState = getAlarmState(totalWindowFraction, m_asicWindowsAlarmLevels);
376 m_text1->AddText(Form("Fraction outside red lines: %.2f %%", totalWindowFraction * 100.0));
377 }
378 delete px;
379 delete band;
380 }
381
382 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
383
384 auto* canvas = findCanvas("TOP/c_window_vs_slot");
385 if (canvas) {
386 canvas->Clear();
387 canvas->cd();
388 if (hraw) hraw->Draw();
389 m_text1->Draw();
390 for (auto* line : m_asicWindowsBandLines) line->Draw();
391 canvas->Pad()->SetFrameFillColor(10);
392 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
393 canvas->SetGridx();
394 canvas->Modified();
395 }
396
397}
398
400{
401 int alarmState = c_Gray;
402 m_windowMedian->Reset();
403
404 for (int slot = 1; slot <= 16; slot++) {
405 std::string name = "TOP/window_vs_asic_" + std::to_string(slot);
406 auto* h = static_cast<TH2F*>(findHist(name));
407 if (not h) continue;
408 for (int bs = 1; bs <= 4; bs++) {
409 std::vector<double> longArray;
410 longArray.reserve(16 * h->GetNbinsY());
411 for (int asic = 1; asic <= 16; asic++) {
412 int binX = (bs - 1) * 16 + asic;
413 for (int binY = 1; binY <= h->GetNbinsY(); binY++) longArray.push_back(h->GetBinContent(binX, binY));
414 }
415 auto median = TMath::Median(longArray.size(), longArray.data(), 0, 0);
416 int bin = (slot - 1) * 4 + bs;
417 m_windowMedian->SetBinContent(bin, median);
418 }
419 }
420
421 double hmax = m_windowMedian->GetMaximum();
422 alarmState = getAlarmState(hmax, m_windowMedianAlarmLevels);
423
424 setEpicsPV("windowMedian", hmax);
425 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
426
427 auto* canvas = m_c_windowMedian;
428 canvas->Clear();
429 canvas->cd();
430 m_windowMedian->Draw("hist");
431 canvas->Pad()->SetFrameFillColor(10);
432 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
433 canvas->SetGridx();
434 canvas->Modified();
435
436}
437
439{
440 int alarmState = c_Gray;
441 m_text2->Clear();
443 m_evtMonitorFract = nullptr;
444
445 auto* h = findHist("TOP/BoolEvtMonitor");
446 if (h) {
447 double badEvts = 0;
448 double totalEvts = 0;
449 auto* evtMonitor = dynamic_cast<TH2D*>(h);
450 if (evtMonitor) { // new 2D histogram
451 m_evtMonitorFract = evtMonitor->ProjectionX("TOP/evtMonitorFract", 2, 2);
452 auto* tmp = evtMonitor->ProjectionX("tmp");
453 badEvts = m_evtMonitorFract->Integral();
454 totalEvts = tmp->Integral();
455 m_evtMonitorFract->Divide(m_evtMonitorFract, tmp, 1, 1, "B");
456 delete tmp;
457 m_evtMonitorFract->SetTitle("EventSynchonization (fractions)");
458 m_evtMonitorFract->SetYTitle("fraction of de-synchronized hits");
459 m_evtMonitorFract->SetFillColor(9);
460 } else { // old 1D histogram
461 badEvts = h->GetBinContent(2);
462 totalEvts = h->Integral();
463 }
464 if (totalEvts > 0) {
465 double badRatio = badEvts / totalEvts;
466 alarmState = getAlarmState(badRatio, m_eventMonitorAlarmLevels);
467 m_text2->AddText(Form("Fraction: %.4f %%", badRatio * 100.0));
468 }
469 }
470
471 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
472
473 auto* canvas = findCanvas("TOP/c_BoolEvtMonitor");
474 if (canvas) {
475 canvas->cd();
476 m_text2->Draw();
477 canvas->Pad()->SetFrameFillColor(10);
478 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
479 canvas->SetGridx();
480 canvas->Modified();
481 }
482
483 canvas = m_c_evtMonitorFract;
484 canvas->Clear();
485 canvas->cd();
486 if (m_evtMonitorFract) {
487 m_evtMonitorFract->Draw("hist");
488 canvas->Pad()->SetFrameFillColor(10);
489 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
490 canvas->SetGridx();
491 }
492 canvas->Modified();
493
494}
495
496
498{
499 int alarmState = c_Gray;
500
501 auto* hist = static_cast<TH1F*>(findHist("TOP/unpackErr"));
502 if (hist) {
503 double hmax = 0;
504 for (int i = 1; i <= hist->GetNbinsX(); i++) {
505 hmax = std::max(hmax, hist->GetBinContent(i) - 3 * hist->GetBinError(i));
506 }
507 alarmState = getAlarmState(hmax, m_unpackerErrAlarmLevels);
508 }
509
510 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
511
512 auto* canvas = findCanvas("TOP/c_unpackErr");
513 if (canvas) {
514 canvas->cd();
515 canvas->Pad()->SetFrameFillColor(10);
516 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
517 canvas->Modified();
518 }
519}
520
521
523{
524 int alarmState = c_Gray;
525 m_text4->Clear();
526
527 double fract = 0;
528 double xcut = 0;
529 double ymax = 0;
530 auto* h = static_cast<TH1F*>(findHist("TOP/goodHitsPerEventAll"));
531 if (h) {
532 xcut = h->GetBinCenter(h->GetMaximumBin()) + 900;
533 ymax = h->GetMaximum() / 2;
534 double totalEvts = h->GetEntries();
535 if (totalEvts > 1000) {
536 // fraction of events with more than xcut hits - these are mostly containing injection BG
537 fract = h->Integral(h->FindBin(xcut), h->GetNbinsX() + 1) / totalEvts * 100; // in %
538 alarmState = getAlarmState(fract, m_injectionBGAlarmLevels);
539 m_text4->AddText(Form("Events w/ Injection BG: %.2f %%", fract));
540 }
541 }
542
543 setEpicsPV("injectionBGAlarmLevels", fract);
544 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
545
546 auto* canvas = findCanvas("TOP/c_goodHitsPerEventAll");
547 if (canvas) {
548 canvas->cd();
549 if (not m_injBGCutLine) {
550 m_injBGCutLine = new TLine(xcut, 0, xcut, ymax);
551 m_injBGCutLine->SetLineWidth(2);
552 m_injBGCutLine->SetLineColor(kRed);
553 m_injBGCutLine->Draw("same");
554 } else {
555 m_injBGCutLine->SetX1(xcut);
556 m_injBGCutLine->SetX2(xcut);
557 m_injBGCutLine->SetY2(ymax);
558 }
559 m_text4->Draw();
560 canvas->Pad()->SetFrameFillColor(10);
561 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
562 canvas->Modified();
563 }
564}
565
566
568{
569 int alarmState = c_Gray;
570
571 auto* h = static_cast<TH1F*>(findHist("TOP/eventT0"));
572 if (h) {
573 double totalEvts = h->GetEntries();
574 if (totalEvts > 100) {
575 double mean = h->GetMean();
576 double rms = h->GetRMS();
577 alarmState = std::max(getAlarmState(fabs(mean), m_eventT0MeanAlarmLevels), getAlarmState(rms, m_eventT0RmsAlarmLevels));
578 }
579 }
580
581 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
582
583 auto* canvas = findCanvas("TOP/c_eventT0");
584 if (canvas) {
585 canvas->cd();
586 canvas->Pad()->SetFrameFillColor(10);
587 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
588 canvas->Modified();
589 }
590}
591
592
594{
595 int alarmState = c_Gray;
596
597 auto* h = static_cast<TH1F*>(findHist("TOP/bunchOffset"));
598 if (h) {
599 double totalEvts = h->GetEntries();
600 if (totalEvts > 100) {
601 double mean = h->GetMean();
602 double rms = h->GetRMS();
603 alarmState = std::max(getAlarmState(fabs(mean), m_offsetMeanAlarmLevels), getAlarmState(rms, m_offsetRmsAlarmLevels));
604 }
605 }
606
607 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
608
609 auto* canvas = findCanvas("TOP/c_bunchOffset");
610 if (canvas) {
611 canvas->cd();
612 canvas->Pad()->SetFrameFillColor(10);
613 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
614 canvas->Modified();
615 }
616}
617
618
620{
621 int alarmState = c_Gray;
622
623 auto* h = static_cast<TH1F*>(findHist("TOP/goodHitTimes"));
624 auto* href = static_cast<TH1F*>(findRefHist("TOP/goodHitTimes"));
625 if (h and href) {
626 double n = h->Integral();
627 double nref = href->Integral();
628 if (n > 0 and nref > 0 and sameHistDefinition(h, href)) {
629 auto* h_clone = static_cast<TH1F*>(h->Clone("tmp"));
630 auto* href_clone = static_cast<TH1F*>(href->Clone("tmpref"));
631 h_clone->Scale(1 / n);
632 href_clone->Scale(1 / nref);
633 h_clone->Add(h_clone, href_clone, 1, -1);
634 double sumDiff = 0;
635 double errDiff = 0;
636 for (int i = 1; i <= h_clone->GetNbinsX(); i++) {
637 sumDiff += fabs(h_clone->GetBinContent(i));
638 errDiff += pow(h_clone->GetBinError(i), 2);
639 }
640 errDiff = sqrt(errDiff);
641 if (sumDiff < 5 * errDiff) sumDiff = 0; // difference not significant
642 alarmState = getAlarmState(sumDiff, m_timingAlarmLevels);
643 delete h_clone;
644 delete href_clone;
645 }
646 }
647
648 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
649
650 auto* canvas = findCanvas("TOP/c_goodHitTimes");
651 if (canvas) {
652 canvas->cd();
653 canvas->Pad()->SetFrameFillColor(10);
654 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
655 canvas->Modified();
656 }
657}
658
660{
661 if (h1->GetNbinsX() != h2->GetNbinsX()) return false;
662 if (h1->GetXaxis()->GetXmin() != h2->GetXaxis()->GetXmin()) return false;
663 if (h1->GetXaxis()->GetXmax() != h2->GetXaxis()->GetXmax()) return false;
664 return true;
665}
666
668{
669 m_deadFraction->Reset();
670 m_hotFraction->Reset();
671 m_excludedFraction->Reset();
672 m_activeFraction->Reset();
673 double inactiveFract = 0; // max inactive channel fraction when some boardstacks are excluded from alarming
674
675 for (int slot = 1; slot <= 16; slot++) {
676 auto* h = static_cast<TH1F*>(findHist("TOP/good_channel_hits_" + std::to_string(slot)));
677 if (not h) continue;
678
679 auto cuts = getDeadAndHotCuts(h);
680 double deadCut = cuts.first;
681 double hotCut = cuts.second;
682 double deadFract = 0;
683 double hotFract = 0;
684 double deadFractIncl = 0;
685 double hotFractIncl = 0;
686 for (int chan = 0; chan < h->GetNbinsX(); chan++) {
687 double y = h->GetBinContent(chan + 1);
688 int bs = chan / 128 + (slot - 1) * 4;
689 bool included = m_includedBoardstacks[bs];
690 if (y <= deadCut) {
691 deadFract += 1;
692 if (included) deadFractIncl += 1;
693 } else if (y > hotCut) {
694 hotFract += 1;
695 if (included) hotFractIncl += 1;
696 }
697 }
698 deadFract /= h->GetNbinsX();
699 hotFract /= h->GetNbinsX();
700 deadFractIncl /= h->GetNbinsX();
701 hotFractIncl /= h->GetNbinsX();
702 m_deadFraction->SetBinContent(slot, deadFractIncl);
703 m_hotFraction->SetBinContent(slot, hotFractIncl);
704 m_excludedFraction->SetBinContent(slot, deadFract - deadFractIncl + hotFract - hotFractIncl);
705 m_activeFraction->SetBinContent(slot, 1 - deadFract - hotFract);
706 inactiveFract = std::max(inactiveFract, deadFractIncl + hotFractIncl);
707 }
708
709 setMiraBelleVariables("ActiveChannelFraction_slot", m_activeFraction);
710
711 int alarmState = c_Gray;
712 if (m_activeFraction->Integral() > 0) {
713 alarmState = getAlarmState(inactiveFract, m_deadChannelsAlarmLevels);
714 }
715
716 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
717
718 m_deadFraction->SetFillColor(1);
719 m_deadFraction->SetLineColor(1);
720 m_deadFraction->GetXaxis()->SetNdivisions(16);
721
722 m_hotFraction->SetFillColor(2);
723 m_hotFraction->SetLineColor(2);
724 m_hotFraction->GetXaxis()->SetNdivisions(16);
725
726 m_excludedFraction->SetFillColor(kGray);
727 m_excludedFraction->SetLineColor(kGray);
728 m_excludedFraction->GetXaxis()->SetNdivisions(16);
729
730 m_activeFraction->SetFillColor(0);
731 m_activeFraction->GetXaxis()->SetNdivisions(16);
732
733 auto* canvas = m_c_deadAndHot;
734 canvas->Clear();
735 canvas->cd();
736 canvas->Pad()->SetFrameFillColor(10);
737 if (not m_stack) {
738 m_stack = new THStack("TOP/stack", "Fraction of dead and hot channels");
743 }
744 m_stack->Draw();
745
746 for (auto* line : m_deadChannelsAlarmLines) line->Draw("same");
747
748 if (not m_legend) {
749 m_legend = new TLegend(0.8, 0.87, 0.99, 0.99);
750 m_legend->AddEntry(m_hotFraction, "hot");
751 m_legend->AddEntry(m_deadFraction, "dead");
752 m_legend->AddEntry(m_excludedFraction, "excluded");
753 }
754 m_legend->Draw("same");
755
756 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
757 canvas->Modified();
758
759 return m_activeFraction;
760}
761
762
764{
765 for (auto* canvas : {m_c_photonYields, m_c_backgroundRates}) {
766 canvas->Clear();
767 canvas->Pad()->SetFrameFillColor(10);
768 canvas->Pad()->SetFillColor(getAlarmColor(c_Gray));
769 canvas->Modified();
770 }
771 m_averageRate = 0;
772
773 auto* signalHits = static_cast<TProfile*>(findHist("TOP/signalHits"));
774 if (not signalHits) return;
775
776 auto* backgroundHits = static_cast<TProfile*>(findHist("TOP/backgroundHits"));
777 if (not backgroundHits) return;
778
779 if (m_photonYields) delete m_photonYields;
780 m_photonYields = signalHits->ProjectionX("TOP/photonYields");
782 m_backgroundRates = backgroundHits->ProjectionX("TOP/backgroundRates");
783 auto* activeFract = static_cast<TH1F*>(activeFraction->Clone("tmp"));
784 for (int i = 1; i <= activeFract->GetNbinsX(); i++) activeFract->SetBinError(i, 0);
785
787 m_photonYields->Divide(m_photonYields, activeFract);
788 setMiraBelleVariables("PhotonsPerTrack_slot", m_photonYields);
789
790 int alarmState = c_Gray;
791 if (signalHits->GetEntries() > 0 and activeFraction->Integral() > 0) {
792 double hmin = 1000;
793 for (int i = 1; i <= m_photonYields->GetNbinsX(); i++) {
794 if (signalHits->GetBinEntries(i) < 10) continue;
795 hmin = std::min(hmin, m_photonYields->GetBinContent(i) + 3 * m_photonYields->GetBinError(i));
796 }
797 if (hmin < 1000) alarmState = getAlarmState(hmin, m_photonYieldsAlarmLevels, false);
798 }
799 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
800
801 m_photonYields->SetTitle("Number of photons per track");
802 m_photonYields->SetYTitle("photons per track");
803 m_photonYields->SetMarkerStyle(24);
804 m_photonYields->GetXaxis()->SetNdivisions(16);
805
806 auto* canvas = m_c_photonYields;
807 canvas->cd();
808 m_photonYields->SetMinimum(0);
809 m_photonYields->Draw();
810 for (auto* line : m_photonYieldsAlarmLines) line->Draw("same");
811 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
812 canvas->Modified();
813
814 m_backgroundRates->Scale(1.0 / 50.0e-3 / 32); // measured in 50 ns window, 32 PMT's ==> rate in MHz/PMT
815 m_backgroundRates->Divide(m_backgroundRates, activeFract);
816 setMiraBelleVariables("BackgroundRate_slot", m_backgroundRates);
817
818 alarmState = c_Gray;
819 m_text3->Clear();
820 if (backgroundHits->GetEntries() > 100 and activeFraction->Integral() > 0) {
821 int status = m_backgroundRates->Fit("pol0", "Q0");
822 if (status == 0) {
823 auto* fun = m_backgroundRates->GetFunction("pol0");
824 if (fun) {
825 m_averageRate = fun->GetParameter(0);
826 double error = fun->GetParError(0);
827 alarmState = getAlarmState(m_averageRate - 3 * error, m_backgroundAlarmLevels);
828 m_text3->AddText(Form("Average: %.2f MHz/PMT", m_averageRate));
829 }
830 }
831 }
832 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
833
834 m_backgroundRates->SetTitle("Background rates");
835 m_backgroundRates->SetYTitle("background rate [MHz/PMT]");
836 m_backgroundRates->SetMarkerStyle(24);
837 m_backgroundRates->GetXaxis()->SetNdivisions(16);
838
839 canvas = m_c_backgroundRates;
840 canvas->cd();
841 m_backgroundRates->SetMinimum(0);
842 m_backgroundRates->Draw();
843 for (auto* line : m_backgroundAlarmLines) line->Draw("same");
844 m_text3->Draw();
845 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
846 canvas->Modified();
847
848 delete activeFract;
849}
850
851
853{
854 m_junkFraction->Reset();
855 m_excludedBSHisto->Reset();
856 auto* allHits = static_cast<TH1D*>(m_junkFraction->Clone("tmp"));
857 for (int slot = 1; slot <= 16; slot++) {
858 auto* good = static_cast<TH1F*>(findHist("TOP/good_channel_hits_" + std::to_string(slot)));
859 if (not good) continue;
860 auto* bad = static_cast<TH1F*>(findHist("TOP/bad_channel_hits_" + std::to_string(slot)));
861 if (not bad) continue;
862 for (int i = 0; i < 512; i++) {
863 int bs = i / 128;
864 allHits->Fill(slot + bs / 4.0, good->GetBinContent(i + 1) + bad->GetBinContent(i + 1));
865 m_junkFraction->Fill(slot + bs / 4.0, bad->GetBinContent(i + 1));
866 }
867 }
868
869 m_junkFraction->Divide(m_junkFraction, allHits, 1, 1, "B");
870
871 int alarmState = c_Gray;
872 if (allHits->Integral() > 0) {
873 double hmax = 0;
874 for (size_t i = 0; i < m_includedBoardstacks.size(); i++) {
875 if (m_includedBoardstacks[i]) hmax = std::max(hmax, m_junkFraction->GetBinContent(i + 1));
876 else m_excludedBSHisto->SetBinContent(i + 1, 1);
877 }
878 alarmState = getAlarmState(hmax, m_junkHitsAlarmLevels);
879 }
880 delete allHits;
881 m_alarmStateOverall = std::max(m_alarmStateOverall, alarmState);
882
883 auto* canvas = m_c_junkFraction;
884 canvas->Clear();
885 canvas->cd();
886 canvas->SetGridx();
887 canvas->Pad()->SetFrameFillColor(10);
888 canvas->Pad()->SetFillColor(getAlarmColor(alarmState));
889 m_excludedBSHisto->SetFillColor(kGray);
890 m_excludedBSHisto->SetLineColor(kGray);
891 m_excludedBSHisto->GetYaxis()->SetRangeUser(0, 1);
892 m_excludedBSHisto->Draw();
893 m_junkFraction->SetMarkerStyle(24);
894 // m_junkFraction->GetYaxis()->SetRangeUser(0, 1); // Note: m_junkFraction->GetMaximum() will now give 1 and not the histogram maximum!
895 m_junkFraction->Draw("same");
896 for (auto* line : m_junkHitsAlarmLines) line->Draw("same");
897 canvas->Modified();
898}
899
900
901void DQMHistAnalysisTOPModule::setZAxisRange(const std::string& name, double scale)
902{
903 double totalHits = 0;
904 std::vector<TH2F*> histos;
905 for (int slot = 1; slot <= 16; slot++) {
906 TH2F* h = static_cast<TH2F*>(findHist(name + std::to_string(slot)));
907 if (not h) continue;
908 histos.push_back(h);
909 totalHits += h->Integral();
910 }
911 if (histos.empty()) return;
912 double average = totalHits / 512 / histos.size(); // per pixel or asic channel
913
914 for (auto* h : histos) h->GetZaxis()->SetRangeUser(0, std::max(average * scale, 1.0));
915}
916
917
918void DQMHistAnalysisTOPModule::makeBGSubtractedTimingPlot(const std::string& name, const TH2F* trackHits, int slot)
919{
920 auto* canvas = findCanvas("TOP/c_" + name);
921 if (not canvas) return;
922
923 auto* h = static_cast<TH1F*>(findHist("TOP/" + name));
924 if (not h) return;
925
926 auto* hb = static_cast<TH1F*>(findHist("TOP/" + name + "BG"));
927 if (not hb) return;
928
929 if (trackHits) {
930 // use the ratio of events w/ and w/o track in the slot to scale the background
931 double s = (slot == 0) ? trackHits->Integral(1, 16, 2, 2) : trackHits->GetBinContent(slot, 2);
932 if (s == 0) return;
933 double sb = (slot == 0) ? trackHits->Integral(1, 16, 1, 1) : trackHits->GetBinContent(slot, 1);
934 if (sb == 0) return;
935 h->Add(h, hb, 1, -s / sb);
936 } else {
937 // use the content of bins at t < 0 to scale the background
938 int i0 = h->GetXaxis()->FindBin(0.); // bin at t = 0
939 double s = h->Integral(1, i0);
940 if (s == 0) return;
941 double sb = hb->Integral(1, i0);
942 if (sb == 0) return;
943 if (s / sb > 1) return; // this can happen due to low statistics and is not reliable
944 h->Add(h, hb, 1, -s / sb);
945 }
946
947 TString title = TString(h->GetTitle()) + " (BG subtracted)";
948 h->SetTitle(title);
949
950 canvas->Clear();
951 canvas->cd();
952 h->Draw();
953 canvas->Modified();
954}
955
956
958{
959 auto* h0 = static_cast<TH1F*>(findHist("TOP/goodHitsPerEventAll"));
960 if (not h0) return;
961 double numEvents = h0->GetEntries();
962 if (numEvents == 0) return;
963
964 int numSlots = m_pmtHitRates.size();
965 for (int slot = 1; slot <= numSlots; slot++) {
966 string name = "TOP/good_hits_xy_" + to_string(slot);
967 auto* hxy = static_cast<TH2F*>(findHist(name));
968 if (not hxy) continue;
969 std::vector<double> pmts(32, 0);
970 for (int row = 0; row < 8; row++) {
971 for (int col = 0; col < 64; col++) {
972 int pmt = col / 4 + (row / 4) * 16;
973 pmts[pmt] += hxy->GetBinContent(col + 1, row + 1);
974 }
975 }
976 auto* h = m_pmtHitRates[slot - 1];
977 for (size_t i = 0; i < pmts.size(); i++) {
978 h->SetBinContent(i + 1, pmts[i] / numEvents);
979 }
980 auto* canvas = m_c_pmtHitRates[slot - 1];
981 canvas->Clear();
982 canvas->cd();
983 h->SetMinimum(0);
984 h->Draw();
985 canvas->Modified();
986 }
987}
988
989
991{
992 for (std::string name : {"nhitInjLER", "nhitInjHER", "nhitInjLERcut", "nhitInjHERcut"}) {
993 std::string hname = "TOP/" + name;
994 auto* h = static_cast<TProfile2D*>(findHist(hname));
995 if (not h) continue;
996 for (std::string proj : {"_px", "_py"}) {
997 std::string cname = "TOP/c_" + name + proj;
998 auto* canvas = m_c_injBGs[cname];
999 if (not canvas) continue;
1000 canvas->Clear();
1001 canvas->cd();
1002 auto& hproj = m_profiles[cname];
1003 if (hproj) delete hproj;
1004 hproj = (proj == "_px") ? h->ProfileX((hname + proj).c_str()) : h->ProfileY((hname + proj).c_str());
1005 std::string xtitle = (proj == "_px") ? h->GetXaxis()->GetTitle() : h->GetYaxis()->GetTitle();
1006 hproj->SetXTitle(xtitle.c_str());
1007 hproj->SetYTitle(h->GetZaxis()->GetTitle());
1008 hproj->SetMinimum(0);
1009 hproj->Draw("hist");
1010 canvas->Modified();
1011 }
1012 }
1013
1014 for (std::string name : {"eventInjLER", "eventInjHER", "eventInjLERcut", "eventInjHERcut"}) {
1015 std::string hname = "TOP/" + name;
1016 auto* h = static_cast<TH2F*>(findHist(hname));
1017 if (not h) continue;
1018 for (std::string proj : {"_px", "_py"}) {
1019 std::string cname = "TOP/c_" + name + proj;
1020 auto* canvas = m_c_injBGs[cname];
1021 if (not canvas) continue;
1022 canvas->Clear();
1023 canvas->cd();
1024 auto& hproj = m_projections[cname];
1025 if (hproj) delete hproj;
1026 hproj = (proj == "_px") ? h->ProjectionX((hname + proj).c_str()) : h->ProjectionY((hname + proj).c_str());
1027 std::string xtitle = (proj == "_px") ? h->GetXaxis()->GetTitle() : h->GetYaxis()->GetTitle();
1028 hproj->SetXTitle(xtitle.c_str());
1029 hproj->SetYTitle(h->GetZaxis()->GetTitle());
1030 hproj->SetMinimum(0);
1031 hproj->Draw("hist");
1032 canvas->Modified();
1033 }
1034 }
1035
1036}
1037
1038void DQMHistAnalysisTOPModule::makeFlagFractPlot(const std::string& hname, TH1* histogram, TCanvas* canvas)
1039{
1040 if (histogram) delete histogram;
1041 auto* h = static_cast<TH2F*>(findHist(hname));
1042 if (not h) return;
1043
1044 histogram = h->ProjectionX((hname + "Fract").c_str(), 2, 2);
1045 auto* px = h->ProjectionX("tmp");
1046 histogram->Divide(histogram, px, 1, 1, "B");
1047 delete px;
1048 histogram->SetTitle(TString(h->GetTitle()) + " is set");
1049 histogram->SetYTitle("fraction of events");
1050 histogram->SetMarkerStyle(24);
1051 histogram->SetMinimum(0);
1052
1053 if (not canvas) return;
1054 canvas->Clear();
1055 canvas->SetGridx();
1056 canvas->cd();
1057 histogram->Draw();
1058 canvas->Modified();
1059}
1060
1061void DQMHistAnalysisTOPModule::setMiraBelleVariables(const std::string& variableName, const TH1* histogram)
1062{
1063 for (int slot = 1; slot <= 16; slot++) {
1064 auto vname = variableName + std::to_string(slot);
1065 double value = histogram ? histogram->GetBinContent(slot) : 0;
1066 m_mirabelleVariables[vname] = value;
1067 }
1068}
1069
1070
1071int DQMHistAnalysisTOPModule::getAlarmState(double value, const std::vector<double>& alarmLevels, bool bigRed) const
1072{
1073 if (m_IsNullRun or m_numEvents < 1000) return c_Gray;
1074
1075 if (bigRed) {
1076 if (value < alarmLevels[0]) return c_Green;
1077 else if (value < alarmLevels[1]) return c_Yellow;
1078 else return c_Red;
1079 } else {
1080 if (value < alarmLevels[0]) return c_Red;
1081 else if (value < alarmLevels[1]) return c_Yellow;
1082 else return c_Green;
1083 }
1084}
1085
1086
1087void DQMHistAnalysisTOPModule::setAlarmLines(const std::vector<double>& alarmLevels, double xmin, double xmax,
1088 std::vector<TLine*>& alarmLines, bool bigRed)
1089{
1090 std::vector<int> colors = {kOrange, kRed};
1091 if (not bigRed) std::reverse(colors.begin(), colors.end());
1092 for (size_t i = 0; i < std::min(colors.size(), alarmLevels.size()); i++) {
1093 if (i < alarmLines.size()) {
1094 auto* line = alarmLines[i];
1095 line->SetX1(xmin);
1096 line->SetX2(xmax);
1097 line->SetY1(alarmLevels[i]);
1098 line->SetY2(alarmLevels[i]);
1099 } else {
1100 auto* line = new TLine(xmin, alarmLevels[i], xmax, alarmLevels[i]);
1101 line->SetLineWidth(2);
1102 line->SetLineStyle(2);
1103 line->SetLineColor(colors[i]);
1104 alarmLines.push_back(line);
1105 }
1106 }
1107}
1108
1109
1111{
1112 for (size_t i = 0; i < m_asicWindowsBand.size(); i++) {
1113 double y = m_asicWindowsBand[i];
1114 if (i < m_asicWindowsBandLines.size()) {
1115 auto* line = m_asicWindowsBandLines[i];
1116 line->SetY1(y);
1117 line->SetY2(y);
1118 } else {
1119 auto* line = new TLine(1, y, 17, y);
1120 line->SetLineWidth(2);
1121 line->SetLineColor(kRed);
1122 m_asicWindowsBandLines.push_back(line);
1123 }
1124 }
1125
1130}
1131
1132
1133std::pair<double, double> DQMHistAnalysisTOPModule::getDeadAndHotCuts(const TH1* h)
1134{
1135 std::vector<double> binContents;
1136 for (int k = 1; k <= h->GetNbinsY(); k++) {
1137 for (int i = 1; i <= h->GetNbinsX(); i++) {
1138 binContents.push_back(h->GetBinContent(i, k));
1139 }
1140 }
1141
1142 double mean = 0;
1143 double rms = h->GetMaximum();
1144 for (int iter = 0; iter < 5; iter++) {
1145 double sumy = 0;
1146 double sumyy = 0;
1147 int n = 0;
1148 for (auto y : binContents) {
1149 if (y == 0 or fabs(y - mean) > 3 * rms) continue;
1150 sumy += y;
1151 sumyy += y * y;
1152 n++;
1153 }
1154 if (n == 0) continue;
1155 mean = sumy / n;
1156 rms = sqrt(sumyy / n - mean * mean);
1157 }
1158
1159 return std::make_pair(mean / 5, std::max(mean * 2, mean + 6 * rms));
1160}
1161
1162
1164{
1165 int badBoardstacks = 0;
1166 int badCarriers = 0;
1167 int badAsics = 0;
1168 for (int slot = 1; slot <= 16; slot++) {
1169 std::string hname = "TOP/good_hits_asics_" + to_string(slot);
1170 auto* h = static_cast<TH2F*>(findHist(hname));
1171 if (not h) continue;
1172
1173 auto cuts = getDeadAndHotCuts(h);
1174 double deadCut = cuts.first;
1175 double hotCut = cuts.second;
1176 std::vector<int> asics(64, 0);
1177 std::vector<int> carriers(16, 0);
1178 std::vector<int> boardstacks(4, 0);
1179 for (int asic = 0; asic < 64; asic++) {
1180 int carrier = asic / 4;
1181 int boardstack = carrier / 4;
1182 for (int chan = 0; chan < 8; chan++) {
1183 double y = h->GetBinContent(asic + 1, chan + 1);
1184 if (y > deadCut and y <= hotCut) {
1185 asics[asic]++;
1186 carriers[carrier]++;
1187 boardstacks[boardstack]++;
1188 }
1189 }
1190 }
1191 for (int n : asics) if (n == 0) badAsics++;
1192 for (int n : carriers) if (n == 0) badCarriers++;
1193 for (int n : boardstacks) if (n == 0) badBoardstacks++;
1194 }
1195 badAsics -= badCarriers * 4;
1196 badCarriers -= badBoardstacks * 4;
1197
1198 int badPMTs = 0;
1199 for (int slot = 1; slot <= 16; slot++) {
1200 std::string hname = "TOP/good_hits_xy_" + to_string(slot);
1201 auto* h = static_cast<TH2F*>(findHist(hname));
1202 if (not h) continue;
1203
1204 auto cuts = getDeadAndHotCuts(h);
1205 double deadCut = cuts.first;
1206 double hotCut = cuts.second;
1207 std::vector<int> pmts(32, 0);
1208 for (int row = 0; row < 8; row++) {
1209 for (int col = 0; col < 64; col++) {
1210 double y = h->GetBinContent(col + 1, row + 1);
1211 if (y > deadCut and y <= hotCut) {
1212 int pmt = col / 4 + (row / 4) * 16;
1213 pmts[pmt]++;
1214 }
1215 }
1216 }
1217 for (int n : pmts) if (n == 0) badPMTs++;
1218 }
1219 badPMTs -= badBoardstacks * 8;
1220
1221 setEpicsPV("badBoardstacks", badBoardstacks);
1222 setEpicsPV("badCarriers", badCarriers);
1223 setEpicsPV("badAsics", badAsics);
1224 setEpicsPV("badPMTs", badPMTs);
1225 int numBS = 0;
1226 for (auto included : m_includedBoardstacks) if (not included) numBS++;
1227 setEpicsPV("numExcludedBS", numBS);
1229 setEpicsPV("backgroundAlarmLevels", m_averageRate);
1230
1231 B2DEBUG(20, "badBoardstacks: " << badBoardstacks);
1232 B2DEBUG(20, "badCarriers: " << badCarriers);
1233 B2DEBUG(20, "badAsics: " << badAsics);
1234 B2DEBUG(20, "badPMTs: " << badPMTs);
1235 B2DEBUG(20, "excludedBS: " << numBS);
1236 B2DEBUG(20, "histoAlarmState: " << getOffcialAlarmStatus(m_alarmStateOverall));
1237 B2DEBUG(20, "backgroundAlarmLevels" << m_averageRate);
1238}
1239
1241{
1242 double unused = 0;
1243
1244 double yLo = m_asicWindowsBand[0];
1245 double yHi = m_asicWindowsBand[1];
1246 requestLimitsFromEpicsPVs("asicWindowsBand", yLo, unused, unused, yHi);
1247 m_asicWindowsBand[0] = yLo;
1248 m_asicWindowsBand[1] = yHi;
1249
1250 requestLimitsFromEpicsPVs("asicWindowsAlarmLevels", unused, unused, m_asicWindowsAlarmLevels[0], m_asicWindowsAlarmLevels[1]);
1252 requestLimitsFromEpicsPVs("eventMonitorAlarmLevels", unused, unused, m_eventMonitorAlarmLevels[0], m_eventMonitorAlarmLevels[1]);
1253 requestLimitsFromEpicsPVs("unpackerErrAlarmLevels", unused, unused, m_unpackerErrAlarmLevels[0], m_unpackerErrAlarmLevels[1]);
1254 requestLimitsFromEpicsPVs("junkHitsAlarmLevels", unused, unused, m_junkHitsAlarmLevels[0], m_junkHitsAlarmLevels[1]);
1255 requestLimitsFromEpicsPVs("deadChannelsAlarmLevels", unused, unused, m_deadChannelsAlarmLevels[0], m_deadChannelsAlarmLevels[1]);
1256 requestLimitsFromEpicsPVs("backgroundAlarmLevels", unused, unused, m_backgroundAlarmLevels[0], m_backgroundAlarmLevels[1]);
1257 requestLimitsFromEpicsPVs("photonYieldsAlarmLevels", m_photonYieldsAlarmLevels[0], m_photonYieldsAlarmLevels[1], unused, unused);
1258
1259 requestLimitsFromEpicsPVs("injectionBGAlarmLevels", unused, unused, m_injectionBGAlarmLevels[0], m_injectionBGAlarmLevels[1]);
1260 requestLimitsFromEpicsPVs("timingAlarmLevels", unused, unused, m_timingAlarmLevels[0], m_timingAlarmLevels[1]);
1261 requestLimitsFromEpicsPVs("eventT0MeanAlarmLevels", unused, unused, m_eventT0MeanAlarmLevels[0], m_eventT0MeanAlarmLevels[1]);
1262 requestLimitsFromEpicsPVs("eventT0RmsAlarmLevels", unused, unused, m_eventT0RmsAlarmLevels[0], m_eventT0RmsAlarmLevels[1]);
1263 requestLimitsFromEpicsPVs("offsetMeanAlarmLevels", unused, unused, m_offsetMeanAlarmLevels[0], m_offsetMeanAlarmLevels[1]);
1264 requestLimitsFromEpicsPVs("offsetRmsAlarmLevels", unused, unused, m_offsetRmsAlarmLevels[0], m_offsetRmsAlarmLevels[1]);
1265
1266 setAlarmLines();
1267
1268 bool status = false;
1269 std::string excludedBS = getEpicsStringPV("excludedBoardstacks", status);
1270
1271 if (status) {
1272 m_excludedBoardstacks.clear();
1273 std::string name;
1274 for (auto c : excludedBS) {
1275 if (isspace(c)) continue;
1276 else if (ispunct(c)) {
1277 if (not name.empty()) {
1278 m_excludedBoardstacks.push_back(name);
1279 name.clear();
1280 }
1281 } else name.push_back(c);
1282 }
1283 if (not name.empty()) {
1284 m_excludedBoardstacks.push_back(name);
1285 }
1287 }
1288
1289 B2DEBUG(20, "asicWindowsBand: [" << m_asicWindowsBand[0] << ", " << m_asicWindowsBand[1] << "]");
1290 B2DEBUG(20, "asicWindowsAlarmLevels: [" << m_asicWindowsAlarmLevels[0] << ", " << m_asicWindowsAlarmLevels[1] << "]");
1291 B2DEBUG(20, "windowMedianAlarmLevels: [" << m_windowMedianAlarmLevels[0] << ", " << m_windowMedianAlarmLevels[1] << "]");
1292 B2DEBUG(20, "eventMonitorAlarmLevels: [" << m_eventMonitorAlarmLevels[0] << ", " << m_eventMonitorAlarmLevels[1] << "]");
1293 B2DEBUG(20, "unpackerErrAlarmLevels: [" << m_unpackerErrAlarmLevels[0] << ", " << m_unpackerErrAlarmLevels[1] << "]");
1294 B2DEBUG(20, "junkHitsAlarmLevels: [" << m_junkHitsAlarmLevels[0] << ", " << m_junkHitsAlarmLevels[1] << "]");
1295 B2DEBUG(20, "deadChannelsAlarmLevels: [" << m_deadChannelsAlarmLevels[0] << ", " << m_deadChannelsAlarmLevels[1] << "]");
1296 B2DEBUG(20, "backgroundAlarmLevels: [" << m_backgroundAlarmLevels[0] << ", " << m_backgroundAlarmLevels[1] << "]");
1297 B2DEBUG(20, "photonYieldsAlarmLevels: [" << m_photonYieldsAlarmLevels[0] << ", " << m_photonYieldsAlarmLevels[1] << "]");
1298
1299 B2DEBUG(20, "injectionBGAlarmLevels: [" << m_injectionBGAlarmLevels[0] << ", " << m_injectionBGAlarmLevels[1] << "]");
1300 B2DEBUG(20, "timingAlarmLevels: [" << m_timingAlarmLevels[0] << ", " << m_timingAlarmLevels[1] << "]");
1301 B2DEBUG(20, "eventT0MeanAlarmLevels: [" << m_eventT0MeanAlarmLevels[0] << ", " << m_eventT0MeanAlarmLevels[1] << "]");
1302 B2DEBUG(20, "eventT0RmsAlarmLevels: [" << m_eventT0RmsAlarmLevels[0] << ", " << m_eventT0RmsAlarmLevels[1] << "]");
1303 B2DEBUG(20, "offsetMeanAlarmLevels: [" << m_offsetMeanAlarmLevels[0] << ", " << m_offsetMeanAlarmLevels[1] << "]");
1304 B2DEBUG(20, "offsetRmsAlarmLevels: [" << m_offsetRmsAlarmLevels[0] << ", " << m_offsetRmsAlarmLevels[1] << "]");
1305
1306 std::string ss;
1307 for (const auto& s : m_excludedBoardstacks) ss += "'" + s + "', ";
1308 if (ss.size() > 2) {ss.pop_back(); ss.pop_back();}
1309 B2DEBUG(20, "excludedBoardstacks: [" << ss << "]");
1310
1311}
1312
1313void DQMHistAnalysisTOPModule::setIncludedBoardstacks(const std::vector<std::string>& excludedBoardstacks)
1314{
1315 m_includedBoardstacks.clear();
1316 m_includedBoardstacks.resize(64, true);
1317
1318 for (const auto& bsname : excludedBoardstacks) {
1319 int id = m_bsmap[bsname];
1320 if (id > 0) m_includedBoardstacks[id - 1] = false;
1321 else B2ERROR("Invalid boardstack name: " << bsname);
1322 }
1323}
1324
1325void DQMHistAnalysisTOPModule::setGridX(const std::string& cname)
1326{
1327 auto* canvas = findCanvas(cname);
1328 if (not canvas) return;
1329 canvas->SetGridx();
1330 canvas->Modified();
1331}
static TCanvas * findCanvas(TString cname)
Find canvas by name.
static TH1 * findRefHist(const std::string &histname, ERefScaling scaling=ERefScaling::c_RefScaleNone, const TH1 *hist=nullptr)
Get referencehistogram from list (no other search).
int registerEpicsPV(const std::string &pvname, const std::string &keyname="")
EPICS related Functions.
static MonitoringObject * getMonitoringObject(const std::string &name)
Get MonitoringObject with given name (new object is created if non-existing)
static TH1 * findHist(const std::string &histname, bool onlyIfUpdated=false)
Get histogram from list (no other search).
DQMHistAnalysisModule()
Constructor / Destructor.
std::string getEpicsStringPV(const std::string &keyname, bool &status)
Read value from a EPICS PV.
bool requestLimitsFromEpicsPVs(chid id, double &lowerAlarm, double &lowerWarn, double &upperWarn, double &upperAlarm)
Get Alarm Limits from EPICS PV.
void setEpicsPV(const std::string &keyname, double value)
Write value to a EPICS PV.
void updateEventMonitorCanvas()
Updates canvas of event desynchronization monitor w/ alarming.
TCanvas * m_c_evtMonitorFract
Canvas: fractions of de-synchronized hits.
TH1D * m_skipProcFlagFract
fraction of events w/ skip processing flag set vs.
std::vector< int > m_asicWindowsBand
lower and upper bin of a band denoting good windows
void updateWindowMedianCanvas()
Updates canvas of window_vs_slot median w/ alarming.
static void setZAxisRange(const std::string &name, double scale)
Sets z-axis range of 2D histograms.
TCanvas * m_c_photonYields
Canvas: photon yields per slot.
std::vector< double > m_offsetRmsAlarmLevels
alarm levels for r.m.s.
void initialize() override final
Initializer.
void makePMTHitRatesPlots()
Makes plots of the number of PMT hits per event.
TH1F * m_excludedFraction
fraction of dead and hot channels per slot in excluded boardstacks only
void updateEventT0Canvas()
Updates canvas of event T0 w/ alarming.
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.
static void makeBGSubtractedTimingPlot(const std::string &name, const TH2F *trackHits, int slot)
Makes background subtracted time distribution plot.
void updateTimingCanvas()
Updates canvas of timing plot w/ alarming.
void updateUnpackerErrCanvas()
Updates canvas of unpacker errors w/ alarming.
TPaveText * m_text3
text to be written to background rates
std::vector< TLine * > m_deadChannelsAlarmLines
lines representing alarm levels
std::vector< TCanvas * > m_c_pmtHitRates
Canvases of PMT hits per event (index = slot - 1)
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
static std::pair< double, double > getDeadAndHotCuts(const TH1 *h)
Returns cut levels for dead and hot channels.
std::vector< double > m_offsetMeanAlarmLevels
alarm levels for mean of bunch offset [ns]
std::vector< bool > m_includedBoardstacks
boardstacks included in alarming
TH1D * m_evtMonitorFract
fractions of de-synchronized hits
static bool sameHistDefinition(TH1 *h1, TH1 *h2)
Checks if histograms are defined in the same way (nbins, xmin, xmax)
TPaveText * m_text4
text to be written to number of good hits per event
std::string m_pvPrefix
Epics PV prefix.
TH1D * m_photonYields
photon yields per slot
TH1D * m_backgroundRates
background rates per slot
TCanvas * m_c_windowMedian
Canvas: window_vs_slot medians.
MonitoringObject * m_monObj
MiraBelle monitoring object.
TCanvas * m_c_backgroundRates
Canvas: background rates per slot.
std::map< std::string, TCanvas * > m_c_injBGs
Canvases for projections of injection BG histograms.
std::vector< double > m_eventMonitorAlarmLevels
alarm levels for fraction of desynchronized digits
static void makeFlagFractPlot(const std::string &hname, TH1 *histogram, TCanvas *canvas)
Makes a plot of fraction of events with the flag is set.
void terminate() override final
This method is called at the end of the event processing.
std::map< std::string, double > m_mirabelleVariables
variables for MiraBelle
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.
std::vector< double > m_eventT0MeanAlarmLevels
alarm levels for mean of event T0 [ns]
void event() override final
This method is called for each event.
void makeInjectionBGPlots()
Makes projections of injection BG plots.
static void setGridX(const std::string &canvasName)
Sets grid x on the canvas.
std::vector< double > m_photonYieldsAlarmLevels
alarm levels for the number of photons per track
TCanvas * m_c_skipProcFlagFract
Canvas: fraction of events w/ skip processing flag set vs.
TCanvas * m_c_injVetoFlagFract
Canvas: fraction of events w/ injection veto flag set vs.
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.
std::vector< double > m_injectionBGAlarmLevels
alarm levels for injection background (in % of events)
TH1F * m_deadFraction
fraction of dead channels per slot (included boardstacks only)
double m_averageRate
average BG rate (to pass to EpicsPV)
TH1F * m_hotFraction
fraction of hot channels per slot (included boardstacks only)
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
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.
TH1F * m_windowMedian
window_vs_slot medians
std::vector< double > m_eventT0RmsAlarmLevels
alarm levels for r.m.s.
std::vector< TLine * > m_asicWindowsBandLines
lines denoting a band of good windows
void makeJunkFractionPlot()
Makes a plot of fractions of junk hits per boardstack.
std::vector< double > m_windowMedianAlarmLevels
alarm levels for window_vs_slot medians
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
std::vector< double > m_unpackerErrAlarmLevels
alarm levels for the fraction of unpacker errors
void updateWindowVsSlotCanvas()
Updates canvas of window_vs_slot w/ alarming.
TH1D * m_injVetoFlagFract
fraction of events w/ injection veto flag set vs.
double m_numEvents
number of events processed with TOPDQM module
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]
std::map< std::string, TH1D * > m_projections
projections of injection BG
void updateBunchOffsetCanvas()
Updates canvas of bunch offset w/ alarming.
void setEpicsVariables()
Calculates and sets epics variables.
std::vector< double > m_junkHitsAlarmLevels
alarm levels for the fraction of junk hits
bool m_IsNullRun
Run type flag for null runs.
void updateNGoodHitsCanvas()
Updates canvas of number of good hits per event w/ alarming (injection BG)
TLine * m_injBGCutLine
a line denoting the cut on the number of hits for injection BG counting
std::vector< double > m_timingAlarmLevels
alarm levels for time distribution (fraction of area difference)
int getOffcialAlarmStatus(unsigned alarmState) const
Converts alarm state to official status (see EStatus of the base class)
std::vector< TH1F * > m_pmtHitRates
histograms of PMT hits per event (index = slot - 1)
TH1F * m_excludedBSHisto
histogram to show excluded boardstacks on junk fraction plot
std::map< std::string, TProfile * > m_profiles
profiles of injection BG
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 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
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Abstract base class for different kinds of events.
STL namespace.