Belle II Software  release-08-01-10
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 
28 using namespace std;
29 
30 namespace Belle2 {
36  using namespace TOP;
37 
38  //-----------------------------------------------------------------
40  //-----------------------------------------------------------------
41 
42  REG_MODULE(TOPRawDigitConverter);
43 
44  //-----------------------------------------------------------------
45  // Implementation
46  //-----------------------------------------------------------------
47 
48  TOPRawDigitConverterModule::TOPRawDigitConverterModule() : Module()
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
118  m_rawDigits.isRequired(m_inputRawDigitsName);
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 FrontEndMapper & getFrontEndMapper() const
Returns front-end mapper (mapping of SCROD's to positions within TOP modules)
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
const ChannelMapper & getChannelMapper() const
Returns default channel mapper (mapping of channels to pixels)
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.