11 #include <top/modules/TOPDigitizer/TOPDigitizerModule.h>
12 #include <top/geometry/TOPGeometryPar.h>
13 #include <top/modules/TOPDigitizer/TimeDigitizer.h>
16 #include <framework/datastore/DataStore.h>
17 #include <framework/datastore/StoreArray.h>
18 #include <framework/datastore/StoreObjPtr.h>
21 #include <framework/logging/Logger.h>
52 setDescription(
"Digitize TOPSimHits");
53 setPropertyFlags(c_ParallelProcessingCertified);
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)",
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.",
95 addParam(
"minWidthXheight", m_minWidthXheight,
96 "minimal product of width and height [ns * ADC counts]", 100.0);
101 void TOPDigitizerModule::initialize()
104 m_simHits.isRequired();
105 m_simCalPulses.isOptional();
106 m_mcParticles.isOptional();
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);
119 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
121 if (m_electronicJitter < 0) {
122 m_electronicJitter = geo->getNominalTDC().getTimeJitter();
126 TOPDigit::setDoubleHitResolution(geo->getNominalTDC().getDoubleHitResolution());
127 TOPDigit::setPileupTime(geo->getNominalTDC().getPileupTime());
130 m_syncTimeBase = geo->getNominalTDC().getSyncTimeBase();
131 m_sampleTimes.setTimeAxis(m_syncTimeBase);
139 void TOPDigitizerModule::beginRun()
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());
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());
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());
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());
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());
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());
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());
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());
189 if (not m_thresholds.isValid()) {
190 B2FATAL(
"Channel thresholds requested but not available for run "
191 << evtMetaData->getRun()
192 <<
" of experiment " << evtMetaData->getExperiment());
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());
199 if (m_timeWalk.isValid()) {
200 TimeDigitizer::setTimeWalk(&m_timeWalk);
202 TimeDigitizer::setTimeWalk(0);
204 B2WARNING(
"Time-walk parameters not available for run "
205 << evtMetaData->getRun()
206 <<
" of experiment " << evtMetaData->getExperiment());
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());
217 if (not m_feSetting.isValid()) {
218 B2FATAL(
"Front-end settings are not available for run "
219 << evtMetaData->getRun()
220 <<
" of experiment " << evtMetaData->getExperiment());
224 TimeDigitizer::setReadoutWindows(m_feSetting->getReadoutWindows());
225 if ((evtMetaData->getExperiment() > 0 and evtMetaData->getExperiment() < 5) or
226 evtMetaData->getExperiment() == 1002) {
227 TimeDigitizer::maskSamples(
true);
229 TimeDigitizer::maskSamples(
false);
234 void TOPDigitizerModule::event()
238 unsigned revo9cnt = gRandom->Integer(11520);
241 double SSTfrac = (revo9cnt % 6) / 6.0;
242 double offset = m_feSetting->getOffset() / 24.0;
243 double trgTimeOffset = (SSTfrac + offset) * m_syncTimeBase;
244 int offsetWindows = m_feSetting->getWindowShift(revo9cnt);
245 TimeDigitizer::setOffsetWindows(offsetWindows);
248 int SSTcnt = revo9cnt / 6;
249 int refWindow = SSTcnt * 2;
250 const auto& writeDepths = m_feSetting->getWriteDepths();
251 if (writeDepths.empty()) {
252 B2ERROR(
"TOPDigitzer: vector of write depths is empty. No digitization possible");
255 int lastDepth = writeDepths.back();
257 for (
auto depth : writeDepths) {
259 if (SSTcnt < 0)
break;
261 refWindow = SSTcnt * 2;
264 unsigned storageDepth = lastDepth * 2;
265 TimeDigitizer::setStorageDepth(storageDepth);
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);
275 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
278 double timeMin = geo->getSignalShape().getTMin() + offsetWindows * m_syncTimeBase / 2;
279 double timeMax = geo->getSignalShape().getTMax() +
280 (m_feSetting->getReadoutWindows() + offsetWindows) * m_syncTimeBase / 2;
283 double startTimeJitter = gRandom->Gaus(0, m_timeZeroJitter);
286 double electronicEfficiency = geo->getNominalTDC().getEfficiency();
289 std::map<unsigned, TimeDigitizer> pixels;
290 typedef std::map<unsigned, TimeDigitizer>::iterator
Iterator;
294 for (
const auto& simHit : m_simHits) {
295 if (not m_useWaveforms) {
297 if (gRandom->Rndm() > electronicEfficiency)
continue;
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;
309 double time = simHit.getTime() + startTimeJitter;
311 const auto& tts = TOPGeometryPar::Instance()->getTTS(moduleID, pmtID);
312 time += tts.generateTTS();
316 auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
319 if (time + timeOffset.value < timeMin + timeOffset.timeShift)
continue;
320 if (time + timeOffset.value > timeMax + timeOffset.timeShift)
continue;
323 double pulseHeight = generatePulseHeight(moduleID, pixelID);
324 auto hitType = TimeDigitizer::c_Hit;
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);
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;
345 auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
348 if (time + timeOffset.value < timeMin + timeOffset.timeShift)
continue;
349 if (time + timeOffset.value > timeMax + timeOffset.timeShift)
continue;
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);
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);
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));
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);
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);
423 digitizer.setNoise(rmsNoise);
430 for (
auto& pixel : pixels) {
431 const auto& digitizer = pixel.second;
432 int threshold = m_threshold;
434 threshold = m_thresholds->getThr(digitizer.getModuleID(), digitizer.getChannel());
435 if (threshold <= 0) threshold = m_threshold;
437 if (m_useWaveforms) {
438 digitizer.digitize(m_waveforms, m_rawDigits, m_digits,
439 threshold, m_hysteresis, m_thresholdCount);
441 digitizer.digitize(m_rawDigits, m_digits,
442 threshold, m_thresholdCount, m_electronicJitter);
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();
456 for (
auto& waveform : m_waveforms) {
457 waveform.setRevo9Counter(revo9cnt);
458 waveform.setOffsetWindows(offsetWindows);
464 for (
auto& digit : m_digits) {
465 if (m_channelT0->isCalibrated(digit.getModuleID(), digit.getChannel())) {
466 digit.addStatus(TOPDigit::c_ChannelT0Calibrated);
468 if (m_moduleT0->isCalibrated(digit.getModuleID())) {
469 digit.addStatus(TOPDigit::c_ModuleT0Calibrated);
471 if (m_commonT0->isCalibrated()) {
472 digit.addStatus(TOPDigit::c_CommonT0Calibrated);
479 for (
auto& digit : m_digits) {
480 if (digit.getPulseWidth() * digit.getPulseHeight() < m_minWidthXheight)
481 digit.setHitQuality(TOPDigit::c_Junk);
491 double timeOffset = trgOffset;
492 double calErrorSq = 0;
494 double timeShift = 0;
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;
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;
509 if (m_moduleT0->isCalibrated(moduleID)) {
510 timeOffset += m_moduleT0->getT0(moduleID);
511 double err = m_moduleT0->getT0Error(moduleID);
512 calErrorSq += err * err;
514 if (m_commonT0->isCalibrated()) {
515 timeOffset += m_commonT0->getT0();
516 double err = m_commonT0->getT0Error();
517 calErrorSq += err * err;
520 return TimeOffset(timeOffset, calErrorSq, winShift, timeShift);
524 double TOPDigitizerModule::generatePulseHeight(
int moduleID,
int pixelID)
const
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);
532 return generator.generate();
536 return m_pulseHeightGenerator.generate();