Belle II Software  release-05-02-19
TOPDigitizerModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - 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 // Own include
11 #include <top/modules/TOPDigitizer/TOPDigitizerModule.h>
12 #include <top/geometry/TOPGeometryPar.h>
13 #include <top/modules/TOPDigitizer/TimeDigitizer.h>
14 
15 // framework - DataStore
16 #include <framework/datastore/DataStore.h>
17 #include <framework/datastore/StoreArray.h>
18 #include <framework/datastore/StoreObjPtr.h>
19 
20 // framework aux
21 #include <framework/logging/Logger.h>
22 
23 // ROOT
24 #include <TRandom.h>
25 
26 #include <map>
27 
28 using namespace std;
29 
30 namespace Belle2 {
36  using namespace TOP;
37 
38  //-----------------------------------------------------------------
39  // Register the Module
40  //-----------------------------------------------------------------
41 
42  REG_MODULE(TOPDigitizer)
43 
44 
45  //-----------------------------------------------------------------
46  // Implementation
47  //-----------------------------------------------------------------
48 
50  {
51  // Set description()
52  setDescription("Digitize TOPSimHits");
53  setPropertyFlags(c_ParallelProcessingCertified);
54 
55  // Add parameters
56  addParam("timeZeroJitter", m_timeZeroJitter,
57  "r.m.s of T0 jitter [ns]", 15e-3);
58  addParam("electronicJitter", m_electronicJitter,
59  "r.m.s of electronic jitter [ns], "
60  "if negative the one from TOPNominalTDC is used. "
61  "This parameter is ignored in the full waveform digitization.", -1.0);
62  addParam("darkNoise", m_darkNoise,
63  "uniformly distributed dark noise (hits per module)", 0.0);
64  addParam("ADCx0", m_ADCx0,
65  "pulse height distribution parameter [ADC counts]", 204.1);
66  addParam("ADCp1", m_ADCp1,
67  "pulse height distribution parameter (must be non-negative)", 1.0);
68  addParam("ADCp2", m_ADCp2,
69  "pulse height distribution parameter (must be non-negative)", 1.025);
70  addParam("ADCmax", m_ADCmax,
71  "pulse height distribution upper bound [ADC counts]", 2000.0);
72  addParam("rmsNoise", m_rmsNoise,
73  "r.m.s of noise [ADC counts]", 9.7);
74  addParam("threshold", m_threshold,
75  "pulse height threshold [ADC counts]", 40);
76  addParam("hysteresis", m_hysteresis,
77  "pulse height threshold hysteresis [ADC counts]", 10);
78  addParam("thresholdCount", m_thresholdCount,
79  "minimal number of samples above threshold", 3);
80  addParam("useWaveforms", m_useWaveforms,
81  "if true, use full waveform digitization", true);
82  addParam("allChannels", m_allChannels,
83  "if true, make waveforms for all 8192 channels "
84  "(note: this will slow-down digitization)", false);
85  addParam("useDatabase", m_useDatabase,
86  "if true, use channel dependent constants from database (incl. time base)",
87  true);
88  addParam("useSampleTimeCalibration", m_useSampleTimeCalibration,
89  "if true, use only time base calibration from database "
90  "(has no effect if useDatabase = True)", false);
91  addParam("simulateTTS", m_simulateTTS,
92  "if true, simulate time transition spread. "
93  "Should be always switched ON, except for some dedicated timing studies.",
94  true);
95  addParam("minWidthXheight", m_minWidthXheight,
96  "minimal product of width and height [ns * ADC counts]", 100.0);
97 
98  }
99 
100 
101  void TOPDigitizerModule::initialize()
102  {
103  // input from datastore
104  m_simHits.isRequired();
105  m_simCalPulses.isOptional();
106  m_mcParticles.isOptional();
107 
108  // output to datastore
109  m_rawDigits.registerInDataStore();
110  m_digits.registerInDataStore();
111  m_digits.registerRelationTo(m_simHits);
112  m_digits.registerRelationTo(m_mcParticles);
113  m_digits.registerRelationTo(m_rawDigits);
114  m_waveforms.registerInDataStore(DataStore::c_DontWriteOut);
115  m_rawDigits.registerRelationTo(m_waveforms, DataStore::c_Event,
116  DataStore::c_DontWriteOut);
117 
118  // geometry and nominal data
119  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
120 
121  if (m_electronicJitter < 0) {
122  m_electronicJitter = geo->getNominalTDC().getTimeJitter();
123  }
124 
125  // set pile-up and double hit resolution times (needed for BG overlay)
126  TOPDigit::setDoubleHitResolution(geo->getNominalTDC().getDoubleHitResolution());
127  TOPDigit::setPileupTime(geo->getNominalTDC().getPileupTime());
128 
129  // default sample times (equidistant)
130  m_syncTimeBase = geo->getNominalTDC().getSyncTimeBase();
131  m_sampleTimes.setTimeAxis(m_syncTimeBase); // equidistant time base
132 
133  // default pulse height generator
134  m_pulseHeightGenerator = PulseHeightGenerator(m_ADCx0, m_ADCp1, m_ADCp2, m_ADCmax);
135 
136  }
137 
138 
139  void TOPDigitizerModule::beginRun()
140  {
141  StoreObjPtr<EventMetaData> evtMetaData;
142 
143  // check availability of mappers
144  const auto& channelMapper = TOPGeometryPar::Instance()->getChannelMapper();
145  if (not channelMapper.isValid()) {
146  B2FATAL("No valid channel mapper found for run "
147  << evtMetaData->getRun()
148  << " of experiment " << evtMetaData->getExperiment());
149  }
150  const auto& frontEndMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
151  if (not frontEndMapper.isValid()) {
152  B2FATAL("No valid front-end mapper found for run "
153  << evtMetaData->getRun()
154  << " of experiment " << evtMetaData->getExperiment());
155  }
156 
157  // check availability of constants in database
158  if (m_useDatabase) {
159  if (not m_timebases.isValid()) {
160  B2FATAL("Sample time calibration constants requested but not available for run "
161  << evtMetaData->getRun()
162  << " of experiment " << evtMetaData->getExperiment());
163  }
164  if (not m_channelT0.isValid()) {
165  B2FATAL("Channel T0 calibration constants requested but not available for run "
166  << evtMetaData->getRun()
167  << " of experiment " << evtMetaData->getExperiment());
168  }
169  if (not m_asicShift.isValid()) {
170  B2FATAL("ASIC shifts calibration requested but not available for run "
171  << evtMetaData->getRun()
172  << " of experiment " << evtMetaData->getExperiment());
173  }
174  if (not m_moduleT0.isValid()) {
175  B2FATAL("Module T0 calibration constants requested but not available for run "
176  << evtMetaData->getRun()
177  << " of experiment " << evtMetaData->getExperiment());
178  }
179  if (not m_commonT0.isValid()) {
180  B2FATAL("Common T0 calibration constants requested but not available for run "
181  << evtMetaData->getRun()
182  << " of experiment " << evtMetaData->getExperiment());
183  }
184  if (not m_pulseHeights.isValid()) {
185  B2FATAL("Pulse height calibration constants requested but not available for run "
186  << evtMetaData->getRun()
187  << " of experiment " << evtMetaData->getExperiment());
188  }
189  if (not m_thresholds.isValid()) {
190  B2FATAL("Channel thresholds requested but not available for run "
191  << evtMetaData->getRun()
192  << " of experiment " << evtMetaData->getExperiment());
193  }
194  if (not m_noises.isValid()) {
195  B2FATAL("Channel noise levels requested but not available for run "
196  << evtMetaData->getRun()
197  << " of experiment " << evtMetaData->getExperiment());
198  }
199  if (m_timeWalk.isValid()) {
200  TimeDigitizer::setTimeWalk(&m_timeWalk);
201  } else {
202  TimeDigitizer::setTimeWalk(0);
203  // B2FATAL("Time-walk parameters requested but not available for run "
204  B2WARNING("Time-walk parameters not available for run "
205  << evtMetaData->getRun()
206  << " of experiment " << evtMetaData->getExperiment());
207  }
208  } else if (m_useSampleTimeCalibration) {
209  if (not m_timebases.isValid()) {
210  B2FATAL("Sample time calibration constants requested but not available for run "
211  << evtMetaData->getRun()
212  << " of experiment " << evtMetaData->getExperiment());
213  }
214  }
215 
216  // check availability of front-end settings
217  if (not m_feSetting.isValid()) {
218  B2FATAL("Front-end settings are not available for run "
219  << evtMetaData->getRun()
220  << " of experiment " << evtMetaData->getExperiment());
221  }
222 
223  // pass a parameter to TimeDigitizer
224  TimeDigitizer::setReadoutWindows(m_feSetting->getReadoutWindows());
225  if ((evtMetaData->getExperiment() > 0 and evtMetaData->getExperiment() < 5) or
226  evtMetaData->getExperiment() == 1002) {
227  TimeDigitizer::maskSamples(true); // phase-2: mask samples at window boundaries
228  } else {
229  TimeDigitizer::maskSamples(false); // phase-3: no masking
230  }
231 
232  }
233 
234  void TOPDigitizerModule::event()
235  {
236 
237  // generate revo9 count
238  unsigned revo9cnt = gRandom->Integer(11520);
239 
240  // from revo9 count determine trigger time offset and the number of offset windows
241  double SSTfrac = (revo9cnt % 6) / 6.0;
242  double offset = m_feSetting->getOffset() / 24.0;
243  double trgTimeOffset = (SSTfrac + offset) * m_syncTimeBase; // in [ns]
244  int offsetWindows = m_feSetting->getWindowShift(revo9cnt);
245  TimeDigitizer::setOffsetWindows(offsetWindows);
246 
247  // from revo9 and write depths determine reference window, phase and storage depth
248  int SSTcnt = revo9cnt / 6;
249  int refWindow = SSTcnt * 2; // same as lastWriteAddr
250  const auto& writeDepths = m_feSetting->getWriteDepths();
251  if (writeDepths.empty()) {
252  B2ERROR("TOPDigitzer: vector of write depths is empty. No digitization possible");
253  return;
254  }
255  int lastDepth = writeDepths.back();
256  unsigned phase = 0;
257  for (auto depth : writeDepths) {
258  SSTcnt -= depth;
259  if (SSTcnt < 0) break;
260  phase++;
261  refWindow = SSTcnt * 2;
262  lastDepth = depth;
263  }
264  unsigned storageDepth = lastDepth * 2;
265  TimeDigitizer::setStorageDepth(storageDepth);
266 
267  // from reference window and lookback determine first of the readout windows
268  int lookBackWindows = m_feSetting->getLookbackWindows() -
269  m_feSetting->getExtraWindows();
270  int window = refWindow - lookBackWindows;
271  if (window < 0) window += storageDepth;
272  TimeDigitizer::setFirstWindow(window);
273 
274  // geometry and nominal data
275  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
276 
277  // time range for digitization
278  double timeMin = geo->getSignalShape().getTMin() + offsetWindows * m_syncTimeBase / 2;
279  double timeMax = geo->getSignalShape().getTMax() +
280  (m_feSetting->getReadoutWindows() + offsetWindows) * m_syncTimeBase / 2;
281 
282  // simulate start time jitter
283  double startTimeJitter = gRandom->Gaus(0, m_timeZeroJitter);
284 
285  // get electronic efficiency
286  double electronicEfficiency = geo->getNominalTDC().getEfficiency();
287 
288  // define pixels with time digitizers
289  std::map<unsigned, TimeDigitizer> pixels;
290  typedef std::map<unsigned, TimeDigitizer>::iterator Iterator;
291 
292  // add simulated hits to time digitizers
293 
294  for (const auto& simHit : m_simHits) {
295  if (not m_useWaveforms) {
296  // simulate electronic efficiency
297  if (gRandom->Rndm() > electronicEfficiency) continue;
298  }
299  // do spatial digitization
300  double x = simHit.getX();
301  double y = simHit.getY();
302  int pmtID = simHit.getPmtID();
303  int moduleID = simHit.getModuleID();
304  if (not geo->isModuleIDValid(moduleID)) continue;
305  int pixelID = geo->getModule(moduleID).getPMTArray().getPixelID(x, y, pmtID);
306  if (pixelID == 0) continue;
307 
308  // add start time jitter and generated TTS to photon time
309  double time = simHit.getTime() + startTimeJitter;
310  if (m_simulateTTS) {
311  const auto& tts = TOPGeometryPar::Instance()->getTTS(moduleID, pmtID);
312  time += tts.generateTTS();
313  }
314 
315  // get time offset for a given pixel
316  auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
317 
318  // time range cut (to speed up digitization)
319  if (time + timeOffset.value < timeMin + timeOffset.timeShift) continue;
320  if (time + timeOffset.value > timeMax + timeOffset.timeShift) continue;
321 
322  // generate pulse height
323  double pulseHeight = generatePulseHeight(moduleID, pixelID);
324  auto hitType = TimeDigitizer::c_Hit;
325 
326  // add time and pulse height to digitizer of a given pixel
327  TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
328  timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
329  if (not digitizer.isValid()) continue;
330  unsigned id = digitizer.getUniqueID();
331  Iterator it = pixels.insert(pair<unsigned, TimeDigitizer>(id, digitizer)).first;
332  it->second.addTimeOfHit(time, pulseHeight, hitType, &simHit);
333  }
334 
335  // add calibration pulses
336 
337  for (const auto& simCalPulses : m_simCalPulses) {
338  auto moduleID = simCalPulses.getModuleID();
339  auto pixelID = simCalPulses.getPixelID();
340  auto pulseHeight = simCalPulses.getAmplitude();
341  auto time = simCalPulses.getTime();
342  auto hitType = TimeDigitizer::c_CalPulse;
343 
344  // get time offset for a given pixel
345  auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
346 
347  // time range cut (to speed up digitization)
348  if (time + timeOffset.value < timeMin + timeOffset.timeShift) continue;
349  if (time + timeOffset.value > timeMax + timeOffset.timeShift) continue;
350 
351  // add time and pulse height to digitizer of a given pixel
352  TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
353  timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
354  if (not digitizer.isValid()) continue;
355  unsigned id = digitizer.getUniqueID();
356  Iterator it = pixels.insert(pair<unsigned, TimeDigitizer>(id, digitizer)).first;
357  it->second.addTimeOfHit(time, pulseHeight, hitType);
358  }
359 
360  // add randomly distributed dark noise (maybe not needed anymore?)
361 
362  if (m_darkNoise > 0) {
363  int numModules = geo->getNumModules();
364  for (int moduleID = 1; moduleID <= numModules; moduleID++) {
365  int numPixels = geo->getModule(moduleID).getPMTArray().getNumPixels();
366  int numHits = gRandom->Poisson(m_darkNoise);
367  for (int i = 0; i < numHits; i++) {
368  int pixelID = int(gRandom->Rndm() * numPixels) + 1;
369  double time = (timeMax - timeMin) * gRandom->Rndm() + timeMin;
370  double pulseHeight = generatePulseHeight(moduleID, pixelID);
371  auto hitType = TimeDigitizer::c_Hit;
372  auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
373  time += timeOffset.timeShift;
374  time -= timeOffset.value;
375  TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
376  timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
377  if (not digitizer.isValid()) continue;
378  unsigned id = digitizer.getUniqueID();
379  Iterator it = pixels.insert(pair<unsigned, TimeDigitizer>(id, digitizer)).first;
380  it->second.addTimeOfHit(time, pulseHeight, hitType);
381  }
382  }
383  }
384 
385  // if making waveforms for all channels, add missing digitizers.
386 
387  if (m_allChannels) {
388  int numModules = geo->getNumModules();
389  for (int moduleID = 1; moduleID <= numModules; moduleID++) {
390  int numPixels = geo->getModule(moduleID).getPMTArray().getNumPixels();
391  for (int pixelID = 1; pixelID <= numPixels; pixelID++) {
392  auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
393  TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
394  timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
395  if (not digitizer.isValid()) continue;
396  unsigned id = digitizer.getUniqueID();
397  pixels.insert(pair<unsigned, TimeDigitizer>(id, digitizer));
398  }
399  }
400  }
401 
402  // replace equidistant time base with calibrated one if available
403 
404  if (m_useDatabase or m_useSampleTimeCalibration) {
405  for (auto& pixel : pixels) {
406  auto& digitizer = pixel.second;
407  const auto* sampleTimes = m_timebases->getSampleTimes(digitizer.getScrodID(),
408  digitizer.getChannel());
409  if (not sampleTimes) continue;
410  if (sampleTimes->isCalibrated()) digitizer.setSampleTimes(sampleTimes);
411  }
412  }
413 
414  // replace default noise level with channel dependent one if available,
415 
416  if (m_useDatabase) {
417  for (auto& pixel : pixels) {
418  auto& digitizer = pixel.second;
419  auto moduleID = digitizer.getModuleID();
420  auto channel = digitizer.getChannel();
421  auto rmsNoise = m_noises->getNoise(moduleID, channel);
422  if (rmsNoise > 0) {
423  digitizer.setNoise(rmsNoise);
424  }
425  }
426  }
427 
428  // digitize in time
429 
430  for (auto& pixel : pixels) {
431  const auto& digitizer = pixel.second;
432  int threshold = m_threshold;
433  if (m_useDatabase) { // use channel dependent ones
434  threshold = m_thresholds->getThr(digitizer.getModuleID(), digitizer.getChannel());
435  if (threshold <= 0) threshold = m_threshold; // not available, use the default
436  }
437  if (m_useWaveforms) {
438  digitizer.digitize(m_waveforms, m_rawDigits, m_digits,
439  threshold, m_hysteresis, m_thresholdCount);
440  } else {
441  digitizer.digitize(m_rawDigits, m_digits,
442  threshold, m_thresholdCount, m_electronicJitter);
443  }
444  }
445 
446  // set additional info
447 
448  for (auto& rawDigit : m_rawDigits) {
449  rawDigit.setRevo9Counter(revo9cnt);
450  rawDigit.setPhase(phase);
451  rawDigit.setLastWriteAddr(refWindow);
452  rawDigit.setLookBackWindows(lookBackWindows);
453  rawDigit.setOfflineFlag();
454  }
455 
456  for (auto& waveform : m_waveforms) {
457  waveform.setRevo9Counter(revo9cnt);
458  waveform.setOffsetWindows(offsetWindows);
459  }
460 
461  // set calibration flags
462 
463  if (m_useDatabase) {
464  for (auto& digit : m_digits) {
465  if (m_channelT0->isCalibrated(digit.getModuleID(), digit.getChannel())) {
466  digit.addStatus(TOPDigit::c_ChannelT0Calibrated);
467  }
468  if (m_moduleT0->isCalibrated(digit.getModuleID())) {
469  digit.addStatus(TOPDigit::c_ModuleT0Calibrated);
470  }
471  if (m_commonT0->isCalibrated()) {
472  digit.addStatus(TOPDigit::c_CommonT0Calibrated);
473  }
474  }
475  }
476 
477  // cut on product of pulse width and height, as for data in TOPRawDigitConverter
478 
479  for (auto& digit : m_digits) {
480  if (digit.getPulseWidth() * digit.getPulseHeight() < m_minWidthXheight)
481  digit.setHitQuality(TOPDigit::c_Junk);
482  }
483 
484  }
485 
486 
487  TOPDigitizerModule::TimeOffset TOPDigitizerModule::getTimeOffset(double trgOffset,
488  int moduleID,
489  int pixelID)
490  {
491  double timeOffset = trgOffset;
492  double calErrorSq = 0;
493  int winShift = 0;
494  double timeShift = 0;
495  if (m_useDatabase) {
496  const auto& channelMapper = TOPGeometryPar::Instance()->getChannelMapper();
497  auto channel = channelMapper.getChannel(pixelID);
498  if (m_channelT0->isCalibrated(moduleID, channel)) {
499  timeOffset += m_channelT0->getT0(moduleID, channel);
500  double err = m_channelT0->getT0Error(moduleID, channel);
501  calErrorSq += err * err;
502  }
503  auto asic = channel / 8;
504  if (m_asicShift->isCalibrated(moduleID, asic)) {
505  timeOffset += m_asicShift->getT0(moduleID, asic);
506  winShift = lround(m_asicShift->getT0(moduleID, asic) / m_syncTimeBase * 2);
507  timeShift = winShift * m_syncTimeBase / 2;
508  }
509  if (m_moduleT0->isCalibrated(moduleID)) {
510  timeOffset += m_moduleT0->getT0(moduleID);
511  double err = m_moduleT0->getT0Error(moduleID);
512  calErrorSq += err * err;
513  }
514  if (m_commonT0->isCalibrated()) {
515  timeOffset += m_commonT0->getT0();
516  double err = m_commonT0->getT0Error();
517  calErrorSq += err * err;
518  }
519  }
520  return TimeOffset(timeOffset, calErrorSq, winShift, timeShift);
521  }
522 
523 
524  double TOPDigitizerModule::generatePulseHeight(int moduleID, int pixelID) const
525  {
526  if (m_useDatabase) {
527  const auto& channelMapper = TOPGeometryPar::Instance()->getChannelMapper();
528  auto channel = channelMapper.getChannel(pixelID);
529  if (m_pulseHeights->isCalibrated(moduleID, channel)) {
530  const auto& par = m_pulseHeights->getParameters(moduleID, channel);
531  PulseHeightGenerator generator(par.x0, par.p1, par.p2, m_ADCmax);
532  return generator.generate();
533  }
534  }
535 
536  return m_pulseHeightGenerator.generate();
537  }
538 
540 } // end Belle2 namespace
541 
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::Iterator
map< unsigned, const TOPSampleTimes * >::const_iterator Iterator
Iteratior for m_map.
Definition: TOPCalTimebase.cc:25
Belle2::TOP::PulseHeightGenerator
Generates pulse height according to distribution: P(x) = (x/x0)^p1 * exp(-(x/x0)^p2),...
Definition: PulseHeightGenerator.h:35
Belle2::Module
Base class for Modules.
Definition: Module.h:74
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
Belle2::TOPDigitizerModule
TOP digitizer.
Definition: TOPDigitizerModule.h:59
Belle2::TOP::TimeDigitizer
Time digitization of simulated hits in a single electronic channel.
Definition: TimeDigitizer.h:43
Belle2::TOPDigitizerModule::TimeOffset
Utility structure for time offset.
Definition: TOPDigitizerModule.h:89