Belle II Software  release-06-00-14
KLMUnpackerModule.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 /* Own header. */
10 #include <klm/modules/KLMUnpacker/KLMUnpackerModule.h>
11 
12 /* KLM headers. */
13 #include <klm/dataobjects/bklm/BKLMElementNumbers.h>
14 #include <klm/dataobjects/KLMScintillatorFirmwareFitResult.h>
15 #include <klm/rawdata/RawData.h>
16 
17 /* Belle 2 headers. */
18 #include <framework/logging/Logger.h>
19 
20 /* C++ headers. */
21 #include <cstdint>
22 
23 using namespace std;
24 using namespace Belle2;
25 using namespace Belle2::KLM;
26 
27 REG_MODULE(KLMUnpacker)
28 
30  m_Time(&(KLMTime::Instance())),
31  m_ElementNumbers(&(KLMElementNumbers::Instance())),
32  m_triggerCTimeOfPreviousEvent(0)
33 {
34  setDescription("KLM unpacker (creates KLMDigits from RawKLM).");
35  setPropertyFlags(c_ParallelProcessingCertified);
36  addParam("outputKLMDigitsName", m_outputKLMDigitsName,
37  "Name of KLMDigit store array.", string(""));
38  addParam("WriteDigitRaws", m_WriteDigitRaws,
39  "Record raw data in dataobject format (e.g. for debugging).", false);
40  addParam("WriteWrongHits", m_WriteWrongHits,
41  "Record wrong hits (e.g. for debugging).", false);
42  addParam("DebugElectronicsMap", m_DebugElectronicsMap,
43  "Debug electronics map (record DAQ channel instead of strip).",
44  false);
45  addParam("DAQChannelBKLMScintillators", m_DAQChannelBKLMScintillators,
46  "Record DAQ channel for BKLM scintillators.", false);
47  addParam("DAQChannelModule", m_DAQChannelModule,
48  "Record DAQ channel for specific module.", -1);
49  addParam("IgnoreWrongHits", m_IgnoreWrongHits,
50  "Ignore wrong hits (i.e. no B2ERROR).", false);
51  addParam("IgnoreStrip0", m_IgnoreStrip0,
52  "Ignore hits with strip = 0 (normally expected for certain firmware "
53  "versions).", true);
54  addParam("keepEvenPackages", m_keepEvenPackages,
55  "Keep packages that have even length normally indicating that "
56  "data was corrupted ", false);
57 }
58 
59 KLMUnpackerModule::~KLMUnpackerModule()
60 {
61 }
62 
63 void KLMUnpackerModule::initialize()
64 {
65  m_RawKLMs.isRequired();
66  /* Digits. */
67  m_Digits.registerInDataStore(m_outputKLMDigitsName);
68  m_klmDigitsOutOfRange.registerInDataStore("KLMDigitsOutOfRange");
69  /* Event information. */
70  m_DigitEventInfos.registerInDataStore();
71  m_Digits.registerRelationTo(m_DigitEventInfos);
72  m_klmDigitsOutOfRange.registerRelationTo(m_DigitEventInfos);
73  /* Raw data in dataobject format. */
74  if (m_WriteDigitRaws) {
75  m_klmDigitRaws.registerInDataStore();
76  m_Digits.registerRelationTo(m_klmDigitRaws);
77  m_klmDigitsOutOfRange.registerRelationTo(m_klmDigitRaws);
78  }
79 }
80 
81 void KLMUnpackerModule::beginRun()
82 {
83  if (!m_ElectronicsMap.isValid())
84  B2FATAL("KLM electronics map is not available.");
85  if (!m_FEEParameters.isValid())
86  B2FATAL("KLM scintillator FEE parameters are not available.");
87  m_triggerCTimeOfPreviousEvent = 0;
88  m_Time->updateConstants();
89 }
90 
91 void KLMUnpackerModule::createDigit(
92  const KLM::RawData* raw, const KLMDigitRaw* klmDigitRaw,
93  KLMDigitEventInfo* klmDigitEventInfo, int subdetector, int section,
94  int sector, int layer, int plane, int strip, int lastStrip)
95 {
96  KLMDigit* klmDigit = m_Digits.appendNew();
97  klmDigit->addRelationTo(klmDigitEventInfo);
98  if (m_WriteDigitRaws)
99  klmDigit->addRelationTo(klmDigitRaw);
100  bool isRPC = (subdetector == KLMElementNumbers::c_BKLM) &&
101  (layer >= BKLMElementNumbers::c_FirstRPCLayer);
102  if (isRPC) {
103  /*
104  * For RPC hits, digitize both the coarse (ctime) and fine (tdc) times
105  * relative to the revo9 trigger time rather than the event header's
106  * TriggerCTime. For the fine-time (tdc) measurement (11 bits), shift
107  * the revo9Trig time by 10 ticks to align the new prompt-time peak
108  * with the TriggerCtime-relative peak.
109  */
110  klmDigitEventInfo->increaseRPCHits();
111  float triggerTime = klmDigitEventInfo->getRevo9TriggerWord();
112  std::pair<int, double> rpcTimes =
113  m_Time->getRPCTimes(raw->getCTime(), raw->getTDC(), triggerTime);
114  klmDigit->setTime(rpcTimes.second);
115  } else {
116  /*
117  * For scintillator hits, store the ctime relative to the event header's
118  * trigger ctime.
119  */
120  klmDigitEventInfo->increaseSciHits();
121  double time = m_Time->getScintillatorTime(
122  raw->getCTime(), klmDigitEventInfo->getTriggerCTime());
123  klmDigit->setTime(time);
124  KLMChannelNumber channelNumber = m_ElementNumbers->channelNumber(subdetector, section, sector, layer, plane, strip);
125  const KLMScintillatorFEEData* FEEData =
126  m_FEEParameters->getFEEData(channelNumber);
127  if (FEEData == nullptr)
128  B2FATAL("Incomplete KLM scintillator FEE data.");
129  if (raw->getCharge() < FEEData->getThreshold())
130  klmDigit->setFitStatus(KLM::c_ScintillatorFirmwareSuccessfulFit);
131  else
132  klmDigit->setFitStatus(KLM::c_ScintillatorFirmwareNoSignal);
133  }
134  klmDigit->setSubdetector(subdetector);
135  klmDigit->setSection(section);
136  klmDigit->setLayer(layer);
137  klmDigit->setSector(sector);
138  klmDigit->setPlane(plane);
139  klmDigit->setStrip(strip);
140  if (lastStrip > 0)
141  klmDigit->setLastStrip(lastStrip);
142  klmDigit->setCharge(raw->getCharge());
143  klmDigit->setCTime(raw->getCTime());
144  klmDigit->setTDC(raw->getTDC());
145 }
146 
147 void KLMUnpackerModule::unpackKLMDigit(
148  const int* rawData, int copper, int hslb, int daqSubdetector,
149  KLMDigitEventInfo* klmDigitEventInfo)
150 {
151  KLMDigitRaw* klmDigitRaw;
152  KLM::RawData raw(copper, hslb + 1, rawData,
153  &m_klmDigitRaws, &klmDigitRaw, m_WriteDigitRaws);
154  const KLMChannelNumber* detectorChannel;
155  int subdetector, section, sector, layer, plane, strip;
156  /* Get channel groups. */
157  std::vector<ChannelGroup> channelGroups;
158  raw.getChannelGroups(channelGroups);
159  /* Get detector channels. */
160  KLMElectronicsChannel electronicsChannel(
161  copper, hslb + 1, raw.getLane(), raw.getAxis(), raw.getChannel());
162  bool channelFound = false;
163  for (ChannelGroup& channelGroup : channelGroups) {
164  if (channelGroup.lastChannel == 0) {
165  /* Single-strip hit. */
166  detectorChannel =
167  m_ElectronicsMap->getDetectorChannel(&electronicsChannel);
168  if (detectorChannel != nullptr) {
169  /* The channel is found, get element numbers. */
170  channelFound = true;
171  m_ElementNumbers->channelNumberToElementNumbers(
172  *detectorChannel, &subdetector, &section, &sector, &layer, &plane,
173  &strip);
174  channelGroup.firstStrip = strip;
175  channelGroup.lastStrip = 0;
176  } else {
177  /* The channel is not found, print error message. */
178  if (!(m_IgnoreWrongHits || (raw.getChannel() == 0 && m_IgnoreStrip0))) {
179  if (daqSubdetector == KLMElementNumbers::c_BKLM) {
180  B2DEBUG(20, "Channel does not exist in the KLM electronics map."
181  << LogVar("Copper", electronicsChannel.getCopper())
182  << LogVar("Slot", electronicsChannel.getSlot())
183  << LogVar("Lane", electronicsChannel.getLane())
184  << LogVar("Axis", electronicsChannel.getAxis())
185  << LogVar("Channel", electronicsChannel.getChannel()));
186  } else {
187  B2ERROR("Channel does not exist in the KLM electronics map."
188  << LogVar("Copper", electronicsChannel.getCopper())
189  << LogVar("Slot", electronicsChannel.getSlot())
190  << LogVar("Lane", electronicsChannel.getLane())
191  << LogVar("Axis", electronicsChannel.getAxis())
192  << LogVar("Channel", electronicsChannel.getChannel()));
193  }
194  }
195  }
196  } else {
197  /* Do not process multiple-strip hit in the electronics map debug mode. */
198  if (m_DebugElectronicsMap)
199  return;
200  /*
201  * Multiple-strip hit. It is necessary to find matching detector channels
202  * for all DAQ channels, because all channels in the group may not
203  * be necessary connected to strips in case of BKLM.
204  */
205  bool firstMatchedChannel = true;
206  for (int channel = channelGroup.firstChannel;
207  channel <= channelGroup.lastChannel; ++channel) {
208  electronicsChannel.setChannel(channel);
209  detectorChannel =
210  m_ElectronicsMap->getDetectorChannel(&electronicsChannel);
211  /* The channel is found, get element numbers. */
212  if (detectorChannel != nullptr) {
213  channelFound = true;
214  m_ElementNumbers->channelNumberToElementNumbers(
215  *detectorChannel, &subdetector, &section, &sector, &layer, &plane,
216  &strip);
217  if (firstMatchedChannel) {
218  firstMatchedChannel = false;
219  channelGroup.firstStrip = strip;
220  channelGroup.lastStrip = 0;
221  } else {
222  channelGroup.lastStrip = strip;
223  }
224  }
225  }
226  /* No matches found for this group at all. */
227  if (firstMatchedChannel) {
228  B2DEBUG(20, "No matching channels exist in the KLM electronics map."
229  << LogVar("Copper", electronicsChannel.getCopper())
230  << LogVar("Slot", electronicsChannel.getSlot())
231  << LogVar("Lane", electronicsChannel.getLane())
232  << LogVar("Axis", electronicsChannel.getAxis())
233  << LogVar("First channel", channelGroup.firstChannel)
234  << LogVar("Last channel", channelGroup.lastChannel)
235  << LogVar("Trigger bits", raw.getTriggerBits()));
236  }
237  }
238  }
239  /* No detector channel is found. */
240  if (!channelFound) {
241  if (!(m_WriteWrongHits || m_DebugElectronicsMap))
242  return;
243  /*
244  * Try to find channel from the same plane.
245  * BKLM phi-plane channels may start from 3 or 5.
246  */
247  electronicsChannel.setChannel(5);
248  detectorChannel = m_ElectronicsMap->getDetectorChannel(&electronicsChannel);
249  if (detectorChannel == nullptr)
250  return;
251  /* The channel is found, store out-of-range digit. */
252  m_ElementNumbers->channelNumberToElementNumbers(
253  *detectorChannel, &subdetector, &section, &sector, &layer, &plane,
254  &strip);
255  if (m_WriteWrongHits) {
256  klmDigitEventInfo->increaseOutOfRangeHits();
257  KLMDigit* klmDigitOutOfRange =
258  m_klmDigitsOutOfRange.appendNew();
259  klmDigitOutOfRange->addRelationTo(klmDigitEventInfo);
260  if (m_WriteDigitRaws)
261  klmDigitOutOfRange->addRelationTo(klmDigitRaw);
262  klmDigitOutOfRange->setSubdetector(KLMElementNumbers::c_BKLM);
263  klmDigitOutOfRange->setSection(section);
264  klmDigitOutOfRange->setLayer(layer);
265  klmDigitOutOfRange->setSector(sector);
266  klmDigitOutOfRange->setPlane(plane);
267  klmDigitOutOfRange->setStrip(strip);
268  klmDigitOutOfRange->setCharge(raw.getCharge());
269  klmDigitOutOfRange->setCTime(raw.getCTime());
270  klmDigitOutOfRange->setTDC(raw.getTDC());
271  return;
272  }
273  }
274  /* Debug mode: write raw channel number to strip number. */
275  if (m_DebugElectronicsMap) {
276  if (m_DAQChannelBKLMScintillators) {
277  if ((subdetector == KLMElementNumbers::c_BKLM) &&
278  (layer < BKLMElementNumbers::c_FirstRPCLayer))
279  strip = raw.getChannel();
280  }
281  if (m_DAQChannelModule >= 0) {
282  KLMModuleNumber klmModule =
283  m_ElementNumbers->moduleNumberByChannel(*detectorChannel);
284  if (klmModule == m_DAQChannelModule)
285  strip = raw.getChannel();
286  }
287  }
288  /* Create KLM digits. */
289  for (const ChannelGroup& channelGroup : channelGroups) {
290  if (channelGroup.firstStrip != 0) {
291  createDigit(&raw, klmDigitRaw, klmDigitEventInfo, subdetector, section,
292  sector, layer, plane, channelGroup.firstStrip,
293  channelGroup.lastStrip);
294  }
295  }
296 }
297 
298 void KLMUnpackerModule::convertPCIe40ToCOPPER(int channel, unsigned int* copper, int* hslb) const
299 {
300  if (channel >= 0 && channel < 16) {
301  int id = channel / 4;
302  *copper = BKLM_ID + id + 1;
303  *hslb = channel - id * 4;
304  } else if (channel >= 16 && channel < 32) {
305  int id = (channel - 16) / 4;
306  *copper = EKLM_ID + id + 1;
307  *hslb = (channel - 16) - id * 4;
308  } else
309  B2FATAL("The PCIe40 channel is invalid."
310  << LogVar("Channel", channel));
311 }
312 
313 void KLMUnpackerModule::event()
314 {
315  /*
316  * Length of one hit in 4-byte words. This is needed to find the hits in the
317  * detector buffer.
318  */
319  const int hitLength = 2;
320  for (int i = 0; i < m_RawKLMs.getEntries(); i++) {
321  if (m_RawKLMs[i]->GetNumEvents() != 1) {
322  B2ERROR("RawKLM a wrong number of entries (should be 1)."
323  << LogVar("RawKLM index", i)
324  << LogVar("Number of entries", m_RawKLMs[i]->GetNumEvents()));
325  continue;
326  }
327  /*
328  * GetNumEntries is defined in RawDataBlock.h and gives the numberOfNodes*numberOfEvents.
329  * Number of nodes is the number of COPPER boards.
330  */
331  for (int j = 0; j < m_RawKLMs[i]->GetNumEntries(); j++) {
332  unsigned int copper = m_RawKLMs[i]->GetNodeID(j);
333  int hslb, subdetector;
334  m_RawKLMs[i]->GetBuffer(j);
335  for (int channelReadoutBoard = 0; channelReadoutBoard < m_RawKLMs[i]->GetMaxNumOfCh(j); channelReadoutBoard++) {
336  if (m_RawKLMs[i]->GetMaxNumOfCh(j) == 4) { // COPPER data
337  hslb = channelReadoutBoard;
338  if ((copper >= EKLM_ID) && (copper <= EKLM_ID + 4))
339  subdetector = KLMElementNumbers::c_EKLM;
340  else if ((copper >= BKLM_ID) && (copper <= BKLM_ID + 4))
341  subdetector = KLMElementNumbers::c_BKLM;
342  else
343  continue;
344  } else if (m_RawKLMs[i]->GetMaxNumOfCh(j) == 48) { // PCIe40 data
345  if (channelReadoutBoard >= 0 && channelReadoutBoard < 16)
346  subdetector = KLMElementNumbers::c_BKLM;
347  else if (channelReadoutBoard >= 16 && channelReadoutBoard < 32)
348  subdetector = KLMElementNumbers::c_EKLM;
349  else
350  continue;
351  convertPCIe40ToCOPPER(channelReadoutBoard, &copper, &hslb);
352  } else {
353  B2FATAL("The maximum number of channels per readout board is invalid."
354  << LogVar("Number of channels", m_RawKLMs[i]->GetMaxNumOfCh(j)));
355  }
356  KLMDigitEventInfo* klmDigitEventInfo =
357  m_DigitEventInfos.appendNew(m_RawKLMs[i], j);
358  klmDigitEventInfo->setPreviousEventTriggerCTime(
359  m_triggerCTimeOfPreviousEvent);
360  m_triggerCTimeOfPreviousEvent = klmDigitEventInfo->getTriggerCTime();
361  int numDetNwords = m_RawKLMs[i]->GetDetectorNwords(j, channelReadoutBoard);
362  int* hslbBuffer = m_RawKLMs[i]->GetDetectorBuffer(j, channelReadoutBoard);
363  int numHits = numDetNwords / hitLength;
364  if (numDetNwords % hitLength != 1 && numDetNwords != 0) {
365  B2ERROR("Incorrect number of data words."
366  << LogVar("Number of data words", numDetNwords));
367  if (!m_keepEvenPackages)
368  continue;
369  }
370  if (numDetNwords > 0) {
371  /*
372  * In the last word there are the revo9 trigger word
373  * and the the user word (both from DCs).
374  */
375  unsigned int revo9TriggerWord =
376  (hslbBuffer[numDetNwords - 1] >> 16) & 0xFFFF;
377  klmDigitEventInfo->setRevo9TriggerWord(revo9TriggerWord);
378  unsigned int userWord = hslbBuffer[numDetNwords - 1] & 0xFFFF;
379  klmDigitEventInfo->setUserWord(userWord);
380  } else {
381  klmDigitEventInfo->setRevo9TriggerWord(0);
382  klmDigitEventInfo->setUserWord(0);
383  }
384  for (int iHit = 0; iHit < numHits; iHit++) {
385  unpackKLMDigit(&hslbBuffer[iHit * hitLength], copper, hslb,
386  subdetector, klmDigitEventInfo);
387  }
388  }
389  }
390  }
391 }
392 
393 void KLMUnpackerModule::endRun()
394 {
395 }
396 
397 void KLMUnpackerModule::terminate()
398 {
399 }
Class to store debugging informations from the unpacker (event based).
void increaseOutOfRangeHits()
Increase by 1 the number of outOfRange-flagged hits in the event.
unsigned int getTriggerCTime() const
Get trigger CTIME.
void increaseSciHits()
Increase by 1 the number of scintillator hits in the event.
void setUserWord(unsigned int userWord)
Set user word (from DCs).
void setRevo9TriggerWord(unsigned int revo9TriggerWord)
Set Revo9 trigger word (from DCs).
void setPreviousEventTriggerCTime(unsigned int triggerCTimeOfPreviousEvent)
Set trigger CTime of previous event.
unsigned int getRevo9TriggerWord() const
Get revo9 trigger word (from DCs).
void increaseRPCHits()
Increase by 1 the number of RPC hits in the event.
Class to store the raw words from the unpacker, digit-by-digit.
Definition: KLMDigitRaw.h:29
KLM digit (class representing a digitized hit in RPCs or scintillators).
Definition: KLMDigit.h:30
void setLastStrip(int lastStrip)
Set last strip number (for multi-strip digits).
Definition: KLMDigit.h:196
void setSection(int section)
Set section number.
Definition: KLMDigit.h:106
void setCTime(uint16_t ctime)
Set CTIME.
Definition: KLMDigit.h:256
void setStrip(int strip)
Set strip number.
Definition: KLMDigit.h:178
void setTime(float time)
Set hit time.
Definition: KLMDigit.h:292
void setSubdetector(int subdetector)
Set subdetector number.
Definition: KLMDigit.h:88
void setSector(int sector)
Set sector number.
Definition: KLMDigit.h:124
void setTDC(uint16_t tdc)
Set TDC.
Definition: KLMDigit.h:274
void setFitStatus(int s)
Set fit status.
Definition: KLMDigit.h:373
void setCharge(uint16_t charge)
Set charge.
Definition: KLMDigit.h:238
void setPlane(int plane)
Set plane number.
Definition: KLMDigit.h:160
void setLayer(int layer)
Set layer number.
Definition: KLMDigit.h:142
BKLM electronics channel.
int getCopper() const
Get copper.
int getChannel() const
Get channel.
void setChannel(int channel)
Set channel.
KLM element numbers.
int getThreshold() const
Get threshold.
KLM time conversion.
Definition: KLMTime.h:27
KLM raw data.
Definition: RawData.h:47
Base class for Modules.
Definition: Module.h:72
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
Class to store variables with their name which were sent to the logging service.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
uint16_t KLMChannelNumber
Channel number.
uint16_t KLMModuleNumber
Module number.
Abstract base class for different kinds of events.
Channel group.
Definition: RawData.h:28