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