37 std::vector<o2::fdd::Digit>& digitsBC,
38 std::vector<o2::fdd::ChannelData>& digitsCh,
39 std::vector<o2::fdd::DetTrigInput>& digitsTrig,
45 flush(digitsBC, digitsCh, digitsTrig, labels);
47 auto sorted_hits{hits};
49 return a.GetTrackID() < b.GetTrackID();
53 for (
auto& hit : sorted_hits) {
54 int iChannel = hit.GetDetectorID();
57 if (mDeadChannelMap && !mDeadChannelMap->
isChannelAlive(iChannel)) {
61 if (hit.GetTime() > 20e3) {
62 const int maxWarn = 10;
63 static int warnNo = 0;
64 if (warnNo < maxWarn) {
65 LOG(warning) <<
"Ignoring hit with time_in_event = " << hit.GetTime() <<
" ns"
66 << ((++warnNo < maxWarn) ?
"" :
" (suppressing further warnings)");
71 std::array<o2::InteractionRecord, NBC2Cache> cachedIR;
74 double delayScintillator = mRndScintDelay.
getNextValue();
75 double timeHit = delayScintillator + hit.GetTime();
81 timeHit += -timeOfFlight + timeOffset;
86 for (
int i = BCCacheMin;
i < BCCacheMax + 1;
i++) {
88 cachedIR[nCachedIR].setFromNS(tNS);
89 if (tNS < 0 && cachedIR[nCachedIR] > irHit) {
92 setBCCache(cachedIR[nCachedIR++]);
95 createPulse(nPhotoElectrons, hit.GetTrackID(), timeHit, cachedIR, nCachedIR, iChannel);
100void Digitizer::createPulse(
int nPhE,
int parID,
double timeHit, std::array<o2::InteractionRecord, NBC2Cache>
const& cachedIR,
int nCachedIR,
int channel)
102 auto const roundVc = [&](
int i) ->
int {
103 return (
i / Vc::float_v::Size) * Vc::float_v::Size;
106 double time0 = cachedIR[0].bc2ns();
107 float timeDiff = time0 - timeHit;
117 Bool_t added[nCachedIR];
118 for (
int ir = 0;
ir < nCachedIR;
ir++) {
122 constexpr float BinSizeInv = 1.0 / mBinSize;
123 for (
int iPhE = 0; iPhE < nPhE; ++iPhE) {
125 int const firstBin = roundVc(TMath::Max((
int)0, (
int)((tPhE -
PMTransitTime) * BinSizeInv)));
129 float const tempT = mBinSize * (0.5f + firstBin) - tPhE;
130 long iStart = std::lround((tempT + 2.0f *
PMTransitTime) * BinSizeInv);
134 LOG(error) <<
"FDDDigitizer: table lookup failure";
136 iStart = roundVc(std::max(
long(0), iStart));
140 float const* q = mPMResponseTables[parameters.
NResponseTables / 2 + iOffset].data() + iStart;
141 float const* qEnd = &mPMResponseTables[parameters.
NResponseTables / 2 + iOffset].back();
146 auto bcCache = getBCCache(cachedIR[
ir]);
147 auto& analogSignal = (*bcCache).pulse[channel];
148 float* p = analogSignal.data() + localFirst;
150 for (
int localBin = localFirst, iEnd = roundVc(localLast); q < qEnd && localBin < iEnd; localBin += Vc::float_v::Size) {
152 q += Vc::float_v::Size;
153 Vc::prefetchForOneRead(q);
157 p += Vc::float_v::Size;
158 Vc::prefetchForOneRead(p);
163 for (
int ir = 0;
ir < nCachedIR;
ir++) {
165 auto bcCache = getBCCache(cachedIR[
ir]);
166 (*bcCache).labels.emplace_back(parID, mEventID, mSrcID, channel);
172 std::vector<o2::fdd::ChannelData>& digitsCh,
173 std::vector<o2::fdd::DetTrigInput>& digitsTrig,
178 int nCached = mCache.size();
183 LOG(
debug) <<
"Generating new pedestal BL fluct. for BC range " << mCache.front() <<
" : " << mCache.back();
192 for (
int ibc = 0; ibc < nCached; ibc++) {
193 auto&
bc = mCache[ibc];
194 storeBC(
bc, digitsBC, digitsCh, digitsTrig, labels);
198 mCache.erase(mCache.begin(), mCache.end());
201void Digitizer::storeBC(
const BCCache&
bc,
202 std::vector<o2::fdd::Digit>& digitsBC, std::vector<o2::fdd::ChannelData>& digitsCh,
203 std::vector<o2::fdd::DetTrigInput>& digitsTrig,
207 int first = digitsCh.size(), nStored = 0;
208 float totalChargeA = 0, totalChargeC = 0;
209 int n_hit_A = 0, n_hit_C = 0, total_time_A = 0, total_time_C = 0;
215 if (chargeADC != 0) {
217 totalChargeC += chargeADC;
218 total_time_C += cfdTime;
221 totalChargeA += chargeADC;
222 total_time_A += cfdTime;
226 if (std::rand() % 2) {
229 digitsCh.emplace_back(ic, cfdTime,
int(chargeADC), channelBits);
234 Bool_t is_A, is_C, isVertex, is_Central, is_SemiCentral = 0;
237 uint32_t
amplA = is_A ? totalChargeA * 0.125 : -5000;
238 uint32_t
amplC = is_C ? totalChargeC * 0.125 : -5000;
239 int timeA = is_A ? total_time_A / n_hit_A : -5000;
240 int timeC = is_C ? total_time_C / n_hit_C : -5000;
241 isVertex = is_A && is_C;
243 bool isLaser =
false;
244 bool isOutputsAreBlocked =
false;
245 bool isDataValid =
true;
246 mTriggers.
setTriggers(is_A, is_C, isVertex, is_Central, is_SemiCentral, int8_t(n_hit_A), int8_t(n_hit_C),
249 int nBC = digitsBC.size();
250 digitsBC.emplace_back(
first, nStored,
bc, mTriggers);
251 digitsTrig.emplace_back(
bc, is_A, is_C, isVertex, is_Central, is_SemiCentral);
253 for (
const auto& lbl :
bc.labels) {
265 chargeADC += pulse[iBin];
268 if (chargeADC > 4095) {
273 return std::lround(chargeADC);
279 std::fill(mTimeCFD.begin(), mTimeCFD.end(), 0);
280 float timeCFD = -1024;
281 int binShift = TMath::Nint(parameters.
TimeShiftCFD / mBinSize);
284 if (iBin >= binShift) {
285 mTimeCFD[iBin] = 5.0 * pulse[iBin - binShift] - pulse[iBin];
287 mTimeCFD[iBin] = -1.0 * pulse[iBin];
291 if (mTimeCFD[iBin - 1] < 0 && mTimeCFD[iBin] >= 0) {
292 timeCFD = mBinSize * float(iBin);
298 return std::lround(timeCFD);
303 if (mCache.empty() || mCache.back() <
ir) {
304 mCache.emplace_back();
305 auto& cb = mCache.back();
309 if (mCache.front() >
ir) {
310 mCache.emplace_front();
311 auto& cb = mCache.front();
316 for (
auto cb = mCache.begin(); cb != mCache.end(); cb++) {
321 auto cbnew = mCache.emplace(cb);
326 return mCache.front();
332 for (
auto cb = mCache.begin(); cb != mCache.end(); cb++) {
347 auto const roundVc = [&](
int i) ->
int {
348 return (
i / Vc::float_v::Size) * Vc::float_v::Size;
351 float offset = -0.5f * mBinSize;
352 int const nBins = roundVc(std::lround(4.0f *
PMTransitTime / mBinSize));
353 for (
auto& table : mPMResponseTables) {
356 for (
int j = 0;
j < nBins; ++
j) {
357 table[
j] = Digitizer::PMResponse(t);
369 pmtResponseFn.SetNpx(100);
373 TF1 singlePhESpectrumFn(
"mSinglePhESpectrum",
374 &Digitizer::SinglePhESpectrum, 0, 30, 0);
375 float const meansPhE = singlePhESpectrumFn.Mean(0, 30);
377 return singlePhESpectrumFn.GetRandom(0, 30) / meansPhE;
380 TF1 signalShapeFn(
"signalShape",
"crystalball", 0, 300);
383 return signalShapeFn.GetRandom(0, 200);
393 if (p == 1.0f || nPhot == 0) {
396 const int n =
int(nPhot < 100 ? gRandom->Binomial(nPhot, p) : gRandom->Gaus(p * nPhot + 0.5, TMath::Sqrt(p * (1 - p) * nPhot)));
400Double_t Digitizer::PMResponse(Double_t*
x, Double_t*)
402 return Digitizer::PMResponse(
x[0]);
405Double_t Digitizer::PMResponse(Double_t
x)
412Double_t Digitizer::SinglePhESpectrum(Double_t*
x, Double_t*)
424 printf(
"Cached Orbit:%5d/BC:%4d",
orbit,
bc);
425 for (
int ic = 0; ic < 16; ic++) {
426 printf(
"Ch[%d] | ", ic);
429 printf(
"%f ", pulse[ic][ib]);
#define O2ParamImpl(classname)
Configurable digitization parameters.
Definition of a container to keep Monte Carlo truth external to simulation objects.
static const FDDDigParam & Instance()
int simulateLightYield(int pmt, int nPhot)
float simulateTimeCFD(const ChannelBCDataF &pulse)
float integrateCharge(const ChannelBCDataF &pulse)
void process(const std::vector< o2::fdd::Hit > &hits, std::vector< o2::fdd::Digit > &digitsBC, std::vector< o2::fdd::ChannelData > &digitsCh, std::vector< o2::fdd::DetTrigInput > &digitsTrig, o2::dataformats::MCTruthContainer< o2::fdd::MCLabel > &labels)
void setTriggers(o2::fdd::Digit *digit)
void flush(std::vector< o2::fdd::Digit > &digitsBC, std::vector< o2::fdd::ChannelData > &digitsCh, std::vector< o2::fdd::DetTrigInput > &digitsTrig, o2::dataformats::MCTruthContainer< o2::fdd::MCLabel > &labels)
void setTriggers(uint8_t trgsig, uint8_t chanA, uint8_t chanC, int32_t aamplA, int32_t aamplC, int16_t atimeA, int16_t atimeC)
void initialize(const RandomType randomType=RandomType::Gaus)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
constexpr double LHCBunchSpacingNS
constexpr float LightSpeedCm2NS
constexpr float ChargePerADC
constexpr float PMTransitTime
constexpr float PMTransparency
constexpr float PMNbOfSecElec
constexpr float invTimePerTDC
constexpr float PhotoCathodeEfficiency
constexpr float IntTimeRes
constexpr int NTimeBinsPerBC
constexpr short Nchannels
int64_t differenceInBC(const InteractionRecord &other) const
double getTimeNS() const
get time in ns from orbit=0/bc=0
static void setFlag(EEventDataBit bitFlag, uint8_t &mFEEBits)
static constexpr float ShapeSigma
static constexpr float TimeDelayFDC
static constexpr float ShapeAlpha
static constexpr int NResponseTables
static constexpr uint8_t defaultFEEbits
static constexpr float TimeDelayFDA
static constexpr float ShapeN
static constexpr float TimeShiftCFD
static constexpr float LightYield
std::array< ChannelBCDataF, Nchannels > pulse
float hitTimeOffsetC
Hit time offset on the C side [ns].
float hitTimeOffsetA
Hit time offset on the A side [ns].
const bool isChannelAlive(const uint8_t &chId) const
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)