14#include <TGeoManager.h>
17#include <fairlogger/Logger.h>
49 int maxthreads = omp_get_max_threads();
50 if (askedthreads < 0) {
51 mNumThreads = maxthreads;
53 mNumThreads = std::min(maxthreads, askedthreads);
55 LOG(info) <<
"TRD: Digitizing with " << mNumThreads <<
" threads ";
59 mGausRandomRings.resize(mNumThreads);
60 mFlatRandomRings.resize(mNumThreads);
61 mLogRandomRings.resize(mNumThreads);
62 for (
int i = 0;
i < mNumThreads; ++
i) {
65 mLogRandomRings[
i].initialize([]() ->
float {
return std::log(gRandom->Rndm()); });
69 setSimulationParameters();
72void Digitizer::setSimulationParameters()
75 if (mSimParam.
trfOn()) {
78 mMaxTimeBins = TIMEBINS;
79 mMaxTimeBinsTRAP = TIMEBINS;
86 if (mPileupSignals.size() > 0) {
90 bool status = convertSignalsToADC(smc,
digits);
92 LOG(warn) <<
"TRD conversion of signals to digits failed";
99 for (
auto& smc : mSignalsMapCollection) {
100 bool status = convertSignalsToADC(smc,
digits);
102 LOG(warn) <<
"TRD conversion of signals to digits failed";
112 for (
const auto& iter : smc) {
113 if (iter.second.isDigit) {
114 labels.addElements(
labels.getIndexedSize(), iter.second.labels);
115 if (iter.second.isShared) {
116 labels.addElements(
labels.getIndexedSize(), iter.second.labels);
124 return pileupTool.
addSignals(mPileupSignals, mCurrentTriggerTime);
129 mPileupSignals.push_back(mSignalsMapCollection);
133void Digitizer::clearContainers()
135 for (
auto& sm : mSignalsMapCollection) {
144 std::array<std::vector<Hit>, MAXCHAMBER> hitsPerDetector;
145 getHitContainerPerDetector(hits, hitsPerDetector);
149#pragma omp parallel for schedule(dynamic) num_threads(mNumThreads)
151 for (
int det = 0; det < MAXCHAMBER; ++det) {
153 const int threadid = omp_get_thread_num();
155 const int threadid = 0;
157 auto& signalsMap = mSignalsMapCollection[det];
169 if (hitsPerDetector[det].
size() == 0) {
173 if (!convertHits(det, hitsPerDetector[det], signalsMap, threadid)) {
174 LOG(warn) <<
"TRD conversion of hits failed for detector " << det;
180void Digitizer::getHitContainerPerDetector(
const std::vector<Hit>& hits, std::array<std::vector<Hit>, MAXCHAMBER>& hitsPerDetector)
187 for (
const auto& hit : hits) {
188 hitsPerDetector[hit.GetDetectorID()].push_back(hit);
192bool Digitizer::convertHits(
const int det,
const std::vector<Hit>& hits,
SignalContainer& signalMapCont,
int thread)
198 double padSignal[mNpad];
200 const double calExBDetValue = mCalVdriftExB->
getExB(det,
true);
201 const PadPlane* padPlane = mGeo->getPadPlane(det);
202 const int layer = mGeo->getLayer(det);
203 const float rowEndROC = padPlane->getRowEndROC();
204 const float row0 = padPlane->getRow0ROC();
205 const int nColMax = padPlane->getNcols();
208 for (
const auto& hit : hits) {
209 const int qTotal = hit.GetCharge();
221 double locC = hit.getLocalC();
222 double locR = hit.getLocalR();
223 double locT = hit.getLocalT();
224 const double driftLength = -1 * locT;
229 if ((locR < rowEndROC) || (locR > row0)) {
232 if ((driftLength < DrMin) || (driftLength > DrMax)) {
237 int rowE = padPlane->getPadRowNumberROC(locR);
242 double rowOffset = padPlane->getPadRowOffsetROC(rowE, locR);
243 double offsetTilt = padPlane->getTiltOffset(rowE, rowOffset);
244 int colE = padPlane->getPadColNumber(locC + offsetTilt);
249 double absDriftLength = std::fabs(driftLength);
251 absDriftLength /= std::sqrt(1 / (1 + calExBDetValue * calExBDetValue));
261 const int nElectrons = std::fabs(qTotal);
262 for (
int el = 0; el < nElectrons; ++el) {
265 if (mFlatRandomRings[thread].getNextValue() < absDriftLength * mElAttachProp) {
270 double locRd{locR}, locCd{locC}, locTd{locT};
274 if (!diffusion(driftVelocity, absDriftLength, calExBDetValue, locR, locC, locT, locRd, locCd, locTd, thread)) {
282 locCd = locCd - TMath::Tan(calExBDetValue) * driftLength;
285 rowE = padPlane->getPadRowNumberROC(locRd);
289 rowOffset = padPlane->getPadRowOffsetROC(rowE, locRd);
291 offsetTilt = padPlane->getTiltOffset(rowE, rowOffset);
292 colE = padPlane->getPadColNumber(locCd + offsetTilt);
296 const double colOffset = padPlane->getPadColOffset(colE, locCd + offsetTilt);
303 double zz = row0 - locRd + padPlane->getAnodeWireOffset();
304 zz -= ((
int)(2 * zz)) * 0.5;
309 driftTime = mDriftEstimators[thread].timeStruct(driftVelocity, 0.5 * AmWidth - 1.0 * locTd, zz, &(mFlagVdriftOutOfRange[det])) + hit.GetTime();
312 driftTime = std::fabs(locTd) / driftVelocity + hit.GetTime();
316 double timeDepGainFactor = mCalGain->
getMPVdEdx(det,
true) / constants::MPVDEDXDEFAULT;
317 const double signal = -(mSimParam.
getGasGain()) * timeDepGainFactor * mLogRandomRings[thread].getNextValue();
320 if (mSimParam.
prfOn()) {
322 double dist = (colOffset - 0.5 * padPlane->getColSize(colE)) / padPlane->getColSize(colE);
326 if (!(mPRF.
getPRF(signal, dist,
layer, padSignal))) {
331 padSignal[1] = signal;
336 double timeBinIdeal = (driftTime +
t0) * mSamplingRate;
338 if (std::fabs(timeBinIdeal) > (2 * mMaxTimeBins)) {
339 timeBinIdeal = 2 * mMaxTimeBins;
341 int timeBinTruncated = ((
int)timeBinIdeal);
343 double timeOffset = ((float)timeBinTruncated + 0.5 - timeBinIdeal) / mSamplingRate;
346 const int firstTimeBin = std::max(timeBinTruncated, 0);
347 const int lastTimeBin = std::min(timeBinTruncated + mTimeBinTRFend, mMaxTimeBins);
351 for (
int pad = 0; pad < mNpad; ++pad) {
352 int colPos = colE + pad - 1;
356 if (colPos >= nColMax) {
360 const int key = calculateKey(det, rowE, colPos);
361 auto& currentSignalData = signalMapCont[
key];
362 auto& currentSignal = currentSignalData.signals;
363 auto& trackIds = currentSignalData.trackIds;
364 auto&
labels = currentSignalData.labels;
365 currentSignalData.firstTBtime = mTime;
366 addLabel(hit.GetTrackID(),
labels, trackIds);
369 if (colPos != colE) {
370 for (
int tb = firstTimeBin; tb < lastTimeBin; ++tb) {
371 const double t = (tb - timeBinTruncated) / mSamplingRate + timeOffset;
373 const double crossTalk = mSimParam.
ctOn() ? mSimParam.
crossTalk(t) : 0;
374 currentSignal[tb] += padSignal[pad] * (timeResponse + crossTalk);
377 for (
int tb = firstTimeBin; tb < lastTimeBin; ++tb) {
378 const double t = (tb - timeBinTruncated) / mSamplingRate + timeOffset;
380 currentSignal[tb] += padSignal[pad] * timeResponse;
389void Digitizer::addLabel(
const int& trackId, std::vector<o2::MCCompLabel>&
labels, std::unordered_set<int>& trackIds)
391 if (trackIds.count(trackId) == 0) {
392 trackIds.insert(trackId);
411 constexpr double kEl2fC = 1.602e-19 * 1.0e15;
416 double baselineEl = baseline /
convert;
418 for (
auto& signalMapIter : signalMapCont) {
419 const auto key = signalMapIter.first;
420 const int det = getDetectorFromKey(
key);
421 const int row = getRowFromKey(
key);
422 const int col = getColFromKey(
key);
425 int halfchamberside = (
mcm > 3) ? 1 : 0;
433 float padgain = std::fabs(mLocalGainFactor->
getValue(det,
col,
row));
435 LOG(fatal) <<
"Not a valid gain " << padgain <<
", " << det <<
", " <<
col <<
", " <<
row;
438 signalMapIter.second.isDigit =
true;
440 const auto& signalArray = signalMapIter.second.signals;
442 for (
int tb = 0; tb < mMaxTimeBinsTRAP; ++tb) {
443 float signalAmp = (float)signalArray[tb];
444 signalAmp *= coupling;
445 signalAmp *= padgain;
447 signalAmp = std::max((
double)
drawGaus(mGausRandomRings[thread], signalAmp, mSimParam.
getNoise()), -baselineEl);
449 signalAmp += baseline;
456 adc = std::lround(signalAmp * adcConvert);
463 if (mCreateSharedDigits) {
464 auto digit =
digits.back();
465 if ((digit.getChannel() == 2) && !((digit.getROB() % 2 != 0) && (digit.getMCM() % NMCMROBINCOL == 3))) {
467 int robShared = (digit.getMCM() % NMCMROBINCOL == 3) ? digit.getROB() + 1 : digit.getROB();
468 int mcmShared = (robShared == digit.getROB()) ? digit.getMCM() + 1 : digit.getMCM() - 3;
469 digits.emplace_back(det, robShared, mcmShared, NADCMCM - 1, adcs);
470 signalMapIter.second.isShared =
true;
471 }
else if ((digit.getChannel() == 18 || digit.getChannel() == 19) && !((digit.getROB() % 2 == 0) && (digit.getMCM() % NMCMROBINCOL == 0))) {
473 int robShared = (digit.getMCM() % NMCMROBINCOL == 0) ? digit.getROB() - 1 : digit.getROB();
474 int mcmShared = (robShared == digit.getROB()) ? digit.getMCM() - 1 : digit.getMCM() + 3;
475 digits.emplace_back(det, robShared, mcmShared, digit.getChannel() - NCOLMCM, adcs);
476 signalMapIter.second.isShared =
true;
483bool Digitizer::diffusion(
float vdrift,
float absdriftlength,
float exbvalue,
484 float lRow0,
float lCol0,
float lTime0,
485 double& lRow,
double& lCol,
double& lTime,
int thread)
493 if (mDriftEstimators[thread].getDiffCoeff(diffL, diffT, vdrift)) {
494 float driftSqrt = std::sqrt(absdriftlength);
495 float sigmaT = driftSqrt * diffT;
496 float sigmaL = driftSqrt * diffL;
497 lRow =
drawGaus(mGausRandomRings[thread], lRow0, sigmaT);
499 const float exbfactor = 1.f / (1.f + exbvalue * exbvalue);
500 lCol =
drawGaus(mGausRandomRings[thread], lCol0, sigmaT * exbfactor);
501 lTime =
drawGaus(mGausRandomRings[thread], lTime0, sigmaL * exbfactor);
503 lCol =
drawGaus(mGausRandomRings[thread], lCol0, sigmaT);
504 lTime =
drawGaus(mGausRandomRings[thread], lTime0, sigmaL);
515 for (
int iDet = 0; iDet < MAXCHAMBER; ++iDet) {
516 if (mFlagVdriftOutOfRange[iDet]) {
Definition of the GeometryManager class.
std::vector< o2::MCCompLabel > labels
float drawGaus(o2::math_utils::RandomRing<> &normaldistRing, float mu, float sigma)
static const TRDSimParams & Instance()
float getMPVdEdx(int iDet, bool defaultAvg=true) const
float getExB(int iDet, bool defaultAvg=true) const
float getVdrift(int iDet, bool defaultAvg=true) const
void process(std::vector< Hit > const &)
void dumpLabels(const SignalContainer &, o2::dataformats::MCTruthContainer< MCLabel > &)
void flush(DigitContainer &, o2::dataformats::MCTruthContainer< MCLabel > &)
int getFedChamberStatus(int det)
std::string dumpFlaggedChambers() const
bool createClusterMatrixArray()
static Geometry * instance()
bool chamberInGeometry(int det) const
T getValue(int roc, int col, int row) const
int getPRF(double, double, int, double *) const
bool isNotConnected(int roc, int col, int row) const
bool isMasked(int roc, int col, int row) const
float getADCoutRange() const
bool timeStructOn() const
float getCachedField() const
float getEffVdriftDefault() const
double timeResponse(double) const
double crossTalk(double) const
GasMixture getGasMixture() const
float getADCinRange() const
float getPadCoupling() const
int getADCbaseline() const
float getTimeCoupling() const
float getElAttachProp() const
float getSamplingFrequency() const
int getNumberOfPadsInPadResponse() const
float getChipGain() const
GLuint GLsizei const GLchar * label
GLenum GLuint GLint GLint layer
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
uint8_t int statusCode int
constexpr double VDRIFTDEFAULT
default value for vDrift
std::unordered_map< int, SignalArray > SignalContainer
std::vector< Digit > DigitContainer
std::array< ADC_t, constants::TIMEBINS > ArrayADC
std::string to_string(gsl::span< T, Size > span)
int digithreads
number of digitizer threads
std::vector< uint64_t > convert(gsl::span< const uint64_t > page)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits