10 #include <dqm/analysis/modules/DQMHistAnalysisECLSummary.h>
13 #include <ecl/geometry/ECLGeometryPar.h>
21 #include "boost/format.hpp"
29 m_neighbours_obj(
"F", 0.1)
32 B2DEBUG(20,
"DQMHistAnalysisECLSummary: Constructor done.");
34 std::string(
"ECL:channels_info:"));
36 "Mask Cell IDs based on information from ECL PVs",
39 "The higher this parameter, the larger differences in occupancy are allowed for adjacent channels", 0.28);
41 "The higher this parameter, the larger differences in the number of hits with bad chi2 are allowed for adjacent channels",
43 addParam(
"onlyIfUpdated",
m_onlyIfUpdated,
"If true (default), update EPICS PVs only if there histograms were updated.",
59 {
"dead",
"#splitline{dead}{channels}", 1, 1, 1e5},
60 {
"cold",
"#splitline{cold}{channels}", 1, 2, 1e5},
61 {
"hot",
"#splitline{hot}{channels}", 25, 50, 1e5},
62 {
"bad_chi2",
"#splitline{bad #chi^{2}}{channels}", 5, 10, 1e6},
63 {
"bad_fit",
"#splitline{fit incon-}{sistencies}", 5, 10, 0 },
69 for (
int crate_id = 1; crate_id <= ECL::ECL_CRATES; crate_id++) {
70 std::string pv_name = (boost::format(
"crate%02d:%s") % crate_id % alarm.name).str();
74 for (
auto& ecl_part : {
"All",
"FWDEndcap",
"Barrel",
"BWDEndcap"}) {
75 std::string pv_name = (boost::format(
"%s:%s") % ecl_part % alarm.name).str();
79 std::string mask_pv_name = (boost::format(
"mask:%s") % alarm.name).str();
88 TString title =
"#splitline{ECL errors monitoring}";
89 title +=
"{E - Error, W - Warning, L - Low statistics}";
90 title +=
";ECLCollector ID (same as Crate ID)";
92 ECL::ECL_CRATES, 1, ECL::ECL_CRATES + 1,
102 for (
int i = 1; i <= ECL::ECL_CRATES; i++) {
122 c_occupancy =
new TCanvas(
"ECL/c_cid_Thr5MeV_overlaid_analysis");
123 c_bad_chi2 =
new TCanvas(
"ECL/c_bad_quality_overlaid_analysis");
126 1, ECL::ECL_TOTAL_CHANNELS + 1);
133 1, ECL::ECL_TOTAL_CHANNELS + 1);
140 1, ECL::ECL_TOTAL_CHANNELS + 1);
147 1, ECL::ECL_TOTAL_CHANNELS + 1);
153 B2DEBUG(20,
"DQMHistAnalysisECLSummary: initialized.");
158 B2DEBUG(20,
"DQMHistAnalysisECLSummary: beginRun called.");
179 if (!h_total_events)
return;
187 const double HISTCOLOR_RED = 0.9;
188 const double HISTCOLOR_GREEN = 0.45;
189 const double HISTCOLOR_ORANGE = 0.65;
190 const double HISTCOLOR_BLUE = 0.01;
192 std::vector<TText*> labels;
194 for (
size_t alarm_idx = 0; alarm_idx < alarm_counts.size(); alarm_idx++) {
195 for (
size_t crate = 0; crate < alarm_counts[alarm_idx].size(); crate++) {
197 char label_text[2] = {0};
199 int warning_limit =
m_ecl_alarms[alarm_idx].warning_limit;
201 color = HISTCOLOR_BLUE;
203 }
else if (alarm_counts[alarm_idx][crate] >= alarm_limit) {
204 color = HISTCOLOR_RED;
206 }
else if (alarm_counts[alarm_idx][crate] >= warning_limit) {
207 color = HISTCOLOR_ORANGE;
210 color = HISTCOLOR_GREEN;
212 if (label_text[0] ==
'E' || label_text[0] ==
'W') {
213 B2DEBUG(100,
"Non-zero (" << alarm_counts[alarm_idx][crate]
214 <<
") for alarm_idx, crate = " << alarm_idx <<
", " << crate);
217 if (label_text[0] != 0) {
218 auto text =
new TText((crate + 1.5), (alarm_idx + 0.5), label_text);
219 text->SetTextColor(kWhite);
220 text->SetTextSize(0.03);
221 text->SetTextAlign(22);
222 labels.push_back(text);
230 int gstyle_title_h = gStyle->GetTitleH();
231 int gstyle_title_x = gStyle->GetTitleX();
232 int gstyle_title_y = gStyle->GetTitleY();
233 gStyle->SetTitleH(0.04);
234 gStyle->SetTitleX(0.60);
235 gStyle->SetTitleY(1.00);
249 "gStyle->SetPalette(kRainBow);"
250 "channels_summary->SetDrawOption(\"col\");");
253 "gStyle->SetPalette(kBird);");
259 for (
auto& text : labels) {
270 gStyle->SetTitleH(gstyle_title_h);
271 gStyle->SetTitleX(gstyle_title_x);
272 gStyle->SetTitleY(gstyle_title_y);
277 B2DEBUG(20,
"DQMHistAnalysisECLSummary: endRun called");
285 B2DEBUG(20,
"terminate called");
297 if (alarm_info.name == name)
return {index, alarm_info};
300 B2FATAL(
"Could not get ECL alarm " + name);
312 std::string pv_name = (boost::format(
"crate%02d:%s") % crate_id % alarm.name).str();
314 double upper_warning_limit = 0;
315 double upper_alarm_limit = 0;
318 if (!accessed || upper_alarm_limit <= 0 || upper_warning_limit <= 0) {
319 B2WARNING(
"Failed to get alarm limits");
323 alarm.alarm_limit = upper_alarm_limit;
324 alarm.warning_limit = upper_warning_limit;
330 static std::map<std::string, dbr_sts_long_array> mask_info;
332 B2WARNING(
"Failed to get arrays of masked channels");
338 m_mask[alarm.name].clear();
340 int cell_id = mask_info[alarm.name].value[i];
343 if (cell_id == 0)
break;
344 m_mask[alarm.name].insert(cell_id);
352 std::string mask_pv_name = (boost::format(
"mask:%s") % alarm.name).str();
355 if (mask_chid ==
nullptr)
return false;
359 if (r != ECA_NORMAL)
return false;
365 auto r = ca_pend_io(5.0);
366 if (r != ECA_NORMAL)
return false;
373 std::vector< std::vector<int> > alarm_counts(
374 m_ecl_alarms.size(), std::vector<int>(ECL::ECL_CRATES));
381 for (
int crate_id = 1; crate_id <= ECL::ECL_CRATES; crate_id++) {
382 int errors_count = 0;
383 if (h_fail_crateid) {
384 errors_count = h_fail_crateid->GetBinContent(crate_id);
389 alarm_counts[fit_alarm_index][crate_id - 1] += errors_count;
393 std::map<int, int> error_bitmasks;
398 error_bitmasks[cell_id] |= error_bitmask;
403 error_bitmasks[cell_id] |= error_bitmask;
408 if (!update_mirabelle) {
415 static std::vector<std::string> indices = {
"dead",
"cold",
"hot",
"bad_chi2"};
416 for (
auto& index_name : indices) {
418 int alarm_bit = 1 << alarm_index;
419 for (
auto& [cid, error_bitmask] : error_bitmasks) {
421 if ((error_bitmask & alarm_bit) == 0)
continue;
423 bool masked = (
m_mask[index_name].find(cid) !=
m_mask[index_name].end());
425 if (!masked) alarm_counts[alarm_index][crate_id - 1] += 1;
427 if (update_mirabelle)
continue;
429 if (index_name ==
"bad_chi2") {
432 }
else if (index_name ==
"dead" || index_name ==
"cold" || index_name ==
"hot") {
438 if (update_mirabelle)
continue;
441 if (index_name ==
"hot" || index_name ==
"bad_chi2") {
442 TCanvas* current_canvas;
445 TH1F* overlay_hist_green;
446 if (index_name ==
"hot") {
459 for (
auto& overlay : {overlay_hist, overlay_hist_green}) {
460 for (
int bin_id = 1; bin_id <= ECL::ECL_TOTAL_CHANNELS; bin_id++) {
461 if (overlay->GetBinContent(bin_id) == 0)
continue;
463 if (main_hist->GetBinContent(bin_id) == 0)
continue;
464 overlay->SetBinContent(bin_id, main_hist->GetBinContent(bin_id));
468 current_canvas->Clear();
469 current_canvas->cd();
470 main_hist->Draw(
"hist");
471 overlay_hist->Draw(
"hist;same");
472 overlay_hist_green->Draw(
"hist;same");
473 current_canvas->Modified();
474 current_canvas->Update();
475 current_canvas->Draw();
482 for (
size_t alarm_idx = 0; alarm_idx < alarm_counts.size(); alarm_idx++) {
484 std::map<std::string, int> total;
486 for (
size_t crate = 0; crate < alarm_counts[alarm_idx].size(); crate++) {
487 int crate_id = crate + 1;
488 int value = alarm_counts[alarm_idx][crate];
490 if (!update_mirabelle) {
491 std::string pv_name = (boost::format(
"crate%02d:%s") % crate_id % alarm.name).str();
495 total[
"All"] += value;
496 if (crate_id <= ECL::ECL_BARREL_CRATES) {
497 total[
"Barrel"] += value;
498 }
else if (crate_id <= ECL::ECL_BARREL_CRATES + ECL::ECL_FWD_CRATES) {
499 total[
"FWDEndcap"] += value;
501 total[
"BWDEndcap"] += value;
505 for (
auto& ecl_part : {
"All",
"FWDEndcap",
"Barrel",
"BWDEndcap"}) {
506 std::string pv_name = (boost::format(
"%s:%s") % ecl_part % alarm.name).str();
507 if (update_mirabelle) {
508 std::string var_name = pv_name;
509 std::replace(var_name.begin(), var_name.end(),
':',
'_');
510 B2DEBUG(100, var_name <<
" = " << total[ecl_part]);
525 static std::vector< std::vector<short> > neighbours(ECL::ECL_TOTAL_CHANNELS);
526 if (neighbours[0].size() == 0) {
527 for (
int cid0 = 0; cid0 < ECL::ECL_TOTAL_CHANNELS; cid0++) {
535 neighbours[cid0].erase(neighbours[cid0].begin());
542 max_deviation,
true);
549 static std::vector< std::vector<short> > neighbours(ECL::ECL_TOTAL_CHANNELS);
550 if (neighbours[0].size() == 0) {
551 for (
int cid_center = 1; cid_center <= ECL::ECL_TOTAL_CHANNELS; cid_center++) {
552 geom->Mapping(cid_center - 1);
553 const int theta_id_center = geom->GetThetaID();
554 int phi_id_center = geom->GetPhiID();
556 phi_id_center = phi_id_center * 144 / crystals_in_ring;
557 for (
int cid0 = 0; cid0 < 8736; cid0++) {
558 if (cid0 == cid_center - 1)
continue;
560 int theta_id = geom->GetThetaID();
561 int phi_id = geom->GetPhiID();
563 if (std::abs(theta_id - theta_id_center) <= 2 &&
564 std::abs(phi_id - phi_id_center) <= 2) {
565 neighbours[cid_center - 1].push_back(cid0);
574 max_deviation,
false);
578 TH1* hist,
double total_events,
579 const std::vector< std::vector<short> >& neighbours,
580 double max_deviation,
bool occupancy_histogram)
582 std::map<int, int> retval;
584 if (!hist)
return retval;
587 if (hist->Integral() <= 0)
return retval;
597 const auto& [chi2_index, chi2_alarm] =
getAlarmByName(
"bad_chi2");
599 double min_required_events;
601 if (occupancy_histogram) {
602 min_required_events = std::min({
603 dead_alarm.required_statistics,
604 cold_alarm.required_statistics,
605 hot_alarm.required_statistics,
608 min_required_events = chi2_alarm.required_statistics;
611 if (total_events < min_required_events)
return retval;
613 int dead_bit = 1 << dead_index;
614 int cold_bit = 1 << cold_index;
615 int hot_bit = 1 << hot_index;
616 int chi2_bit = 1 << chi2_index;
620 if (occupancy_histogram) {
622 bool not_normalized = (
findCanvas(
"ECL/c_cid_Thr5MeV_analysis") ==
nullptr);
623 if (total_events >= dead_alarm.required_statistics) {
627 double min_occupancy = 1e-6;
628 if (not_normalized) {
630 min_occupancy *= total_events;
632 for (
int cid = 1; cid <= ECL::ECL_TOTAL_CHANNELS; cid++) {
633 if (hist->GetBinContent(cid) > min_occupancy)
continue;
634 retval[cid] |= dead_bit;
637 if (total_events >= hot_alarm.required_statistics) {
639 double max_occupancy = 0.7;
640 if (not_normalized) {
642 max_occupancy *= total_events;
644 for (
int cid = 1; cid <= ECL::ECL_TOTAL_CHANNELS; cid++) {
645 if (hist->GetBinContent(cid) < max_occupancy)
continue;
646 retval[cid] |= hot_bit;
653 for (
int cid = 1; cid <= ECL::ECL_TOTAL_CHANNELS; cid++) {
654 double actual_value = hist->GetBinContent(cid);
656 std::vector<short> neighb = neighbours[cid - 1];
657 std::multiset<double> values_sorted;
658 for (
auto& neighbour_cid : neighb) {
659 values_sorted.insert(hist->GetBinContent(neighbour_cid));
662 double expected_value;
663 if (occupancy_histogram) {
665 expected_value = *std::next(values_sorted.begin(), 1 * neighb.size() / 4);
668 expected_value = *std::next(values_sorted.begin(), 35 * neighb.size() / 48);
670 double deviation = std::abs((actual_value - expected_value) /
673 if (!occupancy_histogram) {
675 double min_occupancy = 1.41e-5;
676 if (
findCanvas(
"ECL/c_bad_quality_analysis") ==
nullptr) {
678 min_occupancy *= total_events;
681 if (actual_value < min_occupancy)
continue;
684 if (deviation < max_deviation)
continue;
686 if (occupancy_histogram) {
687 if (actual_value < expected_value) retval[cid] |= cold_bit;
688 if (actual_value > 2 * expected_value) retval[cid] |= hot_bit;
690 if (actual_value > expected_value) retval[cid] |= chi2_bit;
699 int x_min = hist->GetXaxis()->GetXmin();
700 int x_max = hist->GetXaxis()->GetXmax();
701 int y_min = hist->GetYaxis()->GetXmin();
702 int y_max = hist->GetYaxis()->GetXmax();
703 for (
int x = x_min + 1; x < x_max; x++) {
704 auto l =
new TLine(x, 0, x, 5);
705 l->SetLineStyle(kDashed);
708 for (
int y = y_min + 1; y < y_max; y++) {
709 auto l =
new TLine(1, y, ECL::ECL_CRATES + 1, y);
710 l->SetLineStyle(kDashed);
std::map< int, int > getSuspiciousChannels(TH1 *hist, double total_events, const std::vector< std::vector< short > > &neighbours, double max_deviation, bool occupancy_histogram)
Get outlier channels, ones with values (occupancy, errors, etc) that are much higher than the values ...
double m_total_events
Number of events with ECL data in the current run.
double m_maxDeviationForChi2
The higher this parameter, the larger differences in the number of hits with bad chi2 are allowed for...
TH1F * h_bad_occ_overlay
Overlay to indicate bad channels on occupancy histogram.
void initialize() override final
Initialize the module.
void updateAlarmConfig()
Set alarm limits in DQM based on EPICS PV limits.
std::vector< std::vector< int > > updateAlarmCounts(bool update_mirabelle=false)
Calculate and return number of problems per crate for all alarm categories.
ECL::ECLChannelMapper m_mapper
Object to map ECL crystal ID to ECL crate ID.
void drawGrid(TH2 *hist)
Draw grid with TLine primitives for the specified histogram.
TCanvas * c_channels_summary
TCanvas for ECL alarms regarding suspicious channels.
std::map< int, int > getChannelsWithChi2Problems()
static const int c_max_masked_channels
Size of an array with masked channels.
std::pair< int, ECLAlarmType > getAlarmByName(std::string name)
Returns index of the specific alarm type and detailed information.
TH2F * h_channels_summary
Summarized information about ECL channels.
double m_maxDeviationForOccupancy
The higher this parameter, the larger differences in occupancy are allowed for adjacent channels.
ECL::ECLNeighbours m_neighbours_obj
Object to get ECL crystal neighbours.
~DQMHistAnalysisECLSummaryModule()
Destructor.
TCanvas * c_occupancy
ECL occupancy histogram with highlighted suspicious channels.
TExec * m_ecl_style
Special object to specify style parameters.
std::string m_pvPrefix
Prefix to use for PVs registered by this module.
MonitoringObject * m_monObj
MiraBelle monitoring object.
void terminate() override final
Terminate.
void event() override final
Event processor.
TCanvas * c_bad_chi2
ECL bad chi2 histogram with highlighted suspicious channels.
TH1F * h_bad_chi2_overlay
Overlay to indicate bad channels on chi2 histogram.
void endRun() override final
Call when a run ends.
bool m_onlyIfUpdated
If true (default), update EPICS PVs only if there were changes in the histograms.
std::map< int, int > getChannelsWithOccupancyProblems()
TH1F * h_bad_chi2_overlay_green
Overlay to indicate masked bad channels on chi2 histogram.
void beginRun() override final
Call when a run begins.
DQMHistAnalysisECLSummaryModule()
< derived from DQMHistAnalysisModule class.
TExec * m_default_style
Special object to revert changes done by ecl_style.
TH1F * h_bad_occ_overlay_green
Overlay to indicate masked bad channels on occupancy histogram.
std::map< std::string, std::set< int > > m_mask
List of masked Cell IDs for each alarm type.
bool getMaskedChannels(std::map< std::string, dbr_sts_long_array > &mask_info)
Get the array of masked channels for each type of alarm case monitored by this module.
bool m_useChannelMask
If true, mask Cell IDs based on DQM:ECL:channels_info:{alarm_type} PV info.
std::vector< ECLAlarmType > m_ecl_alarms
Different alarms monitored in h_channels_summary.
The base class for the histogram analysis module.
TCanvas * findCanvas(TString cname)
Find canvas by name.
int registerEpicsPV(std::string pvname, std::string keyname="", bool update_pvs=true)
EPICS related Functions.
static TH1 * findHist(const std::string &histname, bool onlyIfUpdated=false)
Get histogram from list (no other search).
void setEpicsPV(std::string keyname, double value)
Write value to a EPICS PV.
static MonitoringObject * getMonitoringObject(const std::string &histname)
Get MonitoringObject with given name (new object is created if non-existing)
chid getEpicsPVChID(std::string keyname)
Get EPICS PV Channel Id.
bool requestLimitsFromEpicsPVs(chid id, double &lowerAlarm, double &lowerWarn, double &upperWarn, double &upperAlarm)
Get Alarm Limits from EPICS PV.
int updateEpicsPVs(float timeout)
Update all EPICS PV (flush to network)
bool initFromFile()
Initialize channel mapper using data stored in default location.
int getCrateID(int iCOPPERNode, int iFINESSE, bool pcie40=false)
Get crate number by given COPPER node number and FINESSE number.
The Class for ECL Geometry Parameters.
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
const std::vector< short int > & getNeighbours(short int cid) const
Return the neighbours for a given cell ID.
short int getCrystalsPerRing(const short int thetaid) const
return number of crystals in a given theta ring
void setVariable(const std::string &var, float val, float upErr=-1., float dwErr=-1)
set value to float variable (new variable is made if not yet existing)
REG_MODULE(arichBtest)
Register the Module.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Abstract base class for different kinds of events.