Belle II Software  release-06-01-15
DQMHistComparitor.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 : DQMHistComparitor.cc
10 // Description : DQM Histogram analysis module, compares histo with references
11 //-
12 
13 
14 #include <framework/core/ModuleParam.templateDetails.h>
15 #include <dqm/analysis/modules/DQMHistComparitor.h>
16 #include <daq/slc/base/StringUtil.h>
17 #include <TROOT.h>
18 #include <TStyle.h>
19 #include <TClass.h>
20 #include <TDirectory.h>
21 #include <TH1F.h>
22 #include <TH2F.h>
23 #include <TKey.h>
24 
25 using namespace std;
26 using namespace Belle2;
27 
28 //-----------------------------------------------------------------
29 // Register the Module
30 //-----------------------------------------------------------------
31 REG_MODULE(DQMHistComparitor)
32 
33 //-----------------------------------------------------------------
34 // Implementation
35 //-----------------------------------------------------------------
36 
39 {
40  //Parameter definition
41  addParam("HistoList", m_histlist, "['histname', 'refhistname', 'canvas', 'minentry', 'warnlvl', 'errlvl', 'pvname'],[...],...");
42  addParam("RefHistoFile", m_refFileName, "Reference histrogram file name", std::string("refHisto.root"));
43  addParam("ColorAlert", m_color, "Whether to show the color alert", true);
44  B2DEBUG(1, "DQMHistComparitor: Constructor done.");
45 }
46 
47 DQMHistComparitorModule::~DQMHistComparitorModule()
48 {
49 #ifdef _BELLE2_EPICS
50  if (ca_current_context()) ca_context_destroy();
51 #endif
52 }
53 
54 TH1* DQMHistComparitorModule::find_histo_in_canvas(TString histo_name)
55 {
56  StringList s = StringUtil::split(histo_name.Data(), '/');
57  std::string dirname = s[0];
58  std::string hname = s[1];
59  std::string canvas_name = dirname + "/c_" + hname;
60 
61  TIter nextckey(gROOT->GetListOfCanvases());
62  TObject* cobj = NULL;
63 
64  while ((cobj = (TObject*)nextckey())) {
65  if (cobj->IsA()->InheritsFrom("TCanvas")) {
66  if (cobj->GetName() == canvas_name)
67  break;
68  }
69  }
70  if (cobj == NULL) return NULL;
71 
72  TIter nextkey(((TCanvas*)cobj)->GetListOfPrimitives());
73  TObject* obj = NULL;
74 
75  while ((obj = (TObject*)nextkey())) {
76  if (obj->IsA()->InheritsFrom("TH1")) {
77  if (obj->GetName() == histo_name)
78  return (TH1*)obj;
79  }
80  }
81  return NULL;
82 }
83 
84 TH1* DQMHistComparitorModule::GetHisto(TString histoname)
85 {
86  TH1* hh1;
87  gROOT->cd();
88  hh1 = findHist(histoname.Data());
89  if (hh1 == NULL) {
90  B2DEBUG(20, "findHisto failed " << histoname << " not in memfile");
91 
92  // first search reference root file ... if ther is one
93  if (m_refFile && m_refFile->IsOpen()) {
94  TDirectory* d = m_refFile;
95  TString myl = histoname;
96  TString tok;
97  Ssiz_t from = 0;
98  B2DEBUG(20, myl);
99  while (myl.Tokenize(tok, from, "/")) {
100  TString dummy;
101  Ssiz_t f;
102  f = from;
103  if (myl.Tokenize(dummy, f, "/")) { // check if its the last one
104  auto e = d->GetDirectory(tok);
105  if (e) {
106  B2DEBUG(20, "Cd Dir " << tok << " from " << d->GetPath());
107  d = e;
108  } else {
109  B2DEBUG(20, "cd failed " << tok << " from " << d->GetPath());
110  }
111  } else {
112  break;
113  }
114  }
115  TObject* obj = d->FindObject(tok);
116  if (obj != NULL) {
117  if (obj->IsA()->InheritsFrom("TH1")) {
118  B2DEBUG(20, "Histo " << histoname << " found in ref file");
119  hh1 = (TH1*)obj;
120  } else {
121  B2DEBUG(20, "Histo " << histoname << " found in ref file but wrong type");
122  }
123  } else {
124  // seems find will only find objects, not keys, thus get the object on first access
125  TIter next(d->GetListOfKeys());
126  TKey* key;
127  while ((key = (TKey*)next())) {
128  TObject* obj2 = key->ReadObj() ;
129  if (obj2->InheritsFrom("TH1")) {
130  if (obj2->GetName() == tok) {
131  hh1 = (TH1*)obj2;
132  B2DEBUG(20, "Histo " << histoname << " found as key -> readobj");
133  break;
134  }
135  }
136  }
137  if (hh1 == NULL) B2DEBUG(20, "Histo " << histoname << " NOT found in ref file " << tok);
138  }
139  }
140 
141  if (hh1 == NULL) {
142  B2DEBUG(20, "Histo " << histoname << " not in memfile or ref file");
143 
144  TDirectory* d = gROOT;
145  TString myl = histoname;
146  TString tok;
147  Ssiz_t from = 0;
148  while (myl.Tokenize(tok, from, "/")) {
149  TString dummy;
150  Ssiz_t f;
151  f = from;
152  if (myl.Tokenize(dummy, f, "/")) { // check if its the last one
153  auto e = d->GetDirectory(tok);
154  if (e) {
155  B2DEBUG(20, "Cd Dir " << tok);
156  d = e;
157  } else B2DEBUG(20, "cd failed " << tok);
158  d->cd();
159  } else {
160  break;
161  }
162  }
163  TObject* obj = d->FindObject(tok);
164  if (obj != NULL) {
165  if (obj->IsA()->InheritsFrom("TH1")) {
166  B2DEBUG(20, "Histo " << histoname << " found in mem");
167  hh1 = (TH1*)obj;
168  }
169  } else {
170  B2DEBUG(20, "Histo " << histoname << " NOT found in mem");
171  }
172  }
173  }
174 
175  if (hh1 == NULL) {
176  B2DEBUG(20, "Histo " << histoname << " not found");
177  }
178 
179  return hh1;
180 }
181 
182 void DQMHistComparitorModule::initialize()
183 {
184  m_refFile = NULL;
185  if (m_refFileName != "") {
186  m_refFile = new TFile(m_refFileName.data());
187  }
188 
189  gStyle->SetOptStat(0);
190  gStyle->SetStatStyle(1);
191  gStyle->SetOptDate(22);// Date and Time in Bottom Right, does no work
192 
193 #ifdef _BELLE2_EPICS
194  if (!ca_current_context()) SEVCHK(ca_context_create(ca_disable_preemptive_callback), "ca_context_create");
195 #endif
196  for (auto& it : m_histlist) {
197  if (it.size() != 7) {
198  B2WARNING("Histolist with wrong nr of parameters (" << it.size() << "), hist1=" << it.at(0));
199  continue;
200  }
201 
202  // Do not check for histogram existance here, as it might not be
203  // in memfile when analysis task is started
204  TString a = it.at(2).c_str();
205 
206  auto n = new CMPNODE;
207  n->histo1 = it.at(0);
208  n->histo2 = it.at(1);
209  TCanvas* c = new TCanvas(a);
210  n->canvas = c;
211 
212  n->min_entries = atoi(it.at(3).c_str());
213  n->warning = atof(it.at(4).c_str());
214  n->error = atof(it.at(5).c_str());
215  n->epicsflag = false;
216 
217 #ifdef _BELLE2_EPICS
218  if (it.at(6) != "") {
219  SEVCHK(ca_create_channel(it.at(6).c_str(), NULL, NULL, 10, &n->mychid), "ca_create_channel failure");
220  n->epicsflag = true;
221  }
222 #endif
223  m_pnode.push_back(n);
224  }
225 #ifdef _BELLE2_EPICS
226  SEVCHK(ca_pend_io(5.0), "ca_pend_io failure");
227 #endif
228 
229  B2DEBUG(20, "DQMHistComparitor: initialized.");
230 }
231 
232 
233 void DQMHistComparitorModule::beginRun()
234 {
235  B2DEBUG(20, "DQMHistComparitor: beginRun called.");
236 }
237 
238 void DQMHistComparitorModule::event()
239 {
240  for (auto& it : m_pnode) {
241 
242  TH1* hist1, *hist2;
243 
244  B2DEBUG(20, "== Search for " << it->histo1 << " with ref " << it->histo2 << "==");
245  hist1 = find_histo_in_canvas(it->histo1);
246  if (!hist1) B2DEBUG(20, "NOT Found " << it->histo1);
247  hist2 = GetHisto(it->histo2);
248  if (!hist2) B2DEBUG(20, "NOT Found " << it->histo2);
249  // Dont compare if any of hists is missing ... TODO We should clean CANVAS, raise some error if we cannot compare
250  if (!hist1) continue;
251  if (!hist2) continue;
252 
253  B2DEBUG(20, "Compare " << it->histo1 << " with ref " << it->histo2);
254  // if compare normalized ... does not work!
255  // hist2->Scale(hist1->GetEntries()/hist2->GetEntries());
256 
257  double data = hist1->KolmogorovTest(hist2, ""); // returns p value (0 bad, 1 good), N - do not compare normalized
258  // data = hist1->Chi2Test(hist2);// return p value (0 bad, 1 good), ignores normalization
259  // data= BinByBinTest(hits1,hist2);// user function (like Peters test)
260  // printf(" %.2f %.2f %.2f\n",(float)data,it->warning,it->error);
261 #ifdef _BELLE2_EPICS
262  if (it->epicsflag) SEVCHK(ca_put(DBR_DOUBLE, it->mychid, (void*)&data), "ca_set failure");
263 #endif
264  it->canvas->cd();
265  hist2->SetLineStyle(3);// 2 or 3
266  hist2->SetLineColor(3);
267 
268  TIter nextkey(it->canvas->GetListOfPrimitives());
269  TObject* obj = NULL;
270  while ((obj = (TObject*)nextkey())) {
271  if (obj->IsA()->InheritsFrom("TH1")) {
272  if (string(obj->GetName()) == string(hist2->GetName())) {
273  delete obj;
274  }
275  }
276  }
277 
278  // if draw normalized
279  TH1* h;
280  if (1) {
281  h = (TH1*)hist2->Clone(); // Anoying ... Maybe an memory leak? TODO
282  if (abs(hist2->Integral()) > 0)
283  h->Scale(hist1->Integral() / hist2->Integral());
284  } else {
285  hist2->Draw("hist");
286  }
287 
288  h->SetFillColor(0);
289  h->SetStats(kFALSE);
290  hist1->SetFillColor(0);
291  if (h->GetMaximum() > hist1->GetMaximum())
292  hist1->SetMaximum(1.1 * h->GetMaximum());
293  hist1->Draw("hist");
294  h->Draw("hist,same");
295 
296  it->canvas->Pad()->SetFrameFillColor(10);
297  if (m_color) {
298  if (hist1->GetEntries() < it->min_entries) {
299  // not enough Entries
300  it->canvas->Pad()->SetFillColor(6);// Magenta
301  } else {
302  if (data < it->error) {
303  it->canvas->Pad()->SetFillColor(2);// Red
304  } else if (data < it->warning) {
305  it->canvas->Pad()->SetFillColor(5);// Yellow
306  } else {
307  it->canvas->Pad()->SetFillColor(0);// White
308  }
309  }
310  } else {
311  it->canvas->Pad()->SetFillColor(0);// White
312  }
313  it->canvas->Modified();
314  it->canvas->Update();
315  }
316 #ifdef _BELLE2_EPICS
317  SEVCHK(ca_pend_io(5.0), "ca_pend_io failure");
318 #endif
319 }
320 
321 void DQMHistComparitorModule::endRun()
322 {
323  B2DEBUG(20, "DQMHistComparitor: endRun called");
324 }
325 
326 
327 void DQMHistComparitorModule::terminate()
328 {
329  B2DEBUG(20, "DQMHistComparitor: terminate called");
330  if (m_refFile) delete m_refFile;
331 }
The base class for the histogram analysis module.
Class definition for the reference histogram display.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
The struct for reference histogram comparison.