diff --git a/Detectors/ITSMFT/MFT/workflow/src/mft-ca-tracker-workflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/mft-ca-tracker-workflow.cxx index c8d236ce8983e..a42eb6f29f3c0 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/mft-ca-tracker-workflow.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/mft-ca-tracker-workflow.cxx @@ -13,6 +13,7 @@ #include +#include "CommonUtils/ConfigurableParam.h" #include "Framework/ConfigParamSpec.h" #include "MFTWorkflow/CATrackerSpec.h" @@ -23,12 +24,15 @@ void customize(std::vector& workflowOptions) workflowOptions.push_back(ConfigParamSpec{"disable-mc", VariantType::Bool, false, {"disable MC labels"}}); workflowOptions.push_back(ConfigParamSpec{"use-geom", VariantType::Bool, false, {"use geometry from the global geometry manager"}}); workflowOptions.push_back(ConfigParamSpec{"use-irframes", VariantType::Bool, false, {"consume ITS IR frames"}}); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g. MFTAlpideParam.roFrameLengthInBC=594)"}}); } #include "Framework/runDataProcessing.h" WorkflowSpec defineDataProcessing(ConfigContext const& config) { + o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); + const bool useMC = !config.options().get("disable-mc"); const bool useGeom = config.options().get("use-geom"); const bool useIRFrames = config.options().get("use-irframes"); diff --git a/Detectors/ITSMFT/common/CMakeLists.txt b/Detectors/ITSMFT/common/CMakeLists.txt index 3991f3e67a82b..5cfc80c16610a 100644 --- a/Detectors/ITSMFT/common/CMakeLists.txt +++ b/Detectors/ITSMFT/common/CMakeLists.txt @@ -10,6 +10,7 @@ # or submit itself to any jurisdiction. add_subdirectory(base) +add_subdirectory(tracking) add_subdirectory(simulation) add_subdirectory(reconstruction) add_subdirectory(workflow) diff --git a/Detectors/ITSMFT/common/tracking/CMakeLists.txt b/Detectors/ITSMFT/common/tracking/CMakeLists.txt new file mode 100644 index 0000000000000..b734a310f53e5 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/CMakeLists.txt @@ -0,0 +1,41 @@ +# 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. + +o2_add_library(ITSMFTTracking + TARGETVARNAME targetName + SOURCES src/IOUtils.cxx + src/TrackingConfigParam.cxx + src/Configuration.cxx + src/TimeFrame.cxx + PUBLIC_LINK_LIBRARIES + O2::ITStracking + O2::GPUCommon + O2::CommonConstants + O2::DetectorsCommonDataFormats + O2::DataFormatsITSMFT + O2::ITSMFTBase + O2::CommonUtils + O2::DetectorsBase + O2::MathUtils + Microsoft.GSL::GSL + O2::SimulationDataFormat + O2::ReconstructionDataFormats + PRIVATE_LINK_LIBRARIES + O2::Framework + O2::ITSBase + O2::MFTBase + O2::DataFormatsITS) + +# Only dictionary params (see ITSMFTTrackingLinkDef.h). TimeFrame and other +# headers pull ITStracking internals not exposed to rootcling include paths. +o2_target_root_dictionary(ITSMFTTracking + HEADERS include/ITSMFTTracking/TrackingConfigParam.h + LINKDEF src/ITSMFTTrackingLinkDef.h) diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Cell.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Cell.h new file mode 100644 index 0000000000000..b32ae812319ac --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Cell.h @@ -0,0 +1,172 @@ +// 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 Cell.h +/// \brief CA cell/track seed types with hole-layer support (ITS PR #15390) +/// + +#ifndef ALICEO2_ITSMFT_TRACKING_INCLUDE_CACELL_H_ +#define ALICEO2_ITSMFT_TRACKING_INCLUDE_CACELL_H_ + +#include +#include + +#include "ITStracking/Constants.h" +#include "ITSMFTTracking/LayerMask.h" +#include "DataFormatsITS/TimeEstBC.h" +#include "ReconstructionDataFormats/Track.h" +#include "GPUCommonDef.h" + +namespace o2::itsmft::tracking +{ + +struct CellNeighbour { + int cellTopology{-1}; + int cell{-1}; + int nextCellTopology{-1}; + int nextCell{-1}; + int level{-1}; +}; + +template +class SeedBase : public o2::track::TrackParCovF +{ + public: + GPUhd() LayerMask getHitLayerMask() const { return LayerMask{static_cast(getUserField())}; } + GPUhd() void setHitLayerMask(LayerMask mask) { setUserField(mask.value()); } + GPUhd() int getInnerLayer() const { return getHitLayerMask().first(); } + GPUhd() int getFirstTrackletIndex() const { return mTracklets[0]; }; + GPUhd() void setFirstTrackletIndex(int trkl) { mTracklets[0] = trkl; }; + GPUhd() int getSecondTrackletIndex() const { return mTracklets[1]; }; + GPUhd() void setSecondTrackletIndex(int trkl) { mTracklets[1] = trkl; }; + GPUhd() float getChi2() const { return mChi2; }; + GPUhd() void setChi2(float chi2) { mChi2 = chi2; }; + GPUhd() int getLevel() const { return mLevel; }; + GPUhd() void setLevel(int level) { mLevel = level; }; + GPUhd() int* getLevelPtr() { return &mLevel; } + GPUhd() auto& getTimeStamp() noexcept { return mTime; } + GPUhd() const auto& getTimeStamp() const noexcept { return mTime; } + + protected: + GPUhdDefault() SeedBase() = default; + GPUhdDefault() SeedBase(const SeedBase&) = default; + GPUhdDefault() ~SeedBase() = default; + GPUhdDefault() SeedBase(SeedBase&&) = default; + GPUhdDefault() SeedBase& operator=(const SeedBase&) = default; + GPUhdDefault() SeedBase& operator=(SeedBase&&) = default; + GPUhd() SeedBase(const o2::track::TrackParCovF& tpc, float chi2, int level, const o2::its::TimeEstBC& time) + : o2::track::TrackParCovF(tpc), mChi2(chi2), mLevel(level), mTime(time) + { + } + GPUhd() auto& clustersRaw() { return mClusters; } + GPUhd() const auto& clustersRaw() const { return mClusters; } + + private: + float mChi2{o2::its::constants::UnsetValue}; + int mLevel{o2::its::constants::UnusedIndex}; + std::array mTracklets = o2::its::constants::helpers::initArray(); + std::array mClusters = o2::its::constants::helpers::initArray(); + o2::its::TimeEstBC mTime; +}; + +class CellSeed final : public SeedBase +{ + using Base = SeedBase; + + public: + GPUhdDefault() CellSeed() = default; + GPUhd() CellSeed(int innerL, int cl0, int cl1, int cl2, int trkl0, int trkl1, const o2::track::TrackParCovF& tpc, float chi2, const o2::its::TimeEstBC& time) + : CellSeed(LayerMask(innerL, innerL + 1, innerL + 2), cl0, cl1, cl2, trkl0, trkl1, tpc, chi2, time) + { + } + GPUhd() CellSeed(LayerMask hitLayerMask, int cl0, int cl1, int cl2, int trkl0, int trkl1, const o2::track::TrackParCovF& tpc, float chi2, const o2::its::TimeEstBC& time) + : Base(tpc, chi2, 1, time) + { + setHitLayerMask(hitLayerMask); + auto& clusters = this->clustersRaw(); + clusters[0] = cl0; + clusters[1] = cl1; + clusters[2] = cl2; + setFirstTrackletIndex(trkl0); + setSecondTrackletIndex(trkl1); + } + GPUhdDefault() CellSeed(const CellSeed&) = default; + GPUhdDefault() ~CellSeed() = default; + GPUhdDefault() CellSeed(CellSeed&&) = default; + GPUhdDefault() CellSeed& operator=(const CellSeed&) = default; + GPUhdDefault() CellSeed& operator=(CellSeed&&) = default; + + GPUhd() int getFirstClusterIndex() const { return this->clustersRaw()[0]; }; + GPUhd() int getSecondClusterIndex() const { return this->clustersRaw()[1]; }; + GPUhd() int getThirdClusterIndex() const { return this->clustersRaw()[2]; }; + GPUhd() auto& getClusters() { return this->clustersRaw(); } + GPUhd() const auto& getClusters() const { return this->clustersRaw(); } + GPUhd() int getCluster(int layer) const + { + const int slot = getHitLayerMask().slot(layer); + return (slot >= 0 && slot < o2::its::constants::ClustersPerCell) ? this->clustersRaw()[slot] : o2::its::constants::UnusedIndex; + } +}; + +template +class TrackSeed final : public SeedBase +{ + using Base = SeedBase; + + public: + GPUhdDefault() TrackSeed() = default; + GPUhd() TrackSeed(const CellSeed& cs) + : Base(static_cast(cs), cs.getChi2(), cs.getLevel(), cs.getTimeStamp()) + { + this->setHitLayerMask(cs.getHitLayerMask()); + this->setFirstTrackletIndex(cs.getFirstTrackletIndex()); + this->setSecondTrackletIndex(cs.getSecondTrackletIndex()); + auto& clusters = this->clustersRaw(); + int slot = 0; + const auto hitMask = cs.getHitLayerMask(); + for (int layer = 0; layer < NLayers; ++layer) { + if (hitMask.has(layer)) { + clusters[layer] = cs.getClusters()[slot++]; + } + } + } + GPUhdDefault() TrackSeed(const TrackSeed&) = default; + GPUhdDefault() ~TrackSeed() = default; + GPUhdDefault() TrackSeed(TrackSeed&&) = default; + GPUhdDefault() TrackSeed& operator=(const TrackSeed&) = default; + GPUhdDefault() TrackSeed& operator=(TrackSeed&&) = default; + + GPUhd() int getFirstClusterIndex() const { return getClusterBySlot(0); } + GPUhd() int getSecondClusterIndex() const { return getClusterBySlot(1); } + GPUhd() int getThirdClusterIndex() const { return getClusterBySlot(2); } + GPUhd() auto& getClusters() { return this->clustersRaw(); } + GPUhd() const auto& getClusters() const { return this->clustersRaw(); } + GPUhd() int getCluster(int layer) const { return this->clustersRaw()[layer]; } + + private: + GPUhd() int getClusterBySlot(int requestedSlot) const + { + int slot = 0; + const auto hitMask = this->getHitLayerMask(); + for (int layer = 0; layer < NLayers; ++layer) { + if (hitMask.has(layer)) { + if (slot++ == requestedSlot) { + return this->clustersRaw()[layer]; + } + } + } + return o2::its::constants::UnusedIndex; + } +}; + +} // namespace o2::itsmft::tracking + +#endif /* ALICEO2_ITSMFT_TRACKING_INCLUDE_CACELL_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Configuration.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Configuration.h new file mode 100644 index 0000000000000..150a364bc1466 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Configuration.h @@ -0,0 +1,154 @@ +// 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 Configuration.h +/// \brief Shared CA tracking configuration for ITS and MFT +/// + +#ifndef ALICEO2_ITSMFT_TRACKING_CONFIGURATION_H_ +#define ALICEO2_ITSMFT_TRACKING_CONFIGURATION_H_ + +#include +#ifndef GPUCA_GPUCODE_DEVICE +#include +#include +#include +#endif + +#include "CommonUtils/EnumFlags.h" +#include "DetectorsBase/Propagator.h" +#include "ITSMFTTracking/Constants.h" + +namespace o2::itsmft +{ + +inline constexpr int ClustersPerCell = 3; + +// Steering of dedicated steps in an iteration +enum class IterationStep : uint8_t { + FirstPass = 0, + RebuildClusterLUT, + UseUPCMask, + SelectUPCVertices, + ResetVertices, + SkipROFsAboveThreshold, + MarkVerticesAsUPC, +}; +using IterationSteps = o2::utils::EnumFlags; + +struct TrackingParameters { + int CellMinimumLevel() const noexcept + { + const int minClusters = MinTrackLength - (MaxHoles > 0 ? MaxHoles : 0); + const int effectiveMinClusters = minClusters > ClustersPerCell ? minClusters : ClustersPerCell; + return effectiveMinClusters - ClustersPerCell + 1; + } + int NeighboursPerRoad() const noexcept { return NLayers - 3; } + int CellsPerRoad() const noexcept { return NLayers - 2; } + int TrackletsPerRoad() const noexcept { return NLayers - 1; } + std::string asString() const; + + IterationSteps PassFlags{IterationStep::FirstPass, IterationStep::RebuildClusterLUT}; + int NLayers = tracking::constants::ITSNLayers; + std::vector AddTimeError = {0, 0, 0, 0, 0, 0, 0}; + 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 LayerColHalfExtent{}; // index-table column half extent (ITS: z, MFT: global x); falls back to LayerZ + float IndexRowMin{0.f}; // index-table row origin (MFT: global y min; unused for ITS phi-z) + float IndexRowMax{0.f}; // index-table row span end (MFT: global y max; 0 => TwoPI for ITS) + 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}; + std::vector LayerResolution = {5.e-4f, 5.e-4f, 5.e-4f, 5.e-4f, 5.e-4f, 5.e-4f, 5.e-4f}; + std::vector SystError2Row = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; // systematic error^2 along local row (ALPIDE X) per layer + std::vector SystError2Col = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; // systematic error^2 along local column (ALPIDE Z) per layer + int ColBins{256}; + int RowBins{128}; + 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 + int MinTrackLength = 7; + int MaxHoles = 0; + uint16_t HoleLayerMask = 0; + float NSigmaCut = 5; + float PVres = 1.e-2f; + /// Trackleting cuts + float TrackletMinPt = 0.3f; + /// Cell finding cuts + float CellDeltaTanLambdaSigma = 0.007f; + /// Fitter parameters + o2::base::PropagatorImpl::MatCorrType CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE; + float MaxChi2ClusterAttachment = 60.f; + float MaxChi2NDF = 30.f; + int ReseedIfShorter = 6; // reseed for the final fit track with the length shorter than this + std::vector MinPt = {0.f, 0.f, 0.f, 0.f}; + uint32_t StartLayerMask = 0x7F; + bool RepeatRefitOut = false; // repeat outward refit using inward refit as a seed + bool ShiftRefToCluster = true; // TrackFit: after update shift the linearization reference to cluster + bool PerPrimaryVertexProcessing = false; + bool SaveTimeBenchmarks = false; + bool DoUPCIteration = false; + bool FataliseUponFailure = true; + bool CreateArtefactLabels{false}; + bool PrintMemory = false; // print allocator usage in epilog report + size_t MaxMemory = std::numeric_limits::max(); + bool DropTFUponFailure = false; + + // Selections on tracks sharing clusters + bool AllowSharingFirstCluster = false; + float SharedClusterMaxDeltaPhi = 0.05f; // For tracks sharing clusters, maximum allowed delta phi at the cluster position + float SharedClusterMaxDeltaEta = 0.03f; // For tracks sharing clusters, maximum allowed delta eta at the cluster position + bool SharedClusterOppositeSign = false; // For tracks sharing clusters, require opposite sign of the tracklets + int SharedMaxClusters = 0; // Maximal allowed shared clusters (excluding first cluster) +}; + +struct VertexingParameters { + std::string asString() const; + + IterationSteps PassFlags{IterationStep::FirstPass, IterationStep::ResetVertices}; + 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 vertPerRofThreshold = 0; // Maximum number of vertices per ROF to trigger second a round + int ColBins = 1; + int RowBins = 128; + float zCut = -1.f; + float phiCut = -1.f; + float pairCut = -1.f; + float clusterCut = -1.f; + float coarseZWindow = -1.f; + float seedDedupZCut = -1.f; + float refitDedupZCut = -1.f; + float duplicateZCut = -1.f; + float finalSelectionZCut = -1.f; + float duplicateDistance2Cut = -1.f; + float tanLambdaCut = -1.f; + float NSigmaCut = -1; + float maxZPositionAllowed = -1.f; + int clusterContributorsCut = -1; + int suppressLowMultDebris = -1; + int seedMemberRadiusTime = -1; + int seedMemberRadiusZ = -1; + int maxTrackletsPerCluster = -1; + int phiSpan = -1; + int zSpan = -1; + bool SaveTimeBenchmarks = false; + + bool useTruthSeeding = false; // overwrite found vertices with MC events + + int nThreads = 1; + bool PrintMemory = false; // print allocator usage in epilog report + size_t MaxMemory = std::numeric_limits::max(); + bool DropTFUponFailure = false; +}; + +} // namespace o2::itsmft + +#endif /* ALICEO2_ITSMFT_TRACKING_CONFIGURATION_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Constants.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Constants.h new file mode 100644 index 0000000000000..db24cd81c26d9 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/Constants.h @@ -0,0 +1,35 @@ +// 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 Constants.h +/// \brief Detector-specific layer counts for shared ITSMFT CA tracking +/// + +#ifndef ALICEO2_ITSMFT_TRACKING_INCLUDE_CONSTANTS_H_ +#define ALICEO2_ITSMFT_TRACKING_INCLUDE_CONSTANTS_H_ + +#include "DetectorsCommonDataFormats/DetID.h" + +namespace o2::itsmft::tracking::constants +{ + +constexpr int ITSNLayers = 7; +constexpr int MFTNLayers = 10; +constexpr int MaxIter = 4; // same as o2::its::constants::MaxIter + +constexpr int nLayersForDet(o2::detectors::DetID::ID detId) +{ + return detId == o2::detectors::DetID::MFT ? MFTNLayers : ITSNLayers; +} + +} // namespace o2::itsmft::tracking::constants + +#endif /* ALICEO2_ITSMFT_TRACKING_INCLUDE_CONSTANTS_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/IOUtils.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/IOUtils.h new file mode 100644 index 0000000000000..d38426df13cac --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/IOUtils.h @@ -0,0 +1,122 @@ +// 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 IOUtils.h +/// \brief Shared cluster I/O utilities for ITS and MFT (based on ITStracking/IOUtils.h) +/// + +#ifndef ALICEO2_ITSMFT_TRACKING_IOUTILS_H_ +#define ALICEO2_ITSMFT_TRACKING_IOUTILS_H_ + +#include +#include + +#include + +#include "DetectorsCommonDataFormats/DetID.h" +#include "ITSMFTBase/SegmentationAlpide.h" +#include "ReconstructionDataFormats/BaseCluster.h" +#include "DataFormatsITSMFT/ClusterPattern.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "MathUtils/Cartesian.h" + +namespace o2::its +{ +struct TrackingFrameInfo; +} + +namespace o2::itsmft::ioutils +{ + +constexpr float DefClusErrorRow = o2::itsmft::SegmentationAlpide::PitchRow * 0.5f; +constexpr float DefClusErrorCol = o2::itsmft::SegmentationAlpide::PitchCol * 0.5f; +constexpr float DefClusError2Row = DefClusErrorRow * DefClusErrorRow; +constexpr float DefClusError2Col = DefClusErrorCol * DefClusErrorCol; + +void fillMatrixCache(o2::detectors::DetID::ID detId); +int getClusterLayer(o2::detectors::DetID::ID detId, const CompClusterExt& cluster); + +template +unsigned int extractClusterSize(const CompClusterExt& c, iterator& iter, const TopologyDictionary* dict) +{ + auto pattID = c.getPatternID(); + if (pattID != CompCluster::InvalidPatternID) { + if (!dict->isGroup(pattID)) { + return dict->getNpixels(pattID); + } + ClusterPattern patt(iter); + return patt.getNPixels(); + } + ClusterPattern patt(iter); + return patt.getNPixels(); +} + +/// Decode a compact cluster into layer, size, and a TrackingFrameInfo (global + local frame). +template +void loadClusterTrackingFrameInfo(const CompClusterExt& c, + gsl::span::iterator& pattIt, + const TopologyDictionary* dict, + int& layer, + unsigned int& clusterSize, + o2::its::TrackingFrameInfo& tfInfo, + bool applySysErrors = true); + +/// Convert compact clusters to 3D spacepoints. +/// \tparam DetId o2::detectors::DetID::ITS or DetID::MFT +template +void convertCompactClusters(gsl::span clusters, + gsl::span::iterator& pattIt, + std::vector>& output, + const TopologyDictionary* dict); + +template +o2::math_utils::Point3D extractClusterData(const CompClusterExt& c, iterator& iter, const TopologyDictionary* dict, T& sig2Row, T& sig2Col) +{ + auto pattID = c.getPatternID(); + sig2Row = DefClusError2Row; + sig2Col = DefClusError2Col; // Dummy COG errors (about half pixel size) + if (pattID != CompCluster::InvalidPatternID) { + sig2Row = dict->getErr2X(pattID); + sig2Col = dict->getErr2Z(pattID); + if (!dict->isGroup(pattID)) { + return dict->getClusterCoordinates(c); + } + ClusterPattern patt(iter); + return dict->getClusterCoordinates(c, patt); + } + ClusterPattern patt(iter); + return dict->getClusterCoordinates(c, patt, false); +} + +// same method returning coordinates as an array (suitable for the TGeoMatrix) +template +std::array extractClusterDataA(const CompClusterExt& c, iterator& iter, const TopologyDictionary* dict, T& sig2Row, T& sig2Col) +{ + auto pattID = c.getPatternID(); + sig2Row = DefClusError2Row; + sig2Col = DefClusError2Col; // Dummy COG errors (about half pixel size) + if (pattID != CompCluster::InvalidPatternID) { + sig2Row = dict->getErr2X(pattID); + sig2Col = dict->getErr2Z(pattID); + if (!dict->isGroup(pattID)) { + return dict->getClusterCoordinatesA(c); + } + ClusterPattern patt(iter); + return dict->getClusterCoordinatesA(c, patt); + } + ClusterPattern patt(iter); + return dict->getClusterCoordinatesA(c, patt, false); +} + +} // namespace o2::itsmft::ioutils + +#endif /* ALICEO2_ITSMFT_TRACKING_IOUTILS_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/IndexTableUtils.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/IndexTableUtils.h new file mode 100644 index 0000000000000..acfdb7c066982 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/IndexTableUtils.h @@ -0,0 +1,202 @@ +// 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.h +/// \brief Shared index-table utilities for ITS (phi-z) and MFT (x-y) +/// + +#ifndef ALICEO2_ITSMFT_TRACKING_INDEXTABLEUTILS_H_ +#define ALICEO2_ITSMFT_TRACKING_INDEXTABLEUTILS_H_ + +#include + +#include "CommonConstants/MathConstants.h" +#include "GPUCommonMath.h" +#include "GPUCommonDef.h" +#include "ITSMFTTracking/Configuration.h" + +namespace o2::itsmft +{ + +enum class IndexTableCoordType : uint8_t { PhiZ, XY }; + +namespace index_table_utils +{ +GPUhdi() float getNormalizedPhi(float phi) +{ + phi -= o2::constants::math::TwoPI * o2::gpu::GPUCommonMath::Floor(phi * (1.f / o2::constants::math::TwoPI)); + return phi; +} +} // namespace index_table_utils + +/// Row/column LUT helper (ITS: row=phi, col=z; MFT: row=y, col=x). +template +class IndexTableUtils +{ + public: + /// Configure LUT geometry. ITS (PhiZ): row = phi [0, TwoPI), col = z; MFT (XY): row = y, col = x. + void setIndexTableParams(IndexTableCoordType coordType, int nRowBins, int nColBins, + float rowMin, float rowMax, + const std::array& layerColHalfExtent) + { + mCoordType = coordType; + mRowOrigin = (coordType == IndexTableCoordType::PhiZ) ? 0.f : rowMin; + mRowCoordinateSpan = rowMax - rowMin; + mInverseRowBinSize = (mRowCoordinateSpan > 0.f) ? static_cast(nRowBins) / mRowCoordinateSpan : 0.f; + mNcolBins = nColBins; + mNrowBins = nRowBins; + for (int iLayer{0}; iLayer < nLayers; ++iLayer) { + mLayerColHalfExtent[iLayer] = layerColHalfExtent[iLayer]; + mInverseColBinSize[iLayer] = 0.5f * nColBins / layerColHalfExtent[iLayer]; + } + } + + /// Fill LUT geometry from any struct exposing RowBins, ColBins and LayerZ (ITS phi-z). + template + void setTrackingParameters(const T& params) + { + setIndexTableParams(IndexTableCoordType::PhiZ, params.RowBins, params.ColBins, + 0.f, o2::constants::math::TwoPI, layerColHalfExtentFrom(params)); + } + + /// Fill LUT geometry for MFT (row = global y, col = global x). + template + void setTrackingParametersXY(const T& params, float rowMin, float rowMax) + { + setIndexTableParams(IndexTableCoordType::XY, params.RowBins, params.ColBins, + rowMin, rowMax, layerColHalfExtentFrom(params)); + } + + GPUhdi() float getInverseColCoordinate(const int layerIndex) const + { + return 0.5f * mNcolBins / mLayerColHalfExtent[layerIndex]; + } + + GPUhdi() int getColBinIndex(const int layerIndex, const float colCoordinate) const + { + return (colCoordinate + mLayerColHalfExtent[layerIndex]) * mInverseColBinSize[layerIndex]; + } + + GPUhdi() int getRowBinIndex(const float rowCoordinate) const + { + if (mCoordType == IndexTableCoordType::PhiZ) { + return rowCoordinate * mInverseRowBinSize; + } + return (rowCoordinate - mRowOrigin) * mInverseRowBinSize; + } + + GPUhdi() int getBinIndex(const int colIndex, const int rowIndex) const + { + return o2::gpu::GPUCommonMath::Min(rowIndex * mNcolBins + colIndex, (mNcolBins * mNrowBins) - 1); + } + + GPUhdi() int countRowSelectedBins(const int* indexTable, const int rowBinIndex, + const int minColBinIndex, const int maxColBinIndex) const + { + const int firstBinIndex{getBinIndex(minColBinIndex, rowBinIndex)}; + const int maxBinIndex{firstBinIndex + maxColBinIndex - minColBinIndex + 1}; + + return indexTable[maxBinIndex] - indexTable[firstBinIndex]; + } + + void print() const; + + GPUhdi() int getNcolBins() const { return mNcolBins; } + GPUhdi() int getNrowBins() const { return mNrowBins; } + GPUhdi() float getLayerColHalfExtent(int i) const { return mLayerColHalfExtent[i]; } + GPUhdi() void setNcolBins(const int colBins) { mNcolBins = colBins; } + GPUhdi() void setNrowBins(const int rowBins) { mNrowBins = rowBins; } + GPUhdi() IndexTableCoordType getCoordType() const { return mCoordType; } + + private: + template + static std::array layerColHalfExtentFrom(const T& params) + { + std::array extents{}; + if constexpr (requires { params.LayerColHalfExtent; }) { + const auto& colExtents = params.LayerColHalfExtent.empty() ? params.LayerZ : params.LayerColHalfExtent; + for (int iLayer{0}; iLayer < nLayers && iLayer < static_cast(colExtents.size()); ++iLayer) { + extents[iLayer] = colExtents[iLayer]; + } + } else { + for (int iLayer{0}; iLayer < nLayers && iLayer < static_cast(params.LayerZ.size()); ++iLayer) { + extents[iLayer] = params.LayerZ[iLayer]; + } + } + return extents; + } + + int mNcolBins = 0; + int mNrowBins = 0; + float mInverseRowBinSize = 0.f; + float mRowOrigin = 0.f; + float mRowCoordinateSpan = o2::constants::math::TwoPI; + IndexTableCoordType mCoordType{IndexTableCoordType::PhiZ}; + std::array mLayerColHalfExtent{}; + std::array mInverseColBinSize{}; +}; + +template +void IndexTableUtils::print() const +{ + printf("NcolBins: %d, NrowBins: %d, InverseRowBinSize: %f\n", mNcolBins, mNrowBins, mInverseRowBinSize); + for (int iLayer{0}; iLayer < nLayers; ++iLayer) { + printf("Layer %d: ColHalfExtent: %f, InverseColBinSize: %f\n", iLayer, mLayerColHalfExtent[iLayer], mInverseColBinSize[iLayer]); + } +} + +/// ITS: row = phi, col = z. +template +GPUhdi() int4 getBinsPhiZ(float phi, const int layerIndex, + float z1, float z2, float maxDeltaCol, float maxDeltaRow, + const IndexTableUtils& utils) +{ + const float colRangeMin = o2::gpu::GPUCommonMath::Min(z1, z2) - maxDeltaCol; + const float rowRangeMin = (maxDeltaRow > o2::constants::math::PI) ? 0.f : phi - maxDeltaRow; + const float colRangeMax = o2::gpu::GPUCommonMath::Max(z1, z2) + maxDeltaCol; + const float rowRangeMax = (maxDeltaRow > o2::constants::math::PI) ? o2::constants::math::TwoPI : phi + maxDeltaRow; + + if (colRangeMax < -utils.getLayerColHalfExtent(layerIndex) || + colRangeMin > utils.getLayerColHalfExtent(layerIndex) || colRangeMin > colRangeMax) { + return int4{-1, -1, -1, -1}; + } + + return int4{o2::gpu::GPUCommonMath::Max(0, utils.getColBinIndex(layerIndex, colRangeMin)), + utils.getRowBinIndex(index_table_utils::getNormalizedPhi(rowRangeMin)), + o2::gpu::GPUCommonMath::Min(utils.getNcolBins() - 1, utils.getColBinIndex(layerIndex, colRangeMax)), + utils.getRowBinIndex(index_table_utils::getNormalizedPhi(rowRangeMax))}; +} + +/// MFT: row = y, col = x. +template +GPUhdi() int4 getBinsXY(float x, float y, const int layerIndex, + float x1, float x2, float maxDeltaCol, float maxDeltaRow, + const IndexTableUtils& utils) +{ + const float colRangeMin = o2::gpu::GPUCommonMath::Min(x1, x2) - maxDeltaCol; + const float rowRangeMin = y - maxDeltaRow; + const float colRangeMax = o2::gpu::GPUCommonMath::Max(x1, x2) + maxDeltaCol; + const float rowRangeMax = y + maxDeltaRow; + + const float colHalf = utils.getLayerColHalfExtent(layerIndex); + if (colRangeMax < -colHalf || colRangeMin > colHalf || colRangeMin > colRangeMax) { + return int4{-1, -1, -1, -1}; + } + + return int4{o2::gpu::GPUCommonMath::Max(0, utils.getColBinIndex(layerIndex, colRangeMin)), + o2::gpu::GPUCommonMath::Max(0, utils.getRowBinIndex(rowRangeMin)), + o2::gpu::GPUCommonMath::Min(utils.getNcolBins() - 1, utils.getColBinIndex(layerIndex, colRangeMax)), + utils.getRowBinIndex(rowRangeMax)}; +} + +} // namespace o2::itsmft + +#endif /* ALICEO2_ITSMFT_TRACKING_INDEXTABLEUTILS_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/LayerMask.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/LayerMask.h new file mode 100644 index 0000000000000..e9afc26a916bd --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/LayerMask.h @@ -0,0 +1,115 @@ +// 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_ITSMFT_TRACKING_INCLUDE_LAYERMASK_H_ +#define ALICEO2_ITSMFT_TRACKING_INCLUDE_LAYERMASK_H_ + +#include +#include + +#ifndef GPUCA_GPUCODE +#include +#include +#endif + +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" +#include "ITStracking/Constants.h" + +namespace o2::itsmft::tracking +{ + +struct LayerMask { + GPUhdDefault() constexpr LayerMask() noexcept = default; + GPUhdDefault() constexpr LayerMask(uint16_t mask) noexcept : mBits{mask} {} + GPUhdDefault() constexpr LayerMask(int layer0, int layer1, int layer2) noexcept + : mBits{static_cast((uint16_t(1) << layer0) | (uint16_t(1) << layer1) | (uint16_t(1) << layer2))} + { + } + GPUhdi() constexpr operator uint16_t() const noexcept { return mBits; } + GPUhdi() constexpr uint16_t value() const noexcept { return mBits; } + GPUhdi() constexpr void set(int layer) noexcept { mBits |= (uint16_t(1) << layer); } + + GPUhdi() LayerMask operator~() const noexcept { return LayerMask{static_cast(~mBits)}; } + GPUhdi() LayerMask operator&(LayerMask other) const noexcept { return LayerMask{static_cast(mBits & other.mBits)}; } + GPUhdi() LayerMask operator|(LayerMask other) const noexcept { return LayerMask{static_cast(mBits | other.mBits)}; } + GPUhdi() LayerMask& operator&=(LayerMask other) noexcept + { + mBits &= other.mBits; + return *this; + } + GPUhdi() LayerMask& operator|=(LayerMask other) noexcept + { + mBits |= other.mBits; + return *this; + } + + GPUhdi() bool empty() const noexcept { return mBits == 0; } + GPUhdi() bool has(int layer) const noexcept { return mBits & (uint16_t(1) << layer); } + GPUhdi() bool isSubsetOf(LayerMask allowed) const noexcept { return (*this & ~allowed).empty(); } + GPUhdi() bool isAllowedHoleMask(int maxHoles, LayerMask allowedHoleMask) const noexcept + { + const int allowedHoles = maxHoles > 0 ? maxHoles : 0; + return count() <= allowedHoles && isSubsetOf(allowedHoleMask); + } + GPUhdi() bool isAllowed(int maxHoles, LayerMask allowedHoleMask) const noexcept + { + return holeMask().isAllowedHoleMask(maxHoles, allowedHoleMask); + } + GPUhdi() int length() const noexcept { return empty() ? 0 : last() - first() + 1; } + GPUhdi() int count() const noexcept { return static_cast(o2::gpu::GPUCommonMath::Popcount(mBits)); } + GPUhdi() int first() const noexcept { return mBits ? static_cast(o2::gpu::GPUCommonMath::Ctz(mBits)) : o2::its::constants::UnusedIndex; } + GPUhdi() int last() const noexcept { return mBits ? 31 - static_cast(o2::gpu::GPUCommonMath::Clz(mBits)) : o2::its::constants::UnusedIndex; } + GPUhdi() LayerMask holeMask() const noexcept + { + return empty() ? LayerMask{0} : (span(first(), last()) & ~(*this)); + } + + GPUhdi() int slot(int layer) const noexcept + { + if (!has(layer)) { + return o2::its::constants::UnusedIndex; + } + const uint32_t lowerLayers = (uint32_t(1) << layer) - 1; + return static_cast(o2::gpu::GPUCommonMath::Popcount(static_cast(mBits) & lowerLayers)); + } + + static GPUhdi() LayerMask span(int fromLayer, int toLayer) noexcept + { + if (fromLayer > toLayer) { + return 0; + } + const uint32_t upper = (uint32_t(1) << (toLayer + 1)) - 1; + const uint32_t lower = (uint32_t(1) << fromLayer) - 1; + return static_cast(upper & ~lower); + } + + static GPUhdi() LayerMask skipped(int fromLayer, int toLayer) noexcept + { + return (toLayer - fromLayer <= 1) ? LayerMask{0} : span(fromLayer + 1, toLayer - 1); + } + +#ifndef GPUCA_GPUCODE + std::string asString() const { return fmt::format("{:016b}", mBits); } +#endif + + private: + uint16_t mBits{0}; +}; + +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); +static_assert(sizeof(LayerMask) == sizeof(uint16_t)); +static_assert(alignof(LayerMask) == alignof(uint16_t)); + +} // namespace o2::itsmft::tracking + +#endif /* ALICEO2_ITSMFT_TRACKING_INCLUDE_LAYERMASK_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TimeFrame.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TimeFrame.h new file mode 100644 index 0000000000000..fe0ad66e7f65a --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TimeFrame.h @@ -0,0 +1,639 @@ +// 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_ITSMFT_TRACKING_TIMEFRAME_H_ +#define ALICEO2_ITSMFT_TRACKING_TIMEFRAME_H_ + +#include +#include +#include +#include +#include +#include + +#include "DataFormatsITS/TrackITS.h" +#include "DataFormatsITS/Vertex.h" + +#include "ITStracking/BoundedAllocator.h" +#include "ITSMFTTracking/Cell.h" +#include "ITStracking/Cluster.h" +#include "ITStracking/ClusterLines.h" +#include "ITStracking/ExternalAllocator.h" +#include "ITStracking/ROFLookupTables.h" +#include "ITStracking/Tracklet.h" + +#include "ITSMFTTracking/Configuration.h" +#include "ITSMFTTracking/Constants.h" +#include "ITSMFTTracking/IndexTableUtils.h" +#include "ITSMFTTracking/LayerMask.h" +#include "ITSMFTTracking/TrackingTopology.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +#include "DetectorsBase/Propagator.h" +#include "DetectorsCommonDataFormats/DetID.h" + +namespace o2 +{ +namespace gpu +{ +class GPUChainITS; +} + +namespace itsmft +{ +class CompClusterExt; +class TopologyDictionary; +class ROFRecord; +} // namespace itsmft + +namespace itsmft::tracking +{ + +// Re-use ITS CA tracking data structures; only TimeFrame and index-table I/O are detector-aware. +using Cluster = o2::its::Cluster; +using TrackingFrameInfo = o2::its::TrackingFrameInfo; +using CellSeed = o2::itsmft::tracking::CellSeed; +using Tracklet = o2::its::Tracklet; +using LayerMask = o2::itsmft::tracking::LayerMask; +using BoundedMemoryResource = o2::its::BoundedMemoryResource; +template +using bounded_vector = o2::its::bounded_vector; +using ExternalAllocator = o2::its::ExternalAllocator; +using Line = o2::its::Line; +using ClusterLines = o2::its::ClusterLines; +using Vertex = o2::its::Vertex; +using VertexLabel = o2::its::VertexLabel; +using TrackITSExt = o2::its::TrackITSExt; + +namespace constants +{ +using namespace o2::its::constants; +using o2::itsmft::tracking::constants::ITSNLayers; +using o2::itsmft::tracking::constants::MFTNLayers; +using o2::itsmft::tracking::constants::nLayersForDet; +} // namespace constants + +template +struct TimeFrame { + using IndexTableUtilsN = o2::itsmft::IndexTableUtils; + using ROFOverlapTableN = o2::its::ROFOverlapTable; + using ROFVertexLookupTableN = o2::its::ROFVertexLookupTable; + using ROFMaskTableN = o2::its::ROFMaskTable; + using TrackingTopologyN = o2::itsmft::tracking::TrackingTopology; + using TrackSeedN = o2::itsmft::tracking::TrackSeed; + + TimeFrame() = default; + virtual ~TimeFrame() = default; + + const Vertex& getPrimaryVertex(const int ivtx) const { return mPrimaryVertices[ivtx]; } + 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; + void addPrimaryVertex(const Vertex& vertex); + void addPrimaryVertexLabel(const VertexLabel& label) { mPrimaryVerticesLabels.push_back(label); } + + // read-in data + void loadROFrameData(gsl::span rofs, + gsl::span clusters, + gsl::span::iterator& pattIt, + const itsmft::TopologyDictionary* dict, + int layer, + const dataformats::MCTruthContainer* mcLabels = nullptr, + o2::detectors::DetID::ID detId = o2::detectors::DetID::ITS); + o2::detectors::DetID::ID getDetId() const { return mDetId; } + void setDetId(o2::detectors::DetID::ID detId) { mDetId = detId; } + void resetROFrameData(int iLayer); + void prepareROFrameData(gsl::span clusters, int layer); + + int getTotalClusters() const; + bool empty() const { return getTotalClusters() == 0; } + 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(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]; } + std::array& getBeamXY() { return mBeamPos; } + + auto& getMinRs() { return mMinR; } + auto& getMaxRs() { return mMaxR; } + float getMinR(int layer) const { return mMinR[layer]; } + float getMaxR(int layer) const { return mMaxR[layer]; } + float getTransitionPhiCut(int transitionId) const { return mTransitionPhiCuts[transitionId]; } + float getTransitionMSAngle(int transitionId) const { return mTransitionMSAngles[transitionId]; } + auto& getTransitionPhiCuts() { return mTransitionPhiCuts; } + auto& getTransitionMSAngles() { return mTransitionMSAngles; } + float getPositionResolution(int layer) const { return mPositionResolution[layer]; } + auto& getPositionResolutions() { return mPositionResolution; } + + 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; + gsl::span getROFrameClusters(int layerId) const; + gsl::span getNClustersROFrange(int rofMin, int range, int layerId) const; + gsl::span getIndexTable(int rofId, int layerId); + const auto& getTrackingFrameInfoOnLayer(int layerId) const { return mTrackingFrameInfo[layerId]; } + + // navigation tables + const auto& getIndexTableUtils() const { return mIndexTableUtils; } + const auto& getROFOverlapTable() const { return mROFOverlapTable; } + const auto& getROFOverlapTableView() const { return mROFOverlapTableView; } + const auto& getTrackerTopologies() const { return mTrackerTopologies; } + const auto& getTrackingTopologyView() const { return mTrackingTopologyView; } + void setROFOverlapTable(ROFOverlapTableN table) + { + 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()); } + void setMultiplicityCutMask(ROFMaskTableN cutMask) + { + mMultiplicityCutMask = std::move(cutMask); + mROFMaskView = mROFMask->getView(); + } + void useMultiplictyMask() noexcept + { + mROFMask = &mMultiplicityCutMask; + mROFMaskView = mROFMask->getView(); + } + void setUPCCutMask(ROFMaskTableN cutMask) { mUPCCutMask = std::move(cutMask); } + void useUPCMask() noexcept + { + mROFMask = &mUPCCutMask; + mROFMaskView = mROFMask->getView(); + } + const auto& getROFMaskView() const { return mROFMaskView; } + + 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[((mIsStaggered) ? layerId : 0)]->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); } + + auto& getTrackletsLabel(int layer) { return mTrackletLabels[layer]; } + auto& getCellsLabel(int layer) { return mCellLabels[layer]; } + + bool hasMCinformation() const { return mClusterLabels[0] != nullptr; } + void initVertexingTopology(const TrackingParameters& trkParam); + void initDefaultTrackingTopology(const TrackingParameters& trkParam, const int maxLayers = NLayers); + void initTrackerTopologies(gsl::span trkParams, const int maxLayers = NLayers); + void initialise(const TrackingParameters& trkParam, const int maxLayers = NLayers, const int iteration = constants::UnusedIndex); + + 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& getTracklets() { return mTracklets; } + auto& getTrackletsLookupTable() { return mTrackletsLookupTable; } + + auto& getClusters() { return mClusters; } + auto& getUnsortedClusters() { return mUnsortedClusters; } + int getClusterROF(int iLayer, int iCluster); + auto& getCells() { return mCells; } + + auto& getCellsLookupTable() { return mCellsLookupTable; } + auto& getCellsNeighbours() { return mCellsNeighbours; } + auto& getCellsNeighboursTopology() { return mCellsNeighboursTopology; } + auto& getCellsNeighboursLUT() { return mCellsNeighboursLUT; } + auto& getTracks() { return mTracks; } + auto& getTracksLabel() { return mTracksLabel; } + auto& getLinesLabel(const int rofId) { return mLinesLabels[rofId]; } + + size_t getNumberOfClusters() const; + virtual size_t getNumberOfCells() const; + virtual size_t getNumberOfTracklets() const; + virtual size_t getNumberOfNeighbours() const; + size_t getNumberOfTracks() const; + size_t getNumberOfUsedClusters() const; + + /// memory management + 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; + + /// staggering + void setIsStaggered(bool b) noexcept { mIsStaggered = b; } + + // 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; + // \Vertexer + + int hasBogusClusters() const { return std::accumulate(mBogusClusters.begin(), mBogusClusters.end(), 0); } + + void setBz(float bz) { mBz = bz; } + float getBz() const { return mBz; } + + /// State if memory will be externally managed by the GPU framework + ExternalAllocator* mExternalAllocator{nullptr}; + std::shared_ptr mExtMemoryPool; // host memory pool managed by the framework + 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(); } + + // Propagator + const o2::base::PropagatorImpl* getDevicePropagator() const { return mPropagatorDevice; } + virtual void setDevicePropagator(const o2::base::PropagatorImpl* /*unused*/) {}; + + template + void addClusterToLayer(int layer, T&&... args); + template + void addTrackingFrameInfoToLayer(int layer, T&&... args); + void addTrackingFrameInfoToLayer(int layer, const TrackingFrameInfo& tfInfo) { mTrackingFrameInfo[layer].push_back(tfInfo); } + void addClusterExternalIndexToLayer(int layer, const int idx) { mClusterExternalIndices[layer].push_back(idx); } + + std::array, NLayers> mClusters; + std::array, NLayers> mTrackingFrameInfo; + std::array, NLayers> mClusterExternalIndices; + std::array, NLayers> mROFramesClusters; + std::array*, NLayers> mClusterLabels{nullptr}; + std::array, 2> mNTrackletsPerCluster; + std::array, 2> mNTrackletsPerClusterSum; + std::array, NLayers> mNClustersPerROF; + std::array, NLayers> mIndexTables; + std::vector> mTrackletsLookupTable; + std::array, NLayers> mUsedClusters; + + std::array, NLayers> mUnsortedClusters; + std::vector> mTracklets; + std::vector> mCells; + bounded_vector mTracks; + bounded_vector mTracksLabel; + std::vector> mCellsNeighbours; + std::vector> mCellsNeighboursTopology; + std::vector> mCellsLookupTable; + + const o2::base::PropagatorImpl* mPropagatorDevice = nullptr; // Needed only for GPU + o2::detectors::DetID::ID mDetId{o2::detectors::DetID::ITS}; + + virtual void wipe(); + + // interface + virtual bool isGPU() const noexcept { return false; } + virtual const char* getName() const noexcept { return "CPU"; } + + protected: + 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 mTransitionPhiCuts; + bounded_vector mTransitionMSAngles; + bounded_vector mPositionResolution; + std::array, NLayers> mClusterSize; + + bounded_vector> mPValphaX; /// PV x and alpha for track propagation + std::vector> mTrackletLabels; + std::vector> mCellLabels; + std::vector> mCellsNeighboursLUT; + bounded_vector mBogusClusters; /// keep track of clusters with wild coordinates + + // Vertexer + bounded_vector mPrimaryVertices; + bounded_vector mPrimaryVerticesLabels; + std::vector> mNTrackletsPerROF; + std::vector> mLines; + std::vector> mTrackletClusters; + std::array, 2> mTrackletsIndexROF; + std::vector> mLinesLabels; + std::array mTotalTracklets = {0, 0}; + uint32_t mTotalLines = 0; + // \Vertexer + + // lookup tables + IndexTableUtilsN mIndexTableUtils; + ROFOverlapTableN mROFOverlapTable; + ROFOverlapTableN::View mROFOverlapTableView; + TrackingTopologyN mVertexingTopology; + TrackingTopologyN mDefaultTrackingTopology; + std::vector mTrackerTopologies; + typename TrackingTopologyN::View mTrackingTopologyView; + ROFVertexLookupTableN mROFVertexLookupTable; + ROFVertexLookupTableN::View mROFVertexLookupTableView; + ROFMaskTableN mMultiplicityCutMask; + ROFMaskTableN mUPCCutMask; + ROFMaskTableN* mROFMask = &mMultiplicityCutMask; + ROFMaskTableN::View mROFMaskView; + + bool mIsStaggered{false}; + + std::shared_ptr mMemoryPool; +}; + +template +gsl::span TimeFrame::getPrimaryVertices(int layer, int rofId) const +{ + if (rofId < 0 || rofId >= getNrof(layer)) { + return {}; + } + const auto& entry = mROFVertexLookupTableView.getVertices(layer, rofId); + return {&mPrimaryVertices[entry.getFirstEntry()], static_cast::size_type>(entry.getEntries())}; +} + +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 +{ + return {&mROFramesClusters[layerId][0], static_cast::size_type>(mROFramesClusters[layerId].size())}; +} + +template +inline gsl::span TimeFrame::getClustersOnLayer(int rofId, int layerId) +{ + 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 +{ + 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) +{ + 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 +{ + 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 +{ + 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, 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 +{ + 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 +{ + 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 +{ + int startIdx{rofMin}; // First cluster of rofMin + int endIdx{o2::gpu::CAMath::Min(rofMin + range, getNrof(layerId))}; + return mROFramesClusters[layerId][endIdx] - mROFramesClusters[layerId][startIdx]; +} + +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 +{ + 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) +{ + if (rofId < 0 || rofId >= getNrof(layer)) { + return {}; + } + const int tableSize = mIndexTableUtils.getNrowBins() * mIndexTableUtils.getNcolBins() + 1; + return {&mIndexTables[layer][rofId * tableSize], static_cast::size_type>(tableSize)}; +} + +template +template +void TimeFrame::addClusterToLayer(int layer, T&&... values) +{ + mUnsortedClusters[layer].emplace_back(std::forward(values)...); +} + +template +template +void TimeFrame::addTrackingFrameInfoToLayer(int layer, T&&... values) +{ + mTrackingFrameInfo[layer].emplace_back(std::forward(values)...); +} + +template +inline gsl::span TimeFrame::getUsedClusters(const int layer) +{ + return {&mUsedClusters[layer][0], static_cast::size_type>(mUsedClusters[layer].size())}; +} + +template +inline gsl::span TimeFrame::getNTrackletsCluster(int rofId, int combId) +{ + if (rofId < 0 || rofId >= getNrof(1)) { + 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 >= getNrof(1)) { + 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 >= getNrof(1) || 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 >= getNrof(1)) { + 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 >= getNrof(1) || !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 +{ + size_t totalClusters{0}; + for (const auto& clusters : mUnsortedClusters) { + totalClusters += clusters.size(); + } + return int(totalClusters); +} + +template +inline size_t TimeFrame::getNumberOfClusters() const +{ + size_t nClusters{0}; + for (const auto& layer : mClusters) { + nClusters += layer.size(); + } + return nClusters; +} + +template +inline size_t TimeFrame::getNumberOfCells() const +{ + size_t nCells{0}; + for (const auto& layer : mCells) { + nCells += layer.size(); + } + return nCells; +} + +template +inline size_t TimeFrame::getNumberOfTracklets() const +{ + size_t nTracklets{0}; + for (const auto& layer : mTracklets) { + nTracklets += layer.size(); + } + return nTracklets; +} + +template +inline size_t TimeFrame::getNumberOfNeighbours() const +{ + size_t neigh{0}; + for (const auto& l : mCellsNeighbours) { + neigh += l.size(); + } + return neigh; +} + +template +inline size_t TimeFrame::getNumberOfTracks() const +{ + return mTracks.size(); +} + +template +inline size_t TimeFrame::getNumberOfUsedClusters() const +{ + size_t nClusters = 0; + for (const auto& layer : mUsedClusters) { + nClusters += std::count(layer.begin(), layer.end(), true); + } + return nClusters; +} + +using TimeFrameITS = TimeFrame; +using TimeFrameMFT = TimeFrame; + +} // namespace itsmft::tracking +} // namespace o2 + +#endif /* ALICEO2_ITSMFT_TRACKING_TIMEFRAME_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TrackingConfigParam.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TrackingConfigParam.h new file mode 100644 index 0000000000000..119a5cbccbfb7 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TrackingConfigParam.h @@ -0,0 +1,154 @@ +// 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_ITSMFT_TRACKING_CONFIG_PARAM_H_ +#define ALICEO2_ITSMFT_TRACKING_CONFIG_PARAM_H_ + +#include +#include + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "ITSMFTTracking/Constants.h" + +namespace o2::itsmft +{ + +/// ITS vertexer settings (not used for MFT) +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. + + // geometrical cuts for tracklet selection for Pb-Pb + float zCut = 0.002f; + float phiCut = 0.005f; + float pairCut = 0.017321f; + float clusterCut = 0.170048f; + float coarseZWindow = 0.055458f; + float seedDedupZCut = 0.116685f; + float refitDedupZCut = 0.039855f; + float duplicateZCut = 0.200097f; + float finalSelectionZCut = 0.034535f; + float duplicateDistance2Cut = 0.005117f; + float tanLambdaCut = 0.002f; // tanLambda = deltaZ/deltaR + float nSigmaCut = 0.0164651f; + float maxZPositionAllowed = 25.f; // 4x sZ of the beam + + // Artefacts selections + int clusterContributorsCut = 3; // minimum number of contributors for an accepted final vertex + int suppressLowMultDebris = 16; // suppress all vertices below this threshold if a vertex was already found in a rof + int seedMemberRadiusTime = 0; + int seedMemberRadiusZ = 2; + int maxTrackletsPerCluster = 100; + 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 + + int nThreads = 1; + bool printMemory = false; + size_t maxMemory = std::numeric_limits::max(); + bool dropTFUponFailure = false; + + O2ParamDef(VertexerParamConfig, "ITSVertexerParam"); +}; + +template +struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper> { + static constexpr std::string_view getParamName() + { + return N == o2::detectors::DetID::ITS ? TrackerParamName[0] : TrackerParamName[1]; + } + + static constexpr int MinTrackLength = N == o2::detectors::DetID::ITS ? 4 : 5; + static constexpr int MaxTrackLength = N == o2::detectors::DetID::ITS ? o2::itsmft::tracking::constants::ITSNLayers + : o2::itsmft::tracking::constants::MFTNLayers; + + static constexpr int getNLayers() + { + return N == o2::detectors::DetID::ITS ? o2::itsmft::tracking::constants::ITSNLayers : o2::itsmft::tracking::constants::MFTNLayers; + } + + bool useMatCorrTGeo = false; // use full geometry to corect 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 addTimeError[getNLayers()] = {0}; // configure the width of the window in BC to be considered for the tracking. + int minTrackLgtIter[tracking::constants::MaxIter] = {}; // minimum track length at each iteration, used only if >0, otherwise use code defaults + uint8_t startLayerMask[tracking::constants::MaxIter] = {}; // mask of start layer for this iteration (if >0) + int maxHolesIter[tracking::constants::MaxIter] = {}; // maximum number of missing internal layers allowed in the CA topology for each iteration + uint16_t holeLayerMaskIter[tracking::constants::MaxIter] = {}; // layers that may be skipped by the CA topology for each iteration + float minPtIterLgt[tracking::constants::MaxIter * (MaxTrackLength - MinTrackLength + 1)] = {}; // min.pT for given track length at this iteration, used only if >0, otherwise use code defaults + float sysErr2Row[getNLayers()] = {0}; // systematic error^2 along ALPIDE rows (local X) per layer + float sysErr2Col[getNLayers()] = {0}; // systematic error^2 along ALPIDE columns (local Z) per layer + 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 LUTbinsU = -1; // number of LUT bins along the first coordinate (ITS: phi, MFT: global x) + int LUTbinsV = -1; // number of LUT bins along the second coordinate (ITS: z, MFT: global y) + float diamondPos[3] = {0.f, 0.f, 0.f}; // override the position of the vertex + bool useDiamond = false; // enable overriding the vertex position + bool perPrimaryVertexProcessing = false; // perform the full tracking considering the vertex hypotheses one at the time. + bool saveTimeBenchmarks = false; // dump metrics on file + bool overrideBeamEstimation = false; // use beam position from meanVertex CCDB object + int trackingMode = -1; // -1: unset, 0=sync, 1=async, 2=cosmics used by gpuwf only + bool doUPCIteration = false; // Perform an additional iteration for UPC events on tagged vertices. You want to combine this config with VertexerParamConfig.nIterations=2 + int nIterations = tracking::constants::MaxIter; // overwrite the number of iterations + int reseedIfShorter = 6; // for the final refit reseed the track with circle if they are shorter than this value + bool shiftRefToCluster{true}; // TrackFit: after update shift the linearization reference to cluster + bool repeatRefitOut{false}; // repeat outward refit using inward refit as a seed + bool createArtefactLabels{false}; // create on-the-fly labels for the artefacts + + int nThreads = 1; + bool printMemory = false; + size_t maxMemory = std::numeric_limits::max(); + bool dropTFUponFailure = false; + bool fataliseUponFailure = true; // granular management of the fatalisation in async mode + + // Selections on tracks sharing clusters + bool allowSharingFirstCluster = false; // allow first cluster sharing among tracks + float sharedClusterMaxDeltaPhi = 0.05f; // Maximum allowed delta phi at the cluster position + float sharedClusterMaxDeltaEta = 0.03f; // Maximum allowed delta eta at the cluster position + bool sharedClusterOppositeSign = false; // Require opposite sign of the tracklets + + O2ParamDef(TrackerParamConfig, getParamName().data()); + + private: + static constexpr std::string_view TrackerParamName[2] = {"ITSCATrackerParam", "MFTCATrackerParam"}; +}; + +template +TrackerParamConfig TrackerParamConfig::sInstance; + +} // namespace o2::itsmft + +namespace framework +{ +template +struct is_messageable; +template <> +struct is_messageable : std::true_type { +}; +template <> +struct is_messageable> : std::true_type { +}; +template <> +struct is_messageable> : std::true_type { +}; +} // namespace framework + +#endif /* ALICEO2_ITSMFT_TRACKING_CONFIG_PARAM_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TrackingTopology.h b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TrackingTopology.h new file mode 100644 index 0000000000000..822369508af31 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TrackingTopology.h @@ -0,0 +1,215 @@ +// 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_ITSMFT_TRACKING_INCLUDE_TRACKINGTOPOLOGY_H_ +#define ALICEO2_ITSMFT_TRACKING_INCLUDE_TRACKINGTOPOLOGY_H_ + +#include +#include +#include +#include + +#ifndef GPUCA_GPUCODE +#include +#include +#include "Framework/Logger.h" +#endif + +#include "CommonDataFormat/RangeReference.h" +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" +#include "ITSMFTTracking/LayerMask.h" + +namespace o2::itsmft::tracking +{ + +template +class TrackingTopology +{ + public: + using Id = uint8_t; + using Mask = LayerMask; + using Range = o2::dataformats::RangeReference; + static constexpr int MaxTransitions = (NLayers * (NLayers - 1)) / 2; + static constexpr int MaxCells = (NLayers * (NLayers - 1) * (NLayers - 2)) / 6; + static_assert(NLayers < std::numeric_limits::max()); + static_assert(MaxTransitions <= std::numeric_limits::max()); + static_assert(MaxCells <= std::numeric_limits::max()); + + struct LayerTransition { + Id fromLayer{0}; + Id toLayer{0}; + }; + static_assert(std::is_standard_layout_v); + static_assert(std::is_trivially_copyable_v); + static_assert(sizeof(LayerTransition) == (2 * sizeof(Id))); + + struct CellTopology { + Id firstTransition{0}; + Id secondTransition{0}; + Mask hitLayerMask{0}; + }; + static_assert(std::is_standard_layout_v); + static_assert(std::is_trivially_copyable_v); + static_assert(sizeof(CellTopology) == (2 * sizeof(Id)) + sizeof(Mask)); + + struct View { + const LayerTransition* transitions{nullptr}; + const CellTopology* cells{nullptr}; + const Range* cellsByFirstTransitionIndex{nullptr}; + const Id* cellsByFirstTransition{nullptr}; + Id nTransitions{0}; + Id nCells{0}; + Id nCellsByFirstTransition{0}; + + GPUhdi() const LayerTransition& getTransition(Id id) const { return transitions[id]; } + GPUhdi() const CellTopology& getCell(Id id) const { return cells[id]; } + GPUhdi() Range getCellsStartingWithTransition(Id transitionId) const { return cellsByFirstTransitionIndex[transitionId]; } + +#ifndef GPUCA_GPUCODE + std::string asString() const + { + std::string out = fmt::format("TrackingTopology: transitions={} cells={}", nTransitions, nCells); + out += "\n transitions:"; + for (Id transitionId = 0; transitionId < nTransitions; ++transitionId) { + const auto& t = transitions[transitionId]; + out += fmt::format("\n {}: {} -> {}", transitionId, t.fromLayer, t.toLayer); + } + out += "\n cells:"; + for (Id cellId = 0; cellId < nCells; ++cellId) { + const auto& c = cells[cellId]; + const auto& first = transitions[c.firstTransition]; + const auto& second = transitions[c.secondTransition]; + out += fmt::format("\n {}: {} -> {} -> {} hitMask={} transitions=({}, {})", cellId, first.fromLayer, first.toLayer, second.toLayer, c.hitLayerMask.asString(), c.firstTransition, c.secondTransition); + } + return out; + } + + void print() const + { + LOGP(info, "{}", asString()); + } +#endif + }; + + void init(int maxLayers, int maxHoles, Mask holeLayerMask) + { + clear(); + mMaxLayers = o2::gpu::CAMath::Max(0, o2::gpu::CAMath::Min(maxLayers, NLayers)); + mMaxHoles = o2::gpu::CAMath::Max(maxHoles, 0); + mHoleLayerMask = holeLayerMask; + for (int fromLayer = 0; fromLayer < mMaxLayers; ++fromLayer) { + for (int toLayer = fromLayer + 1; toLayer < mMaxLayers; ++toLayer) { + if (Mask::skipped(fromLayer, toLayer).isAllowedHoleMask(mMaxHoles, mHoleLayerMask)) { + mTransitions[mNTransitions++] = LayerTransition{static_cast(fromLayer), static_cast(toLayer)}; + } + } + } + + for (Id firstId = 0; firstId < mNTransitions; ++firstId) { + const auto& first = mTransitions[firstId]; + for (Id secondId = 0; secondId < mNTransitions; ++secondId) { + const auto& second = mTransitions[secondId]; + if (first.toLayer != second.fromLayer) { + continue; + } + const Mask hitMask{first.fromLayer, first.toLayer, second.toLayer}; + if (hitMask.isAllowed(mMaxHoles, mHoleLayerMask)) { + mCells[mNCells++] = CellTopology{firstId, secondId, hitMask}; + } + } + } + + fillCellsByTransition(); + } + + View getView() const + { + return View{mTransitions.data(), + mCells.data(), + mCellsByFirstTransitionIndex.data(), + mCellsByFirstTransition.data(), + mNTransitions, + mNCells, + mNCellsByFirstTransition}; + } + + View getDeviceView(const LayerTransition* deviceTransitions, + const CellTopology* deviceCells, + const Range* deviceCellsByFirstTransitionIndex, + const Id* deviceCellsByFirstTransition) const + { + return View{deviceTransitions, + deviceCells, + deviceCellsByFirstTransitionIndex, + deviceCellsByFirstTransition, + mNTransitions, + mNCells, + mNCellsByFirstTransition}; + } + + const auto& getTransitions() const noexcept { return mTransitions; } + const auto& getCells() const noexcept { return mCells; } + const auto& getCellsByFirstTransitionIndex() const noexcept { return mCellsByFirstTransitionIndex; } + const auto& getCellsByFirstTransition() const noexcept { return mCellsByFirstTransition; } + Id getNTransitions() const noexcept { return mNTransitions; } + Id getNCells() const noexcept { return mNCells; } + Id getNCellsByFirstTransition() const noexcept { return mNCellsByFirstTransition; } + + private: + void clear() + { + mNTransitions = 0; + mNCells = 0; + mNCellsByFirstTransition = 0; + mTransitions.fill({}); + mCells.fill({}); + mCellsByFirstTransitionIndex.fill(Range{0, 0}); + mCellsByFirstTransition.fill(0); + } + + void fillCellsByTransition() + { + std::array counts{}; + for (Id cellId = 0; cellId < mNCells; ++cellId) { + ++counts[mCells[cellId].firstTransition]; + } + + Id offset = 0; + for (Id transitionId = 0; transitionId < mNTransitions; ++transitionId) { + mCellsByFirstTransitionIndex[transitionId].setFirstEntry(offset); + mCellsByFirstTransitionIndex[transitionId].setEntries(counts[transitionId]); + offset += counts[transitionId]; + } + + std::array cursor{}; + for (Id cellId = 0; cellId < mNCells; ++cellId) { + const Id transitionId = mCells[cellId].firstTransition; + mCellsByFirstTransition[mCellsByFirstTransitionIndex[transitionId].getFirstEntry() + cursor[transitionId]++] = cellId; + } + mNCellsByFirstTransition = offset; + } + + int mMaxLayers{0}; + int mMaxHoles{0}; + Mask mHoleLayerMask{0}; + Id mNTransitions{0}; + Id mNCells{0}; + Id mNCellsByFirstTransition{0}; + std::array mTransitions{}; + std::array mCells{}; + std::array mCellsByFirstTransitionIndex{}; + std::array mCellsByFirstTransition{}; +}; + +} // namespace o2::itsmft::tracking + +#endif /* ALICEO2_ITSMFT_TRACKING_INCLUDE_TRACKINGTOPOLOGY_H_ */ diff --git a/Detectors/ITSMFT/common/tracking/src/Configuration.cxx b/Detectors/ITSMFT/common/tracking/src/Configuration.cxx new file mode 100644 index 0000000000000..ce3b3926c5079 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/src/Configuration.cxx @@ -0,0 +1,74 @@ +// 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 "ITSMFTTracking/Configuration.h" + +namespace o2::itsmft +{ + +std::string TrackingParameters::asString() const +{ + std::string str = std::format("NColB:{} NRowB:{} PerVtx:{} DropFail:{} TtklMinPt:{:.2f} MinCl:{}", ColBins, RowBins, PerPrimaryVertexProcessing, DropTFUponFailure, TrackletMinPt, MinTrackLength); + auto isSet = [](auto e) { return e >= 0; }; + auto isAnySet = [&isSet](auto v) { return !v.empty() && std::any_of(v.begin(), v.end(), isSet); }; + bool first = true; + for (int il = NLayers; il >= MinTrackLength; il--) { + int slot = NLayers - il; + if (slot < (int)MinPt.size() && MinPt[slot] > 0) { + if (first) { + first = false; + str += " MinPt: "; + } + str += std::format("L{}:{:.2f} ", il, MinPt[slot]); + } + } + if (isAnySet(SystError2Row) || isAnySet(SystError2Col)) { + str += " SystErrRow/Col:"; + for (size_t i = 0; i < SystError2Row.size(); i++) { + str += std::format("{:.2e}/{:.2e} ", SystError2Row[i], SystError2Col[i]); + } + } + if (isAnySet(AddTimeError)) { + str += " AddTimeError:"; + for (unsigned int i : AddTimeError) { + str += std::format("{} ", i); + } + } + if (SharedMaxClusters) { + str += std::format(" ShaMaxCls:{} ", SharedMaxClusters); + } + if (AllowSharingFirstCluster) { + str += std::format(" ShaClsDPhi:{} ShaClsDEta:{} ShaClsSign:{}", SharedClusterMaxDeltaPhi, SharedClusterMaxDeltaEta, SharedClusterOppositeSign); + } + if (MaxHoles) { + str += std::format(" MaxHoles:{} HoleMask:{:016b}", MaxHoles, HoleLayerMask); + } + if (std::numeric_limits::max() != MaxMemory) { + str += std::format(" MemLimit {:.2f} GB", double(MaxMemory) / (1024.f * 1024.f * 1024.f)); + } + return str; +} + +std::string VertexingParameters::asString() const +{ + std::string str = std::format("NColB:{} NRowB:{} MinVtxCont:{} SupLowMultDebris:{} MaxTrkltCls:{} ZCut:{} PhCut:{} PairCut:{} ClCut:{} SeedRad:{}x{}", + ColBins, RowBins, clusterContributorsCut, suppressLowMultDebris, maxTrackletsPerCluster, zCut, phiCut, pairCut, clusterCut, seedMemberRadiusTime, seedMemberRadiusZ); + if (std::numeric_limits::max() != MaxMemory) { + str += std::format(" MemLimit {:.2f} GB", double(MaxMemory) / (1024.f * 1024.f * 1024.f)); + } + return str; +} + +} // namespace o2::itsmft diff --git a/Detectors/ITSMFT/common/tracking/src/IOUtils.cxx b/Detectors/ITSMFT/common/tracking/src/IOUtils.cxx new file mode 100644 index 0000000000000..6ed2dfd8a13af --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/src/IOUtils.cxx @@ -0,0 +1,211 @@ +// 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 IOUtils.cxx +/// \brief Shared cluster I/O utilities for ITS and MFT (based on ITStracking/IOUtils.cxx) +/// + +#include "ITSMFTTracking/IOUtils.h" +#include "ITSMFTTracking/TrackingConfigParam.h" +#include "ITStracking/Cluster.h" + +#include "Framework/Logger.h" +#include "ITSBase/GeometryTGeo.h" +#include "MFTBase/GeometryTGeo.h" +#include "MathUtils/Utils.h" + +namespace +{ +constexpr int PrimaryVertexLayerId{-1}; +constexpr int EventLabelsSeparator{-1}; + +template +bool shouldApplySysErrors() +{ + const auto& conf = o2::itsmft::TrackerParamConfig::Instance(); + for (int il = 0; il < o2::itsmft::TrackerParamConfig::getNLayers(); il++) { + if (conf.sysErr2Row[il] > 0.f || conf.sysErr2Col[il] > 0.f) { + return true; + } + } + return false; +} + +template +void loadClusterTrackingFrameInfoImpl(GeomT* geom, + const o2::itsmft::CompClusterExt& c, + gsl::span::iterator& pattIt, + const o2::itsmft::TopologyDictionary* dict, + int& layer, + unsigned int& clusterSize, + o2::its::TrackingFrameInfo& tfInfo, + bool applySysErrors) +{ + const auto sensorID = c.getSensorID(); + layer = geom->getLayer(sensorID); + clusterSize = o2::itsmft::ioutils::extractClusterSize(c, pattIt, dict); + + float sigma2Row{0.f}; + float sigma2Col{0.f}; + const auto locXYZ = o2::itsmft::ioutils::extractClusterData(c, pattIt, dict, sigma2Row, sigma2Col); + if (applySysErrors && shouldApplySysErrors()) { + const auto layerId = geom->getLayer(sensorID); + const auto& conf = o2::itsmft::TrackerParamConfig::Instance(); + sigma2Row += conf.sysErr2Row[layerId]; + sigma2Col += conf.sysErr2Col[layerId]; + } + + if constexpr (DetId == o2::detectors::DetID::ITS) { + const auto trkXYZ = geom->getMatrixT2L(sensorID) ^ locXYZ; + const auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; + tfInfo = o2::its::TrackingFrameInfo{ + gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), trkXYZ.x(), geom->getSensorRefAlpha(sensorID), + std::array{trkXYZ.y(), trkXYZ.z()}, + std::array{sigma2Row, 0.f, sigma2Col}}; + } else { + const auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; + // ALPIDE row (local X) -> global X, column (local Z) -> global Y + tfInfo = o2::its::TrackingFrameInfo{ + gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), gloXYZ.x(), 0.f, + std::array{gloXYZ.y(), gloXYZ.z()}, + std::array{sigma2Row, 0.f, sigma2Col}}; + } +} + +template +void fillOutputClusters(GeomT* geom, + gsl::span clusters, + gsl::span::iterator& pattIt, + std::vector>& output, + const o2::itsmft::TopologyDictionary* dict, + const o2::itsmft::TrackerParamConfig& conf, + bool applyMisalignment) +{ + for (const auto& c : clusters) { + float sigma2Row{0.f}, sigma2Col{0.f}; + const float sigmaRowCol{0.f}; // row-column covariance (unused) + auto locXYZ = o2::itsmft::ioutils::extractClusterData(c, pattIt, dict, sigma2Row, sigma2Col); + if (applyMisalignment) { + const auto layerId = geom->getLayer(c.getSensorID()); + sigma2Row += conf.sysErr2Row[layerId]; + sigma2Col += conf.sysErr2Col[layerId]; + } + o2::math_utils::Point3D outXYZ{}; + if constexpr (DetId == o2::detectors::DetID::ITS) { + outXYZ = geom->getMatrixT2L(c.getSensorID()) ^ locXYZ; + } else { + outXYZ = geom->getMatrixL2G(c.getSensorID()) * locXYZ; + } + auto& cl3d = output.emplace_back(c.getSensorID(), outXYZ); + cl3d.setErrors(sigma2Row, sigma2Col, sigmaRowCol); + } +} + +} // namespace + +namespace o2::itsmft::ioutils +{ + +void fillMatrixCache(o2::detectors::DetID::ID detId) +{ + const auto mask = o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G); + if (detId == o2::detectors::DetID::ITS) { + o2::its::GeometryTGeo::Instance()->fillMatrixCache(mask); + } else if (detId == o2::detectors::DetID::MFT) { + o2::mft::GeometryTGeo::Instance()->fillMatrixCache(mask); + } else { + LOGP(fatal, "Unsupported detector id {} in fillMatrixCache", static_cast(detId)); + } +} + +int getClusterLayer(o2::detectors::DetID::ID detId, const CompClusterExt& cluster) +{ + if (detId == o2::detectors::DetID::ITS) { + return o2::its::GeometryTGeo::Instance()->getLayer(cluster.getSensorID()); + } + if (detId == o2::detectors::DetID::MFT) { + return o2::mft::GeometryTGeo::Instance()->getLayer(cluster.getSensorID()); + } + LOGP(fatal, "Unsupported detector id {} in getClusterLayer", static_cast(detId)); + return -1; +} + +template +void loadClusterTrackingFrameInfo(const CompClusterExt& c, + gsl::span::iterator& pattIt, + const TopologyDictionary* dict, + int& layer, + unsigned int& clusterSize, + o2::its::TrackingFrameInfo& tfInfo, + bool applySysErrors) +{ + if constexpr (DetId == o2::detectors::DetID::ITS) { + loadClusterTrackingFrameInfoImpl(o2::its::GeometryTGeo::Instance(), c, pattIt, dict, layer, clusterSize, tfInfo, applySysErrors); + } else { + loadClusterTrackingFrameInfoImpl(o2::mft::GeometryTGeo::Instance(), c, pattIt, dict, layer, clusterSize, tfInfo, applySysErrors); + } +} + +template void loadClusterTrackingFrameInfo(const CompClusterExt& c, + gsl::span::iterator& pattIt, + const TopologyDictionary* dict, + int& layer, + unsigned int& clusterSize, + o2::its::TrackingFrameInfo& tfInfo, + bool applySysErrors); + +template void loadClusterTrackingFrameInfo(const CompClusterExt& c, + gsl::span::iterator& pattIt, + const TopologyDictionary* dict, + int& layer, + unsigned int& clusterSize, + o2::its::TrackingFrameInfo& tfInfo, + bool applySysErrors); + +template +void convertCompactClusters(gsl::span clusters, + gsl::span::iterator& pattIt, + std::vector>& output, + const TopologyDictionary* dict) +{ + const auto mask = o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G); + + const auto& conf = TrackerParamConfig::Instance(); + bool applyMisalignment = false; + for (int il = 0; il < TrackerParamConfig::getNLayers(); il++) { + if (conf.sysErr2Row[il] > 0.f || conf.sysErr2Col[il] > 0.f) { + applyMisalignment = true; + break; + } + } + + if constexpr (DetId == o2::detectors::DetID::ITS) { + auto* geom = o2::its::GeometryTGeo::Instance(); + geom->fillMatrixCache(mask); + fillOutputClusters(geom, clusters, pattIt, output, dict, conf, applyMisalignment); + } else { + auto* geom = o2::mft::GeometryTGeo::Instance(); + geom->fillMatrixCache(mask); + fillOutputClusters(geom, clusters, pattIt, output, dict, conf, applyMisalignment); + } +} + +template void convertCompactClusters(gsl::span clusters, + gsl::span::iterator& pattIt, + std::vector>& output, + const TopologyDictionary* dict); + +template void convertCompactClusters(gsl::span clusters, + gsl::span::iterator& pattIt, + std::vector>& output, + const TopologyDictionary* dict); + +} // namespace o2::itsmft::ioutils diff --git a/Detectors/ITSMFT/common/tracking/src/ITSMFTTrackingLinkDef.h b/Detectors/ITSMFT/common/tracking/src/ITSMFTTrackingLinkDef.h new file mode 100644 index 0000000000000..3deddc108e4b5 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/src/ITSMFTTrackingLinkDef.h @@ -0,0 +1,27 @@ +// 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::itsmft::VertexerParamConfig + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::itsmft::VertexerParamConfig> + ; + +#pragma link C++ class o2::itsmft::TrackerParamConfig < o2::detectors::DetID::ITS> + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::itsmft::TrackerParamConfig < o2::detectors::DetID::ITS>> + ; + +#pragma link C++ class o2::itsmft::TrackerParamConfig < o2::detectors::DetID::MFT> + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::itsmft::TrackerParamConfig < o2::detectors::DetID::MFT>> + ; + +#endif diff --git a/Detectors/ITSMFT/common/tracking/src/TimeFrame.cxx b/Detectors/ITSMFT/common/tracking/src/TimeFrame.cxx new file mode 100644 index 0000000000000..27d486ecb9fd5 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/src/TimeFrame.cxx @@ -0,0 +1,540 @@ +// 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 TimeFrame.cxx +/// \brief +/// + +#include + +#include "Framework/Logger.h" +#include "ITSMFTTracking/TimeFrame.h" +#include "ITSMFTTracking/IOUtils.h" +#include "ITStracking/MathUtils.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DetectorsCommonDataFormats/DetID.h" + +namespace +{ +struct ClusterHelper { + float rowCoord; + float r; + int bin; + int ind; +}; + +void loadClusterForDet(o2::detectors::DetID::ID detId, + const o2::itsmft::CompClusterExt& cluster, + gsl::span::iterator& pattIt, + const o2::itsmft::TopologyDictionary* dict, + int& layer, + unsigned int& clusterSize, + o2::its::TrackingFrameInfo& tfInfo) +{ + switch (detId) { + case o2::detectors::DetID::ITS: + o2::itsmft::ioutils::loadClusterTrackingFrameInfo(cluster, pattIt, dict, layer, clusterSize, tfInfo); + break; + case o2::detectors::DetID::MFT: + o2::itsmft::ioutils::loadClusterTrackingFrameInfo(cluster, pattIt, dict, layer, clusterSize, tfInfo); + break; + default: + LOGP(fatal, "Unsupported detector id {} in loadROFrameData", static_cast(detId)); + } +} + +template +void configureIndexTableUtils(o2::itsmft::IndexTableUtils& utils, + o2::detectors::DetID::ID detId, + const o2::itsmft::TrackingParameters& params) +{ + if (detId == o2::detectors::DetID::MFT) { + constexpr float defaultYMin{-20.f}; + constexpr float defaultYMax{20.f}; + const bool hasRowRange = params.IndexRowMax != 0.f; + const float rowMin = hasRowRange ? params.IndexRowMin : defaultYMin; + const float rowMax = hasRowRange ? params.IndexRowMax : defaultYMax; + utils.setTrackingParametersXY(params, rowMin, rowMax); + } else { + utils.setTrackingParameters(params); + } +} +} // namespace + +namespace o2::itsmft::tracking +{ + +using o2::its::clearResizeBoundedVector; +using o2::its::deepVectorClear; +namespace math_utils = o2::its::math_utils; +using o2::itsmft::IndexTableCoordType; +using o2::itsmft::IterationStep; +using o2::itsmft::TrackingParameters; + +template +void TimeFrame::addPrimaryVertex(const Vertex& vert) +{ + mPrimaryVertices.emplace_back(vert); + if (!isBeamPositionOverridden) { + const float w = vert.getNContributors(); + mBeamPos[0] = (mBeamPos[0] * mBeamPosWeight + vert.getX() * w) / (mBeamPosWeight + w); + mBeamPos[1] = (mBeamPos[1] * mBeamPosWeight + vert.getY() * w) / (mBeamPosWeight + w); + mBeamPosWeight += w; + } +} + +template +void TimeFrame::loadROFrameData(gsl::span rofs, + gsl::span clusters, + gsl::span::iterator& pattIt, + const itsmft::TopologyDictionary* dict, + int layer, + const dataformats::MCTruthContainer* mcLabels, + o2::detectors::DetID::ID detId) +{ + mDetId = detId; + if (NLayers != constants::nLayersForDet(detId)) { + LOGP(fatal, "TimeFrame<{}> is incompatible with detector {} (expected {} layers)", + NLayers, static_cast(detId), constants::nLayersForDet(detId)); + } + ioutils::fillMatrixCache(detId); + resetROFrameData(layer); + prepareROFrameData(clusters, layer); + + // check for missing/empty/unset rofs + // the code requires consistent monotonically increasing input without gaps + const auto& timing = mROFOverlapTableView.getLayer(layer >= 0 ? layer : 0); + if (timing.mNROFsTF != rofs.size()) { + LOGP(fatal, "Received inconsistent number of rofs on layer:{} expected:{} received:{}", layer, timing.mNROFsTF, rofs.size()); + } + + 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 lay{0}; + unsigned int clusterSize{0}; + TrackingFrameInfo tfInfo; + loadClusterForDet(detId, c, pattIt, dict, lay, clusterSize, tfInfo); + mClusterSize[layer >= 0 ? layer : 0][clusterId] = std::clamp(clusterSize, 0u, 255u); + addTrackingFrameInfoToLayer(lay, tfInfo); + addClusterToLayer(lay, tfInfo.xCoordinate, tfInfo.yCoordinate, tfInfo.zCoordinate, mUnsortedClusters[lay].size()); + addClusterExternalIndexToLayer(lay, clusterId); + } + // effectively calculating an exclusive sum + if (layer >= 0) { + mROFramesClusters[layer][iRof + 1] = mUnsortedClusters[layer].size(); + } else { + for (unsigned int iL{0}; iL < mUnsortedClusters.size(); ++iL) { + mROFramesClusters[iL][iRof + 1] = mUnsortedClusters[iL].size(); + } + } + } + + if (layer == 1 || layer == -1) { + for (auto i = 0; i < mNTrackletsPerCluster.size(); ++i) { + mNTrackletsPerCluster[i].resize(mUnsortedClusters[1].size()); + mNTrackletsPerClusterSum[i].resize(mUnsortedClusters[1].size() + 1); + } + } + + if (mcLabels != nullptr) { + mClusterLabels[layer >= 0 ? layer : 0] = mcLabels; + } else { + mClusterLabels[layer >= 0 ? layer : 0] = nullptr; + } +} + +template +void TimeFrame::resetROFrameData(int layer) +{ + if (layer >= 0) { + deepVectorClear(mUnsortedClusters[layer], getMaybeFrameworkHostResource()); + deepVectorClear(mTrackingFrameInfo[layer], getMaybeFrameworkHostResource()); + deepVectorClear(mClusterExternalIndices[layer], mMemoryPool.get()); + clearResizeBoundedVector(mROFramesClusters[layer], mROFOverlapTableView.getLayer(layer).mNROFsTF + 1, getMaybeFrameworkHostResource()); + } else { + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + deepVectorClear(mUnsortedClusters[iLayer], getMaybeFrameworkHostResource()); + deepVectorClear(mTrackingFrameInfo[iLayer], getMaybeFrameworkHostResource()); + deepVectorClear(mClusterExternalIndices[iLayer], mMemoryPool.get()); + clearResizeBoundedVector(mROFramesClusters[iLayer], mROFOverlapTableView.getLayer(iLayer).mNROFsTF + 1, getMaybeFrameworkHostResource()); + } + } +} + +template +void TimeFrame::prepareROFrameData(gsl::span clusters, int layer) +{ + if (layer >= 0) { + mUnsortedClusters[layer].reserve(clusters.size()); + mTrackingFrameInfo[layer].reserve(clusters.size()); + mClusterExternalIndices[layer].reserve(clusters.size()); + clearResizeBoundedVector(mClusterSize[layer], clusters.size(), mMemoryPool.get()); + } else { + clearResizeBoundedVector(mClusterSize[0], clusters.size(), mMemoryPool.get()); + std::array clusterCountPerLayer{0}; + for (const auto& cls : clusters) { + ++clusterCountPerLayer[ioutils::getClusterLayer(mDetId, cls)]; + } + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + mUnsortedClusters[iLayer].reserve(clusterCountPerLayer[iLayer]); + mTrackingFrameInfo[iLayer].reserve(clusterCountPerLayer[iLayer]); + mClusterExternalIndices[iLayer].reserve(clusterCountPerLayer[iLayer]); + } + } +} + +template +void TimeFrame::prepareClusters(const TrackingParameters& trkParam, const int maxLayers) +{ + const int numBins{trkParam.RowBins * trkParam.ColBins}; + 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 iLayer{0}, stopLayer = std::min(trkParam.NLayers, maxLayers); iLayer < stopLayer; ++iLayer) { + for (int rof{0}; rof < getNrof(iLayer); ++rof) { + if (!mROFMaskView.isROFEnabled(iLayer, rof)) { + continue; + } + const auto& unsortedClusters{getUnsortedClustersOnLayer(rof, iLayer)}; + const int clustersNum{static_cast(unsortedClusters.size())}; + auto* tableBase = mIndexTables[iLayer].data() + rof * stride; + + cHelper.resize(clustersNum); + + const bool useXYBinning = mIndexTableUtils.getCoordType() == IndexTableCoordType::XY; + for (int iCluster{0}; iCluster < clustersNum; ++iCluster) { + const Cluster& c = unsortedClusters[iCluster]; + ClusterHelper& h = cHelper[iCluster]; + + const float x = c.xCoordinate - (useXYBinning ? 0.f : mBeamPos[0]); + const float y = c.yCoordinate - (useXYBinning ? 0.f : mBeamPos[1]); + const float z = c.zCoordinate; + + const float rowCoord = useXYBinning ? c.yCoordinate : math_utils::computePhi(x, y); + const float colCoord = useXYBinning ? c.xCoordinate : z; + int colBin{mIndexTableUtils.getColBinIndex(iLayer, colCoord)}; + if (colBin < 0 || colBin >= trkParam.ColBins) { + colBin = std::clamp(colBin, 0, trkParam.ColBins - 1); + mBogusClusters[iLayer]++; + } + int bin = mIndexTableUtils.getBinIndex(colBin, mIndexTableUtils.getRowBinIndex(rowCoord)); + h.rowCoord = rowCoord; + h.r = math_utils::hypot(x, y); + mMinR[iLayer] = o2::gpu::GPUCommonMath::Min(h.r, mMinR[iLayer]); + mMaxR[iLayer] = o2::gpu::GPUCommonMath::Max(h.r, mMaxR[iLayer]); + h.bin = bin; + h.ind = clsPerBin[bin]++; + } + std::exclusive_scan(clsPerBin.begin(), clsPerBin.end(), lutPerBin.begin(), 0); + + auto clusters2beSorted{getClustersOnLayer(rof, iLayer)}; + for (int iCluster{0}; iCluster < clustersNum; ++iCluster) { + const ClusterHelper& h = cHelper[iCluster]; + Cluster& c = clusters2beSorted[lutPerBin[h.bin] + h.ind]; + + c = unsortedClusters[iCluster]; + c.phi = useXYBinning ? math_utils::computePhi(c.xCoordinate, c.yCoordinate) : h.rowCoord; + c.radius = h.r; + c.indexTableBinIndex = h.bin; + } + std::copy_n(lutPerBin.data(), clsPerBin.size(), tableBase); + std::fill_n(tableBase + clsPerBin.size(), stride - clsPerBin.size(), clustersNum); + + std::fill(clsPerBin.begin(), clsPerBin.end(), 0); + cHelper.clear(); + } + } +} + +template +void TimeFrame::initVertexingTopology(const TrackingParameters& trkParam) +{ + mVertexingTopology.init(3, trkParam.MaxHoles, LayerMask{trkParam.HoleLayerMask}); +} + +template +void TimeFrame::initDefaultTrackingTopology(const TrackingParameters& trkParam, const int maxLayers) +{ + mDefaultTrackingTopology.init(maxLayers, trkParam.MaxHoles, LayerMask{trkParam.HoleLayerMask}); +} + +template +void TimeFrame::initTrackerTopologies(gsl::span trkParams, const int maxLayers) +{ + mTrackerTopologies.resize(trkParams.size()); + for (size_t iteration = 0; iteration < trkParams.size(); ++iteration) { + const int iterationMaxLayers = std::min(maxLayers, trkParams[iteration].NLayers); + mTrackerTopologies[iteration].init(iterationMaxLayers, trkParams[iteration].MaxHoles, LayerMask{trkParams[iteration].HoleLayerMask}); + } +} + +template +void TimeFrame::initialise(const TrackingParameters& trkParam, const int maxLayers, const int iteration) +{ + mTrackingTopologyView = iteration != constants::UnusedIndex ? mTrackerTopologies[iteration].getView() : (maxLayers == 3 ? mVertexingTopology.getView() : mDefaultTrackingTopology.getView()); + + if (trkParam.PassFlags[IterationStep::FirstPass]) { + deepVectorClear(mTracks); + deepVectorClear(mTracksLabel); + deepVectorClear(mLines); + deepVectorClear(mLinesLabels); + if (trkParam.PassFlags[IterationStep::ResetVertices]) { + deepVectorClear(mPrimaryVertices); + deepVectorClear(mPrimaryVerticesLabels); + } + clearResizeBoundedVector(mLinesLabels, getNrof(1), mMemoryPool.get()); + configureIndexTableUtils(mIndexTableUtils, mDetId, 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.SystError2Col[iLayer] + trkParam.SystError2Row[iLayer])) + (trkParam.LayerResolution[iLayer] * trkParam.LayerResolution[iLayer])); + } + clearResizeBoundedVector(mLines, getNrof(1), mMemoryPool.get()); + clearResizeBoundedVector(mTrackletClusters, getNrof(1), mMemoryPool.get()); + + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + clearResizeBoundedVector(mIndexTables[iLayer], getNrof(iLayer) * ((trkParam.ColBins * trkParam.RowBins) + 1), getMaybeFrameworkHostResource()); + } + for (int iLayer{0}; iLayer < trkParam.NLayers; ++iLayer) { + if (trkParam.SystError2Row[iLayer] > 0.f || trkParam.SystError2Col[iLayer] > 0.f) { + for (auto& tfInfo : mTrackingFrameInfo[iLayer]) { + /// Account for alignment systematics in the cluster covariance matrix + tfInfo.covarianceTrackingFrame[0] += trkParam.SystError2Row[iLayer]; + tfInfo.covarianceTrackingFrame[2] += trkParam.SystError2Col[iLayer]; + } + } + } + + mMinR.fill(std::numeric_limits::max()); + mMaxR.fill(std::numeric_limits::min()); + } + clearResizeBoundedVector(mCells, mTrackingTopologyView.nCells, mMemoryPool.get()); + clearResizeBoundedVector(mCellsLookupTable, mTrackingTopologyView.nCells, mMemoryPool.get()); + clearResizeBoundedVector(mCellsNeighbours, mTrackingTopologyView.nCells, mMemoryPool.get()); + clearResizeBoundedVector(mCellsNeighboursTopology, mTrackingTopologyView.nCells, mMemoryPool.get()); + clearResizeBoundedVector(mCellsNeighboursLUT, mTrackingTopologyView.nCells, mMemoryPool.get()); + clearResizeBoundedVector(mCellLabels, mTrackingTopologyView.nCells, mMemoryPool.get()); + clearResizeBoundedVector(mTracklets, mTrackingTopologyView.nTransitions, mMemoryPool.get()); + clearResizeBoundedVector(mTrackletLabels, mTrackingTopologyView.nTransitions, mMemoryPool.get()); + clearResizeBoundedVector(mTrackletsLookupTable, mTrackingTopologyView.nTransitions, mMemoryPool.get()); + clearResizeBoundedVector(mTransitionPhiCuts, mTrackingTopologyView.nTransitions, mMemoryPool.get()); + clearResizeBoundedVector(mTransitionMSAngles, mTrackingTopologyView.nTransitions, mMemoryPool.get()); + mNTrackletsPerROF.resize(2); + for (auto& v : mNTrackletsPerROF) { + v = bounded_vector(getNrof(1) + 1, 0, mMemoryPool.get()); + } + if (trkParam.PassFlags[IterationStep::RebuildClusterLUT]) { + 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()); + } + } + + // estimate MS per layer + std::array msAngles{}; + for (unsigned int iLayer{0}; iLayer < NLayers; ++iLayer) { + msAngles[iLayer] = math_utils::MSangle(0.14f, trkParam.TrackletMinPt, trkParam.LayerxX0[iLayer]); + mPositionResolution[iLayer] = o2::gpu::CAMath::Sqrt((0.5f * (trkParam.SystError2Col[iLayer] + trkParam.SystError2Row[iLayer])) + (trkParam.LayerResolution[iLayer] * trkParam.LayerResolution[iLayer])); + } + + // for each transition calculate the phi-cuts + integrated MS + float oneOverR{0.001f * 0.3f * std::abs(mBz) / trkParam.TrackletMinPt}; + for (int transitionId{0}; transitionId < (int)mTracklets.size(); ++transitionId) { + const auto& transition = mTrackingTopologyView.getTransition(transitionId); + float ms2 = 0.; + for (int layer = transition.fromLayer; layer < transition.toLayer; ++layer) { + ms2 += math_utils::Sq(msAngles[layer]); + } + mTransitionMSAngles[transitionId] = o2::gpu::CAMath::Sqrt(ms2); + const float& r1 = trkParam.LayerRadii[transition.fromLayer]; + const float& r2 = trkParam.LayerRadii[transition.toLayer]; + oneOverR = (0.5 * oneOverR >= 1.f / r2) ? (2.f / r2) - o2::constants::math::Almost0 : oneOverR; + const float res1 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[transition.fromLayer]); + const float res2 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[transition.toLayer]); + 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))); + /// the expression std::asin(0.5f * x * oneOverR) is equivalent to std::aCos(0.5f * r1 * oneOverR) - std::acos(0.5 * r2 * oneOverR) + mTransitionPhiCuts[transitionId] = o2::gpu::CAMath::Min(o2::gpu::CAMath::ASin(0.5f * x * oneOverR) + 2.f * mTransitionMSAngles[transitionId] + delta, o2::constants::math::PI * 0.5f); + + // some cleanup + deepVectorClear(mTracklets[transitionId]); + deepVectorClear(mTrackletLabels[transitionId]); + deepVectorClear(mTrackletsLookupTable[transitionId]); + mTrackletsLookupTable[transitionId].resize(mClusters[transition.fromLayer].size() + 1, 0); + } + + for (int cellId{0}; cellId < (int)mCells.size(); ++cellId) { + deepVectorClear(mCells[cellId]); + deepVectorClear(mCellsLookupTable[cellId]); + deepVectorClear(mCellsNeighbours[cellId]); + deepVectorClear(mCellsNeighboursTopology[cellId]); + deepVectorClear(mCellsNeighboursLUT[cellId]); + deepVectorClear(mCellLabels[cellId]); + } +} + +template +unsigned long TimeFrame::getArtefactsMemory() const +{ + unsigned long size{0}; + for (const auto& trkl : mTracklets) { + size += sizeof(Tracklet) * trkl.size(); + } + for (const auto& cells : mCells) { + size += sizeof(CellSeed) * cells.size(); + } + for (const auto& cellsN : mCellsNeighbours) { + size += sizeof(int) * cellsN.size(); + } + for (const auto& cellsN : mCellsNeighboursTopology) { + size += sizeof(int) * cellsN.size(); + } + return size; +} + +template +void TimeFrame::printArtefactsMemory() const +{ + LOGP(info, "TimeFrame: Artefacts occupy {:.2f} MB", getArtefactsMemory() / constants::MB); +} + +template +void TimeFrame::computeTrackletsPerROFScans() +{ + for (ushort iLayer = 0; iLayer < 2; ++iLayer) { + for (unsigned int iRof{0}; iRof < getNrof(1); ++iRof) { + if (mROFMaskView.isROFEnabled(1, 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::setMemoryPool(std::shared_ptr pool) +{ + mMemoryPool = pool; + + auto initVector = [&](bounded_vector& vec, bool useExternal = false) { + std::pmr::memory_resource* mr = (useExternal) ? mExtMemoryPool.get() : mMemoryPool.get(); + deepVectorClear(vec, mr); + }; + + auto initContainers = [&](Container& container, bool useExternal = false) { + for (auto& v : container) { + initVector(v, useExternal); + } + }; + + // these will only reside on the host for the cpu part + initContainers(mClusterExternalIndices); + initContainers(mNTrackletsPerCluster); + initContainers(mNTrackletsPerClusterSum); + initContainers(mNClustersPerROF); + initVector(mPrimaryVertices); + initVector(mTransitionPhiCuts); + initVector(mTransitionMSAngles); + initVector(mPositionResolution); + initContainers(mClusterSize); + initVector(mPValphaX); + initVector(mBogusClusters); + initContainers(mTrackletsIndexROF); + initVector(mTracks); + initContainers(mTracklets); + initContainers(mCells); + initContainers(mCellsNeighbours); + initContainers(mCellsLookupTable); + // MC info (we don't know if we have MC) + initVector(mPrimaryVerticesLabels); + initContainers(mLinesLabels); + initContainers(mTrackletLabels); + initContainers(mCellLabels); + initVector(mTracksLabel); + // these will use possibly an externally provided allocator + initContainers(mClusters, hasFrameworkAllocator()); + initContainers(mUsedClusters, hasFrameworkAllocator()); + initContainers(mUnsortedClusters, hasFrameworkAllocator()); + initContainers(mIndexTables, hasFrameworkAllocator()); + initContainers(mTrackingFrameInfo, hasFrameworkAllocator()); + initContainers(mROFramesClusters, hasFrameworkAllocator()); +} + +template +void TimeFrame::setFrameworkAllocator(ExternalAllocator* ext) +{ + mExternalAllocator = ext; + mExtMemoryPool = std::make_shared(mExternalAllocator); +} + +template +void TimeFrame::wipe() +{ + deepVectorClear(mTracks); + deepVectorClear(mTracklets); + deepVectorClear(mCells); + deepVectorClear(mCellsNeighbours); + deepVectorClear(mCellsNeighboursTopology); + deepVectorClear(mCellsLookupTable); + deepVectorClear(mPrimaryVertices); + deepVectorClear(mTrackletsLookupTable); + deepVectorClear(mClusterExternalIndices); + deepVectorClear(mNTrackletsPerCluster); + deepVectorClear(mNTrackletsPerClusterSum); + deepVectorClear(mNClustersPerROF); + deepVectorClear(mTransitionPhiCuts); + deepVectorClear(mTransitionMSAngles); + 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()) { + deepVectorClear(mClusters); + deepVectorClear(mUsedClusters); + deepVectorClear(mUnsortedClusters); + deepVectorClear(mIndexTables); + deepVectorClear(mTrackingFrameInfo); + deepVectorClear(mROFramesClusters); + } + // only needed to clear if we have MC info + if (hasMCinformation()) { + deepVectorClear(mLinesLabels); + deepVectorClear(mPrimaryVerticesLabels); + deepVectorClear(mTrackletLabels); + deepVectorClear(mCellLabels); + deepVectorClear(mTracksLabel); + } +} + +template class TimeFrame; +template class TimeFrame; + +} // namespace o2::itsmft::tracking diff --git a/Detectors/ITSMFT/common/tracking/src/TrackingConfigParam.cxx b/Detectors/ITSMFT/common/tracking/src/TrackingConfigParam.cxx new file mode 100644 index 0000000000000..fc90f9243a996 --- /dev/null +++ b/Detectors/ITSMFT/common/tracking/src/TrackingConfigParam.cxx @@ -0,0 +1,18 @@ +// 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 "ITSMFTTracking/TrackingConfigParam.h" + +O2ParamImpl(o2::itsmft::VertexerParamConfig); + +// force registration of templated params in the parameter database (see ClustererParam.cxx) +static auto& sTrackerParamITS = o2::itsmft::TrackerParamConfig::Instance(); +static auto& sTrackerParamMFT = o2::itsmft::TrackerParamConfig::Instance();