33 LOG(fatal) <<
"Module id = " << md.
id <<
" not in allowed range [0:" <<
NModules <<
")";
51 std::vector<o2::zdc::BCData>& digitsBC,
52 std::vector<o2::zdc::ChannelData>& digitsCh,
56 LOG(
debug) <<
"Processing IR = " << mIR <<
" | NHits = " << hits.size();
58 flush(digitsBC, digitsCh, labels);
60 for (
auto& hit : hits) {
62 std::array<o2::InteractionRecord, NBC2Cache> cachedIR;
65 int detID = hit.GetDetectorID();
66 int secID = hit.getSector();
70 nPhotons = hit.getPMCLightYield();
72 nPhotons = (secID ==
Common) ? hit.getPMCLightYield() : hit.getPMQLightYield();
77 if (nPhotons < 0 || nPhotons > 1e6) {
79 LOG(error) <<
"Anomalous number of photons " << nPhotons <<
" for channel " << chan <<
'(' <<
channelName(chan) <<
')';
90 LOG(
debug) <<
"Skipping hit with more than " << diffBC <<
" difference in bunch crossing";
98 for (
int i = BCCacheMin;
i < BCCacheMax + 1;
i++) {
100 cachedIR[nCachedIR].setFromNS(tNS);
101 if (tNS < 0 && cachedIR[nCachedIR] > irHit) {
104 getCreateBCCache(cachedIR[nCachedIR++]);
107 phe2Sample(nPhotons, hit.getParentID(), hTime, cachedIR, nCachedIR, channel);
114 std::vector<o2::zdc::ChannelData>& digitsCh,
118 int lastDoneBCid = -1, diff2Last = 0;
119 int nCached = mCache.size();
124 LOG(
debug) <<
"Generating new pedestal BL fluct. for BC range " << mCache.front() <<
" : " << mCache.back();
130 int cacheSpan = 1 + mCache.back().differenceInBC(
ir0);
131 LOG(
debug) <<
"Cache spans " << cacheSpan <<
" with " << nCached <<
" BCs cached";
134 mFastCache.resize(cacheSpan,
nullptr);
135 mStoreChanMask.clear();
136 mStoreChanMask.resize(cacheSpan + mNBCAHead, 0);
138 for (
int ibc = nCached; ibc--;) {
139 auto&
bc = mCache[ibc];
144 int bcSlot = mCache[ibc].differenceInBC(
ir0);
145 mFastCache[bcSlot] = &mCache[ibc];
148 digitizeBC(mDummyBC);
151 for (
int ibc = 0; ibc < cacheSpan; ibc++) {
152 if (mFastCache[ibc] && !mFastCache[ibc]->triggerChecked) {
158 for (
int ibc = -mNBCAHead; ibc < cacheSpan; ibc++) {
159 auto bcr = mStoreChanMask[ibc + mNBCAHead];
164 if (ibc < 0 || !mFastCache[ibc]) {
165 mDummyBC =
ir0 + ibc;
168 bcPtr = mFastCache[ibc];
170 storeBC(*bcPtr, bcr, digitsBC, digitsCh, labels);
175 mCache.erase(mCache.begin(), mCache.end());
179void Digitizer::generatePedestal()
184 mPedestalBLFluct[chanSum] = gRandom->Gaus(0, mSimCondition->
channels[chanSum].pedestalFluct);
186 mPedestalBLFluct[comm] = gRandom->Gaus(0, mSimCondition->
channels[comm].pedestalFluct);
189 mPedestalBLFluct[chan] = gRandom->Gaus(0, mSimCondition->
channels[chan].pedestalFluct);
191 mPedestalBLFluct[chanSum] += mPedestalBLFluct[chan];
199void Digitizer::digitizeBC(BCCache&
bc)
201 auto& bcdata =
bc.data;
202 auto& bcdigi =
bc.digi;
207 auto gain = mSimCondition->
channels[chan].gain;
209 bcdata[chan][ib] *= gain;
236 for (
const auto& md : mModuleConfig->modules) {
237 if (md.id >= 0 && md.id <
NModules) {
239 int id = md.channelID[ic];
241 const auto& chanConf = mSimCondition->
channels[
id];
242 auto pedBaseLine = mSimCondition->
channels[
id].pedestal;
246 bcdigi[ipos][ib] = bcdata[
id][ib] + gRandom->Gaus(pedBaseLine + mPedestalBLFluct[
id], chanConf.pedestalNoise);
247 int adc = std::nearbyint(bcdigi[ipos][ib]);
251 << bcdigi[ipos][0] <<
" " << bcdigi[ipos][1] <<
" " << bcdigi[ipos][2] <<
" " << bcdigi[ipos][3] <<
" " << bcdigi[ipos][4] <<
" " << bcdigi[ipos][5] <<
" "
252 << bcdigi[ipos][6] <<
" " << bcdigi[ipos][7] <<
" " << bcdigi[ipos][8] <<
" " << bcdigi[ipos][9] <<
" " << bcdigi[ipos][10] <<
" " << bcdigi[ipos][11];
261bool Digitizer::triggerBC(
int ibc)
264 auto& bcCached = *mFastCache[ibc];
266 LOG(
debug) <<
"CHECK TRIGGER " << ibc <<
" IR=" << bcCached;
269 for (
const auto& md : mModuleConfig->modules) {
270 if (md.id >= 0 && md.id <
NModules) {
273 auto trigCh = md.trigChannelConf[ic];
277 int last1 = trigCh.last + 2;
279#ifdef ZDC_DOUBLE_TRIGGER_CONDITION
282 for (
int ib = trigCh.first; ib < last1; ib++) {
283 int binF, bcFidx = ibc + binHelper(ib, binF);
284 int binL, bcLidx = ibc + binHelper(ib + trigCh.shift, binL);
285 const auto& bcF = (bcFidx < 0 || !mFastCache[bcFidx]) ? mDummyBC : *mFastCache[bcFidx];
286 const auto& bcL = (bcLidx < 0 || !mFastCache[bcLidx]) ? mDummyBC : *mFastCache[bcLidx];
287 bool ok = bcF.digi[ipos][binF] - bcL.digi[ipos][binL] > trigCh.threshold;
289 bcCached.trigChanMask |= 0x1 << (
NChPerModule * md.id + ic);
290 LOG(
debug) << bcF.digi[ipos][binF] <<
" - " << bcL.digi[ipos][binL] <<
" = " << bcF.digi[ipos][binF] - bcL.digi[ipos][binL] <<
" > " << trigCh.threshold;
291 LOG(
debug) <<
" hit [" << md.id <<
"," << ic <<
"] " <<
int(
id) <<
"(" <<
ChannelNames[
id] <<
") => " << bcCached.trigChanMask;
297 bool okPPrev =
false;
300 for (
int ib = trigCh.first - 1; ib < last1; ib++) {
301 int binF, bcFidx = ibc + binHelper(ib, binF);
302 int binL, bcLidx = ibc + binHelper(ib + trigCh.shift, binL);
303 const auto& bcF = (bcFidx < 0 || !mFastCache[bcFidx]) ? mDummyBC : *mFastCache[bcFidx];
304 const auto& bcL = (bcLidx < 0 || !mFastCache[bcLidx]) ? mDummyBC : *mFastCache[bcLidx];
305 bool ok = bcF.digi[ipos][binF] - bcL.digi[ipos][binL] > trigCh.threshold;
306 if (ok && okPrev && okPPrev) {
307 bcCached.trigChanMask |= 0x1 << (
NChPerModule * md.id + ic);
308 LOG(
debug) << bcF.digi[ipos][binF] <<
" - " << bcL.digi[ipos][binL] <<
" = " << bcF.digi[ipos][binF] - bcL.digi[ipos][binL] <<
" > " << trigCh.threshold;
309 LOG(
debug) <<
" hit [" << md.id <<
"," << ic <<
"] " <<
int(
id) <<
"(" <<
ChannelNames[
id] <<
") => " << bcCached.trigChanMask;
322 if (!mIRExternalTrigger.empty() && mIRExternalTrigger.front() == bcCached) {
324 mIRExternalTrigger.pop_front();
327 if (bcCached.trigChanMask & mTriggerableChanMask) {
328 for (
int ibcr = ibc - mNBCAHead; ibcr <= ibc; ibcr++) {
329 auto& bcr = mStoreChanMask[ibcr + mNBCAHead];
330 for (
const auto& mdh : mModConfAux) {
331 if (bcCached.trigChanMask & mdh.trigChannels) {
332 bcr |= mdh.readChannels;
337 bcCached.triggerChecked =
true;
338 return bcCached.trigChanMask;
342void Digitizer::storeBC(
const BCCache&
bc, uint32_t chan2Store,
343 std::vector<o2::zdc::BCData>& digitsBC, std::vector<o2::zdc::ChannelData>& digitsCh,
350 LOG(
debug) <<
"Storing ch: " << chanPattern(chan2Store) <<
" trigger: " << chanPattern(
bc.trigChanMask) <<
" for BC " <<
bc;
352 int first = digitsCh.size(), nSto = 0;
353 for (
const auto& md : mModuleConfig->modules) {
354 if (md.id >= 0 && md.id <
NModules) {
357 if (chan2Store & (0x1 << ipos)) {
358 digitsCh.emplace_back(md.channelID[ic],
bc.digi[ipos]);
365 int nBC = digitsBC.size();
366 digitsBC.emplace_back(
first, nSto,
bc, chan2Store,
bc.trigChanMask,
bc.extTrig);
368 if (!mSkipMCLabels) {
369 for (
const auto& lbl :
bc.labels) {
370 if (chan2Store & (0x1 << lbl.getChannel())) {
378void Digitizer::phe2Sample(
int nphe,
int parID,
double timeHit, std::array<o2::InteractionRecord, NBC2Cache>
const& cachedIR,
int nCachedIR,
int channel)
383 double time0 = cachedIR[0].bc2ns();
384 const auto& chanConfig = mSimCondition->
channels[channel];
386 float timeDiff = time0 - timeHit;
392 auto bcCache = getBCCache(cachedIR[
ir]);
395 if (sample >= chanConfig.shape.size()) {
400 auto signal = chanConfig.shape[sample] * nphe;
401 (*bcCache).data[channel][ib] += signal;
407 (*bcCache).labels.emplace_back(parID, mEventID, mSrcID, channel);
409 }
while (++
ir < nCachedIR && !stop);
415 if (mCache.empty() || mCache.back() <
ir) {
416 mCache.emplace_back();
417 auto& cb = mCache.back();
421 if (mCache.front() >
ir) {
422 mCache.emplace_front();
423 auto& cb = mCache.front();
428 for (
auto cb = mCache.begin(); cb != mCache.end(); cb++) {
433 auto cbnew = mCache.emplace(cb);
438 return mCache.front();
445 for (
auto cb = mCache.begin(); cb != mCache.end(); cb++) {
457 mIsContinuous = sopt.continuous;
458 mNBCAHead = mIsContinuous ? sopt.nBCAheadCont : sopt.nBCAheadTrig;
459 LOG(info) <<
"Initialized in " << (mIsContinuous ?
"Cont" :
"Trig") <<
" mode, " << mNBCAHead
460 <<
" BCs will be stored ahead of Trigger";
461 LOG(info) <<
"Trigger bit masking is " << (mMaskTriggerBits ?
"ON (default)" :
"OFF (debugging)");
462 LOG(info) <<
"MC Labels are " << (mSkipMCLabels ?
"SKIPPED" :
"SAVED (default)");
464 mTriggerConfig.clear();
466 for (
const auto& md : mModuleConfig->
modules) {
467 if (md.id >= 0 && md.id <
NModules) {
468 mModConfAux.emplace_back(md);
471 if (md.trigChannel[ic] || (md.trigChannelConf[ic].shift > 0 && md.trigChannelConf[ic].threshold > 0)) {
472 const auto& trgChanConf = md.trigChannelConf[ic];
474 LOG(error) <<
"Wrong trigger settings";
476 mTriggerConfig.emplace_back(trgChanConf);
480 if (md.trigChannel[ic]) {
481 LOG(info) <<
"Adding channel [" << md.id <<
"," << ic <<
"] " <<
int(trgChanConf.id) <<
'(' <<
channelName(trgChanConf.id) <<
") as triggering one";
483 mTriggerableChanMask |= 0x1 << (
NChPerModule * md.id + ic);
485 LOG(info) <<
"Adding channel [" << md.id <<
"," << ic <<
"] " <<
int(trgChanConf.id) <<
'(' <<
channelName(trgChanConf.id) <<
") as discriminator";
487 if (trgChanConf.first < mTrigBinMin) {
488 mTrigBinMin = trgChanConf.first;
490 if (trgChanConf.last + trgChanConf.shift > mTrigBinMax) {
491 mTrigBinMax = trgChanConf.last + trgChanConf.shift;
494 if (md.feeID[ic] < 0 || md.feeID[ic] >=
NLinks) {
495 LOG(fatal) <<
"FEEID " << md.feeID[ic] <<
" not in allowed range [0:" <<
NLinks <<
")";
499 LOG(fatal) <<
"Module id: " << md.id <<
" is out of range";
502 mModuleConfig->
print();
503 mSimCondition->
print();
511 std::bitset<NChannels> tmsk(trigChanMask);
512 printf(
"Cached Orbit:%5d/BC:%4d | digitized:%d triggerChecked:%d (trig.: %s)\n",
513 orbit,
bc, digitized, triggerChecked, tmsk.to_string().c_str());
517 printf(
"%+8.1f ",
data[ic][ib]);
524void Digitizer::setTriggerMask()
527 std::string printTriggerMask{};
529 for (
int im = 0; im <
NModules; im++) {
531 printTriggerMask +=
" ";
534 printTriggerMask +=
"[";
536 if (mModuleConfig->
modules[im].trigChannel[ic]) {
538 mTriggerMask = mTriggerMask | tmask;
539 printTriggerMask +=
"T";
541 printTriggerMask +=
" ";
544 printTriggerMask +=
"]";
547 LOGF(info,
"Trigger mask for module %d 0123 %c%c%c%c", im, mytmask & 0x1 ?
'T' :
'N', mytmask & 0x2 ?
'T' :
'N', mytmask & 0x4 ?
'T' :
'N', mytmask & 0x8 ?
'T' :
'N');
550 LOGF(info,
"TriggerMask=0x%08x %s", mTriggerMask, printTriggerMask.c_str());
554void Digitizer::setReadoutMask()
557 std::string printReadoutMask{};
559 for (
int im = 0; im <
NModules; im++) {
561 printReadoutMask +=
" ";
564 printReadoutMask +=
"[";
566 if (mModuleConfig->
modules[im].readChannel[ic]) {
568 mReadoutMask = mReadoutMask | rmask;
569 printReadoutMask +=
"R";
571 printReadoutMask +=
" ";
574 printReadoutMask +=
"]";
577 LOGF(info,
"Readout mask for module %d 0123 %c%c%c%c", im, myrmask & 0x1 ?
'R' :
'N', myrmask & 0x2 ?
'R' :
'N', myrmask & 0x4 ?
'R' :
'N', myrmask & 0x8 ?
'R' :
'N');
580 LOGF(info,
"ReadoutMask=0x%08x %s", mReadoutMask, printReadoutMask.c_str());
588 uint32_t nbcTot = bcData.size();
589 auto& currBC = bcData[ibc];
591 for (
int is = -1; is < 4; is++) {
592 int ibc_peek = ibc + is;
596 if (ibc_peek >= nbcTot) {
599 const auto& otherBC = bcData[ibc_peek];
600 auto diffBC = otherBC.ir.differenceInBC(currBC.ir);
607 if (otherBC.ext_triggers && diffBC >= 0) {
608 for (
int im = 0; im <
NModules; im++) {
609 currBC.moduleTriggers[im] |= 0x1 << diffBC;
612 if (otherBC.triggers) {
614 for (
int im = 0; im <
NModules; im++) {
615 uint32_t tmask = (0xf << (im *
NChPerModule)) & mTriggerMask;
616 if (otherBC.triggers & tmask) {
617 currBC.moduleTriggers[im] |= 0x1 << (5 + diffBC);
629 for (Int_t ipd = 0; ipd < pData.size(); ipd++) {
631 pData[ipd].scaler[
id] = 0;
634 for (
int im = 0; im <
NModules; im++) {
637 auto id = mModuleConfig->
modules[im].channelID[ic];
638 for (uint32_t ibc = 0; ibc < bcData.size(); ibc++) {
639 auto& currBC = bcData[ibc];
640 if ((currBC.triggers &
mask) && (mReadoutMask &
mask)) {
641 for (Int_t ipd = 0; ipd < pData.size(); ipd++) {
642 if (pData[ipd].
ir.
orbit == currBC.ir.orbit) {
643 pData[ipd].scaler[
id]++;
651 if (mMaskTriggerBits) {
652 for (uint32_t ibc = 0; ibc < bcData.size(); ibc++) {
653 auto& currBC = bcData[ibc];
654 for (
int im = 0; im <
NModules; im++) {
656 uint32_t mmask = 0xf << im;
657 if ((currBC.triggers & mTriggerMask & mmask) == 0) {
658 currBC.triggers = currBC.triggers & (~mmask);
662 currBC.triggers &= mReadoutMask;
676 LOG(info) <<
"Empty bunches from ModuleConfig: " << mNEmptyBCs <<
" Baseline factor: " << mPedFactor;
678 LOG(fatal) <<
"Invalid configuration for baseline computation from ModuleConfig object";
686 for (uint32_t
id = 0;
id <
NChannels;
id++) {
687 auto base_m = mSimCondition->
channels[
id].pedestal;
688 auto base_s = mSimCondition->
channels[
id].pedestalFluct;
689 auto base_n = mSimCondition->
channels[
id].pedestalNoise;
692 float mean_sum = 12. * mNEmptyBCs * base_m;
693 float rms_sum = 12. * 2. * base_s * std::sqrt(mNEmptyBCs / 2.);
694 float rms_noise_sum = base_n * std::sqrt(12. * mNEmptyBCs);
695 float ped = gRandom->Gaus(mean_sum, rms_sum) + gRandom->Gaus(0, rms_noise_sum);
696 int16_t peds = std::round(ped / mNEmptyBCs / 12. / mModuleConfig->
baselineFactor);
697 if (peds < SHRT_MIN) {
699 }
else if (peds > SHRT_MAX) {
Header to collect LHC related constants.
static const ZDCSimParam & Instance()
void updatePedestalReference(OrbitData &pdata)
void flush(std::vector< o2::zdc::BCData > &digitsBC, std::vector< o2::zdc::ChannelData > &digitsCh, o2::dataformats::MCTruthContainer< o2::zdc::MCLabel > &labels)
void process(const std::vector< o2::zdc::Hit > &hits, std::vector< o2::zdc::BCData > &digitsBC, std::vector< o2::zdc::ChannelData > &digitsCh, o2::dataformats::MCTruthContainer< o2::zdc::MCLabel > &labels)
void Finalize(std::vector< BCData > &bcData, std::vector< o2::zdc::OrbitData > &pData)
void assignTriggerBits(uint32_t ibc, std::vector< BCData > &bcData)
void findEmptyBunches(const std::bitset< o2::constants::lhc::LHCMaxBunches > &bunchPattern)
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
constexpr int toChannel(int det, int tower)
constexpr float getTOFCorrection(int det)
constexpr int NTimeBinsPerBC
constexpr int NChPerModule
constexpr const char * channelName(int channel)
constexpr uint8_t ALICETriggerMask
constexpr std::string_view ChannelNames[]
std::string to_string(gsl::span< T, Size > span)
uint16_t bc
bunch crossing ID of interaction
int64_t differenceInBC(const InteractionRecord &other) const
double getTimeNS() const
get time in ns from orbit=0/bc=0
static constexpr float ShapeBinWidthInv
std::array< Module, MaxNModules > modules
std::array< bool, MaxChannels > trigChannel
std::array< bool, MaxChannels > readChannel
static constexpr int MaxChannels
std::array< int8_t, MaxChannels > channelID
std::array< int16_t, NChannels > data
std::array< ChannelSimCondition, NChannels > channels
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
o2::InteractionRecord ir0(3, 5)