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