Belle II Software development
TOPRawDigitConverterModule.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 <top/modules/TOPRawDigitConverter/TOPRawDigitConverterModule.h>
11
12// framework - DataStore
13#include <framework/datastore/StoreArray.h>
14#include <framework/datastore/StoreObjPtr.h>
15
16// framework aux
17#include <framework/logging/Logger.h>
18
19// Dataobject classes
20#include <top/dataobjects/TOPRawDigit.h>
21#include <top/dataobjects/TOPRawWaveform.h>
22#include <top/dataobjects/TOPDigit.h>
23#include <framework/dataobjects/EventMetaData.h>
24
25#include <top/geometry/TOPGeometryPar.h>
26
27
28using namespace std;
29
30namespace Belle2 {
36 using namespace TOP;
37
38 //-----------------------------------------------------------------
40 //-----------------------------------------------------------------
41
42 REG_MODULE(TOPRawDigitConverter);
43
44 //-----------------------------------------------------------------
45 // Implementation
46 //-----------------------------------------------------------------
47
49
50 {
51 // set module description (e.g. insert text)
52 setDescription("Converts row digits to digits and applies time calibration");
54
55 // Add parameters
56 addParam("inputRawDigitsName", m_inputRawDigitsName,
57 "name of TOPRawDigit store array", string(""));
58 addParam("outputDigitsName", m_outputDigitsName,
59 "name of TOPDigit store array", string(""));
60 addParam("useSampleTimeCalibration", m_useSampleTimeCalibration,
61 "if true, use sample time calibration", true);
62 addParam("useAsicShiftCalibration", m_useAsicShiftCalibration,
63 "if true, use ASIC shifts calibration", true);
64 addParam("useChannelT0Calibration", m_useChannelT0Calibration,
65 "if true, use channel T0 calibration", true);
66 addParam("useModuleT0Calibration", m_useModuleT0Calibration,
67 "if true, use module T0 calibration", true);
68 addParam("useCommonT0Calibration", m_useCommonT0Calibration,
69 "if true, use common T0 calibration", true);
70 addParam("useTimeWalkCalibration", m_useTimeWalkCalibration,
71 "if true, use time-walk calibration", true);
72 addParam("pedestalRMS", m_pedestalRMS,
73 "r.m.s of pedestals [ADC counts], "
74 "if positive, timeError will be estimated from FE data. "
75 "This is the default value used if r.m.s is not available from DB.", 9.7);
76 addParam("minPulseWidth", m_minPulseWidth,
77 "minimal pulse width [ns] to flag digit as good", 1.0);
78 addParam("maxPulseWidth", m_maxPulseWidth,
79 "maximal pulse width [ns] to flag digit as good", 10.0);
80 addParam("minWidthXheight", m_minWidthXheight,
81 "minimal product of width and height [ns * ADC counts]", 100.0);
82 addParam("storageDepth", m_storageDepth,
83 "ASIC analog storage depth of Interim FE format (ignored in other formats)",
84 (unsigned) 508);
85 addParam("lookBackWindows", m_lookBackWindows,
86 "number of look back windows, if positive override the number from database",
87 0);
88 addParam("setPhase", m_setPhase,
89 "if true, set (override) phase in TOPRawDigits", true);
90 addParam("calibrationChannel", m_calibrationChannel,
91 "calpulse selection: ASIC channel (use -1 to turn off the selection)", -1);
92 addParam("calpulseWidthMin", m_calpulseWidthMin,
93 "calpulse selection: minimal width [ns]", 0.0);
94 addParam("calpulseWidthMax", m_calpulseWidthMax,
95 "calpulse selection: maximal width [ns]", 0.0);
96 addParam("calpulseHeightMin", m_calpulseHeightMin,
97 "calpulse selection: minimal height [ADC counts]", 0);
98 addParam("calpulseHeightMax", m_calpulseHeightMax,
99 "calpulse selection: maximal height [ADC counts]", 0);
100 addParam("calpulseTimeMin", m_calpulseTimeMin,
101 "calpulse selection (ON if max > min): minimal time [ns]", 0.0);
102 addParam("calpulseTimeMax", m_calpulseTimeMax,
103 "calpulse selection (ON if max > min): maximal time [ns]", 0.0);
104 addParam("addRelations", m_addRelations, "if true, make relations to TOPRawDigits", true);
105
106 }
107
108
110 {
111 }
112
113
115 {
116
117 // registration of objects in datastore
119 m_eventDebugs.isOptional();
120 m_digits.registerInDataStore(m_outputDigitsName);
121 m_digits.registerRelationTo(m_rawDigits);
122 m_asicMask.registerInDataStore();
123
124 // equidistant sample times in case calibration is not required
125 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
126 m_syncTimeBase = geo->getNominalTDC().getSyncTimeBase();
128
129 }
130
131
133 {
134
135 StoreObjPtr<EventMetaData> evtMetaData;
136
137 // check if calibrations are available when needed - if not, terminate
138
140 if (not m_timebase.isValid()) {
141 B2FATAL("Sample time calibration requested but not available for run "
142 << evtMetaData->getRun()
143 << " of experiment " << evtMetaData->getExperiment());
144 }
145 }
147 if (not m_channelT0.isValid()) {
148 B2FATAL("Channel T0 calibration requested but not available for run "
149 << evtMetaData->getRun()
150 << " of experiment " << evtMetaData->getExperiment());
151 }
152 }
154 if (not m_asicShift.isValid()) {
155 B2FATAL("ASIC shifts calibration requested but not available for run "
156 << evtMetaData->getRun()
157 << " of experiment " << evtMetaData->getExperiment());
158 }
159 }
161 if (not m_moduleT0.isValid()) {
162 B2FATAL("Module T0 calibration requested but not available for run "
163 << evtMetaData->getRun()
164 << " of experiment " << evtMetaData->getExperiment());
165 }
166 }
168 if (not m_commonT0.isValid()) {
169 B2FATAL("Common T0 calibration requested but not available for run "
170 << evtMetaData->getRun()
171 << " of experiment " << evtMetaData->getExperiment());
172 }
173 }
174 if (not m_timeWalk.isValid()) {
175 // B2FATAL("Time-walk calibration is not available for run "
176 B2WARNING("Time-walk calibration is not available for run "
177 << evtMetaData->getRun()
178 << " of experiment " << evtMetaData->getExperiment());
179 }
180 if (m_pedestalRMS > 0 and not m_noises.isValid()) {
181 B2FATAL("Channel noise levels are not available for run "
182 << evtMetaData->getRun()
183 << " of experiment " << evtMetaData->getExperiment());
184 }
185
186 if (not m_feSetting.isValid()) {
187 B2FATAL("Front-end settings are not available for run "
188 << evtMetaData->getRun()
189 << " of experiment " << evtMetaData->getExperiment());
190 }
191
192 }
193
194
196 {
197
198 // get mappers
199
200 const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
201 const auto& chMapper = TOPGeometryPar::Instance()->getChannelMapper();
202 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
203
204 // clear TOPDigits
205
206 m_digits.clear();
207
208 // set storage windows in RawDigits if not already done in unpacker
209
210 for (auto& rawDigit : m_rawDigits) {
211 const auto* waveform = rawDigit.getRelated<TOPRawWaveform>();
212 if (waveform and rawDigit.getStorageWindows().empty()) {
213 rawDigit.setStorageWindows(waveform->getStorageWindows());
214 }
215 }
216
217 // set asic masks (asics and whole boardstacks masked in firmware for this event)
218
219 m_asicMask.create();
220 if (m_eventDebugs.getEntries() > 0) {
221 std::vector<unsigned short> masks(64, 0xFFFF);
222 for (const auto& eventDebug : m_eventDebugs) {
223 auto scrodID = eventDebug.getScrodID();
224 const auto* feemap = feMapper.getMap(scrodID);
225 if (not feemap) {
226 B2WARNING("TOPRawDigitConverter: No front-end map available."
227 << LogVar("scrodID", scrodID));
228 continue;
229 }
230 auto moduleID = feemap->getModuleID();
231 auto boardstack = feemap->getBoardstackNumber();
232 unsigned bs = (moduleID - 1) * 4 + boardstack;
233 if (bs < 64) {
234 masks[bs] = eventDebug.getAsicMask();
235 } else {
236 B2ERROR("TOPRawDigitConverter: Invalid global boardstack number."
237 << LogVar("bs", bs));
238 }
239 }
240 m_asicMask->set(masks);
241 }
242
243 // convert to TOPDigits
244
245 for (const auto& rawDigit : m_rawDigits) {
246
247 if (rawDigit.getErrorFlags() != 0) continue;
248
249 // determine moduleID, pixedID and channel
250
251 auto scrodID = rawDigit.getScrodID();
252 const auto* feemap = feMapper.getMap(scrodID);
253 if (not feemap) {
254 B2WARNING("TOPRawDigitConverter: No front-end map available."
255 << LogVar("scrodID", scrodID));
256 continue;
257 }
258 auto moduleID = feemap->getModuleID();
259 auto boardstack = feemap->getBoardstackNumber();
260 auto channel = chMapper.getChannel(boardstack,
261 rawDigit.getCarrierNumber(),
262 rawDigit.getASICNumber(),
263 rawDigit.getASICChannel());
264 auto pixelID = chMapper.getPixelID(channel);
265
266 // get raw times
267
268 double rawTimeLeading = rawDigit.getCFDLeadingTime(); // time in [samples]
269 double rawTimeFalling = rawDigit.getCFDFallingTime(); // time in [samples]
270
271 // get ASIC window
272
273 int window = rawDigit.getASICWindow();
274
275 // timing alignment: set time origin according to data type
276
277 double timeOffset = 0;
278 int storageDepth = m_storageDepth;
279 if (rawDigit.getDataType() == TOPRawDigit::c_Interim) {
280
281 // correct raw times for possible window discontinuity
282 rawTimeLeading = rawDigit.correctTime(rawTimeLeading, m_storageDepth);
283 rawTimeFalling = rawDigit.correctTime(rawTimeFalling, m_storageDepth);
284
285 // set window number: number of look back windows back from the last write address
286 int lastWriteAddr = rawDigit.getLastWriteAddr();
287 int nback = lastWriteAddr - window;
288 if (nback < 0) nback += m_storageDepth;
289 int lookBackWindows = m_feSetting->getLookbackWindows();
290 if (m_lookBackWindows > 0) lookBackWindows = m_lookBackWindows;
291 int nwin = lookBackWindows - nback;
292 window -= nwin;
293 if (window < 0) window += m_storageDepth;
294 if (window >= (int) m_storageDepth) window -= m_storageDepth;
295
296 // add samples to raw time to account for the new window number
297 rawTimeLeading += nwin * TOPRawDigit::c_WindowSize;
298 rawTimeFalling += nwin * TOPRawDigit::c_WindowSize;
299 } else if (rawDigit.getDataType() == TOPRawDigit::c_ProductionDebug) {
300
301 // take revo9 counter and calculate corresponding SST count and its fraction
302 int revo9cnt = rawDigit.getRevo9Counter();
303 int SSTcnt = revo9cnt / 6;
304 double SSTfrac = (revo9cnt % 6) / 6.0;
305 double offset = m_feSetting->getOffset() / 24.0;
306 timeOffset = (SSTfrac + offset) * m_syncTimeBase; // in [ns], to be subtracted
307
308 // find reference window
309 int refWindow = SSTcnt * 2; // seems to be the same as lastWriteAddr
310 const auto& writeDepths = m_feSetting->getWriteDepths();
311 if (writeDepths.empty()) {
312 B2ERROR("TOPRawDigitConverter: vector of write depths is empty. Return!");
313 return;
314 }
315 int lastDepth = writeDepths.back();
316 unsigned phase = 0;
317 for (auto depth : writeDepths) {
318 SSTcnt -= depth;
319 if (SSTcnt < 0) break;
320 phase++;
321 refWindow = SSTcnt * 2;
322 lastDepth = depth;
323 }
324 if (m_setPhase) const_cast<TOPRawDigit&>(rawDigit).setPhase(phase);
325 storageDepth = lastDepth * 2;
326
327 if (window >= storageDepth) {
328 B2WARNING("TOPRawDigitConverter: window number greater than storage depth."
329 << LogVar("window number", window)
330 << LogVar("storage depth", storageDepth)
331 << LogVar("refWindow", refWindow)
332 << LogVar("phase", phase));
333 continue;
334 }
335
336 // set window number: number of look back windows back from the reference window
337 int deltaWindow = window - refWindow;
338 if (deltaWindow > 0) deltaWindow -= storageDepth;
339 int lookBackWindows = m_feSetting->getLookbackWindows();
340 if (m_lookBackWindows > 0) lookBackWindows = m_lookBackWindows;
341 lookBackWindows -= m_feSetting->getExtraWindows();
342
343 int nwin = lookBackWindows + deltaWindow;
344 int startWindow = refWindow - lookBackWindows;
345 if (startWindow < 0) startWindow += storageDepth;
346 window = startWindow;
347
348 // add samples to raw time to account for the new window number
349 rawTimeLeading += nwin * TOPRawDigit::c_WindowSize;
350 rawTimeFalling += nwin * TOPRawDigit::c_WindowSize;
351 }
352
353 // convert raw time to time using equidistant or calibrated time base
354
355 unsigned short statusBits = 0;
356 const auto* sampleTimes = &m_sampleTimes; // equidistant sample times
358 sampleTimes = m_timebase->getSampleTimes(scrodID, channel % 128);
359 if (sampleTimes->isCalibrated()) {
360 statusBits |= TOPDigit::c_TimeBaseCalibrated;
361 }
362 }
363 // time and width in [ns]
364 double time = sampleTimes->getTime(window, rawTimeLeading) - timeOffset;
365 double width = sampleTimes->getDeltaTime(window, rawTimeFalling, rawTimeLeading);
366
367 // default time uncertainty
368 double timeError = geo->getNominalTDC().getTimeJitter();
369
370 if (rawDigit.getDataType() == TOPRawDigit::c_MC) {
371 // MC with simplified digitization
372 time -= geo->getNominalTDC().getOffset();
373 statusBits |= TOPDigit::c_OffsetSubtracted;
374 } else {
375 // data and MC with full waveform digitization
376 if (m_pedestalRMS > 0) {
377 double rmsNoise = m_pedestalRMS;
378 if (m_noises->isCalibrated(moduleID, channel)) {
379 rmsNoise = m_noises->getNoise(moduleID, channel);
380 }
381 double rawErr = rawDigit.getCFDLeadingTimeError(rmsNoise); // in [samples]
382 int sample = static_cast<int>(rawTimeLeading);
383 if (rawTimeLeading < 0) sample--;
384 timeError = rawErr * sampleTimes->getTimeBin(window, sample); // [ns]
385 }
386
387 auto pulseHeight = rawDigit.getValuePeak();
388 double timeErrorSq = timeError * timeError;
389 if (m_timeWalk.isValid()) timeErrorSq += m_timeWalk->getSigmaSq(pulseHeight);
390
391 if (m_useTimeWalkCalibration and m_timeWalk.isValid()) {
392 if (m_timeWalk->isCalibrated()) {
393 time -= m_timeWalk->getTimeWalk(pulseHeight);
394 }
395 }
397 const auto& cal = m_channelT0;
398 if (cal->isCalibrated(moduleID, channel)) {
399 time -= cal->getT0(moduleID, channel);
400 double err = cal->getT0Error(moduleID, channel);
401 timeErrorSq += err * err;
402 statusBits |= TOPDigit::c_ChannelT0Calibrated;
403 }
404 }
406 auto asic = channel / 8;
407 if (m_asicShift->isCalibrated(moduleID, asic)) {
408 time -= m_asicShift->getT0(moduleID, asic);
409 }
410 }
412 const auto& cal = m_moduleT0;
413 if (cal->isCalibrated(moduleID)) {
414 time -= cal->getT0(moduleID);
415 double err = cal->getT0Error(moduleID);
416 timeErrorSq += err * err;
417 statusBits |= TOPDigit::c_ModuleT0Calibrated;
418 }
419 }
421 const auto& cal = m_commonT0;
422 if (cal->isCalibrated()) {
423 time -= cal->getT0();
424 double err = cal->getT0Error();
425 timeErrorSq += err * err;
426 statusBits |= TOPDigit::c_CommonT0Calibrated;
427 }
428 }
429 timeError = sqrt(timeErrorSq);
430 }
431
432 // append new TOPDigit and set it
433
434 auto* digit = m_digits.appendNew(moduleID, pixelID, rawTimeLeading);
435 digit->setTime(time);
436 digit->setTimeError(timeError);
437 digit->setPulseHeight(rawDigit.getValuePeak());
438 digit->setIntegral(rawDigit.getIntegral());
439 digit->setPulseWidth(width);
440 digit->setChannel(channel);
441 digit->setFirstWindow(window);
442 digit->setStatus(statusBits);
443 if (m_addRelations) digit->addRelationTo(&rawDigit);
444
445 if (not rawDigit.isFEValid() or rawDigit.isPedestalJump())
446 digit->setHitQuality(TOPDigit::c_Junk);
447 if (rawDigit.isAtWindowDiscontinuity(storageDepth))
448 digit->setHitQuality(TOPDigit::c_Junk);
449 if (digit->getPulseWidth() < m_minPulseWidth or
450 digit->getPulseWidth() > m_maxPulseWidth or
451 digit->getPulseWidth() * digit->getPulseHeight() < m_minWidthXheight)
452 digit->setHitQuality(TOPDigit::c_Junk);
453 }
454
455 // if calibration channel given, select and flag cal pulses
456
457 unsigned calibrationChannel = m_calibrationChannel;
458 if (calibrationChannel < 8) {
459 for (auto& digit : m_digits) {
460 if (digit.getHitQuality() != TOPDigit::c_Good) continue;
461 if (digit.getASICChannel() != calibrationChannel) continue;
462 if (digit.getPulseHeight() < m_calpulseHeightMin) continue;
463 if (digit.getPulseHeight() > m_calpulseHeightMax) continue;
464 if (digit.getPulseWidth() < m_calpulseWidthMin) continue;
465 if (digit.getPulseWidth() > m_calpulseWidthMax) continue;
467 if (digit.getTime() < m_calpulseTimeMin) continue;
468 if (digit.getTime() > m_calpulseTimeMax) continue;
469 }
470 digit.setHitQuality(TOPDigit::c_CalPulse);
471 }
472 }
473
474 }
475
476
478 {
479 }
480
482 {
483 }
484
485
487} // end Belle2 namespace
488
Base class for Modules.
Definition: Module.h:72
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
@ 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
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
double m_pedestalRMS
r.m.s of pedestals [ADC counts]
StoreArray< TOPRawDigit > m_rawDigits
collection of raw digits
DBObjPtr< TOPCalTimebase > m_timebase
sample time calibration constants
int m_lookBackWindows
number of "look back" windows
DBObjPtr< TOPCalAsicShift > m_asicShift
ASIC shifts calibration constants.
DBObjPtr< TOPFrontEndSetting > m_feSetting
front-end settings
double m_maxPulseWidth
max pulse width to set digit as good [ns]
int m_calpulseHeightMax
maximal height of calibration pulse
double m_calpulseWidthMax
maximal width of calibration pulse
DBObjPtr< TOPCalCommonT0 > m_commonT0
common T0 calibration constants
bool m_useAsicShiftCalibration
if true, use asic shifts calibration
double m_minPulseWidth
min pulse width to set digit as good [ns]
bool m_useSampleTimeCalibration
if true, use sample time calibration
DBObjPtr< TOPCalChannelT0 > m_channelT0
channel T0 calibration constants
bool m_useTimeWalkCalibration
if true, use time-walk calibration
DBObjPtr< TOPCalChannelNoise > m_noises
r.m.s.
StoreArray< TOPProductionEventDebug > m_eventDebugs
collection of debug data
double m_calpulseTimeMin
minimal time of calibration pulse
int m_calpulseHeightMin
minimal height of calibration pulse
std::string m_outputDigitsName
name of TOPDigit store array
std::string m_inputRawDigitsName
name of TOPRawDigit store array
OptionalDBObjPtr< TOPCalTimeWalk > m_timeWalk
time-walk calibration constants
bool m_useChannelT0Calibration
if true, use channel T0 calibration
bool m_useCommonT0Calibration
if true, use common T0 calibration
bool m_useModuleT0Calibration
if true, use module T0 calibration
StoreArray< TOPDigit > m_digits
collection of digits
DBObjPtr< TOPCalModuleT0 > m_moduleT0
module T0 calibration constants
int m_calibrationChannel
ASIC channel number with calibration pulse.
double m_calpulseWidthMin
minimal width of calibration pulse
double m_minWidthXheight
minimal width * height [ns * ADC counts]
StoreObjPtr< TOPAsicMask > m_asicMask
masked asics in firmware
bool m_setPhase
if true, set phase in TOPRawDigits
double m_calpulseTimeMax
maximal time of calibration pulse
bool m_addRelations
switch ON/OFF relations to TOPRawDigits
TOPSampleTimes m_sampleTimes
equidistant in case no calibration required
unsigned m_storageDepth
ASIC analog storage depth.
Class to store unpacked raw data (hits in feature-extraction format) It provides also calculation of ...
Definition: TOPRawDigit.h:24
@ c_Interim
from interim feature extraction
Definition: TOPRawDigit.h:44
@ c_ProductionDebug
from production debugging format
Definition: TOPRawDigit.h:46
@ c_MC
from MC digitization
Definition: TOPRawDigit.h:43
@ c_WindowSize
number of samples per window
Definition: TOPRawDigit.h:54
Class to store raw data waveforms.
void setStorageWindows(const std::vector< unsigned short > &windows)
Sets storage window numbers.
const TOPGeometry * getGeometry() const
Returns pointer to geometry object using basf2 units.
const ChannelMapper & getChannelMapper() const
Returns default channel mapper (mapping of channels to pixels)
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
const FrontEndMapper & getFrontEndMapper() const
Returns front-end mapper (mapping of SCROD's to positions within TOP modules)
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:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
virtual void initialize() override
Initialize the Module.
virtual void event() override
Event processor.
virtual void endRun() override
End-of-run action.
virtual void terminate() override
Termination action.
virtual void beginRun() override
Called when entering a new run.
void setTimeAxis(double syncTimeBase)
Sets equidistant time axis (uncalibrated).
Abstract base class for different kinds of events.
STL namespace.