Belle II Software  release-05-02-19
TOPRawDigitConverterModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2016 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Marko Staric *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 // Own include
12 #include <top/modules/TOPRawDigitConverter/TOPRawDigitConverterModule.h>
13 
14 // framework - DataStore
15 #include <framework/datastore/StoreArray.h>
16 #include <framework/datastore/StoreObjPtr.h>
17 
18 // framework aux
19 #include <framework/logging/Logger.h>
20 
21 // Dataobject classes
22 #include <top/dataobjects/TOPRawDigit.h>
23 #include <top/dataobjects/TOPRawWaveform.h>
24 #include <top/dataobjects/TOPDigit.h>
25 #include <framework/dataobjects/EventMetaData.h>
26 
27 #include <top/geometry/TOPGeometryPar.h>
28 
29 
30 using namespace std;
31 
32 namespace Belle2 {
38  using namespace TOP;
39 
40  //-----------------------------------------------------------------
41  // Register module
42  //-----------------------------------------------------------------
43 
44  REG_MODULE(TOPRawDigitConverter)
45 
46  //-----------------------------------------------------------------
47  // Implementation
48  //-----------------------------------------------------------------
49 
51 
52  {
53  // set module description (e.g. insert text)
54  setDescription("Converts row digits to digits and applies time calibration");
55  setPropertyFlags(c_ParallelProcessingCertified);
56 
57  // Add parameters
58  addParam("inputRawDigitsName", m_inputRawDigitsName,
59  "name of TOPRawDigit store array", string(""));
60  addParam("outputDigitsName", m_outputDigitsName,
61  "name of TOPDigit store array", string(""));
62  addParam("useSampleTimeCalibration", m_useSampleTimeCalibration,
63  "if true, use sample time calibration", true);
64  addParam("useAsicShiftCalibration", m_useAsicShiftCalibration,
65  "if true, use ASIC shifts calibration", true);
66  addParam("useChannelT0Calibration", m_useChannelT0Calibration,
67  "if true, use channel T0 calibration", true);
68  addParam("useModuleT0Calibration", m_useModuleT0Calibration,
69  "if true, use module T0 calibration", true);
70  addParam("useCommonT0Calibration", m_useCommonT0Calibration,
71  "if true, use common T0 calibration", true);
72  addParam("useTimeWalkCalibration", m_useTimeWalkCalibration,
73  "if true, use time-walk calibration", true);
74  addParam("pedestalRMS", m_pedestalRMS,
75  "r.m.s of pedestals [ADC counts], "
76  "if positive, timeError will be estimated from FE data. "
77  "This is the default value used if r.m.s is not available from DB.", 9.7);
78  addParam("minPulseWidth", m_minPulseWidth,
79  "minimal pulse width [ns] to flag digit as good", 1.0);
80  addParam("maxPulseWidth", m_maxPulseWidth,
81  "maximal pulse width [ns] to flag digit as good", 10.0);
82  addParam("minWidthXheight", m_minWidthXheight,
83  "minimal product of width and height [ns * ADC counts]", 100.0);
84  addParam("storageDepth", m_storageDepth,
85  "ASIC analog storage depth of Interim FE format (ignored in other formats)",
86  (unsigned) 508);
87  addParam("lookBackWindows", m_lookBackWindows,
88  "number of look back windows, if positive override the number from database",
89  0);
90  addParam("setPhase", m_setPhase,
91  "if true, set (override) phase in TOPRawDigits", true);
92  addParam("calibrationChannel", m_calibrationChannel,
93  "calpulse selection: ASIC channel (use -1 to turn off the selection)", -1);
94  addParam("calpulseWidthMin", m_calpulseWidthMin,
95  "calpulse selection: minimal width [ns]", 0.0);
96  addParam("calpulseWidthMax", m_calpulseWidthMax,
97  "calpulse selection: maximal width [ns]", 0.0);
98  addParam("calpulseHeightMin", m_calpulseHeightMin,
99  "calpulse selection: minimal height [ADC counts]", 0);
100  addParam("calpulseHeightMax", m_calpulseHeightMax,
101  "calpulse selection: maximal height [ADC counts]", 0);
102  addParam("calpulseTimeMin", m_calpulseTimeMin,
103  "calpulse selection (ON if max > min): minimal time [ns]", 0.0);
104  addParam("calpulseTimeMax", m_calpulseTimeMax,
105  "calpulse selection (ON if max > min): maximal time [ns]", 0.0);
106  }
107 
108 
109  TOPRawDigitConverterModule::~TOPRawDigitConverterModule()
110  {
111  }
112 
113 
114  void TOPRawDigitConverterModule::initialize()
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();
127  m_sampleTimes.setTimeAxis(m_syncTimeBase);
128 
129  }
130 
131 
132  void TOPRawDigitConverterModule::beginRun()
133  {
134 
135  StoreObjPtr<EventMetaData> evtMetaData;
136 
137  // check if calibrations are available when needed - if not, terminate
138 
139  if (m_useSampleTimeCalibration) {
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  }
146  if (m_useChannelT0Calibration) {
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  }
153  if (m_useAsicShiftCalibration) {
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  }
160  if (m_useModuleT0Calibration) {
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  }
167  if (m_useCommonT0Calibration) {
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 
195  void TOPRawDigitConverterModule::event()
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  continue;
332  }
333 
334  // set window number: number of look back windows back from the reference window
335  int deltaWindow = window - refWindow;
336  if (deltaWindow > 0) deltaWindow -= storageDepth;
337  int lookBackWindows = m_feSetting->getLookbackWindows();
338  if (m_lookBackWindows > 0) lookBackWindows = m_lookBackWindows;
339  lookBackWindows -= m_feSetting->getExtraWindows();
340 
341  int nwin = lookBackWindows + deltaWindow;
342  int startWindow = refWindow - lookBackWindows;
343  if (startWindow < 0) startWindow += storageDepth;
344  window = startWindow;
345 
346  // add samples to raw time to account for the new window number
347  rawTimeLeading += nwin * TOPRawDigit::c_WindowSize;
348  rawTimeFalling += nwin * TOPRawDigit::c_WindowSize;
349  }
350 
351  // convert raw time to time using equidistant or calibrated time base
352 
353  unsigned short statusBits = 0;
354  const auto* sampleTimes = &m_sampleTimes; // equidistant sample times
355  if (m_useSampleTimeCalibration) {
356  sampleTimes = m_timebase->getSampleTimes(scrodID, channel % 128);
357  if (sampleTimes->isCalibrated()) {
358  statusBits |= TOPDigit::c_TimeBaseCalibrated;
359  }
360  }
361  // time and width in [ns]
362  double time = sampleTimes->getTime(window, rawTimeLeading) - timeOffset;
363  double width = sampleTimes->getDeltaTime(window, rawTimeFalling, rawTimeLeading);
364 
365  // default time uncertainty
366  double timeError = geo->getNominalTDC().getTimeJitter();
367 
368  if (rawDigit.getDataType() == TOPRawDigit::c_MC) {
369  // MC with simplified digitization
370  time -= geo->getNominalTDC().getOffset();
371  statusBits |= TOPDigit::c_OffsetSubtracted;
372  } else {
373  // data and MC with full waveform digitization
374  if (m_pedestalRMS > 0) {
375  double rmsNoise = m_pedestalRMS;
376  if (m_noises->isCalibrated(moduleID, channel)) {
377  rmsNoise = m_noises->getNoise(moduleID, channel);
378  }
379  double rawErr = rawDigit.getCFDLeadingTimeError(rmsNoise); // in [samples]
380  int sample = static_cast<int>(rawTimeLeading);
381  if (rawTimeLeading < 0) sample--;
382  timeError = rawErr * sampleTimes->getTimeBin(window, sample); // [ns]
383  }
384 
385  auto pulseHeight = rawDigit.getValuePeak();
386  double timeErrorSq = timeError * timeError;
387  if (m_timeWalk.isValid()) timeErrorSq += m_timeWalk->getSigmaSq(pulseHeight);
388 
389  if (m_useTimeWalkCalibration and m_timeWalk.isValid()) {
390  if (m_timeWalk->isCalibrated()) {
391  time -= m_timeWalk->getTimeWalk(pulseHeight);
392  }
393  }
394  if (m_useChannelT0Calibration) {
395  const auto& cal = m_channelT0;
396  if (cal->isCalibrated(moduleID, channel)) {
397  time -= cal->getT0(moduleID, channel);
398  double err = cal->getT0Error(moduleID, channel);
399  timeErrorSq += err * err;
400  statusBits |= TOPDigit::c_ChannelT0Calibrated;
401  }
402  }
403  if (m_useAsicShiftCalibration) {
404  auto asic = channel / 8;
405  if (m_asicShift->isCalibrated(moduleID, asic)) {
406  time -= m_asicShift->getT0(moduleID, asic);
407  }
408  }
409  if (m_useModuleT0Calibration) {
410  const auto& cal = m_moduleT0;
411  if (cal->isCalibrated(moduleID)) {
412  time -= cal->getT0(moduleID);
413  double err = cal->getT0Error(moduleID);
414  timeErrorSq += err * err;
415  statusBits |= TOPDigit::c_ModuleT0Calibrated;
416  }
417  }
418  if (m_useCommonT0Calibration) {
419  const auto& cal = m_commonT0;
420  if (cal->isCalibrated()) {
421  time -= cal->getT0();
422  double err = cal->getT0Error();
423  timeErrorSq += err * err;
424  statusBits |= TOPDigit::c_CommonT0Calibrated;
425  }
426  }
427  timeError = sqrt(timeErrorSq);
428  }
429 
430  // append new TOPDigit and set it
431 
432  auto* digit = m_digits.appendNew(moduleID, pixelID, rawTimeLeading);
433  digit->setTime(time);
434  digit->setTimeError(timeError);
435  digit->setPulseHeight(rawDigit.getValuePeak());
436  digit->setIntegral(rawDigit.getIntegral());
437  digit->setPulseWidth(width);
438  digit->setChannel(channel);
439  digit->setFirstWindow(window);
440  digit->setStatus(statusBits);
441  digit->addRelationTo(&rawDigit);
442 
443  if (not rawDigit.isFEValid() or rawDigit.isPedestalJump())
444  digit->setHitQuality(TOPDigit::c_Junk);
445  if (rawDigit.isAtWindowDiscontinuity(storageDepth))
446  digit->setHitQuality(TOPDigit::c_Junk);
447  if (digit->getPulseWidth() < m_minPulseWidth or
448  digit->getPulseWidth() > m_maxPulseWidth or
449  digit->getPulseWidth() * digit->getPulseHeight() < m_minWidthXheight)
450  digit->setHitQuality(TOPDigit::c_Junk);
451  }
452 
453  // if calibration channel given, select and flag cal pulses
454 
455  unsigned calibrationChannel = m_calibrationChannel;
456  if (calibrationChannel < 8) {
457  for (auto& digit : m_digits) {
458  if (digit.getHitQuality() != TOPDigit::c_Good) continue;
459  if (digit.getASICChannel() != calibrationChannel) continue;
460  if (digit.getPulseHeight() < m_calpulseHeightMin) continue;
461  if (digit.getPulseHeight() > m_calpulseHeightMax) continue;
462  if (digit.getPulseWidth() < m_calpulseWidthMin) continue;
463  if (digit.getPulseWidth() > m_calpulseWidthMax) continue;
464  if (m_calpulseTimeMax > m_calpulseTimeMin) {
465  if (digit.getTime() < m_calpulseTimeMin) continue;
466  if (digit.getTime() > m_calpulseTimeMax) continue;
467  }
468  digit.setHitQuality(TOPDigit::c_CalPulse);
469  }
470  }
471 
472  }
473 
474 
475  void TOPRawDigitConverterModule::endRun()
476  {
477  }
478 
479  void TOPRawDigitConverterModule::terminate()
480  {
481  }
482 
483 
485 } // end Belle2 namespace
486 
Belle2::TOPRawDigitConverterModule
TOPRawDigits to TOPDigits converter.
Definition: TOPRawDigitConverterModule.h:50
Belle2::TOPRawWaveform::setStorageWindows
void setStorageWindows(const std::vector< unsigned short > &windows)
Sets storage window numbers.
Definition: TOPRawWaveform.h:106
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::TOPRawWaveform
Class to store raw data waveforms.
Definition: TOPRawWaveform.h:34
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::TOPRawDigit
Class to store unpacked raw data (hits in feature-extraction format) It provides also calculation of ...
Definition: TOPRawDigit.h:34
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::StoreObjPtr
Type-safe access to single objects in the data store.
Definition: ParticleList.h:33
LogVar
Class to store variables with their name which were sent to the logging service.
Definition: LogVariableStream.h:24