35template <
typename Float>
40 Float const b = -0.83344945;
48 double const a = -0.45458;
49 double const b = -0.83344945;
59 auto const mask = (
x >= 0.0f);
62 Vc::float_v
const a(-0.45458f);
63 Vc::float_v
const b(-0.83344945f);
64 Vc::float_v
result = -(Vc::exp(
b * arg) /
b - Vc::exp(
a * arg) /
a) / 7.8446501f;
71 assert(std::is_sorted(std::begin(
times), std::end(
times)));
74 for (
float&
n : mNoiseSamples) {
79 auto value_at = [&](
float time) {
83 Vc::float_v tableVal(0);
84 const float* tp =
times.data();
85 size_t m =
times.size() / Vc::float_v::size();
86 for (
size_t i = 0;
i <
m; ++
i) {
88 tp += Vc::float_v::size();
89 Vc::prefetchForOneRead(tp);
94 for (
size_t i = Vc::float_v::size() *
m;
i <
times.size(); ++
i, ++tp) {
100 int timeOffset = timeIndex / mSincTable.size();
101 timeIndex %= mSincTable.size();
102 if (timeOffset >= mNumNoiseSamples) {
103 timeOffset = mNumNoiseSamples - 1;
104 LOG(
debug) <<
"timeOffset >= mNumNoiseSamples";
106 if (timeOffset <= -mNumNoiseSamples) {
107 timeOffset = -mNumNoiseSamples + 1;
108 LOG(
debug) <<
"timeOffset <= -mNumNoiseSamples";
110 Vc::float_v noiseVal(0);
111 const float* np = mNoiseSamples.data();
112 tp = mSincTable[timeIndex].data() + mNumNoiseSamples - timeOffset;
114 m = mNumNoiseSamples / Vc::float_v::Size;
115 for (
size_t i = 0;
i <
m; ++
i) {
117 tp += Vc::float_v::Size;
118 Vc::prefetchForOneRead(tp);
120 np += Vc::float_v::Size;
121 Vc::prefetchForOneRead(np);
122 acc += noiseVal * tableVal;
126 for (
size_t i = Vc::float_v::Size *
m;
i < mNumNoiseSamples; ++
i, ++tp, ++np) {
127 val += (*np) * (*tp);
131 auto const min_time = std::max(deadTime, *std::min_element(std::begin(
times),
134 bool is_positive =
true;
137 std::fill_n(std::begin(mSignalCache), std::size(mSignalCache), -1.0f);
141 float const val = value_at(
time);
143 if (
index >= 0 &&
index < mSignalCache.size()) {
147 float val_prev = 0.0f;
149 val_prev = ((index_prev < 0 || index_prev >= mSignalCache.size() || mSignalCache[index_prev] < 0.0f)
151 : mSignalCache[index_prev]);
152 float const cfd_val = 5.0f * val_prev -
val;
153 if (std::abs(
val) >
params.mCFD_trsh && !is_positive && cfd_val > 0.0f) {
161 is_positive = cfd_val > 0.0f;
174 const float* tp =
times.data();
175 size_t const m =
times.size() / Vc::float_v::Size;
176 for (
size_t i = 0;
i <
m; ++
i) {
178 tp += Vc::float_v::Size;
179 Vc::prefetchForOneRead(tp);
184 for (
size_t i = Vc::float_v::Size *
m;
i <
times.size(); ++
i, ++tp) {
191 std::vector<o2::ft0::Digit>& digitsBC,
192 std::vector<o2::ft0::ChannelData>& digitsCh,
193 std::vector<o2::ft0::DetTrigInput>& digitsTrig,
198 LOG(
debug) <<
" process firstBCinDeque " << firstBCinDeque <<
" mIntRecord " << mIntRecord;
199 if (firstBCinDeque != mIntRecord) {
204 for (
auto const& hit : *hits) {
205 if (hit.GetEnergyLoss() > 0) {
209 Int_t hit_ch = hit.GetDetectorID();
212 if (mDeadChannelMap && !mDeadChannelMap->
isChannelAlive(hit_ch)) {
218 Bool_t is_A_side = (hit_ch < 4 * mGeometry.
NCellsA);
223 Double_t hit_time = hit.GetTime() - timeOfFlight + timeOffset;
225 if (hit_time > 150) {
230 if (mCache.size() <= relBC.bc) {
231 mCache.resize(relBC.bc + 1);
233 mCache[relBC.bc].hits.emplace_back(
BCCache::particle{hit_ch, hit_time - relBC.bc2ns()});
235 Int_t parentID = hit.GetTrackID();
236 if (parentID != parent) {
237 mCache[relBC.bc].labels.emplace(parentID, mEventID, mSrcID, hit_ch);
243void Digitizer::storeBC(BCCache&
bc,
244 std::vector<o2::ft0::Digit>& digitsBC,
245 std::vector<o2::ft0::ChannelData>& digitsCh,
246 std::vector<o2::ft0::DetTrigInput>& digitsTrig,
249 if (
bc.hits.empty()) {
252 int n_hit_A = 0, n_hit_C = 0, mean_time_A = 0, mean_time_C = 0;
253 int summ_ampl_A = 0, summ_ampl_C = 0;
256 int first = digitsCh.size(), nStored = 0;
257 auto& particles =
bc.hits;
258 std::sort(std::begin(particles), std::end(particles));
259 auto channel_end = particles.begin();
260 std::vector<float> channel_times;
261 for (Int_t ipmt = 0; ipmt <
params.mMCPs; ++ipmt) {
262 auto channel_begin = channel_end;
263 channel_end = std::find_if(channel_begin, particles.end(),
264 [ipmt](BCCache::particle
const& p) { return p.hit_ch != ipmt; });
268 if (channel_end - channel_begin <
params.mAmp_trsh) {
271 channel_times.resize(channel_end - channel_begin);
272 std::transform(channel_begin, channel_end, channel_times.begin(), [](BCCache::particle
const& p) { return p.hit_time; });
273 int chain = (std::rand() % 2) ? 1 : 0;
274 auto cfd =
get_time(channel_times, mDeadTimes[ipmt].intrec.bc2ns() -
275 firstBCinDeque.
bc2ns() +
276 mDeadTimes[ipmt].deadTime);
277 mDeadTimes[ipmt].intrec = firstBCinDeque;
278 mDeadTimes[ipmt].deadTime = cfd.deadTime;
288 int smeared_time = 1000. * (*cfd.particle -
params.mCfdShift) *
params.mChannelWidthInverse + miscalib +
int(1000. * mIntRecord.
getTimeOffsetWrtBC() *
params.mChannelWidthInverse);
289 bool is_time_in_signal_gate = (smeared_time > -
params.mTime_trg_gate && smeared_time <
params.mTime_trg_gate);
291 float amp = is_time_in_signal_gate ?
params.mMV_2_Nchannels *
charge : 0;
296 LOG(
debug) << mEventID <<
" bc " << firstBCinDeque.
bc <<
" orbit " << firstBCinDeque.
orbit <<
", ipmt " << ipmt <<
", smeared_time " << smeared_time <<
" nStored " << nStored <<
" offset " << miscalib;
297 if (is_time_in_signal_gate) {
301 digitsCh.emplace_back(ipmt, smeared_time,
int(amp),
chain);
306 Bool_t is_A_side = (ipmt < 4 * mGeometry.
NCellsA);
307 if (!is_time_in_signal_gate) {
314 mean_time_A += smeared_time;
318 mean_time_C += smeared_time;
321 Bool_t is_A, is_C, isVertex, is_Central, is_SemiCentral = 0;
324 is_Central = summ_ampl_A + summ_ampl_C >=
params.mtrg_central_trh;
325 is_SemiCentral = summ_ampl_A + summ_ampl_C >=
params.mtrg_semicentral_trh;
326 uint32_t
amplA = is_A ? summ_ampl_A * 0.125 : -5000;
327 uint32_t
amplC = is_C ? summ_ampl_C * 0.125 : -5000;
328 int timeA = is_A ? mean_time_A / n_hit_A : -5000;
329 int timeC = is_C ? mean_time_C / n_hit_C : -5000;
331 isVertex = is_A && is_C && (vertex_time > -
params.mTime_trg_gate && vertex_time <
params.mTime_trg_gate);
332 LOG(
debug) <<
" A " << is_A <<
" timeA " <<
timeA <<
" mean_time_A " << mean_time_A <<
" n_hit_A " << n_hit_A <<
" C " << is_C <<
" timeC " <<
timeC <<
" mean_time_C " << mean_time_C <<
" n_hit_C " << n_hit_C <<
" vertex_time " << vertex_time;
334 bool isLaser =
false;
335 bool isOutputsAreBlocked =
false;
336 bool isDataValid =
true;
338 triggers.
setTriggers(is_A, is_C, isVertex, is_Central, is_SemiCentral, int8_t(n_hit_A), int8_t(n_hit_C),
340 digitsBC.emplace_back(
first, nStored, firstBCinDeque, triggers, mEventID - 1);
341 digitsTrig.emplace_back(firstBCinDeque, is_A, is_C, isVertex, is_Central, is_SemiCentral);
342 size_t const nBC = digitsBC.size();
343 for (
auto const& lbl :
bc.labels) {
349 LOG(
debug) <<
"Event ID: " << mEventID <<
", bc " << firstBCinDeque.
bc <<
", N hit " <<
bc.hits.size();
352 <<
" mean time C: " << triggers.
getTimeC() <<
" nStored " << nStored;
359 std::vector<o2::ft0::ChannelData>& digitsCh,
360 std::vector<o2::ft0::DetTrigInput>& digitsTrig,
364 assert(firstBCinDeque <= mIntRecord);
366 while (firstBCinDeque < mIntRecord && !mCache.empty()) {
367 storeBC(mCache.front(), digitsBC, digitsCh, digitsTrig, labels);
371 firstBCinDeque = mIntRecord;
375 std::vector<o2::ft0::ChannelData>& digitsCh,
376 std::vector<o2::ft0::DetTrigInput>& digitsTrig,
380 assert(firstBCinDeque <= mIntRecord);
382 while (!mCache.empty()) {
383 storeBC(mCache.front(), digitsBC, digitsCh, digitsTrig, labels);
391 auto const sinc = [](
double x) {
x *= TMath::Pi();
return (std::abs(
x) < 1e-12) ? 1.0 : std::sin(
x) /
x; };
395 mNumNoiseSamples = std::ceil(
params.mBunchWidth /
params.mNoisePeriod);
396 mNoiseSamples.resize(mNumNoiseSamples);
399 for (
size_t i = 0,
n = mSincTable.size();
i <
n; ++
i) {
403 mSincTable[
i].resize(3 * mNumNoiseSamples);
404 for (
int j = -mNumNoiseSamples;
j < 2 * mNumNoiseSamples; ++
j) {
405 mSincTable[
i][mNumNoiseSamples +
j] =
params.mNoiseVar * sinc((
time + 0.5f *
params.mBunchWidth) /
params.mNoisePeriod -
j);
420 LOG(info) <<
" @@@ Digitizer::init " << std::endl;
434 LOG(info) <<
" Run Digitzation with parametrs: \n"
435 <<
" CFD amplitude threshold \n " <<
params.mCFD_trsh <<
" CFD signal gate in ps \n"
436 <<
params.mTime_trg_gate <<
"shift to have signal around zero after CFD trancformation \n"
437 <<
params.mCfdShift <<
"CFD distance between 0.3 of max amplitude to max \n"
438 <<
params.mCFDShiftPos <<
"MIP -> mV " <<
params.mMip_in_V <<
" Pe in MIP \n"
439 <<
params.mPe_in_mip <<
"noise level " <<
params.mNoiseVar <<
" noise frequency \n"
std::vector< unsigned long > times
#define O2ParamImpl(classname)
uint64_t exp(uint64_t base, uint8_t exp) noexcept
Configurable digitization parameters.
Definition of a container to keep Monte Carlo truth external to simulation objects.
Header to collect physics constants.
static const FT0DigParam & Instance()
uint8_t getNChanC() const
void setTriggers(uint8_t trgsig, uint8_t chanA, uint8_t chanC, int32_t aamplA, int32_t aamplC, int16_t atimeA, int16_t atimeC)
uint8_t getNChanA() const
void flush(std::vector< o2::ft0::Digit > &digitsBC, std::vector< o2::ft0::ChannelData > &digitsCh, std::vector< o2::ft0::DetTrigInput > &digitsTrig, o2::dataformats::MCTruthContainer< o2::ft0::MCLabel > &label)
void printParameters() const
CFDOutput get_time(const std::vector< float > ×, float deadTime)
VcType signalFormVc(VcType x) const
void process(const std::vector< o2::ft0::HitType > *hits, std::vector< o2::ft0::Digit > &digitsBC, std::vector< o2::ft0::ChannelData > &digitsCh, std::vector< o2::ft0::DetTrigInput > &digitsTrig, o2::dataformats::MCTruthContainer< o2::ft0::MCLabel > &label)
void flush_all(std::vector< o2::ft0::Digit > &digitsBC, std::vector< o2::ft0::ChannelData > &digitsCh, std::vector< o2::ft0::DetTrigInput > &digitsTrig, o2::dataformats::MCTruthContainer< o2::ft0::MCLabel > &label)
double measure_amplitude(const std::vector< float > ×) const
float signalForm(float x) const
static constexpr int NCellsA
GLboolean GLboolean GLboolean b
GLenum const GLfloat * params
GLuint GLsizei const GLchar * label
GLboolean GLboolean GLboolean GLboolean a
constexpr float LightSpeedCm2NS
Float signalForm_i(Float x)
Vc::float_v signalForm_integralVc(Vc::float_v x)
float signalForm_integral(float x)
Defining DataPointCompositeObject explicitly as copiable.
uint16_t bc
bunch crossing ID of interaction
static double bc2ns(int bc, unsigned int orbit)
double getTimeOffsetWrtBC() const
const bool isChannelAlive(const uint8_t &chId) const
static constexpr double SIGNAL_CACHE_DT
static constexpr int SIGNAL_TABLE_SIZE
std::array< int16_t, o2::ft0::Geometry::Nchannels > mTimeOffsets
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"