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