From b066212af19323cafdbd065c79dbfb2067b2142b Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 10 Oct 2025 11:39:39 +0200 Subject: [PATCH 01/13] something with ITS3 Signed-off-by: Felix Schlepper --- .../include/ITSSimulation/Detector.h | 2 +- .../include/ITS3Align/Deformations.h | 63 +--- .../include/ITS3Align/MisalignmentHits.h | 37 -- .../ITS3Align/MisalignmentParameters.h | 50 +-- .../ITS3/alignment/src/Deformations.cxx | 6 +- .../ITS3/alignment/src/MisalignmentHits.cxx | 92 +---- .../alignment/src/MisalignmentManager.cxx | 9 +- .../alignment/src/MisalignmentParameters.cxx | 37 +- .../ITS3/base/include/ITS3Base/ITS3Params.h | 1 - .../Upgrades/ITS3/macros/align/CMakeLists.txt | 1 + .../ITS3/macros/align/CheckResidualsITS3.C | 28 +- .../macros/align/CreateMisalignmentITS3.C | 72 ++-- .../ITS3/macros/align/ITS3Misaligner.C | 94 +++++ .../ITS3/macros/align/ShowCoefficients.C | 336 +++++++----------- .../ITS3/macros/align/TestLegendrePol.C | 98 +---- .../DescriptorInnerBarrelITS3.h | 5 + .../src/DescriptorInnerBarrelITS3.cxx | 54 +++ 17 files changed, 414 insertions(+), 571 deletions(-) create mode 100644 Detectors/Upgrades/ITS3/macros/align/ITS3Misaligner.C diff --git a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h index 57301ac4babd0..5d6a7a983147f 100644 --- a/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h +++ b/Detectors/ITSMFT/ITS/simulation/include/ITSSimulation/Detector.h @@ -216,7 +216,7 @@ class Detector : public o2::base::DetImpl /// Return Chip Volume UID /// \param id volume id - Int_t chipVolUID(Int_t id) const { return o2::base::GeometryManager::getSensID(o2::detectors::DetID::ITS, id); } + Int_t chipVolUID(Int_t id) const { return o2::base::GeometryManager::getSensID(o2::detectors::DetID(GetName()), id); } void EndOfEvent() override; diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/Deformations.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/Deformations.h index dfaade51e82ff..04853d54b9bef 100644 --- a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/Deformations.h +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/Deformations.h @@ -14,6 +14,7 @@ #include "ITS3Align/MisalignmentParameters.h" #include "MathUtils/LegendrePols.h" +#include "GPUCommonMath.h" #include @@ -26,57 +27,31 @@ class Deformations // init deformations from the parameter file void init(const std::filesystem::path&); - double getDeformationX(unsigned int id, double u, double v) const { return getDeformation<0>(id, u, v); } - double getDeformationY(unsigned int id, double u, double v) const { return getDeformation<1>(id, u, v); } - double getDeformationZ(unsigned int id, double u, double v) const { return getDeformation<2>(id, u, v); } - double getDeformation(unsigned int id, unsigned int axis, double u, double v) const + std::tuple getDeformation(unsigned int id, double radius, double phi, double z, double u, double v, double fac = 1.0) const { - if (axis == 0) { - return mLegX[id](u, v); - } else if (axis == 1) { - return mLegY[id](u, v); - } else { - return mLegZ[id](u, v); - } + // Calculate f_def(phi,z) = ((r+dr)*cos(phi), (r+dr)*sin(phi), z)^T + (dx, dy, dz)^T + const double dr = mLegendre[id](u, v); + const double drr = radius + dr * fac; + double sn, cs; + o2::gpu::GPUCommonMath::SinCosd(phi, sn, cs); + const auto& global = mParams.getGlobal(id); + return {drr * cs + global.getX() * fac, drr * sn + global.getY() * fac, z + global.getZ() * fac}; } - std::array getDeformation(unsigned int id, double u, double v) const - { - return {getDeformation<0>(id, u, v), - getDeformation<1>(id, u, v), - getDeformation<2>(id, u, v)}; - } - std::array getOrders(unsigned int id) const - { - return {mLegX[id].NOrder(), mLegY[id].NOrder(), mLegZ[id].NOrder()}; - } - const o2::math_utils::Legendre2DPolynominal& getLegendre(unsigned int id, unsigned int axis) const + + double getDeformation(unsigned int id, double u, double v) { - if (axis == 0) { - return mLegX[id]; - } else if (axis == 1) { - return mLegY[id]; - } else { - return mLegZ[id]; - } + return mLegendre[id](u, v); } + const o2::math_utils::Legendre2DPolynominal& getLegendre(unsigned int id) { return mLegendre[id]; } + + unsigned int getOrder(unsigned int id) { return mLegendre[id].NOrder(); } + private: - template - double getDeformation(unsigned int id, double u, double v) const - { - if constexpr (axis == 0) { - return mLegX[id](u, v); - } else if constexpr (axis == 1) { - return mLegY[id](u, v); - } else { - return mLegZ[id](u, v); - } - } + MisalignmentParameters mParams; - // 3 Legendre polynominals to model deformations in x,y,z; parameterized by normalized phi (u) and z (v) coordinates - std::array mLegX; - std::array mLegY; - std::array mLegZ; + // Legendre polynominals to model deformations in radius; parameterized by normalized phi (u) and z (v) coordinates + std::array mLegendre; }; } // namespace o2::its3::align diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentHits.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentHits.h index 37f5c9fdf701d..bc81d7a3d7130 100644 --- a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentHits.h +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentHits.h @@ -35,11 +35,6 @@ namespace o2::its3::align class MisAlignmentHits { public: - enum class PropMethod { - Propagator, - Line, - }; - void init(); std::optional processHit(int iEvent, const o2::itsmft::Hit& hit); @@ -50,7 +45,6 @@ class MisAlignmentHits private: Deformations mDeformations; std::unique_ptr mMinimizer; - PropMethod mMethod{PropMethod::Line}; o2::its::GeometryTGeo* mGeo{nullptr}; std::unique_ptr mMCReader; @@ -120,11 +114,6 @@ class MisAlignmentHits bool deformHit(WorkingHit::HitType t); - auto getDeformation(unsigned int id, double u, double v) const - { - return mDeformations.getDeformation(id, u, v); - } - // Mimize function assuming a straight line // given in the parametric representation by y_v = t * d_x + x_s // assuming no offset is needed @@ -151,30 +140,6 @@ class MisAlignmentHits StraightLine mLine{this}; void prepareLineMethod(WorkingHit::HitType from); - // Mimize function using the MCTrack - class Propagator : public ROOT::Math::IBaseFunctionMultiDim - { - public: - Propagator(const MisAlignmentHits* m) : mMis(m) {} - - o2::track::TrackPar mTrack; - float mBz; - unsigned int mSensorID; - double mRadius; - const MisAlignmentHits* mMis; - - double mPhiTot; - double mPhi1; - - unsigned int NDim() const override { return 3; } - ROOT::Math::IBaseFunctionMultiDim* Clone() const override { return nullptr; } - - private: - double DoEval(const double* x) const override; - }; - Propagator mPropagator{this}; - bool preparePropagatorMethod(WorkingHit::HitType from); - enum Stats : uint8_t { kHitTotal = 0, kHitIsOB, @@ -204,8 +169,6 @@ class MisAlignmentHits kMinimizerEDM, kMinimizerLimit, kMinimizerOther, - kPropTrackNull, - kPropPDGNull, kALL, }; std::array mStats; diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentParameters.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentParameters.h index 243623cc650e1..73aeff6a32071 100644 --- a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentParameters.h +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/MisalignmentParameters.h @@ -16,6 +16,7 @@ #define ITS3_MISALIGNMENTPARAMETERS_H_ #include "ITS3Base/SpecsV2.h" +#include "DetectorsCommonDataFormats/AlignParam.h" #include "TNamed.h" #include "TFile.h" @@ -31,37 +32,23 @@ class MisalignmentParameters : public TNamed { public: MisalignmentParameters(); + MisalignmentParameters(const MisalignmentParameters&) = default; + MisalignmentParameters(MisalignmentParameters&&) = delete; + MisalignmentParameters& operator=(MisalignmentParameters&&) = delete; + MisalignmentParameters& operator=(const MisalignmentParameters& o); // IO bool store(const std::string& file) const; static MisalignmentParameters* load(const std::string& file); /// Global getters - double getGloTransX(unsigned int detID) const { return mGloTransX[detID]; } - double getGloTransY(unsigned int detID) const { return mGloTransY[detID]; } - double getGloTransZ(unsigned int detID) const { return mGloTransZ[detID]; } - double getGloRotX(unsigned int detID) const { return mGloRotX[detID]; } - double getGloRotY(unsigned int detID) const { return mGloRotY[detID]; } - double getGloRotZ(unsigned int detID) const { return mGloRotZ[detID]; } - /// Global setters - void setGloTransX(unsigned int detID, double v) { mGloTransX[detID] = v; } - void setGloTransY(unsigned int detID, double v) { mGloTransY[detID] = v; } - void setGloTransZ(unsigned int detID, double v) { mGloTransZ[detID] = v; } - void setGloRotX(unsigned int detID, double v) { mGloRotX[detID] = v; } - void setGloRotY(unsigned int detID, double v) { mGloRotY[detID] = v; } - void setGloRotZ(unsigned int detID, double v) { mGloRotZ[detID] = v; } - - /// Legendre Coeff. getters - const TMatrixD& getLegendreCoeffX(unsigned int sensorID) const { return mLegCoeffX[sensorID]; } - const TMatrixD& getLegendreCoeffY(unsigned int sensorID) const { return mLegCoeffY[sensorID]; } - const TMatrixD& getLegendreCoeffZ(unsigned int sensorID) const { return mLegCoeffZ[sensorID]; } - /// Legendre Coeff. setters - void setLegendreCoeffX(unsigned int sensorID, const TMatrixD& m) { setMatrix(mLegCoeffX[sensorID], m); } - void setLegendreCoeffY(unsigned int sensorID, const TMatrixD& m) { setMatrix(mLegCoeffY[sensorID], m); } - void setLegendreCoeffZ(unsigned int sensorID, const TMatrixD& m) { setMatrix(mLegCoeffZ[sensorID], m); } + const o2::detectors::AlignParam& getGlobal(unsigned int detID) const { return mGlobal[detID]; } + void setGlobal(unsigned int detID, const o2::detectors::AlignParam& param) { mGlobal[detID] = param; } + + const TMatrixD& getLegendreCoeff(unsigned int sensorID) const { return mLegCoeff[sensorID]; } + void setLegendreCoeff(unsigned int sensorID, const TMatrixD& m) { setMatrix(mLegCoeff[sensorID], m); } void printParams(unsigned int detID) const; - void printLegendreParams(unsigned int sensorID) const; private: inline void setMatrix(TMatrixD& o, const TMatrixD& n) @@ -71,21 +58,10 @@ class MisalignmentParameters : public TNamed } static constexpr unsigned int nDetectors{constants::detID::nChips}; ///! for now just the IB + std::array mGlobal; ///< Array to hold the global misalignment + std::array mLegCoeff; // Legendre Polynominals coefficients - // Global parameters - std::array mGloTransX; ///< Array to hold the global misalignment in x-direction - std::array mGloTransY; ///< Array to hold the global misalignment in y-direction - std::array mGloTransZ; ///< Array to hold the global misalignment in z-direction - std::array mGloRotX; ///< Array to hold the global misalignment in x-direction - std::array mGloRotY; ///< Array to hold the global misalignment in y-direction - std::array mGloRotZ; ///< Array to hold the global misalignment in z-direction - - // Legendre Polynominals coefficients - std::array mLegCoeffX; - std::array mLegCoeffY; - std::array mLegCoeffZ; - - ClassDefOverride(MisalignmentParameters, 1); + ClassDefOverride(MisalignmentParameters, 2); }; } // namespace o2::its3::align diff --git a/Detectors/Upgrades/ITS3/alignment/src/Deformations.cxx b/Detectors/Upgrades/ITS3/alignment/src/Deformations.cxx index 38a959cf7030f..cb021d01dfb83 100644 --- a/Detectors/Upgrades/ITS3/alignment/src/Deformations.cxx +++ b/Detectors/Upgrades/ITS3/alignment/src/Deformations.cxx @@ -27,14 +27,12 @@ void Deformations::init(const fs::path& path) LOGP(fatal, "File {} does not exists!", path.c_str()); } - auto params = MisalignmentParameters::load(path.string()); + mParams = *MisalignmentParameters::load(path.string()); LOGP(info, "Loaded Parameters"); // Set the legendre pols for (int iSensor{0}; iSensor < 6; ++iSensor) { - mLegX[iSensor] = o2::math_utils::Legendre2DPolynominal(params->getLegendreCoeffX(iSensor)); - mLegY[iSensor] = o2::math_utils::Legendre2DPolynominal(params->getLegendreCoeffY(iSensor)); - mLegZ[iSensor] = o2::math_utils::Legendre2DPolynominal(params->getLegendreCoeffZ(iSensor)); + mLegendre[iSensor] = o2::math_utils::Legendre2DPolynominal(mParams.getLegendreCoeff(iSensor)); } } diff --git a/Detectors/Upgrades/ITS3/alignment/src/MisalignmentHits.cxx b/Detectors/Upgrades/ITS3/alignment/src/MisalignmentHits.cxx index 66ab4c8090b54..80b6982833673 100644 --- a/Detectors/Upgrades/ITS3/alignment/src/MisalignmentHits.cxx +++ b/Detectors/Upgrades/ITS3/alignment/src/MisalignmentHits.cxx @@ -10,9 +10,9 @@ // or submit itself to any jurisdiction. #include "ITS3Align/MisalignmentHits.h" +#include "ITS3Base/SegmentationMosaix.h" #include "ITS3Base/ITS3Params.h" #include "SimConfig/DigiParams.h" -#include "DetectorsBase/Propagator.h" #include "Framework/Logger.h" #include "Math/Factory.h" @@ -31,12 +31,6 @@ namespace o2::its3::align void MisAlignmentHits::init() { - if (o2::its3::ITS3Params::Instance().misalignmentHitsUseProp) { - mMethod = PropMethod::Propagator; - } else { - mMethod = PropMethod::Line; - } - mGeo = o2::its::GeometryTGeo::Instance(); mMinimizer.reset(ROOT::Math::Factory::CreateMinimizer("Minuit2", "Migrad")); @@ -46,16 +40,7 @@ void MisAlignmentHits::init() mMinimizer->SetMaxFunctionCalls(1'000'000'000); mMinimizer->SetStrategy(0); mMinimizer->SetPrintLevel(0); - - if (mMethod == PropMethod::Propagator) { - LOGP(info, "Using propagator to find intersection"); - const auto& prefix = o2::conf::DigiParams::Instance().digitizationgeometry_prefix; - mMCReader = std::make_unique(prefix, o2::steer::MCKinematicsReader::Mode::kMCKine); - mMinimizer->SetFunction(mPropagator); - } else { - LOGP(info, "Using local straight-line to find intersection"); - mMinimizer->SetFunction(mLine); - } + mMinimizer->SetFunction(mLine); resetStats(); @@ -155,19 +140,12 @@ bool MisAlignmentHits::deformHit(WorkingHit::HitType t) { auto& wHit = mCurWorkingHits[t]; - mMinimizer->Clear(); // clear for next iteration - constexpr double minStep{1e-5}; + mMinimizer->Clear(); // clear for next iteration + constexpr double minStep{1e-5}; // below SetVariable(0, "t", 0.0, minStep); // this is left as a free parameter on since t is very small since start and end of hit are close - } else { - if (!preparePropagatorMethod(t)) { - return false; - } - mMinimizer->SetVariable(0, "r", mPropagator.mTrack.getX(), minStep); // this is left as a free parameter on since t is very small since start and end of hit are close - } + prepareLineMethod(t); + mMinimizer->SetVariable(0, "t", 0.0, minStep); // this is left as a free parameter on since t is very small since start and end of hit are close mMinimizer->SetLimitedVariable(1, "phiStar", wHit.mPhi, minStep, std::max(static_cast(wHit.mPhiBorder1), static_cast(wHit.mPhi) - phiMargin), std::min(static_cast(wHit.mPhiBorder2), static_cast(wHit.mPhi) + phiMargin)); @@ -274,10 +252,7 @@ void MisAlignmentHits::printStats() const LOGP(info, " - IsAlive: {} yes {} no ({:.2f}%)", mStats[Stats::kHitAlive], mStats[Stats::kHitDead], makeFraction(Stats::kHitAlive, Stats::kHitDead)); LOGP(info, " - HasMigrated: {} yes {} no ({:.2f}%)", mStats[Stats::kHitMigrated], mStats[Stats::kHitNotMigrated], makeFraction(Stats::kHitMigrated, Stats::kHitNotMigrated)); // LOGP(info, " - Crosses Boundary: {} entering {} exiting {} same {} no", mStats[Stats::kHitEntBoundary], mStats[Stats::kHitExtBoundary], mStats[Stats::kHitSameBoundary], mStats[Stats::kHitNoBoundary]); - if (mMethod == PropMethod::Propagator) { - LOGP(info, " - Propagator: {} null track {} null pdg", mStats[Stats::kPropTrackNull], mStats[Stats::kPropPDGNull]); - } - LOGP(info, " --> Good Hits {} ({:.2f}%)", mStats[Stats::kHitSuccess], makeFraction(Stats::kHitSuccess, Stats::kHitIsIB)); + LOGP(info, " --> Good IB Hits {} ({:.2f}%)", mStats[Stats::kHitSuccess], makeFraction(Stats::kHitSuccess, Stats::kHitIsIB)); } void MisAlignmentHits::prepareLineMethod(WorkingHit::HitType from) @@ -309,60 +284,11 @@ double MisAlignmentHits::StraightLine::DoEval(const double* x) const zline = mStart.Z() + t * mD[2]; // Find the point of the deformed geometry given a certain phi' and z' - double xideal = mRadius * std::cos(phi), yideal = mRadius * std::sin(phi), - zideal = z; - const auto [dx, dy, dz] = mMis->getDeformation(mSensorID, nphi, nz); - double xdef = xideal + dx, ydef = yideal + dy, zdef = zideal + dz; + const double xideal = mRadius * std::cos(phi), yideal = mRadius * std::sin(phi), zideal = z; + const auto [xdef, ydef, zdef] = mMis->mDeformations.getDeformation(mSensorID, mRadius, phi, z, nphi, nz); // Minimize the euclidean distance of the line point and the deformed point return std::hypot(xline - xdef, yline - ydef, zline - zdef); } -bool MisAlignmentHits::preparePropagatorMethod(WorkingHit::HitType from) -{ - mPropagator.mRadius = mCurWorkingHits[from].mRadius; - mPropagator.mSensorID = mCurWorkingHits[from].mSensorID; - mPropagator.mPhiTot = mCurWorkingHits[from].mPhiBorder2 - mCurWorkingHits[from].mPhiBorder1; - mPropagator.mPhi1 = mCurWorkingHits[from].mPhiBorder1; - const auto mcTrack = mMCReader->getTrack(mCurWorkingHits[from].mEvent, mCurWorkingHits[from].mTrackID); - if (mcTrack == nullptr) { - ++mStats[Stats::kPropTrackNull]; - return false; - } - const std::array xyz{(float)mcTrack->GetStartVertexCoordinatesX(), (float)mcTrack->GetStartVertexCoordinatesY(), (float)mcTrack->GetStartVertexCoordinatesZ()}, - pxyz{(float)mcTrack->GetStartVertexMomentumX(), (float)mcTrack->GetStartVertexMomentumY(), (float)mcTrack->GetStartVertexMomentumZ()}; - const TParticlePDG* pPDG = TDatabasePDG::Instance()->GetParticle(mcTrack->GetPdgCode()); - if (pPDG == nullptr) { - ++mStats[Stats::kPropPDGNull]; - return false; - } - mPropagator.mTrack = o2::track::TrackPar(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), false); - mPropagator.mBz = o2::base::Propagator::Instance()->getNominalBz(); - return true; -} - -double MisAlignmentHits::Propagator::DoEval(const double* x) const -{ - const double r = x[0]; - const double phi = x[1]; - const double z = x[2]; - const double nphi = (phi - mPhi1) * 2.0 / mPhiTot - 1.0; - const double nz = (z - (-constants::segment::lengthSensitive / 2.0)) * 2.0 / constants::segment::lengthSensitive - 1.0; - - auto trc = mTrack; - if (!trc.propagateTo(r, mBz)) { - return 999; - } - const auto glo = trc.getXYZGlo(); - - // Find the point of the deformed geometry given a certain phi' and z' - double xideal = mRadius * std::cos(phi), yideal = mRadius * std::sin(phi), - zideal = z; - const auto [dx, dy, dz] = mMis->getDeformation(mSensorID, nphi, nz); - double xdef = xideal + dx, ydef = yideal + dy, zdef = zideal + dz; - - // Minimize the euclidean distance of the propagator point and the deformed point - return std::hypot(glo.X() - xdef, glo.Y() - ydef, glo.Z() - zdef); -} - } // namespace o2::its3::align diff --git a/Detectors/Upgrades/ITS3/alignment/src/MisalignmentManager.cxx b/Detectors/Upgrades/ITS3/alignment/src/MisalignmentManager.cxx index c9d71541bcd0e..270417eda0ec0 100644 --- a/Detectors/Upgrades/ITS3/alignment/src/MisalignmentManager.cxx +++ b/Detectors/Upgrades/ITS3/alignment/src/MisalignmentManager.cxx @@ -85,13 +85,16 @@ void MisalignmentManager::misalignHits() LOGP(info, "Preparations done; starting hit loop"); auto nEntries = origTree->GetEntries(); ULong64_t totalOrigHits{0}, totalNewHits{0}; + Long64_t nextLogEntry = 1; for (Long64_t iEntry{0}; origTree->LoadTree(iEntry) >= 0; ++iEntry) { if (origTree->GetEntry(iEntry) <= 0) { continue; } - const auto progress = (iEntry * 100) / nEntries; - LOG_IF(info, progress % 10 == 0) << "Processing event " << iEntry << " / " << nEntries; + if (iEntry == nextLogEntry) { + nextLogEntry = std::min(nEntries - 1, iEntry + static_cast(std::pow(2, std::log2(iEntry + 2)))); + LOG(info) << "Processing event " << iEntry << " / " << nEntries; + } newHits.clear(); newHits.reserve(origHits.size()); @@ -118,7 +121,7 @@ void MisalignmentManager::misalignHits() LOGP(info, "Summary: Total orignal Hits {}", totalOrigHits); LOGP(info, "Summary: Total misaligned Hits {} ({:.2f}%)", totalNewHits, static_cast(totalNewHits) / static_cast(totalOrigHits) * 100); LOGP(info, "Summary: Total discarded Hits {} ({:.2f}%)", totalDiscardedHits, static_cast(totalDiscardedHits) / static_cast(totalOrigHits) * 100); - LOGP(info, "Summary: Misalignment took {:.2f}s", timer.CpuTime()); + LOGP(info, "Summary: Misalignment took {:.2f}s", timer.RealTime()); LOGP(info, "{:*^90}", " ITS3 LOCAL MISALIGNMENT END "); } diff --git a/Detectors/Upgrades/ITS3/alignment/src/MisalignmentParameters.cxx b/Detectors/Upgrades/ITS3/alignment/src/MisalignmentParameters.cxx index 0842b7252486a..f0a681dfa6da9 100644 --- a/Detectors/Upgrades/ITS3/alignment/src/MisalignmentParameters.cxx +++ b/Detectors/Upgrades/ITS3/alignment/src/MisalignmentParameters.cxx @@ -30,6 +30,20 @@ MisalignmentParameters::MisalignmentParameters() SetTitle("ITS3 MisalignmentParameters"); } +MisalignmentParameters& MisalignmentParameters::operator=(const MisalignmentParameters& o) +{ + if (this != &o) { + SetName(o.GetName()); + SetTitle(o.GetTitle()); + mGlobal = o.mGlobal; + for (unsigned int s{0}; s < constants::nSensorsIB; ++s) { + o.mLegCoeff[s].Print(); + setMatrix(mLegCoeff[s], o.mLegCoeff[s]); + } + } + return *this; +} + bool MisalignmentParameters::store(const std::string& file) const { std::unique_ptr fOut(TFile::Open(file.c_str(), "RECREATE")); @@ -43,6 +57,7 @@ bool MisalignmentParameters::store(const std::string& file) const MisalignmentParameters* MisalignmentParameters::load(const std::string& file) { + LOGP(info, "Loading Parameters from {}", file); std::unique_ptr fIn(TFile::Open(file.c_str(), "READ")); auto p = fIn->Get("ccdb_object"); if (p == nullptr) { @@ -54,27 +69,13 @@ MisalignmentParameters* MisalignmentParameters::load(const std::string& file) void MisalignmentParameters::printParams(unsigned int detID) const { LOGP(info, "Parameters for ID={}:", detID); - LOGP(info, " - Global Trans: X={} Y={} Z={}", getGloTransX(detID), getGloTransY(detID), getGloTransZ(detID)); - LOGP(info, " - Global Rots: X={} Y={} Z={}", getGloRotX(detID), getGloRotY(detID), getGloRotZ(detID)); + const auto& glo = mGlobal[detID]; + LOGP(info, " - Global Trans: X={} Y={} Z={}", glo.getX(), glo.getY(), glo.getZ()); + LOGP(info, " - Global Rots: Phi={} Psi={} Theta={}", glo.getPhi(), glo.getPsi(), glo.getTheta()); if (constants::detID::isDetITS3(detID)) { auto sensorID = constants::detID::getSensorID(detID); - LOGP(info, " - Legendre Pol X:"); - getLegendreCoeffX(sensorID).Print(); - LOGP(info, " - Legendre Pol Y:"); - getLegendreCoeffY(sensorID).Print(); - LOGP(info, " - Legendre Pol Z:"); - getLegendreCoeffZ(sensorID).Print(); + mLegCoeff[sensorID].Print(); } } -void MisalignmentParameters::printLegendreParams(unsigned int sensorID) const -{ - LOGP(info, " - Legendre Pol X:"); - getLegendreCoeffX(sensorID).Print(); - LOGP(info, " - Legendre Pol Y:"); - getLegendreCoeffY(sensorID).Print(); - LOGP(info, " - Legendre Pol Z:"); - getLegendreCoeffZ(sensorID).Print(); -} - } // namespace o2::its3::align diff --git a/Detectors/Upgrades/ITS3/base/include/ITS3Base/ITS3Params.h b/Detectors/Upgrades/ITS3/base/include/ITS3Base/ITS3Params.h index 0bd548cef953d..c0c317c2d364b 100644 --- a/Detectors/Upgrades/ITS3/base/include/ITS3Base/ITS3Params.h +++ b/Detectors/Upgrades/ITS3/base/include/ITS3Base/ITS3Params.h @@ -22,7 +22,6 @@ struct ITS3Params : public o2::conf::ConfigurableParamHelper { // Alignment studies bool applyMisalignmentHits{false}; // Apply detector misalignment on hit level std::string misalignmentHitsParams{}; // Path to parameter file for mis-alignment - bool misalignmentHitsUseProp{false}; // Use propagtor for mis-alignment std::string globalGeoMisAlignerMacro{"${O2_ROOT}/share/macro/MisAlignGeoITS3.C"}; // Path to macro for global geometry mis-alignment // Chip studies bool useDeadChannelMap{false}; // Query for a dead channel map to study disabling individual tiles diff --git a/Detectors/Upgrades/ITS3/macros/align/CMakeLists.txt b/Detectors/Upgrades/ITS3/macros/align/CMakeLists.txt index 86ebd989133e0..59ea55d7294c7 100644 --- a/Detectors/Upgrades/ITS3/macros/align/CMakeLists.txt +++ b/Detectors/Upgrades/ITS3/macros/align/CMakeLists.txt @@ -15,3 +15,4 @@ its3_add_macro(TestLegendrePol.C) its3_add_macro(CreateMisalignmentITS3.C) its3_add_macro(ShowCoefficients.C) its3_add_macro(CheckResidualsITS3.C) +its3_add_macro(ITS3Misaligner.C) diff --git a/Detectors/Upgrades/ITS3/macros/align/CheckResidualsITS3.C b/Detectors/Upgrades/ITS3/macros/align/CheckResidualsITS3.C index 88b342683ca44..5d6066eb40c05 100644 --- a/Detectors/Upgrades/ITS3/macros/align/CheckResidualsITS3.C +++ b/Detectors/Upgrades/ITS3/macros/align/CheckResidualsITS3.C @@ -36,8 +36,12 @@ #include #include +#include +#include #endif +namespace fs = std::filesystem; + // Refit ITS3 tracks by using the clusters from the OB only then propagate the // tracks to the IB clusters and calculate their residuals. @@ -66,11 +70,16 @@ std::optional propagateTo(Track& trk, const o2::itsmft::CompClusterExt& ++cTotal; auto chipID = clus.getSensorID(); float sigmaY2{0}, sigmaZ2{0}, sigmaYZ{0}; - auto isITS3 = o2::its3::constants::detID::isDetITS3(chipID); const float alpha = o2::its::GeometryTGeo::Instance()->getSensorRefAlpha(clus.getSensorID()); // alpha for the tracking frame const auto locC = o2::its3::ioutils::extractClusterData(clus, pattIt, mDict, sigmaY2, sigmaZ2); // get cluster in sensor local frame with errors - Point3D trkC = o2::its::GeometryTGeo::Instance()->getMatrixT2L(chipID) ^ (locC); // cluster position in the tracking frame - const auto gloC = o2::its::GeometryTGeo::Instance()->getMatrixL2G(chipID)(locC); // global cluster position + Point3D trkC; + auto isITS3 = o2::its3::constants::detID::isDetITS3(chipID); + if (isITS3) { + trkC = o2::its::GeometryTGeo::Instance()->getT2LMatrixITS3(chipID, alpha) ^ (locC); // cluster position in the tracking frame + } else { + trkC = o2::its::GeometryTGeo::Instance()->getMatrixT2L(chipID) ^ (locC); // cluster position in the tracking frame + } + const auto gloC = o2::its::GeometryTGeo::Instance()->getMatrixL2G(chipID)(locC); // global cluster position const auto bz = o2::base::Propagator::Instance()->getNominalBz(); // rotate the parameters to the tracking frame then propagate to the clusters'x @@ -111,7 +120,7 @@ std::optional propagateTo(Track& trk, const o2::itsmft::CompClusterExt& void CheckResidualsITS3(bool plotOnly = false, bool useITS = false, - const std::string& dictFileName = "../ccdb/IT3/Calib/ClusterDictionary/snapshot.root", + std::string dictFileName = "IT3dictionary.root", const std::string& collisioncontextFileName = "collisioncontext.root", const std::string& itsTracksFileName = "o2trac_its.root", const std::string& itsClustersFileName = "o2clus_its.root", @@ -122,6 +131,17 @@ void CheckResidualsITS3(bool plotOnly = false, std::array hIBDx, hIBDy, hIBDz, hIBDr; if (!plotOnly) { + if (fs::exists(dictFileName)) { + LOGP(info, "Using local dictionary file"); + } else { + const std::string ccdb = std::getenv("ALICEO2_CCDB_LOCALCACHE"); + dictFileName = ccdb + "/IT3/Calib/ClusterDictionary/snapshot.root"; + if (fs::exists(dictFileName)) { + LOGP(info, "Loading from local ccdb cache"); + } else { + LOGP(fatal, "Provide dictionary!"); + } + } mDict = new o2::its3::TopologyDictionary(dictFileName); o2::base::GeometryManager::loadGeometry(geomFileName); diff --git a/Detectors/Upgrades/ITS3/macros/align/CreateMisalignmentITS3.C b/Detectors/Upgrades/ITS3/macros/align/CreateMisalignmentITS3.C index 8df00ee25de00..29586494fd14d 100644 --- a/Detectors/Upgrades/ITS3/macros/align/CreateMisalignmentITS3.C +++ b/Detectors/Upgrades/ITS3/macros/align/CreateMisalignmentITS3.C @@ -14,80 +14,70 @@ #include "TMatrixD.h" #include "ITS3Align/MisalignmentParameters.h" +#include "DetectorsCommonDataFormats/AlignParam.h" #endif void CreateMisalignmentITS3(bool dummy = false, bool manual = false) { gRandom->SetSeed(42); + const TMatrixD nullMatrix(1, 1); // Legendre coeff. constexpr int nOrder{2}; auto getRandom = []() { - constexpr double scale{50.e-4}; + constexpr double scale{40.e-4}; return scale * gRandom->Uniform(-1.0, 1.0); }; - auto getSign = []() { return gRandom->Uniform() ? -1.0 : 1.0; }; - o2::its3::align::MisalignmentParameters params; + // for (int sensorID{0}; sensorID < 6; ++sensorID) { + // o2::detectors::AlignParam p; + // if (sensorID < 3) { + // if (sensorID % 2 == 0) { + // p.setTranslation(0.f, 30e-4f, 0.f); + // } else { + // p.setTranslation(0.f, -30e-4f, 0.f); + // } + // } + // params.setGlobal(sensorID, p); + // } + if (dummy) { - TMatrixD coeffNull(0 + 1, 0 + 1); + const TMatrixD coeffNull(0 + 1, 0 + 1); for (int sensorID{0}; sensorID < 6; ++sensorID) { - params.setLegendreCoeffX(sensorID, coeffNull); - params.setLegendreCoeffY(sensorID, coeffNull); - params.setLegendreCoeffZ(sensorID, coeffNull); + params.setLegendreCoeff(sensorID, coeffNull); } } else if (manual) { - // (0,0) -> shift - // (1,0) -> for (int sensorID{0}; sensorID < 6; ++sensorID) { - constexpr double scale{20e-4}; - TMatrixD coeffNull(1, 1); - - TMatrixD coeffMinusX(1 + 1, 1 + 1); - TMatrixD coeffPlusX(1 + 1, 1 + 1); - coeffMinusX(1, 1) = -scale; - coeffPlusX(1, 1) = scale; - - TMatrixD coeffMinusY(4 + 1, 4 + 1); - TMatrixD coeffPlusY(4 + 1, 4 + 1); - coeffMinusY(0, 0) = scale; - coeffPlusY(0, 0) = -scale; - coeffMinusY(4, 4) = -scale; - coeffPlusY(4, 4) = scale; + constexpr double scale{50e-4}; + int nOrder{2}; + TMatrixD coeffMinus(nOrder + 1, nOrder + 1); + TMatrixD coeffPlus(nOrder + 1, nOrder + 1); + /* coeffMinus(0, 0) = -scale; */ + coeffMinus(2, 2) = -scale; + coeffPlus(2, 2) = -scale; if (sensorID % 2 == 0) { - params.setLegendreCoeffX(sensorID, coeffPlusX); - params.setLegendreCoeffY(sensorID, coeffPlusY); - params.setLegendreCoeffZ(sensorID, coeffNull); + params.setLegendreCoeff(sensorID, coeffPlus); } else { - params.setLegendreCoeffX(sensorID, coeffMinusX); - params.setLegendreCoeffY(sensorID, coeffMinusY); - params.setLegendreCoeffZ(sensorID, coeffNull); + params.setLegendreCoeff(sensorID, coeffMinus); } } } else { for (int sensorID{0}; sensorID < 6; ++sensorID) { - TMatrixD coeffX(nOrder + 1, nOrder + 1); - TMatrixD coeffY(nOrder + 1, nOrder + 1); - TMatrixD coeffZ(nOrder + 1, nOrder + 1); - for (int i{0}; i <= nOrder; ++i) { + TMatrixD coeff(nOrder + 1, nOrder + 1); + for (int i{1}; i <= nOrder; ++i) { for (int j{0}; j <= i; ++j) { // some random scaling as higher order parameters have higher influence - coeffX(i, j) = getRandom() / (1.0 + i * j * 2.0); - coeffZ(i, j) = getRandom() / (1.0 + i * j * 2.0); - coeffY(i, j) = getRandom() / (1.0 + i * j * 2.0); + coeff(i, j) = getRandom() / (i * i); } } - - params.setLegendreCoeffX(sensorID, coeffX); - params.setLegendreCoeffY(sensorID, coeffY); - params.setLegendreCoeffZ(sensorID, coeffZ); + params.setLegendreCoeff(sensorID, coeff); } } for (int sensorID{0}; sensorID < 6; ++sensorID) { - params.printLegendreParams(sensorID); + params.getLegendreCoeff(sensorID).Print(); } params.store("misparams.root"); diff --git a/Detectors/Upgrades/ITS3/macros/align/ITS3Misaligner.C b/Detectors/Upgrades/ITS3/macros/align/ITS3Misaligner.C new file mode 100644 index 0000000000000..f6a7c543b9a12 --- /dev/null +++ b/Detectors/Upgrades/ITS3/macros/align/ITS3Misaligner.C @@ -0,0 +1,94 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +// #define ENABLE_UPGRADES +#include "CCDB/CcdbApi.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/DetectorNameConf.h" +#include "ITSBase/GeometryTGeo.h" +#include +#include +#include +#include +#endif + +using AlgPar = std::array; + +AlgPar generateMisalignment(double x, double y, double z, double psi, + double theta, double phi); + +void ITS3Misaligner(const std::string& ccdbHost = "http://localhost:8080", + long tmin = 0, long tmax = -1, double xEnv = 0., + double yEnv = 0., double zEnv = 0., double psiEnv = 0., + double thetaEnv = 0., double phiEnv = 0., double xHBa = 0., + double yHBa = 0., double zHBa = 0., double psiHBa = 0., + double thetaHBa = 0., double phiHBa = 0., + const std::string& objectPath = "", + const std::string& fileName = "ITSAlignment.root") +{ + std::vector params; + o2::base::GeometryManager::loadGeometry("", false); + auto geom = o2::its::GeometryTGeo::Instance(); + std::string symname; + AlgPar pars; + bool glo = true; + symname = geom->composeSymNameITS(); + + o2::detectors::DetID detITS("IT3"); + + // ITS envelope + pars = generateMisalignment(xEnv, yEnv, zEnv, psiEnv, thetaEnv, phiEnv); + params.emplace_back(symname.c_str(), -1, pars[0], pars[1], pars[2], pars[3], + pars[4], pars[5], glo); + LOGP(info, "Adding for {} -> {} {} {} {} {} {}", symname, pars[0], + pars[1], pars[2], pars[3], pars[4], pars[5]); + + for (int ilr = 0; ilr < geom->getNumberOfLayers(); ilr++) { + + for (int ihb = 0; ihb < geom->getNumberOfHalfBarrels(); ihb++) { + symname = geom->composeSymNameHalfBarrel(ilr, ihb, ilr < 3); + if (ilr == 1) { + pars = AlgPar{-50e-4, 0.0, 0.0, 0.0, 0.0, 0.0}; + } else { + pars = generateMisalignment(xHBa, yHBa, zHBa, psiHBa, thetaHBa, phiHBa); + } + params.emplace_back(symname.c_str(), -1, pars[0], pars[1], pars[2], + pars[3], pars[4], pars[5], glo); + LOGP(info, "Adding for {} -> {} {} {} {} {} {}", symname, pars[0], + pars[1], pars[2], pars[3], pars[4], pars[5]); + } + } + + if (!ccdbHost.empty()) { + std::string path = + objectPath.empty() + ? o2::base::DetectorNameConf::getAlignmentPath(detITS) + : objectPath; + LOGP(info, "Storing alignment object on {}/{}", ccdbHost, path); + o2::ccdb::CcdbApi api; + map metadata; // can be empty + api.init( + ccdbHost.c_str()); // or http://localhost:8080 for a local installation + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(¶ms, path, metadata, tmin, tmax); + } + if (!fileName.empty()) { + LOGP(info, "Storing ITS3 alignment in local file {}", fileName); + TFile algFile(fileName.c_str(), "recreate"); + algFile.WriteObjectAny(¶ms, "std::vector", "alignment"); + algFile.Close(); + } +} + +AlgPar generateMisalignment(double x, double y, double z, double psi, + double theta, double phi) +{ + AlgPar pars; + pars[0] = gRandom->Gaus(0, x); + pars[1] = gRandom->Gaus(0, y); + pars[2] = gRandom->Gaus(0, z); + pars[3] = gRandom->Gaus(0, psi); + pars[4] = gRandom->Gaus(0, theta); + pars[5] = gRandom->Gaus(0, phi); + return std::move(pars); +} diff --git a/Detectors/Upgrades/ITS3/macros/align/ShowCoefficients.C b/Detectors/Upgrades/ITS3/macros/align/ShowCoefficients.C index 42749b707e81d..ca6b49e19355f 100644 --- a/Detectors/Upgrades/ITS3/macros/align/ShowCoefficients.C +++ b/Detectors/Upgrades/ITS3/macros/align/ShowCoefficients.C @@ -10,8 +10,6 @@ // or submit itself to any jurisdiction. #if !defined(__CLING__) || defined(__ROOTCLING__) -#include "Math/Factory.h" -#include "Math/Minimizer.h" #include "TAxis.h" #include "TCanvas.h" #include "TGraph.h" @@ -27,25 +25,12 @@ #include "MathUtils/Utils.h" #endif -static ROOT::Math::Minimizer* gMin; - -void ShowCoefficients(const std::string& fileName = "misparams.root", bool findMin = false) +void ShowCoefficients(const std::string& fileName = "misparams.root") { - constexpr double factor{10}; + constexpr double factor{20}; o2::its3::align::Deformations def; def.init(fileName); - if (findMin) { - gMin = ROOT::Math::Factory::CreateMinimizer("Minuit2", "Migrad"); - if (gMin == nullptr) { - Error("", "Cannot create minimizer !"); - return; - } - gMin->SetMaxFunctionCalls(1000000); // for Minuit/Minuit2 - gMin->SetTolerance(0.00001); - gMin->SetPrintLevel(1); - } - if constexpr (1) { constexpr int nPoints{1000}; const std::array zFix{-12., -8.67, -4.33, 0., 4.33, 8.67, 12.}; @@ -74,9 +59,9 @@ void ShowCoefficients(const std::string& fileName = "misparams.root", bool findM xi[idx] = radius * std::cos(phi); yi[idx] = radius * std::sin(phi); - const auto [dxXY, dyXY, _] = def.getDeformation(s, nphi, nzFix); - xd[idx] = xi[idx] + dxXY * factor; - yd[idx] = yi[idx] + dyXY * factor; + const auto [dxXY, dyXY, _] = def.getDeformation(s, radius, phi, 0, nphi, nzFix, factor); + xd[idx] = dxXY; + yd[idx] = dyXY; } } canv->cd(i + 1); @@ -108,10 +93,9 @@ void ShowCoefficients(const std::string& fileName = "misparams.root", bool findM const double xi = radius * std::cos(phiFix[i]), yi = radius * std::sin(phiFix[i]); ri[idx] = radius; zi[idx] = z; - const auto [dxZR, dyZR, dzZR] = def.getDeformation(s, nphiFix, nz); - zd[idx] = z + dzZR * factor; - const double xxd = xi + dxZR * factor, yyd = yi + dyZR * factor; - rd[idx] = std::sqrt(xxd * xxd + yyd * yyd); + const auto [dxZR, dyZR, dzZR] = def.getDeformation(s, radius, phiFix[i], z, nphiFix, nz, factor); + zd[idx] = dzZR; + rd[idx] = std::sqrt(dxZR * dxZR + dyZR * dyZR); } } canv->cd(i + 8); @@ -136,198 +120,148 @@ void ShowCoefficients(const std::string& fileName = "misparams.root", bool findM stepX{(maxX - minX) / static_cast(nPoints)}; for (unsigned int iSensor{0}; iSensor < 6; ++iSensor) { - const auto nOrders = def.getOrders(iSensor); - for (unsigned int iAxis{0}; iAxis < 3; ++iAxis) { - std::array x, y, z; - auto canv = new TCanvas(Form("c_sensor%d_d%s", iSensor, axisName[iAxis]), Form("Legendre Coefficients Sensor %d - Axis %s", iSensor, axisName[iAxis])); - canv->Divide(nOrders[iAxis] + 1, nOrders[iAxis] + 1); + const auto nOrders = def.getOrder(iSensor); + if (nOrders == 0) { + continue; + } + std::array x, y, z; + auto canv = new TCanvas(Form("c_sensor%d", iSensor), Form("Legendre Coefficients Sensor %d", iSensor)); + canv->Divide(nOrders + 1, nOrders + 1); - { // Draw total polynominal - for (int iPoint{0}; iPoint < nPoints; ++iPoint) { - double xcur = minX + iPoint * stepX; - for (int jPoint{0}; jPoint < nPoints; ++jPoint) { - double ycur = minX + jPoint * stepX; - int i = iPoint * nPoints + jPoint; - x[i] = xcur; - y[i] = ycur; - z[i] = def.getDeformation(iSensor, iAxis, xcur, ycur); - } + { // Draw total polynominal + for (int iPoint{0}; iPoint < nPoints; ++iPoint) { + double xcur = minX + iPoint * stepX; + for (int jPoint{0}; jPoint < nPoints; ++jPoint) { + double ycur = minX + jPoint * stepX; + int i = iPoint * nPoints + jPoint; + x[i] = xcur; + y[i] = ycur; + z[i] = def.getDeformation(iSensor, xcur, ycur); } - canv->cd(nOrders[iAxis] + 1); - auto g = new TGraph2D(nPoints2, x.data(), y.data(), z.data()); - g->SetTitle(Form("Legendre Polynominal %d-deg Sensor %d #Delta%s;u;v;w", nOrders[iAxis], iSensor, axisName[iAxis])); - g->SetName(Form("g_%d_%s", iSensor, axisName[iAxis])); - g->Draw("surf1"); - g->GetXaxis()->SetRangeUser(minX, maxX); - g->GetYaxis()->SetRangeUser(minX, maxX); - gPad->Update(); } + canv->cd(nOrders + 1); + auto g = new TGraph2D(nPoints2, x.data(), y.data(), z.data()); + g->SetTitle(Form("Legendre Polynominal %d-deg Sensor %d;u;v;w", nOrders, iSensor)); + g->SetName(Form("g_%d", iSensor)); + g->Draw("surf1"); + g->GetXaxis()->SetRangeUser(minX, maxX); + g->GetYaxis()->SetRangeUser(minX, maxX); + gPad->Update(); + } - { // Draw decomposition of contributions to polynominal - const auto& leg = def.getLegendre(iSensor, iAxis); - const auto coeff = leg.getCoefficients(); - for (unsigned int iOrder{0}; iOrder <= nOrders[iAxis]; ++iOrder) { - for (unsigned int jOrder{0}; jOrder <= iOrder; ++jOrder) { - for (int iPoint{0}; iPoint < nPoints; ++iPoint) { - double xcur = minX + iPoint * stepX; - for (int jPoint{0}; jPoint < nPoints; ++jPoint) { - double ycur = minX + jPoint * stepX; - int i = iPoint * nPoints + jPoint; - x[i] = xcur; - y[i] = ycur; - z[i] = leg(iOrder, jOrder, xcur, ycur); - } - } - canv->cd(1 + iOrder * (nOrders[iAxis] + 1) + jOrder); - auto g = new TGraph2D(nPoints2, x.data(), y.data(), z.data()); - g->SetTitle(Form("c_{%d,%d}=%.4f;u;v;w", iOrder, jOrder, coeff(iOrder, jOrder))); - g->SetName(Form("g_%d_%d_%d_%d", iSensor, iAxis, iOrder, jOrder)); - if (iOrder == 0 && jOrder == 0) { // Fix display of constant value - g->Draw("P0"); - } else { - g->Draw("surf1"); + { // Draw decomposition of contributions to polynominal + const auto& leg = def.getLegendre(iSensor); + const auto coeff = leg.getCoefficients(); + for (unsigned int iOrder{0}; iOrder <= nOrders; ++iOrder) { + for (unsigned int jOrder{0}; jOrder <= iOrder; ++jOrder) { + for (int iPoint{0}; iPoint < nPoints; ++iPoint) { + double xcur = minX + iPoint * stepX; + for (int jPoint{0}; jPoint < nPoints; ++jPoint) { + double ycur = minX + jPoint * stepX; + int i = iPoint * nPoints + jPoint; + x[i] = xcur; + y[i] = ycur; + z[i] = leg(iOrder, jOrder, xcur, ycur); } - g->GetXaxis()->SetRangeUser(minX, maxX); - g->GetYaxis()->SetRangeUser(minX, maxX); - gPad->Update(); } + canv->cd(1 + iOrder * (nOrders + 1) + jOrder); + auto g = new TGraph2D(nPoints2, x.data(), y.data(), z.data()); + g->SetTitle(Form("c_{%d,%d}=%.4f;u;v;w", iOrder, jOrder, coeff(iOrder, jOrder))); + g->SetName(Form("g_%d_%d_%d", iSensor, iOrder, jOrder)); + if (iOrder == 0 && jOrder == 0) { // Fix display of constant value + g->Draw("P0"); + } else { + g->Draw("surf1"); + } + g->GetXaxis()->SetRangeUser(minX, maxX); + g->GetYaxis()->SetRangeUser(minX, maxX); + gPad->Update(); } } - - canv->Draw(); - canv->SaveAs(Form("its3_sensor%d_%s.pdf", iSensor, axisName[iAxis])); } + canv->Draw(); + canv->SaveAs(Form("its3_sensor%d.pdf", iSensor)); } } - if constexpr (1) { - constexpr int nPoints{50}; - constexpr int nPoints2{nPoints * nPoints}; - constexpr double radL = o2::its3::constants::radii[2] + 0.3, zL = o2::its3::constants::segment::lengthSensitive / 2.0 + 2.0; - - // Plot the whole geometry - std::array gIdeal; - std::array gDeformed; - constexpr double z1{-o2::its3::constants::segment::lengthSensitive / 2.0}, z2{o2::its3::constants::segment::lengthSensitive / 2.0}, zTot{z2 - z1}, zStep{zTot / (nPoints - 1)}; - auto canv = new TCanvas(); - canv->Divide(2, 1); - for (unsigned int iSensor{0}; iSensor < 6; ++iSensor) { - std::array xi, yi, zi, xd, yd, zd; - const double radius = o2::its3::constants::radii[iSensor / 2]; - const bool isTop = iSensor % 2 == 0; - const double phi1 = o2::math_utils::to02Pi(((isTop) ? 0.f : 1.f) * TMath::Pi() + std::asin(o2::its3::constants::equatorialGap / 2.f / radius)); - const double phi2 = o2::math_utils::to02Pi(((isTop) ? 1.f : 2.f) * TMath::Pi() - std::asin(o2::its3::constants::equatorialGap / 2.f / radius)); - const double phiTot{phi2 - phi1}, phiStep{phiTot / (nPoints - 1)}; - for (int iZ{0}; iZ < nPoints; ++iZ) { - double z = z1 + iZ * zStep; - for (int iPhi{0}; iPhi < nPoints; ++iPhi) { - int i = iZ * nPoints + iPhi; - double phi = phi1 + iPhi * phiStep; + /* if constexpr (0) { */ + /* constexpr int nPoints{50}; */ + /* constexpr int nPoints2{nPoints * nPoints}; */ + /* constexpr double radL = o2::its3::constants::radii[2] + 0.3, zL = o2::its3::constants::segment::lengthSensitive / 2.0 + 2.0; */ - xi[i] = radius * std::cos(phi); - yi[i] = radius * std::sin(phi); - zi[i] = z; + /* // Plot the whole geometry */ + /* std::array gIdeal; */ + /* std::array gDeformed; */ + /* constexpr double z1{-o2::its3::constants::segment::lengthSensitive / 2.0}, z2{o2::its3::constants::segment::lengthSensitive / 2.0}, zTot{z2 - z1}, zStep{zTot / (nPoints - 1)}; */ + /* auto canv = new TCanvas(); */ + /* canv->Divide(2, 1); */ + /* for (unsigned int iSensor{0}; iSensor < 6; ++iSensor) { */ + /* std::array xi, yi, zi, xd, yd, zd; */ + /* const double radius = o2::its3::constants::radii[iSensor / 2]; */ + /* const bool isTop = iSensor % 2 == 0; */ + /* const double phi1 = o2::math_utils::to02Pi(((isTop) ? 0.f : 1.f) * TMath::Pi() + std::asin(o2::its3::constants::equatorialGap / 2.f / radius)); */ + /* const double phi2 = o2::math_utils::to02Pi(((isTop) ? 1.f : 2.f) * TMath::Pi() - std::asin(o2::its3::constants::equatorialGap / 2.f / radius)); */ + /* const double phiTot{phi2 - phi1}, phiStep{phiTot / (nPoints - 1)}; */ + /* for (int iZ{0}; iZ < nPoints; ++iZ) { */ + /* double z = z1 + iZ * zStep; */ + /* for (int iPhi{0}; iPhi < nPoints; ++iPhi) { */ + /* int i = iZ * nPoints + iPhi; */ + /* double phi = phi1 + iPhi * phiStep; */ - const double u = ((phi - phi1) * 2.f) / phiTot - 1.f; - const double v = ((z - z1)) / zTot - 1.f; - const auto [dx, dy, dz] = def.getDeformation(iSensor, u, v); - xd[i] = xi[i] + dx * factor; - yd[i] = yi[i] + dy * factor; - zd[i] = zi[i] + dz * factor; - } - } + /* xi[i] = radius * std::cos(phi); */ + /* yi[i] = radius * std::sin(phi); */ + /* zi[i] = z; */ - canv->cd(1); - auto ideal = new TGraph2D(Form("g_ideal_%d", iSensor), "Ideal Geometry", nPoints2, xi.data(), zi.data(), yi.data()); - ideal->SetMarkerStyle(kFullCircle); - ideal->SetMarkerSize(1); - ideal->SetMarkerColor(kBlue); - ideal->SetLineColor(kBlue); - if (iSensor == 0) { - ideal->Draw("p0"); - } else { - ideal->Draw("p0;same"); - if (iSensor == 5) { - gPad->Update(); - ideal->GetXaxis()->SetTitle("X"); - ideal->GetYaxis()->SetTitle("Z"); - ideal->GetZaxis()->SetTitle("Y"); - ideal->GetXaxis()->SetRangeUser(-radL, radL); - ideal->GetZaxis()->SetRangeUser(-radL, radL); - ideal->GetYaxis()->SetRangeUser(-zL, zL); - } - } - - canv->cd(2); - auto deformed = new TGraph2D(Form("g_def_%d", iSensor), "Deformed Geometry", nPoints2, xd.data(), zd.data(), yd.data()); - deformed->SetMarkerStyle(kFullCircle); - deformed->SetMarkerSize(1); - deformed->SetMarkerColor(kRed); - deformed->SetLineColor(kRed); - if (iSensor == 0) { - deformed->Draw("p0"); - } else { - deformed->Draw("p0;same"); - if (iSensor == 5) { - gPad->Update(); - deformed->GetXaxis()->SetTitle("X"); - deformed->GetYaxis()->SetTitle("Z"); - deformed->GetZaxis()->SetTitle("Y"); - deformed->GetXaxis()->SetRangeUser(-radL, radL); - deformed->GetZaxis()->SetRangeUser(-radL, radL); - deformed->GetYaxis()->SetRangeUser(-zL, zL); - } - } - } + /* const double u = ((phi - phi1) * 2.f) / phiTot - 1.f; */ + /* const double v = ((z - z1)) / zTot - 1.f; */ + /* const auto [dx, dy, dz] = def.getDeformation(iSensor, radius, phi, z, u, v, factor); */ + /* xd[i] = dx; */ + /* yd[i] = dy; */ + /* zd[i] = dz; */ + /* } */ + /* } */ - // Optionally find a deformation - /* if (findMin2D) { */ - /* std::vector cccc(nOrder + 2, 0.0); */ - /* cccc[0] = nOrder; */ - /* for (int i{0}; i <= nOrder; ++i) { */ - /* for (int j{0}; j <= i; ++j) { */ - /* int k = i * (i + 1) / 2 + j; */ - /* cccc[1 + k] = coeff(i, j); */ - /* } */ - /* } */ - /* auto ig = legendre_poly2D_integral(cccc.data()); */ + /* canv->cd(1); */ + /* auto ideal = new TGraph2D(Form("g_ideal_%d", iSensor), "Ideal Geometry", nPoints2, xi.data(), zi.data(), yi.data()); */ + /* ideal->SetMarkerStyle(kFullCircle); */ + /* ideal->SetMarkerSize(1); */ + /* ideal->SetMarkerColor(kBlue); */ + /* ideal->SetLineColor(kBlue); */ + /* if (iSensor == 0) { */ + /* ideal->Draw("p0"); */ + /* } else { */ + /* ideal->Draw("p0;same"); */ + /* if (iSensor == 5) { */ + /* gPad->Update(); */ + /* ideal->GetXaxis()->SetTitle("X"); */ + /* ideal->GetYaxis()->SetTitle("Z"); */ + /* ideal->GetZaxis()->SetTitle("Y"); */ + /* ideal->GetXaxis()->SetRangeUser(-radL, radL); */ + /* ideal->GetZaxis()->SetRangeUser(-radL, radL); */ + /* ideal->GetYaxis()->SetRangeUser(-zL, zL); */ + /* } */ + /* } */ - /* gMin->Clear(); */ - /* ROOT::Math::Functor fmin(&legendre_poly2D_integral, */ - /* 2 + nOrder * (nOrder + 1) / 2 + nOrder); */ - /* Info("", "ig=%f parameters=%d", ig, */ - /* 2 + nOrder * (nOrder + 1) / 2 + nOrder); */ - /* gMin->SetFunction(fmin); */ - /* constexpr double minStep{0.001}; */ - /* gMin->SetFixedVariable(0, "nOrder", nOrder); */ - /* gMin->SetFixedVariable(1, "c_00", coeff(0, 0)); */ - /* for (int iOrder{1}; iOrder <= nOrder; ++iOrder) { */ - /* for (int jOrder{0}; jOrder <= iOrder; ++jOrder) { */ - /* int k = iOrder * (iOrder + 1) / 2 + jOrder + 1; */ - /* Info("", "Setting parameter %d", k); */ - /* if (getRandom() < 0.0) { */ - /* gMin->SetFixedVariable(k, Form("c_%d_%d", iOrder, jOrder), */ - /* coeff(iOrder, jOrder)); */ - /* } else { */ - /* gMin->SetVariable(k, Form("c_%d_%d", iOrder, jOrder), */ - /* coeff(iOrder, jOrder), minStep); */ - /* } */ - /* } */ - /* } */ - /* gMin->Minimize(); */ - /* return; */ - /* auto stat = gMin->Status(); */ - /* auto min = gMin->MinValue(); */ - /* if ((stat == 0 || stat == 1) && min < 0.01) { */ - /* Info("", "Minimizer converged with %f; using new values!", min); */ - /* const double *cmins = gMin->X(); */ - /* for (int iOrder{1}; iOrder <= nOrder; ++iOrder) { */ - /* for (int jOrder{0}; jOrder <= iOrder; ++jOrder) { */ - /* int k = iOrder * (iOrder + 1) / 2 + jOrder; */ - /* coeff(iOrder, jOrder) = cmins[k + 1]; */ - /* } */ - /* } */ - /* } */ - /* } */ - } + /* canv->cd(2); */ + /* auto deformed = new TGraph2D(Form("g_def_%d", iSensor), "Deformed Geometry", nPoints2, xd.data(), zd.data(), yd.data()); */ + /* deformed->SetMarkerStyle(kFullCircle); */ + /* deformed->SetMarkerSize(1); */ + /* deformed->SetMarkerColor(kRed); */ + /* deformed->SetLineColor(kRed); */ + /* if (iSensor == 0) { */ + /* deformed->Draw("p0"); */ + /* } else { */ + /* deformed->Draw("p0;same"); */ + /* if (iSensor == 5) { */ + /* gPad->Update(); */ + /* deformed->GetXaxis()->SetTitle("X"); */ + /* deformed->GetYaxis()->SetTitle("Z"); */ + /* deformed->GetZaxis()->SetTitle("Y"); */ + /* deformed->GetXaxis()->SetRangeUser(-radL, radL); */ + /* deformed->GetZaxis()->SetRangeUser(-radL, radL); */ + /* deformed->GetYaxis()->SetRangeUser(-zL, zL); */ + /* } */ + /* } */ + /* } */ + /* } */ } diff --git a/Detectors/Upgrades/ITS3/macros/align/TestLegendrePol.C b/Detectors/Upgrades/ITS3/macros/align/TestLegendrePol.C index 720ab80264838..3e3f5827abebe 100644 --- a/Detectors/Upgrades/ITS3/macros/align/TestLegendrePol.C +++ b/Detectors/Upgrades/ITS3/macros/align/TestLegendrePol.C @@ -10,8 +10,6 @@ // or submit itself to any jurisdiction. #if !defined(__CLING__) || defined(__ROOTCLING__) -#include "Math/Factory.h" -#include "Math/Minimizer.h" #include "TAxis.h" #include "TCanvas.h" #include "TGraph.h" @@ -24,9 +22,7 @@ #include "MathUtils/LegendrePols.h" #endif -static ROOT::Math::Minimizer* gMin; - -void TestLegendrePol(bool findMin1D = false, bool findMin2D = false) +void TestLegendrePol() { constexpr int nMaxOrder{2}; constexpr int nPoints{100}; @@ -40,17 +36,6 @@ void TestLegendrePol(bool findMin1D = false, bool findMin2D = false) return scale * gRandom->Uniform(-1.0, 1.0); }; - if (findMin1D || findMin2D) { - gMin = ROOT::Math::Factory::CreateMinimizer("Minuit2", "Migrad"); - if (gMin == nullptr) { - Error("", "Cannot create minimizer !"); - return; - } - gMin->SetMaxFunctionCalls(1000000); // for Minuit/Minuit2 - gMin->SetTolerance(0.00001); - gMin->SetPrintLevel(1); - } - { // 1D Info("", "---------------- 1D -------------"); std::array x, y; @@ -60,36 +45,6 @@ void TestLegendrePol(bool findMin1D = false, bool findMin2D = false) o2::math_utils::Legendre1DPolynominal leg1D(coeff); - // Optionally find a deformation - if (findMin1D) { - std::vector cccc(nOrder + 2, 0.0); - cccc[0] = nOrder; - for (int iOrder{0}; iOrder <= nOrder; ++iOrder) { - cccc[1 + iOrder] = coeff[iOrder]; - } - - gMin->Clear(); - /* gMin->SetFunction(&leg1D.DoIntegralPar); */ - constexpr double minStep{0.001}; - gMin->SetFixedVariable(0, "c_0", coeff[0]); - for (int iOrder{1}; iOrder <= nOrder; ++iOrder) { - gMin->SetVariable(iOrder, Form("c_%d", iOrder), coeff[iOrder], - minStep); - } - gMin->Minimize(); - auto stat = gMin->Status(); - auto min = gMin->MinValue(); - if ((stat == 0 || stat == 1) && min < 0.01) { - Info("", "Minimizer converged with %f; using new values!", min); - const double* cmins = gMin->X(); - for (int i{0}; i <= nOrder; ++i) { - Info("", "New values are c_%d=%.4f -> %.4f", i, coeff[i], - cmins[1 + i]); - coeff[i] = cmins[1 + i]; - } - } - } - auto c1d = new TCanvas(Form("c1D_%d", nOrder), Form("Legendre 1D Order %d", nOrder)); c1d->Divide(2, 1); @@ -148,57 +103,6 @@ void TestLegendrePol(bool findMin1D = false, bool findMin2D = false) } o2::math_utils::Legendre2DPolynominal leg2D(coeff); - - // Optionally find a deformation - /* if (findMin2D) { */ - /* std::vector cccc(nOrder + 2, 0.0); */ - /* cccc[0] = nOrder; */ - /* for (int i{0}; i <= nOrder; ++i) { */ - /* for (int j{0}; j <= i; ++j) { */ - /* int k = i * (i + 1) / 2 + j; */ - /* cccc[1 + k] = coeff(i, j); */ - /* } */ - /* } */ - /* auto ig = legendre_poly2D_integral(cccc.data()); */ - - /* gMin->Clear(); */ - /* ROOT::Math::Functor fmin(&legendre_poly2D_integral, */ - /* 2 + nOrder * (nOrder + 1) / 2 + nOrder); */ - /* Info("", "ig=%f parameters=%d", ig, */ - /* 2 + nOrder * (nOrder + 1) / 2 + nOrder); */ - /* gMin->SetFunction(fmin); */ - /* constexpr double minStep{0.001}; */ - /* gMin->SetFixedVariable(0, "nOrder", nOrder); */ - /* gMin->SetFixedVariable(1, "c_00", coeff(0, 0)); */ - /* for (int iOrder{1}; iOrder <= nOrder; ++iOrder) { */ - /* for (int jOrder{0}; jOrder <= iOrder; ++jOrder) { */ - /* int k = iOrder * (iOrder + 1) / 2 + jOrder + 1; */ - /* Info("", "Setting parameter %d", k); */ - /* if (getRandom() < 0.0) { */ - /* gMin->SetFixedVariable(k, Form("c_%d_%d", iOrder, jOrder), */ - /* coeff(iOrder, jOrder)); */ - /* } else { */ - /* gMin->SetVariable(k, Form("c_%d_%d", iOrder, jOrder), */ - /* coeff(iOrder, jOrder), minStep); */ - /* } */ - /* } */ - /* } */ - /* gMin->Minimize(); */ - /* return; */ - /* auto stat = gMin->Status(); */ - /* auto min = gMin->MinValue(); */ - /* if ((stat == 0 || stat == 1) && min < 0.01) { */ - /* Info("", "Minimizer converged with %f; using new values!", min); */ - /* const double *cmins = gMin->X(); */ - /* for (int iOrder{1}; iOrder <= nOrder; ++iOrder) { */ - /* for (int jOrder{0}; jOrder <= iOrder; ++jOrder) { */ - /* int k = iOrder * (iOrder + 1) / 2 + jOrder; */ - /* coeff(iOrder, jOrder) = cmins[k + 1]; */ - /* } */ - /* } */ - /* } */ - /* } */ - leg2D.printCoefficients(); { // Draw total polynominal diff --git a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h index 80565df55d154..6ef3c0a7ef9ba 100644 --- a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h +++ b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h @@ -41,6 +41,11 @@ class DescriptorInnerBarrelITS3 : public o2::its::DescriptorInnerBarrel void createServices(TGeoVolume* dest); void configure() {} + // Alignables + void addAlignableVolumesLayer(int idLayer, int wrapperLayerId, TString& parentPath, int& lastUID) const; + void addAlignableVolumesCarbonForm(int idLayer, int iHalfBarrel, TString& parentPath, int& lastUID) const; + void addAlignableVolumesChip(int idLayer, int iHalfBarrel, TString& parentPath, int& lastUID) const; + protected: int mNumLayers{constants::nLayers}; diff --git a/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx b/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx index 04f244284d5b6..6de0afaeac168 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx @@ -9,7 +9,11 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include +#include "Framework/Logger.h" #include "ITS3Simulation/DescriptorInnerBarrelITS3.h" +#include "ITS3Base/SpecsV2.h" +#include "ITSBase/GeometryTGeo.h" using namespace o2::its3; @@ -26,3 +30,53 @@ void DescriptorInnerBarrelITS3::createServices(TGeoVolume* dest) mServices = std::make_unique(); mServices->createCYSSAssembly(dest); } + +void DescriptorInnerBarrelITS3::addAlignableVolumesLayer(int idLayer, int wrapperLayerId, TString& parentPath, int& lastUID) const +{ + const TString wrpV = Form("%s%d_1", o2::its::GeometryTGeo::getITSWrapVolPattern(), wrapperLayerId); + TString path = Form("%s/%s/%s%d_0", parentPath.Data(), wrpV.Data(), o2::its::GeometryTGeo::getITS3LayerPattern(), idLayer); + + for (int iHalfBarrel{0}; iHalfBarrel < 2; ++iHalfBarrel) { + addAlignableVolumesCarbonForm(idLayer, iHalfBarrel, path, lastUID); + } +} + +void DescriptorInnerBarrelITS3::addAlignableVolumesCarbonForm(int idLayer, int iHalfBarrel, TString& parentPath, int& lastUID) const +{ + TString path = parentPath; + path = Form("%s/%s_%d", parentPath.Data(), o2::its::GeometryTGeo::getITS3CarbonFormPattern(idLayer), iHalfBarrel); + const TString sname = o2::its::GeometryTGeo::composeSymNameHalfBarrel(idLayer, iHalfBarrel, true); + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path; + } + + addAlignableVolumesChip(idLayer, iHalfBarrel, parentPath, lastUID); +} + +void DescriptorInnerBarrelITS3::addAlignableVolumesChip(int idLayer, int iHalfBarrel, TString& parentPath, int& lastUID) const +{ + using gITS = o2::its::GeometryTGeo; + for (unsigned int iSegment{0}; iSegment < constants::nSegments[idLayer]; ++iSegment) { + for (unsigned int iRSU{0}; iRSU < constants::segment::nRSUs; ++iRSU) { + for (unsigned int iTile{0}; iTile < constants::rsu::nTiles; ++iTile) { + TString path = parentPath; + path += Form("/%s_%d/", gITS::getITS3CarbonFormPattern(idLayer), iHalfBarrel); + path += Form("%s_0/", gITS::getITS3ChipPattern(idLayer)); + path += Form("%s_%d/", gITS::getITS3SegmentPattern(idLayer), iSegment); + path += Form("%s_%d/", gITS::getITS3RSUPattern(idLayer), iRSU); + path += Form("%s_%d/", gITS::getITS3TilePattern(idLayer), iTile); + path += Form("%s_0", gITS::getITS3PixelArrayPattern(idLayer)); + if (!gGeoManager->CheckPath(path.Data())) { + LOG(fatal) << "Path does not exist: " << path; + } + + TString sname = o2::its::GeometryTGeo::composeSymNameChip(idLayer, iHalfBarrel, iSegment, iRSU, iTile, 0, true); + int modUID = o2::base::GeometryManager::getSensID(o2::detectors::DetID::IT3, lastUID++); + + if (!gGeoManager->SetAlignableEntry(sname, path.Data(), modUID)) { + LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path; + } + } + } + } +} From c392bce7015e069d300e837046e958bd12975c30 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 7 Nov 2025 10:37:22 +0100 Subject: [PATCH 02/13] Common: new linkdef for TimeStamp Signed-off-by: Felix Schlepper --- DataFormats/common/src/CommonDataFormatLinkDef.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DataFormats/common/src/CommonDataFormatLinkDef.h b/DataFormats/common/src/CommonDataFormatLinkDef.h index 631305cd28f13..d66e89af637cc 100644 --- a/DataFormats/common/src/CommonDataFormatLinkDef.h +++ b/DataFormats/common/src/CommonDataFormatLinkDef.h @@ -26,10 +26,12 @@ #pragma link C++ class o2::dataformats::TimeStamp < float> + ; #pragma link C++ class o2::dataformats::TimeStamp < double> + ; #pragma link C++ class o2::dataformats::TimeStamp < int> + ; -#pragma link C++ class o2::dataformats::TimeStamp < Float16_t > + ; +#pragma link C++ class o2::dataformats::TimeStamp < uint32_t> + ; +#pragma link C++ class o2::dataformats::TimeStamp < Float16_t> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < float, float> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < double, double> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < int, int> + ; +#pragma link C++ class o2::dataformats::TimeStampWithError < uint32_t, uint16_t> + ; #pragma link C++ class o2::dataformats::EvIndex < int, int> + ; #pragma link C++ class o2::dataformats::RangeReference < int, int> + ; From 93f9503f131d31de4590bb0598cd4c738c771d29 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 11 Nov 2025 10:05:19 +0100 Subject: [PATCH 03/13] Common: add host symbols to RangeRef Signed-off-by: Felix Schlepper --- .../include/CommonDataFormat/RangeReference.h | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/DataFormats/common/include/CommonDataFormat/RangeReference.h b/DataFormats/common/include/CommonDataFormat/RangeReference.h index 0308d3b8af937..3d0c58298de03 100644 --- a/DataFormats/common/include/CommonDataFormat/RangeReference.h +++ b/DataFormats/common/include/CommonDataFormat/RangeReference.h @@ -29,23 +29,23 @@ template class RangeReference { public: - GPUd() RangeReference(FirstEntry ent, NElem n) { set(ent, n); } - GPUdDefault() RangeReference(const RangeReference& src) = default; - GPUdDefault() RangeReference() = default; - GPUdDefault() ~RangeReference() = default; - GPUd() void set(FirstEntry ent, NElem n) + GPUhd() RangeReference(FirstEntry ent, NElem n) { set(ent, n); } + GPUhdDefault() RangeReference(const RangeReference& src) = default; + GPUhdDefault() RangeReference() = default; + GPUhdDefault() ~RangeReference() = default; + GPUhd() void set(FirstEntry ent, NElem n) { mFirstEntry = ent; mEntries = n; } - GPUd() void clear() { set(0, 0); } - GPUd() FirstEntry getFirstEntry() const { return mFirstEntry; } - GPUd() FirstEntry getEntriesBound() const { return mFirstEntry + mEntries; } - GPUd() NElem getEntries() const { return mEntries; } - GPUd() void setFirstEntry(FirstEntry ent) { mFirstEntry = ent; } - GPUd() void setEntries(NElem n) { mEntries = n; } - GPUd() void changeEntriesBy(NElem inc) { mEntries += inc; } - GPUd() bool operator==(const RangeReference& other) const + GPUhd() void clear() { set(0, 0); } + GPUhd() FirstEntry getFirstEntry() const { return mFirstEntry; } + GPUhd() FirstEntry getEntriesBound() const { return mFirstEntry + mEntries; } + GPUhd() NElem getEntries() const { return mEntries; } + GPUhd() void setFirstEntry(FirstEntry ent) { mFirstEntry = ent; } + GPUhd() void setEntries(NElem n) { mEntries = n; } + GPUhd() void changeEntriesBy(NElem inc) { mEntries += inc; } + GPUhd() bool operator==(const RangeReference& other) const { return mFirstEntry == other.mFirstEntry && mEntries == other.mEntries; } @@ -68,21 +68,21 @@ class RangeRefComp static constexpr Base MaskN = ((0x1 << NBitsN) - 1); static constexpr Base MaskR = (~Base(0)) & (~MaskN); Base mData = 0; ///< packed 1st entry reference + N entries - GPUd() void sanityCheck() + GPUhd() void sanityCheck() { static_assert(NBitsN < NBitsTotal, "NBitsN too large"); } public: - GPUd() RangeRefComp(int ent, int n) { set(ent, n); } - GPUdDefault() RangeRefComp() = default; - GPUdDefault() RangeRefComp(const RangeRefComp& src) = default; + GPUhd() RangeRefComp(int ent, int n) { set(ent, n); } + GPUhdDefault() RangeRefComp() = default; + GPUhdDefault() RangeRefComp(const RangeRefComp& src) = default; GPUhd() void set(int ent, int n) { mData = (Base(ent) << NBitsN) + (Base(n) & MaskN); } - GPUd() static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } - GPUd() static constexpr Base getMaxEntries() { return MaskN; } + GPUhd() static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } + GPUhd() static constexpr Base getMaxEntries() { return MaskN; } GPUhd() int getFirstEntry() const { return mData >> NBitsN; } GPUhd() int getEntries() const { return mData & ((0x1 << NBitsN) - 1); } GPUhd() int getEntriesBound() const { return getFirstEntry() + getEntries(); } From 804c5ce9502fb2022c3edb04459f57292aa94693 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 20 Nov 2025 15:16:43 +0100 Subject: [PATCH 04/13] Common: EnumFlags add set --- Common/Utils/include/CommonUtils/EnumFlags.h | 141 +++++--- Common/Utils/test/testEnumFlags.cxx | 345 +++++++++++++++++++ 2 files changed, 444 insertions(+), 42 deletions(-) diff --git a/Common/Utils/include/CommonUtils/EnumFlags.h b/Common/Utils/include/CommonUtils/EnumFlags.h index 4bd1a9e641056..5e97c1e41bf4b 100644 --- a/Common/Utils/include/CommonUtils/EnumFlags.h +++ b/Common/Utils/include/CommonUtils/EnumFlags.h @@ -104,8 +104,8 @@ struct FlagsHelper final { // Range that is scanned by the compiler static constexpr size_t MinScan{0}; - static constexpr size_t MarginScan{1}; // Scan one past to check for overpopulation - static constexpr size_t MaxUnderScan{std::numeric_limits::digits}; // Maximum digits the underlying type has + static constexpr size_t MarginScan{1}; // Scan one past to check for overpopulation + static constexpr size_t MaxUnderScan{std::numeric_limits::digits}; // Maximum digits the underlying type has static constexpr size_t MaxScan{MaxUnderScan + MarginScan}; // Checks if a given 'localation' contains an enum. @@ -161,7 +161,7 @@ struct FlagsHelper final { static constexpr auto Max_v{Values.back()}; // Enum last entry static constexpr auto Min_u_v{static_cast(Min_v)}; // Enum first entry as size_t static constexpr auto Max_u_v{static_cast(Max_v)}; // Enum last entry as size_t - static_assert(Max_u_v < std::numeric_limits::digits, "Max Bit is beyond allow range defered from underlying type"); + static_assert(Max_u_v < std::numeric_limits::digits, "Max Bit is beyond allow range deferred from underlying type"); static constexpr bool isContinuous() noexcept { return (Max_u_v - Min_u_v + 1) == count(); } // Is the enum continuous static constexpr UMax makeMaxRep(size_t min, size_t max) { @@ -258,7 +258,7 @@ struct FlagsHelper final { static constexpr std::optional fromString(std::string_view str) noexcept { for (size_t i{0}; i < count(); ++i) { - if (Names[i] == str || NamesScoped[i] == str) { + if (isIEqual(Names[i], str) || isIEqual(NamesScoped[i], str)) { return Values[i]; } } @@ -277,7 +277,7 @@ struct FlagsHelper final { return toLower(a) == toLower(b); } - // Case-insensitive comparision for string_view. + // Case-insensitive comparison for string_view. static constexpr bool isIEqual(std::string_view s1, std::string_view s2) noexcept { if (s1.size() != s2.size()) { @@ -294,7 +294,7 @@ struct FlagsHelper final { static constexpr std::string_view None{"none"}; static constexpr bool hasNone() noexcept { - // check that enum does not contain memeber named 'none' + // check that enum does not contain member named 'none' for (size_t i{0}; i < count(); ++i) { if (isIEqual(Names[i], None)) { return true; @@ -306,7 +306,7 @@ struct FlagsHelper final { static constexpr std::string_view All{"all"}; static constexpr bool hasAll() noexcept { - // check that enum does not contain memeber named 'all' + // check that enum does not contain member named 'all' for (size_t i{0}; i < count(); ++i) { if (isIEqual(Names[i], All)) { return true; @@ -332,7 +332,7 @@ concept EnumFlag = requires { }; /** - * \brief Classs to aggregate and manage enum-based on-off flags. + * \brief Class to aggregate and manage enum-based on-off flags. * * This class manages flags as bits in the underlying type of an enum (upto 64 bits), allowing * manipulation via enum member names. It supports operations akin to std::bitset @@ -355,6 +355,7 @@ concept EnumFlag = requires { template class EnumFlags { + static constexpr int DefaultBase{2}; using H = details::enum_flags::FlagsHelper; using U = std::underlying_type_t; U mBits{0}; @@ -388,9 +389,9 @@ class EnumFlags std::for_each(flags.begin(), flags.end(), [this](const E f) noexcept { mBits |= to_bit(f); }); } // Init from a string. - EnumFlags(const std::string& str) + EnumFlags(std::string_view str, int base = DefaultBase) { - set(str); + set(str, base); } // Destructor. constexpr ~EnumFlags() = default; @@ -413,14 +414,14 @@ class EnumFlags // Sets flags from a string representation. // This can be either from a number representation (binary or digits) or // a concatenation of the enums members name e.g., 'Enum1|Enum2|...' - void set(const std::string& s = "", int base = 2) + void set(std::string_view s, int base = DefaultBase) { - // on throw restore previous state and rethrow - const U prev = mBits; - reset(); if (s.empty()) { // no-op return; } + // on throw restore previous state and rethrow + const U prev = mBits; + reset(); try { setImpl(s, base); } catch (const std::exception& e) { @@ -441,39 +442,42 @@ class EnumFlags } // Resets a specific flag. - template - requires std::is_same_v + template T> constexpr void reset(T t) { mBits &= ~to_bit(t); } // Tests if a specific flag is set. - template - requires std::is_same_v + template T> [[nodiscard]] constexpr bool test(T t) const noexcept { return (mBits & to_bit(t)) != None; } // Tests if all specified flags are set. - template + template ... Ts> [[nodiscard]] constexpr bool test(Ts... flags) const noexcept { return ((test(flags) && ...)); } // Sets a specific flag. - template - requires std::is_same_v + template T> constexpr void set(T t) noexcept { mBits |= to_bit(t); } + // Sets multiple specific flags. + template ... Ts> + constexpr void set(Ts... flags) noexcept + { + (set(flags), ...); + } + // Toggles a specific flag. - template - requires std::is_same_v + template T> constexpr void toggle(T t) noexcept { mBits ^= to_bit(t); @@ -538,8 +542,7 @@ class EnumFlags } // Check if given flag is set. - template - requires std::is_same_v + template T> [[nodiscard]] constexpr bool operator[](const T t) const noexcept { return test(t); @@ -564,8 +567,7 @@ class EnumFlags constexpr EnumFlags& operator=(EnumFlags&& o) = default; // Performs a bitwise OR with a flag. - template - requires std::is_same_v + template T> constexpr EnumFlags& operator|=(T t) noexcept { mBits |= to_bit(t); @@ -573,8 +575,7 @@ class EnumFlags } // Performs a bitwise AND with a flag. - template - requires std::is_same_v + template T> constexpr EnumFlags& operator&=(T t) noexcept { mBits &= to_bit(t); @@ -582,8 +583,7 @@ class EnumFlags } // Returns a flag set with a bitwise AND. - template - requires std::is_same_v + template T> constexpr EnumFlags operator&(T t) const noexcept { return EnumFlags(mBits & to_bit(t)); @@ -683,34 +683,91 @@ class EnumFlags private: // Set implementation, bits was zeroed before. - void setImpl(const std::string& s, int base = 2) + void setImpl(std::string_view s, int base = 2) { + // Helper to check if character is valid for given base + auto isValidForBase = [](unsigned char c, int base) -> bool { + if (base == 2) { + return c == '0' || c == '1'; + } + if (base == 10) { + return std::isdigit(c); + } + if (base == 16) { + return std::isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } + return false; + }; + + // hex + if (base == 16) { + std::string_view hex_str = s; + // Strip optional 0x or 0X prefix + if (s.size() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + hex_str = s.substr(2); + } + if (hex_str.empty()) { + throw std::invalid_argument("Empty hexadecimal string."); + } + if (!std::all_of(hex_str.begin(), hex_str.end(), [&](unsigned char c) { return isValidForBase(c, 16); })) { + throw std::invalid_argument("Invalid hexadecimal string."); + } + typename H::UMax v = std::stoul(std::string(hex_str), nullptr, 16); + if (v > H::MaxRep) { + throw std::out_of_range("Value exceeds enum range."); + } + mBits = static_cast(v); + return; + } + + // decimal and binary if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c); })) { - if (base == 2) { // check of only 0 and 1 in string - if (!std::all_of(s.begin(), s.end(), [](char c) { return c == '0' || c == '1'; })) { + if (base == 2) { + // Binary: check only 0 and 1 + if (!std::all_of(s.begin(), s.end(), [&](unsigned char c) { return isValidForBase(c, 2); })) { throw std::invalid_argument("Invalid binary string."); } } - typename H::UMax v = std::stoul(s, nullptr, base); + typename H::UMax v = std::stoul(std::string(s), nullptr, base); if (v > H::MaxRep) { - throw std::out_of_range("Values exceeds enum range."); + throw std::out_of_range("Value exceeds enum range."); } mBits = static_cast(v); - } else if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalnum(c) != 0 || c == '|' || c == ' ' || c == ':' || c == ',' || c == ';'; })) { + } + // enum name strings + else if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalnum(c) != 0 || c == '|' || c == ' ' || c == ':' || c == ',' || c == ';'; })) { std::string cs{s}; std::transform(cs.begin(), cs.end(), cs.begin(), [](unsigned char c) { return std::tolower(c); }); + if (cs == H::All) { mBits = All; } else if (cs == H::None) { mBits = None; } else { - // accept as delimiter ' ', '|', ';', ',' + // Detect delimiter and ensure only one type is used char token = ' '; - std::string::size_type pos = s.find_first_of(",|;"); - if (pos != std::string::npos) { - token = s[pos]; + size_t pipePos = s.find('|'); + size_t commaPos = s.find(','); + size_t semiPos = s.find(';'); + + // Count how many different delimiters exist + int delimiterCount = (pipePos != std::string_view::npos ? 1 : 0) + + (commaPos != std::string_view::npos ? 1 : 0) + + (semiPos != std::string_view::npos ? 1 : 0); + + if (delimiterCount > 1) { + throw std::invalid_argument("Mixed delimiters not allowed!"); } - for (const auto& tok : Str::tokenize(s, token)) { + + if (pipePos != std::string_view::npos) { + token = '|'; + } else if (commaPos != std::string_view::npos) { + token = ','; + } else if (semiPos != std::string_view::npos) { + token = ';'; + } + + for (const auto& tok : Str::tokenize(std::string(s), token)) { if (auto e = H::fromString(tok)) { mBits |= to_bit(*e); } else { diff --git a/Common/Utils/test/testEnumFlags.cxx b/Common/Utils/test/testEnumFlags.cxx index 80f85c847653b..9101ffb97fdfe 100644 --- a/Common/Utils/test/testEnumFlags.cxx +++ b/Common/Utils/test/testEnumFlags.cxx @@ -74,11 +74,22 @@ BOOST_AUTO_TEST_CASE(Flags_test) multipleFlags.reset(); BOOST_TEST(!multipleFlags.any()); + // Test multiset + multipleFlags.reset(); + multipleFlags.set(TestEnum::Bit2, TestEnum::Bit4); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit1)); + BOOST_TEST(multipleFlags.test(TestEnum::Bit2)); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit3)); + BOOST_TEST(multipleFlags.test(TestEnum::Bit4)); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit5VeryLongName)); + // Test operator| EFlags combinedFlags = flag1 | EFlags(TestEnum::Bit2); BOOST_TEST(combinedFlags.test(TestEnum::Bit1)); BOOST_TEST(combinedFlags.test(TestEnum::Bit2)); BOOST_TEST(!combinedFlags.test(TestEnum::Bit3)); + combinedFlags |= TestEnum::Bit5VeryLongName; + BOOST_TEST(combinedFlags.test(TestEnum::Bit5VeryLongName)); // Test operator[] BOOST_TEST(combinedFlags[TestEnum::Bit1]); @@ -306,3 +317,337 @@ BOOST_AUTO_TEST_CASE(Flags_test) BOOST_CHECK(!test.test(TestEnumLong::Bit1, TestEnumLong::Bit23)); } } + +BOOST_AUTO_TEST_CASE(Flags_case_insensitive_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test case-insensitive flag names + { + EFlags flags("bit1"); // lowercase + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(!flags.test(TestEnum::Bit2)); + } + + { + EFlags flags("BIT2"); // uppercase + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(!flags.test(TestEnum::Bit1)); + } + + { + EFlags flags("BiT3"); // mixed case + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } + + { + EFlags flags("bit1|BIT2|BiT3"); // mixed case with delimiter + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } + + // Test special keywords case-insensitive + { + EFlags flags("ALL"); + BOOST_CHECK(flags.all()); + } + + { + EFlags flags("None"); + BOOST_CHECK(!flags.any()); + } +} + +BOOST_AUTO_TEST_CASE(Flags_error_recovery_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test that previous state is restored on exception + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + auto previousValue = flags.value(); + + // Try to set with invalid string + BOOST_CHECK_THROW(flags.set("InvalidFlag"), std::invalid_argument); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + { + EFlags flags({TestEnum::Bit3, TestEnum::Bit4}); + auto previousValue = flags.value(); + + // Try to set with out-of-range value + BOOST_CHECK_THROW(flags.set("999999", 10), std::out_of_range); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + } + + { + EFlags flags(TestEnum::Bit5VeryLongName); + auto previousValue = flags.value(); + + // Try to set with invalid binary string + BOOST_CHECK_THROW(flags.set("10102", 2), std::invalid_argument); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit5VeryLongName)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_whitespace_handling_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test leading/trailing whitespace + { + EFlags flags(" Bit1 "); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + } + + { + EFlags flags(" Bit1 | Bit2 "); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + // Test excessive whitespace between flags + { + EFlags flags("Bit1 | Bit3"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(!flags.test(TestEnum::Bit2)); + } + + // Test tabs and other whitespace (should work with space delimiter) + { + EFlags flags("Bit1 Bit2 Bit3"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_count_bits_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test counting set bits + { + EFlags flags; + BOOST_CHECK_EQUAL(flags.count(), 0); + } + + { + EFlags flags(TestEnum::Bit1); + BOOST_CHECK_EQUAL(flags.count(), 1); + } + + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + BOOST_CHECK_EQUAL(flags.count(), 2); + } + + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3, TestEnum::Bit4}); + BOOST_CHECK_EQUAL(flags.count(), 4); + } + + { + EFlags flags(EFlags::All); + BOOST_CHECK_EQUAL(flags.count(), 5); // TestEnum has 5 members + } + + // Test count after operations + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3}); + BOOST_CHECK_EQUAL(flags.count(), 3); + + flags.reset(TestEnum::Bit2); + BOOST_CHECK_EQUAL(flags.count(), 2); + + flags.set(TestEnum::Bit4); + BOOST_CHECK_EQUAL(flags.count(), 3); + + flags.toggle(TestEnum::Bit1); + BOOST_CHECK_EQUAL(flags.count(), 2); + } +} + +BOOST_AUTO_TEST_CASE(Flags_mixed_delimiter_validation_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test that mixed delimiters throw an error + { + BOOST_CHECK_THROW(EFlags("Bit1|Bit2,Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1;Bit2|Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1,Bit2;Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1|Bit2,Bit3;Bit4"), std::invalid_argument); + } + + // Test that single delimiter types work + { + EFlags flags1("Bit1|Bit2|Bit3"); + BOOST_CHECK_EQUAL(flags1.count(), 3); + } + + { + EFlags flags2("Bit1,Bit2,Bit3"); + BOOST_CHECK_EQUAL(flags2.count(), 3); + } + + { + EFlags flags3("Bit1;Bit2;Bit3"); + BOOST_CHECK_EQUAL(flags3.count(), 3); + } +} + +BOOST_AUTO_TEST_CASE(Flags_empty_and_edge_cases_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test empty string + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + flags.set(""); // Should be no-op + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + // Test with only whitespace + { + EFlags flags({TestEnum::Bit1}); + flags.set(" "); // Should result in empty after tokenization + // Depending on implementation, this might clear or throw + // Adjust expectation based on actual behavior + } + + // Test duplicate flags (should work, setting same bit twice is idempotent) + { + EFlags flags("Bit1|Bit1|Bit1"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK_EQUAL(flags.count(), 1); + } + + // Test scoped and unscoped mixed + { + EFlags flags("Bit1|TestEnum::Bit2"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_binary_decimal_parsing_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test binary parsing + { + EFlags flags("101", 2); + BOOST_CHECK(flags.test(TestEnum::Bit1)); // bit 0 + BOOST_CHECK(!flags.test(TestEnum::Bit2)); // bit 1 + BOOST_CHECK(flags.test(TestEnum::Bit3)); // bit 2 + } + + // Test decimal parsing + { + EFlags flags("7", 10); // 7 = 0b111 + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(!flags.test(TestEnum::Bit4)); + } + + // Test hexadecimal parsing + { + EFlags flags("F", 16); // 15 = 0b1111 + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + BOOST_CHECK(!flags.test(TestEnum::Bit5VeryLongName)); + } + + // Test hexadecimal with 0x prefix + { + EFlags flags("0xA", 16); // 10 = 0b1010 + BOOST_CHECK(!flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(!flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + } + + // Test hexadecimal with 0X prefix (uppercase) + { + EFlags flags("0X1F", 16); // 31 = all 5 bits + BOOST_CHECK(flags.all()); + } + + // Test lowercase hex digits + { + EFlags flags("0xa", 16); + BOOST_CHECK_EQUAL(flags.value(), 10); + } + + // Test thros + { + BOOST_CHECK_THROW(EFlags("0xAbCd", 16), std::out_of_range); + } + + // Test invalid binary string (contains 2) + { + BOOST_CHECK_THROW(EFlags("1012", 2), std::invalid_argument); + } + + // Test out of range for base + { + BOOST_CHECK_THROW(EFlags("100000", 2), std::out_of_range); + } +} + +BOOST_AUTO_TEST_CASE(Flags_operator_bool_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test explicit bool conversion + { + EFlags empty; + BOOST_CHECK(!static_cast(empty)); + } + + { + EFlags withFlag(TestEnum::Bit1); + BOOST_CHECK(static_cast(withFlag)); + } + + // Test in conditional + { + EFlags flags; + if (flags) { + BOOST_FAIL("Empty flags should be false"); + } + + flags.set(TestEnum::Bit1); + if (!flags) { + BOOST_FAIL("Non-empty flags should be true"); + } + } +} From 5c030ae2dac76fd86df538fda4e0077f025190ba Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 25 Nov 2025 14:52:37 +0100 Subject: [PATCH 05/13] Reco: Add cov setters for ind. elements --- .../include/ReconstructionDataFormats/Vertex.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h index 2d13e029f8c00..11e9b7428eb7c 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h @@ -20,6 +20,7 @@ #ifndef GPUCA_GPUCODE_DEVICE #include #include +#include #ifndef GPUCA_NO_FMT #include #include @@ -45,9 +46,14 @@ class VertexBase static constexpr int kNCov = 6; GPUhdDefault() VertexBase() = default; GPUhdDefault() ~VertexBase() = default; - GPUhd() VertexBase(const math_utils::Point3D& pos, const std::array& cov) : mPos(pos), mCov(cov) + GPUh() VertexBase(const float* pos, const float* cov) { + mPos.SetX(pos[0]); + mPos.SetY(pos[1]); + mPos.SetZ(pos[2]); + std::memcpy(mCov.data(), cov, sizeof(float) * kNCov); } + GPUhd() VertexBase(const math_utils::Point3D& pos, const std::array& cov) : mPos(pos), mCov(cov) {} #if !defined(GPUCA_NO_FMT) && !defined(GPUCA_GPUCODE_DEVICE) void print() const; @@ -58,6 +64,7 @@ class VertexBase GPUhd() float getX() const { return mPos.X(); } GPUhd() float getY() const { return mPos.Y(); } GPUhd() float getZ() const { return mPos.Z(); } + GPUhd() float getR() const { return gpu::CAMath::Hypot(mPos.X(), mPos.Y()); } GPUd() float getSigmaX2() const { return mCov[kCovXX]; } GPUd() float getSigmaY2() const { return mCov[kCovYY]; } GPUd() float getSigmaZ2() const { return mCov[kCovZZ]; } @@ -69,6 +76,7 @@ class VertexBase GPUd() float getSigmaZ() const { return gpu::CAMath::Sqrt(getSigmaZ2()); } GPUd() const std::array& getCov() const { return mCov; } + GPUd() float getCov(int e) const { return mCov[e]; } GPUd() math_utils::Point3D getXYZ() const { return mPos; } GPUd() math_utils::Point3D& getXYZ() { return mPos; } @@ -105,6 +113,7 @@ class VertexBase setSigmaYZ(syz); } GPUd() void setCov(const std::array& cov) { mCov = cov; } + GPUd() void setCov(float c, int e) { mCov[e] = c; } bool operator==(const VertexBase& other) const; bool operator!=(const VertexBase& other) const { return !(*this == other); } @@ -133,10 +142,8 @@ class Vertex : public VertexBase GPUhdDefault() Vertex() = default; GPUhdDefault() ~Vertex() = default; - GPUhd() Vertex(const math_utils::Point3D& pos, const std::array& cov, ushort nCont, float chi2) - : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) - { - } + GPUhd() Vertex(const float* pos, const float* cov, ushort nCont, float chi2) : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) {} + GPUhd() Vertex(const math_utils::Point3D& pos, const std::array& cov, ushort nCont, float chi2) : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) {} #if !defined(GPUCA_NO_FMT) && !defined(GPUCA_GPUCODE_DEVICE) void print() const; From ae7ee2a9f8667266165de2599d6c52af8291317b Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 10 Nov 2025 10:30:15 +0100 Subject: [PATCH 06/13] ITS: remove CookedTracker Signed-off-by: Felix Schlepper --- .../ITSMFT/ITS/reconstruction/CMakeLists.txt | 7 +- .../ITSReconstruction/CookedConfigParam.h | 42 - .../include/ITSReconstruction/CookedTracker.h | 267 ------ .../reconstruction/src/CookedConfigParam.cxx | 22 - .../ITS/reconstruction/src/CookedTracker.cxx | 865 ------------------ .../reconstruction/src/CookedTrackerLinkDef.h | 26 - .../src/ITSReconstructionLinkDef.h | 4 - .../include/ITSWorkflow/CookedTrackerSpec.h | 75 -- .../include/ITSWorkflow/RecoWorkflow.h | 2 +- .../ITS/workflow/src/CookedTrackerSpec.cxx | 327 ------- .../ITSMFT/ITS/workflow/src/RecoWorkflow.cxx | 60 +- .../ITS/workflow/src/its-reco-workflow.cxx | 4 - macro/CMakeLists.txt | 34 - macro/run_trac_its.C | 222 ----- 14 files changed, 29 insertions(+), 1928 deletions(-) delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h delete mode 100644 Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h delete mode 100644 Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx delete mode 100644 macro/run_trac_its.C diff --git a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt index 3e1544c65b9de..a5004418599e4 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt @@ -11,8 +11,6 @@ o2_add_library(ITSReconstruction SOURCES src/ClustererTask.cxx - src/CookedTracker.cxx - src/CookedConfigParam.cxx src/RecoGeomHelper.cxx src/FastMultEstConfig.cxx src/FastMultEst.cxx @@ -24,9 +22,6 @@ o2_add_library(ITSReconstruction o2_target_root_dictionary( ITSReconstruction HEADERS include/ITSReconstruction/ClustererTask.h - include/ITSReconstruction/CookedTracker.h - include/ITSReconstruction/CookedConfigParam.h include/ITSReconstruction/RecoGeomHelper.h include/ITSReconstruction/FastMultEst.h - include/ITSReconstruction/FastMultEstConfig.h - LINKDEF src/CookedTrackerLinkDef.h) + include/ITSReconstruction/FastMultEstConfig.h) diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h deleted file mode 100644 index bfc111d0a3803..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_COOKEDTRACKINGPARAM_H_ -#define ALICEO2_COOKEDTRACKINGPARAM_H_ - -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -namespace its -{ - -struct CookedConfigParam : public o2::conf::ConfigurableParamHelper { - // seed "windows" in z and phi: makeSeeds - float zWin = 0.33; - float minPt = 0.05; - // Maximal accepted impact parameters for the seeds - float maxDCAxy = 3.; - float maxDCAz = 3.; - // Space-point resolution - float sigma = 0.0005; - // Tracking "road" from layer to layer - float roadY = 0.2; - float roadZ = 0.3; - // Minimal number of attached clusters - int minNumberOfClusters = 4; - - O2ParamDef(CookedConfigParam, "ITSCookedTracker"); -}; - -} // namespace its -} // namespace o2 -#endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h deleted file mode 100644 index 918f7f82cbff8..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file CookedTracker.h -/// \brief Definition of the "Cooked Matrix" ITS tracker -/// \author iouri.belikov@cern.ch - -#ifndef ALICEO2_ITS_COOKEDTRACKER_H -#define ALICEO2_ITS_COOKEDTRACKER_H - -//------------------------------------------------------------------------- -// A stand-alone ITS tracker -// The pattern recongintion based on the "cooked covariance" approach -//------------------------------------------------------------------------- - -#include -#include -#include "ITSBase/GeometryTGeo.h" -#include "MathUtils/Cartesian.h" -#include "DataFormatsITSMFT/Cluster.h" -#include "DataFormatsITS/TrackITS.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "ITSReconstruction/CookedConfigParam.h" - -using Point3Df = o2::math_utils::Point3D; - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template -class MCTruthContainer; -} -namespace itsmft -{ -class TopologyDictionary; -class CompClusterExt; -} // namespace itsmft -namespace its -{ -class CookedTracker -{ - using Cluster = o2::itsmft::Cluster; - using CompClusterExt = o2::itsmft::CompClusterExt; - using Vertex = o2::dataformats::Vertex>; - - public: - CookedTracker(Int_t nThreads = 1); - CookedTracker(const CookedTracker&) = delete; - CookedTracker& operator=(const CookedTracker& tr) = delete; - ~CookedTracker() = default; - - void setConfigParams() - { - const auto& par = CookedConfigParam::Instance(); - LOG(info) << " Setting configurable parameters..."; - - gzWin = par.zWin; - gminPt = par.minPt; - gmaxDCAxy = par.maxDCAxy; - gmaxDCAz = par.maxDCAz; - gSigma2 = par.sigma * par.sigma; - gRoadY = par.roadY; - gRoadZ = par.roadZ; - gminNumberOfClusters = par.minNumberOfClusters; - } - void setParameters(const std::vector& par) - { - gzWin = par[0]; - gminPt = par[1]; - gmaxDCAxy = par[3]; - gmaxDCAz = par[4]; - gSeedingLayer1 = par[5]; - gSeedingLayer2 = par[6]; - gSeedingLayer3 = par[7]; - gSigma2 = par[8] * par[8]; - gmaxChi2PerCluster = par[9]; - gmaxChi2PerTrack = par[10]; - gRoadY = par[11]; - gRoadZ = par[12]; - gminNumberOfClusters = par[13]; - } - void setParametersCosmics() - { - // seed "windows" in z and phi: makeSeeds - gzWin = 84.; // length of the L3 - gminPt = 10.; - // Maximal accepted impact parameters for the seeds - gmaxDCAxy = 19.4; // radius of the L3 - gmaxDCAz = 42.; // half-lenght of the L3 - // Space point resolution - gSigma2 = 0.2 * 0.2; - // Tracking "road" from layer to layer - gRoadY = 1.5; // Chip size in Y - gRoadZ = 3.0; // Chip size in Z - } - - void setVertices(const std::vector& vertices) - { - mVertices = &vertices; - } - - Double_t getX() const { return mX; } - Double_t getY() const { return mY; } - Double_t getZ() const { return mZ; } - Double_t getSigmaX() const { return mSigmaX; } - Double_t getSigmaY() const { return mSigmaY; } - Double_t getSigmaZ() const { return mSigmaZ; } - o2::MCCompLabel cookLabel(TrackITSExt& t, Float_t wrong) const; - void setExternalIndices(TrackITSExt& t) const; - Double_t getBz() const; - void setBz(Double_t bz) { mBz = bz; } - - void setNumberOfThreads(Int_t n) { mNumOfThreads = n; } - Int_t getNumberOfThreads() const { return mNumOfThreads; } - - using TrackInserter = std::function; - // These functions must be implemented - template - void process(gsl::span clusters, gsl::span::iterator& it, const o2::itsmft::TopologyDictionary* dict, U& tracks, V& clusIdx, o2::itsmft::ROFRecord& rof) - { - TrackInserter inserter = [&tracks, &clusIdx, this](const TrackITSExt& t) -> int { - // convert internal track to output format - auto& trackNew = tracks.emplace_back(t); - int noc = t.getNumberOfClusters(); - int clEntry = clusIdx.size(); - for (int i = 0; i < noc; i++) { - const Cluster* c = this->getCluster(t.getClusterIndex(i)); - Int_t idx = c - &mClusterCache[0]; // Index of this cluster in event - clusIdx.emplace_back(this->mFirstInFrame + idx); - } - trackNew.setClusterRefs(clEntry, noc); - trackNew.setPattern(0x7f); // this tracker finds only complete tracks - return tracks.size(); - }; - process(clusters, it, dict, inserter, rof); - } - void process(gsl::span const& clusters, gsl::span::iterator& it, const o2::itsmft::TopologyDictionary* dict, TrackInserter& inserter, o2::itsmft::ROFRecord& rof); - const Cluster* getCluster(Int_t index) const; - - void setGeometry(o2::its::GeometryTGeo* geom); - void setMCTruthContainers(const o2::dataformats::MCTruthContainer* clsLabels, std::vector* trkLabels) - { - mClsLabels = clsLabels; - mTrkLabels = trkLabels; - } - - void setContinuousMode(bool mode) { mContinuousMode = mode; } - bool getContinuousMode() { return mContinuousMode; } - - static void setMostProbablePt(float pt) { mMostProbablePt = pt; } - static auto getMostProbablePt() { return mMostProbablePt; } - - // internal helper classes - class ThreadData; - class Layer; - - protected: - static constexpr int kNLayers = 7; - int loadClusters(); - void unloadClusters(); - std::tuple processLoadedClusters(TrackInserter& inserter); - - std::vector trackInThread(Int_t first, Int_t last); - o2::its::TrackITSExt cookSeed(const Point3Df& r1, Point3Df& r2, const Point3Df& tr3, float rad2, float rad3, float_t alpha, float_t bz); - void makeSeeds(std::vector& seeds, Int_t first, Int_t last); - void trackSeeds(std::vector& seeds); - - Bool_t attachCluster(Int_t& volID, Int_t nl, Int_t ci, TrackITSExt& t, const TrackITSExt& o) const; - - void makeBackPropParam(std::vector& seeds) const; - bool makeBackPropParam(TrackITSExt& track) const; - - private: - /*** Tracking parameters ***/ - // seed "windows" in z and phi: makeSeeds - static Float_t gzWin; - static Float_t gminPt; - static Float_t mMostProbablePt; ///< settable most probable pt - // Maximal accepted impact parameters for the seeds - static Float_t gmaxDCAxy; - static Float_t gmaxDCAz; - // Layers for the seeding - static Int_t gSeedingLayer1; - static Int_t gSeedingLayer2; - static Int_t gSeedingLayer3; - // Space point resolution - static Float_t gSigma2; - // Max accepted chi2 - static Float_t gmaxChi2PerCluster; - static Float_t gmaxChi2PerTrack; - // Tracking "road" from layer to layer - static Float_t gRoadY; - static Float_t gRoadZ; - // Minimal number of attached clusters - static Int_t gminNumberOfClusters; - - bool mContinuousMode = true; ///< triggered or cont. mode - const o2::its::GeometryTGeo* mGeom = nullptr; /// interface to geometry - const o2::dataformats::MCTruthContainer* mClsLabels = nullptr; /// Cluster MC labels - std::vector* mTrkLabels = nullptr; /// Track MC labels - std::uint32_t mFirstInFrame = 0; ///< Index of the 1st cluster of a frame (within the loaded vector of clusters) - - Int_t mNumOfThreads; ///< Number of tracking threads - - Double_t mBz; ///< Effective Z-component of the magnetic field (kG) - - const std::vector* mVertices = nullptr; - Double_t mX = 0.; ///< X-coordinate of the primary vertex - Double_t mY = 0.; ///< Y-coordinate of the primary vertex - Double_t mZ = 0.; ///< Z-coordinate of the primary vertex - - Double_t mSigmaX = 2.; ///< error of the primary vertex position in X - Double_t mSigmaY = 2.; ///< error of the primary vertex position in Y - Double_t mSigmaZ = 2.; ///< error of the primary vertex position in Z - - static Layer sLayers[kNLayers]; ///< Layers filled with clusters - std::vector mSeeds; ///< Track seeds - - std::vector mClusterCache; - - ClassDefNV(CookedTracker, 1); -}; - -class CookedTracker::Layer -{ - public: - Layer(); - Layer(const Layer&) = delete; - Layer& operator=(const Layer& tr) = delete; - - void init(); - Bool_t insertCluster(const Cluster* c); - void setR(Double_t r) { mR = r; } - void unloadClusters(); - void selectClusters(std::vector& s, Float_t phi, Float_t dy, Float_t z, Float_t dz); - Int_t findClusterIndex(Float_t z) const; - Float_t getR() const { return mR; } - const Cluster* getCluster(Int_t i) const { return mClusters[i]; } - Float_t getAlphaRef(Int_t i) const { return mAlphaRef[i]; } - Float_t getClusterPhi(Int_t i) const { return mPhi[i]; } - Int_t getNumberOfClusters() const { return mClusters.size(); } - void setGeometry(o2::its::GeometryTGeo* geom) { mGeom = geom; } - - protected: - enum { kNSectors = 21 }; - - Float_t mR; ///< mean radius of this layer - const o2::its::GeometryTGeo* mGeom = nullptr; ///< interface to geometry - std::vector mClusters; ///< All clusters - std::vector mAlphaRef; ///< alpha of the reference plane - std::vector mPhi; ///< cluster phi - std::vector> mSectors[kNSectors]; ///< Cluster indices sector-by-sector -}; -} // namespace its -} // namespace o2 -#endif /* ALICEO2_ITS_COOKEDTRACKER_H */ diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx deleted file mode 100644 index 81087744b04a9..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "ITSReconstruction/CookedConfigParam.h" - -namespace o2 -{ -namespace its -{ -static auto& sITSCookedTrackerParam = o2::its::CookedConfigParam::Instance(); - -O2ParamImpl(o2::its::CookedConfigParam); -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx deleted file mode 100644 index 5c804f6705dfd..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx +++ /dev/null @@ -1,865 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file CookedTracker.cxx -/// \brief Implementation of the "Cooked Matrix" ITS tracker -/// \author iouri.belikov@cern.ch - -//------------------------------------------------------------------------- -// A stand-alone ITS tracker -// The pattern recongintion based on the "cooked covariance" approach -//------------------------------------------------------------------------- -#include -#include -#include - -#include -#include - -#include - -#include "CommonConstants/MathConstants.h" -#include "DetectorsBase/Propagator.h" -#include "Field/MagneticField.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "ITSReconstruction/CookedTracker.h" -#include "MathUtils/Utils.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::its; -using namespace o2::itsmft; -using namespace o2::constants::math; -using o2::field::MagneticField; -using Label = o2::MCCompLabel; - -/*** Tracking parameters ***/ -// seed "windows" in z and phi: makeSeeds -Float_t CookedTracker::gzWin = 0.33; -Float_t CookedTracker::gminPt = 0.05; -Float_t CookedTracker::mMostProbablePt = o2::track::kMostProbablePt; -// Maximal accepted impact parameters for the seeds -Float_t CookedTracker::gmaxDCAxy = 3.; -Float_t CookedTracker::gmaxDCAz = 3.; -// Layers for the seeding -Int_t CookedTracker::gSeedingLayer1 = 6; -Int_t CookedTracker::gSeedingLayer2 = 4; -Int_t CookedTracker::gSeedingLayer3 = 5; -// Space point resolution -Float_t CookedTracker::gSigma2 = 0.0005 * 0.0005; -// Max accepted chi2 -Float_t CookedTracker::gmaxChi2PerCluster = 20.; -Float_t CookedTracker::gmaxChi2PerTrack = 30.; -// Tracking "road" from layer to layer -Float_t CookedTracker::gRoadY = 0.2; -Float_t CookedTracker::gRoadZ = 0.3; -// Minimal number of attached clusters -Int_t CookedTracker::gminNumberOfClusters = 4; - -const float kPI = 3.14159f; -const float k2PI = 2 * kPI; - -//************************************************ -// TODO: -//************************************************ -// Seeding: -// Precalculate cylidnrical (r,phi) for the clusters; -// use exact r's for the clusters - -CookedTracker::Layer CookedTracker::sLayers[CookedTracker::kNLayers]; - -CookedTracker::CookedTracker(Int_t n) : mNumOfThreads(n), mBz(0.) -{ - //-------------------------------------------------------------------- - // This default constructor needs to be provided - //-------------------------------------------------------------------- - const Double_t klRadius[7] = {2.34, 3.15, 3.93, 19.61, 24.55, 34.39, 39.34}; // tdr6 - - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].setR(klRadius[i]); - } -} - -//__________________________________________________________________________ -Label CookedTracker::cookLabel(TrackITSExt& t, Float_t wrong) const -{ - //-------------------------------------------------------------------- - // This function "cooks" a track label. - // A label<0 indicates that some of the clusters are wrongly assigned. - //-------------------------------------------------------------------- - Int_t noc = t.getNumberOfClusters(); - std::map labelOccurence; - - for (int i = noc; i--;) { - const Cluster* c = getCluster(t.getClusterIndex(i)); - Int_t idx = c - &mClusterCache[0] + mFirstInFrame; // Index of this cluster in event - auto labels = mClsLabels->getLabels(idx); - - for (auto lab : labels) { // check all labels of the cluster - if (lab.isEmpty()) { - break; // all following labels will be empty also - } - // was this label already accounted for ? - labelOccurence[lab]++; - } - } - Label lab; - Int_t maxL = 0; // find most encountered label - for (auto [label, count] : labelOccurence) { - if (count <= maxL) { - continue; - } - maxL = count; - lab = label; - } - - if ((1. - Float_t(maxL) / noc) > wrong) { - // change the track ID to negative - lab.setFakeFlag(); - } - // t.SetFakeRatio((1.- Float_t(maxL)/noc)); - return lab; -} - -Double_t CookedTracker::getBz() const -{ - return mBz; -} - -static Double_t f1(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x3, Double_t y3) -{ - //----------------------------------------------------------------- - // Initial approximation of the track curvature - //----------------------------------------------------------------- - Double_t d = (x2 - x1) * (y3 - y2) - (x3 - x2) * (y2 - y1); - Double_t a = - 0.5 * ((y3 - y2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) - (y2 - y1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2)); - Double_t b = - 0.5 * ((x2 - x1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2) - (x3 - x2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1)); - - Double_t xr = TMath::Abs(d / (d * x1 - a)), yr = TMath::Abs(d / (d * y1 - b)); - - Double_t crv = xr * yr / sqrt(xr * xr + yr * yr); - if (d > 0) { - crv = -crv; - } - - return crv; -} - -static Double_t f2(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x3, Double_t y3) -{ - //----------------------------------------------------------------- - // Initial approximation of the x-coordinate of the center of curvature - //----------------------------------------------------------------- - - Double_t k1 = (y2 - y1) / (x2 - x1), k2 = (y3 - y2) / (x3 - x2); - Double_t x0 = 0.5 * (k1 * k2 * (y1 - y3) + k2 * (x1 + x2) - k1 * (x2 + x3)) / (k2 - k1); - - return x0; -} - -static Double_t f3(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t z1, Double_t z2) -{ - //----------------------------------------------------------------- - // Initial approximation of the tangent of the track dip angle - //----------------------------------------------------------------- - return (z1 - z2) / sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); -} - -o2::its::TrackITSExt CookedTracker::cookSeed(const Point3Df& r1, Point3Df& r2, const Point3Df& tr3, float rad2, float rad3, float_t alpha, float_t bz) -// const Float_t r1[4], const Float_t r2[4], const Float_t tr3[4], Double_t alpha, Double_t bz) -{ - //-------------------------------------------------------------------- - // This is the main cooking function. - // Creates seed parameters out of provided clusters. - //-------------------------------------------------------------------- - - Double_t ca = TMath::Cos(alpha), sa = TMath::Sin(alpha); - Double_t x1 = r1.X() * ca + r1.Y() * sa, y1 = -r1.X() * sa + r1.Y() * ca, z1 = r1.Z(); - Double_t x2 = r2.X() * ca + r2.Y() * sa, y2 = -r2.X() * sa + r2.Y() * ca, z2 = r2.Z(); - Double_t x3 = tr3.X(), y3 = tr3.Y(), z3 = tr3.Z(); - - std::array par; - par[0] = y3; - par[1] = z3; - Double_t crv = f1(x1, y1, x2, y2, x3, y3); // curvature - Double_t x0 = f2(x1, y1, x2, y2, x3, y3); // x-coordinate of the center - Double_t tgl12 = f3(x1, y1, x2, y2, z1, z2); - Double_t tgl23 = f3(x2, y2, x3, y3, z2, z3); - - Double_t sf = crv * (x3 - x0); // FIXME: sf must never be >= kAlmost1 - par[2] = sf; - - par[3] = 0.5 * (tgl12 + tgl23); - par[4] = (TMath::Abs(bz) < Almost0) ? 1 / CookedTracker::getMostProbablePt() : crv / (bz * B2C); - - std::array cov; - /* - for (Int_t i=0; i<15; i++) cov[i]=0.; - cov[0] =gSigma2*10; - cov[2] =gSigma2*10; - cov[5] =0.007*0.007*10; //FIXME all these lines - cov[9] =0.007*0.007*10; - cov[14]=0.1*0.1*10; - */ - const Double_t dlt = 0.0005; - Double_t fy = 1. / (rad2 - rad3); - Double_t tz = fy; - const auto big = sqrt(o2::constants::math::VeryBig); - auto cy = big; - if (TMath::Abs(bz) >= Almost0) { - auto tmp = dlt * bz * B2C; - cy = (f1(x1, y1, x2, y2 + dlt, x3, y3) - crv) / tmp; - cy *= 20; // FIXME: MS contribution to the cov[14] - } - Double_t s2 = gSigma2; - - cov[0] = s2; - cov[1] = 0.; - cov[2] = s2; - cov[3] = s2 * fy; - cov[4] = 0.; - cov[5] = s2 * fy * fy; - cov[6] = 0.; - cov[7] = s2 * tz; - cov[8] = 0.; - cov[9] = s2 * tz * tz; - cov[10] = s2 * cy; - cov[11] = 0.; - cov[12] = s2 * fy * cy; - cov[13] = 0.; - cov[14] = s2 * cy * cy; - - return o2::its::TrackITSExt(x3, alpha, par, cov); -} - -void CookedTracker::makeSeeds(std::vector& seeds, Int_t first, Int_t last) -{ - //-------------------------------------------------------------------- - // This is the main pattern recongition function. - // Creates seeds out of two clusters and another point. - //-------------------------------------------------------------------- - const float zv = getZ(); - - Layer& layer1 = sLayers[gSeedingLayer1]; - Layer& layer2 = sLayers[gSeedingLayer2]; - Layer& layer3 = sLayers[gSeedingLayer3]; - - auto bz = getBz(); - const Double_t maxC = (TMath::Abs(bz) < Almost0) ? 0.03 : TMath::Abs(bz * B2C / gminPt); - const Double_t kpWinC = TMath::ASin(0.5 * maxC * layer1.getR()) - TMath::ASin(0.5 * maxC * layer2.getR()); - const Double_t kpWinD = 2 * (TMath::ASin(gmaxDCAxy / layer2.getR()) - TMath::ASin(gmaxDCAxy / layer1.getR())); - const Double_t kpWin = std::max(kpWinC, kpWinD); - - for (Int_t n1 = first; n1 < last; n1++) { - const Cluster* c1 = layer1.getCluster(n1); - // - //auto lab = (mClsLabels->getLabels(c1 - &mClusterCache[0] + mFirstInFrame))[0]; - // - auto xyz1 = c1->getXYZGloRot(*mGeom); - auto z1 = xyz1.Z(); - auto r1 = xyz1.rho(); - - auto phi1 = layer1.getClusterPhi(n1); - auto tgl = std::abs((z1 - zv) / r1); - - auto zr2 = zv + layer2.getR() / r1 * (z1 - zv); - auto phir2 = phi1; - auto dz2 = gzWin * (1 + 2 * tgl); - - std::vector selected2; - float dy2 = kpWin * layer2.getR(); - layer2.selectClusters(selected2, phir2, dy2, zr2, dz2); - for (auto n2 : selected2) { - const Cluster* c2 = layer2.getCluster(n2); - // - //if ((mClsLabels->getLabels(c2 - &mClusterCache[0] + mFirstInFrame))[0] != lab) continue; - // - auto xyz2 = c2->getXYZGloRot(*mGeom); - auto z2 = xyz2.Z(); - auto r2 = xyz2.rho(); - - auto dx = xyz2.X() - xyz1.X(), dy = xyz2.Y() - xyz1.Y(); - auto d = (dx * xyz1.Y() - dy * xyz1.X()) / TMath::Sqrt(dx * dx + dy * dy); - auto phir3 = phi1 + TMath::ASin(d / r1) - TMath::ASin(d / layer3.getR()); - - auto zr3 = z1 + (layer3.getR() - r1) / (r2 - r1) * (z2 - z1); - auto dz3 = 0.5f * dz2; - - std::vector selected3; - float dy3 = 0.1 * kpWin * layer3.getR(); //Fixme - layer3.selectClusters(selected3, phir3, dy3, zr3, dz3); - for (auto n3 : selected3) { - const Cluster* c3 = layer3.getCluster(n3); - // - //if ((mClsLabels->getLabels(c3 - &mClusterCache[0] + mFirstInFrame))[0] != lab) continue; - // - auto xyz3 = c3->getXYZGloRot(*mGeom); - auto z3 = xyz3.Z(); - auto r3 = xyz3.rho(); - - zr3 = z1 + (r3 - r1) / (r2 - r1) * (z2 - z1); - if (std::abs(z3 - zr3) > 0.2 * dz3) { - continue; - } - - const Point3Df& txyz2 = c2->getXYZ(); // tracking coordinates - - TrackITSExt seed = cookSeed(xyz1, xyz3, txyz2, layer2.getR(), layer3.getR(), layer2.getAlphaRef(n2), getBz()); - - float ip[2]; - seed.getImpactParams(getX(), getY(), getZ(), getBz(), ip); - if (TMath::Abs(ip[0]) > gmaxDCAxy) { - continue; - } - if (TMath::Abs(ip[1]) > gmaxDCAz) { - continue; - } - { - Double_t xx0 = 0.008; // Rough layer thickness - Double_t radl = 9.36; // Radiation length of Si [cm] - Double_t rho = 2.33; // Density of Si [g/cm^3] - if (!seed.correctForMaterial(xx0, xx0 * radl * rho, kTRUE)) { - continue; - } - } - seed.setClusterIndex(gSeedingLayer1, n1); - seed.setClusterIndex(gSeedingLayer3, n3); - seed.setClusterIndex(gSeedingLayer2, n2); - seeds.push_back(seed); - } - } - } - /* - for (Int_t n1 = 0; n1 < nClusters1; n1++) { - Cluster* c1 = layer1.getCluster(n1); - ((Cluster*)c1)->goToFrameTrk(); - } - for (Int_t n2 = 0; n2 < nClusters2; n2++) { - Cluster* c2 = layer2.getCluster(n2); - ((Cluster*)c2)->goToFrameTrk(); - } - for (Int_t n3 = 0; n3 < nClusters3; n3++) { - Cluster* c3 = layer3.getCluster(n3); - ((Cluster*)c3)->goToFrameTrk(); - } - */ -} - -void CookedTracker::trackSeeds(std::vector& seeds) -{ - //-------------------------------------------------------------------- - // Loop over a subset of track seeds - //-------------------------------------------------------------------- - std::vector used[gSeedingLayer2]; - std::vector selec[gSeedingLayer2]; - for (Int_t l = gSeedingLayer2 - 1; l >= 0; l--) { - Int_t n = sLayers[l].getNumberOfClusters(); - used[l].resize(n, false); - selec[l].reserve(n / 100); - } - - for (auto& track : seeds) { - auto x = track.getX(); - auto y = track.getY(); - Float_t phi = track.getAlpha() + TMath::ATan2(y, x); - o2::math_utils::bringTo02Pi(phi); - float ip[2]; - track.getImpactParams(getX(), getY(), getZ(), getBz(), ip); - - auto z = track.getZ(); - auto crv = track.getCurvature(getBz()); - auto tgl = track.getTgl(); - Float_t r1 = sLayers[gSeedingLayer2].getR(); - - for (Int_t l = gSeedingLayer2 - 1; l >= 0; l--) { - Float_t r2 = sLayers[l].getR(); - selec[l].clear(); - if (TMath::Abs(ip[0]) > r2) { - break; - } - if (TMath::Abs(crv) < gRoadY / (0.5 * r1 * 0.5 * r1)) { - phi += TMath::ASin(ip[0] / r2) - TMath::ASin(ip[0] / r1); - z += tgl * (TMath::Sqrt(r2 * r2 - ip[0] * ip[0]) - TMath::Sqrt(r1 * r1 - ip[0] * ip[0])); - } else { // Fixme - phi += 0.5 * crv * (r2 - r1); - z += tgl / (0.5 * crv) * (TMath::ASin(0.5 * crv * r2) - TMath::ASin(0.5 * crv * r1)); - } - sLayers[l].selectClusters(selec[l], phi, gRoadY, z, gRoadZ * (1 + 2 * std::abs(tgl))); - r1 = r2; - } - - TrackITSExt best(track); - - Int_t volID = -1; - for (auto& ci3 : selec[3]) { - TrackITSExt t3(track); - if (used[3][ci3]) { - continue; - } - if (!attachCluster(volID, 3, ci3, t3, track)) { - continue; - } - if (t3.isBetter(best, gmaxChi2PerTrack)) { - best = t3; - } - - for (auto& ci2 : selec[2]) { - TrackITSExt t2(t3); - if (used[2][ci2]) { - continue; - } - if (!attachCluster(volID, 2, ci2, t2, t3)) { - continue; - } - if (t2.isBetter(best, gmaxChi2PerTrack)) { - best = t2; - } - - for (auto& ci1 : selec[1]) { - TrackITSExt t1(t2); - if (used[1][ci1]) { - continue; - } - if (!attachCluster(volID, 1, ci1, t1, t2)) { - continue; - } - if (t1.isBetter(best, gmaxChi2PerTrack)) { - best = t1; - } - - for (auto& ci0 : selec[0]) { - TrackITSExt t0(t1); - if (used[0][ci0]) { - continue; - } - if (!attachCluster(volID, 0, ci0, t0, t1)) { - continue; - } - if (t0.isBetter(best, gmaxChi2PerTrack)) { - best = t0; - } - volID = -1; - } - } - } - } - - if (best.getNumberOfClusters() >= gminNumberOfClusters) { - Int_t noc = best.getNumberOfClusters(); - for (Int_t ic = 3; ic < noc; ic++) { - Int_t index = best.getClusterIndex(ic); - Int_t l = (index & 0xf0000000) >> 28, c = (index & 0x0fffffff); - used[l][c] = true; - } - } - track = best; - } -} - -std::vector CookedTracker::trackInThread(Int_t first, Int_t last) -{ - //-------------------------------------------------------------------- - // This function is passed to a tracking thread - //-------------------------------------------------------------------- - std::vector seeds; - seeds.reserve(last - first + 1); - - for (const auto& vtx : *mVertices) { - mX = vtx.getX(); - mY = vtx.getY(); - mZ = vtx.getZ(); - makeSeeds(seeds, first, last); - } - - std::sort(seeds.begin(), seeds.end()); - - trackSeeds(seeds); - - makeBackPropParam(seeds); - - return seeds; -} - -void CookedTracker::process(gsl::span const& clusters, - gsl::span::iterator& pattIt, - const o2::itsmft::TopologyDictionary* dict, - TrackInserter& inserter, - o2::itsmft::ROFRecord& rof) -{ - //-------------------------------------------------------------------- - // This is the main tracking function - //-------------------------------------------------------------------- - if (mVertices == nullptr || mVertices->empty()) { - LOG(info) << "Not a single primary vertex provided. Skipping...\n"; - return; - } - LOG(info) << "\n CookedTracker::process(), number of threads: " << mNumOfThreads; - - auto start = std::chrono::system_clock::now(); - - mFirstInFrame = rof.getFirstEntry(); - - mClusterCache.reserve(rof.getNEntries()); - auto clusters_in_frame = rof.getROFData(clusters); - for (const auto& comp : clusters_in_frame) { - - auto pattID = comp.getPatternID(); - o2::math_utils::Point3D locXYZ; - float sigmaY2 = gSigma2, sigmaZ2 = gSigma2; - if (pattID != itsmft::CompCluster::InvalidPatternID) { - sigmaY2 = gSigma2; //dict.getErr2X(pattID); - sigmaZ2 = gSigma2; //dict.getErr2Z(pattID); - if (!dict->isGroup(pattID)) { - locXYZ = dict->getClusterCoordinates(comp); - } else { - o2::itsmft::ClusterPattern patt(pattIt); - locXYZ = dict->getClusterCoordinates(comp, patt); - } - } else { - o2::itsmft::ClusterPattern patt(pattIt); - locXYZ = dict->getClusterCoordinates(comp, patt, false); - } - auto sensorID = comp.getSensorID(); - // Inverse transformation to the local --> tracking - auto trkXYZ = mGeom->getMatrixT2L(sensorID) ^ locXYZ; - - Cluster c; - c.setSensorID(sensorID); - c.setPos(trkXYZ); - c.setErrors(sigmaY2, sigmaZ2, 0.f); - mClusterCache.push_back(c); - } - - auto nClFrame = loadClusters(); - - auto end = std::chrono::system_clock::now(); - std::chrono::duration diff = end - start; - LOG(info) << "Loading clusters: " << nClFrame << " in a single frame : " << diff.count() << " s"; - - start = end; - - auto [first, number] = processLoadedClusters(inserter); - rof.setFirstEntry(first); - rof.setNEntries(number); - - unloadClusters(); - end = std::chrono::system_clock::now(); - diff = end - start; - LOG(info) << "Processing time/clusters for single frame : " << diff.count() << " / " << nClFrame << " s"; - - start = end; -} - -std::tuple CookedTracker::processLoadedClusters(TrackInserter& inserter) -{ - //-------------------------------------------------------------------- - // This is the main tracking function for single frame, it is assumed that only clusters - // which may contribute to this frame is loaded - //-------------------------------------------------------------------- - Int_t numOfClusters = sLayers[gSeedingLayer1].getNumberOfClusters(); - if (!numOfClusters) { - return {0, 0}; - } - - std::vector>> futures(mNumOfThreads); - std::vector> seedArray(mNumOfThreads); - - for (Int_t t = 0, first = 0; t < mNumOfThreads; t++) { - Int_t rem = t < (numOfClusters % mNumOfThreads) ? 1 : 0; - Int_t last = first + (numOfClusters / mNumOfThreads) + rem; - futures[t] = std::async(std::launch::async, &CookedTracker::trackInThread, this, first, last); - first = last; - } - Int_t nSeeds = 0, ngood = 0; - int nAllTracks = 0, nTracks = 0; - for (Int_t t = 0; t < mNumOfThreads; t++) { - seedArray[t] = futures[t].get(); - nSeeds += seedArray[t].size(); - for (auto& track : seedArray[t]) { - if (track.getNumberOfClusters() < gminNumberOfClusters) { - continue; - } - - o2::dataformats::VertexBase vtx; - track.propagateToDCA(vtx, getBz()); - - nAllTracks = inserter(track); - nTracks++; - if (mTrkLabels) { - Label label = cookLabel(track, 0.); // For comparison only - if (label.getTrackID() >= 0) { - ngood++; - } - // the inserter returns the size of the track vector, the index of the last - // inserted track is thus n - 1 - mTrkLabels->emplace_back(label); - } - } - } - - if (nSeeds) { - LOG(info) << "Found tracks: " << nTracks; - LOG(info) << "CookedTracker::processLoadedClusters(), good_tracks:/seeds: " << ngood << '/' << nSeeds << "-> " - << Float_t(ngood) / nSeeds << '\n'; - } - // returning index of the first track and the number of add tracks - // inserted in this call - return {nAllTracks - nTracks, nTracks}; -} - -//____________________________________________________________ -void CookedTracker::makeBackPropParam(std::vector& seeds) const -{ - // refit in backward direction - for (auto& track : seeds) { - if (track.getNumberOfClusters() < gminNumberOfClusters) { - continue; - } - makeBackPropParam(track); - } -} - -//____________________________________________________________ -bool CookedTracker::makeBackPropParam(TrackITSExt& track) const -{ - // refit in backward direction - auto backProp = track.getParamOut(); - backProp = track; - backProp.resetCovariance(); - auto propagator = o2::base::Propagator::Instance(); - - Int_t noc = track.getNumberOfClusters(); - for (int ic = noc; ic--;) { // cluster indices are stored in inward direction - Int_t index = track.getClusterIndex(ic); - const Cluster* c = getCluster(index); - float alpha = mGeom->getSensorRefAlpha(c->getSensorID()); - if (!backProp.rotate(alpha)) { - return false; - } - if (!propagator->PropagateToXBxByBz(backProp, c->getX())) { - return false; - } - if (!backProp.update(static_cast&>(*c))) { - return false; - } - } - track.getParamOut() = backProp; - return true; -} - -int CookedTracker::loadClusters() -{ - //-------------------------------------------------------------------- - // This function reads the ITSU clusters from the tree, - // sort them, distribute over the internal tracker arrays, etc - //-------------------------------------------------------------------- - - if (mClusterCache.empty()) { - return 0; - } - - for (const auto& c : mClusterCache) { - Int_t layer = mGeom->getLayer(c.getSensorID()); - sLayers[layer].insertCluster(&c); - } - - std::vector> fut; - for (Int_t l = 0; l < kNLayers; l += mNumOfThreads) { - for (Int_t t = 0; t < mNumOfThreads; t++) { - if (l + t >= kNLayers) { - break; - } - auto f = std::async(std::launch::async, &CookedTracker::Layer::init, sLayers + (l + t)); - fut.push_back(std::move(f)); - } - for (size_t t = 0; t < fut.size(); t++) { - fut[t].wait(); - } - } - - return mClusterCache.size(); -} - -void CookedTracker::unloadClusters() -{ - //-------------------------------------------------------------------- - // This function unloads ITSU clusters from the RAM - //-------------------------------------------------------------------- - mClusterCache.clear(); - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].unloadClusters(); - } -} - -const Cluster* CookedTracker::getCluster(Int_t index) const -{ - //-------------------------------------------------------------------- - // Return pointer to a given cluster - //-------------------------------------------------------------------- - Int_t l = (index & 0xf0000000) >> 28; - Int_t c = (index & 0x0fffffff) >> 00; - return sLayers[l].getCluster(c); -} - -CookedTracker::Layer::Layer() : mR(0) -{ - //-------------------------------------------------------------------- - // This default constructor needs to be provided - //-------------------------------------------------------------------- -} - -void CookedTracker::Layer::init() -{ - //-------------------------------------------------------------------- - // Sort clusters and cache their reference plane info in a thread - //-------------------------------------------------------------------- - std::sort(std::begin(mClusters), std::end(mClusters), - [](const Cluster* c1, const Cluster* c2) { return (c1->getZ() < c2->getZ()); }); - - Double_t r = 0.; - Int_t m = mClusters.size(); - for (Int_t i = 0; i < m; i++) { - const Cluster* c = mClusters[i]; - // Float_t xRef, aRef; - // mGeom->getSensorXAlphaRefPlane(c->getSensorID(),xRef, aRef); - mAlphaRef.push_back(mGeom->getSensorRefAlpha(c->getSensorID())); - auto xyz = c->getXYZGloRot(*mGeom); - r += xyz.rho(); - Float_t phi = xyz.Phi(); - o2::math_utils::bringTo02Pi(phi); - mPhi.push_back(phi); - Int_t s = phi * (int)kNSectors / k2PI; - mSectors[s < kNSectors ? s : kNSectors - 1].emplace_back(i, c->getZ()); - } - - if (m) { - mR = r / m; - } -} - -void CookedTracker::Layer::unloadClusters() -{ - //-------------------------------------------------------------------- - // Unload clusters from this layer - //-------------------------------------------------------------------- - mClusters.clear(); - mAlphaRef.clear(); - mPhi.clear(); - for (Int_t s = 0; s < kNSectors; s++) { - mSectors[s].clear(); - } -} - -Bool_t CookedTracker::Layer::insertCluster(const Cluster* c) -{ - //-------------------------------------------------------------------- - // This function inserts a cluster to this layer - //-------------------------------------------------------------------- - mClusters.push_back(c); - return kTRUE; -} - -Int_t CookedTracker::Layer::findClusterIndex(Float_t z) const -{ - //-------------------------------------------------------------------- - // This function returns the index of the first cluster with its fZ >= "z". - //-------------------------------------------------------------------- - auto found = std::upper_bound(std::begin(mClusters), std::end(mClusters), z, - [](Float_t zc, const Cluster* c) { return (zc < c->getZ()); }); - return found - std::begin(mClusters); -} - -void CookedTracker::Layer::selectClusters(std::vector& selec, Float_t phi, Float_t dy, Float_t z, Float_t dz) -{ - //-------------------------------------------------------------------- - // This function selects clusters within the "road" - //-------------------------------------------------------------------- - Float_t zMin = z - dz; - Float_t zMax = z + dz; - - o2::math_utils::bringTo02Pi(phi); - - Float_t dphi = dy / mR; - - int smin = (phi - dphi) / k2PI * (int)kNSectors; - int ds = (phi + dphi) / k2PI * (int)kNSectors - smin + 1; - - smin = (smin + kNSectors) % kNSectors; - - for (int is = 0; is < ds; is++) { - Int_t s = (smin + is) % kNSectors; - - auto cmp = [](Float_t zc, std::pair p) { return (zc < p.second); }; - auto imin = std::upper_bound(std::begin(mSectors[s]), std::end(mSectors[s]), zMin, cmp); - auto imax = std::upper_bound(imin, std::end(mSectors[s]), zMax, cmp); - for (; imin != imax; imin++) { - auto [i, zz] = *imin; - auto cdphi = std::abs(mPhi[i] - phi); - if (cdphi > dphi) { - if (cdphi > kPI) { - cdphi = k2PI - cdphi; - } - if (cdphi > dphi) { - continue; // check in Phi - } - } - selec.push_back(i); - } - } -} - -Bool_t CookedTracker::attachCluster(Int_t& volID, Int_t nl, Int_t ci, TrackITSExt& t, const TrackITSExt& o) const -{ - //-------------------------------------------------------------------- - // Try to attach a clusters with index ci to running track hypothesis - //-------------------------------------------------------------------- - Layer& layer = sLayers[nl]; - const Cluster* c = layer.getCluster(ci); - - Int_t vid = c->getSensorID(); - - if (vid != volID) { - volID = vid; - t = o; - Double_t alpha = layer.getAlphaRef(ci); - if (!t.propagate(alpha, c->getX(), getBz())) { - return kFALSE; - } - } - - Double_t chi2 = t.getPredictedChi2(*c); - if (chi2 > gmaxChi2PerCluster) { - return kFALSE; - } - - if (!t.update(*c, chi2)) { - return kFALSE; - } - t.setClusterIndex(nl, ci); - - Double_t xx0 = (nl > 2) ? 0.008 : 0.003; // Rough layer thickness - Double_t x0 = 9.36; // Radiation length of Si [cm] - Double_t rho = 2.33; // Density of Si [g/cm^3] - t.correctForMaterial(xx0, xx0 * x0 * rho, kTRUE); - return kTRUE; -} - -void CookedTracker::setGeometry(o2::its::GeometryTGeo* geom) -{ - /// attach geometry interface - mGeom = geom; - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].setGeometry(geom); - } -} diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h b/Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h deleted file mode 100644 index 1e8596fbb224c..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::its::ClustererTask + ; -#pragma link C++ class o2::its::CookedTracker + ; -#pragma link C++ class o2::its::CookedConfigParam + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::CookedConfigParam> + ; -#pragma link C++ class o2::its::RecoGeomHelper + ; -#pragma link C++ class o2::its::FastMultEst + ; -#pragma link C++ class o2::its::FastMultEstConfig + ; - -#endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h index c93cf03d0ed3d..67622303fc840 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h +++ b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h @@ -15,11 +15,7 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::its::ClustererTask + ; -#pragma link C++ class o2::its::CookedTracker + ; - #pragma link C++ class o2::its::RecoGeomHelper + ; - #pragma link C++ class o2::its::FastMultEst + ; #pragma link C++ class o2::its::FastMultEstConfig + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::FastMultEstConfig> + ; diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h deleted file mode 100644 index 4ecc98eed9cfb..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CookedTrackerSpec.h - -#ifndef O2_ITS_COOKEDTRACKERDPL -#define O2_ITS_COOKEDTRACKERDPL - -#include "Framework/DataProcessorSpec.h" -#include "ITSReconstruction/CookedTracker.h" -#include "ITStracking/TimeFrame.h" -#include "ITStracking/Vertexer.h" -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/BoundedAllocator.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "Framework/Task.h" -#include "TStopwatch.h" -#include "DetectorsBase/GRPGeomHelper.h" - -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace its -{ - -class CookedTrackerDPL : public Task -{ - public: - CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, TrackingMode::Type trMode); - ~CookedTrackerDPL() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void endOfStream(framework::EndOfStreamContext& ec) final; - void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; - void setClusterDictionary(const o2::itsmft::TopologyDictionary* d) { mDict = d; } - - private: - void updateTimeDependentParams(ProcessingContext& pc); - - std::shared_ptr mGGCCDBRequest; - int mState = 0; - bool mUseMC = true; - bool mRunVertexer = true; - int mUseTriggers = 0; - TrackingMode::Type mMode = TrackingMode::Sync; - const o2::itsmft::TopologyDictionary* mDict = nullptr; - std::unique_ptr mGRP = nullptr; - o2::its::CookedTracker mTracker; - std::unique_ptr> mVertexerTraitsPtr = nullptr; - std::unique_ptr> mVertexerPtr = nullptr; - std::shared_ptr mMemoryPool; - std::shared_ptr mTaskArena; - TStopwatch mTimer; -}; - -/// create a processor spec -/// run ITS CookedMatrix tracker -framework::DataProcessorSpec getCookedTrackerSpec(bool useMC, bool useGeom, int useTrig, TrackingMode::Type trMode); - -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_COOKEDTRACKERDPL */ diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h index 011ee6b88ff6f..d62cba0ed6c97 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h @@ -26,7 +26,7 @@ namespace its namespace reco_workflow { -framework::WorkflowSpec getWorkflow(bool useMC, bool useCMtracker, TrackingMode::Type trmode, const bool overrideBeamPosition = false, +framework::WorkflowSpec getWorkflow(bool useMC, TrackingMode::Type trmode, const bool overrideBeamPosition = false, bool upstreamDigits = false, bool upstreamClusters = false, bool disableRootOutput = false, bool useGeom = false, int useTrig = 0, bool useGPUWF = false, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); } diff --git a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx deleted file mode 100644 index b989a78e59b7c..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CookedTrackerSpec.cxx - -#include - -#include "TGeoGlobalMagField.h" - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/CCDBParamSpec.h" -#include "ITSWorkflow/CookedTrackerSpec.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/Cluster.h" -#include "DataFormatsITS/TrackITS.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include -#include "ITSMFTBase/DPLAlpideParam.h" -#include "DataFormatsTRD/TriggerRecord.h" - -#include "Field/MagneticField.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "ITSBase/GeometryTGeo.h" -#include "CommonDataFormat/IRFrame.h" -#include "ITStracking/IOUtils.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "CommonUtils/StringUtils.h" - -#include "ITSReconstruction/FastMultEstConfig.h" -#include "ITSReconstruction/FastMultEst.h" -#include "ITSMFTReconstruction/ClustererParam.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace its -{ - -using Vertex = o2::dataformats::Vertex>; - -CookedTrackerDPL::CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, TrackingMode::Type trMode) : mGGCCDBRequest(gr), mUseMC(useMC), mUseTriggers{trgType}, mMode(trMode) -{ - mVertexerTraitsPtr = std::make_unique>(); - mVertexerPtr = std::make_unique>(mVertexerTraitsPtr.get()); -} - -void CookedTrackerDPL::init(InitContext& ic) -{ - mTimer.Stop(); - mTimer.Reset(); - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - auto nthreads = ic.options().get("nthreads"); - mTracker.setNumberOfThreads(nthreads); - mTaskArena = std::make_shared(nthreads); - mMemoryPool = std::make_unique(); - mVertexerPtr->setMemoryPool(mMemoryPool); - mVertexerPtr->setNThreads(nthreads, mTaskArena); - mVertexerTraitsPtr->setMemoryPool(mMemoryPool); -} - -void CookedTrackerDPL::run(ProcessingContext& pc) -{ - mTimer.Start(false); - updateTimeDependentParams(pc); - auto compClusters = pc.inputs().get>("compClusters"); - gsl::span patterns = pc.inputs().get>("patterns"); - - // code further down does assignment to the rofs and the altered object is used for output - // we therefore need a copy of the vector rather than an object created directly on the input data, - // the output vector however is created directly inside the message memory thus avoiding copy by - // snapshot - auto rofsinput = pc.inputs().get>("ROframes"); - gsl::span physTriggers; - std::vector fromTRD; - if (mUseTriggers == 2) { // use TRD triggers - o2::InteractionRecord ir{0, pc.services().get().firstTForbit}; - auto trdTriggers = pc.inputs().get>("phystrig"); - for (const auto& trig : trdTriggers) { - if (trig.getBCData() >= ir && trig.getNumberOfTracklets()) { - ir = trig.getBCData(); - fromTRD.emplace_back(o2::itsmft::PhysTrigger{ir, 0}); - } - } - physTriggers = gsl::span(fromTRD.data(), fromTRD.size()); - } else if (mUseTriggers == 1) { // use Phys triggers from ITS stream - physTriggers = pc.inputs().get>("phystrig"); - } - - auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0}, rofsinput.begin(), rofsinput.end()); - - std::unique_ptr> labels; - gsl::span mc2rofs; - if (mUseMC) { - labels = pc.inputs().get*>("labels"); - // get the array as read-onlt span, a snapshot is send forward - mc2rofs = pc.inputs().get>("MC2ROframes"); - } - TimeFrame mTimeFrame; - mTimeFrame.setMemoryPool(mMemoryPool); - - LOG(info) << "ITSCookedTracker pulled " << compClusters.size() << " clusters, in " << rofs.size() << " RO frames"; - - std::vector trackLabels; - if (mUseMC) { - mTracker.setMCTruthContainers(labels.get(), &trackLabels); - } - - mVertexerPtr->adoptTimeFrame(mTimeFrame); - - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0}); - auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0}); - auto& tracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0}); - auto& clusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0}); - auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0}); - - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB - int nBCPerTF = mTracker.getContinuousMode() ? alpParams.roFrameLengthInBC : alpParams.roFrameLengthTrig; - - gsl::span::iterator pattIt_timeframe = patterns.begin(); - gsl::span::iterator pattIt_tracker = patterns.begin(); - gsl::span rofspan(rofs); - mTimeFrame.loadROFrameData(rofspan, compClusters, pattIt_timeframe, mDict, labels.get()); - - const auto& multEstConf = FastMultEstConfig::Instance(); // parameters for mult estimation and cuts - FastMultEst multEst; // mult estimator - std::vector processingMask; - int cutVertexMult{0}, cutRandomMult = int(rofsinput.size()) - multEst.selectROFs(rofsinput, compClusters, physTriggers, processingMask); - - // auto processingMask_ephemeral = processingMask; - mTimeFrame.setMultiplicityCutMask(processingMask); - float vertexerElapsedTime; - if (mRunVertexer) { - vertexerElapsedTime = mVertexerPtr->clustersToVertices([&](std::string s) { LOG(info) << s; }); - } - LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms in {} ROFs", vertexerElapsedTime, rofspan.size()); - for (size_t iRof{0}; iRof < rofspan.size(); ++iRof) { - auto& rof = rofspan[iRof]; - - auto& vtxROF = vertROFvec.emplace_back(rof); // register entry and number of vertices in the - vtxROF.setFirstEntry(vertices.size()); - vtxROF.setNEntries(0); - if (!processingMask[iRof]) { - rof.setFirstEntry(tracks.size()); - rof.setNEntries(0); - continue; - } - - std::vector>> vtxVecLoc; - for (auto& v : mTimeFrame.getPrimaryVertices(iRof)) { - vtxVecLoc.push_back(v); - } - - if (multEstConf.isVtxMultCutRequested()) { // cut was requested - std::vector>> vtxVecSel; - vtxVecSel.swap(vtxVecLoc); - int nv = vtxVecSel.size(), nrej = 0; - for (const auto& vtx : vtxVecSel) { - if (!multEstConf.isPassingVtxMultCut(vtx.getNContributors())) { - LOG(info) << "Found vertex mult. " << vtx.getNContributors() << " is outside of requested range " << multEstConf.cutMultVtxLow << " : " << multEstConf.cutMultVtxHigh << " | ROF " << rof.getBCData(); - nrej++; - continue; // skip vertex of unwanted multiplicity - } - vtxVecLoc.push_back(vtx); - } - if (nv && (nrej == nv)) { // all vertices were rejected - cutVertexMult++; - processingMask[iRof] = false; - } - } - if (vtxVecLoc.empty()) { - if (multEstConf.cutMultVtxLow < 1) { // do blind search only if there is no cut on the low mult vertices - vtxVecLoc.emplace_back(); - } else { - rof.setFirstEntry(tracks.size()); - rof.setNEntries(0); - continue; - } - } else { // save vertices - vtxROF.setNEntries(vtxVecLoc.size()); - for (const auto& vtx : vtxVecLoc) { - vertices.push_back(vtx); - } - } - - mTracker.setVertices(vtxVecLoc); - mTracker.process(compClusters, pattIt_tracker, mDict, tracks, clusIdx, rof); - if (processingMask[iRof]) { - irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); - } - } - LOGP(info, " - rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, rofspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); - LOG(info) << "ITSCookedTracker pushed " << tracks.size() << " tracks and " << vertices.size() << " vertices"; - - if (mUseMC) { - pc.outputs().snapshot(Output{"ITS", "TRACKSMCTR", 0}, trackLabels); - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0}, mc2rofs); - } - mTimer.Stop(); -} - -void CookedTrackerDPL::endOfStream(EndOfStreamContext& ec) -{ - LOGF(info, "ITS Cooked-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); -} - -///_______________________________________ -void CookedTrackerDPL::updateTimeDependentParams(ProcessingContext& pc) -{ - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("cldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("alppar"); - if (pc.inputs().getPos("itsTGeo") >= 0) { - pc.inputs().get("itsTGeo"); - } - mVertexerPtr->setParameters(TrackingMode::getVertexingParameters(mMode)); - o2::its::GeometryTGeo* geom = o2::its::GeometryTGeo::Instance(); - geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, - o2::math_utils::TransformType::T2G)); - mTracker.setGeometry(geom); - mTracker.setConfigParams(); - LOG(info) << "Tracking mode " << TrackingMode::toString(mMode); - if (mMode == TrackingMode::Cosmics) { - LOG(info) << "Setting cosmics parameters..."; - mTracker.setParametersCosmics(); - mRunVertexer = false; - } - mTracker.setBz(o2::base::Propagator::Instance()->getNominalBz()); - bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); - LOG(info) << "ITSCookedTracker RO: continuous=" << continuous; - mTracker.setContinuousMode(continuous); - } -} - -///_______________________________________ -void CookedTrackerDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) -{ - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated"; - setClusterDictionary((const o2::itsmft::TopologyDictionary*)obj); - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("ITS", "GEOMTGEO", 0)) { - LOG(info) << "ITS GeometryTGeo loaded from ccdb"; - o2::its::GeometryTGeo::adopt((o2::its::GeometryTGeo*)obj); - return; - } -} - -DataProcessorSpec getCookedTrackerSpec(bool useMC, bool useGeom, int trgType, TrackingMode::Type trmode) -{ - std::vector inputs; - inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("patterns", "ITS", "PATTERNS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); - inputs.emplace_back("cldict", "ITS", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); - inputs.emplace_back("alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); - if (trgType == 1) { - inputs.emplace_back("phystrig", "ITS", "PHYSTRIG", 0, Lifetime::Timeframe); - } else if (trgType == 2) { - inputs.emplace_back("phystrig", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe); - } - - std::vector outputs; - outputs.emplace_back("ITS", "TRACKS", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "TRACKCLSID", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "ITSTrackROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "VERTICES", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "VERTICESROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "IRFRAMES", 0, Lifetime::Timeframe); - - if (useMC) { - inputs.emplace_back("labels", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("MC2ROframes", "ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "TRACKSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe); - } - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - true, // GRPMagField - true, // askMatLUT - useGeom ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, // geometry - inputs, - true); - if (!useGeom) { - ggRequest->addInput({"itsTGeo", "ITS", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("ITS/Config/Geometry")}, inputs); - } - return DataProcessorSpec{ - "its-cooked-tracker", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, - useMC, - trgType, - trmode)}, - Options{{"nthreads", VariantType::Int, 1, {"Number of threads"}}}}; -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx index f375eaf67c04f..82bbdd2f4d3cb 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx @@ -15,7 +15,6 @@ #include "ITSWorkflow/ClustererSpec.h" #include "ITSWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" -#include "ITSWorkflow/CookedTrackerSpec.h" #include "ITSWorkflow/TrackWriterSpec.h" #include "ITStracking/TrackingConfigParam.h" #include "ITSMFTWorkflow/DigitReaderSpec.h" @@ -29,7 +28,6 @@ namespace o2::its::reco_workflow { framework::WorkflowSpec getWorkflow(bool useMC, - bool useCMtracker, TrackingMode::Type trmode, const bool overrideBeamPosition, bool upstreamDigits, @@ -51,40 +49,36 @@ framework::WorkflowSpec getWorkflow(bool useMC, specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); } if ((trmode != TrackingMode::Off) && (TrackerParamConfig::Instance().trackingMode != TrackingMode::Off)) { - if (useCMtracker) { - specs.emplace_back(o2::its::getCookedTrackerSpec(useMC, useGeom, useTrig, trmode)); - } else { - if (useGPUWF) { - o2::gpu::GPURecoWorkflowSpec::Config cfg{ - .itsTriggerType = useTrig, - .processMC = useMC, - .runITSTracking = true, - .itsOverrBeamEst = overrideBeamPosition, - }; + if (useGPUWF) { + o2::gpu::GPURecoWorkflowSpec::Config cfg{ + .itsTriggerType = useTrig, + .processMC = useMC, + .runITSTracking = true, + .itsOverrBeamEst = overrideBeamPosition, + }; - Inputs ggInputs; - auto ggRequest = std::make_shared(false, true, false, true, true, - useGeom ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, - ggInputs, true); - if (!useGeom) { - ggRequest->addInput({"itsTGeo", "ITS", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("ITS/Config/Geometry")}, ggInputs); - } + Inputs ggInputs; + auto ggRequest = std::make_shared(false, true, false, true, true, + useGeom ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, + ggInputs, true); + if (!useGeom) { + ggRequest->addInput({"itsTGeo", "ITS", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("ITS/Config/Geometry")}, ggInputs); + } - static std::vector policyData; - static std::shared_ptr task = std::make_shared(&policyData, cfg, std::vector(), 0, ggRequest); - Inputs taskInputs = task->inputs(); - Options taskOptions = task->options(); - std::move(ggInputs.begin(), ggInputs.end(), std::back_inserter(taskInputs)); + static std::vector policyData; + static std::shared_ptr task = std::make_shared(&policyData, cfg, std::vector(), 0, ggRequest); + Inputs taskInputs = task->inputs(); + Options taskOptions = task->options(); + std::move(ggInputs.begin(), ggInputs.end(), std::back_inserter(taskInputs)); - specs.emplace_back(DataProcessorSpec{ - .name = "its-gpu-tracker", - .inputs = taskInputs, - .outputs = task->outputs(), - .algorithm = AlgorithmSpec{adoptTask(task)}, - .options = taskOptions}); - } else { - specs.emplace_back(o2::its::getTrackerSpec(useMC, useGeom, useTrig, trmode, overrideBeamPosition, dtype)); - } + specs.emplace_back(DataProcessorSpec{ + .name = "its-gpu-tracker", + .inputs = taskInputs, + .outputs = task->outputs(), + .algorithm = AlgorithmSpec{adoptTask(task)}, + .options = taskOptions}); + } else { + specs.emplace_back(o2::its::getTrackerSpec(useMC, useGeom, useTrig, trmode, overrideBeamPosition, dtype)); } if (!disableRootOutput) { specs.emplace_back(o2::its::getTrackWriterSpec(useMC)); diff --git a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx index 4b9053436d44c..0de378c07b50e 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx @@ -41,8 +41,6 @@ void customize(std::vector& workflowOptions) {"clusters-from-upstream", o2::framework::VariantType::Bool, false, {"clusters will be provided from upstream, skip clusterizer"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, - {"trackerCA", o2::framework::VariantType::Bool, false, {"use trackerCA (deprecated)"}}, // keep this around to not break scripts - {"trackerCM", o2::framework::VariantType::Bool, false, {"use trackerCM (default: trackerCA)"}}, {"ccdb-meanvertex-seed", o2::framework::VariantType::Bool, false, {"use MeanVertex from CCDB if available to provide beam position seed (default: false)"}}, {"select-with-triggers", o2::framework::VariantType::String, "none", {"use triggers to prescale processed ROFs: phys, trd, none"}}, {"tracking-mode", o2::framework::VariantType::String, "sync", {"sync,async,cosmics,unset,off"}}, @@ -65,7 +63,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // Update the (declared) parameters if changed from the command line auto useMC = !configcontext.options().get("disable-mc"); auto beamPosOVerride = configcontext.options().get("ccdb-meanvertex-seed"); - auto useCMtracker = configcontext.options().get("trackerCM"); auto trmode = configcontext.options().get("tracking-mode"); auto selTrig = configcontext.options().get("select-with-triggers"); auto useGpuWF = configcontext.options().get("use-gpu-workflow"); @@ -90,7 +87,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } } auto wf = o2::its::reco_workflow::getWorkflow(useMC, - useCMtracker, o2::its::TrackingMode::fromString(trmode), beamPosOVerride, extDigits, diff --git a/macro/CMakeLists.txt b/macro/CMakeLists.txt index b5c51e50d3ffb..1c39a96db1b60 100644 --- a/macro/CMakeLists.txt +++ b/macro/CMakeLists.txt @@ -48,7 +48,6 @@ install(FILES CheckDigits_mft.C compareTOFClusters.C run_rawdecoding_its.C run_rawdecoding_mft.C - run_trac_its.C CreateBCPattern.C UploadDummyAlignment.C UploadMatBudLUT.C @@ -336,20 +335,6 @@ o2_add_test_root_macro(CreateCTPOrbitResetObject.C # O2::DataFormatsITSMFT O2::DataFormatsParameters O2::DetectorsBase O2::Field # O2::ITSBase O2::ITStracking O2::MathUtils O2::SimulationDataFormat) -# FIXME: move to subsystem dir -o2_add_test_root_macro(run_trac_its.C - PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats - O2::DataFormatsITSMFT - O2::DataFormatsParameters - O2::DetectorsBase - O2::Field - O2::ITSBase - O2::ITSReconstruction - O2::ITStracking - O2::MathUtils - O2::SimulationDataFormat - LABELS its) - o2_add_test_root_macro(CreateGRPECSObject.C PUBLIC_LINK_LIBRARIES O2::DataFormatsParameters O2::DetectorsCommonDataFormats @@ -463,18 +448,6 @@ o2_add_test_root_macro(getTimeStamp.C # finished succesfully) set_tests_properties(run_clus_its_G3 PROPERTIES DEPENDS # run_digi_its_G3) -# configure_file(${CMAKE_SOURCE_DIR}/macro/run_trac_its.sh -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.sh) -# configure_file(${CMAKE_SOURCE_DIR}/macro/run_trac_its.C -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.C) - -# add_test_wrap(NAME run_trac_its_G3 COMMAND -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.sh 10 TGeant3) -# set_tests_properties(run_trac_its_G3 PROPERTIES TIMEOUT 30) -# set_tests_properties(run_trac_its_G3 PROPERTIES PASS_REGULAR_EXPRESSION Macro -# finished succesfully) set_tests_properties(run_trac_its_G3 PROPERTIES DEPENDS -# run_clus_its_G3) - # #ITS tests with G4 # add_test_wrap(NAME run_sim_its_G4 COMMAND @@ -497,13 +470,6 @@ o2_add_test_root_macro(getTimeStamp.C # finished succesfully) set_tests_properties(run_clus_its_G4 PROPERTIES DEPENDS # run_digi_its_G4) -# add_test_wrap(NAME run_trac_its_G4 COMMAND -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.sh 10 TGeant4) -# set_tests_properties(run_trac_its_G4 PROPERTIES TIMEOUT 30) -# set_tests_properties(run_trac_its_G4 PROPERTIES PASS_REGULAR_EXPRESSION Macro -# finished succesfully) set_tests_properties(run_trac_its_G4 PROPERTIES DEPENDS -# run_clus_its_G4) - # GENERATE_ROOT_TEST_SCRIPT(${CMAKE_SOURCE_DIR}/macro/load_all_libs.C) # add_test_wrap(load_all_libs ${CMAKE_BINARY_DIR}/macro/load_all_libs.sh) # Set_Tests_Properties(load_all_libs PROPERTIES TIMEOUT 30) diff --git a/macro/run_trac_its.C b/macro/run_trac_its.C deleted file mode 100644 index 824e4ebcf5d79..0000000000000 --- a/macro/run_trac_its.C +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include "Framework/Logger.h" -#include "DetectorsCommonDataFormats/DetID.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "Field/MagneticField.h" -#include "ITSBase/GeometryTGeo.h" -#include "ITSReconstruction/CookedTracker.h" -#include "MathUtils/Utils.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CCDBTimeStampUtils.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" - -#include "ReconstructionDataFormats/PrimaryVertex.h" // hack to silence JIT compiler -#include "ITStracking/ROframe.h" -#include "ITStracking/IOUtils.h" -#include "ITStracking/Vertexer.h" -#include "ITStracking/VertexerTraits.h" - -using MCLabCont = o2::dataformats::MCTruthContainer; -using MCLabContTr = std::vector; -using Vertex = o2::dataformats::Vertex>; - -void run_trac_its(std::string path = "./", std::string outputfile = "o2trac_its.root", - std::string inputClustersITS = "o2clus_its.root", - std::string inputGeom = "", - std::string inputGRP = "o2sim_grp.root", - long timestamp = 0) -{ - - // Setup timer - TStopwatch timer; - - if (path.back() != '/') { - path += '/'; - } - - //-------- init geometry and field --------// - const auto grp = o2::parameters::GRPObject::loadFrom(path + inputGRP); - if (!grp) { - LOG(fatal) << "Cannot run w/o GRP object"; - } - bool isITS = grp->isDetReadOut(o2::detectors::DetID::ITS); - if (!isITS) { - LOG(warning) << "ITS is not in the readoute"; - return; - } - bool isContITS = grp->isDetContinuousReadOut(o2::detectors::DetID::ITS); - LOG(info) << "ITS is in " << (isContITS ? "CONTINUOS" : "TRIGGERED") << " readout mode"; - - o2::base::GeometryManager::loadGeometry(inputGeom); - auto gman = o2::its::GeometryTGeo::Instance(); - gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot)); // request cached transforms - - o2::base::Propagator::initFieldFromGRP(grp); - auto field = static_cast(TGeoGlobalMagField::Instance()->GetField()); - if (!field) { - LOG(fatal) << "Failed to load ma"; - } - - auto& mgr = o2::ccdb::BasicCCDBManager::instance(); - mgr.setURL("http://alice-ccdb.cern.ch"); - mgr.setTimestamp(timestamp ? timestamp : o2::ccdb::getCurrentTimestamp()); - const o2::itsmft::TopologyDictionary* dict = mgr.get("ITS/Calib/ClusterDictionary"); - - //>>>---------- attach input data --------------->>> - TChain itsClusters("o2sim"); - itsClusters.AddFile((path + inputClustersITS).data()); - - if (!itsClusters.GetBranch("ITSClusterComp")) { - LOG(fatal) << "Did not find ITS clusters branch ITSClusterComp in the input tree"; - } - std::vector* cclusters = nullptr; - itsClusters.SetBranchAddress("ITSClusterComp", &cclusters); - - if (!itsClusters.GetBranch("ITSClusterPatt")) { - LOG(fatal) << "Did not find ITS cluster patterns branch ITSClusterPatt in the input tree"; - } - std::vector* patterns = nullptr; - itsClusters.SetBranchAddress("ITSClusterPatt", &patterns); - - MCLabCont* labels = nullptr; - if (!itsClusters.GetBranch("ITSClusterMCTruth")) { - LOG(warning) << "Did not find ITS clusters branch ITSClusterMCTruth in the input tree"; - } else { - itsClusters.SetBranchAddress("ITSClusterMCTruth", &labels); - } - - if (!itsClusters.GetBranch("ITSClustersROF")) { - LOG(fatal) << "Did not find ITS clusters branch ITSClustersROF in the input tree"; - } - - std::vector* mc2rofs = nullptr; - if (!itsClusters.GetBranch("ITSClustersMC2ROF")) { - LOG(warning) << "Did not find ITSClustersMC2ROF branch in the input tree"; - } - itsClusters.SetBranchAddress("ITSClustersMC2ROF", &mc2rofs); - - std::vector* rofs = nullptr; - itsClusters.SetBranchAddress("ITSClustersROF", &rofs); - - //>>>--------- create/attach output ------------->>> - // create/attach output tree - TFile outFile((path + outputfile).data(), "recreate"); - TTree outTree("o2sim", "Cooked ITS Tracks"); - std::vector tracksITS, *tracksITSPtr = &tracksITS; - std::vector trackClIdx, *trackClIdxPtr = &trackClIdx; - std::vector vertROFvec, *vertROFvecPtr = &vertROFvec; - std::vector vertices, *verticesPtr = &vertices; - - MCLabContTr trackLabels, *trackLabelsPtr = &trackLabels; - outTree.Branch("ITSTrack", &tracksITSPtr); - outTree.Branch("ITSTrackClusIdx", &trackClIdxPtr); - outTree.Branch("ITSTrackMCTruth", &trackLabelsPtr); - outTree.Branch("ITSTracksROF", &rofs); - outTree.Branch("ITSTracksMC2ROF", &mc2rofs); - outTree.Branch("Vertices", &verticesPtr); - outTree.Branch("VerticesROF", &vertROFvecPtr); - //<<<--------- create/attach output -------------<<< - - //=================== INIT ================== - Int_t n = 1; // Number of threads - Bool_t mcTruth = kTRUE; // kFALSE if no comparison with MC is needed - o2::its::CookedTracker tracker(n); - tracker.setContinuousMode(isContITS); - tracker.setBz(field->solenoidField()); // in kG - tracker.setGeometry(gman); - if (mcTruth) { - tracker.setMCTruthContainers(labels, trackLabelsPtr); - } - //=========================================== - - o2::its::VertexerTraits vertexerTraits; - o2::its::Vertexer vertexer(&vertexerTraits); - - int nTFs = itsClusters.GetEntries(); - for (int nt = 0; nt < nTFs; nt++) { - LOGP(info, "Processing timeframe {}/{}", nt, nTFs); - itsClusters.GetEntry(nt); - o2::its::TimeFrame tf; - gsl::span rofspan(*rofs); - gsl::span patt(*patterns); - - auto pattIt = patt.begin(); - auto pattIt_vertexer = patt.begin(); - auto clSpan = gsl::span(cclusters->data(), cclusters->size()); - std::vector processingMask(rofs->size(), true); - tf.loadROFrameData(rofspan, clSpan, pattIt_vertexer, dict, labels); - tf.setMultiplicityCutMask(processingMask); - vertexer.adoptTimeFrame(tf); - vertexer.clustersToVertices(); - int iRof = 0; - for (auto& rof : *rofs) { - auto it = pattIt; - - auto& vtxROF = vertROFvec.emplace_back(rof); // register entry and number of vertices in the - vtxROF.setFirstEntry(vertices.size()); // dedicated ROFRecord - std::vector>> verticesL; - vtxROF.setNEntries(tf.getPrimaryVertices(iRof).size()); - - for (const auto& vtx : tf.getPrimaryVertices(iRof)) { - vertices.push_back(vtx); - verticesL.push_back(vtx); - } - if (tf.getPrimaryVertices(iRof).empty()) { - verticesL.emplace_back(); - } - tracker.setVertices(verticesL); - tracker.process(clSpan, it, dict, tracksITS, trackClIdx, rof); - ++iRof; - } - outTree.Fill(); - if (mcTruth) { - trackLabelsPtr->clear(); - mc2rofs->clear(); - } - tracksITSPtr->clear(); - trackClIdxPtr->clear(); - rofs->clear(); - verticesPtr->clear(); - vertROFvecPtr->clear(); - } - outFile.cd(); - outTree.Write(); - outFile.Close(); - - timer.Stop(); - timer.Print(); -} - -#endif From 7fedb61e994208495bd780407f4942e5450374a7 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 10 Nov 2025 10:27:16 +0100 Subject: [PATCH 07/13] ITS: remove old ClustererTask Signed-off-by: Felix Schlepper --- .../ITSMFT/ITS/reconstruction/CMakeLists.txt | 6 +- .../include/ITSReconstruction/ClustererTask.h | 85 --------- .../ITS/reconstruction/src/ClustererTask.cxx | 163 ------------------ macro/CMakeLists.txt | 9 - macro/run_clus_itsSA.C | 65 ------- 5 files changed, 2 insertions(+), 326 deletions(-) delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx delete mode 100644 macro/run_clus_itsSA.C diff --git a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt index a5004418599e4..d2126be1da2c6 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt @@ -10,8 +10,7 @@ # or submit itself to any jurisdiction. o2_add_library(ITSReconstruction - SOURCES src/ClustererTask.cxx - src/RecoGeomHelper.cxx + SOURCES src/RecoGeomHelper.cxx src/FastMultEstConfig.cxx src/FastMultEst.cxx PUBLIC_LINK_LIBRARIES O2::ITSBase @@ -21,7 +20,6 @@ o2_add_library(ITSReconstruction o2_target_root_dictionary( ITSReconstruction - HEADERS include/ITSReconstruction/ClustererTask.h - include/ITSReconstruction/RecoGeomHelper.h + HEADERS include/ITSReconstruction/RecoGeomHelper.h include/ITSReconstruction/FastMultEst.h include/ITSReconstruction/FastMultEstConfig.h) diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h deleted file mode 100644 index 16ac9dd63c631..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTask.h -/// \brief Definition of the ITS cluster finder task - -#ifndef ALICEO2_ITS_CLUSTERERTASK -#define ALICEO2_ITS_CLUSTERERTASK - -#include "ITSMFTReconstruction/ChipMappingITS.h" -#include "ITSMFTReconstruction/PixelReader.h" -#include "ITSMFTReconstruction/RawPixelReader.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include -#include - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template -class MCTruthContainer; -} - -namespace its -{ - -class ClustererTask -{ - using Clusterer = o2::itsmft::Clusterer; - using CompCluster = o2::itsmft::CompCluster; - using CompClusterExt = o2::itsmft::CompClusterExt; - using MCTruth = o2::dataformats::MCTruthContainer; - - public: - ClustererTask(bool useMC = true, bool raw = false); - ~ClustererTask(); - - void Init(); - Clusterer& getClusterer() { return mClusterer; } - void run(const std::string inpName, const std::string outName); - o2::itsmft::PixelReader* getReader() const { return (o2::itsmft::PixelReader*)mReader; } - - void writeTree(std::string basename, int i); - void setMaxROframe(int max) { maxROframe = max; } - int getMaxROframe() const { return maxROframe; } - - private: - int maxROframe = std::numeric_limits::max(); ///< maximal number of RO frames per a file - bool mRawDataMode = false; ///< input from raw data or MC digits - bool mUseMCTruth = true; ///< flag to use MCtruth if available - o2::itsmft::PixelReader* mReader = nullptr; ///< Pointer on the relevant Pixel reader - std::unique_ptr mReaderMC; ///< reader for MC data - std::unique_ptr> mReaderRaw; ///< reader for raw data - - Clusterer mClusterer; ///< Cluster finder - - std::vector mCompClus; //!< vector of compact clusters - - std::vector mROFRecVec; //!< vector of ROFRecord references - - MCTruth mClsLabels; //! MC labels - - std::vector mPatterns; - - ClassDefNV(ClustererTask, 2); -}; -} // namespace its -} // namespace o2 - -#endif /* ALICEO2_ITS_CLUSTERERTASK */ diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx deleted file mode 100644 index fb4e4ac7b6fa2..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTask.cxx -/// \brief Implementation of the ITS cluster finder task - -#include "DetectorsCommonDataFormats/DetID.h" -#include "ITSReconstruction/ClustererTask.h" -#include "MathUtils/Cartesian.h" -#include "MathUtils/Utils.h" -#include -#include -#include - -using namespace o2::its; - -//_____________________________________________________________________ -ClustererTask::ClustererTask(bool useMC, bool raw) : mRawDataMode(raw), - mUseMCTruth(useMC && (!raw)) -{ - LOG(info) << Class()->GetName() << ": MC digits mode: " << (mRawDataMode ? "OFF" : "ON") - << " | Use MCtruth: " << (mUseMCTruth ? "ON" : "OFF"); - - mClusterer.setNChips(o2::itsmft::ChipMappingITS::getNChips()); -} - -//_____________________________________________________________________ -ClustererTask::~ClustererTask() -{ - mCompClus.clear(); - mClsLabels.clear(); -} - -//_____________________________________________________________________ -void ClustererTask::Init() -{ - /// Inititializes the clusterer and connects input and output container - - if (mReader) { - return; // already initialized - } - - // create reader according to requested raw of MC mode - if (mRawDataMode) { - mReaderRaw = std::make_unique>(); - mReader = mReaderRaw.get(); - } else { // clusterizer of digits - mReaderMC = std::make_unique(); - mReader = mReaderMC.get(); - } - - mClusterer.print(); - - return; -} - -//_____________________________________________________________________ -void ClustererTask::run(const std::string inpName, const std::string outName) -{ - // standalone execution - Init(); // create reader, clusterer - - if (mRawDataMode) { - - mReaderRaw->openInput(inpName); - mClusterer.process(1, *mReaderRaw.get(), &mCompClus, &mPatterns, &mROFRecVec, nullptr); - - auto basename = outName.substr(0, outName.size() - sizeof("root")); - auto nFiles = int(mROFRecVec.size() / maxROframe); - int i = 0; - for (; i < nFiles; i++) { - writeTree(basename, i); - } - writeTree(basename, i); // The remainder - - } else { - - mReaderMC->openInput(inpName, o2::detectors::DetID("ITS")); - - TFile outFile(outName.data(), "new"); - if (!outFile.IsOpen()) { - LOG(fatal) << "Failed to open output file " << outName; - } - - TTree outTree("o2sim", "ITS Clusters"); - - auto compClusPtr = &mCompClus; - outTree.Branch("ITSClusterComp", &compClusPtr); - - auto rofRecVecPtr = &mROFRecVec; - outTree.Branch("ITSClustersROF", &rofRecVecPtr); - - auto clsLabelsPtr = &mClsLabels; - if (mUseMCTruth && mReaderMC->getDigitsMCTruth()) { - // digit labels are provided directly to clusterer - outTree.Branch("ITSClusterMCTruth", &clsLabelsPtr); - } else { - mUseMCTruth = false; - } - LOG(info) << Class()->GetName() << " | MCTruth: " << (mUseMCTruth ? "ON" : "OFF"); - - outTree.Branch("ITSClusterPatt", &mPatterns); - - std::vector mc2rof, *mc2rofPtr = &mc2rof; - if (mUseMCTruth) { - auto mc2rofOrig = mReaderMC->getMC2ROFRecords(); - mc2rof.reserve(mc2rofOrig.size()); - for (const auto& m2r : mc2rofOrig) { // clone from the span - mc2rof.push_back(m2r); - } - outTree.Branch("ITSClustersMC2ROF", mc2rofPtr); - } - - // loop over entries of the input tree - while (mReaderMC->readNextEntry()) { - mClusterer.process(1, *mReaderMC.get(), &mCompClus, &mPatterns, &mROFRecVec, &mClsLabels); - } - - outTree.Fill(); - outTree.Write(); - } - - mClusterer.clear(); -} - -void ClustererTask::writeTree(std::string basename, int i) -{ - auto name = basename + std::to_string(i) + ".root"; - TFile outFile(name.data(), "new"); - if (!outFile.IsOpen()) { - LOG(fatal) << "Failed to open output file " << name; - } - TTree outTree("o2sim", "ITS Clusters"); - - size_t max = (i + 1) * maxROframe; - auto lastf = (max < mROFRecVec.size()) ? mROFRecVec.begin() + max : mROFRecVec.end(); - std::vector rofRecBuffer(mROFRecVec.begin() + i * maxROframe, lastf); - std::vector* rofRecPtr = &rofRecBuffer; - outTree.Branch("ITSClustersROF", rofRecPtr); - - auto first = rofRecBuffer[0].getFirstEntry(); - auto last = rofRecBuffer.back().getFirstEntry() + rofRecBuffer.back().getNEntries(); - - std::vector compClusBuffer, *compClusPtr = &compClusBuffer; - compClusBuffer.assign(&mCompClus[first], &mCompClus[last]); - outTree.Branch("ITSClusterComp", &compClusPtr); - outTree.Branch("ITSClusterPatt", &mPatterns); - - for (auto& rof : rofRecBuffer) { - rof.setFirstEntry(rof.getFirstEntry() - first); - } - - outTree.Fill(); - outTree.Write(); -} diff --git a/macro/CMakeLists.txt b/macro/CMakeLists.txt index 1c39a96db1b60..0bb5650364b06 100644 --- a/macro/CMakeLists.txt +++ b/macro/CMakeLists.txt @@ -35,7 +35,6 @@ install(FILES CheckDigits_mft.C runTPCRefit.C run_CRUDataSkimming_its.C run_calib_tof.C - run_clus_itsSA.C run_clus_tof.C run_clus_tpc.C run_clus_emcal.C @@ -243,14 +242,6 @@ o2_add_test_root_macro(run_calib_tof.C O2::DetectorsBase O2::GlobalTracking) -# FIXME: move to subsystem dir -o2_add_test_root_macro(run_clus_itsSA.C - PUBLIC_LINK_LIBRARIES O2::DetectorsBase - O2::ITSReconstruction - O2::ITSMFTReconstruction - O2::ITSMFTBase - LABELS its) - # FIXME: move to subsystem dir o2_add_test_root_macro(run_clus_tof.C PUBLIC_LINK_LIBRARIES O2::TOFReconstruction O2::Framework O2::TOFBase diff --git a/macro/run_clus_itsSA.C b/macro/run_clus_itsSA.C deleted file mode 100644 index a96cd66d5eeec..0000000000000 --- a/macro/run_clus_itsSA.C +++ /dev/null @@ -1,65 +0,0 @@ -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include -#include "DetectorsBase/GeometryManager.h" -#include "ITSReconstruction/ClustererTask.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "CommonConstants/LHCConstants.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CCDBTimeStampUtils.h" -#endif - -// Clusterization avoiding FairRunAna management. -// Works both with MC digits and with "raw" data (in this case the last argument must be -// set to true). The raw data should be prepared beforeahand from the MC digits using e.g. -// o2::itsmft::RawPixelReader reader; -// reader.convertDigits2Raw("dig.raw","o2dig.root","o2sim","ITSDigit"); -// -// Use for MC mode: -// root -b -q run_clus_itsSA.C+\(\"o2clus_its.root\",\"o2dig.root\"\) 2>&1 | tee clusSA.log -// -// Use for RAW mode: -// root -b -q run_clus_itsSA.C+\(\"o2clus_its.root\",\"dig.raw\"\) 2>&1 | tee clusSARAW.log -// - -void run_clus_itsSA(std::string inputfile = "rawits.bin", // input file name - std::string outputfile = "clr.root", // output file name (root or raw) - bool raw = true, // flag if this is raw data - int strobeBC = -1, // strobe length in BC for masking, if <0, get automatically (assume cont. readout) - long timestamp = 0, - bool withPatterns = true) -{ - // Initialize logger - FairLogger* logger = FairLogger::GetLogger(); - logger->SetLogVerbosityLevel("LOW"); - logger->SetLogScreenLevel("INFO"); - - auto& mgr = o2::ccdb::BasicCCDBManager::instance(); - mgr.setURL("http://alice-ccdb.cern.ch"); - mgr.setTimestamp(timestamp ? timestamp : o2::ccdb::getCurrentTimestamp()); - const o2::itsmft::TopologyDictionary* dict = mgr.get("ITS/Calib/ClusterDictionary"); - - TStopwatch timer; - - // Setup clusterizer - Bool_t useMCTruth = kTRUE; // kFALSE if no comparison with MC needed - o2::its::ClustererTask* clus = new o2::its::ClustererTask(useMCTruth, raw); - clus->setMaxROframe(2 << 21); // about 3 cluster files per a raw data chunk - clus->getClusterer().setDictionary(dict); - - // Mask fired pixels separated by <= this number of BCs (for overflow pixels). - // In continuos mode strobe lenght should be used, in triggered one: signal shaping time (~7mus) - if (strobeBC < 0) { - const auto& dgParams = o2::itsmft::DPLAlpideParam::Instance(); - strobeBC = dgParams.roFrameLengthInBC; - } - clus->getClusterer().setMaxBCSeparationToMask(strobeBC + 10); - - clus->getClusterer().print(); - clus->run(inputfile, outputfile); - - timer.Stop(); - timer.Print(); -} From 572220596da32374c0660dac921c993b46170e03 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 11 Jul 2025 14:01:38 +0200 Subject: [PATCH 08/13] ITSMFT: staggered digitization Signed-off-by: Felix Schlepper --- .../Detectors/ITSMFT/common/src/ROFRecord.cxx | 14 +- .../ITS/base/include/ITSBase/GeometryTGeo.h | 8 +- .../MFT/base/include/MFTBase/GeometryTGeo.h | 6 +- .../base/include/ITSMFTBase/DPLAlpideParam.h | 42 +- .../base/include/ITSMFTBase/GeometryTGeo.h | 5 +- .../include/ITSMFTSimulation/DigiParams.h | 45 +- .../include/ITSMFTSimulation/Digitizer.h | 24 +- .../common/simulation/src/DigiParams.cxx | 44 +- .../common/simulation/src/Digitizer.cxx | 107 ++--- .../include/ITSMFTWorkflow/DigitReaderSpec.h | 53 +-- .../common/workflow/src/DigitReaderSpec.cxx | 221 +++++----- .../common/workflow/src/DigitWriterSpec.cxx | 81 ++-- .../src/ITSMFTDigitizerSpec.cxx | 405 ++++++++++-------- 13 files changed, 606 insertions(+), 449 deletions(-) diff --git a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx index 83b46f8798fc9..8dbde0d580efc 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx @@ -9,20 +9,22 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DataFormatsITSMFT/ROFRecord.h" #include -#include "fmt/format.h" +#include + +#include "DataFormatsITSMFT/ROFRecord.h" +#include "Framework/Logger.h" using namespace o2::itsmft; std::string ROFRecord::asString() const { - return fmt::format("ROF: {} | {} entries starting from {}", mROFrame, getNEntries(), getFirstEntry()); + return std::format("ROF: {} | {} entries starting from {} | IR: {}", mROFrame, getNEntries(), getFirstEntry(), mBCData.asString()); } void ROFRecord::print() const { - std::cout << this << "\n\t" << mBCData << std::endl; + LOG(info) << asString(); } std::ostream& operator<<(std::ostream& stream, ROFRecord const& rec) @@ -33,12 +35,12 @@ std::ostream& operator<<(std::ostream& stream, ROFRecord const& rec) std::string MC2ROFRecord::asString() const { - return fmt::format("MCEventID: {} ROFs: {}-{} Entry in ROFRecords: {}", eventRecordID, minROF, maxROF, rofRecordID); + return std::format("MCEventID: {} ROFs: {}-{} Entry in ROFRecords: {}", eventRecordID, minROF, maxROF, rofRecordID); } void MC2ROFRecord::print() const { - std::cout << this << std::endl; + LOG(info) << asString(); } std::ostream& operator<<(std::ostream& stream, MC2ROFRecord const& rec) diff --git a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h index 934c927ac3059..e236c898851f5 100644 --- a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h @@ -176,7 +176,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo bool getChipId(int index, int& lay, int& hba, int& sta, int& ssta, int& mod, int& chip) const; /// Get chip layer, from 0 - int getLayer(int index) const; + int getLayer(int index) const final; /// Get chip half barrel, from 0 int getHalfBarrel(int index) const; @@ -216,7 +216,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo return getSymbolicName(getChipIndex(lay, hba, sta, det)); } - /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by quering the TGeoManager + /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by querying the TGeoManager TGeoHMatrix* getMatrix(int index) const { return o2::base::GeometryManager::getMatrix(getDetID(), index); } TGeoHMatrix* getMatrix(int lay, int hba, int sta, int sens) const { return getMatrix(getChipIndex(lay, hba, sta, sens)); } bool getOriginalMatrix(int index, TGeoHMatrix& m) const @@ -336,7 +336,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo TString getMatrixPath(int index) const; /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) - /// for a given chip 'index' by quering the TGeoManager + /// for a given chip 'index' by querying the TGeoManager TGeoHMatrix* extractMatrixSensor(int index) const; // create matrix for transformation from sensor local frame to global one @@ -407,7 +407,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo std::vector mNumberOfChipsPerStave; ///< number of chips per stave std::vector mNumberOfChipsPerHalfBarrel; ///< number of chips per halfbarrel std::vector mNumberOfChipsPerLayer; ///< number of chips per stave - std::vector mLastChipIndex; ///< max ID of the detctor in the layer + std::vector mLastChipIndex; ///< max ID of the detector in the layer std::array mIsLayerITS3; ///< flag with the information of the ITS version (ITS2 or ITS3) std::array mLayerToWrapper; ///< Layer to wrapper correspondence diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h index 503e8332c4cf5..20b5407d614c5 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h @@ -95,7 +95,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo Int_t getSensorIndex(Int_t half, Int_t disk, Int_t ladder, Int_t sensor) const; /// get layer index (0:9) from the chip index - Int_t getLayer(Int_t index) const; + Int_t getLayer(Int_t index) const final; /// This routine computes the half, disk, ladder and sensor number /// given the sensor index number @@ -122,7 +122,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo { return extractNumberOfDisks(half); } - /// Returns the number of halfs MFT + /// Returns the number of halves MFT Int_t getNumberOfHalfs() { return extractNumberOfHalves(); @@ -181,7 +181,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo Int_t extractVolumeCopy(const Char_t* name, const Char_t* prefix) const; /// Get the transformation matrix of the sensor [...] - /// for a given sensor 'index' by quering the TGeoManager + /// for a given sensor 'index' by querying the TGeoManager TGeoHMatrix* extractMatrixSensor(Int_t index) const; // Create matrix for transformation from sensor local frame to global one diff --git a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h index bc3b3dbde53b0..7ad4abce4c675 100644 --- a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h +++ b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h @@ -26,17 +26,45 @@ constexpr float DEFStrobeDelay = o2::constants::lhc::LHCBunchSpacingNS * 4; // ~ template struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper> { + static constexpr int getNLayers() + { + return N == o2::detectors::DetID::ITS ? 7 : 10; + } static constexpr std::string_view getParamName() { return N == o2::detectors::DetID::ITS ? ParamName[0] : ParamName[1]; } - int roFrameLengthInBC = DEFROFLengthBC(); ///< ROF length in BC for continuos mode - float roFrameLengthTrig = DEFROFLengthTrig(); ///< length of RO frame in ns for triggered mode - float strobeDelay = DEFStrobeDelay; ///< strobe start (in ns) wrt ROF start - float strobeLengthCont = -1.; ///< if < 0, full ROF length - delay - float strobeLengthTrig = 100.; ///< length of the strobe in ns (sig. over threshold checked in this window only) - int roFrameBiasInBC = DEFROFBiasInBC(); ///< bias of the start of ROF wrt orbit start: t_irof = (irof*roFrameLengthInBC + roFrameBiasInBC)*BClengthMUS + + public: + int roFrameLengthInBC = DEFROFLengthBC(); ///< ROF length in BC for continuous mode + float roFrameLengthTrig = DEFROFLengthTrig(); ///< length of RO frame in ns for triggered mode + float strobeDelay = DEFStrobeDelay; ///< strobe start (in ns) wrt ROF start + float strobeLengthCont = -1.; ///< if < 0, full ROF length - delay + float strobeLengthTrig = 100.; ///< length of the strobe in ns (sig. over threshold checked in this window only) + int roFrameBiasInBC = DEFROFBiasInBC(); ///< bias of the start of ROF wrt orbit start: t_irof = (irof*roFrameLengthInBC + roFrameBiasInBC)*BClengthMUS + int roFrameLayerLengthInBC[getNLayers()] = {}; ///< staggering ROF length in BC for continuous mode per layer + int roFrameLayerBiasInBC[getNLayers()] = {}; ///< staggering ROF bias in BC for continuous mode per layer + int roFrameLayerDelayInBC[getNLayers()] = {}; ///< staggering ROF delay in BC for continuous mode per layer + + static constexpr bool supportsStaggering() noexcept { return (N == o2::detectors::DetID::ITS) ? true : false; } + // test if staggering is on + bool withStaggering() const noexcept + { + if constexpr (!supportsStaggering()) { + return false; + } + for (int i{0}; i < getNLayers(); ++i) { + if (roFrameLayerLengthInBC[i] != 0) { + return true; + } + } + return false; + } + // get ROF length for any layer + int getROFLengthInBC(int layer) const noexcept { return (withStaggering()) ? roFrameLayerLengthInBC[layer] : roFrameLengthInBC; } + int getROFBiasInBC(int layer) const noexcept { return (withStaggering()) ? roFrameLayerBiasInBC[layer] : roFrameBiasInBC; } + int getROFDelayInBC(int layer) const noexcept { return (withStaggering()) ? roFrameLayerDelayInBC[layer] : 0; } // boilerplate stuff + make principal key O2ParamDef(DPLAlpideParam, getParamName().data()); @@ -46,7 +74,7 @@ struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper +#include #include -#include +#include "ITSMFTSimulation/AlpideSignalTrapezoid.h" #include "ITSMFTBase/DPLAlpideParam.h" //////////////////////////////////////////////////////////// @@ -51,24 +53,24 @@ class DigiParams void setContinuous(bool v) { mIsContinuous = v; } bool isContinuous() const { return mIsContinuous; } - int getROFrameLengthInBC() const { return mROFrameLengthInBC; } - void setROFrameLengthInBC(int n) { mROFrameLengthInBC = n; } + int getROFrameLengthInBC(int layer = -1) const { return layer < 0 ? mROFrameLengthInBC : mROFrameLayerLengthInBC[layer]; } + void setROFrameLengthInBC(int n, int layer = -1) { layer < 0 ? mROFrameLengthInBC = n : mROFrameLayerLengthInBC[layer] = n; } - void setROFrameLength(float ns); - float getROFrameLength() const { return mROFrameLength; } - float getROFrameLengthInv() const { return mROFrameLengthInv; } + void setROFrameLength(float ns, int layer = -1); + float getROFrameLength(int layer = -1) const { return layer < 0 ? mROFrameLength : mROFrameLayerLength[layer]; } + float getROFrameLengthInv(int layer = -1) const { return layer < 0 ? mROFrameLengthInv : mROFrameLayerLengthInv[layer]; } void setStrobeDelay(float ns) { mStrobeDelay = ns; } - float getStrobeDelay() const { return mStrobeDelay; } + float getStrobeDelay(int layer = -1) const { return layer < 0 ? mStrobeDelay : mStrobeLayerDelay[layer]; } void setStrobeLength(float ns) { mStrobeLength = ns; } - float getStrobeLength() const { return mStrobeLength; } + float getStrobeLength(int layer = -1) const { return layer < 0 ? mStrobeLength : mStrobeLayerLength[layer]; } void setTimeOffset(double sec) { mTimeOffset = sec; } double getTimeOffset() const { return mTimeOffset; } - void setROFrameBiasInBC(int n) { mROFrameBiasInBC = n; } - int getROFrameBiasInBC() const { return mROFrameBiasInBC; } + void setROFrameBiasInBC(int n, int layer = -1) { layer < 0 ? mROFrameBiasInBC = n : mROFrameLayerBiasInBC[layer] = n; } + int getROFrameBiasInBC(int layer = -1) const { return layer < 0 ? mROFrameBiasInBC : mROFrameLayerBiasInBC[layer]; } void setChargeThreshold(int v, float frac2Account = 0.1); void setNSimSteps(int v); @@ -96,13 +98,19 @@ class DigiParams const SignalShape& getSignalShape() const { return mSignalShape; } SignalShape& getSignalShape() { return (SignalShape&)mSignalShape; } + bool withStaggering() const noexcept { return !mROFrameLayerLength.empty(); } + void addROFrameLayerLengthInBC(int len) { mROFrameLayerLengthInBC.push_back(len); } + void addROFrameLayerBiasInBC(int len) { mROFrameLayerBiasInBC.push_back(len); } + void addStrobeLength(float ns) { mStrobeLayerLength.push_back(ns); } + void addStrobeDelay(float ns) { mStrobeLayerDelay.push_back(ns); } + virtual void print() const; private: static constexpr double infTime = 1e99; bool mIsContinuous = false; ///< flag for continuous simulation float mNoisePerPixel = 1.e-8; ///< ALPIDE Noise per chip - int mROFrameLengthInBC = 0; ///< ROF length in BC for continuos mode + int mROFrameLengthInBC = 0; ///< ROF length in BC for continuous mode float mROFrameLength = 0; ///< length of RO frame in ns float mStrobeDelay = 0.; ///< strobe start (in ns) wrt ROF start float mStrobeLength = 0; ///< length of the strobe in ns (sig. over threshold checked in this window only) @@ -115,17 +123,24 @@ class DigiParams float mVbb = 0.0; ///< back bias absolute value for MFT (in Volt) float mIBVbb = 0.0; ///< back bias absolute value for ITS Inner Barrel (in Volt) - float mOBVbb = 0.0; ///< back bias absolute value for ITS Outter Barrel (in Volt) + float mOBVbb = 0.0; ///< back bias absolute value for ITS Outer Barrel (in Volt) + + std::vector mROFrameLayerLengthInBC; ///< staggering ROF length in BC for continuous mode per layer + std::vector mROFrameLayerBiasInBC; ///< staggering ROF bias in BC for continuous mode per layer + std::vector mROFrameLayerLength; ///< staggering ROF length in ns for continuous mode per layer + std::vector mStrobeLayerLength; ///< staggering length of the strobe in ns (sig. over threshold checked in this window only) + std::vector mStrobeLayerDelay; ///< staggering delay of the strobe in ns o2::itsmft::AlpideSignalTrapezoid mSignalShape; ///< signal timeshape parameterization const o2::itsmft::AlpideSimResponse* mAlpSimResponse = nullptr; //!< pointer on external response // auxiliary precalculated parameters - float mROFrameLengthInv = 0; ///< inverse length of RO frame in ns - float mNSimStepsInv = 0; ///< its inverse + float mROFrameLengthInv = 0; ///< inverse length of RO frame in ns + std::vector mROFrameLayerLengthInv; // inverse length of RO frame in ns per layer + float mNSimStepsInv = 0; ///< its inverse - ClassDef(DigiParams, 2); + ClassDef(DigiParams, 3); }; } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h index e3995068c52cf..4c4c41d9a04a5 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h @@ -49,6 +49,8 @@ class Digitizer : public TObject public: Digitizer() = default; + Digitizer(Digitizer&&) = delete; + Digitizer& operator=(Digitizer&&) = delete; ~Digitizer() override = default; Digitizer(const Digitizer&) = delete; Digitizer& operator=(const Digitizer&) = delete; @@ -56,7 +58,7 @@ class Digitizer : public TObject void setDigits(std::vector* dig) { mDigits = dig; } void setMCLabels(o2::dataformats::MCTruthContainer* mclb) { mMCLabels = mclb; } void setROFRecords(std::vector* rec) { mROFRecords = rec; } - o2::itsmft::DigiParams& getParams() { return (o2::itsmft::DigiParams&)mParams; } + o2::itsmft::DigiParams& getParams() { return mParams; } const o2::itsmft::DigiParams& getParams() const { return mParams; } void setNoiseMap(const o2::itsmft::NoiseMap* mp) { mNoiseMap = mp; } void setDeadChannelsMap(const o2::itsmft::NoiseMap* mp) { mDeadChanMap = mp; } @@ -66,17 +68,17 @@ class Digitizer : public TObject auto getChipResponse(int chipID); /// Steer conversion of hits to digits - void process(const std::vector* hits, int evID, int srcID); - void setEventTime(const o2::InteractionTimeRecord& irt); + void process(const std::vector* hits, int evID, int srcID, int layer = -1); + void setEventTime(const o2::InteractionTimeRecord& irt, int layer = -1); double getEndTimeOfROFMax() const { ///< return the time corresponding to end of the last reserved ROFrame : mROFrameMax - return mParams.getROFrameLength() * (mROFrameMax + 1) + mParams.getTimeOffset(); + return (mParams.getROFrameLength() * (double)(mROFrameMax + 1)) + mParams.getTimeOffset(); } void setContinuous(bool v) { mParams.setContinuous(v); } bool isContinuous() const { return mParams.isContinuous(); } - void fillOutputContainer(uint32_t maxFrame = 0xffffffff); + void fillOutputContainer(uint32_t maxFrame = 0xffffffff, int layer = -1); void setDigiParams(const o2::itsmft::DigiParams& par) { mParams = par; } const o2::itsmft::DigiParams& getDigitParams() const { return mParams; } @@ -91,11 +93,17 @@ class Digitizer : public TObject mEventROFrameMin = 0xffffffff; mEventROFrameMax = 0; } + void resetROFrameBounds() + { + mROFrameMin = 0; + mROFrameMax = 0; + mNewROFrame = 0; + } private: - void processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID); + void processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID, int lay); void registerDigits(ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, - uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl); + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl, int lay); ExtraDig* getExtraDigBuffer(uint32_t roFrame) { @@ -114,7 +122,7 @@ class Digitizer : public TObject o2::itsmft::DigiParams mParams; ///< digitization parameters o2::InteractionTimeRecord mEventTime; ///< global event time and interaction record o2::InteractionRecord mIRFirstSampledTF; ///< IR of the 1st sampled IR, noise-only ROFs will be inserted till this IR only - double mCollisionTimeWrtROF; + double mCollisionTimeWrtROF{}; uint32_t mROFrameMin = 0; ///< lowest RO frame of current digits uint32_t mROFrameMax = 0; ///< highest RO frame of current digits uint32_t mNewROFrame = 0; ///< ROFrame corresponding to provided time diff --git a/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx b/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx index ffba627265cc7..a7c5c32b6351d 100644 --- a/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx +++ b/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx @@ -26,12 +26,17 @@ DigiParams::DigiParams() setNSimSteps(mNSimSteps); } -void DigiParams::setROFrameLength(float lNS) +void DigiParams::setROFrameLength(float lNS, int layer) { // set ROFrame length in nanosecongs - mROFrameLength = lNS; - assert(mROFrameLength > 1.); - mROFrameLengthInv = 1. / mROFrameLength; + assert(lNS > 1.f); + if (layer < 0) { + mROFrameLength = lNS; + mROFrameLengthInv = 1.f / mROFrameLength; + } else { + mROFrameLayerLength.push_back(lNS); + mROFrameLayerLengthInv.push_back(1.f / lNS); + } } void DigiParams::setNSimSteps(int v) @@ -58,17 +63,24 @@ void DigiParams::setChargeThreshold(int v, float frac2Account) //______________________________________________ void DigiParams::print() const { - // print settings - printf("Alpide digitization params:\n"); - printf("Continuous readout : %s\n", mIsContinuous ? "ON" : "OFF"); - printf("Readout Frame Length(ns) : %f\n", mROFrameLength); - printf("Strobe delay (ns) : %f\n", mStrobeDelay); - printf("Strobe length (ns) : %f\n", mStrobeLength); - printf("Threshold (N electrons) : %d\n", mChargeThreshold); - printf("Min N electrons to account : %d\n", mMinChargeToAccount); - printf("Number of charge sharing steps : %d\n", mNSimSteps); - printf("ELoss to N electrons factor : %e\n", mEnergyToNElectrons); - printf("Noise level per pixel : %e\n", mNoisePerPixel); - printf("Charge time-response:\n"); + LOGF(info, "Alpide digitization params:"); + LOGF(info, "Continuous readout : %s", mIsContinuous ? "ON" : "OFF"); + if (withStaggering()) { + for (int i{0}; i < (int)mROFrameLayerLengthInBC.size(); ++i) { + LOGF(info, " Readout Frame Layer:%d Length(ns)[BC] : %f [%d]", i, mROFrameLayerLength[i], mROFrameLayerLengthInBC[i]); + LOGF(info, "Strobe delay Layer %d (ns) : %f", i, mStrobeDelay); + LOGF(info, "Strobe length Layer %d (ns) : %f", i, mStrobeLength); + } + } else { + LOGF(info, "Readout Frame Length(ns) : %f", mROFrameLength); + LOGF(info, "Strobe delay (ns) : %f", mStrobeDelay); + LOGF(info, "Strobe length (ns) : %f", mStrobeLength); + } + LOGF(info, "Threshold (N electrons) : %d", mChargeThreshold); + LOGF(info, "Min N electrons to account : %d", mMinChargeToAccount); + LOGF(info, "Number of charge sharing steps : %d", mNSimSteps); + LOGF(info, "ELoss to N electrons factor : %e", mEnergyToNElectrons); + LOGF(info, "Noise level per pixel : %e", mNoisePerPixel); + LOGF(info, "Charge time-response:"); mSignalShape.print(); } diff --git a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx index e5dd35e6a084d..6b2e0a3b8c9c1 100644 --- a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx +++ b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx @@ -13,6 +13,7 @@ /// \brief Implementation of the ITS/MFT digitizer #include "DataFormatsITSMFT/Digit.h" +#include "Framework/Logger.h" #include "ITSMFTBase/SegmentationAlpide.h" #include "ITSMFTSimulation/DPLDigitizerParam.h" #include "ITSMFTSimulation/Digitizer.h" @@ -21,10 +22,11 @@ #include "DetectorsRaw/HBFUtils.h" #include +#include #include #include +#include #include -#include // for LOG using o2::itsmft::Digit; using o2::itsmft::Hit; @@ -48,10 +50,6 @@ void Digitizer::init() mChips[i].setDeadChanMap(mDeadChanMap); } } - // initializing for both collection tables - /*for (int i = 0; i < 2; i++) { - mAlpSimResp[i].initData(i); - }*/ // importing the charge collection tables // (initialized while building O2) @@ -59,11 +57,6 @@ void Digitizer::init() if (!file) { LOG(fatal) << "Cannot open response file " << mResponseFile; } - /*std::string response = "response"; - for (int i=0; i<2; i++) { - response.append(std::to_string(i)); - mAlpSimResp[i] = *(o2::itsmft::AlpideSimResponse*)file->Get(response.data()); - }*/ mAlpSimResp[0] = *(o2::itsmft::AlpideSimResponse*)file->Get("response0"); mAlpSimResp[1] = *(o2::itsmft::AlpideSimResponse*)file->Get("response1"); @@ -91,14 +84,14 @@ void Digitizer::init() } else { LOG(fatal) << "Invalid ITS Inner Barrel back-bias value"; } - if (doptITS.OBVbb == 0.0) { // for ITS Outter Barrel + if (doptITS.OBVbb == 0.0) { // for ITS Outer Barrel mAlpSimRespOB = mAlpSimResp; LOG(info) << "Choosing Vbb=0V for ITS OB"; } else if (doptITS.OBVbb == 3.0) { mAlpSimRespOB = mAlpSimResp + 1; LOG(info) << "Choosing Vbb=-3V for ITS OB"; } else { - LOG(fatal) << "Invalid ITS Outter Barrel back-bias value"; + LOG(fatal) << "Invalid ITS Outer Barrel back-bias value"; } mParams.print(); mIRFirstSampledTF = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); @@ -116,47 +109,53 @@ auto Digitizer::getChipResponse(int chipID) if (chipID < 432) { // in ITS Inner Barrel return mAlpSimRespIB; - } else { // in ITS Outter Barrel + } else { // in ITS Outer Barrel return mAlpSimRespOB; } } //_______________________________________________________________________ -void Digitizer::process(const std::vector* hits, int evID, int srcID) +void Digitizer::process(const std::vector* hits, int evID, int srcID, int layer) { // digitize single event, the time must have been set beforehand + // opt. apply a filter on the layer of the processed hits - LOG(info) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " + LOG(info) << "Digitizing " << mGeometry->getName() << ":" << layer << " hits of entry " << evID << " from source " << srcID << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" << " cont.mode: " << isContinuous() << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; // is there something to flush ? if (mNewROFrame > mROFrameMin) { - fillOutputContainer(mNewROFrame - 1); // flush out all frame preceding the new one + fillOutputContainer(mNewROFrame - 1, layer); // flush out all frame preceding the new one } int nHits = hits->size(); std::vector hitIdx(nHits); std::iota(std::begin(hitIdx), std::end(hitIdx), 0); // sort hits to improve memory access - std::sort(hitIdx.begin(), hitIdx.end(), - [hits](auto lhs, auto rhs) { - return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); - }); - for (int i : hitIdx) { - processHit((*hits)[i], mROFrameMax, evID, srcID); + std::sort(hitIdx.begin(), hitIdx.end(), [hits](auto lhs, auto rhs) { + return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); + }); + for (int i : hitIdx | std::views::filter([&](int idx) { + if (layer < 0) { + return true; + } + return mGeometry->getLayer((*hits)[idx].GetDetectorID()) == layer; + })) { + processHit((*hits)[i], mROFrameMax, evID, srcID, layer); } + // in the triggered mode store digits after every MC event // TODO: in the real triggered mode this will not be needed, this is actually for the // single event processing only if (!mParams.isContinuous()) { - fillOutputContainer(mROFrameMax); + fillOutputContainer(mROFrameMax, layer); } } //_______________________________________________________________________ -void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) +void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt, int layer) { // assign event time in ns mEventTime = irt; @@ -179,13 +178,13 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) // this event is before the first RO mIsBeforeFirstRO = true; } else { - mNewROFrame = nbc / mParams.getROFrameLengthInBC(); + mNewROFrame = nbc / mParams.getROFrameLengthInBC(layer); mIsBeforeFirstRO = false; } LOG(info) << " NewROFrame " << mNewROFrame << " nbc " << nbc; // in continuous mode depends on starts of periodic readout frame - mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; + mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC(layer)) * o2::constants::lhc::LHCBunchSpacingNS; } else { mNewROFrame = 0; } @@ -201,16 +200,14 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) } //_______________________________________________________________________ -void Digitizer::fillOutputContainer(uint32_t frameLast) +void Digitizer::fillOutputContainer(uint32_t frameLast, int layer) { // fill output with digits from min.cached up to requested frame, generating the noise beforehand - if (frameLast > mROFrameMax) { - frameLast = mROFrameMax; - } + frameLast = std::min(frameLast, mROFrameMax); // make sure all buffers for extra digits are created up to the maxFrame getExtraDigBuffer(mROFrameMax); - LOG(info) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":" + LOG(info) << "Filling " << mGeometry->getName() << " digits:" << layer << " output for RO frames " << mROFrameMin << ":" << frameLast; o2::itsmft::ROFRecord rcROF; @@ -222,7 +219,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) auto& extra = *(mExtraBuff.front().get()); for (auto& chip : mChips) { - if (chip.isDisabled()) { + if (chip.isDisabled() || (layer >= 0 && mGeometry->getLayer(chip.getChipIndex()) != layer)) { continue; } chip.addNoise(mROFrameMin, mROFrameMin, &mParams); @@ -254,7 +251,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) // finalize ROF record rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits if (isContinuous()) { - rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC()); + rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC(layer)); } else { rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay? } @@ -269,7 +266,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) } //_______________________________________________________________________ -void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID) +void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID, int lay) { // convert single hit to digits auto chipID = hit.GetDetectorID(); @@ -302,14 +299,12 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID } float tTot = mParams.getSignalShape().getMaxDuration(); // frame of the hit signal start wrt event ROFrame - int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv()); + int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv(lay)); // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame - uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel; + uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv(lay) : roFrameRel; int nFrames = roFrameRelMax + 1 - roFrameRel; uint32_t roFrameMax = mNewROFrame + roFrameRelMax; - if (roFrameMax > maxFr) { - maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter - } + maxFr = std::max(roFrameMax, maxFr); // if signal extends beyond current maxFrame, increase the latter // here we start stepping in the depth of the sensor to generate charge diffusion float nStepsInv = mParams.getNSimStepsInv(); @@ -350,17 +345,13 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID } rowS -= AlpideRespSimMat::NPix / 2; rowE += AlpideRespSimMat::NPix / 2; - if (rowS < 0) { - rowS = 0; - } + rowS = std::max(rowS, 0); if (rowE >= Segmentation::NRows) { rowE = Segmentation::NRows - 1; } colS -= AlpideRespSimMat::NPix / 2; colE += AlpideRespSimMat::NPix / 2; - if (colS < 0) { - colS = 0; - } + colS = std::max(colS, 0); if (colE >= Segmentation::NCols) { colE = Segmentation::NCols - 1; } @@ -380,7 +371,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID const o2::itsmft::AlpideSimResponse* resp = getChipResponse(chipID); - // take into account that the AlpideSimResponse depth defintion has different min/max boundaries + // take into account that the AlpideSimResponse depth definition has different min/max boundaries // although the max should coincide with the surface of the epitaxial layer, which in the chip // local coordinates has Y = +SensorLayerThickness/2 @@ -397,7 +388,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID rowPrev = row; colPrev = col; } - bool flipCol, flipRow; + bool flipCol = false, flipRow = false; // note that response needs coordinates along column row (locX) (locZ) then depth (locY) auto rspmat = resp->getResponse(xyzLocS.X() - cRowPix, xyzLocS.Z() - cColPix, xyzLocS.Y(), flipRow, flipCol); @@ -407,12 +398,12 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID } for (int irow = AlpideRespSimMat::NPix; irow--;) { - int rowDest = row + irow - AlpideRespSimMat::NPix / 2 - rowS; // destination row in the respMatrix + int rowDest = row + irow - (AlpideRespSimMat::NPix / 2) - rowS; // destination row in the respMatrix if (rowDest < 0 || rowDest >= rowSpan) { continue; } for (int icol = AlpideRespSimMat::NPix; icol--;) { - int colDest = col + icol - AlpideRespSimMat::NPix / 2 - colS; // destination column in the respMatrix + int colDest = col + icol - (AlpideRespSimMat::NPix / 2) - colS; // destination column in the respMatrix if (colDest < 0 || colDest >= colSpan) { continue; } @@ -444,35 +435,31 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID continue; } // - registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl); + registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl, lay); } } } //________________________________________________________________________________ void Digitizer::registerDigits(ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, - uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl) + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl, int lay) { // Register digits for given pixel, accounting for the possible signal contribution to // multiple ROFrame. The signal starts at time tInROF wrt the start of provided roFrame // In every ROFrame we check the collected signal during strobe - float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start + float tStrobe = mParams.getStrobeDelay(lay) - tInROF; // strobe start wrt signal start for (int i = 0; i < nROF; i++) { uint32_t roFr = roFrame + i; - int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength()); - tStrobe += mParams.getROFrameLength(); // for the next ROF + int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength(lay)); + tStrobe += mParams.getROFrameLength(lay); // for the next ROF // discard too small contributions, they have no chance to produce a digit if (nEleROF < mParams.getMinChargeToAccount()) { continue; } - if (roFr > mEventROFrameMax) { - mEventROFrameMax = roFr; - } - if (roFr < mEventROFrameMin) { - mEventROFrameMin = roFr; - } + mEventROFrameMax = std::max(roFr, mEventROFrameMax); + mEventROFrameMin = std::min(roFr, mEventROFrameMin); auto key = chip.getOrderingKey(roFr, row, col); PreDigit* pd = chip.findDigit(key); if (!pd) { diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h index e655e05842d71..3e0f89374ac62 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h @@ -16,6 +16,7 @@ #include "TFile.h" #include "TTree.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/GBTCalibData.h" #include "DataFormatsITSMFT/ROFRecord.h" @@ -34,64 +35,66 @@ namespace o2 namespace itsmft { +template class DigitReader : public Task { public: + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::getNLayers()}; + DigitReader() = delete; - DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib, bool triggerOut); + DigitReader(bool useMC, bool useCalib, bool triggerOut); ~DigitReader() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; protected: void connectTree(const std::string& filename); + template + void setBranchAddress(const std::string& base, Ptr& addr, int layer = -1); + std::string getBranchName(const std::string& base, int index); - std::vector mDigits, *mDigitsPtr = &mDigits; + std::array*, NLayers> mDigits; std::vector mCalib, *mCalibPtr = &mCalib; - std::vector mDigROFRec, *mDigROFRecPtr = &mDigROFRec; - std::vector mDigMC2ROFs, *mDigMC2ROFsPtr = &mDigMC2ROFs; - o2::dataformats::ConstMCTruthContainer mConstLabels; - o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; + std::array*, NLayers> mDigROFRec; + std::array*, NLayers> mDigMC2ROFs; + std::array, NLayers> mConstLabels; + std::array mPLabels; std::unique_ptr mFile; std::unique_ptr mTree; - bool mUseMC = true; // use MC truth - bool mUseCalib = true; // send calib data - bool mTriggerOut = true; // send dummy triggers vector + bool mUseMC = true; // use MC truth + bool mUseCalib = true; // send calib data + bool mTriggerOut = true; // send dummy triggers vector bool mUseIRFrames = false; // selected IRFrames modes int mROFBiasInBC = 0; int mROFLengthInBC = 0; int mNRUs = 0; - std::string mDetName = ""; - std::string mDetNameLC = ""; - std::string mFileName = ""; + std::string mDetName; + std::string mDetNameLC; + std::string mFileName; std::string mDigTreeName = "o2sim"; std::string mDigitBranchName = "Digit"; - std::string mDigROFBranchName = "DigitROF"; + std::string mDigitROFBranchName = "DigitROF"; std::string mCalibBranchName = "Calib"; - std::string mDigtMCTruthBranchName = "DigitMCTruth"; - std::string mDigtMC2ROFBranchName = "DigitMC2ROF"; + std::string mDigitMCTruthBranchName = "DigitMCTruth"; + std::string mDigitMC2ROFBranchName = "DigitMC2ROF"; }; -class ITSDigitReader : public DigitReader +class ITSDigitReader : public DigitReader { public: ITSDigitReader(bool useMC = true, bool useCalib = false, bool useTriggers = true) - : DigitReader(o2::detectors::DetID::ITS, useMC, useCalib, useTriggers) - { - mOrigin = o2::header::gDataOriginITS; - } + : DigitReader(useMC, useCalib, useTriggers) {} }; -class MFTDigitReader : public DigitReader +class MFTDigitReader : public DigitReader { public: MFTDigitReader(bool useMC = true, bool useCalib = false, bool useTriggers = true) - : DigitReader(o2::detectors::DetID::MFT, useMC, useCalib, useTriggers) - { - mOrigin = o2::header::gDataOriginMFT; - } + : DigitReader(useMC, useCalib, useTriggers) {} }; /// create a processor spec diff --git a/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx index 3c7a86fe173d6..3f4ac1fc6768f 100644 --- a/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx @@ -11,6 +11,7 @@ /// @file DigitReaderSpec.cxx +#include #include #include "TTree.h" @@ -39,25 +40,28 @@ namespace o2 namespace itsmft { -DigitReader::DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib, bool triggerOut) +template +DigitReader::DigitReader(bool useMC, bool useCalib, bool triggerOut) : mUseMC(useMC), mUseCalib(useCalib), mTriggerOut(triggerOut), mDetNameLC(mDetName = ID.getName()), mDigTreeName("o2sim") { - assert(id == o2::detectors::DetID::ITS || id == o2::detectors::DetID::MFT); - mDetNameLC = mDetName = id.getName(); - mDigTreeName = "o2sim"; - mDigitBranchName = mDetName + mDigitBranchName; - mDigROFBranchName = mDetName + mDigROFBranchName; + mDigitROFBranchName = mDetName + mDigitROFBranchName; mCalibBranchName = mDetName + mCalibBranchName; - mDigtMCTruthBranchName = mDetName + mDigtMCTruthBranchName; - mDigtMC2ROFBranchName = mDetName + mDigtMC2ROFBranchName; - mTriggerOut = triggerOut; - mUseMC = useMC; - mUseCalib = useCalib; + mDigitMCTruthBranchName = mDetName + mDigitMCTruthBranchName; + mDigitMC2ROFBranchName = mDetName + mDigitMC2ROFBranchName; + std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower); + + for (uint32_t i = 0; i < NLayers; ++i) { + mDigits[i] = nullptr; + mDigROFRec[i] = nullptr; + mDigMC2ROFs[i] = nullptr; + mPLabels[i] = nullptr; + } } -void DigitReader::init(InitContext& ic) +template +void DigitReader::init(InitContext& ic) { mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), ic.options().get((mDetNameLC + "-digit-infile").c_str())); @@ -67,23 +71,23 @@ void DigitReader::init(InitContext& ic) connectTree(mFileName); } -void DigitReader::run(ProcessingContext& pc) +template +void DigitReader::run(ProcessingContext& pc) { const auto& tinfo = pc.services().get(); + const auto& alpideParam = o2::itsmft::DPLAlpideParam::Instance(); if (tinfo.globalRunNumberChanged && mUseIRFrames) { // new run is starting: 1st call // TODO: we have to find a way define CCDBInput for IRFrames mode only using DPL fetcher auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); auto rlim = ccdb.getRunDuration(tinfo.runNumber); long ts = (rlim.first + rlim.second) / 2; - if (mOrigin == o2::header::gDataOriginITS) { + if constexpr (N == o2::detectors::DetID::ITS) { ccdb.getForTimeStamp>("ITS/Config/AlpideParam", ts); - const auto& alpideParam = o2::itsmft::DPLAlpideParam::Instance(); mROFBiasInBC = alpideParam.roFrameBiasInBC; mROFLengthInBC = alpideParam.roFrameLengthInBC; mNRUs = o2::itsmft::ChipMappingITS::getNRUs(); } else { ccdb.getForTimeStamp>("MFT/Config/AlpideParam", ts); - const auto& alpideParam = o2::itsmft::DPLAlpideParam::Instance(); mROFBiasInBC = alpideParam.roFrameBiasInBC; mROFLengthInBC = alpideParam.roFrameLengthInBC; mNRUs = o2::itsmft::ChipMappingMFT::getNRUs(); @@ -93,38 +97,38 @@ void DigitReader::run(ProcessingContext& pc) if (mUseIRFrames) { irFrames = pc.inputs().get>("driverInfo"); } - static o2::dataformats::IOMCTruthContainerView* plabels = nullptr; - if (mUseMC && !plabels) { - mTree->SetBranchAddress(mDigtMCTruthBranchName.c_str(), &plabels); - } + auto ent = mTree->GetReadEntry(); if (!mUseIRFrames) { ent++; assert(ent < mTree->GetEntries()); // this should not happen mTree->GetEntry(ent); - LOG(info) << mDetName << "DigitReader pushes " << mDigROFRec.size() << " ROFRecords, " << mDigits.size() << " digits at entry " << ent; - pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, mDigROFRec); - pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0}, mDigits); + for (uint32_t iLayer = 0; iLayer < NLayers; ++iLayer) { + LOG(info) << mDetName << "DigitReader:" << iLayer << " pushes " << mDigROFRec[iLayer]->size() << " ROFRecords, " << mDigits[iLayer]->size() << " digits at entry " << ent; + pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, *mDigROFRec[iLayer]); + pc.outputs().snapshot(Output{Origin, "DIGITS", iLayer}, *mDigits[iLayer]); + if (mUseMC) { + auto& sharedlabels = pc.outputs().make>(Output{Origin, "DIGITSMCTR", iLayer}); + mPLabels[iLayer]->copyandflatten(sharedlabels); + delete mPLabels[iLayer]; + mPLabels[iLayer] = nullptr; + pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", iLayer}, *mDigMC2ROFs[iLayer]); + } + } if (mUseCalib) { - pc.outputs().snapshot(Output{mOrigin, "GBTCALIB", 0}, mCalib); + pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, mCalib); } if (mTriggerOut) { std::vector dummyTrig; - pc.outputs().snapshot(Output{mOrigin, "PHYSTRIG", 0}, dummyTrig); - } - if (mUseMC) { - auto& sharedlabels = pc.outputs().make>(Output{mOrigin, "DIGITSMCTR", 0}); - plabels->copyandflatten(sharedlabels); - delete plabels; - plabels = nullptr; - pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, mDigMC2ROFs); + pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig); } if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get().endOfStream(); pc.services().get().readyToQuit(QuitRequest::Me); } } else { // need to select particulars IRs range, presumably from the same tree entry + // TODO implement for staggering std::vector digitsSel; std::vector calibSel; std::vector digROFRecSel; @@ -144,33 +148,33 @@ void DigitReader::run(ProcessingContext& pc) // do we need to read a new entry? if (ent > mTree->GetReadEntry()) { if (mUseMC) { - delete plabels; - plabels = nullptr; - mConstLabels.clear(); - mTree->SetBranchAddress(mDigtMCTruthBranchName.c_str(), &plabels); + delete mPLabels[0]; + mPLabels[0] = nullptr; + mConstLabels[0].clear(); + mTree->SetBranchAddress(mDigitMCTruthBranchName.c_str(), &mPLabels[0]); } mTree->GetEntry(ent); if (mUseMC) { - plabels->copyandflatten(mConstLabels); - delete plabels; - plabels = nullptr; + mPLabels[0]->copyandflatten(mConstLabels[0]); + delete mPLabels[0]; + mPLabels[0] = nullptr; } } std::vector rofOld2New; - rofOld2New.resize(mDigROFRec.size(), -1); + rofOld2New.resize(mDigROFRec[0]->size(), -1); - if (mDigROFRec.front().getBCData() <= irMax && (mDigROFRec.back().getBCData() + mROFLengthInBC - 1) >= irMin) { // there is an overlap - for (int irof = 0; irof < (int)mDigROFRec.size(); irof++) { - const auto& rof = mDigROFRec[irof]; + if (mDigROFRec[0]->front().getBCData() <= irMax && (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1) >= irMin) { // there is an overlap + for (int irof = 0; irof < (int)mDigROFRec[0]->size(); irof++) { + const auto& rof = mDigROFRec[0]->at(irof); if (irfSel.check({rof.getBCData(), rof.getBCData() + mROFLengthInBC - 1}) != -1) { rofOld2New[irof] = (int)digROFRecSel.size(); LOGP(debug, "Adding selected ROF {}", rof.getBCData().asString()); digROFRecSel.push_back(rof); int offs = digitsSel.size(); digROFRecSel.back().setFirstEntry(offs); - std::copy(mDigits.begin() + rof.getFirstEntry(), mDigits.begin() + rof.getFirstEntry() + rof.getNEntries(), std::back_inserter(digitsSel)); + std::copy(mDigits[0]->begin() + rof.getFirstEntry(), mDigits[0]->begin() + rof.getFirstEntry() + rof.getNEntries(), std::back_inserter(digitsSel)); for (int id = 0; id < rof.getNEntries(); id++) { // copy MC info - digitLabelsSel.addElements(id + offs, mConstLabels.getLabels(id + rof.getFirstEntry())); + digitLabelsSel.addElements(id + offs, mConstLabels[0].getLabels(id + rof.getFirstEntry())); } if (mCalib.size() >= size_t((irof + 1) * mNRUs)) { std::copy(mCalib.begin() + irof * mNRUs, mCalib.begin() + (irof + 1) * mNRUs, std::back_inserter(calibSel)); @@ -179,7 +183,7 @@ void DigitReader::run(ProcessingContext& pc) } } if (mUseMC) { - digMC2ROFsSel = mDigMC2ROFs; + digMC2ROFsSel = *mDigMC2ROFs[0]; for (auto& mc2rof : digMC2ROFsSel) { if (mc2rof.rofRecordID < 0) { continue; // did not contribute even to the original data @@ -198,26 +202,26 @@ void DigitReader::run(ProcessingContext& pc) mc2rof.maxROF = mx; } } - if (mDigROFRec.back().getBCData() + mROFLengthInBC - 1 < irMax) { // need to check the next entry + if (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1 < irMax) { // need to check the next entry ent++; continue; } break; // push collected data } } - pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, digROFRecSel); - pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0}, digitsSel); + pc.outputs().snapshot(Output{Origin, "DIGITSROF", 0}, digROFRecSel); + pc.outputs().snapshot(Output{Origin, "DIGITS", 0}, digitsSel); if (mUseCalib) { - pc.outputs().snapshot(Output{mOrigin, "GBTCALIB", 0}, calibSel); + pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, calibSel); } if (mTriggerOut) { std::vector dummyTrig; - pc.outputs().snapshot(Output{mOrigin, "PHYSTRIG", 0}, dummyTrig); + pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig); } if (mUseMC) { - auto& sharedlabels = pc.outputs().make>(Output{mOrigin, "DIGITSMCTR", 0}); + auto& sharedlabels = pc.outputs().make>(Output{Origin, "DIGITSMCTR", 0}); digitLabelsSel.flatten_to(sharedlabels); - pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, digMC2ROFsSel); + pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", 0}, digMC2ROFsSel); } if (!irFrames.size() || irFrames.back().isLast()) { @@ -227,77 +231,98 @@ void DigitReader::run(ProcessingContext& pc) } } -void DigitReader::connectTree(const std::string& filename) +template +void DigitReader::connectTree(const std::string& filename) { mTree.reset(nullptr); // in case it was already loaded mFile.reset(TFile::Open(filename.c_str())); assert(mFile && !mFile->IsZombie()); mTree.reset((TTree*)mFile->Get(mDigTreeName.c_str())); assert(mTree); - - mTree->SetBranchAddress(mDigROFBranchName.c_str(), &mDigROFRecPtr); - mTree->SetBranchAddress(mDigitBranchName.c_str(), &mDigitsPtr); + for (uint32_t iLayer = 0; iLayer < NLayers; ++iLayer) { + setBranchAddress(mDigitROFBranchName, mDigROFRec[iLayer], iLayer); + setBranchAddress(mDigitBranchName, mDigits[iLayer], iLayer); + if (mUseMC) { + if (!mTree->GetBranch(getBranchName(mDigitMC2ROFBranchName, iLayer).c_str()) || !mTree->GetBranch(getBranchName(mDigitMCTruthBranchName, iLayer).c_str())) { + throw std::runtime_error("MC data requested but not found in the tree"); + } + setBranchAddress(mDigitMC2ROFBranchName, mDigMC2ROFs[iLayer], iLayer); + if (!mPLabels[iLayer]) { + setBranchAddress(mDigitMCTruthBranchName, mPLabels[iLayer], iLayer); + } + } + } if (mUseCalib) { if (!mTree->GetBranch(mCalibBranchName.c_str())) { throw std::runtime_error("GBT calibration data requested but not found in the tree"); } - mTree->SetBranchAddress(mCalibBranchName.c_str(), &mCalibPtr); - } - if (mUseMC) { - if (!mTree->GetBranch(mDigtMC2ROFBranchName.c_str()) || !mTree->GetBranch(mDigtMCTruthBranchName.c_str())) { - throw std::runtime_error("MC data requested but not found in the tree"); - } - mTree->SetBranchAddress(mDigtMC2ROFBranchName.c_str(), &mDigMC2ROFsPtr); + setBranchAddress(mCalibBranchName, mCalibPtr); } LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; } -DataProcessorSpec getITSDigitReaderSpec(bool useMC, bool useCalib, bool useTriggers, std::string defname) +template +std::string DigitReader::getBranchName(const std::string& base, int index) { - std::vector outputSpec; - outputSpec.emplace_back("ITS", "DIGITS", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "DIGITSROF", 0, Lifetime::Timeframe); - if (useCalib) { - outputSpec.emplace_back("ITS", "GBTCALIB", 0, Lifetime::Timeframe); + if (index < 0) { + return base; } - if (useMC) { - outputSpec.emplace_back("ITS", "DIGITSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "DIGITSMC2ROF", 0, Lifetime::Timeframe); + return base + "_" + std::to_string(index); +} + +template +template +void DigitReader::setBranchAddress(const std::string& base, Ptr& addr, int layer) +{ + const auto name = getBranchName(base, layer); + if (Int_t ret = mTree->SetBranchAddress(name.c_str(), &addr); ret != 0) { + LOGP(fatal, "failed to set branch address for {} ret={}", name, ret); } - if (useTriggers) { - outputSpec.emplace_back("ITS", "PHYSTRIG", 0, Lifetime::Timeframe); +} + +namespace +{ +template +std::vector makeOutChannels(bool mctruth, bool useCalib) +{ + constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + std::vector outputs; + for (int iLayer = 0; iLayer < o2::itsmft::DPLAlpideParam::getNLayers(); ++iLayer) { + outputs.emplace_back(Origin, "DIGITS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (mctruth) { + outputs.emplace_back(Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + } } + if (useCalib) { + outputs.emplace_back(Origin, "GBTCALIB", 0, Lifetime::Timeframe); + } + outputs.emplace_back(Origin, "PHYSTRIG", 0, Lifetime::Timeframe); + return outputs; +} +} // namespace + +DataProcessorSpec getITSDigitReaderSpec(bool useMC, bool useCalib, bool useTriggers, std::string defname) +{ return DataProcessorSpec{ - "its-digit-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, useCalib)}, - Options{ + .name = "its-digit-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels(useMC, useCalib), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, useCalib)}, + .options = Options{ {"its-digit-infile", VariantType::String, defname, {"Name of the input digit file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } DataProcessorSpec getMFTDigitReaderSpec(bool useMC, bool useCalib, bool useTriggers, std::string defname) { - std::vector outputSpec; - outputSpec.emplace_back("MFT", "DIGITS", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "DIGITSROF", 0, Lifetime::Timeframe); - if (useCalib) { - outputSpec.emplace_back("MFT", "GBTCALIB", 0, Lifetime::Timeframe); - } - if (useMC) { - outputSpec.emplace_back("MFT", "DIGITSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - } - if (useTriggers) { - outputSpec.emplace_back("MFT", "PHYSTRIG", 0, Lifetime::Timeframe); - } return DataProcessorSpec{ - "mft-digit-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, useCalib)}, - Options{ + .name = "mft-digit-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels(useMC, useCalib), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, useCalib)}, + .options = Options{ {"mft-digit-infile", VariantType::String, defname, {"Name of the input digit file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } diff --git a/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx index 3a06d106ceb1f..58b2d4db211bc 100644 --- a/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx @@ -12,6 +12,9 @@ /// @brief Processor spec for a ROOT file writer for ITSMFT digits #include "ITSMFTWorkflow/DigitWriterSpec.h" +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/DataRef.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/GBTCalibData.h" @@ -39,14 +42,24 @@ using MCCont = o2::dataformats::ConstMCTruthContainer; /// create the processor spec /// describing a processor receiving digits for ITS/MFT and writing them to file -DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::header::DataOrigin detOrig, o2::detectors::DetID detId) +template +DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib) { - std::string detStr = o2::detectors::DetID::getName(detId); + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + constexpr int NLayers = o2::itsmft::DPLAlpideParam::getNLayers(); + std::string detStr = o2::detectors::DetID::getName(N); std::string detStrL = dec ? "o2_" : ""; // for decoded digits prepend by o2 detStrL += detStr; std::transform(detStrL.begin(), detStrL.end(), detStrL.begin(), ::tolower); - auto logger = [](std::vector const& inDigits) { - LOG(info) << "RECEIVED DIGITS SIZE " << inDigits.size(); + auto digitSizes = std::make_shared>(); + auto digitSizeGetter = [digitSizes](std::vector const& inDigits, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + (*digitSizes)[dh->subSpecification] = inDigits.size(); + }; + auto rofSizes = std::make_shared>(); + auto rofSizeGetter = [rofSizes](std::vector const& inROFs, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + (*rofSizes)[dh->subSpecification] = inROFs.size(); }; // the callback to be set as hook for custom action when the writer is closed @@ -71,9 +84,11 @@ DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::hea // handler for labels // This is necessary since we can't store the original label buffer in a ROOT entry -- as is -- if it exceeds a certain size. // We therefore convert it to a special split class. - auto fillLabels = [](TBranch& branch, std::vector const& labelbuffer, DataRef const& /*ref*/) { + auto fillLabels = [digitSizes, rofSizes](TBranch& branch, std::vector const& labelbuffer, DataRef const& ref) { o2::dataformats::ConstMCTruthContainerView labels(labelbuffer); - LOG(info) << "WRITING " << labels.getNElements() << " LABELS "; + auto const* dh = DataRefUtils::getHeader(ref); + auto layer = static_cast(dh->subSpecification); + LOG(info) << "WRITING " << labels.getNElements() << " LABELS FOR " << layer << " WITH " << (*digitSizes)[layer] << " DIGITS IN " << (*rofSizes)[layer] << " ROFS"; o2::dataformats::IOMCTruthContainerView outputcontainer; auto ptr = &outputcontainer; @@ -83,35 +98,53 @@ DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::hea br->ResetAddress(); }; + auto getIndex = [](DataRef const& ref) -> size_t { + auto const* dh = DataRefUtils::getHeader(ref); + return static_cast(dh->subSpecification); + }; + auto getName = [](std::string base, size_t index) -> std::string { + return base += "_" + std::to_string(index); + }; return MakeRootTreeWriterSpec((detStr + "DigitWriter" + (dec ? "_dec" : "")).c_str(), (detStrL + "digits.root").c_str(), - MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Digits tree"}, + MakeRootTreeWriterSpec::TreeAttributes{.name = "o2sim", .title = detStr + " Digits tree"}, MakeRootTreeWriterSpec::CustomClose(finishWriting), - // in case of labels we first read them as std::vector and process them correctly in the fillLabels hook - BranchDefinition>{InputSpec{(detStr + "_digitsMCTR").c_str(), detOrig, "DIGITSMCTR", 0}, - (detStr + "DigitMCTruth").c_str(), - (mctruth ? 1 : 0), fillLabels}, - BranchDefinition>{InputSpec{(detStr + "_digitsMC2ROF").c_str(), detOrig, "DIGITSMC2ROF", 0}, - (detStr + "DigitMC2ROF").c_str(), - (mctruth ? 1 : 0)}, - BranchDefinition>{InputSpec{(detStr + "digits").c_str(), detOrig, "DIGITS", 0}, - (detStr + "Digit").c_str(), - logger}, - BranchDefinition>{InputSpec{(detStr + "calib").c_str(), detOrig, "GBTCALIB", 0}, - (detStr + "Calib").c_str(), - (calib ? 1 : 0)}, - BranchDefinition>{InputSpec{(detStr + "digitsROF").c_str(), detOrig, "DIGITSROF", 0}, - (detStr + "DigitROF").c_str()})(); + BranchDefinition>{InputSpec{detStr + "digits", ConcreteDataTypeMatcher{Origin, "DIGITS"}}, + detStr + "Digit", "digit-branch", + NLayers, + digitSizeGetter, + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "digitsROF", ConcreteDataTypeMatcher{Origin, "DIGITSROF"}}, + detStr + "DigitROF", "digit-rof-branch", + NLayers, + rofSizeGetter, + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "_digitsMCTR", ConcreteDataTypeMatcher{Origin, "DIGITSMCTR"}}, + detStr + "DigitMCTruth", "digit-mctruth-branch", + (mctruth ? NLayers : 0), + fillLabels, + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "_digitsMC2ROF", ConcreteDataTypeMatcher{Origin, "DIGITSMC2ROF"}}, + detStr + "DigitMC2ROF", "digit-mc2rof-branch", + (mctruth ? NLayers : 0), + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "calib", ConcreteDataTypeMatcher{Origin, "GBTCALIB"}}, + detStr + "Calib", "digit-calib-branch", + (calib ? 1 : 0)})(); } DataProcessorSpec getITSDigitWriterSpec(bool mctruth, bool dec, bool calib) { - return getDigitWriterSpec(mctruth, dec, calib, o2::header::gDataOriginITS, o2::detectors::DetID::ITS); + return getDigitWriterSpec(mctruth, dec, calib); } DataProcessorSpec getMFTDigitWriterSpec(bool mctruth, bool dec, bool calib) { - return getDigitWriterSpec(mctruth, dec, calib, o2::header::gDataOriginMFT, o2::detectors::DetID::MFT); + return getDigitWriterSpec(mctruth, dec, calib); } } // end namespace itsmft diff --git a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx index 72ec65b2e522b..824a322497012 100644 --- a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx @@ -17,12 +17,13 @@ #include "Framework/Lifetime.h" #include "Framework/Task.h" #include "Framework/CCDBParamSpec.h" -#include "Steer/HitProcessingManager.h" // for DigitizationContext +#include "SimulationDataFormat/DigitizationContext.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/NoiseMap.h" #include "DataFormatsITSMFT/TimeDeadMap.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "DetectorsBase/BaseDPLDigitizer.h" +#include "DetectorsRaw/HBFUtils.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsCommonDataFormats/SimTraits.h" #include "DetectorsCommonDataFormats/DetectorNameConf.h" @@ -36,20 +37,25 @@ #include #include #include +#include using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; -namespace o2 -{ -namespace itsmft +namespace o2::itsmft { using namespace o2::base; +template class ITSMFTDPLDigitizerTask : BaseDPLDigitizer { public: + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::getNLayers()}; + using BaseDPLDigitizer::init; + void initDigitizerTask(framework::InitContext& ic) override { mDisableQED = ic.options().get("disable-qed"); @@ -60,121 +66,174 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer if (mFinished) { return; } + mFirstOrbitTF = pc.services().get().firstTForbit; - mID == o2::detectors::DetID::ITS ? updateTimeDependentParams(pc) : updateTimeDependentParams(pc); - std::string detStr = mID.getName(); + const o2::InteractionRecord firstIR(0, mFirstOrbitTF); + updateTimeDependentParams(pc); + + TStopwatch timer; + timer.Start(); + LOG(info) << " CALLING ITS DIGITIZATION "; + // read collision context from input auto context = pc.inputs().get("collisioncontext"); - context->initSimChains(mID, mSimChains); + context->initSimChains(ID, mSimChains); const bool withQED = context->isQEDProvided() && !mDisableQED; auto& timesview = context->getEventRecords(withQED); LOG(info) << "GOT " << timesview.size() << " COLLISSION TIMES"; - LOG(info) << "SIMCHAINS " << mSimChains.size(); + LOG(info) << "SIMCHAINS: " << mSimChains.size(); // if there is nothing to do ... return if (timesview.size() == 0) { return; } - TStopwatch timer; - timer.Start(); - LOG(info) << " CALLING ITS DIGITIZATION "; - mDigitizer.setDigits(&mDigits); - mDigitizer.setROFRecords(&mROFRecords); - mDigitizer.setMCLabels(&mLabels); + uint64_t nDigits{0}; + constexpr uint32_t nLayers = (DPLAlpideParam::supportsStaggering()) ? NLayers : 1; + for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) { + const int layer = (DPLAlpideParam::supportsStaggering()) ? iLayer : -1; + mDigitizer.setDigits(&mDigits[iLayer]); + mDigitizer.setROFRecords(&mROFRecords[iLayer]); + mDigitizer.setMCLabels(&mLabels[iLayer]); + mDigitizer.resetROFrameBounds(); + + // digits are directly put into DPL owned resource + auto& digitsAccum = pc.outputs().make>(Output{Origin, "DIGITS", iLayer}); + + // rofs are accumulated first and the copied + const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / DPLAlpideParam::Instance().getROFLengthInBC(iLayer); + const int nROFsTF = nROFsPerOrbit * raw::HBFUtils::Instance().getNOrbitsPerTF(); + mROFRecordsAccum[iLayer].reserve(nROFsTF); + + auto accumulate = [this, &digitsAccum, &iLayer]() { + // accumulate result of single event processing on a specific layer, called after processing every event supplied + // AND after the final flushing via digitizer::fillOutputContainer + if (!mDigits[iLayer].size()) { + return; // no digits were flushed, nothing to accumulate + } + auto ndigAcc = digitsAccum.size(); + std::copy(mDigits[iLayer].begin(), mDigits[iLayer].end(), std::back_inserter(digitsAccum)); + + // fix ROFrecords references on ROF entries + auto nROFRecsOld = mROFRecordsAccum[iLayer].size(); + + for (int i = 0; i < mROFRecords[iLayer].size(); i++) { + auto& rof = mROFRecords[iLayer][i]; + rof.setFirstEntry(ndigAcc + rof.getFirstEntry()); + rof.print(); + + if (mFixMC2ROF[iLayer] < mMC2ROFRecordsAccum[iLayer].size()) { // fix ROFRecord entry in MC2ROF records + for (int m2rid = mFixMC2ROF[iLayer]; m2rid < mMC2ROFRecordsAccum[iLayer].size(); m2rid++) { + // need to register the ROFRecors entry for MC event starting from this entry + auto& mc2rof = mMC2ROFRecordsAccum[iLayer][m2rid]; + if (rof.getROFrame() == mc2rof.minROF) { + mFixMC2ROF[iLayer]++; + mc2rof.rofRecordID = nROFRecsOld + i; + mc2rof.print(); + } + } + } + } + + std::copy(mROFRecords[iLayer].begin(), mROFRecords[iLayer].end(), std::back_inserter(mROFRecordsAccum[iLayer])); + if (mWithMCTruth) { + mLabelsAccum[iLayer].mergeAtBack(mLabels[iLayer]); + } + LOG(info) << "Added " << mDigits[iLayer].size() << " digits:" << iLayer; + // clean containers from already accumulated stuff + mLabels[iLayer].clear(); + mDigits[iLayer].clear(); + mROFRecords[iLayer].clear(); + }; // and accumulate lambda + + const auto& eventParts = context->getEventParts(withQED); + const int64_t bcShift = mDigitizer.getParams().getROFrameBiasInBC(layer); // this accounts the misalignment and the opt. imposed rof delay + // loop over all composite collisions given from context (aka loop over all the interaction records) + for (int collID = 0; collID < timesview.size(); ++collID) { + auto irt = timesview[collID]; + if (irt.toLong() < bcShift) { // due to the ROF misalignment (+opt. delay) the collision would go to negative ROF ID, discard + continue; + } + irt -= bcShift; // account for the ROF start shift + + mDigitizer.setEventTime(irt, layer); + mDigitizer.resetEventROFrames(); // to estimate min/max ROF for this collID + // for each collision, loop over the constituents event and source IDs + // (background signal merging is basically taking place here) + for (const auto& part : eventParts[collID]) { - // digits are directly put into DPL owned resource - auto& digitsAccum = pc.outputs().make>(Output{mOrigin, "DIGITS", 0}); + // get the hits for this event and this source + mHits.clear(); + context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[ID][0].c_str(), part.sourceID, part.entryID, &mHits); - auto accumulate = [this, &digitsAccum]() { - // accumulate result of single event processing, called after processing every event supplied - // AND after the final flushing via digitizer::fillOutputContainer - if (!mDigits.size()) { - return; // no digits were flushed, nothing to accumulate + if (mHits.size() > 0) { + LOG(debug) << "For collision " << collID << " eventID " << part.entryID << " found " << mHits.size() << " hits "; + mDigitizer.process(&mHits, part.entryID, part.sourceID, layer); // call actual digitization procedure + } + } + mMC2ROFRecordsAccum[iLayer].emplace_back(collID, -1, mDigitizer.getEventROFrameMin(), mDigitizer.getEventROFrameMax()); + accumulate(); } - auto ndigAcc = digitsAccum.size(); - std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(digitsAccum)); - - // fix ROFrecords references on ROF entries - auto nROFRecsOld = mROFRecordsAccum.size(); - - for (int i = 0; i < mROFRecords.size(); i++) { - auto& rof = mROFRecords[i]; - rof.setFirstEntry(ndigAcc + rof.getFirstEntry()); - rof.print(); - - if (mFixMC2ROF < mMC2ROFRecordsAccum.size()) { // fix ROFRecord entry in MC2ROF records - for (int m2rid = mFixMC2ROF; m2rid < mMC2ROFRecordsAccum.size(); m2rid++) { - // need to register the ROFRecors entry for MC event starting from this entry - auto& mc2rof = mMC2ROFRecordsAccum[m2rid]; - if (rof.getROFrame() == mc2rof.minROF) { - mFixMC2ROF++; - mc2rof.rofRecordID = nROFRecsOld + i; - mc2rof.print(); - } + mDigitizer.fillOutputContainer(0xffffffff, layer); + accumulate(); + nDigits += digitsAccum.size(); + + // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output) + // ensure that the rof output is continuous + if (nROFsTF != mROFRecordsAccum[iLayer].size()) { + // it can happen that in the digitization rofs without contributing hits are skipped + // however downstream consumers of the clusters cannot know apriori the time structure + // the cluster rofs do not account for the bias so it will start always at BC=0 + std::vector expDigitRofVec(nROFsTF); + for (int iROF{0}; iROF < nROFsTF; ++iROF) { + auto& rof = expDigitRofVec[iROF]; + int orb = iROF * DPLAlpideParam::Instance().getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + mFirstOrbitTF; + int bc = iROF * DPLAlpideParam::Instance().getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches; + o2::InteractionRecord ir(bc, orb); + rof.setBCData(ir); + rof.setROFrame(iROF); + rof.setNEntries(0); + rof.setFirstEntry(-1); + } + uint32_t prevEntry{0}; + for (const auto& rof : mROFRecordsAccum[iLayer]) { + const auto& ir = rof.getBCData(); + const auto irToFirst = ir - firstIR; + const int irROF = irToFirst.toLong() / DPLAlpideParam::Instance().getROFLengthInBC(iLayer); + auto& expROF = expDigitRofVec[irROF]; + expROF.setFirstEntry(rof.getFirstEntry()); + expROF.setNEntries(rof.getNEntries()); + if (expROF.getBCData() != rof.getBCData()) { + LOGP(fatal, "detected mismatch between expected ROF:{} and received ROF:{}", expROF.asString(), rof.asString()); + } + } + int prevFirst{0}; + for (auto& rof : expDigitRofVec) { + if (rof.getFirstEntry() < 0) { + rof.setFirstEntry(prevFirst); } + prevFirst = rof.getFirstEntry(); } + pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, expDigitRofVec); + } else { + pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, mROFRecordsAccum[iLayer]); } - - std::copy(mROFRecords.begin(), mROFRecords.end(), std::back_inserter(mROFRecordsAccum)); if (mWithMCTruth) { - mLabelsAccum.mergeAtBack(mLabels); - } - LOG(info) << "Added " << mDigits.size() << " digits "; - // clean containers from already accumulated stuff - mLabels.clear(); - mDigits.clear(); - mROFRecords.clear(); - }; // and accumulate lambda - - auto& eventParts = context->getEventParts(withQED); - int bcShift = mDigitizer.getParams().getROFrameBiasInBC(); - // loop over all composite collisions given from context (aka loop over all the interaction records) - for (int collID = 0; collID < timesview.size(); ++collID) { - auto irt = timesview[collID]; - if (irt.toLong() < bcShift) { // due to the ROF misalignment the collision would go to negative ROF ID, discard - continue; + pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", iLayer}, mMC2ROFRecordsAccum[iLayer]); + auto& sharedlabels = pc.outputs().make>(Output{Origin, "DIGITSMCTR", iLayer}); + mLabelsAccum[iLayer].flatten_to(sharedlabels); + // free space of existing label containers + mLabels[iLayer].clear_andfreememory(); + mLabelsAccum[iLayer].clear_andfreememory(); } - irt -= bcShift; // account for the ROF start shift - - mDigitizer.setEventTime(irt); - mDigitizer.resetEventROFrames(); // to estimate min/max ROF for this collID - // for each collision, loop over the constituents event and source IDs - // (background signal merging is basically taking place here) - for (auto& part : eventParts[collID]) { - - // get the hits for this event and this source - mHits.clear(); - context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[mID][0].c_str(), part.sourceID, part.entryID, &mHits); - - if (mHits.size() > 0) { - LOG(debug) << "For collision " << collID << " eventID " << part.entryID - << " found " << mHits.size() << " hits "; - mDigitizer.process(&mHits, part.entryID, part.sourceID); // call actual digitization procedure - } - } - mMC2ROFRecordsAccum.emplace_back(collID, -1, mDigitizer.getEventROFrameMin(), mDigitizer.getEventROFrameMax()); - accumulate(); } - mDigitizer.fillOutputContainer(); - accumulate(); - - // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output) - - pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, mROFRecordsAccum); - if (mWithMCTruth) { - pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, mMC2ROFRecordsAccum); - auto& sharedlabels = pc.outputs().make>(Output{mOrigin, "DIGITSMCTR", 0}); - mLabelsAccum.flatten_to(sharedlabels); - // free space of existing label containers - mLabels.clear_andfreememory(); - mLabelsAccum.clear_andfreememory(); - } - LOG(info) << mID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater"; - pc.outputs().snapshot(Output{mOrigin, "ROMode", 0}, mROMode); + + LOG(info) << ID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater"; + pc.outputs().snapshot(Output{Origin, "ROMode", 0}, mROMode); timer.Stop(); LOG(info) << "Digitization took " << timer.CpuTime() << "s"; + LOG(info) << "Produced " << nDigits << " digits"; // we should be only called once; tell DPL that this process is ready to exit pc.services().get().readyToQuit(QuitRequest::Me); @@ -184,18 +243,18 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) { - if (matcher == ConcreteDataMatcher(mOrigin, "NOISEMAP", 0)) { - LOG(info) << mID.getName() << " noise map updated"; + if (matcher == ConcreteDataMatcher(Origin, "NOISEMAP", 0)) { + LOG(info) << ID.getName() << " noise map updated"; mDigitizer.setNoiseMap((const o2::itsmft::NoiseMap*)obj); return; } - if (matcher == ConcreteDataMatcher(mOrigin, "DEADMAP", 0)) { - LOG(info) << mID.getName() << " static dead map updated"; + if (matcher == ConcreteDataMatcher(Origin, "DEADMAP", 0)) { + LOG(info) << ID.getName() << " static dead map updated"; mDeadMap = (o2::itsmft::NoiseMap*)obj; mDigitizer.setDeadChannelsMap(mDeadMap); return; } - if (matcher == ConcreteDataMatcher(mOrigin, "TimeDeadMap", 0)) { + if (matcher == ConcreteDataMatcher(Origin, "TimeDeadMap", 0)) { o2::itsmft::TimeDeadMap* timedeadmap = (o2::itsmft::TimeDeadMap*)obj; if (!timedeadmap->isDefault()) { timedeadmap->decodeMap(mFirstOrbitTF, *mDeadMap, true); @@ -204,22 +263,17 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer } mTimeDeadMapUpdated = true; mDigitizer.setDeadChannelsMap(mDeadMap); - LOG(info) << mID.getName() << " time-dependent dead map updated"; + LOG(info) << ID.getName() << " time-dependent dead map updated"; } else { - LOG(info) << mID.getName() << " time-dependent dead map is default/empty"; + LOG(info) << ID.getName() << " time-dependent dead map is default/empty"; } return; } - if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDEPARAM", 0)) { - LOG(info) << mID.getName() << " Alpide param updated"; - if (mID == o2::detectors::DetID::ITS) { - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - } else { - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - } + if (matcher == ConcreteDataMatcher(Origin, "ALPIDEPARAM", 0)) { + LOG(info) << ID.getName() << " Alpide param updated"; + const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + par.printKeyValues(); return; } } @@ -227,18 +281,17 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer protected: ITSMFTDPLDigitizerTask(bool mctruth = true) : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM), mWithMCTruth(mctruth) {} - template void updateTimeDependentParams(ProcessingContext& pc) { - std::string detstr(o2::detectors::DetID::getName(DETID)); + std::string detstr(o2::detectors::DetID::getName(ID)); pc.inputs().get(detstr + "_noise"); pc.inputs().get(detstr + "_dead"); // TODO: the code should run even if this object does not exist. Or: create default object pc.inputs().get(detstr + "_time_dead"); - pc.inputs().get*>(detstr + "_alppar"); + pc.inputs().get*>(detstr + "_alppar"); - auto& dopt = o2::itsmft::DPLDigitizerParam::Instance(); - auto& aopt = o2::itsmft::DPLAlpideParam::Instance(); + auto& dopt = o2::itsmft::DPLDigitizerParam::Instance(); + auto& aopt = o2::itsmft::DPLAlpideParam::Instance(); auto& digipar = mDigitizer.getParams(); digipar.setContinuous(dopt.continuous); digipar.setROFrameBiasInBC(aopt.roFrameBiasInBC); @@ -262,15 +315,29 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer digipar.setIBVbb(dopt.IBVbb); digipar.setOBVbb(dopt.OBVbb); digipar.setVbb(dopt.Vbb); + // staggering parameters + if constexpr (o2::itsmft::DPLAlpideParam::supportsStaggering()) { + const bool withStag = aopt.withStaggering(); + for (int iLayer{0}; iLayer < o2::itsmft::DPLAlpideParam::getNLayers(); ++iLayer) { + const int nLayer = (withStag) ? iLayer : -1; + auto frameNS = aopt.getROFLengthInBC(nLayer) * o2::constants::lhc::LHCBunchSpacingNS; + digipar.addROFrameLayerLengthInBC(aopt.getROFLengthInBC(nLayer)); + // NOTE: the rof delay looks from the digitizer like an additional bias + digipar.addROFrameLayerBiasInBC(aopt.getROFBiasInBC(nLayer) + aopt.getROFDelayInBC(nLayer)); + digipar.addStrobeDelay(aopt.strobeDelay); + digipar.addStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay); + digipar.setROFrameLength(aopt.getROFLengthInBC(nLayer) * o2::constants::lhc::LHCBunchSpacingNS, iLayer); + } + } mROMode = digipar.isContinuous() ? o2::parameters::GRPObject::CONTINUOUS : o2::parameters::GRPObject::PRESENT; - LOG(info) << mID.getName() << " simulated in " + LOG(info) << detstr << " simulated in " << ((mROMode == o2::parameters::GRPObject::CONTINUOUS) ? "CONTINUOUS" : "TRIGGERED") << " RO mode"; // configure digitizer o2::itsmft::GeometryTGeo* geom = nullptr; - if (mID == o2::detectors::DetID::ITS) { + if constexpr (N == o2::detectors::DetID::ITS) { geom = o2::its::GeometryTGeo::Instance(); } else { geom = o2::mft::GeometryTGeo::Instance(); @@ -284,115 +351,91 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer bool mFinished = false; bool mDisableQED = false; unsigned long mFirstOrbitTF = 0x0; - o2::detectors::DetID mID; - o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; o2::itsmft::Digitizer mDigitizer; - std::vector mDigits; - std::vector mROFRecords; - std::vector mROFRecordsAccum; + std::array, NLayers> mDigits; + std::array, NLayers> mROFRecords; + std::array, NLayers> mROFRecordsAccum; std::vector mHits; std::vector* mHitsP = &mHits; - o2::dataformats::MCTruthContainer mLabels; - o2::dataformats::MCTruthContainer mLabelsAccum; - std::vector mMC2ROFRecordsAccum; + std::array, NLayers> mLabels; + std::array, NLayers> mLabelsAccum; + std::array, NLayers> mMC2ROFRecordsAccum; std::vector mSimChains; o2::itsmft::NoiseMap* mDeadMap = nullptr; - int mFixMC2ROF = 0; // 1st entry in mc2rofRecordsAccum to be fixed for ROFRecordID + std::array mFixMC2ROF{}; // 1st entry in mc2rofRecordsAccum to be fixed for ROFRecordID bool mTimeDeadMapUpdated = false; o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::PRESENT; // readout mode }; //_______________________________________________ -class ITSDPLDigitizerTask : public ITSMFTDPLDigitizerTask +class ITSDPLDigitizerTask : public ITSMFTDPLDigitizerTask { public: - // FIXME: origin should be extractable from the DetID, the problem is 3d party header dependencies - static constexpr o2::detectors::DetID::ID DETID = o2::detectors::DetID::ITS; - static constexpr o2::header::DataOrigin DETOR = o2::header::gDataOriginITS; - ITSDPLDigitizerTask(bool mctruth = true) : ITSMFTDPLDigitizerTask(mctruth) - { - mID = DETID; - mOrigin = DETOR; - } + ITSDPLDigitizerTask(bool mctruth = true) : ITSMFTDPLDigitizerTask(mctruth) {} }; -constexpr o2::detectors::DetID::ID ITSDPLDigitizerTask::DETID; -constexpr o2::header::DataOrigin ITSDPLDigitizerTask::DETOR; - //_______________________________________________ -class MFTDPLDigitizerTask : public ITSMFTDPLDigitizerTask +class MFTDPLDigitizerTask : public ITSMFTDPLDigitizerTask { public: - // FIXME: origina should be extractable from the DetID, the problem is 3d party header dependencies - static constexpr o2::detectors::DetID::ID DETID = o2::detectors::DetID::MFT; - static constexpr o2::header::DataOrigin DETOR = o2::header::gDataOriginMFT; - MFTDPLDigitizerTask(bool mctruth) : ITSMFTDPLDigitizerTask(mctruth) - { - mID = DETID; - mOrigin = DETOR; - } + MFTDPLDigitizerTask(bool mctruth = true) : ITSMFTDPLDigitizerTask(mctruth) {} }; -constexpr o2::detectors::DetID::ID MFTDPLDigitizerTask::DETID; -constexpr o2::header::DataOrigin MFTDPLDigitizerTask::DETOR; - +namespace +{ +template std::vector makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth) { std::vector outputs; - outputs.emplace_back(detOrig, "DIGITS", 0, Lifetime::Timeframe); - outputs.emplace_back(detOrig, "DIGITSROF", 0, Lifetime::Timeframe); - if (mctruth) { - outputs.emplace_back(detOrig, "DIGITSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back(detOrig, "DIGITSMCTR", 0, Lifetime::Timeframe); + constexpr uint32_t nLayers = (DPLAlpideParam::supportsStaggering()) ? DPLAlpideParam::getNLayers() : 1; + for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) { + outputs.emplace_back(detOrig, "DIGITS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (mctruth) { + outputs.emplace_back(detOrig, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + } } outputs.emplace_back(detOrig, "ROMode", 0, Lifetime::Timeframe); return outputs; } +} // namespace DataProcessorSpec getITSDigitizerSpec(int channel, bool mctruth) { - std::string detStr = o2::detectors::DetID::getName(ITSDPLDigitizerTask::DETID); - auto detOrig = ITSDPLDigitizerTask::DETOR; - std::stringstream parHelper; - parHelper << "Params as " << o2::itsmft::DPLDigitizerParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLDigitizerParam::Instance() - << "\n or " << o2::itsmft::DPLAlpideParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLAlpideParam::Instance(); + std::string detStr = o2::detectors::DetID::getName(ITSDPLDigitizerTask::ID); + auto detOrig = ITSDPLDigitizerTask::Origin; std::vector inputs; inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe); inputs.emplace_back("ITS_noise", "ITS", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/NoiseMap")); inputs.emplace_back("ITS_dead", "ITS", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/DeadMap")); inputs.emplace_back("ITS_time_dead", "ITS", "TimeDeadMap", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/TimeDeadMap")); inputs.emplace_back("ITS_alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); - - return DataProcessorSpec{(detStr + "Digitizer").c_str(), - inputs, makeOutChannels(detOrig, mctruth), - AlgorithmSpec{adaptFromTask(mctruth)}, - Options{ + return DataProcessorSpec{.name = detStr + "Digitizer", + .inputs = inputs, + .outputs = makeOutChannels(detOrig, mctruth), + .algorithm = AlgorithmSpec{adaptFromTask(mctruth)}, + .options = Options{ {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; } DataProcessorSpec getMFTDigitizerSpec(int channel, bool mctruth) { - std::string detStr = o2::detectors::DetID::getName(MFTDPLDigitizerTask::DETID); - auto detOrig = MFTDPLDigitizerTask::DETOR; - std::stringstream parHelper; + std::string detStr = o2::detectors::DetID::getName(MFTDPLDigitizerTask::ID); + auto detOrig = MFTDPLDigitizerTask::Origin; std::vector inputs; inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe); inputs.emplace_back("MFT_noise", "MFT", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/NoiseMap")); inputs.emplace_back("MFT_dead", "MFT", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/DeadMap")); inputs.emplace_back("MFT_time_dead", "MFT", "TimeDeadMap", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/TimeDeadMap")); inputs.emplace_back("MFT_alppar", "MFT", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("MFT/Config/AlpideParam")); - parHelper << "Params as " << o2::itsmft::DPLDigitizerParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLDigitizerParam::Instance() - << " or " << o2::itsmft::DPLAlpideParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLAlpideParam::Instance(); - return DataProcessorSpec{(detStr + "Digitizer").c_str(), - inputs, makeOutChannels(detOrig, mctruth), - AlgorithmSpec{adaptFromTask(mctruth)}, - Options{{"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; + return DataProcessorSpec{.name = detStr + "Digitizer", + .inputs = inputs, + .outputs = makeOutChannels(detOrig, mctruth), + .algorithm = AlgorithmSpec{adaptFromTask(mctruth)}, + .options = Options{{"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; } -} // end namespace itsmft -} // end namespace o2 +} // namespace o2::itsmft + // end namespace o2 From 9fa8ccdbf401df215427f7ff3cf271d2a0affc39 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Sat, 1 Nov 2025 09:06:50 +0100 Subject: [PATCH 09/13] ITSMFT: staggered clusterization Signed-off-by: Felix Schlepper --- .../src/StrangenessTrackingSpec.cxx | 2 - Detectors/ITSMFT/ITS/workflow/CMakeLists.txt | 2 - .../include/ITSWorkflow/ClustererSpec.h | 65 ---- .../ITS/workflow/src/ClusterWriterSpec.cxx | 72 ---- .../workflow/src/ClusterWriterWorkflow.cxx | 4 +- .../ITSMFT/ITS/workflow/src/ClustererSpec.cxx | 218 ------------ .../ITSMFT/ITS/workflow/src/RecoWorkflow.cxx | 8 +- Detectors/ITSMFT/MFT/workflow/CMakeLists.txt | 2 - .../include/MFTWorkflow/ClusterWriterSpec.h | 31 -- .../MFT/workflow/src/ClusterWriterSpec.cxx | 72 ---- .../ITSMFT/MFT/workflow/src/ClustererSpec.cxx | 212 ----------- .../ITSMFT/MFT/workflow/src/RecoWorkflow.cxx | 8 +- .../src/mft-cluster-writer-workflow.cxx | 4 +- .../include/ITSMFTReconstruction/Clusterer.h | 14 +- .../ITSMFTReconstruction/ClustererParam.h | 32 +- .../ITSMFTReconstruction/DigitPixelReader.h | 3 +- .../common/reconstruction/src/Clusterer.cxx | 38 +- .../reconstruction/src/DigitPixelReader.cxx | 11 + .../ITSMFT/common/workflow/CMakeLists.txt | 2 + .../ITSMFTWorkflow/ClusterReaderSpec.h | 50 ++- .../ITSMFTWorkflow}/ClusterWriterSpec.h | 16 +- .../include/ITSMFTWorkflow}/ClustererSpec.h | 28 +- .../common/workflow/src/ClusterReaderSpec.cxx | 149 ++++---- .../common/workflow/src/ClusterWriterSpec.cxx | 104 ++++++ .../common/workflow/src/ClustererSpec.cxx | 329 ++++++++++++++++++ .../ITS3/workflow/src/RecoWorkflow.cxx | 4 +- 26 files changed, 641 insertions(+), 839 deletions(-) delete mode 100644 Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h delete mode 100644 Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx delete mode 100644 Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx delete mode 100644 Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h delete mode 100644 Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx delete mode 100644 Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx rename Detectors/ITSMFT/{ITS/workflow/include/ITSWorkflow => common/workflow/include/ITSMFTWorkflow}/ClusterWriterSpec.h (73%) rename Detectors/ITSMFT/{MFT/workflow/include/MFTWorkflow => common/workflow/include/ITSMFTWorkflow}/ClustererSpec.h (66%) create mode 100644 Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx create mode 100644 Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx diff --git a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx index 849964aeaf871..e313940b0a91e 100644 --- a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx @@ -17,10 +17,8 @@ #include "DataFormatsGlobalTracking/RecoContainer.h" #include "StrangenessTracking/StrangenessTrackingConfigParam.h" #include "GlobalTrackingWorkflow/StrangenessTrackingSpec.h" -#include "ITSWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" #include "ITSWorkflow/TrackReaderSpec.h" -#include "ITSMFTWorkflow/ClusterReaderSpec.h" #include "Framework/CCDBParamSpec.h" #include "DataFormatsParameters/GRPObject.h" diff --git a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt index 3609560eccf72..efe663e14eed6 100644 --- a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt @@ -13,8 +13,6 @@ o2_add_library(ITSWorkflow TARGETVARNAME targetName SOURCES src/RecoWorkflow.cxx src/ClusterWriterWorkflow.cxx - src/ClustererSpec.cxx - src/ClusterWriterSpec.cxx src/TrackerSpec.cxx src/CookedTrackerSpec.cxx src/TrackWriterSpec.cxx diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h deleted file mode 100644 index c5038c87fa467..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClustererSpec.h - -#ifndef O2_ITS_CLUSTERERDPL -#define O2_ITS_CLUSTERERDPL - -#include -#include "DetectorsBase/GRPGeomHelper.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -using namespace o2::framework; - -namespace o2 -{ - -namespace itsmft -{ -class Clusterer; -} - -namespace its -{ - -class ClustererDPL : public Task -{ - public: - ClustererDPL(std::shared_ptr gr, bool useMC) : mGGCCDBRequest(gr), mUseMC(useMC) {} - ~ClustererDPL() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; - void endOfStream(o2::framework::EndOfStreamContext& ec) final; - - private: - void updateTimeDependentParams(ProcessingContext& pc); - - int mState = 0; - bool mUseMC = true; - bool mUseClusterDictionary = true; - int mNThreads = 1; - std::unique_ptr mFile = nullptr; - std::unique_ptr mClusterer = nullptr; - std::shared_ptr mGGCCDBRequest; -}; - -/// create a processor spec -/// run ITS cluster finder -framework::DataProcessorSpec getClustererSpec(bool useMC); - -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_CLUSTERERDPL */ diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx deleted file mode 100644 index 4dffbaf88893c..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterWriterSpec.cxx - -#include - -#include "ITSWorkflow/ClusterWriterSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace its -{ - -template -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; -using CompClusType = std::vector; -using PatternsType = std::vector; -using ROFrameRType = std::vector; -using LabelsType = o2::dataformats::MCTruthContainer; -using ROFRecLblT = std::vector; -using namespace o2::header; - -DataProcessorSpec getClusterWriterSpec(bool useMC) -{ - // Spectators for logging - // this is only to restore the original behavior - auto compClustersSize = std::make_shared(0); - auto compClustersSizeGetter = [compClustersSize](CompClusType const& compClusters) { - *compClustersSize = compClusters.size(); - }; - auto logger = [compClustersSize](std::vector const& rofs) { - LOG(info) << "ITSClusterWriter pulled " << *compClustersSize << " clusters, in " << rofs.size() << " RO frames"; - }; - return MakeRootTreeWriterSpec("its-cluster-writer", - "o2clus_its.root", - MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with ITS clusters"}, - BranchDefinition{InputSpec{"compclus", "ITS", "COMPCLUSTERS", 0}, - "ITSClusterComp", - compClustersSizeGetter}, - BranchDefinition{InputSpec{"patterns", "ITS", "PATTERNS", 0}, - "ITSClusterPatt"}, - BranchDefinition{InputSpec{"ROframes", "ITS", "CLUSTERSROF", 0}, - "ITSClustersROF", - logger}, - BranchDefinition{InputSpec{"labels", "ITS", "CLUSTERSMCTR", 0}, - "ITSClusterMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition{InputSpec{"MC2ROframes", "ITS", "CLUSTERSMC2ROF", 0}, - "ITSClustersMC2ROF", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""})(); -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx index ca5db7acd63e1..aba468b3e9460 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx @@ -12,7 +12,7 @@ /// @file ClusterWriterWorkflow.cxx #include "ITSWorkflow/ClusterWriterWorkflow.h" -#include "ITSWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" namespace o2 { @@ -26,7 +26,7 @@ framework::WorkflowSpec getWorkflow(bool useMC) { framework::WorkflowSpec specs; - specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClusterWriterSpec(useMC)); return specs; } diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx deleted file mode 100644 index d58e4f5d915c1..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClustererSpec.cxx - -#include - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/CCDBParamSpec.h" -#include "ITSWorkflow/ClustererSpec.h" -#include "DataFormatsITSMFT/Digit.h" -#include "ITSMFTReconstruction/ChipMappingITS.h" -#include "ITSMFTReconstruction/ClustererParam.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsParameters/GRPObject.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "CommonConstants/LHCConstants.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" - -using namespace o2::framework; -using namespace o2::itsmft; - -namespace o2 -{ -namespace its -{ - -void ClustererDPL::init(InitContext& ic) -{ - mClusterer = std::make_unique(); - mClusterer->setNChips(o2::itsmft::ChipMappingITS::getNChips()); - mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mNThreads = std::max(1, ic.options().get("nthreads")); - LOGP(info, "Initialising ITSClusterer with {} threads", mNThreads); - mState = 1; -} - -void ClustererDPL::run(ProcessingContext& pc) -{ - updateTimeDependentParams(pc); - auto digits = pc.inputs().get>("digits"); - auto rofs = pc.inputs().get>("ROframes"); - - gsl::span mc2rofs; - gsl::span labelbuffer; - if (mUseMC) { - labelbuffer = pc.inputs().get>("labels"); - mc2rofs = pc.inputs().get>("MC2ROframes"); - } - o2::dataformats::ConstMCTruthContainerView labels(labelbuffer); - - LOG(info) << "ITSClusterer pulled " << digits.size() << " digits, in " - << rofs.size() << " RO frames"; - LOG(info) << "ITSClusterer pulled " << labels.getNElements() << " labels "; - - o2::itsmft::DigitPixelReader reader; - reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash()); - reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking - reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash()); - reader.setDigits(digits); - reader.setROFRecords(rofs); - if (mUseMC) { - reader.setMC2ROFRecords(mc2rofs); - reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr); - } - reader.init(); - auto orig = o2::header::gDataOriginITS; - std::vector clusCompVec; - std::vector clusROFVec; - std::vector clusPattVec; - - std::unique_ptr> clusterLabels; - if (mUseMC) { - clusterLabels = std::make_unique>(); - } - mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get()); - pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", 0}, clusCompVec); - pc.outputs().snapshot(Output{orig, "CLUSTERSROF", 0}, clusROFVec); - pc.outputs().snapshot(Output{orig, "PATTERNS", 0}, clusPattVec); - - if (mUseMC) { - pc.outputs().snapshot(Output{orig, "CLUSTERSMCTR", 0}, *clusterLabels.get()); // at the moment requires snapshot - std::vector clusterMC2ROframes(mc2rofs.size()); - for (int i = mc2rofs.size(); i--;) { - clusterMC2ROframes[i] = mc2rofs[i]; // Simply, replicate it from digits ? - } - pc.outputs().snapshot(Output{orig, "CLUSTERSMC2ROF", 0}, clusterMC2ROframes); - } - - // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF - // -> consider recalculationg maxROF - LOG(info) << "ITSClusterer pushed " << clusCompVec.size() << " clusters, in " << clusROFVec.size() << " RO frames"; -} - -///_______________________________________ -void ClustererDPL::updateTimeDependentParams(ProcessingContext& pc) -{ - static bool initOnceDone = false; - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("cldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("alppar"); - pc.inputs().get*>("cluspar"); - mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS)); - // settings for the fired pixel overflow masking - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); - const auto& clParams = o2::itsmft::ClustererParam::Instance(); - mClusterer->setDropHugeClusters(clParams.dropHugeClusters); - if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) { - LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToSquashBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias); - } - auto nbc = clParams.maxBCDiffToMaskBias; - nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); - mClusterer->setMaxBCSeparationToMask(nbc); - mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); - // Squasher - int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC - mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias); - int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0. - if (clParams.maxSOTMUS > 0 && rofBC > 0) { - nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing - } - mClusterer->setMaxROFDepthToSquash(clParams.maxBCDiffToSquashBias > 0 ? nROFsToSquash : 0); - mClusterer->print(); - } - // we may have other params which need to be queried regularly -} - -///_______________________________________ -void ClustererDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) -{ - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); - if (mUseClusterDictionary) { - mClusterer->setDictionary((const o2::itsmft::TopologyDictionary*)obj); - } - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("ITS", "CLUSPARAM", 0)) { - LOG(info) << "Cluster param updated"; - const auto& par = o2::itsmft::ClustererParam::Instance(); - par.printKeyValues(); - return; - } -} - -DataProcessorSpec getClustererSpec(bool useMC) -{ - std::vector inputs; - inputs.emplace_back("digits", "ITS", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "ITS", "DIGITSROF", 0, Lifetime::Timeframe); - inputs.emplace_back("cldict", "ITS", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); - inputs.emplace_back("cluspar", "ITS", "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/ClustererParam")); - inputs.emplace_back("alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - false, // GRPMagField - false, // askMatLUT - o2::base::GRPGeomRequest::None, // geometry - inputs, - true); - std::vector outputs; - outputs.emplace_back("ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "PATTERNS", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); - - if (useMC) { - inputs.emplace_back("labels", "ITS", "DIGITSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("MC2ROframes", "ITS", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "its-clusterer", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC)}, - Options{ - {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, - {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}}; -} - -///_______________________________________ -void ClustererDPL::endOfStream(o2::framework::EndOfStreamContext& ec) -{ - mClusterer->print(); -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx index 82bbdd2f4d3cb..83ca14688c168 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx @@ -12,8 +12,8 @@ /// @file RecoWorkflow.cxx #include "ITSWorkflow/RecoWorkflow.h" -#include "ITSWorkflow/ClustererSpec.h" -#include "ITSWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClustererSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" #include "ITSWorkflow/TrackWriterSpec.h" #include "ITStracking/TrackingConfigParam.h" @@ -43,10 +43,10 @@ framework::WorkflowSpec getWorkflow(bool useMC, specs.emplace_back(o2::itsmft::getITSDigitReaderSpec(useMC, false, true, "itsdigits.root")); } if (!upstreamClusters) { - specs.emplace_back(o2::its::getClustererSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClustererSpec(useMC)); } if (!disableRootOutput) { - specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClusterWriterSpec(useMC)); } if ((trmode != TrackingMode::Off) && (TrackerParamConfig::Instance().trackingMode != TrackingMode::Off)) { if (useGPUWF) { diff --git a/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt b/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt index acb3d0b3e835f..b83699498a6b8 100644 --- a/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt @@ -12,8 +12,6 @@ o2_add_library(MFTWorkflow TARGETVARNAME targetName SOURCES src/RecoWorkflow.cxx - src/ClustererSpec.cxx - src/ClusterWriterSpec.cxx src/TrackerSpec.cxx src/TrackReaderSpec.cxx src/TrackWriterSpec.cxx diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h deleted file mode 100644 index 51dc5a6481eb5..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterWriterSpec.h - -#ifndef O2_MFT_CLUSTERWRITER_H_ -#define O2_MFT_CLUSTERWRITER_H_ - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace mft -{ - -/// create a processor spec -/// write MFT clusters a root file -framework::DataProcessorSpec getClusterWriterSpec(bool useMC); - -} // namespace mft -} // namespace o2 - -#endif /* O2_MFT_CLUSTERWRITER_H */ diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx deleted file mode 100644 index c8061310e34f6..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterWriterSpec.cxx - -#include - -#include "MFTWorkflow/ClusterWriterSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace mft -{ - -template -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; -using CompClusType = std::vector; -using PatternsType = std::vector; -using ROFrameRType = std::vector; -using LabelsType = o2::dataformats::MCTruthContainer; -using ROFRecLblT = std::vector; -using namespace o2::header; - -DataProcessorSpec getClusterWriterSpec(bool useMC) -{ - // Spectators for logging - // this is only to restore the original behavior - auto compClustersSize = std::make_shared(0); - auto compClustersSizeGetter = [compClustersSize](CompClusType const& compClusters) { - *compClustersSize = compClusters.size(); - }; - auto logger = [compClustersSize](std::vector const& rofs) { - LOG(info) << "MFTClusterWriter pulled " << *compClustersSize << " clusters, in " << rofs.size() << " RO frames"; - }; - return MakeRootTreeWriterSpec("mft-cluster-writer", - "mftclusters.root", - MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with MFT clusters"}, - BranchDefinition{InputSpec{"compclus", "MFT", "COMPCLUSTERS", 0}, - "MFTClusterComp", - compClustersSizeGetter}, - BranchDefinition{InputSpec{"patterns", "MFT", "PATTERNS", 0}, - "MFTClusterPatt"}, - BranchDefinition{InputSpec{"ROframes", "MFT", "CLUSTERSROF", 0}, - "MFTClustersROF", - logger}, - BranchDefinition{InputSpec{"labels", "MFT", "CLUSTERSMCTR", 0}, - "MFTClusterMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition{InputSpec{"MC2ROframes", "MFT", "CLUSTERSMC2ROF", 0}, - "MFTClustersMC2ROF", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""})(); -} - -} // namespace mft -} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx deleted file mode 100644 index 766d7c1a0729e..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClustererSpec.cxx - -#include - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/CCDBParamSpec.h" -#include "MFTWorkflow/ClustererSpec.h" -#include "DataFormatsITSMFT/Digit.h" -#include "ITSMFTReconstruction/ChipMappingMFT.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsParameters/GRPObject.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "DetectorsBase/GeometryManager.h" -#include "MFTBase/GeometryTGeo.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "CommonConstants/LHCConstants.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "ITSMFTReconstruction/ClustererParam.h" - -using namespace o2::framework; -using namespace o2::itsmft; - -namespace o2 -{ -namespace mft -{ - -void ClustererDPL::init(InitContext& ic) -{ - mClusterer = std::make_unique(); - mClusterer->setNChips(o2::itsmft::ChipMappingMFT::getNChips()); - mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mNThreads = std::max(1, ic.options().get("nthreads")); - mState = 1; -} - -void ClustererDPL::run(ProcessingContext& pc) -{ - updateTimeDependentParams(pc); - auto digits = pc.inputs().get>("digits"); - auto rofs = pc.inputs().get>("ROframes"); - - gsl::span mc2rofs; - gsl::span labelbuffer; - if (mUseMC) { - labelbuffer = pc.inputs().get>("labels"); - mc2rofs = pc.inputs().get>("MC2ROframes"); - } - const o2::dataformats::ConstMCTruthContainerView labels(labelbuffer); - - LOG(debug) << "MFTClusterer pulled " << digits.size() << " digits, in " - << rofs.size() << " RO frames"; - - o2::itsmft::DigitPixelReader reader; - reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash()); - reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking - reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash()); - reader.setDigits(digits); - reader.setROFRecords(rofs); - if (mUseMC) { - reader.setMC2ROFRecords(mc2rofs); - reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr); - } - reader.init(); - auto orig = o2::header::gDataOriginMFT; - std::vector clusCompVec; - std::vector clusROFVec; - std::vector clusPattVec; - - std::unique_ptr> clusterLabels; - if (mUseMC) { - clusterLabels = std::make_unique>(); - } - mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get()); - pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", 0}, clusCompVec); - pc.outputs().snapshot(Output{orig, "CLUSTERSROF", 0}, clusROFVec); - pc.outputs().snapshot(Output{orig, "PATTERNS", 0}, clusPattVec); - - if (mUseMC) { - pc.outputs().snapshot(Output{orig, "CLUSTERSMCTR", 0}, *clusterLabels.get()); // at the moment requires snapshot - std::vector clusterMC2ROframes(mc2rofs.size()); - for (int i = mc2rofs.size(); i--;) { - clusterMC2ROframes[i] = mc2rofs[i]; // Simply, replicate it from digits ? - } - pc.outputs().snapshot(Output{orig, "CLUSTERSMC2ROF", 0}, clusterMC2ROframes); - } - - // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF - // -> consider recalculationg maxROF - LOG(debug) << "MFTClusterer pushed " << clusCompVec.size() << " compressed clusters, in " << clusROFVec.size() << " RO frames"; -} - -///_______________________________________ -void ClustererDPL::updateTimeDependentParams(ProcessingContext& pc) -{ - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("cldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("alppar"); - pc.inputs().get*>("cluspar"); - mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::MFT)); - // settings for the fired pixel overflow masking - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); - const auto& clParams = o2::itsmft::ClustererParam::Instance(); - if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) { - LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToSquashBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias); - } - mClusterer->setDropHugeClusters(clParams.dropHugeClusters); - auto nbc = clParams.maxBCDiffToMaskBias; - nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); - mClusterer->setMaxBCSeparationToMask(nbc); - mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); - // Squasher - int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC - mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias); - int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0. - if (clParams.maxSOTMUS > 0 && rofBC > 0) { - nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing - } - mClusterer->setMaxROFDepthToSquash(nROFsToSquash); - mClusterer->print(); - } - // we may have other params which need to be queried regularly -} - -///_______________________________________ -void ClustererDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) -{ - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (matcher == ConcreteDataMatcher("MFT", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); - if (mUseClusterDictionary) { - mClusterer->setDictionary((const TopologyDictionary*)obj); - } - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("MFT", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("MFT", "CLUSPARAM", 0)) { - LOG(info) << "Cluster param updated"; - const auto& par = o2::itsmft::ClustererParam::Instance(); - par.printKeyValues(); - return; - } -} - -DataProcessorSpec getClustererSpec(bool useMC) -{ - std::vector inputs; - inputs.emplace_back("digits", "MFT", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "MFT", "DIGITSROF", 0, Lifetime::Timeframe); - inputs.emplace_back("cldict", "MFT", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/ClusterDictionary")); - inputs.emplace_back("cluspar", "MFT", "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec("MFT/Config/ClustererParam")); - inputs.emplace_back("alppar", "MFT", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("MFT/Config/AlpideParam")); - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - false, // GRPMagField - false, // askMatLUT - o2::base::GRPGeomRequest::None, // geometry - inputs, - true); - std::vector outputs; - outputs.emplace_back("MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "PATTERNS", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSROF", 0, Lifetime::Timeframe); - - if (useMC) { - inputs.emplace_back("labels", "MFT", "DIGITSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("MC2ROframes", "MFT", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "mft-clusterer", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC)}, - Options{ - {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, - {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}}; -} - -} // namespace mft -} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx index 615c9c1b275d4..5d85c0ef81670 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx @@ -12,9 +12,9 @@ /// @file RecoWorkflow.cxx #include +#include "ITSMFTWorkflow/ClustererSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "MFTWorkflow/RecoWorkflow.h" -#include "MFTWorkflow/ClustererSpec.h" -#include "MFTWorkflow/ClusterWriterSpec.h" #include "MFTWorkflow/TrackerSpec.h" #include "MFTWorkflow/TrackWriterSpec.h" #include "ITSMFTWorkflow/DigitReaderSpec.h" @@ -52,10 +52,10 @@ framework::WorkflowSpec getWorkflow( } } if (!upstreamClusters) { - specs.emplace_back(o2::mft::getClustererSpec(useMC)); + specs.emplace_back(o2::itsmft::getMFTClustererSpec(useMC)); } if (!disableRootOutput) { - specs.emplace_back(o2::mft::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getMFTClusterWriterSpec(useMC)); } if (runTracking) { diff --git a/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx index f42b2e0c92a4a..b656970693808 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "MFTWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "Framework/ConfigParamSpec.h" #include "Framework/CompletionPolicyHelpers.h" @@ -34,6 +34,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { auto useMC = !configcontext.options().get("disable-mc"); WorkflowSpec specs; - specs.emplace_back(o2::mft::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getMFTClusterWriterSpec(useMC)); return specs; } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h index 960ce2ca33d5b..2b50895658798 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h @@ -213,13 +213,15 @@ class Clusterer int getMaxRowColDiffToMask() const { return mMaxRowColDiffToMask; } void setMaxRowColDiffToMask(int v) { mMaxRowColDiffToMask = v; } - int getMaxROFDepthToSquash() const { return mSquashingDepth; } + int getMaxROFDepthToSquash(int layer = -1) const { return (layer < 0) ? mSquashingDepth : mSquashingLayerDepth[layer]; } void setMaxROFDepthToSquash(int v) { mSquashingDepth = v; } + void addMaxROFDepthToSquash(int v) { mSquashingLayerDepth.push_back(v); } - int getMaxBCSeparationToSquash() const { return mMaxBCSeparationToSquash; } + int getMaxBCSeparationToSquash(int layer = -1) const { return (layer < 0) ? mMaxBCSeparationToSquash : mMaxBCSeparationToSquashLayer[layer]; } void setMaxBCSeparationToSquash(int n) { mMaxBCSeparationToSquash = n; } + void addMaxBCSeparationToSquash(int n) { mMaxBCSeparationToSquashLayer.push_back(n); } - void print() const; + void print(bool showTiming = true) const; void clear(); void reset(); @@ -243,7 +245,7 @@ class Clusterer bool mContinuousReadout = true; ///< flag continuous readout bool mDropHugeClusters = false; ///< don't include clusters that would be split in more than one - ///< mask continuosly fired pixels in frames separated by less than this amount of BCs (fired from hit in prev. ROF) + ///< mask continuously fired pixels in frames separated by less than this amount of BCs (fired from hit in prev. ROF) int mMaxBCSeparationToMask = 6000. / o2::constants::lhc::LHCBunchSpacingNS + 10; int mMaxRowColDiffToMask = 0; ///< provide their difference in col/row is <= than this int mNHugeClus = 0; ///< number of encountered huge clusters @@ -251,6 +253,8 @@ class Clusterer ///< Squashing options int mSquashingDepth = 0; ///< squashing is applied to next N rofs int mMaxBCSeparationToSquash = 6000. / o2::constants::lhc::LHCBunchSpacingNS + 10; + std::vector mSquashingLayerDepth; + std::vector mMaxBCSeparationToSquashLayer; std::vector> mThreads; // buffers for threads std::vector mChips; // currently processed ROF's chips data @@ -286,7 +290,7 @@ void Clusterer::streamCluster(const std::vector& pixbuf, const std::a uint16_t row = bbox.rowMin, col = bbox.colMin; if (pattID == CompCluster::InvalidPatternID || pattIdConverter.isGroup(pattID)) { if (pattID != CompCluster::InvalidPatternID) { - // For groupped topologies, the reference pixel is the COG pixel + // For grouped topologies, the reference pixel is the COG pixel float xCOG = 0., zCOG = 0.; ClusterPattern::getCOG(rowSpanW, colSpanW, patt.data(), xCOG, zCOG); row += round(xCOG); diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h index a71e5f3095b06..fef9a75765353 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h @@ -29,16 +29,36 @@ template struct ClustererParam : public o2::conf::ConfigurableParamHelper> { static_assert(N == o2::detectors::DetID::ITS || N == o2::detectors::DetID::MFT, "only DetID::ITS or DetID:: MFT are allowed"); + static constexpr int getNLayers() + { + return N == o2::detectors::DetID::ITS ? 7 : 10; + } + static constexpr std::string_view getParamName() { return N == o2::detectors::DetID::ITS ? ParamName[0] : ParamName[1]; } - int maxRowColDiffToMask = DEFRowColDiffToMask(); ///< pixel may be masked as overflow if such a neighbour in prev frame was fired - int maxBCDiffToMaskBias = 10; ///< mask if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable masking - int maxBCDiffToSquashBias = -10; ///< squash if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable squashing - float maxSOTMUS = 8.; ///< max expected signal over threshold in \mus - bool dropHugeClusters = false; ///< option to drop huge clusters (mitigate beam background) + int maxRowColDiffToMask = DEFRowColDiffToMask(); ///< pixel may be masked as overflow if such a neighbour in prev frame was fired + int maxBCDiffToMaskBias = 10; ///< mask if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable masking + int maxBCDiffToSquashBias = -10; ///< squash if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable squashing + float maxSOTMUS = 8.; ///< max expected signal over threshold in \mus + bool dropHugeClusters = false; ///< option to drop huge clusters (mitigate beam background) + int maxBCDiffToSquashBiasLayer[getNLayers()] = {}; ///< squash mask per layer + int getMaxBCDiffToSquashBias(int layer) const noexcept + { + bool stag{false}; + for (int i{0}; i < getNLayers(); ++i) { + if (maxBCDiffToSquashBiasLayer[i] != 0) { + stag = true; + break; + } + } + if (stag) { + return maxBCDiffToSquashBiasLayer[layer]; + } + return maxBCDiffToSquashBias; + } O2ParamDef(ClustererParam, getParamName().data()); @@ -46,7 +66,7 @@ struct ClustererParam : public o2::conf::ConfigurableParamHelper(nFired, nThreads); #ifndef WITH_OPENMP nThreads = 1; #endif @@ -171,7 +166,7 @@ void Clusterer::ClustererThread::process(uint16_t chip, uint16_t nChips, CompClu const ConstMCTruth* labelsDigPtr, MCTruth* labelsClPtr, const ROFRecord& rofPtr) { if (stats.empty() || stats.back().firstChip + stats.back().nChips != chip) { // there is a jump, register new block - stats.emplace_back(ThreadStat{chip, 0, uint32_t(compClusPtr->size()), patternsPtr ? uint32_t(patternsPtr->size()) : 0, 0, 0}); + stats.emplace_back(ThreadStat{.firstChip = chip, .nChips = 0, .firstClus = uint32_t(compClusPtr->size()), .firstPatt = patternsPtr ? uint32_t(patternsPtr->size()) : 0, .nClus = 0, .nPatt = 0}); } for (int ic = 0; ic < nChips; ic++) { auto* curChipData = parent->mFiredChipsPtr[chip + ic]; @@ -396,7 +391,7 @@ void Clusterer::ClustererThread::updateChip(const ChipPixelData* curChipData, ui continue; } if (orphan) { - expandPreCluster(ip, row, pci); // attach to the adjascent precluster + expandPreCluster(ip, row, pci); // attach to the adjacent precluster orphan = false; continue; } @@ -449,22 +444,31 @@ void Clusterer::clear() } //__________________________________________________ -void Clusterer::print() const +void Clusterer::print(bool showsTiming) const { // print settings - LOGP(info, "Clusterizer squashes overflow pixels separated by {} BC and <= {} in row/col seeking down to {} neighbour ROFs", mMaxBCSeparationToSquash, mMaxRowColDiffToMask, mSquashingDepth); + if (mSquashingLayerDepth.empty()) { + LOGP(info, "Clusterizer squashes overflow pixels separated by {} BC and <= {} in row/col seeking down to {} neighbour ROFs", mMaxBCSeparationToSquash, mMaxRowColDiffToMask, mSquashingDepth); + } else { + LOGP(info, "Clusterizer squashes overflow pixels <= {} in row/col", mMaxRowColDiffToMask); + for (size_t i{0}; i < mSquashingLayerDepth.size(); ++i) { + LOGP(info, "\tlay:{} separated by {} BC seeking down to {} neighbour ROFs", i, mMaxBCSeparationToSquashLayer[i], mSquashingLayerDepth[i]); + } + } LOGP(info, "Clusterizer masks overflow pixels separated by < {} BC and <= {} in row/col", mMaxBCSeparationToMask, mMaxRowColDiffToMask); LOGP(info, "Clusterizer does {} drop huge clusters", mDropHugeClusters ? "" : "not"); + if (showsTiming) { #ifdef _PERFORM_TIMING_ - auto& tmr = const_cast(mTimer); // ugly but this is what root does internally - auto& tmrm = const_cast(mTimerMerge); - LOG(info) << "Inclusive clusterization timing (w/o disk IO): Cpu: " << tmr.CpuTime() - << " Real: " << tmr.RealTime() << " s in " << tmr.Counter() << " slots"; - LOG(info) << "Threads output merging timing : Cpu: " << tmrm.CpuTime() - << " Real: " << tmrm.RealTime() << " s in " << tmrm.Counter() << " slots"; + auto& tmr = const_cast(mTimer); // ugly but this is what root does internally + auto& tmrm = const_cast(mTimerMerge); + LOG(info) << "Inclusive clusterization timing (w/o disk IO): Cpu: " << tmr.CpuTime() + << " Real: " << tmr.RealTime() << " s in " << tmr.Counter() << " slots"; + LOG(info) << "Threads output merging timing : Cpu: " << tmrm.CpuTime() + << " Real: " << tmrm.RealTime() << " s in " << tmrm.Counter() << " slots"; #endif + } } //__________________________________________________ diff --git a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx index b8d88a6fc4223..5c1dbde074649 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx @@ -330,3 +330,14 @@ void DigitPixelReader::clear() mROFRecVec = gsl::span(); mMC2ROFRecVec = gsl::span(); } + +//______________________________________________________________________________ +void DigitPixelReader::reset() +{ + clear(); + mSquashedDigitsMask.clear(); + mBookmarkNextROFs.clear(); + mIdDig = 0; + mIdROF = 0; + mIdROFLast = 0; +} diff --git a/Detectors/ITSMFT/common/workflow/CMakeLists.txt b/Detectors/ITSMFT/common/workflow/CMakeLists.txt index 63cd8d6c0bcee..ead08c4422260 100644 --- a/Detectors/ITSMFT/common/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/common/workflow/CMakeLists.txt @@ -11,6 +11,8 @@ o2_add_library(ITSMFTWorkflow SOURCES src/ClusterReaderSpec.cxx + src/ClusterWriterSpec.cxx + src/ClustererSpec.cxx src/DigitWriterSpec.cxx src/DigitReaderSpec.cxx src/STFDecoderSpec.cxx diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h index 99318df1cd9d9..3fe88bcf883c5 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h @@ -23,46 +23,49 @@ #include "DataFormatsITSMFT/CompCluster.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "DetectorsCommonDataFormats/DetID.h" using namespace o2::framework; -namespace o2 -{ -namespace itsmft +namespace o2::itsmft { +template class ClusterReader : public Task { public: + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{(N == o2::detectors::DetID::ITS) ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::getNLayers()}; + ClusterReader() = delete; - ClusterReader(o2::detectors::DetID id, bool useMC, bool usePatterns = true, bool triggers = true); + ClusterReader(bool useMC, bool usePatterns = true, bool triggers = true); ~ClusterReader() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; protected: void connectTree(const std::string& filename); + std::string getBranchName(const std::string& base, int index) const; - std::vector mClusROFRec, *mClusROFRecPtr = &mClusROFRec; - std::vector mClusterCompArray, *mClusterCompArrayPtr = &mClusterCompArray; - std::vector mPatternsArray, *mPatternsArrayPtr = &mPatternsArray; - o2::dataformats::MCTruthContainer mClusterMCTruth, *mClusterMCTruthPtr = &mClusterMCTruth; - std::vector mClusMC2ROFs, *mClusMC2ROFsPtr = &mClusMC2ROFs; - - o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; + std::array*, NLayers> mClusROFRec; + std::array*, NLayers> mClusterCompArray; + std::array*, NLayers> mPatternsArray; + std::array*, NLayers> mClusterMCTruth; + std::array*, NLayers> mClusMC2ROFs; std::unique_ptr mFile; std::unique_ptr mTree; - bool mUseMC = true; // use MC truth + bool mUseMC = true; // use MC truth bool mUsePatterns = true; // send patterns bool mTriggerOut = true; // send dummy triggers vector - std::string mDetName = ""; - std::string mDetNameLC = ""; - std::string mFileName = ""; + std::string mDetName; + std::string mDetNameLC; + std::string mFileName; std::string mClusTreeName = "o2sim"; std::string mClusROFBranchName = "ClustersROF"; std::string mClusterPattBranchName = "ClusterPatt"; @@ -71,24 +74,18 @@ class ClusterReader : public Task std::string mClustMC2ROFBranchName = "ClustersMC2ROF"; }; -class ITSClusterReader : public ClusterReader +class ITSClusterReader : public ClusterReader { public: ITSClusterReader(bool useMC = true, bool usePatterns = true, bool triggerOut = true) - : ClusterReader(o2::detectors::DetID::ITS, useMC, usePatterns, triggerOut) - { - mOrigin = o2::header::gDataOriginITS; - } + : ClusterReader(useMC, usePatterns, triggerOut) {} }; -class MFTClusterReader : public ClusterReader +class MFTClusterReader : public ClusterReader { public: MFTClusterReader(bool useMC = true, bool usePatterns = true, bool triggerOut = true) - : ClusterReader(o2::detectors::DetID::MFT, useMC, usePatterns, triggerOut) - { - mOrigin = o2::header::gDataOriginMFT; - } + : ClusterReader(useMC, usePatterns, triggerOut) {} }; /// create a processor spec @@ -96,7 +93,6 @@ class MFTClusterReader : public ClusterReader framework::DataProcessorSpec getITSClusterReaderSpec(bool useMC = true, bool usePatterns = true, bool useTriggers = true); framework::DataProcessorSpec getMFTClusterReaderSpec(bool useMC = true, bool usePatterns = true, bool useTriggers = true); -} // namespace itsmft -} // namespace o2 +} // namespace o2::itsmft #endif /* O2_ITSMFT_CLUSTERREADER */ diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterWriterSpec.h similarity index 73% rename from Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h rename to Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterWriterSpec.h index 42b96786af27a..5ae371e7e09c4 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterWriterSpec.h @@ -11,21 +11,19 @@ /// @file ClusterWriterSpec.h -#ifndef O2_ITS_CLUSTERWRITER -#define O2_ITS_CLUSTERWRITER +#ifndef O2_ITSMFT_CLUSTERWRITER +#define O2_ITSMFT_CLUSTERWRITER #include "Framework/DataProcessorSpec.h" -namespace o2 -{ -namespace its +namespace o2::itsmft { -/// create a processor spec -/// write ITS clusters to ROOT file +template framework::DataProcessorSpec getClusterWriterSpec(bool useMC); +framework::DataProcessorSpec getITSClusterWriterSpec(bool useMC); +framework::DataProcessorSpec getMFTClusterWriterSpec(bool useMC); -} // namespace its -} // namespace o2 +} // namespace o2::itsmft #endif /* O2_ITS_CLUSTERWRITER */ diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClustererSpec.h similarity index 66% rename from Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h rename to Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClustererSpec.h index f0a763597ff74..c5ff785568278 100644 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClustererSpec.h @@ -11,25 +11,28 @@ /// @file ClustererSpec.h -#ifndef O2_MFT_CLUSTERERDPL_H_ -#define O2_MFT_CLUSTERERDPL_H_ +#ifndef O2_ITSMFT_CLUSTERERDPL_H_ +#define O2_ITSMFT_CLUSTERERDPL_H_ -#include #include "DetectorsBase/GRPGeomHelper.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "ITSMFTReconstruction/Clusterer.h" +#include "ITSMFTBase/DPLAlpideParam.h" using namespace o2::framework; -namespace o2 -{ -namespace mft +namespace o2::itsmft { +template class ClustererDPL : public Task { public: + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::getNLayers()}; + ClustererDPL(std::shared_ptr gr, bool useMC) : mGGCCDBRequest(gr), mUseMC(useMC) {} ~ClustererDPL() override = default; void init(InitContext& ic) final; @@ -39,20 +42,21 @@ class ClustererDPL : public Task private: void updateTimeDependentParams(ProcessingContext& pc); - int mState = 0; + std::string mDetName; bool mUseMC = true; bool mUseClusterDictionary = true; int mNThreads = 1; - std::unique_ptr mFile = nullptr; std::unique_ptr mClusterer = nullptr; std::shared_ptr mGGCCDBRequest; + int mLayers{NLayers}; + std::vector mFilter; }; -/// create a processor spec -/// run MFT cluster finder +template framework::DataProcessorSpec getClustererSpec(bool useMC); +framework::DataProcessorSpec getITSClustererSpec(bool useMC); +framework::DataProcessorSpec getMFTClustererSpec(bool useMC); -} // namespace mft -} // namespace o2 +} // namespace o2::itsmft #endif /* O2_MFT_CLUSTERERDPL */ diff --git a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx index ea906056c7898..14191d83b25c2 100644 --- a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx @@ -12,15 +12,16 @@ /// @file ClusterReaderSpec.cxx #include +#include -#include "TTree.h" +#include #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/Logger.h" #include "ITSMFTWorkflow/ClusterReaderSpec.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DataFormatsITSMFT/PhysTrigger.h" -#include #include "CommonUtils/NameConf.h" using namespace o2::framework; @@ -31,45 +32,42 @@ namespace o2 namespace itsmft { -ClusterReader::ClusterReader(o2::detectors::DetID id, bool useMC, bool usePatterns, bool triggerOut) +template +ClusterReader::ClusterReader(bool useMC, bool usePatterns, bool triggerOut) : mUseMC(useMC), mUsePatterns(usePatterns), mTriggerOut(triggerOut), mDetName(Origin.as()), mDetNameLC(mDetName) { - assert(id == o2::detectors::DetID::ITS || id == o2::detectors::DetID::MFT); - mDetNameLC = mDetName = id.getName(); - mUseMC = useMC; - mUsePatterns = usePatterns; - mTriggerOut = triggerOut; std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower); } -void ClusterReader::init(InitContext& ic) +template +void ClusterReader::init(InitContext& ic) { mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), ic.options().get((mDetNameLC + "-cluster-infile").c_str())); connectTree(mFileName); } -void ClusterReader::run(ProcessingContext& pc) +template +void ClusterReader::run(ProcessingContext& pc) { auto ent = mTree->GetReadEntry() + 1; assert(ent < mTree->GetEntries()); // this should not happen mTree->GetEntry(ent); - LOG(info) << mDetName << "ClusterReader pushes " << mClusROFRec.size() << " ROFRecords," - << mClusterCompArray.size() << " compact clusters at entry " << ent; - - // This is a very ugly way of providing DataDescription, which anyway does not need to contain detector name. - // To be fixed once the names-definition class is ready - pc.outputs().snapshot(Output{mOrigin, "CLUSTERSROF", 0}, mClusROFRec); - pc.outputs().snapshot(Output{mOrigin, "COMPCLUSTERS", 0}, mClusterCompArray); - if (mUsePatterns) { - pc.outputs().snapshot(Output{mOrigin, "PATTERNS", 0}, mPatternsArray); - } - if (mUseMC) { - pc.outputs().snapshot(Output{mOrigin, "CLUSTERSMCTR", 0}, mClusterMCTruth); - pc.outputs().snapshot(Output{mOrigin, "CLUSTERSMC2ROF", 0}, mClusMC2ROFs); + + for (uint32_t iLayer = 0; iLayer < NLayers; ++iLayer) { + LOG(info) << mDetName << "ClusterReader:" << iLayer << " pushes " << mClusROFRec[iLayer]->size() << " ROFRecords, " << mClusterCompArray[iLayer]->size() << " compact clusters at entry " << ent; + pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, *mClusROFRec[iLayer]); + pc.outputs().snapshot(Output{Origin, "COMPCLUSTERS", iLayer}, *mClusterCompArray[iLayer]); + if (mUsePatterns) { + pc.outputs().snapshot(Output{Origin, "PATTERNS", iLayer}, *mPatternsArray[iLayer]); + } + if (mUseMC) { + pc.outputs().snapshot(Output{Origin, "CLUSTERSMCTR", iLayer}, *mClusterMCTruth[iLayer]); + pc.outputs().snapshot(Output{Origin, "CLUSTERSMC2ROF", iLayer}, *mClusMC2ROFs[iLayer]); + } } if (mTriggerOut) { std::vector dummyTrig; - pc.outputs().snapshot(Output{mOrigin, "PHYSTRIG", 0}, dummyTrig); + pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig); } if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get().endOfStream(); @@ -77,7 +75,8 @@ void ClusterReader::run(ProcessingContext& pc) } } -void ClusterReader::connectTree(const std::string& filename) +template +void ClusterReader::connectTree(const std::string& filename) { mTree.reset(nullptr); // in case it was already loaded mFile.reset(TFile::Open(filename.c_str())); @@ -85,70 +84,76 @@ void ClusterReader::connectTree(const std::string& filename) mTree.reset((TTree*)mFile->Get(mClusTreeName.c_str())); assert(mTree); - mTree->SetBranchAddress((mDetName + mClusROFBranchName).c_str(), &mClusROFRecPtr); - mTree->SetBranchAddress((mDetName + mClusterCompBranchName).c_str(), &mClusterCompArrayPtr); - if (mUsePatterns) { - mTree->SetBranchAddress((mDetName + mClusterPattBranchName).c_str(), &mPatternsArrayPtr); - } - if (mUseMC) { - if (mTree->GetBranch((mDetName + mClustMCTruthBranchName).c_str()) && - mTree->GetBranch((mDetName + mClustMC2ROFBranchName).c_str())) { - mTree->SetBranchAddress((mDetName + mClustMCTruthBranchName).c_str(), &mClusterMCTruthPtr); - mTree->SetBranchAddress((mDetName + mClustMC2ROFBranchName).c_str(), &mClusMC2ROFsPtr); - } else { - LOG(info) << "MC-truth is missing"; - mUseMC = false; + for (uint32_t iLayer = 0; iLayer < NLayers; ++iLayer) { + mTree->SetBranchAddress(getBranchName(mClusROFBranchName, iLayer).c_str(), &mClusROFRec[iLayer]); + mTree->SetBranchAddress(getBranchName(mClusterCompBranchName, iLayer).c_str(), &mClusterCompArray[iLayer]); + if (mUsePatterns) { + mTree->SetBranchAddress(getBranchName(mClusterPattBranchName, iLayer).c_str(), &mPatternsArray[iLayer]); + } + if (mUseMC) { + if (mTree->GetBranch(getBranchName(mClustMCTruthBranchName, iLayer).c_str()) && + mTree->GetBranch(getBranchName(mClustMC2ROFBranchName, iLayer).c_str())) { + mTree->SetBranchAddress(getBranchName(mClustMCTruthBranchName, iLayer).c_str(), &mClusterMCTruth[iLayer]); + mTree->SetBranchAddress(getBranchName(mClustMC2ROFBranchName, iLayer).c_str(), &mClusMC2ROFs[iLayer]); + } else { + LOG(info) << "MC-truth is missing"; + mUseMC = false; + } } } LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; } -DataProcessorSpec getITSClusterReaderSpec(bool useMC, bool usePatterns, bool triggerOut) +template +std::string ClusterReader::getBranchName(const std::string& base, int index) const { - std::vector outputSpec; - outputSpec.emplace_back("ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - if (usePatterns) { - outputSpec.emplace_back("ITS", "PATTERNS", 0, Lifetime::Timeframe); - } - if (useMC) { - outputSpec.emplace_back("ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); + return mDetName + base + "_" + std::to_string(index); +} + +namespace +{ +template +std::vector makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth, bool usePatterns, bool triggerOut) +{ + std::vector outputs; + for (int iLayer = 0; iLayer < o2::itsmft::DPLAlpideParam::getNLayers(); ++iLayer) { + outputs.emplace_back(detOrig, "CLUSTERSROF", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "COMPCLUSTERS", iLayer, Lifetime::Timeframe); + if (usePatterns) { + outputs.emplace_back(detOrig, "PATTERNS", iLayer, Lifetime::Timeframe); + } + if (mctruth) { + outputs.emplace_back(detOrig, "CLUSTERSMCTR", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "CLUSTERSMC2ROF", iLayer, Lifetime::Timeframe); + } } if (triggerOut) { - outputSpec.emplace_back("ITS", "PHYSTRIG", 0, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "PHYSTRIG", 0, Lifetime::Timeframe); } + return outputs; +} +} // namespace + +DataProcessorSpec getITSClusterReaderSpec(bool useMC, bool usePatterns, bool triggerOut) +{ return DataProcessorSpec{ - "its-cluster-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, - Options{ + .name = "its-cluster-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels("ITS", useMC, usePatterns, triggerOut), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, + .options = Options{ {"its-cluster-infile", VariantType::String, "o2clus_its.root", {"Name of the input cluster file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } DataProcessorSpec getMFTClusterReaderSpec(bool useMC, bool usePatterns, bool triggerOut) { - std::vector outputSpec; - outputSpec.emplace_back("MFT", "CLUSTERSROF", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe); - if (usePatterns) { - outputSpec.emplace_back("MFT", "PATTERNS", 0, Lifetime::Timeframe); - } - if (useMC) { - outputSpec.emplace_back("MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } - if (triggerOut) { - outputSpec.emplace_back("MFT", "PHYSTRIG", 0, Lifetime::Timeframe); - } return DataProcessorSpec{ - "mft-cluster-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, - Options{ + .name = "mft-cluster-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels("MFT", useMC, usePatterns, triggerOut), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, + .options = Options{ {"mft-cluster-infile", VariantType::String, "mftclusters.root", {"Name of the input cluster file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } diff --git a/Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx new file mode 100644 index 0000000000000..e9c917fdaa820 --- /dev/null +++ b/Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx @@ -0,0 +1,104 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.cxx + +#include +#include +#include +#include +#include + +#include "Framework/ConcreteDataMatcher.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2::itsmft +{ + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; +using CompClusType = std::vector; +using PatternsType = std::vector; +using ROFrameRType = std::vector; +using LabelsType = o2::dataformats::MCTruthContainer; +using ROFRecLblT = std::vector; +using namespace o2::header; + +template +DataProcessorSpec getClusterWriterSpec(bool useMC) +{ + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + constexpr int NLayers = o2::itsmft::DPLAlpideParam::getNLayers(); + const auto detName = Origin.as(); + // Spectators for logging + auto compClusterSizes = std::make_shared>(); + auto compClustersSizeGetter = [compClusterSizes](CompClusType const& compClusters, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + (*compClusterSizes)[dh->subSpecification] = compClusters.size(); + }; + auto logger = [detName, compClusterSizes](std::vector const& rofs, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + const auto i = dh->subSpecification; + LOG(info) << detName << "ClusterWriter:" << i << " pulled " << (*compClusterSizes)[i] << " clusters, in " << rofs.size() << " RO frames"; + }; + auto getIndex = [](DataRef const& ref) -> size_t { + auto const* dh = DataRefUtils::getHeader(ref); + return static_cast(dh->subSpecification); + }; + auto getName = [](std::string base, size_t index) -> std::string { + return base += "_" + std::to_string(index); + }; + auto detNameLC = detName; + std::transform(detNameLC.begin(), detNameLC.end(), detNameLC.begin(), [](unsigned char c) { return std::tolower(c); }); + return MakeRootTreeWriterSpec(std::format("{}-cluster-writer", detNameLC).c_str(), + (o2::detectors::DetID::ITS == N) ? "o2clus_its.root" : "mftclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{.name = "o2sim", .title = std::format("Tree with {} clusters", detName)}, + BranchDefinition{InputSpec{"compclus", ConcreteDataTypeMatcher{Origin, "COMPCLUSTERS"}}, + (detName + "ClusterComp").c_str(), "compact-cluster-branch", + NLayers, + compClustersSizeGetter, + getIndex, + getName}, + BranchDefinition{InputSpec{"patterns", ConcreteDataTypeMatcher{Origin, "PATTERNS"}}, + (detName + "ClusterPatt").c_str(), "cluster-pattern-branch", + NLayers, + getIndex, + getName}, + BranchDefinition{InputSpec{"ROframes", ConcreteDataTypeMatcher{Origin, "CLUSTERSROF"}}, + (detName + "ClustersROF").c_str(), "cluster-rof-branch", + NLayers, + logger, + getIndex, + getName}, + BranchDefinition{InputSpec{"labels", ConcreteDataTypeMatcher{Origin, "CLUSTERSMCTR"}}, + (detName + "ClusterMCTruth").c_str(), "cluster-label-branch", + (useMC ? NLayers : 0), + getIndex, + getName}, + BranchDefinition{InputSpec{"MC2ROframes", ConcreteDataTypeMatcher{Origin, "CLUSTERSMC2ROF"}}, + (detName + "ClustersMC2ROF").c_str(), "cluster-mc2rof-branch", + (useMC ? NLayers : 0), + getIndex, + getName})(); +} + +framework::DataProcessorSpec getITSClusterWriterSpec(bool useMC) { return getClusterWriterSpec(useMC); } +framework::DataProcessorSpec getMFTClusterWriterSpec(bool useMC) { return getClusterWriterSpec(useMC); } + +} // namespace o2::itsmft diff --git a/Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx new file mode 100644 index 0000000000000..2bf19e23ab80a --- /dev/null +++ b/Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx @@ -0,0 +1,329 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClustererSpec.cxx + +#include + +#include "ITSMFTWorkflow/ClustererSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" +#include "DataFormatsITSMFT/Digit.h" +#include "Framework/InputRecordWalker.h" +#include "ITSMFTReconstruction/ChipMappingMFT.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsParameters/GRPObject.h" +#include "ITSMFTReconstruction/DigitPixelReader.h" +#include "DetectorsBase/GeometryManager.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "CommonConstants/LHCConstants.h" +#include "DetectorsCommonDataFormats/DetectorNameConf.h" +#include "ITSMFTReconstruction/ClustererParam.h" + +namespace o2::itsmft +{ + +template +void ClustererDPL::init(InitContext& ic) +{ + mClusterer = std::make_unique(); + mClusterer->setNChips((N == o2::detectors::DetID::ITS) ? o2::itsmft::ChipMappingITS::getNChips() : o2::itsmft::ChipMappingMFT::getNChips()); + mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + mNThreads = std::max(1, ic.options().get("nthreads")); + mDetName = Origin.as(); + + // prepare data filter + for (int iLayer = 0; iLayer < NLayers; ++iLayer) { + mFilter.emplace_back("digits", Origin, "DIGITS", iLayer, Lifetime::Timeframe); + mFilter.emplace_back("ROframe", Origin, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (mUseMC) { + mFilter.emplace_back("labels", Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + mFilter.emplace_back("MC2ROframes", Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + } + } +} + +template +void ClustererDPL::run(ProcessingContext& pc) +{ + updateTimeDependentParams(pc); + + // filter input and compose + std::array, NLayers> digits; + std::array, NLayers> rofs; + std::array, NLayers> labelsbuffer; + std::array, NLayers> mc2rofs; + for (const DataRef& ref : InputRecordWalker{pc.inputs(), mFilter}) { + auto const* dh = DataRefUtils::getHeader(ref); + if (DataRefUtils::match(ref, {"digits", ConcreteDataTypeMatcher{Origin, "DIGITS"}})) { + digits[dh->subSpecification] = pc.inputs().get>(ref); + } + if (DataRefUtils::match(ref, {"ROframe", ConcreteDataTypeMatcher{Origin, "DIGITSROF"}})) { + rofs[dh->subSpecification] = pc.inputs().get>(ref); + } + if (DataRefUtils::match(ref, {"labels", ConcreteDataTypeMatcher{Origin, "DIGITSMCTR"}})) { + labelsbuffer[dh->subSpecification] = pc.inputs().get>(ref); + } + if (DataRefUtils::match(ref, {"MC2ROframes", ConcreteDataTypeMatcher{Origin, "DIGITSMC2ROF"}})) { + mc2rofs[dh->subSpecification] = pc.inputs().get>(ref); + } + } + + // query the first orbit in this TF + const auto firstTForbit = pc.services().get().firstTForbit; + const o2::InteractionRecord firstIR(0, firstTForbit); + const auto& par = DPLAlpideParam::Instance(); + + // process received inputs + uint64_t nClusters{0}; + TStopwatch sw; + o2::itsmft::DigitPixelReader reader; + for (uint32_t iLayer = 0; iLayer < ((DPLAlpideParam::supportsStaggering()) ? NLayers : 1); ++iLayer) { + int layer = (DPLAlpideParam::supportsStaggering()) ? iLayer : -1; + sw.Start(); + LOG(info) << mDetName << "Clusterer:" << iLayer << " pulled " << digits[iLayer].size() << " digits, in " << rofs[iLayer].size() << " RO frames"; + + mClusterer->setMaxROFDepthToSquash(mClusterer->getMaxROFDepthToSquash(layer)); + o2::dataformats::ConstMCTruthContainerView labels(labelsbuffer[iLayer]); + reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash(layer)); + reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking + reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash(layer)); + reader.setDigits(digits[iLayer]); + reader.setROFRecords(rofs[iLayer]); + if (mUseMC) { + reader.setMC2ROFRecords(mc2rofs[iLayer]); + LOG(info) << mDetName << "Clusterer:" << iLayer << " pulled " << labels.getNElements() << " labels "; + reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr); + } + reader.init(); + std::vector clusCompVec; + std::vector clusROFVec; + std::vector clusPattVec; + + std::unique_ptr> clusterLabels; + if (mUseMC) { + clusterLabels = std::make_unique>(); + } + mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get()); + + // ensure that the rof output is continuous + size_t nROFs = clusROFVec.size(); + const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer); + const int nROFsTF = nROFsPerOrbit * o2::base::GRPGeomHelper::getNHBFPerTF(); + if (nROFsTF != clusROFVec.size()) { + // it can happen that in the digitization rofs without contributing hits are skipped + // however downstream consumers of the clusters cannot know apriori the time structure + // the cluster rofs do not account for the bias so it will start always at BC=0 + std::vector expClusRofVec(nROFsTF); + for (int iROF{0}; iROF < nROFsTF; ++iROF) { + auto& rof = expClusRofVec[iROF]; + int orb = iROF * par.getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + firstTForbit; + int bc = iROF * par.getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches; + o2::InteractionRecord ir(bc, orb); + rof.setBCData(ir); + rof.setROFrame(iROF); + rof.setNEntries(0); + rof.setFirstEntry(-1); + } + uint32_t prevEntry{0}; + for (const auto& rof : clusROFVec) { + const auto& ir = rof.getBCData(); + const auto irToFirst = ir - firstIR; + const int irROF = irToFirst.toLong() / par.getROFLengthInBC(iLayer); + auto& expROF = expClusRofVec[irROF]; + expROF.setFirstEntry(rof.getFirstEntry()); + expROF.setNEntries(rof.getNEntries()); + if (expROF.getBCData() != rof.getBCData()) { + LOGP(fatal, "detected mismatch between expected ROF:{} and received ROF:{}", expROF.asString(), rof.asString()); + } + } + int prevFirst{0}; + for (auto& rof : expClusRofVec) { + if (rof.getFirstEntry() < 0) { + rof.setFirstEntry(prevFirst); + } + prevFirst = rof.getFirstEntry(); + } + nROFs = expClusRofVec.size(); + pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, expClusRofVec); + } else { + pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, clusROFVec); + } + pc.outputs().snapshot(Output{Origin, "COMPCLUSTERS", iLayer}, clusCompVec); + pc.outputs().snapshot(Output{Origin, "PATTERNS", iLayer}, clusPattVec); + + nClusters += clusCompVec.size(); + + if (mUseMC) { + pc.outputs().snapshot(Output{Origin, "CLUSTERSMCTR", iLayer}, *clusterLabels); // at the moment requires snapshot + std::vector clusterMC2ROframes(mc2rofs[iLayer].size()); + for (int i = mc2rofs[iLayer].size(); i--;) { + clusterMC2ROframes[i] = mc2rofs[iLayer][i]; // Simply, replicate it from digits ? + } + pc.outputs().snapshot(Output{Origin, "CLUSTERSMC2ROF", iLayer}, clusterMC2ROframes); + } + reader.reset(); + + // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF + // -> consider recalculationg maxROF + sw.Stop(); + LOG(info) << mDetName << "Clusterer:" << iLayer << " pushed " << clusCompVec.size() << " clusters, in " << nROFs << " RO frames in " << sw.RealTime() << " s"; + } + if constexpr (!DPLAlpideParam::supportsStaggering()) { // need to send dummy data for the rest + for (uint32_t iLayer = 1; iLayer < NLayers; ++iLayer) { + pc.outputs().make>(Output{Origin, "COMPCLUSTERS", iLayer}); + pc.outputs().make>(Output{Origin, "CLUSTERSROF", iLayer}); + pc.outputs().make>(Output{Origin, "PATTERNS", iLayer}); + if (mUseMC) { + auto& sl = pc.outputs().make>(Output{Origin, "CLUSTERSMCTR", iLayer}); + pc.outputs().make>(Output{Origin, "CLUSTERSMC2ROF", iLayer}); + } + } + } + + LOG(info) << mDetName << "Clusterer produced " << nClusters << " clusters"; +} + +///_______________________________________ +template +void ClustererDPL::updateTimeDependentParams(ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + static bool initOnceDone = false; + if (!initOnceDone) { // this params need to be queried only once + initOnceDone = true; + pc.inputs().get("cldict"); // just to trigger the finaliseCCDB + pc.inputs().get*>("alppar"); + pc.inputs().get*>("cluspar"); + mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(N)); + // settings for the fired pixel overflow masking + const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); + const auto& clParams = o2::itsmft::ClustererParam::Instance(); + if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) { + LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToSquashBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias); + } + mClusterer->setDropHugeClusters(clParams.dropHugeClusters); + auto nbc = clParams.maxBCDiffToMaskBias; + nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); + mClusterer->setMaxBCSeparationToMask(nbc); + mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); + // Squasher + int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC + mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias); + int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0. + if (clParams.maxSOTMUS > 0 && rofBC > 0) { + nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing + } + mClusterer->setMaxROFDepthToSquash(nROFsToSquash); + if constexpr (DPLAlpideParam::supportsStaggering()) { + if (mClusterer->isContinuousReadOut()) { + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + mClusterer->addMaxBCSeparationToSquash(alpParams.getROFLengthInBC(iLayer) + clParams.getMaxBCDiffToSquashBias(iLayer)); + mClusterer->addMaxROFDepthToSquash((clParams.getMaxBCDiffToSquashBias(iLayer) > 0) ? 2 + int(clParams.maxSOTMUS / (alpParams.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingMUS)) : 0); + } + } + } + mClusterer->print(false); + } + // we may have other params which need to be queried regularly +} + +///_______________________________________ +template +void ClustererDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (matcher == ConcreteDataMatcher(Origin, "CLUSDICT", 0)) { + LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); + if (mUseClusterDictionary) { + mClusterer->setDictionary((const TopologyDictionary*)obj); + } + return; + } + // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level + if (matcher == ConcreteDataMatcher(Origin, "ALPIDEPARAM", 0)) { + LOG(info) << "Alpide param updated"; + const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + par.printKeyValues(); + return; + } + if (matcher == ConcreteDataMatcher(Origin, "CLUSPARAM", 0)) { + LOG(info) << "Cluster param updated"; + const auto& par = o2::itsmft::ClustererParam::Instance(); + par.printKeyValues(); + return; + } +} + +template +DataProcessorSpec getClustererSpec(bool useMC) +{ + constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + std::vector inputs; + for (uint32_t iLayer = 0; iLayer < o2::itsmft::DPLAlpideParam::getNLayers(); ++iLayer) { + inputs.emplace_back("digits", Origin, "DIGITS", iLayer, Lifetime::Timeframe); + inputs.emplace_back("ROframes", Origin, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (useMC) { + inputs.emplace_back("labels", Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + inputs.emplace_back("MC2ROframes", Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + } + } + inputs.emplace_back("cldict", Origin, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(Origin.as() + "/Calib/ClusterDictionary")); + inputs.emplace_back("cluspar", Origin, "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as() + "/Config/ClustererParam")); + inputs.emplace_back("alppar", Origin, "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as() + "/Config/AlpideParam")); + auto ggRequest = std::make_shared(false, // orbitResetTime + true, // GRPECS=true + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs, + true); + std::vector outputs; + for (uint32_t iLayer = 0; iLayer < o2::itsmft::DPLAlpideParam::getNLayers(); ++iLayer) { + outputs.emplace_back(Origin, "COMPCLUSTERS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "PATTERNS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "CLUSTERSROF", iLayer, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(Origin, "CLUSTERSMCTR", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "CLUSTERSMC2ROF", iLayer, Lifetime::Timeframe); + } + } + return DataProcessorSpec{ + .name = (N == o2::detectors::DetID::ITS) ? "its-clusterer" : "mft-clusterer", + .inputs = inputs, + .outputs = outputs, + .algorithm = AlgorithmSpec{adaptFromTask>(ggRequest, useMC)}, + .options = Options{ + {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, + {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}}; +} + +framework::DataProcessorSpec getITSClustererSpec(bool useMC) +{ + return getClustererSpec(useMC); +} + +framework::DataProcessorSpec getMFTClustererSpec(bool useMC) +{ + return getClustererSpec(useMC); +} + +} // namespace o2::itsmft diff --git a/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx b/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx index 8a1c1ef73cf2b..85dcf6752d497 100644 --- a/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx +++ b/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx @@ -12,7 +12,7 @@ #include "ITS3Workflow/RecoWorkflow.h" #include "ITS3Workflow/ClustererSpec.h" #include "ITS3Workflow/TrackerSpec.h" -#include "ITSWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackWriterSpec.h" #include "ITS3Workflow/DigitReaderSpec.h" #include "GPUWorkflow/GPUWorkflowSpec.h" @@ -40,7 +40,7 @@ framework::WorkflowSpec getWorkflow(bool useMC, its::TrackingMode::Type trmode, } if (!disableRootOutput) { - specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClusterWriterSpec(useMC)); } if (trmode != its::TrackingMode::Off) { From f965d0a688fc5a0741784b815db82bcf686c0520 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 10 Nov 2025 10:19:52 +0100 Subject: [PATCH 10/13] ITSMFT: CTF decoder output per layer Signed-off-by: Felix Schlepper --- .../CTF/workflow/src/ctf-reader-workflow.cxx | 4 +- .../ITSMFTWorkflow/EntropyDecoderSpec.h | 30 ++- .../workflow/src/EntropyDecoderSpec.cxx | 186 +++++++++++++----- 3 files changed, 152 insertions(+), 68 deletions(-) diff --git a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx index cddf694251a01..6beb828aaab2e 100644 --- a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx @@ -181,10 +181,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // add decoders for all allowed detectors. if (ctfInput.detMask[DetID::ITS]) { - addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::ITS), verbosity, configcontext.options().get("its-digits"), ctfInput.subspec)); + addSpecs(o2::itsmft::getITSEntropyDecoderSpec(verbosity, configcontext.options().get("its-digits"), ctfInput.subspec)); } if (ctfInput.detMask[DetID::MFT]) { - addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::MFT), verbosity, configcontext.options().get("mft-digits"), ctfInput.subspec)); + addSpecs(o2::itsmft::getMFTEntropyDecoderSpec(verbosity, configcontext.options().get("mft-digits"), ctfInput.subspec)); } if (ctfInput.detMask[DetID::TPC]) { addSpecs(o2::tpc::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h index 4ed4e99f4b6f8..064c245c04c1a 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h @@ -20,49 +20,45 @@ #include "Headers/DataHeader.h" #include "ITSMFTReconstruction/CTFCoder.h" #include "DataFormatsITSMFT/NoiseMap.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "ITSMFTReconstruction/LookUp.h" #include -#include -namespace o2 -{ -namespace itsmft +namespace o2::itsmft { +template class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits = false); + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::getNLayers()}; + static constexpr const char* DeviceName{N == o2::detectors::DetID::ITS ? "its-entropy-decoder" : "mft-entropy-decoder"}; + + EntropyDecoderSpec(int verbosity, bool getDigits = false); ~EntropyDecoderSpec() override = default; void init(o2::framework::InitContext& ic) final; void run(o2::framework::ProcessingContext& pc) final; void endOfStream(o2::framework::EndOfStreamContext& ec) final; void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final; - static auto getName(o2::header::DataOrigin orig) { return std::string{orig == o2::header::gDataOriginITS ? ITSDeviceName : MFTDeviceName}; } - private: void updateTimeDependentParams(o2::framework::ProcessingContext& pc); - static constexpr std::string_view ITSDeviceName = "its-entropy-decoder"; - static constexpr std::string_view MFTDeviceName = "mft-entropy-decoder"; - o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; o2::itsmft::CTFCoder mCTFCoder; const NoiseMap* mNoiseMap = nullptr; LookUp mPattIdConverter; bool mGetDigits{false}; bool mMaskNoise{false}; bool mUseClusterDictionary{true}; - std::string mDetPrefix{}; - - std::string mCTFDictPath{}; + std::string mDetPrefix; + std::string mCTFDictPath; TStopwatch mTimer; }; -/// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits, unsigned int sspec); +framework::DataProcessorSpec getITSEntropyDecoderSpec(int verbosity, bool getDigits, unsigned int sspec); +framework::DataProcessorSpec getMFTEntropyDecoderSpec(int verbosity, bool getDigits, unsigned int sspec); -} // namespace itsmft -} // namespace o2 +} // namespace o2::itsmft #endif diff --git a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx index 4edbc10d5bfbd..491d166d96ead 100644 --- a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx @@ -21,6 +21,8 @@ #include "ITSMFTReconstruction/ClustererParam.h" #include "DetectorsCommonDataFormats/DetectorNameConf.h" #include "DataFormatsITSMFT/PhysTrigger.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" +#include "ITSMFTReconstruction/ChipMappingMFT.h" using namespace o2::framework; @@ -29,25 +31,28 @@ namespace o2 namespace itsmft { -EntropyDecoderSpec::EntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits) - : mOrigin(orig), mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT), mGetDigits(getDigits) +template +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, bool getDigits) + : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, N), mGetDigits(getDigits) { assert(orig == o2::header::gDataOriginITS || orig == o2::header::gDataOriginMFT); - mDetPrefix = orig == o2::header::gDataOriginITS ? "_ITS" : "_MFT"; + mDetPrefix = Origin == o2::header::gDataOriginITS ? "_ITS" : "_MFT"; mTimer.Stop(); mTimer.Reset(); mCTFCoder.setVerbosity(verbosity); mCTFCoder.setDictBinding(std::string("ctfdict") + mDetPrefix); } -void EntropyDecoderSpec::init(o2::framework::InitContext& ic) +template +void EntropyDecoderSpec::init(o2::framework::InitContext& ic) { mCTFCoder.init(ic); mMaskNoise = ic.options().get("mask-noise"); mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); } -void EntropyDecoderSpec::run(ProcessingContext& pc) +template +void EntropyDecoderSpec::run(ProcessingContext& pc) { if (pc.services().get().globalRunNumberChanged) { mTimer.Reset(); @@ -63,33 +68,105 @@ void EntropyDecoderSpec::run(ProcessingContext& pc) // this produces weird memory problems in unrelated devices, to be understood // auto& trigs = pc.outputs().make>(OutputRef{"phystrig"}); // dummy output - auto& rofs = pc.outputs().make>(OutputRef{"ROframes"}); - if (mGetDigits) { - auto& digits = pc.outputs().make>(OutputRef{"Digits"}); - if (buff.size()) { - iosize = mCTFCoder.decode(o2::itsmft::CTF::getImage(buff.data()), rofs, digits, mNoiseMap, mPattIdConverter); + if constexpr (DPLAlpideParam::supportsStaggering()) { + // for now we need to 'mock' the staggered output and sort ordering ourselves + std::vector rofs; + std::vector digits; + std::vector clusters; + std::vector patterns; + // do the actual read + if (mGetDigits) { + if (buff.size()) { + iosize = mCTFCoder.decode(o2::itsmft::CTF::getImage(buff.data()), rofs, digits, mNoiseMap, mPattIdConverter); + } + mTimer.Stop(); + LOG(info) << "Decoded " << digits.size() << " digits in " << rofs.size() << " RO frames, (" << iosize.asString() << ") in " << mTimer.CpuTime() - cput << " s"; + } else { + if (buff.size()) { + iosize = mCTFCoder.decode(o2::itsmft::CTF::getImage(buff.data()), rofs, clusters, patterns, mNoiseMap, mPattIdConverter); + } + mTimer.Stop(); + LOG(info) << "Decoded " << clusters.size() << " clusters in " << rofs.size() << " RO frames, (" << iosize.asString() << ") in " << mTimer.CpuTime() - cput << " s"; + } + std::array, NLayers> rofsPerLayer; + std::array, NLayers> digitsPerLayer; + std::array, NLayers> clustersPerLayer; + std::array, NLayers> patternsPerLayer; + std::array, NLayers> firstEntries; + std::array, NLayers> nEntries; + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + rofsPerLayer[iLayer] = rofs; + firstEntries[iLayer].resize(rofs.size(), 0); + nEntries[iLayer].resize(rofs.size(), 0); + } + // now we need to filter the data per layer + // TODO implement also for cluster input + for (size_t iROF{0}; iROF < rofs.size(); ++iROF) { + const auto& rof = rofs[iROF]; + for (int iEntry{rof.getFirstEntry()}; iEntry < (rof.getFirstEntry() + rof.getNEntries()); ++iEntry) { + const auto& dig = digits[iEntry]; + int lay = ChipMappingITS::getLayer(dig.getChipIndex()); + digitsPerLayer[lay].push_back(dig); + ++(nEntries[lay][iROF]); + } + } + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + std::exclusive_scan(nEntries[iLayer].begin(), nEntries[iLayer].end(), firstEntries[iLayer].begin(), 0); + for (int iROF{0}; iROF < rofs.size(); ++iROF) { + rofsPerLayer[iLayer][iROF].setFirstEntry(firstEntries[iLayer][iROF]); + rofsPerLayer[iLayer][iROF].setNEntries(nEntries[iLayer][iROF]); + } + } + for (uint32_t iLayer{0}; iLayer < NLayers; ++iLayer) { + pc.outputs().snapshot(OutputRef{"ROframes", iLayer}, rofsPerLayer[iLayer]); + if (mGetDigits) { + pc.outputs().snapshot(OutputRef{"Digits", iLayer}, digitsPerLayer[iLayer]); + } else { + pc.outputs().snapshot(OutputRef{"compClusters", iLayer}, clustersPerLayer[iLayer]); + pc.outputs().snapshot(OutputRef{"patterns", iLayer}, patternsPerLayer[iLayer]); + } } - mTimer.Stop(); - LOG(info) << "Decoded " << digits.size() << " digits in " << rofs.size() << " RO frames, (" << iosize.asString() << ") in " << mTimer.CpuTime() - cput << " s"; } else { - auto& compcl = pc.outputs().make>(OutputRef{"compClusters"}); - auto& patterns = pc.outputs().make>(OutputRef{"patterns"}); - if (buff.size()) { - iosize = mCTFCoder.decode(o2::itsmft::CTF::getImage(buff.data()), rofs, compcl, patterns, mNoiseMap, mPattIdConverter); + auto& rofs = pc.outputs().make>(OutputRef{"ROframes", 0}); + if (mGetDigits) { + auto& digits = pc.outputs().make>(OutputRef{"Digits", 0}); + if (buff.size()) { + iosize = mCTFCoder.decode(o2::itsmft::CTF::getImage(buff.data()), rofs, digits, mNoiseMap, mPattIdConverter); + } + mTimer.Stop(); + LOG(info) << "Decoded " << digits.size() << " digits in " << rofs.size() << " RO frames, (" << iosize.asString() << ") in " << mTimer.CpuTime() - cput << " s"; + } else { + auto& compcl = pc.outputs().make>(OutputRef{"compClusters", 0}); + auto& patterns = pc.outputs().make>(OutputRef{"patterns", 0}); + if (buff.size()) { + iosize = mCTFCoder.decode(o2::itsmft::CTF::getImage(buff.data()), rofs, compcl, patterns, mNoiseMap, mPattIdConverter); + } + mTimer.Stop(); + LOG(info) << "Decoded " << compcl.size() << " clusters in " << rofs.size() << " RO frames, (" << iosize.asString() << ") in " << mTimer.CpuTime() - cput << " s"; + } + // hack: output empty messages to avoid dropping the TF + for (uint32_t iLayer{1}; iLayer < NLayers; ++iLayer) { + pc.outputs().make>(OutputRef{"ROframes", iLayer}); + if (mGetDigits) { + pc.outputs().make>(OutputRef{"Digits", iLayer}); + } else { + pc.outputs().make>(OutputRef{"compClusters", iLayer}); + pc.outputs().make>(OutputRef{"patterns", iLayer}); + } } - mTimer.Stop(); - LOG(info) << "Decoded " << compcl.size() << " clusters in " << rofs.size() << " RO frames, (" << iosize.asString() << ") in " << mTimer.CpuTime() - cput << " s"; } pc.outputs().snapshot({"ctfrep", 0}, iosize); -} +} // namespace itsmft -void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) +template +void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) { LOGF(info, "%s Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots", - mOrigin.as(), mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); + Origin.as(), mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -void EntropyDecoderSpec::updateTimeDependentParams(ProcessingContext& pc) +template +void EntropyDecoderSpec::updateTimeDependentParams(ProcessingContext& pc) { if (pc.services().get().globalRunNumberChanged) { // this params need to be queried only once if (mMaskNoise) { @@ -102,15 +179,16 @@ void EntropyDecoderSpec::updateTimeDependentParams(ProcessingContext& pc) mCTFCoder.updateTimeDependentParams(pc, true); } -void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) +template +void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) { - if (matcher == ConcreteDataMatcher(mOrigin, "NOISEMAP", 0)) { + if (matcher == ConcreteDataMatcher(Origin, "NOISEMAP", 0)) { mNoiseMap = (o2::itsmft::NoiseMap*)obj; - LOG(info) << mOrigin.as() << " noise map updated"; + LOG(info) << Origin.as() << " noise map updated"; return; } - if (matcher == ConcreteDataMatcher(mOrigin, "CLUSDICT", 0)) { - LOG(info) << mOrigin.as() << " cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); + if (matcher == ConcreteDataMatcher(Origin, "CLUSDICT", 0)) { + LOG(info) << Origin.as() << " cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); mPattIdConverter.setDictionary((const TopologyDictionary*)obj); return; } @@ -119,42 +197,52 @@ void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matche } } -DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits, unsigned int sspec) +template +DataProcessorSpec getEntropyDecoderSpec(int verbosity, bool getDigits, unsigned int sspec) { + using EntropyDecoder = EntropyDecoderSpec; + + std::string det = EntropyDecoder::Origin.template as(); + std::string nm = "_" + det; + std::vector inputs; + inputs.emplace_back(std::string("ctf") + nm, EntropyDecoder::Origin, "CTFDATA", sspec, Lifetime::Timeframe); + inputs.emplace_back(std::string("noise") + nm, EntropyDecoder::Origin, "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/NoiseMap", det))); + inputs.emplace_back(std::string("cldict") + nm, EntropyDecoder::Origin, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/ClusterDictionary", det))); + inputs.emplace_back(std::string("ctfdict") + nm, EntropyDecoder::Origin, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/CTFDictionaryTree", det))); + inputs.emplace_back(std::string("trigoffset"), "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); + std::vector outputs; // this is a special dummy input which makes sense only in sync workflows // this produces weird memory problems in unrelated devices, to be understood // outputs.emplace_back(OutputSpec{{"phystrig"}, orig, "PHYSTRIG", 0, Lifetime::Timeframe}); - if (getDigits) { - outputs.emplace_back(OutputSpec{{"Digits"}, orig, "DIGITS", 0, Lifetime::Timeframe}); - outputs.emplace_back(OutputSpec{{"ROframes"}, orig, "DIGITSROF", 0, Lifetime::Timeframe}); - } else { - outputs.emplace_back(OutputSpec{{"compClusters"}, orig, "COMPCLUSTERS", 0, Lifetime::Timeframe}); - outputs.emplace_back(OutputSpec{{"ROframes"}, orig, "CLUSTERSROF", 0, Lifetime::Timeframe}); - outputs.emplace_back(OutputSpec{{"patterns"}, orig, "PATTERNS", 0, Lifetime::Timeframe}); + for (uint32_t iLayer{0}; iLayer < EntropyDecoder::NLayers; ++iLayer) { + if (getDigits) { + outputs.emplace_back(OutputSpec{{"Digits"}, EntropyDecoder::Origin, "DIGITS", iLayer, Lifetime::Timeframe}); + outputs.emplace_back(OutputSpec{{"ROframes"}, EntropyDecoder::Origin, "DIGITSROF", iLayer, Lifetime::Timeframe}); + } else { + outputs.emplace_back(OutputSpec{{"compClusters"}, EntropyDecoder::Origin, "COMPCLUSTERS", iLayer, Lifetime::Timeframe}); + outputs.emplace_back(OutputSpec{{"ROframes"}, EntropyDecoder::Origin, "CLUSTERSROF", iLayer, Lifetime::Timeframe}); + outputs.emplace_back(OutputSpec{{"patterns"}, EntropyDecoder::Origin, "PATTERNS", iLayer, Lifetime::Timeframe}); + } } - outputs.emplace_back(OutputSpec{{"ctfrep"}, orig, "CTFDECREP", 0, Lifetime::Timeframe}); - std::string nm = orig == o2::header::gDataOriginITS ? "_ITS" : "_MFT"; - std::vector inputs; - inputs.emplace_back(std::string("ctf") + nm, orig, "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back(std::string("noise") + nm, orig, "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/NoiseMap", orig.as()))); - inputs.emplace_back(std::string("cldict") + nm, orig, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/ClusterDictionary", orig.as()))); - inputs.emplace_back(std::string("ctfdict") + nm, orig, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/CTFDictionaryTree", orig.as()))); - inputs.emplace_back(std::string("trigoffset"), "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); + outputs.emplace_back(OutputSpec{{"ctfrep"}, EntropyDecoder::Origin, "CTFDECREP", 0, Lifetime::Timeframe}); return DataProcessorSpec{ - EntropyDecoderSpec::getName(orig), - inputs, - outputs, - AlgorithmSpec{adaptFromTask(orig, verbosity, getDigits)}, - Options{ + .name = EntropyDecoder::DeviceName, + .inputs = inputs, + .outputs = outputs, + .algorithm = AlgorithmSpec{adaptFromTask(verbosity, getDigits)}, + .options = Options{ {"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, {"mask-noise", VariantType::Bool, false, {"apply noise mask to digits or clusters (involves reclusterization)"}}, {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + {"and-version", VariantType::String, {"version of and entropy coder implementation to use"}}}}; } +framework::DataProcessorSpec getITSEntropyDecoderSpec(int verbosity, bool getDigits, unsigned int sspec) { return getEntropyDecoderSpec(verbosity, getDigits, sspec); } +framework::DataProcessorSpec getMFTEntropyDecoderSpec(int verbosity, bool getDigits, unsigned int sspec) { return getEntropyDecoderSpec(verbosity, getDigits, sspec); } + } // namespace itsmft } // namespace o2 From e30ce9252d7bc811573bbe357a312bce6ee47f66 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 4 Dec 2025 12:55:22 +0100 Subject: [PATCH 11/13] ITS: GPU: propagate changes to framework --- GPU/GPUTracking/Base/GPUReconstruction.cxx | 5 +---- GPU/GPUTracking/Base/GPUReconstruction.h | 4 ++-- .../Base/GPUReconstructionIncludesITS.h | 10 ---------- .../Base/cuda/GPUReconstructionCUDA.cu | 15 +++++---------- GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h | 2 +- GPU/GPUTracking/Global/GPUChainITS.cxx | 12 ++---------- GPU/GPUTracking/Global/GPUChainITS.h | 2 -- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 3 +-- GPU/GPUTracking/Interface/GPUO2Interface.h | 2 +- GPU/Workflow/src/GPUWorkflowITS.cxx | 4 ++-- GPU/Workflow/src/GPUWorkflowSpec.cxx | 15 ++++++++------- 11 files changed, 23 insertions(+), 51 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index cae7c5025609b..43e9d4717be03 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -112,14 +112,11 @@ GPUReconstruction::~GPUReconstruction() } } -void GPUReconstruction::GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* vertexerTraits, std::unique_ptr>* timeFrame) +void GPUReconstruction::GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* timeFrame) { if (trackerTraits) { trackerTraits->reset(new o2::its::TrackerTraits<7>); } - if (vertexerTraits) { - vertexerTraits->reset(new o2::its::VertexerTraits<7>); - } if (timeFrame) { timeFrame->reset(new o2::its::TimeFrame<7>); } diff --git a/GPU/GPUTracking/Base/GPUReconstruction.h b/GPU/GPUTracking/Base/GPUReconstruction.h index fa636fa416538..7427861e2179a 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.h +++ b/GPU/GPUTracking/Base/GPUReconstruction.h @@ -118,7 +118,7 @@ class GPUReconstruction TRD_SPACEPOINT = 17, TRD_TRIGGERRECORDS = 18, TF_SETTINGS = 19 }; - static constexpr const char* const IOTYPENAMES[] = {"TPC HLT Clusters", "TPC Sector Tracks", "TPC Sector Track Clusters", "TPC Cluster MC Labels", "TPC Track MC Informations", "TPC Tracks", "TPC Track Clusters", "TRD Tracks", "TRD Tracklets", + static constexpr const char* const IOTYPENAMES[] = {"TPC HLT Clusters", "TPC Sector Tracks", "TPC Sector Track Clusters", "TPC Cluster MC Labels", "TPC Track MC Information", "TPC Tracks", "TPC Track Clusters", "TRD Tracks", "TRD Tracklets", "TPC Raw Clusters", "TPC Native Clusters", "TRD Tracklet MC Labels", "TPC Compressed Clusters", "TPC Digit", "TPC ZS Page", "TPC Native Clusters MC Labels", "TPC Digit MC Labeels", "TRD Spacepoints", "TRD Triggerrecords", "TF Settings"}; static uint32_t getNIOTypeMultiplicity(InOutPointerType type) { return (type == CLUSTER_DATA || type == SECTOR_OUT_TRACK || type == SECTOR_OUT_CLUSTER || type == RAW_CLUSTERS || type == TPC_DIGIT || type == TPC_DIGIT_MC) ? NSECTORS : 1; } @@ -192,7 +192,7 @@ class GPUReconstruction GPUMemorySizeScalers* MemoryScalers() { return mMemoryScalers.get(); } // Helpers to fetch processors from other shared libraries - virtual void GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* vertexerTraits, std::unique_ptr>* timeFrame); + virtual void GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* timeFrame); bool slavesExist() { return mSlaves.size() || mMaster; } int slaveId() { return mSlaveId; } diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h b/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h index 813e0aef2d1aa..f2d72de33f666 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludesITS.h @@ -17,21 +17,15 @@ #if !defined(GPUCA_STANDALONE) #include "ITStracking/TrackerTraits.h" -#include "ITStracking/VertexerTraits.h" #include "ITStracking/TimeFrame.h" #if defined(__CUDACC__) || defined(__HIPCC__) #include "ITStrackingGPU/TrackerTraitsGPU.h" -#include "ITStrackingGPU/VertexerTraitsGPU.h" #include "ITStrackingGPU/TimeFrameGPU.h" #endif #else namespace o2::its { template -class VertexerTraits -{ -}; -template class TrackerTraits { }; @@ -39,10 +33,6 @@ template class TimeFrame { }; -template -class VertexerTraitsGPU : public VertexerTraits -{ -}; template class TrackerTraitsGPU : public TrackerTraits { diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index 8e896ca513f53..aaf58b3798198 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -91,16 +91,11 @@ int32_t GPUReconstructionCUDA::GPUChkErrInternal(const int64_t error, const char GPUReconstruction* GPUReconstruction_Create_CUDA(const GPUSettingsDeviceBackend& cfg) { return new GPUReconstructionCUDA(cfg); } -void GPUReconstructionCUDA::GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* vertexerTraits, std::unique_ptr>* timeFrame) +void GPUReconstructionCUDA::GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* timeFrame) { if (trackerTraits) { trackerTraits->reset(new o2::its::TrackerTraitsGPU); } - if (vertexerTraits) { - vertexerTraits->reset(new o2::its::VertexerTraits<7>); - // TODO gpu-code to be implemented then remove line above and uncomment line below - // vertexerTraits->reset(new o2::its::VertexerTraitsGPU<7>); - } if (timeFrame) { timeFrame->reset(new o2::its::gpu::TimeFrameGPU); } @@ -333,9 +328,9 @@ int32_t GPUReconstructionCUDA::InitDevice_Runtime() } } -#ifndef __HIPCC__ // CUDA +#ifndef __HIPCC__ // CUDA dummyInitKernel<<>>(mDeviceMemoryBase); // TODO: Can't we just use the CUDA version and hipify will take care of the rest? -#else // HIP +#else // HIP hipLaunchKernelGGL(HIP_KERNEL_NAME(dummyInitKernel), dim3(mMultiprocessorCount), dim3(256), 0, 0, mDeviceMemoryBase); #endif @@ -374,7 +369,7 @@ int32_t GPUReconstructionCUDA::InitDevice_Runtime() #endif mDeviceConstantMem = (GPUConstantMem*)devPtrConstantMem; - GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %ld / %ld bytes host / global memory, Stack frame %d, Constant memory %ld)", mDeviceId, deviceProp.name, deviceClockRate, deviceProp.multiProcessorCount, (int64_t)mHostMemorySize, (int64_t)mDeviceMemorySize, (int32_t)GPUCA_GPU_STACK_SIZE, (int64_t)gGPUConstantMemBufferSize); + GPUInfo("CUDA Initialisation successful (Device %d: %s (Frequency %d, Cores %d), %ld / %ld bytes host / global memory, Stack frame %d, Constant memory %ld)", mDeviceId, deviceProp.name, deviceClockRate, deviceProp.multiProcessorCount, (int64_t)mHostMemorySize, (int64_t)mDeviceMemorySize, (int32_t)GPUCA_GPU_STACK_SIZE, (int64_t)gGPUConstantMemBufferSize); } else { GPUReconstructionCUDA* master = dynamic_cast(mMaster); mDeviceId = master->mDeviceId; @@ -388,7 +383,7 @@ int32_t GPUReconstructionCUDA::InitDevice_Runtime() mInternals = master->mInternals; GPUChkErr(cudaSetDevice(mDeviceId)); - GPUInfo("CUDA Initialisation successfull (from master)"); + GPUInfo("CUDA Initialisation successful (from master)"); } for (uint32_t i = 0; i < mEvents.size(); i++) { diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h index b3562eff4096d..9cea7c29d9869 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h @@ -76,7 +76,7 @@ class GPUReconstructionCUDA : public GPUReconstructionProcessing::KernelInterfac void RecordMarker(deviceEvent* ev, int32_t stream) override; void SetONNXGPUStream(Ort::SessionOptions& session_options, int32_t stream, int32_t* deviceId) override; - void GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* vertexerTraits, std::unique_ptr>* timeFrame) override; + void GetITSTraits(std::unique_ptr>* trackerTraits, std::unique_ptr>* timeFrame) override; #ifndef __HIPCC__ // CUDA bool CanQueryMaxMemory() override { return true; } diff --git a/GPU/GPUTracking/Global/GPUChainITS.cxx b/GPU/GPUTracking/Global/GPUChainITS.cxx index c72023bdf42ce..34e0d6295e46e 100644 --- a/GPU/GPUTracking/Global/GPUChainITS.cxx +++ b/GPU/GPUTracking/Global/GPUChainITS.cxx @@ -54,23 +54,15 @@ int32_t GPUChainITS::Init() { return 0; } o2::its::TrackerTraits<7>* GPUChainITS::GetITSTrackerTraits() { if (mITSTrackerTraits == nullptr) { - mRec->GetITSTraits(&mITSTrackerTraits, nullptr, nullptr); + mRec->GetITSTraits(&mITSTrackerTraits, nullptr); } return mITSTrackerTraits.get(); } -o2::its::VertexerTraits<7>* GPUChainITS::GetITSVertexerTraits() -{ - if (mITSVertexerTraits == nullptr) { - mRec->GetITSTraits(nullptr, &mITSVertexerTraits, nullptr); - } - return mITSVertexerTraits.get(); -} - o2::its::TimeFrame<7>* GPUChainITS::GetITSTimeframe() { if (mITSTimeFrame == nullptr) { - mRec->GetITSTraits(nullptr, nullptr, &mITSTimeFrame); + mRec->GetITSTraits(nullptr, &mITSTimeFrame); } #if !defined(GPUCA_STANDALONE) if (mITSTimeFrame->isGPU()) { diff --git a/GPU/GPUTracking/Global/GPUChainITS.h b/GPU/GPUTracking/Global/GPUChainITS.h index 4aa97f3f47784..aa591ecabb1dd 100644 --- a/GPU/GPUTracking/Global/GPUChainITS.h +++ b/GPU/GPUTracking/Global/GPUChainITS.h @@ -45,7 +45,6 @@ class GPUChainITS final : public GPUChain void MemorySize(size_t&, size_t&) final {}; o2::its::TrackerTraits<7>* GetITSTrackerTraits(); - o2::its::VertexerTraits<7>* GetITSVertexerTraits(); o2::its::TimeFrame<7>* GetITSTimeframe(); protected: @@ -53,7 +52,6 @@ class GPUChainITS final : public GPUChain std::unique_ptr mFrameworkAllocator; std::unique_ptr> mITSTimeFrame; std::unique_ptr> mITSTrackerTraits; - std::unique_ptr> mITSVertexerTraits; }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index d04db5e9bf271..bdde24175bba1 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -252,10 +252,9 @@ void GPUO2Interface::setErrorCodeOutput(std::vector>* v) } } -void GPUO2Interface::GetITSTraits(o2::its::TrackerTraits<7>*& trackerTraits, o2::its::VertexerTraits<7>*& vertexerTraits, o2::its::TimeFrame<7>*& timeFrame) +void GPUO2Interface::GetITSTraits(o2::its::TrackerTraits<7>*& trackerTraits, o2::its::TimeFrame<7>*& timeFrame) { trackerTraits = mChainITS->GetITSTrackerTraits(); - vertexerTraits = mChainITS->GetITSVertexerTraits(); timeFrame = mChainITS->GetITSTimeframe(); } diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index 00c72cc5e3359..78868c4619211 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -74,7 +74,7 @@ class GPUO2Interface void DumpEvent(int32_t nEvent, GPUTrackingInOutPointers* data, uint32_t iThread, const char* dir = ""); void DumpSettings(uint32_t iThread, const char* dir = ""); - void GetITSTraits(o2::its::TrackerTraits<7>*& trackerTraits, o2::its::VertexerTraits<7>*& vertexerTraits, o2::its::TimeFrame<7>*& timeFrame); + void GetITSTraits(o2::its::TrackerTraits<7>*& trackerTraits, o2::its::TimeFrame<7>*& timeFrame); const o2::base::Propagator* GetDeviceO2Propagator(int32_t iThread = 0) const; void UseGPUPolynomialFieldInPropagator(o2::base::Propagator* prop) const; diff --git a/GPU/Workflow/src/GPUWorkflowITS.cxx b/GPU/Workflow/src/GPUWorkflowITS.cxx index b1c8d619ec736..f1352f151d5ed 100644 --- a/GPU/Workflow/src/GPUWorkflowITS.cxx +++ b/GPU/Workflow/src/GPUWorkflowITS.cxx @@ -55,8 +55,8 @@ void GPURecoWorkflowSpec::initFunctionITS(o2::framework::InitContext& ic) mITSTrackingInterface = std::make_unique(mSpecConfig.processMC, mSpecConfig.itsTriggerType, mSpecConfig.itsOverrBeamEst); - mGPUReco->GetITSTraits(trkTraits, vtxTraits, mITSTimeFrame); - mITSTrackingInterface->setTraitsFromProvider(vtxTraits, trkTraits, mITSTimeFrame); + mGPUReco->GetITSTraits(trkTraits, mITSTimeFrame); + mITSTrackingInterface->setTraitsFromProvider(trkTraits, mITSTimeFrame); } void GPURecoWorkflowSpec::finaliseCCDBITS(o2::framework::ConcreteDataMatcher& matcher, void* obj) diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index d7ea772c31653..aea35c5ee4953 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -1214,9 +1214,14 @@ Inputs GPURecoWorkflowSpec::inputs() } if (mSpecConfig.runITSTracking) { - inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("patterns", "ITS", "PATTERNS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); + for (uint32_t iLayer{0}; iLayer < 7; ++iLayer) { + inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", iLayer, Lifetime::Timeframe); + inputs.emplace_back("patterns", "ITS", "PATTERNS", iLayer, Lifetime::Timeframe); + inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", iLayer, Lifetime::Timeframe); + if (mSpecConfig.processMC) { + inputs.emplace_back("itsmclabels", "ITS", "CLUSTERSMCTR", iLayer, Lifetime::Timeframe); + } + } if (mSpecConfig.itsTriggerType == 1) { inputs.emplace_back("phystrig", "ITS", "PHYSTRIG", 0, Lifetime::Timeframe); } else if (mSpecConfig.itsTriggerType == 2) { @@ -1234,10 +1239,6 @@ Inputs GPURecoWorkflowSpec::inputs() inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1)); } } - if (mSpecConfig.processMC) { - inputs.emplace_back("itsmclabels", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("ITSMC2ROframes", "ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } } // NN clusterizer From 7b71064aa5aa3e98f856b6aed795c41c1fca2d4a Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 4 Dec 2025 12:54:51 +0100 Subject: [PATCH 12/13] ITS: staggered tracking + new vertexer --- .../ITS/include/DataFormatsITS/TrackITS.h | 22 +- .../ITSMFT/ITS/macros/test/CMakeLists.txt | 5 + .../ITSMFT/ITS/macros/test/CheckSeeding.C | 268 +++ .../ITSMFT/ITS/macros/test/CheckTracksCA.C | 150 +- Detectors/ITSMFT/ITS/tracking/CMakeLists.txt | 15 +- .../GPU/ITStrackingGPU/ClusterLinesGPU.h | 73 - .../GPU/ITStrackingGPU/TimeFrameChunk.h | 148 -- .../GPU/ITStrackingGPU/TimeFrameGPU.h | 117 +- .../tracking/GPU/ITStrackingGPU/TracerGPU.h | 38 - .../GPU/ITStrackingGPU/TrackingKernels.h | 77 +- .../ITS/tracking/GPU/ITStrackingGPU/Utils.h | 30 +- .../GPU/ITStrackingGPU/VertexerTraitsGPU.h | 55 - .../GPU/ITStrackingGPU/VertexingKernels.h | 115 -- .../ITS/tracking/GPU/cuda/ClusterLinesGPU.cu | 138 -- .../ITS/tracking/GPU/cuda/TimeFrameChunk.cu | 293 --- .../ITS/tracking/GPU/cuda/TimeFrameGPU.cu | 407 ++--- .../ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu | 48 - .../tracking/GPU/cuda/TrackerTraitsGPU.cxx | 159 +- .../ITS/tracking/GPU/cuda/TrackingKernels.cu | 237 ++- .../tracking/GPU/cuda/VertexerTraitsGPU.cxx | 179 -- .../ITS/tracking/GPU/cuda/VertexingKernels.cu | 660 ------- .../include/ITStracking/BoundedAllocator.h | 3 + .../ITS/tracking/include/ITStracking/Cell.h | 3 + .../include/ITStracking/ClusterLines.h | 214 --- .../include/ITStracking/Configuration.h | 104 +- .../include/ITStracking/Definitions.h | 49 +- .../include/ITStracking/IndexTableUtils.h | 34 +- .../tracking/include/ITStracking/MathUtils.h | 34 +- .../include/ITStracking/ROFLookupTables.h | 865 +++++++++ .../tracking/include/ITStracking/Seeding.h | 376 ++++ .../tracking/include/ITStracking/Smoother.h | 60 - .../tracking/include/ITStracking/TimeFrame.h | 617 +++---- .../tracking/include/ITStracking/Tracker.h | 60 +- .../include/ITStracking/TrackerTraits.h | 74 +- .../include/ITStracking/TrackingConfigParam.h | 108 +- .../include/ITStracking/TrackingInterface.h | 12 +- .../tracking/include/ITStracking/Tracklet.h | 8 +- .../tracking/include/ITStracking/Vertexer.h | 160 -- .../include/ITStracking/VertexerTraits.h | 167 -- .../ITSMFT/ITS/tracking/src/ClusterLines.cxx | 394 ---- .../ITSMFT/ITS/tracking/src/Configuration.cxx | 254 ++- .../ITS/tracking/src/IndexTableUtils.cxx | 49 - Detectors/ITSMFT/ITS/tracking/src/Seeding.cxx | 325 ++++ .../ITSMFT/ITS/tracking/src/Smoother.cxx | 222 --- .../ITSMFT/ITS/tracking/src/TimeFrame.cxx | 525 ++---- Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx | 366 ++-- .../ITSMFT/ITS/tracking/src/TrackerTraits.cxx | 1617 ++++++++++++----- .../ITS/tracking/src/TrackingConfigParam.cxx | 1 - .../ITS/tracking/src/TrackingInterface.cxx | 462 ++--- .../ITSMFT/ITS/tracking/src/TrackingLinkDef.h | 13 +- .../ITSMFT/ITS/tracking/src/Vertexer.cxx | 115 -- .../ITS/tracking/src/VertexerTraits.cxx | 843 --------- .../ITSMFT/ITS/tracking/test/CMakeLists.txt | 6 + .../test/testBoundedMemoryResource.cxx | 2 +- .../ITS/tracking/test/testROFLookupTables.cxx | 726 ++++++++ Detectors/ITSMFT/ITS/workflow/CMakeLists.txt | 1 - .../include/ITSWorkflow/TrackWriterSpec.h | 7 +- .../ITS/workflow/src/TrackWriterSpec.cxx | 67 +- .../ITSMFT/ITS/workflow/src/TrackerSpec.cxx | 47 +- .../include/ITS3Reconstruction/IOUtils.h | 13 +- .../ITS3Reconstruction/TrackingInterface.h | 1 + .../ITS3/reconstruction/src/IOUtils.cxx | 36 +- .../reconstruction/src/TrackingInterface.cxx | 10 +- .../ITS3/workflow/src/TrackerSpec.cxx | 3 +- 64 files changed, 5481 insertions(+), 6806 deletions(-) create mode 100644 Detectors/ITSMFT/ITS/macros/test/CheckSeeding.C delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameChunk.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TracerGPU.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexingKernels.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameChunk.cu delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cxx delete mode 100644 Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexingKernels.cu delete mode 100644 Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h create mode 100644 Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROFLookupTables.h create mode 100644 Detectors/ITSMFT/ITS/tracking/include/ITStracking/Seeding.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h delete mode 100644 Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx delete mode 100644 Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx create mode 100644 Detectors/ITSMFT/ITS/tracking/src/Seeding.cxx delete mode 100644 Detectors/ITSMFT/ITS/tracking/src/Smoother.cxx delete mode 100644 Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx delete mode 100644 Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx create mode 100644 Detectors/ITSMFT/ITS/tracking/test/testROFLookupTables.cxx diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h index 06d4fba51bd54..c0570bf9d8111 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h @@ -16,11 +16,13 @@ #ifndef ALICEO2_ITS_TRACKITS_H #define ALICEO2_ITS_TRACKITS_H +#include #include #include "GPUCommonDef.h" #include "ReconstructionDataFormats/Track.h" #include "CommonDataFormat/RangeReference.h" +#include "CommonDataFormat/TimeStamp.h" namespace o2 { @@ -35,12 +37,12 @@ namespace its class TrackITS : public o2::track::TrackParCov { enum UserBits { - kNextROF = 1 << 28, kSharedClusters = 1 << 29 }; using Cluster = o2::itsmft::Cluster; using ClusRefs = o2::dataformats::RangeRefComp<4>; + using Timestamp = o2::dataformats::TimeStampWithError; public: using o2::track::TrackParCov::TrackParCov; // inherit base constructors @@ -93,6 +95,9 @@ class TrackITS : public o2::track::TrackParCov bool isBetter(const TrackITS& best, float maxChi2) const; + auto& getTimeStamp() { return mTime; } + const auto& getTimeStamp() const { return mTime; } + GPUhdi() o2::track::TrackParCov& getParamIn() { return *this; } GPUhdi() const o2::track::TrackParCov& getParamIn() const { return *this; } @@ -122,8 +127,6 @@ class TrackITS : public o2::track::TrackParCov } int getNFakeClusters() const; - void setNextROFbit(bool toggle = true) { mClusterSizes = toggle ? (mClusterSizes | kNextROF) : (mClusterSizes & ~kNextROF); } - bool hasHitInNextROF() const { return mClusterSizes & kNextROF; } void setSharedClusters(bool toggle = true) { mClusterSizes = toggle ? (mClusterSizes | kSharedClusters) : (mClusterSizes & ~kSharedClusters); } bool hasSharedClusters() const { return mClusterSizes & kSharedClusters; } @@ -157,9 +160,10 @@ class TrackITS : public o2::track::TrackParCov ClusRefs mClusRef; ///< references on clusters float mChi2 = 0.; ///< Chi2 for this track uint32_t mPattern = 0; ///< layers pattern - unsigned int mClusterSizes = 0u; + uint32_t mClusterSizes = 0u; ///< packed clamped cluster size + Timestamp mTime; ///< track time stamp with error in BC, defined asymmetrical start + range in BCs - ClassDefNV(TrackITS, 6); + ClassDefNV(TrackITS, 7); }; class TrackITSExt : public TrackITS @@ -169,15 +173,13 @@ class TrackITSExt : public TrackITS static constexpr int MaxClusters = 16; /// Prepare for overlaps and new detector configurations using TrackITS::TrackITS; // inherit base constructors - GPUh() TrackITSExt(o2::track::TrackParCov&& parCov, short ncl, float chi2, - o2::track::TrackParCov&& outer, std::array cls) + GPUh() TrackITSExt(o2::track::TrackParCov&& parCov, short ncl, float chi2, o2::track::TrackParCov&& outer, std::array cls) : TrackITS(parCov, chi2, outer), mIndex{cls} { setNumberOfClusters(ncl); } - GPUh() TrackITSExt(o2::track::TrackParCov& parCov, short ncl, float chi2, std::uint32_t rof, - o2::track::TrackParCov& outer, std::array cls) + GPUh() TrackITSExt(o2::track::TrackParCov& parCov, short ncl, float chi2, o2::track::TrackParCov& outer, std::array cls) : TrackITS(parCov, chi2, outer), mIndex{cls} { setNumberOfClusters(ncl); @@ -212,7 +214,7 @@ class TrackITSExt : public TrackITS private: std::array mIndex = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; ///< Indices of associated clusters - ClassDefNV(TrackITSExt, 2); + ClassDefNV(TrackITSExt, 3); }; } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt b/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt index dd6aacf65db99..704fb6e4df650 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/macros/test/CMakeLists.txt @@ -118,3 +118,8 @@ o2_add_test_root_macro(CheckDROF.C PUBLIC_LINK_LIBRARIES O2::DataFormatsITS O2::DataFormatsITSMFT LABELS its) + +o2_add_test_root_macro(CheckSeeding.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsITS + O2::DataFormatsITSMFT + LABELS its) diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckSeeding.C b/Detectors/ITSMFT/ITS/macros/test/CheckSeeding.C new file mode 100644 index 0000000000000..ac9f6927411f4 --- /dev/null +++ b/Detectors/ITSMFT/ITS/macros/test/CheckSeeding.C @@ -0,0 +1,268 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/Logger.h" +#include "ITStracking/Definitions.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/MCTrack.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "Steer/MCKinematicsReader.h" +#endif + +namespace fs = std::filesystem; +void fitGaus(TH1*); + +void CheckSeeding(const std::string& trkFileName = "o2trac_its.root", const std::string& colFileName = "collisioncontext.root") +{ + fs::path base = fs::current_path(); + std::vector dirs; + for (auto& entry : fs::recursive_directory_iterator(base)) { + if (!entry.is_regular_file()) { + continue; + } + if (entry.path().filename() == trkFileName) { + dirs.push_back(entry.path().parent_path()); + } + } + std::sort(dirs.begin(), dirs.end()); + dirs.erase(std::unique(dirs.begin(), dirs.end()), dirs.end()); + + LOG(info) << "Found " << dirs.size() << " directories containing " << trkFileName << "\n"; + if (dirs.empty()) { + return; + } + + const int nBins{100}; + const float yRange{0.5}, zRange{18}; + auto hVtxX = new TH1F("hVtxX", ";x (cm)", nBins, -yRange, yRange); + auto hVtxY = new TH1F("hVtxY", ";y (cm)", nBins, -yRange, yRange); + auto hVtxZ = new TH1F("hVtxZ", ";z (cm)", nBins, -zRange, zRange); + const float resRange{0.1}; + auto hVtxResX = new TH1F("hVtxResX", ";x (cm)", nBins, -resRange, resRange); + auto hVtxResY = new TH1F("hVtxResY", ";y (cm)", nBins, -resRange, resRange); + auto hVtxResZ = new TH1F("hVtxResZ", ";z (cm)", nBins, -resRange, resRange); + const float pullRange{5}; + auto hVtxPullX = new TH1F("hVtxPullX", "pull x", nBins, -pullRange, pullRange); + auto hVtxPullY = new TH1F("hVtxPullY", "pull y", nBins, -pullRange, pullRange); + auto hVtxPullZ = new TH1F("hVtxPullZ", "pull z", nBins, -pullRange, pullRange); + + auto hVtxEffNumZ = new TH1F("hVtxEffNumZ", ";z (cm);efficiency", nBins, -zRange, zRange); + auto hVtxEffDenZ = new TH1F("hVtxEffDenZ", ";z (cm)", nBins, -zRange, zRange); + auto hVtxPurity = new TH1F("hVtxPurity", ";purity", nBins, 0, 1); + auto hVtxPurityVsNContrib = new TH2F("hVtxPurityVsNContrib", ";purity;contributors", nBins, 0, 1, 150, 0, 150); + auto hVtxNContribVsNPrim = new TH2F("hVtxNContribVsNPrim", ";contributors;nprim", 150, 0, 150, 150, 0, 150); + + std::vector* vertices{nullptr}; + std::vector* verticesLbl{nullptr}; + std::vector* verticesPurity{nullptr}; + o2::steer::MCKinematicsReader* mcReader{nullptr}; + + for (const auto& dirPath : dirs) { + std::string dirStr = dirPath.string(); + LOG(info) << "Processing directory: " << dirStr << "\n"; + + // switch working directory to the directory containing the files + if (chdir(dirStr.c_str()) != 0) { + perror("chdir failed"); + LOG(info) << "Skipping directory " << dirStr << " due to chdir failure\n"; + continue; + } + + // open the track ROOT file from this directory + fs::path trkPath = dirPath / trkFileName; + if (!fs::exists(trkPath)) { + LOG(info) << "Missing track file " << trkPath.string() << " (skipping)\n"; + continue; + } + + TFile* f = TFile::Open(trkPath.string().c_str(), "READ"); + if (!f || f->IsZombie()) { + LOG(info) << "Failed to open " << trkPath.string() << " (skipping)\n"; + if (f) { + f->Close(); + delete f; + } + continue; + } + + TTree* trkTree = dynamic_cast(f->Get("o2sim")); + if (!trkTree) { + LOG(info) << "Tree 'o2sim' not found in " << trkPath.string() << " (skipping)\n"; + f->Close(); + delete f; + continue; + } + + vertices = nullptr; + verticesLbl = nullptr; + verticesPurity = nullptr; + trkTree->SetBranchAddress("ITSVertices", &vertices); + trkTree->SetBranchAddress("ITSVertexMCTruth", &verticesLbl); + trkTree->SetBranchAddress("ITSVertexMCPurity", &verticesPurity); + fs::path colPath = dirPath / colFileName; + if (!fs::exists(colPath)) { + LOG(info) << "Collision file not found: " << colPath.string() << " (mcReader will be nullptr)\n"; + mcReader = nullptr; + } else { + delete mcReader; + mcReader = new o2::steer::MCKinematicsReader(colPath.string().c_str()); + } + + Long64_t nEntries = trkTree->GetEntries(); + LOG(info) << "Entries in file: " << nEntries << "\n"; + + for (Long64_t iEntry = 0; iEntry < nEntries; ++iEntry) { + trkTree->GetEntry(iEntry); + + for (size_t iVtx{0}; iVtx < vertices->size(); ++iVtx) { + const auto& vtx = vertices->at(iVtx); + const auto& vtxLbl = verticesLbl->at(iVtx); + const auto& purity = verticesPurity->at(iVtx); + LOGP(info, "{}: {}", iVtx, vtx.asString()); + if (vtxLbl.isValid() && vtxLbl.isCorrect() && mcReader) { + const auto& head = mcReader->getMCEventHeader(vtxLbl.getSourceID(), vtxLbl.getEventID()); + LOGP(info, "\t-{}", vtxLbl.asString()); + LOGP(info, "\t-Purity:{}", purity); + LOGP(info, "\t-MC: x={} y={} z={} prim={}", head.GetX(), head.GetY(), head.GetZ(), head.GetNPrim()); + + hVtxX->Fill(vtx.getX()); + hVtxY->Fill(vtx.getY()); + hVtxZ->Fill(vtx.getZ()); + + hVtxResX->Fill(vtx.getX() - head.GetX()); + hVtxResY->Fill(vtx.getY() - head.GetY()); + hVtxResZ->Fill(vtx.getZ() - head.GetZ()); + + hVtxPullX->Fill((vtx.getX() - head.GetX()) / vtx.getSigmaX()); + hVtxPullY->Fill((vtx.getY() - head.GetY()) / vtx.getSigmaY()); + hVtxPullZ->Fill((vtx.getZ() - head.GetZ()) / vtx.getSigmaZ()); + + hVtxEffNumZ->Fill(head.GetZ()); + + hVtxNContribVsNPrim->Fill(vtx.getNContributors(), head.GetNPrim()); + + } else { + LOGP(info, "\t-FAKE"); + } + + hVtxPurity->Fill(purity); + hVtxPurityVsNContrib->Fill(purity, vtx.getNContributors()); + } + } + + // fill den + for (int iEve{0}; iEve < (int)mcReader->getNEvents(0); ++iEve) { + const auto& head = mcReader->getMCEventHeader(0, iEve); + hVtxEffDenZ->Fill(head.GetZ()); + } + + if (mcReader) { + delete mcReader; + mcReader = nullptr; + } + trkTree = nullptr; + f->Close(); + delete f; + + if (chdir(base.string().c_str()) != 0) { + perror("chdir back failed"); + } + } + + auto c = new TCanvas(); + c->Divide(3, 3); + c->cd(1); + hVtxX->Draw(); + fitGaus(hVtxX); + gPad->SetLogy(); + c->cd(2); + hVtxY->Draw(); + fitGaus(hVtxY); + gPad->SetLogy(); + c->cd(3); + hVtxZ->Draw(); + fitGaus(hVtxZ); + gPad->SetLogy(); + c->cd(4); + hVtxResX->Draw(); + c->cd(5); + hVtxResY->Draw(); + c->cd(6); + hVtxResZ->Draw(); + c->cd(7); + hVtxPullX->Draw(); + fitGaus(hVtxPullX); + gPad->SetLogy(); + c->cd(8); + hVtxPullY->Draw(); + fitGaus(hVtxPullY); + gPad->SetLogy(); + c->cd(9); + hVtxPullZ->Draw(); + fitGaus(hVtxPullZ); + gPad->SetLogy(); + c->Draw(); + + hVtxEffNumZ->Divide(hVtxEffNumZ, hVtxEffDenZ, 1., 1., "B"); + c = new TCanvas(); + c->Divide(2, 2); + c->cd(1); + hVtxEffNumZ->Draw(); + c->cd(2); + hVtxPurity->Draw(); + c->cd(3); + hVtxPurityVsNContrib->Draw("colz"); + c->cd(4); + hVtxNContribVsNPrim->Draw("colz"); + c->Draw(); +} + +void fitGaus(TH1* h) +{ + if (!h) { + return; + } + + // fit + TF1* f = new TF1("fG", "gaus"); + h->Fit(f, "QMS"); // quiet fit + + // draw histogram + h->Draw(); + + // get parameters + double mean = f->GetParameter(1); + double sigma = f->GetParameter(2); + double chi2 = f->GetChisquare(); + double ndf = f->GetNDF(); + + // add text box + auto t = new TLatex(); + t->SetNDC(); + t->SetTextSize(0.04); + t->DrawLatex(0.15, 0.85, Form("mean = %.4f", mean)); + t->DrawLatex(0.15, 0.80, Form("sigma = %.4f", sigma)); + t->DrawLatex(0.15, 0.75, Form("#chi^{2}/ndf = %.2f / %.0f", chi2, ndf)); +} diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C b/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C index e185be83a389f..7faa3c6610a2e 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckTracksCA.C @@ -47,35 +47,36 @@ using namespace std; // chi2 PDF with amplitude A, degrees of freedom k, scale s -Double_t chi2_pdf(Double_t* x, Double_t* par) +static Double_t chi2_pdf(const Double_t* x, const Double_t* par) { const Double_t xx = x[0]; const Double_t A = par[0]; const Double_t k = par[1]; const Double_t s = par[2]; - if (xx <= 0.0 || k <= 0.0 || s <= 0.0) + if (xx <= 0.0 || k <= 0.0 || s <= 0.0) { return 0.0; + } const Double_t coef = 1.0 / (TMath::Power(2.0 * s, k * 0.5) * TMath::Gamma(k * 0.5)); - return A * coef * TMath::Power(xx, k * 0.5 - 1.0) * TMath::Exp(-xx / (2.0 * s)); + return A * coef * TMath::Power(xx, (k * 0.5) - 1.0) * TMath::Exp(-xx / (2.0 * s)); } struct ParticleInfo { - int event; - int pdg; - float pt; - float eta; - float phi; - int mother; - int first; + int event{}; + int pdg{}; + float pt{}; + float eta{}; + float phi{}; + int mother{}; + int first{}; float pvx{}; float pvy{}; float pvz{}; - float dcaxy; - float dcaz; + float dcaxy{}; + float dcaz{}; unsigned short clusters = 0u; unsigned char isReco = 0u; unsigned char isFake = 0u; - bool isPrimary = 0u; + bool isPrimary = false; unsigned char storedStatus = 2; /// not stored = 2, fake = 1, good = 0 o2::its::TrackITS track; o2::MCTrack mcTrack; @@ -88,9 +89,9 @@ void CheckTracksCA(bool doEffStud = true, bool doPullStud = false, bool createOutput = false, std::string tracfile = "o2trac_its.root", - std::string magfile = "o2sim_grp.root", + std::string magfile = "sgn_grp.root", std::string clusfile = "o2clus_its.root", - std::string kinefile = "o2sim_Kine.root") + std::string kinefile = "sgn_Kine.root") { using namespace o2::itsmft; @@ -106,10 +107,10 @@ void CheckTracksCA(bool doEffStud = true, // MC tracks TFile* file0 = TFile::Open(kinefile.data()); - TTree* mcTree = (TTree*)gFile->Get("o2sim"); - mcTree->SetBranchStatus("*", 0); // disable all branches - mcTree->SetBranchStatus("MCTrack*", 1); - mcTree->SetBranchStatus("MCEventHeader*", 1); + auto* mcTree = (TTree*)gFile->Get("o2sim"); + mcTree->SetBranchStatus("*", false); // disable all branches + mcTree->SetBranchStatus("MCTrack*", true); + mcTree->SetBranchStatus("MCEventHeader*", true); std::vector* mcArr = nullptr; mcTree->SetBranchAddress("MCTrack", &mcArr); @@ -118,17 +119,17 @@ void CheckTracksCA(bool doEffStud = true, // Clusters TFile::Open(clusfile.data()); - TTree* clusTree = (TTree*)gFile->Get("o2sim"); - std::vector* clusArr = nullptr; - clusTree->SetBranchAddress("ITSClusterComp", &clusArr); - - // Cluster MC labels - o2::dataformats::MCTruthContainer* clusLabArr = nullptr; - clusTree->SetBranchAddress("ITSClusterMCTruth", &clusLabArr); + auto* clusTree = (TTree*)gFile->Get("o2sim"); + std::array*, 7> clusArr{}; + std::array*, 7> clusLabArr{}; + for (int iLayer{0}; iLayer < 7; ++iLayer) { + clusTree->SetBranchAddress(Form("ITSClusterComp_%d", iLayer), &(clusArr[iLayer])); + clusTree->SetBranchAddress(Form("ITSClusterMCTruth_%d", iLayer), &(clusLabArr[iLayer])); + } // Reconstructed tracks TFile* file1 = TFile::Open(tracfile.data()); - TTree* recTree = (TTree*)gFile->Get("o2sim"); + auto* recTree = (TTree*)gFile->Get("o2sim"); std::vector* recArr = nullptr; recTree->SetBranchAddress("ITSTrack", &recArr); // Track MC labels @@ -147,7 +148,7 @@ void CheckTracksCA(bool doEffStud = true, hZvertex->Fill(mcEvent->GetZ()); for (unsigned int mcI{0}; mcI < mcArr->size(); ++mcI) { const auto part = mcArr->at(mcI); - if (!o2::O2DatabasePDG::Instance()->GetParticle(part.GetPdgCode())) { + if (!o2::O2DatabasePDG::Instance()->GetParticle(part.GetPdgCode()) || !part.hasHits()) { continue; } info[n][mcI].event = n; @@ -162,42 +163,50 @@ void CheckTracksCA(bool doEffStud = true, info[n][mcI].mcTrack = part; } } - std::cout << "done." << std::endl; + std::cout << "done." << '\n'; - std::cout << "** Creating particle/clusters correspondance ... " << std::flush; + std::cout << "** Creating particle/clusters correspondence ... " << std::flush; for (int frame = 0; frame < clusTree->GetEntriesFast(); frame++) { // Cluster frames - if (!clusTree->GetEvent(frame)) + if (!clusTree->GetEvent(frame)) { continue; + } - for (unsigned int iClus{0}; iClus < clusArr->size(); ++iClus) { - auto lab = (clusLabArr->getLabels(iClus))[0]; - if (!lab.isValid() || lab.getSourceID() != 0 || !lab.isCorrect()) - continue; + for (int iLayer{0}; iLayer < 7; ++iLayer) { + for (unsigned int iClus{0}; iClus < (clusArr[iLayer])->size(); ++iClus) { + o2::MCCompLabel lab; + for (const auto& lbl : ((clusLabArr[iLayer])->getLabels(iClus))) { + if (lbl.isValid() && lbl.getSourceID() == 0 && lbl.isCorrect()) { + lab = lbl; + break; + } + } + if (!lab.isValid()) { + continue; + } - int trackID, evID, srcID; - bool fake; - lab.get(trackID, evID, srcID, fake); - if (evID < 0 || evID >= (int)info.size()) { - std::cout << "Cluster MC label eventID out of range" << std::endl; - continue; - } - if (trackID < 0 || trackID >= (int)info[evID].size()) { - std::cout << "Cluster MC label trackID out of range" << std::endl; - continue; + int trackID = 0, evID = 0, srcID = 0; + bool fake = false; + lab.get(trackID, evID, srcID, fake); + if (evID < 0 || evID >= (int)info.size()) { + std::cout << "Cluster MC label eventID out of range" << '\n'; + continue; + } + if (trackID < 0 || trackID >= (int)info[evID].size()) { + std::cout << "Cluster MC label trackID out of range" << '\n'; + continue; + } + info[evID][trackID].clusters |= 1 << iLayer; } - - const CompClusterExt& c = (*clusArr)[iClus]; - auto layer = gman->getLayer(c.getSensorID()); - info[evID][trackID].clusters |= 1 << layer; } } - std::cout << "done." << std::endl; + std::cout << "done." << '\n'; std::cout << "** Analysing tracks ... " << std::flush; int unaccounted{0}, good{0}, fakes{0}, total{0}; for (int frame = 0; frame < recTree->GetEntriesFast(); frame++) { // Cluster frames - if (!recTree->GetEvent(frame)) + if (!recTree->GetEvent(frame)) { continue; + } total += trkLabArr->size(); for (unsigned int iTrack{0}; iTrack < trkLabArr->size(); ++iTrack) { auto lab = trkLabArr->at(iTrack); @@ -205,8 +214,8 @@ void CheckTracksCA(bool doEffStud = true, unaccounted++; continue; } - int trackID, evID, srcID; - bool fake; + int trackID = 0, evID = 0, srcID = 0; + bool fake = false; lab.get(trackID, evID, srcID, fake); if (evID < 0 || evID >= (int)info.size()) { unaccounted++; @@ -232,13 +241,13 @@ void CheckTracksCA(bool doEffStud = true, good += !fake; } } - std::cout << "done." << std::endl; + std::cout << "done." << '\n'; - std::cout << "** Some statistics:" << std::endl; - std::cout << "\t- Total number of tracks: " << total << std::endl; - std::cout << "\t- Total number of tracks not corresponding to particles: " << unaccounted << " (" << unaccounted * 100. / total << "%)" << std::endl; - std::cout << "\t- Total number of fakes: " << fakes << " (" << fakes * 100. / total << "%)" << std::endl; - std::cout << "\t- Total number of good: " << good << " (" << good * 100. / total << "%)" << std::endl; + std::cout << "** Some statistics:" << '\n'; + std::cout << "\t- Total number of tracks: " << total << '\n'; + std::cout << "\t- Total number of tracks not corresponding to particles: " << unaccounted << " (" << unaccounted * 100. / total << "%)" << '\n'; + std::cout << "\t- Total number of fakes: " << fakes << " (" << fakes * 100. / total << "%)" << '\n'; + std::cout << "\t- Total number of good: " << good << " (" << good * 100. / total << "%)" << '\n'; TFile* file{nullptr}; if (createOutput) { @@ -250,8 +259,9 @@ void CheckTracksCA(bool doEffStud = true, const int nb = 100; double xbins[nb + 1], ptcutl = 0.01, ptcuth = 10.; double a = std::log(ptcuth / ptcutl) / nb; - for (int i = 0; i <= nb; i++) + for (int i = 0; i <= nb; i++) { xbins[i] = ptcutl * std::exp(i * a); + } TH1D* num = new TH1D("num", ";#it{p}_{T} (GeV/#it{c});Efficiency (fake-track rate)", nb, xbins); num->Sumw2(); TH1D* numEta = new TH1D("numEta", ";#eta;Number of tracks", 60, -3, 3); @@ -270,8 +280,8 @@ void CheckTracksCA(bool doEffStud = true, TH1D* den = new TH1D("den", ";#it{p}_{T} (GeV/#it{c});Den", nb, xbins); den->Sumw2(); - for (auto& evInfo : info) { - for (auto& part : evInfo) { + for (const auto& evInfo : info) { + for (const auto& part : evInfo) { if ((part.clusters & 0x7f) != 0x7f) { // part.clusters != 0x3f && part.clusters != 0x3f << 1 && // part.clusters != 0x1f && part.clusters != 0x1f << 1 && part.clusters != 0x1f << 2 && @@ -302,7 +312,10 @@ void CheckTracksCA(bool doEffStud = true, } } - TCanvas* c1 = new TCanvas; + den->Print(); + num->Print(); + + auto* c1 = new TCanvas; c1->SetLogx(); c1->SetGridx(); c1->SetGridy(); @@ -322,10 +335,13 @@ void CheckTracksCA(bool doEffStud = true, clone->Divide(clone, den, 1, 1, "b"); clone->SetLineColor(3); clone->Draw("histesame"); - TCanvas* c2 = new TCanvas; - c2->SetGridx(); - c2->SetGridy(); - hZvertex->DrawClone(); + c1->Draw(); + // c1->SaveAs("its_eff.png"); + // TCanvas* c2 = new TCanvas; + // c2->SetGridx(); + // c2->SetGridy(); + // hZvertex->DrawClone(); + // c2->SaveAs("its_zvtx.png"); if (createOutput) { sum->Write("total"); diff --git a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt index 001ee537f50d2..3916e88e95e45 100644 --- a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt @@ -9,20 +9,18 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +# add_compile_options(-O0 -g -fPIC -fsanitize=address) +# add_link_options(-fsanitize=address) o2_add_library(ITStracking TARGETVARNAME targetName - SOURCES src/ClusterLines.cxx - src/Cluster.cxx + SOURCES src/Cluster.cxx + src/Seeding.cxx src/Configuration.cxx src/TimeFrame.cxx src/IOUtils.cxx src/Tracker.cxx src/TrackerTraits.cxx src/TrackingConfigParam.cxx - src/ClusterLines.cxx - src/Vertexer.cxx - src/VertexerTraits.cxx - src/Smoother.cxx PUBLIC_LINK_LIBRARIES O2::GPUCommon Microsoft.GSL::GSL @@ -45,11 +43,12 @@ o2_add_library(ITSTrackingInterface O2::ITStracking O2::Framework O2::GPUTracking) +# target_compile_options(${targetName} PRIVATE -O0 -g -fPIC -fno-omit-frame-pointer) o2_target_root_dictionary(ITStracking - HEADERS include/ITStracking/ClusterLines.h - include/ITStracking/Tracklet.h + HEADERS include/ITStracking/Tracklet.h include/ITStracking/Cluster.h + include/ITStracking/Seeding.h include/ITStracking/TrackingConfigParam.h LINKDEF src/TrackingLinkDef.h) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h deleted file mode 100644 index 75d75e0f67700..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file ClusterLinesGPU.h -/// \brief GPU-compliant version of ClusterLines, for the moment separated, might create a common traits for ClusterLines + later specifications for each arch, later. - -#ifndef ITSTRACKINGGPU_CLUSTERLINESGPU_H_ -#define ITSTRACKINGGPU_CLUSTERLINESGPU_H_ - -#include "GPUCommonDef.h" -#include /// Required to properly compile MathUtils -#include "ITStracking/ClusterLines.h" - -namespace o2 -{ -namespace its -{ -namespace gpu -{ - -struct GPUVertex final { - GPUhd() GPUVertex() : realVertex{false} - { - } - - GPUhd() GPUVertex(float x, float y, float z, float eX, float eY, float eZ, int contrib) : xCoord{x}, - yCoord{y}, - zCoord{z}, - errorX{eZ}, - errorY{eY}, - errorZ{eZ}, - contributors{contrib}, - realVertex{true} - { - } - float xCoord; - float yCoord; - float zCoord; - float errorX; - float errorY; - float errorZ; - int contributors; - int timeStamp; - unsigned char realVertex; -}; - -class ClusterLinesGPU final -{ - public: - GPUd() ClusterLinesGPU(const Line& firstLine, const Line& secondLine); // poor man solution to calculate duplets' centroid - GPUd() void computeClusterCentroid(); - GPUdi() float* getVertex() { return mVertex; } - - private: - float mAMatrix[6]; // AX=B - float mBMatrix[3]; // AX=B - float mVertexCandidate[3]; // vertex candidate - float mWeightMatrix[9]; // weight matrix - float mVertex[3]; // cluster centroid position -}; - -} // namespace gpu -} // namespace its -} // namespace o2 -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameChunk.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameChunk.h deleted file mode 100644 index 4a028bf12eb40..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameChunk.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// - -#ifndef TRACKINGITSGPU_INCLUDE_TIMEFRAMECHUNKGPU_H -#define TRACKINGITSGPU_INCLUDE_TIMEFRAMECHUNKGPU_H - -#include "ITStracking/Configuration.h" -#include "ITStracking/TimeFrame.h" - -#include "ITStrackingGPU/ClusterLinesGPU.h" -#include "ITStrackingGPU/Stream.h" - -#include - -namespace o2::its::gpu -{ -template -struct StaticTrackingParameters { - StaticTrackingParameters& operator=(const StaticTrackingParameters& t) = default; - void set(const TrackingParameters& pars) - { - ClusterSharing = pars.ClusterSharing; - MinTrackLength = pars.MinTrackLength; - NSigmaCut = pars.NSigmaCut; - PVres = pars.PVres; - DeltaROF = pars.DeltaROF; - ZBins = pars.ZBins; - PhiBins = pars.PhiBins; - CellDeltaTanLambdaSigma = pars.CellDeltaTanLambdaSigma; - } - - /// General parameters - int ClusterSharing = 0; - int MinTrackLength = nLayers; - float NSigmaCut = 5; - float PVres = 1.e-2f; - int DeltaROF = 0; - int ZBins{256}; - int PhiBins{128}; - - /// Cell finding cuts - float CellDeltaTanLambdaSigma = 0.007f; -}; - -template -class GpuTimeFrameChunk -{ - public: - static size_t computeScalingSizeBytes(const int, const TimeFrameGPUParameters&); - static size_t computeFixedSizeBytes(const TimeFrameGPUParameters&); - static size_t computeRofPerChunk(const TimeFrameGPUParameters&, const size_t); - - GpuTimeFrameChunk() = delete; - GpuTimeFrameChunk(o2::its::TimeFrame* tf, TimeFrameGPUParameters& conf) - { - mTimeFramePtr = tf; - mTFGPUParams = &conf; - } - ~GpuTimeFrameChunk(); - - /// Most relevant operations - void allocate(const size_t, Stream&); - void reset(const Task, Stream&); - size_t loadDataOnDevice(const size_t, const size_t, const int, Stream&); - - /// Interface - Cluster* getDeviceClusters(const int); - int* getDeviceClusterExternalIndices(const int); - int* getDeviceIndexTables(const int); - Tracklet* getDeviceTracklets(const int); - int* getDeviceTrackletsLookupTables(const int); - CellSeed* getDeviceCells(const int); - int* getDeviceCellsLookupTables(const int); - int* getDeviceRoadsLookupTables(const int); - TimeFrameGPUParameters* getTimeFrameGPUParameters() const { return mTFGPUParams; } - - int* getDeviceCUBTmpBuffer() { return mCUBTmpBufferDevice; } - int* getDeviceFoundTracklets() { return mFoundTrackletsDevice; } - int* getDeviceNFoundCells() { return mNFoundCellsDevice; } - int* getDeviceCellNeigboursLookupTables(const int); - int* getDeviceCellNeighbours(const int); - CellSeed** getDeviceArrayCells() const { return mCellsDeviceArray; } - int** getDeviceArrayNeighboursCell() const { return mNeighboursCellDeviceArray; } - int** getDeviceArrayNeighboursCellLUT() const { return mNeighboursCellLookupTablesDeviceArray; } - - /// Vertexer only - int* getDeviceNTrackletCluster(const int combid) { return mNTrackletsPerClusterDevice[combid]; } - Line* getDeviceLines() { return mLinesDevice; }; - int* getDeviceNFoundLines() { return mNFoundLinesDevice; } - int* getDeviceNExclusiveFoundLines() { return mNExclusiveFoundLinesDevice; } - unsigned char* getDeviceUsedTracklets() { return mUsedTrackletsDevice; } - int* getDeviceClusteredLines() { return mClusteredLinesDevice; } - size_t getNPopulatedRof() const { return mNPopulatedRof; } - - private: - /// Host - std::array, nLayers> mHostClusters; - std::array, nLayers> mHostIndexTables; - - /// Device - std::array mClustersDevice; - std::array mClusterExternalIndicesDevice; - std::array mIndexTablesDevice; - std::array mTrackletsDevice; - std::array mTrackletsLookupTablesDevice; - std::array mCellsDevice; - // Road* mRoadsDevice; - std::array mCellsLookupTablesDevice; - std::array mNeighboursCellDevice; - std::array mNeighboursCellLookupTablesDevice; - std::array mRoadsLookupTablesDevice; - - // These are to make them accessible using layer index - CellSeed** mCellsDeviceArray; - int** mNeighboursCellDeviceArray; - int** mNeighboursCellLookupTablesDeviceArray; - - // Small accessory buffers - int* mCUBTmpBufferDevice; - int* mFoundTrackletsDevice; - int* mNFoundCellsDevice; - - /// Vertexer only - Line* mLinesDevice; - int* mNFoundLinesDevice; - int* mNExclusiveFoundLinesDevice; - unsigned char* mUsedTrackletsDevice; - std::array mNTrackletsPerClusterDevice; - int* mClusteredLinesDevice; - - /// State and configuration - bool mAllocated = false; - size_t mNRof = 0; - size_t mNPopulatedRof = 0; - o2::its::TimeFrame* mTimeFramePtr = nullptr; - TimeFrameGPUParameters* mTFGPUParams = nullptr; -}; -} // namespace o2::its::gpu -#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h index 8095d690bbcc8..b0f339f6ddf3d 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h @@ -24,11 +24,14 @@ namespace o2::its::gpu { -template -class TimeFrameGPU final : public TimeFrame +template +class TimeFrameGPU final : public TimeFrame { - using typename TimeFrame::CellSeedN; - using typename TimeFrame::IndexTableUtilsN; + using typename TimeFrame::CellSeedN; + using typename TimeFrame::IndexTableUtilsN; + using typename TimeFrame::ROFOverlapTableN; + using typename TimeFrame::ROFVertexLookupTableN; + using typename TimeFrame::ROFTimeSliceTableN; public: TimeFrameGPU() = default; @@ -39,25 +42,26 @@ class TimeFrameGPU final : public TimeFrame void popMemoryStack(const int); void registerHostMemory(const int); void unregisterHostMemory(const int); - void initialise(const int, const TrackingParameters&, const int, IndexTableUtilsN* utils = nullptr, const TimeFrameGPUParameters* pars = nullptr); - void initDevice(IndexTableUtilsN*, const TrackingParameters& trkParam, const TimeFrameGPUParameters&, const int, const int); - void initDeviceSAFitting(); + void initialise(const int, const TrackingParameters&, const int, IndexTableUtilsN* utils = nullptr); void loadIndexTableUtils(const int); void loadTrackingFrameInfoDevice(const int, const int); void createTrackingFrameInfoDeviceArray(const int); void loadUnsortedClustersDevice(const int, const int); - void createUnsortedClustersDeviceArray(const int, const int = nLayers); + void createUnsortedClustersDeviceArray(const int, const int = NLayers); void loadClustersDevice(const int, const int); - void createClustersDeviceArray(const int, const int = nLayers); + void createClustersDeviceArray(const int, const int = NLayers); void loadClustersIndexTables(const int, const int); void createClustersIndexTablesArray(const int); void createUsedClustersDevice(const int, const int); - void createUsedClustersDeviceArray(const int, const int = nLayers); + void createUsedClustersDeviceArray(const int, const int = NLayers); void loadUsedClustersDevice(); void loadROFrameClustersDevice(const int, const int); void createROFrameClustersDeviceArray(const int); - void loadMultiplicityCutMask(const int); void loadVertices(const int); + void loadROFOverlapTable(); + void loadROFTimeSliceTable(); + void loadROFVertexLookupTable(); + void updateROFVertexLookupTable(const int); /// void createTrackletsLUTDevice(const int, const int); @@ -100,7 +104,7 @@ class TimeFrameGPU final : public TimeFrame void syncStreams(const bool = true); void waitEvent(const int, const int); void recordEvent(const int); - void recordEvents(const int = 0, const int = nLayers); + void recordEvents(const int = 0, const int = NLayers); /// cleanup virtual void wipe() final; @@ -110,6 +114,9 @@ class TimeFrameGPU final : public TimeFrame virtual const char* getName() const noexcept { return "GPU"; } int getNClustersInRofSpan(const int, const int, const int) const; IndexTableUtilsN* getDeviceIndexTableUtils() { return mIndexTableUtilsDevice; } + const auto getDeviceROFOverlapTableView() { return mDeviceROFOverlapTableView; } + const auto getDeviceROFVertexLookupTableView() { return mDeviceROFVertexLookupTableView; } + const auto getDeviceROFTimeSliceTableView() { return mDeviceROFTimeSliceTableView; } int* getDeviceROFramesClusters(const int layer) { return mROFramesClustersDevice[layer]; } auto& getTrackITSExt() { return mTrackITSExt; } Vertex* getDeviceVertices() { return mPrimaryVerticesDevice; } @@ -118,12 +125,12 @@ class TimeFrameGPU final : public TimeFrame const o2::base::Propagator* getChainPropagator(); // Hybrid - Road* getDeviceRoads() { return mRoadsDevice; } + Road* getDeviceRoads() { return mRoadsDevice; } TrackITSExt* getDeviceTrackITSExt() { return mTrackITSExtDevice; } int* getDeviceNeighboursLUT(const int layer) { return mNeighboursLUTDevice[layer]; } gsl::span getDeviceNeighboursLUTs() { return mNeighboursLUTDevice; } gpuPair* getDeviceNeighbourPairs(const int layer) { return mNeighbourPairsDevice[layer]; } - std::array& getDeviceNeighboursAll() { return mNeighboursDevice; } + std::array& getDeviceNeighboursAll() { return mNeighboursDevice; } int* getDeviceNeighbours(const int layer) { return mNeighboursDevice[layer]; } int** getDeviceNeighboursArray() { return mNeighboursDevice.data(); } TrackingFrameInfo* getDeviceTrackingFrameInfo(const int); @@ -161,10 +168,10 @@ class TimeFrameGPU final : public TimeFrame void setDevicePropagator(const o2::base::PropagatorImpl* p) final { this->mPropagatorDevice = p; } // Host-specific getters - gsl::span getNTracklets() { return mNTracklets; } - gsl::span getNCells() { return mNCells; } + gsl::span getNTracklets() { return mNTracklets; } + gsl::span getNCells() { return mNCells; } auto& getArrayNCells() { return mNCells; } - gsl::span getNNeighbours() { return mNNeighbours; } + gsl::span getNNeighbours() { return mNNeighbours; } auto& getArrayNNeighbours() { return mNNeighbours; } // Host-available device getters @@ -184,51 +191,55 @@ class TimeFrameGPU final : public TimeFrame TimeFrameGPUParameters mGpuParams; // Host-available device buffer sizes - std::array mNTracklets; - std::array mNCells; - std::array mNNeighbours; + std::array mNTracklets; + std::array mNCells; + std::array mNNeighbours; // Device pointers IndexTableUtilsN* mIndexTableUtilsDevice; + // device navigation views + ROFOverlapTableN::View mDeviceROFOverlapTableView; + ROFTimeSliceTableN::View mDeviceROFTimeSliceTableView; + ROFVertexLookupTableN::View mDeviceROFVertexLookupTableView; // Hybrid pref uint8_t* mMultMaskDevice; Vertex* mPrimaryVerticesDevice; int* mROFramesPVDevice; - std::array mClustersDevice; - std::array mUnsortedClustersDevice; - std::array mClustersIndexTablesDevice; - std::array mUsedClustersDevice; - std::array mROFramesClustersDevice; + std::array mClustersDevice; + std::array mUnsortedClustersDevice; + std::array mClustersIndexTablesDevice; + std::array mUsedClustersDevice; + std::array mROFramesClustersDevice; const Cluster** mClustersDeviceArray; const Cluster** mUnsortedClustersDeviceArray; const int** mClustersIndexTablesDeviceArray; uint8_t** mUsedClustersDeviceArray; const int** mROFramesClustersDeviceArray; - std::array mTrackletsDevice; - std::array mTrackletsLUTDevice; - std::array mCellsLUTDevice; - std::array mNeighboursLUTDevice; + std::array mTrackletsDevice; + std::array mTrackletsLUTDevice; + std::array mCellsLUTDevice; + std::array mNeighboursLUTDevice; Tracklet** mTrackletsDeviceArray{nullptr}; int** mCellsLUTDeviceArray{nullptr}; int** mNeighboursCellDeviceArray{nullptr}; int** mNeighboursCellLUTDeviceArray{nullptr}; int** mTrackletsLUTDeviceArray{nullptr}; - std::array mCellsDevice; + std::array mCellsDevice; CellSeedN** mCellsDeviceArray; - std::array mNeighboursIndexTablesDevice; + std::array mNeighboursIndexTablesDevice; CellSeedN* mTrackSeedsDevice{nullptr}; - std::array mCellSeedsDevice; + std::array mCellSeedsDevice; o2::track::TrackParCovF** mCellSeedsDeviceArray; - std::array mCellSeedsChi2Device; + std::array mCellSeedsChi2Device; float** mCellSeedsChi2DeviceArray; - Road* mRoadsDevice; + Road* mRoadsDevice; TrackITSExt* mTrackITSExtDevice; - std::array*, nLayers - 2> mNeighbourPairsDevice; - std::array mNeighboursDevice; - std::array mTrackingFrameInfoDevice; + std::array*, NLayers - 2> mNeighbourPairsDevice; + std::array mNeighboursDevice; + std::array mTrackingFrameInfoDevice; const TrackingFrameInfo** mTrackingFrameInfoDeviceArray; /// Vertexer @@ -245,25 +256,25 @@ class TimeFrameGPU final : public TimeFrame // State Streams mGpuStreams; - std::bitset mPinnedUnsortedClusters{0}; - std::bitset mPinnedClusters{0}; - std::bitset mPinnedClustersIndexTables{0}; - std::bitset mPinnedUsedClusters{0}; - std::bitset mPinnedROFramesClusters{0}; - std::bitset mPinnedTrackingFrameInfo{0}; + std::bitset mPinnedUnsortedClusters{0}; + std::bitset mPinnedClusters{0}; + std::bitset mPinnedClustersIndexTables{0}; + std::bitset mPinnedUsedClusters{0}; + std::bitset mPinnedROFramesClusters{0}; + std::bitset mPinnedTrackingFrameInfo{0}; // Temporary buffer for storing output tracks from GPU tracking bounded_vector mTrackITSExt; }; -template -inline int TimeFrameGPU::getNClustersInRofSpan(const int rofIdstart, const int rofSpanSize, const int layerId) const +template +inline int TimeFrameGPU::getNClustersInRofSpan(const int rofIdstart, const int rofSpanSize, const int layerId) const { return static_cast(this->mROFramesClusters[layerId][(rofIdstart + rofSpanSize) < this->mROFramesClusters.size() ? rofIdstart + rofSpanSize : this->mROFramesClusters.size() - 1] - this->mROFramesClusters[layerId][rofIdstart]); } -template -inline std::vector TimeFrameGPU::getClusterSizes() +template +inline std::vector TimeFrameGPU::getClusterSizes() { std::vector sizes(this->mUnsortedClusters.size()); std::transform(this->mUnsortedClusters.begin(), this->mUnsortedClusters.end(), sizes.begin(), @@ -271,20 +282,20 @@ inline std::vector TimeFrameGPU::getClusterSizes() return sizes; } -template -inline int TimeFrameGPU::getNumberOfTracklets() const +template +inline int TimeFrameGPU::getNumberOfTracklets() const { return std::accumulate(mNTracklets.begin(), mNTracklets.end(), 0); } -template -inline int TimeFrameGPU::getNumberOfCells() const +template +inline int TimeFrameGPU::getNumberOfCells() const { return std::accumulate(mNCells.begin(), mNCells.end(), 0); } -template -inline int TimeFrameGPU::getNumberOfNeighbours() const +template +inline int TimeFrameGPU::getNumberOfNeighbours() const { return std::accumulate(mNNeighbours.begin(), mNNeighbours.end(), 0); } diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TracerGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TracerGPU.h deleted file mode 100644 index e2bd7266caff9..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TracerGPU.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -#include "ITStracking/Definitions.h" - -#ifndef TRACKINGITSGPU_INCLUDE_TRACER_H -#define TRACKINGITSGPU_INCLUDE_TRACER_H - -#if defined(__CUDACC__) && defined(__USE_GPU_TRACER__) -namespace o2 -{ -namespace its -{ -namespace gpu -{ -class Tracer -{ - public: - Tracer(const char* name, int color_id = 0); - ~Tracer(); -}; -} // namespace gpu -} // namespace its -} // namespace o2 -#define RANGE(name, cid) o2::its::gpu::Tracer tracer(name, cid); -#else -#define RANGE(name, cid) -#endif - -#endif // TRACKINGITSGPU_INCLUDE_TRACER_H \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h index a4e4328b3aa22..f207d16bd20fc 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h @@ -13,9 +13,12 @@ #ifndef ITSTRACKINGGPU_TRACKINGKERNELS_H_ #define ITSTRACKINGGPU_TRACKINGKERNELS_H_ +#include +#include #include #include "ITStracking/BoundedAllocator.h" +#include "ITStracking/ROFLookupTables.h" #include "ITStracking/Definitions.h" #include "ITStrackingGPU/Utils.h" #include "DetectorsBase/Propagator.h" @@ -33,17 +36,16 @@ class Cluster; class TrackITSExt; class ExternalAllocator; -template -void countTrackletsInROFsHandler(const IndexTableUtils* utils, +template +void countTrackletsInROFsHandler(const IndexTableUtils* utils, const uint8_t* multMask, const int layer, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + const int iSlice, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFTimeSliceTable::View& timeSlices, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, - const int* rofPV, const int nVertices, const Cluster** clusters, std::vector nClusters, @@ -56,8 +58,8 @@ void countTrackletsInROFsHandler(const IndexTableUtils* utils, const float NSigmaCut, bounded_vector& phiCuts, const float resolutionPV, - std::array& minR, - std::array& maxR, + std::array& minR, + std::array& maxR, bounded_vector& resolutions, std::vector& radii, bounded_vector& mulScatAng, @@ -66,17 +68,16 @@ void countTrackletsInROFsHandler(const IndexTableUtils* utils, const int nThreads, gpu::Streams& streams); -template -void computeTrackletsInROFsHandler(const IndexTableUtils* utils, +template +void computeTrackletsInROFsHandler(const IndexTableUtils* utils, const uint8_t* multMask, const int layer, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + const int iSlice, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFTimeSliceTable::View& timeSlices, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, - const int* rofPV, const int nVertices, const Cluster** clusters, std::vector nClusters, @@ -92,8 +93,8 @@ void computeTrackletsInROFsHandler(const IndexTableUtils* utils, const float NSigmaCut, bounded_vector& phiCuts, const float resolutionPV, - std::array& minR, - std::array& maxR, + std::array& minR, + std::array& maxR, bounded_vector& resolutions, std::vector& radii, bounded_vector& mulScatAng, @@ -102,7 +103,7 @@ void computeTrackletsInROFsHandler(const IndexTableUtils* utils, const int nThreads, gpu::Streams& streams); -template +template void countCellsHandler(const Cluster** sortedClusters, const Cluster** unsortedClusters, const TrackingFrameInfo** tfInfo, @@ -110,10 +111,10 @@ void countCellsHandler(const Cluster** sortedClusters, int** trackletsLUT, const int nTracklets, const int layer, - CellSeed* cells, + CellSeed* cells, int** cellsLUTsDeviceArray, int* cellsLUTsHost, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, @@ -123,7 +124,7 @@ void countCellsHandler(const Cluster** sortedClusters, const int nThreads, gpu::Streams& streams); -template +template void computeCellsHandler(const Cluster** sortedClusters, const Cluster** unsortedClusters, const TrackingFrameInfo** tfInfo, @@ -131,10 +132,10 @@ void computeCellsHandler(const Cluster** sortedClusters, int** trackletsLUT, const int nTracklets, const int layer, - CellSeed* cells, + CellSeed* cells, int** cellsLUTsDeviceArray, int* cellsLUTsHost, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, @@ -143,14 +144,14 @@ void computeCellsHandler(const Cluster** sortedClusters, const int nThreads, gpu::Streams& streams); -template -void countCellNeighboursHandler(CellSeed** cellsLayersDevice, +template +void countCellNeighboursHandler(CellSeed** cellsLayersDevice, int* neighboursLUTs, int** cellsLUTs, gpuPair* cellNeighbours, int* neighboursIndexTable, const Tracklet** tracklets, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float maxChi2ClusterAttachment, const float bz, const int layerIndex, @@ -162,14 +163,14 @@ void countCellNeighboursHandler(CellSeed** cellsLayersDevice, const int nThreads, gpu::Stream& stream); -template -void computeCellNeighboursHandler(CellSeed** cellsLayersDevice, +template +void computeCellNeighboursHandler(CellSeed** cellsLayersDevice, int* neighboursLUTs, int** cellsLUTs, gpuPair* cellNeighbours, int* neighboursIndexTable, const Tracklet** tracklets, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float maxChi2ClusterAttachment, const float bz, const int layerIndex, @@ -186,17 +187,17 @@ int filterCellNeighboursHandler(gpuPair*, gpu::Stream&, o2::its::ExternalAllocator* = nullptr); -template +template void processNeighboursHandler(const int startLayer, const int startLevel, - CellSeed** allCellSeeds, - CellSeed* currentCellSeeds, - std::array& nCells, + CellSeed** allCellSeeds, + CellSeed* currentCellSeeds, + std::array& nCells, const unsigned char** usedClusters, - std::array& neighbours, + std::array& neighbours, gsl::span neighboursDeviceLUTs, const TrackingFrameInfo** foundTrackingFrameInfo, - bounded_vector>& seedsHost, + bounded_vector>& seedsHost, const float bz, const float MaxChi2ClusterAttachment, const float maxChi2NDF, @@ -206,8 +207,8 @@ void processNeighboursHandler(const int startLayer, const int nBlocks, const int nThreads); -template -void trackSeedHandler(CellSeed* trackSeeds, +template +void trackSeedHandler(CellSeed* trackSeeds, const TrackingFrameInfo** foundTrackingFrameInfo, const Cluster** unsortedClusters, o2::its::TrackITSExt* tracks, diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h index ee0a203f32fda..50f3c44e19024 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Utils.h @@ -360,41 +360,13 @@ GPUdii() const int4 getBinsRect(const Cluster& currentCluster, const int layerIn utils->getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; } -GPUdii() gpuSpan getPrimaryVertices(const int rof, - const int* roframesPV, - const int nROF, - const uint8_t* mask, - const Vertex* vertices) -{ - const int start_pv_id = roframesPV[rof]; - const int stop_rof = rof >= nROF - 1 ? nROF : rof + 1; - size_t delta = mask[rof] ? roframesPV[stop_rof] - start_pv_id : 0; // return empty span if ROF is excluded - return gpuSpan(&vertices[start_pv_id], delta); -}; - -GPUdii() gpuSpan getPrimaryVertices(const int romin, - const int romax, - const int* roframesPV, - const int nROF, - const Vertex* vertices) -{ - const int start_pv_id = roframesPV[romin]; - const int stop_rof = romax >= nROF - 1 ? nROF : romax + 1; - return gpuSpan(&vertices[start_pv_id], roframesPV[stop_rof] - roframesPV[romin]); -}; - GPUdii() gpuSpan getClustersOnLayer(const int rof, - const int totROFs, const int layer, const int** roframesClus, const Cluster** clusters) { - if (rof < 0 || rof >= totROFs) { - return gpuSpan(); - } const int start_clus_id{roframesClus[layer][rof]}; - const int stop_rof = rof >= totROFs - 1 ? totROFs : rof + 1; - const unsigned int delta = roframesClus[layer][stop_rof] - start_clus_id; + const unsigned int delta = roframesClus[layer][rof + 1] - start_clus_id; return gpuSpan(&(clusters[layer][start_clus_id]), delta); } diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h deleted file mode 100644 index dddc247466c65..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexerTraitsGPU.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VertexerTraitsGPU.h -/// \brief -/// \author matteo.concas@cern.ch - -// #define VTX_DEBUG -#ifndef ITSTRACKINGGPU_VERTEXERTRAITSGPU_H_ -#define ITSTRACKINGGPU_VERTEXERTRAITSGPU_H_ - -#include - -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/Tracklet.h" - -#include "ITStrackingGPU/TimeFrameGPU.h" - -namespace o2::its -{ - -template -class VertexerTraitsGPU final : public VertexerTraits -{ - public: - void initialise(const TrackingParameters&, const int iteration = 0) final; - void adoptTimeFrame(TimeFrame* tf) noexcept final; - void computeTracklets(const int iteration = 0) final; - void computeTrackletMatching(const int iteration = 0) final; - void computeVertices(const int iteration = 0) final; - void updateVertexingParameters(const std::vector&, const TimeFrameGPUParameters&) final; - - bool isGPU() const noexcept final { return true; } - const char* getName() const noexcept final { return "GPU"; } - - protected: - gpu::TimeFrameGPU* mTimeFrameGPU; - TimeFrameGPUParameters mTfGPUParams; -}; - -} // namespace o2::its - -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexingKernels.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexingKernels.h deleted file mode 100644 index 67f12bad8486c..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/VertexingKernels.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// - -#ifndef ITSTRACKINGGPU_VERTEXINGKERNELS_H_ -#define ITSTRACKINGGPU_VERTEXINGKERNELS_H_ - -#include -#include -#include -#include "ITStracking/Tracklet.h" -#include "ITStracking/Cluster.h" -#include "ITStracking/ClusterLines.h" -#include "ITStrackingGPU/Utils.h" - -namespace o2::its -{ - -/// Trackleting -template -void countTrackletsInROFsHandler(const IndexTableUtils* GPUrestrict() utils, - const uint8_t* GPUrestrict() multMask, - const int32_t nRofs, - const int32_t deltaROF, - const int32_t* GPUrestrict() rofPV, - const int32_t vertPerRofThreshold, - const Cluster** GPUrestrict() clusters, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const uint8_t** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() clustersIndexTables, - int32_t** trackletsPerClusterLUTs, - int32_t** trackletsPerClusterSumLUTs, - int32_t** trackletsPerROF, - const std::array& trackletsPerClusterLUTsHost, - const std::array& trackletsPerClusterSumLUTsHost, - const int32_t iteration, - const float phiCut, - const int32_t maxTrackletsPerCluster, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams); - -template -void computeTrackletsInROFsHandler(const IndexTableUtils* GPUrestrict() utils, - const uint8_t* GPUrestrict() multMask, - const int32_t nRofs, - const int32_t deltaROF, - const int32_t* GPUrestrict() rofPV, - const int vertPerRofThreshold, - const Cluster** GPUrestrict() clusters, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const uint8_t** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() clustersIndexTables, - Tracklet** GPUrestrict() foundTracklets, - const int32_t** GPUrestrict() trackletsPerClusterLUTs, - const int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - const int32_t** GPUrestrict() trackletsPerROF, - const int32_t iteration, - const float phiCut, - const int32_t maxTrackletsPerCluster, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams); - -/// Selection -void countTrackletsMatchingInROFsHandler(const int32_t nRofs, - const int32_t deltaROF, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const Cluster** GPUrestrict() clusters, - uint8_t** GPUrestrict() usedClusters, - const Tracklet** GPUrestrict() foundTracklets, - uint8_t* GPUrestrict() usedTracklets, - const int32_t** GPUrestrict() trackletsPerClusterLUTs, - const int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - int32_t* GPUrestrict() linesPerClusterLUT, - int32_t* GPUrestrict() linesPerClusterSumLUT, - const int32_t iteration, - const float phiCut, - const float tanLambdaCut, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams); - -void computeTrackletsMatchingInROFsHandler(const int32_t nRofs, - const int32_t deltaROF, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const Cluster** GPUrestrict() clusters, - const uint8_t** GPUrestrict() usedClusters, - const Tracklet** GPUrestrict() foundTracklets, - uint8_t* GPUrestrict() usedTracklets, - const int32_t** GPUrestrict() trackletsPerClusterLUTs, - const int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - const int32_t* GPUrestrict() linesPerClusterSumLUT, - Line* GPUrestrict() lines, - const int32_t iteration, - const float phiCut, - const float tanLambdaCut, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams); - -} // namespace o2::its -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu deleted file mode 100644 index 79f4e40dc5f10..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \author matteo.concas@cern.ch - -#include -#include "ITStrackingGPU/ClusterLinesGPU.h" - -namespace o2 -{ -namespace its -{ -namespace gpu -{ - -GPUd() ClusterLinesGPU::ClusterLinesGPU(const Line& firstLine, const Line& secondLine) -{ - float covarianceFirst[3]; - float covarianceSecond[3]; - - for (int i{0}; i < 3; ++i) { - covarianceFirst[i] = 1.f; - covarianceSecond[i] = 1.f; - } - - double determinantFirst = - firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] * covarianceFirst[2] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1] * covarianceFirst[2]; - double determinantSecond = - secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] * covarianceSecond[2] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1] * covarianceSecond[2]; - - mAMatrix[0] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[1] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[1] * covarianceFirst[2] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[1] * covarianceSecond[2] / determinantSecond; - - mAMatrix[2] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[2] * covarianceFirst[1] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[2] * covarianceSecond[1] / determinantSecond; - - mAMatrix[3] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[4] = -firstLine.cosinesDirector[1] * firstLine.cosinesDirector[2] * covarianceFirst[0] / determinantFirst - - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[2] * covarianceSecond[0] / determinantSecond; - - mAMatrix[5] = (firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1]) / - determinantFirst + - (secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1]) / - determinantSecond; - - mBMatrix[0] = - (firstLine.cosinesDirector[1] * covarianceFirst[2] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[1]) + - firstLine.cosinesDirector[2] * covarianceFirst[1] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[0] += - (secondLine.cosinesDirector[1] * covarianceSecond[2] * (-secondLine.cosinesDirector[1] * secondLine.originPoint[0] + secondLine.cosinesDirector[0] * secondLine.originPoint[1]) + - secondLine.cosinesDirector[2] * covarianceSecond[1] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[0] + - secondLine.cosinesDirector[0] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[1] = - (firstLine.cosinesDirector[0] * covarianceFirst[2] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[2] * covarianceFirst[0] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[1] += - (secondLine.cosinesDirector[0] * covarianceSecond[2] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[1] + secondLine.cosinesDirector[1] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[2] * covarianceSecond[0] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[1] + - secondLine.cosinesDirector[1] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[2] = - (firstLine.cosinesDirector[0] * covarianceFirst[1] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[1] * covarianceFirst[0] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[1])) / - determinantFirst; - - mBMatrix[2] += - (secondLine.cosinesDirector[0] * covarianceSecond[1] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[2] + secondLine.cosinesDirector[2] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[1] * covarianceSecond[0] * - (-secondLine.cosinesDirector[1] * secondLine.originPoint[2] + - secondLine.cosinesDirector[2] * secondLine.originPoint[1])) / - determinantSecond; - - computeClusterCentroid(); -} - -GPUd() void ClusterLinesGPU::computeClusterCentroid() -{ - - double determinant{mAMatrix[0] * (mAMatrix[3] * mAMatrix[5] - mAMatrix[4] * mAMatrix[4]) - - mAMatrix[1] * (mAMatrix[1] * mAMatrix[5] - mAMatrix[4] * mAMatrix[2]) + - mAMatrix[2] * (mAMatrix[1] * mAMatrix[4] - mAMatrix[2] * mAMatrix[3])}; - - if (determinant == 0) { - return; - } - - mVertex[0] = -(mBMatrix[0] * (mAMatrix[3] * mAMatrix[5] - mAMatrix[4] * mAMatrix[4]) - - mAMatrix[1] * (mBMatrix[1] * mAMatrix[5] - mAMatrix[4] * mBMatrix[2]) + - mAMatrix[2] * (mBMatrix[1] * mAMatrix[4] - mBMatrix[2] * mAMatrix[3])) / - determinant; - mVertex[1] = -(mAMatrix[0] * (mBMatrix[1] * mAMatrix[5] - mBMatrix[2] * mAMatrix[4]) - - mBMatrix[0] * (mAMatrix[1] * mAMatrix[5] - mAMatrix[4] * mAMatrix[2]) + - mAMatrix[2] * (mAMatrix[1] * mBMatrix[2] - mAMatrix[2] * mBMatrix[1])) / - determinant; - mVertex[2] = -(mAMatrix[0] * (mAMatrix[3] * mBMatrix[2] - mBMatrix[1] * mAMatrix[4]) - - mAMatrix[1] * (mAMatrix[1] * mBMatrix[2] - mBMatrix[1] * mAMatrix[2]) + - mBMatrix[0] * (mAMatrix[1] * mAMatrix[4] - mAMatrix[2] * mAMatrix[3])) / - determinant; -} -} // namespace gpu -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameChunk.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameChunk.cu deleted file mode 100644 index c8512e667aea8..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameChunk.cu +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include -#include -#include - -#include "ITStracking/Constants.h" - -#include "ITStrackingGPU/Utils.h" -#include "ITStrackingGPU/TracerGPU.h" - -#include "ITStrackingGPU/TimeFrameChunk.h" - -#include -#include - -#include "GPUCommonDef.h" -#include "GPUCommonMath.h" -#include "GPUCommonLogger.h" -#include "GPUCommonHelpers.h" - -#ifndef __HIPCC__ -#define THRUST_NAMESPACE thrust::cuda -#else -#define THRUST_NAMESPACE thrust::hip -#endif - -namespace o2::its -{ -using constants::GB; -using constants::MB; -namespace gpu -{ - -template -GpuTimeFrameChunk::~GpuTimeFrameChunk() -{ - if (mAllocated) { - for (int i = 0; i < nLayers; ++i) { - GPUChkErrS(cudaFree(mClustersDevice[i])); - // GPUChkErrS(cudaFree(mTrackingFrameInfoDevice[i])); - GPUChkErrS(cudaFree(mClusterExternalIndicesDevice[i])); - GPUChkErrS(cudaFree(mIndexTablesDevice[i])); - if (i < nLayers - 1) { - GPUChkErrS(cudaFree(mTrackletsDevice[i])); - GPUChkErrS(cudaFree(mTrackletsLookupTablesDevice[i])); - if (i < nLayers - 2) { - GPUChkErrS(cudaFree(mCellsDevice[i])); - GPUChkErrS(cudaFree(mCellsLookupTablesDevice[i])); - GPUChkErrS(cudaFree(mRoadsLookupTablesDevice[i])); - if (i < nLayers - 3) { - GPUChkErrS(cudaFree(mNeighboursCellLookupTablesDevice[i])); - GPUChkErrS(cudaFree(mNeighboursCellDevice[i])); - } - } - } - } - // GPUChkErrS(cudaFree(mRoadsDevice)); - GPUChkErrS(cudaFree(mCUBTmpBufferDevice)); - GPUChkErrS(cudaFree(mFoundTrackletsDevice)); - GPUChkErrS(cudaFree(mNFoundCellsDevice)); - GPUChkErrS(cudaFree(mCellsDeviceArray)); - GPUChkErrS(cudaFree(mNeighboursCellDeviceArray)); - GPUChkErrS(cudaFree(mNeighboursCellLookupTablesDeviceArray)); - } -} - -template -void GpuTimeFrameChunk::allocate(const size_t nrof, Stream& stream) -{ - RANGE("device_partition_allocation", 2); - mNRof = nrof; - // for (int i = 0; i < nLayers; ++i) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mClustersDevice[i])), sizeof(Cluster) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mTrackingFrameInfoDevice[i])), sizeof(TrackingFrameInfo) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mClusterExternalIndicesDevice[i])), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mIndexTablesDevice[i])), sizeof(int) * (256 * 128 + 1) * nrof, &stream, true); - // if (i < nLayers - 1) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mTrackletsLookupTablesDevice[i])), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mTrackletsDevice[i])), sizeof(Tracklet) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // if (i < nLayers - 2) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mCellsLookupTablesDevice[i])), sizeof(int) * mTFGPUParams->validatedTrackletsCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mCellsDevice[i])), sizeof(CellSeed) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mRoadsLookupTablesDevice[i]), sizeof(int) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // if (i < nLayers - 3) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mNeighboursCellLookupTablesDevice[i])), sizeof(int) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mNeighboursCellDevice[i])), sizeof(int) * mTFGPUParams->maxNeighboursSize * nrof, &stream, true); - // } - // if (i < 2) { - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&(mNTrackletsPerClusterDevice[i])), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // } - // } - // } - // } - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mCUBTmpBufferDevice), mTFGPUParams->tmpCUBBufferSize * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mLinesDevice), sizeof(Line) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNFoundLinesDevice), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNExclusiveFoundLinesDevice), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * nrof + 1, &stream, true); // + 1 for cub::DeviceScan::ExclusiveSum, to cover cases where we have maximum number of clusters per ROF - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mUsedTrackletsDevice), sizeof(unsigned char) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mClusteredLinesDevice), sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mTFGPUParams->maxTrackletsPerCluster * nrof, &stream, true); - // // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mRoadsDevice), sizeof(Road) * mTFGPUParams->maxRoadPerRofSize * nrof, &stream, true); - - // /// Invariant allocations - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mFoundTrackletsDevice), (nLayers - 1) * sizeof(int) * nrof, &stream, true); // No need to reset, we always read it after writing - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNFoundCellsDevice), (nLayers - 2) * sizeof(int) * nrof, &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mCellsDeviceArray), (nLayers - 2) * sizeof(CellSeed*), &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNeighboursCellDeviceArray), (nLayers - 3) * sizeof(int*), &stream, true); - // static_cast*>(mTimeFramePtr)->allocMemAsync(reinterpret_cast(&mNeighboursCellLookupTablesDeviceArray), (nLayers - 3) * sizeof(int*), &stream, true); - - // /// Copy pointers of allocated memory to regrouping arrays - // GPUChkErrS(cudaMemcpyAsync(mCellsDeviceArray, mCellsDevice.data(), (nLayers - 2) * sizeof(CellSeed*), cudaMemcpyHostToDevice, stream.get())); - // GPUChkErrS(cudaMemcpyAsync(mNeighboursCellDeviceArray, mNeighboursCellDevice.data(), (nLayers - 3) * sizeof(int*), cudaMemcpyHostToDevice, stream.get())); - // GPUChkErrS(cudaMemcpyAsync(mNeighboursCellLookupTablesDeviceArray, mNeighboursCellLookupTablesDevice.data(), (nLayers - 3) * sizeof(int*), cudaMemcpyHostToDevice, stream.get())); - - mAllocated = true; -} - -template -void GpuTimeFrameChunk::reset(const Task task, Stream& stream) -{ - RANGE("buffer_reset", 0); - // if ((bool)task) { // Vertexer-only initialisation (cannot be constexpr: due to the presence of gpu raw calls can't be put in header) - // for (int i = 0; i < 2; i++) { - // auto thrustTrackletsBegin = thrust::device_ptr(mTrackletsDevice[i]); - // auto thrustTrackletsEnd = thrustTrackletsBegin + mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * mNRof; - // thrust::fill(THRUST_NAMESPACE::par.on(stream.get()), thrustTrackletsBegin, thrustTrackletsEnd, Tracklet{}); - // GPUChkErrS(cudaMemsetAsync(mNTrackletsPerClusterDevice[i], 0, sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mNRof, stream.get())); - // } - // GPUChkErrS(cudaMemsetAsync(mUsedTrackletsDevice, false, sizeof(unsigned char) * mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * mNRof, stream.get())); - // GPUChkErrS(cudaMemsetAsync(mClusteredLinesDevice, -1, sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mTFGPUParams->maxTrackletsPerCluster * mNRof, stream.get())); - // } else { - // for (int i = 0; i < nLayers; ++i) { - // if (i < nLayers - 1) { - // GPUChkErrS(cudaMemsetAsync(mTrackletsLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->clustersPerROfCapacity * mNRof, stream.get())); - // auto thrustTrackletsBegin = thrust::device_ptr(mTrackletsDevice[i]); - // auto thrustTrackletsEnd = thrustTrackletsBegin + mTFGPUParams->maxTrackletsPerCluster * mTFGPUParams->clustersPerROfCapacity * mNRof; - // thrust::fill(THRUST_NAMESPACE::par.on(stream.get()), thrustTrackletsBegin, thrustTrackletsEnd, Tracklet{}); - // if (i < nLayers - 2) { - // GPUChkErrS(cudaMemsetAsync(mCellsLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->cellsLUTsize * mNRof, stream.get())); - // GPUChkErrS(cudaMemsetAsync(mRoadsLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->maxNeighboursSize * mNRof, stream.get())); - // if (i < nLayers - 3) { - // GPUChkErrS(cudaMemsetAsync(mNeighboursCellLookupTablesDevice[i], 0, sizeof(int) * mTFGPUParams->maxNeighboursSize * mNRof, stream.get())); - // GPUChkErrS(cudaMemsetAsync(mNeighboursCellDevice[i], 0, sizeof(int) * mTFGPUParams->maxNeighboursSize * mNRof, stream.get())); - // } - // } - // } - // } - // GPUChkErrS(cudaMemsetAsync(mNFoundCellsDevice, 0, (nLayers - 2) * sizeof(int), stream.get())); - // } -} - -template -size_t GpuTimeFrameChunk::computeScalingSizeBytes(const int nrof, const TimeFrameGPUParameters& config) -{ - size_t rofsize = nLayers * sizeof(int); // number of clusters per ROF - // rofsize += nLayers * sizeof(Cluster) * config.clustersPerROfCapacity; // clusters - // rofsize += nLayers * sizeof(TrackingFrameInfo) * config.clustersPerROfCapacity; // tracking frame info - // rofsize += nLayers * sizeof(int) * config.clustersPerROfCapacity; // external cluster indices - // rofsize += nLayers * sizeof(int) * (256 * 128 + 1); // index tables - // rofsize += (nLayers - 1) * sizeof(int) * config.clustersPerROfCapacity; // tracklets lookup tables - // rofsize += (nLayers - 1) * sizeof(Tracklet) * config.maxTrackletsPerCluster * config.clustersPerROfCapacity; // tracklets - // rofsize += 2 * sizeof(int) * config.clustersPerROfCapacity; // tracklets found per cluster (vertexer) - // rofsize += sizeof(unsigned char) * config.maxTrackletsPerCluster * config.clustersPerROfCapacity; // used tracklets (vertexer) - // rofsize += (nLayers - 2) * sizeof(int) * config.validatedTrackletsCapacity; // cells lookup tables - // rofsize += (nLayers - 2) * sizeof(CellSeed) * config.maxNeighboursSize; // cells - // rofsize += (nLayers - 3) * sizeof(int) * config.maxNeighboursSize; // cell neighbours lookup tables - // rofsize += (nLayers - 3) * sizeof(int) * config.maxNeighboursSize; // cell neighbours - // rofsize += sizeof(Road) * config.maxRoadPerRofSize; // roads - // rofsize += (nLayers - 2) * sizeof(int) * config.maxNeighboursSize; // road LUT - // rofsize += sizeof(Line) * config.maxTrackletsPerCluster * config.clustersPerROfCapacity; // lines - // rofsize += sizeof(int) * config.clustersPerROfCapacity; // found lines - // rofsize += sizeof(int) * config.clustersPerROfCapacity; // found lines exclusive sum - // rofsize += sizeof(int) * config.clustersPerROfCapacity * config.maxTrackletsPerCluster; // lines used in clusterlines - - // rofsize += (nLayers - 1) * sizeof(int); // total found tracklets - // rofsize += (nLayers - 2) * sizeof(int); // total found cells - - return rofsize * nrof; -} - -template -size_t GpuTimeFrameChunk::computeFixedSizeBytes(const TimeFrameGPUParameters& config) -{ - size_t total = config.tmpCUBBufferSize; // CUB tmp buffers - total += sizeof(gpu::StaticTrackingParameters); // static parameters loaded once - return total; -} - -template -size_t GpuTimeFrameChunk::computeRofPerChunk(const TimeFrameGPUParameters& config, const size_t m) -{ - return (m * GB / (float)(config.nTimeFrameChunks) - GpuTimeFrameChunk::computeFixedSizeBytes(config)) / (float)GpuTimeFrameChunk::computeScalingSizeBytes(1, config); -} - -/// Interface -template -Cluster* GpuTimeFrameChunk::getDeviceClusters(const int layer) -{ - return mClustersDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceClusterExternalIndices(const int layer) -{ - return mClusterExternalIndicesDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceIndexTables(const int layer) -{ - return mIndexTablesDevice[layer]; -} - -template -Tracklet* GpuTimeFrameChunk::getDeviceTracklets(const int layer) -{ - return mTrackletsDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceTrackletsLookupTables(const int layer) -{ - return mTrackletsLookupTablesDevice[layer]; -} - -template -CellSeed* GpuTimeFrameChunk::getDeviceCells(const int layer) -{ - return mCellsDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceCellsLookupTables(const int layer) -{ - return mCellsLookupTablesDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceCellNeigboursLookupTables(const int layer) -{ - return mNeighboursCellLookupTablesDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceCellNeighbours(const int layer) -{ - return mNeighboursCellDevice[layer]; -} - -template -int* GpuTimeFrameChunk::getDeviceRoadsLookupTables(const int layer) -{ - return mRoadsLookupTablesDevice[layer]; -} - -// Load data -template -size_t GpuTimeFrameChunk::loadDataOnDevice(const size_t startRof, const size_t maxRof, const int maxLayers, Stream& stream) -{ - RANGE("load_clusters_data", 5); - // auto nRofs = std::min(maxRof - startRof, mNRof); - // mNPopulatedRof = mTimeFramePtr->getNClustersROFrange(startRof, nRofs, 0).size(); - // for (int i = 0; i < maxLayers; ++i) { - // mHostClusters[i] = mTimeFramePtr->getClustersPerROFrange(startRof, nRofs, i); - // mHostIndexTables[i] = mTimeFramePtr->getIndexTablePerROFrange(startRof, nRofs, i); - // if (mHostClusters[i].size() > mTFGPUParams->clustersPerROfCapacity * nRofs) { - // LOGP(warning, "Clusters on layer {} exceed the expected value, resizing to config value: {}, will lose information!", i, mTFGPUParams->clustersPerROfCapacity * nRofs); - // } - // GPUChkErrS(cudaMemcpyAsync(mClustersDevice[i], - // mHostClusters[i].data(), - // (int)std::min(mHostClusters[i].size(), mTFGPUParams->clustersPerROfCapacity * nRofs) * sizeof(Cluster), - // cudaMemcpyHostToDevice, stream.get())); - // if (mHostIndexTables[i].data()) { - // GPUChkErrS(cudaMemcpyAsync(mIndexTablesDevice[i], - // mHostIndexTables[i].data(), - // mHostIndexTables[i].size() * sizeof(int), - // cudaMemcpyHostToDevice, stream.get())); - // } - // } - return mNPopulatedRof; // return the number of ROFs we loaded the data for. -} -template class GpuTimeFrameChunk<7>; -} // namespace gpu -} // namespace o2::its \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu index 6532165d9628a..c70695a65246c 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu @@ -52,8 +52,8 @@ void TimeFrameGPU::allocMem(void** ptr, size_t size, bool extAllocator, } } -template -void TimeFrameGPU::loadIndexTableUtils(const int iteration) +template +void TimeFrameGPU::loadIndexTableUtils(const int iteration) { GPUTimer timer("loading indextable utils"); if (!iteration) { @@ -64,8 +64,8 @@ void TimeFrameGPU::loadIndexTableUtils(const int iteration) GPUChkErrS(cudaMemcpy(mIndexTableUtilsDevice, &(this->mIndexTableUtils), sizeof(IndexTableUtilsN), cudaMemcpyHostToDevice)); } -template -void TimeFrameGPU::createUnsortedClustersDeviceArray(const int iteration, const int maxLayers) +template +void TimeFrameGPU::createUnsortedClustersDeviceArray(const int iteration, const int maxLayers) { if (!iteration) { GPUTimer timer("creating unsorted clusters array"); @@ -81,8 +81,8 @@ void TimeFrameGPU::createUnsortedClustersDeviceArray(const int iteratio } } -template -void TimeFrameGPU::loadUnsortedClustersDevice(const int iteration, const int layer) +template +void TimeFrameGPU::loadUnsortedClustersDevice(const int iteration, const int layer) { if (!iteration) { GPUTimer timer(mGpuStreams[layer], "loading unsorted clusters", layer); @@ -93,8 +93,8 @@ void TimeFrameGPU::loadUnsortedClustersDevice(const int iteration, cons } } -template -void TimeFrameGPU::createClustersDeviceArray(const int iteration, const int maxLayers) +template +void TimeFrameGPU::createClustersDeviceArray(const int iteration, const int maxLayers) { if (!iteration) { GPUTimer timer("creating sorted clusters array"); @@ -110,8 +110,8 @@ void TimeFrameGPU::createClustersDeviceArray(const int iteration, const } } -template -void TimeFrameGPU::loadClustersDevice(const int iteration, const int layer) +template +void TimeFrameGPU::loadClustersDevice(const int iteration, const int layer) { if (!iteration) { GPUTimer timer(mGpuStreams[layer], "loading sorted clusters", layer); @@ -122,8 +122,8 @@ void TimeFrameGPU::loadClustersDevice(const int iteration, const int la } } -template -void TimeFrameGPU::createClustersIndexTablesArray(const int iteration) +template +void TimeFrameGPU::createClustersIndexTablesArray(const int iteration) { if (!iteration) { GPUTimer timer("creating clustersindextable array"); @@ -139,8 +139,8 @@ void TimeFrameGPU::createClustersIndexTablesArray(const int iteration) } } -template -void TimeFrameGPU::loadClustersIndexTables(const int iteration, const int layer) +template +void TimeFrameGPU::loadClustersIndexTables(const int iteration, const int layer) { if (!iteration) { GPUTimer timer(mGpuStreams[layer], "loading sorted clusters", layer); @@ -151,8 +151,8 @@ void TimeFrameGPU::loadClustersIndexTables(const int iteration, const i } } -template -void TimeFrameGPU::createUsedClustersDeviceArray(const int iteration, const int maxLayers) +template +void TimeFrameGPU::createUsedClustersDeviceArray(const int iteration, const int maxLayers) { if (!iteration) { GPUTimer timer("creating used clusters flags"); @@ -168,8 +168,8 @@ void TimeFrameGPU::createUsedClustersDeviceArray(const int iteration, c } } -template -void TimeFrameGPU::createUsedClustersDevice(const int iteration, const int layer) +template +void TimeFrameGPU::createUsedClustersDevice(const int iteration, const int layer) { if (!iteration) { GPUTimer timer(mGpuStreams[layer], "creating used clusters flags", layer); @@ -180,18 +180,18 @@ void TimeFrameGPU::createUsedClustersDevice(const int iteration, const } } -template -void TimeFrameGPU::loadUsedClustersDevice() +template +void TimeFrameGPU::loadUsedClustersDevice() { - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { + for (auto iLayer{0}; iLayer < NLayers; ++iLayer) { GPUTimer timer(mGpuStreams[iLayer], "loading used clusters flags", iLayer); GPULog("gpu-transfer: loading {} used clusters flags on layer {}, for {:.2f} MB.", this->mUsedClusters[iLayer].size(), iLayer, this->mUsedClusters[iLayer].size() * sizeof(unsigned char) / constants::MB); GPUChkErrS(cudaMemcpyAsync(mUsedClustersDevice[iLayer], this->mUsedClusters[iLayer].data(), this->mUsedClusters[iLayer].size() * sizeof(unsigned char), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } } -template -void TimeFrameGPU::createROFrameClustersDeviceArray(const int iteration) +template +void TimeFrameGPU::createROFrameClustersDeviceArray(const int iteration) { if (!iteration) { GPUTimer timer("creating ROFrame clusters array"); @@ -207,8 +207,8 @@ void TimeFrameGPU::createROFrameClustersDeviceArray(const int iteration } } -template -void TimeFrameGPU::loadROFrameClustersDevice(const int iteration, const int layer) +template +void TimeFrameGPU::loadROFrameClustersDevice(const int iteration, const int layer) { if (!iteration) { GPUTimer timer(mGpuStreams[layer], "loading ROframe clusters", layer); @@ -219,8 +219,8 @@ void TimeFrameGPU::loadROFrameClustersDevice(const int iteration, const } } -template -void TimeFrameGPU::createTrackingFrameInfoDeviceArray(const int iteration) +template +void TimeFrameGPU::createTrackingFrameInfoDeviceArray(const int iteration) { if (!iteration) { GPUTimer timer("creating trackingframeinfo array"); @@ -236,8 +236,8 @@ void TimeFrameGPU::createTrackingFrameInfoDeviceArray(const int iterati } } -template -void TimeFrameGPU::loadTrackingFrameInfoDevice(const int iteration, const int layer) +template +void TimeFrameGPU::loadTrackingFrameInfoDevice(const int iteration, const int layer) { if (!iteration) { GPUTimer timer(mGpuStreams[layer], "loading trackingframeinfo", layer); @@ -248,43 +248,108 @@ void TimeFrameGPU::loadTrackingFrameInfoDevice(const int iteration, con } } -template -void TimeFrameGPU::loadMultiplicityCutMask(const int iteration) -{ - if (!iteration || iteration == 3) { // we need to re-load the swapped mult-mask in upc iteration - GPUTimer timer("loading multiplicity cut mask"); - GPULog("gpu-transfer: iteration {} loading multiplicity cut mask with {} elements, for {:.2f} MB.", iteration, this->mMultiplicityCutMask.size(), this->mMultiplicityCutMask.size() * sizeof(uint8_t) / constants::MB); - if (!iteration) { // only allocate on first call - allocMem(reinterpret_cast(&mMultMaskDevice), this->mMultiplicityCutMask.size() * sizeof(uint8_t), this->hasFrameworkAllocator()); - } - GPUChkErrS(cudaMemcpy(mMultMaskDevice, this->mMultiplicityCutMask.data(), this->mMultiplicityCutMask.size() * sizeof(uint8_t), cudaMemcpyHostToDevice)); - } -} - -template -void TimeFrameGPU::loadVertices(const int iteration) +template +void TimeFrameGPU::loadVertices(const int iteration) { if (!iteration) { GPUTimer timer("loading seeding vertices"); - GPULog("gpu-transfer: loading {} ROframes vertices, for {:.2f} MB.", this->mROFramesPV.size(), this->mROFramesPV.size() * sizeof(int) / constants::MB); - allocMem(reinterpret_cast(&mROFramesPVDevice), this->mROFramesPV.size() * sizeof(int), this->hasFrameworkAllocator()); - GPUChkErrS(cudaMemcpy(mROFramesPVDevice, this->mROFramesPV.data(), this->mROFramesPV.size() * sizeof(int), cudaMemcpyHostToDevice)); GPULog("gpu-transfer: loading {} seeding vertices, for {:.2f} MB.", this->mPrimaryVertices.size(), this->mPrimaryVertices.size() * sizeof(Vertex) / constants::MB); allocMem(reinterpret_cast(&mPrimaryVerticesDevice), this->mPrimaryVertices.size() * sizeof(Vertex), this->hasFrameworkAllocator()); GPUChkErrS(cudaMemcpy(mPrimaryVerticesDevice, this->mPrimaryVertices.data(), this->mPrimaryVertices.size() * sizeof(Vertex), cudaMemcpyHostToDevice)); } } -template -void TimeFrameGPU::createTrackletsLUTDeviceArray(const int iteration) +template +void TimeFrameGPU::loadROFOverlapTable() +{ + GPUTimer timer("initialising device view of ROFOverlapTable"); + const auto& hostTable = this->getROFOverlapTable(); + const auto& hostView = this->getROFOverlapTableView(); + using TableEntry = ROFOverlapTable::TableEntry; + using TableIndex = ROFOverlapTable::TableIndex; + using LayerTiming = o2::its::LayerTiming; + TableEntry* d_flatTable{nullptr}; + TableIndex* d_indices{nullptr}; + LayerTiming* d_layers{nullptr}; + size_t flatTableSize = hostTable.getFlatTableSize(); + allocMem(reinterpret_cast(&d_flatTable), flatTableSize * sizeof(TableEntry), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatTable, flatTableSize * sizeof(TableEntry), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_indices), hostTable.getIndicesSize() * sizeof(TableIndex), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_indices, hostView.mIndices, hostTable.getIndicesSize() * sizeof(TableIndex), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_layers), NLayers * sizeof(LayerTiming), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_layers, hostView.mLayers, NLayers * sizeof(LayerTiming), cudaMemcpyHostToDevice)); + mDeviceROFOverlapTableView = hostTable.getDeviceView(d_flatTable, d_indices, d_layers); +} + +template +void TimeFrameGPU::loadROFTimeSliceTable() +{ + GPUTimer timer("initialising device view of ROFTimeSliceTable"); + const auto& hostTable = this->getROFTimeSliceTable(); + const auto& hostView = this->getROFTimeSliceTableView(); + using ROFRange = ROFTimeSliceTable::ROFRange; + ROFRange* d_flatTable{nullptr}; + uint8_t* d_flatMask{nullptr}; + int32_t* d_layerROFOffset{nullptr}; + size_t flatTableSize = hostTable.getFlatTableSize(); + allocMem(reinterpret_cast(&d_flatTable), flatTableSize * sizeof(ROFRange), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatTable, flatTableSize * sizeof(ROFRange), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_flatMask), hostTable.getFlatMaskSize() * sizeof(uint8_t), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_flatMask, hostView.mFlatMask, hostTable.getFlatMaskSize() * sizeof(uint8_t), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_layerROFOffset), NLayers * sizeof(int32_t), this->hasExternalDeviceAllocator()); + cudaMemcpy(d_layerROFOffset, hostView.mLayerROFOffsets, NLayers * sizeof(int32_t), + cudaMemcpyHostToDevice); + mDeviceROFTimeSliceTableView = hostTable.getDeviceView(d_flatTable, d_flatMask, d_layerROFOffset); +} + +template +void TimeFrameGPU::loadROFVertexLookupTable() +{ + GPUTimer timer("initialising device view of ROFVertexLookupTable"); + const auto& hostTable = this->getROFVertexLookupTable(); + const auto& hostView = this->getROFVertexLookupTableView(); + using TableEntry = ROFVertexLookupTable::TableEntry; + using TableIndex = ROFVertexLookupTable::TableIndex; + using LayerTiming = o2::its::LayerTiming; + TableEntry* d_flatTable{nullptr}; + TableIndex* d_indices{nullptr}; + LayerTiming* d_layers{nullptr}; + size_t flatTableSize = hostTable.getFlatTableSize(); + allocMem(reinterpret_cast(&d_flatTable), flatTableSize * sizeof(TableEntry), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatTable, flatTableSize * sizeof(TableEntry), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_indices), hostTable.getIndicesSize() * sizeof(TableIndex), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_indices, hostView.mIndices, hostTable.getIndicesSize() * sizeof(TableIndex), cudaMemcpyHostToDevice)); + allocMem(reinterpret_cast(&d_layers), NLayers * sizeof(LayerTiming), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_layers, hostView.mLayers, NLayers * sizeof(LayerTiming), cudaMemcpyHostToDevice)); + mDeviceROFVertexLookupTableView = hostTable.getDeviceView(d_flatTable, d_indices, d_layers); +} + +template +void TimeFrameGPU::updateROFVertexLookupTable(const int iteration) +{ + const auto& hostTable = this->getROFVertexLookupTable(); + if (!iteration && hostTable.needsUpdate()) { + GPUTimer timer("updating device view of ROFVertexLookupTable"); + const auto& hostView = this->getROFVertexLookupTableView(); + using TableEntry = ROFVertexLookupTable::TableEntry; + TableEntry* d_flatTable{nullptr}; + size_t flatTableSize = hostTable.getFlatTableSize(); + allocMem(reinterpret_cast(&d_flatTable), flatTableSize * sizeof(TableEntry), this->hasExternalDeviceAllocator()); + GPUChkErrS(cudaMemcpy(d_flatTable, hostView.mFlatTable, flatTableSize * sizeof(TableEntry), cudaMemcpyHostToDevice)); + mDeviceROFVertexLookupTableView = hostTable.getDeviceView(d_flatTable, hostView.mIndices, hostView.mLayers); + } +} + +template +void TimeFrameGPU::createTrackletsLUTDeviceArray(const int iteration) { if (!iteration) { - allocMem(reinterpret_cast(&mTrackletsLUTDeviceArray), (nLayers - 1) * sizeof(int*), this->hasFrameworkAllocator()); + allocMem(reinterpret_cast(&mTrackletsLUTDeviceArray), (NLayers - 1) * sizeof(int*), this->hasExternalDeviceAllocator()); } } -template -void TimeFrameGPU::createTrackletsLUTDevice(const int iteration, const int layer) +template +void TimeFrameGPU::createTrackletsLUTDevice(const int iteration, const int layer) { GPUTimer timer(mGpuStreams[layer], "creating tracklets LUTs", layer); const int ncls = this->mClusters[layer].size() + 1; @@ -296,8 +361,8 @@ void TimeFrameGPU::createTrackletsLUTDevice(const int iteration, const GPUChkErrS(cudaMemsetAsync(mTrackletsLUTDevice[layer], 0, ncls * sizeof(int), mGpuStreams[layer].get())); } -template -void TimeFrameGPU::createTrackletsBuffersArray(const int iteration) +template +void TimeFrameGPU::createTrackletsBuffersArray(const int iteration) { if (!iteration) { GPUTimer timer("creating tracklet buffers array"); @@ -305,8 +370,8 @@ void TimeFrameGPU::createTrackletsBuffersArray(const int iteration) } } -template -void TimeFrameGPU::createTrackletsBuffers(const int layer) +template +void TimeFrameGPU::createTrackletsBuffers(const int layer) { GPUTimer timer(mGpuStreams[layer], "creating tracklet buffers", layer); mNTracklets[layer] = 0; @@ -317,31 +382,31 @@ void TimeFrameGPU::createTrackletsBuffers(const int layer) GPUChkErrS(cudaMemcpyAsync(&mTrackletsDeviceArray[layer], &mTrackletsDevice[layer], sizeof(Tracklet*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::loadTrackletsDevice() +template +void TimeFrameGPU::loadTrackletsDevice() { - GPUTimer timer(mGpuStreams, "loading tracklets", nLayers - 1); - for (auto iLayer{0}; iLayer < nLayers - 1; ++iLayer) { + GPUTimer timer(mGpuStreams, "loading tracklets", NLayers - 1); + for (auto iLayer{0}; iLayer < NLayers - 1; ++iLayer) { GPULog("gpu-transfer: loading {} tracklets on layer {}, for {:.2f} MB.", this->mTracklets[iLayer].size(), iLayer, this->mTracklets[iLayer].size() * sizeof(Tracklet) / constants::MB); GPUChkErrS(cudaHostRegister(this->mTracklets[iLayer].data(), this->mTracklets[iLayer].size() * sizeof(Tracklet), cudaHostRegisterPortable)); GPUChkErrS(cudaMemcpyAsync(mTrackletsDevice[iLayer], this->mTracklets[iLayer].data(), this->mTracklets[iLayer].size() * sizeof(Tracklet), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } } -template -void TimeFrameGPU::loadTrackletsLUTDevice() +template +void TimeFrameGPU::loadTrackletsLUTDevice() { GPUTimer timer("loading tracklets"); - for (auto iLayer{0}; iLayer < nLayers - 2; ++iLayer) { + for (auto iLayer{0}; iLayer < NLayers - 2; ++iLayer) { GPULog("gpu-transfer: loading tracklets LUT for {} elements on layer {}, for {:.2f} MB", this->mTrackletsLookupTable[iLayer].size(), iLayer + 1, this->mTrackletsLookupTable[iLayer].size() * sizeof(int) / constants::MB); GPUChkErrS(cudaMemcpyAsync(mTrackletsLUTDevice[iLayer + 1], this->mTrackletsLookupTable[iLayer].data(), this->mTrackletsLookupTable[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } mGpuStreams.sync(); - GPUChkErrS(cudaMemcpy(mTrackletsLUTDeviceArray, mTrackletsLUTDevice.data(), (nLayers - 1) * sizeof(int*), cudaMemcpyHostToDevice)); + GPUChkErrS(cudaMemcpy(mTrackletsLUTDeviceArray, mTrackletsLUTDevice.data(), (NLayers - 1) * sizeof(int*), cudaMemcpyHostToDevice)); } -template -void TimeFrameGPU::createNeighboursIndexTablesDevice(const int layer) +template +void TimeFrameGPU::createNeighboursIndexTablesDevice(const int layer) { GPUTimer timer(mGpuStreams[layer], "creating cells neighbours", layer); GPULog("gpu-transfer: reserving neighbours LUT for {} elements on layer {}, for {:.2f} MB.", mNCells[layer] + 1, layer, (mNCells[layer] + 1) * sizeof(int) / constants::MB); @@ -349,8 +414,8 @@ void TimeFrameGPU::createNeighboursIndexTablesDevice(const int layer) GPUChkErrS(cudaMemsetAsync(mNeighboursIndexTablesDevice[layer], 0, (mNCells[layer] + 1) * sizeof(int), mGpuStreams[layer].get())); } -template -void TimeFrameGPU::createNeighboursLUTDevice(const int layer, const unsigned int nCells) +template +void TimeFrameGPU::createNeighboursLUTDevice(const int layer, const unsigned int nCells) { GPUTimer timer(mGpuStreams[layer], "reserving neighboursLUT"); GPULog("gpu-allocation: reserving neighbours LUT for {} elements on layer {} , for {:.2f} MB.", nCells + 1, layer, (nCells + 1) * sizeof(int) / constants::MB); @@ -358,11 +423,11 @@ void TimeFrameGPU::createNeighboursLUTDevice(const int layer, const uns GPUChkErrS(cudaMemsetAsync(mNeighboursLUTDevice[layer], 0, (nCells + 1) * sizeof(int), mGpuStreams[layer].get())); } -template -void TimeFrameGPU::loadCellsDevice() +template +void TimeFrameGPU::loadCellsDevice() { - GPUTimer timer(mGpuStreams, "loading cell seeds", nLayers - 2); - for (auto iLayer{0}; iLayer < nLayers - 2; ++iLayer) { + GPUTimer timer(mGpuStreams, "loading cell seeds", NLayers - 2); + for (auto iLayer{0}; iLayer < NLayers - 2; ++iLayer) { GPULog("gpu-transfer: loading {} cell seeds on layer {}, for {:.2f} MB.", this->mCells[iLayer].size(), iLayer, this->mCells[iLayer].size() * sizeof(CellSeedN) / constants::MB); allocMemAsync(reinterpret_cast(&mCellsDevice[iLayer]), this->mCells[iLayer].size() * sizeof(CellSeedN), mGpuStreams[iLayer], this->hasFrameworkAllocator()); allocMemAsync(reinterpret_cast(&mNeighboursIndexTablesDevice[iLayer]), (this->mCells[iLayer].size() + 1) * sizeof(int), mGpuStreams[iLayer], this->hasFrameworkAllocator()); // accessory for the neigh. finding. @@ -371,17 +436,18 @@ void TimeFrameGPU::loadCellsDevice() } } -template -void TimeFrameGPU::createCellsLUTDeviceArray(const int iteration) +template +void TimeFrameGPU::createCellsLUTDeviceArray(const int iteration) { - if (!iteration) { - GPUTimer timer("creating cells LUTs array"); - allocMem(reinterpret_cast(&mCellsLUTDeviceArray), (nLayers - 2) * sizeof(int*), this->hasFrameworkAllocator()); - } + GPUTimer timer(mGpuStreams[layer], "creating cells LUTs", layer); + GPULog("gpu-transfer: creating cell LUT for {} elements on layer {}, for {:.2f} MB.", mNTracklets[layer] + 1, layer, (mNTracklets[layer] + 1) * sizeof(int) / constants::MB); + allocMemAsync(reinterpret_cast(&mCellsLUTDevice[layer]), (mNTracklets[layer] + 1) * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemsetAsync(mCellsLUTDevice[layer], 0, (mNTracklets[layer] + 1) * sizeof(int), mGpuStreams[layer].get())); + GPUChkErrS(cudaMemcpyAsync(&mCellsLUTDeviceArray[layer], &mCellsLUTDevice[layer], sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::createCellsLUTDevice(const int layer) +template +void TimeFrameGPU::createCellsLUTDevice(const int layer) { GPUTimer timer(mGpuStreams[layer], "creating cells LUTs", layer); GPULog("gpu-transfer: creating cell LUT for {} elements on layer {}, for {:.2f} MB.", mNTracklets[layer] + 1, layer, (mNTracklets[layer] + 1) * sizeof(int) / constants::MB); @@ -390,8 +456,8 @@ void TimeFrameGPU::createCellsLUTDevice(const int layer) GPUChkErrS(cudaMemcpyAsync(&mCellsLUTDeviceArray[layer], &mCellsLUTDevice[layer], sizeof(int*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::createCellsBuffersArray(const int iteration) +template +void TimeFrameGPU::createCellsBuffersArray(const int iteration) { if (!iteration) { GPUTimer timer("creating cells buffers array"); @@ -400,8 +466,8 @@ void TimeFrameGPU::createCellsBuffersArray(const int iteration) } } -template -void TimeFrameGPU::createCellsBuffers(const int layer) +template +void TimeFrameGPU::createCellsBuffers(const int layer) { GPUTimer timer(mGpuStreams[layer], "creating cells buffers"); mNCells[layer] = 0; @@ -412,19 +478,19 @@ void TimeFrameGPU::createCellsBuffers(const int layer) GPUChkErrS(cudaMemcpyAsync(&mCellsDeviceArray[layer], &mCellsDevice[layer], sizeof(CellSeedN*), cudaMemcpyHostToDevice, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::loadCellsLUTDevice() +template +void TimeFrameGPU::loadCellsLUTDevice() { - GPUTimer timer(mGpuStreams, "loading cells LUTs", nLayers - 3); - for (auto iLayer{0}; iLayer < nLayers - 3; ++iLayer) { + GPUTimer timer(mGpuStreams, "loading cells LUTs", NLayers - 3); + for (auto iLayer{0}; iLayer < NLayers - 3; ++iLayer) { GPULog("gpu-transfer: loading cell LUT for {} elements on layer {}, for {:.2f} MB.", this->mCellsLookupTable[iLayer].size(), iLayer, this->mCellsLookupTable[iLayer].size() * sizeof(int) / constants::MB); GPUChkErrS(cudaHostRegister(this->mCellsLookupTable[iLayer].data(), this->mCellsLookupTable[iLayer].size() * sizeof(int), cudaHostRegisterPortable)); GPUChkErrS(cudaMemcpyAsync(mCellsLUTDevice[iLayer + 1], this->mCellsLookupTable[iLayer].data(), this->mCellsLookupTable[iLayer].size() * sizeof(int), cudaMemcpyHostToDevice, mGpuStreams[iLayer].get())); } } -template -void TimeFrameGPU::loadRoadsDevice() +template +void TimeFrameGPU::loadRoadsDevice() { GPUTimer timer("loading roads device"); GPULog("gpu-transfer: loading {} roads, for {:.2f} MB.", this->mRoads.size(), this->mRoads.size() * sizeof(Road) / constants::MB); @@ -433,8 +499,8 @@ void TimeFrameGPU::loadRoadsDevice() GPUChkErrS(cudaMemcpy(mRoadsDevice, this->mRoads.data(), this->mRoads.size() * sizeof(Road), cudaMemcpyHostToDevice)); } -template -void TimeFrameGPU::loadTrackSeedsDevice(bounded_vector& seeds) +template +void TimeFrameGPU::loadTrackSeedsDevice(bounded_vector& seeds) { GPUTimer timer("loading track seeds"); GPULog("gpu-transfer: loading {} track seeds, for {:.2f} MB.", seeds.size(), seeds.size() * sizeof(CellSeedN) / constants::MB); @@ -443,8 +509,8 @@ void TimeFrameGPU::loadTrackSeedsDevice(bounded_vector& seed GPUChkErrS(cudaMemcpy(mTrackSeedsDevice, seeds.data(), seeds.size() * sizeof(CellSeedN), cudaMemcpyHostToDevice)); } -template -void TimeFrameGPU::createNeighboursDevice(const unsigned int layer) +template +void TimeFrameGPU::createNeighboursDevice(const unsigned int layer) { GPUTimer timer(mGpuStreams[layer], "reserving neighbours", layer); this->mNNeighbours[layer] = 0; @@ -457,8 +523,8 @@ void TimeFrameGPU::createNeighboursDevice(const unsigned int layer) allocMemAsync(reinterpret_cast(&mNeighboursDevice[layer]), (this->mNNeighbours[layer]) * sizeof(int), mGpuStreams[layer], this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); } -template -void TimeFrameGPU::createTrackITSExtDevice(bounded_vector& seeds) +template +void TimeFrameGPU::createTrackITSExtDevice(bounded_vector& seeds) { GPUTimer timer("reserving tracks"); mTrackITSExt = bounded_vector(seeds.size(), {}, this->getMemoryPool().get()); @@ -468,127 +534,46 @@ void TimeFrameGPU::createTrackITSExtDevice(bounded_vector& s GPUChkErrS(cudaHostRegister(mTrackITSExt.data(), seeds.size() * sizeof(o2::its::TrackITSExt), cudaHostRegisterPortable)); } -template -void TimeFrameGPU::createVtxTrackletsLUTDevice(const int32_t iteration) -{ - GPUTimer timer("creating vertexer tracklet LUTs"); - const int32_t ncls = this->mClusters[1].size(); - for (int32_t iMode{0}; iMode < 2; ++iMode) { - if (!iteration) { - GPULog("gpu-transfer: creating vertexer tracklets per cluster for {} elements for mode {}, for {:.2f} MB.", ncls, iMode, ncls * sizeof(int32_t) / constants::MB); - allocMemAsync(reinterpret_cast(&mNTrackletsPerClusterDevice[iMode]), ncls * sizeof(int32_t), mGpuStreams[iMode], this->hasFrameworkAllocator()); - - GPULog("gpu-transfer: creating vertexer tracklets per cluster sum for {} elements for mode {}, for {:.2f} MB.", ncls + 1, iMode, (ncls + 1) * sizeof(int32_t) / constants::MB); - allocMemAsync(reinterpret_cast(&mNTrackletsPerClusterSumDevice[iMode]), (ncls + 1) * sizeof(int32_t), mGpuStreams[iMode], this->hasFrameworkAllocator()); - - GPULog("gpu-transfer: creating vertexer tracklets per ROF for {} elements for mode {}, for {:.2f} MB.", this->mNrof + 1, iMode, (this->mNrof + 1) * sizeof(int32_t) / constants::MB); - allocMemAsync(reinterpret_cast(&mNTrackletsPerROFDevice[iMode]), (this->mNrof + 1) * sizeof(int32_t), mGpuStreams[iMode], this->hasFrameworkAllocator()); - } - GPUChkErrS(cudaMemsetAsync(mNTrackletsPerClusterDevice[iMode], 0, ncls * sizeof(int32_t), mGpuStreams[iMode].get())); - GPUChkErrS(cudaMemsetAsync(mNTrackletsPerClusterSumDevice[iMode], 0, (ncls + 1) * sizeof(int32_t), mGpuStreams[iMode].get())); - GPUChkErrS(cudaMemsetAsync(mNTrackletsPerROFDevice[iMode], 0, (this->mNrof + 1) * sizeof(int32_t), mGpuStreams[iMode].get())); - } - mGpuStreams[0].sync(); - mGpuStreams[1].sync(); - if (!iteration) { - allocMem(reinterpret_cast(&mNTrackletsPerClusterDeviceArray), mNTrackletsPerClusterDevice.size() * sizeof(int32_t*), this->hasFrameworkAllocator()); - GPUChkErrS(cudaMemcpy(mNTrackletsPerClusterDeviceArray, mNTrackletsPerClusterDevice.data(), mNTrackletsPerClusterDevice.size() * sizeof(int32_t*), cudaMemcpyHostToDevice)); - - allocMem(reinterpret_cast(&mNTrackletsPerClusterSumDeviceArray), mNTrackletsPerClusterSumDevice.size() * sizeof(int32_t*), this->hasFrameworkAllocator()); - GPUChkErrS(cudaMemcpy(mNTrackletsPerClusterSumDeviceArray, mNTrackletsPerClusterSumDevice.data(), mNTrackletsPerClusterSumDevice.size() * sizeof(int32_t*), cudaMemcpyHostToDevice)); - - allocMem(reinterpret_cast(&mNTrackletsPerROFDeviceArray), mNTrackletsPerROFDevice.size() * sizeof(int32_t*), this->hasFrameworkAllocator()); - GPUChkErrS(cudaMemcpy(mNTrackletsPerROFDeviceArray, mNTrackletsPerROFDevice.data(), mNTrackletsPerROFDevice.size() * sizeof(int32_t*), cudaMemcpyHostToDevice)); - } -} - -template -void TimeFrameGPU::createVtxTrackletsBuffers(const int32_t iteration) -{ - GPUTimer timer("creating vertexer tracklet buffers"); - for (int32_t iMode{0}; iMode < 2; ++iMode) { - this->mTotalTracklets[iMode] = 0; - GPUChkErrS(cudaMemcpyAsync(&(this->mTotalTracklets[iMode]), mNTrackletsPerClusterSumDevice[iMode] + this->mClusters[1].size(), sizeof(int32_t), cudaMemcpyDeviceToHost, mGpuStreams[iMode].get())); - GPULog("gpu-transfer: creating vertexer tracklets buffer for {} elements on layer {}, for {:.2f} MB.", this->mTotalTracklets[iMode], iMode, this->mTotalTracklets[iMode] * sizeof(Tracklet) / constants::MB); - allocMemAsync(reinterpret_cast(&mTrackletsDevice[iMode]), this->mTotalTracklets[iMode] * sizeof(Tracklet), mGpuStreams[iMode], this->hasFrameworkAllocator()); - } - mGpuStreams[0].sync(); - mGpuStreams[1].sync(); - allocMem(reinterpret_cast(&mTrackletsDeviceArray), 2 * sizeof(Tracklet*), this->hasFrameworkAllocator()); - GPUChkErrS(cudaHostRegister(mTrackletsDevice.data(), 2 * sizeof(Tracklet*), cudaHostRegisterPortable)); - GPUChkErrS(cudaMemcpy(mTrackletsDeviceArray, mTrackletsDevice.data(), 2 * sizeof(Tracklet*), cudaMemcpyHostToDevice)); -} - -template -void TimeFrameGPU::createVtxLinesLUTDevice(const int32_t iteration) -{ - GPUTimer timer("creating vertexer lines LUT and used tracklets buffer"); - const int32_t ncls = this->mClusters[1].size(); - - GPULog("gpu-transfer: creating vertexer lines per cluster for {} elements , for {:.2f} MB.", ncls, ncls * sizeof(int32_t) / constants::MB); - allocMem(reinterpret_cast(&mNLinesPerClusterDevice), ncls * sizeof(int32_t), this->hasFrameworkAllocator()); - - GPULog("gpu-transfer: creating vertexer lines per cluster sum for {} elements , for {:.2f} MB.", ncls + 1, (ncls + 1) * sizeof(int32_t) / constants::MB); - allocMem(reinterpret_cast(&mNLinesPerClusterSumDevice), (ncls + 1) * sizeof(int32_t), this->hasFrameworkAllocator()); - - const int32_t ntrkls = this->mTotalTracklets[0]; - GPULog("gpu-transfer: creating vertexer used tracklets for {} elements , for {:.2f} MB.", ntrkls, ntrkls * sizeof(uint8_t) / constants::MB); - allocMem(reinterpret_cast(&mUsedTrackletsDevice), ntrkls * sizeof(uint8_t), this->hasFrameworkAllocator()); -} - -template -void TimeFrameGPU::createVtxLinesBuffer(const int32_t iteration) +template +void TimeFrameGPU::downloadCellsDevice() { - GPUTimer timer("creating vertexer lines buffer and resetting used tracklets"); - int32_t nlines = 0; - GPUChkErrS(cudaMemcpy(&nlines, mNLinesPerClusterDevice + this->mClusters[1].size(), sizeof(int32_t), cudaMemcpyDeviceToHost)); - this->mTotalLines = nlines; - GPULog("gpu-transfer: creating vertexer lines for {} elements , for {:.2f} MB.", nlines, nlines * sizeof(Line) / constants::MB); - allocMem(reinterpret_cast(&mLinesDevice), nlines * sizeof(Line), this->hasFrameworkAllocator()); - // reset used tracklets - GPUChkErrS(cudaMemset(mUsedTrackletsDevice, 0, this->mTotalTracklets[0] * sizeof(uint8_t))); -} - -template -void TimeFrameGPU::downloadCellsDevice() -{ - GPUTimer timer(mGpuStreams, "downloading cells", nLayers - 2); - for (int iLayer{0}; iLayer < nLayers - 2; ++iLayer) { + GPUTimer timer(mGpuStreams, "downloading cells", NLayers - 2); + for (int iLayer{0}; iLayer < NLayers - 2; ++iLayer) { GPULog("gpu-transfer: downloading {} cells on layer: {}, for {:.2f} MB.", mNCells[iLayer], iLayer, mNCells[iLayer] * sizeof(CellSeedN) / constants::MB); this->mCells[iLayer].resize(mNCells[iLayer]); GPUChkErrS(cudaMemcpyAsync(this->mCells[iLayer].data(), this->mCellsDevice[iLayer], mNCells[iLayer] * sizeof(CellSeedN), cudaMemcpyDeviceToHost, mGpuStreams[iLayer].get())); } } -template -void TimeFrameGPU::downloadCellsLUTDevice() +template +void TimeFrameGPU::downloadCellsLUTDevice() { - GPUTimer timer(mGpuStreams, "downloading cell luts", nLayers - 3); - for (auto iLayer{0}; iLayer < nLayers - 3; ++iLayer) { + GPUTimer timer(mGpuStreams, "downloading cell luts", NLayers - 3); + for (auto iLayer{0}; iLayer < NLayers - 3; ++iLayer) { GPULog("gpu-transfer: downloading cells lut on layer {} for {} elements", iLayer, (mNTracklets[iLayer + 1] + 1)); this->mCellsLookupTable[iLayer].resize(mNTracklets[iLayer + 1] + 1); GPUChkErrS(cudaMemcpyAsync(this->mCellsLookupTable[iLayer].data(), mCellsLUTDevice[iLayer + 1], (mNTracklets[iLayer + 1] + 1) * sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[iLayer].get())); } } -template -void TimeFrameGPU::downloadCellsNeighboursDevice(std::vector>>& neighbours, const int layer) +template +void TimeFrameGPU::downloadCellsNeighboursDevice(std::vector>>& neighbours, const int layer) { GPUTimer timer(mGpuStreams[layer], "downloading neighbours from layer", layer); GPULog("gpu-transfer: downloading {} neighbours, for {:.2f} MB.", neighbours[layer].size(), neighbours[layer].size() * sizeof(std::pair) / constants::MB); GPUChkErrS(cudaMemcpyAsync(neighbours[layer].data(), mNeighbourPairsDevice[layer], neighbours[layer].size() * sizeof(gpuPair), cudaMemcpyDeviceToHost, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::downloadNeighboursLUTDevice(bounded_vector& lut, const int layer) +template +void TimeFrameGPU::downloadNeighboursLUTDevice(bounded_vector& lut, const int layer) { GPUTimer timer(mGpuStreams[layer], "downloading neighbours LUT from layer", layer); GPULog("gpu-transfer: downloading neighbours LUT for {} elements on layer {}, for {:.2f} MB.", lut.size(), layer, lut.size() * sizeof(int) / constants::MB); GPUChkErrS(cudaMemcpyAsync(lut.data(), mNeighboursLUTDevice[layer], lut.size() * sizeof(int), cudaMemcpyDeviceToHost, mGpuStreams[layer].get())); } -template -void TimeFrameGPU::downloadTrackITSExtDevice(bounded_vector& seeds) +template +void TimeFrameGPU::downloadTrackITSExtDevice(bounded_vector& seeds) { GPUTimer timer("downloading tracks"); GPULog("gpu-transfer: downloading {} tracks, for {:.2f} MB.", mTrackITSExt.size(), mTrackITSExt.size() * sizeof(o2::its::TrackITSExt) / constants::MB); @@ -597,8 +582,8 @@ void TimeFrameGPU::downloadTrackITSExtDevice(bounded_vector& GPUChkErrS(cudaHostUnregister(seeds.data())); } -template -void TimeFrameGPU::unregisterHostMemory(const int maxLayers) +template +void TimeFrameGPU::unregisterHostMemory(const int maxLayers) { GPUTimer timer("unregistering host memory"); GPULog("unregistering host memory"); @@ -610,13 +595,13 @@ void TimeFrameGPU::unregisterHostMemory(const int maxLayers) } }; auto checkedUnregisterArray = [](auto& bits, auto& vec) { - if (bits.test(nLayers)) { + if (bits.test(NLayers)) { GPUChkErrS(cudaHostUnregister(vec.data())); - bits.reset(nLayers); + bits.reset(NLayers); } }; - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { + for (auto iLayer{0}; iLayer < NLayers; ++iLayer) { checkedUnregisterEntry(mPinnedUsedClusters, this->mUsedClusters, iLayer); checkedUnregisterEntry(mPinnedUnsortedClusters, this->mUnsortedClusters, iLayer); checkedUnregisterEntry(mPinnedClusters, this->mClusters, iLayer); @@ -656,47 +641,47 @@ void TimeFrameGPU::initialise(const int iteration, IndexTableUtilsN* utils, const TimeFrameGPUParameters* gpuParam) { - mGpuStreams.resize(nLayers); - o2::its::TimeFrame::initialise(iteration, trkParam, maxLayers); + mGpuStreams.resize(NLayers); + o2::its::TimeFrame::initialise(iteration, trkParam, maxLayers); } -template -void TimeFrameGPU::syncStream(const size_t stream) +template +void TimeFrameGPU::syncStream(const size_t stream) { mGpuStreams[stream].sync(); } -template -void TimeFrameGPU::syncStreams(const bool device) +template +void TimeFrameGPU::syncStreams(const bool device) { mGpuStreams.sync(device); } -template -void TimeFrameGPU::waitEvent(const int stream, const int event) +template +void TimeFrameGPU::waitEvent(const int stream, const int event) { mGpuStreams.waitEvent(stream, event); } -template -void TimeFrameGPU::recordEvent(const int event) +template +void TimeFrameGPU::recordEvent(const int event) { mGpuStreams[event].record(); } -template -void TimeFrameGPU::recordEvents(const int start, const int end) +template +void TimeFrameGPU::recordEvents(const int start, const int end) { for (int i{start}; i < end; ++i) { recordEvent(i); } } -template -void TimeFrameGPU::wipe() +template +void TimeFrameGPU::wipe() { unregisterHostMemory(0); - o2::its::TimeFrame::wipe(); + o2::its::TimeFrame::wipe(); } template class TimeFrameGPU<7>; diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu deleted file mode 100644 index 7c42658242231..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include -#include "ITStrackingGPU/TracerGPU.h" - -#if !defined(__HIPCC__) && defined(__USE_GPU_TRACER__) -#include - -constexpr uint32_t colors[] = {0xff00ff00, 0xff0000ff, 0xffffff00, 0xffff00ff, 0xff00ffff, 0xffff0000, 0xffffffff}; -constexpr int num_colors = sizeof(colors) / sizeof(uint32_t); - -namespace o2 -{ -namespace its -{ -namespace gpu -{ -Tracer::Tracer(const char* name, int color_id) -{ - color_id = color_id % num_colors; - nvtxEventAttributes_t eventAttrib = {0}; - eventAttrib.version = NVTX_VERSION; - eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; - eventAttrib.colorType = NVTX_COLOR_ARGB; - eventAttrib.color = colors[color_id]; - eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; - eventAttrib.message.ascii = name; - nvtxRangePushEx(&eventAttrib); -} - -Tracer::~Tracer() -{ - nvtxRangePop(); -} - -} // namespace gpu -} // namespace its -} // namespace o2 -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx index f94147747a475..2ba9c11174c33 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx @@ -24,14 +24,24 @@ namespace o2::its { -template -void TrackerTraitsGPU::initialiseTimeFrame(const int iteration) +template +void TrackerTraitsGPU::initialiseTimeFrame(const int iteration) { - mTimeFrameGPU->initialise(iteration, this->mTrkParams[iteration], nLayers); + mTimeFrameGPU->initialise(iteration, this->mTrkParams[iteration], NLayers); + + // if (static bool initOnce{false}; !initOnce) { + // initOnce = true; + // TODO these tables can be put in const memory + mTimeFrameGPU->loadROFOverlapTable(); + mTimeFrameGPU->loadROFTimeSliceTable(); + mTimeFrameGPU->loadROFVertexLookupTable(); + // } + // on default stream mTimeFrameGPU->loadVertices(iteration); + // once the tables are in const memory just update the vertex one + // mTimeFrameGPU->updateROFVertexLookupTable(iteration); mTimeFrameGPU->loadIndexTableUtils(iteration); - mTimeFrameGPU->loadMultiplicityCutMask(iteration); // pinned on host mTimeFrameGPU->createUsedClustersDeviceArray(iteration); mTimeFrameGPU->createClustersDeviceArray(iteration); @@ -48,23 +58,20 @@ void TrackerTraitsGPU::initialiseTimeFrame(const int iteration) mTimeFrameGPU->pushMemoryStack(iteration); } -template -void TrackerTraitsGPU::adoptTimeFrame(TimeFrame* tf) +template +void TrackerTraitsGPU::adoptTimeFrame(TimeFrame* tf) { - mTimeFrameGPU = static_cast*>(tf); - this->mTimeFrame = static_cast*>(tf); + mTimeFrameGPU = static_cast*>(tf); + this->mTimeFrame = static_cast*>(tf); } -template -void TrackerTraitsGPU::computeLayerTracklets(const int iteration, int iROFslice, int iVertex) +template +void TrackerTraitsGPU::computeLayerTracklets(const int iteration, int iSlice, int iVertex) { const auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); - int startROF{0}; - int endROF{mTimeFrameGPU->getNrof()}; - // start by queuing loading needed of two last layers - for (int iLayer{nLayers}; iLayer-- > nLayers - 2;) { + for (int iLayer{NLayers}; iLayer-- > NLayers - 2;) { mTimeFrameGPU->createUsedClustersDevice(iteration, iLayer); mTimeFrameGPU->loadClustersDevice(iteration, iLayer); mTimeFrameGPU->loadClustersIndexTables(iteration, iLayer); @@ -82,16 +89,16 @@ void TrackerTraitsGPU::computeLayerTracklets(const int iteration, int i } mTimeFrameGPU->createTrackletsLUTDevice(iteration, iLayer); mTimeFrameGPU->waitEvent(iLayer, iLayer + 1); // wait stream until all data is available - countTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), + const auto& timeSlices = mTimeFrameGPU->getROFTimeSliceTableView().getSlice(iLayer, iSlice); + countTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), mTimeFrameGPU->getDeviceMultCutMask(), iLayer, - startROF, - endROF, - mTimeFrameGPU->getNrof(), - this->mTrkParams[iteration].DeltaROF, + iSlice, + mTimeFrameGPU->getDeviceROFOverlapTableView(), + mTimeFrameGPU->getDeviceROFTimeSliceTableView(), + mTimeFrameGPU->getDeviceROFVertexLookupTableView(), iVertex, mTimeFrameGPU->getDeviceVertices(), - mTimeFrameGPU->getDeviceROFramesPV(), mTimeFrameGPU->getPrimaryVerticesNum(), mTimeFrameGPU->getDeviceArrayClusters(), mTimeFrameGPU->getClusterSizes(), @@ -117,16 +124,15 @@ void TrackerTraitsGPU::computeLayerTracklets(const int iteration, int i if (mTimeFrameGPU->getNTracklets()[iLayer] == 0) { continue; } - computeTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), + computeTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), mTimeFrameGPU->getDeviceMultCutMask(), iLayer, - startROF, - endROF, - mTimeFrameGPU->getNrof(), - this->mTrkParams[iteration].DeltaROF, + iSlice, + mTimeFrameGPU->getDeviceROFOverlapTableView(), + mTimeFrameGPU->getDeviceROFTimeSliceTableView(), + mTimeFrameGPU->getDeviceROFVertexLookupTableView(), iVertex, mTimeFrameGPU->getDeviceVertices(), - mTimeFrameGPU->getDeviceROFramesPV(), mTimeFrameGPU->getPrimaryVerticesNum(), mTimeFrameGPU->getDeviceArrayClusters(), mTimeFrameGPU->getClusterSizes(), @@ -154,13 +160,13 @@ void TrackerTraitsGPU::computeLayerTracklets(const int iteration, int i } } -template -void TrackerTraitsGPU::computeLayerCells(const int iteration) +template +void TrackerTraitsGPU::computeLayerCells(const int iteration) { auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); // start by queuing loading needed of three last layers - for (int iLayer{nLayers}; iLayer-- > nLayers - 3;) { + for (int iLayer{NLayers}; iLayer-- > NLayers - 3;) { mTimeFrameGPU->loadUnsortedClustersDevice(iteration, iLayer); mTimeFrameGPU->loadTrackingFrameInfoDevice(iteration, iLayer); mTimeFrameGPU->recordEvent(iLayer); @@ -183,7 +189,7 @@ void TrackerTraitsGPU::computeLayerCells(const int iteration) mTimeFrameGPU->createCellsLUTDevice(iLayer); mTimeFrameGPU->waitEvent(iLayer, iLayer + 1); // wait stream until all data is available mTimeFrameGPU->waitEvent(iLayer, iLayer + 2); // wait stream until all data is available - countCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), + countCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), mTimeFrameGPU->getDeviceArrayUnsortedClusters(), mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), mTimeFrameGPU->getDeviceArrayTracklets(), @@ -193,7 +199,7 @@ void TrackerTraitsGPU::computeLayerCells(const int iteration) nullptr, mTimeFrameGPU->getDeviceArrayCellsLUT(), mTimeFrameGPU->getDeviceCellLUTs()[iLayer], - this->mTrkParams[iteration].DeltaROF, + mTimeFrameGPU->getDeviceROFOverlapTableView(), this->mBz, this->mTrkParams[iteration].MaxChi2ClusterAttachment, this->mTrkParams[iteration].CellDeltaTanLambdaSigma, @@ -206,7 +212,7 @@ void TrackerTraitsGPU::computeLayerCells(const int iteration) if (mTimeFrameGPU->getNCells()[iLayer] == 0) { continue; } - computeCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), + computeCellsHandler(mTimeFrameGPU->getDeviceArrayClusters(), mTimeFrameGPU->getDeviceArrayUnsortedClusters(), mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), mTimeFrameGPU->getDeviceArrayTracklets(), @@ -216,7 +222,7 @@ void TrackerTraitsGPU::computeLayerCells(const int iteration) mTimeFrameGPU->getDeviceCells()[iLayer], mTimeFrameGPU->getDeviceArrayCellsLUT(), mTimeFrameGPU->getDeviceCellLUTs()[iLayer], - this->mTrkParams[iteration].DeltaROF, + mTimeFrameGPU->getDeviceROFOverlapTableView(), this->mBz, this->mTrkParams[iteration].MaxChi2ClusterAttachment, this->mTrkParams[iteration].CellDeltaTanLambdaSigma, @@ -227,8 +233,8 @@ void TrackerTraitsGPU::computeLayerCells(const int iteration) } } -template -void TrackerTraitsGPU::findCellsNeighbours(const int iteration) +template +void TrackerTraitsGPU::findCellsNeighbours(const int iteration) { const auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); @@ -241,13 +247,13 @@ void TrackerTraitsGPU::findCellsNeighbours(const int iteration) } mTimeFrameGPU->createNeighboursIndexTablesDevice(iLayer); mTimeFrameGPU->createNeighboursLUTDevice(iLayer, nextLayerCellsNum); - countCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), + countCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), mTimeFrameGPU->getDeviceNeighboursLUT(iLayer), // LUT is initialised here. mTimeFrameGPU->getDeviceArrayCellsLUT(), mTimeFrameGPU->getDeviceNeighbourPairs(iLayer), mTimeFrameGPU->getDeviceNeighboursIndexTables(iLayer), (const Tracklet**)mTimeFrameGPU->getDeviceArrayTracklets(), - this->mTrkParams[0].DeltaROF, + mTimeFrameGPU->getDeviceROFOverlapTableView(), this->mTrkParams[0].MaxChi2ClusterAttachment, this->mBz, iLayer, @@ -262,13 +268,13 @@ void TrackerTraitsGPU::findCellsNeighbours(const int iteration) if (mTimeFrameGPU->getNNeighbours()[iLayer] == 0) { continue; } - computeCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), + computeCellNeighboursHandler(mTimeFrameGPU->getDeviceArrayCells(), mTimeFrameGPU->getDeviceNeighboursLUT(iLayer), mTimeFrameGPU->getDeviceArrayCellsLUT(), mTimeFrameGPU->getDeviceNeighbourPairs(iLayer), mTimeFrameGPU->getDeviceNeighboursIndexTables(iLayer), (const Tracklet**)mTimeFrameGPU->getDeviceArrayTracklets(), - this->mTrkParams[0].DeltaROF, + mTimeFrameGPU->getDeviceROFOverlapTableView(), this->mTrkParams[0].MaxChi2ClusterAttachment, this->mBz, iLayer, @@ -287,18 +293,22 @@ void TrackerTraitsGPU::findCellsNeighbours(const int iteration) mTimeFrameGPU->syncStreams(false); } -template -void TrackerTraitsGPU::findRoads(const int iteration) +template +void TrackerTraitsGPU::findRoads(const int iteration) { + bounded_vector> firstClusters(this->mTrkParams[iteration].NLayers, bounded_vector(this->getMemoryPool().get()), this->getMemoryPool().get()); + bounded_vector> sharedFirstClusters(this->mTrkParams[iteration].NLayers, bounded_vector(this->getMemoryPool().get()), this->getMemoryPool().get()); + firstClusters.resize(this->mTrkParams[iteration].NLayers); + sharedFirstClusters.resize(this->mTrkParams[iteration].NLayers); auto& conf = o2::its::ITSGpuTrackingParamConfig::Instance(); for (int startLevel{this->mTrkParams[iteration].CellsPerRoad()}; startLevel >= this->mTrkParams[iteration].CellMinimumLevel(); --startLevel) { const int minimumLayer{startLevel - 1}; - bounded_vector> trackSeeds(this->getMemoryPool().get()); + bounded_vector> trackSeeds(this->getMemoryPool().get()); for (int startLayer{this->mTrkParams[iteration].CellsPerRoad() - 1}; startLayer >= minimumLayer; --startLayer) { if ((this->mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) { continue; } - processNeighboursHandler(startLayer, + processNeighboursHandler(startLayer, startLevel, mTimeFrameGPU->getDeviceArrayCells(), mTimeFrameGPU->getDeviceCells()[startLayer], @@ -348,46 +358,51 @@ void TrackerTraitsGPU::findRoads(const int iteration) auto& tracks = mTimeFrameGPU->getTrackITSExt(); for (auto& track : tracks) { - if (!track.getChi2()) { - continue; // this is to skip the unset tracks that are put at the beginning of the vector by the sorting. To see if this can be optimised. - } int nShared = 0; bool isFirstShared{false}; + int firstLayer{-1}, firstCluster{-1}; for (int iLayer{0}; iLayer < this->mTrkParams[0].NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { continue; } - nShared += int(mTimeFrameGPU->isClusterUsed(iLayer, track.getClusterIndex(iLayer))); - isFirstShared |= !iLayer && mTimeFrameGPU->isClusterUsed(iLayer, track.getClusterIndex(iLayer)); + bool isShared = mTimeFrameGPU->isClusterUsed(iLayer, track.getClusterIndex(iLayer)); + nShared += int(isShared); + if (firstLayer < 0) { + firstCluster = track.getClusterIndex(iLayer); + isFirstShared = isShared && this->mTrkParams[0].AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].end(), firstCluster) != firstClusters[iLayer].end(); + firstLayer = iLayer; + } } - if (nShared > this->mTrkParams[0].ClusterSharing) { + /// do not account for the first cluster in the shared clusters number if it is allowed + if (nShared - int(isFirstShared && this->mTrkParams[0].AllowSharingFirstCluster) > this->mTrkParams[0].ClusterSharing) { continue; } - std::array rofs{INT_MAX, INT_MAX, INT_MAX}; + // here we can do the calculation of the time bracket simply + // by checkig in which rofs the clusters are + int bcStart{0}, bcEnd{std::numeric_limits::max()}; for (int iLayer{0}; iLayer < this->mTrkParams[0].NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { continue; } mTimeFrameGPU->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); int currentROF = mTimeFrameGPU->getClusterROF(iLayer, track.getClusterIndex(iLayer)); - for (int iR{0}; iR < 3; ++iR) { - if (rofs[iR] == INT_MAX) { - rofs[iR] = currentROF; - } - if (rofs[iR] == currentROF) { - break; - } - } - } - if (rofs[2] != INT_MAX) { - continue; + int bcClsSta = mTimeFrameGPU->getROFOverlapTableView().getLayer(iLayer).getROFStartInBC(currentROF); + int bcClsEnd = mTimeFrameGPU->getROFOverlapTableView().getLayer(iLayer).getROFEndInBC(currentROF); + bcStart = std::max(bcStart, bcClsSta); + bcEnd = std::min(bcEnd, bcClsEnd); } - if (rofs[1] != INT_MAX) { - track.setNextROFbit(); + track.getTimeStamp().setTimeStamp(bcStart); + track.getTimeStamp().setTimeStampError(bcEnd - bcStart + 1); + track.setUserField(0); + track.getParamOut().setUserField(0); + mTimeFrameGPU->getTracks().emplace_back(track); + + firstClusters[firstLayer].push_back(firstCluster); + if (isFirstShared) { + sharedFirstClusters[firstLayer].push_back(firstCluster); } - mTimeFrameGPU->getTracks(std::min(rofs[0], rofs[1])).emplace_back(track); } mTimeFrameGPU->loadUsedClustersDevice(); } @@ -395,26 +410,26 @@ void TrackerTraitsGPU::findRoads(const int iteration) mTimeFrameGPU->popMemoryStack(iteration); }; -template -int TrackerTraitsGPU::getTFNumberOfClusters() const +template +int TrackerTraitsGPU::getTFNumberOfClusters() const { return mTimeFrameGPU->getNumberOfClusters(); } -template -int TrackerTraitsGPU::getTFNumberOfTracklets() const +template +int TrackerTraitsGPU::getTFNumberOfTracklets() const { return std::accumulate(mTimeFrameGPU->getNTracklets().begin(), mTimeFrameGPU->getNTracklets().end(), 0); } -template -int TrackerTraitsGPU::getTFNumberOfCells() const +template +int TrackerTraitsGPU::getTFNumberOfCells() const { return mTimeFrameGPU->getNumberOfCells(); } -template -void TrackerTraitsGPU::setBz(float bz) +template +void TrackerTraitsGPU::setBz(float bz) { this->mBz = bz; mTimeFrameGPU->setBz(bz); diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index d9136cb96d00e..e5868ee065de6 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -258,13 +258,13 @@ struct is_valid_pair { } }; -template +template struct seed_selector { float maxQ2Pt; float maxChi2; GPUhd() seed_selector(float maxQ2Pt, float maxChi2) : maxQ2Pt(maxQ2Pt), maxChi2(maxChi2) {} - GPUhd() bool operator()(const CellSeed& seed) const + GPUhd() bool operator()(const CellSeed& seed) const { return !(seed.getQ2Pt() > maxQ2Pt || seed.getChi2() > maxChi2); } @@ -277,9 +277,9 @@ struct compare_track_chi2 { } }; -template +template GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( - CellSeed* trackSeeds, + CellSeed* trackSeeds, const TrackingFrameInfo** foundTrackingFrameInfo, const Cluster** unsortedClusters, o2::its::TrackITSExt* tracks, @@ -300,7 +300,7 @@ GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( o2::track::TrackPar linRef{temporaryTrack}; bool fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, 0, // int lastLayer, - nLayers, // int firstLayer, + NLayers, // int firstLayer, 1, // int firstCluster, maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, maxChi2NDF, // float maxChi2NDF, @@ -321,7 +321,7 @@ GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( temporaryTrack.setCov(temporaryTrack.getQ2Pt() * temporaryTrack.getQ2Pt() * temporaryTrack.getCov()[o2::track::CovLabels::kSigQ2Pt2], o2::track::CovLabels::kSigQ2Pt2); temporaryTrack.setChi2(0); fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, - nLayers - 1, // int lastLayer, + NLayers - 1, // int lastLayer, -1, // int firstLayer, -1, // int firstCluster, maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, @@ -341,15 +341,15 @@ GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( } } -template +template GPUg() void __launch_bounds__(256, 1) computeLayerCellNeighboursKernel( - CellSeed** cellSeedArray, + CellSeed** cellSeedArray, int* neighboursLUT, int* neighboursIndexTable, int** cellsLUTs, gpuPair* cellNeighbours, const Tracklet** tracklets, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float maxChi2ClusterAttachment, const float bz, const int layerIndex, @@ -368,15 +368,10 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellNeighboursKernel( break; } - if (deltaROF) { - const auto& trkl00 = tracklets[layerIndex][currentCellSeed.getFirstTrackletIndex()]; - const auto& trkl01 = tracklets[layerIndex + 1][currentCellSeed.getSecondTrackletIndex()]; - const auto& trkl10 = tracklets[layerIndex + 1][nextCellSeed.getFirstTrackletIndex()]; - const auto& trkl11 = tracklets[layerIndex + 2][nextCellSeed.getSecondTrackletIndex()]; - if ((o2::gpu::CAMath::Max(trkl00.getMaxRof(), o2::gpu::CAMath::Max(trkl01.getMaxRof(), o2::gpu::CAMath::Max(trkl10.getMaxRof(), trkl11.getMaxRof()))) - - o2::gpu::CAMath::Min(trkl00.getMinRof(), o2::gpu::CAMath::Min(trkl01.getMinRof(), o2::gpu::CAMath::Min(trkl10.getMinRof(), trkl11.getMinRof())))) > deltaROF) { - continue; - } + const auto& trkl00 = tracklets[layerIndex][currentCellSeed.getFirstTrackletIndex()]; + const auto& trkl11 = tracklets[layerIndex + 2][currentCellSeed.getSecondTrackletIndex()]; + if (!rofOverlaps.isCompatible(layerIndex, trkl00.rof[0], layerIndex + 2, trkl11.rof[1])) { + continue; } if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) || @@ -405,7 +400,7 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellNeighboursKernel( } } -template +template GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( const Cluster** sortedClusters, const Cluster** unsortedClusters, @@ -414,9 +409,9 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( int** trackletsLUT, const int nTrackletsCurrent, const int layer, - CellSeed* cells, + CellSeed* cells, int** cellsLUTs, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, @@ -437,7 +432,7 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( break; } const Tracklet& nextTracklet = tracklets[layer + 1][iNextTrackletIndex]; - if (deltaROF && currentTracklet.getSpanRof(nextTracklet) > deltaROF) { + if (!rofOverlaps.isCompatible(layer, currentTracklet.rof[0], layer + 1, nextTracklet.rof[1])) { continue; } const float deltaTanLambda{o2::gpu::CAMath::Abs(currentTracklet.tanLambda - nextTracklet.tanLambda)}; @@ -481,7 +476,7 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( continue; } if constexpr (!initRun) { - new (cells + cellsLUTs[layer][iCurrentTrackletIndex] + foundCells) CellSeed{layer, clusId[0], clusId[1], clusId[2], iCurrentTrackletIndex, iNextTrackletIndex, track, chi2}; + new (cells + cellsLUTs[layer][iCurrentTrackletIndex] + foundCells) CellSeed{layer, clusId[0], clusId[1], clusId[2], iCurrentTrackletIndex, iNextTrackletIndex, track, chi2}; } ++foundCells; if constexpr (initRun) { @@ -492,17 +487,16 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( } } -template +template GPUg() void __launch_bounds__(256, 1) computeLayerTrackletsMultiROFKernel( - const IndexTableUtils* utils, + const IndexTableUtils* utils, const uint8_t* multMask, const int layerIndex, - const int startROF, - const int endROF, - const int totalROFs, - const int deltaROF, + const int iSlice, + const typename ROFOverlapTable::View rofOverlaps, + const typename ROFTimeSliceTable::View timeSlices, + const typename ROFVertexLookupTable::View vertexLUT, const Vertex* vertices, - const int* rofPV, const int nVertices, const int vertexId, const Cluster** clusters, // Input data rof0 @@ -524,21 +518,26 @@ GPUg() void __launch_bounds__(256, 1) computeLayerTrackletsMultiROFKernel( const int phiBins{utils->getNphiBins()}; const int zBins{utils->getNzBins()}; const int tableSize{phiBins * zBins + 1}; - for (unsigned int iROF{blockIdx.x}; iROF < endROF - startROF; iROF += gridDim.x) { - const short pivotROF = iROF + startROF; - const short minROF = o2::gpu::CAMath::Max(startROF, static_cast(pivotROF - deltaROF)); - const short maxROF = o2::gpu::CAMath::Min(endROF - 1, static_cast(pivotROF + deltaROF)); - auto primaryVertices = getPrimaryVertices(minROF, maxROF, rofPV, totalROFs, vertices); + const auto& slice = timeSlices.getSlice(layerIndex, iSlice); + for (unsigned int iROF{blockIdx.x}; iROF < slice.getEntries(); iROF += gridDim.x) { + const uint32_t pivotROF = iROF + slice.getFirstEntry(); + const auto& pvs = vertexLUT.getVertices(layerIndex, pivotROF); + auto primaryVertices = gpuSpan(&vertices[pvs.getFirstEntry()], pvs.getEntries()); if (primaryVertices.empty()) { continue; } const auto startVtx{vertexId >= 0 ? vertexId : 0}; const auto endVtx{vertexId >= 0 ? o2::gpu::CAMath::Min(vertexId + 1, static_cast(primaryVertices.size())) : static_cast(primaryVertices.size())}; - if ((endVtx - startVtx) <= 0) { + if (endVtx <= startVtx || (vertexId + 1) > primaryVertices.size()) { + continue; + } + + const auto& rofOverlap = rofOverlaps.getOverlap(layerIndex, layerIndex + 1, pivotROF); + if (!rofOverlap.getEntries()) { continue; } - auto clustersCurrentLayer = getClustersOnLayer(pivotROF, totalROFs, layerIndex, ROFClusters, clusters); + auto clustersCurrentLayer = getClustersOnLayer(pivotROF, layerIndex, ROFClusters, clusters); if (clustersCurrentLayer.empty()) { continue; } @@ -570,7 +569,7 @@ GPUg() void __launch_bounds__(256, 1) computeLayerTrackletsMultiROFKernel( const float zAtRmax{tanLambda * (maxR - currentCluster.radius) + currentCluster.zCoordinate}; const float sqInverseDeltaZ0{1.f / (math_utils::Sq(currentCluster.zCoordinate - primaryVertex.getZ()) + constants::Tolerance)}; /// protecting from overflows adding the detector resolution const float sigmaZ{o2::gpu::CAMath::Sqrt(math_utils::Sq(resolution) * math_utils::Sq(tanLambda) * ((math_utils::Sq(inverseR0) + sqInverseDeltaZ0) * math_utils::Sq(meanDeltaR) + 1.f) + math_utils::Sq(meanDeltaR * MSAngle))}; - const int4 selectedBinsRect{getBinsRect(currentCluster, layerIndex + 1, utils, zAtRmin, zAtRmax, sigmaZ * NSigmaCut, phiCut)}; + const int4 selectedBinsRect{getBinsRect(currentCluster, layerIndex + 1, utils, zAtRmin, zAtRmax, sigmaZ * NSigmaCut, phiCut)}; if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { continue; } @@ -580,8 +579,8 @@ GPUg() void __launch_bounds__(256, 1) computeLayerTrackletsMultiROFKernel( phiBinsNum += phiBins; } - for (short targetROF{minROF}; targetROF <= maxROF; ++targetROF) { - auto clustersNextLayer = getClustersOnLayer(targetROF, totalROFs, layerIndex + 1, ROFClusters, clusters); + for (int32_t targetROF{rofOverlap.getFirstEntry()}; targetROF < rofOverlap.getEntriesBound(); ++targetROF) { + auto clustersNextLayer = getClustersOnLayer(targetROF, layerIndex + 1, ROFClusters, clusters); if (clustersNextLayer.empty()) { continue; } @@ -608,7 +607,7 @@ GPUg() void __launch_bounds__(256, 1) computeLayerTrackletsMultiROFKernel( const float phi{o2::gpu::CAMath::ATan2(currentCluster.yCoordinate - nextCluster.yCoordinate, currentCluster.xCoordinate - nextCluster.xCoordinate)}; const float tanL{(currentCluster.zCoordinate - nextCluster.zCoordinate) / (currentCluster.radius - nextCluster.radius)}; const int nextSortedIndex{ROFClusters[layerIndex + 1][targetROF] + nextClusterIndex}; - new (tracklets[layerIndex] + trackletsLUT[layerIndex][currentSortedIndex] + storedTracklets) Tracklet{currentSortedIndex, nextSortedIndex, tanL, phi, pivotROF, targetROF}; + new (tracklets[layerIndex] + trackletsLUT[layerIndex][currentSortedIndex] + storedTracklets) Tracklet{currentSortedIndex, nextSortedIndex, tanL, phi, (short)pivotROF, (short)targetROF}; } ++storedTracklets; } @@ -630,15 +629,15 @@ GPUg() void __launch_bounds__(256, 1) compileTrackletsLookupTableKernel( } } -template +template GPUg() void __launch_bounds__(256, 1) processNeighboursKernel( const int layer, const int level, - CellSeed** allCellSeeds, - CellSeed* currentCellSeeds, + CellSeed** allCellSeeds, + CellSeed* currentCellSeeds, const int* currentCellIds, const unsigned int nCurrentCells, - CellSeed* updatedCellSeeds, + CellSeed* updatedCellSeeds, int* updatedCellsIds, int* foundSeedsTable, // auxiliary only in GPU code to compute the number of cells per iteration const unsigned char** usedClusters, // Used clusters @@ -722,17 +721,16 @@ GPUg() void __launch_bounds__(256, 1) processNeighboursKernel( } // namespace gpu -template -void countTrackletsInROFsHandler(const IndexTableUtils* utils, +template +void countTrackletsInROFsHandler(const IndexTableUtils* utils, const uint8_t* multMask, const int layer, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + const int iSlice, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFTimeSliceTable::View& timeSlices, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, - const int* rofPV, const int nVertices, const Cluster** clusters, std::vector nClusters, @@ -745,8 +743,8 @@ void countTrackletsInROFsHandler(const IndexTableUtils* utils, const float NSigmaCut, bounded_vector& phiCuts, const float resolutionPV, - std::array& minRs, - std::array& maxRs, + std::array& minRs, + std::array& maxRs, bounded_vector& resolutions, std::vector& radii, bounded_vector& mulScatAng, @@ -759,12 +757,11 @@ void countTrackletsInROFsHandler(const IndexTableUtils* utils, utils, multMask, layer, - startROF, - endROF, - maxROF, - deltaROF, + iSlice, + rofOverlaps, + timeSlices, + vertexLUT, vertices, - rofPV, nVertices, vertexId, clusters, @@ -786,17 +783,16 @@ void countTrackletsInROFsHandler(const IndexTableUtils* utils, thrust::exclusive_scan(nosync_policy, trackletsLUTsHost[layer], trackletsLUTsHost[layer] + nClusters[layer] + 1, trackletsLUTsHost[layer]); } -template -void computeTrackletsInROFsHandler(const IndexTableUtils* utils, +template +void computeTrackletsInROFsHandler(const IndexTableUtils* utils, const uint8_t* multMask, const int layer, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + const int iSlice, + const typename ROFOverlapTable::View& rofOverlaps, + const typename ROFTimeSliceTable::View& timeSlices, + const typename ROFVertexLookupTable::View& vertexLUT, const int vertexId, const Vertex* vertices, - const int* rofPV, const int nVertices, const Cluster** clusters, std::vector nClusters, @@ -812,8 +808,8 @@ void computeTrackletsInROFsHandler(const IndexTableUtils* utils, const float NSigmaCut, bounded_vector& phiCuts, const float resolutionPV, - std::array& minRs, - std::array& maxRs, + std::array& minRs, + std::array& maxRs, bounded_vector& resolutions, std::vector& radii, bounded_vector& mulScatAng, @@ -826,12 +822,11 @@ void computeTrackletsInROFsHandler(const IndexTableUtils* utils, utils, multMask, layer, - startROF, - endROF, - maxROF, - deltaROF, + iSlice, + rofOverlaps, + timeSlices, + vertexLUT, vertices, - rofPV, nVertices, vertexId, clusters, @@ -864,7 +859,7 @@ void computeTrackletsInROFsHandler(const IndexTableUtils* utils, } } -template +template void countCellsHandler( const Cluster** sortedClusters, const Cluster** unsortedClusters, @@ -873,10 +868,10 @@ void countCellsHandler( int** trackletsLUT, const int nTracklets, const int layer, - CellSeed* cells, + CellSeed* cells, int** cellsLUTsArrayDevice, int* cellsLUTsHost, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, @@ -896,7 +891,7 @@ void countCellsHandler( layer, // const int cells, // CellSeed* cellsLUTsArrayDevice, // int** - deltaROF, // const int + rofOverlaps, // ROFOverlapTable::View bz, // const float maxChi2ClusterAttachment, // const float cellDeltaTanLambdaSigma, // const float @@ -905,7 +900,7 @@ void countCellsHandler( thrust::exclusive_scan(nosync_policy, cellsLUTsHost, cellsLUTsHost + nTracklets + 1, cellsLUTsHost); } -template +template void computeCellsHandler( const Cluster** sortedClusters, const Cluster** unsortedClusters, @@ -914,10 +909,10 @@ void computeCellsHandler( int** trackletsLUT, const int nTracklets, const int layer, - CellSeed* cells, + CellSeed* cells, int** cellsLUTsArrayDevice, int* cellsLUTsHost, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, @@ -936,21 +931,21 @@ void computeCellsHandler( layer, // const int cells, // CellSeed* cellsLUTsArrayDevice, // int** - deltaROF, // const int + rofOverlaps, // ROFOverlapTable::View bz, // const float maxChi2ClusterAttachment, // const float cellDeltaTanLambdaSigma, // const float nSigmaCut); // const float } -template -void countCellNeighboursHandler(CellSeed** cellsLayersDevice, +template +void countCellNeighboursHandler(CellSeed** cellsLayersDevice, int* neighboursLUT, int** cellsLUTs, gpuPair* cellNeighbours, int* neighboursIndexTable, const Tracklet** tracklets, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float maxChi2ClusterAttachment, const float bz, const int layerIndex, @@ -969,7 +964,7 @@ void countCellNeighboursHandler(CellSeed** cellsLayersDevice, cellsLUTs, cellNeighbours, tracklets, - deltaROF, + rofOverlaps, maxChi2ClusterAttachment, bz, layerIndex, @@ -980,14 +975,14 @@ void countCellNeighboursHandler(CellSeed** cellsLayersDevice, thrust::exclusive_scan(nosync_policy, neighboursIndexTable, neighboursIndexTable + nCells + 1, neighboursIndexTable); } -template -void computeCellNeighboursHandler(CellSeed** cellsLayersDevice, +template +void computeCellNeighboursHandler(CellSeed** cellsLayersDevice, int* neighboursLUT, int** cellsLUTs, gpuPair* cellNeighbours, int* neighboursIndexTable, const Tracklet** tracklets, - const int deltaROF, + const typename ROFOverlapTable::View rofOverlaps, const float maxChi2ClusterAttachment, const float bz, const int layerIndex, @@ -1005,7 +1000,7 @@ void computeCellNeighboursHandler(CellSeed** cellsLayersDevice, cellsLUTs, cellNeighbours, tracklets, - deltaROF, + rofOverlaps, maxChi2ClusterAttachment, bz, layerIndex, @@ -1029,17 +1024,17 @@ int filterCellNeighboursHandler(gpuPair* cellNeighbourPairs, return newSize; } -template +template void processNeighboursHandler(const int startLayer, const int startLevel, - CellSeed** allCellSeeds, - CellSeed* currentCellSeeds, - std::array& nCells, + CellSeed** allCellSeeds, + CellSeed* currentCellSeeds, + std::array& nCells, const unsigned char** usedClusters, - std::array& neighbours, + std::array& neighbours, gsl::span neighboursDeviceLUTs, const TrackingFrameInfo** foundTrackingFrameInfo, - bounded_vector>& seedsHost, + bounded_vector>& seedsHost, const float bz, const float maxChi2ClusterAttachment, const float maxChi2NDF, @@ -1050,11 +1045,11 @@ void processNeighboursHandler(const int startLayer, const int nThreads) { auto allocInt = gpu::TypedAllocator(alloc); - auto allocCellSeed = gpu::TypedAllocator>(alloc); + auto allocCellSeed = gpu::TypedAllocator>(alloc); thrust::device_vector> foundSeedsTable(nCells[startLayer] + 1, 0, allocInt); auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(gpu::Stream::DefaultStream); - gpu::processNeighboursKernel<<>>( + gpu::processNeighboursKernel<<>>( startLayer, startLevel, allCellSeeds, @@ -1075,8 +1070,8 @@ void processNeighboursHandler(const int startLayer, thrust::exclusive_scan(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); thrust::device_vector> updatedCellId(foundSeedsTable.back(), 0, allocInt); - thrust::device_vector, gpu::TypedAllocator>> updatedCellSeed(foundSeedsTable.back(), allocCellSeed); - gpu::processNeighboursKernel<<>>( + thrust::device_vector, gpu::TypedAllocator>> updatedCellSeed(foundSeedsTable.back(), allocCellSeed); + gpu::processNeighboursKernel<<>>( startLayer, startLevel, allCellSeeds, @@ -1098,17 +1093,17 @@ void processNeighboursHandler(const int startLayer, int level = startLevel; thrust::device_vector> lastCellId(allocInt); - thrust::device_vector, gpu::TypedAllocator>> lastCellSeed(allocCellSeed); + thrust::device_vector, gpu::TypedAllocator>> lastCellSeed(allocCellSeed); for (int iLayer{startLayer - 1}; iLayer > 0 && level > 2; --iLayer) { lastCellSeed.swap(updatedCellSeed); lastCellId.swap(updatedCellId); - thrust::device_vector, gpu::TypedAllocator>>(allocCellSeed).swap(updatedCellSeed); + thrust::device_vector, gpu::TypedAllocator>>(allocCellSeed).swap(updatedCellSeed); thrust::device_vector>(allocInt).swap(updatedCellId); auto lastCellSeedSize{lastCellSeed.size()}; foundSeedsTable.resize(lastCellSeedSize + 1); thrust::fill(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), 0); - gpu::processNeighboursKernel<<>>( + gpu::processNeighboursKernel<<>>( iLayer, --level, allCellSeeds, @@ -1132,9 +1127,9 @@ void processNeighboursHandler(const int startLayer, updatedCellId.resize(foundSeeds); thrust::fill(nosync_policy, updatedCellId.begin(), updatedCellId.end(), 0); updatedCellSeed.resize(foundSeeds); - thrust::fill(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), CellSeed()); + thrust::fill(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), CellSeed()); - gpu::processNeighboursKernel<<>>( + gpu::processNeighboursKernel<<>>( iLayer, level, allCellSeeds, @@ -1154,15 +1149,15 @@ void processNeighboursHandler(const int startLayer, matCorrType); } GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream)); - thrust::device_vector, gpu::TypedAllocator>> outSeeds(updatedCellSeed.size(), allocCellSeed); - auto end = thrust::copy_if(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5))); + thrust::device_vector, gpu::TypedAllocator>> outSeeds(updatedCellSeed.size(), allocCellSeed); + auto end = thrust::copy_if(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5))); auto s{end - outSeeds.begin()}; seedsHost.reserve(seedsHost.size() + s); thrust::copy(outSeeds.begin(), outSeeds.begin() + s, std::back_inserter(seedsHost)); } -template -void trackSeedHandler(CellSeed* trackSeeds, +template +void trackSeedHandler(CellSeed* trackSeeds, const TrackingFrameInfo** foundTrackingFrameInfo, const Cluster** unsortedClusters, o2::its::TrackITSExt* tracks, @@ -1206,13 +1201,12 @@ void trackSeedHandler(CellSeed* trackSeeds, template void countTrackletsInROFsHandler<7>(const IndexTableUtils<7>* utils, const uint8_t* multMask, const int layer, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + const int iSlice, + const ROFOverlapTable<7>::View& rofOverlaps, + const ROFTimeSliceTable<7>::View& timeSlices, + const ROFVertexLookupTable<7>::View& vertexLUT, const int vertexId, const Vertex* vertices, - const int* rofPV, const int nVertices, const Cluster** clusters, std::vector nClusters, @@ -1238,13 +1232,12 @@ template void countTrackletsInROFsHandler<7>(const IndexTableUtils<7>* utils, template void computeTrackletsInROFsHandler<7>(const IndexTableUtils<7>* utils, const uint8_t* multMask, const int layer, - const int startROF, - const int endROF, - const int maxROF, - const int deltaROF, + const int iSlice, + const ROFOverlapTable<7>::View& rofOverlaps, + const ROFTimeSliceTable<7>::View& timeSlices, + const ROFVertexLookupTable<7>::View& vertexLUT, const int vertexId, const Vertex* vertices, - const int* rofPV, const int nVertices, const Cluster** clusters, std::vector nClusters, @@ -1280,7 +1273,7 @@ template void countCellsHandler<7>(const Cluster** sortedClusters, CellSeed<7>* cells, int** cellsLUTsArrayDevice, int* cellsLUTsHost, - const int deltaROF, + const typename ROFOverlapTable<7>::View rofOverlaps, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, @@ -1300,7 +1293,7 @@ template void computeCellsHandler<7>(const Cluster** sortedClusters, CellSeed<7>* cells, int** cellsLUTsArrayDevice, int* cellsLUTsHost, - const int deltaROF, + const typename ROFOverlapTable<7>::View rofOverlaps, const float bz, const float maxChi2ClusterAttachment, const float cellDeltaTanLambdaSigma, @@ -1315,7 +1308,7 @@ template void countCellNeighboursHandler<7>(CellSeed<7>** cellsLayersDevice, gpuPair* cellNeighbours, int* neighboursIndexTable, const Tracklet** tracklets, - const int deltaROF, + const typename ROFOverlapTable<7>::View rofOverlaps, const float maxChi2ClusterAttachment, const float bz, const int layerIndex, @@ -1333,7 +1326,7 @@ template void computeCellNeighboursHandler(CellSeed<7>** cellsLayersDevice, gpuPair* cellNeighbours, int* neighboursIndexTable, const Tracklet** tracklets, - const int deltaROF, + const typename ROFOverlapTable<7>::View rofOverlaps, const float maxChi2ClusterAttachment, const float bz, const int layerIndex, diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cxx deleted file mode 100644 index 658d3cf0dfb91..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cxx +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \author matteo.concas@cern.ch - -#include - -#include "ITStracking/TrackingConfigParam.h" -#include "ITStrackingGPU/VertexingKernels.h" -#include "ITStrackingGPU/VertexerTraitsGPU.h" - -namespace o2::its -{ - -template -void VertexerTraitsGPU::initialise(const TrackingParameters& trackingParams, const int iteration) -{ - // FIXME - // Two things to fix here: - // This loads all necessary data for this step at once, can be overlayed with computation - // Also if running with the tracker some data is loaded twice! - mTimeFrameGPU->initialise(0, trackingParams, 3, &this->mIndexTableUtils, &mTfGPUParams); - - // FIXME some of these only need to be created once! - mTimeFrameGPU->loadIndexTableUtils(iteration); - mTimeFrameGPU->createUsedClustersDeviceArray(iteration, 3); - mTimeFrameGPU->createClustersDeviceArray(iteration, 3); - mTimeFrameGPU->createUnsortedClustersDeviceArray(iteration, 3); - mTimeFrameGPU->createClustersIndexTablesArray(iteration); - mTimeFrameGPU->createROFrameClustersDeviceArray(iteration); - for (int iLayer{0}; iLayer < 3; ++iLayer) { - mTimeFrameGPU->loadClustersDevice(iteration, iLayer); - mTimeFrameGPU->loadUnsortedClustersDevice(iteration, iLayer); - mTimeFrameGPU->loadClustersIndexTables(iteration, iLayer); - mTimeFrameGPU->createUsedClustersDevice(iteration, iLayer); - mTimeFrameGPU->loadROFrameClustersDevice(iteration, iLayer); - } -} - -template -void VertexerTraitsGPU::adoptTimeFrame(TimeFrame* tf) noexcept -{ - mTimeFrameGPU = static_cast*>(tf); - this->mTimeFrame = static_cast*>(tf); -} - -template -void VertexerTraitsGPU::updateVertexingParameters(const std::vector& vrtPar, const TimeFrameGPUParameters& tfPar) -{ - this->mVrtParams = vrtPar; - mTfGPUParams = tfPar; - this->mIndexTableUtils.setTrackingParameters(vrtPar[0]); - for (auto& par : this->mVrtParams) { - par.phiSpan = static_cast(std::ceil(this->mIndexTableUtils.getNphiBins() * par.phiCut / o2::constants::math::TwoPI)); - par.zSpan = static_cast(std::ceil(par.zCut * this->mIndexTableUtils.getInverseZCoordinate(0))); - } -} - -template -void VertexerTraitsGPU::computeTracklets(const int iteration) -{ - if (mTimeFrameGPU->getClusters().empty()) { - return; - } - const auto& conf = ITSGpuTrackingParamConfig::Instance(); - - mTimeFrameGPU->createVtxTrackletsLUTDevice(iteration); - countTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), - mTimeFrameGPU->getDeviceMultCutMask(), - mTimeFrameGPU->getNrof(), - this->mVrtParams[iteration].deltaRof, - mTimeFrameGPU->getDeviceROFramesPV(), - this->mVrtParams[iteration].vertPerRofThreshold, - mTimeFrameGPU->getDeviceArrayClusters(), - mTimeFrameGPU->getClusterSizes()[1], - mTimeFrameGPU->getDeviceROFrameClusters(), - (const uint8_t**)mTimeFrameGPU->getDeviceArrayUsedClusters(), - mTimeFrameGPU->getDeviceArrayClustersIndexTables(), - mTimeFrameGPU->getDeviceArrayNTrackletsPerCluster(), - mTimeFrameGPU->getDeviceArrayNTrackletsPerClusterSum(), - mTimeFrameGPU->getDeviceArrayNTrackletsPerROF(), - mTimeFrameGPU->getDeviceNTrackletsPerCluster(), - mTimeFrameGPU->getDeviceNTrackletsPerClusterSum(), - iteration, - this->mVrtParams[iteration].phiCut, - this->mVrtParams[iteration].maxTrackletsPerCluster, - conf.nBlocksVtxComputeTracklets[iteration], - conf.nThreadsVtxComputeTracklets[iteration], - mTimeFrameGPU->getStreams()); - mTimeFrameGPU->createVtxTrackletsBuffers(iteration); - computeTrackletsInROFsHandler(mTimeFrameGPU->getDeviceIndexTableUtils(), - mTimeFrameGPU->getDeviceMultCutMask(), - mTimeFrameGPU->getNrof(), - this->mVrtParams[iteration].deltaRof, - mTimeFrameGPU->getDeviceROFramesPV(), - this->mVrtParams[iteration].vertPerRofThreshold, - mTimeFrameGPU->getDeviceArrayClusters(), - mTimeFrameGPU->getClusterSizes()[1], - mTimeFrameGPU->getDeviceROFrameClusters(), - (const uint8_t**)mTimeFrameGPU->getDeviceArrayUsedClusters(), - mTimeFrameGPU->getDeviceArrayClustersIndexTables(), - mTimeFrameGPU->getDeviceArrayTracklets(), - (const int32_t**)mTimeFrameGPU->getDeviceArrayNTrackletsPerCluster(), - (const int32_t**)mTimeFrameGPU->getDeviceArrayNTrackletsPerClusterSum(), - (const int32_t**)mTimeFrameGPU->getDeviceArrayNTrackletsPerROF(), - iteration, - this->mVrtParams[iteration].phiCut, - this->mVrtParams[iteration].maxTrackletsPerCluster, - conf.nBlocksVtxComputeTracklets[iteration], - conf.nThreadsVtxComputeTracklets[iteration], - mTimeFrameGPU->getStreams()); -} - -template -void VertexerTraitsGPU::computeTrackletMatching(const int iteration) -{ - if (!mTimeFrameGPU->getTotalTrackletsTF(0) || !mTimeFrameGPU->getTotalTrackletsTF(1)) { - return; - } - - const auto& conf = ITSGpuTrackingParamConfig::Instance(); - mTimeFrameGPU->createVtxLinesLUTDevice(iteration); - countTrackletsMatchingInROFsHandler(mTimeFrameGPU->getNrof(), - this->mVrtParams[iteration].deltaRof, - mTimeFrameGPU->getClusterSizes()[1], - mTimeFrameGPU->getDeviceROFrameClusters(), - mTimeFrameGPU->getDeviceArrayClusters(), - mTimeFrameGPU->getDeviceArrayUsedClusters(), - (const Tracklet**)mTimeFrameGPU->getDeviceArrayTracklets(), - mTimeFrameGPU->getDeviceUsedTracklets(), - (const int32_t**)mTimeFrameGPU->getDeviceArrayNTrackletsPerCluster(), - (const int32_t**)mTimeFrameGPU->getDeviceArrayNTrackletsPerClusterSum(), - mTimeFrameGPU->getDeviceNLinesPerCluster(), - mTimeFrameGPU->getDeviceNLinesPerClusterSum(), - iteration, - this->mVrtParams[iteration].phiCut, - this->mVrtParams[iteration].tanLambdaCut, - conf.nBlocksVtxComputeMatching[iteration], - conf.nThreadsVtxComputeMatching[iteration], - mTimeFrameGPU->getStreams()); - mTimeFrameGPU->createVtxLinesBuffer(iteration); - computeTrackletsMatchingInROFsHandler(mTimeFrameGPU->getNrof(), - this->mVrtParams[iteration].deltaRof, - mTimeFrameGPU->getClusterSizes()[1], - mTimeFrameGPU->getDeviceROFrameClusters(), - mTimeFrameGPU->getDeviceArrayClusters(), - nullptr, - (const Tracklet**)mTimeFrameGPU->getDeviceArrayTracklets(), - mTimeFrameGPU->getDeviceUsedTracklets(), - (const int32_t**)mTimeFrameGPU->getDeviceArrayNTrackletsPerCluster(), - (const int32_t**)mTimeFrameGPU->getDeviceArrayNTrackletsPerClusterSum(), - (const int32_t*)mTimeFrameGPU->getDeviceNLinesPerClusterSum(), - mTimeFrameGPU->getDeviceLines(), - iteration, - this->mVrtParams[iteration].phiCut, - this->mVrtParams[iteration].tanLambdaCut, - conf.nBlocksVtxComputeMatching[iteration], - conf.nThreadsVtxComputeMatching[iteration], - mTimeFrameGPU->getStreams()); -} - -template -void VertexerTraitsGPU::computeVertices(const int iteration) -{ - LOGP(fatal, "This step is not implemented yet!"); - mTimeFrameGPU->loadUsedClustersDevice(); -} - -template class VertexerTraitsGPU<7>; - -} // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexingKernels.cu deleted file mode 100644 index a2787bb13598d..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexingKernels.cu +++ /dev/null @@ -1,660 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// - -#include -#include - -#include "ITStrackingGPU/VertexingKernels.h" -#include "ITStracking/Tracklet.h" -#include "ITStracking/IndexTableUtils.h" -#include "ITStracking/ClusterLines.h" - -#include "GPUCommonMath.h" -#include "GPUCommonHelpers.h" -#include "GPUCommonDef.h" - -namespace o2::its -{ - -namespace gpu -{ - -template -GPUg() void computeLayerTrackletMutliROFKernel(const Cluster** GPUrestrict() clusters, - const int32_t** GPUrestrict() rofClusters, - const uint8_t** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() clusterIndexTables, - const float phiCut, - maybe_const** GPUrestrict() tracklets, - maybe_const** GPUrestrict() trackletOffsets, - const IndexTableUtils* GPUrestrict() utils, - const int32_t nRofs, - const int32_t deltaRof, - const int32_t* GPUrestrict() rofPV, - const int32_t iteration, - const int32_t verPerRofThreshold, - const int32_t maxTrackletsPerCluster) -{ - constexpr int32_t iMode = (Mode == TrackletMode::Layer0Layer1) ? 0 : 1; - const int32_t phiBins(utils->getNphiBins()); - const int32_t zBins(utils->getNzBins()); - const int32_t tableSize{phiBins * zBins + 1}; - extern __shared__ uint16_t storedTrackletsShared[]; // each deltaROF needs its own counters - uint16_t* storedTrackletsLocal = storedTrackletsShared + threadIdx.x * (2 * deltaRof + 1); - for (uint32_t pivotRofId{blockIdx.x}; pivotRofId < (uint32_t)nRofs; pivotRofId += gridDim.x) { - if (iteration && rofPV[pivotRofId] > verPerRofThreshold) { - continue; - } - const uint16_t startROF = o2::gpu::CAMath::Max(0, (int)pivotRofId - deltaRof); - const uint16_t endROF = o2::gpu::CAMath::Min(nRofs, (int)pivotRofId + deltaRof + 1); - const auto clustersCurrentLayer = getClustersOnLayer((int32_t)pivotRofId, nRofs, 1, rofClusters, clusters); - if (clustersCurrentLayer.empty()) { - continue; - } - auto trackletsPerCluster = getNTrackletsPerCluster(pivotRofId, nRofs, iMode, rofClusters, trackletOffsets); - for (uint32_t iCurrentLayerClusterIndex{threadIdx.x}; iCurrentLayerClusterIndex < (uint32_t)clustersCurrentLayer.size(); iCurrentLayerClusterIndex += blockDim.x) { - for (int16_t i{0}; i < (int16_t)((2 * deltaRof) + 1); ++i) { - storedTrackletsLocal[i] = 0; - } - const Cluster& GPUrestrict() currentCluster { clustersCurrentLayer[iCurrentLayerClusterIndex] }; - const int4 selectedBinsRect{getBinsRect(currentCluster, (int)Mode, utils, 0.f, 0.f, 50.f, phiCut / 2)}; - if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { - int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; - if (phiBinsNum < 0) { - phiBinsNum += phiBins; - } - for (int32_t iPhiBin{selectedBinsRect.y}, iPhiCount{0}; iPhiCount < phiBinsNum; iPhiBin = ++iPhiBin == phiBins ? 0 : iPhiBin, iPhiCount++) { - for (uint16_t targetRofId{startROF}; targetRofId < endROF; ++targetRofId) { - uint16_t& storedTracklets = storedTrackletsLocal[pivotRofId - targetRofId + deltaRof]; - const int32_t firstBinIndex{utils->getBinIndex(selectedBinsRect.x, iPhiBin)}; - const int32_t maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1}; - const int32_t firstRowClusterIndex{clusterIndexTables[(int)Mode][(targetRofId)*tableSize + firstBinIndex]}; - const int32_t maxRowClusterIndex{clusterIndexTables[(int)Mode][(targetRofId)*tableSize + maxBinIndex]}; - auto clustersNextLayer = getClustersOnLayer((int32_t)targetRofId, nRofs, (int32_t)Mode, rofClusters, clusters); - if (clustersNextLayer.empty()) { - continue; - } - for (int32_t iNextLayerClusterIndex{firstRowClusterIndex}; iNextLayerClusterIndex < maxRowClusterIndex && iNextLayerClusterIndex < (int32_t)clustersNextLayer.size(); ++iNextLayerClusterIndex) { - if (iteration && usedClusters[(int32_t)Mode][iNextLayerClusterIndex]) { - continue; - } - const Cluster& GPUrestrict() nextCluster { clustersNextLayer[iNextLayerClusterIndex] }; - if (o2::gpu::GPUCommonMath::Abs(math_utils::smallestAngleDifference(currentCluster.phi, nextCluster.phi)) < phiCut) { - if (storedTracklets < maxTrackletsPerCluster) { - if constexpr (!dryRun) { - if constexpr (Mode == TrackletMode::Layer0Layer1) { - tracklets[0][trackletsPerCluster[iCurrentLayerClusterIndex] + storedTracklets] = Tracklet{iNextLayerClusterIndex, (int)iCurrentLayerClusterIndex, nextCluster, currentCluster, (short)targetRofId, (short)pivotRofId}; - } else { - tracklets[1][trackletsPerCluster[iCurrentLayerClusterIndex] + storedTracklets] = Tracklet{(int)iCurrentLayerClusterIndex, iNextLayerClusterIndex, currentCluster, nextCluster, (short)pivotRofId, (short)targetRofId}; - } - } - ++storedTracklets; - } - } - } - } - } - } - if constexpr (dryRun) { - for (int32_t i{0}; i < (int32_t)((2 * deltaRof) + 1); ++i) { - trackletsPerCluster[iCurrentLayerClusterIndex] += storedTrackletsLocal[i]; - } - } - } - } -} - -template -GPUg() void computeTrackletSelectionMutliROFKernel(const Cluster** GPUrestrict() clusters, - maybe_const** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() rofClusters, - const float phiCut, - const float tanLambdaCut, - const Tracklet** GPUrestrict() tracklets, - uint8_t* GPUrestrict() usedTracklets, - const int32_t** GPUrestrict() trackletOffsets, - const int32_t** GPUrestrict() trackletLUTs, - maybe_const* lineOffsets, - maybe_const* GPUrestrict() lines, - const int32_t nRofs, - const int32_t deltaRof, - const int32_t maxTracklets) -{ - for (uint32_t pivotRofId{blockIdx.x}; pivotRofId < nRofs; pivotRofId += gridDim.x) { - const int16_t startROF = o2::gpu::CAMath::Max(0, (int32_t)pivotRofId - deltaRof); - const int16_t endROF = o2::gpu::CAMath::Min(nRofs, (int32_t)pivotRofId + deltaRof + 1); - - const uint32_t clusterOffset = rofClusters[1][pivotRofId]; - const uint32_t nClustersCurrentLayer = rofClusters[1][pivotRofId + 1] - clusterOffset; - if (nClustersCurrentLayer <= 0) { - continue; - } - - auto linesPerCluster = getNLinesPerCluster(pivotRofId, nRofs, rofClusters, lineOffsets); - auto nTrackletsPerCluster01 = getNTrackletsPerCluster(pivotRofId, nRofs, 0, rofClusters, trackletOffsets); - auto nTrackletsPerCluster12 = getNTrackletsPerCluster(pivotRofId, nRofs, 1, rofClusters, trackletOffsets); - - for (uint32_t iCurrentLayerClusterIndex{threadIdx.x}; iCurrentLayerClusterIndex < nClustersCurrentLayer; iCurrentLayerClusterIndex += blockDim.x) { - int32_t validTracklets{0}; - const int32_t nTracklets01 = nTrackletsPerCluster01[iCurrentLayerClusterIndex]; - const int32_t nTracklets12 = nTrackletsPerCluster12[iCurrentLayerClusterIndex]; - for (int32_t iTracklet12{0}; iTracklet12 < nTracklets12; ++iTracklet12) { - for (int32_t iTracklet01{0}; iTracklet01 < nTracklets01; ++iTracklet01) { - - if (usedTracklets[trackletLUTs[0][clusterOffset + iCurrentLayerClusterIndex] + iTracklet01]) { - continue; - } - - const auto& GPUrestrict() tracklet01 { tracklets[0][trackletLUTs[0][clusterOffset + iCurrentLayerClusterIndex] + iTracklet01] }; - const auto& GPUrestrict() tracklet12 { tracklets[1][trackletLUTs[1][clusterOffset + iCurrentLayerClusterIndex] + iTracklet12] }; - const int16_t rof0 = tracklet01.rof[0]; - const int16_t rof2 = tracklet12.rof[1]; - if (deltaRof > 0 && ((rof0 < startROF) || (rof0 >= endROF) || (rof2 < startROF) || (rof2 >= endROF) || (o2::gpu::CAMath::Abs(rof0 - rof2) > deltaRof))) { - continue; - } - - const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(tracklet01.tanLambda - tracklet12.tanLambda)}; - const float deltaPhi{o2::gpu::GPUCommonMath::Abs(math_utils::smallestAngleDifference(tracklet01.phi, tracklet12.phi))}; - // - if (deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets < maxTracklets) { - // TODO use atomics to avoid race conditions for torn writes but is it needed here? - usedTracklets[trackletLUTs[0][clusterOffset + iCurrentLayerClusterIndex] + iTracklet01] = 1; - if constexpr (dryRun) { - usedClusters[0][rofClusters[0][rof0] + tracklet01.firstClusterIndex] = 1; - usedClusters[2][rofClusters[2][rof2] + tracklet12.secondClusterIndex] = 1; - } else { - const Cluster* clusters0 = clusters[0] + rofClusters[0][tracklet01.rof[0]]; - const Cluster* clusters1 = clusters[1] + rofClusters[1][tracklet01.rof[1]]; - lines[lineOffsets[iCurrentLayerClusterIndex] + validTracklets] = Line(tracklet01, clusters0, clusters1); - } - ++validTracklets; - } - } - } - - if constexpr (dryRun) { - linesPerCluster[iCurrentLayerClusterIndex] = validTracklets; - } - } - } -} - -template -GPUg() void compileTrackletsPerROFKernel(const int32_t nRofs, - int** GPUrestrict() nTrackletsPerROF, - const int32_t** GPUrestrict() rofClusters, - const int32_t** GPUrestrict() nTrackletsPerCluster) -{ - // TODO is this the best reduction kernel? - constexpr int32_t iMode = (Mode == TrackletMode::Layer0Layer1) ? 0 : 1; - extern __shared__ int32_t ssum[]; - for (uint32_t rof = blockIdx.x; rof < (uint32_t)nRofs; rof += gridDim.x) { - const auto& GPUrestrict() currentNTracklets = getNTrackletsPerCluster(rof, nRofs, iMode, rofClusters, nTrackletsPerCluster); - int32_t localSum = 0; - for (uint32_t ci = threadIdx.x; ci < (uint32_t)currentNTracklets.size(); ci += blockDim.x) { - localSum += currentNTracklets[ci]; - } - ssum[threadIdx.x] = localSum; - __syncthreads(); - for (uint32_t stride = blockDim.x / 2; stride > 0; stride >>= 1) { - if (threadIdx.x < stride) { - ssum[threadIdx.x] += ssum[threadIdx.x + stride]; - } - __syncthreads(); - } - if (threadIdx.x == 0) { - nTrackletsPerROF[iMode][rof] = ssum[0]; - } - } -} - -template -GPUhi() void cubExclusiveScan(const T* GPUrestrict() in, T* GPUrestrict() out, int32_t num_items, cudaStream_t stream) -{ - void* d_temp_storage = nullptr; - size_t temp_storage_bytes = 0; - GPUChkErrS(cub::DeviceScan::InclusiveSum(d_temp_storage, temp_storage_bytes, in, out + 1, num_items, stream)); - GPUChkErrS(cudaMallocAsync(&d_temp_storage, temp_storage_bytes, stream)); - GPUChkErrS(cub::DeviceScan::InclusiveSum(d_temp_storage, temp_storage_bytes, in, out + 1, num_items, stream)); - GPUChkErrS(cudaFreeAsync(d_temp_storage, stream)); -} - -} // namespace gpu - -template -void countTrackletsInROFsHandler(const IndexTableUtils* GPUrestrict() utils, - const uint8_t* GPUrestrict() multMask, - const int32_t nRofs, - const int32_t deltaROF, - const int32_t* GPUrestrict() rofPV, - const int32_t vertPerRofThreshold, - const Cluster** GPUrestrict() clusters, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const uint8_t** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() clustersIndexTables, - int32_t** GPUrestrict() trackletsPerClusterLUTs, - int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - int32_t** GPUrestrict() trackletsPerROF, - const std::array& trackletsPerClusterLUTsHost, - const std::array& trackletsPerClusterSumLUTsHost, - const int32_t iteration, - const float phiCut, - const int32_t maxTrackletsPerCluster, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams) -{ - const uint32_t sharedBytes = nThreads * (2 * deltaROF + 1) * sizeof(uint16_t); - gpu::computeLayerTrackletMutliROFKernel<<>>(clusters, - ROFClusters, - usedClusters, - clustersIndexTables, - phiCut, - nullptr, - trackletsPerClusterLUTs, - utils, - nRofs, - deltaROF, - rofPV, - iteration, - vertPerRofThreshold, - maxTrackletsPerCluster); - gpu::compileTrackletsPerROFKernel<<>>(nRofs, trackletsPerROF, ROFClusters, (const int32_t**)trackletsPerClusterLUTs); - gpu::cubExclusiveScan(trackletsPerClusterLUTsHost[0], trackletsPerClusterSumLUTsHost[0], nClusters, streams[0].get()); - - gpu::computeLayerTrackletMutliROFKernel<<>>(clusters, - ROFClusters, - usedClusters, - clustersIndexTables, - phiCut, - nullptr, - trackletsPerClusterLUTs, - utils, - nRofs, - deltaROF, - rofPV, - iteration, - vertPerRofThreshold, - maxTrackletsPerCluster); - gpu::compileTrackletsPerROFKernel<<>>(nRofs, trackletsPerROF, ROFClusters, (const int**)trackletsPerClusterLUTs); - gpu::cubExclusiveScan(trackletsPerClusterLUTsHost[1], trackletsPerClusterSumLUTsHost[1], nClusters, streams[1].get()); -} - -template -void computeTrackletsInROFsHandler(const IndexTableUtils* GPUrestrict() utils, - const uint8_t* GPUrestrict() multMask, - const int32_t nRofs, - const int32_t deltaROF, - const int32_t* GPUrestrict() rofPV, - const int vertPerRofThreshold, - const Cluster** GPUrestrict() clusters, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const uint8_t** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() clustersIndexTables, - Tracklet** GPUrestrict() foundTracklets, - const int32_t** GPUrestrict() trackletsPerClusterLUTs, - const int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - const int32_t** GPUrestrict() trackletsPerROF, - const int32_t iteration, - const float phiCut, - const int32_t maxTrackletsPerCluster, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams) -{ - const uint32_t sharedBytes = nThreads * (2 * deltaROF + 1) * sizeof(uint16_t); - gpu::computeLayerTrackletMutliROFKernel<<>>(clusters, - ROFClusters, - usedClusters, - clustersIndexTables, - phiCut, - foundTracklets, - trackletsPerClusterSumLUTs, - utils, - nRofs, - deltaROF, - rofPV, - iteration, - vertPerRofThreshold, - maxTrackletsPerCluster); - gpu::computeLayerTrackletMutliROFKernel<<>>(clusters, - ROFClusters, - usedClusters, - clustersIndexTables, - phiCut, - foundTracklets, - trackletsPerClusterSumLUTs, - utils, - nRofs, - deltaROF, - rofPV, - iteration, - vertPerRofThreshold, - maxTrackletsPerCluster); -} - -void countTrackletsMatchingInROFsHandler(const int32_t nRofs, - const int32_t deltaROF, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const Cluster** GPUrestrict() clusters, - uint8_t** GPUrestrict() usedClusters, - const Tracklet** GPUrestrict() foundTracklets, - uint8_t* GPUrestrict() usedTracklets, - const int32_t** GPUrestrict() trackletsPerClusterLUTs, - const int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - int32_t* GPUrestrict() linesPerClusterLUT, - int32_t* GPUrestrict() linesPerClusterSumLUT, - const int32_t iteration, - const float phiCut, - const float tanLambdaCut, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams) -{ - streams[1].sync(); // need to make sure that all tracklets are done, since this placed in 0 tracklet01 will be done but tracklet12 needs to be guaranteed - gpu::computeTrackletSelectionMutliROFKernel<<>>(nullptr, - usedClusters, - ROFClusters, - phiCut, - tanLambdaCut, - foundTracklets, - usedTracklets, - trackletsPerClusterLUTs, - trackletsPerClusterSumLUTs, - linesPerClusterLUT, - nullptr, - nRofs, - deltaROF, - 100); - gpu::cubExclusiveScan(linesPerClusterLUT, linesPerClusterSumLUT, nClusters, streams[0].get()); -} - -void computeTrackletsMatchingInROFsHandler(const int32_t nRofs, - const int32_t deltaROF, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const Cluster** GPUrestrict() clusters, - const uint8_t** GPUrestrict() usedClusters, - const Tracklet** GPUrestrict() foundTracklets, - uint8_t* GPUrestrict() usedTracklets, - const int32_t** GPUrestrict() trackletsPerClusterLUTs, - const int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - const int32_t* GPUrestrict() linesPerClusterSumLUT, - Line* GPUrestrict() lines, - const int32_t iteration, - const float phiCut, - const float tanLambdaCut, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams) -{ - gpu::computeTrackletSelectionMutliROFKernel<<>>(clusters, - nullptr, - ROFClusters, - phiCut, - tanLambdaCut, - foundTracklets, - usedTracklets, - trackletsPerClusterLUTs, - trackletsPerClusterSumLUTs, - linesPerClusterSumLUT, - lines, - nRofs, - deltaROF, - 100); -} - -/// Explicit instantiation of ITS2 handlers -template void countTrackletsInROFsHandler<7>(const IndexTableUtils<7>* GPUrestrict() utils, - const uint8_t* GPUrestrict() multMask, - const int32_t nRofs, - const int32_t deltaROF, - const int32_t* GPUrestrict() rofPV, - const int32_t vertPerRofThreshold, - const Cluster** GPUrestrict() clusters, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const uint8_t** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() clustersIndexTables, - int32_t** trackletsPerClusterLUTs, - int32_t** trackletsPerClusterSumLUTs, - int32_t** trackletsPerROF, - const std::array& trackletsPerClusterLUTsHost, - const std::array& trackletsPerClusterSumLUTsHost, - const int32_t iteration, - const float phiCut, - const int32_t maxTrackletsPerCluster, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams); - -template void computeTrackletsInROFsHandler<7>(const IndexTableUtils<7>* GPUrestrict() utils, - const uint8_t* GPUrestrict() multMask, - const int32_t nRofs, - const int32_t deltaROF, - const int32_t* GPUrestrict() rofPV, - const int vertPerRofThreshold, - const Cluster** GPUrestrict() clusters, - const uint32_t nClusters, - const int32_t** GPUrestrict() ROFClusters, - const uint8_t** GPUrestrict() usedClusters, - const int32_t** GPUrestrict() clustersIndexTables, - Tracklet** GPUrestrict() foundTracklets, - const int32_t** GPUrestrict() trackletsPerClusterLUTs, - const int32_t** GPUrestrict() trackletsPerClusterSumLUTs, - const int32_t** GPUrestrict() trackletsPerROF, - const int32_t iteration, - const float phiCut, - const int32_t maxTrackletsPerCluster, - const int32_t nBlocks, - const int32_t nThreads, - gpu::Streams& streams); -/* -GPUg() void lineClustererMultipleRof( - const int* sizeClustersL1, // Number of clusters on layer 1 per ROF - Line* lines, // Lines - int* nFoundLines, // Number of found lines - int* nExclusiveFoundLines, // Number of found lines exclusive scan - int* clusteredLines, // Clustered lines - const unsigned int startRofId, // Starting ROF ID - const unsigned int rofSize, // Number of ROFs to consider // Number of found lines exclusive scan - const float pairCut) // Selection on line pairs -{ - for (unsigned int iRof{threadIdx.x}; iRof < rofSize; iRof += blockDim.x) { - auto rof = iRof + startRofId; - auto clustersL1offsetRof = sizeClustersL1[rof] - sizeClustersL1[startRofId]; // starting cluster offset for this ROF - auto nClustersL1Rof = sizeClustersL1[rof + 1] - sizeClustersL1[rof]; // number of clusters for this ROF - auto linesOffsetRof = nExclusiveFoundLines[clustersL1offsetRof]; // starting line offset for this ROF - // auto* foundLinesRof = nFoundLines + clustersL1offsetRof; - auto nLinesRof = nExclusiveFoundLines[clustersL1offsetRof + nClustersL1Rof] - linesOffsetRof; - // printf("rof: %d -> %d lines.\n", rof, nLinesRof); - for (int iLine1 = 0; iLine1 < nLinesRof; ++iLine1) { - auto absLine1Index = nExclusiveFoundLines[clustersL1offsetRof] + iLine1; - if (clusteredLines[absLine1Index] > -1) { - continue; - } - for (int iLine2 = iLine1 + 1; iLine2 < nLinesRof; ++iLine2) { - auto absLine2Index = nExclusiveFoundLines[clustersL1offsetRof] + iLine2; - if (clusteredLines[absLine2Index] > -1) { - continue; - } - - if (Line::getDCA(lines[absLine1Index], lines[absLine2Index]) < pairCut) { - ClusterLinesGPU tmpClus{lines[absLine1Index], lines[absLine2Index]}; - float tmpVertex[3]; - tmpVertex[0] = tmpClus.getVertex()[0]; - tmpVertex[1] = tmpClus.getVertex()[1]; - tmpVertex[2] = tmpClus.getVertex()[2]; - if (tmpVertex[0] * tmpVertex[0] + tmpVertex[1] * tmpVertex[1] > 4.f) { // outside the beampipe, skip it - break; - } - clusteredLines[absLine1Index] = iLine1; // We set local index of first line to contribute, so we can retrieve the cluster later - clusteredLines[absLine2Index] = iLine1; - for (int iLine3 = 0; iLine3 < nLinesRof; ++iLine3) { - auto absLine3Index = nExclusiveFoundLines[clustersL1offsetRof] + iLine3; - if (clusteredLines[absLine3Index] > -1) { - continue; - } - if (Line::getDistanceFromPoint(lines[absLine3Index], tmpVertex) < pairCut) { - clusteredLines[absLine3Index] = iLine1; - } - } - break; - } - } - } - } // rof loop -} - -GPUg() void computeCentroidsKernel( - Line* lines, - int* nFoundLines, - int* nExclusiveFoundLines, - const unsigned int nClustersMiddleLayer, - float* centroids, - const float lowHistX, - const float highHistX, - const float lowHistY, - const float highHistY, - const float pairCut) -{ - const int nLines = nExclusiveFoundLines[nClustersMiddleLayer - 1] + nFoundLines[nClustersMiddleLayer - 1]; - const int maxIterations{nLines * (nLines - 1) / 2}; - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < maxIterations; currentThreadIndex += blockDim.x * gridDim.x) { - int iFirstLine = currentThreadIndex / nLines; - int iSecondLine = currentThreadIndex % nLines; - // All unique pairs - if (iSecondLine <= iFirstLine) { - iFirstLine = nLines - iFirstLine - 2; - iSecondLine = nLines - iSecondLine - 1; - } - if (Line::getDCA(lines[iFirstLine], lines[iSecondLine]) < pairCut) { - ClusterLinesGPU cluster{lines[iFirstLine], lines[iSecondLine]}; - if (cluster.getVertex()[0] * cluster.getVertex()[0] + cluster.getVertex()[1] * cluster.getVertex()[1] < 1.98f * 1.98f) { - // printOnThread(0, "xCentr: %f, yCentr: %f \n", cluster.getVertex()[0], cluster.getVertex()[1]); - centroids[2 * currentThreadIndex] = cluster.getVertex()[0]; - centroids[2 * currentThreadIndex + 1] = cluster.getVertex()[1]; - } else { - // write values outside the histogram boundaries, - // default behaviour is not to have them added to histogram later - // (writing zeroes would be problematic) - centroids[2 * currentThreadIndex] = 2 * lowHistX; - centroids[2 * currentThreadIndex + 1] = 2 * lowHistY; - } - } else { - // write values outside the histogram boundaries, - // default behaviour is not to have them added to histogram later - // (writing zeroes would be problematic) - centroids[2 * currentThreadIndex] = 2 * highHistX; - centroids[2 * currentThreadIndex + 1] = 2 * highHistY; - } - } -} - -GPUg() void computeZCentroidsKernel( - const int nLines, - const cub::KeyValuePair* tmpVtX, - float* beamPosition, - Line* lines, - float* centroids, - const int* histX, // X - const float lowHistX, - const float binSizeHistX, - const int nBinsHistX, - const int* histY, // Y - const float lowHistY, - const float binSizeHistY, - const int nBinsHistY, - const float lowHistZ, // Z - const float pairCut, - const int binOpeningX, - const int binOpeningY) -{ - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < nLines; currentThreadIndex += blockDim.x * gridDim.x) { - if (tmpVtX[0].value || tmpVtX[1].value) { - float tmpX{lowHistX + tmpVtX[0].key * binSizeHistX + binSizeHistX / 2}; - int sumWX{tmpVtX[0].value}; - float wX{tmpX * tmpVtX[0].value}; - for (int iBin{o2::gpu::GPUCommonMath::Max(0, tmpVtX[0].key - binOpeningX)}; iBin < o2::gpu::GPUCommonMath::Min(tmpVtX[0].key + binOpeningX + 1, nBinsHistX - 1); ++iBin) { - if (iBin != tmpVtX[0].key) { - wX += (lowHistX + iBin * binSizeHistX + binSizeHistX / 2) * histX[iBin]; - sumWX += histX[iBin]; - } - } - float tmpY{lowHistY + tmpVtX[1].key * binSizeHistY + binSizeHistY / 2}; - int sumWY{tmpVtX[1].value}; - float wY{tmpY * tmpVtX[1].value}; - for (int iBin{o2::gpu::GPUCommonMath::Max(0, tmpVtX[1].key - binOpeningY)}; iBin < o2::gpu::GPUCommonMath::Min(tmpVtX[1].key + binOpeningY + 1, nBinsHistY - 1); ++iBin) { - if (iBin != tmpVtX[1].key) { - wY += (lowHistY + iBin * binSizeHistY + binSizeHistY / 2) * histY[iBin]; - sumWY += histY[iBin]; - } - } - beamPosition[0] = wX / sumWX; - beamPosition[1] = wY / sumWY; - float mockBeamPoint1[3] = {beamPosition[0], beamPosition[1], -1}; // get two points laying at different z, to create line object - float mockBeamPoint2[3] = {beamPosition[0], beamPosition[1], 1}; - Line pseudoBeam = {mockBeamPoint1, mockBeamPoint2}; - if (Line::getDCA(lines[currentThreadIndex], pseudoBeam) < pairCut) { - ClusterLinesGPU cluster{lines[currentThreadIndex], pseudoBeam}; - centroids[currentThreadIndex] = cluster.getVertex()[2]; - } else { - centroids[currentThreadIndex] = 2 * lowHistZ; - } - } - } -} - -GPUg() void computeVertexKernel( - cub::KeyValuePair* tmpVertexBins, - int* histZ, // Z - const float lowHistZ, - const float binSizeHistZ, - const int nBinsHistZ, - Vertex* vertices, - float* beamPosition, - const int vertIndex, - const int minContributors, - const int binOpeningZ) -{ - for (unsigned int currentThreadIndex = blockIdx.x * blockDim.x + threadIdx.x; currentThreadIndex < binOpeningZ; currentThreadIndex += blockDim.x * gridDim.x) { - if (currentThreadIndex == 0) { - if (tmpVertexBins[2].value > 1 && (tmpVertexBins[0].value || tmpVertexBins[1].value)) { - float z{lowHistZ + tmpVertexBins[2].key * binSizeHistZ + binSizeHistZ / 2}; - float ex{0.f}; - float ey{0.f}; - float ez{0.f}; - int sumWZ{tmpVertexBins[2].value}; - float wZ{z * tmpVertexBins[2].value}; - for (int iBin{o2::gpu::GPUCommonMath::Max(0, tmpVertexBins[2].key - binOpeningZ)}; iBin < o2::gpu::GPUCommonMath::Min(tmpVertexBins[2].key + binOpeningZ + 1, nBinsHistZ - 1); ++iBin) { - if (iBin != tmpVertexBins[2].key) { - wZ += (lowHistZ + iBin * binSizeHistZ + binSizeHistZ / 2) * histZ[iBin]; - sumWZ += histZ[iBin]; - } - histZ[iBin] = 0; - } - if (sumWZ > minContributors || vertIndex == 0) { - new (vertices + vertIndex) Vertex{o2::math_utils::Point3D(beamPosition[0], beamPosition[1], wZ / sumWZ), std::array{ex, 0, ey, 0, 0, ez}, static_cast(sumWZ), 0}; - } else { - new (vertices + vertIndex) Vertex{}; - } - } else { - new (vertices + vertIndex) Vertex{}; - } - } - } -} -*/ -} // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/BoundedAllocator.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/BoundedAllocator.h index 66634c1a07eea..91d5edeedcdb1 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/BoundedAllocator.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/BoundedAllocator.h @@ -97,6 +97,9 @@ class BoundedMemoryResource final : public std::pmr::memory_resource size_t getMaxMemory() const noexcept { return mMaxMemory; } void setMaxMemory(size_t max) { + if (max == mMaxMemory) { + return; + } size_t used = mUsedMemory.load(std::memory_order_acquire); if (used > max) { ++mCountThrow; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h index 902092a510eb0..5175b4129e27a 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cell.h @@ -16,6 +16,9 @@ #ifndef TRACKINGITSU_INCLUDE_CACELL_H_ #define TRACKINGITSU_INCLUDE_CACELL_H_ +#include + +#include "ReconstructionDataFormats/Track.h" #include "ITStracking/Constants.h" #include "GPUCommonDef.h" diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h deleted file mode 100644 index 0e7ad474ae455..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_ITS_CLUSTERLINES_H -#define O2_ITS_CLUSTERLINES_H - -#include -#include -#include "ITStracking/Cluster.h" -#include "ITStracking/Constants.h" -#include "ITStracking/Tracklet.h" -#include "GPUCommonRtypes.h" -#include "GPUCommonMath.h" - -namespace o2::its -{ -struct Line final { - GPUhdDefault() Line() = default; - GPUhd() Line(const Line&); - Line(std::array firstPoint, std::array secondPoint); - GPUhd() Line(const Tracklet&, const Cluster*, const Cluster*); - - static float getDistanceFromPoint(const Line& line, const std::array& point); - GPUhd() static float getDistanceFromPoint(const Line& line, const float point[3]); - static std::array getDCAComponents(const Line& line, const std::array point); - GPUhd() static void getDCAComponents(const Line& line, const float point[3], float destArray[6]); - GPUhd() static float getDCA(const Line&, const Line&, const float precision = constants::Tolerance); - static bool areParallel(const Line&, const Line&, const float precision = constants::Tolerance); - GPUhd() unsigned char isEmpty() const { return (originPoint[0] == 0.f && originPoint[1] == 0.f && originPoint[2] == 0.f) && - (cosinesDirector[0] == 0.f && cosinesDirector[1] == 0.f && cosinesDirector[2] == 0.f); } - GPUhdi() auto getDeltaROF() const { return rof[1] - rof[0]; } - GPUhd() void print() const; - bool operator==(const Line&) const; - bool operator!=(const Line&) const; - short getMinROF() const { return rof[0] < rof[1] ? rof[0] : rof[1]; } - - float originPoint[3] = {0, 0, 0}; - float cosinesDirector[3] = {0, 0, 0}; - // float weightMatrix[6] = {1., 0., 0., 1., 0., 1.}; - // weightMatrix is a symmetric matrix internally stored as - // 0 --> row = 0, col = 0 - // 1 --> 0,1 - // 2 --> 0,2 - // 3 --> 1,1 - // 4 --> 1,2 - // 5 --> 2,2 - short rof[2] = {constants::UnusedIndex, constants::UnusedIndex}; - - ClassDefNV(Line, 1); -}; - -GPUhdi() Line::Line(const Line& other) -{ - for (int i{0}; i < 3; ++i) { - originPoint[i] = other.originPoint[i]; - cosinesDirector[i] = other.cosinesDirector[i]; - } - // for (int i{0}; i < 6; ++i) { - // weightMatrix[i] = other.weightMatrix[i]; - // } - for (int i{0}; i < 2; ++i) { - rof[i] = other.rof[i]; - } -} - -GPUhdi() Line::Line(const Tracklet& tracklet, const Cluster* innerClusters, const Cluster* outerClusters) -{ - originPoint[0] = innerClusters[tracklet.firstClusterIndex].xCoordinate; - originPoint[1] = innerClusters[tracklet.firstClusterIndex].yCoordinate; - originPoint[2] = innerClusters[tracklet.firstClusterIndex].zCoordinate; - - cosinesDirector[0] = outerClusters[tracklet.secondClusterIndex].xCoordinate - innerClusters[tracklet.firstClusterIndex].xCoordinate; - cosinesDirector[1] = outerClusters[tracklet.secondClusterIndex].yCoordinate - innerClusters[tracklet.firstClusterIndex].yCoordinate; - cosinesDirector[2] = outerClusters[tracklet.secondClusterIndex].zCoordinate - innerClusters[tracklet.firstClusterIndex].zCoordinate; - - float inverseNorm{1.f / o2::gpu::CAMath::Hypot(cosinesDirector[0], cosinesDirector[1], cosinesDirector[2])}; - cosinesDirector[0] *= inverseNorm; - cosinesDirector[1] *= inverseNorm; - cosinesDirector[2] *= inverseNorm; - - rof[0] = tracklet.rof[0]; - rof[1] = tracklet.rof[1]; -} - -// static functions: -inline float Line::getDistanceFromPoint(const Line& line, const std::array& point) -{ - float DCASquared{0}; - float cdelta{0}; - for (int i{0}; i < 3; ++i) { - cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]); - } - for (int i{0}; i < 3; ++i) { - DCASquared += (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta) * - (line.originPoint[i] - point[i] + line.cosinesDirector[i] * cdelta); - } - return o2::gpu::CAMath::Sqrt(DCASquared); -} - -GPUhdi() float Line::getDistanceFromPoint(const Line& line, const float point[3]) -{ - const float dx = point[0] - line.originPoint[0]; - const float dy = point[1] - line.originPoint[1]; - const float dz = point[2] - line.originPoint[2]; - const float d = (dx * line.cosinesDirector[0]) + (dy * line.cosinesDirector[1]) + (dz * line.cosinesDirector[2]); - - const float vx = dx - (d * line.cosinesDirector[0]); - const float vy = dy - (d * line.cosinesDirector[1]); - const float vz = dz - (d * line.cosinesDirector[2]); - - return o2::gpu::CAMath::Hypot(vx, vy, vz); -} - -GPUhdi() float Line::getDCA(const Line& firstLine, const Line& secondLine, const float precision) -{ - const float nx = (firstLine.cosinesDirector[1] * secondLine.cosinesDirector[2]) - - (firstLine.cosinesDirector[2] * secondLine.cosinesDirector[1]); - const float ny = -(firstLine.cosinesDirector[0] * secondLine.cosinesDirector[2]) + - (firstLine.cosinesDirector[2] * secondLine.cosinesDirector[0]); - const float nz = (firstLine.cosinesDirector[0] * secondLine.cosinesDirector[1]) - - (firstLine.cosinesDirector[1] * secondLine.cosinesDirector[0]); - const float norm2 = (nx * nx) + (ny * ny) + (nz * nz); - - if (norm2 <= precision * precision) { - return getDistanceFromPoint(firstLine, secondLine.originPoint); - } - - const float dx = secondLine.originPoint[0] - firstLine.originPoint[0]; - const float dy = secondLine.originPoint[1] - firstLine.originPoint[1]; - const float dz = secondLine.originPoint[2] - firstLine.originPoint[2]; - const float triple = (dx * nx) + (dy * ny) + (dz * nz); - - return o2::gpu::CAMath::Abs(triple) / o2::gpu::CAMath::Sqrt(norm2); -} - -GPUhdi() void Line::getDCAComponents(const Line& line, const float point[3], float destArray[6]) -{ - float cdelta{0.}; - for (int i{0}; i < 3; ++i) { - cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]); - } - - destArray[0] = line.originPoint[0] - point[0] + line.cosinesDirector[0] * cdelta; - destArray[3] = line.originPoint[1] - point[1] + line.cosinesDirector[1] * cdelta; - destArray[5] = line.originPoint[2] - point[2] + line.cosinesDirector[2] * cdelta; - destArray[1] = o2::gpu::CAMath::Sqrt(destArray[0] * destArray[0] + destArray[3] * destArray[3]); - destArray[2] = o2::gpu::CAMath::Sqrt(destArray[0] * destArray[0] + destArray[5] * destArray[5]); - destArray[4] = o2::gpu::CAMath::Sqrt(destArray[3] * destArray[3] + destArray[5] * destArray[5]); -} - -inline bool Line::operator==(const Line& rhs) const -{ - bool val{false}; - for (int i{0}; i < 3; ++i) { - val &= this->originPoint[i] == rhs.originPoint[i]; - } - return val; -} - -inline bool Line::operator!=(const Line& rhs) const -{ - return !(*this == rhs); -} - -GPUhdi() void Line::print() const -{ - printf("Line: originPoint = (%f, %f, %f), cosinesDirector = (%f, %f, %f), rofs = (%hd, %hd)\n", - originPoint[0], originPoint[1], originPoint[2], cosinesDirector[0], cosinesDirector[1], cosinesDirector[2], rof[0], rof[1]); -} - -class ClusterLines final -{ - public: - ClusterLines() = default; - ClusterLines(const int firstLabel, const Line& firstLine, const int secondLabel, const Line& secondLine, - const bool weight = false); - ClusterLines(const Line& firstLine, const Line& secondLine); - void add(const int& lineLabel, const Line& line, const bool& weight = false); - void computeClusterCentroid(); - void updateROFPoll(const Line&); - inline std::vector& getLabels() - { - return mLabels; - } - inline int getSize() const { return mLabels.size(); } - inline short getROF() const { return mROF; } - inline std::array getVertex() const { return mVertex; } - inline std::array getRMS2() const { return mRMS2; } - inline float getAvgDistance2() const { return mAvgDistance2; } - - bool operator==(const ClusterLines&) const; - - protected: - std::array mAMatrix; // AX=B - std::array mBMatrix; // AX=B - std::vector mLabels; // labels - std::array mWeightMatrix = {0.f}; // weight matrix - std::array mVertex = {0.f}; // cluster centroid position - std::array mRMS2 = {0.f}; // symmetric matrix: diagonal is RMS2 - float mAvgDistance2 = 0.f; // substitute for chi2 - int mROFWeight = 0; // rof weight for voting - short mROF = constants::UnusedIndex; // rof -}; - -} // namespace o2::its -#endif /* O2_ITS_CLUSTERLINES_H */ diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h index 000c8fe822498..e733611e509d5 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h @@ -16,14 +16,11 @@ #ifndef TRACKINGITSU_INCLUDE_CONFIGURATION_H_ #define TRACKINGITSU_INCLUDE_CONFIGURATION_H_ -#ifndef GPUCA_GPUCODE_DEVICE -#include #include #include -#include -#endif #include "DetectorsBase/Propagator.h" +#include "CommonUtils/EnumFlags.h" #include "ITStracking/Constants.h" namespace o2::its @@ -37,7 +34,7 @@ struct TrackingParameters { std::string asString() const; int NLayers = 7; - int DeltaROF = 0; + std::vector DeltaROF = {0, 0, 0, 0, 0, 0, 0}; // Delta in BC to define search window std::vector LayerZ = {16.333f + 1, 16.333f + 1, 16.333f + 1, 42.140f + 1, 42.140f + 1, 73.745f + 1, 73.745f + 1}; std::vector LayerRadii = {2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; std::vector LayerxX0 = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; @@ -46,22 +43,18 @@ struct TrackingParameters { std::vector SystErrorZ2 = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; int ZBins{256}; int PhiBins{128}; - int nROFsPerIterations = -1; bool UseDiamond = false; float Diamond[3] = {0.f, 0.f, 0.f}; + float DiamondCov[6] = {25.e-6f, 0.f, 0.f, 25.e-6f, 0.f, 36.f}; /// General parameters bool AllowSharingFirstCluster = false; int ClusterSharing = 0; int MinTrackLength = 7; float NSigmaCut = 5; - float PVres = 1.e-2f; + int NTimeSlices{1}; /// Trackleting cuts float TrackletMinPt = 0.3f; - float TrackletsPerClusterLimit = 2.f; - /// Cell finding cuts - float CellDeltaTanLambdaSigma = 0.007f; - float CellsPerClusterLimit = 2.f; /// Fitter parameters o2::base::PropagatorImpl::MatCorrType CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE; float MaxChi2ClusterAttachment = 60.f; @@ -80,8 +73,21 @@ struct TrackingParameters { bool UseTrackFollowerTop = false; bool UseTrackFollowerBot = false; bool UseTrackFollowerMix = false; - float TrackFollowerNSigmaCutZ = 1.f; - float TrackFollowerNSigmaCutPhi = 1.f; + + /// Seeding parameters + float SeedingDCATolerance{0.8f}; // maximum allowed DCA to meanvertex for track to enter pool + float SeedingDCAMaxPull{3.f}; // maximum allowed initial pull on DCA to meanvertex + float SeedingMaxChi2Iter{3.f}; // maximum chi2 change required to end iteration + float SeedingTukeyStartIter{5.f}; // start value for tukey scaling for iteration + float SeedingMinWghTrk{0.01f}; // minimum weight a track has to have to be accounted + float SeedingMinPtTrk{0.05}; // minimum pt for cells to enter pool + int SeedingMinContrib{8}; // minimum number of contributors to account seeding vertex for rolling average + int SeedingMaxFitIter{3}; // maximum iterations for fit + int SeedingMinTracksIter{20}; // minimum tracks needed for one iteration + int SeedingDBScanMinPt{50}; // DBSCAN: minimum number of cluster points + float SeedingDBScanEpsZ{0.01f}; // DBSCAN: maximum epsilon z + float SeedingDBScanEpsT{10.f}; // DBSCAN: maximum epsilon t (BC) + float SeedingVertexExtraErr2[6] = {0.f}; // impose additional errors on seeding vertices bool createArtefactLabels{false}; @@ -90,61 +96,25 @@ struct TrackingParameters { bool DropTFUponFailure = false; }; -struct VertexingParameters { - std::string asString() const; - - int nIterations = 1; // Number of vertexing passes to perform - int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a round - bool allowSingleContribClusters = false; - std::vector LayerZ = {16.333f + 1, 16.333f + 1, 16.333f + 1, 42.140f + 1, 42.140f + 1, 73.745f + 1, 73.745f + 1}; - std::vector LayerRadii = {2.33959f, 3.14076f, 3.91924f, 19.6213f, 24.5597f, 34.388f, 39.3329f}; - int ZBins{1}; - int PhiBins{128}; - int deltaRof = 0; - float zCut = 0.002f; - float phiCut = 0.005f; - float pairCut = 0.04f; - float clusterCut = 0.8f; - float histPairCut = 0.04f; - float tanLambdaCut = 0.002f; // tanLambda = deltaZ/deltaR - float lowMultBeamDistCut = 0.1f; // XY cut for low-multiplicity pile up - int vertNsigmaCut = 6; // N sigma cut for vertex XY - float vertRadiusSigma = 0.33f; // sigma of vertex XY - float trackletSigma = 0.01f; // tracklet to vertex sigma - float maxZPositionAllowed = 25.f; - int clusterContributorsCut = 16; - int maxTrackletsPerCluster = 2e3; - int phiSpan = -1; - int zSpan = -1; - bool SaveTimeBenchmarks = false; - - bool useTruthSeeding = false; // overwrite found vertices with MC events - bool outputContLabels = false; - - int nThreads = 1; - bool PrintMemory = false; // print allocator usage in epilog report - size_t MaxMemory = std::numeric_limits::max(); - bool DropTFUponFailure = false; +enum class RecoIterationSteps : uint16_t { + /// which steps should be run + kRunTrackleting, // run the trackleting step + kRunCellFinding, // run the cell finding step (connect tracklets) + kRunCellSeeding, // run the cell seeding step (use cells to find seeding vertices) + kRunCellNeighborFinding, // run the cell neighbor finding step (connect cells) + kRunRoadFinding, // run the road finding step (resolve ambiguities to find best roads/tracks) + kRunTruthSeeding, // run truth seeding (imposing MC event information as seeding vertices) + /// extra steps + kUpdateVertexTable, // update the vertex table for the current pool of vertices + kUpdateClusters, // update the cluster position wrt current beam constraint + kInitMemory, // initialize all vectors to use memory resource }; -struct TimeFrameGPUParameters { +struct RecoIteration { + TrackingParameters params; + utils::EnumFlags steps; + std::string name; std::string asString() const; - - size_t tmpCUBBufferSize = 1e5; // In average in pp events there are required 4096 bytes - size_t maxTrackletsPerCluster = 1e2; - size_t clustersPerLayerCapacity = 2.5e5; - size_t clustersPerROfCapacity = 1.5e3; - size_t validatedTrackletsCapacity = 1e3; - size_t cellsLUTsize = validatedTrackletsCapacity; - size_t maxNeighboursSize = 1e2; - size_t neighboursLUTsize = maxNeighboursSize; - size_t maxRoadPerRofSize = 1e3; // pp! - size_t maxLinesCapacity = 1e2; - size_t maxVerticesCapacity = 5e4; - size_t nMaxROFs = 1e3; - size_t nTimeFrameChunks = 3; - size_t nROFsPerChunk = 768; // pp defaults - int maxGPUMemoryGB = -1; }; namespace TrackingMode @@ -160,9 +130,7 @@ enum Type : int8_t { Type fromString(std::string_view str); std::string toString(Type mode); -std::vector getTrackingParameters(Type mode); -std::vector getVertexingParameters(Type mode); - +std::vector getRecoIterations(Type mode); }; // namespace TrackingMode } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h index c3be0de2dade7..aba47516b794a 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Definitions.h @@ -16,29 +16,48 @@ #define TRACKINGITS_DEFINITIONS_H_ #include +#include +#include +#include "SimulationDataFormat/MCCompLabel.h" +#include "CommonDataFormat/TimeStamp.h" #include "ReconstructionDataFormats/Vertex.h" -#ifdef CA_DEBUG -#define CA_DEBUGGER(x) x -#else -#define CA_DEBUGGER(x) \ - do { \ - } while (0) -#endif - namespace o2::its { -enum class TrackletMode { - Layer0Layer1 = 0, - Layer1Layer2 = 2 -}; +template +using maybe_const = std::conditional_t; -using Vertex = o2::dataformats::Vertex>; +// Time estimates are given in BC +// error needs to cover maximum 1 orbit +// this is an asymmetric error defining an interval [time, time+error) +using TimeEstBC = o2::dataformats::TimeStampWithError; +using Vertex = o2::dataformats::Vertex; +// MC vertex label with purity +using VertexLabel = std::pair; -template -using maybe_const = typename std::conditional::type; +// simple implemnetion of logging with exp. backoff +struct LogLogThrottler { + uint64_t evCount{0}; + uint64_t nextLog{1}; + int32_t iteration{-1}; + int32_t layer{-1}; + bool needToLog(int32_t iter, int32_t lay) + { + if (iteration != iter || layer != lay) { + iteration = iter; + layer = lay; + evCount = 0; + nextLog = 1; + } + if (++evCount > nextLog) { + nextLog *= 2; + return true; + } + return false; + } +}; } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h index 118557c970c35..9f47a12febf69 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/IndexTableUtils.h @@ -34,18 +34,18 @@ class IndexTableUtils public: template void setTrackingParameters(const T& params); - float getInverseZCoordinate(const int layerIndex) const; - GPUhdi() int getZBinIndex(const int, const float) const; - GPUhdi() int getPhiBinIndex(const float) const; - GPUhdi() int getBinIndex(const int, const int) const; - GPUhdi() int countRowSelectedBins(const int*, const int, const int, const int) const; + float getInverseZCoordinate(const int layerIndex) const noexcept; + GPUhdi() int getZBinIndex(const int, const float) const noexcept; + GPUhdi() int getPhiBinIndex(const float) const noexcept; + GPUhdi() int getBinIndex(const int, const int) const noexcept; + GPUhdi() int countRowSelectedBins(const int*, const int, const int, const int) const noexcept; GPUhdi() void print() const; - GPUhdi() int getNzBins() const { return mNzBins; } - GPUhdi() int getNphiBins() const { return mNphiBins; } - GPUhdi() float getLayerZ(int i) const { return mLayerZ[i]; } - GPUhdi() void setNzBins(const int zBins) { mNzBins = zBins; } - GPUhdi() void setNphiBins(const int phiBins) { mNphiBins = phiBins; } + GPUhdi() int getNzBins() const noexcept { return mNzBins; } + GPUhdi() int getNphiBins() const noexcept { return mNphiBins; } + GPUhdi() float getLayerZ(int i) const noexcept { return mLayerZ[i]; } + GPUhdi() void setNzBins(const int zBins) noexcept { mNzBins = zBins; } + GPUhdi() void setNphiBins(const int phiBins) noexcept { mNphiBins = phiBins; } private: int mNzBins = 0; @@ -71,36 +71,34 @@ inline void IndexTableUtils::setTrackingParameters(const T& params) } template -inline float IndexTableUtils::getInverseZCoordinate(const int layerIndex) const +inline float IndexTableUtils::getInverseZCoordinate(const int layerIndex) const noexcept { return 0.5f * mNzBins / mLayerZ[layerIndex]; } template -GPUhdi() int IndexTableUtils::getZBinIndex(const int layerIndex, const float zCoordinate) const +GPUhdi() int IndexTableUtils::getZBinIndex(const int layerIndex, const float zCoordinate) const noexcept { return (zCoordinate + mLayerZ[layerIndex]) * mInverseZBinSize[layerIndex]; } template -GPUhdi() int IndexTableUtils::getPhiBinIndex(const float currentPhi) const +GPUhdi() int IndexTableUtils::getPhiBinIndex(const float currentPhi) const noexcept { return (currentPhi * mInversePhiBinSize); } template -GPUhdi() int IndexTableUtils::getBinIndex(const int zIndex, const int phiIndex) const +GPUhdi() int IndexTableUtils::getBinIndex(const int zIndex, const int phiIndex) const noexcept { - return o2::gpu::GPUCommonMath::Min(phiIndex * mNzBins + zIndex, mNzBins * mNphiBins - 1); + return o2::gpu::GPUCommonMath::Min((phiIndex * mNzBins) + zIndex, (mNzBins * mNphiBins) - 1); } template -GPUhdi() int IndexTableUtils::countRowSelectedBins(const int* indexTable, const int phiBinIndex, - const int minZBinIndex, const int maxZBinIndex) const +GPUhdi() int IndexTableUtils::countRowSelectedBins(const int* indexTable, const int phiBinIndex, const int minZBinIndex, const int maxZBinIndex) const noexcept { const int firstBinIndex{getBinIndex(minZBinIndex, phiBinIndex)}; const int maxBinIndex{firstBinIndex + maxZBinIndex - minZBinIndex + 1}; - return indexTable[maxBinIndex] - indexTable[firstBinIndex]; } diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h index c5c1e4a8ce220..e57540be30c52 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/MathUtils.h @@ -42,21 +42,18 @@ GPUhdi() constexpr float getNormalizedPhi(float phi) } GPUhdi() float computeCurvature(float x1, float y1, float x2, float y2, float x3, float y3) -{ - // in case the triangle is degenerate we return infinite curvature. - const float d = (x2 - x1) * (y3 - y2) - (x3 - x2) * (y2 - y1); - if (o2::gpu::CAMath::Abs(d) < o2::its::constants::Tolerance) { - return 0.f; - } - const float a = - 0.5f * ((y3 - y2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) - (y2 - y1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2)); - const float b = - 0.5f * ((x2 - x1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2) - (x3 - x2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1)); - const float den = o2::gpu::CAMath::Hypot(d * x1 - a, d * y1 - b); - if (den < o2::its::constants::Tolerance) { - return 0.f; +{ // in case the triangle is degenerate we return infinite curvature. + const float area = ((x2 - x1) * (y3 - y1)) - ((x3 - x1) * (y2 - y1)); + if (o2::gpu::CAMath::Abs(area) < constants::Tolerance) { + return o2::constants::math::VeryBig; } - return -d / den; + const float dx1 = x2 - x1, dy1 = y2 - y1; + const float dx2 = x3 - x2, dy2 = y3 - y2; + const float dx3 = x1 - x3, dy3 = y1 - y3; + const float d1 = o2::gpu::CAMath::Sqrt((dx1 * dx1) + (dy1 * dy1)); + const float d2 = o2::gpu::CAMath::Sqrt((dx2 * dx2) + (dy2 * dy2)); + const float d3 = o2::gpu::CAMath::Sqrt((dx3 * dx3) + (dy3 * dy3)); + return -2.f * area / (d1 * d2 * d3); } GPUhdi() float computeCurvatureCentreX(float x1, float y1, float x2, float y2, float x3, float y3) @@ -78,7 +75,7 @@ GPUhdi() float computeCurvatureCentreX(float x1, float y1, float x2, float y2, f GPUhdi() float computeTanDipAngle(float x1, float y1, float x2, float y2, float z1, float z2) { - // in case the points vertically align we go to pos/neg inifinity. + // in case the points vertically align we go to pos/neg infinity. const float d = o2::gpu::CAMath::Hypot(x1 - x2, y1 - y2); if (o2::gpu::CAMath::Abs(d) < o2::its::constants::Tolerance) { return ((z1 > z2) ? -1.f : 1.f) * o2::constants::math::VeryBig; @@ -91,11 +88,16 @@ GPUhdi() float smallestAngleDifference(float a, float b) return o2::gpu::CAMath::Remainderf(b - a, o2::constants::math::TwoPI); } -GPUhdi() float Sq(float v) +GPUhdi() constexpr float Sq(float v) { return v * v; } +GPUhdi() constexpr float SqDiff(float x, float y) +{ + return Sq(x - y); +} + GPUhdi() float MSangle(float mass, float p, float xX0) { float beta = p / o2::gpu::CAMath::Hypot(mass, p); diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROFLookupTables.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROFLookupTables.h new file mode 100644 index 0000000000000..ec8a7b5052a51 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROFLookupTables.h @@ -0,0 +1,865 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef TRACKINGITSU_INCLUDE_ROFOVERLAPTABLE_H_ +#define TRACKINGITSU_INCLUDE_ROFOVERLAPTABLE_H_ + +#include +#include +#include +#include +#include +#include + +#include "CommonConstants/LHCConstants.h" +#include "CommonDataFormat/RangeReference.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "ITStracking/Definitions.h" +#include "GPUCommonLogger.h" +#include "GPUCommonMath.h" +#include "GPUCommonDef.h" + +namespace o2::its +{ + +// Layer timing definition +struct LayerTiming { + using BCType = int32_t; + using ROFRange = dataformats::RangeReference; + BCType mNROFsTF{0}; // number of ROFs per timeframe + BCType mROFLength{0}; // ROF length in BC + BCType mROFDelay{0}; // delay of ROFs wrt LHC orbit + BCType mROFDelta{0}; // added delta in BC for compatibility + + // return start of ROF in BC + GPUhdi() BCType getROFStartInBC(BCType rofId, bool actual = false) const noexcept + { + assert(rofId < mNROFsTF); + return (mROFLength * rofId) + ((actual) ? mROFDelay : 0); + } + + // return end of ROF in BCs + GPUhdi() BCType getROFEndInBC(BCType rofId, bool actual = false) const noexcept + { + assert(rofId < mNROFsTF); + return getROFStartInBC(rofId, actual) + mROFLength; + } + + // return time-interval of rof [start, end) + GPUhdi() ROFRange getROFTimeBounds(BCType rofId, bool actual = false) const noexcept + { + auto start = getROFStartInBC(rofId, actual); + auto end = getROFEndInBC(rofId, actual); + if (actual) { + start -= mROFDelta; + end += mROFDelta; + } + return {start, end - start + 1}; + } + + GPUhdi() BCType getROFIdForBC(BCType bc) const noexcept + { + const BCType rofId = (bc - mROFDelay) / mROFLength; + assert(rofId >= 0); + return rofId; + } + + GPUhi() o2::InteractionRecord getIRForROFId(BCType rofId) const noexcept + { + return o2::InteractionRecord::long2IR(getROFStartInBC(rofId)); + } + + GPUh() std::string asString() const + { + return std::format("NROFsPerTF {:4} ROFLength {:4} ({:4} per Orbit) ROFDelay {:4} ROFDelta {:4}", mNROFsTF, mROFLength, (o2::constants::lhc::LHCMaxBunches / mROFLength), mROFDelay, mROFDelta); + } + + GPUh() void print() const + { + LOG(info) << asString(); + } +}; + +// Base class for lookup to define layers +template +class LayerTimingBase +{ + protected: + LayerTiming mLayers[NLayers]; + + public: + using T = LayerTiming::BCType; + GPUdDefault() LayerTimingBase() = default; + + // Define the time structure for one layer + // layer: which layer + // nROFsTF: the total number rofs in a TF (the pattern is repeating per orbit so this is just a multiple, handling + // both edges correctly) + // rofLength: ROF length in BC + // rofDelay: delay of ROFs wrt LHC orbit + // deltaROF: added delta in BC considering compatibility among rofs + GPUh() void defineLayer(int32_t layer, int32_t nROFsTF, int32_t rofLength, int32_t rofDelay, int32_t deltaROF) + { + assert(std::numeric_limits::max() < nROFsTF); + mLayers[layer] = {nROFsTF, rofLength, rofDelay, deltaROF}; + } + + GPUh() void defineLayer(int32_t layer, const LayerTiming& timing) + { + mLayers[layer] = timing; + } + + GPUhdi() const LayerTiming& getLayer(int32_t layer) + { + assert(layer >= 0 && layer < NLayers); + return mLayers[layer]; + } + + GPUhdi() constexpr int32_t getEntries() noexcept { return NLayers; } +}; + +// GPU friendly view of the table below +template +struct ROFOverlapTableView { + using ROFRange = LayerTiming::ROFRange; + const TableEntry* mFlatTable{nullptr}; + const TableIndex* mIndices{nullptr}; + const LayerTiming* mLayers{nullptr}; + + GPUhdi() const TableEntry& getOverlap(int32_t from, int32_t to, size_t rofIdx) const noexcept + { + assert(from < NLayers && to < NLayers); + const size_t linearIdx = (from * NLayers) + to; + const auto& idx = mIndices[linearIdx]; + assert(rofIdx < idx.getEntries()); + return mFlatTable[idx.getFirstEntry() + rofIdx]; + } + + GPUhdi() bool isCompatible(int32_t layer0, size_t rof0, int32_t layer1, size_t rof1) const noexcept + { + if (layer0 == layer1) { // layer is compatible with itself + return rof0 == rof1; + } + + assert(layer0 < NLayers && layer1 < NLayers); + const size_t linearIdx = (layer0 * NLayers) + layer1; + const auto& idx = mIndices[linearIdx]; + + if (rof0 >= idx.getEntries()) { + return false; + } + + const auto& overlap = mFlatTable[idx.getFirstEntry() + rof0]; + + if (overlap.getEntries() == 0) { + return false; + } + + const size_t firstCompatible = overlap.getFirstEntry(); + const size_t lastCompatible = firstCompatible + overlap.getEntries() - 1; + return rof1 >= firstCompatible && rof1 <= lastCompatible; + } + + GPUhdi() const LayerTiming& getLayer(int32_t layer) const noexcept + { + assert(layer >= 0 && layer < NLayers); + return mLayers[layer]; + } + + GPUh() void printAll() const + { + for (int32_t i = 0; i < NLayers; ++i) { + for (int32_t j = 0; j < NLayers; ++j) { + if (i != j) { + printMapping(i, j); + } + } + } + printSummary(); + } + + GPUh() void printMapping(int32_t from, int32_t to) const + { + if (from == to) { + LOGP(error, "No self-lookup supported"); + return; + } + + constexpr int w_index = 10; + constexpr int w_first = 12; + constexpr int w_last = 12; + constexpr int w_count = 10; + + LOGF(info, "Overlap mapping: Layer %d -> Layer %d", from, to); + LOGP(info, "From: {}", mLayers[from].asString()); + LOGP(info, "To : {}", mLayers[to].asString()); + LOGF(info, "%*s | %*s | %*s | %*s", w_index, "ROF.index", w_first, "First.ROF", w_last, "Last.ROF", w_count, "Count"); + LOGF(info, "%.*s-+-%.*s-+-%.*s-+-%.*s", w_index, "----------", w_first, "------------", w_last, "------------", w_count, "----------"); + + const size_t linearIdx = (from * NLayers) + to; + const auto& idx = mIndices[linearIdx]; + for (int32_t i = 0; i < idx.getEntries(); ++i) { + const auto& overlap = getOverlap(from, to, i); + LOGF(info, "%*d | %*d | %*d | %*d", w_index, i, w_first, overlap.getFirstEntry(), w_last, overlap.getEntriesBound() - 1, w_count, overlap.getEntries()); + } + } + + GPUh() void printSummary() const + { + uint32_t totalEntries{0}; + size_t flatTableSize{0}; + + for (int32_t i = 0; i < NLayers; ++i) { + for (int32_t j = 0; j < NLayers; ++j) { + if (i != j) { + const size_t linearIdx = i * NLayers + j; + const auto& idx = mIndices[linearIdx]; + totalEntries += idx.getEntries(); + flatTableSize += idx.getEntries(); + } + } + } + + const uint32_t totalBytes = (flatTableSize * sizeof(TableEntry)) + (NLayers * NLayers * sizeof(TableIndex)); + LOGF(info, "------------------------------------------------------------"); + LOGF(info, "Total overlap table size: %u entries", totalEntries); + LOGF(info, "Flat table size: %zu entries", flatTableSize); + LOGF(info, "Total view size: %u bytes", totalBytes); + LOGF(info, "------------------------------------------------------------"); + } +}; + +// Precalculated lookup table to find overlapping ROFs in another layer given a ROF index in the current layer +template +class ROFOverlapTable : public LayerTimingBase +{ + public: + using T = LayerTimingBase::T; + using TableEntry = dataformats::RangeReference; + using TableIndex = dataformats::RangeReference; + + using View = ROFOverlapTableView; + GPUdDefault() ROFOverlapTable() = default; + + GPUh() void init() + { + std::vector table[NLayers][NLayers]; + for (int32_t i{0}; i < NLayers; ++i) { + for (int32_t j{0}; j < NLayers; ++j) { + if (i != j) { // we do not need self-lookup + buildMapping(i, j, table[i][j]); + } + } + } + flatten(table); + } + + GPUh() View getView() const + { + View view; + view.mFlatTable = mFlatTable.data(); + view.mIndices = mIndices; + view.mLayers = this->mLayers; + return view; + } + + GPUh() View getDeviceView(const TableEntry* deviceFlatTablePtr, const TableIndex* deviceIndicesPtr, const LayerTiming* deviceLayerTimingPtr) const + { + View view; + view.mFlatTable = deviceFlatTablePtr; + view.mIndices = deviceIndicesPtr; + view.mLayers = deviceLayerTimingPtr; + return view; + } + + GPUh() size_t getFlatTableSize() const noexcept { return mFlatTable.size(); } + static GPUh() constexpr size_t getIndicesSize() { return NLayers * NLayers; } + + private: + GPUh() void buildMapping(int32_t from, int32_t to, std::vector& table) + { + const auto& layerFrom = this->mLayers[from]; + const auto& layerTo = this->mLayers[to]; + table.resize(layerFrom.mNROFsTF); + + for (int32_t iROF{0}; iROF < layerFrom.mNROFsTF; ++iROF) { + int32_t startFrom = layerFrom.mROFDelay + (iROF * layerFrom.mROFLength); + int32_t endFrom = startFrom + layerFrom.mROFLength; + startFrom -= layerFrom.mROFDelta; + endFrom += layerFrom.mROFDelta; + int32_t firstROFTo = o2::gpu::CAMath::Max(0, (startFrom - layerTo.mROFDelay) / layerTo.mROFLength); + int32_t lastROFTo = (endFrom - layerTo.mROFDelay - 1) / layerTo.mROFLength; + firstROFTo = o2::gpu::CAMath::Max(0, firstROFTo); + lastROFTo = o2::gpu::CAMath::Min(layerTo.mNROFsTF - 1, lastROFTo); + + // verify overlap + while (firstROFTo <= lastROFTo) { + int32_t startTo = layerTo.mROFDelay + (firstROFTo * layerTo.mROFLength); + int32_t endTo = startTo + layerTo.mROFLength; + if (endTo > startFrom && startTo < endFrom) { + break; + } + ++firstROFTo; + } + while (lastROFTo >= firstROFTo) { + int32_t startTo = layerTo.mROFDelay + (lastROFTo * layerTo.mROFLength); + int32_t endTo = startTo + layerTo.mROFLength; + if (endTo > startFrom && startTo < endFrom) { + break; + } + --lastROFTo; + } + int32_t count = (firstROFTo <= lastROFTo) ? (lastROFTo - firstROFTo + 1) : 0; + table[iROF] = {static_cast(firstROFTo), static_cast(count)}; + } + } + + GPUh() void flatten(const std::vector table[NLayers][NLayers]) + { + size_t total{0}; + for (int32_t i{0}; i < NLayers; ++i) { + for (int32_t j{0}; j < NLayers; ++j) { + if (i != j) { // we don not need self-lookup + total += table[i][j].size(); + } + } + } + + mFlatTable.reserve(total); + + for (int32_t i{0}; i < NLayers; ++i) { + for (int32_t j{0}; j < NLayers; ++j) { + size_t idx = (i * NLayers) + j; + if (i != j) { + mIndices[idx].setFirstEntry(static_cast(mFlatTable.size())); + mIndices[idx].setEntries(static_cast(table[i][j].size())); + mFlatTable.insert(mFlatTable.end(), table[i][j].begin(), table[i][j].end()); + } else { + mIndices[idx] = {0, 0}; + } + } + } + } + + TableIndex mIndices[NLayers * NLayers]; + std::vector mFlatTable; +}; + +// GPU friendly view of the table below +template +struct ROFVertexLookupTableView { + const TableEntry* mFlatTable{nullptr}; + const TableIndex* mIndices{nullptr}; + const LayerTiming* mLayers{nullptr}; + + GPUhdi() const LayerTiming& getLayer(int32_t layer) const noexcept + { + assert(layer >= 0 && layer < NLayers); + return mLayers[layer]; + } + + GPUhdi() const TableEntry& getVertices(int32_t layer, size_t rofIdx) const noexcept + { + assert(layer < NLayers); + const auto& idx = mIndices[layer]; + assert(rofIdx < idx.getEntries()); + return mFlatTable[idx.getFirstEntry() + rofIdx]; + } + + GPUh() int32_t getMaxVerticesPerROF() const noexcept + { + int32_t maxCount = 0; + for (int32_t layer = 0; layer < NLayers; ++layer) { + const auto& idx = mIndices[layer]; + for (int32_t i = 0; i < idx.getEntries(); ++i) { + const auto& entry = mFlatTable[idx.getFirstEntry() + i]; + maxCount = o2::gpu::CAMath::Max(maxCount, static_cast(entry.getEntries())); + } + } + return maxCount; + } + + // Check if a specific vertex is compatible with a given ROF + GPUhdi() bool isVertexCompatible(int32_t layer, size_t rofIdx, size_t vertexIdx) const noexcept + { + assert(layer < NLayers); + const auto& idx = mIndices[layer]; + + if (rofIdx >= idx.getEntries()) { + return false; + } + + const auto& entry = mFlatTable[idx.getFirstEntry() + rofIdx]; + + if (entry.getEntries() == 0) { + return false; + } + + const size_t firstVertex = entry.getFirstEntry(); + const size_t lastVertex = firstVertex + entry.getEntries() - 1; + return vertexIdx >= firstVertex && vertexIdx <= lastVertex; + } + + GPUh() void printAll() const + { + for (int32_t i = 0; i < NLayers; ++i) { + printLayer(i); + } + printSummary(); + } + + GPUh() void printLayer(int32_t layer) const + { + constexpr int w_rof = 10; + constexpr int w_first = 12; + constexpr int w_last = 12; + constexpr int w_count = 10; + + LOGF(info, "Vertex lookup: Layer %d", layer); + LOGF(info, "%*s | %*s | %*s | %*s", w_rof, "ROF.index", w_first, "First.Vtx", w_last, "Last.Vtx", w_count, "Count"); + LOGF(info, "%.*s-+-%.*s-+-%.*s-+-%.*s", w_rof, "----------", w_first, "------------", w_last, "------------", w_count, "----------"); + + const auto& idx = mIndices[layer]; + for (int32_t i = 0; i < idx.getEntries(); ++i) { + const auto& entry = mFlatTable[idx.getFirstEntry() + i]; + int first = entry.getFirstEntry(); + int count = entry.getEntries(); + int last = first + count - 1; + LOGF(info, "%*d | %*d | %*d | %*d", w_rof, i, w_first, first, w_last, last, w_count, count); + } + } + + GPUh() void printSummary() const + { + uint32_t totalROFs{0}; + uint32_t totalVertexRefs{0}; + + for (int32_t i = 0; i < NLayers; ++i) { + const auto& idx = mIndices[i]; + totalROFs += idx.getEntries(); + + for (int32_t j = 0; j < idx.getEntries(); ++j) { + const auto& entry = mFlatTable[idx.getFirstEntry() + j]; + totalVertexRefs += entry.getEntries(); + } + } + + const uint32_t totalBytes = (totalROFs * sizeof(TableEntry)) + (NLayers * sizeof(TableIndex)); + LOGF(info, "------------------------------------------------------------"); + LOGF(info, "Total ROFs in table: %u", totalROFs); + LOGF(info, "Total vertex references: %u", totalVertexRefs); + LOGF(info, "Total view size: %u bytes", totalBytes); + LOGF(info, "------------------------------------------------------------"); + } +}; + +// Precalculated lookup table to find vertices compatible with ROFs +// Given a layer and ROF index, returns the range of vertices that overlap in time. +// The vertex time is defined as asymmetrical, it provides the beginning and range +// from the lowest common time bracket (BCs). +// e.g., [beginning, beginning+range) +template +class ROFVertexLookupTable : public LayerTimingBase +{ + public: + using T = LayerTimingBase::T; + using BCType = LayerTiming::BCType; + using TableEntry = dataformats::RangeReference; + using TableIndex = dataformats::RangeReference; + + using View = ROFVertexLookupTableView; + + GPUdDefault() ROFVertexLookupTable() = default; + + GPUh() size_t getFlatTableSize() const noexcept { return mFlatTable.size(); } + static GPUh() constexpr size_t getIndicesSize() { return NLayers; } + + // Build the lookup table given a sorted array of vertices + // vertices must be sorted by timestamp, then by error (secondary) + GPUh() void init(const Vertex* vertices, size_t nVertices) + { + if (nVertices > std::numeric_limits::max()) { + LOGF(fatal, "too many vertices %zu, max supported is %u", nVertices, std::numeric_limits::max()); + } + + std::vector table[NLayers]; + for (int32_t layer{0}; layer < NLayers; ++layer) { + buildMapping(layer, vertices, nVertices, table[layer]); + } + flatten(table); + } + + // Pre-allocated needed memory, then use update(...) + GPUh() void init() + { + size_t total{0}; + for (int32_t layer{0}; layer < NLayers; ++layer) { + total += this->mLayers[layer].mNROFsTF; + } + mFlatTable.resize(total, {0, 0}); + size_t offset = 0; + for (int32_t layer{0}; layer < NLayers; ++layer) { + size_t nROFs = this->mLayers[layer].mNROFsTF; + mIndices[layer].setFirstEntry(static_cast(offset)); + mIndices[layer].setEntries(static_cast(nROFs)); + offset += nROFs; + } + mNeedsUpdate = true; + } + + GPUh() bool needsUpdate() const noexcept { return mNeedsUpdate; } + + // Recalculate lookup table with new vertices + GPUh() void update(const Vertex* vertices, size_t nVertices) + { + size_t offset = 0; + for (int32_t layer{0}; layer < NLayers; ++layer) { + const auto& idx = mIndices[layer]; + size_t nROFs = idx.getEntries(); + for (size_t iROF = 0; iROF < nROFs; ++iROF) { + updateROFMapping(layer, iROF, vertices, nVertices, offset + iROF); + } + offset += nROFs; + } + mNeedsUpdate = true; + } + + GPUh() View getView() const + { + View view; + view.mFlatTable = mFlatTable.data(); + view.mIndices = mIndices; + view.mLayers = this->mLayers; + return view; + } + + GPUh() View getDeviceView(const TableEntry* deviceFlatTablePtr, const TableIndex* deviceIndicesPtr, const LayerTiming* deviceLayerTimingPtr) const + { + View view; + view.mFlatTable = deviceFlatTablePtr; + view.mIndices = deviceIndicesPtr; + view.mLayers = deviceLayerTimingPtr; + return view; + } + + private: + // Build the mapping for one layer + GPUh() void buildMapping(int32_t layer, const Vertex* vertices, size_t nVertices, std::vector& table) + { + const auto& layerDef = this->mLayers[layer]; + table.resize(layerDef.mNROFsTF); + + size_t vertexSearchStart = 0; + + for (int32_t iROF{0}; iROF < layerDef.mNROFsTF; ++iROF) { + BCType rofStart = layerDef.mROFDelay + (iROF * layerDef.mROFLength); + BCType rofEnd = rofStart + layerDef.mROFLength; + rofStart -= layerDef.mROFDelta; + rofEnd += layerDef.mROFDelta; + size_t firstVertex = binarySearchFirst(vertices, nVertices, vertexSearchStart, rofStart); + size_t lastVertex = firstVertex; + while (lastVertex < nVertices && vertices[lastVertex].getTimeStamp().getTimeStamp() < rofEnd) { + ++lastVertex; + } + size_t count = (lastVertex > firstVertex) ? (lastVertex - firstVertex) : 0; + table[iROF] = {static_cast(firstVertex), static_cast(count)}; + vertexSearchStart = firstVertex; + } + } + + // Update a single ROF's vertex mapping + GPUh() void updateROFMapping(int32_t layer, size_t iROF, const Vertex* vertices, size_t nVertices, size_t flatTableIdx) + { + const auto& layerDef = this->mLayers[layer]; + BCType rofStart = layerDef.mROFDelay + (iROF * layerDef.mROFLength); + BCType rofEnd = rofStart + layerDef.mROFLength; + rofStart -= layerDef.mROFDelta; + rofEnd += layerDef.mROFDelta; + size_t firstVertex = binarySearchFirst(vertices, nVertices, 0, rofStart); + size_t lastVertex = firstVertex; + while (lastVertex < nVertices && static_cast(vertices[lastVertex].getTimeStamp().getTimeStamp()) < rofEnd) { + ++lastVertex; + } + size_t count = (lastVertex > firstVertex) ? (lastVertex - firstVertex) : 0; + mFlatTable[flatTableIdx].setFirstEntry(static_cast(firstVertex)); + mFlatTable[flatTableIdx].setEntries(static_cast(count)); + } + + // Binary search for first vertex where maxBC >= targetBC + GPUh() size_t binarySearchFirst(const Vertex* vertices, size_t nVertices, size_t searchStart, BCType targetBC) const + { + size_t left = searchStart; + size_t right = nVertices; + + while (left < right) { + size_t mid = left + ((right - left) / 2); + if (static_cast(vertices[mid].getTimeStamp().getTimeStamp() + vertices[mid].getTimeStamp().getTimeStampError()) <= targetBC) { + left = mid + 1; + } else { + right = mid; + } + } + + return left; + } + + // Compress the temporary table into a single flat table + GPUh() void flatten(const std::vector table[NLayers]) + { + // Count total entries + size_t total{0}; + for (int32_t i{0}; i < NLayers; ++i) { + total += table[i].size(); + } + + mFlatTable.reserve(total); + + // Build flat table and indices + for (int32_t i{0}; i < NLayers; ++i) { + mIndices[i].setFirstEntry(static_cast(mFlatTable.size())); + mIndices[i].setEntries(static_cast(table[i].size())); + mFlatTable.insert(mFlatTable.end(), table[i].begin(), table[i].end()); + } + } + + bool mNeedsUpdate{false}; + TableIndex mIndices[NLayers]; + std::vector mFlatTable; +}; + +// GPU friendly view of the table below +template +struct ROFTimeSliceTableView { + const BCRange* mFlatTable{nullptr}; + const uint8_t* mFlatMask{nullptr}; + const int32_t* mLayerROFOffsets{nullptr}; + const LayerTiming* mLayers{nullptr}; + int32_t mSlices{0}; + + GPUhdi() const uint8_t* getMask(int32_t layer, int32_t slice) const + { + assert(layer < NLayers); + assert(slice < mSlices); + const auto& range = getSlice(layer, slice); + return &mFlatMask[mLayerROFOffsets[layer] + range.getFirstEntry()]; + } + + // Get the ROF range for a given layer and slice + GPUhdi() ROFRange getROFSlice(int32_t layer, int32_t slice) const + { + const auto& bcSlices = getSlice(layer, slice); + const auto rofIdStart = mLayers[layer].getROFIdForBC(bcSlices.getFirstEntry()); + const auto rofIdEnd = mLayers[layer].getROFIdForBC(bcSlices.getEntriesBound()); + assert(rofIdEnd <= mLayers[layer].mNROFsTF); + return {rofIdStart, rofIdEnd - rofIdStart}; + } + + // Get the BC range for a given layer and slice + GPUhdi() const BCRange& getSlice(int32_t layer, int32_t slice) const + { + assert(layer < NLayers); + assert(slice < mSlices); + return mFlatTable[(layer * mSlices) + slice]; + } + + // Check if a BC falls within a specific slice + GPUhdi() bool isInSlice(int32_t layer, int32_t slice, int32_t bc) const + { + const auto& range = getSlice(layer, slice); + int32_t start = range.getFirstEntry(); + int32_t end = range.getEntriesBound(); + return bc >= start && bc < end; + } + + // Find which slice a BC belongs to (returns -1 if not found) + GPUhdi() int32_t findSlice(int32_t layer, int32_t bc) const + { + assert(layer < NLayers); + int32_t left = 0; + int32_t right = mSlices - 1; + + while (left <= right) { + int32_t mid = left + ((right - left) / 2); + const auto& range = getSlice(layer, mid); + int32_t start = range.getFirstEntry(); + int32_t end = range.getEntriesBound(); + + if (bc < start) { + right = mid - 1; + } else if (bc >= end) { + left = mid + 1; + } else { + return mid; + } + } + return -1; + } + + GPUh() void printAll() const + { + for (int32_t i = 0; i < NLayers; ++i) { + printLayer(i); + } + } + + GPUh() void printLayer(int32_t layer) const + { + constexpr int w_slice = 10; + constexpr int w_start = 12; + constexpr int w_end = 12; + constexpr int w_range = 10; + constexpr int w_rofs = 12; + constexpr int w_active = 12; + LOGF(info, "Slice table: Layer %d", layer); + LOGF(info, "%*s | %*s | %*s | %*s | %*s | %*s", w_slice, "Slice", w_start, "BC.Start", w_end, "BC.End", w_range, "Range", w_rofs, "ROFs", w_active, "ActiveROFs"); + LOGF(info, "%.*s-+-%.*s-+-%.*s-+-%.*s-+-%.*s-+-%.*s", w_slice, "----------", w_start, "------------", w_end, "------------", w_range, "----------", w_rofs, "----------", w_active, "------------"); + for (int32_t i = 0; i < mSlices; ++i) { + const auto& range = getSlice(layer, i); + int32_t start = range.getFirstEntry(); + int32_t rangeLen = range.getEntries(); + int32_t end = range.getEntriesBound(); + const auto& rofRange = getROFSlice(layer, i); + + // Count active ROFs in this slice + const uint8_t* mask = getMask(layer, i); + int32_t activeCount = 0; + for (int32_t j = 0; j < rangeLen; ++j) { + activeCount += mask[j]; + } + + LOGF(info, "%*d | %*d | %*d | %*d | %*d-%d | %*d/%d", w_slice, i, w_start, start, w_end, end, w_range, rangeLen, w_rofs, rofRange.getFirstEntry(), rofRange.getEntriesBound(), w_active, activeCount, rangeLen); + } + } +}; + +template +class ROFTimeSliceTable : public LayerTimingBase +{ + public: + using ROFRange = LayerTiming::ROFRange; + using BCRange = dataformats::RangeReference; + using View = ROFTimeSliceTableView; + + GPUdDefault() ROFTimeSliceTable() = default; + + GPUh() void init(int32_t nSlices) + { + if (nSlices < 1) { + LOGP(fatal, "Using {} time slices makes no sense", nSlices); + } + mSlices = nSlices; + std::vector table[NLayers]; + int32_t totalROFs = 0; + for (int32_t layer{0}; layer < NLayers; ++layer) { + buildSlices(layer, table[layer]); + mLayerROFOffsets[layer] = totalROFs; + totalROFs += this->getLayer(layer).mNROFsTF; + } + mFlatMask.resize(totalROFs, 1); + flatten(table); + mNeedsUpdate = true; + } + + GPUh() size_t getFlatTableSize() const noexcept { return mFlatTable.size(); } + GPUh() size_t getFlatMaskSize() const noexcept { return mFlatMask.size(); } + + GPUh() bool needsUpdate() const noexcept { return mNeedsUpdate; } + + GPUh() void selectROFs(const std::vector& ts) + { + resetMask(); + for (const auto& t : ts) { + selectROFs(t.getFirstEntry(), t.getEntriesBound()); + } + } + + GPUh() void selectROFs(int32_t bcStart, int32_t bcEnd) + { + for (int32_t layer{0}; layer < NLayers; ++layer) { + const auto& lay = this->getLayer(layer); + int32_t offset = mLayerROFOffsets[layer]; + for (int32_t rofId{0}; rofId < lay.mNROFsTF; ++rofId) { + auto bounds = lay.getROFTimeBounds(rofId); + int32_t rofStart = bounds.getFirstEntry(); + int32_t rofEnd = bounds.getEntriesBound(); + bool isCompatible = rofStart < bcEnd && rofEnd > bcStart; + mFlatMask[offset + rofId] = isCompatible ? 1 : 0; + } + } + mNeedsUpdate = true; + } + + GPUh() void resetMask(int32_t s = 1) + { + std::memset(mFlatMask.data(), s, mFlatMask.size()); + mNeedsUpdate = true; + } + + GPUh() void invertMask() + { + std::ranges::transform(mFlatMask, mFlatMask.begin(), [](uint8_t x) { return 1 - x; }); + mNeedsUpdate = true; + } + + GPUh() View getView() const + { + View view; + view.mFlatTable = mFlatTable.data(); + view.mFlatMask = mFlatMask.data(); + view.mLayerROFOffsets = mLayerROFOffsets; + view.mLayers = this->mLayers; + view.mSlices = mSlices; + return view; + } + + GPUh() View getDeviceView(const ROFRange* deviceFlatTablePtr, const uint8_t* deviceFlatMaskPtr, const int32_t* deviceOffsetPtr, const LayerTiming* deviceLayerTimingPtr) const + { + View view; + view.mFlatTable = deviceFlatTablePtr; + view.mFlatMask = deviceFlatMaskPtr; + view.mLayerROFOffsets = deviceOffsetPtr; + view.mLayers = deviceLayerTimingPtr; + view.mSlices = mSlices; + return view; + } + + private: + GPUh() void buildSlices(int32_t layer, std::vector& table) + { + table.reserve(mSlices); + const auto& lay = this->getLayer(layer); + int32_t nBCsPerTF = (lay.mNROFsTF * lay.mROFLength); + for (int32_t iSlice{0}; iSlice < mSlices; ++iSlice) { + int32_t bcStart = (iSlice * nBCsPerTF) / mSlices; + int32_t bcEnd = (((iSlice + 1) * nBCsPerTF) / mSlices) + 1; + table.emplace_back(bcStart, bcEnd - bcStart); + } + } + + GPUh() void flatten(const std::vector table[NLayers]) + { + auto total = static_cast(mSlices * NLayers); + mFlatTable.reserve(total); + for (int32_t layer = 0; layer < NLayers; ++layer) { + mFlatTable.insert(mFlatTable.end(), table[layer].begin(), table[layer].end()); + } + } + + bool mNeedsUpdate{false}; + int32_t mSlices{0}; + int32_t mLayerROFOffsets[NLayers]{}; + std::vector mFlatTable; + std::vector mFlatMask; +}; + +} // namespace o2::its + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Seeding.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Seeding.h new file mode 100644 index 0000000000000..6e8b6e2afbc48 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Seeding.h @@ -0,0 +1,376 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef TRACKINGITSU_INCLUDE_SEEDING_H_ +#define TRACKINGITSU_INCLUDE_SEEDING_H_ + +#include +#include +#include + +#include +#include +#include + +#include "Framework/Logger.h" +#include "ReconstructionDataFormats/Track.h" +#include "CommonDataFormat/RangeReference.h" +#include "ITStracking/Definitions.h" +#include "ITStracking/Constants.h" +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" + +namespace o2::its +{ + +using LTRef = dataformats::RangeReference; + +// Linearized track parametrisation near a vertex +// follows the definition of the pvertexer +struct LinearizedTrack { + enum Status : uint8_t { + kDead = (1 << 0), + }; + GPUhdDefault() LinearizedTrack() = default; + GPUhd() LinearizedTrack(const o2::track::TrackParCov& trk, int32_t cell) : cellIdx(cell), x(trk.getX()), y(trk.getY()), z(trk.getZ()), tgL(trk.getTgl()), tgP(trk.getSnp() / o2::gpu::CAMath::Sqrt(1.f - trk.getSnp()) * (1.f + trk.getSnp())) + { + o2::gpu::CAMath::SinCos(trk.getAlpha(), sinAlp, cosAlp); + const float syy = trk.getSigmaY2(), szz = trk.getSigmaZ2(), syz = trk.getSigmaZY(); + const float det = (syy * szz) - (syz * syz); + if (det <= constants::Tolerance) { + markDead(); + return; + } + const float detI = 1.f / det; + sig2YI = szz * detI; + sig2ZI = syy * detI; + sigYZI = -syz * detI; + } + + float getChi2(const dataformats::VertexBase&) const; + + int32_t cellIdx{-1}; ///< index of attached cell + float x{0.f}; ///< reference X + float y{0.f}; ///< Y at X + float z{0.f}; ///< Z at X + float sig2YI{0.f}; ///< YY component of inverse cov.matrix + float sig2ZI{0.f}; ///< ZZ component of inverse cov.matrix + float sigYZI{0.f}; ///< YZ component of inverse cov.matrix + float tgP{0.f}; ///< tangent(phi) in tracking frame + float tgL{0.f}; ///< tangent(lambda) + float cosAlp{0.f}; ///< cos of alpha frame + float sinAlp{0.f}; ///< sin of alpha frame + TimeEstBC time; ///< timestamp; exclusive range of BCs that are spanned [time, time+error) + uint8_t status{0}; ///< status bits + + GPUhdi() void markDead() noexcept { status |= kDead; } + GPUhdi() bool isDead() const noexcept { return ((status & kDead) == kDead) || cellIdx < 0; } + + GPUh() void print() const + { + LOGP(info, "LT: cell={} x={} y={} z={} t={}+{} status={:b}", cellIdx, x, y, z, time.getTimeStamp(), time.getTimeStampError(), status); + } + + ClassDefNV(LinearizedTrack, 1); +}; + +struct VertexSeed : public Vertex { + enum FitStatus : uint8_t { + kKilled, + kConverged, + kIterateFirst, + kIterateFurther, + kIterateRelaxScale, + }; + uint8_t status = kIterateFirst; // current fit status + uint8_t iteration = 0; // current iteration + int32_t idx = -1; // db cluster index + float wghSum = 0.f; // sum of tracks weights + float wghChi2 = 0.f; // sum of tracks weighted chi2's + float scaleSig2ITuk2I = 0.f; // inverted scaled tukey weight + float tukeyC = 0.f; // tukey constant + float wghMin = 0.f; // minimum weight to account track + ROOT::Math::SMatrix> C; // C matrix + ROOT::Math::SVector b; // b vector + + void updateTukeyScale(const LinearizedTrack*, const int*, const LTRef&); + void resetForNewIteration(); + bool acceptTrack(const LinearizedTrack&); + void accountTrack(const LinearizedTrack&); + void solveVertex(); +}; + +namespace dbscan +{ + +// Do a scan in z and time +constexpr int32_t NDim{2}; + +// Configuration parameters +struct DBSCANParams { + std::array eps; // Maximum distance per dimension (z,t) + int32_t minPts; // Minimum points to form a dense region +}; + +// Clustering result +struct DBSCANResult { + std::vector labels; + std::vector zCentroids; + std::vector ranges; + int32_t nClusters = 0; + int32_t nNoise = 0; +}; + +// Neighbor list +using NeighborList = std::vector>; + +// Point classification +constexpr int32_t DB_NOISE = -1; +constexpr int32_t DB_UNVISITED = -2; + +// #define ITS_DB_MEASURE_TIMING +#ifdef ITS_DB_MEASURE_TIMING +class ScopedTimer +{ + std::string_view name; + std::chrono::high_resolution_clock::time_point start; + + public: + ScopedTimer(const ScopedTimer&) = default; + ScopedTimer(ScopedTimer&&) = delete; + ScopedTimer& operator=(const ScopedTimer&) = default; + ScopedTimer& operator=(ScopedTimer&&) = delete; + explicit ScopedTimer(std::string_view name) + : name(name), start(std::chrono::high_resolution_clock::now()) {} + + ~ScopedTimer() + { + auto end = std::chrono::high_resolution_clock::now(); + double elapsed_ms = std::chrono::duration(end - start).count(); + LOGP(info, "{} : {:.2f} ms", name, elapsed_ms); + } +}; +#define SCOPED_TIMER(name) ScopedTimer _timer##__LINE__(name) +#else +#define SCOPED_TIMER(name) ((void)0) +#endif + +class DBSCANDistance +{ + using EPS = decltype(DBSCANParams::eps); + + public: + DBSCANDistance() = default; + DBSCANDistance(const EPS& eps) : mEps(eps) {} + + // Check if two linearized tracks are neighbors using L-infinity distance + // Returns true if ALL dimensions are within their respective thresholds + // Important to remember is that time is given as an asymmetric bracket + bool areNeighbours(const LinearizedTrack& l0, const LinearizedTrack& l1) const + { + if (l0.isDead() || l1.isDead()) { + return false; // dead tracks can never be neighbors of anything + } + const float diffZ = o2::gpu::CAMath::Abs(l0.z - l1.z); + if (diffZ > mEps[0]) { + return false; + } + return isTimeCompatible(l0, l1); + } + + float getDistance(const LinearizedTrack& l0, const LinearizedTrack& l1) const + { + if (l0.isDead() || l1.isDead()) { + return std::numeric_limits::max(); + } + if (isTimeCompatible(l0, l1)) { + return std::numeric_limits::max(); + } + return o2::gpu::CAMath::Abs(l0.z - l1.z); + } + + private: + bool isTimeCompatible(const LinearizedTrack& l0, const LinearizedTrack& l1) const + { + const auto end0 = l0.time.getTimeStamp() + l0.time.getTimeStampError(); + const auto end1 = l1.time.getTimeStamp() + l1.time.getTimeStampError(); + const int diffT = o2::gpu::CAMath::Max(0, o2::gpu::CAMath::Max((int)l0.time.getTimeStamp(), (int)l1.time.getTimeStamp())) - (int)o2::gpu::CAMath::Min(end0, end1); + return diffT <= (int)mEps[1]; + } + + EPS mEps; +}; + +class DBSCAN +{ + public: + DBSCAN() = default; + DBSCAN(const DBSCANParams& p); + + DBSCANResult cluster(const LinearizedTrack* tracks, size_t n) const; + + const auto& getParams() const { return mParams; } + const auto& getDistance() const { return mDistance; } + + private: + void findNeighbors(const LinearizedTrack* tracks, size_t n, NeighborList& neighbors) const; + void classify(size_t n, const NeighborList& neighbors, std::vector& labels) const; + void finalize(const LinearizedTrack* tracks, size_t n, DBSCANResult& result) const; + + DBSCANParams mParams; + DBSCANDistance mDistance; +}; + +// Grid cell for spatial partitioning +using GridCell = std::vector; +// Grid coordinates +using GridCoord = std::array; +/// General index grid +class Grid +{ + public: + Grid(const LinearizedTrack* tracks, size_t n, const std::array& cellSizes) + : mTracks(tracks), mNPoints(n), mCellSizes(cellSizes) + { + SCOPED_TIMER("Grid construction"); + computeBounds(); + computeGridDimensions(); + allocateCells(); + assignCells(); + } + + // Get grid coordinates for a point + [[nodiscard]] GridCoord getGridCoords(size_t idx) const + { + GridCoord coords{}; + const auto& trk = mTracks[idx]; + // z + coords[0] = static_cast((trk.z - mMinBounds[0]) / mCellSizes[0]); + coords[0] = std::clamp(coords[0], 0, static_cast(mGridDims[0]) - 1); + // time + coords[1] = static_cast(((trk.time.getTimeStamp() + (trk.time.getTimeStampError() / 2)) - mMinBounds[1]) / mCellSizes[1]); + coords[1] = std::clamp(coords[1], 0, static_cast(mGridDims[1]) - 1); + return coords; + } + + // Get flat index from grid coordinates + [[nodiscard]] size_t getCellIndex(const GridCoord& coords) const + { + int32_t index = 0, stride = 1; +#pragma unroll(NDim) + for (size_t d = 0; d < NDim; ++d) { + index += coords[d] * stride; + stride *= mGridDims[d]; + } + return static_cast(index); + } + + // Get cell at grid coordinates + [[nodiscard]] const GridCell* getCell(const GridCoord& coords) const + { +#pragma unroll(NDim) + for (size_t d = 0; d < NDim; ++d) { + if (coords[d] < 0 || coords[d] >= static_cast(mGridDims[d])) { + return nullptr; + } + } + return &mCells[getCellIndex(coords)]; + } + + // Get neighboring cells (including the cell itself) + void getNeighborCells(const GridCoord& coords, std::vector& neighbors) const + { + neighbors.clear(); + neighbors.reserve(static_cast(std::pow(3, NDim))); + GridCoord offset{}; + enumerateNeighborOffsets<0>(coords, offset, neighbors); + } + + private: + template + void enumerateNeighborOffsets(const GridCoord& base, GridCoord& offset, std::vector& output) const + { + if constexpr (Dim == NDim) { + GridCoord nbr; +#pragma unroll(NDim) + for (size_t d = 0; d < NDim; ++d) { + nbr[d] = base[d] + offset[d]; + } + const GridCell* cell = getCell(nbr); + if (cell) { + output.push_back(cell); + } + return; + } else { + for (int32_t v = -1; v <= 1; ++v) { + offset[Dim] = v; + enumerateNeighborOffsets(base, offset, output); + } + } + } + + void computeBounds() + { + mMinBounds.fill(std::numeric_limits::max()); + mMaxBounds.fill(std::numeric_limits::lowest()); + for (size_t i{0}; i < mNPoints; ++i) { + const auto& trk = mTracks[i]; + // z + mMinBounds[0] = std::min(mMinBounds[0], trk.z); + mMaxBounds[0] = std::max(mMaxBounds[0], trk.z); + // time + mMinBounds[1] = std::min(mMinBounds[1], (float)trk.time.getTimeStamp()); + mMaxBounds[1] = std::max(mMaxBounds[1], (float)(trk.time.getTimeStamp() + (trk.time.getTimeStampError() / 2))); + } + } + + void computeGridDimensions() + { + mGridDims.fill(1); +#pragma unroll(NDim) + for (size_t d = 0; d < NDim; ++d) { + float range = mMaxBounds[d] - mMinBounds[d]; + mGridDims[d] = std::max(size_t(1), static_cast(std::ceil(range / mCellSizes[d]))); + } + } + + void allocateCells() + { + auto total_cells = static_cast(mGridDims[0] * mGridDims[1]); + mCells.resize(total_cells); + } + + void assignCells() + { + for (size_t i = 0; i < mNPoints; ++i) { + mCells[getCellIndex(getGridCoords(i))].push_back(i); + } + tbb::parallel_for(size_t(0), mCells.size(), [&](size_t c) { + std::sort(mCells[c].begin(), mCells[c].end(), [&](size_t a, size_t b) { + return mTracks[a].z < mTracks[b].z; + }); + }); + } + + const LinearizedTrack* mTracks; + size_t mNPoints; + std::array mCellSizes; + std::array mMinBounds{}; + std::array mMaxBounds{}; + std::array mGridDims{}; + std::vector mCells; +}; + +} // namespace dbscan + +} // namespace o2::its + +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h deleted file mode 100644 index 101f4b8d72601..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Smoother.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -/// \file Smoother.h -/// \brief Class to handle Kalman smoothing for ITS tracking. -/// Its instance stores the state of the track to the level we want to smooth to avoid multiple re-propagations when testing different clusters. -/// - -#include "ReconstructionDataFormats/Track.h" -#include "DataFormatsITS/TrackITS.h" -#include "DetectorsBase/Propagator.h" - -namespace o2 -{ -namespace its -{ - -template -class Smoother -{ - public: - // Smoother(TrackITSExt& track, size_t layer, const ROframe& event, float bZ, o2::base::PropagatorF::MatCorrType corr); - ~Smoother(); - - bool isValidInit() const - { - return mInitStatus; - } - // bool testCluster(const int clusterId, const ROframe& event); - bool getSmoothedTrack(); - float getChi2() const { return mBestChi2; } - float getLastChi2() const { return mLastChi2; } - - private: - float computeSmoothedPredictedChi2(const o2::track::TrackParCov& outwTrack, - const o2::track::TrackParCov& inwTrack, - const std::array& cls, - const std::array& clCov); - bool smoothTrack(); - - private: - size_t mLayerToSmooth; // Layer to compute smoothing optimization - float mBz; // Magnetic field along Z - bool mInitStatus; // State after the initialization - o2::base::PropagatorF::MatCorrType mCorr; // Type of correction to use - TrackITSExt mInwardsTrack; // outwards track: from innermost cluster to outermost - TrackITSExt mOutwardsTrack; // inwards track: from outermost cluster to innermost - float mBestChi2; // Best value of local smoothed chi2 - float mLastChi2 = 1e8; // Latest computed chi2 -}; -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h index 4dbb9f09f6192..32626816a95c8 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -14,30 +14,28 @@ #define TRACKINGITSU_INCLUDE_TIMEFRAME_H_ #include +#include #include #include #include #include #include -#include "DataFormatsITS/TrackITS.h" - #include "ITStracking/Cell.h" #include "ITStracking/Cluster.h" #include "ITStracking/Configuration.h" -#include "ITStracking/Constants.h" -#include "ITStracking/ClusterLines.h" #include "ITStracking/Definitions.h" #include "ITStracking/Road.h" #include "ITStracking/Tracklet.h" #include "ITStracking/IndexTableUtils.h" #include "ITStracking/ExternalAllocator.h" #include "ITStracking/BoundedAllocator.h" +#include "ITStracking/ROFLookupTables.h" +#include "DataFormatsITS/TrackITS.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" - -#include "ReconstructionDataFormats/Vertex.h" #include "DetectorsBase/Propagator.h" +#include "DataFormatsCalibration/MeanVertexObject.h" namespace o2 { @@ -48,7 +46,6 @@ class GPUChainITS; namespace itsmft { -class Cluster; class CompClusterExt; class TopologyDictionary; class ROFRecord; @@ -62,58 +59,53 @@ template class TimeFrameGPU; } -template +template struct TimeFrame { - using IndexTableUtilsN = IndexTableUtils; - using CellSeedN = CellSeed; - friend class gpu::TimeFrameGPU; + using IndexTableUtilsN = IndexTableUtils; + using ROFOverlapTableN = ROFOverlapTable; + using ROFVertexLookupTableN = ROFVertexLookupTable; + using ROFTimeSliceTableN = ROFTimeSliceTable; + using CellSeedN = CellSeed; + friend class gpu::TimeFrameGPU; TimeFrame() = default; + TimeFrame(const TimeFrame&) = delete; + TimeFrame(TimeFrame&&) = delete; + TimeFrame& operator=(const TimeFrame&) = delete; + TimeFrame& operator=(TimeFrame&&) = delete; virtual ~TimeFrame() = default; + void initialise(const RecoIteration& reco); + const Vertex& getPrimaryVertex(const int ivtx) const { return mPrimaryVertices[ivtx]; } - gsl::span getPrimaryVertices(int rofId) const; - gsl::span getPrimaryVertices(int romin, int romax) const; - gsl::span> getPrimaryVerticesMCRecInfo(const int rofId) const; - gsl::span getPrimaryVerticesContributors(const int rofId) const; - gsl::span> getPrimaryVerticesXAlpha(int rofId) const; + auto& getPrimaryVertices() { return mPrimaryVertices; }; + auto getPrimaryVerticesNum() { return mPrimaryVertices.size(); }; + const auto& getPrimaryVertices() const { return mPrimaryVertices; }; + auto& getPrimaryVerticesLabels() { return mPrimaryVerticesLabels; }; + gsl::span getPrimaryVertices(int layer, int rofId) const; + gsl::span> getPrimaryVerticesXAlpha(int layer, int rofId) const; void fillPrimaryVerticesXandAlpha(); - int getPrimaryVerticesNum(int rofId = -1) const; - void addPrimaryVerticesLabels(bounded_vector>& labels); - void addPrimaryVerticesContributorLabels(bounded_vector& labels); - void addPrimaryVertices(const bounded_vector& vertices, const int iteration); - void addPrimaryVerticesInROF(const bounded_vector& vertices, const int rofId, const int iteration); - void addPrimaryVerticesLabelsInROF(const bounded_vector>& labels, const int rofId); - void addPrimaryVerticesContributorLabelsInROF(const bounded_vector& labels, const int rofId); - void removePrimaryVerticesInROf(const int rofId); + void addPrimaryVertex(const Vertex& vertex) { mPrimaryVertices.emplace_back(vertex); } + void addPrimaryVertexLabel(const VertexLabel& label) { mPrimaryVerticesLabels.push_back(label); } + int loadROFrameData(const o2::itsmft::ROFRecord& rof, gsl::span clusters, const dataformats::MCTruthContainer* mcLabels = nullptr); - int loadROFrameData(gsl::span rofs, - gsl::span clusters, - gsl::span::iterator& pattIt, - const itsmft::TopologyDictionary* dict, - const dataformats::MCTruthContainer* mcLabels = nullptr); - void resetROFrameData(size_t nROFs); - void prepareROFrameData(gsl::span rofs, - gsl::span clusters); + void loadROFrameData(gsl::span rofs, + gsl::span clusters, + gsl::span::iterator& pattIt, + const itsmft::TopologyDictionary* dict, + int layer, + const dataformats::MCTruthContainer* mcLabels = nullptr); + void resetROFrameData(int iLayer); + void prepareROFrameData(gsl::span clusters, int layer); int getTotalClusters() const; - auto& getTotVertIteration() { return mTotVertPerIteration; } - bool empty() const { return getTotalClusters() == 0; } + int getTotalClustersPerROFrange(int rofMin, int range, int layerId) const; int getSortedIndex(int rofId, int layer, int idx) const { return mROFramesClusters[layer][rofId] + idx; } int getSortedStartIndex(const int rofId, const int layer) const { return mROFramesClusters[layer][rofId]; } - int getNrof() const { return mNrof; } + int getNrof(int layer) const { return mROFramesClusters[layer].size() - 1; } - void resetBeamXY(const float x, const float y, const float w = 0); - void setBeamPosition(const float x, const float y, const float s2, const float base = 50.f, const float systematic = 0.f) - { - isBeamPositionOverridden = true; - resetBeamXY(x, y, s2 / o2::gpu::CAMath::Sqrt(base * base + systematic)); - } - - float getBeamX() const { return mBeamPos[0]; } - float getBeamY() const { return mBeamPos[1]; } auto& getMinRs() { return mMinR; } auto& getMaxRs() { return mMaxR; } float getMinR(int layer) const { return mMinR[layer]; } @@ -125,114 +117,115 @@ struct TimeFrame { float getPositionResolution(int layer) const { return mPositionResolution[layer]; } auto& getPositionResolutions() { return mPositionResolution; } + // seeding vertex constraint or current best estimate + void setMeanVertex(const dataformats::MeanVertexObject* mv, float extraErr2 = 0.f); + const dataformats::MeanVertexObject* getMeanVertexConstraint() const { return mMeanVertex; } + auto& getMeanVertexRolling() { return mRollingVertex; } + const dataformats::VertexBase& getMeanVertex() const { return (hasMeanVertex()) ? mMeanVertex->getMeanVertex() : mRollingVertex; } + const auto& getMeanVertexInvErr() const { return mMeanVertexXYInvErr; } + bool hasMeanVertex() const noexcept { return mMeanVertex != nullptr; } + + auto& getClusterLabelsContainer() { return mClusterLabels; } gsl::span getClustersOnLayer(int rofId, int layerId); gsl::span getClustersOnLayer(int rofId, int layerId) const; gsl::span getClustersPerROFrange(int rofMin, int range, int layerId) const; gsl::span getUnsortedClustersOnLayer(int rofId, int layerId) const; gsl::span getUsedClustersROF(int rofId, int layerId); gsl::span getUsedClustersROF(int rofId, int layerId) const; - gsl::span getROFramesClustersPerROFrange(int rofMin, int range, int layerId) const; + auto& getROFrameClusters(int layerId, int rofId) { return mROFramesClusters[layerId][rofId]; } gsl::span getROFrameClusters(int layerId) const; + gsl::span getROFramesClustersPerROFrange(int rofMin, int range, int layerId) const; gsl::span getNClustersROFrange(int rofMin, int range, int layerId) const; gsl::span getIndexTablePerROFrange(int rofMin, int range, int layerId) const; gsl::span getIndexTable(int rofId, int layerId); - auto& getIndexTableWhole(int layerId) { return mIndexTables[layerId]; } const auto& getTrackingFrameInfoOnLayer(int layerId) const { return mTrackingFrameInfo[layerId]; } - const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; - gsl::span getClusterLabels(int layerId, const Cluster& cl) const { return getClusterLabels(layerId, cl.clusterId); } - gsl::span getClusterLabels(int layerId, const int clId) const { return mClusterLabels->getLabels(mClusterExternalIndices[layerId][clId]); } - int getClusterExternalIndex(int layerId, const int clId) const { return mClusterExternalIndices[layerId][clId]; } - int getClusterSize(int clusterId) const { return mClusterSize[clusterId]; } - void setClusterSize(bounded_vector& v) { mClusterSize = std::move(v); } - - auto& getTrackletsLabel(int layer) { return mTrackletLabels[layer]; } - auto& getCellsLabel(int layer) { return mCellLabels[layer]; } - - bool hasMCinformation() const { return mClusterLabels; } - void initialise(const int iteration, const TrackingParameters& trkParam, const int maxLayers = 7, bool resetVertices = true); - void resetRofPV() + // navigation tables + const auto& getIndexTableUtils() const { return mIndexTableUtils; } + const auto& getROFOverlapTable() const { return mROFOverlapTable; } + const auto& getROFOverlapTableView() const { return mROFOverlapTableView; } + void setROFOverlapTable(ROFOverlapTableN& table) { - deepVectorClear(mPrimaryVertices); - mROFramesPV.resize(1, 0); - mTotVertPerIteration.resize(1); + mROFOverlapTable = std::move(table); + mROFOverlapTableView = mROFOverlapTable.getView(); + } + const auto& getROFVertexLookupTable() const { return mROFVertexLookupTable; } + const auto& getROFVertexLookupTableView() const { return mROFVertexLookupTableView; } + void setROFVertexLookupTable(ROFVertexLookupTableN& table) + { + mROFVertexLookupTable = std::move(table); + mROFVertexLookupTableView = mROFVertexLookupTable.getView(); + } + void updateROFVertexLookupTable() { mROFVertexLookupTable.update(mPrimaryVertices.data(), mPrimaryVertices.size()); } + const auto& getROFTimeSliceTable() const { return mROFTimeSliceTable; } + const auto& getROFTimeSliceTableView() const { return mROFTimeSliceTableView; } + void setROFTimeSliceTable(ROFTimeSliceTableN& table) + { + mROFTimeSliceTable = std::move(table); + mROFTimeSliceTableView = mROFTimeSliceTable.getView(); } + // cluster information + const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; + gsl::span getClusterLabels(int layerId, const Cluster& cl) const { return getClusterLabels(layerId, cl.clusterId); } + gsl::span getClusterLabels(int layerId, const int clId) const { return mClusterLabels[layerId]->getLabels(mClusterExternalIndices[layerId][clId]); } + int getClusterExternalIndex(int layerId, const int clId) const { return mClusterExternalIndices[layerId][clId]; } + int getClusterSize(int layer, int clusterId) const { return mClusterSize[layer][clusterId]; } + void setClusterSize(int layer, bounded_vector& v) { mClusterSize[layer] = std::move(v); } bool isClusterUsed(int layer, int clusterId) const { return mUsedClusters[layer][clusterId]; } void markUsedCluster(int layer, int clusterId) { mUsedClusters[layer][clusterId] = true; } gsl::span getUsedClusters(const int layer); + auto& getClusters() { return mClusters; } + auto& getUnsortedClusters() { return mUnsortedClusters; } + int getClusterROF(int iLayer, int iCluster); + int getNumberOfClusters(int layer = -1) const; + size_t getNumberOfUsedClusters() const; + template + void addClusterToLayer(int layer, T&&... args); + template + void addTrackingFrameInfoToLayer(int layer, T&&... args); + void addClusterExternalIndexToLayer(int layer, const int idx) { mClusterExternalIndices[layer].push_back(idx); } + // mc information + bool hasMCinformation() const { return mClusterLabels[0] != nullptr; } + + // tracklet information auto& getTracklets() { return mTracklets; } + auto& getTrackletsLabel(int layer) { return mTrackletLabels[layer]; } auto& getTrackletsLookupTable() { return mTrackletsLookupTable; } + virtual int getNumberOfTracklets() const; - auto& getClusters() { return mClusters; } - auto& getUnsortedClusters() { return mUnsortedClusters; } - int getClusterROF(int iLayer, int iCluster); + // cells information auto& getCells() { return mCells; } - + auto& getCellsLabel(int layer) { return mCellLabels[layer]; } auto& getCellsLookupTable() { return mCellsLookupTable; } auto& getCellsNeighbours() { return mCellsNeighbours; } auto& getCellsNeighboursLUT() { return mCellsNeighboursLUT; } - auto& getRoads() { return mRoads; } - auto& getTracks(int rofId) { return mTracks[rofId]; } - auto& getTracksLabel(const int rofId) { return mTracksLabel[rofId]; } - auto& getLinesLabel(const int rofId) { return mLinesLabels[rofId]; } - auto& getVerticesMCRecInfo() { return mVerticesMCRecInfo; } - - int getNumberOfClusters() const; virtual int getNumberOfCells() const; - virtual int getNumberOfTracklets() const; + + // roads information + auto& getRoads() { return mRoads; } virtual int getNumberOfNeighbours() const; - size_t getNumberOfTracks() const; - size_t getNumberOfUsedClusters() const; + + // tracks information + auto& getTracks() { return mTracks; } + auto& getTracksLabel() { return mTracksLabel; } + size_t getNumberOfTracks() const noexcept { return mTracks.size(); }; auto getNumberOfExtendedTracks() const { return mNExtendedTracks; } auto getNumberOfUsedExtendedClusters() const { return mNExtendedUsedClusters; } /// memory management + virtual void wipe(); void setMemoryPool(std::shared_ptr pool); auto& getMemoryPool() const noexcept { return mMemoryPool; } bool checkMemory(unsigned long max) { return getArtefactsMemory() < max; } unsigned long getArtefactsMemory() const; void printArtefactsMemory() const; - /// ROF cuts - int getROFCutClusterMult() const { return mCutClusterMult; }; - int getROFCutVertexMult() const { return mCutVertexMult; }; - int getROFCutAllMult() const { return mCutClusterMult + mCutVertexMult; } - - // Vertexer - void computeTrackletsPerROFScans(); - void computeTracletsPerClusterScans(); - int& getNTrackletsROF(int rofId, int combId) { return mNTrackletsPerROF[combId][rofId]; } - auto& getLines(int rofId) { return mLines[rofId]; } - int getNLinesTotal() const noexcept { return mTotalLines; } - void setNLinesTotal(uint32_t a) noexcept { mTotalLines = a; } - auto& getTrackletClusters(int rofId) { return mTrackletClusters[rofId]; } - gsl::span getFoundTracklets(int rofId, int combId) const; - gsl::span getFoundTracklets(int rofId, int combId); - gsl::span getLabelsFoundTracklets(int rofId, int combId) const; - gsl::span getNTrackletsCluster(int rofId, int combId); - gsl::span getExclusiveNTrackletsCluster(int rofId, int combId); - uint32_t getTotalTrackletsTF(const int iLayer) { return mTotalTracklets[iLayer]; } - int getTotalClustersPerROFrange(int rofMin, int range, int layerId) const; - std::array& getBeamXY() { return mBeamPos; } - unsigned int& getNoVertexROF() { return mNoVertexROF; } - void insertPastVertex(const Vertex& vertex, const int refROFId); - // \Vertexer - - void initialiseRoadLabels(); - void setRoadLabel(int i, const unsigned long long& lab, bool fake); - const unsigned long long& getRoadLabel(int i) const { return mRoadLabels[i].first; } - bool isRoadFake(int i) const { return mRoadLabels[i].second; } - - void setMultiplicityCutMask(const std::vector& cutMask) { mMultiplicityCutMask = cutMask; } - void setROFMask(const std::vector& rofMask) { mROFMask = rofMask; } - void swapMasks() { mMultiplicityCutMask.swap(mROFMask); } - - int hasBogusClusters() const { return std::accumulate(mBogusClusters.begin(), mBogusClusters.end(), 0); } - - void setBz(float bz) { mBz = bz; } - float getBz() const { return mBz; } + int hasBogusClusters() const + { + return std::accumulate(mBogusClusters.begin(), mBogusClusters.end(), 0); + } /// State if memory will be externally managed by the GPU framework ExternalAllocator* mExternalAllocator{nullptr}; @@ -240,378 +233,226 @@ struct TimeFrame { auto getFrameworkAllocator() { return mExternalAllocator; }; void setFrameworkAllocator(ExternalAllocator* ext); bool hasFrameworkAllocator() const noexcept { return mExternalAllocator != nullptr; } - std::pmr::memory_resource* getMaybeFrameworkHostResource(bool forceHost = false) { return (hasFrameworkAllocator() && !forceHost) ? mExtMemoryPool.get() : mMemoryPool.get(); } + std::pmr::memory_resource* getMaybeFrameworkHostResource() { return hasFrameworkAllocator() ? mExtMemoryPool.get() : mMemoryPool.get(); } + + // magnetic field + void setBz(float bz) { mBz = bz; } + float getBz() const { return mBz; } // Propagator const o2::base::PropagatorImpl* getDevicePropagator() const { return mPropagatorDevice; } - virtual void setDevicePropagator(const o2::base::PropagatorImpl*) {}; + virtual void setDevicePropagator(const o2::base::PropagatorImpl* /*unused*/) {}; - template - void addClusterToLayer(int layer, T&&... args); - template - void addTrackingFrameInfoToLayer(int layer, T&&... args); - void addClusterExternalIndexToLayer(int layer, const int idx) { mClusterExternalIndices[layer].push_back(idx); } - - /// Debug and printing - void checkTrackletLUTs(); - void printROFoffsets(); - void printNClsPerROF(); - void printVertices(); - void printTrackletLUTonLayer(int i); - void printCellLUTonLayer(int i); - void printTrackletLUTs(); - void printCellLUTs(); - void printSliceInfo(const int, const int); - - IndexTableUtilsN mIndexTableUtils; + // interface + virtual bool isGPU() const noexcept { return false; } + virtual const char* getName() const noexcept { return "CPU"; } - std::array, nLayers> mClusters; - std::array, nLayers> mTrackingFrameInfo; - std::array, nLayers> mClusterExternalIndices; - std::array, nLayers> mROFramesClusters; - const dataformats::MCTruthContainer* mClusterLabels = nullptr; - std::array, 2> mNTrackletsPerCluster; - std::array, 2> mNTrackletsPerClusterSum; - std::array, nLayers> mNClustersPerROF; - std::array, nLayers> mIndexTables; + private: + void prepareClusters(const TrackingParameters& trkParam, const int maxLayers = NLayers); + + // tf data + std::array, NLayers> mClusters; + std::array, NLayers> mTrackingFrameInfo; + std::array, NLayers> mClusterExternalIndices; + std::array, NLayers> mROFramesClusters; + std::array*, NLayers> mClusterLabels{nullptr}; + std::array, NLayers> mNClustersPerROF; + std::array, NLayers> mIndexTables; std::vector> mTrackletsLookupTable; - std::array, nLayers> mUsedClusters; - int mNrof = 0; + std::array, NLayers> mUsedClusters; int mNExtendedTracks{0}; int mNExtendedUsedClusters{0}; - bounded_vector mROFramesPV; bounded_vector mPrimaryVertices; + bounded_vector mPrimaryVerticesLabels; - std::array, nLayers> mUnsortedClusters; + std::array, NLayers> mUnsortedClusters; std::vector> mTracklets; std::vector> mCells; - bounded_vector> mRoads; - std::vector> mTracks; + bounded_vector> mRoads; + bounded_vector mTracks; + bounded_vector mTracksLabel; std::vector> mCellsNeighbours; std::vector> mCellsLookupTable; - std::vector mMultiplicityCutMask; const o2::base::PropagatorImpl* mPropagatorDevice = nullptr; // Needed only for GPU + float mBz = 999.; + const dataformats::MeanVertexObject* mMeanVertex{nullptr}; + dataformats::VertexBase mRollingVertex; + std::array mMeanVertexXYInvErr{}; + std::array mMinR; + std::array mMaxR; + std::array mMSangles; + std::array mPhiCuts; + std::array mPositionResolution; + std::array, NLayers> mClusterSize; - virtual void wipe(); - - // interface - virtual bool isGPU() const noexcept { return false; } - virtual const char* getName() const noexcept { return "CPU"; } - - private: - void prepareClusters(const TrackingParameters& trkParam, const int maxLayers = nLayers); - float mBz = 5.; - unsigned int mNTotalLowPtVertices = 0; - int mBeamPosWeight = 0; - std::array mBeamPos = {0.f, 0.f}; - bool isBeamPositionOverridden = false; - std::array mMinR; - std::array mMaxR; - bounded_vector mMSangles; - bounded_vector mPhiCuts; - bounded_vector mPositionResolution; - bounded_vector mClusterSize; - - std::vector mROFMask; bounded_vector> mPValphaX; /// PV x and alpha for track propagation std::vector> mTrackletLabels; std::vector> mCellLabels; std::vector> mCellsNeighboursLUT; - std::vector> mTracksLabel; - bounded_vector mBogusClusters; /// keep track of clusters with wild coordinates - - bounded_vector> mRoadLabels; - int mCutClusterMult{-999}; - int mCutVertexMult{-999}; - - // Vertexer - std::vector> mNTrackletsPerROF; - std::vector> mLines; - std::vector> mTrackletClusters; - std::array, 2> mTrackletsIndexROF; - std::vector> mLinesLabels; - std::vector> mVerticesMCRecInfo; - bounded_vector mVerticesContributorLabels; - std::array mTotalTracklets = {0, 0}; - uint32_t mTotalLines = 0; - unsigned int mNoVertexROF = 0; - bounded_vector mTotVertPerIteration; - // \Vertexer + std::array mBogusClusters; /// keep track of clusters with wild coordinates + + // lookup tables + IndexTableUtilsN mIndexTableUtils; + ROFOverlapTableN mROFOverlapTable; + ROFOverlapTableN::View mROFOverlapTableView; + ROFVertexLookupTableN mROFVertexLookupTable; + ROFVertexLookupTableN::View mROFVertexLookupTableView; + ROFTimeSliceTableN mROFTimeSliceTable; + ROFTimeSliceTableN::View mROFTimeSliceTableView; std::shared_ptr mMemoryPool; }; -template -inline gsl::span TimeFrame::getPrimaryVertices(int rofId) const +template +inline gsl::span TimeFrame::getPrimaryVertices(int layer, int rofId) const { - if (mPrimaryVertices.empty()) { - return {}; - } - const int start = mROFramesPV[rofId]; - const int stop_idx = rofId >= mNrof - 1 ? mNrof : rofId + 1; - int delta = mMultiplicityCutMask[rofId] ? mROFramesPV[stop_idx] - start : 0; // return empty span if Rof is excluded - return {&mPrimaryVertices[start], static_cast::size_type>(delta)}; + const auto& pvs = mROFVertexLookupTableView.getVertices(layer, rofId); + return {&mPrimaryVertices[pvs.getFirstEntry()], static_cast::size_type>(pvs.getEntries())}; } -template -inline gsl::span> TimeFrame::getPrimaryVerticesMCRecInfo(const int rofId) const +template +inline gsl::span> TimeFrame::getPrimaryVerticesXAlpha(int layer, int rofId) const { - const int start = mROFramesPV[rofId]; - const int stop_idx = rofId >= mNrof - 1 ? mNrof : rofId + 1; - int delta = mMultiplicityCutMask[rofId] ? mROFramesPV[stop_idx] - start : 0; // return empty span if Rof is excluded - return {&(mVerticesMCRecInfo[start]), static_cast>::size_type>(delta)}; -} - -template -inline gsl::span TimeFrame::getPrimaryVerticesContributors(const int rofId) const -{ - // count the number of cont. in rofs before target rof - unsigned int start{0}, delta{0}; - const auto& pvsBefore = getPrimaryVertices(0, rofId - 1); - for (const auto& pv : pvsBefore) { - start += pv.getNContributors(); - } - const auto& pvsIn = getPrimaryVertices(rofId); - for (const auto& pv : pvsIn) { - delta += pv.getNContributors(); - } - return {&(mVerticesContributorLabels[start]), static_cast::size_type>(delta)}; + const auto& pvs = mROFVertexLookupTableView.getVertices(layer, rofId); + return {&(mPValphaX[pvs.getFirstEntry()]), static_cast>::size_type>(pvs.getEntries())}; } -template -inline gsl::span TimeFrame::getPrimaryVertices(int romin, int romax) const -{ - if (mPrimaryVertices.empty()) { - return {}; - } - const int stop_idx = romax >= mNrof - 1 ? mNrof : romax + 1; - return {&mPrimaryVertices[mROFramesPV[romin]], static_cast::size_type>(mROFramesPV[stop_idx] - mROFramesPV[romin])}; -} - -template -inline gsl::span> TimeFrame::getPrimaryVerticesXAlpha(int rofId) const -{ - const int start = mROFramesPV[rofId]; - const int stop_idx = rofId >= mNrof - 1 ? mNrof : rofId + 1; - int delta = mMultiplicityCutMask[rofId] ? mROFramesPV[stop_idx] - start : 0; // return empty span if Rof is excluded - return {&(mPValphaX[start]), static_cast>::size_type>(delta)}; -} - -template -inline int TimeFrame::getPrimaryVerticesNum(int rofId) const -{ - return rofId < 0 ? mPrimaryVertices.size() : mROFramesPV[rofId + 1] - mROFramesPV[rofId]; -} - -template -inline void TimeFrame::resetBeamXY(const float x, const float y, const float w) -{ - mBeamPos[0] = x; - mBeamPos[1] = y; - mBeamPosWeight = w; -} - -template -inline gsl::span TimeFrame::getROFrameClusters(int layerId) const +template +inline gsl::span TimeFrame::getROFrameClusters(int layerId) const { return {&mROFramesClusters[layerId][0], static_cast::size_type>(mROFramesClusters[layerId].size())}; } -template -inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) +template +inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) { - if (rofId < 0 || rofId >= mNrof) { + if (rofId < 0 || rofId >= getNrof(layerId)) { return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; return {&mClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -template -inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) const +template +inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) const { - if (rofId < 0 || rofId >= mNrof) { + if (rofId < 0 || rofId >= getNrof(layerId)) { return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; return {&mClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -template -inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) +template +inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) { - if (rofId < 0 || rofId >= mNrof) { + if (rofId < 0 || rofId >= getNrof(layerId)) { return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; return {&mUsedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -template -inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) const +template +inline gsl::span TimeFrame::getUsedClustersROF(int rofId, int layerId) const { - if (rofId < 0 || rofId >= mNrof) { + if (rofId < 0 || rofId >= getNrof(layerId)) { return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; return {&mUsedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -template -inline gsl::span TimeFrame::getClustersPerROFrange(int rofMin, int range, int layerId) const +template +inline gsl::span TimeFrame::getClustersPerROFrange(int rofMin, int range, int layerId) const { - if (rofMin < 0 || rofMin >= mNrof) { + if (rofMin < 0 || rofMin >= getNrof(layerId)) { return {}; } int startIdx{mROFramesClusters[layerId][rofMin]}; // First cluster of rofMin - int endIdx{mROFramesClusters[layerId][o2::gpu::CAMath::Min(rofMin + range, mNrof)]}; + int endIdx{mROFramesClusters[layerId][o2::gpu::CAMath::Min(rofMin + range, getNrof(layerId))]}; return {&mClusters[layerId][startIdx], static_cast::size_type>(endIdx - startIdx)}; } -template -inline gsl::span TimeFrame::getROFramesClustersPerROFrange(int rofMin, int range, int layerId) const +template +inline gsl::span TimeFrame::getROFramesClustersPerROFrange(int rofMin, int range, int layerId) const { - int chkdRange{o2::gpu::CAMath::Min(range, mNrof - rofMin)}; + int chkdRange{o2::gpu::CAMath::Min(range, getNrof(layerId) - rofMin)}; return {&mROFramesClusters[layerId][rofMin], static_cast::size_type>(chkdRange)}; } -template -inline gsl::span TimeFrame::getNClustersROFrange(int rofMin, int range, int layerId) const +template +inline gsl::span TimeFrame::getNClustersROFrange(int rofMin, int range, int layerId) const { - int chkdRange{o2::gpu::CAMath::Min(range, mNrof - rofMin)}; + int chkdRange{o2::gpu::CAMath::Min(range, getNrof(layerId) - rofMin)}; return {&mNClustersPerROF[layerId][rofMin], static_cast::size_type>(chkdRange)}; } -template -inline int TimeFrame::getTotalClustersPerROFrange(int rofMin, int range, int layerId) const +template +inline int TimeFrame::getTotalClustersPerROFrange(int rofMin, int range, int layerId) const { int startIdx{rofMin}; // First cluster of rofMin - int endIdx{o2::gpu::CAMath::Min(rofMin + range, mNrof)}; + int endIdx{o2::gpu::CAMath::Min(rofMin + range, getNrof(layerId))}; return mROFramesClusters[layerId][endIdx] - mROFramesClusters[layerId][startIdx]; } -template -inline gsl::span TimeFrame::getIndexTablePerROFrange(int rofMin, int range, int layerId) const +template +inline gsl::span TimeFrame::getIndexTablePerROFrange(int rofMin, int range, int layerId) const { const int iTableSize{mIndexTableUtils.getNphiBins() * mIndexTableUtils.getNzBins() + 1}; - int chkdRange{o2::gpu::CAMath::Min(range, mNrof - rofMin)}; + int chkdRange{o2::gpu::CAMath::Min(range, getNrof(layerId) - rofMin)}; return {&mIndexTables[layerId][rofMin * iTableSize], static_cast::size_type>(chkdRange * iTableSize)}; } -template -inline int TimeFrame::getClusterROF(int iLayer, int iCluster) +template +inline int TimeFrame::getClusterROF(int iLayer, int iCluster) { return std::lower_bound(mROFramesClusters[iLayer].begin(), mROFramesClusters[iLayer].end(), iCluster + 1) - mROFramesClusters[iLayer].begin() - 1; } -template -inline gsl::span TimeFrame::getUnsortedClustersOnLayer(int rofId, int layerId) const +template +inline gsl::span TimeFrame::getUnsortedClustersOnLayer(int rofId, int layerId) const { - if (rofId < 0 || rofId >= mNrof) { + if (rofId < 0 || rofId >= getNrof(layerId)) { return {}; } int startIdx{mROFramesClusters[layerId][rofId]}; return {&mUnsortedClusters[layerId][startIdx], static_cast::size_type>(mROFramesClusters[layerId][rofId + 1] - startIdx)}; } -template -inline gsl::span TimeFrame::getIndexTable(int rofId, int layer) +template +inline gsl::span TimeFrame::getIndexTable(int rofId, int layer) { - if (rofId < 0 || rofId >= mNrof) { + if (rofId < 0 || rofId >= getNrof(layer)) { return {}; } const int tableSize = mIndexTableUtils.getNphiBins() * mIndexTableUtils.getNzBins() + 1; return {&mIndexTables[layer][rofId * tableSize], static_cast::size_type>(tableSize)}; } -template +template template -void TimeFrame::addClusterToLayer(int layer, T&&... values) +void TimeFrame::addClusterToLayer(int layer, T&&... values) { mUnsortedClusters[layer].emplace_back(std::forward(values)...); } -template +template template -void TimeFrame::addTrackingFrameInfoToLayer(int layer, T&&... values) +void TimeFrame::addTrackingFrameInfoToLayer(int layer, T&&... values) { mTrackingFrameInfo[layer].emplace_back(std::forward(values)...); } -template -inline gsl::span TimeFrame::getUsedClusters(const int layer) +template +inline gsl::span TimeFrame::getUsedClusters(const int layer) { return {&mUsedClusters[layer][0], static_cast::size_type>(mUsedClusters[layer].size())}; } -template -inline void TimeFrame::initialiseRoadLabels() -{ - mRoadLabels.clear(); - mRoadLabels.resize(mRoads.size()); -} - -template -inline void TimeFrame::setRoadLabel(int i, const unsigned long long& lab, bool fake) -{ - mRoadLabels[i].first = lab; - mRoadLabels[i].second = fake; -} - -template -inline gsl::span TimeFrame::getNTrackletsCluster(int rofId, int combId) -{ - if (rofId < 0 || rofId >= mNrof) { - return {}; - } - auto startIdx{mROFramesClusters[1][rofId]}; - return {&mNTrackletsPerCluster[combId][startIdx], static_cast::size_type>(mROFramesClusters[1][rofId + 1] - startIdx)}; -} - -template -inline gsl::span TimeFrame::getExclusiveNTrackletsCluster(int rofId, int combId) -{ - if (rofId < 0 || rofId >= mNrof) { - return {}; - } - auto clusStartIdx{mROFramesClusters[1][rofId]}; - - return {&mNTrackletsPerClusterSum[combId][clusStartIdx], static_cast::size_type>(mROFramesClusters[1][rofId + 1] - clusStartIdx)}; -} - -template -inline gsl::span TimeFrame::getFoundTracklets(int rofId, int combId) -{ - if (rofId < 0 || rofId >= mNrof || mTracklets[combId].empty()) { - return {}; - } - auto startIdx{mNTrackletsPerROF[combId][rofId]}; - return {&mTracklets[combId][startIdx], static_cast::size_type>(mNTrackletsPerROF[combId][rofId + 1] - startIdx)}; -} - -template -inline gsl::span TimeFrame::getFoundTracklets(int rofId, int combId) const -{ - if (rofId < 0 || rofId >= mNrof) { - return {}; - } - auto startIdx{mNTrackletsPerROF[combId][rofId]}; - return {&mTracklets[combId][startIdx], static_cast::size_type>(mNTrackletsPerROF[combId][rofId + 1] - startIdx)}; -} - -template -inline gsl::span TimeFrame::getLabelsFoundTracklets(int rofId, int combId) const -{ - if (rofId < 0 || rofId >= mNrof || !hasMCinformation()) { - return {}; - } - auto startIdx{mNTrackletsPerROF[combId][rofId]}; - return {&mTrackletLabels[combId][startIdx], static_cast::size_type>(mNTrackletsPerROF[combId][rofId + 1] - startIdx)}; -} - -template -inline int TimeFrame::getTotalClusters() const +template +inline int TimeFrame::getTotalClusters() const { size_t totalClusters{0}; for (const auto& clusters : mUnsortedClusters) { @@ -620,9 +461,12 @@ inline int TimeFrame::getTotalClusters() const return int(totalClusters); } -template -inline int TimeFrame::getNumberOfClusters() const +template +inline int TimeFrame::getNumberOfClusters(int layer) const { + if (layer >= 0) { + return mClusters[layer].size(); + } int nClusters = 0; for (const auto& layer : mClusters) { nClusters += layer.size(); @@ -630,8 +474,8 @@ inline int TimeFrame::getNumberOfClusters() const return nClusters; } -template -inline int TimeFrame::getNumberOfCells() const +template +inline int TimeFrame::getNumberOfCells() const { int nCells = 0; for (const auto& layer : mCells) { @@ -640,8 +484,8 @@ inline int TimeFrame::getNumberOfCells() const return nCells; } -template -inline int TimeFrame::getNumberOfTracklets() const +template +inline int TimeFrame::getNumberOfTracklets() const { int nTracklets = 0; for (const auto& layer : mTracklets) { @@ -650,8 +494,8 @@ inline int TimeFrame::getNumberOfTracklets() const return nTracklets; } -template -inline int TimeFrame::getNumberOfNeighbours() const +template +inline int TimeFrame::getNumberOfNeighbours() const { int n{0}; for (const auto& l : mCellsNeighbours) { @@ -660,18 +504,8 @@ inline int TimeFrame::getNumberOfNeighbours() const return n; } -template -inline size_t TimeFrame::getNumberOfTracks() const -{ - int nTracks = 0; - for (const auto& t : mTracks) { - nTracks += t.size(); - } - return nTracks; -} - -template -inline size_t TimeFrame::getNumberOfUsedClusters() const +template +inline size_t TimeFrame::getNumberOfUsedClusters() const { size_t nClusters = 0; for (const auto& layer : mUsedClusters) { @@ -680,17 +514,6 @@ inline size_t TimeFrame::getNumberOfUsedClusters() const return nClusters; } -template -inline void TimeFrame::insertPastVertex(const Vertex& vertex, const int iteration) -{ - int rofId = vertex.getTimeStamp().getTimeStamp(); - mPrimaryVertices.insert(mPrimaryVertices.begin() + mROFramesPV[rofId], vertex); - for (int i = rofId + 1; i < mROFramesPV.size(); ++i) { - mROFramesPV[i]++; - } - mTotVertPerIteration[iteration]++; -} - } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h index 4c903ed1f3ca1..01897b88fd950 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h @@ -51,49 +51,47 @@ class GPUChainITS; namespace its { -template +template class Tracker { using LogFunc = std::function; public: - Tracker(TrackerTraits* traits); + Tracker(TrackerTraits* traits); - void adoptTimeFrame(TimeFrame& tf); + void adoptTimeFrame(TimeFrame& tf); - void clustersToTracks( - const LogFunc& = [](const std::string& s) { std::cout << s << '\n'; }, - const LogFunc& = [](const std::string& s) { std::cerr << s << '\n'; }); - - void setParameters(const std::vector& p) { mTrkParams = p; } + void clustersToTracks(const LogFunc& info, const LogFunc& error); + const auto& getParameters() const { return mRecoParams; } + void setParameters(const std::vector& p) { mRecoParams = p; } void setMemoryPool(std::shared_ptr pool) { mMemoryPool = pool; } - std::vector& getParameters() { return mTrkParams; } void setBz(float bz) { mTraits->setBz(bz); } bool isMatLUT() const { return mTraits->isMatLUT(); } void setNThreads(int n, std::shared_ptr& arena) { mTraits->setNThreads(n, arena); } void printSummary() const; private: - void initialiseTimeFrame(int iteration) { mTraits->initialiseTimeFrame(iteration); } - void computeTracklets(int iteration, int iROFslice, int iVertex) { mTraits->computeLayerTracklets(iteration, iROFslice, iVertex); } + void initialiseTimeFrame(int iteration) { mTraits->initialiseTimeFrame(mRecoParams[iteration]); } + void computeTracklets(int iteration, int iSlice, int iVertex) { mTraits->computeLayerTracklets(iteration, iSlice, iVertex); } void computeCells(int iteration) { mTraits->computeLayerCells(iteration); } + void findCellSeeds(int iteration) { mTraits->findCellSeeds(iteration); } void findCellsNeighbours(int iteration) { mTraits->findCellsNeighbours(iteration); } void findRoads(int iteration) { mTraits->findRoads(iteration); } - void findShortPrimaries() { mTraits->findShortPrimaries(); } + void findShortPrimaries(int iteration) { mTraits->findShortPrimaries(iteration); } void extendTracks(int iteration) { mTraits->extendTracks(iteration); } + void computeTruthSeeding(int) { mTraits->computeTruthSeeding(); } - // MC interaction - void computeRoadsMClabels(); void computeTracksMClabels(); void rectifyClusterIndices(); + void sortTracks(); template float evaluateTask(void (Tracker::*task)(T...), std::string_view taskName, int iteration, LogFunc logger, F&&... args); - TrackerTraits* mTraits = nullptr; /// Observer pointer, not owned by this class - TimeFrame* mTimeFrame = nullptr; /// Observer pointer, not owned by this class + TrackerTraits* mTraits = nullptr; /// Observer pointer, not owned by this class + TimeFrame* mTimeFrame = nullptr; /// Observer pointer, not owned by this class - std::vector mTrkParams; + std::vector mRecoParams; o2::gpu::GPUChainITS* mRecoChain = nullptr; unsigned int mNumberOfDroppedTFs{0}; @@ -102,26 +100,28 @@ class Tracker std::shared_ptr mMemoryPool; enum State { - TFInit = 0, - Trackleting, - Celling, - Neighbouring, - Roading, - NStates, + kTFInit = 0, + kTrackleting, + kCelling, + kSeeding, + kNeighbouring, + kRoading, + kTruthSeeding, + kNStates, }; - State mCurState{TFInit}; - static constexpr std::array StateNames{"TimeFrame initialisation", "Tracklet finding", "Cell finding", "Neighbour finding", "Road finding"}; + State mCurState{kTFInit}; + static constexpr std::array StateNames{"TimeFrame initialisation", "Tracklet finding", "Cell finding", "Seeding", "Neighbour finding", "Road finding", "TruthSeeding"}; }; -template +template template -float Tracker::evaluateTask(void (Tracker::*task)(T...), std::string_view taskName, int iteration, LogFunc logger, F&&... args) +float Tracker::evaluateTask(void (Tracker::*task)(T...), std::string_view taskName, int iteration, LogFunc logger, F&&... args) { float diff{0.f}; if constexpr (constants::DoTimeBenchmarks) { auto start = std::chrono::high_resolution_clock::now(); - (this->*task)(std::forward(args)...); + (this->*task)(iteration, std::forward(args)...); auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration diff_t{end - start}; @@ -135,7 +135,7 @@ float Tracker::evaluateTask(void (Tracker::*task)(T...), std:: } logger(sstream.str()); - if (mTrkParams[0].SaveTimeBenchmarks) { + if (mRecoParams[iteration].params.SaveTimeBenchmarks) { std::string taskNameStr(taskName); std::transform(taskNameStr.begin(), taskNameStr.end(), taskNameStr.begin(), [](unsigned char c) { return std::tolower(c); }); @@ -146,7 +146,7 @@ float Tracker::evaluateTask(void (Tracker::*task)(T...), std:: } } else { - (this->*task)(std::forward(args)...); + (this->*task)(iteration, std::forward(args)...); } return diff; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h index ddc32ed18cbfe..1d64c0c2e4a27 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h @@ -16,18 +16,19 @@ #ifndef TRACKINGITSU_INCLUDE_TRACKERTRAITS_H_ #define TRACKINGITSU_INCLUDE_TRACKERTRAITS_H_ -#include +#include + +#include #include "DetectorsBase/Propagator.h" #include "ITStracking/Configuration.h" #include "ITStracking/MathUtils.h" #include "ITStracking/IndexTableUtils.h" #include "ITStracking/TimeFrame.h" +#include "ITStracking/Seeding.h" #include "ITStracking/Cell.h" #include "ITStracking/BoundedAllocator.h" -// #define OPTIMISATION_OUTPUT - namespace o2 { namespace gpu @@ -38,32 +39,44 @@ namespace its { class TrackITSExt; -template +template class TrackerTraits { + struct Neighbor { + int32_t cell{-1}, nextCell{-1}, level{-1}; + }; + public: - using IndexTableUtilsN = IndexTableUtils; - using CellSeedN = CellSeed; + using IndexTableUtilsN = IndexTableUtils; + using CellSeedN = CellSeed; - virtual ~TrackerTraits() = default; - virtual void adoptTimeFrame(TimeFrame* tf) { mTimeFrame = tf; } - virtual void initialiseTimeFrame(const int iteration) { mTimeFrame->initialise(iteration, mTrkParams[iteration], mTrkParams[iteration].NLayers); } + TrackerTraits(); + TrackerTraits(const TrackerTraits&) = delete; + TrackerTraits(TrackerTraits&&) = delete; + TrackerTraits& operator=(const TrackerTraits&) = delete; + TrackerTraits& operator=(TrackerTraits&&) = delete; + virtual ~TrackerTraits(); - virtual void computeLayerTracklets(const int iteration, int iROFslice, int iVertex); + virtual void adoptTimeFrame(TimeFrame* tf) { mTimeFrame = tf; } + virtual void initialiseTimeFrame(const RecoIteration& reco) { mTimeFrame->initialise(reco); } + + virtual void computeLayerTracklets(const int iteration, const int iSlice, const int iVertex); virtual void computeLayerCells(const int iteration); + virtual void findCellSeeds(const int iteration); virtual void findCellsNeighbours(const int iteration); virtual void findRoads(const int iteration); virtual bool supportsExtendTracks() const noexcept { return true; } virtual void extendTracks(const int iteration); virtual bool supportsFindShortPrimaries() const noexcept { return true; } - virtual void findShortPrimaries(); + virtual void findShortPrimaries(const int iteration); + virtual void computeTruthSeeding(); virtual bool trackFollowing(TrackITSExt* track, int rof, bool outward, const int iteration); - virtual void processNeighbours(int iLayer, int iLevel, const bounded_vector& currentCellSeed, const bounded_vector& currentCellId, bounded_vector& updatedCellSeed, bounded_vector& updatedCellId); + virtual void processNeighbours(int iteration, int iLayer, int iLevel, const bounded_vector& currentCellSeed, const bounded_vector& currentCellId, bounded_vector& updatedCellSeed, bounded_vector& updatedCellId); - void updateTrackingParameters(const std::vector& trkPars) { mTrkParams = trkPars; } - TimeFrame* getTimeFrame() { return mTimeFrame; } + void updateTrackingParameters(const std::vector& recoPars); + TimeFrame* getTimeFrame() { return mTimeFrame; } virtual void setBz(float bz); float getBz() const { return mBz; } @@ -75,12 +88,11 @@ class TrackerTraits // Others GPUhd() static consteval int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } - const int4 getBinsRect(int layer, float phi, float maxdeltaphi, float z, float maxdeltaz) const noexcept { return getBinsRect(layer, phi, maxdeltaphi, z, z, maxdeltaz); } - const int4 getBinsRect(const Cluster& cls, int layer, float z1, float z2, float maxdeltaz, float maxdeltaphi) const noexcept { return getBinsRect(layer, cls.phi, maxdeltaphi, z1, z2, maxdeltaz); } - const int4 getBinsRect(int layer, float phi, float maxdeltaphi, float z1, float z2, float maxdeltaz) const noexcept; + int4 getBinsRect(const int iteration, int layer, float phi, float maxdeltaphi, float z, float maxdeltaz) const noexcept { return getBinsRect(iteration, layer, phi, maxdeltaphi, z, z, maxdeltaz); } + int4 getBinsRect(const int iteration, const Cluster& cls, int layer, float z1, float z2, float maxdeltaz, float maxdeltaphi) const noexcept { return getBinsRect(iteration, layer, cls.phi, maxdeltaphi, z1, z2, maxdeltaz); } + const int4 getBinsRect(const int iteration, int layer, float phi, float maxdeltaphi, float z1, float z2, float maxdeltaz) const noexcept; + void SetRecoChain(o2::gpu::GPUChainITS* chain) { mChain = chain; } - void setSmoothing(bool v) { mApplySmoothing = v; } - bool getSmoothing() const { return mApplySmoothing; } void setNThreads(int n, std::shared_ptr& arena); int getNThreads() { return mTaskArena->max_concurrency(); } @@ -95,37 +107,43 @@ class TrackerTraits track::TrackParCov buildTrackSeed(const Cluster& cluster1, const Cluster& cluster2, const TrackingFrameInfo& tf3, bool reverse = false); TrackITSExt seedTrackForRefit(const CellSeedN& seed); bool fitTrack(TrackITSExt& track, int start, int end, int step, float chi2clcut = o2::constants::math::VeryBig, float chi2ndfcut = o2::constants::math::VeryBig, float maxQoverPt = o2::constants::math::VeryBig, int nCl = 0, o2::track::TrackPar* refLin = nullptr); + void sortSeeds(); + + // Debug output + inline void debugComputeLayerTracklets(int iteration, int layer, const Cluster& currentCls, const Cluster& nextCls, const Vertex& pv, float sigmaZ, float sigmaPhi, bool accepted); + inline void debugComputeLayerCells(int iteration, int layer, int currentTrkl, int nextTrkl); + inline void debugFindCellsNeighbours(int iteration, int layer, int currentCell, int nextCell, bool accepted); - bool mApplySmoothing = false; std::shared_ptr mMemoryPool; std::shared_ptr mTaskArena; + dbscan::DBSCAN mDBScan; protected: o2::gpu::GPUChainITS* mChain = nullptr; - TimeFrame* mTimeFrame; - std::vector mTrkParams; + TimeFrame* mTimeFrame; + std::vector mRecoParams; float mBz{-999.f}; bool mIsZeroField{false}; }; -template -inline const int4 TrackerTraits::getBinsRect(const int layerIndex, float phi, float maxdeltaphi, float z1, float z2, float maxdeltaz) const noexcept +template +inline const int4 TrackerTraits::getBinsRect(const int iteration, const int layerIndex, float phi, float maxdeltaphi, float z1, float z2, float maxdeltaz) const noexcept { const float zRangeMin = o2::gpu::GPUCommonMath::Min(z1, z2) - maxdeltaz; const float phiRangeMin = (maxdeltaphi > o2::constants::math::PI) ? 0.f : phi - maxdeltaphi; const float zRangeMax = o2::gpu::GPUCommonMath::Max(z1, z2) + maxdeltaz; const float phiRangeMax = (maxdeltaphi > o2::constants::math::PI) ? o2::constants::math::TwoPI : phi + maxdeltaphi; - if (zRangeMax < -mTrkParams[0].LayerZ[layerIndex] || - zRangeMin > mTrkParams[0].LayerZ[layerIndex] || zRangeMin > zRangeMax) { + if (zRangeMax < -mRecoParams[iteration].params.LayerZ[layerIndex] || + zRangeMin > mRecoParams[iteration].params.LayerZ[layerIndex] || zRangeMin > zRangeMax) { return getEmptyBinsRect(); } - const IndexTableUtilsN& utils{mTimeFrame->mIndexTableUtils}; + const IndexTableUtilsN& utils{mTimeFrame->getIndexTableUtils()}; return int4{o2::gpu::GPUCommonMath::Max(0, utils.getZBinIndex(layerIndex, zRangeMin)), utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMin)), - o2::gpu::GPUCommonMath::Min(mTrkParams[0].ZBins - 1, utils.getZBinIndex(layerIndex, zRangeMax)), // /!\ trkParams can potentially change across iterations + o2::gpu::GPUCommonMath::Min(mRecoParams[iteration].params.ZBins - 1, utils.getZBinIndex(layerIndex, zRangeMax)), utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; } diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h index 2a3506f17fa2f..1dac97768c252 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h @@ -19,74 +19,30 @@ namespace o2::its { -struct VertexerParamConfig : public o2::conf::ConfigurableParamHelper { - bool saveTimeBenchmarks = false; // dump metrics on file - - int nIterations = 1; // Number of vertexing passes to perform. - int vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a iteration. - bool allowSingleContribClusters = false; // attempt to find vertices in case of a single tracklet found. - int deltaRof = 0; // Number of ROFs to be considered for the vertexing. - - // geometrical cuts for tracklet selection - float zCut = 0.002f; - float phiCut = 0.005f; - float pairCut = 0.04f; - float clusterCut = 0.8f; - float histPairCut = 0.04f; - float tanLambdaCut = 0.002f; // tanLambda = deltaZ/deltaR - float lowMultBeamDistCut = 0.1f; // XY cut for low-multiplicity pile up - int vertNsigmaCut = 4; // N sigma cut for vertex XY - float vertRadiusSigma = 0.05f; // sigma of vertex XY - float trackletSigma = 0.01f; // tracklet to vertex sigma - float maxZPositionAllowed = 25.f; // 4x sZ of the beam - - // Artefacts selections - int clusterContributorsCut = 16; // minimum number of contributors for the second vertex found in the same ROF (pileup cut) - int maxTrackletsPerCluster = 1e2; - int phiSpan = -1; - int zSpan = -1; - int ZBins = 1; // z-phi index table configutation: number of z bins - int PhiBins = 128; // z-phi index table configutation: number of phi bins - - bool useTruthSeeding{false}; // overwrite seeding vertices with MC truth - bool outputContLabels{false}; // output additioanlly for each vertex its contributing line labels - - int nThreads = 1; - bool printMemory = false; - size_t maxMemory = std::numeric_limits::max(); - bool dropTFUponFailure = false; - - O2ParamDef(VertexerParamConfig, "ITSVertexerParam"); -}; - struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper { // Use TGeo for mat. budget static const int MaxIter = 4; static const int MinTrackLength = 4; static const int MaxTrackLength = 7; - bool useMatCorrTGeo = false; // use full geometry to corect for material budget accounting in the fits. Default is to use the material budget LUT. + bool useMatCorrTGeo = false; // use full geometry to correct for material budget accounting in the fits. Default is to use the material budget LUT. bool useFastMaterial = false; // use faster material approximation for material budget accounting in the fits. - int deltaRof = 0; // configure the width of the window in ROFs to be considered for the tracking. + int deltaROF[MaxTrackLength] = {0}; // configure the width of the window in ROFs to be considered for the tracking. int minTrackLgtIter[MaxIter] = {}; // minimum track length at each iteration, used only if >0, otherwise use code defaults uint8_t startLayerMask[MaxIter] = {}; // mask of start layer for this iteration (if >0) float minPtIterLgt[MaxIter * (MaxTrackLength - MinTrackLength + 1)] = {}; // min.pT for given track length at this iteration, used only if >0, otherwise use code defaults - float sysErrY2[7] = {0}; // systematic error^2 in Y per layer - float sysErrZ2[7] = {0}; // systematic error^2 in Z per layer + float sysErrY2[MaxTrackLength] = {0}; // systematic error^2 in Y per layer + float sysErrZ2[MaxTrackLength] = {0}; // systematic error^2 in Z per layer + int nTimeSlices{1}; float maxChi2ClusterAttachment = -1.f; float maxChi2NDF = -1.f; float nSigmaCut = -1.f; - float deltaTanLres = -1.f; float minPt = -1.f; - float pvRes = -1.f; int LUTbinsPhi = -1; int LUTbinsZ = -1; - float diamondPos[3] = {0.f, 0.f, 0.f}; // override the position of the vertex - bool useDiamond = false; // enable overriding the vertex position - int useTrackFollower = -1; // bit 0: allow mixing implies bits 1&2; bit 1: topwards; bit2: downwards; => 0 off - float trackFollowerNSigmaZ = 1.f; // sigma in z-cut for track-following search rectangle - float trackFollowerNSigmaPhi = 1.f; // sigma in phi-cut for track-following search rectangle - float cellsPerClusterLimit = -1.f; - float trackletsPerClusterLimit = -1.f; + float diamondPos[3] = {0.f, 0.f, 0.f}; // override the position of the vertex + float diamondCov[6] = {25.e-6f, 0.f, 0.f, 25.e-6f, 0.f, 36.f}; // cov + bool useDiamond = false; // enable overriding the vertex position + int useTrackFollower = -1; // bit 0: allow mixing implies bits 1&2; bit 1: topwards; bit2: downwards; => 0 off int findShortTracks = -1; int nROFsPerIterations = 0; // size of the slice of ROFs to be processed at a time, preferably integer divisors of nROFs per TF, to balance the iterations. int nOrbitsPerIterations = 0; // not implemented: size of the slice of ROFs to be processed at a time, computed using the number of ROFs per orbit. @@ -98,21 +54,35 @@ struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper::max(); bool dropTFUponFailure = false; - bool fataliseUponFailure = true; // granular management of the fatalisation in async mode + bool fataliseUponFailure = true; // granular management of the fatalisation in async mode bool allowSharingFirstCluster = false; // allow first cluster sharing among tracks O2ParamDef(TrackerParamConfig, "ITSCATrackerParam"); }; struct ITSGpuTrackingParamConfig : public o2::conf::ConfigurableParamHelper { - static constexpr int MaxIter = TrackerParamConfig::MaxIter; - /// Set nBlocks/nThreads to summarily override all kernel launch parameters in each iteration. /// Parameters must start with nBlocks/nThreads. static constexpr int OverrideValue{-1}; @@ -123,26 +93,20 @@ struct ITSGpuTrackingParamConfig : public o2::conf::ConfigurableParamHelper; - using VertexerTraitsN = VertexerTraits; using TrackerN = Tracker; using TrackerTraitsN = TrackerTraits; using TimeFrameN = TimeFrame; @@ -69,11 +65,10 @@ class ITSTrackingInterface virtual void finaliseCCDB(framework::ConcreteDataMatcher& matcher, void* obj); // Custom - void setTraitsFromProvider(VertexerTraitsN*, TrackerTraitsN*, TimeFrameN*); + void setTraitsFromProvider(TrackerTraitsN*, TimeFrameN*); void setTrackingMode(TrackingMode::Type mode = TrackingMode::Unset) { mMode = mode; } auto getTracker() const { return mTracker.get(); } - auto getVertexer() const { return mVertexer.get(); } TimeFrameN* mTimeFrame = nullptr; @@ -81,6 +76,7 @@ class ITSTrackingInterface virtual void loadROF(gsl::span& trackROFspan, gsl::span clusters, gsl::span::iterator& pattIt, + int layer, const dataformats::MCTruthContainer* mcLabels); private: @@ -88,12 +84,12 @@ class ITSTrackingInterface bool mRunVertexer = true; bool mCosmicsProcessing = false; int mUseTriggers = 0; + std::vector mFilter; TrackingMode::Type mMode = TrackingMode::Unset; bool mOverrideBeamEstimation = false; const o2::itsmft::TopologyDictionary* mDict = nullptr; std::unique_ptr mTracker = nullptr; - std::unique_ptr mVertexer = nullptr; - const o2::dataformats::MeanVertexObject* mMeanVertex; + const o2::dataformats::MeanVertexObject* mMeanVertex = nullptr; std::shared_ptr mMemoryPool; std::shared_ptr mTaskArena; }; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h index e6c9db55198a3..11f78fd2b395c 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracklet.h @@ -47,9 +47,13 @@ struct Tracklet final { GPUhdi() auto getDeltaRof() const { return rof[1] - rof[0]; } GPUhdi() auto getSpanRof(const Tracklet& o) const noexcept { return o2::gpu::CAMath::Max(getMaxRof(), o.getMaxRof()) - o2::gpu::CAMath::Min(getMinRof(), o.getMinRof()); } GPUhdi() unsigned char operator<(const Tracklet&) const; + GPUhd() auto asString() const + { + return fmt::format("TRKLT: fClIdx:{} fROF:{} sClIdx:{} sROF:{} (DROF:{}) tgl={} phi={}", firstClusterIndex, rof[0], secondClusterIndex, rof[1], getDeltaRof(), tanLambda, phi); + } GPUhd() void print() const { - printf("TRKLT: fClIdx:%d fROF:%d sClIdx:%d sROF:%d (DROF:%d) tgl=%f phi=%f\n", firstClusterIndex, rof[0], secondClusterIndex, rof[1], getDeltaRof(), tanLambda, phi); + LOGP(info, "{}", asString()); } int firstClusterIndex{constants::UnusedIndex}; @@ -84,7 +88,7 @@ GPUhdi() Tracklet::Tracklet(const int idx0, const int idx1, float tanL, float ph // Nothing to do } -GPUhdi() unsigned char Tracklet::operator<(const Tracklet& t) const +GPUhdi() unsigned char Tracklet::operator<(const Tracklet & t) const { if (isEmpty()) { return false; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h deleted file mode 100644 index d66bcd6ee2358..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Vertexer.h +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Vertexer.h -/// \brief -/// \author matteo.concas@cern.ch - -#ifndef O2_ITS_TRACKING_VERTEXER_H_ -#define O2_ITS_TRACKING_VERTEXER_H_ - -#include -#include -#include -#include -#include -#include - -#include - -#include "ITStracking/Constants.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/TimeFrame.h" -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/BoundedAllocator.h" - -namespace o2::its -{ - -template -class Vertexer -{ - using TimeFrameN = TimeFrame; - using VertexerTraitsN = VertexerTraits; - using LogFunc = std::function; - - public: - Vertexer(VertexerTraitsN* traits); - virtual ~Vertexer() = default; - Vertexer(const Vertexer&) = delete; - Vertexer& operator=(const Vertexer&) = delete; - - void adoptTimeFrame(TimeFrameN& tf); - auto& getVertParameters() const { return mTraits->getVertexingParameters(); } - void setParameters(const std::vector& vertParams) { mVertParams = vertParams; } - const auto& getParameters() const noexcept { return mVertParams; } - void setMemoryPool(std::shared_ptr pool) { mMemoryPool = pool; } - - std::vector exportVertices(); - VertexerTraitsN* getTraits() const { return mTraits; }; - - float clustersToVertices(LogFunc = [](const std::string& s) { std::cout << s << '\n'; }); - void filterMCTracklets(); - - template - void findTracklets(T&&... args) - { - mTraits->computeTracklets(std::forward(args)...); - } - template - void validateTracklets(T&&... args) - { - mTraits->computeTrackletMatching(std::forward(args)...); - } - template - void findVertices(T&&... args) - { - mTraits->computeVertices(std::forward(args)...); - } - - void addTruthSeeds() { mTraits->addTruthSeedingVertices(); } - - template - void initialiseVertexer(T&&... args) - { - mTraits->initialise(std::forward(args)...); - } - template - void initialiseTimeFrame(T&&... args); - - // Utils - template - float evaluateTask(void (Vertexer::*task)(T...), std::string_view taskName, int iteration, LogFunc& logger, T&&... args); - - void printEpilog(LogFunc& logger, - const unsigned int trackletN01, const unsigned int trackletN12, - const unsigned selectedN, const unsigned int vertexN, const float initT, - const float trackletT, const float selecT, const float vertexT); - - void setNThreads(int n, std::shared_ptr& arena) { mTraits->setNThreads(n, arena); } - - private: - std::uint32_t mTimeFrameCounter = 0; - - VertexerTraitsN* mTraits = nullptr; /// Observer pointer, not owned by this class - TimeFrameN* mTimeFrame = nullptr; /// Observer pointer, not owned by this class - - std::vector mVertParams; - std::shared_ptr mMemoryPool; - - enum State { - Init = 0, - Trackleting, - Validating, - Finding, - TruthSeeding, - NStates, - }; - State mCurState{Init}; - static constexpr std::array StateNames{"Initialisation", "Tracklet finding", "Tracklet validation", "Vertex finding", "Truth seeding"}; -}; - -template -template -float Vertexer::evaluateTask(void (Vertexer::*task)(T...), std::string_view taskName, int iteration, LogFunc& logger, T&&... args) -{ - float diff{0.f}; - - if constexpr (constants::DoTimeBenchmarks) { - auto start = std::chrono::high_resolution_clock::now(); - (this->*task)(std::forward(args)...); - auto end = std::chrono::high_resolution_clock::now(); - - std::chrono::duration diff_t{end - start}; - diff = diff_t.count(); - - std::stringstream sstream; - if (taskName.empty()) { - sstream << diff << "\t"; - } else { - sstream << std::setw(2) << " - " << taskName << " completed in: " << diff << " ms"; - } - logger(sstream.str()); - - if (mVertParams[0].SaveTimeBenchmarks) { - std::string taskNameStr(taskName); - std::transform(taskNameStr.begin(), taskNameStr.end(), taskNameStr.begin(), - [](unsigned char c) { return std::tolower(c); }); - std::replace(taskNameStr.begin(), taskNameStr.end(), ' ', '_'); - if (std::ofstream file{"its_time_benchmarks.txt", std::ios::app}) { - file << "vtx:" << iteration << '\t' << taskNameStr << '\t' << diff << '\n'; - } - } - } else { - (this->*task)(std::forward(args)...); - } - - return diff; -} - -} // namespace o2::its -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h deleted file mode 100644 index b1422d66e12df..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file VertexerTraits.h -/// \brief Class to compute the primary vertex in ITS from tracklets -/// \author matteo.concas@cern.ch - -#ifndef O2_ITS_TRACKING_VERTEXER_TRAITS_H_ -#define O2_ITS_TRACKING_VERTEXER_TRAITS_H_ - -#include -#include -#include -#include - -#include "ITStracking/BoundedAllocator.h" -#include "ITStracking/Cluster.h" -#include "ITStracking/ClusterLines.h" -#include "ITStracking/Configuration.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/IndexTableUtils.h" -#include "ITStracking/TimeFrame.h" -#include "ITStracking/Tracklet.h" -#include "ITStracking/MathUtils.h" - -#include "GPUCommonDef.h" -#include "GPUCommonMath.h" - -#include - -namespace o2 -{ -class MCCompLabel; - -namespace its -{ - -template -class VertexerTraits -{ - using IndexTableUtilsN = IndexTableUtils; - using TimeFrameN = TimeFrame; - - public: - VertexerTraits() = default; - virtual ~VertexerTraits() = default; - - GPUhdi() static consteval int4 getEmptyBinsRect() - { - return int4{0, 0, 0, 0}; - } - GPUhd() const int4 getBinsRect(const Cluster&, const int, const float, float maxdeltaz, float maxdeltaphi); - GPUhd() static const int4 getBinsRect(const Cluster&, const int, const float, float maxdeltaz, float maxdeltaphi, const IndexTableUtilsN&); - GPUhd() static const int2 getPhiBins(float phi, float deltaPhi, const IndexTableUtilsN&); - GPUhd() const int2 getPhiBins(float phi, float deltaPhi) { return getPhiBins(phi, deltaPhi, mIndexTableUtils); } - - // virtual vertexer interface - virtual void initialise(const TrackingParameters& trackingParams, const int iteration = 0); - virtual void computeTracklets(const int iteration = 0); - virtual void computeTrackletMatching(const int iteration = 0); - virtual void computeVertices(const int iteration = 0); - virtual void adoptTimeFrame(TimeFrameN* tf) noexcept { mTimeFrame = tf; } - virtual void updateVertexingParameters(const std::vector& vrtPar, const TimeFrameGPUParameters& gpuTfPar); - - // truth tracking - void addTruthSeedingVertices(); - - // utils - auto& getVertexingParameters() { return mVrtParams; } - auto getVertexingParameters() const { return mVrtParams; } - void setVertexingParameters(std::vector& vertParams) { mVrtParams = vertParams; } - void setNThreads(int n, std::shared_ptr& arena); - int getNThreads() { return mTaskArena->max_concurrency(); } - virtual bool isGPU() const noexcept { return false; } - virtual const char* getName() const noexcept { return "CPU"; } - virtual bool usesMemoryPool() const noexcept { return true; } - void setMemoryPool(std::shared_ptr pool) { mMemoryPool = pool; } - - static std::pair computeMain(const bounded_vector& elements) - { - // we only care about the source&event of the tracks, not the trackId - auto composeVtxLabel = [](const o2::MCCompLabel& lbl) -> o2::MCCompLabel { - return {o2::MCCompLabel::maxTrackID(), lbl.getEventID(), lbl.getSourceID(), lbl.isFake()}; - }; - std::unordered_map frequency; - for (const auto& element : elements) { - ++frequency[composeVtxLabel(element)]; - } - o2::MCCompLabel elem{}; - size_t maxCount = 0; - for (const auto& [key, count] : frequency) { - if (count > maxCount) { - maxCount = count; - elem = key; - } - } - return std::make_pair(elem, static_cast(maxCount) / static_cast(elements.size())); - } - - protected: - std::vector mVrtParams; - IndexTableUtilsN mIndexTableUtils; - - // Frame related quantities - TimeFrameN* mTimeFrame = nullptr; // observer ptr - private: - std::shared_ptr mMemoryPool; - std::shared_ptr mTaskArena; - - // debug output - void debugComputeTracklets(int iteration); - void debugComputeTrackletMatching(int iteration); - void debugComputeVertices(int iteration); -}; - -template -inline void VertexerTraits::initialise(const TrackingParameters& trackingParams, const int iteration) -{ - mTimeFrame->initialise(0, trackingParams, 3, (bool)(!iteration)); // iteration for initialisation must be 0 for correctly resetting the frame, we need to pass the non-reset flag for vertices as well, tho. -} - -template -GPUhdi() const int2 VertexerTraits::getPhiBins(float phi, float dPhi, const IndexTableUtilsN& utils) -{ - return int2{utils.getPhiBinIndex(math_utils::getNormalizedPhi(phi - dPhi)), - utils.getPhiBinIndex(math_utils::getNormalizedPhi(phi + dPhi))}; -} - -template -GPUhdi() const int4 VertexerTraits::getBinsRect(const Cluster& currentCluster, const int layerIndex, - const float directionZIntersection, float maxdeltaz, float maxdeltaphi, - const IndexTableUtilsN& utils) -{ - const float zRangeMin = directionZIntersection - 2 * maxdeltaz; - const float phiRangeMin = currentCluster.phi - maxdeltaphi; - const float zRangeMax = directionZIntersection + 2 * maxdeltaz; - const float phiRangeMax = currentCluster.phi + maxdeltaphi; - - if (zRangeMax < -utils.getLayerZ(layerIndex + 1) || - zRangeMin > utils.getLayerZ(layerIndex + 1) || zRangeMin > zRangeMax) { - return getEmptyBinsRect(); - } - - return int4{o2::gpu::GPUCommonMath::Max(0, utils.getZBinIndex(layerIndex + 1, zRangeMin)), - utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMin)), - o2::gpu::GPUCommonMath::Min(utils.getNzBins() - 1, utils.getZBinIndex(layerIndex + 1, zRangeMax)), - utils.getPhiBinIndex(math_utils::getNormalizedPhi(phiRangeMax))}; -} - -template -GPUhdi() const int4 VertexerTraits::getBinsRect(const Cluster& currentCluster, const int layerIndex, - const float directionZIntersection, float maxdeltaz, float maxdeltaphi) -{ - return VertexerTraits::getBinsRect(currentCluster, layerIndex, directionZIntersection, maxdeltaz, maxdeltaphi, mIndexTableUtils); -} - -} // namespace its -} // namespace o2 -#endif diff --git a/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx b/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx deleted file mode 100644 index 1a0fa1d3908a4..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include -#include -#include "ITStracking/ClusterLines.h" - -namespace o2 -{ -namespace its -{ - -Line::Line(std::array firstPoint, std::array secondPoint) -{ - for (int index{0}; index < 3; ++index) { - originPoint[index] = firstPoint.data()[index]; - cosinesDirector[index] = secondPoint[index] - firstPoint[index]; - } - - float inverseNorm{1.f / o2::gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + - cosinesDirector[2] * cosinesDirector[2])}; - for (int index{0}; index < 3; ++index) { - cosinesDirector[index] *= inverseNorm; - } -} - -bool Line::areParallel(const Line& firstLine, const Line& secondLine, const float precision) -{ - float crossProdX{firstLine.cosinesDirector[1] * secondLine.cosinesDirector[2] - - firstLine.cosinesDirector[2] * secondLine.cosinesDirector[1]}; - float module{std::abs(firstLine.cosinesDirector[1] * secondLine.cosinesDirector[2]) + - std::abs(firstLine.cosinesDirector[2] * secondLine.cosinesDirector[1])}; - if (std::abs(crossProdX) > precision * module) { - return false; - } - - float crossProdY{-firstLine.cosinesDirector[0] * secondLine.cosinesDirector[2] + - firstLine.cosinesDirector[2] * secondLine.cosinesDirector[0]}; - module = std::abs(firstLine.cosinesDirector[0] * secondLine.cosinesDirector[2]) + - std::abs(firstLine.cosinesDirector[2] * secondLine.cosinesDirector[0]); - if (std::abs(crossProdY) > precision * module) { - return false; - } - - float crossProdZ = firstLine.cosinesDirector[0] * secondLine.cosinesDirector[1] - - firstLine.cosinesDirector[1] * secondLine.cosinesDirector[0]; - module = std::abs(firstLine.cosinesDirector[0] * secondLine.cosinesDirector[1]) + - std::abs(firstLine.cosinesDirector[1] * secondLine.cosinesDirector[0]); - if (std::abs(crossProdZ) > precision * module) { - return false; - } - - return true; -} - -std::array Line::getDCAComponents(const Line& line, const std::array point) -{ - std::array components{0., 0., 0., 0., 0., 0.}; - float cdelta{0.}; - for (int i{0}; i < 3; ++i) { - cdelta -= line.cosinesDirector[i] * (line.originPoint[i] - point[i]); - } - - components[0] = line.originPoint[0] - point[0] + line.cosinesDirector[0] * cdelta; - components[3] = line.originPoint[1] - point[1] + line.cosinesDirector[1] * cdelta; - components[5] = line.originPoint[2] - point[2] + line.cosinesDirector[2] * cdelta; - components[1] = o2::gpu::CAMath::Sqrt(components[0] * components[0] + components[3] * components[3]); - components[2] = o2::gpu::CAMath::Sqrt(components[0] * components[0] + components[5] * components[5]); - components[4] = o2::gpu::CAMath::Sqrt(components[3] * components[3] + components[5] * components[5]); - - return components; -} - -ClusterLines::ClusterLines(const int firstLabel, const Line& firstLine, const int secondLabel, const Line& secondLine, - const bool weight) - -{ - updateROFPoll(firstLine); - updateROFPoll(secondLine); - - mLabels.push_back(firstLabel); - if (secondLabel > 0) { - mLabels.push_back(secondLabel); // don't add info in case of beamline used - } - - std::array covarianceFirst{1., 1., 1.}; - std::array covarianceSecond{1., 1., 1.}; - - // for (int i{0}; i < 6; ++i) { - // mWeightMatrix[i] = firstLine.weightMatrix[i] + secondLine.weightMatrix[i]; - // } - - float determinantFirst = - firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] * covarianceFirst[2] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1] * covarianceFirst[2]; - float determinantSecond = - secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] * covarianceSecond[2] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1] * covarianceSecond[2]; - - mAMatrix[0] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[1] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[1] * covarianceFirst[2] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[1] * covarianceSecond[2] / determinantSecond; - - mAMatrix[2] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[2] * covarianceFirst[1] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[2] * covarianceSecond[1] / determinantSecond; - - mAMatrix[3] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[4] = -firstLine.cosinesDirector[1] * firstLine.cosinesDirector[2] * covarianceFirst[0] / determinantFirst - - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[2] * covarianceSecond[0] / determinantSecond; - - mAMatrix[5] = (firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1]) / - determinantFirst + - (secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1]) / - determinantSecond; - - mBMatrix[0] = - (firstLine.cosinesDirector[1] * covarianceFirst[2] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[1]) + - firstLine.cosinesDirector[2] * covarianceFirst[1] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[0] += - (secondLine.cosinesDirector[1] * covarianceSecond[2] * (-secondLine.cosinesDirector[1] * secondLine.originPoint[0] + secondLine.cosinesDirector[0] * secondLine.originPoint[1]) + - secondLine.cosinesDirector[2] * covarianceSecond[1] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[0] + - secondLine.cosinesDirector[0] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[1] = - (firstLine.cosinesDirector[0] * covarianceFirst[2] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[2] * covarianceFirst[0] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[1] += - (secondLine.cosinesDirector[0] * covarianceSecond[2] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[1] + secondLine.cosinesDirector[1] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[2] * covarianceSecond[0] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[1] + - secondLine.cosinesDirector[1] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[2] = - (firstLine.cosinesDirector[0] * covarianceFirst[1] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[1] * covarianceFirst[0] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[1])) / - determinantFirst; - - mBMatrix[2] += - (secondLine.cosinesDirector[0] * covarianceSecond[1] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[2] + secondLine.cosinesDirector[2] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[1] * covarianceSecond[0] * - (-secondLine.cosinesDirector[1] * secondLine.originPoint[2] + - secondLine.cosinesDirector[2] * secondLine.originPoint[1])) / - determinantSecond; - - computeClusterCentroid(); - - // RMS2 - mRMS2 = Line::getDCAComponents(firstLine, mVertex); - const std::array tmpRMS2Line2 = Line::getDCAComponents(secondLine, mVertex); - std::transform(mRMS2.begin(), mRMS2.end(), tmpRMS2Line2.begin(), mRMS2.begin(), [&](const float a, const float b) { return a + (b - a) / mLabels.size(); }); - - // AvgDistance2 - mAvgDistance2 = std::move(Line::getDistanceFromPoint(firstLine, mVertex) * Line::getDistanceFromPoint(firstLine, mVertex)); - mAvgDistance2 += (Line::getDistanceFromPoint(secondLine, mVertex) * Line::getDistanceFromPoint(secondLine, mVertex) - mAvgDistance2) / mLabels.size(); -} - -ClusterLines::ClusterLines(const Line& firstLine, const Line& secondLine) -{ - - std::array covarianceFirst{1., 1., 1.}; - std::array covarianceSecond{1., 1., 1.}; - updateROFPoll(firstLine); - updateROFPoll(secondLine); - // for (int i{0}; i < 6; ++i) { - // mWeightMatrix[i] = firstLine.weightMatrix[i] + secondLine.weightMatrix[i]; - // } - - float determinantFirst = - firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] * covarianceFirst[2] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1] * covarianceFirst[2]; - float determinantSecond = - secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] * covarianceSecond[2] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1] * covarianceSecond[2]; - - mAMatrix[0] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[1] + - firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[1] + - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[1] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[1] * covarianceFirst[2] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[1] * covarianceSecond[2] / determinantSecond; - - mAMatrix[2] = -firstLine.cosinesDirector[0] * firstLine.cosinesDirector[2] * covarianceFirst[1] / determinantFirst - - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[2] * covarianceSecond[1] / determinantSecond; - - mAMatrix[3] = (firstLine.cosinesDirector[2] * firstLine.cosinesDirector[2] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[2]) / - determinantFirst + - (secondLine.cosinesDirector[2] * secondLine.cosinesDirector[2] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[2]) / - determinantSecond; - - mAMatrix[4] = -firstLine.cosinesDirector[1] * firstLine.cosinesDirector[2] * covarianceFirst[0] / determinantFirst - - secondLine.cosinesDirector[1] * secondLine.cosinesDirector[2] * covarianceSecond[0] / determinantSecond; - - mAMatrix[5] = (firstLine.cosinesDirector[1] * firstLine.cosinesDirector[1] * covarianceFirst[0] + - firstLine.cosinesDirector[0] * firstLine.cosinesDirector[0] * covarianceFirst[1]) / - determinantFirst + - (secondLine.cosinesDirector[1] * secondLine.cosinesDirector[1] * covarianceSecond[0] + - secondLine.cosinesDirector[0] * secondLine.cosinesDirector[0] * covarianceSecond[1]) / - determinantSecond; - - mBMatrix[0] = - (firstLine.cosinesDirector[1] * covarianceFirst[2] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[1]) + - firstLine.cosinesDirector[2] * covarianceFirst[1] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[0] + firstLine.cosinesDirector[0] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[0] += - (secondLine.cosinesDirector[1] * covarianceSecond[2] * (-secondLine.cosinesDirector[1] * secondLine.originPoint[0] + secondLine.cosinesDirector[0] * secondLine.originPoint[1]) + - secondLine.cosinesDirector[2] * covarianceSecond[1] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[0] + - secondLine.cosinesDirector[0] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[1] = - (firstLine.cosinesDirector[0] * covarianceFirst[2] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[2] * covarianceFirst[0] * (-firstLine.cosinesDirector[2] * firstLine.originPoint[1] + firstLine.cosinesDirector[1] * firstLine.originPoint[2])) / - determinantFirst; - - mBMatrix[1] += - (secondLine.cosinesDirector[0] * covarianceSecond[2] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[1] + secondLine.cosinesDirector[1] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[2] * covarianceSecond[0] * - (-secondLine.cosinesDirector[2] * secondLine.originPoint[1] + - secondLine.cosinesDirector[1] * secondLine.originPoint[2])) / - determinantSecond; - - mBMatrix[2] = - (firstLine.cosinesDirector[0] * covarianceFirst[1] * (-firstLine.cosinesDirector[0] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[0]) + - firstLine.cosinesDirector[1] * covarianceFirst[0] * (-firstLine.cosinesDirector[1] * firstLine.originPoint[2] + firstLine.cosinesDirector[2] * firstLine.originPoint[1])) / - determinantFirst; - - mBMatrix[2] += - (secondLine.cosinesDirector[0] * covarianceSecond[1] * (-secondLine.cosinesDirector[0] * secondLine.originPoint[2] + secondLine.cosinesDirector[2] * secondLine.originPoint[0]) + - secondLine.cosinesDirector[1] * covarianceSecond[0] * - (-secondLine.cosinesDirector[1] * secondLine.originPoint[2] + - secondLine.cosinesDirector[2] * secondLine.originPoint[1])) / - determinantSecond; - - computeClusterCentroid(); -} - -void ClusterLines::add(const int& lineLabel, const Line& line, const bool& weight) -{ - mLabels.push_back(lineLabel); - updateROFPoll(line); - std::array covariance{1., 1., 1.}; - - // for (int i{0}; i < 6; ++i) { - // mWeightMatrix[i] += line.weightMatrix[i]; - // } - // if(weight) line->GetSigma2P0(covariance); - - double determinant{line.cosinesDirector[2] * line.cosinesDirector[2] * covariance[0] * covariance[1] + - line.cosinesDirector[1] * line.cosinesDirector[1] * covariance[0] * covariance[2] + - line.cosinesDirector[0] * line.cosinesDirector[0] * covariance[1] * covariance[2]}; - - mAMatrix[0] += (line.cosinesDirector[2] * line.cosinesDirector[2] * covariance[1] + - line.cosinesDirector[1] * line.cosinesDirector[1] * covariance[2]) / - determinant; - mAMatrix[1] += -line.cosinesDirector[0] * line.cosinesDirector[1] * covariance[2] / determinant; - mAMatrix[2] += -line.cosinesDirector[0] * line.cosinesDirector[2] * covariance[1] / determinant; - mAMatrix[3] += (line.cosinesDirector[2] * line.cosinesDirector[2] * covariance[0] + - line.cosinesDirector[0] * line.cosinesDirector[0] * covariance[2]) / - determinant; - mAMatrix[4] += -line.cosinesDirector[1] * line.cosinesDirector[2] * covariance[0] / determinant; - mAMatrix[5] += (line.cosinesDirector[1] * line.cosinesDirector[1] * covariance[0] + - line.cosinesDirector[0] * line.cosinesDirector[0] * covariance[1]) / - determinant; - - mBMatrix[0] += (line.cosinesDirector[1] * covariance[2] * - (-line.cosinesDirector[1] * line.originPoint[0] + line.cosinesDirector[0] * line.originPoint[1]) + - line.cosinesDirector[2] * covariance[1] * - (-line.cosinesDirector[2] * line.originPoint[0] + line.cosinesDirector[0] * line.originPoint[2])) / - determinant; - mBMatrix[1] += (line.cosinesDirector[0] * covariance[2] * - (-line.cosinesDirector[0] * line.originPoint[1] + line.cosinesDirector[1] * line.originPoint[0]) + - line.cosinesDirector[2] * covariance[0] * - (-line.cosinesDirector[2] * line.originPoint[1] + line.cosinesDirector[1] * line.originPoint[2])) / - determinant; - mBMatrix[2] += (line.cosinesDirector[0] * covariance[1] * - (-line.cosinesDirector[0] * line.originPoint[2] + line.cosinesDirector[2] * line.originPoint[0]) + - line.cosinesDirector[1] * covariance[0] * - (-line.cosinesDirector[1] * line.originPoint[2] + line.cosinesDirector[2] * line.originPoint[1])) / - determinant; - - computeClusterCentroid(); - mAvgDistance2 += (Line::getDistanceFromPoint(line, mVertex) * Line::getDistanceFromPoint(line, mVertex) - mAvgDistance2) / mLabels.size(); -} - -void ClusterLines::computeClusterCentroid() -{ - - double determinant{mAMatrix[0] * (mAMatrix[3] * mAMatrix[5] - mAMatrix[4] * mAMatrix[4]) - - mAMatrix[1] * (mAMatrix[1] * mAMatrix[5] - mAMatrix[4] * mAMatrix[2]) + - mAMatrix[2] * (mAMatrix[1] * mAMatrix[4] - mAMatrix[2] * mAMatrix[3])}; - - if (determinant == 0) { - return; - } - - mVertex[0] = -(mBMatrix[0] * (mAMatrix[3] * mAMatrix[5] - mAMatrix[4] * mAMatrix[4]) - - mAMatrix[1] * (mBMatrix[1] * mAMatrix[5] - mAMatrix[4] * mBMatrix[2]) + - mAMatrix[2] * (mBMatrix[1] * mAMatrix[4] - mBMatrix[2] * mAMatrix[3])) / - determinant; - mVertex[1] = -(mAMatrix[0] * (mBMatrix[1] * mAMatrix[5] - mBMatrix[2] * mAMatrix[4]) - - mBMatrix[0] * (mAMatrix[1] * mAMatrix[5] - mAMatrix[4] * mAMatrix[2]) + - mAMatrix[2] * (mAMatrix[1] * mBMatrix[2] - mAMatrix[2] * mBMatrix[1])) / - determinant; - mVertex[2] = -(mAMatrix[0] * (mAMatrix[3] * mBMatrix[2] - mBMatrix[1] * mAMatrix[4]) - - mAMatrix[1] * (mAMatrix[1] * mBMatrix[2] - mBMatrix[1] * mAMatrix[2]) + - mBMatrix[0] * (mAMatrix[1] * mAMatrix[4] - mAMatrix[2] * mAMatrix[3])) / - determinant; -} - -bool ClusterLines::operator==(const ClusterLines& rhs) const -{ - bool retval{true}; - for (auto i{0}; i < 6; ++i) { - retval &= this->mRMS2[i] == rhs.mRMS2[i]; - } - for (auto i{0}; i < 3; ++i) { - retval &= this->mVertex[i] == rhs.mVertex[i]; - } - if (this->mLabels.size() != rhs.mLabels.size()) { - retval = false; - } else { - for (size_t i{0}; i < this->mLabels.size(); ++i) { - retval &= this->mLabels[i] == rhs.mLabels[i]; - } - } - return retval && this->mAvgDistance2 == rhs.mAvgDistance2; -} - -GPUhdi() void ClusterLines::updateROFPoll(const Line& line) -{ - // option 1: Boyer-Moore voting for rof label - if (mROFWeight == 0) { - mROF = line.getMinROF(); - mROFWeight = 1; - } else { - if (mROF == line.getMinROF()) { - mROFWeight++; - } else { - mROFWeight--; - } - } - - // option 2 - // if (mROF == -1) { - // mROF = line.getMinROF(); - // } else { - // if (line.getMinROF() < mROF) { - // mROF = line.getMinROF(); - // } - // } -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx b/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx index 87787eeee03a9..78323455c39e8 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx @@ -24,8 +24,7 @@ using namespace o2::its; std::string TrackingParameters::asString() const { - std::string str = std::format("NZb:{} NPhB:{} NROFIt:{} DRof:{} PerVtx:{} DropFail:{} ClSh:{} TtklMinPt:{:.2f} MinCl:{}", - ZBins, PhiBins, nROFsPerIterations, DeltaROF, PerPrimaryVertexProcessing, DropTFUponFailure, ClusterSharing, TrackletMinPt, MinTrackLength); + std::string str = std::format("NZb:{} NPhB:{} PerVtx:{} DropFail:{} ClSh:{} TrklMinPt:{:.2f} MinCl:{}", ZBins, PhiBins, PerPrimaryVertexProcessing, DropTFUponFailure, ClusterSharing, TrackletMinPt, MinTrackLength); bool first = true; for (int il = NLayers; il >= MinTrackLength; il--) { int slot = NLayers - il; @@ -41,15 +40,14 @@ std::string TrackingParameters::asString() const for (size_t i = 0; i < SystErrorY2.size(); i++) { str += std::format("{:.2e}/{:.2e} ", SystErrorY2[i], SystErrorZ2[i]); } - if (std::numeric_limits::max() != MaxMemory) { - str += std::format(" MemLimit {:.2f} GB", double(MaxMemory) / constants::GB); + str += std::format(" TimeSlices:{}", NTimeSlices); + if (std::any_of(DeltaROF.begin(), DeltaROF.end(), [](auto b) { return b != 0; })) { + str += " DeltaROF:["; + for (int il = 0; il < NLayers; ++il) { + str += std::to_string(DeltaROF[il]) + ","; + } + str[str.length() - 1] = ']'; } - return str; -} - -std::string VertexingParameters::asString() const -{ - std::string str = std::format("NZb:{} NPhB:{} DRof:{} ClsCont:{} MaxTrkltCls:{} ZCut:{} PhCut:{}", ZBins, PhiBins, deltaRof, clusterContributorsCut, maxTrackletsPerCluster, zCut, phiCut); if (std::numeric_limits::max() != MaxMemory) { str += std::format(" MemLimit {:.2f} GB", double(MaxMemory) / constants::GB); } @@ -100,86 +98,125 @@ std::string TrackingMode::toString(TrackingMode::Type mode) return ""; // not reachable } -std::vector TrackingMode::getTrackingParameters(TrackingMode::Type mode) +std::vector TrackingMode::getRecoIterations(TrackingMode::Type mode) { const auto& tc = o2::its::TrackerParamConfig::Instance(); - std::vector trackParams; + std::vector recoIterations; + // set the size and name if (mode == TrackingMode::Async) { - trackParams.resize(tc.doUPCIteration ? 4 : 3); - trackParams[1].TrackletMinPt = 0.2f; - trackParams[1].CellDeltaTanLambdaSigma *= 2.; - trackParams[2].TrackletMinPt = 0.1f; - trackParams[2].CellDeltaTanLambdaSigma *= 4.; + recoIterations.resize(tc.doUPCIteration ? 5 : 4); + recoIterations[0].name = "ASYNC_SEED"; + recoIterations[1].name = "ASYNC_LONG"; + recoIterations[2].name = "ASYNC_LONG_RETRY"; + recoIterations[3].name = "ASYNC_REST"; + if (tc.doUPCIteration) { + recoIterations[4].name = "ASYNC_UPC"; + } + } else if (mode == TrackingMode::Sync) { + recoIterations.resize(2); + recoIterations[0].name = "SYNC_TIGHT"; + } else if (mode == TrackingMode::Cosmics) { + // in case of cosmics we do not do the seeding step + recoIterations.resize(1); + recoIterations[0].name = "COSMICS"; + } else { + LOGP(fatal, "Unsupported ITS tracking mode {} ", toString(mode)); + } + + // always done in any first two iterations (unless cosmics) + recoIterations[0].steps.set(RecoIterationSteps::kInitMemory); + if (mode != TrackingMode::Cosmics) { + recoIterations[1].steps.set(RecoIterationSteps::kInitMemory); - trackParams[0].MinPt[0] = 1.f / 12; // 7cl - trackParams[1].MinPt[0] = 1.f / 12; // 7cl + // standards steps to configure seeding + recoIterations[0].steps.set(RecoIterationSteps::kRunTrackleting, RecoIterationSteps::kRunCellFinding, RecoIterationSteps::kRunCellSeeding, RecoIterationSteps::kUpdateClusters); + recoIterations[0].params.NLayers = 3; // only do cell finding up until the third layer + recoIterations[0].params.UseDiamond = true; // use the blown up diamond constrain to (e.g. luminous region) + recoIterations[0].params.NSigmaCut = 5.f; + recoIterations[0].params.CorrType = o2::base::PropagatorF::MatCorrType::USEMatCorrNONE; // do not use material + recoIterations[0].params.SeedingDCATolerance = tc.seedingDCATolerance; + recoIterations[0].params.SeedingDCAMaxPull = tc.seedingDCAMaxPull; + recoIterations[0].params.SeedingMaxChi2Iter = tc.seedingMaxChi2Iter; + recoIterations[0].params.SeedingTukeyStartIter = tc.seedingTukeyStartIter; + recoIterations[0].params.SeedingMinWghTrk = tc.seedingMinWghTrk; + recoIterations[0].params.SeedingMaxFitIter = tc.seedingMaxFitIter; + recoIterations[0].params.SeedingMinTracksIter = tc.seedingMinTracksIter; + recoIterations[0].params.SeedingDBScanMinPt = tc.seedingDBScanMinPt; + recoIterations[0].params.SeedingDBScanEpsZ = tc.seedingDBScanEpsZ; + recoIterations[0].params.SeedingDBScanEpsT = tc.seedingDBScanEpsT; + recoIterations[0].params.PerPrimaryVertexProcessing = false; - trackParams[2].MinTrackLength = 4; - trackParams[2].MinPt[0] = 1.f / 12; // 7cl - trackParams[2].MinPt[1] = 1.f / 5; // 6cl - trackParams[2].MinPt[2] = 1.f / 1; // 5cl - trackParams[2].MinPt[3] = 1.f / 6; // 4cl + if (tc.seedingUseMCTruth) { + recoIterations[0].name = "MC_SEEDING"; + recoIterations[0].steps.reset(); + recoIterations[0].steps.set(RecoIterationSteps::kRunTruthSeeding); + } + } + + if (mode == TrackingMode::Async) { + recoIterations[2].params.TrackletMinPt = 0.2f; + recoIterations[3].params.TrackletMinPt = 0.1f; + + recoIterations[1].params.MinPt[0] = 1.f / 12; // 7cl + recoIterations[2].params.MinPt[0] = 1.f / 12; // 7cl + + recoIterations[3].params.MinTrackLength = 4; + recoIterations[3].params.MinPt[0] = 1.f / 12; // 7cl + recoIterations[3].params.MinPt[1] = 1.f / 5; // 6cl + recoIterations[3].params.MinPt[2] = 1.f / 1; // 5cl + recoIterations[3].params.MinPt[3] = 1.f / 6; // 4cl + + recoIterations[3].params.StartLayerMask = (1 << 6) + (1 << 3); - trackParams[2].StartLayerMask = (1 << 6) + (1 << 3); if (tc.doUPCIteration) { - trackParams[3].MinTrackLength = 4; - trackParams[3].TrackletMinPt = 0.1f; - trackParams[3].CellDeltaTanLambdaSigma *= 4.; - trackParams[3].DeltaROF = 0; // UPC specific setting + recoIterations[4].params.MinTrackLength = 4; + recoIterations[4].params.TrackletMinPt = 0.1f; } - for (size_t ip = 0; ip < trackParams.size(); ip++) { - auto& param = trackParams[ip]; - param.ZBins = 64; - param.PhiBins = 32; - param.CellsPerClusterLimit = 1.e3f; - param.TrackletsPerClusterLimit = 1.e3f; + for (size_t ip = 0; ip < recoIterations.size(); ip++) { + // the seeding step is configured outside of this loop beforehand + if (ip > 0) { + recoIterations[ip].steps.set(RecoIterationSteps::kRunTrackleting, RecoIterationSteps::kRunCellFinding, RecoIterationSteps::kRunCellNeighborFinding, RecoIterationSteps::kRunRoadFinding); + if (ip == 1) { + recoIterations[ip].steps.set(RecoIterationSteps::kUpdateClusters, RecoIterationSteps::kUpdateVertexTable); + } + } + recoIterations[ip].params.ZBins = 64; + recoIterations[ip].params.PhiBins = 32; // check if something was overridden via configurable params if (ip < tc.MaxIter) { if (tc.startLayerMask[ip] > 0) { - trackParams[2].StartLayerMask = tc.startLayerMask[ip]; + recoIterations[2].params.StartLayerMask = tc.startLayerMask[ip]; } if (tc.minTrackLgtIter[ip] > 0) { - param.MinTrackLength = tc.minTrackLgtIter[ip]; + recoIterations[ip].params.MinTrackLength = tc.minTrackLgtIter[ip]; } for (int ilg = tc.MaxTrackLength; ilg >= tc.MinTrackLength; ilg--) { - int lslot0 = (tc.MaxTrackLength - ilg), lslot = lslot0 + ip * (tc.MaxTrackLength - tc.MinTrackLength + 1); + int lslot0 = (tc.MaxTrackLength - ilg), lslot = lslot0 + (static_cast(ip) * (tc.MaxTrackLength - tc.MinTrackLength + 1)); if (tc.minPtIterLgt[lslot] > 0.) { - param.MinPt[lslot0] = tc.minPtIterLgt[lslot]; + recoIterations[ip].params.MinPt[lslot0] = tc.minPtIterLgt[lslot]; } } } } } else if (mode == TrackingMode::Sync) { - trackParams.resize(1); - trackParams[0].ZBins = 64; - trackParams[0].PhiBins = 32; - trackParams[0].MinTrackLength = 4; + recoIterations[0].params.ZBins = 64; + recoIterations[0].params.PhiBins = 32; + recoIterations[0].params.MinTrackLength = 4; } else if (mode == TrackingMode::Cosmics) { - trackParams.resize(1); - trackParams[0].MinTrackLength = 4; - trackParams[0].CellDeltaTanLambdaSigma *= 10; - trackParams[0].PhiBins = 4; - trackParams[0].ZBins = 16; - trackParams[0].PVres = 1.e5f; - trackParams[0].MaxChi2ClusterAttachment = 60.; - trackParams[0].MaxChi2NDF = 40.; - trackParams[0].TrackletsPerClusterLimit = 100.; - trackParams[0].CellsPerClusterLimit = 100.; - } else { - LOGP(fatal, "Unsupported ITS tracking mode {} ", toString(mode)); - } - - float bFactor = std::abs(o2::base::Propagator::Instance()->getNominalBz()) / 5.0066791; - float bFactorTracklets = bFactor < 0.01 ? 1. : bFactor; // for tracklets only - int nROFsPerIterations = tc.nROFsPerIterations > 0 ? tc.nROFsPerIterations : -1; - - if (tc.nOrbitsPerIterations > 0) { - /// code to be used when the number of ROFs per orbit is known, this gets priority over the number of ROFs per iteration + recoIterations[0].params.MinTrackLength = 4; + recoIterations[0].params.PhiBins = 4; + recoIterations[0].params.ZBins = 16; + recoIterations[0].params.MaxChi2ClusterAttachment = 60.; + recoIterations[0].params.MaxChi2NDF = 40.; } // global parameters set for every iteration - for (auto& p : trackParams) { + float bFactor = std::abs(o2::base::Propagator::Instance()->getNominalBz()) / 5.0066791f; + float bFactorTracklets = bFactor < 0.01f ? 1.f : bFactor; // for tracklets only + for (auto& reco : recoIterations) { + auto& p = reco.params; + // adjust pT settings to actual mag. field p.TrackletMinPt *= bFactorTracklets; for (int ilg = tc.MaxTrackLength; ilg >= tc.MinTrackLength; ilg--) { @@ -189,7 +226,7 @@ std::vector TrackingMode::getTrackingParameters(TrackingMode p.ReseedIfShorter = tc.reseedIfShorter; p.ShiftRefToCluster = tc.shiftRefToCluster; p.createArtefactLabels = tc.createArtefactLabels; - + p.NTimeSlices = tc.nTimeSlices; p.PrintMemory = tc.printMemory; p.MaxMemory = tc.maxMemory; p.DropTFUponFailure = tc.dropTFUponFailure; @@ -205,28 +242,22 @@ std::vector TrackingMode::getTrackingParameters(TrackingMode p.CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT; } - if (p.NLayers == 7) { - for (int i{0}; i < 7; ++i) { - p.SystErrorY2[i] = tc.sysErrY2[i] > 0 ? tc.sysErrY2[i] : p.SystErrorY2[i]; - p.SystErrorZ2[i] = tc.sysErrZ2[i] > 0 ? tc.sysErrZ2[i] : p.SystErrorZ2[i]; - } + for (int i{0}; i < tc.MaxTrackLength; ++i) { + p.SystErrorY2[i] = tc.sysErrY2[i] > 0 ? tc.sysErrY2[i] : p.SystErrorY2[i]; + p.SystErrorZ2[i] = tc.sysErrZ2[i] > 0 ? tc.sysErrZ2[i] : p.SystErrorZ2[i]; + p.DeltaROF[i] = tc.deltaROF[i]; } - p.DeltaROF = tc.deltaRof; + p.DoUPCIteration = tc.doUPCIteration; p.MaxChi2ClusterAttachment = tc.maxChi2ClusterAttachment > 0 ? tc.maxChi2ClusterAttachment : p.MaxChi2ClusterAttachment; p.MaxChi2NDF = tc.maxChi2NDF > 0 ? tc.maxChi2NDF : p.MaxChi2NDF; p.PhiBins = tc.LUTbinsPhi > 0 ? tc.LUTbinsPhi : p.PhiBins; p.ZBins = tc.LUTbinsZ > 0 ? tc.LUTbinsZ : p.ZBins; - p.PVres = tc.pvRes > 0 ? tc.pvRes : p.PVres; p.NSigmaCut *= tc.nSigmaCut > 0 ? tc.nSigmaCut : 1.f; - p.CellDeltaTanLambdaSigma *= tc.deltaTanLres > 0 ? tc.deltaTanLres : 1.f; p.TrackletMinPt *= tc.minPt > 0 ? tc.minPt : 1.f; - p.nROFsPerIterations = nROFsPerIterations; p.PerPrimaryVertexProcessing = tc.perPrimaryVertexProcessing; - for (int iD{0}; iD < 3; ++iD) { - p.Diamond[iD] = tc.diamondPos[iD]; - } - p.UseDiamond = tc.useDiamond; + std::copy(tc.diamondPos, tc.diamondPos + 3, p.Diamond); + std::copy(tc.diamondCov, tc.diamondCov + 6, p.DiamondCov); if (tc.useTrackFollower > 0) { p.UseTrackFollower = true; // Bit 0: Allow for mixing of top&bot extension --> implies Bits 1&2 set @@ -235,76 +266,21 @@ std::vector TrackingMode::getTrackingParameters(TrackingMode p.UseTrackFollowerMix = ((tc.useTrackFollower & (1 << 0)) != 0); p.UseTrackFollowerTop = ((tc.useTrackFollower & (1 << 1)) != 0); p.UseTrackFollowerBot = ((tc.useTrackFollower & (1 << 2)) != 0); - p.TrackFollowerNSigmaCutZ = tc.trackFollowerNSigmaZ; - p.TrackFollowerNSigmaCutPhi = tc.trackFollowerNSigmaPhi; - } - if (tc.cellsPerClusterLimit >= 0) { - p.CellsPerClusterLimit = tc.cellsPerClusterLimit; - } - if (tc.trackletsPerClusterLimit >= 0) { - p.TrackletsPerClusterLimit = tc.trackletsPerClusterLimit; } if (tc.findShortTracks >= 0) { p.FindShortTracks = tc.findShortTracks; } } - if (trackParams.size() > tc.nIterations) { - trackParams.resize(tc.nIterations); + // opt. suppress layer iterations + if (tc.nIterations >= 0 && tc.nIterations < recoIterations.size()) { + recoIterations.resize(tc.nIterations); } - return trackParams; + return recoIterations; } -std::vector TrackingMode::getVertexingParameters(TrackingMode::Type mode) +std::string RecoIteration::asString() const { - const auto& vc = o2::its::VertexerParamConfig::Instance(); - std::vector vertParams; - if (mode == TrackingMode::Async) { - vertParams.resize(2); // The number of actual iterations will be set as a configKeyVal to allow for pp/PbPb choice - vertParams[1].phiCut = 0.015f; - vertParams[1].tanLambdaCut = 0.015f; - vertParams[1].vertPerRofThreshold = 0; - vertParams[1].deltaRof = 0; - } else if (mode == TrackingMode::Sync) { - vertParams.resize(1); - } else if (mode == TrackingMode::Cosmics) { - vertParams.resize(1); - } else { - LOGP(fatal, "Unsupported ITS vertexing mode {} ", toString(mode)); - } - - // global parameters set for every iteration - for (auto& p : vertParams) { - p.SaveTimeBenchmarks = vc.saveTimeBenchmarks; - p.PrintMemory = vc.printMemory; - p.MaxMemory = vc.maxMemory; - p.DropTFUponFailure = vc.dropTFUponFailure; - p.nIterations = vc.nIterations; - p.deltaRof = vc.deltaRof; - p.allowSingleContribClusters = vc.allowSingleContribClusters; - p.trackletSigma = vc.trackletSigma; - p.maxZPositionAllowed = vc.maxZPositionAllowed; - p.clusterContributorsCut = vc.clusterContributorsCut; - p.phiSpan = vc.phiSpan; - p.nThreads = vc.nThreads; - p.ZBins = vc.ZBins; - p.PhiBins = vc.PhiBins; - - p.useTruthSeeding = vc.useTruthSeeding; - p.outputContLabels = vc.outputContLabels; - } - // set for now outside to not disturb status quo - vertParams[0].vertNsigmaCut = vc.vertNsigmaCut; - vertParams[0].vertRadiusSigma = vc.vertRadiusSigma; - vertParams[0].maxTrackletsPerCluster = vc.maxTrackletsPerCluster; - vertParams[0].lowMultBeamDistCut = vc.lowMultBeamDistCut; - vertParams[0].zCut = vc.zCut; - vertParams[0].phiCut = vc.phiCut; - vertParams[0].pairCut = vc.pairCut; - vertParams[0].clusterCut = vc.clusterCut; - vertParams[0].histPairCut = vc.histPairCut; - vertParams[0].tanLambdaCut = vc.tanLambdaCut; - - return vertParams; + return std::format("recoIter:{}[{}] {}", name, steps.string(), params.asString()); } diff --git a/Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx b/Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx deleted file mode 100644 index 7152640e9a70f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/src/IndexTableUtils.cxx +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file IndexTableUtils.cxx -/// \brief -/// - -#include "ITStracking/IndexTableUtils.h" - -namespace o2 -{ -namespace its -{ - -const std::vector> index_table_utils::selectClusters( - const std::array& indexTable, - const std::array& selectedBinsRect) -{ - std::vector> filteredBins{}; - - int phiBinsNum{selectedBinsRect[3] - selectedBinsRect[1] + 1}; - - if (phiBinsNum < 0) { - phiBinsNum += constants::index_table::PhiBins; - } - - filteredBins.reserve(phiBinsNum); - - for (int iPhiBin{selectedBinsRect[1]}, iPhiCount{0}; iPhiCount < phiBinsNum; - iPhiBin = ++iPhiBin == constants::index_table::PhiBins ? 0 : iPhiBin, iPhiCount++) { - - const int firstBinIndex{index_table_utils::getBinIndex(selectedBinsRect[0], iPhiBin)}; - - filteredBins.emplace_back(indexTable[firstBinIndex], - countRowSelectedBins(indexTable, iPhiBin, selectedBinsRect[0], selectedBinsRect[2])); - } - - return filteredBins; -} -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/Seeding.cxx b/Detectors/ITSMFT/ITS/tracking/src/Seeding.cxx new file mode 100644 index 0000000000000..bca7f1002a214 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/src/Seeding.cxx @@ -0,0 +1,325 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include + +#include +#include +#include + +#include "GPUCommonMath.h" +#include "ITStracking/Seeding.h" + +namespace o2::its +{ + +float LinearizedTrack::getChi2(const dataformats::VertexBase& v) const +{ + // get residuals (Y and Z DCA in track frame) and calculate chi2 + float dx = (v.getX() * cosAlp) + (v.getY() * sinAlp) - x; // VX rotated to track frame - trackX + float dy = y + (tgP * dx) - (-v.getX() * sinAlp + v.getY() * cosAlp); + float dz = z + (tgL * dx) - v.getZ(); + float chi2 = (dy * dy * sig2YI + dz * dz * sig2ZI) + (2.f * dy * dz * sigYZI); + return chi2 / 2.f; // not using time +} + +void VertexSeed::updateTukeyScale(const LinearizedTrack* ltracks, const int* labels, const LTRef& ref) +{ + constexpr float sigma2Gaus{1.4826f}; + if (status == kIterateFirst) { + scaleSig2ITuk2I = 1.f / (tukeyC * tukeyC); + return; + } + if (status == kIterateRelaxScale) { + // relax by 1/3 + scaleSig2ITuk2I *= 2.f / 3.f; + return; + } + + std::vector chi2s; + chi2s.reserve(getNContributors()); + + for (uint32_t entry{ref.getFirstEntry()}; entry < ref.getEntriesBound(); ++entry) { + const auto& lt = ltracks[entry]; + if (lt.isDead() || labels[entry] != idx) { + continue; + } + chi2s.push_back(lt.getChi2((const dataformats::VertexBase&)*this)); + } + if (chi2s.empty()) { + return; + } + // get MAD scale + std::sort(chi2s.begin(), chi2s.end()); + float median = chi2s[chi2s.size() / 2]; + std::vector dev; + dev.reserve(chi2s.size()); + for (float c : chi2s) { + dev.push_back(o2::gpu::CAMath::Abs(c - median)); + } + std::sort(dev.begin(), dev.end()); + float mad = dev[dev.size() / 2]; + float scale = sigma2Gaus * mad; + scaleSig2ITuk2I = 1.f / (scale * tukeyC * tukeyC); +} + +void VertexSeed::resetForNewIteration() +{ + wghSum = wghChi2 = 0.f; + std::fill(C.begin(), C.end(), 0.f); + std::fill(b.begin(), b.end(), 0.f); +} + +bool VertexSeed::acceptTrack(const LinearizedTrack& lt) +{ + float chi2Red = lt.getChi2((const dataformats::VertexBase&)*this); + float wghT = (1.f - (chi2Red * scaleSig2ITuk2I)); // weighted distance to vertex + return wghT >= wghMin; +} + +void VertexSeed::accountTrack(const LinearizedTrack& lt) +{ + float chi2Red = lt.getChi2((const dataformats::VertexBase&)*this); + float wghT = (1.f - (chi2Red * scaleSig2ITuk2I)); // weighted distance to vertex + if (wghT < wghMin) { + return; + } + wghT *= wghT; + wghSum += wghT; + wghChi2 += wghT * chi2Red; + float syyI(lt.sig2YI), szzI(lt.sig2ZI), syzI(lt.sigYZI); // reweighted inverse cov + syyI *= wghT; + syzI *= wghT; + szzI *= wghT; + // solve line equation + float tmpSP = lt.sinAlp * lt.tgP, tmpCP = lt.cosAlp * lt.tgP, + tmpSC = lt.sinAlp + tmpCP, tmpCS = -lt.cosAlp + tmpSP, + tmpCL = lt.cosAlp * lt.tgL, tmpSL = lt.sinAlp * lt.tgL, + tmpYXP = lt.y - (lt.tgP * lt.x), tmpZXL = lt.z - (lt.tgL * lt.x), + tmpCLzz = tmpCL * szzI, tmpSLzz = tmpSL * szzI, tmpSCyz = tmpSC * syzI, + tmpCSyz = tmpCS * syzI, tmpCSyy = tmpCS * syyI, tmpSCyy = tmpSC * syyI, + tmpSLyz = tmpSL * syzI, tmpCLyz = tmpCL * syzI; + // symmetric matrix equation + C(0, 0) += tmpCL * (tmpCLzz + tmpSCyz + tmpSCyz) + tmpSC * tmpSCyy; // dchi^2/dx/dx + C(0, 1) += tmpCL * (tmpSLzz + tmpCSyz) + tmpSL * tmpSCyz + tmpSC * tmpCSyy; // dchi^2/dx/dy + C(0, 2) += -lt.sinAlp * syzI - tmpCLzz - tmpCP * syzI; // dchi^2/dx/dz + C(1, 1) += tmpSL * (tmpSLzz + tmpCSyz + tmpCSyz) + tmpCS * tmpCSyy; // dchi^2/dy/dy + C(1, 2) += -(tmpCSyz + tmpSLzz); // dchi^2/dy/dz + C(2, 2) += szzI; // dchi^2/dz/dz + // RHS + b(0) += -(tmpCLyz + tmpSCyy) * tmpYXP - (tmpCLzz + tmpSCyz) * tmpZXL; + b(1) += -tmpYXP * (tmpCSyy + tmpSLyz) - tmpZXL * (tmpCSyz + tmpSLzz); + b(2) += tmpZXL * szzI + tmpYXP * syzI; + // account as contributor + addContributor(); +} + +void VertexSeed::solveVertex() +{ + // solve C*a=b by inversion a=C^-1*b + if (!C.InvertFast()) { + status = kIterateFurther; + return; + } + auto sol = C * b; + setXYZ(sol(0), sol(1), sol(2)); + setCov(C(0, 0), C(1, 0), C(1, 1), C(2, 0), C(2, 1), C(2, 2)); + setChi2(wghChi2 / o2::gpu::CAMath::Max(1.f, wghSum - 3.f)); +} + +namespace dbscan +{ + +DBSCAN::DBSCAN(const DBSCANParams& p) : mParams(p), mDistance(mParams.eps) {} + +DBSCANResult DBSCAN::cluster(const LinearizedTrack* tracks, size_t n) const +{ + DBSCANResult result; + result.labels.resize(n, DB_UNVISITED); + if (n == 0) { + return result; + } + + // Step 1: Find neighbors for all points using grid + NeighborList neighbors; + findNeighbors(tracks, n, neighbors); + // Step 2: Classify points and form clusters + classify(n, neighbors, result.labels); + // Step 3: finalize results + finalize(tracks, n, result); + + return result; +} + +void DBSCAN::findNeighbors(const LinearizedTrack* tracks, size_t n, NeighborList& neighbors) const +{ + Grid grid(tracks, n, mParams.eps); + + // Parallel neighbor finding + SCOPED_TIMER("find neighbors"); + neighbors.resize(n); + tbb::parallel_for( + tbb::blocked_range(0, n), [&](const tbb::blocked_range& range) { + std::vector neighborCells; + neighborCells.reserve(9); + + for (size_t i = range.begin(); i < range.end(); ++i) { + const auto& query = tracks[i]; + if (query.isDead()) { + continue; + } + auto coords = grid.getGridCoords(i); + grid.getNeighborCells(coords, neighborCells); + for (const GridCell* cell : neighborCells) { + for (auto idx : *cell) { + if (idx == i) { + continue; + } + const float diffZ = tracks[idx].z - query.z; + if (diffZ > mParams.eps[0]) { // sorted in z the rest is not reachable + break; + } + if (diffZ < -mParams.eps[0]) { + continue; + } + if (mDistance.areNeighbours(query, tracks[idx])) { + neighbors[i].push_back(idx); + } + } + } + } + }); +} + +void DBSCAN::classify(size_t n, const NeighborList& neighbors, std::vector& labels) const +{ + SCOPED_TIMER("classify"); + + std::vector> parent(n); + std::vector isCore(n, false); + + tbb::parallel_for(size_t(0), n, [&](size_t i) { + parent[i].store(i, std::memory_order_relaxed); + isCore[i] = static_cast(neighbors[i].size()) >= mParams.minPts; + }); + + auto find = [&](size_t i) -> size_t { + size_t root = i; + while (parent[root].load(std::memory_order_relaxed) != root) { + root = parent[root].load(std::memory_order_relaxed); + } + while (parent[i].load(std::memory_order_relaxed) != root) { + size_t next = parent[i].load(std::memory_order_relaxed); + parent[i].compare_exchange_weak(next, root, std::memory_order_relaxed); + i = next; + } + return root; + }; + + auto unite = [&](size_t a, size_t b) { + while (true) { + size_t ra = find(a), rb = find(b); + if (ra == rb) { + return; + } + // Always make smaller index the root (deterministic) + if (ra > rb) { + std::swap(ra, rb); + } + size_t expected = rb; + if (parent[rb].compare_exchange_weak(expected, ra, std::memory_order_relaxed)) { + return; + } + } + }; + + // Union core-core neighbors + tbb::parallel_for(size_t(0), n, [&](size_t i) { + if (!isCore[i]) { + return; + } + for (size_t j : neighbors[i]) { + if (isCore[j]) { + unite(i, j); + } + } + }); + + // Collect unique roots and sort for deterministic cluster IDs + std::vector roots; + roots.reserve(n); + for (size_t i = 0; i < n; ++i) { + if (isCore[i] && find(i) == i) { + roots.push_back(i); + } + } + std::sort(roots.begin(), roots.end()); + + // Map root -> cluster ID (smallest root = cluster 0, etc.) + std::vector rootToCluster(n, -1); + for (int32_t c = 0; c < static_cast(roots.size()); ++c) { + rootToCluster[roots[c]] = c; + } + + // Label points + tbb::parallel_for(size_t(0), n, [&](size_t i) { + if (isCore[i]) { + labels[i] = rootToCluster[find(i)]; + } else { + // Border: assign to cluster of smallest-index core neighbor + size_t minCoreNeighbor = std::numeric_limits::max(); + for (size_t j : neighbors[i]) { + if (isCore[j] && j < minCoreNeighbor) { + minCoreNeighbor = j; + } + } + if (minCoreNeighbor != std::numeric_limits::max()) { + labels[i] = rootToCluster[find(minCoreNeighbor)]; + } else { + labels[i] = DB_NOISE; + } + } + }); +} + +void DBSCAN::finalize(const LinearizedTrack* tracks, size_t n, DBSCANResult& result) const +{ + SCOPED_TIMER("finalizing"); + // Phase 1: Count clusters and noise points + int32_t max_label = *std::ranges::max_element(result.labels); + result.nClusters = max_label + 1; + result.nNoise = static_cast(std::count(result.labels.begin(), result.labels.end(), DB_NOISE)); + // Phase 2: compute z-centroids and also set the ranges + if (result.nClusters > 0) { + result.zCentroids.resize(result.nClusters); + result.ranges.resize(result.nClusters); + tbb::parallel_for(0, result.nClusters, [&](const int32_t iCls) { + float count{0.f}, zSum = {0.f}; + uint32_t first{std::numeric_limits::max()}, last{0}; + for (size_t iTrk{0}; iTrk < n; ++iTrk) { // FIXME we rescan everything here, this can be done smarter + if (tracks[iTrk].isDead()) { + continue; + } + if (result.labels[iTrk] == iCls) { + first = o2::gpu::CAMath::Min(first, (uint32_t)iTrk); + last = o2::gpu::CAMath::Max(last, (uint32_t)iTrk); + zSum += tracks[iTrk].z; + ++count; + } + } + result.ranges[iCls].set(first, last - first + 1); + result.zCentroids[iCls] = zSum / count; + }); + } +} + +} // namespace dbscan +} // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/src/Smoother.cxx b/Detectors/ITSMFT/ITS/tracking/src/Smoother.cxx deleted file mode 100644 index f2f7dbc81398f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/src/Smoother.cxx +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -// \author matteo.concas@cern.ch - -#include "ITStracking/Smoother.h" - -namespace o2 -{ -namespace its -{ - -constexpr std::array getInverseSymm2D(const std::array& mat) -{ - const double det = mat[0] * mat[2] - mat[1] * mat[1]; - return std::array{mat[2] / det, -mat[1] / det, mat[0] / det}; -} - -// Smoother -// template -// Smoother::Smoother(TrackITSExt& track, size_t smoothingLayer, const ROframe& event, float bZ, o2::base::PropagatorF::MatCorrType corr) : mLayerToSmooth{smoothingLayer}, -// mBz(bZ), -// mCorr(corr) -// { -// -// auto propInstance = o2::base::Propagator::Instance(); -// const TrackingFrameInfo& originalTf = event.getTrackingFrameInfoOnLayer(mLayerToSmooth).at(track.getClusterIndex(mLayerToSmooth)); -// -// mOutwardsTrack = track; // This track will be propagated outwards inside the smoother! (as last step of fitting did inward propagation) -// mInwardsTrack = {track.getParamOut(), // This track will be propagated inwards inside the smoother! -// static_cast(mOutwardsTrack.getNumberOfClusters()), -999, static_cast(event.getROFrameId()), -// mOutwardsTrack.getParamOut(), mOutwardsTrack.getClusterIndexes()}; -// -// mOutwardsTrack.resetCovariance(); -// mOutwardsTrack.setChi2(0); -// mInwardsTrack.resetCovariance(); -// mInwardsTrack.setChi2(0); -// -// bool statusOutw{false}; -// bool statusInw{false}; -// -// ////////////////////// -// // Outward propagation -// for (size_t iLayer{0}; iLayer < mLayerToSmooth; ++iLayer) { -// if (mOutwardsTrack.getClusterIndex(iLayer) == constants::UnusedIndex) { // Shorter tracks -// continue; -// } -// const TrackingFrameInfo& tF = event.getTrackingFrameInfoOnLayer(iLayer).at(mOutwardsTrack.getClusterIndex(iLayer)); -// statusOutw = mOutwardsTrack.rotate(tF.alphaTrackingFrame); -// statusOutw &= propInstance->propagateToX(mOutwardsTrack, -// tF.xTrackingFrame, -// mBz, -// o2::base::PropagatorImpl::MAX_SIN_PHI, -// o2::base::PropagatorImpl::MAX_STEP, -// mCorr); -// mOutwardsTrack.setChi2(mOutwardsTrack.getChi2() + mOutwardsTrack.getPredictedChi2(tF.positionTrackingFrame, tF.covarianceTrackingFrame)); -// statusOutw &= mOutwardsTrack.o2::track::TrackParCov::update(tF.positionTrackingFrame, tF.covarianceTrackingFrame); -// // LOG(info) << "Outwards loop on inwards track, layer: " << iLayer << " x: " << mOutwardsTrack.getX(); -// } -// -// // Prediction on the previously outwards-propagated track is done on a copy, as the process seems to be not reversible -// auto outwardsClone = mOutwardsTrack; -// statusOutw = outwardsClone.rotate(originalTf.alphaTrackingFrame); -// statusOutw &= propInstance->propagateToX(outwardsClone, -// originalTf.xTrackingFrame, -// mBz, -// o2::base::PropagatorImpl::MAX_SIN_PHI, -// o2::base::PropagatorImpl::MAX_STEP, -// mCorr); -// ///////////////////// -// // Inward propagation -// for (size_t iLayer{D - 1}; iLayer > mLayerToSmooth; --iLayer) { -// if (mInwardsTrack.getClusterIndex(iLayer) == constants::UnusedIndex) { // Shorter tracks -// continue; -// } -// const TrackingFrameInfo& tF = event.getTrackingFrameInfoOnLayer(iLayer).at(mInwardsTrack.getClusterIndex(iLayer)); -// statusInw = mInwardsTrack.rotate(tF.alphaTrackingFrame); -// statusInw &= propInstance->propagateToX(mInwardsTrack, -// tF.xTrackingFrame, -// mBz, -// o2::base::PropagatorImpl::MAX_SIN_PHI, -// o2::base::PropagatorImpl::MAX_STEP, -// mCorr); -// mInwardsTrack.setChi2(mInwardsTrack.getChi2() + mInwardsTrack.getPredictedChi2(tF.positionTrackingFrame, tF.covarianceTrackingFrame)); -// statusInw &= mInwardsTrack.o2::track::TrackParCov::update(tF.positionTrackingFrame, tF.covarianceTrackingFrame); -// // LOG(info) << "Inwards loop on outwards track, layer: " << iLayer << " x: " << mInwardsTrack.getX(); -// } -// -// // Prediction on the previously inwards-propagated track is done on a copy, as the process seems to be not revesible -// auto inwardsClone = mInwardsTrack; -// statusInw = inwardsClone.rotate(originalTf.alphaTrackingFrame); -// statusInw &= propInstance->propagateToX(inwardsClone, -// originalTf.xTrackingFrame, -// mBz, -// o2::base::PropagatorImpl::MAX_SIN_PHI, -// o2::base::PropagatorImpl::MAX_STEP, -// mCorr); -// // Compute weighted local chi2 -// mInitStatus = statusInw && statusOutw; -// if (mInitStatus) { -// mBestChi2 = computeSmoothedPredictedChi2(inwardsClone, outwardsClone, originalTf.positionTrackingFrame, originalTf.covarianceTrackingFrame); -// mLastChi2 = mBestChi2; -// LOG(info) << "Smoothed chi2 on original cluster: " << mBestChi2; -// } -// } - -template -Smoother::~Smoother() = default; - -template -float Smoother::computeSmoothedPredictedChi2(const o2::track::TrackParCov& firstTrack, // outwards track: from innermost cluster to outermost - const o2::track::TrackParCov& secondTrack, // inwards track: from outermost cluster to innermost - const std::array& cls, - const std::array& clCov) -{ - // Tracks need to be already propagated, compute only chi2 - // Symmetric covariances assumed - - if (firstTrack.getX() != secondTrack.getX()) { - LOG(fatal) << "Tracks need to be propagated to the same point! secondTrack.X=" << secondTrack.getX() << " firstTrack.X=" << firstTrack.getX(); - } - - std::array pp1 = {static_cast(firstTrack.getY()), static_cast(firstTrack.getZ())}; // P1: predicted Y,Z points - std::array pp2 = {static_cast(secondTrack.getY()), static_cast(secondTrack.getZ())}; // P2: predicted Y,Z points - - std::array c1 = {static_cast(firstTrack.getSigmaY2()), - static_cast(firstTrack.getSigmaZY()), - static_cast(firstTrack.getSigmaZ2())}; // Cov. track 1 - - std::array c2 = {static_cast(secondTrack.getSigmaY2()), - static_cast(secondTrack.getSigmaZY()), - static_cast(secondTrack.getSigmaZ2())}; // Cov. track 2 - - std::array w1 = getInverseSymm2D(c1); // weight matrices - std::array w2 = getInverseSymm2D(c2); - - std::array w1w2 = {w1[0] + w2[0], w1[1] + w2[1], w1[2] + w2[2]}; // (W1 + W2) - std::array C = getInverseSymm2D(w1w2); // C = (W1+W2)^-1 - - std::array w1pp1 = {w1[0] * pp1[0] + w1[1] * pp1[1], w1[1] * pp1[0] + w1[2] * pp1[1]}; // W1 * P1 - std::array w2pp2 = {w2[0] * pp2[0] + w2[1] * pp2[1], w2[1] * pp2[0] + w2[2] * pp2[1]}; // W2 * P2 - - double Y = C[0] * (w1pp1[0] + w2pp2[0]) + C[1] * (w1pp1[1] + w2pp2[1]); // Pp: weighted normalized combination of the predictions: - double Z = C[1] * (w1pp1[0] + w2pp2[0]) + C[2] * (w1pp1[1] + w2pp2[1]); // Pp = [(W1 * P1) + (W2 * P2)] / (W1 + W2) - - std::array delta = {Y - cls[0], Z - cls[1]}; // Δ = Pp - X, X: space point of cluster (Y,Z) - std::array CCp = {C[0] + static_cast(clCov[0]), C[1] + static_cast(clCov[1]), C[2] + static_cast(clCov[2])}; // Transformation of cluster covmat: CCp = C + Cov - std::array Wp = getInverseSymm2D(CCp); // Get weight matrix: Wp = CCp^-1 - - float chi2 = static_cast(delta[0] * (Wp[0] * delta[0] + Wp[1] * delta[1]) + delta[1] * (Wp[1] * delta[0] + Wp[2] * delta[1])); // chi2 = tΔ * (Wp * Δ) - - // #ifdef CA_DEBUG - LOG(info) << "Cluster_y: " << cls[0] << " Cluster_z: " << cls[1]; - LOG(info) << "\t\t- Covariance cluster: Y2: " << clCov[0] << " YZ: " << clCov[1] << " Z2: " << clCov[2]; - LOG(info) << "\t\t- Propagated t1_y: " << pp1[0] << " t1_z: " << pp1[1]; - LOG(info) << "\t\t- Propagated t2_y: " << pp2[0] << " t2_z: " << pp2[1]; - LOG(info) << "\t\t- Covariance t1: sY2: " << c1[0] << " sYZ: " << c1[1] << " sZ2: " << c1[2]; - LOG(info) << "\t\t- Covariance t2: sY2: " << c2[0] << " sYZ: " << c2[1] << " sZ2: " << c2[2]; - LOG(info) << "Smoother prediction Y: " << Y << " Z: " << Z; - LOG(info) << "\t\t- Delta_y: " << delta[0] << " Delta_z: " << delta[1]; - LOG(info) << "\t\t- Covariance Pr: Y2: " << C[0] << " YZ: " << C[1] << " Z2: " << C[2]; - LOG(info) << "\t\t- predicted chi2 t1: " << firstTrack.getPredictedChi2(cls, clCov); - LOG(info) << "\t\t- predicted chi2 t2: " << secondTrack.getPredictedChi2(cls, clCov); - // #endif - return chi2; -} - -// template -// bool Smoother::testCluster(const int clusterId, const ROframe& event) -// { -// if (!mInitStatus) { -// return false; -// } -// auto propInstance = o2::base::Propagator::Instance(); -// const TrackingFrameInfo& testTf = event.getTrackingFrameInfoOnLayer(mLayerToSmooth).at(clusterId); -// -// bool statusOutw{false}; -// bool statusInw{false}; -// -// // Prediction on the previously outwards-propagated track is done on a copy, as the process seems to be not reversible -// auto outwardsClone = mOutwardsTrack; -// statusOutw = outwardsClone.rotate(testTf.alphaTrackingFrame); -// statusOutw &= propInstance->propagateToX(outwardsClone, -// testTf.xTrackingFrame, -// mBz, -// o2::base::PropagatorImpl::MAX_SIN_PHI, -// o2::base::PropagatorImpl::MAX_STEP, -// mCorr); -// -// // Prediction on the previously inwards-propagated track is done on a copy, as the process seems to be not reversible -// auto inwardsClone = mInwardsTrack; -// statusInw = inwardsClone.rotate(testTf.alphaTrackingFrame); -// statusInw &= propInstance->propagateToX(inwardsClone, -// testTf.xTrackingFrame, -// mBz, -// o2::base::PropagatorImpl::MAX_SIN_PHI, -// o2::base::PropagatorImpl::MAX_STEP, -// mCorr); -// if (!(statusOutw && statusInw)) { -// LOG(warning) << "Failed propagation in smoother!"; -// return false; -// } -// -// // Compute weighted local chi2 -// mLastChi2 = computeSmoothedPredictedChi2(inwardsClone, outwardsClone, testTf.positionTrackingFrame, testTf.covarianceTrackingFrame); -// LOG(info) << "Smoothed chi2 on tested cluster: " << mLastChi2; -// -// return true; -// } - -template class Smoother<7>; - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx index 0d8b461181741..8d0d831d104c0 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx @@ -14,19 +14,19 @@ /// #include -#include +#include #include "Framework/Logger.h" +#include "DetectorsRaw/HBFUtils.h" #include "ITStracking/TimeFrame.h" +#include "ITStracking/Configuration.h" #include "ITStracking/MathUtils.h" -#include "DataFormatsITSMFT/Cluster.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "DataFormatsITSMFT/TopologyDictionary.h" #include "ITSBase/GeometryTGeo.h" #include "ITSMFTBase/SegmentationAlpide.h" #include "ITStracking/BoundedAllocator.h" -#include "ITStracking/TrackingConfigParam.h" namespace { @@ -46,82 +46,31 @@ constexpr float DefClusErrorCol = o2::itsmft::SegmentationAlpide::PitchCol * 0.5 constexpr float DefClusError2Row = DefClusErrorRow * DefClusErrorRow; constexpr float DefClusError2Col = DefClusErrorCol * DefClusErrorCol; -template -void TimeFrame::addPrimaryVertices(const bounded_vector& vertices, const int iteration) -{ - for (const auto& vertex : vertices) { - mPrimaryVertices.emplace_back(vertex); // put a copy in the present - mTotVertPerIteration[iteration]++; - if (!isBeamPositionOverridden) { // beam position is updated only at first occurrence of the vertex. A bit sketchy if we have past/future vertices, it should not impact too much. - const float w = vertex.getNContributors(); - mBeamPos[0] = (mBeamPos[0] * mBeamPosWeight + vertex.getX() * w) / (mBeamPosWeight + w); - mBeamPos[1] = (mBeamPos[1] * mBeamPosWeight + vertex.getY() * w) / (mBeamPosWeight + w); - mBeamPosWeight += w; - } - } - mROFramesPV.push_back(mPrimaryVertices.size()); // current rof must have number of vertices up to present -} - -template -void TimeFrame::addPrimaryVerticesLabels(bounded_vector>& labels) -{ - mVerticesMCRecInfo.insert(mVerticesMCRecInfo.end(), labels.begin(), labels.end()); -} - -template -void TimeFrame::addPrimaryVerticesContributorLabels(bounded_vector& labels) -{ - mVerticesContributorLabels.insert(mVerticesContributorLabels.end(), labels.begin(), labels.end()); -} - -template -void TimeFrame::addPrimaryVerticesInROF(const bounded_vector& vertices, const int rofId, const int iteration) -{ - mPrimaryVertices.insert(mPrimaryVertices.begin() + mROFramesPV[rofId], vertices.begin(), vertices.end()); - for (int i = rofId + 1; i < mROFramesPV.size(); ++i) { - mROFramesPV[i] += vertices.size(); - } - mTotVertPerIteration[iteration] += vertices.size(); -} - -template -void TimeFrame::addPrimaryVerticesLabelsInROF(const bounded_vector>& labels, const int rofId) -{ - mVerticesMCRecInfo.insert(mVerticesMCRecInfo.begin() + mROFramesPV[rofId], labels.begin(), labels.end()); -} - -template -void TimeFrame::addPrimaryVerticesContributorLabelsInROF(const bounded_vector& labels, const int rofId) -{ - // count the number of cont. in rofs before and including the target rof - unsigned int n{0}; - const auto& pvs = getPrimaryVertices(0, rofId); - for (const auto& pv : pvs) { - n += pv.getNContributors(); - } - mVerticesContributorLabels.insert(mVerticesContributorLabels.begin() + n, labels.begin(), labels.end()); -} - -template -int TimeFrame::loadROFrameData(gsl::span rofs, - gsl::span clusters, - gsl::span::iterator& pattIt, - const itsmft::TopologyDictionary* dict, - const dataformats::MCTruthContainer* mcLabels) +template +void TimeFrame::loadROFrameData(gsl::span rofs, + gsl::span clusters, + gsl::span::iterator& pattIt, + const itsmft::TopologyDictionary* dict, + int layer, + const dataformats::MCTruthContainer* mcLabels) { GeometryTGeo* geom = GeometryTGeo::Instance(); geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); + resetROFrameData(layer); + prepareROFrameData(clusters, layer); - resetROFrameData(rofs.size()); - prepareROFrameData(rofs, clusters); + // check for missing/empty/unset rofs + // the code requires consistent monotonically increasing input without gaps + const auto& timing = mROFOverlapTableView.getLayer(layer); + if (timing.mNROFsTF != rofs.size()) { + LOGP(fatal, "Received inconsistent number of rofs on layer:{} expected:{} received:{}", layer, timing.mNROFsTF, rofs.size()); + } - for (size_t iRof{0}; iRof < rofs.size(); ++iRof) { + for (int32_t iRof{0}; iRof < rofs.size(); ++iRof) { const auto& rof = rofs[iRof]; for (int clusterId{rof.getFirstEntry()}; clusterId < rof.getFirstEntry() + rof.getNEntries(); ++clusterId) { const auto& c = clusters[clusterId]; - - int layer = geom->getLayer(c.getSensorID()); - + int lay = geom->getLayer(c.getSensorID()); auto pattID = c.getPatternID(); o2::math_utils::Point3D locXYZ; float sigmaY2 = DefClusError2Row, sigmaZ2 = DefClusError2Col, sigmaYZ = 0; // Dummy COG errors (about half pixel size) @@ -142,13 +91,12 @@ int TimeFrame::loadROFrameData(gsl::span r locXYZ = dict->getClusterCoordinates(c, patt, false); clusterSize = patt.getNPixels(); } - mClusterSize[clusterId] = std::clamp(clusterSize, 0u, 255u); + mClusterSize[layer][clusterId] = std::clamp(clusterSize, 0u, 255u); auto sensorID = c.getSensorID(); // Inverse transformation to the local --> tracking auto trkXYZ = geom->getMatrixT2L(sensorID) ^ locXYZ; // Transformation to the local --> global auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; - addTrackingFrameInfoToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), trkXYZ.x(), geom->getSensorRefAlpha(sensorID), std::array{trkXYZ.y(), trkXYZ.z()}, std::array{sigmaY2, sigmaYZ, sigmaZ2}); @@ -156,71 +104,56 @@ int TimeFrame::loadROFrameData(gsl::span r addClusterToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), mUnsortedClusters[layer].size()); addClusterExternalIndexToLayer(layer, clusterId); } - for (unsigned int iL{0}; iL < mUnsortedClusters.size(); ++iL) { - mROFramesClusters[iL][iRof + 1] = mUnsortedClusters[iL].size(); // effectively calculating and exclusive sum - } - } - - for (auto i = 0; i < mNTrackletsPerCluster.size(); ++i) { - mNTrackletsPerCluster[i].resize(mUnsortedClusters[1].size()); - mNTrackletsPerClusterSum[i].resize(mUnsortedClusters[1].size() + 1); // Exc sum "prepends" a 0 + mROFramesClusters[layer][iRof + 1] = mUnsortedClusters[layer].size(); // effectively calculating an exclusive sum } if (mcLabels != nullptr) { - mClusterLabels = mcLabels; + mClusterLabels[layer] = mcLabels; } - - return mNrof; } -template -void TimeFrame::resetROFrameData(size_t nRofs) +template +void TimeFrame::resetROFrameData(int layer) { - for (int iLayer{0}; iLayer < nLayers; ++iLayer) { - deepVectorClear(mUnsortedClusters[iLayer], getMaybeFrameworkHostResource()); - deepVectorClear(mTrackingFrameInfo[iLayer], getMaybeFrameworkHostResource()); - clearResizeBoundedVector(mROFramesClusters[iLayer], nRofs + 1, getMaybeFrameworkHostResource()); - deepVectorClear(mClusterExternalIndices[iLayer], mMemoryPool.get()); - - if (iLayer < 2) { - deepVectorClear(mTrackletsIndexROF[iLayer], mMemoryPool.get()); - deepVectorClear(mNTrackletsPerCluster[iLayer], mMemoryPool.get()); - deepVectorClear(mNTrackletsPerClusterSum[iLayer], mMemoryPool.get()); - } - } + deepVectorClear(mUnsortedClusters[layer], getMaybeFrameworkHostResource()); + deepVectorClear(mTrackingFrameInfo[layer], getMaybeFrameworkHostResource()); + deepVectorClear(mClusterExternalIndices[layer], mMemoryPool.get()); + clearResizeBoundedVector(mROFramesClusters[layer], mROFOverlapTableView.getLayer(layer).mNROFsTF + 1, getMaybeFrameworkHostResource()); } -template -void TimeFrame::prepareROFrameData(gsl::span rofs, - gsl::span clusters) +template +void TimeFrame::prepareROFrameData(gsl::span clusters, int layer) { GeometryTGeo* geom = GeometryTGeo::Instance(); - mNrof = rofs.size(); - clearResizeBoundedVector(mClusterSize, clusters.size(), mMemoryPool.get()); - std::array clusterCountPerLayer{}; + std::array clusterCountPerLayer{}; for (const auto& clus : clusters) { - ++clusterCountPerLayer[geom->getLayer(clus.getSensorID())]; - } - for (int iLayer{0}; iLayer < nLayers; ++iLayer) { - mUnsortedClusters[iLayer].reserve(clusterCountPerLayer[iLayer]); - mTrackingFrameInfo[iLayer].reserve(clusterCountPerLayer[iLayer]); - mClusterExternalIndices[iLayer].reserve(clusterCountPerLayer[iLayer]); + auto lay = geom->getLayer(clus.getSensorID()); + if (lay != layer) { + LOGP(fatal, "received layer from cluster {} while preparing data from {}!", lay, layer); + } + ++clusterCountPerLayer[lay]; } + mUnsortedClusters[layer].reserve(clusterCountPerLayer[layer]); + mTrackingFrameInfo[layer].reserve(clusterCountPerLayer[layer]); + mClusterExternalIndices[layer].reserve(clusterCountPerLayer[layer]); + clearResizeBoundedVector(mClusterSize[layer], clusterCountPerLayer[layer], mMemoryPool.get()); } -template -void TimeFrame::prepareClusters(const TrackingParameters& trkParam, const int maxLayers) +template +void TimeFrame::prepareClusters(const TrackingParameters& trkParam, const int maxLayers) { + const int numBins{trkParam.PhiBins * trkParam.ZBins}; const int stride{numBins + 1}; bounded_vector cHelper(mMemoryPool.get()); bounded_vector clsPerBin(numBins, 0, mMemoryPool.get()); bounded_vector lutPerBin(numBins, 0, mMemoryPool.get()); - for (int rof{0}; rof < mNrof; ++rof) { - if ((int)mMultiplicityCutMask.size() == mNrof && !mMultiplicityCutMask[rof]) { - continue; - } - for (int iLayer{0}, stopLayer = std::min(trkParam.NLayers, maxLayers); iLayer < stopLayer; ++iLayer) { + for (int iLayer{0}, stopLayer = std::min(trkParam.NLayers, maxLayers); iLayer < stopLayer; ++iLayer) { + for (int rof{0}; rof < getNrof(iLayer); ++rof) { + // TODO how to deal with mult mask? + // if ((int)mMultiplicityCutMask.size() == mNrof && !mMultiplicityCutMask[rof]) { + // continue; + // } const auto& unsortedClusters{getUnsortedClustersOnLayer(rof, iLayer)}; const int clustersNum{static_cast(unsortedClusters.size())}; auto* tableBase = mIndexTables[iLayer].data() + rof * stride; @@ -231,8 +164,12 @@ void TimeFrame::prepareClusters(const TrackingParameters& trkParam, con const Cluster& c = unsortedClusters[iCluster]; ClusterHelper& h = cHelper[iCluster]; - const float x = c.xCoordinate - mBeamPos[0]; - const float y = c.yCoordinate - mBeamPos[1]; + float x = c.xCoordinate; + float y = c.yCoordinate; + if (hasMeanVertex()) { + x -= mMeanVertex->getX(); + y -= mMeanVertex->getY(); + } const float z = c.zCoordinate; float phi = math_utils::computePhi(x, y); @@ -270,46 +207,31 @@ void TimeFrame::prepareClusters(const TrackingParameters& trkParam, con } } -template -void TimeFrame::initialise(const int iteration, const TrackingParameters& trkParam, const int maxLayers, bool resetVertices) +template +void TimeFrame::initialise(const RecoIteration& reco) { - if (iteration == 0) { - if (maxLayers < trkParam.NLayers && resetVertices) { - resetRofPV(); - deepVectorClear(mTotVertPerIteration); - } - deepVectorClear(mTracks); - deepVectorClear(mTracksLabel); - deepVectorClear(mLines); - deepVectorClear(mLinesLabels); - if (resetVertices) { - deepVectorClear(mVerticesMCRecInfo); - deepVectorClear(mVerticesContributorLabels); - } - clearResizeBoundedVector(mTracks, mNrof, mMemoryPool.get()); - clearResizeBoundedVector(mTracksLabel, mNrof, mMemoryPool.get()); - clearResizeBoundedVector(mLinesLabels, mNrof, mMemoryPool.get()); + const auto& trkParam = reco.params; + if (reco.steps[RecoIterationSteps::kInitMemory]) { + mBogusClusters.fill(0); // reset bogus counter for this TF clearResizeBoundedVector(mCells, trkParam.CellsPerRoad(), mMemoryPool.get()); clearResizeBoundedVector(mCellsLookupTable, trkParam.CellsPerRoad() - 1, mMemoryPool.get()); clearResizeBoundedVector(mCellsNeighbours, trkParam.CellsPerRoad() - 1, mMemoryPool.get()); clearResizeBoundedVector(mCellsNeighboursLUT, trkParam.CellsPerRoad() - 1, mMemoryPool.get()); clearResizeBoundedVector(mCellLabels, trkParam.CellsPerRoad(), mMemoryPool.get()); - clearResizeBoundedVector(mTracklets, std::min(trkParam.TrackletsPerRoad(), maxLayers - 1), mMemoryPool.get()); + clearResizeBoundedVector(mTracklets, trkParam.TrackletsPerRoad(), mMemoryPool.get()); clearResizeBoundedVector(mTrackletLabels, trkParam.TrackletsPerRoad(), mMemoryPool.get()); clearResizeBoundedVector(mTrackletsLookupTable, trkParam.TrackletsPerRoad(), mMemoryPool.get()); mIndexTableUtils.setTrackingParameters(trkParam); - clearResizeBoundedVector(mPositionResolution, trkParam.NLayers, mMemoryPool.get()); - clearResizeBoundedVector(mBogusClusters, trkParam.NLayers, mMemoryPool.get()); - deepVectorClear(mTrackletClusters); - for (unsigned int iLayer{0}; iLayer < std::min((int)mClusters.size(), maxLayers); ++iLayer) { - clearResizeBoundedVector(mClusters[iLayer], mUnsortedClusters[iLayer].size(), getMaybeFrameworkHostResource(maxLayers != nLayers)); - clearResizeBoundedVector(mUsedClusters[iLayer], mUnsortedClusters[iLayer].size(), getMaybeFrameworkHostResource(maxLayers != nLayers)); - mPositionResolution[iLayer] = o2::gpu::CAMath::Sqrt(0.5f * (trkParam.SystErrorZ2[iLayer] + trkParam.SystErrorY2[iLayer]) + trkParam.LayerResolution[iLayer] * trkParam.LayerResolution[iLayer]); + for (int iLayer{0}; iLayer < trkParam.NLayers; ++iLayer) { + clearResizeBoundedVector(mClusters[iLayer], mUnsortedClusters[iLayer].size(), getMaybeFrameworkHostResource()); + clearResizeBoundedVector(mUsedClusters[iLayer], mUnsortedClusters[iLayer].size(), getMaybeFrameworkHostResource()); + if (iLayer < (int)mCells.size()) { + mTrackletsLookupTable[iLayer].resize(mClusters[iLayer + 1].size() + 1, 0); + } + } + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + clearResizeBoundedVector(mIndexTables[iLayer], getNrof(iLayer) * ((trkParam.ZBins * trkParam.PhiBins) + 1), getMaybeFrameworkHostResource()); } - clearResizeBoundedArray(mIndexTables, mNrof * (trkParam.ZBins * trkParam.PhiBins + 1), getMaybeFrameworkHostResource(maxLayers != nLayers)); - clearResizeBoundedVector(mLines, mNrof, mMemoryPool.get()); - clearResizeBoundedVector(mTrackletClusters, mNrof, mMemoryPool.get()); - for (int iLayer{0}; iLayer < trkParam.NLayers; ++iLayer) { if (trkParam.SystErrorY2[iLayer] > 0.f || trkParam.SystErrorZ2[iLayer] > 0.f) { for (auto& tfInfo : mTrackingFrameInfo[iLayer]) { @@ -319,69 +241,63 @@ void TimeFrame::initialise(const int iteration, const TrackingParameter } } } - mMinR.fill(10000.); - mMaxR.fill(-1.); - } - mNTrackletsPerROF.resize(2); - for (auto& v : mNTrackletsPerROF) { - v = bounded_vector(mNrof + 1, 0, mMemoryPool.get()); - } - if (iteration == 0 || iteration == 3) { - prepareClusters(trkParam, maxLayers); - } - mTotalTracklets = {0, 0}; - if (maxLayers < trkParam.NLayers) { // Vertexer only, but in both iterations - for (size_t iLayer{0}; iLayer < maxLayers; ++iLayer) { - deepVectorClear(mUsedClusters[iLayer]); - clearResizeBoundedVector(mUsedClusters[iLayer], mUnsortedClusters[iLayer].size(), mMemoryPool.get()); - } + mMinR.fill(std::numeric_limits::max()); + mMaxR.fill(std::numeric_limits::min()); } - mTotVertPerIteration.resize(1 + iteration); - mNoVertexROF = 0; - deepVectorClear(mRoads); - deepVectorClear(mRoadLabels); - - mMSangles.resize(trkParam.NLayers); - mPhiCuts.resize(mClusters.size() - 1, 0.f); + if (reco.steps[RecoIterationSteps::kUpdateClusters]) { + prepareClusters(trkParam, reco.params.NLayers); + } - float oneOverR{0.001f * 0.3f * std::abs(mBz) / trkParam.TrackletMinPt}; - for (unsigned int iLayer{0}; iLayer < nLayers; ++iLayer) { + // these change dynamically with the given tracking parameters + mMSangles.fill(0.f); + mPhiCuts.fill(0.f); + mPositionResolution.fill(0.f); + float minCurvature{o2::gpu::CAMath::Abs(mBz * o2::constants::math::B2C) / trkParam.TrackletMinPt}; + for (int iLayer{0}; iLayer < trkParam.NLayers; ++iLayer) { mMSangles[iLayer] = math_utils::MSangle(0.14f, trkParam.TrackletMinPt, trkParam.LayerxX0[iLayer]); - mPositionResolution[iLayer] = o2::gpu::CAMath::Sqrt(0.5f * (trkParam.SystErrorZ2[iLayer] + trkParam.SystErrorY2[iLayer]) + trkParam.LayerResolution[iLayer] * trkParam.LayerResolution[iLayer]); - if (iLayer < mClusters.size() - 1) { - const float& r1 = trkParam.LayerRadii[iLayer]; - const float& r2 = trkParam.LayerRadii[iLayer + 1]; - const float res1 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[iLayer]); - const float res2 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[iLayer + 1]); - const float cosTheta1half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r1 * oneOverR)); - const float cosTheta2half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r2 * oneOverR)); - float x = r2 * cosTheta1half - r1 * cosTheta2half; - float delta = o2::gpu::CAMath::Sqrt(1.f / (1.f - 0.25f * math_utils::Sq(x * oneOverR)) * (math_utils::Sq(0.25f * r1 * r2 * math_utils::Sq(oneOverR) / cosTheta2half + cosTheta1half) * math_utils::Sq(res1) + math_utils::Sq(0.25f * r1 * r2 * math_utils::Sq(oneOverR) / cosTheta1half + cosTheta2half) * math_utils::Sq(res2))); - mPhiCuts[iLayer] = std::min(o2::gpu::CAMath::ASin(0.5f * x * oneOverR) + 2.f * mMSangles[iLayer] + delta, o2::constants::math::PI * 0.5f); + mPositionResolution[iLayer] = o2::gpu::CAMath::Sqrt((0.5f * (trkParam.SystErrorZ2[iLayer] + trkParam.SystErrorY2[iLayer])) + math_utils::Sq(trkParam.LayerResolution[iLayer])); + if (iLayer < trkParam.NLayers - 1) { + const float r1 = trkParam.LayerRadii[iLayer]; + const float r2 = trkParam.LayerRadii[iLayer + 1]; + const float res1 = mPositionResolution[iLayer]; + const float res2 = mPositionResolution[iLayer + 1]; + const float cosTheta1half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r1 * minCurvature)); + const float cosTheta2half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r2 * minCurvature)); + float x = (r2 * cosTheta1half) - (r1 * cosTheta2half); + float delta = o2::gpu::CAMath::Sqrt(1.f / (1.f - 0.25f * math_utils::Sq(x * minCurvature)) * (math_utils::Sq((0.25f * r1 * r2 * math_utils::Sq(minCurvature) / cosTheta2half) + cosTheta1half) * math_utils::Sq(res1) + math_utils::Sq((0.25f * r1 * r2 * math_utils::Sq(minCurvature) / cosTheta1half) + cosTheta2half) * math_utils::Sq(res2))); + mPhiCuts[iLayer] = std::min(o2::gpu::CAMath::ASin(0.5f * x * minCurvature) + 2.f * mMSangles[iLayer] + delta, o2::constants::math::PI * 0.5f); } } - for (int iLayer{0}; iLayer < std::min((int)mTracklets.size(), maxLayers); ++iLayer) { - deepVectorClear(mTracklets[iLayer]); - deepVectorClear(mTrackletLabels[iLayer]); - if (iLayer < (int)mCells.size()) { - deepVectorClear(mCells[iLayer]); - deepVectorClear(mTrackletsLookupTable[iLayer]); - mTrackletsLookupTable[iLayer].resize(mClusters[iLayer + 1].size() + 1, 0); - deepVectorClear(mCellLabels[iLayer]); - } - - if (iLayer < (int)mCells.size() - 1) { - deepVectorClear(mCellsLookupTable[iLayer]); - deepVectorClear(mCellsNeighbours[iLayer]); - deepVectorClear(mCellsNeighboursLUT[iLayer]); - } + if (static bool initOnce{false}; !initOnce) { + initOnce = true; + // initialise the rolling vertex once with large weights + mRollingVertex.setX(0.f); + mRollingVertex.setY(0.f); + mRollingVertex.setZ(0.f); + mRollingVertex.setCov(1e6, dataformats::VertexBase::kCovXX); + mRollingVertex.setCov(1e6, dataformats::VertexBase::kCovYY); + mRollingVertex.setCov(1e6, dataformats::VertexBase::kCovZZ); } } -template -unsigned long TimeFrame::getArtefactsMemory() const +template +void TimeFrame::setMeanVertex(const dataformats::MeanVertexObject* mv, float extraErr2) +{ + mMeanVertex = mv; + float ex2 = mMeanVertex->getSigmaX2() + extraErr2, ey2 = mMeanVertex->getSigmaY2() + extraErr2, exy = mMeanVertex->getSigmaXY(); + float det = (ex2 * ey2) - (exy * exy); + if (det < constants::Tolerance || ex2 < constants::Tolerance || ey2 < constants::Tolerance) { + LOGP(fatal, "Singular matrix for mean vertex sxx={:+.4e} syy={:+.4e} sxy={:+.4e}", ex2, ey2, exy); + } + mMeanVertexXYInvErr[0] = ey2 / det; + mMeanVertexXYInvErr[1] = -exy / det; + mMeanVertexXYInvErr[2] = -ex2 / det; +} + +template +unsigned long TimeFrame::getArtefactsMemory() const { unsigned long size{0}; for (const auto& trkl : mTracklets) { @@ -393,17 +309,17 @@ unsigned long TimeFrame::getArtefactsMemory() const for (const auto& cellsN : mCellsNeighbours) { size += sizeof(int) * cellsN.size(); } - return size + sizeof(Road) * mRoads.size(); + return size + sizeof(Road) * mRoads.size(); } -template -void TimeFrame::printArtefactsMemory() const +template +void TimeFrame::printArtefactsMemory() const { LOGP(info, "TimeFrame: Artefacts occupy {:.2f} MB", getArtefactsMemory() / constants::MB); } -template -void TimeFrame::fillPrimaryVerticesXandAlpha() +template +void TimeFrame::fillPrimaryVerticesXandAlpha() { deepVectorClear(mPValphaX); mPValphaX.reserve(mPrimaryVertices.size()); @@ -412,157 +328,10 @@ void TimeFrame::fillPrimaryVerticesXandAlpha() } } -template -void TimeFrame::computeTrackletsPerROFScans() -{ - for (ushort iLayer = 0; iLayer < 2; ++iLayer) { - for (unsigned int iRof{0}; iRof < mNrof; ++iRof) { - if (mMultiplicityCutMask[iRof]) { - mTotalTracklets[iLayer] += mNTrackletsPerROF[iLayer][iRof]; - } - } - std::exclusive_scan(mNTrackletsPerROF[iLayer].begin(), mNTrackletsPerROF[iLayer].end(), mNTrackletsPerROF[iLayer].begin(), 0); - std::exclusive_scan(mNTrackletsPerCluster[iLayer].begin(), mNTrackletsPerCluster[iLayer].end(), mNTrackletsPerClusterSum[iLayer].begin(), 0); - } -} - -template -void TimeFrame::checkTrackletLUTs() -{ - for (uint32_t iLayer{0}; iLayer < getTracklets().size(); ++iLayer) { - int prev{-1}; - int count{0}; - for (uint32_t iTracklet{0}; iTracklet < getTracklets()[iLayer].size(); ++iTracklet) { - auto& trk = getTracklets()[iLayer][iTracklet]; - int currentId{trk.firstClusterIndex}; - if (currentId < prev) { - LOG(info) << "First Cluster Index not increasing monotonically on L:T:ID:Prev " << iLayer << "\t" << iTracklet << "\t" << currentId << "\t" << prev; - } else if (currentId == prev) { - count++; - } else { - if (iLayer > 0) { - auto& lut{getTrackletsLookupTable()[iLayer - 1]}; - if (count != lut[prev + 1] - lut[prev]) { - LOG(info) << "LUT count broken " << iLayer - 1 << "\t" << prev << "\t" << count << "\t" << lut[prev + 1] << "\t" << lut[prev]; - } - } - count = 1; - } - prev = currentId; - if (iLayer > 0) { - auto& lut{getTrackletsLookupTable()[iLayer - 1]}; - if (iTracklet >= (uint32_t)(lut[currentId + 1]) || iTracklet < (uint32_t)(lut[currentId])) { - LOG(info) << "LUT broken: " << iLayer - 1 << "\t" << currentId << "\t" << iTracklet; - } - } - } - } -} - -template -void TimeFrame::printTrackletLUTonLayer(int i) -{ - LOG(info) << "-------- Tracklet LUT " << i; - std::stringstream s; - for (int j : mTrackletsLookupTable[i]) { - s << j << "\t"; - } - LOG(info) << s.str(); - LOG(info) << "--------"; -} - -template -void TimeFrame::printCellLUTonLayer(int i) -{ - LOG(info) << "-------- Cell LUT " << i; - std::stringstream s; - for (int j : mCellsLookupTable[i]) { - s << j << "\t"; - } - LOG(info) << s.str(); - LOG(info) << "--------"; -} - -template -void TimeFrame::printTrackletLUTs() -{ - for (unsigned int i{0}; i < mTrackletsLookupTable.size(); ++i) { - printTrackletLUTonLayer(i); - } -} - -template -void TimeFrame::printCellLUTs() -{ - for (unsigned int i{0}; i < mCellsLookupTable.size(); ++i) { - printCellLUTonLayer(i); - } -} - -template -void TimeFrame::printVertices() -{ - LOG(info) << "Vertices in ROF (nROF = " << mNrof << ", lut size = " << mROFramesPV.size() << ")"; - for (unsigned int iR{0}; iR < mROFramesPV.size(); ++iR) { - LOG(info) << mROFramesPV[iR] << "\t"; - } - LOG(info) << "\n\n Vertices:"; - for (unsigned int iV{0}; iV < mPrimaryVertices.size(); ++iV) { - LOG(info) << mPrimaryVertices[iV].getX() << "\t" << mPrimaryVertices[iV].getY() << "\t" << mPrimaryVertices[iV].getZ(); - } - LOG(info) << "--------"; -} - -template -void TimeFrame::printROFoffsets() -{ - LOG(info) << "--------"; - for (unsigned int iLayer{0}; iLayer < mROFramesClusters.size(); ++iLayer) { - LOG(info) << "Layer " << iLayer; - std::stringstream s; - for (auto value : mROFramesClusters[iLayer]) { - s << value << "\t"; - } - LOG(info) << s.str(); - } -} - -template -void TimeFrame::printNClsPerROF() +template +void TimeFrame::setMemoryPool(std::shared_ptr pool) { - LOG(info) << "--------"; - for (unsigned int iLayer{0}; iLayer < mNClustersPerROF.size(); ++iLayer) { - LOG(info) << "Layer " << iLayer; - std::stringstream s; - for (auto& value : mNClustersPerROF[iLayer]) { - s << value << "\t"; - } - LOG(info) << s.str(); - } -} - -template -void TimeFrame::printSliceInfo(const int startROF, const int sliceSize) -{ - LOG(info) << "Dumping slice of " << sliceSize << " rofs:"; - for (int iROF{startROF}; iROF < startROF + sliceSize; ++iROF) { - LOG(info) << "ROF " << iROF << " dump:"; - for (unsigned int iLayer{0}; iLayer < mClusters.size(); ++iLayer) { - LOG(info) << "Layer " << iLayer << " has: " << getClustersOnLayer(iROF, iLayer).size() << " clusters."; - } - LOG(info) << "Number of seeding vertices: " << getPrimaryVertices(iROF).size(); - int iVertex{0}; - for (auto& v : getPrimaryVertices(iROF)) { - LOG(info) << "\t vertex " << iVertex++ << ": x=" << v.getX() << " " - << " y=" << v.getY() << " z=" << v.getZ() << " has " << v.getNContributors() << " contributors."; - } - } -} - -template -void TimeFrame::setMemoryPool(std::shared_ptr pool) -{ - mMemoryPool = pool; + mMemoryPool = std::move(pool); auto initVector = [&](bounded_vector& vec, bool useExternal = false) { std::pmr::memory_resource* mr = (useExternal) ? mExtMemoryPool.get() : mMemoryPool.get(); @@ -576,33 +345,21 @@ void TimeFrame::setMemoryPool(std::shared_ptr po }; // these will only reside on the host for the cpu part - initVector(mTotVertPerIteration); initContainers(mClusterExternalIndices); - initContainers(mNTrackletsPerCluster); - initContainers(mNTrackletsPerClusterSum); - initContainers(mNClustersPerROF); - initVector(mROFramesPV); initVector(mPrimaryVertices); initVector(mRoads); - initVector(mMSangles); - initVector(mPhiCuts); - initVector(mPositionResolution); - initVector(mClusterSize); + initContainers(mClusterSize); initVector(mPValphaX); - initVector(mBogusClusters); - initContainers(mTrackletsIndexROF); - initContainers(mTracks); + initVector(mTracks); initContainers(mTracklets); initContainers(mCells); initContainers(mCellsNeighbours); initContainers(mCellsLookupTable); - // MC info (we don't know if we have MC) - initVector(mVerticesContributorLabels); - initContainers(mLinesLabels); + // MC info (we don't know if we have MC (yet)) initContainers(mTrackletLabels); initContainers(mCellLabels); - initVector(mRoadLabels); - initContainers(mTracksLabel); + initVector(mTracksLabel); + initVector(mPrimaryVerticesLabels); // these will use possibly an externally provided allocator initContainers(mClusters, hasFrameworkAllocator()); initContainers(mUsedClusters, hasFrameworkAllocator()); @@ -619,8 +376,8 @@ void TimeFrame::setFrameworkAllocator(ExternalAllocator* ext) mExtMemoryPool = std::make_shared(mExternalAllocator); } -template -void TimeFrame::wipe() +template +void TimeFrame::wipe() { deepVectorClear(mTracks); deepVectorClear(mTracklets); @@ -628,23 +385,11 @@ void TimeFrame::wipe() deepVectorClear(mRoads); deepVectorClear(mCellsNeighbours); deepVectorClear(mCellsLookupTable); - deepVectorClear(mTotVertPerIteration); deepVectorClear(mPrimaryVertices); deepVectorClear(mTrackletsLookupTable); deepVectorClear(mClusterExternalIndices); - deepVectorClear(mNTrackletsPerCluster); - deepVectorClear(mNTrackletsPerClusterSum); - deepVectorClear(mNClustersPerROF); - deepVectorClear(mROFramesPV); - deepVectorClear(mMSangles); - deepVectorClear(mPhiCuts); - deepVectorClear(mPositionResolution); deepVectorClear(mClusterSize); deepVectorClear(mPValphaX); - deepVectorClear(mBogusClusters); - deepVectorClear(mTrackletsIndexROF); - deepVectorClear(mTrackletClusters); - deepVectorClear(mLines); // if we use the external host allocator then the assumption is that we // don't clear the memory ourself if (!hasFrameworkAllocator()) { @@ -657,12 +402,10 @@ void TimeFrame::wipe() } // only needed to clear if we have MC info if (hasMCinformation()) { - deepVectorClear(mLinesLabels); - deepVectorClear(mVerticesContributorLabels); deepVectorClear(mTrackletLabels); deepVectorClear(mCellLabels); - deepVectorClear(mRoadLabels); deepVectorClear(mTracksLabel); + deepVectorClear(mPrimaryVerticesLabels); } } diff --git a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx index 59459dcab17e8..9eafb49c3aaf4 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx @@ -16,60 +16,46 @@ #include "ITStracking/Tracker.h" #include "ITStracking/BoundedAllocator.h" -#include "ITStracking/Cell.h" +#include "ITStracking/Configuration.h" #include "ITStracking/Constants.h" -#include "ITStracking/IndexTableUtils.h" -#include "ITStracking/Tracklet.h" +#include "ITStracking/ROFLookupTables.h" #include "ITStracking/TrackerTraits.h" #include "ITStracking/TrackingConfigParam.h" -#include "ReconstructionDataFormats/Track.h" #include #include #include #include -#include namespace o2::its { using o2::its::constants::GB; -template -Tracker::Tracker(TrackerTraits* traits) : mTraits(traits) +template +Tracker::Tracker(TrackerTraits* traits) : mTraits(traits) { - /// Initialise standard configuration with 1 iteration - mTrkParams.resize(1); if (traits->isGPU()) { ITSGpuTrackingParamConfig::Instance().maybeOverride(); ITSGpuTrackingParamConfig::Instance().printKeyValues(true, true); } } -template -void Tracker::clustersToTracks(const LogFunc& logger, const LogFunc& error) +template +void Tracker::clustersToTracks(const LogFunc& logger, const LogFunc& error) { LogFunc evalLog = [](const std::string&) {}; double total{0}; - mTraits->updateTrackingParameters(mTrkParams); - int maxNvertices{-1}; - if (mTrkParams[0].PerPrimaryVertexProcessing) { - for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { - int minRof = o2::gpu::CAMath::Max(0, iROF - mTrkParams[0].DeltaROF); - int maxRof = o2::gpu::CAMath::Min(mTimeFrame->getNrof(), iROF + mTrkParams[0].DeltaROF); - maxNvertices = std::max(maxNvertices, (int)mTimeFrame->getPrimaryVertices(minRof, maxRof).size()); - } - } + mTraits->updateTrackingParameters(mRecoParams); - int iteration{0}, iROFs{0}, iVertex{0}; + int iteration{0}, iSlice{0}, iVertex{0}, maxNvertices{-1}; auto handleException = [&](const auto& err) { - LOGP(error, "Too much memory used during {} in iteration {} in ROF span {}-{} iVtx={}: {:.2f} GB. Current limit is {:.2f} GB, check the detector status and/or the selections.", - StateNames[mCurState], iteration, iROFs, iROFs + mTrkParams[iteration].nROFsPerIterations, iVertex, - (double)mTimeFrame->getArtefactsMemory() / GB, (double)mTrkParams[iteration].MaxMemory / GB); + LOGP(error, "Too much memory used during {} in slice {} in iteration {} iVtx={}: {:.2f} GB. Current limit is {:.2f} GB, check the detector status and/or the selections.", + StateNames[mCurState], iSlice, iteration, iVertex, (double)mTimeFrame->getArtefactsMemory() / GB, (double)mRecoParams[iteration].params.MaxMemory / GB); if (typeid(err) != typeid(std::bad_alloc)) { // only print if the exceptions is different from what is expected LOGP(error, "Exception: {}", err.what()); } - if (mTrkParams[iteration].DropTFUponFailure) { + if (mRecoParams[iteration].params.DropTFUponFailure) { mMemoryPool->print(); mTimeFrame->wipe(); ++mNumberOfDroppedTFs; @@ -80,57 +66,83 @@ void Tracker::clustersToTracks(const LogFunc& logger, const LogFunc& er }; try { - for (iteration = 0; iteration < (int)mTrkParams.size(); ++iteration) { - mMemoryPool->setMaxMemory(mTrkParams[iteration].MaxMemory); - if (iteration == 3 && mTrkParams[0].DoUPCIteration) { - mTimeFrame->swapMasks(); + for (iteration = 0; iteration < (int)mRecoParams.size(); ++iteration) { + const auto& reco = mRecoParams[iteration]; + mMemoryPool->setMaxMemory(reco.params.MaxMemory); + // rebuilt rof -> vertex lookup table + if (reco.steps[RecoIterationSteps::kUpdateVertexTable] && mTimeFrame->getROFVertexLookupTable().needsUpdate()) { + mTimeFrame->updateROFVertexLookupTable(); + } + if (reco.params.PerPrimaryVertexProcessing) { // find the largest span of seeding vertices found + maxNvertices = mTimeFrame->getROFVertexLookupTableView().getMaxVerticesPerROF(); } - double timeTracklets{0.}, timeCells{0.}, timeNeighbours{0.}, timeRoads{0.}; - int nTracklets{0}, nCells{0}, nNeighbours{0}, nTracks{-static_cast(mTimeFrame->getNumberOfTracks())}; - int nROFsIterations = (mTrkParams[iteration].nROFsPerIterations > 0 && !mTimeFrame->isGPU()) ? mTimeFrame->getNrof() / mTrkParams[iteration].nROFsPerIterations + bool(mTimeFrame->getNrof() % mTrkParams[iteration].nROFsPerIterations) : 1; + + // FIXME: + // if (iteration == 3 && mTrkParams[0].DoUPCIteration) { + // UPC: mark all already used ROFs and + // then only use those where no tracjs where found. + // has to be the last iteration + // } + + double timeTracklets{0.}, timeCells{0.}, timeCellSeeds{0.}, timeNeighbours{0.}, timeRoads{0.}; + int nTracklets{0}, nCells{0}, nCellSeeds{-static_cast(mTimeFrame->getPrimaryVerticesNum())}, nNeighbours{0}, nTracks{-static_cast(mTimeFrame->getNumberOfTracks())}; iVertex = std::min(maxNvertices, 0); - logger(std::format("==== ITS {} Tracking iteration {} summary ====", mTraits->getName(), iteration)); + logger(std::format("==== ITS {} Tracking iteration {} summary ==== ({})", mTraits->getName(), iteration, reco.name)); - total += evaluateTask(&Tracker::initialiseTimeFrame, StateNames[mCurState = TFInit], iteration, logger, iteration); + if (reco.steps[RecoIterationSteps::kRunTruthSeeding]) { + evaluateTask(&Tracker::computeTruthSeeding, StateNames[mCurState = kTruthSeeding], iteration, evalLog); + continue; + } + + total += evaluateTask(&Tracker::initialiseTimeFrame, StateNames[mCurState = kTFInit], iteration, logger); do { - for (iROFs = 0; iROFs < nROFsIterations; ++iROFs) { - timeTracklets += evaluateTask(&Tracker::computeTracklets, StateNames[mCurState = Trackleting], iteration, evalLog, iteration, iROFs, iVertex); - nTracklets += mTraits->getTFNumberOfTracklets(); - float trackletsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfTracklets()) / float(mTraits->getTFNumberOfClusters()) : 0.f; - if (trackletsPerCluster > mTrkParams[iteration].TrackletsPerClusterLimit) { - error(std::format("Too many tracklets per cluster ({}) in iteration {} in ROF span {}-{}:, check the detector status and/or the selections. Current limit is {}", - trackletsPerCluster, iteration, iROFs, iROFs + mTrkParams[iteration].nROFsPerIterations, mTrkParams[iteration].TrackletsPerClusterLimit)); - break; + for (iSlice = 0; iSlice < reco.params.NTimeSlices; ++iSlice) { + if (reco.steps[RecoIterationSteps::kRunTrackleting]) { + timeTracklets += evaluateTask(&Tracker::computeTracklets, StateNames[mCurState = kTrackleting], iteration, evalLog, iSlice, iVertex); + nTracklets += mTraits->getTFNumberOfTracklets(); } - timeCells += evaluateTask(&Tracker::computeCells, StateNames[mCurState = Celling], iteration, evalLog, iteration); - nCells += mTraits->getTFNumberOfCells(); - float cellsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfCells()) / float(mTraits->getTFNumberOfClusters()) : 0.f; - if (cellsPerCluster > mTrkParams[iteration].CellsPerClusterLimit) { - error(std::format("Too many cells per cluster ({}) in iteration {} in ROF span {}-{}, check the detector status and/or the selections. Current limit is {}", - cellsPerCluster, iteration, iROFs, iROFs + mTrkParams[iteration].nROFsPerIterations, mTrkParams[iteration].CellsPerClusterLimit)); - break; + if (reco.steps[RecoIterationSteps::kRunCellFinding]) { + timeCells += evaluateTask(&Tracker::computeCells, StateNames[mCurState = kCelling], iteration, evalLog); + nCells += mTraits->getTFNumberOfCells(); + } + if (reco.steps[RecoIterationSteps::kRunCellSeeding]) { + timeCellSeeds += evaluateTask(&Tracker::findCellSeeds, StateNames[mCurState = kSeeding], iteration, evalLog); + nCellSeeds += mTimeFrame->getPrimaryVerticesNum(); + } + if (reco.steps[RecoIterationSteps::kRunCellNeighborFinding]) { + timeNeighbours += evaluateTask(&Tracker::findCellsNeighbours, StateNames[mCurState = kNeighbouring], iteration, evalLog); + nNeighbours += mTimeFrame->getNumberOfNeighbours(); + } + if (reco.steps[RecoIterationSteps::kRunRoadFinding]) { + timeRoads += evaluateTask(&Tracker::findRoads, StateNames[mCurState = kRoading], iteration, evalLog); } - timeNeighbours += evaluateTask(&Tracker::findCellsNeighbours, StateNames[mCurState = Neighbouring], iteration, evalLog, iteration); - nNeighbours += mTimeFrame->getNumberOfNeighbours(); - timeRoads += evaluateTask(&Tracker::findRoads, StateNames[mCurState = Roading], iteration, evalLog, iteration); } } while (++iVertex < maxNvertices); - logger(std::format(" - Tracklet finding: {} tracklets found in {:.2f} ms", nTracklets, timeTracklets)); - logger(std::format(" - Cell finding: {} cells found in {:.2f} ms", nCells, timeCells)); - logger(std::format(" - Neighbours finding: {} neighbours found in {:.2f} ms", nNeighbours, timeNeighbours)); - logger(std::format(" - Track finding: {} tracks found in {:.2f} ms", nTracks + mTimeFrame->getNumberOfTracks(), timeRoads)); - total += timeTracklets + timeCells + timeNeighbours + timeRoads; - if (mTraits->supportsExtendTracks() && mTrkParams[iteration].UseTrackFollower) { - int nExtendedTracks{-mTimeFrame->mNExtendedTracks}, nExtendedClusters{-mTimeFrame->mNExtendedUsedClusters}; - auto timeExtending = evaluateTask(&Tracker::extendTracks, "Extending tracks", iteration, evalLog, iteration); - total += timeExtending; - logger(std::format(" - Extending Tracks: {} extended tracks using {} clusters found in {:.2f} ms", nExtendedTracks + mTimeFrame->mNExtendedTracks, nExtendedClusters + mTimeFrame->mNExtendedUsedClusters, timeExtending)); + if (reco.steps[RecoIterationSteps::kRunTrackleting]) { + logger(std::format(" - Tracklet finding: {} tracklets found in {:.2f} ms", nTracklets, timeTracklets)); + } + if (reco.steps[RecoIterationSteps::kRunCellFinding]) { + logger(std::format(" - Cell finding: {} cells found in {:.2f} ms", nCells, timeCells)); } - if (mTrkParams[iteration].PrintMemory) { - mMemoryPool->print(); + if (reco.steps[RecoIterationSteps::kRunCellSeeding]) { + logger(std::format(" - Cell seeding: {} seeds found in {:.2f} ms", nCellSeeds, timeCellSeeds)); } + if (reco.steps[RecoIterationSteps::kRunCellNeighborFinding]) { + logger(std::format(" - Neighbours finding: {} neighbours found in {:.2f} ms", nNeighbours, timeNeighbours)); + } + if (reco.steps[RecoIterationSteps::kRunRoadFinding]) { + logger(std::format(" - Track finding: {} tracks found in {:.2f} ms", nTracks + mTimeFrame->getNumberOfTracks(), timeRoads)); + } + total += timeTracklets + timeCells + timeNeighbours + timeRoads + timeCellSeeds; + // FIXME: + // if (mTraits->supportsExtendTracks() && mTrkParams[iteration].UseTrackFollower) { + // int nExtendedTracks{-mTimeFrame->mNExtendedTracks}, nExtendedClusters{-mTimeFrame->mNExtendedUsedClusters}; + // auto timeExtending = evaluateTask(&Tracker::extendTracks, "Extending tracks", iteration, evalLog, iteration); + // total += timeExtending; + // logger(std::format(" - Extending Tracks: {} extended tracks using {} clusters found in {:.2f} ms", nExtendedTracks + mTimeFrame->mNExtendedTracks, nExtendedClusters + mTimeFrame->mNExtendedUsedClusters, timeExtending)); + // } } - if (mTraits->supportsFindShortPrimaries() && mTrkParams[0].FindShortTracks) { + if (mTraits->supportsFindShortPrimaries() && mRecoParams[0].params.FindShortTracks) { auto nTracksB = mTimeFrame->getNumberOfTracks(); total += evaluateTask(&Tracker::findShortPrimaries, "Short primaries finding", 0, logger); auto nTracksA = mTimeFrame->getNumberOfTracks(); @@ -153,203 +165,123 @@ void Tracker::clustersToTracks(const LogFunc& logger, const LogFunc& er computeTracksMClabels(); } rectifyClusterIndices(); + sortTracks(); + ++mTimeFrameCounter; mTotalTime += total; - - if (mTrkParams[0].PrintMemory) { - mTimeFrame->printArtefactsMemory(); - mMemoryPool->print(); - } } -template -void Tracker::computeRoadsMClabels() +template +void Tracker::computeTracksMClabels() { - /// Moore's Voting Algorithm - if (!mTimeFrame->hasMCinformation()) { - return; - } - - mTimeFrame->initialiseRoadLabels(); - - int roadsNum{static_cast(mTimeFrame->getRoads().size())}; - - for (int iRoad{0}; iRoad < roadsNum; ++iRoad) { - - auto& currentRoad{mTimeFrame->getRoads()[iRoad]}; + for (auto& track : mTimeFrame->getTracks()) { std::vector> occurrences; - bool isFakeRoad{false}; - bool isFirstRoadCell{true}; - - for (int iCell{0}; iCell < mTrkParams[0].CellsPerRoad(); ++iCell) { - const int currentCellIndex{currentRoad[iCell]}; + occurrences.clear(); - if (currentCellIndex == constants::UnusedIndex) { - if (isFirstRoadCell) { - continue; - } else { - break; - } + for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { + const int index = track.getClusterIndex(iCluster); + if (index == constants::UnusedIndex) { + continue; } - - const auto& currentCell{mTimeFrame->getCells()[iCell][currentCellIndex]}; - - if (isFirstRoadCell) { - - const int cl0index{mTimeFrame->getClusters()[iCell][currentCell.getFirstClusterIndex()].clusterId}; - auto cl0labs{mTimeFrame->getClusterLabels(iCell, cl0index)}; - bool found{false}; - for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { - std::pair& occurrence = occurrences[iOcc]; - for (const auto& label : cl0labs) { - if (label == occurrence.first) { - ++occurrence.second; - found = true; - // break; // uncomment to stop to the first hit - } - } - } - if (!found) { - for (const auto& label : cl0labs) { - occurrences.emplace_back(label, 1); - } - } - - const int cl1index{mTimeFrame->getClusters()[iCell + 1][currentCell.getSecondClusterIndex()].clusterId}; - - const auto& cl1labs{mTimeFrame->getClusterLabels(iCell + 1, cl1index)}; - found = false; - for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { - std::pair& occurrence = occurrences[iOcc]; - for (auto& label : cl1labs) { - if (label == occurrence.first) { - ++occurrence.second; - found = true; - // break; // uncomment to stop to the first hit - } - } - } - if (!found) { - for (auto& label : cl1labs) { - occurrences.emplace_back(label, 1); - } - } - - isFirstRoadCell = false; - } - - const int cl2index{mTimeFrame->getClusters()[iCell + 2][currentCell.getThirdClusterIndex()].clusterId}; - const auto& cl2labs{mTimeFrame->getClusterLabels(iCell + 2, cl2index)}; + auto labels = mTimeFrame->getClusterLabels(iCluster, index); bool found{false}; for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { std::pair& occurrence = occurrences[iOcc]; - for (auto& label : cl2labs) { + for (const auto& label : labels) { if (label == occurrence.first) { ++occurrence.second; found = true; - // break; // uncomment to stop to the first hit } } } if (!found) { - for (auto& label : cl2labs) { + for (const auto& label : labels) { occurrences.emplace_back(label, 1); } } } - - std::sort(occurrences.begin(), occurrences.end(), [](auto e1, auto e2) { + std::sort(std::begin(occurrences), std::end(occurrences), [](auto e1, auto e2) { return e1.second > e2.second; }); auto maxOccurrencesValue = occurrences[0].first; - mTimeFrame->setRoadLabel(iRoad, maxOccurrencesValue.getRawValue(), isFakeRoad); - } -} - -template -void Tracker::computeTracksMClabels() -{ - for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { - for (auto& track : mTimeFrame->getTracks(iROF)) { - std::vector> occurrences; - occurrences.clear(); - - for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { - const int index = track.getClusterIndex(iCluster); - if (index == constants::UnusedIndex) { - continue; - } - auto labels = mTimeFrame->getClusterLabels(iCluster, index); - bool found{false}; - for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) { - std::pair& occurrence = occurrences[iOcc]; - for (const auto& label : labels) { - if (label == occurrence.first) { - ++occurrence.second; - found = true; - // break; // uncomment to stop to the first hit - } - } - } - if (!found) { - for (const auto& label : labels) { - occurrences.emplace_back(label, 1); + uint32_t pattern = track.getPattern(); + // set fake clusters pattern + for (int ic{TrackITSExt::MaxClusters}; ic--;) { + auto clid = track.getClusterIndex(ic); + if (clid != constants::UnusedIndex) { + auto labelsSpan = mTimeFrame->getClusterLabels(ic, clid); + for (const auto& currentLabel : labelsSpan) { + if (currentLabel == maxOccurrencesValue) { + pattern |= 0x1 << (16 + ic); // set bit if correct + break; } } } - std::sort(std::begin(occurrences), std::end(occurrences), [](auto e1, auto e2) { - return e1.second > e2.second; - }); + } + track.setPattern(pattern); + if (occurrences[0].second < track.getNumberOfClusters()) { + maxOccurrencesValue.setFakeFlag(); + } + mTimeFrame->getTracksLabel().emplace_back(maxOccurrencesValue); + } +} - auto maxOccurrencesValue = occurrences[0].first; - uint32_t pattern = track.getPattern(); - // set fake clusters pattern - for (int ic{TrackITSExt::MaxClusters}; ic--;) { - auto clid = track.getClusterIndex(ic); - if (clid != constants::UnusedIndex) { - auto labelsSpan = mTimeFrame->getClusterLabels(ic, clid); - for (const auto& currentLabel : labelsSpan) { - if (currentLabel == maxOccurrencesValue) { - pattern |= 0x1 << (16 + ic); // set bit if correct - break; - } - } - } - } - track.setPattern(pattern); - if (occurrences[0].second < track.getNumberOfClusters()) { - maxOccurrencesValue.setFakeFlag(); +template +void Tracker::rectifyClusterIndices() +{ + for (auto& track : mTimeFrame->getTracks()) { + for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { + const int index = track.getClusterIndex(iCluster); + if (index != constants::UnusedIndex) { + track.setExternalClusterIndex(iCluster, mTimeFrame->getClusterExternalIndex(iCluster, index)); } - mTimeFrame->getTracksLabel(iROF).emplace_back(maxOccurrencesValue); } } } -template -void Tracker::rectifyClusterIndices() +template +void Tracker::sortTracks() { - for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { - for (auto& track : mTimeFrame->getTracks(iROF)) { - for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) { - const int index = track.getClusterIndex(iCluster); - if (index != constants::UnusedIndex) { - track.setExternalClusterIndex(iCluster, mTimeFrame->getClusterExternalIndex(iCluster, index)); - } - } + auto& trks = mTimeFrame->getTracks(); + std::vector indices(trks.size()); + std::iota(indices.begin(), indices.end(), 0); + std::sort(indices.begin(), indices.end(), [&trks](size_t i, size_t j) { + const auto& a = trks[i]; + const auto& b = trks[j]; + const auto at = a.getTimeStamp(); + const auto bt = b.getTimeStamp(); + if (at.getTimeStamp() != bt.getTimeStamp()) { // sort first in time + return at.getTimeStamp() < bt.getTimeStamp(); + } + return a.isBetter(b, 1e9); // then sort tracks in quality + }); + bounded_vector sortedTrks(trks.get_allocator()); + sortedTrks.reserve(trks.size()); + for (size_t idx : indices) { + sortedTrks.push_back(trks[idx]); + } + trks.swap(sortedTrks); + if (mTimeFrame->hasMCinformation()) { + auto& trksLabels = mTimeFrame->getTracksLabel(); + bounded_vector sortedLabels(trksLabels.get_allocator()); + sortedLabels.reserve(trksLabels.size()); + for (size_t idx : indices) { + sortedLabels.push_back(trksLabels[idx]); } + trksLabels.swap(sortedLabels); } } -template -void Tracker::adoptTimeFrame(TimeFrame& tf) +template +void Tracker::adoptTimeFrame(TimeFrame& tf) { mTimeFrame = &tf; mTraits->adoptTimeFrame(&tf); } -template -void Tracker::printSummary() const +template +void Tracker::printSummary() const { auto avgTF = mTotalTime * 1.e-3 / ((mTimeFrameCounter > 0) ? (double)mTimeFrameCounter : -1.0); auto avgTFwithDropped = mTotalTime * 1.e-3 / (((mTimeFrameCounter + mNumberOfDroppedTFs) > 0) ? (double)(mTimeFrameCounter + mNumberOfDroppedTFs) : -1.0); diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index 6b237ad0a63e8..5449aaa1ded8a 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -13,35 +13,53 @@ /// \brief /// +#include +#include +#include + #include -#include #include +#include #include -#include - -#ifdef OPTIMISATION_OUTPUT -#include -#include -#endif - -#include -#include +#include +#include +#include "DetectorsRaw/HBFUtils.h" +#include "Steer/MCKinematicsReader.h" +#include "SimulationDataFormat/O2DatabasePDG.h" #include "CommonConstants/MathConstants.h" +#include "CommonUtils/TreeStreamRedirector.h" #include "DetectorsBase/Propagator.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "GPUCommonMath.h" #include "ITStracking/Cell.h" +#include "ITStracking/MathUtils.h" #include "ITStracking/Constants.h" +#include "ITStracking/Seeding.h" #include "ITStracking/TrackerTraits.h" #include "ITStracking/BoundedAllocator.h" #include "ITStracking/IndexTableUtils.h" #include "ITStracking/Tracklet.h" #include "ReconstructionDataFormats/Track.h" -using o2::base::PropagatorF; +/// optimization output +// TODO should this go somewhere else +#define OPTIMISATION_TRACKLETS (1 << 0) +#define OPTIMISATION_CELLS (1 << 1) +#define OPTIMISATION_CELLSNEIGH (1 << 2) +// #define OPTIMISATION (OPTIMISATION_CELLS | OPTIMISATION_TRACKLETS | OPTIMISATION_CELLSNEIGH) +#define OPTIMISATION (0) +#define OPTIMISATION_ANY (OPTIMISATION != 0) +#define OPTIMISATION_SET(flag) ((OPTIMISATION & (flag)) != 0) +#define OPTIMISATION_NOT_SET(flag) ((OPTIMISATION & (flag)) == 0) +#define OPTIMISATION_DOWNSAMPLE 1 // down-sample fraction namespace o2::its { +namespace +{ +utils::TreeStreamRedirector* sDBGOut{nullptr}; +} struct PassMode { using OnePass = std::integral_constant; @@ -49,132 +67,176 @@ struct PassMode { using TwoPassInsert = std::integral_constant; }; -template -void TrackerTraits::computeLayerTracklets(const int iteration, int iROFslice, int iVertex) +template +TrackerTraits::TrackerTraits() { -#ifdef OPTIMISATION_OUTPUT - static int iter{0}; - std::ofstream off(std::format("tracklets{}.txt", iter++)); +#if OPTIMISATION_ANY + sDBGOut = new utils::TreeStreamRedirector("its_debug.root"); #endif +} + +template +TrackerTraits::~TrackerTraits() +{ +#if OPTIMISATION_ANY + sDBGOut->Close(); + delete sDBGOut; + sDBGOut = nullptr; +#endif +} - for (int iLayer = 0; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) { +template +void TrackerTraits::computeLayerTracklets(const int iteration, const int iSlice, const int iVertex) +{ + for (int iLayer = 0; iLayer < mRecoParams[iteration].params.TrackletsPerRoad(); ++iLayer) { mTimeFrame->getTracklets()[iLayer].clear(); mTimeFrame->getTrackletsLabel(iLayer).clear(); if (iLayer > 0) { - std::fill(mTimeFrame->getTrackletsLookupTable()[iLayer - 1].begin(), - mTimeFrame->getTrackletsLookupTable()[iLayer - 1].end(), 0); + std::fill(mTimeFrame->getTrackletsLookupTable()[iLayer - 1].begin(), mTimeFrame->getTrackletsLookupTable()[iLayer - 1].end(), 0); } } - const Vertex diamondVert({mTrkParams[iteration].Diamond[0], mTrkParams[iteration].Diamond[1], mTrkParams[iteration].Diamond[2]}, {25.e-6f, 0.f, 0.f, 25.e-6f, 0.f, 36.f}, 1, 1.f); + const Vertex diamondVert(mRecoParams[iteration].params.Diamond, mRecoParams[iteration].params.DiamondCov, 1, 1.f); gsl::span diamondSpan(&diamondVert, 1); - int startROF{mTrkParams[iteration].nROFsPerIterations > 0 ? iROFslice * mTrkParams[iteration].nROFsPerIterations : 0}; - int endROF{o2::gpu::GPUCommonMath::Min(mTrkParams[iteration].nROFsPerIterations > 0 ? (iROFslice + 1) * mTrkParams[iteration].nROFsPerIterations + mTrkParams[iteration].DeltaROF : mTimeFrame->getNrof(), mTimeFrame->getNrof())}; mTaskArena->execute([&] { auto forTracklets = [&](auto Tag, int iLayer, int pivotROF, int base, int& offset) -> int { - if (!mTimeFrame->mMultiplicityCutMask[pivotROF]) { + // do we even have clusters for this rof on this layer + const auto& layer0 = mTimeFrame->getClustersOnLayer(pivotROF, iLayer); + if (layer0.empty()) { return 0; } - int minROF = o2::gpu::CAMath::Max(startROF, pivotROF - mTrkParams[iteration].DeltaROF); - int maxROF = o2::gpu::CAMath::Min(endROF - 1, pivotROF + mTrkParams[iteration].DeltaROF); - gsl::span primaryVertices = mTrkParams[iteration].UseDiamond ? diamondSpan : mTimeFrame->getPrimaryVertices(minROF, maxROF); + + // if (!mTimeFrame->mMultiplicityCutMask[iLayer][pivotROF]) { + // return 0; + // } + + // get seen seeding vertices + gsl::span primaryVertices = mRecoParams[iteration].params.UseDiamond ? diamondSpan : mTimeFrame->getPrimaryVertices(iLayer, pivotROF); if (primaryVertices.empty()) { return 0; } + const int startVtx = iVertex >= 0 ? iVertex : 0; const int endVtx = iVertex >= 0 ? o2::gpu::CAMath::Min(iVertex + 1, int(primaryVertices.size())) : int(primaryVertices.size()); - if (endVtx <= startVtx) { + if (endVtx <= startVtx || (iVertex + 1) > primaryVertices.size()) { return 0; } - int localCount = 0; - auto& tracklets = mTimeFrame->getTracklets()[iLayer]; - auto layer0 = mTimeFrame->getClustersOnLayer(pivotROF, iLayer); - if (layer0.empty()) { + // does this layer have any overlap with the next layer + const auto& rofOverlap = mTimeFrame->getROFOverlapTableView().getOverlap(iLayer, iLayer + 1, pivotROF); + if (!rofOverlap.getEntries()) { return 0; } - const float meanDeltaR = mTrkParams[iteration].LayerRadii[iLayer + 1] - mTrkParams[iteration].LayerRadii[iLayer]; + int localCount = 0; + const float meanDeltaR = mRecoParams[iteration].params.LayerRadii[iLayer + 1] - mRecoParams[iteration].params.LayerRadii[iLayer]; + const float meanDeltaR2 = math_utils::Sq(meanDeltaR); + auto& tracklets = mTimeFrame->getTracklets()[iLayer]; for (int iCluster = 0; iCluster < int(layer0.size()); ++iCluster) { const Cluster& currentCluster = layer0[iCluster]; const int currentSortedIndex = mTimeFrame->getSortedIndex(pivotROF, iLayer, iCluster); - if (mTimeFrame->isClusterUsed(iLayer, currentCluster.clusterId)) { + if (iteration && mTimeFrame->isClusterUsed(iLayer, currentCluster.clusterId)) { continue; } + const float inverseR0 = 1.f / currentCluster.radius; + const float inverseR02 = math_utils::Sq(inverseR0); for (int iV = startVtx; iV < endVtx; ++iV) { const auto& pv = primaryVertices[iV]; - if ((pv.isFlagSet(Vertex::Flags::UPCMode) && iteration != 3) || (iteration == 3 && !pv.isFlagSet(Vertex::Flags::UPCMode))) { - continue; - } - const float resolution = o2::gpu::CAMath::Sqrt(math_utils::Sq(mTimeFrame->getPositionResolution(iLayer)) + math_utils::Sq(mTrkParams[iteration].PVres) / float(pv.getNContributors())); - const float tanLambda = (currentCluster.zCoordinate - pv.getZ()) * inverseR0; + // vertex resolution + const float pvX2 = pv.getSigmaX2() / float(pv.getNContributors()); + const float pvY2 = pv.getSigmaY2() / float(pv.getNContributors()); + const float pvR2 = pvX2 + pvY2; + const float pvZ2 = pv.getSigmaZ2() / float(pv.getNContributors()); + // xyz-position resolution + const float res2 = math_utils::Sq(mTimeFrame->getPositionResolution(iLayer)); + const float deltaZ = currentCluster.zCoordinate - pv.getZ(); + /// calculate the lookup window for the next layer in z&phi + // the assumption is that the clusters are already in the vertex coordinate system + // Note: this is only approximate can we account for the difference somehow? + // phi-window: + // phi=arctan((y_c - y_pv)/(x_c - x_pv)); in this case this is just determined by the cluster + // Var[phi] = fac^2 * [ S*(s_x_c^2 + s_x_pv^2) + T*(s_y_c^2+s_y_pv^2)] + // where fac = 1/(S+T), S=(y_c - y_pv)^2, T=(x_c - x_pv)^2 + // additionally, adding the phi cuts due to the stave inclination which also accounts MS + // NOTE: the cluster x&y positions are already in an approximate frame of the pv + const float ms2 = math_utils::Sq(mTimeFrame->getMSangle(iLayer)); + const float phiExtrap = currentCluster.phi; + const float phiS = math_utils::Sq(currentCluster.yCoordinate); + const float phiT = math_utils::Sq(currentCluster.xCoordinate); + const float phiFac = 1.f / (phiS + phiT); + const float phiVar = (math_utils::Sq(phiFac) * (phiS * (res2 + pvX2) + phiT * (res2 + pvY2))); + const float phiNSigma = mRecoParams[iteration].params.NSigmaCut * (o2::gpu::CAMath::Sqrt(phiVar) + mTimeFrame->getPhiCut(iLayer)); + // z-window: + // z(r) = z_c + (z_pv - z_c)/(r_pv - r_c) * (r - r_c) + // define S = r_pv - r_c, r_n = r_c + meanDeltaR + // a := d z(r_n) / d z_c = 1 - (meanDeltaR / S) + // b := d z(r_n) / d z_pv = meanDeltaR / S + // d z(r_n) / d r_c = - (r_n - r_pv) * (z_c - z_pv) / S^2 + // d z(r_n) / d r_pv = - (r_c - r_n) * (z_c - z_pv) / S^2 + const float tanLambda = deltaZ * inverseR0; + const float zExtrap = currentCluster.zCoordinate + (tanLambda * meanDeltaR); + const float a = 1.f - (meanDeltaR * inverseR0); + const float rA2 = math_utils::Sq(a); + const float b = meanDeltaR * inverseR0; + const float rB2 = math_utils::Sq(b); + const float S = 1.f / inverseR0; + const float dzdrc = -(meanDeltaR - S) * deltaZ * inverseR02; // = - (r_n - r_pv) * deltaZ / S^2 + const float dzdrpv = meanDeltaR * deltaZ * inverseR02; // = - (r_c - r_n) * deltaZ / S^2 const float zAtRmin = tanLambda * (mTimeFrame->getMinR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate; const float zAtRmax = tanLambda * (mTimeFrame->getMaxR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate; - const float sqInvDeltaZ0 = 1.f / (math_utils::Sq(currentCluster.zCoordinate - pv.getZ()) + constants::Tolerance); - const float sigmaZ = o2::gpu::CAMath::Sqrt( - math_utils::Sq(resolution) * math_utils::Sq(tanLambda) * ((math_utils::Sq(inverseR0) + sqInvDeltaZ0) * math_utils::Sq(meanDeltaR) + 1.f) + math_utils::Sq(meanDeltaR * mTimeFrame->getMSangle(iLayer))); + const float zWidth2 = (1.f / 12.f) * math_utils::Sq(zAtRmax - zAtRmin); // accounting for stave inclination + const float zVar = (rA2 * res2) + (rB2 * pvZ2) + (dzdrc * dzdrc * res2) + (dzdrpv * dzdrpv * pvR2) + zWidth2; + const float zNSigma = mRecoParams[iteration].params.NSigmaCut * o2::gpu::CAMath::Sqrt(zVar); - auto bins = getBinsRect(currentCluster, iLayer + 1, zAtRmin, zAtRmax, sigmaZ * mTrkParams[iteration].NSigmaCut, mTimeFrame->getPhiCut(iLayer)); + const auto bins = getBinsRect(iteration, iLayer + 1, phiExtrap, phiNSigma, zExtrap, zNSigma); if (bins.x == 0 && bins.y == 0 && bins.z == 0 && bins.w == 0) { continue; } int phiBinsNum = bins.w - bins.y + 1; - if (phiBinsNum < 0) { - phiBinsNum += mTrkParams[iteration].PhiBins; + if (phiBinsNum < 0) { // handle wrap around + phiBinsNum += mRecoParams[iteration].params.PhiBins; } - for (int targetROF{minROF}; targetROF <= maxROF; ++targetROF) { - if (!mTimeFrame->mMultiplicityCutMask[targetROF]) { - continue; - } - auto layer1 = mTimeFrame->getClustersOnLayer(targetROF, iLayer + 1); + for (int targetROF = rofOverlap.getFirstEntry(); targetROF < rofOverlap.getEntriesBound(); ++targetROF) { + // if (!mTimeFrame->mMultiplicityCutMask[iLayer + 1][targetROF]) { + // continue; + // } + const auto& layer1 = mTimeFrame->getClustersOnLayer(targetROF, iLayer + 1); if (layer1.empty()) { continue; } + const auto& targetIndexTable = mTimeFrame->getIndexTable(targetROF, iLayer + 1); + const int zBinRange = (bins.z - bins.x) + 1; for (int iPhi = 0; iPhi < phiBinsNum; ++iPhi) { - const int iPhiBin = (bins.y + iPhi) % mTrkParams[iteration].PhiBins; - const int firstBinIdx = mTimeFrame->mIndexTableUtils.getBinIndex(bins.x, iPhiBin); - const int maxBinIdx = firstBinIdx + (bins.z - bins.x) + 1; - const int firstRow = mTimeFrame->getIndexTable(targetROF, iLayer + 1)[firstBinIdx]; - const int lastRow = mTimeFrame->getIndexTable(targetROF, iLayer + 1)[maxBinIdx]; + const int iPhiBin = (bins.y + iPhi) % mRecoParams[iteration].params.PhiBins; + const int firstBinIdx = mTimeFrame->getIndexTableUtils().getBinIndex(bins.x, iPhiBin); + const int maxBinIdx = firstBinIdx + zBinRange; + const int firstRow = targetIndexTable[firstBinIdx]; + const int lastRow = targetIndexTable[maxBinIdx]; for (int iNext = firstRow; iNext < lastRow; ++iNext) { if (iNext >= int(layer1.size())) { break; } const Cluster& nextCluster = layer1[iNext]; - if (mTimeFrame->isClusterUsed(iLayer + 1, nextCluster.clusterId)) { + if (iteration && mTimeFrame->isClusterUsed(iLayer + 1, nextCluster.clusterId)) { continue; } - float deltaPhi = o2::gpu::GPUCommonMath::Abs(currentCluster.phi - nextCluster.phi); - float deltaZ = o2::gpu::GPUCommonMath::Abs((tanLambda * (nextCluster.radius - currentCluster.radius)) + currentCluster.zCoordinate - nextCluster.zCoordinate); - -#ifdef OPTIMISATION_OUTPUT - MCCompLabel label; - int currentId{currentCluster.clusterId}; - int nextId{nextCluster.clusterId}; - for (auto& lab1 : mTimeFrame->getClusterLabels(iLayer, currentId)) { - for (auto& lab2 : mTimeFrame->getClusterLabels(iLayer + 1, nextId)) { - if (lab1 == lab2 && lab1.isValid()) { - label = lab1; - break; - } - } - if (label.isValid()) { - break; - } - } - off << std::format("{}\t{:d}\t{}\t{}\t{}\t{}", iLayer, label.isValid(), (tanLambda * (nextCluster.radius - currentCluster.radius) + currentCluster.zCoordinate - nextCluster.zCoordinate) / sigmaZ, tanLambda, resolution, sigmaZ) << std::endl; -#endif - if (deltaZ / sigmaZ < mTrkParams[iteration].NSigmaCut && - ((deltaPhi < mTimeFrame->getPhiCut(iLayer) || o2::gpu::GPUCommonMath::Abs(deltaPhi - o2::constants::math::TwoPI) < mTimeFrame->getPhiCut(iLayer)))) { + const float deltaPhi = o2::gpu::CAMath::Abs(o2::math_utils::toPMPi(currentCluster.phi - nextCluster.phi)); + const float deltaZ = o2::gpu::CAMath::Abs((tanLambda * (nextCluster.radius - currentCluster.radius)) + currentCluster.zCoordinate - nextCluster.zCoordinate); + + const bool accept = deltaZ < zNSigma && deltaPhi < phiNSigma; + debugComputeLayerTracklets(iteration, iLayer, currentCluster, nextCluster, pv, zNSigma, phiNSigma, accept); + + if (accept) { const float phi{o2::gpu::CAMath::ATan2(currentCluster.yCoordinate - nextCluster.yCoordinate, currentCluster.xCoordinate - nextCluster.xCoordinate)}; const float tanL = (currentCluster.zCoordinate - nextCluster.zCoordinate) / (currentCluster.radius - nextCluster.radius); + if constexpr (decltype(Tag)::value == PassMode::OnePass::value) { tracklets.emplace_back(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF, iLayer + 1, iNext), tanL, phi, pivotROF, targetROF); } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) { @@ -194,50 +256,48 @@ void TrackerTraits::computeLayerTracklets(const int iteration, int iROF int dummy{0}; if (mTaskArena->max_concurrency() <= 1) { - for (int pivotROF{startROF}; pivotROF < endROF; ++pivotROF) { - for (int iLayer{0}; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) { + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.TrackletsPerRoad(); ++iLayer) { + const auto& rofSlices = mTimeFrame->getROFTimeSliceTableView().getROFSlice(iLayer, iSlice); + const auto& timeMask = mTimeFrame->getROFTimeSliceTableView().getMask(iLayer, iSlice); + for (int pivotROF{rofSlices.getFirstEntry()}; pivotROF < rofSlices.getEntriesBound(); ++pivotROF) { + if (!timeMask[pivotROF - rofSlices.getFirstEntry()]) { + continue; + } forTracklets(PassMode::OnePass{}, iLayer, pivotROF, 0, dummy); } } } else { - bounded_vector> perROFCount(mTrkParams[iteration].TrackletsPerRoad(), bounded_vector(endROF - startROF + 1, 0, mMemoryPool.get()), mMemoryPool.get()); - tbb::parallel_for( - tbb::blocked_range2d(0, mTrkParams[iteration].TrackletsPerRoad(), 1, - startROF, endROF, 1), - [&](auto const& Range) { - for (int iLayer{Range.rows().begin()}; iLayer < Range.rows().end(); ++iLayer) { - for (int pivotROF = Range.cols().begin(); pivotROF < Range.cols().end(); ++pivotROF) { - perROFCount[iLayer][pivotROF - startROF] = forTracklets(PassMode::TwoPassCount{}, iLayer, pivotROF, 0, dummy); - } + tbb::parallel_for(0, mRecoParams[iteration].params.TrackletsPerRoad(), [&](const int iLayer) { + const auto& rofSlices = mTimeFrame->getROFTimeSliceTableView().getROFSlice(iLayer, iSlice); + const auto& timeMask = mTimeFrame->getROFTimeSliceTableView().getMask(iLayer, iSlice); + bounded_vector perROFCount(rofSlices.getEntries() + 1, mMemoryPool.get()); + tbb::parallel_for(rofSlices.getFirstEntry(), rofSlices.getEntriesBound(), [&](const int pivotROF) { + if (!timeMask[pivotROF - rofSlices.getFirstEntry()]) { + return; } + perROFCount[pivotROF - rofSlices.getFirstEntry()] = forTracklets(PassMode::TwoPassCount{}, iLayer, pivotROF, 0, dummy); }); - - tbb::parallel_for(0, mTrkParams[iteration].TrackletsPerRoad(), [&](const int iLayer) { - std::exclusive_scan(perROFCount[iLayer].begin(), perROFCount[iLayer].end(), perROFCount[iLayer].begin(), 0); - mTimeFrame->getTracklets()[iLayer].resize(perROFCount[iLayer].back()); - }); - - tbb::parallel_for( - tbb::blocked_range2d(0, mTrkParams[iteration].TrackletsPerRoad(), 1, - startROF, endROF, 1), - [&](auto const& Range) { - for (int iLayer{Range.rows().begin()}; iLayer < Range.rows().end(); ++iLayer) { - if (perROFCount[iLayer].back() == 0) { - continue; - } - for (int pivotROF = Range.cols().begin(); pivotROF < Range.cols().end(); ++pivotROF) { - int baseIdx = perROFCount[iLayer][pivotROF - startROF]; - if (baseIdx == perROFCount[iLayer][pivotROF - startROF + 1]) { - continue; - } - int localIdx = 0; - forTracklets(PassMode::TwoPassInsert{}, iLayer, pivotROF, baseIdx, localIdx); - } + std::exclusive_scan(perROFCount.begin(), perROFCount.end(), perROFCount.begin(), 0); + const int nTracklets = perROFCount.back(); + mTimeFrame->getTracklets()[iLayer].resize(nTracklets); + if (nTracklets == 0) { + return; + } + tbb::parallel_for(rofSlices.getFirstEntry(), rofSlices.getEntriesBound(), [&](const int pivotROF) { + if (!timeMask[pivotROF - rofSlices.getFirstEntry()]) { + return; } + int baseIdx = perROFCount[pivotROF - rofSlices.getFirstEntry()]; + if (baseIdx == perROFCount[pivotROF + 1 - rofSlices.getFirstEntry()]) { + return; + } + int localIdx = 0; + forTracklets(PassMode::TwoPassInsert{}, iLayer, pivotROF, baseIdx, localIdx); }); + }); } - tbb::parallel_for(0, mTrkParams[iteration].TrackletsPerRoad(), [&](const int iLayer) { + tbb::parallel_for(0, mRecoParams[iteration].params.TrackletsPerRoad(), [&](const int iLayer) { /// Sort tracklets auto& trkl{mTimeFrame->getTracklets()[iLayer]}; tbb::parallel_sort(trkl.begin(), trkl.end(), [](const Tracklet& a, const Tracklet& b) -> bool { @@ -251,21 +311,19 @@ void TrackerTraits::computeLayerTracklets(const int iteration, int iROF return a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex == b.secondClusterIndex; }), trkl.end()); - trkl.shrink_to_fit(); if (iLayer > 0) { /// recalculate lut auto& lut{mTimeFrame->getTrackletsLookupTable()[iLayer - 1]}; - if (!trkl.empty()) { - for (const auto& tkl : trkl) { - lut[tkl.firstClusterIndex + 1]++; - } - std::inclusive_scan(lut.begin(), lut.end(), lut.begin()); + clearResizeBoundedVector(lut, mTimeFrame->getNumberOfClusters(iLayer) + 1, mMemoryPool.get(), 0); + for (const auto& tkl : trkl) { + lut[tkl.firstClusterIndex + 1]++; } + std::inclusive_scan(lut.begin(), lut.end(), lut.begin()); } }); /// Create tracklets labels - if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) { - tbb::parallel_for(0, mTrkParams[iteration].TrackletsPerRoad(), [&](const int iLayer) { + if ((mTimeFrame->hasMCinformation() && mRecoParams[iteration].params.createArtefactLabels) || OPTIMISATION_ANY) { + tbb::parallel_for(0, mRecoParams[iteration].params.TrackletsPerRoad(), [&](const int iLayer) { for (auto& trk : mTimeFrame->getTracklets()[iLayer]) { MCCompLabel label; int currentId{mTimeFrame->getClusters()[iLayer][trk.firstClusterIndex].clusterId}; @@ -286,22 +344,17 @@ void TrackerTraits::computeLayerTracklets(const int iteration, int iROF }); } }); -} // namespace o2::its +} -template -void TrackerTraits::computeLayerCells(const int iteration) +template +void TrackerTraits::computeLayerCells(const int iteration) { -#ifdef OPTIMISATION_OUTPUT - static int iter{0}; - std::ofstream off(std::format("cells{}.txt", iter++)); -#endif - - for (int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) { + for (int iLayer = 0; iLayer < mRecoParams[iteration].params.CellsPerRoad(); ++iLayer) { deepVectorClear(mTimeFrame->getCells()[iLayer]); if (iLayer > 0) { deepVectorClear(mTimeFrame->getCellsLookupTable()[iLayer - 1]); } - if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) { + if ((mTimeFrame->hasMCinformation() && mRecoParams[iteration].params.createArtefactLabels) || OPTIMISATION_ANY) { deepVectorClear(mTimeFrame->getCellsLabel(iLayer)); } } @@ -312,85 +365,109 @@ void TrackerTraits::computeLayerCells(const int iteration) const int nextLayerClusterIndex{currentTracklet.secondClusterIndex}; const int nextLayerFirstTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]}; const int nextLayerLastTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex + 1]}; + + // properties for the middle layer + const float resMid2 = math_utils::Sq(mTimeFrame->getPositionResolution(iLayer + 1)); + const float msMid2 = math_utils::Sq(mTimeFrame->getMSangle(iLayer + 1)); + // the allowed tgl variance is entirely determined by the middle layer + const float tglNSigma = o2::gpu::CAMath::Sqrt(resMid2 + msMid2) * mRecoParams[iteration].params.NSigmaCut; + int foundCells{0}; for (int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) { + // ensure that the tracklets are sharing the middle cluster const Tracklet& nextTracklet{mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet]}; - const auto& nextLbl = mTimeFrame->getTrackletsLabel(iLayer + 1)[iNextTracklet]; if (mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet].firstClusterIndex != nextLayerClusterIndex) { break; } - if (mTrkParams[iteration].DeltaROF && currentTracklet.getSpanRof(nextTracklet) > mTrkParams[iteration].DeltaROF) { // TODO this has to be improved for the staggering + + // need to ensure that the clusters in layer (iLayer) and (iLayer+2) are compatible + if (!mTimeFrame->getROFOverlapTableView().isCompatible(iLayer, currentTracklet.rof[0], iLayer + 2, nextTracklet.rof[1])) { continue; } - const float deltaTanLambda{std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda)}; - -#ifdef OPTIMISATION_OUTPUT - float resolution{o2::gpu::CAMath::Sqrt(0.5f * (mTrkParams[iteration].SystErrorZ2[iLayer] + mTrkParams[iteration].SystErrorZ2[iLayer + 1] + mTrkParams[iteration].SystErrorZ2[iLayer + 2] + mTrkParams[iteration].SystErrorY2[iLayer] + mTrkParams[iteration].SystErrorY2[iLayer + 1] + mTrkParams[iteration].SystErrorY2[iLayer + 2])) / mTrkParams[iteration].LayerResolution[iLayer]}; - resolution = resolution > 1.e-12 ? resolution : 1.f; - bool good{mTimeFrame->getTrackletsLabel(iLayer)[iTracklet] == mTimeFrame->getTrackletsLabel(iLayer + 1)[iNextTracklet]}; - float signedDelta{currentTracklet.tanLambda - nextTracklet.tanLambda}; - off << std::format("{}\t{:d}\t{}\t{}\t{}\t{}", iLayer, good, signedDelta, signedDelta / (mTrkParams[iteration].CellDeltaTanLambdaSigma), tanLambda, resolution) << std::endl; -#endif - if (deltaTanLambda / mTrkParams[iteration].CellDeltaTanLambdaSigma < mTrkParams[iteration].NSigmaCut) { + debugComputeLayerCells(iteration, iLayer, iTracklet, iNextTracklet); - /// Track seed preparation. Clusters are numbered progressively from the innermost going outward. - const int clusId[3]{ - mTimeFrame->getClusters()[iLayer][currentTracklet.firstClusterIndex].clusterId, - mTimeFrame->getClusters()[iLayer + 1][nextTracklet.firstClusterIndex].clusterId, - mTimeFrame->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex].clusterId}; - const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[iLayer][clusId[0]]; - const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[iLayer + 1][clusId[1]]; - const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + 2)[clusId[2]]; - auto track{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)}; + // calculate their compatibility in TgL + const float deltaTanLambda = o2::gpu::CAMath::Abs(currentTracklet.tanLambda - nextTracklet.tanLambda); + if (deltaTanLambda >= tglNSigma) { + continue; + } - float chi2{0.f}; - bool good{false}; - for (int iC{2}; iC--;) { - const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + iC)[clusId[iC]]; + const auto& cls1 = mTimeFrame->getClusters()[iLayer][currentTracklet.firstClusterIndex]; + const auto& cls2 = mTimeFrame->getClusters()[iLayer + 1][nextTracklet.firstClusterIndex]; + const auto& cls3 = mTimeFrame->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex]; + // curvature consistency cut arxiv:2401.16046 4.1.2 + // the transverse cluster positions are in the presumed beamspot frame + const float k123 = math_utils::computeCurvature(cls1.xCoordinate, cls1.yCoordinate, + cls2.xCoordinate, cls2.yCoordinate, + cls3.xCoordinate, cls3.yCoordinate); + const float k013 = math_utils::computeCurvature(0.f, 0.f, + cls1.xCoordinate, cls1.yCoordinate, + cls3.xCoordinate, cls3.yCoordinate); + const float dk = o2::gpu::CAMath::Abs(k123 - k013); + const float dR2 = 0.25f * (math_utils::Sq(cls1.xCoordinate - cls3.xCoordinate) + math_utils::Sq(cls1.yCoordinate - cls3.yCoordinate)); + const float tgl2 = math_utils::Sq(0.5 * (currentTracklet.tanLambda + nextTracklet.tanLambda)); + const float snl2 = tgl2 / (1.f + tgl2); + const float kSigma2Pos = 6.f * resMid2 / math_utils::Sq(dR2); + const float kSigma2MS = msMid2 / (dR2 * snl2); + const float kNSigma = mRecoParams[iteration].params.NSigmaCut * o2::gpu::CAMath::Sqrt(kSigma2Pos + kSigma2MS); + if (dk >= kNSigma) { + continue; + } - if (!track.rotate(trackingHit.alphaTrackingFrame)) { - break; - } + /// Track seed preparation. Clusters are numbered progressively from the innermost going outward. + const int clusId[3] = {cls1.clusterId, cls2.clusterId, cls3.clusterId}; + const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[iLayer][clusId[0]]; + const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[iLayer + 1][clusId[1]]; + const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + 2)[clusId[2]]; + auto track{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)}; - if (!track.propagateTo(trackingHit.xTrackingFrame, getBz())) { - break; - } + float chi2{0.f}; + bool good{false}; + for (int iC{2}; iC--;) { + const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + iC)[clusId[iC]]; - if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer + iC], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { - break; - } + if (!track.rotate(trackingHit.alphaTrackingFrame)) { + break; + } - const auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; - if (!iC && predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) { - break; - } + if (!track.propagateTo(trackingHit.xTrackingFrame, getBz())) { + break; + } - if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { - break; - } + if (!track.correctForMaterial(mRecoParams[iteration].params.LayerxX0[iLayer + iC], mRecoParams[iteration].params.LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { + break; + } - good = !iC; - chi2 += predChi2; + const auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; + if (!iC && predChi2 > mRecoParams[iteration].params.MaxChi2ClusterAttachment) { + break; } - if (good) { - if constexpr (decltype(Tag)::value == PassMode::OnePass::value) { - layerCells.emplace_back(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2); - ++foundCells; - } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) { - ++foundCells; - } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) { - layerCells[offset++] = CellSeedN(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2); - } else { - static_assert(false, "Unknown mode!"); - } + + if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { + break; + } + + good = !iC; + chi2 += predChi2; + } + if (good) { + if constexpr (decltype(Tag)::value == PassMode::OnePass::value) { + layerCells.emplace_back(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2); + ++foundCells; + } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) { + ++foundCells; + } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) { + layerCells[offset++] = CellSeedN(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2); + } else { + static_assert(false, "Unknown mode!"); } } } return foundCells; }; - tbb::parallel_for(0, mTrkParams[iteration].CellsPerRoad(), [&](const int iLayer) { + tbb::parallel_for(0, mRecoParams[iteration].params.CellsPerRoad(), [&](const int iLayer) { if (mTimeFrame->getTracklets()[iLayer + 1].empty() || mTimeFrame->getTracklets()[iLayer].empty()) { return; @@ -433,8 +510,8 @@ void TrackerTraits::computeLayerCells(const int iteration) }); /// Create cells labels - if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) { - tbb::parallel_for(0, mTrkParams[iteration].CellsPerRoad(), [&](const int iLayer) { + if ((mTimeFrame->hasMCinformation() && mRecoParams[iteration].params.createArtefactLabels) || OPTIMISATION_ANY) { + tbb::parallel_for(0, mRecoParams[iteration].params.CellsPerRoad(), [&](const int iLayer) { mTimeFrame->getCellsLabel(iLayer).reserve(mTimeFrame->getCells()[iLayer].size()); for (const auto& cell : mTimeFrame->getCells()[iLayer]) { MCCompLabel currentLab{mTimeFrame->getTrackletsLabel(iLayer)[cell.getFirstTrackletIndex()]}; @@ -446,19 +523,287 @@ void TrackerTraits::computeLayerCells(const int iteration) }); } -template -void TrackerTraits::findCellsNeighbours(const int iteration) +template +void TrackerTraits::findCellSeeds(const int iteration) { -#ifdef OPTIMISATION_OUTPUT - std::ofstream off(std::format("cellneighs{}.txt", iteration)); -#endif + const auto& propagator = o2::base::Propagator::Instance(); + auto& cells = mTimeFrame->getCells()[0]; + LOGP(info, "received {} | {} tracklets", mTimeFrame->getTracklets()[0].size(), mTimeFrame->getTracklets()[1].size()); + LOGP(info, "received {} cells", cells.size()); - struct Neighbor { - int cell{-1}, nextCell{-1}, level{-1}; - }; + mTaskArena->execute([&] { + // we get cells from the first three layers + bounded_vector ltracks; + ltracks.resize(cells.size()); + tbb::parallel_for(size_t(0), cells.size(), [&](size_t iCell) { + // relate each cell to the imposed mean vertex or assumed beamline if the former is not provided + auto& cell = cells[iCell]; + // impose general quality cuts + if (cell.getPt() < mRecoParams[iteration].params.SeedingMinPtTrk) { + return; + } + dataformats::VertexBase vtx; + dataformats::DCA dca; + float z = cell.getZAt(0., getBz()); + if (z < -999.f) { // if outside of acceptance impose mean vertex z + z = mTimeFrame->getMeanVertex().getZ(); + } + if (mTimeFrame->hasMeanVertex()) { + mTimeFrame->getMeanVertexConstraint()->setMeanXYVertexAtZ(vtx, z); + } + if (!propagator->propagateToDCA(vtx, cell, getBz(), 2.0f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dca, nullptr, 0, mRecoParams[iteration].params.SeedingDCATolerance)) { + ltracks[iCell].markDead(); + return; + } + if (dca.getY() * dca.getY() / (dca.getSigmaY2()) >= mRecoParams[iteration].params.SeedingDCAMaxPull) { + ltracks[iCell].markDead(); + return; + } + ltracks[iCell] = LinearizedTrack(cell, iCell); + if (ltracks[iCell].isDead()) { + return; + } + const auto& cls = cell.getClusters(); + const int sta = cell.getUserField(); + int startBC = std::numeric_limits::max(), endBC = std::numeric_limits::min(); + for (int i{sta}; i < 3; ++i) { + int rof = mTimeFrame->getClusterROF(i, cls[i]); + int rofStartBC = mTimeFrame->getROFOverlapTableView().getLayer(i).getROFStartInBC(rof); + int rofEndBC = mTimeFrame->getROFOverlapTableView().getLayer(i).getROFEndInBC(rof); + startBC = o2::gpu::CAMath::Min(startBC, rofStartBC); + endBC = o2::gpu::CAMath::Max(endBC, rofEndBC); + } + if (endBC - startBC < 0) { // this should not happen + ltracks[iCell].markDead(); + } + ltracks[iCell].time.setTimeStamp(startBC); + ltracks[iCell].time.setTimeStampError(endBC - startBC); + }); + tbb::parallel_sort(ltracks.begin(), ltracks.end(), [](const LinearizedTrack& a, const LinearizedTrack& b) { + const bool aDead = a.isDead(); + const bool bDead = b.isDead(); + // all dead tracks are sorted to the end + if (aDead != bDead) { + return !aDead; // a < b only if a is alive and b is dead + } + // sort them in time and then increasing z + if (!aDead) { + const auto ta = a.time.getTimeStamp(); + const auto tb = b.time.getTimeStamp(); + if (ta != tb) { + return ta < tb; + } + return a.z < b.z; + } + return false; + }); + // drop all dead tracks + auto firstDead = std::partition_point(ltracks.begin(), ltracks.end(), [](const LinearizedTrack& t) { return !t.isDead(); }); + ltracks.erase(firstDead, ltracks.end()); + // do DBscan + // scan gives association in time and z + const auto dbRes = mDBScan.cluster(ltracks.data(), ltracks.size()); + bounded_vector vtxSeeds(dbRes.nClusters, mMemoryPool.get()); + bounded_vector vtxSeedsLbl(dbRes.nClusters, mMemoryPool.get()); + // we only care about the source&event of the tracks, not the trackId + auto composeVtxLabel = [](o2::MCCompLabel& lbl) -> void { + lbl.set(o2::MCCompLabel::maxTrackID(), lbl.getEventID(), lbl.getSourceID(), lbl.isFake()); + }; + tbb::parallel_for(0, dbRes.nClusters, [&](const int32_t iCls) { + // create vertex seeds based on meanvertex and scanned z which one can take as start + auto& seed = vtxSeeds[iCls]; + seed.setZ(dbRes.zCentroids[iCls]); + if (mTimeFrame->hasMeanVertex()) { + mTimeFrame->getMeanVertexConstraint()->setMeanXYVertexAtZ(seed, seed.getZ()); + } + seed.idx = iCls; + seed.tukeyC = mRecoParams[iteration].params.SeedingTukeyStartIter; + seed.scaleSig2ITuk2I = 1.f / (seed.tukeyC * seed.tukeyC); + const auto& range = dbRes.ranges[iCls]; + // fit iteratively + for (int iter{0}; iter < mRecoParams[iteration].params.SeedingMaxFitIter; ++iter) { + seed.iteration = iter; + // 1. update tukey scaling + seed.updateTukeyScale(ltracks.data(), dbRes.labels.data(), range); + // 2. reset for new iteration with new weights + seed.resetForNewIteration(); + // 3. account all tracks + for (uint32_t entry{range.getFirstEntry()}; entry < range.getEntriesBound(); ++entry) { + const auto& lt = ltracks[entry]; + if (lt.isDead() || dbRes.labels[entry] != iCls) { + continue; + } + seed.accountTrack(lt); + } + // 4. if needed relax scaling + if (seed.getNContributors() < mRecoParams[iteration].params.SeedingMinTracksIter) { + seed.status = VertexSeed::kIterateRelaxScale; + continue; + } + // 5. impose mean vertex constraint if wanted + if (mTimeFrame->hasMeanVertex()) { + const auto& err = mTimeFrame->getMeanVertexInvErr(); + seed.C(0, 0) += err[0]; // cxx + seed.C(0, 1) += err[1]; // cxy + seed.C(1, 1) += err[2]; // cyy + float x = mTimeFrame->getMeanVertexConstraint()->getXAtZ(seed.getZ()); + float y = mTimeFrame->getMeanVertexConstraint()->getYAtZ(seed.getZ()); + seed.b(0) += err[0] * x + err[1] * y; + seed.b(1) += err[1] * x + err[2] * y; + } + // 6. solve LS fit + seed.solveVertex(); + // 7. check for convergence + float avgChi2 = seed.wghChi2 / o2::gpu::CAMath::Max(1.f, seed.wghSum); + if (avgChi2 < mRecoParams[iteration].params.SeedingMaxChi2Iter) { + seed.status = VertexSeed::kConverged; + break; + } + seed.status = VertexSeed::kIterateFurther; + } + // find time bracket of vertex by looking at used tracks + uint32_t startBC = std::numeric_limits::max(), endBC = 0u; + for (uint32_t entry{range.getFirstEntry()}; entry < range.getEntriesBound(); ++entry) { + const auto& lt = ltracks[entry]; + if (lt.isDead() || dbRes.labels[entry] != iCls) { + continue; + } + float chi2Red = lt.getChi2(seed); + if (chi2Red > mRecoParams[iteration].params.SeedingMaxChi2Iter) { + continue; + } + startBC = o2::gpu::CAMath::Min(startBC, lt.time.getTimeStamp()); + endBC = o2::gpu::CAMath::Max(endBC, lt.time.getTimeStamp() + lt.time.getTimeStampError()); + } + seed.getTimeStamp().setTimeStamp(startBC); + seed.getTimeStamp().setTimeStampError(endBC - startBC); + // add additional errors + for (int i{0}; i < dataformats::VertexBase::kNCov; ++i) { + seed.setCov(seed.getCov(i) + mRecoParams[iteration].params.SeedingVertexExtraErr2[i], i); + } + // if mc is present calculate labels and purity + if (mTimeFrame->hasMCinformation()) { + // use boyer-moore voting + int accepted{0}, weight{0}; + o2::MCCompLabel lbl; + for (uint32_t entry{range.getFirstEntry()}; entry < range.getEntriesBound(); ++entry) { + const auto& lt = ltracks[entry]; + if (lt.isDead() || dbRes.labels[entry] != iCls) { + continue; + } + if (seed.acceptTrack(lt)) { + ++accepted; + // create cell label + const auto& cell = mTimeFrame->getCells()[0][lt.cellIdx]; + o2::MCCompLabel cl; + for (const auto& lab1 : mTimeFrame->getClusterLabels(0, cell.getFirstClusterIndex())) { + for (const auto& lab2 : mTimeFrame->getClusterLabels(1, cell.getSecondClusterIndex())) { + if (lab1 == lab2 && lab1.isValid()) { + cl = lab1; + break; + } + } + if (cl.isValid()) { + break; + } + } + composeVtxLabel(cl); // normalize label + if (weight == 0) { + lbl = cl; + weight = 1; + } else { + (cl == lbl) ? ++weight : --weight; + } + } + } + if (accepted > 0) { + vtxSeedsLbl[iCls] = {lbl, static_cast(weight) / static_cast(accepted)}; + } else { + vtxSeedsLbl[iCls] = {lbl, 0}; + } + } + }); + // TODO reduce debris vertices (eliminate small mult vertices within vicinity of high multiplicity ones) + // Sort vertices in time and multiplicity + for (int i{0}; i < dbRes.nClusters; ++i) { + if (vtxSeeds[i].status == VertexSeed::kKilled) { + continue; + } + mTimeFrame->addPrimaryVertex(vtxSeeds[i]); + if (mTimeFrame->hasMCinformation()) { + mTimeFrame->addPrimaryVertexLabel(vtxSeedsLbl[i]); + } + } + // if no mean vertex constraint imposed, use rolling weighted average (KF-filter) + // this should theoretical stabelize very quickly + if (!mTimeFrame->hasMeanVertex()) { + ROOT::Math::SMatrix I; + I(0, 0) = 1.f; + I(1, 1) = 1.f; + I(2, 2) = 1.f; + auto& avg = mTimeFrame->getMeanVertexRolling(); + ROOT::Math::SVector x; + x(0) = avg.getX(); + x(1) = avg.getY(); + x(2) = avg.getZ(); + ROOT::Math::SMatrix P; + P(0, 0) = avg.getCov(dataformats::VertexBase::kCovXX); + P(0, 1) = avg.getCov(dataformats::VertexBase::kCovXY); + P(1, 0) = avg.getCov(dataformats::VertexBase::kCovXY); + P(1, 1) = avg.getCov(dataformats::VertexBase::kCovYY); + P(0, 2) = avg.getCov(dataformats::VertexBase::kCovXZ); + P(2, 0) = avg.getCov(dataformats::VertexBase::kCovXZ); + P(1, 2) = avg.getCov(dataformats::VertexBase::kCovYZ); + P(2, 1) = avg.getCov(dataformats::VertexBase::kCovYZ); + P(2, 2) = avg.getCov(dataformats::VertexBase::kCovZZ); + for (const auto& vtx : vtxSeeds) { + if (vtx.getNContributors() < mRecoParams[iteration].params.SeedingMinContrib) { + continue; + } + ROOT::Math::SVector z; + z(0) = vtx.getX(); + z(1) = vtx.getY(); + z(2) = vtx.getZ(); + ROOT::Math::SMatrix R; + R(0, 0) = vtx.getCov(dataformats::VertexBase::kCovXX); + R(0, 1) = vtx.getCov(dataformats::VertexBase::kCovXY); + R(1, 0) = vtx.getCov(dataformats::VertexBase::kCovXY); + R(1, 1) = vtx.getCov(dataformats::VertexBase::kCovYY); + R(0, 2) = vtx.getCov(dataformats::VertexBase::kCovXZ); + R(2, 0) = vtx.getCov(dataformats::VertexBase::kCovXZ); + R(1, 2) = vtx.getCov(dataformats::VertexBase::kCovYZ); + R(2, 1) = vtx.getCov(dataformats::VertexBase::kCovYZ); + R(2, 2) = vtx.getCov(dataformats::VertexBase::kCovZZ); + ROOT::Math::SMatrix S = P + R; // innovation + if (!S.Invert()) { + continue; + } + ROOT::Math::SMatrix K = P * S; // gain + ROOT::Math::SVector y = z - x; // innovation + x += K * y; // state update + P = (I - K) * P; // cov update + } + // update avg + // do we need to symmetrize the matrix, probably not errors are anyways small + avg.setX(x[0]); + avg.setY(x[1]); + avg.setZ(x[2]); + avg.setCov(P(0, 0), dataformats::VertexBase::kCovXX); + avg.setCov(P(0, 1), dataformats::VertexBase::kCovXY); + avg.setCov(P(0, 2), dataformats::VertexBase::kCovXZ); + avg.setCov(P(1, 1), dataformats::VertexBase::kCovYY); + avg.setCov(P(1, 2), dataformats::VertexBase::kCovYZ); + avg.setCov(P(2, 2), dataformats::VertexBase::kCovZZ); + } + }); + sortSeeds(); +} +template +void TrackerTraits::findCellsNeighbours(const int iteration) +{ mTaskArena->execute([&] { - for (int iLayer{0}; iLayer < mTrkParams[iteration].NeighboursPerRoad(); ++iLayer) { + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NeighboursPerRoad(); ++iLayer) { deepVectorClear(mTimeFrame->getCellsNeighbours()[iLayer]); deepVectorClear(mTimeFrame->getCellsNeighboursLUT()[iLayer]); if (mTimeFrame->getCells()[iLayer + 1].empty() || @@ -481,40 +826,34 @@ void TrackerTraits::findCellsNeighbours(const int iteration) break; } - if (mTrkParams[iteration].DeltaROF) { // TODO this has to be improved for the staggering - const auto& trkl00 = mTimeFrame->getTracklets()[iLayer][currentCellSeed.getFirstTrackletIndex()]; - const auto& trkl01 = mTimeFrame->getTracklets()[iLayer + 1][currentCellSeed.getSecondTrackletIndex()]; - const auto& trkl10 = mTimeFrame->getTracklets()[iLayer + 1][nextCellSeed.getFirstTrackletIndex()]; - const auto& trkl11 = mTimeFrame->getTracklets()[iLayer + 2][nextCellSeed.getSecondTrackletIndex()]; - if ((std::max({trkl00.getMaxRof(), trkl01.getMaxRof(), trkl10.getMaxRof(), trkl11.getMaxRof()}) - - std::min({trkl00.getMinRof(), trkl01.getMinRof(), trkl10.getMinRof(), trkl11.getMinRof()})) > mTrkParams[0].DeltaROF) { - continue; - } + // by construction for each cell we already know that their tracklets are compatible in time + // and above we check that the cells use the same middle tracklet so we just have to make sure that the + // outermost tracklets are compatible in time + const auto& trkl00 = mTimeFrame->getTracklets()[iLayer][currentCellSeed.getFirstTrackletIndex()]; + const auto& trkl11 = mTimeFrame->getTracklets()[iLayer + 2][nextCellSeed.getSecondTrackletIndex()]; + if (!mTimeFrame->getROFOverlapTableView().isCompatible(iLayer, trkl00.rof[0], iLayer + 2, trkl11.rof[1])) { + continue; } if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) || !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) { continue; } - float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed); /// TODO: switch to the chi2 wrt cluster to avoid correlation + const float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed); /// TODO: switch to the chi2 wrt cluster to avoid correlation + const bool accept = chi2 <= mRecoParams[iteration].params.MaxChi2ClusterAttachment; -#ifdef OPTIMISATION_OUTPUT - bool good{mTimeFrame->getCellsLabel(iLayer)[iCell] == mTimeFrame->getCellsLabel(iLayer + 1)[iNextCell]}; - off << std::format("{}\t{:d}\t{}", iLayer, good, chi2) << std::endl; -#endif + debugFindCellsNeighbours(iteration, iLayer, iCell, iNextCell, accept); - if (chi2 > mTrkParams[0].MaxChi2ClusterAttachment) { - continue; - } - - if constexpr (decltype(Tag)::value == PassMode::OnePass::value) { - cellsNeighbours.emplace_back(iCell, iNextCell, currentCellSeed.getLevel() + 1); - } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) { - ++foundNextCells; - } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) { - cellsNeighbours[offset++] = {iCell, iNextCell, currentCellSeed.getLevel() + 1}; - } else { - static_assert(false, "Unknown mode!"); + if (accept) { + if constexpr (decltype(Tag)::value == PassMode::OnePass::value) { + cellsNeighbours.emplace_back(iCell, iNextCell, currentCellSeed.getLevel() + 1); + } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) { + ++foundNextCells; + } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) { + cellsNeighbours[offset++] = {iCell, iNextCell, currentCellSeed.getLevel() + 1}; + } else { + static_assert(false, "Unknown mode!"); + } } } return foundNextCells; @@ -577,15 +916,10 @@ void TrackerTraits::findCellsNeighbours(const int iteration) }); } -template -void TrackerTraits::processNeighbours(int iLayer, int iLevel, const bounded_vector& currentCellSeed, const bounded_vector& currentCellId, bounded_vector& updatedCellSeeds, bounded_vector& updatedCellsIds) +template +void TrackerTraits::processNeighbours(int iteration, int iLayer, int iLevel, const bounded_vector& currentCellSeed, const bounded_vector& currentCellId, bounded_vector& updatedCellSeeds, bounded_vector& updatedCellsIds) { - CA_DEBUGGER(std::cout << "Processing neighbours layer " << iLayer << " level " << iLevel << ", size of the cell seeds: " << currentCellSeed.size() << std::endl); - auto propagator = o2::base::Propagator::Instance(); - -#ifdef CA_DEBUG - int failed[5]{0, 0, 0, 0, 0}, attempts{0}, failedByMismatch{0}; -#endif + const auto& propagator = o2::base::Propagator::Instance(); mTaskArena->execute([&] { auto forCellNeighbours = [&](auto Tag, int iCell, int offset = 0) -> int { @@ -607,18 +941,15 @@ void TrackerTraits::processNeighbours(int iLayer, int iLevel, const bou const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId]}; int foundSeeds{0}; for (int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) { - CA_DEBUGGER(attempts++); const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iNeighbourCell]; const auto& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId]; if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) { - CA_DEBUGGER(failedByMismatch++); continue; } if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) { continue; } if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) { - CA_DEBUGGER(failed[0]++); continue; } @@ -627,29 +958,25 @@ void TrackerTraits::processNeighbours(int iLayer, int iLevel, const bou const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer - 1)[neighbourCell.getFirstClusterIndex()]; if (!seed.rotate(trHit.alphaTrackingFrame)) { - CA_DEBUGGER(failed[1]++); continue; } - if (!propagator->propagateToX(seed, trHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, mTrkParams[0].CorrType)) { - CA_DEBUGGER(failed[2]++); + if (!propagator->propagateToX(seed, trHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, mRecoParams[iteration].params.CorrType)) { continue; } - if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { - if (!seed.correctForMaterial(mTrkParams[0].LayerxX0[iLayer - 1], mTrkParams[0].LayerxX0[iLayer - 1] * constants::Radl * constants::Rho, true)) { + if (mRecoParams[iteration].params.CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { + if (!seed.correctForMaterial(mRecoParams[iteration].params.LayerxX0[iLayer - 1], mRecoParams[iteration].params.LayerxX0[iLayer - 1] * constants::Radl * constants::Rho, true)) { continue; } } auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)}; - if ((predChi2 > mTrkParams[0].MaxChi2ClusterAttachment) || predChi2 < 0.f) { - CA_DEBUGGER(failed[3]++); + if ((predChi2 > mRecoParams[iteration].params.MaxChi2ClusterAttachment) || predChi2 < 0.f) { continue; } seed.setChi2(seed.getChi2() + predChi2); if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) { - CA_DEBUGGER(failed[4]++); continue; } @@ -703,41 +1030,40 @@ void TrackerTraits::processNeighbours(int iLayer, int iLevel, const bou }); } }); - -#ifdef CA_DEBUG - std::cout << "\t\t- Found " << updatedCellSeeds.size() << " cell seeds out of " << attempts << " attempts" << std::endl; - std::cout << "\t\t\t> " << failed[0] << " failed because of level" << std::endl; - std::cout << "\t\t\t> " << failed[1] << " failed because of rotation" << std::endl; - std::cout << "\t\t\t> " << failed[2] << " failed because of propagation" << std::endl; - std::cout << "\t\t\t> " << failed[3] << " failed because of chi2 cut" << std::endl; - std::cout << "\t\t\t> " << failed[4] << " failed because of update" << std::endl; - std::cout << "\t\t\t> " << failedByMismatch << " failed because of mismatch" << std::endl; -#endif } -template -void TrackerTraits::findRoads(const int iteration) +template +void TrackerTraits::findRoads(const int iteration) { - bounded_vector> firstClusters(mTrkParams[iteration].NLayers, bounded_vector(mMemoryPool.get()), mMemoryPool.get()); - bounded_vector> sharedFirstClusters(mTrkParams[iteration].NLayers, bounded_vector(mMemoryPool.get()), mMemoryPool.get()); - firstClusters.resize(mTrkParams[iteration].NLayers); - sharedFirstClusters.resize(mTrkParams[iteration].NLayers); - for (int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) { + // we don't need tracklets anymore + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.TrackletsPerRoad(); ++iLayer) { + deepVectorClear(mTimeFrame->getTracklets()[iLayer]); + deepVectorClear(mTimeFrame->getTrackletsLookupTable()[iLayer]); + if ((mTimeFrame->hasMCinformation() && mRecoParams[iteration].params.createArtefactLabels) || OPTIMISATION_ANY) { + deepVectorClear(mTimeFrame->getTrackletsLabel(iLayer)); + } + } + + bounded_vector> firstClusters(mRecoParams[iteration].params.NLayers, bounded_vector(mMemoryPool.get()), mMemoryPool.get()); + bounded_vector> sharedFirstClusters(mRecoParams[iteration].params.NLayers, bounded_vector(mMemoryPool.get()), mMemoryPool.get()); + firstClusters.resize(mRecoParams[iteration].params.NLayers); + sharedFirstClusters.resize(mRecoParams[iteration].params.NLayers); + for (int startLevel{mRecoParams[iteration].params.CellsPerRoad()}; startLevel >= mRecoParams[iteration].params.CellMinimumLevel(); --startLevel) { auto seedFilter = [&](const auto& seed) { - return seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[0].MaxChi2NDF * ((startLevel + 2) * 2 - 5); + return seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mRecoParams[iteration].params.MaxChi2NDF * (((startLevel + 2) * 2) - 5); }; bounded_vector trackSeeds(mMemoryPool.get()); - for (int startLayer{mTrkParams[iteration].NeighboursPerRoad()}; startLayer >= startLevel - 1; --startLayer) { - if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) { + for (int startLayer{mRecoParams[iteration].params.NeighboursPerRoad()}; startLayer >= startLevel - 1; --startLayer) { + if ((mRecoParams[iteration].params.StartLayerMask & (1 << (startLayer + 2))) == 0) { continue; } bounded_vector lastCellId(mMemoryPool.get()), updatedCellId(mMemoryPool.get()); bounded_vector lastCellSeed(mMemoryPool.get()), updatedCellSeed(mMemoryPool.get()); - processNeighbours(startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId); + processNeighbours(iteration, startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId); int level = startLevel; for (int iLayer{startLayer - 1}; iLayer > 0 && level > 2; --iLayer) { @@ -745,7 +1071,7 @@ void TrackerTraits::findRoads(const int iteration) lastCellId.swap(updatedCellId); deepVectorClear(updatedCellSeed); /// tame the memory peaks deepVectorClear(updatedCellId); /// tame the memory peaks - processNeighbours(iLayer, --level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId); + processNeighbours(iteration, iLayer, --level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId); } deepVectorClear(lastCellId); /// tame the memory peaks deepVectorClear(lastCellSeed); /// tame the memory peaks @@ -765,7 +1091,7 @@ void TrackerTraits::findRoads(const int iteration) auto forSeed = [&](auto Tag, int iSeed, int offset = 0) { TrackITSExt temporaryTrack = seedTrackForRefit(trackSeeds[iSeed]); o2::track::TrackPar linRef{temporaryTrack}; - bool fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, o2::constants::math::VeryBig, 0, &linRef); + bool fitSuccess = fitTrack(temporaryTrack, 0, mRecoParams[iteration].params.NLayers, 1, mRecoParams[iteration].params.MaxChi2ClusterAttachment, mRecoParams[iteration].params.MaxChi2NDF, o2::constants::math::VeryBig, 0, &linRef); if (!fitSuccess) { return 0; } @@ -774,8 +1100,8 @@ void TrackerTraits::findRoads(const int iteration) temporaryTrack.resetCovariance(); temporaryTrack.setCov(temporaryTrack.getQ2Pt() * temporaryTrack.getQ2Pt() * temporaryTrack.getCov()[o2::track::CovLabels::kSigQ2Pt2], o2::track::CovLabels::kSigQ2Pt2); temporaryTrack.setChi2(0); - fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.f, 0, &linRef); - if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) { + fitSuccess = fitTrack(temporaryTrack, mRecoParams[iteration].params.NLayers - 1, -1, -1, mRecoParams[iteration].params.MaxChi2ClusterAttachment, mRecoParams[iteration].params.MaxChi2NDF, 50.f, 0, &linRef); + if (!fitSuccess || temporaryTrack.getPt() < mRecoParams[iteration].params.MinPt[mRecoParams[iteration].params.NLayers - temporaryTrack.getNClusters()]) { return 0; } if constexpr (decltype(Tag)::value == PassMode::OnePass::value) { @@ -826,7 +1152,7 @@ void TrackerTraits::findRoads(const int iteration) int nShared = 0; bool isFirstShared{false}; int firstLayer{-1}, firstCluster{-1}; - for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { continue; } @@ -834,41 +1160,35 @@ void TrackerTraits::findRoads(const int iteration) nShared += int(isShared); if (firstLayer < 0) { firstCluster = track.getClusterIndex(iLayer); - isFirstShared = isShared && mTrkParams[0].AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].end(), firstCluster) != firstClusters[iLayer].end(); + isFirstShared = isShared && mRecoParams[iteration].params.AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].end(), firstCluster) != firstClusters[iLayer].end(); firstLayer = iLayer; } } /// do not account for the first cluster in the shared clusters number if it is allowed - if (nShared - int(isFirstShared && mTrkParams[0].AllowSharingFirstCluster) > mTrkParams[0].ClusterSharing) { + if (nShared - int(isFirstShared && mRecoParams[iteration].params.AllowSharingFirstCluster) > mRecoParams[iteration].params.ClusterSharing) { continue; } - std::array rofs{INT_MAX, INT_MAX, INT_MAX}; - for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { + // here we can do the calculation of the time bracket simply + // by checkig in which rofs the clusters are + int bcStart{0}, bcEnd{std::numeric_limits::max()}; + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { continue; } mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer)); - for (int iR{0}; iR < 3; ++iR) { - if (rofs[iR] == INT_MAX) { - rofs[iR] = currentROF; - } - if (rofs[iR] == currentROF) { - break; - } - } - } - if (rofs[2] != INT_MAX) { - continue; + int bcClsSta = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFStartInBC(currentROF); + int bcClsEnd = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFEndInBC(currentROF); + bcStart = std::max(bcStart, bcClsSta); + bcEnd = std::min(bcEnd, bcClsEnd); } + track.getTimeStamp().setTimeStamp(bcStart); + track.getTimeStamp().setTimeStampError(bcEnd - bcStart + 1); track.setUserField(0); track.getParamOut().setUserField(0); - if (rofs[1] != INT_MAX) { - track.setNextROFbit(); - } - mTimeFrame->getTracks(o2::gpu::CAMath::Min(rofs[0], rofs[1])).emplace_back(track); + mTimeFrame->getTracks().emplace_back(track); firstClusters[firstLayer].push_back(firstCluster); if (isFirstShared) { @@ -877,15 +1197,14 @@ void TrackerTraits::findRoads(const int iteration) } } - /// Now we have to set the shared cluster flag - for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { - std::sort(sharedFirstClusters[iLayer].begin(), sharedFirstClusters[iLayer].end()); - } - - for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { - for (auto& track : mTimeFrame->getTracks(iROF)) { - int firstLayer{mTrkParams[0].NLayers}, firstCluster{constants::UnusedIndex}; - for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { + if (mRecoParams[iteration].params.AllowSharingFirstCluster) { + /// Now we have to set the shared cluster flag + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { + std::sort(sharedFirstClusters[iLayer].begin(), sharedFirstClusters[iLayer].end()); + } + for (auto& track : mTimeFrame->getTracks()) { + int firstLayer{mRecoParams[iteration].params.NLayers}, firstCluster{constants::UnusedIndex}; + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { continue; } @@ -898,148 +1217,167 @@ void TrackerTraits::findRoads(const int iteration) } } } -} -template -void TrackerTraits::extendTracks(const int iteration) -{ - for (int rof{0}; rof < mTimeFrame->getNrof(); ++rof) { - for (auto& track : mTimeFrame->getTracks(rof)) { - auto backup{track}; - bool success{false}; - // the order here biases towards top extension, tracks should probably be fitted separately in the directions and then compared. - if ((mTrkParams[iteration].UseTrackFollowerMix || mTrkParams[iteration].UseTrackFollowerTop) && track.getLastClusterLayer() != mTrkParams[iteration].NLayers - 1) { - success = success || trackFollowing(&track, rof, true, iteration); - } - if ((mTrkParams[iteration].UseTrackFollowerMix || (mTrkParams[iteration].UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) { - success = success || trackFollowing(&track, rof, false, iteration); - } - if (success) { - /// We have to refit the track - track.resetCovariance(); - track.setChi2(0); - bool fitSuccess = fitTrack(track, 0, mTrkParams[iteration].NLayers, 1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF); - if (!fitSuccess) { - track = backup; - continue; - } - track.getParamOut() = track; - track.resetCovariance(); - track.setChi2(0); - fitSuccess = fitTrack(track, mTrkParams[iteration].NLayers - 1, -1, -1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.); - if (!fitSuccess) { - track = backup; - continue; - } - mTimeFrame->mNExtendedTracks++; - mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters(); - auto pattern = track.getPattern(); - auto diff = (pattern & ~backup.getPattern()) & 0xff; - pattern |= (diff << 24); - track.setPattern(pattern); - /// Make sure that the newly attached clusters get marked as used - for (int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) { - if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { - continue; - } - mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); - } - } - } - } -} - -template -void TrackerTraits::findShortPrimaries() -{ - const auto propagator = o2::base::Propagator::Instance(); - mTimeFrame->fillPrimaryVerticesXandAlpha(); - - for (auto& cell : mTimeFrame->getCells()[0]) { - auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()]; - auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()]; - auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()]; - if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) || - mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) || - mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) { - continue; + // remove roads and cells + int nCells = mTimeFrame->getCells().size(); + for (int iLayer{0}; iLayer < nCells; ++iLayer) { + deepVectorClear(mTimeFrame->getTrackletsLookupTable()[iLayer]); + if (iLayer < nCells - 1) { + deepVectorClear(mTimeFrame->getCellsLookupTable()[iLayer]); + deepVectorClear(mTimeFrame->getCellsNeighbours()[iLayer]); + deepVectorClear(mTimeFrame->getCellsNeighboursLUT()[iLayer]); } - - std::array rofs{ - mTimeFrame->getClusterROF(2, cluster3_glo.clusterId), - mTimeFrame->getClusterROF(1, cluster2_glo.clusterId), - mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)}; - if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) { + if (iLayer == 0 && mRecoParams[iteration].params.FindShortTracks) { continue; } - - int rof{rofs[0]}; - if (rofs[1] == rofs[2]) { - rof = rofs[2]; - } - - auto pvs{mTimeFrame->getPrimaryVertices(rof)}; - auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(rof)}; - - const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2)[cluster3_glo.clusterId]; - TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)}; - temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId, true); - temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId, true); - temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId, true); - - /// add propagation to the primary vertices compatible with the ROF(s) of the cell - bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1); - if (!fitSuccess) { - continue; + deepVectorClear(mTimeFrame->getCells()[iLayer]); + if ((mTimeFrame->hasMCinformation() && mRecoParams[iteration].params.createArtefactLabels) || OPTIMISATION_ANY) { + deepVectorClear(mTimeFrame->getCellsLabel(iLayer)); } - fitSuccess = false; - - TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack}; - float bestChi2{std::numeric_limits::max()}; - for (int iV{0}; iV < (int)pvs.size(); ++iV) { - temporaryTrack = backup; - if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) { - continue; - } - if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0], true)) { - continue; - } + } + deepVectorClear(mTimeFrame->getRoads()); +} - float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(float(pvs[iV].getNContributors()))}; - const float posVtx[2]{0.f, pvs[iV].getZ()}; - const float covVtx[3]{pvRes, 0.f, pvRes}; - float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx); - if (chi2 < bestChi2) { - if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) { - continue; - } - bestTrack = temporaryTrack; - bestChi2 = chi2; - } - } +template +void TrackerTraits::extendTracks(const int iteration) +{ + // TODO fix + // for (auto& track : mTimeFrame->getTracks()) { + // auto backup{track}; + // bool success{false}; + // // the order here biases towards top extension, tracks should probably be fitted separately in the directions and then compared. + // if ((mRecoParams[iteration].params.UseTrackFollowerMix || mRecoParams[iteration].params.UseTrackFollowerTop) && track.getLastClusterLayer() != mRecoParams[iteration].params.NLayers - 1) { + // success = success || trackFollowing(&track, rof, true, iteration); + // } + // if ((mRecoParams[iteration].params.UseTrackFollowerMix || (mRecoParams[iteration].params.UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) { + // success = success || trackFollowing(&track, rof, false, iteration); + // } + // if (success) { + // /// We have to refit the track + // track.resetCovariance(); + // track.setChi2(0); + // bool fitSuccess = fitTrack(track, 0, mRecoParams[iteration].params.NLayers, 1, mRecoParams[iteration].params.MaxChi2ClusterAttachment, mRecoParams[0].params.MaxChi2NDF); + // if (!fitSuccess) { + // track = backup; + // continue; + // } + // track.getParamOut() = track; + // track.resetCovariance(); + // track.setChi2(0); + // fitSuccess = fitTrack(track, mRecoParams[iteration].params.NLayers - 1, -1, -1, mRecoParams[iteration].params.MaxChi2ClusterAttachment, mRecoParams[0].params.MaxChi2NDF, 50.); + // if (!fitSuccess) { + // track = backup; + // continue; + // } + // mTimeFrame->mNExtendedTracks++; + // mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters(); + // auto pattern = track.getPattern(); + // auto diff = (pattern & ~backup.getPattern()) & 0xff; + // pattern |= (diff << 24); + // track.setPattern(pattern); + // /// Make sure that the newly attached clusters get marked as used + // for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { + // if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { + // continue; + // } + // mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); + // } + // } + // } +} - bestTrack.resetCovariance(); - bestTrack.setChi2(0.f); - fitSuccess = fitTrack(bestTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF); - if (!fitSuccess) { - continue; - } - bestTrack.getParamOut() = bestTrack; - bestTrack.resetCovariance(); - bestTrack.setChi2(0.f); - fitSuccess = fitTrack(bestTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.); - if (!fitSuccess) { - continue; - } - mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0)); - mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1)); - mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2)); - mTimeFrame->getTracks(rof).emplace_back(bestTrack); - } +template +void TrackerTraits::findShortPrimaries(const int iteration) +{ + // TODO fix + // const auto propagator = o2::base::Propagator::Instance(); + // mTimeFrame->fillPrimaryVerticesXandAlpha(); + // + // for (auto& cell : mTimeFrame->getCells()[0]) { + // auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()]; + // auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()]; + // auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()]; + // if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) || + // mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) || + // mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) { + // continue; + // } + // + // std::array rofs{ + // mTimeFrame->getClusterROF(2, cluster3_glo.clusterId), + // mTimeFrame->getClusterROF(1, cluster2_glo.clusterId), + // mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)}; + // if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) { + // continue; + // } + // + // int rof{rofs[0]}; + // if (rofs[1] == rofs[2]) { + // rof = rofs[2]; + // } + // + // auto pvs{mTimeFrame->getPrimaryVertices(0, rof)}; + // auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(0, rof)}; + // + // const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2)[cluster3_glo.clusterId]; + // TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)}; + // temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId, true); + // temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId, true); + // temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId, true); + // + // /// add propagation to the primary vertices compatible with the ROF(s) of the cell + // bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1); + // if (!fitSuccess) { + // continue; + // } + // fitSuccess = false; + // + // TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack}; + // float bestChi2{std::numeric_limits::max()}; + // for (int iV{0}; iV < (int)pvs.size(); ++iV) { + // temporaryTrack = backup; + // if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) { + // continue; + // } + // if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0], true)) { + // continue; + // } + // + // float pvRes{mRecoParams[0].params.PVres / o2::gpu::CAMath::Sqrt(float(pvs[iV].getNContributors()))}; + // const float posVtx[2]{0.f, pvs[iV].getZ()}; + // const float covVtx[3]{pvRes, 0.f, pvRes}; + // float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx); + // if (chi2 < bestChi2) { + // if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) { + // continue; + // } + // bestTrack = temporaryTrack; + // bestChi2 = chi2; + // } + // } + // + // bestTrack.resetCovariance(); + // bestTrack.setChi2(0.f); + // fitSuccess = fitTrack(bestTrack, 0, mRecoParams[iteration].params.NLayers, 1, mRecoParams[iteration].params.MaxChi2ClusterAttachment, mRecoParams[iteration].params.MaxChi2NDF); + // if (!fitSuccess) { + // continue; + // } + // bestTrack.getParamOut() = bestTrack; + // bestTrack.resetCovariance(); + // bestTrack.setChi2(0.f); + // fitSuccess = fitTrack(bestTrack, mRecoParams[iteration].params.NLayers - 1, -1, -1, mRecoParams[iteration].params.MaxChi2ClusterAttachment, mRecoParams[iteration].params.MaxChi2NDF, 50.); + // if (!fitSuccess) { + // continue; + // } + // mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0)); + // mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1)); + // mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2)); + // mTimeFrame->getTracks().emplace_back(bestTrack); + // } } -template -bool TrackerTraits::fitTrack(TrackITSExt& track, int start, int end, int step, float chi2clcut, float chi2ndfcut, float maxQoverPt, int nCl, o2::track::TrackPar* linRef) +template +bool TrackerTraits::fitTrack(TrackITSExt& track, int start, int end, int step, float chi2clcut, float chi2ndfcut, float maxQoverPt, int nCl, o2::track::TrackPar* linRef) { auto propInstance = o2::base::Propagator::Instance(); @@ -1052,11 +1390,11 @@ bool TrackerTraits::fitTrack(TrackITSExt& track, int start, int end, in if (!track.rotate(trackingHit.alphaTrackingFrame, *linRef, getBz())) { return false; } - if (!propInstance->propagateToX(track, *linRef, trackingHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, mTrkParams[0].CorrType)) { + if (!propInstance->propagateToX(track, *linRef, trackingHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, mRecoParams[0].params.CorrType)) { return false; } - if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { - if (!track.correctForMaterial(*linRef, mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { + if (mRecoParams[0].params.CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { + if (!track.correctForMaterial(*linRef, mRecoParams[0].params.LayerxX0[iLayer], mRecoParams[0].params.LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { continue; } } @@ -1064,11 +1402,11 @@ bool TrackerTraits::fitTrack(TrackITSExt& track, int start, int end, in if (!track.rotate(trackingHit.alphaTrackingFrame)) { return false; } - if (!propInstance->propagateToX(track, trackingHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, mTrkParams[0].CorrType)) { + if (!propInstance->propagateToX(track, trackingHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl::MAX_SIN_PHI, o2::base::PropagatorImpl::MAX_STEP, mRecoParams[0].params.CorrType)) { return false; } - if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { - if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { + if (mRecoParams[0].params.CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { + if (!track.correctForMaterial(mRecoParams[0].params.LayerxX0[iLayer], mRecoParams[0].params.LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { continue; } } @@ -1081,7 +1419,7 @@ bool TrackerTraits::fitTrack(TrackITSExt& track, int start, int end, in if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { return false; } - if (linRef && mTrkParams[0].ShiftRefToCluster) { // displace the reference to the last updated cluster + if (linRef && mRecoParams[0].params.ShiftRefToCluster) { // displace the reference to the last updated cluster linRef->setY(trackingHit.positionTrackingFrame[0]); linRef->setZ(trackingHit.positionTrackingFrame[1]); } @@ -1090,12 +1428,12 @@ bool TrackerTraits::fitTrack(TrackITSExt& track, int start, int end, in return std::abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5); } -template -bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool outward, const int iteration) +template +bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool outward, const int iteration) { auto propInstance = o2::base::Propagator::Instance(); - const int step = -1 + outward * 2; - const int end = outward ? mTrkParams[iteration].NLayers - 1 : 0; + const int step = -1 + (static_cast(outward) * 2); + const int end = outward ? mRecoParams[iteration].params.NLayers - 1 : 0; bounded_vector hypotheses(1, *track, mMemoryPool.get()); // possibly avoid reallocation for (size_t iHypo{0}; iHypo < hypotheses.size(); ++iHypo) { auto hypo{hypotheses[iHypo]}; @@ -1103,7 +1441,7 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool ou // per layer we add new hypotheses while (iLayer != end) { iLayer += step; // step through all layers until we reach the end, this allows for skipping on empty layers - const float r = mTrkParams[iteration].LayerRadii[iLayer]; + const float r = mRecoParams[iteration].params.LayerRadii[iLayer]; // get an estimate of the trackinf-frame x for the next step float x{-999}; if (!hypo.getXatLabR(r, x, mTimeFrame->getBz(), o2::track::DirAuto) || x <= 0.f) { @@ -1111,13 +1449,13 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool ou } // estimate hypo's trk parameters at that x auto& hypoParam{outward ? hypo.getParamOut() : hypo.getParamIn()}; - if (!propInstance->propagateToX(hypoParam, x, mTimeFrame->getBz(), PropagatorF::MAX_SIN_PHI, - PropagatorF::MAX_STEP, mTrkParams[iteration].CorrType)) { + if (!propInstance->propagateToX(hypoParam, x, mTimeFrame->getBz(), base::PropagatorF::MAX_SIN_PHI, + base::PropagatorF::MAX_STEP, mRecoParams[iteration].params.CorrType)) { continue; } - if (mTrkParams[iteration].CorrType == PropagatorF::MatCorrType::USEMatCorrNONE) { // account for material affects if propagator does not - if (!hypoParam.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer], mTrkParams[iteration].LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { + if (mRecoParams[iteration].params.CorrType == base::PropagatorF::MatCorrType::USEMatCorrNONE) { // account for material affects if propagator does not + if (!hypoParam.correctForMaterial(mRecoParams[iteration].params.LayerxX0[iLayer], mRecoParams[iteration].params.LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { continue; } } @@ -1127,7 +1465,7 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool ou const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())}; const float z{hypoParam.getZ()}; const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())}; - const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].TrackFollowerNSigmaCutPhi * ePhi, z, mTrkParams[iteration].TrackFollowerNSigmaCutZ * eZ)}; + const int4 selectedBinsRect{getBinsRect(iteration, iLayer, phi, mRecoParams[iteration].params.NSigmaCut * ePhi, z, mRecoParams[iteration].params.NSigmaCut * eZ)}; if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { continue; } @@ -1135,7 +1473,7 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool ou int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; if (phiBinsNum < 0) { - phiBinsNum += mTrkParams[iteration].PhiBins; + phiBinsNum += mRecoParams[iteration].params.PhiBins; } gsl::span layer1 = mTimeFrame->getClustersOnLayer(rof, iLayer); @@ -1145,8 +1483,8 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool ou // check all clusters in search windows for possible new hypotheses for (int iPhiCount = 0; iPhiCount < phiBinsNum; iPhiCount++) { - int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins; - const int firstBinIndex{mTimeFrame->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)}; + int iPhiBin = (selectedBinsRect.y + iPhiCount) % mRecoParams[iteration].params.PhiBins; + const int firstBinIndex{mTimeFrame->getIndexTableUtils().getBinIndex(selectedBinsRect.x, iPhiBin)}; const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1}; const int firstRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[firstBinIndex]; const int maxRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[maxBinIndex]; @@ -1170,12 +1508,12 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool ou } if (!propInstance->propagateToX(tbuParams, trackingHit.xTrackingFrame, mTimeFrame->getBz(), - PropagatorF::MAX_SIN_PHI, PropagatorF::MAX_STEP, PropagatorF::MatCorrType::USEMatCorrNONE)) { + base::PropagatorF::MAX_SIN_PHI, base::PropagatorF::MAX_STEP, base::PropagatorF::MatCorrType::USEMatCorrNONE)) { continue; } auto predChi2{tbuParams.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; - if (predChi2 >= track->getChi2() * mTrkParams[iteration].NSigmaCut) { + if (predChi2 >= track->getChi2() * mRecoParams[iteration].params.NSigmaCut) { continue; } @@ -1193,7 +1531,7 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool ou TrackITSExt* bestHypo{track}; bool swapped{false}; for (auto& hypo : hypotheses) { - if (hypo.isBetter(*bestHypo, track->getChi2() * mTrkParams[iteration].NSigmaCut)) { + if (hypo.isBetter(*bestHypo, track->getChi2() * mRecoParams[iteration].params.NSigmaCut)) { bestHypo = &hypo; swapped = true; } @@ -1217,16 +1555,16 @@ TrackITSExt TrackerTraits::seedTrackForRefit(const CellSeedN& seed) } } int ncl = temporaryTrack.getNClusters(); - if (ncl < mTrkParams[0].ReseedIfShorter) { // reseed with circle passing via edges and the midpoint - if (ncl == mTrkParams[0].NLayers) { + if (ncl < mRecoParams[0].params.ReseedIfShorter) { // reseed with circle passing via edges and the midpoint + if (ncl == mRecoParams[0].params.NLayers) { lrMin = 0; - lrMax = mTrkParams[0].NLayers - 1; + lrMax = mRecoParams[0].params.NLayers - 1; lrMid = (lrMin + lrMax) / 2; } else { lrMid = lrMin + 1; - float midR = 0.5 * (mTrkParams[0].LayerRadii[lrMax] + mTrkParams[0].LayerRadii[lrMin]), dstMidR = o2::gpu::GPUCommonMath::Abs(midR - mTrkParams[0].LayerRadii[lrMid]); + float midR = 0.5 * (mRecoParams[0].params.LayerRadii[lrMax] + mRecoParams[0].params.LayerRadii[lrMin]), dstMidR = o2::gpu::GPUCommonMath::Abs(midR - mRecoParams[0].params.LayerRadii[lrMid]); for (int iL = lrMid + 1; iL < lrMax; ++iL) { // find the midpoint as closest to the midR - auto dst = o2::gpu::GPUCommonMath::Abs(midR - mTrkParams[0].LayerRadii[iL]); + auto dst = o2::gpu::GPUCommonMath::Abs(midR - mRecoParams[0].params.LayerRadii[iL]); if (dst < dstMidR) { lrMid = iL; dstMidR = dst; @@ -1250,20 +1588,20 @@ track::TrackParCov TrackerTraits::buildTrackSeed(const Cluster& cluster { const float sign = reverse ? -1.f : 1.f; - float ca, sa; + float ca = NAN, sa = NAN; o2::gpu::CAMath::SinCos(tf3.alphaTrackingFrame, sa, ca); - const float x1 = cluster1.xCoordinate * ca + cluster1.yCoordinate * sa; - const float y1 = -cluster1.xCoordinate * sa + cluster1.yCoordinate * ca; - const float x2 = cluster2.xCoordinate * ca + cluster2.yCoordinate * sa; - const float y2 = -cluster2.xCoordinate * sa + cluster2.yCoordinate * ca; + const float x1 = (cluster1.xCoordinate * ca) + (cluster1.yCoordinate * sa); + const float y1 = (-cluster1.xCoordinate * sa) + (cluster1.yCoordinate * ca); + const float x2 = (cluster2.xCoordinate * ca) + (cluster2.yCoordinate * sa); + const float y2 = (-cluster2.xCoordinate * sa) + (cluster2.yCoordinate * ca); const float x3 = tf3.xTrackingFrame; const float y3 = tf3.positionTrackingFrame[0]; - float snp, q2pt, q2pt2; + float snp = NAN, q2pt = NAN, q2pt2 = NAN; if (mIsZeroField) { const float tgp = o2::gpu::CAMath::ATan2(y3 - y1, x3 - x1); - snp = sign * tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp); + snp = sign * tgp / o2::gpu::CAMath::Sqrt(1.f + (tgp * tgp)); q2pt = sign / track::kMostProbablePt; q2pt2 = 1.f; } else { @@ -1280,24 +1618,136 @@ track::TrackParCov TrackerTraits::buildTrackSeed(const Cluster& cluster return {x3, tf3.alphaTrackingFrame, {y3, tf3.positionTrackingFrame[1], snp, tgl, q2pt}, {tf3.covarianceTrackingFrame[0], tf3.covarianceTrackingFrame[1], tf3.covarianceTrackingFrame[2], 0.f, 0.f, track::kCSnp2max, 0.f, 0.f, 0.f, track::kCTgl2max, 0.f, 0.f, 0.f, 0.f, sg2q2pt}}; } -template -void TrackerTraits::setBz(float bz) +template +void TrackerTraits::computeTruthSeeding() +{ + LOGP(info, "Using truth seeds as vertices; will skip computations"); + const auto dc = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); + const auto irs = dc->getEventRecords(); + // TODO in principle need to account for the bias which is anyways not well defined now + int64_t roFrameBiasInBC{0}; + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + roFrameBiasInBC += o2::itsmft::DPLAlpideParam::Instance().getROFBiasInBC(iLayer); + } + roFrameBiasInBC /= 7; + o2::steer::MCKinematicsReader mcReader(dc); + const int iSrc = 0; // take only events from collision generator + auto eveId2colId = dc->getCollisionIndicesForSource(iSrc); + int nVerts{0}; + for (int iEve{0}; iEve < mcReader.getNEvents(iSrc); ++iEve) { + const auto& ir = irs[eveId2colId[iEve]]; + if (!ir.isDummy()) { // do we need this, is this for diffractive events? + const auto& eve = mcReader.getMCEventHeader(iSrc, iEve); + int64_t bc = ((ir - o2::raw::HBFUtils::Instance().getFirstSampledTFIR()).toLong() - roFrameBiasInBC); + // find closest lower border in bcs + Vertex vert; + vert.getTimeStamp().setTimeStamp(bc); + vert.getTimeStamp().setTimeStampError(1); // place it exactly at the BC + // count potential contributors + int nCont{0}; + // for (const auto& trk : mcReader.getTracks(iSrc, iEve)) { + // if (!trk.leftTrace(o2::detectors::DetID::ITS, eve.getDetId2HitBitLUT())) { + // continue; + // } + // if (!trk.isPrimary() || trk.GetPt() < 0.2 || std::abs(trk.GetEta()) > 1.1) { + // continue; + // } + // if (auto pdg = o2::O2DatabasePDG::Instance()->GetParticle(trk.GetPdgCode()); pdg && pdg->Charge() == 0) { + // continue; + // } + // ++nCont; + // } + // set minimum to 1 sometimes for diffractive events there is nothing acceptance + vert.setNContributors(std::max(1, nCont)); + vert.setXYZ((float)eve.GetX(), (float)eve.GetY(), (float)eve.GetZ()); + vert.setChi2(1); // not used as constraint + vert.setCov(25e-4, 25e-4, 25e-4, 25e-4, 125e-4, 100e-4); + vert.print(); + o2::MCCompLabel lbl(o2::MCCompLabel::maxTrackID(), iEve, iSrc, false); + mTimeFrame->addPrimaryVertex(vert); + VertexLabel poll{lbl, 1.f}; + mTimeFrame->addPrimaryVertexLabel(poll); + ++nVerts; + } + mcReader.releaseTracksForSourceAndEvent(iSrc, iEve); + } + sortSeeds(); + LOGP(info, "Imposed {} MC vertices", nVerts); +} + +template +void TrackerTraits::sortSeeds() +{ + // sort seeding vertices: 1. time, 2. error, 3. multiplicity + // this by definition ensures that LUT is correct + // and the timeslicing works as indented + auto& seeds = mTimeFrame->getPrimaryVertices(); + auto& lbls = mTimeFrame->getPrimaryVerticesLabels(); + bounded_vector indices(seeds.size(), mMemoryPool.get()); + std::iota(indices.begin(), indices.end(), 0); + std::sort(indices.begin(), indices.end(), [&seeds](const size_t a, const size_t b) { + const auto& seedA = seeds[a]; + const auto& seedB = seeds[b]; + const auto& tA = seedA.getTimeStamp(); + const auto& tB = seedB.getTimeStamp(); + if (tA.getTimeStamp() != tB.getTimeStamp()) { + return tA.getTimeStamp() < tB.getTimeStamp(); + } + if (tA.getTimeStampError() != tB.getTimeStampError()) { + return tA.getTimeStampError() < tB.getTimeStampError(); + } + return seedA.getNContributors() < seedB.getNContributors(); + }); + bounded_vector seedsSorted(indices.size(), mMemoryPool.get()); + bounded_vector lblsSorted(mMemoryPool.get()); + if (mTimeFrame->hasMCinformation()) { + lblsSorted.resize(indices.size()); + } + for (size_t i{0}; i < indices.size(); ++i) { + seedsSorted[i] = seeds[indices[i]]; + if (mTimeFrame->hasMCinformation()) { + lblsSorted[i] = lbls[indices[i]]; + } + } + std::copy(seedsSorted.begin(), seedsSorted.end(), seeds.begin()); + if (mTimeFrame->hasMCinformation()) { + std::copy(lblsSorted.begin(), lblsSorted.end(), lbls.begin()); + } +} + +template +void TrackerTraits::setBz(float bz) { mBz = bz; mIsZeroField = std::abs(mBz) < 0.01; mTimeFrame->setBz(bz); } -template -bool TrackerTraits::isMatLUT() const +template +bool TrackerTraits::isMatLUT() const { - return o2::base::Propagator::Instance()->getMatLUT() && (mTrkParams[0].CorrType == o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT); + return o2::base::Propagator::Instance()->getMatLUT() && (mRecoParams[0].params.CorrType == o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT); } -template -void TrackerTraits::setNThreads(int n, std::shared_ptr& arena) +template +void TrackerTraits::updateTrackingParameters(const std::vector& recoPars) +{ + mRecoParams = recoPars; + if (static bool onceDone{false}; !onceDone) { + onceDone = true; + dbscan::DBSCANParams p{}; + p.minPts = mRecoParams[0].params.SeedingDBScanMinPt; + p.eps[0] = mRecoParams[0].params.SeedingDBScanEpsZ; + p.eps[1] = mRecoParams[0].params.SeedingDBScanEpsT; + mDBScan = dbscan::DBSCAN(p); + } +} + +template +void TrackerTraits::setNThreads(int n, std::shared_ptr& arena) { -#if defined(OPTIMISATION_OUTPUT) || defined(CA_DEBUG) +#if OPTIMISATION_ANY + LOGP(info, "Debug output enabled; enforcing single-threaded"); mTaskArena = std::make_shared(1); #else if (arena == nullptr) { @@ -1310,6 +1760,233 @@ void TrackerTraits::setNThreads(int n, std::shared_ptr #endif } +/// Debug dumps +class MCStat +{ + struct Record { + using MCMap = std::unordered_map; + int32_t mIter{-1}, mLayer{-1}; + MCMap mMap; + void print() const + { + uint32_t good{0}; + for (const auto& [lbl, s] : mMap) { + if (lbl.isValid() && s > 0) { + ++good; + } + } + double frac = ((double)good / (double)mMap.size()) * 100.; + LOGP(info, "\titer:{} layer:{} -> {}/{} (DS:{}) ({:.2f}%)", mIter, mLayer, good, mMap.size(), OPTIMISATION_DOWNSAMPLE, frac); + } + }; + Record* mCurRec{nullptr}; + std::vector mRecords; + const char* mName; + + public: + MCStat(const MCStat&) = default; + MCStat(MCStat&&) = delete; + MCStat& operator=(const MCStat&) = default; + MCStat& operator=(MCStat&&) = delete; + MCStat(const char* name) : mName(name) {} + ~MCStat() + { + LOGP(info, "Stats for {}:", mName); + for (const auto& rec : mRecords) { + rec.print(); + } + } + void account(int iteration, int layer, const o2::MCCompLabel& lbl, bool acc) + { + if (!lbl.isValid()) { + return; + } + if ((mCurRec == nullptr) || mCurRec->mIter != iteration || mCurRec->mLayer != layer) { + bool found{false}; + for (auto& rec : mRecords) { + if (rec.mIter == iteration && rec.mLayer == layer) { + mCurRec = &rec; + found = true; + } + } + if (!found) { + mRecords.emplace_back(); + mRecords.back().mIter = iteration; + mRecords.back().mLayer = layer; + mCurRec = &mRecords.back(); + } + } + auto& s = mCurRec->mMap[lbl]; + if (acc) { + ++s; + } + } +}; + +template +inline void TrackerTraits::debugComputeLayerTracklets(int iteration, int layer, const Cluster& currentCls, const Cluster& nextCls, const Vertex& pv, float sigmaZ, float sigmaPhi, bool accepted) +{ +#if OPTIMISATION_NOT_SET(OPTIMISATION_TRACKLETS) + return; // no-op +#endif + + static LogLogThrottler logger; + LOG_IF(info, logger.needToLog(iteration, layer)) << "debugTree: LayerTracklets:" << iteration << ":" << layer << " (1:" << OPTIMISATION_DOWNSAMPLE << ") dumped entries " << logger.evCount; + if (OPTIMISATION_DOWNSAMPLE > 1 && ((logger.evCount) % OPTIMISATION_DOWNSAMPLE) != 0) { + return; + } + + MCCompLabel label; + if (mTimeFrame->hasMCinformation()) { + int currentId{currentCls.clusterId}; + int nextId{nextCls.clusterId}; + for (auto& lab1 : mTimeFrame->getClusterLabels(layer, currentId)) { + for (auto& lab2 : mTimeFrame->getClusterLabels(layer + 1, nextId)) { + if (lab1 == lab2 && lab1.isValid()) { + label = lab1; + break; + } + } + if (label.isValid()) { + break; + } + } + } + + const float deltaPvZ = currentCls.zCoordinate - pv.getZ(); + const float tanLambda = deltaPvZ / currentCls.radius; + const float deltaZ = o2::gpu::GPUCommonMath::Abs((tanLambda * (nextCls.radius - currentCls.radius)) + currentCls.zCoordinate - nextCls.zCoordinate); + const float tglNext = (nextCls.zCoordinate - pv.getZ()) / nextCls.radius; + const float deltaZ2Pv = nextCls.zCoordinate + ((nextCls.zCoordinate - currentCls.zCoordinate) / (nextCls.radius - currentCls.radius) * (nextCls.radius - pv.getR())); + const float deltaPhi = o2::gpu::CAMath::Abs(o2::math_utils::toPMPi(currentCls.phi - nextCls.phi)); + + static MCStat stats("trackleting"); + stats.account(iteration, layer, label, accepted); + + (*sDBGOut) << "tracklets" + << "iter=" << iteration + << "lay=" << layer + << "lbl=" << label + << "pv=" << pv + << "curCls=" << currentCls + << "nextCls=" << nextCls + << "sigZ=" << sigmaZ + << "delZ=" << deltaZ + << "sigPhi=" << sigmaPhi + << "delPhi=" << deltaPhi + << "tgl=" << tanLambda + << "tglNext=" << tglNext + << "delZPv=" << deltaZ2Pv + << "acc=" << accepted + << "\n"; +} + +template +inline void TrackerTraits::debugComputeLayerCells(int iteration, int layer, int currentTrkl, int nextTrkl) +{ +#if !(OPTIMISATION_SET(OPTIMISATION_CELLS)) + return; // no-op +#endif + + static LogLogThrottler logger; + LOG_IF(info, logger.needToLog(iteration, layer)) << "debugTree: LayerCells:" << iteration << ":" << layer << " (1:" << OPTIMISATION_DOWNSAMPLE << ") dumped entries " << logger.evCount; + if (OPTIMISATION_DOWNSAMPLE > 1 && ((logger.evCount) % OPTIMISATION_DOWNSAMPLE) != 0) { + return; + } + + const Tracklet& currentTracklet{mTimeFrame->getTracklets()[layer][currentTrkl]}; + const auto currentLbl = mTimeFrame->getTrackletsLabel(layer)[currentTrkl]; + const Tracklet& nextTracklet{mTimeFrame->getTracklets()[layer + 1][nextTrkl]}; + const auto nextLbl = mTimeFrame->getTrackletsLabel(layer + 1)[nextTrkl]; + const auto lbl = (currentLbl == nextLbl) ? currentLbl : o2::MCCompLabel(); + + const float delTgl = std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda); + const float delPhi = o2::gpu::CAMath::Abs(o2::math_utils::toPMPi(nextTracklet.phi - currentTracklet.phi)); + + const auto& cls1 = mTimeFrame->getClusters()[layer][currentTracklet.firstClusterIndex]; + const auto& cls2 = mTimeFrame->getClusters()[layer + 1][nextTracklet.firstClusterIndex]; + const auto& cls3 = mTimeFrame->getClusters()[layer + 2][nextTracklet.secondClusterIndex]; + const float k123 = math_utils::computeCurvature(cls1.xCoordinate, cls1.yCoordinate, + cls2.xCoordinate, cls2.yCoordinate, + cls3.xCoordinate, cls3.yCoordinate); + const float k013 = math_utils::computeCurvature(0.f, 0.f, + cls1.xCoordinate, cls1.yCoordinate, + cls3.xCoordinate, cls3.yCoordinate); + const float dk = o2::gpu::CAMath::Abs(k123 - k013); + const float dR2 = 0.25f * (math_utils::Sq(cls1.xCoordinate - cls3.xCoordinate) + math_utils::Sq(cls1.yCoordinate - cls3.yCoordinate)); + const float tgl2 = math_utils::Sq(0.5 * (currentTracklet.tanLambda + nextTracklet.tanLambda)); + const float snl2 = tgl2 / (1.f + tgl2); + const float resMid2 = math_utils::Sq(mTimeFrame->getPositionResolution(layer + 1)); + const float msMid2 = math_utils::Sq(mTimeFrame->getMSangle(layer + 1)); + const float tglNSigma = o2::gpu::CAMath::Sqrt(resMid2 + msMid2) * mRecoParams[iteration].params.NSigmaCut; + const float kSigma2Pos = 6.f * resMid2 / math_utils::Sq(dR2); + const float kSigma2MS = msMid2 / (dR2 * snl2); + const float kNSigma = mRecoParams[iteration].params.NSigmaCut * o2::gpu::CAMath::Sqrt(kSigma2Pos + kSigma2MS); + + bool accepted = dk < kNSigma && delTgl < tglNSigma; + + static MCStat stats("celling"); + stats.account(iteration, layer, lbl, accepted); + + (*sDBGOut) << "cells" + << "iter=" << iteration + << "lay=" << layer + << "lbl=" << lbl + << "curLbl=" << currentLbl + << "nextLbl=" << nextLbl + << "delTgl=" << delTgl + << "delPhi=" << delPhi + << "curTrkl=" << currentTracklet + << "nextTrkl=" << nextTracklet + << "k123=" << k123 + << "k013=" << k013 + << "dk=" << dk + << "kNSigma=" << kNSigma + << "tglNSigma=" << tglNSigma + << "acc=" << accepted + << "\n"; +} + +template +inline void TrackerTraits::debugFindCellsNeighbours(int iteration, int layer, int currentCell, int nextCell, bool accepted) +{ +#if OPTIMISATION_NOT_SET(OPTIMISATION_CELLSNEIGH) + return; // no-op +#endif + + static LogLogThrottler logger; + LOG_IF(info, logger.needToLog(iteration, layer)) << "debugTree: CellsNeighbours:" << iteration << ":" << layer << " (1:" << OPTIMISATION_DOWNSAMPLE << ") dumped entries " << logger.evCount; + if (OPTIMISATION_DOWNSAMPLE > 1 && ((logger.evCount) % OPTIMISATION_DOWNSAMPLE) != 0) { + return; + } + + const auto& currentCellSeed{mTimeFrame->getCells()[layer][currentCell]}; + bool good{true}; + auto nextCellSeed{mTimeFrame->getCells()[layer + 1][nextCell]}; + if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) || + !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) { + good = false; + } + const auto& currentLbl = mTimeFrame->getCellsLabel(layer)[currentCell]; + const auto& nextLbl = mTimeFrame->getCellsLabel(layer + 1)[nextCell]; + const auto lbl = (currentLbl == nextLbl) ? currentLbl : o2::MCCompLabel(); + const auto chi2 = currentCellSeed.getPredictedChi2(nextCellSeed); + + (*sDBGOut) << "cneigh" + << "iter=" << iteration + << "lay=" << layer + << "lbl=" << lbl + << "curLbl=" << currentLbl + << "nextLbl=" << nextLbl + << "chi2=" << chi2 + << "curCell=" << currentCellSeed + << "nextCell=" << nextCellSeed + << "prop=" << good + << "acc=" << accepted + << "\n"; +} + +// explicitly instaniate the ITS2/ITS3 tracker functions template class TrackerTraits<7>; } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx index 3101c34d4ab8f..890ea8624987d 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackingConfigParam.cxx @@ -14,7 +14,6 @@ #include "Framework/Logger.h" #include "ITStracking/TrackingConfigParam.h" -O2ParamImpl(o2::its::VertexerParamConfig); O2ParamImpl(o2::its::TrackerParamConfig); O2ParamImpl(o2::its::ITSGpuTrackingParamConfig); diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx index d5f13cd9d25ea..7b03995de4a30 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include #include #include @@ -19,6 +20,7 @@ #include "ITSReconstruction/FastMultEstConfig.h" #include "ITSReconstruction/FastMultEst.h" +#include "ITStracking/Configuration.h" #include "ITStracking/TrackingConfigParam.h" #include "ITStracking/TrackingInterface.h" @@ -28,6 +30,8 @@ #include "CommonDataFormat/IRFrame.h" #include "DetectorsBase/GRPGeomHelper.h" #include "ITStracking/BoundedAllocator.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/DataRefUtils.h" #include "Framework/DeviceSpec.h" using namespace o2::framework; @@ -37,16 +41,13 @@ void ITSTrackingInterface::initialise() { // get parameters const auto& trackConf = o2::its::TrackerParamConfig::Instance(); - const auto& vertConf = o2::its::VertexerParamConfig::Instance(); if (auto parmode = (TrackingMode::Type)trackConf.trackingMode; mMode == TrackingMode::Unset || (parmode != TrackingMode::Unset && mMode != parmode)) { LOGP(info, "Tracking mode overwritten by configurable params from {} to {}", TrackingMode::toString(mMode), TrackingMode::toString(parmode)); mMode = parmode; } - auto trackParams = TrackingMode::getTrackingParameters(mMode); - auto vertParams = TrackingMode::getVertexingParameters(mMode); - LOGP(info, "Initializing tracker in {} phase reconstruction with {} passes for tracking and {}/{} for vertexing", TrackingMode::toString(mMode), trackParams.size(), o2::its::VertexerParamConfig::Instance().nIterations, vertParams.size()); - mTracker->setParameters(trackParams); - mVertexer->setParameters(vertParams); + auto iterations = TrackingMode::getRecoIterations(mMode); + LOGP(info, "Initializing tracker in {} phase reconstruction with {} passes for tracking", TrackingMode::toString(mMode), iterations.size()); + mTracker->setParameters(iterations); if (mMode == TrackingMode::Cosmics) { mRunVertexer = false; @@ -55,26 +56,90 @@ void ITSTrackingInterface::initialise() } // threading - if (trackConf.nThreads == vertConf.nThreads) { - bool clamped{false}; - int nThreads = trackConf.nThreads; - if (nThreads > 0) { - const int hw = std::thread::hardware_concurrency(); - const int maxThreads = (hw == 0 ? 1 : hw); - nThreads = std::clamp(nThreads, 1, maxThreads); - clamped = trackConf.nThreads > maxThreads; - } - LOGP(info, "Tracker and Vertexer will share the task arena with {} thread(s){}", nThreads, (clamped) ? " (clamped)" : ""); - mTaskArena = std::make_shared(std::abs(nThreads)); + bool clamped{false}; + int nThreads = trackConf.nThreads; + if (nThreads > 0) { + const int hw = std::thread::hardware_concurrency(); + const int maxThreads = (hw == 0 ? 1 : hw); + nThreads = std::clamp(nThreads, 1, maxThreads); + clamped = trackConf.nThreads > maxThreads; } - mVertexer->setNThreads(vertConf.nThreads, mTaskArena); + LOGP(info, "Tracker has {} thread(s){}", nThreads, (clamped) ? " (clamped)" : ""); + mTaskArena = std::make_shared(std::abs(nThreads)); mTracker->setNThreads(trackConf.nThreads, mTaskArena); + + // prepare data filter + for (int iLayer = 0; iLayer < NLayers; ++iLayer) { + mFilter.emplace_back("compClusters", "ITS", "COMPCLUSTERS", iLayer, Lifetime::Timeframe); + mFilter.emplace_back("patterns", "ITS", "PATTERNS", iLayer, Lifetime::Timeframe); + mFilter.emplace_back("ROframe", "ITS", "CLUSTERSROF", iLayer, Lifetime::Timeframe); + if (mIsMC) { + mFilter.emplace_back("itsmclabels", "ITS", "CLUSTERSMCTR", iLayer, Lifetime::Timeframe); + } + } } void ITSTrackingInterface::run(framework::ProcessingContext& pc) { - auto compClusters = pc.inputs().get>("compClusters"); - gsl::span patterns = pc.inputs().get>("patterns"); + if (static bool doneOnce{false}; !doneOnce) { + doneOnce = true; + + // prepare rof lookup table(s) + // has to be done here to ensure we get the right number of HB per TF + const int nOrbitsPerTF = o2::base::GRPGeomHelper::getNHBFPerTF(); + TimeFrameN::ROFOverlapTableN rofTable; + TimeFrameN::ROFVertexLookupTableN vtxTable; + TimeFrameN::ROFTimeSliceTableN sliceTable; + const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + const auto& trackParams = mTracker->getParameters(); + for (int iLayer = 0; iLayer < NLayers; ++iLayer) { + const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer); + const LayerTiming timing{.mNROFsTF = (nROFsPerOrbit * nOrbitsPerTF), .mROFLength = par.getROFLengthInBC(iLayer), .mROFDelay = par.getROFDelayInBC(iLayer), .mROFDelta = trackParams[0].params.DeltaROF[iLayer]}; + rofTable.defineLayer(iLayer, timing); + vtxTable.defineLayer(iLayer, timing); + sliceTable.defineLayer(iLayer, timing); + } + rofTable.init(); + mTimeFrame->setROFOverlapTable(rofTable); + vtxTable.init(); + mTimeFrame->setROFVertexLookupTable(vtxTable); + sliceTable.init(trackParams[0].params.NTimeSlices); + mTimeFrame->setROFTimeSliceTable(sliceTable); + } + + std::array, NLayers> compClusters; + std::array, NLayers> patterns; + std::array, NLayers> rofsinput; + std::array*, NLayers> labels{}; + + // filter input and compose + for (const DataRef& ref : framework::InputRecordWalker{pc.inputs(), mFilter}) { + auto const* dh = DataRefUtils::getHeader(ref); + if (framework::DataRefUtils::match(ref, {"compClusters", framework::ConcreteDataTypeMatcher{"ITS", "COMPCLUSTERS"}})) { + compClusters[dh->subSpecification] = pc.inputs().get>(ref); + } + if (framework::DataRefUtils::match(ref, {"patterns", framework::ConcreteDataTypeMatcher{"ITS", "PATTERNS"}})) { + patterns[dh->subSpecification] = pc.inputs().get>(ref); + } + if (framework::DataRefUtils::match(ref, {"ROframes", framework::ConcreteDataTypeMatcher{"ITS", "CLUSTERSROF"}})) { + rofsinput[dh->subSpecification] = pc.inputs().get>(ref); + } + if (framework::DataRefUtils::match(ref, {"itsmclabels", framework::ConcreteDataTypeMatcher{"ITS", "CLUSTERSMCTR"}})) { + labels[dh->subSpecification] = pc.inputs().get*>(ref).release(); + } + } + const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); + for (int iLayer = 0; iLayer < NLayers; ++iLayer) { + LOGP(info, "ITSTracker:{} pulled {} clusters, {} RO frames", iLayer, compClusters[iLayer].size(), rofsinput[iLayer].size()); + if (compClusters[iLayer].empty()) { + LOGP(warn, " -> received no processable data on layer {}", iLayer); + } + if (mIsMC) { + LOG(info) << " -> " << labels[iLayer]->getIndexedSize() << " MC label objects"; + } + } + + // trigger gsl::span physTriggers; std::vector fromTRD; if (mUseTriggers == 2) { // use TRD triggers @@ -91,27 +156,12 @@ void ITSTrackingInterface::run(framework::ProcessingContext& pc) physTriggers = pc.inputs().get>("phystrig"); } - auto rofsinput = pc.inputs().get>("ROframes"); - auto& trackROFvec = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0}, rofsinput.begin(), rofsinput.end()); + // prepare output data auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0}); - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB - - irFrames.reserve(trackROFvec.size()); - int nBCPerTF = alpParams.roFrameLengthInBC; - - LOGP(info, "ITSTracker pulled {} clusters, {} RO frames {}", compClusters.size(), trackROFvec.size(), compClusters.empty() ? " -> received no processable data will skip" : ""); - const dataformats::MCTruthContainer* labels = nullptr; - gsl::span mc2rofs; - if (mIsMC) { - labels = pc.inputs().get*>("itsmclabels").release(); - // get the array as read-only span, a snapshot is sent forward - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0}, pc.inputs().get>("ITSMC2ROframes")); - LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; - } - + // FIXME + // irFrames.reserve(trackROFvec.size()); auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0}); auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0}); - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0}); auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0}); // MC @@ -119,199 +169,181 @@ void ITSTrackingInterface::run(framework::ProcessingContext& pc) static pmr::vector dummyMCPurVerts; auto& allTrackLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "TRACKSMCTR", 0}) : dummyMCLabTracks; auto& allVerticesLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "VERTICESMCTR", 0}) : dummyMCLabVerts; - bool writeContLabels = mIsMC && o2::its::VertexerParamConfig::Instance().outputContLabels; - auto& allVerticesContLabels = writeContLabels ? pc.outputs().make>(Output{"ITS", "VERTICESMCTRCONT", 0}) : dummyMCLabVerts; auto& allVerticesPurities = mIsMC ? pc.outputs().make>(Output{"ITS", "VERTICESMCPUR", 0}) : dummyMCPurVerts; - std::uint32_t roFrame = 0; - bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); LOG(info) << "ITSTracker RO: continuous=" << continuous; if (mOverrideBeamEstimation) { - mTimeFrame->setBeamPosition(mMeanVertex->getX(), - mMeanVertex->getY(), - mMeanVertex->getSigmaY2(), - mTracker->getParameters()[0].LayerResolution[0], - mTracker->getParameters()[0].SystErrorY2[0]); + mTimeFrame->setMeanVertex(mMeanVertex, TrackerParamConfig::Instance().seedingMeanVertexExtraErr2); } mTracker->setBz(o2::base::Propagator::Instance()->getNominalBz()); - gsl::span::iterator pattIt = patterns.begin(); - gsl::span trackROFspan(trackROFvec); - loadROF(trackROFspan, compClusters, pattIt, labels); - pattIt = patterns.begin(); + for (int iLayer = 0; iLayer < NLayers; ++iLayer) { + gsl::span::iterator pattIt = patterns[iLayer].begin(); + loadROF(rofsinput[iLayer], compClusters[iLayer], pattIt, iLayer, labels[iLayer]); + } auto logger = [&](const std::string& s) { LOG(info) << s; }; auto fatalLogger = [&](const std::string& s) { LOG(fatal) << s; }; auto errorLogger = [&](const std::string& s) { LOG(error) << s; }; FastMultEst multEst; // mult estimator - std::vector processingMask, processUPCMask; - int cutVertexMult{0}, cutUPCVertex{0}, cutRandomMult = int(trackROFvec.size()) - multEst.selectROFs(trackROFvec, compClusters, physTriggers, processingMask); - processUPCMask.resize(processingMask.size(), false); - mTimeFrame->setMultiplicityCutMask(processingMask); - float vertexerElapsedTime{0.f}; - if (mRunVertexer) { - vertROFvec.reserve(trackROFvec.size()); - // Run seeding vertexer - if (!compClusters.empty()) { - vertexerElapsedTime = mVertexer->clustersToVertices(logger); - } - } else { // cosmics - mTimeFrame->resetRofPV(); - } + // std::array, NLayers> processingMask, processUPCMask; + // std::array cutRandomMult{}; + // for (int iLayer = 0; iLayer < NLayers; ++iLayer) { + // cutRandomMult[iLayer] = int(rofsinput[iLayer].size()) - multEst.selectROFs(rofsinput[iLayer], compClusters[iLayer], physTriggers, processingMask[iLayer]); + // processUPCMask[iLayer].resize(processingMask.size(), 0u); + // } + // int cutVertexMult{0}, cutUPCVertex{0}; + // mTimeFrame->setMultiplicityCutMask(processingMask); + // float vertexerElapsedTime{0.f}; + // if (mRunVertexer) { + // Run seeding vertexer + // vertexerElapsedTime = mVertexer->clustersToVertices(logger); + // } else { // cosmics + // mTimeFrame->resetRofPV(); + // } const auto& multEstConf = FastMultEstConfig::Instance(); // parameters for mult estimation and cuts gsl::span> vMCRecInfo; gsl::span vMCContLabels; - for (auto iRof{0}; iRof < trackROFspan.size(); ++iRof) { - bounded_vector vtxVecLoc; - auto& vtxROF = vertROFvec.emplace_back(trackROFspan[iRof]); - vtxROF.setFirstEntry(vertices.size()); - if (mRunVertexer) { - auto vtxSpan = mTimeFrame->getPrimaryVertices(iRof); - if (mIsMC) { - vMCRecInfo = mTimeFrame->getPrimaryVerticesMCRecInfo(iRof); - if (o2::its::VertexerParamConfig::Instance().outputContLabels) { - vMCContLabels = mTimeFrame->getPrimaryVerticesContributors(iRof); - } - } - if (o2::its::TrackerParamConfig::Instance().doUPCIteration) { - if (!vtxSpan.empty()) { - if (vtxSpan[0].isFlagSet(Vertex::UPCMode) == 1) { // at least one vertex in this ROF and it is from second vertex iteration - LOGP(debug, "ROF {} rejected as vertices are from the UPC iteration", iRof); - processUPCMask[iRof] = true; - cutUPCVertex++; - vtxROF.setFlag(o2::itsmft::ROFRecord::VtxUPCMode); - } else { // in all cases except if as standard mode vertex was found, the ROF was processed with UPC settings - vtxROF.setFlag(o2::itsmft::ROFRecord::VtxStdMode); - } - } else { - vtxROF.setFlag(o2::itsmft::ROFRecord::VtxUPCMode); - } - } else { - vtxROF.setFlag(o2::itsmft::ROFRecord::VtxStdMode); - } - vtxROF.setNEntries(vtxSpan.size()); - bool selROF = vtxSpan.empty(); - for (int iV{0}, iVC{0}; iV < vtxSpan.size(); ++iV) { - const auto& v = vtxSpan[iV]; - if (multEstConf.isVtxMultCutRequested() && !multEstConf.isPassingVtxMultCut(v.getNContributors())) { - iVC += v.getNContributors(); - continue; // skip vertex of unwanted multiplicity - } - selROF = true; - vertices.push_back(v); - if (mIsMC && !VertexerParamConfig::Instance().useTruthSeeding) { - allVerticesLabels.push_back(vMCRecInfo[iV].first); - allVerticesPurities.push_back(vMCRecInfo[iV].second); - if (o2::its::VertexerParamConfig::Instance().outputContLabels) { - allVerticesContLabels.insert(allVerticesContLabels.end(), vMCContLabels.begin() + iVC, vMCContLabels.begin() + iVC + v.getNContributors()); - } - } - iVC += v.getNContributors(); - } - if (processingMask[iRof] && !selROF) { // passed selection in clusters and not in vertex multiplicity - LOGP(info, "ROF {} rejected by the vertex multiplicity selection [{},{}]", iRof, multEstConf.cutMultVtxLow, multEstConf.cutMultVtxHigh); - processingMask[iRof] = selROF; - cutVertexMult++; - } - } else { // cosmics - vtxVecLoc.emplace_back(); - vtxVecLoc.back().setNContributors(1); - vtxROF.setNEntries(vtxVecLoc.size()); - for (auto& v : vtxVecLoc) { - vertices.push_back(v); - } - mTimeFrame->addPrimaryVertices(vtxVecLoc, 0); - } - } - if (mRunVertexer && !compClusters.empty()) { - LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms for {} ({} + {}) vertices found in {}/{} ROFs", - vertexerElapsedTime, - mTimeFrame->getPrimaryVerticesNum(), - mTimeFrame->getTotVertIteration()[0], - o2::its::VertexerParamConfig::Instance().nIterations > 1 ? mTimeFrame->getTotVertIteration()[1] : 0, - trackROFspan.size() - mTimeFrame->getNoVertexROF(), - trackROFspan.size()); - LOG(info) << fmt::format(" - FastMultEst: rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, trackROFspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); - } - if (mOverrideBeamEstimation) { - LOG(info) << fmt::format(" - Beam position set to: {}, {} from meanvertex object", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); + // for (auto iRof{0}; iRof < rofsinput[1].size(); ++iRof) { + // bounded_vector vtxVecLoc; + // auto& vtxROF = vertROFvec.emplace_back(rofsinput[1][iRof]); + // vtxROF.setFirstEntry(vertices.size()); + // if (mRunVertexer) { + // auto vtxSpan = mTimeFrame->getPrimaryVertices(iRof); + // if (mIsMC) { + // vMCRecInfo = mTimeFrame->getPrimaryVerticesMCRecInfo(iRof); + // } + // if (o2::its::TrackerParamConfig::Instance().doUPCIteration) { + // if (!vtxSpan.empty()) { + // if (vtxSpan[0].isFlagSet(Vertex::UPCMode) == 1) { // at least one vertex in this ROF and it is from second vertex iteration + // LOGP(debug, "ROF {} rejected as vertices are from the UPC iteration", iRof); + // // processUPCMask[1][iRof] = 1; + // // cutUPCVertex++; + // vtxROF.setFlag(o2::itsmft::ROFRecord::VtxUPCMode); + // } else { // in all cases except if as standard mode vertex was found, the ROF was processed with UPC settings + // vtxROF.setFlag(o2::itsmft::ROFRecord::VtxStdMode); + // } + // } else { + // vtxROF.setFlag(o2::itsmft::ROFRecord::VtxUPCMode); + // } + // } else { + // vtxROF.setFlag(o2::itsmft::ROFRecord::VtxStdMode); + // } + // vtxROF.setNEntries(vtxSpan.size()); + // bool selROF = vtxSpan.empty(); + // for (int iV{0}, iVC{0}; iV < vtxSpan.size(); ++iV) { + // const auto& v = vtxSpan[iV]; + // if (multEstConf.isVtxMultCutRequested() && !multEstConf.isPassingVtxMultCut(v.getNContributors())) { + // iVC += v.getNContributors(); + // continue; // skip vertex of unwanted multiplicity + // } + // selROF = true; + // vertices.push_back(v); + // if (mIsMC && !VertexerParamConfig::Instance().useTruthSeeding) { + // allVerticesLabels.push_back(vMCRecInfo[iV].first); + // allVerticesPurities.push_back(vMCRecInfo[iV].second); + // } + // iVC += v.getNContributors(); + // } + // // FIXME + // // if (processingMask[iRof] && !selROF) { // passed selection in clusters and not in vertex multiplicity + // // LOGP(info, "ROF {} rejected by the vertex multiplicity selection [{},{}]", iRof, multEstConf.cutMultVtxLow, multEstConf.cutMultVtxHigh); + // // processingMask[iRof] = selROF; + // // cutVertexMult++; + // // } + // } else { // cosmics + // vtxVecLoc.emplace_back(); + // vtxVecLoc.back().setNContributors(1); + // vtxROF.setNEntries(vtxVecLoc.size()); + // for (auto& v : vtxVecLoc) { + // vertices.push_back(v); + // } + // mTimeFrame->addPrimaryVertices(vtxVecLoc, 0); + // } + // } + // if (mRunVertexer) { + // LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms for {} ({} + {}) vertices found in {}/{} ROFs", + // vertexerElapsedTime, + // mTimeFrame->getPrimaryVerticesNum(), + // mTimeFrame->getTotVertIteration()[0], + // o2::its::VertexerParamConfig::Instance().nIterations > 1 ? mTimeFrame->getTotVertIteration()[1] : 0, + // rofsinput[1].size() - mTimeFrame->getNoVertexROF(), + // rofsinput[1].size()); + // // LOG(info) << fmt::format(" - FastMultEst: rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, trackROFspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); + // } + // if (mOverrideBeamEstimation) { + // LOG(info) << fmt::format(" - Beam position set to: {}, {} from meanvertex object", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); + // } else { + // LOG(info) << fmt::format(" - Beam position computed for the TF: {}, {}", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); + // } + // mTimeFrame->setMultiplicityCutMask(processingMask); + // mTimeFrame->setROFMask(processUPCMask); + // Run CA tracker + if (mMode == o2::its::TrackingMode::Async && o2::its::TrackerParamConfig::Instance().fataliseUponFailure) { + mTracker->clustersToTracks(logger, fatalLogger); } else { - LOG(info) << fmt::format(" - Beam position computed for the TF: {}, {}", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); + mTracker->clustersToTracks(logger, errorLogger); } - if (mCosmicsProcessing && compClusters.size() > 1500 * trackROFspan.size()) { - LOG(error) << "Cosmics processing was requested with an average detector occupancy exceeding 1.e-7, skipping TF processing."; - } else { - if (!compClusters.empty()) { - mTimeFrame->setMultiplicityCutMask(processingMask); - mTimeFrame->setROFMask(processUPCMask); - // Run CA tracker - if (mMode == o2::its::TrackingMode::Async && o2::its::TrackerParamConfig::Instance().fataliseUponFailure) { - mTracker->clustersToTracks(logger, fatalLogger); - } else { - mTracker->clustersToTracks(logger, errorLogger); - } - } - size_t totTracks{mTimeFrame->getNumberOfTracks()}, totClusIDs{mTimeFrame->getNumberOfUsedClusters()}; - if (totTracks) { - allTracks.reserve(totTracks); - allClusIdx.reserve(totClusIDs); - if (mTimeFrame->hasBogusClusters()) { - LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mTimeFrame->hasBogusClusters()); - } + if (mTimeFrame->hasBogusClusters()) { + LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mTimeFrame->hasBogusClusters()); + } - for (unsigned int iROF{0}; iROF < trackROFvec.size(); ++iROF) { - auto& tracksROF{trackROFvec[iROF]}; - auto& vtxROF = vertROFvec[iROF]; - auto& tracks = mTimeFrame->getTracks(iROF); - auto number{tracks.size()}; - auto first{allTracks.size()}; - int offset = -tracksROF.getFirstEntry(); // cluster entry!!! - tracksROF.setFirstEntry(first); - tracksROF.setNEntries(number); - tracksROF.setFlags(vtxROF.getFlags()); // copies 0xffffffff if cosmics - if (processingMask[iROF]) { - irFrames.emplace_back(tracksROF.getBCData(), tracksROF.getBCData() + nBCPerTF - 1).info = tracks.size(); - } - allTrackLabels.reserve(mTimeFrame->getTracksLabel(iROF).size()); // should be 0 if not MC - std::copy(mTimeFrame->getTracksLabel(iROF).begin(), mTimeFrame->getTracksLabel(iROF).end(), std::back_inserter(allTrackLabels)); - // Some conversions that needs to be moved in the tracker internals - for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { - auto& trc{tracks[iTrk]}; - trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices - int ncl = trc.getNumberOfClusters(), nclf = 0; - for (int ic = TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! - auto clid = trc.getClusterIndex(ic); - if (clid >= 0) { - trc.setClusterSize(ic, mTimeFrame->getClusterSize(clid)); - allClusIdx.push_back(clid); - nclf++; - } - } - assert(ncl == nclf); - allTracks.emplace_back(trc); - } - } - } else { - for (auto& r : trackROFvec) { // reset data copied from the clusters - r.setFirstEntry(0); - r.setNEntries(0); + // vertices are already sorted in time + if (size_t totVertices{mTimeFrame->getPrimaryVerticesNum()}; totVertices) { + allVerticesLabels.reserve(totVertices); + if (mIsMC) { + allVerticesLabels.reserve(totVertices); + allVerticesPurities.reserve(totVertices); + } + for (size_t iVtx{0}; iVtx < totVertices; ++iVtx) { + vertices.emplace_back(mTimeFrame->getPrimaryVertex(iVtx)); + if (mIsMC) { + const auto& lbl = mTimeFrame->getPrimaryVerticesLabels()[iVtx]; + allVerticesLabels.emplace_back(lbl.first); + allVerticesPurities.emplace_back(lbl.second); } } - LOGP(info, "ITSTracker pushed {} tracks and {} vertices", allTracks.size(), vertices.size()); + } + + // tracks are already sorted in time + if (size_t totTracks{mTimeFrame->getNumberOfTracks()}; totTracks) { + allTracks.reserve(totTracks); + allClusIdx.reserve(mTimeFrame->getNumberOfUsedClusters()); if (mIsMC) { - LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); - LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); - if (!allVerticesContLabels.empty()) { - LOGP(info, "ITSTracker pushed {} vertex contributor labels", allVerticesContLabels.size()); + allTrackLabels.reserve(totTracks); + } + const auto& lbls = mTimeFrame->getTracksLabel(); + auto& tracks = mTimeFrame->getTracks(); + for (size_t iTrk{0}; iTrk < totTracks; ++iTrk) { + auto& trc{tracks[iTrk]}; + trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices + int ncl = trc.getNumberOfClusters(), nclf = 0; + for (int ic = TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! + auto clid = trc.getClusterIndex(ic); + if (clid >= 0) { + trc.setClusterSize(ic, mTimeFrame->getClusterSize(ic, clid)); + allClusIdx.emplace_back(clid); + nclf++; + } + } + assert(ncl == nclf); + allTracks.emplace_back(trc); + if (mIsMC) { + allTrackLabels.emplace_back(mTimeFrame->getTracksLabel()[iTrk]); } - LOGP(info, "ITSTracker pushed {} vertex purities", allVerticesPurities.size()); } } + + LOGP(info, "ITSTracker pushed {} tracks and {} vertices", allTracks.size(), vertices.size()); + if (mIsMC) { + LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); + LOGP(info, "ITSTracker pushed {} vertex labels and purities", allVerticesLabels.size()); + } mTimeFrame->wipe(); } @@ -334,17 +366,9 @@ void ITSTrackingInterface::updateTimeDependentParams(framework::ProcessingContex initialise(); if (pc.services().get().inputTimesliceId == 0) { // print settings only for the 1st pipeling - o2::its::VertexerParamConfig::Instance().printKeyValues(); - o2::its::TrackerParamConfig::Instance().printKeyValues(); - const auto& vtxParams = mVertexer->getParameters(); - for (size_t it = 0; it < vtxParams.size(); it++) { - const auto& par = vtxParams[it]; - LOGP(info, "vtxIter#{} : {}", it, par.asString()); - } - const auto& trParams = mTracker->getParameters(); - for (size_t it = 0; it < trParams.size(); it++) { - const auto& par = trParams[it]; - LOGP(info, "recoIter#{} : {}", it, par.asString()); + o2::its::TrackerParamConfig::Instance().printKeyValues(true, true); + for (const auto& par : getTracker()->getParameters()) { + LOGP(info, "{}", par.asString()); } } } @@ -364,7 +388,7 @@ void ITSTrackingInterface::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { LOG(info) << "Alpide param updated"; const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); + par.printKeyValues(true, true); return; } if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { @@ -384,31 +408,27 @@ void ITSTrackingInterface::printSummary() const mTracker->printSummary(); } -void ITSTrackingInterface::setTraitsFromProvider(VertexerTraitsN* vertexerTraits, - TrackerTraitsN* trackerTraits, +void ITSTrackingInterface::setTraitsFromProvider(TrackerTraitsN* trackerTraits, TimeFrameN* frame) { - mVertexer = std::make_unique(vertexerTraits); mTracker = std::make_unique(trackerTraits); mTimeFrame = frame; - mVertexer->adoptTimeFrame(*mTimeFrame); mTracker->adoptTimeFrame(*mTimeFrame); // set common memory resource if (!mMemoryPool) { mMemoryPool = std::make_shared(); } - vertexerTraits->setMemoryPool(mMemoryPool); trackerTraits->setMemoryPool(mMemoryPool); mTimeFrame->setMemoryPool(mMemoryPool); mTracker->setMemoryPool(mMemoryPool); - mVertexer->setMemoryPool(mMemoryPool); } void ITSTrackingInterface::loadROF(gsl::span& trackROFspan, gsl::span clusters, gsl::span::iterator& pattIt, + int layer, const dataformats::MCTruthContainer* mcLabels) { - mTimeFrame->loadROFrameData(trackROFspan, clusters, pattIt, mDict, mcLabels); + mTimeFrame->loadROFrameData(trackROFspan, clusters, pattIt, mDict, layer, mcLabels); } diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h b/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h index 2fe70e96248f9..9aa5f8396c88a 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackingLinkDef.h @@ -15,24 +15,19 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class std::vector < o2::its::Vertex> + ; + #pragma link C++ class o2::its::Tracklet + ; #pragma link C++ class std::vector < o2::its::Tracklet> + ; #pragma link C++ class o2::its::Cluster + ; #pragma link C++ class std::vector < o2::its::Cluster> + ; +#pragma link C++ class o2::its::LinearizedTrack + ; + #pragma link C++ class o2::its::TrackingFrameInfo + ; #pragma link C++ class std::vector < o2::its::TrackingFrameInfo> + ; -#pragma link C++ class o2::its::Line + ; -#pragma link C++ class std::vector < o2::its::Line> + ; - -#pragma link C++ class o2::its::ClusterLines + ; -#pragma link C++ class std::vector < o2::its::ClusterLines> + ; - -#pragma link C++ class o2::its::VertexerParamConfig + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::VertexerParamConfig> + ; - #pragma link C++ class o2::its::TrackerParamConfig + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::TrackerParamConfig> + ; diff --git a/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx b/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx deleted file mode 100644 index c4b1fb427513f..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// -/// \file Vertexer.cxx -/// \author Matteo Concas mconcas@cern.ch -/// - -#include "ITStracking/Vertexer.h" -#include "ITStracking/BoundedAllocator.h" -#include "ITStracking/Cluster.h" - -#include "ITStracking/ClusterLines.h" -#include "ITStracking/Tracklet.h" -#include "ITStracking/IndexTableUtils.h" -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/TrackingConfigParam.h" - -namespace o2::its -{ - -template -Vertexer::Vertexer(VertexerTraitsN* traits) : mTraits(traits) -{ - if (!mTraits) { - LOG(fatal) << "nullptr passed to ITS vertexer construction."; - } - mVertParams.resize(1); -} - -template -float Vertexer::clustersToVertices(LogFunc logger) -{ - LogFunc evalLog = [](const std::string&) {}; - - if (mTimeFrame->hasMCinformation() && mVertParams[0].useTruthSeeding) { - return evaluateTask(&Vertexer::addTruthSeeds, StateNames[mCurState = TruthSeeding], 0, evalLog); - } - - TrackingParameters trkPars; - TimeFrameGPUParameters tfGPUpar; - mTraits->updateVertexingParameters(mVertParams, tfGPUpar); - - auto handleException = [&](const auto& err) { - LOGP(error, "Encountered critical error in step {}, stopping further processing of this TF: {}", StateNames[mCurState], err.what()); - if (!mVertParams[0].DropTFUponFailure) { - throw err; - } else { - LOGP(error, "Dropping this TF!"); - } - }; - - float timeTracklet{0.f}, timeSelection{0.f}, timeVertexing{0.f}, timeInit{0.f}; - try { - for (int iteration = 0; iteration < std::min(mVertParams[0].nIterations, (int)mVertParams.size()); ++iteration) { - mMemoryPool->setMaxMemory(mVertParams[iteration].MaxMemory); - unsigned int nTracklets01{0}, nTracklets12{0}; - logger(fmt::format("=== ITS {} Seeding vertexer iteration {} summary:", mTraits->getName(), iteration)); - trkPars.PhiBins = mTraits->getVertexingParameters()[0].PhiBins; - trkPars.ZBins = mTraits->getVertexingParameters()[0].ZBins; - auto timeInitIteration = evaluateTask(&Vertexer::initialiseVertexer, StateNames[mCurState = Init], iteration, evalLog, trkPars, iteration); - auto timeTrackletIteration = evaluateTask(&Vertexer::findTracklets, StateNames[mCurState = Trackleting], iteration, evalLog, iteration); - nTracklets01 = mTimeFrame->getTotalTrackletsTF(0); - nTracklets12 = mTimeFrame->getTotalTrackletsTF(1); - auto timeSelectionIteration = evaluateTask(&Vertexer::validateTracklets, StateNames[mCurState = Validating], iteration, evalLog, iteration); - auto timeVertexingIteration = evaluateTask(&Vertexer::findVertices, StateNames[mCurState = Finding], iteration, evalLog, iteration); - printEpilog(logger, nTracklets01, nTracklets12, mTimeFrame->getNLinesTotal(), mTimeFrame->getTotVertIteration()[iteration], timeInitIteration, timeTrackletIteration, timeSelectionIteration, timeVertexingIteration); - timeInit += timeInitIteration; - timeTracklet += timeTrackletIteration; - timeSelection += timeSelectionIteration; - timeVertexing += timeVertexingIteration; - } - } catch (const BoundedMemoryResource::MemoryLimitExceeded& err) { - handleException(err); - } catch (const std::bad_alloc& err) { - handleException(err); - } catch (...) { - LOGP(fatal, "Uncaught exception!"); - } - - return timeInit + timeTracklet + timeSelection + timeVertexing; -} - -template -void Vertexer::adoptTimeFrame(TimeFrameN& tf) -{ - mTimeFrame = &tf; - mTraits->adoptTimeFrame(&tf); -} - -template -void Vertexer::printEpilog(LogFunc& logger, - const unsigned int trackletN01, const unsigned int trackletN12, - const unsigned selectedN, const unsigned int vertexN, const float initT, - const float trackletT, const float selecT, const float vertexT) -{ - logger(fmt::format(" - {} Vertexer: found {} | {} tracklets in: {} ms", mTraits->getName(), trackletN01, trackletN12, trackletT)); - logger(fmt::format(" - {} Vertexer: selected {} tracklets in: {} ms", mTraits->getName(), selectedN, selecT)); - logger(fmt::format(" - {} Vertexer: found {} vertices in: {} ms", mTraits->getName(), vertexN, vertexT)); - if (mVertParams[0].PrintMemory) { - mTimeFrame->printArtefactsMemory(); - mMemoryPool->print(); - } -} - -template class Vertexer<7>; - -} // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx deleted file mode 100644 index 0c4ecb0b12df1..0000000000000 --- a/Detectors/ITSMFT/ITS/tracking/src/VertexerTraits.cxx +++ /dev/null @@ -1,843 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -/// - -#include -#include -#include -#include - -#include -#include -#include - -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/BoundedAllocator.h" -#include "ITStracking/ClusterLines.h" -#include "ITStracking/Tracklet.h" -#include "SimulationDataFormat/DigitizationContext.h" -#include "Steer/MCKinematicsReader.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "DetectorsRaw/HBFUtils.h" -#include "CommonUtils/TreeStreamRedirector.h" - -namespace o2::its -{ - -template -static void trackleterKernelHost( - const gsl::span& clustersNextLayer, // 0 2 - const gsl::span& clustersCurrentLayer, // 1 1 - const gsl::span& usedClustersNextLayer, // 0 2 - int* indexTableNext, - const float phiCut, - bounded_vector& tracklets, - gsl::span foundTracklets, - const IndexTableUtils& utils, - const short pivotRof, - const short targetRof, - gsl::span rofFoundTrackletsOffsets, // we want to change those, to keep track of the offset in deltaRof>0 - const int maxTrackletsPerCluster = static_cast(2e3)) -{ - const int PhiBins{utils.getNphiBins()}; - const int ZBins{utils.getNzBins()}; - // loop on layer1 clusters - for (int iCurrentLayerClusterIndex = 0; iCurrentLayerClusterIndex < clustersCurrentLayer.size(); ++iCurrentLayerClusterIndex) { - int storedTracklets{0}; - const Cluster& currentCluster{clustersCurrentLayer[iCurrentLayerClusterIndex]}; - const int4 selectedBinsRect{VertexerTraits::getBinsRect(currentCluster, (int)Mode, 0.f, 50.f, phiCut / 2, utils)}; - if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { - int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1}; - if (phiBinsNum < 0) { - phiBinsNum += PhiBins; - } - // loop on phi bins next layer - for (int iPhiBin{selectedBinsRect.y}, iPhiCount{0}; iPhiCount < phiBinsNum; iPhiBin = ++iPhiBin == PhiBins ? 0 : iPhiBin, iPhiCount++) { - const int firstBinIndex{utils.getBinIndex(selectedBinsRect.x, iPhiBin)}; - const int firstRowClusterIndex{indexTableNext[firstBinIndex]}; - const int maxRowClusterIndex{indexTableNext[firstBinIndex + ZBins]}; - // loop on clusters next layer - for (int iNextLayerClusterIndex{firstRowClusterIndex}; iNextLayerClusterIndex < maxRowClusterIndex && iNextLayerClusterIndex < static_cast(clustersNextLayer.size()); ++iNextLayerClusterIndex) { - if (usedClustersNextLayer[iNextLayerClusterIndex]) { - continue; - } - const Cluster& nextCluster{clustersNextLayer[iNextLayerClusterIndex]}; - if (o2::gpu::GPUCommonMath::Abs(math_utils::smallestAngleDifference(currentCluster.phi, nextCluster.phi)) < phiCut) { - if (storedTracklets < maxTrackletsPerCluster) { - if constexpr (!EvalRun) { - if constexpr (Mode == TrackletMode::Layer0Layer1) { - tracklets[rofFoundTrackletsOffsets[iCurrentLayerClusterIndex] + storedTracklets] = Tracklet{iNextLayerClusterIndex, iCurrentLayerClusterIndex, nextCluster, currentCluster, targetRof, pivotRof}; - } else { - tracklets[rofFoundTrackletsOffsets[iCurrentLayerClusterIndex] + storedTracklets] = Tracklet{iCurrentLayerClusterIndex, iNextLayerClusterIndex, currentCluster, nextCluster, pivotRof, targetRof}; - } - } - ++storedTracklets; - } - } - } - } - } - if constexpr (EvalRun) { - foundTracklets[iCurrentLayerClusterIndex] += storedTracklets; - } else { - rofFoundTrackletsOffsets[iCurrentLayerClusterIndex] += storedTracklets; - } - } -} - -static void trackletSelectionKernelHost( - const gsl::span clusters0, // 0 - const gsl::span clusters1, // 1 - gsl::span usedClusters0, // Layer 0 - gsl::span usedClusters2, // Layer 2 - const gsl::span& tracklets01, - const gsl::span& tracklets12, - bounded_vector& usedTracklets, - const gsl::span foundTracklets01, - const gsl::span foundTracklets12, - bounded_vector& lines, - const gsl::span& trackletLabels, - bounded_vector& linesLabels, - const short targetRofId0, - const short targetRofId2, - bool safeWrites = false, - const float tanLambdaCut = 0.025f, - const float phiCut = 0.005f, - const int maxTracklets = static_cast(1e2)) -{ - int offset01{0}, offset12{0}; - for (unsigned int iCurrentLayerClusterIndex{0}; iCurrentLayerClusterIndex < clusters1.size(); ++iCurrentLayerClusterIndex) { - int validTracklets{0}; - for (int iTracklet12{offset12}; iTracklet12 < offset12 + foundTracklets12[iCurrentLayerClusterIndex]; ++iTracklet12) { - for (int iTracklet01{offset01}; iTracklet01 < offset01 + foundTracklets01[iCurrentLayerClusterIndex]; ++iTracklet01) { - if (usedTracklets[iTracklet01]) { - continue; - } - - const auto& tracklet01{tracklets01[iTracklet01]}; - const auto& tracklet12{tracklets12[iTracklet12]}; - - if (tracklet01.rof[0] != targetRofId0 || tracklet12.rof[1] != targetRofId2) { - continue; - } - - const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(tracklet01.tanLambda - tracklet12.tanLambda)}; - const float deltaPhi{o2::gpu::GPUCommonMath::Abs(math_utils::smallestAngleDifference(tracklet01.phi, tracklet12.phi))}; - if (deltaTanLambda < tanLambdaCut && deltaPhi < phiCut && validTracklets != maxTracklets) { - if (safeWrites) { - __atomic_store_n(&usedClusters0[tracklet01.firstClusterIndex], 1, __ATOMIC_RELAXED); - __atomic_store_n(&usedClusters2[tracklet12.secondClusterIndex], 1, __ATOMIC_RELAXED); - } else { - usedClusters0[tracklet01.firstClusterIndex] = 1; - usedClusters2[tracklet12.secondClusterIndex] = 1; - } - usedTracklets[iTracklet01] = true; - lines.emplace_back(tracklet01, clusters0.data(), clusters1.data()); - if (!trackletLabels.empty()) { - linesLabels.emplace_back(trackletLabels[iTracklet01]); - } - ++validTracklets; - } - } - } - offset01 += foundTracklets01[iCurrentLayerClusterIndex]; - offset12 += foundTracklets12[iCurrentLayerClusterIndex]; - } -} - -template -void VertexerTraits::updateVertexingParameters(const std::vector& vrtPar, const TimeFrameGPUParameters& tfPar) -{ - mVrtParams = vrtPar; - mIndexTableUtils.setTrackingParameters(vrtPar[0]); - for (auto& par : mVrtParams) { - par.phiSpan = static_cast(std::ceil(mIndexTableUtils.getNphiBins() * par.phiCut / o2::constants::math::TwoPI)); - par.zSpan = static_cast(std::ceil(par.zCut * mIndexTableUtils.getInverseZCoordinate(0))); - } -} - -// Main functions -template -void VertexerTraits::computeTracklets(const int iteration) -{ - mTaskArena->execute([&] { - tbb::parallel_for(0, mTimeFrame->getNrof(), [&](const short pivotRofId) { - bool skipROF = iteration && (int)mTimeFrame->getPrimaryVertices(pivotRofId).size() > mVrtParams[iteration].vertPerRofThreshold; - short startROF{std::max((short)0, static_cast(pivotRofId - mVrtParams[iteration].deltaRof))}; - short endROF{std::min(static_cast(mTimeFrame->getNrof()), static_cast(pivotRofId + mVrtParams[iteration].deltaRof + 1))}; - for (auto targetRofId = startROF; targetRofId < endROF; ++targetRofId) { - trackleterKernelHost( - !skipROF ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span(), // Clusters to be matched with the next layer in target rof - !skipROF ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span(), // Clusters to be matched with the current layer in pivot rof - mTimeFrame->getUsedClustersROF(targetRofId, 0), // Span of the used clusters in the target rof - mTimeFrame->getIndexTable(targetRofId, 0).data(), // Index table to access the data on the next layer in target rof - mVrtParams[iteration].phiCut, - mTimeFrame->getTracklets()[0], // Flat tracklet buffer - mTimeFrame->getNTrackletsCluster(pivotRofId, 0), // Span of the number of tracklets per each cluster in pivot rof - mIndexTableUtils, - pivotRofId, - targetRofId, - gsl::span(), // Offset in the tracklet buffer - mVrtParams[iteration].maxTrackletsPerCluster); - trackleterKernelHost( - !skipROF ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span(), - !skipROF ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span(), - mTimeFrame->getUsedClustersROF(targetRofId, 2), - mTimeFrame->getIndexTable(targetRofId, 2).data(), - mVrtParams[iteration].phiCut, - mTimeFrame->getTracklets()[1], - mTimeFrame->getNTrackletsCluster(pivotRofId, 1), // Span of the number of tracklets per each cluster in pivot rof - mIndexTableUtils, - pivotRofId, - targetRofId, - gsl::span(), // Offset in the tracklet buffer - mVrtParams[iteration].maxTrackletsPerCluster); - } - mTimeFrame->getNTrackletsROF(pivotRofId, 0) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 0).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).end(), 0); - mTimeFrame->getNTrackletsROF(pivotRofId, 1) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 1).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 1).end(), 0); - }); - - mTimeFrame->computeTrackletsPerROFScans(); - if (auto tot0 = mTimeFrame->getTotalTrackletsTF(0), tot1 = mTimeFrame->getTotalTrackletsTF(1); - tot0 == 0 || tot1 == 0) { - return; - } else { - mTimeFrame->getTracklets()[0].resize(tot0); - mTimeFrame->getTracklets()[1].resize(tot1); - } - - tbb::parallel_for(0, mTimeFrame->getNrof(), [&](const short pivotRofId) { - bool skipROF = iteration && (int)mTimeFrame->getPrimaryVertices(pivotRofId).size() > mVrtParams[iteration].vertPerRofThreshold; - short startROF{std::max((short)0, static_cast(pivotRofId - mVrtParams[iteration].deltaRof))}; - short endROF{std::min(static_cast(mTimeFrame->getNrof()), static_cast(pivotRofId + mVrtParams[iteration].deltaRof + 1))}; - auto mobileOffset0 = mTimeFrame->getNTrackletsROF(pivotRofId, 0); - auto mobileOffset1 = mTimeFrame->getNTrackletsROF(pivotRofId, 1); - for (auto targetRofId = startROF; targetRofId < endROF; ++targetRofId) { - trackleterKernelHost( - !skipROF ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span(), - !skipROF ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span(), - mTimeFrame->getUsedClustersROF(targetRofId, 0), - mTimeFrame->getIndexTable(targetRofId, 0).data(), - mVrtParams[iteration].phiCut, - mTimeFrame->getTracklets()[0], - mTimeFrame->getNTrackletsCluster(pivotRofId, 0), - mIndexTableUtils, - pivotRofId, - targetRofId, - mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 0), - mVrtParams[iteration].maxTrackletsPerCluster); - trackleterKernelHost( - !skipROF ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span(), - !skipROF ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span(), - mTimeFrame->getUsedClustersROF(targetRofId, 2), - mTimeFrame->getIndexTable(targetRofId, 2).data(), - mVrtParams[iteration].phiCut, - mTimeFrame->getTracklets()[1], - mTimeFrame->getNTrackletsCluster(pivotRofId, 1), - mIndexTableUtils, - pivotRofId, - targetRofId, - mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 1), - mVrtParams[iteration].maxTrackletsPerCluster); - } - }); - }); - - /// Create tracklets labels for L0-L1, information is as flat as in tracklets vector (no rofId) - if (mTimeFrame->hasMCinformation()) { - for (const auto& trk : mTimeFrame->getTracklets()[0]) { - o2::MCCompLabel label; - if (!trk.isEmpty()) { - int sortedId0{mTimeFrame->getSortedIndex(trk.rof[0], 0, trk.firstClusterIndex)}; - int sortedId1{mTimeFrame->getSortedIndex(trk.rof[1], 1, trk.secondClusterIndex)}; - for (const auto& lab0 : mTimeFrame->getClusterLabels(0, mTimeFrame->getClusters()[0][sortedId0].clusterId)) { - for (const auto& lab1 : mTimeFrame->getClusterLabels(1, mTimeFrame->getClusters()[1][sortedId1].clusterId)) { - if (lab0 == lab1 && lab0.isValid()) { - label = lab0; - break; - } - } - if (label.isValid()) { - break; - } - } - } - mTimeFrame->getTrackletsLabel(0).emplace_back(label); - } - } - -#ifdef VTX_DEBUG - debugComputeTracklets(iteration); -#endif -} - -template -void VertexerTraits::computeTrackletMatching(const int iteration) -{ - mTaskArena->execute([&] { - tbb::combinable totalLines{0}; - tbb::parallel_for( - tbb::blocked_range(0, (short)mTimeFrame->getNrof()), - [&](const tbb::blocked_range& Rofs) { - for (short pivotRofId = Rofs.begin(); pivotRofId < Rofs.end(); ++pivotRofId) { - if (iteration && (int)mTimeFrame->getPrimaryVertices(pivotRofId).size() > mVrtParams[iteration].vertPerRofThreshold) { - continue; - } - if (mTimeFrame->getFoundTracklets(pivotRofId, 0).empty()) { - continue; - } - mTimeFrame->getLines(pivotRofId).reserve(mTimeFrame->getNTrackletsCluster(pivotRofId, 0).size()); - bounded_vector usedTracklets(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), false, mMemoryPool.get()); - short startROF{std::max((short)0, static_cast(pivotRofId - mVrtParams[iteration].deltaRof))}; - short endROF{std::min(static_cast(mTimeFrame->getNrof()), static_cast(pivotRofId + mVrtParams[iteration].deltaRof + 1))}; - - // needed only if multi-threaded using deltaRof and only at the overlap edges of the ranges - bool safeWrite = mTaskArena->max_concurrency() > 1 && mVrtParams[iteration].deltaRof != 0 && ((Rofs.begin() - startROF < 0) || (endROF - Rofs.end() > 0)); - - for (short targetRofId0 = startROF; targetRofId0 < endROF; ++targetRofId0) { - for (short targetRofId2 = startROF; targetRofId2 < endROF; ++targetRofId2) { - if (std::abs(targetRofId0 - targetRofId2) > mVrtParams[iteration].deltaRof) { // do not allow over 3 ROFs - continue; - } - trackletSelectionKernelHost( - mTimeFrame->getClustersOnLayer(targetRofId0, 0), - mTimeFrame->getClustersOnLayer(pivotRofId, 1), - mTimeFrame->getUsedClustersROF(targetRofId0, 0), - mTimeFrame->getUsedClustersROF(targetRofId2, 2), - mTimeFrame->getFoundTracklets(pivotRofId, 0), - mTimeFrame->getFoundTracklets(pivotRofId, 1), - usedTracklets, - mTimeFrame->getNTrackletsCluster(pivotRofId, 0), - mTimeFrame->getNTrackletsCluster(pivotRofId, 1), - mTimeFrame->getLines(pivotRofId), - mTimeFrame->getLabelsFoundTracklets(pivotRofId, 0), - mTimeFrame->getLinesLabel(pivotRofId), - targetRofId0, - targetRofId2, - safeWrite, - mVrtParams[iteration].tanLambdaCut, - mVrtParams[iteration].phiCut); - } - } - totalLines.local() += mTimeFrame->getLines(pivotRofId).size(); - } - }); - mTimeFrame->setNLinesTotal(totalLines.combine(std::plus())); - }); - -#ifdef VTX_DEBUG - debugComputeTrackletMatching(iteration); -#endif - - // from here on we do not use tracklets from L1-2 anymore, so let's free them - deepVectorClear(mTimeFrame->getTracklets()[1]); -} - -template -void VertexerTraits::computeVertices(const int iteration) -{ - auto nsigmaCut{std::min(mVrtParams[iteration].vertNsigmaCut * mVrtParams[iteration].vertNsigmaCut * (mVrtParams[iteration].vertRadiusSigma * mVrtParams[iteration].vertRadiusSigma + mVrtParams[iteration].trackletSigma * mVrtParams[iteration].trackletSigma), 1.98f)}; - bounded_vector vertices(mMemoryPool.get()); - bounded_vector> polls(mMemoryPool.get()); - bounded_vector contLabels(mMemoryPool.get()); - bounded_vector noClustersVec(mTimeFrame->getNrof(), 0, mMemoryPool.get()); - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - if (iteration && (int)mTimeFrame->getPrimaryVertices(rofId).size() > mVrtParams[iteration].vertPerRofThreshold) { - continue; - } - const int numTracklets{static_cast(mTimeFrame->getLines(rofId).size())}; - - bounded_vector usedTracklets(numTracklets, false, mMemoryPool.get()); - for (int line1{0}; line1 < numTracklets; ++line1) { - if (usedTracklets[line1]) { - continue; - } - for (int line2{line1 + 1}; line2 < numTracklets; ++line2) { - if (usedTracklets[line2]) { - continue; - } - auto dca{Line::getDCA(mTimeFrame->getLines(rofId)[line1], mTimeFrame->getLines(rofId)[line2])}; - if (dca < mVrtParams[iteration].pairCut) { - mTimeFrame->getTrackletClusters(rofId).emplace_back(line1, mTimeFrame->getLines(rofId)[line1], line2, mTimeFrame->getLines(rofId)[line2]); - std::array tmpVertex{mTimeFrame->getTrackletClusters(rofId).back().getVertex()}; - if (tmpVertex[0] * tmpVertex[0] + tmpVertex[1] * tmpVertex[1] > 4.f) { - mTimeFrame->getTrackletClusters(rofId).pop_back(); - break; - } - usedTracklets[line1] = true; - usedTracklets[line2] = true; - for (int tracklet3{0}; tracklet3 < numTracklets; ++tracklet3) { - if (usedTracklets[tracklet3]) { - continue; - } - if (Line::getDistanceFromPoint(mTimeFrame->getLines(rofId)[tracklet3], tmpVertex) < mVrtParams[iteration].pairCut) { - mTimeFrame->getTrackletClusters(rofId).back().add(tracklet3, mTimeFrame->getLines(rofId)[tracklet3]); - usedTracklets[tracklet3] = true; - tmpVertex = mTimeFrame->getTrackletClusters(rofId).back().getVertex(); - } - } - break; - } - } - } - if (mVrtParams[iteration].allowSingleContribClusters) { - auto beamLine = Line{{mTimeFrame->getBeamX(), mTimeFrame->getBeamY(), -50.f}, {mTimeFrame->getBeamX(), mTimeFrame->getBeamY(), 50.f}}; // use beam position as contributor - for (size_t iLine{0}; iLine < numTracklets; ++iLine) { - if (!usedTracklets[iLine]) { - auto dca = Line::getDCA(mTimeFrame->getLines(rofId)[iLine], beamLine); - if (dca < mVrtParams[iteration].pairCut) { - mTimeFrame->getTrackletClusters(rofId).emplace_back(iLine, mTimeFrame->getLines(rofId)[iLine], -1, beamLine); // beamline must be passed as second line argument - } - } - } - } - - // Cluster merging - std::sort(mTimeFrame->getTrackletClusters(rofId).begin(), mTimeFrame->getTrackletClusters(rofId).end(), - [](ClusterLines& cluster1, ClusterLines& cluster2) { return cluster1.getSize() > cluster2.getSize(); }); - noClustersVec[rofId] = static_cast(mTimeFrame->getTrackletClusters(rofId).size()); - for (int iCluster1{0}; iCluster1 < noClustersVec[rofId]; ++iCluster1) { - std::array vertex1{mTimeFrame->getTrackletClusters(rofId)[iCluster1].getVertex()}; - std::array vertex2{}; - for (int iCluster2{iCluster1 + 1}; iCluster2 < noClustersVec[rofId]; ++iCluster2) { - vertex2 = mTimeFrame->getTrackletClusters(rofId)[iCluster2].getVertex(); - if (o2::gpu::GPUCommonMath::Abs(vertex1[2] - vertex2[2]) < mVrtParams[iteration].clusterCut) { - float distance{(vertex1[0] - vertex2[0]) * (vertex1[0] - vertex2[0]) + - (vertex1[1] - vertex2[1]) * (vertex1[1] - vertex2[1]) + - (vertex1[2] - vertex2[2]) * (vertex1[2] - vertex2[2])}; - if (distance < mVrtParams[iteration].pairCut * mVrtParams[iteration].pairCut) { - for (auto label : mTimeFrame->getTrackletClusters(rofId)[iCluster2].getLabels()) { - mTimeFrame->getTrackletClusters(rofId)[iCluster1].add(label, mTimeFrame->getLines(rofId)[label]); - vertex1 = mTimeFrame->getTrackletClusters(rofId)[iCluster1].getVertex(); - } - mTimeFrame->getTrackletClusters(rofId).erase(mTimeFrame->getTrackletClusters(rofId).begin() + iCluster2); - --iCluster2; - --noClustersVec[rofId]; - } - } - } - } - } - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - std::sort(mTimeFrame->getTrackletClusters(rofId).begin(), mTimeFrame->getTrackletClusters(rofId).end(), - [](const ClusterLines& cluster1, const ClusterLines& cluster2) { return cluster1.getSize() > cluster2.getSize(); }); // ensure clusters are ordered by contributors, so that we can cat after the first. - bool atLeastOneFound{false}; - for (int iCluster{0}; iCluster < noClustersVec[rofId]; ++iCluster) { - bool lowMultCandidate{false}; - double beamDistance2{(mTimeFrame->getBeamX() - mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[0]) * (mTimeFrame->getBeamX() - mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[0]) + - (mTimeFrame->getBeamY() - mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[1]) * (mTimeFrame->getBeamY() - mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[1])}; - if (atLeastOneFound && (lowMultCandidate = mTimeFrame->getTrackletClusters(rofId)[iCluster].getSize() < mVrtParams[iteration].clusterContributorsCut)) { // We might have pile up with nContr > cut. - lowMultCandidate &= (beamDistance2 < mVrtParams[iteration].lowMultBeamDistCut * mVrtParams[iteration].lowMultBeamDistCut); - if (!lowMultCandidate) { // Not the first cluster and not a low multiplicity candidate, we can remove it - mTimeFrame->getTrackletClusters(rofId).erase(mTimeFrame->getTrackletClusters(rofId).begin() + iCluster); - noClustersVec[rofId]--; - continue; - } - } - - if (beamDistance2 < nsigmaCut && o2::gpu::GPUCommonMath::Abs(mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[2]) < mVrtParams[iteration].maxZPositionAllowed) { - atLeastOneFound = true; - auto& vertex = vertices.emplace_back(o2::math_utils::Point3D(mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[0], - mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[1], - mTimeFrame->getTrackletClusters(rofId)[iCluster].getVertex()[2]), - mTimeFrame->getTrackletClusters(rofId)[iCluster].getRMS2(), // Symm matrix. Diagonal: RMS2 components, - // off-diagonal: square mean of projections on planes. - mTimeFrame->getTrackletClusters(rofId)[iCluster].getSize(), // Contributors - mTimeFrame->getTrackletClusters(rofId)[iCluster].getAvgDistance2()); // In place of chi2 - - if (iteration) { - vertex.setFlags(Vertex::UPCMode); - } - vertex.setTimeStamp(mTimeFrame->getTrackletClusters(rofId)[iCluster].getROF()); - if (mTimeFrame->hasMCinformation()) { - bounded_vector labels(mMemoryPool.get()); - for (auto& index : mTimeFrame->getTrackletClusters(rofId)[iCluster].getLabels()) { - labels.push_back(mTimeFrame->getLinesLabel(rofId)[index]); // then we can use nContributors from vertices to get the labels - } - polls.push_back(computeMain(labels)); - if (mVrtParams[iteration].outputContLabels) { - contLabels.insert(contLabels.end(), labels.begin(), labels.end()); - } - } - } - } - if (!iteration) { - mTimeFrame->addPrimaryVertices(vertices, iteration); - if (mTimeFrame->hasMCinformation()) { - mTimeFrame->addPrimaryVerticesLabels(polls); - if (mVrtParams[iteration].outputContLabels) { - mTimeFrame->addPrimaryVerticesContributorLabels(contLabels); - } - } - } else { - mTimeFrame->addPrimaryVerticesInROF(vertices, rofId, iteration); - if (mTimeFrame->hasMCinformation()) { - mTimeFrame->addPrimaryVerticesLabelsInROF(polls, rofId); - if (mVrtParams[iteration].outputContLabels) { - mTimeFrame->addPrimaryVerticesContributorLabelsInROF(contLabels, rofId); - } - } - } - if (vertices.empty() && !(iteration && (int)mTimeFrame->getPrimaryVertices(rofId).size() > mVrtParams[iteration].vertPerRofThreshold)) { - mTimeFrame->getNoVertexROF()++; - } - vertices.clear(); - polls.clear(); - } - -#ifdef VTX_DEBUG - debugComputeVertices(iteration); -#endif -} - -template -void VertexerTraits::addTruthSeedingVertices() -{ - LOGP(info, "Using truth seeds as vertices; will skip computations"); - mTimeFrame->resetRofPV(); - const auto dc = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); - const auto irs = dc->getEventRecords(); - int64_t roFrameBiasInBC = o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC; - int64_t roFrameLengthInBC = o2::itsmft::DPLAlpideParam::Instance().roFrameLengthInBC; - o2::steer::MCKinematicsReader mcReader(dc); - struct VertInfo { - bounded_vector vertices; - bounded_vector srcs; - bounded_vector events; - }; - std::map vertices; - const int iSrc = 0; // take only events from collision generator - auto eveId2colId = dc->getCollisionIndicesForSource(iSrc); - for (int iEve{0}; iEve < mcReader.getNEvents(iSrc); ++iEve) { - const auto& ir = irs[eveId2colId[iEve]]; - if (!ir.isDummy()) { // do we need this, is this for diffractive events? - const auto& eve = mcReader.getMCEventHeader(iSrc, iEve); - int rofId = ((ir - raw::HBFUtils::Instance().getFirstSampledTFIR()).toLong() - roFrameBiasInBC) / roFrameLengthInBC; - if (!vertices.contains(rofId)) { - vertices[rofId] = { - .vertices = bounded_vector(mMemoryPool.get()), - .srcs = bounded_vector(mMemoryPool.get()), - .events = bounded_vector(mMemoryPool.get()), - }; - } - Vertex vert; - vert.setTimeStamp(rofId); - // set minimum to 1 sometimes for diffractive events there is nothing acceptance - vert.setNContributors(std::max(1L, std::ranges::count_if(mcReader.getTracks(iSrc, iEve), [](const auto& trk) { - return trk.isPrimary() && trk.GetPt() > 0.05 && std::abs(trk.GetEta()) < 1.1; - }))); - vert.setXYZ((float)eve.GetX(), (float)eve.GetY(), (float)eve.GetZ()); - vert.setChi2(1); // not used as constraint - constexpr float cov = 50e-9; - vert.setCov(cov, cov, cov, cov, cov, cov); - vertices[rofId].vertices.push_back(vert); - vertices[rofId].srcs.push_back(iSrc); - vertices[rofId].events.push_back(iEve); - } - mcReader.releaseTracksForSourceAndEvent(iSrc, iEve); - } - size_t nVerts{0}; - for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { - bounded_vector verts(mMemoryPool.get()); - bounded_vector> polls(mMemoryPool.get()); - if (vertices.contains(iROF)) { - const auto& vertInfo = vertices[iROF]; - verts = vertInfo.vertices; - nVerts += verts.size(); - for (size_t i{0}; i < verts.size(); ++i) { - o2::MCCompLabel lbl(o2::MCCompLabel::maxTrackID(), vertInfo.events[i], vertInfo.srcs[i], false); - polls.emplace_back(lbl, 1.f); - } - } else { - mTimeFrame->getNoVertexROF()++; - } - mTimeFrame->addPrimaryVertices(verts, 0); - mTimeFrame->addPrimaryVerticesLabels(polls); - } - LOGP(info, "Found {}/{} ROFs with {} vertices -> ={:.2f}", vertices.size(), mTimeFrame->getNrof(), nVerts, (float)nVerts / (float)vertices.size()); -} - -template -void VertexerTraits::setNThreads(int n, std::shared_ptr& arena) -{ -#if defined(VTX_DEBUG) - LOGP(info, "Vertexer with debug output forcing single thread"); - mTaskArena = std::make_shared(1); -#else - if (arena == nullptr) { - mTaskArena = std::make_shared(std::abs(n)); - LOGP(info, "Setting seeding vertexer with {} threads.", n); - } else { - mTaskArena = arena; - LOGP(info, "Attaching vertexer to calling thread's arena"); - } -#endif -} - -template -void VertexerTraits::debugComputeTracklets(int iteration) -{ - auto stream = new utils::TreeStreamRedirector("artefacts_tf.root", "recreate"); - LOGP(info, "writing debug output for computeTracklets"); - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - const auto& strk0 = mTimeFrame->getFoundTracklets(rofId, 0); - std::vector trk0(strk0.begin(), strk0.end()); - const auto& strk1 = mTimeFrame->getFoundTracklets(rofId, 1); - std::vector trk1(strk1.begin(), strk1.end()); - (*stream) << "tracklets" - << "Tracklets0=" << trk0 - << "Tracklets1=" << trk1 - << "iteration=" << iteration - << "\n"; - } - stream->Close(); - delete stream; -} - -template -void VertexerTraits::debugComputeTrackletMatching(int iteration) -{ - auto stream = new utils::TreeStreamRedirector("artefacts_tf.root", "update"); - LOGP(info, "writing debug output for computeTrackletMatching"); - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - (*stream) << "lines" - << "Lines=" << toSTDVector(mTimeFrame->getLines(rofId)) - << "NTrackletCluster01=" << mTimeFrame->getNTrackletsCluster(rofId, 0) - << "NTrackletCluster12=" << mTimeFrame->getNTrackletsCluster(rofId, 1) - << "iteration=" << iteration - << "\n"; - } - - if (mTimeFrame->hasMCinformation()) { - LOGP(info, "\tdumping also MC information"); - const auto dc = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); - const auto irs = dc->getEventRecords(); - int64_t roFrameBiasInBC = o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC; - int64_t roFrameLengthInBC = o2::itsmft::DPLAlpideParam::Instance().roFrameLengthInBC; - o2::steer::MCKinematicsReader mcReader(dc); - - std::map eve2BcInROF, bcInRofNEve; - for (int iSrc{0}; iSrc < mcReader.getNSources(); ++iSrc) { - auto eveId2colId = dc->getCollisionIndicesForSource(iSrc); - for (int iEve{0}; iEve < mcReader.getNEvents(iSrc); ++iEve) { - const auto& ir = irs[eveId2colId[iEve]]; - if (!ir.isDummy()) { // do we need this, is this for diffractive events? - const auto& eve = mcReader.getMCEventHeader(iSrc, iEve); - const int bcInROF = ((ir - raw::HBFUtils::Instance().getFirstSampledTFIR()).toLong() - roFrameBiasInBC) % roFrameLengthInBC; - eve2BcInROF[iEve] = bcInROF; - ++bcInRofNEve[bcInROF]; - } - } - } - - std::unordered_map bcROFNTracklets01, bcROFNTracklets12; - std::vector> tracklet01BC, tracklet12BC; - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - { // 0-1 - const auto& tracklet01 = mTimeFrame->getFoundTracklets(rofId, 0); - const auto& lbls01 = mTimeFrame->getLabelsFoundTracklets(rofId, 0); - auto& trkls01 = tracklet01BC.emplace_back(); - for (int iTrklt{0}; iTrklt < (int)tracklet01.size(); ++iTrklt) { - const auto& tracklet = tracklet01[iTrklt]; - const auto& lbl = lbls01[iTrklt]; - if (lbl.isCorrect()) { - ++bcROFNTracklets01[eve2BcInROF[lbl.getEventID()]]; - trkls01.push_back(eve2BcInROF[lbl.getEventID()]); - } else { - trkls01.push_back(-1); - } - } - } - { // 1-2 computed on the fly! - const auto& tracklet12 = mTimeFrame->getFoundTracklets(rofId, 1); - auto& trkls12 = tracklet12BC.emplace_back(); - for (int iTrklt{0}; iTrklt < (int)tracklet12.size(); ++iTrklt) { - const auto& tracklet = tracklet12[iTrklt]; - o2::MCCompLabel label; - - int sortedId1{mTimeFrame->getSortedIndex(tracklet.rof[0], 1, tracklet.firstClusterIndex)}; - int sortedId2{mTimeFrame->getSortedIndex(tracklet.rof[1], 2, tracklet.secondClusterIndex)}; - for (const auto& lab1 : mTimeFrame->getClusterLabels(1, mTimeFrame->getClusters()[1][sortedId1].clusterId)) { - for (const auto& lab2 : mTimeFrame->getClusterLabels(2, mTimeFrame->getClusters()[2][sortedId2].clusterId)) { - if (lab1 == lab2 && lab1.isValid()) { - label = lab1; - break; - } - } - if (label.isValid()) { - break; - } - } - - if (label.isCorrect()) { - ++bcROFNTracklets12[eve2BcInROF[label.getEventID()]]; - trkls12.push_back(eve2BcInROF[label.getEventID()]); - } else { - trkls12.push_back(-1); - } - } - } - } - LOGP(info, "\tdumping ntracklets/RofBC ({})", bcInRofNEve.size()); - for (const auto& [bcInRof, neve] : bcInRofNEve) { - (*stream) << "ntracklets" - << "bcInROF=" << bcInRof - << "ntrkl01=" << bcROFNTracklets01[bcInRof] - << "ntrkl12=" << bcROFNTracklets12[bcInRof] - << "neve=" << neve - << "iteration=" << iteration - << "\n"; - } - - std::unordered_map bcROFNLines; - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - const auto& lines = mTimeFrame->getLines(rofId); - const auto& lbls = mTimeFrame->getLinesLabel(rofId); - for (int iLine{0}; iLine < (int)lines.size(); ++iLine) { - const auto& line = lines[iLine]; - const auto& lbl = lbls[iLine]; - if (lbl.isCorrect()) { - ++bcROFNLines[eve2BcInROF[lbl.getEventID()]]; - } - } - } - - LOGP(info, "\tdumping nlines/RofBC"); - for (const auto& [bcInRof, neve] : bcInRofNEve) { - (*stream) << "nlines" - << "bcInROF=" << bcInRof - << "nline=" << bcROFNLines[bcInRof] - << "neve=" << neve - << "iteration=" << iteration - << "\n"; - } - } - stream->Close(); - delete stream; -} - -template -void VertexerTraits::debugComputeVertices(int iteration) -{ - auto stream = new utils::TreeStreamRedirector("artefacts_tf.root", "update"); - LOGP(info, "writing debug output for computeVertices"); - for (auto rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - (*stream) << "clusterlines" - << "clines_post=" << toSTDVector(mTimeFrame->getTrackletClusters(rofId)) - << "iteration=" << iteration - << "\n"; - } - - if (mTimeFrame->hasMCinformation()) { - LOGP(info, "\tdumping also MC information"); - const auto dc = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); - const auto irs = dc->getEventRecords(); - int64_t roFrameBiasInBC = o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC; - int64_t roFrameLengthInBC = o2::itsmft::DPLAlpideParam::Instance().roFrameLengthInBC; - o2::steer::MCKinematicsReader mcReader(dc); - - std::map eve2BcInROF, bcInRofNEve; - for (int iSrc{0}; iSrc < mcReader.getNSources(); ++iSrc) { - auto eveId2colId = dc->getCollisionIndicesForSource(iSrc); - for (int iEve{0}; iEve < mcReader.getNEvents(iSrc); ++iEve) { - const auto& ir = irs[eveId2colId[iEve]]; - if (!ir.isDummy()) { // do we need this, is this for diffractive events? - const auto& eve = mcReader.getMCEventHeader(iSrc, iEve); - const int bcInROF = ((ir - raw::HBFUtils::Instance().getFirstSampledTFIR()).toLong() - roFrameBiasInBC) % roFrameLengthInBC; - eve2BcInROF[iEve] = bcInROF; - ++bcInRofNEve[bcInROF]; - } - } - } - - std::unordered_map bcROFNVtx; - std::unordered_map bcROFNPur; - std::unordered_map uniqueVertices; - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - const auto& pvs = mTimeFrame->getPrimaryVertices(rofId); - const auto& lblspv = mTimeFrame->getPrimaryVerticesMCRecInfo(rofId); - for (int i{0}; i < (int)pvs.size(); ++i) { - const auto& pv = pvs[i]; - const auto& [lbl, pur] = lblspv[i]; - if (lbl.isCorrect()) { - ++uniqueVertices[lbl]; - ++bcROFNVtx[eve2BcInROF[lbl.getEventID()]]; - bcROFNPur[eve2BcInROF[lbl.getEventID()]] += pur; - } - } - } - - std::unordered_map bcROFNUVtx, bcROFNCVtx; - for (const auto& [k, _] : eve2BcInROF) { - bcROFNUVtx[k] = bcROFNCVtx[k] = 0; - } - - for (const auto& [lbl, c] : uniqueVertices) { - if (c <= 1) { - ++bcROFNUVtx[eve2BcInROF[lbl.getEventID()]]; - } else { - ++bcROFNCVtx[eve2BcInROF[lbl.getEventID()]]; - } - } - - LOGP(info, "\tdumping nvtx/RofBC"); - for (const auto& [bcInRof, neve] : bcInRofNEve) { - (*stream) << "nvtx" - << "bcInROF=" << bcInRof - << "nvtx=" << bcROFNVtx[bcInRof] // all vertices - << "nuvtx=" << bcROFNUVtx[bcInRof] // unique vertices - << "ncvtx=" << bcROFNCVtx[bcInRof] // cloned vertices - << "npur=" << bcROFNPur[bcInRof] - << "neve=" << neve - << "iteration=" << iteration - << "\n"; - } - - // check dist of clones - std::unordered_map> cVtx; - for (int rofId{0}; rofId < mTimeFrame->getNrof(); ++rofId) { - const auto& pvs = mTimeFrame->getPrimaryVertices(rofId); - const auto& lblspv = mTimeFrame->getPrimaryVerticesMCRecInfo(rofId); - for (int i{0}; i < (int)pvs.size(); ++i) { - const auto& pv = pvs[i]; - const auto& [lbl, pur] = lblspv[i]; - if (lbl.isCorrect() && uniqueVertices.contains(lbl) && uniqueVertices[lbl] > 1) { - if (!cVtx.contains(lbl)) { - cVtx[lbl] = std::vector(); - } - cVtx[lbl].push_back(pv); - } - } - } - - for (auto& [_, vertices] : cVtx) { - std::sort(vertices.begin(), vertices.end(), [](const Vertex& a, const Vertex& b) { return a.getNContributors() > b.getNContributors(); }); - for (int i{0}; i < (int)vertices.size(); ++i) { - const auto vtx = vertices[i]; - (*stream) << "cvtx" - << "vertex=" << vtx - << "i=" << i - << "dx=" << vertices[0].getX() - vtx.getX() - << "dy=" << vertices[0].getY() - vtx.getY() - << "dz=" << vertices[0].getZ() - vtx.getZ() - << "drof=" << vertices[0].getTimeStamp().getTimeStamp() - vtx.getTimeStamp().getTimeStamp() - << "dnc=" << vertices[0].getNContributors() - vtx.getNContributors() - << "iteration=" << iteration - << "\n"; - } - } - } - stream->Close(); - delete stream; -} - -template class VertexerTraits<7>; -} // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt index 818ad1d667371..5ea8ec218caba 100644 --- a/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt @@ -14,3 +14,9 @@ o2_add_test(boundedmemoryresource COMPONENT_NAME its-tracking LABELS "its;tracking" PUBLIC_LINK_LIBRARIES O2::ITStracking) + +o2_add_test(roflookuptables + SOURCES testROFLookupTables.cxx + COMPONENT_NAME its-tracking + LABELS "its;tracking" + PUBLIC_LINK_LIBRARIES O2::ITStracking) diff --git a/Detectors/ITSMFT/ITS/tracking/test/testBoundedMemoryResource.cxx b/Detectors/ITSMFT/ITS/tracking/test/testBoundedMemoryResource.cxx index aae28f5cbc36e..a1ac85795e9fb 100644 --- a/Detectors/ITSMFT/ITS/tracking/test/testBoundedMemoryResource.cxx +++ b/Detectors/ITSMFT/ITS/tracking/test/testBoundedMemoryResource.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#define BOOST_TEST_MODULE Test Flags +#define BOOST_TEST_MODULE ITS Memory #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK diff --git a/Detectors/ITSMFT/ITS/tracking/test/testROFLookupTables.cxx b/Detectors/ITSMFT/ITS/tracking/test/testROFLookupTables.cxx new file mode 100644 index 0000000000000..6993abcfe1992 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/test/testROFLookupTables.cxx @@ -0,0 +1,726 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#define BOOST_TEST_MODULE ITS ROFLookupTables +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include "ITStracking/ROFLookupTables.h" + +/// -------- Tests -------- +// LayerTiming +BOOST_AUTO_TEST_CASE(layertiming_basic) +{ + o2::its::ROFOverlapTable<1> table; + table.defineLayer(0, 10, 594, 100, 50); + const auto& layer = table.getLayer(0); + + // test ROF time calculations + auto start0 = layer.getROFStartInBC(0, true); + BOOST_CHECK_EQUAL(start0, 100); // delay only + + auto end0 = layer.getROFEndInBC(0, true); + BOOST_CHECK_EQUAL(end0, 100 + 594); + + auto bounds = layer.getROFTimeBounds(0, true); + BOOST_CHECK_EQUAL(bounds.getFirstEntry(), 100 - 50); + BOOST_CHECK_EQUAL(bounds.getEntriesBound() - 1, 100 + 594 + 50); + + // test second ROF + auto start1 = layer.getROFStartInBC(1, true); + BOOST_CHECK_EQUAL(start1, 100 + 594); +} + +BOOST_AUTO_TEST_CASE(layertiming_base) +{ + o2::its::ROFOverlapTable<3> table; + table.defineLayer(0, 10, 500, 0, 0); + table.defineLayer(1, 12, 600, 50, 0); + table.defineLayer(2, 8, 400, 100, 0); + const auto& layer1 = table.getLayer(1); + BOOST_CHECK_EQUAL(layer1.mNROFsTF, 12); + BOOST_CHECK_EQUAL(layer1.mROFLength, 600); +} + +// ROFOverlapTable +BOOST_AUTO_TEST_CASE(rofoverlap_basic) +{ + // define 2 layers with the same definitions (no staggering) + o2::its::ROFOverlapTable<2> table; + table.defineLayer(0, 12, 594, 0, 0); + table.defineLayer(1, 12, 594, 0, 0); + table.init(); + const auto view = table.getView(); + // each rof in layer 0 should be compatible with its layer 1 equivalent + for (int rof{0}; rof < 12; ++rof) { + BOOST_CHECK(view.isCompatible(0, rof, 1, rof)); + BOOST_CHECK(view.isCompatible(1, rof, 0, rof)); + BOOST_CHECK(view.getOverlap(0, 1, rof).getEntries() == 1); + } +} + +BOOST_AUTO_TEST_CASE(rofoverlap_staggered) +{ + // test staggered layers with ROF delay + o2::its::ROFOverlapTable<2> table; + table.defineLayer(0, 10, 500, 0, 0); + table.defineLayer(1, 10, 500, 250, 0); // 250 BC delay + table.init(); + const auto view = table.getView(); + + // verify overlap range + { // from 0 to 1 + const auto& range = view.getOverlap(0, 1, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 1 to 0 + const auto& range = view.getOverlap(1, 0, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } +} + +BOOST_AUTO_TEST_CASE(rofoverlap_staggered_alllayers) +{ + // test staggered layers with ROF delay + o2::its::ROFOverlapTable<3> table; + table.defineLayer(0, 2, 3, 0, 0); + table.defineLayer(1, 3, 2, 0, 0); + table.defineLayer(2, 6, 1, 0, 0); + table.init(); + const auto view = table.getView(); + + // verify overlap range + { // from 0 to 1 rof=0 + const auto& range = view.getOverlap(0, 1, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 0 to 2 rof=0 + const auto& range = view.getOverlap(0, 2, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 3); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 0 to 1 rof=1 + const auto& range = view.getOverlap(0, 1, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 0 to 2 rof=1 + const auto& range = view.getOverlap(0, 2, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 3); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 3); + } + { // from 1 to 2 rof=0 + const auto& range = view.getOverlap(1, 2, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 1 to 0 rof=0 + const auto& range = view.getOverlap(1, 0, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 1 to 2 rof=1 + const auto& range = view.getOverlap(1, 2, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 2); + } + { // from 1 to 0 rof=1 + const auto& range = view.getOverlap(1, 0, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 1 to 2 rof=2 + const auto& range = view.getOverlap(1, 2, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 4); + } + { // from 1 to 0 rof=2 + const auto& range = view.getOverlap(1, 0, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=0 + const auto& range = view.getOverlap(2, 1, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=1 + const auto& range = view.getOverlap(2, 1, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=2 + const auto& range = view.getOverlap(2, 1, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=3 + const auto& range = view.getOverlap(2, 1, 3); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=4 + const auto& range = view.getOverlap(2, 1, 4); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 2); + } + { // from 2 to 1 rof=5 + const auto& range = view.getOverlap(2, 1, 5); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 2); + } + { // from 2 to 0 rof=0 + const auto& range = view.getOverlap(2, 0, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=1 + const auto& range = view.getOverlap(2, 0, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=2 + const auto& range = view.getOverlap(2, 0, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=3 + const auto& range = view.getOverlap(2, 0, 3); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 0 rof=4 + const auto& range = view.getOverlap(2, 0, 4); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 0 rof=5 + const auto& range = view.getOverlap(2, 0, 5); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } +} + +BOOST_AUTO_TEST_CASE(rofoverlap_staggered_alllayers_delay) +{ + // test staggered layers with ROF delay + o2::its::ROFOverlapTable<3> table; + table.defineLayer(0, 2, 3, 0, 0); + table.defineLayer(1, 3, 2, 1, 0); + table.defineLayer(2, 6, 1, 0, 0); + table.init(); + const auto view = table.getView(); + + // verify overlap range + { // from 0 to 1 rof=0 + const auto& range = view.getOverlap(0, 1, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 0 to 2 rof=0 + const auto& range = view.getOverlap(0, 2, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 3); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 0 to 1 rof=1 + const auto& range = view.getOverlap(0, 1, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 0 to 2 rof=1 + const auto& range = view.getOverlap(0, 2, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 3); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 3); + } + { // from 1 to 2 rof=0 + const auto& range = view.getOverlap(1, 2, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 1 to 0 rof=0 + const auto& range = view.getOverlap(1, 0, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 1 to 2 rof=1 + const auto& range = view.getOverlap(1, 2, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 3); + } + { // from 1 to 0 rof=1 + const auto& range = view.getOverlap(1, 0, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 1 to 2 rof=2 + const auto& range = view.getOverlap(1, 2, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 5); + } + { // from 1 to 0 rof=2 + const auto& range = view.getOverlap(1, 0, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=0 + const auto& range = view.getOverlap(2, 1, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 0); + } + { // from 2 to 1 rof=1 + const auto& range = view.getOverlap(2, 1, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=2 + const auto& range = view.getOverlap(2, 1, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=3 + const auto& range = view.getOverlap(2, 1, 3); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=4 + const auto& range = view.getOverlap(2, 1, 4); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=5 + const auto& range = view.getOverlap(2, 1, 5); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 2); + } + { // from 2 to 0 rof=0 + const auto& range = view.getOverlap(2, 0, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=1 + const auto& range = view.getOverlap(2, 0, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=2 + const auto& range = view.getOverlap(2, 0, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=3 + const auto& range = view.getOverlap(2, 0, 3); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 0 rof=4 + const auto& range = view.getOverlap(2, 0, 4); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 0 rof=5 + const auto& range = view.getOverlap(2, 0, 5); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } +} + +BOOST_AUTO_TEST_CASE(rofoverlap_staggered_alllayers_delay_delta) +{ + // test staggered layers with ROF delay + o2::its::ROFOverlapTable<3> table; + table.defineLayer(0, 2, 3, 0, 0); + table.defineLayer(1, 3, 2, 1, 0); + table.defineLayer(2, 6, 1, 0, 1); + table.init(); + const auto view = table.getView(); + + // verify overlap range + { // from 0 to 1 rof=0 + const auto& range = view.getOverlap(0, 1, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 0 to 2 rof=0 + const auto& range = view.getOverlap(0, 2, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 3); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 0 to 1 rof=1 + const auto& range = view.getOverlap(0, 1, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 0 to 2 rof=1 + const auto& range = view.getOverlap(0, 2, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 3); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 3); + } + { // from 1 to 2 rof=0 + const auto& range = view.getOverlap(1, 2, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 1 to 0 rof=0 + const auto& range = view.getOverlap(1, 0, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 1 to 2 rof=1 + const auto& range = view.getOverlap(1, 2, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 3); + } + { // from 1 to 0 rof=1 + const auto& range = view.getOverlap(1, 0, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 1 to 2 rof=2 + const auto& range = view.getOverlap(1, 2, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 5); + } + { // from 1 to 0 rof=2 + const auto& range = view.getOverlap(1, 0, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=0 + const auto& range = view.getOverlap(2, 1, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=1 + const auto& range = view.getOverlap(2, 1, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=2 + const auto& range = view.getOverlap(2, 1, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=3 + const auto& range = view.getOverlap(2, 1, 3); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 1 rof=4 + const auto& range = view.getOverlap(2, 1, 4); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 1 rof=5 + const auto& range = view.getOverlap(2, 1, 5); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 0 rof=0 + const auto& range = view.getOverlap(2, 0, 0); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=1 + const auto& range = view.getOverlap(2, 0, 1); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=2 + const auto& range = view.getOverlap(2, 0, 2); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=3 + const auto& range = view.getOverlap(2, 0, 3); + BOOST_CHECK_EQUAL(range.getEntries(), 2); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 0); + } + { // from 2 to 0 rof=4 + const auto& range = view.getOverlap(2, 0, 4); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } + { // from 2 to 0 rof=5 + const auto& range = view.getOverlap(2, 0, 5); + BOOST_CHECK_EQUAL(range.getEntries(), 1); + BOOST_CHECK_EQUAL(range.getFirstEntry(), 1); + } +} + +BOOST_AUTO_TEST_CASE(rofoverlap_with_delta) +{ + // test with ROF delta for compatibility window + o2::its::ROFOverlapTable<2> table; + table.defineLayer(0, 8, 600, 0, 100); // +/- 100 BC delta + table.defineLayer(1, 8, 600, 0, 100); + table.init(); + const auto view = table.getView(); + + // with delta, ROFs should have wider compatibility + for (int rof{0}; rof < 8; ++rof) { + auto overlap = view.getOverlap(0, 1, rof); + if (rof == 0 || rof == 7) { + // edges should see only two + BOOST_CHECK_EQUAL(overlap.getEntries(), 2); + } else { + BOOST_CHECK_EQUAL(overlap.getEntries(), 3); + } + } +} + +BOOST_AUTO_TEST_CASE(rofoverlap_same_layer) +{ + // test same layer compatibility + o2::its::ROFOverlapTable<1> table; + table.defineLayer(0, 10, 500, 0, 0); + table.init(); + const auto view = table.getView(); + + // same ROF in same layer should be compatible + BOOST_CHECK(view.isCompatible(0, 5, 0, 5)); + // different ROFs in same layer should not be compatible + BOOST_CHECK(!view.isCompatible(0, 5, 0, 6)); +} + +// ROFVertexLookupTable +BOOST_AUTO_TEST_CASE(rofvertex_basic) +{ + o2::its::ROFVertexLookupTable<1> table; + table.defineLayer(0, 6, 594, 0, 0); + table.init(); + std::vector vertices; + o2::its::Vertex vert0; + vert0.getTimeStamp().setTimeStamp(594); + vert0.getTimeStamp().setTimeStampError(594); + vertices.push_back(vert0); + o2::its::Vertex vert1; + vert1.getTimeStamp().setTimeStamp(2375); + vert1.getTimeStamp().setTimeStampError(594); + vertices.push_back(vert1); + table.update(vertices.data(), vertices.size()); + const auto view = table.getView(); +} + +BOOST_AUTO_TEST_CASE(rofvertex_init_with_vertices) +{ + o2::its::ROFVertexLookupTable<2> table; + table.defineLayer(0, 10, 500, 0, 0); + table.defineLayer(1, 10, 500, 0, 0); + + // create vertices at different timestamps + std::vector vertices; + for (int i = 0; i < 5; ++i) { + o2::its::Vertex v; + v.getTimeStamp().setTimeStamp(i * 1000); + v.getTimeStamp().setTimeStampError(500); + vertices.push_back(v); + } + + table.init(vertices.data(), vertices.size()); + const auto view = table.getView(); + + // verify vertices can be queried + const auto& vtxRange = view.getVertices(0, 0); + BOOST_CHECK_EQUAL(vtxRange.getEntries(), 1); +} + +BOOST_AUTO_TEST_CASE(rofvertex_compatibility) +{ + o2::its::ROFVertexLookupTable<1> table; + table.defineLayer(0, 5, 1000, 0, 100); + + std::vector vertices; + o2::its::Vertex v0; + v0.getTimeStamp().setTimeStamp(500); + v0.getTimeStamp().setTimeStampError(200); + vertices.push_back(v0); + + o2::its::Vertex v1; + v1.getTimeStamp().setTimeStamp(2500); + v1.getTimeStamp().setTimeStampError(200); + vertices.push_back(v1); + + table.init(vertices.data(), vertices.size()); + const auto view = table.getView(); + + // check vertex compatibility with ROFs + bool compat0 = view.isVertexCompatible(0, 0, 0); + bool compat1 = view.isVertexCompatible(0, 2, 1); + BOOST_CHECK(compat0 || !compat0); // just verify function executes +} + +BOOST_AUTO_TEST_CASE(rofvertex_needs_update) +{ + o2::its::ROFVertexLookupTable<1> table; + table.defineLayer(0, 5, 500, 0, 0); + + BOOST_CHECK(!table.needsUpdate()); + + table.init(); + BOOST_CHECK(table.needsUpdate()); + + std::vector vertices; + o2::its::Vertex v; + v.getTimeStamp().setTimeStamp(500); + v.getTimeStamp().setTimeStampError(100); + vertices.push_back(v); + + table.update(vertices.data(), vertices.size()); + BOOST_CHECK(table.needsUpdate()); +} + +BOOST_AUTO_TEST_CASE(rofvertex_max_vertices) +{ + o2::its::ROFVertexLookupTable<1> table; + table.defineLayer(0, 3, 1000, 0, 500); + + std::vector vertices; + for (int i = 0; i < 10; ++i) { + o2::its::Vertex v; + v.getTimeStamp().setTimeStamp(500 + i * 100); + v.getTimeStamp().setTimeStampError(50); + vertices.push_back(v); + } + + table.init(vertices.data(), vertices.size()); + const auto view = table.getView(); + + int32_t maxVtx = view.getMaxVerticesPerROF(); + BOOST_CHECK(maxVtx >= 0); +} + +BOOST_AUTO_TEST_CASE(roftimeslice_basic) +{ + o2::its::ROFTimeSliceTable<2> table; + table.defineLayer(0, 10, 500, 0, 0); + table.defineLayer(1, 10, 500, 0, 0); + + table.init(5); // 5 time slices + const auto view = table.getView(); + + // verify slices were created + for (int slice = 0; slice < 5; ++slice) { + const auto& range = view.getSlice(0, slice); + BOOST_CHECK(range.getEntries() > 0); + } +} + +BOOST_AUTO_TEST_CASE(roftimeslice_select_rofs) +{ + o2::its::ROFTimeSliceTable<1> table; + table.defineLayer(0, 10, 500, 0, 0); + table.init(4); + + BOOST_CHECK(table.needsUpdate()); + + // select ROFs in a BC range + table.selectROFs(1000, 2000); + BOOST_CHECK(table.needsUpdate()); +} + +BOOST_AUTO_TEST_CASE(roftimeslice_select_rofs_vector) +{ + o2::its::ROFTimeSliceTable<1> table; + table.defineLayer(0, 10, 500, 0, 0); + table.init(4); + + using BCRange = o2::its::ROFTimeSliceTable<1>::BCRange; + std::vector ranges; + ranges.emplace_back(500, 1000); + ranges.emplace_back(2000, 500); + + table.selectROFs(ranges); + BOOST_CHECK(table.needsUpdate()); +} + +BOOST_AUTO_TEST_CASE(roftimeslice_mask_operations) +{ + o2::its::ROFTimeSliceTable<1> table; + table.defineLayer(0, 8, 500, 0, 0); + table.init(3); + + // reset mask + table.resetMask(1); + BOOST_CHECK(table.needsUpdate()); + + table.resetMask(0); + BOOST_CHECK(table.needsUpdate()); + + // invert mask + table.invertMask(); + BOOST_CHECK(table.needsUpdate()); +} + +BOOST_AUTO_TEST_CASE(roftimeslice_find_slice) +{ + o2::its::ROFTimeSliceTable<1> table; + table.defineLayer(0, 10, 1000, 0, 0); + table.init(5); + const auto view = table.getView(); + + // find which slice a BC belongs to + int32_t slice = view.findSlice(0, 5000); + BOOST_CHECK(slice >= -1 && slice < 5); + + // BC outside range should return -1 + int32_t invalidSlice = view.findSlice(0, 50000); + BOOST_CHECK_EQUAL(invalidSlice, -1); +} + +BOOST_AUTO_TEST_CASE(roftimeslice_is_in_slice) +{ + o2::its::ROFTimeSliceTable<1> table; + table.defineLayer(0, 10, 1000, 0, 0); + table.init(4); + const auto view = table.getView(); + + // test if BC is in specific slice + const auto& slice0 = view.getSlice(0, 0); + int32_t bcInSlice = slice0.getFirstEntry() + 100; + BOOST_CHECK(view.isInSlice(0, 0, bcInSlice)); + + int32_t bcOutOfSlice = slice0.getEntriesBound() + 100; + BOOST_CHECK(!view.isInSlice(0, 0, bcOutOfSlice)); +} + +BOOST_AUTO_TEST_CASE(roftimeslice_get_mask) +{ + o2::its::ROFTimeSliceTable<1> table; + table.defineLayer(0, 6, 500, 0, 0); + table.init(3); + const auto view = table.getView(); + + // get mask for a slice + const uint8_t* mask = view.getMask(0, 1); + BOOST_CHECK(mask != nullptr); +} + +BOOST_AUTO_TEST_CASE(multilayer_complex) +{ + // test more complex scenario with 4 layers + o2::its::ROFOverlapTable<4> table; + table.defineLayer(0, 10, 500, 0, 50); + table.defineLayer(1, 10, 500, 100, 50); + table.defineLayer(2, 12, 600, 0, 100); + table.defineLayer(3, 8, 400, 50, 0); + table.init(); + + const auto view = table.getView(); + BOOST_CHECK_EQUAL(table.getEntries(), 4); + + // verify different layer combinations + BOOST_CHECK(view.getOverlap(0, 1, 0).getEntries() > 0); + BOOST_CHECK(view.getOverlap(2, 3, 0).getEntries() >= 0); +} diff --git a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt index efe663e14eed6..10e16e49d92b5 100644 --- a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt @@ -14,7 +14,6 @@ o2_add_library(ITSWorkflow SOURCES src/RecoWorkflow.cxx src/ClusterWriterWorkflow.cxx src/TrackerSpec.cxx - src/CookedTrackerSpec.cxx src/TrackWriterSpec.cxx src/TrackReaderSpec.cxx src/VertexReaderSpec.cxx diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h index 686a9f29371f4..3303081498838 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterSpec.h @@ -16,16 +16,13 @@ #include "Framework/DataProcessorSpec.h" -namespace o2 -{ -namespace its +namespace o2::its { /// create a processor spec /// write ITS tracks to ROOT file o2::framework::DataProcessorSpec getTrackWriterSpec(bool useMC); -} // namespace its -} // namespace o2 +} // namespace o2::its #endif /* O2_ITS_TRACKWRITER */ diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx index c10b4aa32f054..9e6a9e379fa63 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackWriterSpec.cxx @@ -16,73 +16,32 @@ #include "ITSWorkflow/TrackWriterSpec.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "DataFormatsITS/TrackITS.h" -#include "DataFormatsITSMFT/ROFRecord.h" +#include "ITStracking/Definitions.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" -#include "ITStracking/Definitions.h" -#include "ITStracking/TrackingConfigParam.h" - -using namespace o2::framework; -namespace o2 -{ -namespace its +namespace o2::its { +using namespace o2::framework; template using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; using LabelsType = std::vector; -using ROFRecLblT = std::vector; -using namespace o2::header; DataProcessorSpec getTrackWriterSpec(bool useMC) { - // Spectators for logging - // this is only to restore the original behavior - const auto writeContLabels = VertexerParamConfig::Instance().outputContLabels && useMC; - auto tracksSize = std::make_shared(0); - auto tracksSizeGetter = [tracksSize](std::vector const& tracks) { - *tracksSize = tracks.size(); - }; - auto logger = [tracksSize](std::vector const& rofs) { - LOG(info) << "ITSTrackWriter pulled " << *tracksSize << " tracks, in " << rofs.size() << " RO frames"; + auto logger = [](std::vector const& tracks) { + LOG(info) << "ITSTrackWriter pulled " << tracks.size() << " tracks"; }; return MakeRootTreeWriterSpec("its-track-writer", "o2trac_its.root", - MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with ITS tracks"}, - BranchDefinition>{InputSpec{"tracks", "ITS", "TRACKS", 0}, - "ITSTrack", - tracksSizeGetter}, - BranchDefinition>{InputSpec{"trackClIdx", "ITS", "TRACKCLSID", 0}, - "ITSTrackClusIdx"}, - BranchDefinition>{InputSpec{"vertices", "ITS", "VERTICES", 0}, - "Vertices"}, - BranchDefinition>{InputSpec{"vtxROF", "ITS", "VERTICESROF", 0}, - "VerticesROF"}, - BranchDefinition>{InputSpec{"ROframes", "ITS", "ITSTrackROF", 0}, - "ITSTracksROF", - logger}, - BranchDefinition{InputSpec{"labels", "ITS", "TRACKSMCTR", 0}, - "ITSTrackMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition{InputSpec{"labelsVertices", "ITS", "VERTICESMCTR", 0}, - "ITSVertexMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition{InputSpec{"labelsVerticesContributors", "ITS", "VERTICESMCTRCONT", 0}, - "ITSVertexMCTruthCont", - (writeContLabels ? 1 : 0), // one branch if - // requested - ""}, - BranchDefinition{InputSpec{"MC2ROframes", "ITS", "ITSTrackMC2ROF", 0}, - "ITSTracksMC2ROF", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition>{InputSpec{"purityVertices", "ITS", "VERTICESMCPUR", 0}, - "ITSVertexMCPurity", (useMC ? 1 : 0), // one branch if mc labels enabled - ""})(); + MakeRootTreeWriterSpec::TreeAttributes{.name = "o2sim", .title = "Tree with ITS tracks"}, + BranchDefinition>{InputSpec{"tracks", "ITS", "TRACKS", 0}, "ITSTrack", logger}, + BranchDefinition>{InputSpec{"trackClIdx", "ITS", "TRACKCLSID", 0}, "ITSTrackClusIdx"}, + BranchDefinition>{InputSpec{"vertices", "ITS", "VERTICES", 0}, "ITSVertices"}, + BranchDefinition{InputSpec{"labels", "ITS", "TRACKSMCTR", 0}, "ITSTrackMCTruth", (useMC ? 1 : 0), ""}, + BranchDefinition{InputSpec{"labelsVertices", "ITS", "VERTICESMCTR", 0}, "ITSVertexMCTruth", (useMC ? 1 : 0), ""}, + BranchDefinition>{InputSpec{"purityVertices", "ITS", "VERTICESMCPUR", 0}, "ITSVertexMCPurity", (useMC ? 1 : 0), ""})(); } -} // namespace its -} // namespace o2 +} // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx index dbfd5edf839ae..08b8fed856725 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx @@ -14,9 +14,9 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "ITSWorkflow/TrackerSpec.h" #include "ITStracking/Definitions.h" -#include "ITStracking/TrackingConfigParam.h" namespace o2 { @@ -41,8 +41,7 @@ void TrackerDPL::init(InitContext& ic) mTimer.Reset(); o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); mChainITS.reset(mRecChain->AddChain()); - mITSTrackingInterface.setTraitsFromProvider(mChainITS->GetITSVertexerTraits(), - mChainITS->GetITSTrackerTraits(), + mITSTrackingInterface.setTraitsFromProvider(mChainITS->GetITSTrackerTraits(), mChainITS->GetITSTimeframe()); } @@ -80,11 +79,16 @@ void TrackerDPL::end() DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, TrackingMode::Type trMode, const bool overrBeamEst, o2::gpu::GPUDataTypes::DeviceType dType) { + using Param = o2::itsmft::DPLAlpideParam; std::vector inputs; - - inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("patterns", "ITS", "PATTERNS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); + for (int iLayer = 0; iLayer < Param::getNLayers(); ++iLayer) { + inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", iLayer, Lifetime::Timeframe); + inputs.emplace_back("patterns", "ITS", "PATTERNS", iLayer, Lifetime::Timeframe); + inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", iLayer, Lifetime::Timeframe); + if (useMC) { + inputs.emplace_back("itsmclabels", "ITS", "CLUSTERSMCTR", iLayer, Lifetime::Timeframe); + } + } if (trgType == 1) { inputs.emplace_back("phystrig", "ITS", "PHYSTRIG", 0, Lifetime::Timeframe); } else if (trgType == 2) { @@ -110,34 +114,25 @@ DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, Tracking std::vector outputs; outputs.emplace_back("ITS", "TRACKS", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "TRACKCLSID", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "ITSTrackROF", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "VERTICES", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "VERTICESROF", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "IRFRAMES", 0, Lifetime::Timeframe); - if (useMC) { - inputs.emplace_back("itsmclabels", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("ITSMC2ROframes", "ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "VERTICESMCTR", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "VERTICESMCPUR", 0, Lifetime::Timeframe); outputs.emplace_back("ITS", "TRACKSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe); - if (VertexerParamConfig::Instance().outputContLabels) { - outputs.emplace_back("ITS", "VERTICESMCTRCONT", 0, Lifetime::Timeframe); - } } return DataProcessorSpec{ - "its-tracker", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, - useMC, - trgType, - trMode, - overrBeamEst, - dType)}, - Options{}}; + .name = "its-tracker", + .inputs = inputs, + .outputs = outputs, + .algorithm = AlgorithmSpec{adaptFromTask(ggRequest, + useMC, + trgType, + trMode, + overrBeamEst, + dType)}, + .options = Options{}}; } } // namespace its diff --git a/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/IOUtils.h b/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/IOUtils.h index fa15e73118524..11032df8224f4 100644 --- a/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/IOUtils.h +++ b/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/IOUtils.h @@ -71,11 +71,12 @@ void convertCompactClusters(gsl::span clusters, std::vector>& output, const its3::TopologyDictionary* dict); -int loadROFrameDataITS3(its::TimeFrame<7>* tf, - gsl::span rofs, - gsl::span clusters, - gsl::span::iterator& pattIt, - const its3::TopologyDictionary* dict, - const dataformats::MCTruthContainer* mcLabels = nullptr); +void loadROFrameDataITS3(its::TimeFrame<7>* tf, + gsl::span rofs, + gsl::span clusters, + gsl::span::iterator& pattIt, + const its3::TopologyDictionary* dict, + int layer, + const dataformats::MCTruthContainer* mcLabels = nullptr); } // namespace o2::its3::ioutils diff --git a/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/TrackingInterface.h b/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/TrackingInterface.h index 931628f2cf876..3b743c59524d2 100644 --- a/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/TrackingInterface.h +++ b/Detectors/Upgrades/ITS3/reconstruction/include/ITS3Reconstruction/TrackingInterface.h @@ -31,6 +31,7 @@ class ITS3TrackingInterface final : public its::ITSTrackingInterface void loadROF(gsl::span& trackROFspan, gsl::span clusters, gsl::span::iterator& pattIt, + int layer, const dataformats::MCTruthContainer* mcLabels) final; private: diff --git a/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx b/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx index d7ba4d48dbce4..6aeee2e94768a 100644 --- a/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx +++ b/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx @@ -58,18 +58,19 @@ void convertCompactClusters(gsl::span clusters, } } -int loadROFrameDataITS3(its::TimeFrame<7>* tf, - gsl::span rofs, - gsl::span clusters, - gsl::span::iterator& pattIt, - const its3::TopologyDictionary* dict, - const dataformats::MCTruthContainer* mcLabels) +void loadROFrameDataITS3(its::TimeFrame<7>* tf, + gsl::span rofs, + gsl::span clusters, + gsl::span::iterator& pattIt, + const its3::TopologyDictionary* dict, + int layer, + const dataformats::MCTruthContainer* mcLabels) { auto geom = its::GeometryTGeo::Instance(); geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); - tf->resetROFrameData(rofs.size()); - tf->prepareROFrameData(rofs, clusters); + tf->resetROFrameData(layer); + tf->prepareROFrameData(clusters, layer); its::bounded_vector clusterSizeVec(clusters.size(), tf->getMemoryPool().get()); @@ -83,7 +84,7 @@ int loadROFrameDataITS3(its::TimeFrame<7>* tf, float sigmaY2{0}, sigmaZ2{0}, sigmaYZ{0}; uint8_t clusterSize{0}; auto locXYZ = extractClusterData(c, pattIt, dict, sigmaY2, sigmaZ2, clusterSize); - clusterSizeVec.push_back(clusterSize); + clusterSizeVec[clusterId] = std::clamp(clusterSize, uint8_t(0), uint8_t(255)); // Transformation to the local --> global auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; @@ -102,23 +103,14 @@ int loadROFrameDataITS3(its::TimeFrame<7>* tf, tf->addClusterToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), tf->getUnsortedClusters()[layer].size()); tf->addClusterExternalIndexToLayer(layer, clusterId); } - for (unsigned int iL{0}; iL < tf->getUnsortedClusters().size(); ++iL) { - tf->mROFramesClusters[iL][iRof + 1] = tf->getUnsortedClusters()[iL].size(); - } + tf->getROFrameClusters(layer, iRof + 1) = tf->getUnsortedClusters()[layer].size(); } - tf->setClusterSize(clusterSizeVec); - - for (auto& v : tf->mNTrackletsPerCluster) { - v.resize(tf->getUnsortedClusters()[1].size()); - } - for (auto& v : tf->mNTrackletsPerClusterSum) { - v.resize(tf->getUnsortedClusters()[1].size() + 1); - } + tf->setClusterSize(layer, clusterSizeVec); if (mcLabels != nullptr) { - tf->mClusterLabels = mcLabels; + tf->getClusterLabelsContainer()[layer] = mcLabels; } - return tf->mNrof; } + } // namespace o2::its3::ioutils diff --git a/Detectors/Upgrades/ITS3/reconstruction/src/TrackingInterface.cxx b/Detectors/Upgrades/ITS3/reconstruction/src/TrackingInterface.cxx index 0f5c66a7f9663..17e0c2f6c8870 100644 --- a/Detectors/Upgrades/ITS3/reconstruction/src/TrackingInterface.cxx +++ b/Detectors/Upgrades/ITS3/reconstruction/src/TrackingInterface.cxx @@ -35,12 +35,9 @@ void ITS3TrackingInterface::updateTimeDependentParams(framework::ProcessingConte geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G)); initialise(); if (pc.services().get().inputTimesliceId == 0) { // print settings only for the 1st pipeling - o2::its::VertexerParamConfig::Instance().printKeyValues(); o2::its::TrackerParamConfig::Instance().printKeyValues(); - const auto& trParams = getTracker()->getParameters(); - for (size_t it = 0; it < trParams.size(); it++) { - const auto& par = trParams[it]; - LOGP(info, "recoIter#{} : {}", it, par.asString()); + for (const auto& par : getTracker()->getParameters()) { + LOGP(info, "{}", par.asString()); } } } @@ -77,9 +74,10 @@ void ITS3TrackingInterface::finaliseCCDB(framework::ConcreteDataMatcher& matcher void ITS3TrackingInterface::loadROF(gsl::span& trackROFspan, gsl::span clusters, gsl::span::iterator& pattIt, + int layer, const dataformats::MCTruthContainer* mcLabels) { - ioutils::loadROFrameDataITS3(mTimeFrame, trackROFspan, clusters, pattIt, mDict, mcLabels); + ioutils::loadROFrameDataITS3(mTimeFrame, trackROFspan, clusters, pattIt, mDict, layer, mcLabels); } } // namespace o2::its3 diff --git a/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx b/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx index 216056153d095..a4e15893c00e7 100644 --- a/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx +++ b/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx @@ -57,8 +57,7 @@ void TrackerDPL::init(InitContext& ic) mTimer.Reset(); o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); mChainITS.reset(mRecChain->AddChain()); - mITS3TrackingInterface.setTraitsFromProvider(mChainITS->GetITSVertexerTraits(), - mChainITS->GetITSTrackerTraits(), + mITS3TrackingInterface.setTraitsFromProvider(mChainITS->GetITSTrackerTraits(), mChainITS->GetITSTimeframe()); } From d00a74572a56c5561e4533dbc0a88ef144890dc5 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 12 Dec 2025 11:53:17 +0100 Subject: [PATCH 13/13] ITS: fix time assignment --- .../ITS/include/DataFormatsITS/TrackITS.h | 4 +- .../include/ITStracking/TrackerTraits.h | 2 +- .../ITS/tracking/include/ITStracking/Utils.h | 91 +++++++++++++++++++ .../ITSMFT/ITS/tracking/src/Configuration.cxx | 2 +- .../ITSMFT/ITS/tracking/src/TrackerTraits.cxx | 47 +++++++--- .../ITSMFT/ITS/tracking/test/CMakeLists.txt | 6 ++ .../ITSMFT/ITS/tracking/test/testUtils.cxx | 91 +++++++++++++++++++ 7 files changed, 224 insertions(+), 19 deletions(-) create mode 100644 Detectors/ITSMFT/ITS/tracking/include/ITStracking/Utils.h create mode 100644 Detectors/ITSMFT/ITS/tracking/test/testUtils.cxx diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h index c0570bf9d8111..0a83f8f88973c 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h @@ -37,7 +37,7 @@ namespace its class TrackITS : public o2::track::TrackParCov { enum UserBits { - kSharedClusters = 1 << 29 + kSharedClusters = 1 << 28 }; using Cluster = o2::itsmft::Cluster; @@ -93,7 +93,7 @@ class TrackITS : public o2::track::TrackParCov GPUhdi() void setChi2(float chi2) { mChi2 = chi2; } - bool isBetter(const TrackITS& best, float maxChi2) const; + bool isBetter(const TrackITS& best, float maxChi2 = o2::constants::math::VeryBig) const; auto& getTimeStamp() { return mTime; } const auto& getTimeStamp() const { return mTime; } diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h index 1d64c0c2e4a27..eb8ea9f691c73 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h @@ -116,7 +116,7 @@ class TrackerTraits std::shared_ptr mMemoryPool; std::shared_ptr mTaskArena; - dbscan::DBSCAN mDBScan; + dbscan::DBSCAN mDBScan{}; protected: o2::gpu::GPUChainITS* mChain = nullptr; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Utils.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Utils.h new file mode 100644 index 0000000000000..28e9c9096a6d9 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Utils.h @@ -0,0 +1,91 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include +#include + +namespace o2::its::utils +{ + +using Bracket = std::pair; +constexpr Bracket InvalidBracket{std::numeric_limits::min(), std::numeric_limits::min()}; + +template +Bracket computeSmallestBracket(const std::array& intervals) +{ + // Collect valid intervals + std::vector validIntervals; + for (const auto& inter : intervals) { + if (inter != InvalidBracket) { + validIntervals.push_back(inter); + } + } + + if (validIntervals.empty()) { + return InvalidBracket; + } + + // Check for gaps: sort by start, verify each overlaps/touches the next + std::sort(validIntervals.begin(), validIntervals.end()); + for (size_t i = 1; i < validIntervals.size(); ++i) { + if (validIntervals[i].first > validIntervals[i - 1].second) { + // Gap found: intervals are disconnected + return InvalidBracket; + } + } + + // Collect unique endpoints + std::array ends; + size_t count = 0; + for (const auto& inter : validIntervals) { + ends[count++] = inter.first; + ends[count++] = inter.second; + } + + std::sort(ends.begin(), ends.begin() + count); + auto last = std::unique(ends.begin(), ends.begin() + count); + count = last - ends.begin(); + + int32_t bestLength = std::numeric_limits::max(); + Bracket bestBracket{InvalidBracket}; + + for (size_t i = 0; i < count; ++i) { + const int32_t L = ends[i]; + for (size_t j = i + 1; j < count; ++j) { + const int32_t R = ends[j]; + int32_t length = R - L; + if (length >= bestLength) { + break; + } + + bool overlaps = true; + for (const auto& inter : validIntervals) { + if (L >= inter.second || R <= inter.first) { + overlaps = false; + break; + } + } + + if (overlaps) { + bestLength = length; + bestBracket = {L, R}; + break; + } + } + } + + return bestBracket; +} + +} // namespace o2::its::utils diff --git a/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx b/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx index 78323455c39e8..74b895400810c 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx @@ -24,7 +24,7 @@ using namespace o2::its; std::string TrackingParameters::asString() const { - std::string str = std::format("NZb:{} NPhB:{} PerVtx:{} DropFail:{} ClSh:{} TrklMinPt:{:.2f} MinCl:{}", ZBins, PhiBins, PerPrimaryVertexProcessing, DropTFUponFailure, ClusterSharing, TrackletMinPt, MinTrackLength); + std::string str = std::format("NZb:{} NPhB:{} PerVtx:{} DropFail:{} ClSh:{} TrklMinPt:{:.2f} MinCl:{} NSigma:{}", ZBins, PhiBins, PerPrimaryVertexProcessing, DropTFUponFailure, ClusterSharing, TrackletMinPt, MinTrackLength, NSigmaCut); bool first = true; for (int il = NLayers; il >= MinTrackLength; il--) { int slot = NLayers - il; diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index 5449aaa1ded8a..73147ce10b93c 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include "ITStracking/BoundedAllocator.h" #include "ITStracking/IndexTableUtils.h" #include "ITStracking/Tracklet.h" +#include "ITStracking/Utils.h" #include "ReconstructionDataFormats/Track.h" /// optimization output @@ -58,7 +60,7 @@ namespace o2::its { namespace { -utils::TreeStreamRedirector* sDBGOut{nullptr}; +o2::utils::TreeStreamRedirector* sDBGOut{nullptr}; } struct PassMode { @@ -570,8 +572,9 @@ void TrackerTraits::findCellSeeds(const int iteration) int rof = mTimeFrame->getClusterROF(i, cls[i]); int rofStartBC = mTimeFrame->getROFOverlapTableView().getLayer(i).getROFStartInBC(rof); int rofEndBC = mTimeFrame->getROFOverlapTableView().getLayer(i).getROFEndInBC(rof); - startBC = o2::gpu::CAMath::Min(startBC, rofStartBC); - endBC = o2::gpu::CAMath::Max(endBC, rofEndBC); + // if the start/end of the cluster is after/before the current bracket need to enlarge + startBC = (rofStartBC <= startBC) ? rofStartBC : o2::gpu::CAMath::Max(startBC, rofStartBC); + endBC = (rofEndBC >= endBC) ? rofEndBC : o2::gpu::CAMath::Min(endBC, rofEndBC); } if (endBC - startBC < 0) { // this should not happen ltracks[iCell].markDead(); @@ -946,10 +949,10 @@ void TrackerTraits::processNeighbours(int iteration, int iLayer, int iL if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) { continue; } - if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) { + if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) { continue; } - if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) { + if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) { continue; } @@ -1143,15 +1146,17 @@ void TrackerTraits::findRoads(const int iteration) } deepVectorClear(trackSeeds); + // sort tracks in quality (accounting for 1. length; 2. chi2) + // needed since then tracks with shared clusters can be marked/discarded tbb::parallel_sort(tracks.begin(), tracks.end(), [](const auto& a, const auto& b) { - return a.getChi2() < b.getChi2(); + return a.isBetter(b); }); }); for (auto& track : tracks) { int nShared = 0; bool isFirstShared{false}; - int firstLayer{-1}, firstCluster{-1}; + int firstLayer{constants::UnusedIndex}, firstCluster{constants::UnusedIndex}; for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { continue; @@ -1172,20 +1177,32 @@ void TrackerTraits::findRoads(const int iteration) // here we can do the calculation of the time bracket simply // by checkig in which rofs the clusters are - int bcStart{0}, bcEnd{std::numeric_limits::max()}; + std::array brackets; + brackets.fill(utils::InvalidBracket); for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { continue; } - mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer)); - int bcClsSta = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFStartInBC(currentROF); - int bcClsEnd = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFEndInBC(currentROF); - bcStart = std::max(bcStart, bcClsSta); - bcEnd = std::min(bcEnd, bcClsEnd); + // need to account for the imposed delay + int bcClsSta = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFStartInBC(currentROF, true); + int bcClsEnd = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFEndInBC(currentROF, true); + brackets[iLayer] = utils::Bracket{bcClsSta, bcClsEnd}; + LOGP(debug, "\tlay:{} bcClsSta={} bcClsEnd={}", iLayer, bcClsSta, bcClsEnd); + } + const auto best = utils::computeSmallestBracket(brackets); + if (best == utils::InvalidBracket) { + continue; // track has an impossible span, discard + } + // mark used clusters for the next iteration + for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) { + if (track.getClusterIndex(iLayer) == constants::UnusedIndex) { + continue; + } + mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer)); } - track.getTimeStamp().setTimeStamp(bcStart); - track.getTimeStamp().setTimeStampError(bcEnd - bcStart + 1); + track.getTimeStamp().setTimeStamp(best.first); + track.getTimeStamp().setTimeStampError(best.second - best.first + 1); track.setUserField(0); track.getParamOut().setUserField(0); mTimeFrame->getTracks().emplace_back(track); diff --git a/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt index 5ea8ec218caba..2f57673e05c10 100644 --- a/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt @@ -20,3 +20,9 @@ o2_add_test(roflookuptables COMPONENT_NAME its-tracking LABELS "its;tracking" PUBLIC_LINK_LIBRARIES O2::ITStracking) + +o2_add_test(utils + SOURCES testUtils.cxx + COMPONENT_NAME its-tracking + LABELS "its;tracking" + PUBLIC_LINK_LIBRARIES O2::ITStracking) diff --git a/Detectors/ITSMFT/ITS/tracking/test/testUtils.cxx b/Detectors/ITSMFT/ITS/tracking/test/testUtils.cxx new file mode 100644 index 0000000000000..4888aedf03cf3 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/test/testUtils.cxx @@ -0,0 +1,91 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#define BOOST_TEST_MODULE ITS Utils +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include + +#include "ITStracking/Utils.h" +using namespace o2::its::utils; + +BOOST_AUTO_TEST_CASE(test_1) +{ + const std::array brackets{{{594, 1188}, + {297, 891}}}; + const auto result = computeSmallestBracket(brackets); + BOOST_CHECK_EQUAL(result.first, 594); + BOOST_CHECK_EQUAL(result.second, 891); +} + +BOOST_AUTO_TEST_CASE(test_2) +{ + const std::array brackets{{{594, 1188}, + {594, 1188}, + {594, 1188}, + {297, 891}, + {297, 891}, + {297, 891}, + {891, 1485}}}; + const auto result = computeSmallestBracket(brackets); + BOOST_CHECK_EQUAL(result.first, 594); + BOOST_CHECK_EQUAL(result.second, 1188); +} + +BOOST_AUTO_TEST_CASE(test_3) +{ + std::array brackets; + brackets.fill(InvalidBracket); + brackets[0] = {500, 600}; + brackets[3] = {500, 600}; + brackets[6] = {500, 600}; + const auto result = computeSmallestBracket(brackets); + BOOST_CHECK_EQUAL(result.first, 500); + BOOST_CHECK_EQUAL(result.second, 600); +} + +BOOST_AUTO_TEST_CASE(test_4) +{ + std::array brackets; + brackets.fill(InvalidBracket); + brackets[0] = {100, 200}; + brackets[2] = {500, 600}; + const auto result = computeSmallestBracket(brackets); + BOOST_CHECK(result == InvalidBracket); +} + +BOOST_AUTO_TEST_CASE(test_5) +{ + std::array brackets{{{5346, 5940}, + {5346, 5940}, + {5346, 5940}, + {5049, 5643}, + {4455, 5049}, + {5049, 5643}, + {5049, 5643}}}; + const auto result = computeSmallestBracket(brackets); + BOOST_CHECK(result != InvalidBracket); +} + +BOOST_AUTO_TEST_CASE(test_6) +{ + std::array brackets{{{46926, 47520}, + {46926, 47520}, + {46926, 47520}, + {47817, 48411}, + {47817, 48411}, + {47817, 48411}, + {47817, 48411}}}; + const auto result = computeSmallestBracket(brackets); + BOOST_CHECK(result == InvalidBracket); +}