diff --git a/Detectors/TRD/base/include/TRDBase/PadPlane.h b/Detectors/TRD/base/include/TRDBase/PadPlane.h index 24c67a8453b48..a4c69671bb162 100644 --- a/Detectors/TRD/base/include/TRDBase/PadPlane.h +++ b/Detectors/TRD/base/include/TRDBase/PadPlane.h @@ -120,7 +120,41 @@ class PadPlane GPUd() int getPadRowNumberROC(double z) const; GPUd() double getPadRow(double z) const; - GPUd() int getPadColNumber(double rphi) const; + + GPUd() int getPadColNumber(double rphi) const + { + // + // Finds the pad column number for a given rphi-position + // + + int col = 0; + int nabove = 0; + int nbelow = 0; + int middle = 0; + + if ((rphi < getCol0()) || (rphi > getColEnd())) { + col = -1; + + } else { + nabove = mNcols; + nbelow = 0; + while (nabove - nbelow > 1) { + middle = (nabove + nbelow) / 2; + if (rphi == mPadCol[middle]) { + col = middle; + } + if (rphi > mPadCol[middle]) { + nbelow = middle; + } else { + nabove = middle; + } + } + col = nbelow; + } + + return col; + } + GPUd() double getPad(double y, double z) const; GPUd() double getTiltOffset(int row, double rowOffset) const diff --git a/Detectors/TRD/base/src/PadPlane.cxx b/Detectors/TRD/base/src/PadPlane.cxx index 8ead898aa1ff0..9c586f20d6efb 100644 --- a/Detectors/TRD/base/src/PadPlane.cxx +++ b/Detectors/TRD/base/src/PadPlane.cxx @@ -76,41 +76,6 @@ int PadPlane::getPadRowNumberROC(double z) const return row; } -//_____________________________________________________________________________ -int PadPlane::getPadColNumber(double rphi) const -{ - // - // Finds the pad column number for a given rphi-position - // - - int col = 0; - int nabove = 0; - int nbelow = 0; - int middle = 0; - - if ((rphi < getCol0()) || (rphi > getColEnd())) { - col = -1; - - } else { - nabove = mNcols; - nbelow = 0; - while (nabove - nbelow > 1) { - middle = (nabove + nbelow) / 2; - if (rphi == mPadCol[middle]) { - col = middle; - } - if (rphi > mPadCol[middle]) { - nbelow = middle; - } else { - nabove = middle; - } - } - col = nbelow; - } - - return col; -} - void PadPlane::setNcols(int n) { if (n > MAXCOLS) { diff --git a/Detectors/TRD/calibration/include/TRDCalibration/CalibrationParams.h b/Detectors/TRD/calibration/include/TRDCalibration/CalibrationParams.h index cadd21af2a55d..48dfb0c953911 100644 --- a/Detectors/TRD/calibration/include/TRDCalibration/CalibrationParams.h +++ b/Detectors/TRD/calibration/include/TRDCalibration/CalibrationParams.h @@ -26,8 +26,10 @@ namespace trd struct TRDCalibParams : public o2::conf::ConfigurableParamHelper { unsigned int nTrackletsMin = 5; ///< minimum amount of tracklets unsigned int nTrackletsMinLoose = 4; ///< minimum amount of tracklets if two layers with a large lever arm both have a hit - unsigned int chi2RedMax = 6; ///< maximum reduced chi2 acceptable for track quality - size_t minEntriesChamber = 200; ///< minimum number of entries per chamber to fit single time slot + unsigned int chi2RedMax = 6; ///< maximum reduced chi2 acceptable for track quality + float minPtCalib = 1.; ///< min pt for vd and ExB calib + bool rejectTPCTRD = true; ///< reject TPC-TRD tracks for vd ExB calib + size_t minEntriesChamber = 200; ///< minimum number of entries per chamber to fit single time slot size_t minEntriesTotal = 400'000; ///< minimum total required for meaningful fits // For gain calibration diff --git a/Detectors/TRD/calibration/src/TrackBasedCalib.cxx b/Detectors/TRD/calibration/src/TrackBasedCalib.cxx index a0cbab6ac8bfa..cd2f8ad7f8594 100644 --- a/Detectors/TRD/calibration/src/TrackBasedCalib.cxx +++ b/Detectors/TRD/calibration/src/TrackBasedCalib.cxx @@ -22,6 +22,7 @@ #include "TRDBase/Geometry.h" #include "TRDBase/PadPlane.h" #include "CommonUtils/NameConf.h" +#include "CommonConstants/GeomConstants.h" #include "DataFormatsTPC/TrackTPC.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include @@ -77,8 +78,9 @@ void TrackBasedCalib::calculateAngResHistos() LOGF(info, "As input tracks are available: %lu ITS-TPC-TRD tracks and %lu TPC-TRD tracks", mTracksInITSTPCTRD.size(), mTracksInTPCTRD.size()); + auto& params = TRDCalibParams::Instance(); int nTracksSuccessITSTPCTRD = doTrdOnlyTrackFits(mTracksInITSTPCTRD); - int nTracksSuccessTPCTRD = doTrdOnlyTrackFits(mTracksInTPCTRD); + int nTracksSuccessTPCTRD = params.rejectTPCTRD ? 0 : doTrdOnlyTrackFits(mTracksInTPCTRD); LOGF(info, "Successfully processed %i tracks (%i from ITS-TPC-TRD and %i from TPC-TRD) and collected %lu angular residuals", nTracksSuccessITSTPCTRD + nTracksSuccessTPCTRD, nTracksSuccessITSTPCTRD, nTracksSuccessTPCTRD, mAngResHistos.getNEntries()); @@ -195,6 +197,11 @@ int TrackBasedCalib::doTrdOnlyTrackFits(gsl::span& tracks) continue; } } + if (trkIn.getPt() < params.minPtCalib) { + // we reject low pt tracks which might suffer from multiple scattering (giving lower quality of the TRD-only fit) + continue; + } + auto trkWork = trkIn; // input is const, so we need to create a copy bool trackFailed = false; @@ -206,6 +213,12 @@ int TrackBasedCalib::doTrdOnlyTrackFits(gsl::span& tracks) continue; } + // reject tracks which cross sectors within TRD (if the extrapolation from the outer TRD to the outer TPC leads to a change in sector or close to the sector edges with 5 cm margin), which have larger uncertainties and probably more fakes + float yOuterTPC = trkIn.getOuterParam().getYAt(o2::constants::geom::XTPCOuterRef, bz); + if (std::fabs(yOuterTPC) > o2::constants::geom::XTPCOuterRef * tan(M_PI / 18.) - 5.) { + continue; + } + // first inward propagation (TRD track fit) int currLayer = NLAYER; for (int iLayer = NLAYER - 1; iLayer >= 0; --iLayer) { @@ -274,6 +287,7 @@ int TrackBasedCalib::doTrdOnlyTrackFits(gsl::span& tracks) if (!((trkWork.getSigmaZ2() < (padLength * padLength / 12.f)) && (std::fabs(mTrackletsCalib[trkltId].getZ() - trkWork.getZ()) < padLength))) { tiltCorrUp = 0.f; } + // use uncalibrated dy because online calibration does not work otherwise float trkltDy = mTrackletsRaw[trkltId].getUncalibratedDy(30.f / o2::trd::constants::VDRIFTDEFAULT) + tiltCorrUp; float trkltAngle = o2::math_utils::atan(trkltDy / Geometry::cdrHght()) * TMath::RadToDeg(); diff --git a/Detectors/TRD/qc/src/Tracking.cxx b/Detectors/TRD/qc/src/Tracking.cxx index 35f0734498a40..65d0ccf9a71bc 100644 --- a/Detectors/TRD/qc/src/Tracking.cxx +++ b/Detectors/TRD/qc/src/Tracking.cxx @@ -160,10 +160,14 @@ void Tracking::checkTrack(const TrackTRD& trkTrd, bool isTPCTRD) float slopeFactor = mTrackletsRaw[trkltId].getSlopeFloat() * pad->getWidthIPad() / 4.f; float yCorrPileUp = tCorrPileUp * slopeFactor; float yAddErrPileUp2 = tErrPileUp2 * slopeFactor * slopeFactor; + float yPosCorrUp = mTrackletsCalib[trkltId].getY() - tiltCorrUp + yCorrPileUp; float angularPull = (mTrackletsCalib[trkltId].getDy() + dyTiltCorr - mRecoParam.convertAngleToDy(trk.getSnp())) / std::sqrt(mRecoParam.getDyRes(trk.getSnp(), 0)); + // Correction of y position based on angular pull + float corrPull = -angularPull * mRecoParam.getCorrYDy(trk.getSnp()); + yPosCorrUp += corrPull; - std::array trkltPosUp{mTrackletsCalib[trkltId].getY() - tiltCorrUp + yCorrPileUp, zPosCorrUp}; + std::array trkltPosUp{yPosCorrUp, zPosCorrUp}; std::array trkltCovUp; mRecoParam.recalcTrkltCov(tilt, trk.getSnp(), pad->getRowSize(tracklet.getPadRow()), trkltCovUp, angularPull, 0); trkltCovUp[0] += yAddErrPileUp2; diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h index c3a5be6a45649..244a3bc0a9a8c 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h @@ -78,6 +78,8 @@ class TRDGlobalTracking : public o2::framework::Task float mTPCTBinMUSInv{1.f / mTPCTBinMUS}; ///< inverse width of a TPC time bin in 1/us float mTPCVdrift{2.58f}; ///< TPC drift velocity (for shifting TPC tracks along Z) float mTPCTDriftOffset{0.f}; ///< TPC drift time additive offset + int32_t mTCorrPileUp{0}; ///< most probable correction in number of BCs due to pile-up in TRD + float mTErrPileUp2{0.f}; ///< error on correction in number of BCs due to pile-up in TRD std::shared_ptr mDataRequest; ///< seeding input (TPC-only, ITS-TPC or both) std::shared_ptr mGGCCDBRequest; o2::tpc::VDriftHelper mTPCVDriftHelper{}; diff --git a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx index e541482dbde2a..2539d09eb509b 100644 --- a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx @@ -153,6 +153,9 @@ void TRDGlobalTracking::updateTimeDependentParams(ProcessingContext& pc) mBase->init(pc); mBase->setLocalGainFactors(pc.inputs().get("localgainfactors").get()); } + + pc.inputs().get*>("chamberstatus"); // called to trigger finaliseCCDB + // pc.inputs().get("padstatus"); // called to trigger finaliseCCDB } const auto& trackTune = TrackTuneParams::Instance(); @@ -198,6 +201,34 @@ void TRDGlobalTracking::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) return; } #endif + if (matcher == ConcreteDataMatcher("TRD", "CHAMBERSTATUS", 0)) { + LOG(info) << "chamber status object updated"; + const std::array* chamberStatus = (const std::array*)obj; + for (int iDet = 0; iDet < constants::MAXCHAMBER; iDet++) { + if ((*chamberStatus)[iDet] == 3) { + mTracker->SetChamberStatus(iDet, false); // chamber is good + } else { + mTracker->SetChamberStatus(iDet, true); // chamber is bad + } + } + return; + } + /*if (matcher == ConcreteDataMatcher("TRD", "PADSTATUS", 0)) { + LOG(info) << "pad status object updated"; + const o2::trd::PadStatus* padStatus = (const o2::trd::PadStatus*)obj; + for (int iDet = 0; iDet < constants::MAXCHAMBER; iDet++) { + for (int iCol = 0; iCol < constants::NCOLUMN; iCol++) { + for (int iRow = 0; iRow < ((iDet % 30) / 6 == 2 ? constants::NROWC0 : constants::NROWC1); iRow++) { + if (padStatus->isMasked(iDet, iCol, iRow) || padStatus->isNotConnected(iDet, iCol, iRow)) { + mTracker->SetPadStatus(iDet * constants::NCOLUMN * constants::NROWC1 + iCol * constants::NROWC1 + iRow, true); // pad is masked + } else { + mTracker->SetPadStatus(iDet * constants::NCOLUMN * constants::NROWC1 + iCol * constants::NROWC1 + iRow, false); // pad is not masked + } + } + } + } + return; + }*/ } void TRDGlobalTracking::fillMCTruthInfo(const TrackTRD& trk, o2::MCCompLabel lblSeed, std::vector& lblContainerTrd, std::vector& lblContainerMatch, const o2::dataformats::MCTruthContainer* trkltLabels) const @@ -500,6 +531,45 @@ void TRDGlobalTracking::run(ProcessingContext& pc) if (trdTrack.getChi2() / trdTrack.getNtracklets() > mTracker->Param().rec.trd.maxChi2Red) { continue; } + + // Find most probable BCs and RMS for pile-up correction and error. Same BC is assumed for all tracklets + float maxProb = 0.f; + // The uncertainty is the RMS wrt the default correction of all possible corrections weighted by their probability + float sumCorr = 0.f; + float sumCorr2 = 0.f; + float sumProb = 0.f; + for (int iBC = 0; iBC < mTriggeredBCFT0.size(); iBC++) { + int deltaBC = roundf(mTriggeredBCFT0[iBC] - mChainTracking->mIOPtrs.trdTriggerTimes[trdTrack.getCollisionId()] / o2::constants::lhc::LHCBunchSpacingMUS); + if (deltaBC <= mRecoParam.getPileUpRangeBefore() || deltaBC >= mRecoParam.getPileUpRangeAfter()) { + continue; + } + // collect the charges + std::array q0; + std::array q1; + for (int iLy = 0; iLy < NLAYER; iLy++) { + int trkltId = trdTrack.getTrackletIndex(iLy); + if (trkltId < 0) { + q0[iLy] = -1; + q1[iLy] = -1; + } else { + q0[iLy] = mTrackletsRaw[trkltId].getQ0(); + q1[iLy] = mTrackletsRaw[trkltId].getQ1(); + } + } + // get pile-up probability + float probBC = mRecoParam.getPileUpProbTrack(deltaBC, q0, q1); + sumCorr += probBC * deltaBC; + sumCorr2 += probBC * deltaBC * deltaBC; + sumProb += probBC; + if (probBC > maxProb) { + maxProb = probBC; + mTCorrPileUp = -deltaBC; + } + } + if (sumProb > 1e-6) { + mTErrPileUp2 = sumCorr2 / sumProb - 2 * mTCorrPileUp * sumCorr / sumProb + mTCorrPileUp * mTCorrPileUp; + } + nTrackletsAttached += trdTrack.getNtracklets(); auto trackGID = trdTrack.getRefGlobalTrackId(); if (trackGID.includesDet(GTrackID::Source::ITS)) { @@ -529,7 +599,7 @@ void TRDGlobalTracking::run(ProcessingContext& pc) } else { tracksOutTPC.back().setPileUpDistance(mTracker->Param().rec.trd.pileupBwdNBC, mTracker->Param().rec.trd.pileupFwdNBC); } - if (!refitTPCTRDTrack(tracksOutTPC.back(), mChainTracking->mIOPtrs.trdTriggerTimes[trdTrack.getCollisionId()], &inputTracks) || std::isnan(tracksOutTPC.back().getSnp())) { + if (!refitTPCTRDTrack(tracksOutTPC.back(), mChainTracking->mIOPtrs.trdTriggerTimes[trdTrack.getCollisionId()] - mTCorrPileUp * o2::constants::lhc::LHCBunchSpacingMUS, &inputTracks) || std::isnan(tracksOutTPC.back().getSnp())) { tracksOutTPC.pop_back(); ++nTracksFailedTPCTRDRefit; continue; @@ -734,7 +804,8 @@ bool TRDGlobalTracking::refitTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::globa return false; } if (pileUpOn) { // account pileup time uncertainty in Z errors - timeZErr = mTPCVdrift * trk.getPileUpTimeErrorMUS(); + // timeZErr = mTPCVdrift * trk.getPileUpTimeErrorMUS(); + timeZErr = mTPCVdrift * mTPCVdrift * mTErrPileUp2; outerParam.updateCov(timeZErr, o2::track::CovLabels::kSigZ2); } if (!refitTRDTrack(trk, chi2Out, false, true)) { @@ -818,46 +889,6 @@ bool TRDGlobalTracking::refitTRDTrack(TrackTRD& trk, float& chi2, bool inwards, } } - // Find most probable BCs and RMS for pile-up correction and error. Same BC is assumed for all tracklets - float tCorrPileUp = 0.; - float tErrPileUp2 = 0; - float maxProb = 0.f; - // The uncertainty is the RMS wrt the default correction of all possible corrections weighted by their probability - float sumCorr = 0.f; - float sumCorr2 = 0.f; - float sumProb = 0.f; - for (int iBC = 0; iBC < mTriggeredBCFT0.size(); iBC++) { - int deltaBC = roundf(mTriggeredBCFT0[iBC] - mChainTracking->mIOPtrs.trdTriggerTimes[trk.getCollisionId()] / o2::constants::lhc::LHCBunchSpacingMUS); - if (deltaBC <= mRecoParam.getPileUpRangeBefore() || deltaBC >= mRecoParam.getPileUpRangeAfter()) { - continue; - } - // collect the charges - std::array q0; - std::array q1; - for (int iLy = 0; iLy < NLAYER; iLy++) { - int trkltId = trk.getTrackletIndex(iLy); - if (trkltId < 0) { - q0[iLy] = -1; - q1[iLy] = -1; - } else { - q0[iLy] = mTrackletsRaw[trkltId].getQ0(); - q1[iLy] = mTrackletsRaw[trkltId].getQ1(); - } - } - // get pile-up probability - float probBC = mRecoParam.getPileUpProbTrack(deltaBC, q0, q1); - sumCorr += probBC * deltaBC; - sumCorr2 += probBC * deltaBC * deltaBC; - sumProb += probBC; - if (probBC > maxProb) { - maxProb = probBC; - tCorrPileUp = -deltaBC; - } - } - if (sumProb > 1e-6) { - tErrPileUp2 = sumCorr2 / sumProb - 2 * tCorrPileUp * sumCorr / sumProb + tCorrPileUp * tCorrPileUp; - } - if (inwards) { // reset covariance to something big for inwards refit trkParam->resetCovariance(100); @@ -891,13 +922,20 @@ bool TRDGlobalTracking::refitTRDTrack(TrackTRD& trk, float& chi2, bool inwards, // conversion from slope in pad per time bin to slope in cm per BC = tracklets[trkltIdx].getSlopeFloat() * padWidth / BCperTimeBin float slopeFactor = mTrackletsRaw[trkltId].getSlopeFloat() * pad->getWidthIPad() / 4.f; - float yCorrPileUp = tCorrPileUp * slopeFactor; - float yAddErrPileUp2 = tErrPileUp2 * slopeFactor * slopeFactor; + float yCorrPileUp = mTCorrPileUp * slopeFactor; + float yAddErrPileUp2 = mTErrPileUp2 * slopeFactor * slopeFactor; + float yPosCorrUp = mTrackletsCalib[trkltId].getY() - tiltCorrUp + yCorrPileUp; int nTrackletsChamber = mTracker->GetNtrackletsChamber(trk.getCollisionId(), trkltDet); float angularPull = (mTrackletsCalib[trkltId].getDy() + dyTiltCorr - mRecoParam.convertAngleToDy(trkParam->getSnp())) / std::sqrt(mRecoParam.getDyRes(trkParam->getSnp(), nTrackletsChamber)); - std::array trkltPosUp{mTrackletsCalib[trkltId].getY() - tiltCorrUp + yCorrPileUp, zPosCorrUp}; + // Correction of y position based on angular pull + if (mRec->GetParam().rec.trd.useAngularPull == 3 || mRec->GetParam().rec.trd.useAngularPull == 4) { + float corrPull = -angularPull * mRecoParam.getCorrYDy(trkParam->getSnp()); + yPosCorrUp += corrPull; + } + + std::array trkltPosUp{yPosCorrUp, zPosCorrUp}; std::array trkltCovUp; mRecoParam.recalcTrkltCov(tilt, trkParam->getSnp(), pad->getRowSize(mTrackletsRaw[trkltId].getPadRow()), trkltCovUp, (mRec->GetParam().rec.trd.useAngularPull != 0 ? angularPull : 0.), nTrackletsChamber); trkltCovUp[0] += yAddErrPileUp2; @@ -1007,6 +1045,10 @@ DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, GTrackID::mask_t src, boo inputs.emplace_back("localgainfactors", "TRD", "LOCALGAINFACTORS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/LocalGainFactor")); } + // request list of bad chambers and masked pads to estimate better the number of findable tracklets + inputs.emplace_back("chamberstatus", "TRD", "CHAMBERSTATUS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/DCSDPsFedChamberStatus")); + // inputs.emplace_back("padstatus", "TRD", "PADSTATUS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/PadStatus")); + if (GTrackID::includesSource(GTrackID::Source::ITSTPC, src)) { outputs.emplace_back(o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0, Lifetime::Timeframe); outputs.emplace_back(o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0, Lifetime::Timeframe); diff --git a/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx index dfe524c38ac6f..b1d5e60d3a6ac 100644 --- a/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx +++ b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx @@ -45,18 +45,18 @@ void GPUTRDRecoParam::init(float bz, const GPUSettingsRec* rec) if (CAMath::Abs(CAMath::Abs(bz) - 2) < 0.1) { if (bz > 0) { // magnetic field +0.2 T - mRPhiC2 = 4.55e-2f; + mRPhiC2 = 0.098f; } else { // magnetic field -0.2 T - mRPhiC2 = 4.55e-2f; + mRPhiC2 = 0.098f; } } else if (CAMath::Abs(CAMath::Abs(bz) - 5) < 0.1) { if (bz > 0) { // magnetic field +0.5 T - mRPhiC2 = 0.0961f; + mRPhiC2 = 0.058f; } else { // magnetic field -0.5 T - mRPhiC2 = 0.1156f; + mRPhiC2 = 0.072f; } } else { LOGP(warning, "No error parameterization available for Bz= {}. Keeping default value (sigma_y = const. = 1cm)", bz); diff --git a/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h index d561349a37a43..61ed436c5c665 100644 --- a/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h +++ b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h @@ -49,7 +49,9 @@ class GPUTRDRecoParam GPUd() float getRPhiRes(float snp, float pull = 0.f, int occupancy = 0) const; GPUd() float getDyRes(float snp, int occupancy = 0) const { return mDyA2 + mDyC2 * (snp - mLorentzAngle) * (snp - mLorentzAngle) + mOccDyA * occupancy; } // a^2 + c^2 * (snp - b)^2 GPUd() float convertAngleToDy(float snp) const { return 3.f * snp / CAMath::Sqrt(1 - snp * snp); } // when calibrated, sin(phi) = (dy / xDrift) / sqrt(1+(dy/xDrift)^2) works well - GPUd() float getCorrYDy() const { return mCorrYDy; } + GPUd() double getDyLikelihood(float snp, float slope, int occupancy = 0) const; + GPUd() double getZLikelihood(float deltaZ, float padLength, float sigmaZtrk) const; + GPUd() float getCorrYDy(float snp) const { return CAMath::Sqrt(mCorrYDyA + mCorrYDyC * (snp - mLorentzAngle) * (snp - mLorentzAngle)); } GPUd() float getPileUpProbTracklet(int nBC, bool withChargeInfo, bool Q0 = true, bool Q1 = true) const; GPUd() float getPileUpProbTrack(int nBC, std::array Q0, std::array Q1) const; @@ -68,17 +70,23 @@ class GPUTRDRecoParam float mRPhiATgp{1.f}; ///< parameterization for tracklet position resolution float mRPhiC2{0.f}; ///< parameterization for tracklet position resolution // angle - float mDyA2{1.225e-3f}; ///< parameterization for tracklet angular resolution - float mDyC2{0.f}; ///< parameterization for tracklet angular resolution - // variation in y when dy variates by one sigma (= cov / sigma_dy = corr * sigma_y) (valid within 2sigma of dy) - float mCorrYDy{0.13f}; + float mDyA2{6e-3f}; ///< parameterization for tracklet angular resolution + float mDyC2{0.3f}; ///< parameterization for tracklet angular resolution + // variation in y when dy variates by one sigma (= cov / sigma_dy = corr * sigma_y) for tracklet (valid within ~[-0.6,0.6] of dy_trklt-dy_trk) + float mCorrYDyA{9e-4f}; + float mCorrYDyC{1.5e-2f}; // error parametrization vs angular pull (pol2) - float mPullA{6.8e-3f}; - float mPullB{0.049f}; + float mPullA{2.8e-3f}; + float mPullB{0.040f}; // error parametrization of y position vs occupancy defined as ntracklets within chamber (prop to sqrt(occupancy)) float mOccA{3.3e-4f}; // error parametrization for dy vs occupancy defined as ntracklets within chamber (prop to sqrt(occupancy)) float mOccDyA{2.5e-4f}; + // slope likelihood parametrization with Gaussian core and left and right exponential tails + float mDyExpA{1.78f}; + float mDyExpC{-1.65f}; + float mDyExpNormA{1.96e-3f}; + float mDyExpNormC{0.21f}; float mZCorrCoefNRC{1.4f}; ///< tracklet z-position depends linearly on track dip angle @@ -128,6 +136,34 @@ GPUdi() float GPUTRDRecoParam::getRPhiRes(float snp, float pull, int occupancy) return (resIdeal * resIdeal + mRPhiC2 * (snp - mLorentzAngle) * (snp - mLorentzAngle) + resPull * resPull + resOccupancy); } +GPUdi() double GPUTRDRecoParam::getDyLikelihood(float snp, float slope, int occupancy) const +{ + // Gaussian + left exponential + right exponential + double likelihood = CAMath::Exp(-0.5f * (slope - GPUTRDRecoParam::convertAngleToDy(snp)) * (slope - GPUTRDRecoParam::convertAngleToDy(snp)) / GPUTRDRecoParam::getDyRes(snp, occupancy)); + + // Normalization for the exponential is parametrized with respect to the Gaussian, it is smaller at lorentz angle + double expNorm = CAMath::Sqrt(mDyExpNormA + mDyExpNormC * (snp - mLorentzAngle) * (snp - mLorentzAngle)); + if (slope < convertAngleToDy(snp)) { + // left tail in this case, larger tail for large positive snp + likelihood += expNorm * CAMath::Exp((mDyExpA + mDyExpC * (snp - mLorentzAngle)) * (slope - GPUTRDRecoParam::convertAngleToDy(snp))); + } else { + // right tail, larger tail for large negative snp + likelihood += expNorm * CAMath::Exp(-(mDyExpA - mDyExpC * (snp - mLorentzAngle)) * (slope - GPUTRDRecoParam::convertAngleToDy(snp))); + } + + // Normalized such that likelihood is 1 when track angle and tracklet slope agree, and always lower than 1 otherwise (such that -log(likelihood) is always positive) + likelihood /= (1.f + expNorm); + return likelihood; +} + +GPUdi() double GPUTRDRecoParam::getZLikelihood(float deltaZ, float padLength, float sigmaZtrk) const +{ + // logistic function as approximation of convolution between uniform tracklet Z and gaussian track, depends on sqrt(3)/pi times the track resolution + // normalized so that maximum is 1 + double lmax = 1.f / (1.f + CAMath::Exp(-0.5f * padLength / 0.5513f / sigmaZtrk)) - 1.f / (1.f + CAMath::Exp(0.5f * padLength / 0.5513f / sigmaZtrk)); + return 1.f / lmax / (1.f + CAMath::Exp((deltaZ - 0.5f * padLength) / 0.5513f / sigmaZtrk)) - 1.f / lmax / (1.f + CAMath::Exp((deltaZ + 0.5f * padLength) / 0.5513f / sigmaZtrk)); +} + GPUdi() float GPUTRDRecoParam::getPileUpProbTracklet(int nBC, bool withChargeInfo, bool Q0, bool Q1) const { // get the probability that the tracklet with charges Q0 and Q1 belongs to a given BC, with a (signed) distance nBC from the TRD-triggered BC diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 842576621c39c..c7ad06199c07d 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -189,13 +189,13 @@ AddOptionRTC(trkltResRPhiIdeal, float, 1.f, "", 0, "Optimal tracklet rphi resolu AddOptionRTC(trkltResVsTanPhiMisalign, float, 0.f, "", 0, "tan(phi) dependence of tracklet error due to radial misalignment (centered at 0 angle)") AddOptionRTC(maxChi2Red, float, 99.f, "", 0, "maximum chi2 per attached tracklet for TRD tracks TODO: currently effectively disabled, requires tuning") AddOptionRTC(applyDeflectionCut, uint8_t, 0, "", 0, "Set to 1 to enable tracklet selection based on deflection") -AddOptionRTC(addDeflectionInChi2, uint8_t, 0, "", 0, "Set to 1 to add the deflection in the chi2 calculation for matching") +AddOptionRTC(addDeflectionInChi2, uint8_t, 0, "", 0, "1 = add the slope in the chi2 calculation for matching, 2 = in addition, take into account the full likelihood of the slope including exponential tails") AddOptionRTC(stopTrkAfterNMissLy, uint8_t, 6, "", 0, "Abandon track following after N layers without a TRD match") AddOptionRTC(nTrackletsMin, uint8_t, 3, "", 0, "Tracks with less attached tracklets are discarded after the tracking") AddOptionRTC(matCorrType, uint8_t, 2, "", 0, "Material correction to use: 0 - none, 1 - TGeo, 2 - matLUT") AddOptionRTC(pileupFwdNBC, uint8_t, 70, "", 0, "Post-trigger Pile-up integration time in BCs") AddOptionRTC(pileupBwdNBC, uint8_t, 130, "", 0, "Pre-trigger Pile-up integration time in BCs") -AddOptionRTC(useAngularPull, uint8_t, 1, "", 0, "0 = don't use angular pull; 1 = additional error based on angular pull for refit only; 2 = add error also for chi2") +AddOptionRTC(useAngularPull, uint8_t, 3, "", 0, "0 = don't use angular pull; 1 = additional error based on angular pull for refit only; 2 = add error also for chi2; 3 and 4 = correction of the average position based on angular pull") AddHelp("help", 'h') EndConfig() diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h b/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h index a99cc5f4a7a2d..d38f601d9cf6d 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDGeometry.h @@ -42,6 +42,7 @@ class GPUTRDpadPlane : private o2::trd::PadPlane GPUd() float GetNrows() const { return getNrows(); } GPUd() float GetNcols() const { return getNcols(); } GPUd() int32_t GetPadRowNumber(double z) const { return getPadRowNumber(z); } + GPUd() int32_t GetPadColNumber(double y) const { return getPadColNumber(y); } }; class GPUTRDGeometry : private o2::trd::GeometryFlat diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h b/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h index 2b847e20de6fb..0d71b35e92c78 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h @@ -152,6 +152,8 @@ class trackInterface : public GPUTPCGMTrackParam GPUd() float getSigmaY2() const { return GetErr2Y(); } GPUd() float getSigmaZ2() const { return GetErr2Z(); } GPUd() float getSigmaZY() const { return GetCov(1); } + GPUd() float getSigmaSnpY() const { return GetCov(3); } + GPUd() float getSigmaSnpZ() const { return GetCov(4); } GPUd() const float* getPar() const { return GetPar(); } GPUd() const float* getCov() const { return GetCov(); } diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx index f5f8f08b1138e..94332b388852f 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx @@ -592,6 +592,7 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK GPUWarning("Track parameter for track %i, x=%f at chamber %i x=%f in layer %i cannot be retrieved", iTrk, trkWork->getX(), currDet, mR[currDet], iLayer); } } + // first propagate track to x of tracklet for (int32_t trkltIdx = glbTrkltIdxOffset + mTrackletIndexArray[trkltIdxOffset + currDet]; trkltIdx < glbTrkltIdxOffset + mTrackletIndexArray[trkltIdxOffset + currDet + 1]; ++trkltIdx) { if (CAMath::Abs(trkWork->getY() - spacePoints[trkltIdx].getY()) > roadY || CAMath::Abs(trkWork->getZ() + zShiftTrk - spacePoints[trkltIdx].getZ()) > roadZ) { @@ -615,6 +616,8 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK // The correction is extracted from the most probable trigger. There is also an additional error depending on all the compatible triggers float yCorrPileUp = 0.f; float yAddErrPileUp2 = 0.f; + // additional zshiftTrk for TPC only tracks due to pile-up + float zShiftTrkPileUp = 0.f; if (nIdxBCMax - nIdxBCMin >= 2) { float maxProb = 0.f; // The uncertainty is the RMS wrt the default correction of all possible corrections weighted by their probability @@ -632,12 +635,14 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK if (probBC > maxProb) { maxProb = probBC; yCorrPileUp = -slopeFactor * deltaBC; + zShiftTrkPileUp = -deltaBC * o2::constants::lhc::LHCBunchSpacingMUS * mTPCVdrift * mTrackAttribs[iTrk].mSide; } } if (sumProb > 1e-6f) { yAddErrPileUp2 = sumCorr2 / sumProb - 2 * yCorrPileUp * sumCorr / sumProb + yCorrPileUp * yCorrPileUp; } } + // number of tracklets within the chamber is the current TRD occupancy estimator int nTrackletsChamber = mTrackletIndexArray[trkltIdxOffset + currDet + 1] - mTrackletIndexArray[trkltIdxOffset + currDet]; float angularPull = GetAngularPull(spacePoints[trkltIdx].getDy() + dyTiltCorr, trkWork->getSnp(), nTrackletsChamber); @@ -645,7 +650,14 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK // correction for mean z position of tracklet (is not the center of the pad if track eta != 0) float zPosCorr = spacePoints[trkltIdx].getZ() + mRecoParam->getZCorrCoeffNRC() * trkWork->getTgl(); float yPosCorr = spacePoints[trkltIdx].getY() - tiltCorr + yCorrPileUp; - zPosCorr -= zShiftTrk; // shift tracklet instead of track in order to avoid having to do a re-fit for each collision + zPosCorr -= zShiftTrk + zShiftTrkPileUp; // shift tracklet instead of track in order to avoid having to do a re-fit for each collision + + // Correction of y position based on angular pull + if (Param().rec.trd.useAngularPull == 3 || Param().rec.trd.useAngularPull == 4) { + float corrPull = -angularPull * mRecoParam->getCorrYDy(trkWork->getSnp()); + yPosCorr += corrPull; + } + float deltaY = yPosCorr - projY; float deltaZ = zPosCorr - projZ; @@ -653,20 +665,49 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK float trkltCovTmp[3] = {0.f}; if ((CAMath::Abs(deltaY) < roadY) && (CAMath::Abs(deltaZ) < roadZ)) { // TODO: check if this is still necessary after the cut before propagation of track // tracklet is in window: get predicted chi2 for update and store tracklet index if best guess - RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(tracklets[trkltIdx].GetZbin()), (Param().rec.trd.useAngularPull == 2 ? angularPull : 0.f), nTrackletsChamber, trkltCovTmp); + RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(tracklets[trkltIdx].GetZbin()), (Param().rec.trd.useAngularPull == 2 || Param().rec.trd.useAngularPull == 4 ? angularPull : 0.f), nTrackletsChamber, trkltCovTmp); trkltCovTmp[0] += yAddErrPileUp2; float chi2 = prop->getPredictedChi2(trkltPosTmpYZ, trkltCovTmp); - if (Param().rec.trd.addDeflectionInChi2 && (trkWork->getSnp() < 1.f - 1e-6f) && (trkWork->getSnp() > -1.f + 1e-6f)) { + + if (Param().rec.trd.addDeflectionInChi2 >= 1 && (trkWork->getSnp() < 1.f - 1e-6f) && (trkWork->getSnp() > -1.f + 1e-6f)) { // we add the slope in the chi2 calculation float trkltCovTmpWithDy[6] = {trkltCovTmp[0], trkltCovTmp[1], trkltCovTmp[2], 0.f, 0.f, 0.f}; - RecalcTrkltCovDy(tilt, trkWork->getSnp(), (Param().rec.trd.useAngularPull == 2 ? angularPull : 0.f), nTrackletsChamber, trkltCovTmpWithDy); + RecalcTrkltCovDy(tilt, trkWork->getSnp(), (Param().rec.trd.useAngularPull == 2 || Param().rec.trd.useAngularPull == 4 ? angularPull : 0.f), nTrackletsChamber, trkltCovTmpWithDy); trkltCovTmpWithDy[0] += trkWork->getSigmaY2(); trkltCovTmpWithDy[1] += trkWork->getSigmaZY(); trkltCovTmpWithDy[2] += trkWork->getSigmaZ2(); + if (Param().rec.trd.useAngularPull == 3 || Param().rec.trd.useAngularPull == 4) { + // In this case the correlation between tracklet y and tracklet dy is already corrected for so we can cancel it + trkltCovTmpWithDy[3] = 0.; + trkltCovTmpWithDy[4] = 0.; + } + + // We add the correlation between track y and track dy + trkltCovTmpWithDy[3] += trkWork->getSigmaSnpY() * mGeo->GetCdrHght(); + trkltCovTmpWithDy[4] += trkWork->getSigmaSnpZ() * mGeo->GetCdrHght(); + + // keep these parameters before matrix inversion + float sigmaZ2 = trkltCovTmpWithDy[2]; + float sigmaDy2 = trkltCovTmpWithDy[5]; + // For now, dy uncertainty parametrization also includes track uncertainty, so no need to add additional uncertainty if (InvertCov(trkltCovTmpWithDy)) { float deltaDy = spacePoints[trkltIdx].getDy() + dyTiltCorr - mRecoParam->convertAngleToDy(trkWork->getSnp()); + if (Param().rec.trd.addDeflectionInChi2 == 2 || Param().rec.trd.addDeflectionInChi2 == 3) { + // In this case we take into account the full likelihood, so we replace (deltaDy/sigmaDy)^2 by -2*ln(likelihood), which is the same in the default Gaussian case + double likelihood = mRecoParam->getDyLikelihood(trkWork->getSnp(), spacePoints[trkltIdx].getDy() + dyTiltCorr, nTrackletsChamber); + if (likelihood < 1e-6f) + continue; // likelihood of 1e-6 is equivalent to 5 sigma deviation, so we can safely cut it to avoid numerical instability in log calculation + deltaDy = CAMath::Sqrt(-2.f * CAMath::Log(likelihood) * sigmaDy2) * (deltaDy > 0.f ? 1.f : -1.f); + } + if (Param().rec.trd.addDeflectionInChi2 == 3) { + // We do the same for deltaZ + double likelihood = mRecoParam->getZLikelihood(deltaZ, pad->GetRowSize(tracklets[trkltIdx].GetZbin()), CAMath::Sqrt(trkWork->getSigmaZ2())); + if (likelihood < 1e-6f) + continue; + deltaZ = CAMath::Sqrt(-2.f * CAMath::Log(likelihood) * sigmaZ2) * (deltaZ > 0.f ? 1.f : -1.f); + } chi2 = deltaY * trkltCovTmpWithDy[0] * deltaY + 2 * deltaY * trkltCovTmpWithDy[1] * deltaZ + 2 * deltaY * trkltCovTmpWithDy[3] * deltaDy + deltaZ * trkltCovTmpWithDy[2] * deltaZ + 2 * deltaZ * trkltCovTmpWithDy[4] * deltaDy + deltaDy * trkltCovTmpWithDy[5] * deltaDy; } } @@ -750,6 +791,9 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK pad = mGeo->GetPadPlane(tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector()); float tiltCorrUp = tilt * (spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getZ() - trkWork->getZ()); float dyTiltCorr = tilt * trkWork->getTgl() * mGeo->GetCdrHght(); + + float yPosCorrUp = spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getY() - tiltCorrUp; + float zPosCorrUp = spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getZ() + mRecoParam->getZCorrCoeffNRC() * trkWork->getTgl(); zPosCorrUp -= zShiftTrk; float padLength = pad->GetRowSize(tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetZbin()); @@ -763,6 +807,7 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK // The correction is extracted from the most probable trigger. There is also an additional error depending on all the compatible triggers float yCorrPileUp = 0.f; float yAddErrPileUp2 = 0.f; + float zShiftTrkPileUp = 0.f; if (nIdxBCMax - nIdxBCMin >= 2) { float maxProb = 0.f; // The uncertainty is the RMS wrt the default correction of all possible corrections weighted by their probability @@ -780,6 +825,7 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK if (probBC > maxProb) { maxProb = probBC; yCorrPileUp = -slopeFactor * deltaBC; + zShiftTrkPileUp = -deltaBC * o2::constants::lhc::LHCBunchSpacingMUS * mTPCVdrift * mTrackAttribs[iTrk].mSide; } } if (sumProb > 1e-6f) { @@ -787,12 +833,21 @@ GPUd() bool GPUTRDTracker_t::FollowProlongation(PROP* prop, TRDTRK } } + zPosCorrUp -= zShiftTrkPileUp; + yPosCorrUp += yCorrPileUp; + const auto currDet = tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetDetector(); int nTrackletsChamber = mTrackletIndexArray[trkltIdxOffset + currDet + 1] - mTrackletIndexArray[trkltIdxOffset + currDet]; + float angularPull = GetAngularPull(spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getDy() + dyTiltCorr, trkWork->getSnp(), nTrackletsChamber); - float trkltPosUp[2] = {spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getY() - tiltCorrUp + yCorrPileUp, zPosCorrUp}; + // Correction of y position based on angular pull + if (Param().rec.trd.useAngularPull == 3 || Param().rec.trd.useAngularPull == 4) { + float corrPull = -angularPull * mRecoParam->getCorrYDy(trkWork->getSnp()); + yPosCorrUp += corrPull; + } + + float trkltPosUp[2] = {yPosCorrUp, zPosCorrUp}; float trkltCovUp[3] = {0.f}; - float angularPull = GetAngularPull(spacePoints[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].getDy() + dyTiltCorr, trkWork->getSnp(), nTrackletsChamber); RecalcTrkltCov(tilt, trkWork->getSnp(), pad->GetRowSize(tracklets[mHypothesis[iUpdate + hypothesisIdxOffset].mTrackletId].GetZbin()), ((Param().rec.trd.useAngularPull != 0) ? angularPull : 0.f), nTrackletsChamber, trkltCovUp); trkltCovUp[0] += yAddErrPileUp2; @@ -1058,8 +1113,8 @@ GPUd() void GPUTRDTracker_t::RecalcTrkltCovDy(const float tilt, co float c2 = 1.f / (1.f + t2); // cos^2 (tilt) // float sy2 = mRecoParam->getRPhiRes(snp, CAMath::Abs(pull), occupancy); float sdy2 = mRecoParam->getDyRes(snp, occupancy); - cov[3] = mRecoParam->getCorrYDy() * CAMath::Sqrt(sdy2 * c2); - cov[4] = -tilt * mRecoParam->getCorrYDy() * CAMath::Sqrt(sdy2 * c2); + cov[3] = mRecoParam->getCorrYDy(snp) * CAMath::Sqrt(sdy2 * c2); + cov[4] = -tilt * mRecoParam->getCorrYDy(snp) * CAMath::Sqrt(sdy2 * c2); cov[5] = sdy2; } @@ -1232,6 +1287,11 @@ GPUd() bool GPUTRDTracker_t::IsGeoFindable(const TRDTRK* t, const return false; } + // reject tracks in bad chambers + if (mChamberStatus[det]) { + return false; + } + const GPUTRDpadPlane* pp = mGeo->GetPadPlane(det); float yMax = pp->GetColEnd(); float zMax = pp->GetRow0(); @@ -1249,6 +1309,14 @@ GPUd() bool GPUTRDTracker_t::IsGeoFindable(const TRDTRK* t, const return false; } + // reject tracks if the corresponding pad and neighboring pads (to take into account track uncertainty and charge sharing with neighbours) are masked + /*int32_t padrow = pp->GetPadRowNumber(zTrk); + int32_t padcol = pp->GetPadColNumber(t->getY()); + int32_t idxPad = det * kNPadColumns * kNPadRows + padcol * kNPadRows + padrow; + if (padrow != -1 && padcol != -1 && mPadStatus[idxPad] && (padrow == 0 || mPadStatus[idxPad - kNPadRows]) && (padrow == kNPadRows - 1 || mPadStatus[idxPad + kNPadRows])) { + return false; + }*/ + return true; } diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h index 0f94732f7d536..91a102396220f 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h @@ -69,7 +69,10 @@ class GPUTRDTracker_t : public GPUProcessor enum EGPUTRDTracker { kNLayers = 6, kNStacks = 5, kNSectors = 18, - kNChambers = 540 }; + kNChambers = 540, + kNPadRows = 16, + kNPadColumns = 144, + kNPads = 1244160 }; struct HelperTrackAttributes { // additional TRD track attributes which are transient @@ -138,6 +141,8 @@ class GPUTRDTracker_t : public GPUProcessor mFT0TriggeredBC = t; mNFT0BC = n; } + GPUd() void SetChamberStatus(int iDet, bool status) { mChamberStatus[iDet] = status; } + // GPUd() void SetPadStatus(int iPad, bool status) { mPadStatus[iPad] = status; } GPUd() bool GetIsDebugOutputOn() const { return mDebugOutput; } GPUd() float GetMaxEta() const { return mMaxEta; } @@ -190,6 +195,8 @@ class GPUTRDTracker_t : public GPUProcessor float mTPCVdrift; // TPC drift velocity used for shifting TPC tracks along Z float mTPCTDriftOffset; // TPC drift time additive offset GPUTRDTrackerDebug* mDebug; // debug output + bool mChamberStatus[kNChambers] = {}; // good (0) or bad (1) chamber from the CCDB, used for determining whether a track is findable + // bool mPadStatus[kNPads] = {}; // whether pad is masked or not in hardware, from the CCDB, used for determining if a track is findable }; } // namespace o2::gpu