Belle II Software development
DQMHistAnalysis.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// File : DQMHistAnalysisModule.cc
10// Description : Baseclass for DQM histogram analysis module
11//-
12
13#include <dqm/core/DQMHistAnalysis.h>
14#include <boost/algorithm/string.hpp>
15#include <TROOT.h>
16#include <TClass.h>
17
18using namespace std;
19using namespace Belle2;
20
21//-----------------------------------------------------------------
22// Register the Module
23//-----------------------------------------------------------------
24REG_MODULE(DQMHistAnalysis);
25
26//-----------------------------------------------------------------
27// Implementation
28//-----------------------------------------------------------------
29
35#ifdef _BELLE2_EPICS
36std::vector <chid> DQMHistAnalysisModule::m_epicsChID;
37#endif
38
39bool DQMHistAnalysisModule::m_useEpics = false; // default to false, to enable EPICS, add special EPICS Module class into chain
41 false; // special for second "online" use (reading limits). default to false, to enable EPICS, add special EPICS Module parameter
42std::string DQMHistAnalysisModule::m_PVPrefix = "TEST:"; // default to "TEST:", for production, set in EPICS enabler to e.g. "DQM:"
43
45{
46 //Set module properties
47 setDescription("Histogram Analysis module base class");
48}
49
51{
52 s_histList.clear();
53 s_refList.clear();
54// s_monObjList;
55 s_deltaList.clear();
56 s_canvasUpdatedList.clear();
57}
58
59bool DQMHistAnalysisModule::addHist(const std::string& dirname, const std::string& histname, TH1* h)
60{
61 std::string fullname;
62 if (dirname.size() > 0) {
63 fullname = dirname + "/" + histname;
64 } else {
65 fullname = histname;
66 }
67
68 if (s_histList[fullname].update(h)) {
69 // only if histogram changed, check if delta histogram update needed
70 auto it = s_deltaList.find(fullname);
71 if (it != s_deltaList.end()) {
72 B2DEBUG(20, "Found Delta" << fullname);
73 it->second.update(h); // update
74 }
75 return true; // histogram changed
76 }
77
78 return false; // histogram didn't change
79}
80
81void DQMHistAnalysisModule::addRefHist(const std::string& dirname, TH1* hist)
82{
83 string histname = hist->GetName();
84 std::string name = dirname + "/" + histname;
85 auto& n = s_refList[name];
86 n.m_orghist_name = name;
87 n.m_refhist_name = "ref/" + name;
88 hist->SetName((n.m_refhist_name).c_str());
89 hist->SetDirectory(0);
90 n.setRefHist(hist); // transfer ownership!
91 n.setRefCopy(nullptr);
92}
93
94void DQMHistAnalysisModule::addDeltaPar(const std::string& dirname, const std::string& histname, HistDelta::EDeltaType t, int p,
95 unsigned int a)
96{
97 std::string fullname;
98 if (dirname.size() > 0) {
99 fullname = dirname + "/" + histname;
100 } else {
101 fullname = histname;
102 }
103 s_deltaList[fullname].set(t, p, a);
104}
105
106bool DQMHistAnalysisModule::hasDeltaPar(const std::string& dirname, const std::string& histname)
107{
108 std::string fullname;
109 if (dirname.size() > 0) {
110 fullname = dirname + "/" + histname;
111 } else {
112 fullname = histname;
113 }
114 return s_deltaList.find(fullname) != s_deltaList.end(); // contains() if we switch to C++20
115}
116
117TH1* DQMHistAnalysisModule::getDelta(const std::string& dirname, const std::string& histname, int n, bool onlyIfUpdated)
118{
119 std::string fullname = dirname + "/" + histname;
120 if (dirname.size() == 0) fullname = histname; // assume contains dirname
121 if (histname.size() == 0) fullname = dirname; // assume contains histname
122
123 auto it = s_deltaList.find(fullname);
124 if (it != s_deltaList.end()) {
125 return it->second.getDelta(n, onlyIfUpdated);
126 }
127 B2WARNING("Delta hist " << fullname << " not found");
128 return nullptr;
129}
130
132{
133 auto obj = &s_monObjList[objName];
134 obj->SetName(objName.c_str());
135 return obj;
136}
137
138TCanvas* DQMHistAnalysisModule::findCanvas(TString canvas_name)
139{
140 TIter nextkey(gROOT->GetListOfCanvases());
141 TObject* obj{};
142
143 while ((obj = dynamic_cast<TObject*>(nextkey()))) {
144 if (obj->IsA()->InheritsFrom("TCanvas")) {
145 if (obj->GetName() == canvas_name)
146 return dynamic_cast<TCanvas*>(obj);
147 }
148 }
149 return nullptr;
150}
151
152
153TH1* DQMHistAnalysisModule::findHist(const std::string& dirname, const std::string& histname, bool was_updated)
154{
155 std::string fullname = dirname + "/" + histname;
156 if (dirname.size() == 0) fullname = histname; // assume contains dirname
157 if (histname.size() == 0) fullname = dirname; // assume contains histname
158
159 if (s_histList.find(fullname) != s_histList.end()) {
160 if (was_updated && !s_histList[fullname].isUpdated()) return nullptr;
161 if (s_histList[fullname].getHist()) {
162 return s_histList[fullname].getHist();
163 } else {
164 B2ERROR("Histogram " << fullname << " in histogram list but nullptr.");
165 }
166 }
167 B2INFO("Histogram " << fullname << " not in list.");
168 return nullptr;
169}
170
171TH1* DQMHistAnalysisModule::scaleReference(ERefScaling scaling, const TH1* hist, TH1* ref)
172{
173 // if hist/ref is nullptr, nothing to do
174 if (!hist || !ref)
175 return ref;
176
177 switch (scaling) {
178 // default: do nothing
179 case ERefScaling::c_RefScaleNone: //do nothing
180 break;
181 case ERefScaling::c_RefScaleEntries: // Integral
182 // only if we have entries in reference
183 if (hist->Integral() != 0 and ref->Integral() != 0) {
184 ref->Scale(hist->Integral() / ref->Integral());
185 }
186 break;
187 case ERefScaling::c_RefScaleMax: // Maximum
188 // only if we have entries in reference
189 if (hist->GetMaximum() != 0 and ref->GetMaximum() != 0) {
190 ref->Scale(hist->GetMaximum() / ref->GetMaximum());
191 }
192 break;
193 }
194 return ref;
195}
196
197TH1* DQMHistAnalysisModule::findRefHist(const std::string& dirname, const std::string& histname, ERefScaling scaling,
198 const TH1* hist)
199{
200 std::string fullname = dirname + "/" + histname;
201 if (dirname.size() == 0) fullname = histname; // assume contains dirname
202 if (histname.size() == 0) fullname = dirname; // assume contains histname
203
204 if (s_refList.find(fullname) != s_refList.end()) {
205 // get a copy of the reference which we can modify
206 // (it is still owned and managed by the framework)
207 // then do the scaling
208 return scaleReference(scaling, hist, s_refList[fullname].getReference());
209 }
210 return nullptr;
211}
212
213TH1* DQMHistAnalysisModule::findHistInCanvas(const std::string& histo_name, TCanvas** cobj)
214{
215 TCanvas* cnv = nullptr;
216 // try to get canvas from outside
217 if (cobj) cnv = *cobj;
218 // if no canvas search for it
219 if (cnv == nullptr) {
220 // parse the dir+histo name and create the corresponding canvas name
221 auto s = StringSplit(histo_name, '/');
222 if (s.size() != 2) {
223 B2ERROR("findHistInCanvas: histoname not valid (missing dir?), should be 'dirname/histname': " << histo_name);
224 return nullptr;
225 }
226 auto dirname = s.at(0);
227 auto hname = s.at(1);
228 std::string canvas_name = dirname + "/c_" + hname;
229 cnv = findCanvas(canvas_name);
230 // set canvas pointer for outside
231 if (cnv && cobj) *cobj = cnv;
232 }
233
234 // get histogram pointer
235 if (cnv != nullptr) {
236 TIter nextkey(cnv->GetListOfPrimitives());
237 TObject* obj{};
238 while ((obj = dynamic_cast<TObject*>(nextkey()))) {
239 if (obj->IsA()->InheritsFrom("TH1")) {
240 if (obj->GetName() == histo_name)
241 return dynamic_cast<TH1*>(obj);
242 }
243 }
244 }
245 return nullptr;
246}
247
248TH1* DQMHistAnalysisModule::findHistInFile(TFile* file, const std::string& histname)
249{
250 // find histogram by name in file, histname CAN contain directory!
251 // will return nullptr if file is zeroptr, not found or not correct type
252 if (file && file->IsOpen()) {
253 auto obj = file->Get(histname.data());
254 if (obj != nullptr) {
255 // check class type
256 if (obj->IsA()->InheritsFrom("TH1")) {
257 B2DEBUG(20, "Histogram " << histname << " found in file");
258 return dynamic_cast<TH1*>(obj);
259 } else {
260 B2INFO("Found Object " << histname << " in file is not a histogram");
261 }
262 } else {
263 B2INFO("Histogram " << histname << " not found in file");
264 }
265 }
266 return nullptr;
267}
268
270{
271 if (s_monObjList.find(objName) != s_monObjList.end()) {
272 return &s_monObjList[objName];
273 }
274 B2INFO("MonitoringObject " << objName << " not in memfile.");
275 return nullptr;
276}
277
279{
280 double probs[2] = {0.16, 1 - 0.16};
281 double quant[2] = {0, 0};
282 h->GetQuantiles(2, quant, probs);
283 const double sigma68 = (-quant[0] + quant[1]) / 2;
284 return sigma68;
285}
286
287std::vector <std::string> DQMHistAnalysisModule::StringSplit(const std::string& in, const char delim)
288{
289 std::vector <std::string> out;
290 boost::split(out, in, [delim](char c) {return c == delim;});
291 return out;
292}
293
295{
296 TIter nextckey(gROOT->GetListOfCanvases());
297 TObject* cobj = nullptr;
298
299 while ((cobj = dynamic_cast<TObject*>(nextckey()))) {
300 if (cobj->IsA()->InheritsFrom("TCanvas")) {
301 TCanvas* cnv = dynamic_cast<TCanvas*>(cobj);
302 cnv->Clear();
304 }
305 }
306}
307
309{
310 for (auto& it : s_histList) {
311 // attention, we must use reference, otherwise we work on a copy
312 it.second.resetBeforeEvent();
313 }
314 for (auto& it : s_deltaList) {
315 // attention, we must use reference, otherwise we work on a copy
316 it.second.setNotUpdated();
317 }
318
319 s_canvasUpdatedList.clear();
320}
321
323{
324 s_histList.clear();
325}
326
328{
329 s_refList.clear();
330}
331
333{
334 for (auto& d : s_deltaList) {
335 d.second.reset();
336 }
337}
338
339void DQMHistAnalysisModule::UpdateCanvas(const std::string& name, bool updated)
340{
341 s_canvasUpdatedList[name] = updated;
342}
343
344void DQMHistAnalysisModule::UpdateCanvas(TCanvas* c, bool updated)
345{
346 if (c) UpdateCanvas(c->GetName(), updated);
347}
348
349void DQMHistAnalysisModule::ExtractRunType(std::vector <TH1*>& hs)
350{
351 s_runType = "";
352 for (size_t i = 0; i < hs.size(); i++) {
353 if (hs[i]->GetName() == std::string("DQMInfo/rtype")) {
354 s_runType = hs[i]->GetTitle();
355 return;
356 }
357 }
358 B2ERROR("ExtractRunType: Histogram \"DQMInfo/rtype\" missing");
359}
360
361void DQMHistAnalysisModule::ExtractNEvent(std::vector <TH1*>& hs)
362{
364 for (size_t i = 0; i < hs.size(); i++) {
365 if (hs[i]->GetName() == std::string("DAQ/Nevent")) {
366 s_eventProcessed = hs[i]->GetEntries();
367 return;
368 }
369 }
370 B2ERROR("ExtractEvent: Histogram \"DAQ/Nevent\" missing");
371}
372
373int DQMHistAnalysisModule::registerEpicsPV(const std::string& pvname, const std::string& keyname)
374{
375 return registerEpicsPVwithPrefix(m_PVPrefix, pvname, keyname);
376}
377
378int DQMHistAnalysisModule::registerExternalEpicsPV(const std::string& pvname, const std::string& keyname)
379{
380 return registerEpicsPVwithPrefix(std::string(""), pvname, keyname);
381}
382
383int DQMHistAnalysisModule::registerEpicsPVwithPrefix(const std::string& prefix, const std::string& pvname,
384 const std::string& keyname)
385{
386 if (!m_useEpics) return -1;
387#ifdef _BELLE2_EPICS
388 if (m_epicsNameToChID[pvname] != nullptr) {
389 B2ERROR("Epics PV " << pvname << " already registered!");
390 return -1;
391 }
392 if (keyname != "" && m_epicsNameToChID[keyname] != nullptr) {
393 B2ERROR("Epics PV with key " << keyname << " already registered!");
394 return -1;
395 }
396
397 m_epicsChID.emplace_back();
398 auto ptr = &m_epicsChID.back();
399 if (!ca_current_context()) SEVCHK(ca_context_create(ca_disable_preemptive_callback), "ca_context_create");
400 // the subscribed name includes the prefix, the map below does *not*
401 CheckEpicsError(ca_create_channel((prefix + pvname).data(), NULL, NULL, 10, ptr), "ca_create_channel failure", pvname);
402
403 m_epicsNameToChID[pvname] = *ptr;
404 if (keyname != "") m_epicsNameToChID[keyname] = *ptr;
405 return m_epicsChID.size() - 1; // return index to last added item
406#else
407 return -1;
408#endif
409}
410
411void DQMHistAnalysisModule::setEpicsPV(const std::string& keyname, double value)
412{
413 if (!m_useEpics || m_epicsReadOnly) return;
414#ifdef _BELLE2_EPICS
415 if (m_epicsNameToChID[keyname] == nullptr) {
416 B2ERROR("Epics PV " << keyname << " not registered!");
417 return;
418 }
419 CheckEpicsError(ca_put(DBR_DOUBLE, m_epicsNameToChID[keyname], &value), "ca_set failure", keyname);
420#endif
421}
422
423void DQMHistAnalysisModule::setEpicsPV(const std::string& keyname, int value)
424{
425 if (!m_useEpics || m_epicsReadOnly) return;
426#ifdef _BELLE2_EPICS
427 if (m_epicsNameToChID[keyname] == nullptr) {
428 B2ERROR("Epics PV " << keyname << " not registered!");
429 return;
430 }
431 CheckEpicsError(ca_put(DBR_SHORT, m_epicsNameToChID[keyname], &value), "ca_set failure", keyname);
432#endif
433}
434
435void DQMHistAnalysisModule::setEpicsStringPV(const std::string& keyname, const std::string& value)
436{
437 if (!m_useEpics || m_epicsReadOnly) return;
438#ifdef _BELLE2_EPICS
439 if (m_epicsNameToChID[keyname] == nullptr) {
440 B2ERROR("Epics PV " << keyname << " not registered!");
441 return;
442 }
443 if (value.length() > 40) {
444 B2ERROR("Epics string PV " << keyname << " too long (>40 characters)!");
445 return;
446 }
447 char text[40];
448 strcpy(text, value.c_str());
449 CheckEpicsError(ca_put(DBR_STRING, m_epicsNameToChID[keyname], text), "ca_set failure", keyname);
450#endif
451}
452
453void DQMHistAnalysisModule::setEpicsPV(int index, double value)
454{
455 if (!m_useEpics || m_epicsReadOnly) return;
456#ifdef _BELLE2_EPICS
457 if (index < 0 || index >= (int)m_epicsChID.size()) {
458 B2ERROR("Epics PV with " << index << " not registered!");
459 return;
460 }
461 CheckEpicsError(ca_put(DBR_DOUBLE, m_epicsChID[index], &value), "ca_set failure", m_epicsChID[index]);
462#endif
463}
464
465void DQMHistAnalysisModule::setEpicsPV(int index, int value)
466{
467 if (!m_useEpics || m_epicsReadOnly) return;
468#ifdef _BELLE2_EPICS
469 if (index < 0 || index >= (int)m_epicsChID.size()) {
470 B2ERROR("Epics PV with " << index << " not registered!");
471 return;
472 }
473 CheckEpicsError(ca_put(DBR_SHORT, m_epicsChID[index], &value), "ca_set failure", m_epicsChID[index]);
474#endif
475}
476
477void DQMHistAnalysisModule::setEpicsStringPV(int index, const std::string& value)
478{
479 if (!m_useEpics || m_epicsReadOnly) return;
480#ifdef _BELLE2_EPICS
481 if (index < 0 || index >= (int)m_epicsChID.size()) {
482 B2ERROR("Epics PV with " << index << " not registered!");
483 return;
484 }
485 char text[41];
486 strncpy(text, value.c_str(), 40);
487 text[40] = 0;
488 CheckEpicsError(ca_put(DBR_STRING, m_epicsChID[index], text), "ca_set failure", m_epicsChID[index]);
489#endif
490}
491
492double DQMHistAnalysisModule::getEpicsPV(const std::string& keyname)
493{
494 double value{NAN};
495 if (!m_useEpics) return value;
496#ifdef _BELLE2_EPICS
497 if (m_epicsNameToChID[keyname] == nullptr) {
498 B2ERROR("Epics PV " << keyname << " not registered!");
499 return value;
500 }
501 // From EPICS doc. When ca_get or ca_array_get are invoked the returned channel value can't be assumed to be stable
502 // in the application supplied buffer until after ECA_NORMAL is returned from ca_pend_io. If a connection is lost
503 // outstanding get requests are not automatically reissued following reconnect.
504 auto r = ca_get(DBR_DOUBLE, m_epicsNameToChID[keyname], &value);
505 if (r == ECA_NORMAL) r = ca_pend_io(5.0); // this is needed!
506 if (r == ECA_NORMAL) {
507 return value;
508 } else {
509 CheckEpicsError(r, "Read PV failed in ca_get or ca_pend_io failure", keyname);
510 }
511#endif
512 return NAN;
513}
514
516{
517 double value{NAN};
518 if (!m_useEpics) return value;
519#ifdef _BELLE2_EPICS
520 if (index < 0 || index >= (int)m_epicsChID.size()) {
521 B2ERROR("Epics PV with " << index << " not registered!");
522 return value;
523 }
524 // From EPICS doc. When ca_get or ca_array_get are invoked the returned channel value can't be assumed to be stable
525 // in the application supplied buffer until after ECA_NORMAL is returned from ca_pend_io. If a connection is lost
526 // outstanding get requests are not automatically reissued following reconnect.
527 auto r = ca_get(DBR_DOUBLE, m_epicsChID[index], &value);
528 if (r == ECA_NORMAL) r = ca_pend_io(5.0); // this is needed!
529 if (r == ECA_NORMAL) {
530 return value;
531 } else {
532 CheckEpicsError(r, "Read PV failed in ca_get or ca_pend_io failure", m_epicsChID[index]);
533 }
534#endif
535 return NAN;
536}
537
538std::string DQMHistAnalysisModule::getEpicsStringPV(const std::string& keyname, bool& status)
539{
540 status = false;
541 char value[40] = "";
542 if (!m_useEpics) return std::string(value);
543#ifdef _BELLE2_EPICS
544 if (m_epicsNameToChID[keyname] == nullptr) {
545 B2ERROR("Epics PV " << keyname << " not registered!");
546 return std::string(value);
547 }
548 // From EPICS doc. When ca_get or ca_array_get are invoked the returned channel value can't be assumed to be stable
549 // in the application supplied buffer until after ECA_NORMAL is returned from ca_pend_io. If a connection is lost
550 // outstanding get requests are not automatically reissued following reconnect.
551 auto r = ca_get(DBR_STRING, m_epicsNameToChID[keyname], value);
552 if (r == ECA_NORMAL) r = ca_pend_io(5.0); // this is needed!
553 if (r == ECA_NORMAL) {
554 status = true;
555 return std::string(value);
556 } else {
557 CheckEpicsError(r, "Read PV (string) failed in ca_get or ca_pend_io failure", keyname);
558 }
559#endif
560 return std::string(value);
561}
562
563std::string DQMHistAnalysisModule::getEpicsStringPV(int index, bool& status)
564{
565 status = false;
566 char value[40] = "";
567 if (!m_useEpics) return std::string(value);
568#ifdef _BELLE2_EPICS
569 if (index < 0 || index >= (int)m_epicsChID.size()) {
570 B2ERROR("Epics PV with " << index << " not registered!");
571 return std::string(value);
572 }
573 // From EPICS doc. When ca_get or ca_array_get are invoked the returned channel value can't be assumed to be stable
574 // in the application supplied buffer until after ECA_NORMAL is returned from ca_pend_io. If a connection is lost
575 // outstanding get requests are not automatically reissued following reconnect.
576 auto r = ca_get(DBR_STRING, m_epicsChID[index], value);
577 if (r == ECA_NORMAL) r = ca_pend_io(5.0); // this is needed!
578 if (r == ECA_NORMAL) {
579 status = true;
580 return std::string(value);
581 } else {
582 CheckEpicsError(r, "Read PV (string) failed in ca_get or ca_pend_io failure", m_epicsChID[index]);
583 }
584#endif
585 return std::string(value);
586}
587
588chid DQMHistAnalysisModule::getEpicsPVChID(const std::string& keyname)
589{
590#ifdef _BELLE2_EPICS
591 if (m_useEpics) {
592 if (m_epicsNameToChID[keyname] != nullptr) {
593 return m_epicsNameToChID[keyname];
594 } else {
595 B2ERROR("Epics PV " << keyname << " not registered!");
596 }
597 }
598#endif
599 return nullptr;
600}
601
603{
604#ifdef _BELLE2_EPICS
605 if (m_useEpics) {
606 if (index >= 0 && index < (int)m_epicsChID.size()) {
607 return m_epicsChID[index];
608 } else {
609 B2ERROR("Epics PV with " << index << " not registered!");
610 }
611 }
612#endif
613 return nullptr;
614}
615
617{
618 int state = ECA_NORMAL;
619 if (!m_useEpics) return state;
620#ifdef _BELLE2_EPICS
621 if (wait > 0.) {
622 state = ca_pend_io(wait);
623 SEVCHK(state, "ca_pend_io failure");
624 }
625#endif
626 return state;
627}
628
630{
631 // this should be called in terminate function of analysis modules
632#ifdef _BELLE2_EPICS
633 if (getUseEpics()) {
634 for (auto& it : m_epicsChID) CheckEpicsError(ca_clear_channel(it), "ca_clear_channel failure", it);
635 updateEpicsPVs(5.0);
636 // Make sure we clean up both afterwards!
637 m_epicsChID.clear();
638 m_epicsNameToChID.clear();
639 }
640#endif
641}
642
643bool DQMHistAnalysisModule::requestLimitsFromEpicsPVs(const std::string& name, double& lowerAlarm, double& lowerWarn,
644 double& upperWarn, double& upperAlarm)
645{
646 return requestLimitsFromEpicsPVs(getEpicsPVChID(name), lowerAlarm, lowerWarn, upperWarn, upperAlarm);
647}
648
649bool DQMHistAnalysisModule::requestLimitsFromEpicsPVs(int index, double& lowerAlarm, double& lowerWarn, double& upperWarn,
650 double& upperAlarm)
651{
652 return requestLimitsFromEpicsPVs(getEpicsPVChID(index), lowerAlarm, lowerWarn, upperWarn, upperAlarm);
653}
654
655bool DQMHistAnalysisModule::requestLimitsFromEpicsPVs(chid pv, double& lowerAlarm, double& lowerWarn, double& upperWarn,
656 double& upperAlarm)
657{
658 // get warn and error limit only if pv exists
659 // overwrite only if limit is defined (not NaN)
660 // user should initialize with NaN before calling, unless
661 // some "default" values should be set otherwise
662 if (pv != nullptr) {
663 struct dbr_ctrl_double tPvData;
664 // From EPICS doc. When ca_get or ca_array_get are invoked the returned channel value can't be assumed to be stable
665 // in the application supplied buffer until after ECA_NORMAL is returned from ca_pend_io. If a connection is lost
666 // outstanding get requests are not automatically reissued following reconnect.
667 auto r = ca_get(DBR_CTRL_DOUBLE, pv, &tPvData);
668 if (r == ECA_NORMAL) r = ca_pend_io(5.0); // this is needed!
669 if (r == ECA_NORMAL) {
670 if (!std::isnan(tPvData.lower_alarm_limit)) {
671 lowerAlarm = tPvData.lower_alarm_limit;
672 }
673 if (!std::isnan(tPvData.lower_warning_limit)) {
674 lowerWarn = tPvData.lower_warning_limit;
675 }
676 if (!std::isnan(tPvData.upper_warning_limit)) {
677 upperWarn = tPvData.upper_warning_limit;
678 }
679 if (!std::isnan(tPvData.upper_alarm_limit)) {
680 upperAlarm = tPvData.upper_alarm_limit;
681 }
682 return true;
683 } else {
684 CheckEpicsError(r, "Reading PV Limits failed in ca_get or ca_pend_io failure", pv);
685 }
686 }
687 return false;
688}
689
690DQMHistAnalysisModule::EStatus DQMHistAnalysisModule::makeStatus(bool enough, bool warn_flag, bool error_flag)
691{
692 // white color is the default, if no colorize
693 if (!enough) {
694 return (c_StatusTooFew);
695 } else {
696 if (error_flag) {
697 return (c_StatusError);
698 } else if (warn_flag) {
699 return (c_StatusWarning);
700 } else {
701 return (c_StatusGood);
702 }
703 }
704
705 return (c_StatusDefault); // default, but should not be reached
706}
707
709{
710 // white color is the default, if no colorize
712 switch (stat) {
713 case c_StatusTooFew:
714 color = c_ColorTooFew; // Magenta or Gray
715 break;
716 case c_StatusDefault:
717 color = c_ColorDefault; // default no colors
718 break;
719 case c_StatusGood:
720 color = c_ColorGood; // Good
721 break;
722 case c_StatusWarning:
723 color = c_ColorWarning; // Warning
724 break;
725 case c_StatusError:
726 color = c_ColorError; // Severe
727 break;
728 default:
729 color = c_ColorDefault; // default no colors
730 break;
731 }
732 return color;
733}
734
736{
737 if (!canvas) return;
738 auto color = DQMHistAnalysisModule::getStatusColor(stat);
739
740 canvas->Pad()->SetFillColor(color);
741
742 canvas->Pad()->SetFrameFillColor(10); // White (kWhite is not used since it results in transparent!)
743 canvas->Pad()->SetFrameFillStyle(1001);// White
744 canvas->Pad()->Modified();
745 canvas->Pad()->Update();
746}
747
749{
750 B2INFO("Check PV Connections");
751
752 for (const auto& it : m_epicsChID) {
753 printPVStatus(it);
754 }
755 B2INFO("Check PVs done");
756}
757
758void DQMHistAnalysisModule::printPVStatus(chid pv, bool onlyError)
759{
760 if (pv == nullptr) {
761 B2WARNING("PV chid was nullptr");
762 return;
763 }
764 auto state = ca_state(pv);
765 switch (state) {
766 case cs_never_conn: /* valid chid, server not found or unavailable */
767 B2WARNING("Channel never connected " << ca_name(pv));
768 break;
769 case cs_prev_conn: /* valid chid, previously connected to server */
770 B2WARNING("Channel was connected, but now is not " << ca_name(pv));
771 break;
772 case cs_closed: /* channel deleted by user */
773 B2WARNING("Channel deleted already " << ca_name(pv));
774 break;
775 case cs_conn: /* valid chid, connected to server */
776 if (!onlyError) B2INFO("Channel connected and OK " << ca_name(pv));
777 break;
778 default:
779 B2WARNING("Undefined status for channel " << ca_name(pv));
780 break;
781 }
782}
783
784void DQMHistAnalysisModule::CheckEpicsError(int state, const std::string& message, const std::string& name)
785{
786 if (state != ECA_NORMAL) {
787 B2WARNING(message << ": " << name);
788 printPVStatus(m_epicsNameToChID[name], false);
789 }
790}
791
792void DQMHistAnalysisModule::CheckEpicsError(int state, const std::string& message, chid id = nullptr)
793{
794 if (state != ECA_NORMAL) {
795 std::string name;
796 if (id) name = ca_name(id);
797 B2WARNING(message << ": " << name);
798 printPVStatus(id, false);
799 }
800}
801
static MonObjList s_monObjList
The list of MonitoringObjects.
static TCanvas * findCanvas(TString cname)
Find canvas by name.
static void printPVStatus(chid pv, bool onlyError=true)
check the status of a PVs and report if disconnected or not found
static bool hasDeltaPar(const std::string &dirname, const std::string &histname)
Check if Delta histogram parameters exist for histogram.
chid getEpicsPVChID(const std::string &keyname)
Get EPICS PV Channel Id.
static bool getUseEpics(void)
Getter for EPICS usage.
std::map< std::string, HistObject > HistList
The type of list of histograms.
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)
std::map< std::string, MonitoringObject > MonObjList
The type of list of MonitoringObjects.
static TH1 * scaleReference(ERefScaling scaling, const TH1 *hist, TH1 *ref)
Using the original and reference, create scaled version.
int registerExternalEpicsPV(const std::string &pvname, const std::string &keyname="")
Register a PV with its name and a key name.
static void addDeltaPar(const std::string &dirname, const std::string &histname, HistDelta::EDeltaType t, int p, unsigned int a=1)
Add Delta histogram parameters.
static double getSigma68(TH1 *h)
Helper function to compute half of the central interval covering 68% of a distribution.
static void addRefHist(const std::string &dirname, TH1 *hist)
Add reference histogram.
static TH1 * findHistInFile(TFile *file, const std::string &histname)
Find histogram in specific TFile (e.g.
static EStatusColor getStatusColor(EStatus status)
Return color for canvas state.
static void colorizeCanvas(TCanvas *canvas, EStatus status)
Helper function for Canvas colorization.
static MonitoringObject * findMonitoringObject(const std::string &objName)
Find MonitoringObject.
static void clearlist(void)
Clear all static global lists.
EStatusColor
Status colors of histogram/canvas (corresponding to status)
@ c_ColorWarning
Analysis result: Warning, there may be minor issues.
@ c_ColorError
Analysis result: Severe issue found.
@ c_ColorTooFew
Not enough entries/event to judge.
@ c_ColorGood
Analysis result: Good.
@ c_ColorDefault
default for non-coloring
static int s_eventProcessed
Number of Events processed to fill histograms.
std::map< std::string, bool > CanvasUpdatedList
The type of list of canvas updated status.
static void UpdateCanvas(const std::string &name, bool updated=true)
Mark canvas as updated (or not)
static HistList s_histList
The list of Histograms.
static RefList s_refList
The list of references.
static void ExtractNEvent(std::vector< TH1 * > &hs)
Extract event processed from daq histogram, called from input module.
static std::string s_runType
The Run type.
static void clearHistList(void)
Clears the list of histograms.
static std::vector< std::string > StringSplit(const std::string &s, const char delim)
Helper function for string token split.
static void clearRefList(void)
Clears the list of ref histograms.
std::map< std::string, HistDelta > DeltaList
The type of list of delta settings and histograms.
void setEpicsStringPV(const std::string &keyname, const std::string &value)
Write string to a EPICS PV.
static DeltaList s_deltaList
The list of Delta Histograms and settings.
DQMHistAnalysisModule()
Constructor / Destructor.
static void checkPVStatus(void)
Check the status of all PVs and report if disconnected or not found.
std::map< std::string, RefHistObject > RefList
The type of list of references.
static bool m_epicsReadOnly
Flag if to use EPICS in ReadOnly mode (for reading limits) do not set by yourself,...
std::string getEpicsStringPV(const std::string &keyname, bool &status)
Read value from a EPICS PV.
EStatus
Status flag of histogram/canvas.
@ c_StatusDefault
default for non-coloring
@ c_StatusTooFew
Not enough entries/event to judge.
@ c_StatusError
Analysis result: Severe issue found.
@ c_StatusWarning
Analysis result: Warning, there may be minor issues.
@ c_StatusGood
Analysis result: Good.
static bool addHist(const std::string &dirname, const std::string &histname, TH1 *h)
Add histogram.
static void ExtractRunType(std::vector< TH1 * > &hs)
Extract Run Type from histogram title, called from input module.
void CheckEpicsError(int state, const std::string &message, const std::string &name)
check the return status and check PV in case of error
TH1 * findHistInCanvas(const std::string &hname, TCanvas **canvas=nullptr)
Find histogram in corresponding canvas.
static std::string m_PVPrefix
The Prefix for EPICS PVs.
TH1 * getDelta(const std::string &dirname, const std::string &histname="", int n=0, bool onlyIfUpdated=true)
Get Delta histogram.
void cleanupEpicsPVs(void)
Unsubscribe from EPICS PVs on terminate.
static void clearCanvases(void)
Clear content of all Canvases.
ERefScaling
Reference plot scaling type.
@ c_RefScaleEntries
to number of entries (integral)
@ c_RefScaleMax
to maximum (bin entry)
static EStatus makeStatus(bool enough, bool warn_flag, bool error_flag)
Helper function to judge the status for coloring and EPICS.
static bool m_useEpics
Flag if to use EPICS do not set by yourself, use EpicsEnable module to set.
static void initHistListBeforeEvent(void)
Reset the list of histograms.
int registerEpicsPVwithPrefix(const std::string &prefix, const std::string &pvname, const std::string &keyname="")
Register a PV with its name and a key name.
double getEpicsPV(const std::string &keyname)
Read value from a EPICS PV.
static TH1 * findRefHist(const std::string &dirname, const std::string &histname="", ERefScaling scaling=ERefScaling::c_RefScaleNone, const TH1 *hist=nullptr)
Find reference histogram.
static void resetDeltaList(void)
Reset Delta.
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.
static TH1 * findHist(const std::string &dirname, const std::string &histname="", bool onlyIfUpdated=false)
Find histogram.
int updateEpicsPVs(float timeout)
Update all EPICS PV (flush to network)
static CanvasUpdatedList s_canvasUpdatedList
The list of canvas updated status.
EDeltaType
enum definition for delta algo Disabled: nothing Entries: use nr histogram entries Underflow: use ent...
Definition HistDelta.h:36
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
Module()
Constructor.
Definition Module.cc:30
MonitoringObject is a basic object to hold data for the run-dependency monitoring Run summary TCanvas...
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
Abstract base class for different kinds of events.
STL namespace.