Belle II Software  release-05-01-25
PXDDAQDQMModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2017 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Bjoern Spruck *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <pxd/modules/pxdDQM/PXDDAQDQMModule.h>
12 
13 #include <TDirectory.h>
14 #include <TAxis.h>
15 #include <boost/format.hpp>
16 #include <string>
17 
18 using namespace std;
19 using namespace Belle2;
20 using namespace Belle2::PXD;
21 using namespace Belle2::PXD::PXDError;
22 using namespace Belle2::VXD;
23 using boost::format;
24 
25 //-----------------------------------------------------------------
26 // Register the Module
27 //-----------------------------------------------------------------
28 REG_MODULE(PXDDAQDQM)
29 
30 //-----------------------------------------------------------------
31 // Implementation
32 //-----------------------------------------------------------------
33 
34 PXDDAQDQMModule::PXDDAQDQMModule() : HistoModule() , m_vxdGeometry(VXD::GeoCache::getInstance())
35 {
36  //Set module properties
37  setDescription("Monitor DAQ errors");
38  setPropertyFlags(c_ParallelProcessingCertified);
39  addParam("histogramDirectoryName", m_histogramDirectoryName, "Name of the directory where histograms will be placed",
40  std::string("pxdDAQ"));
41 }
42 
43 void PXDDAQDQMModule::defineHisto()
44 {
45  TDirectory* oldDir = gDirectory;
46  if (m_histogramDirectoryName != "") {
47  oldDir->mkdir(m_histogramDirectoryName.c_str());// do not rely on return value, might be ZERO
48  oldDir->cd(m_histogramDirectoryName.c_str());
49  }
50 
51  hDAQErrorEvent = new TH1D("PXDDAQError", "PXDDAQError/Event;;Count", ONSEN_USED_TYPE_ERR, 0, ONSEN_USED_TYPE_ERR);
52  hDAQErrorDHC = new TH2D("PXDDAQDHCError", "PXDDAQError/DHC;DHC ID;", 16, 0, 16, ONSEN_USED_TYPE_ERR, 0, ONSEN_USED_TYPE_ERR);
53  hDAQErrorDHE = new TH2D("PXDDAQDHEError", "PXDDAQError/DHE;DHE ID;", 64, 0, 64, ONSEN_USED_TYPE_ERR, 0, ONSEN_USED_TYPE_ERR);
54  hDAQUseableModule = new TH1D("PXDDAQUseableModule", "PXDDAQUseableModule/DHE;DHE ID;", 64, 0, 64);
55  hDAQNotUseableModule = new TH1D("PXDDAQNotUseableModule", "PXDDAQNotUseableModule/DHE;DHE ID;", 64, 0, 64);
56  hDAQDHPDataMissing = new TH1D("PXDDAQDHPDataMissing", "PXDDAQDHPDataMissing/DHE*DHP;DHE ID;", 64 * 4, 0, 64);
57  hDAQEndErrorDHC = new TH2D("PXDDAQDHCEndError", "PXDDAQEndError/DHC;DHC ID;", 16, 0, 16, 32, 0, 32);
58  hDAQEndErrorDHE = new TH2D("PXDDAQDHEEndError", "PXDDAQEndError/DHE;DHE ID;", 64, 0, 64, 4 * 2 * 8, 0, 4 * 2 * 8);
59 
60  // histograms might get unreadable, but, if necessary, you can zoom in anyways.
61  // we could use full alphanumeric histograms, but then, the labels would change (in the worst case) depending on observed errors
62  // and ... the histogram would contain NO labels if there is NO error ... confusing.
63  // ... an we would have to use alphanumeric X axis (DHE ID, DHC ID), too)
64  for (int i = 0; i < ONSEN_USED_TYPE_ERR; i++) {
65  const char* label = getPXDBitErrorName(i).c_str();
66  hDAQErrorEvent->GetXaxis()->SetBinLabel(i + 1, label);
67  hDAQErrorDHE->GetYaxis()->SetBinLabel(i + 1, label);
68  hDAQErrorDHC->GetYaxis()->SetBinLabel(i + 1, label);
69  }
70 
71  hDAQErrorEvent->LabelsOption("v"); // rotate the labels.
72 
73  std::vector<VxdID> sensors = m_vxdGeometry.getListOfSensors();
74  for (VxdID& avxdid : sensors) {
75  VXD::SensorInfoBase info = m_vxdGeometry.getSensorInfo(avxdid);
76  if (info.getType() != VXD::SensorInfoBase::PXD) continue;
77  //Only interested in PXD sensors
78 
79  TString buff = (std::string)avxdid;
80  TString bufful = buff;
81  buff.ReplaceAll(".", "_");
82 
83 // string s = str(format("DHE %d:%d:%d (DHH ID %02Xh)") % num1 % num2 % num3 % i);
84 // string s2 = str(format("_%d.%d.%d") % num1 % num2 % num3);
85 
86  hDAQDHETriggerGate[avxdid] = new TH1D("PXDDAQDHETriggerGate_" + bufful,
87  "TriggerGate DHE " + buff + "; Trigger Gate; Counts", 192, 0, 192);
88  hDAQDHEReduction[avxdid] = new TH1D("PXDDAQDHEDataReduction_" + bufful, "Data Reduction DHE " + buff + "; Raw/Red; Counts", 200, 0,
89  40);// If max changed, check overflow copy below
90  hDAQCM[avxdid] = new TH2D("PXDDAQCM_" + bufful, "Common Mode on DHE " + buff + "; Gate+Chip*192; Common Mode", 192 * 4, 0, 192 * 4,
91  64, 0, 64);
92  hDAQCM2[avxdid] = new TH1D("PXDDAQCM2_" + bufful, "Common Mode on DHE " + buff + "; Common Mode", 64, 0, 64);
93  }
94  for (int i = 0; i < 16; i++) {
95  hDAQDHCReduction[i] = new TH1D(("PXDDAQDHCDataReduction_" + str(format("%d") % i)).c_str(),
96  ("Data Reduction DHC " + str(format(" %d") % i) + "; Raw/Red; Counts").c_str(), 200, 0,
97  40); // If max changed, check overflow copy below
98  }
99 // hDAQErrorEvent->LabelsDeflate("X");
100 // hDAQErrorEvent->LabelsOption("v");
101 // hDAQErrorEvent->SetStats(0);
102  hEODBAfterInjLER = new TH1I("PXDEODBInjLER", "PXDEODBInjLER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
103  hEODBAfterInjHER = new TH1I("PXDEODBInjHER", "PXDEODBInjHER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
104  hCM63AfterInjLER = new TH1I("PXDCM63InjLER", "PXDCM63InjLER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
105  hCM63AfterInjHER = new TH1I("PXDCM63InjHER", "PXDCM63InjHER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
106  hTruncAfterInjLER = new TH1I("PXDTruncInjLER", "PXDTruncInjLER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
107  hTruncAfterInjHER = new TH1I("PXDTruncInjHER", "PXDTruncInjHER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
108  hMissAfterInjLER = new TH1I("PXDMissInjLER", "PXDMissInjLER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
109  hMissAfterInjHER = new TH1I("PXDMissInjHER", "PXDMissInjHER/Time;Time in #mus;Events/Time (5 #mus bins)", 4000, 0, 20000);
110  hEODBTrgDiff = new TH1I("PXDEODBTrgDiff", "PXDEODBTrgDiff/DiffTime;DiffTime in #mus;Events/Time (1 #mus bins)", 2000, 0, 2000);
111  hCM63TrgDiff = new TH1I("PXDCM63TrgDiff", "PXDCM63TrgDiff/DiffTime;DiffTime in #mus;Events/Time (1 #mus bins)", 2000, 0, 2000);
112  hTruncTrgDiff = new TH1I("PXDTruncTrgDiff", "PXDTruncTrgDiff/DiffTime;DiffTime in #mus;Events/Time (1 #mus bins)", 2000, 0, 2000);
113  hMissTrgDiff = new TH1I("PXDMissTrgDiff", "PXDMissTrgDiff/DiffTime;DiffTime in #mus;Events/Time (1 #mus bins)", 2000, 0, 2000);
114 
115  hDAQStat = new TH1D("PXDDAQStat", "PXDDAQStat", 20, 0, 20);
116  auto xa = hDAQStat->GetXaxis();
117  if (xa) {
118  // underflow: number of events -> for normalize
119  xa->SetBinLabel(0 + 1, "EODB/HLT rej"); // event of doom or rejected
120  xa->SetBinLabel(1 + 1, "Trunc 8%");
121  xa->SetBinLabel(2 + 1, "HER Trunc");
122  xa->SetBinLabel(3 + 1, "LER Trunc");
123  xa->SetBinLabel(4 + 1, "CM63");
124  xa->SetBinLabel(5 + 1, "HER CM63");
125  xa->SetBinLabel(6 + 1, "LER CM63");
126  xa->SetBinLabel(7 + 1, "HER CM63>1ms");
127  xa->SetBinLabel(8 + 1, "LER CM63>1ms");
128  xa->SetBinLabel(9 + 1, "HER Trunc>1ms");
129  xa->SetBinLabel(10 + 1, "LER Trunc>1ms");
130  xa->SetBinLabel(11 + 1, "MissFrame");
131  xa->SetBinLabel(12 + 1, "Timeout");
132  xa->SetBinLabel(13 + 1, "Link Down");
133  xa->SetBinLabel(14 + 1, "Mismatch");
134  xa->SetBinLabel(15 + 1, "HER MissFrame");
135  xa->SetBinLabel(16 + 1, "LER MissFrame");
136  xa->SetBinLabel(17 + 1, "HER MissFrame>1ms");
137  xa->SetBinLabel(18 + 1, "LER MissFrame>1ms");
138  xa->SetBinLabel(19 + 1, "unused");
139  }
140  // cd back to root directory
141  oldDir->cd();
142 }
143 
144 void PXDDAQDQMModule::initialize()
145 {
146  REG_HISTOGRAM
147  m_storeDAQEvtStats.isRequired();
148  m_rawTTD.isOptional();
149  m_rawSVD.isOptional();
150 }
151 
152 void PXDDAQDQMModule::beginRun()
153 {
154  hDAQErrorEvent->Reset();
155  hDAQErrorDHC->Reset();
156  hDAQErrorDHE->Reset();
157  hDAQUseableModule->Reset();
158  hDAQNotUseableModule->Reset();
159  hDAQDHPDataMissing->Reset();
160  hDAQEndErrorDHC->Reset();
161  hDAQEndErrorDHE->Reset();
162  for (auto& it : hDAQDHETriggerGate) if (it.second) it.second->Reset();
163  for (auto& it : hDAQDHCReduction) if (it.second) it.second->Reset();
164  for (auto& it : hDAQDHEReduction) if (it.second) it.second->Reset();
165  for (auto& it : hDAQCM) if (it.second) it.second->Reset();
166  for (auto& it : hDAQCM2) if (it.second) it.second->Reset();
167  if (hCM63AfterInjLER) hCM63AfterInjLER->Reset();
168  if (hCM63AfterInjHER) hCM63AfterInjHER->Reset();
169  if (hTruncAfterInjLER) hTruncAfterInjLER->Reset();
170  if (hTruncAfterInjHER) hTruncAfterInjHER->Reset();
171  if (hMissAfterInjLER) hMissAfterInjLER->Reset();
172  if (hMissAfterInjHER) hMissAfterInjHER->Reset();
173  hDAQStat->Reset();
174 }
175 
176 void PXDDAQDQMModule::event()
177 {
178  hDAQStat->Fill(-1); // to normalize to the number of events
179  hDAQDHPDataMissing->Fill(-1); // to normalize to the number of events
180  hDAQErrorDHC->Fill(-1, -1); // to normalize to the number of events
181  hDAQErrorDHE->Fill(-1, -1); // to normalize to the number of events
182  for (auto& it : hDAQCM2) if (it.second) it.second->Fill(-1); // to normalize to the number of events
187 
188  bool eodbFlag = m_rawSVD.getEntries() == 0;
189 
190  bool truncFlag = false; // flag events which are DHE truncated
191  bool nolinkFlag = false; // flag events which are DHE truncated
192  bool missingFlag = false; // flag events where frame is missing
193  bool timeoutFlag = false; // flag events where frame timeout
194  bool mismatchFlag = false; // flag events where trig mismatched
195  bool cm63Flag = false; // flag event which are CM63 truncated
196 
197  B2DEBUG(20, "Iterate PXD DAQ Status");
198  auto evt = *m_storeDAQEvtStats;
199  PXDErrorFlags evt_emask = evt.getErrorMask();
200  for (int i = 0; i < ONSEN_MAX_TYPE_ERR; i++) {
201  PXDErrorFlags mask = (1ull << i);
202  if ((evt_emask & mask) == mask) hDAQErrorEvent->Fill(getPXDBitErrorName(i).c_str(), 1);
203  }
204  B2DEBUG(20, "Iterate PXD Packets, Err " << evt_emask);
205  for (auto& pkt : evt) {
206  B2DEBUG(20, "Iterate PXD DHC in Pkt " << pkt.getPktIndex());
207  for (auto& dhc : pkt) {
208  hDAQErrorDHC->Fill(dhc.getDHCID(), -1);// normalize
209  PXDErrorFlags dhc_emask = dhc.getErrorMask();
210  for (int i = 0; i < ONSEN_MAX_TYPE_ERR; i++) {
211  PXDErrorFlags mask = (1ull << i);
212  if ((dhc_emask & mask) == mask) hDAQErrorDHC->Fill(dhc.getDHCID(), i);
213  }
214  unsigned int cmask = dhc.getEndErrorInfo();
215  for (int i = 0; i < 32; i++) {
216  unsigned int mask = (1 << i);
217  if ((cmask & mask) == mask) hDAQEndErrorDHC->Fill(dhc.getDHCID(), i);
218  }
219  if (hDAQDHCReduction[dhc.getDHCID()]) {
220  float red = dhc.getRedCnt() ? float(dhc.getRawCnt()) / dhc.getRedCnt() : 0.;
221  B2DEBUG(98, "==DHC " << dhc.getDHCID() << "(Raw)" << dhc.getRawCnt() << " / (Red)" << dhc.getRedCnt() << " = " << red);
222  if (red >= 40.) red = 39.999999999; // Bad, bad workaround. but we want to see the overflows
223  hDAQDHCReduction[dhc.getDHCID()]->Fill(red);
224  }
225  B2DEBUG(20, "Iterate PXD DHE in DHC " << dhc.getDHCID() << " , Err " << dhc_emask);
226  for (auto& dhe : dhc) {
227  hDAQErrorDHE->Fill(dhe.getDHEID(), -1);// normalize
228  PXDErrorFlags dhe_emask = dhe.getErrorMask();
229  B2DEBUG(20, "DHE " << dhe.getDHEID() << " , Err " << dhe_emask);
230  for (int i = 0; i < ONSEN_MAX_TYPE_ERR; i++) {
231  PXDErrorFlags mask = (1ull << i);
232  if ((dhe_emask & mask) == mask) hDAQErrorDHE->Fill(dhe.getDHEID(), i);
233  }
234  if (dhe.isUsable()) {
235  hDAQUseableModule->Fill(dhe.getDHEID());
236  } else {
237  hDAQNotUseableModule->Fill(dhe.getDHEID());
238  }
239  for (int i = 0; i < 4; i++) {
240  if ((dhe.getDHPFoundMask() & (1 << i)) == 0) hDAQDHPDataMissing->Fill(dhe.getDHEID() + i * 0.25);
241  }
242  for (auto& dhp : dhe) {
243  truncFlag |= dhp.getTruncated(); // new firmware workaround flag
244  }
245  unsigned int emask = dhe.getEndErrorInfo();
246  // TODO differentiate between link-lost and truncation
247  for (int i = 0; i < 4 * 2; i++) {
248  auto sm = (emask >> i * 4) & 0xF;
249  if (sm >= 8) sm = 7; // clip unknow to 7, as value >6 undefined for now
250  if (sm > 0) hDAQEndErrorDHE->Fill(dhe.getDHEID(), i * 8 + sm); // we dont want to fill noerror=0
251  missingFlag |= sm == 0x1; // missing
252  timeoutFlag |= sm == 0x2; // timeout
253  nolinkFlag |= sm == 0x3; // link down
254  // 4 is DHP masked
255  mismatchFlag |= sm == 0x5; // start/end mismatch
256  truncFlag |= sm == 0x6; // trunc because of size
257  }
258 
259  if (hDAQDHETriggerGate[dhe.getSensorID()]) hDAQDHETriggerGate[dhe.getSensorID()]->Fill(dhe.getTriggerGate());
260  if (hDAQDHEReduction[dhe.getSensorID()]) {
261  float red = dhe.getRedCnt() ? float(dhe.getRawCnt()) / dhe.getRedCnt() : 0.;
262  B2DEBUG(98, "==DHE " << dhe.getSensorID() << "(Raw)" << dhe.getRawCnt() << " / (Red)" << dhe.getRedCnt() << " = " << red);
263  if (red >= 40.) red = 39.999999999; // Bad, bad workaround. but we want to see the overflows
264  hDAQDHEReduction[dhe.getSensorID()]->Fill(red);
265  }
266  for (auto cm = dhe.cm_begin(); cm < dhe.cm_end(); ++cm) {
267  // uint8_t, uint16_t, uint8_t ; tuple of Chip ID (2 bit), Row (10 bit), Common Mode (6 bit)
268  if (hDAQCM[dhe.getSensorID()]) hDAQCM[dhe.getSensorID()]->Fill(std::get<0>(*cm) * 192 + std::get<1>(*cm) / 4, std::get<2>(*cm));
269  if (hDAQCM2[dhe.getSensorID()]) hDAQCM2[dhe.getSensorID()]->Fill(std::get<2>(*cm));
270  cm63Flag |= 63 == std::get<2>(*cm);
271  }
272  }
273  }
274  }
275  // Now fill the histograms which need flags set above
276  // the code is unluckily a copy of whats in PXDInjection Module, but there we dont have the DAQ flags :-/
277  for (auto& it : m_rawTTD) {
278 // B2DEBUG(29, "TTD FTSW : " << hex << it.GetTTUtime(0) << " " << it.GetTTCtime(0) << " EvtNr " << it.GetEveNo(0) << " Type " <<
279 // (it.GetTTCtimeTRGType(0) & 0xF) << " TimeSincePrev " << it.GetTimeSincePrevTrigger(0) << " TimeSinceInj " <<
280 // it.GetTimeSinceLastInjection(0) << " IsHER " << it.GetIsHER(0) << " Bunch " << it.GetBunchNumber(0));
281 
282  double lasttrig = it.GetTimeSincePrevTrigger(0) / 127.; // 127MHz clock ticks to us, inexact rounding
283  if (eodbFlag && hEODBTrgDiff) hEODBTrgDiff->Fill(lasttrig);
284  if (cm63Flag && hCM63TrgDiff) hCM63TrgDiff->Fill(lasttrig);
285  if (truncFlag && hTruncTrgDiff) hTruncTrgDiff->Fill(lasttrig);
286  if (missingFlag && hMissTrgDiff) hMissTrgDiff->Fill(lasttrig);
287 
288  // get last injection time
289  auto difference = it.GetTimeSinceLastInjection(0);
290  // check time overflow, too long ago
291  if (difference != 0x7FFFFFFF) {
292  double diff2 = difference / 127.; // 127MHz clock ticks to us, inexact rounding
293  if (it.GetIsHER(0)) {
294  if (eodbFlag) {
295  if (hEODBAfterInjHER) hEODBAfterInjHER->Fill(diff2);
296  }
297  if (cm63Flag) {
298  hDAQStat->Fill(5); // sum CM63 after HER
299  if (diff2 > 1000) hDAQStat->Fill(7); // sum CM63 after HER, but outside injections, 1ms
300  if (hCM63AfterInjHER) hCM63AfterInjHER->Fill(diff2);
301  }
302  if (truncFlag) {
303  hDAQStat->Fill(2); // sum truncs after HER
304  if (diff2 > 1000) hDAQStat->Fill(9); // sum truncs after HER, but outside injections, 1ms
305  if (hTruncAfterInjHER) hTruncAfterInjHER->Fill(diff2);
306  }
307  if (missingFlag) {
308  hDAQStat->Fill(15); // sum missframe after HER
309  if (diff2 > 1000) hDAQStat->Fill(17); // sum missframe after HER, but outside injections, 1ms
310  if (hMissAfterInjHER) hMissAfterInjHER->Fill(diff2);
311  }
312  } else {
313  if (eodbFlag) {
314  if (hEODBAfterInjLER) hEODBAfterInjLER->Fill(diff2);
315  }
316  if (cm63Flag) {
317  hDAQStat->Fill(6); // sum CM63 after LER
318  if (diff2 > 1000) hDAQStat->Fill(8); // sum CM63 after LER, but outside injections, 1ms
319  if (hCM63AfterInjLER) hCM63AfterInjLER->Fill(diff2);
320  }
321  if (truncFlag) {
322  hDAQStat->Fill(3); // sum truncs after LER
323  if (diff2 > 1000) hDAQStat->Fill(10); // sum truncs after LER, but outside injections, 1ms
324  if (hTruncAfterInjLER) hTruncAfterInjLER->Fill(diff2);
325  }
326  if (missingFlag) {
327  hDAQStat->Fill(16); // sum missframe after LER
328  if (diff2 > 1000) hDAQStat->Fill(18); // sum missframe after LER, but outside injections, 1ms
329  if (hMissAfterInjLER) hMissAfterInjLER->Fill(diff2);
330  }
331  }
332  }
333  break; // only first TTD packet
334  }
335 
336  // make some nice statistics
337  if (truncFlag) hDAQStat->Fill(1);
338  if (cm63Flag) hDAQStat->Fill(4);
339  if (missingFlag) hDAQStat->Fill(11);
340  if (timeoutFlag) hDAQStat->Fill(12);
341  if (nolinkFlag) hDAQStat->Fill(13);
342  if (mismatchFlag) hDAQStat->Fill(14);
343 
344  // Check Event-of-doom-busted or otherwise HLT rejected events
345  if (eodbFlag) hDAQStat->Fill(0);
346 }
Belle2::VxdID
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:43
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::VXD::SensorInfoBase
Base class to provide Sensor Information for PXD and SVD.
Definition: SensorInfoBase.h:40
Belle2::VXD
Namespace to provide code needed by both Vertex Detectors, PXD and SVD, and also testbeam telescopes.
Definition: GeoCache.h:36
Belle2::PXD
Namespace to encapsulate code needed for simulation and reconstrucion of the PXD.
Definition: PXDCalibrationUtilities.h:28
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::VXD::GeoCache
Class to faciliate easy access to sensor information of the VXD like coordinate transformations or pi...
Definition: GeoCache.h:41
Belle2::HistoModule
HistoModule.h is supposed to be used instead of Module.h for the modules with histogram definitions t...
Definition: HistoModule.h:29
Belle2::PXD::PXDDAQDQMModule
The PXD DAQ DQM module.
Definition: PXDDAQDQMModule.h:49