9 #include <top/modules/TOPDigitizer/TOPDigitizerModule.h>
10 #include <top/geometry/TOPGeometryPar.h>
11 #include <top/modules/TOPDigitizer/TimeDigitizer.h>
14 #include <framework/datastore/DataStore.h>
15 #include <framework/datastore/StoreArray.h>
16 #include <framework/datastore/StoreObjPtr.h>
19 #include <framework/logging/Logger.h>
50 setDescription(
"Digitize TOPSimHits");
51 setPropertyFlags(c_ParallelProcessingCertified);
54 addParam(
"timeZeroJitter", m_timeZeroJitter,
55 "r.m.s of T0 jitter [ns]", 15e-3);
56 addParam(
"electronicJitter", m_electronicJitter,
57 "r.m.s of electronic jitter [ns], "
58 "if negative the one from TOPNominalTDC is used. "
59 "This parameter is ignored in the full waveform digitization.", -1.0);
60 addParam(
"darkNoise", m_darkNoise,
61 "uniformly distributed dark noise (hits per module)", 0.0);
62 addParam(
"ADCx0", m_ADCx0,
63 "pulse height distribution parameter [ADC counts]", 204.1);
64 addParam(
"ADCp1", m_ADCp1,
65 "pulse height distribution parameter (must be non-negative)", 1.0);
66 addParam(
"ADCp2", m_ADCp2,
67 "pulse height distribution parameter (must be non-negative)", 1.025);
68 addParam(
"ADCmax", m_ADCmax,
69 "pulse height distribution upper bound [ADC counts]", 2000.0);
70 addParam(
"rmsNoise", m_rmsNoise,
71 "r.m.s of noise [ADC counts]", 9.7);
72 addParam(
"threshold", m_threshold,
73 "pulse height threshold [ADC counts]", 40);
74 addParam(
"hysteresis", m_hysteresis,
75 "pulse height threshold hysteresis [ADC counts]", 10);
76 addParam(
"thresholdCount", m_thresholdCount,
77 "minimal number of samples above threshold", 3);
78 addParam(
"useWaveforms", m_useWaveforms,
79 "if true, use full waveform digitization",
true);
80 addParam(
"allChannels", m_allChannels,
81 "if true, make waveforms for all 8192 channels "
82 "(note: this will slow-down digitization)",
false);
83 addParam(
"useDatabase", m_useDatabase,
84 "if true, use channel dependent constants from database (incl. time base)",
86 addParam(
"useSampleTimeCalibration", m_useSampleTimeCalibration,
87 "if true, use only time base calibration from database "
88 "(has no effect if useDatabase = True)",
false);
89 addParam(
"simulateTTS", m_simulateTTS,
90 "if true, simulate time transition spread. "
91 "Should be always switched ON, except for some dedicated timing studies.",
93 addParam(
"minWidthXheight", m_minWidthXheight,
94 "minimal product of width and height [ns * ADC counts]", 100.0);
95 addParam(
"lookBackWindows", m_lookBackWindows,
96 "number of look back windows, if positive override the number from database", 0);
100 void TOPDigitizerModule::initialize()
103 m_simHits.isRequired();
104 m_simCalPulses.isOptional();
105 m_mcParticles.isOptional();
106 m_simClockState.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 = 0;
239 if (m_simClockState.isValid()) {
240 revo9cnt = m_simClockState->getRevo9Count();
242 revo9cnt = gRandom->Integer(11520);
246 double SSTfrac = (revo9cnt % 6) / 6.0;
247 double offset = m_feSetting->getOffset() / 24.0;
248 double trgTimeOffset = (SSTfrac + offset) * m_syncTimeBase;
249 int offsetWindows = m_feSetting->getWindowShift(revo9cnt);
250 TimeDigitizer::setOffsetWindows(offsetWindows);
253 int SSTcnt = revo9cnt / 6;
254 int refWindow = SSTcnt * 2;
255 const auto& writeDepths = m_feSetting->getWriteDepths();
256 if (writeDepths.empty()) {
257 B2ERROR(
"TOPDigitzer: vector of write depths is empty. No digitization possible");
260 int lastDepth = writeDepths.back();
262 for (
auto depth : writeDepths) {
264 if (SSTcnt < 0)
break;
266 refWindow = SSTcnt * 2;
269 unsigned storageDepth = lastDepth * 2;
270 TimeDigitizer::setStorageDepth(storageDepth);
273 int lookBackWindows = m_feSetting->getLookbackWindows();
274 if (m_lookBackWindows > 0) lookBackWindows = m_lookBackWindows;
275 lookBackWindows -= m_feSetting->getExtraWindows();
276 int window = refWindow - lookBackWindows;
277 if (window < 0) window += storageDepth;
278 TimeDigitizer::setFirstWindow(window);
281 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
284 double timeMin = geo->getSignalShape().getTMin() + offsetWindows * m_syncTimeBase / 2;
285 double timeMax = geo->getSignalShape().getTMax() +
286 (m_feSetting->getReadoutWindows() + offsetWindows) * m_syncTimeBase / 2;
289 double startTimeJitter = gRandom->Gaus(0, m_timeZeroJitter);
292 double electronicEfficiency = geo->getNominalTDC().getEfficiency();
295 std::map<unsigned, TimeDigitizer> pixels;
296 typedef std::map<unsigned, TimeDigitizer>::iterator
Iterator;
300 for (
const auto& simHit : m_simHits) {
301 if (not m_useWaveforms) {
303 if (gRandom->Rndm() > electronicEfficiency)
continue;
306 double x = simHit.getX();
307 double y = simHit.getY();
308 int pmtID = simHit.getPmtID();
309 int moduleID = simHit.getModuleID();
310 if (not geo->isModuleIDValid(moduleID))
continue;
311 int pixelID = geo->getModule(moduleID).getPMTArray().getPixelID(x, y, pmtID);
312 if (pixelID == 0)
continue;
315 double time = simHit.getTime() + startTimeJitter;
317 const auto& tts = TOPGeometryPar::Instance()->getTTS(moduleID, pmtID);
318 time += tts.generateTTS();
322 auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
325 if (time + timeOffset.value < timeMin + timeOffset.timeShift)
continue;
326 if (time + timeOffset.value > timeMax + timeOffset.timeShift)
continue;
329 double pulseHeight = generatePulseHeight(moduleID, pixelID);
330 auto hitType = TimeDigitizer::c_Hit;
333 TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
334 timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
335 if (not digitizer.isValid())
continue;
336 unsigned id = digitizer.getUniqueID();
337 Iterator it = pixels.insert(pair<unsigned, TimeDigitizer>(
id, digitizer)).first;
338 it->second.addTimeOfHit(time, pulseHeight, hitType, &simHit);
343 for (
const auto& simCalPulses : m_simCalPulses) {
344 auto moduleID = simCalPulses.getModuleID();
345 auto pixelID = simCalPulses.getPixelID();
346 auto pulseHeight = simCalPulses.getAmplitude();
347 auto time = simCalPulses.getTime();
348 auto hitType = TimeDigitizer::c_CalPulse;
351 auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
354 if (time + timeOffset.value < timeMin + timeOffset.timeShift)
continue;
355 if (time + timeOffset.value > timeMax + timeOffset.timeShift)
continue;
358 TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
359 timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
360 if (not digitizer.isValid())
continue;
361 unsigned id = digitizer.getUniqueID();
362 Iterator it = pixels.insert(pair<unsigned, TimeDigitizer>(
id, digitizer)).first;
363 it->second.addTimeOfHit(time, pulseHeight, hitType);
368 if (m_darkNoise > 0) {
369 int numModules = geo->getNumModules();
370 for (
int moduleID = 1; moduleID <= numModules; moduleID++) {
371 int numPixels = geo->getModule(moduleID).getPMTArray().getNumPixels();
372 int numHits = gRandom->Poisson(m_darkNoise);
373 for (
int i = 0; i < numHits; i++) {
374 int pixelID = int(gRandom->Rndm() * numPixels) + 1;
375 double time = (timeMax - timeMin) * gRandom->Rndm() + timeMin;
376 double pulseHeight = generatePulseHeight(moduleID, pixelID);
377 auto hitType = TimeDigitizer::c_Hit;
378 auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
379 time += timeOffset.timeShift;
380 time -= timeOffset.value;
381 TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
382 timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
383 if (not digitizer.isValid())
continue;
384 unsigned id = digitizer.getUniqueID();
385 Iterator it = pixels.insert(pair<unsigned, TimeDigitizer>(
id, digitizer)).first;
386 it->second.addTimeOfHit(time, pulseHeight, hitType);
394 int numModules = geo->getNumModules();
395 for (
int moduleID = 1; moduleID <= numModules; moduleID++) {
396 int numPixels = geo->getModule(moduleID).getPMTArray().getNumPixels();
397 for (
int pixelID = 1; pixelID <= numPixels; pixelID++) {
398 auto timeOffset = getTimeOffset(trgTimeOffset, moduleID, pixelID);
399 TimeDigitizer digitizer(moduleID, pixelID, timeOffset.value, timeOffset.error,
400 timeOffset.windowShift, m_rmsNoise, m_sampleTimes);
401 if (not digitizer.isValid())
continue;
402 unsigned id = digitizer.getUniqueID();
403 pixels.insert(pair<unsigned, TimeDigitizer>(
id, digitizer));
410 if (m_useDatabase or m_useSampleTimeCalibration) {
411 for (
auto& pixel : pixels) {
412 auto& digitizer = pixel.second;
413 const auto* sampleTimes = m_timebases->getSampleTimes(digitizer.getScrodID(),
414 digitizer.getChannel());
415 if (not sampleTimes)
continue;
416 if (sampleTimes->isCalibrated()) digitizer.setSampleTimes(sampleTimes);
423 for (
auto& pixel : pixels) {
424 auto& digitizer = pixel.second;
425 auto moduleID = digitizer.getModuleID();
426 auto channel = digitizer.getChannel();
427 auto rmsNoise = m_noises->getNoise(moduleID, channel);
429 digitizer.setNoise(rmsNoise);
436 for (
auto& pixel : pixels) {
437 const auto& digitizer = pixel.second;
438 int threshold = m_threshold;
440 threshold = m_thresholds->getThr(digitizer.getModuleID(), digitizer.getChannel());
441 if (threshold <= 0) threshold = m_threshold;
443 if (m_useWaveforms) {
444 digitizer.digitize(m_waveforms, m_rawDigits, m_digits,
445 threshold, m_hysteresis, m_thresholdCount);
447 digitizer.digitize(m_rawDigits, m_digits,
448 threshold, m_thresholdCount, m_electronicJitter);
454 for (
auto& rawDigit : m_rawDigits) {
455 rawDigit.setRevo9Counter(revo9cnt);
456 rawDigit.setPhase(phase);
457 rawDigit.setLastWriteAddr(refWindow);
458 rawDigit.setLookBackWindows(lookBackWindows);
459 rawDigit.setOfflineFlag();
462 for (
auto& waveform : m_waveforms) {
463 waveform.setRevo9Counter(revo9cnt);
464 waveform.setOffsetWindows(offsetWindows);
470 for (
auto& digit : m_digits) {
471 if (m_channelT0->isCalibrated(digit.getModuleID(), digit.getChannel())) {
472 digit.addStatus(TOPDigit::c_ChannelT0Calibrated);
474 if (m_moduleT0->isCalibrated(digit.getModuleID())) {
475 digit.addStatus(TOPDigit::c_ModuleT0Calibrated);
477 if (m_commonT0->isCalibrated()) {
478 digit.addStatus(TOPDigit::c_CommonT0Calibrated);
485 for (
auto& digit : m_digits) {
486 if (digit.getPulseWidth() * digit.getPulseHeight() < m_minWidthXheight)
487 digit.setHitQuality(TOPDigit::c_Junk);
497 double timeOffset = trgOffset;
498 double calErrorSq = 0;
500 double timeShift = 0;
502 const auto& channelMapper = TOPGeometryPar::Instance()->getChannelMapper();
503 auto channel = channelMapper.getChannel(pixelID);
504 if (m_channelT0->isCalibrated(moduleID, channel)) {
505 timeOffset += m_channelT0->getT0(moduleID, channel);
506 double err = m_channelT0->getT0Error(moduleID, channel);
507 calErrorSq += err * err;
509 auto asic = channel / 8;
510 if (m_asicShift->isCalibrated(moduleID, asic)) {
511 timeOffset += m_asicShift->getT0(moduleID, asic);
512 winShift = lround(m_asicShift->getT0(moduleID, asic) / m_syncTimeBase * 2);
513 timeShift = winShift * m_syncTimeBase / 2;
515 if (m_moduleT0->isCalibrated(moduleID)) {
516 timeOffset += m_moduleT0->getT0(moduleID);
517 double err = m_moduleT0->getT0Error(moduleID);
518 calErrorSq += err * err;
520 if (m_commonT0->isCalibrated()) {
521 timeOffset += m_commonT0->getT0();
522 double err = m_commonT0->getT0Error();
523 calErrorSq += err * err;
526 return TimeOffset(timeOffset, calErrorSq, winShift, timeShift);
530 double TOPDigitizerModule::generatePulseHeight(
int moduleID,
int pixelID)
const
533 const auto& channelMapper = TOPGeometryPar::Instance()->getChannelMapper();
534 auto channel = channelMapper.getChannel(pixelID);
535 if (m_pulseHeights->isCalibrated(moduleID, channel)) {
536 const auto& par = m_pulseHeights->getParameters(moduleID, channel);
538 return generator.generate();
542 return m_pulseHeightGenerator.generate();
Type-safe access to single objects in the data store.
Generates pulse height according to distribution: P(x) = (x/x0)^p1 * exp(-(x/x0)^p2),...
Time digitization of simulated hits in a single electronic channel.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
map< unsigned, const TOPSampleTimes * >::const_iterator Iterator
Iteratior for m_map.
Abstract base class for different kinds of events.
Utility structure for time offset.