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()) {
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) {
115 if (iter.second.isShared) {
124 return pileupTool.
addSignals(mPileupSignals, mCurrentTriggerTime);
129 mPileupSignals.push_back(mSignalsMapCollection);
133void Digitizer::clearContainers()
135 for (
auto& sm : mSignalsMapCollection) {
143 LOG(fatal) <<
"TRD Calibration database not available";
147 std::array<std::vector<Hit>,
MAXCHAMBER> hitsPerDetector;
148 getHitContainerPerDetector(hits, hitsPerDetector);
152#pragma omp parallel for schedule(dynamic) num_threads(mNumThreads)
156 const int threadid = omp_get_thread_num();
158 const int threadid = 0;
160 auto& signalsMap = mSignalsMapCollection[det];
171 if (hitsPerDetector[det].
size() == 0) {
175 if (!convertHits(det, hitsPerDetector[det], signalsMap, threadid)) {
176 LOG(warn) <<
"TRD conversion of hits failed for detector " << det;
182void Digitizer::getHitContainerPerDetector(
const std::vector<Hit>& hits, std::array<std::vector<Hit>,
MAXCHAMBER>& hitsPerDetector)
189 for (
const auto& hit : hits) {
190 hitsPerDetector[hit.GetDetectorID()].push_back(hit);
194bool Digitizer::convertHits(
const int det,
const std::vector<Hit>& hits,
SignalContainer& signalMapCont,
int thread)
200 double padSignal[mNpad];
202 const double calExBDetValue = mCalib->
getExB(det);
203 const PadPlane* padPlane = mGeo->getPadPlane(det);
204 const int layer = mGeo->getLayer(det);
205 const float rowEndROC = padPlane->getRowEndROC();
206 const float row0 = padPlane->getRow0ROC();
207 const int nColMax = padPlane->getNcols();
210 for (
const auto& hit : hits) {
211 const int qTotal = hit.GetCharge();
223 double locC = hit.getLocalC();
224 double locR = hit.getLocalR();
225 double locT = hit.getLocalT();
226 const double driftLength = -1 * locT;
231 if ((locR < rowEndROC) || (locR > row0)) {
234 if ((driftLength < DrMin) || (driftLength > DrMax)) {
239 int rowE = padPlane->getPadRowNumberROC(locR);
244 double rowOffset = padPlane->getPadRowOffsetROC(rowE, locR);
245 double offsetTilt = padPlane->getTiltOffset(rowE, rowOffset);
246 int colE = padPlane->getPadColNumber(locC + offsetTilt);
251 double absDriftLength = std::fabs(driftLength);
253 absDriftLength /= std::sqrt(1 / (1 + calExBDetValue * calExBDetValue));
256 float driftVelocity = mCalib->
getVDrift(det, colE, rowE);
257 float t0 = mCalib->
getT0(det, colE, rowE);
260 const int nElectrons = std::fabs(qTotal);
261 for (
int el = 0; el < nElectrons; ++el) {
264 if (mFlatRandomRings[thread].getNextValue() < absDriftLength * mElAttachProp) {
269 double locRd{locR}, locCd{locC}, locTd{locT};
273 if (!diffusion(driftVelocity, absDriftLength, calExBDetValue, locR, locC, locT, locRd, locCd, locTd, thread)) {
280 locCd = locCd + calExBDetValue * driftLength;
283 rowE = padPlane->getPadRowNumberROC(locRd);
287 rowOffset = padPlane->getPadRowOffsetROC(rowE, locRd);
289 offsetTilt = padPlane->getTiltOffset(rowE, rowOffset);
290 colE = padPlane->getPadColNumber(locCd + offsetTilt);
294 const double colOffset = padPlane->getPadColOffset(colE, locCd + offsetTilt);
295 driftVelocity = mCalib->
getVDrift(det, colE, rowE);
296 t0 = mCalib->
getT0(det, colE, rowE);
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 const double signal = -(mSimParam.
getGasGain()) * mLogRandomRings[thread].getNextValue();
319 if (mSimParam.
prfOn()) {
321 double dist = (colOffset - 0.5 * padPlane->getColSize(colE)) / padPlane->getColSize(colE);
325 if (!(mPRF.
getPRF(signal, dist,
layer, padSignal))) {
330 padSignal[1] = signal;
335 double timeBinIdeal = driftTime * mSamplingRate +
t0;
337 if (std::fabs(timeBinIdeal) > (2 * mMaxTimeBins)) {
338 timeBinIdeal = 2 * mMaxTimeBins;
340 int timeBinTruncated = ((
int)timeBinIdeal);
342 double timeOffset = ((
float)timeBinTruncated + 0.5 - timeBinIdeal) / mSamplingRate;
345 const int firstTimeBin = std::max(timeBinTruncated, 0);
346 const int lastTimeBin = std::min(timeBinTruncated + mTimeBinTRFend, mMaxTimeBins);
350 for (
int pad = 0; pad < mNpad; ++pad) {
351 int colPos = colE + pad - 1;
355 if (colPos >= nColMax) {
359 const int key = calculateKey(det, rowE, colPos);
360 auto& currentSignalData = signalMapCont[
key];
361 auto& currentSignal = currentSignalData.signals;
362 auto& trackIds = currentSignalData.trackIds;
363 auto& labels = currentSignalData.labels;
364 currentSignalData.firstTBtime = mTime;
365 addLabel(hit.GetTrackID(), labels, trackIds);
368 if (colPos != colE) {
369 for (
int tb = firstTimeBin; tb < lastTimeBin; ++tb) {
370 const double t = (tb - timeBinTruncated) / mSamplingRate + timeOffset;
372 const double crossTalk = mSimParam.
ctOn() ? mSimParam.
crossTalk(t) : 0;
373 currentSignal[tb] += padSignal[pad] * (timeResponse + crossTalk);
376 for (
int tb = firstTimeBin; tb < lastTimeBin; ++tb) {
377 const double t = (tb - timeBinTruncated) / mSamplingRate + timeOffset;
379 currentSignal[tb] += padSignal[pad] * timeResponse;
388void Digitizer::addLabel(
const int& trackId, std::vector<o2::MCCompLabel>& labels, std::unordered_set<int>& trackIds)
390 if (trackIds.count(trackId) == 0) {
391 trackIds.insert(trackId);
393 labels.push_back(
label);
410 constexpr double kEl2fC = 1.602e-19 * 1.0e15;
415 double baselineEl = baseline /
convert;
417 for (
auto& signalMapIter : signalMapCont) {
418 const auto key = signalMapIter.first;
419 const int det = getDetectorFromKey(
key);
420 const int row = getRowFromKey(
key);
421 const int col = getColFromKey(
key);
424 int halfchamberside = (
mcm > 3) ? 1 : 0;
440 LOG(fatal) <<
"Not a valid gain " << padgain <<
", " << det <<
", " <<
col <<
", " <<
row;
443 signalMapIter.second.isDigit =
true;
445 const auto& signalArray = signalMapIter.second.signals;
447 for (
int tb = 0; tb < mMaxTimeBinsTRAP; ++tb) {
448 float signalAmp = (
float)signalArray[tb];
449 signalAmp *= coupling;
450 signalAmp *= padgain;
452 signalAmp = std::max((
double)
drawGaus(mGausRandomRings[thread], signalAmp, mSimParam.
getNoise()), -baselineEl);
454 signalAmp += baseline;
461 adc = std::lround(signalAmp * adcConvert);
468 if (mCreateSharedDigits) {
469 auto digit =
digits.back();
470 if ((digit.getChannel() == 2) && !((digit.getROB() % 2 != 0) && (digit.getMCM() %
NMCMROBINCOL == 3))) {
472 int robShared = (digit.getMCM() %
NMCMROBINCOL == 3) ? digit.getROB() + 1 : digit.getROB();
473 int mcmShared = (robShared == digit.getROB()) ? digit.getMCM() + 1 : digit.getMCM() - 3;
474 digits.emplace_back(det, robShared, mcmShared,
NADCMCM - 1, adcs);
475 signalMapIter.second.isShared =
true;
476 }
else if ((digit.getChannel() == 18 || digit.getChannel() == 19) && !((digit.getROB() % 2 == 0) && (digit.getMCM() %
NMCMROBINCOL == 0))) {
478 int robShared = (digit.getMCM() %
NMCMROBINCOL == 0) ? digit.getROB() - 1 : digit.getROB();
479 int mcmShared = (robShared == digit.getROB()) ? digit.getMCM() - 1 : digit.getMCM() + 3;
480 digits.emplace_back(det, robShared, mcmShared, digit.getChannel() -
NCOLMCM, adcs);
481 signalMapIter.second.isShared =
true;
488bool Digitizer::diffusion(
float vdrift,
float absdriftlength,
float exbvalue,
489 float lRow0,
float lCol0,
float lTime0,
490 double& lRow,
double& lCol,
double& lTime,
int thread)
498 if (mDriftEstimators[thread].getDiffCoeff(diffL, diffT, vdrift)) {
499 float driftSqrt = std::sqrt(absdriftlength);
500 float sigmaT = driftSqrt * diffT;
501 float sigmaL = driftSqrt * diffL;
502 lRow =
drawGaus(mGausRandomRings[thread], lRow0, sigmaT);
504 const float exbfactor = 1.f / (1.f + exbvalue * exbvalue);
505 lCol =
drawGaus(mGausRandomRings[thread], lCol0, sigmaT * exbfactor);
506 lTime =
drawGaus(mGausRandomRings[thread], lTime0, sigmaL * exbfactor);
508 lCol =
drawGaus(mGausRandomRings[thread], lCol0, sigmaT);
509 lTime =
drawGaus(mGausRandomRings[thread], lTime0, sigmaL);
520 for (
int iDet = 0; iDet <
MAXCHAMBER; ++iDet) {
521 if (mFlagVdriftOutOfRange[iDet]) {
Definition of the GeometryManager class.
float drawGaus(o2::math_utils::RandomRing<> &normaldistRing, float mu, float sigma)
static const TRDSimParams & Instance()
const ChamberStatus * getChamberStatus() const
float getPadGainFactor(int roc, int col, int row) const
const PadStatus * getPadStatus() const
float getVDrift(int roc, int col, int row) const
float getExB(int roc) const
float getT0(int roc, int col, int row) const
bool isNoDataSideB(int det) const
bool isNoDataSideA(int det) const
bool isNoData(int det) const
void process(std::vector< Hit > const &)
void dumpLabels(const SignalContainer &, o2::dataformats::MCTruthContainer< MCLabel > &)
void flush(DigitContainer &, o2::dataformats::MCTruthContainer< MCLabel > &)
std::string dumpFlaggedChambers() const
bool createClusterMatrixArray()
static Geometry * instance()
bool chamberInGeometry(int det) 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
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
constexpr int NMCMROBINCOL
the number of MCMs per ROB in column direction
constexpr int TIMEBINS
the number of time bins
constexpr int NADCMCM
the number of ADC channels per MCM
constexpr int NCOLMCM
the number of pads per MCM
constexpr int MAXCHAMBER
the maximum number of installed chambers
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