diff --git a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h index db072ef3a421e..5d91c63258e57 100644 --- a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h +++ b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h @@ -27,6 +27,7 @@ #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "DataFormatsCTP/LumiInfo.h" +#include "DataFormatsITSMFT/ClusterID.h" #include #include @@ -188,8 +189,8 @@ namespace globaltracking { // max number of layers for which the ITS/MFT clusters, ROF records and patterns can be provided separately -constexpr int MaxITSLayers = 7; -constexpr int MaxMFTLayers = 10; +constexpr int MaxITSLayers = o2::itsmft::MaxITSClusLayers; +constexpr int MaxMFTLayers = o2::itsmft::MaxMFTClusLayers; // helper class to request DPL input data from the processor specs definition struct DataRequest { diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h index 9b63509cc9424..2f026fce7a588 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h @@ -221,13 +221,6 @@ class TrackITSExt : public TrackITS GPUhdDefault() TrackITSExt(const TrackITSExt& t) = default; - void setClusterIndex(int l, int i) - { - int ncl = getNumberOfClusters(); - mIndex[ncl++] = (l << 28) + i; - getClusterRefs().setEntries(ncl); - } - GPUhdi() int getClusterIndex(int lr) const { return mIndex[lr]; } GPUh() int getFirstLayerClusterIndex() const diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterID.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterID.h new file mode 100644 index 0000000000000..a8d1da83533ce --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClusterID.h @@ -0,0 +1,43 @@ +// 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 ClusterID.h +/// \brief Composition/decomposition of the ITS/MFT cluster IDs referring to per-layer cluster arrays +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_ITSMFT_CLUSTERID_H +#define ALICEO2_ITSMFT_CLUSTERID_H + +namespace o2::itsmft +{ + +// max number of layers for which the ITS/MFT clusters, ROF records and patterns can be provided separately +constexpr int MaxITSClusLayers = 7; +constexpr int MaxMFTClusLayers = 10; +constexpr int MaxClusLayers = MaxITSClusLayers > MaxMFTClusLayers ? MaxITSClusLayers : MaxMFTClusLayers; + +///< With the per-layer (staggered readout) ITS/MFT clusters input the clusters are referred to by the +///< composed ID (layer << ClusLayerShift) + index_in_layer. With a single (monolithic) clusters input +///< all clusters sit in the layer slot 0, hence the composed ID coincides with the flat cluster index +///< and the same decoding works for both cases. +///< Note: the bit 31 is excluded from the layer field, since the negative values of the composed ID +///< are reserved for the "no cluster" flags. +constexpr int ClusLayerShift = 27; +constexpr int ClusIndexMask = (0x1 << ClusLayerShift) - 1; +static_assert((1 << (31 - ClusLayerShift)) >= MaxClusLayers, "ClusLayerShift leaves no room for the layer ID"); + +constexpr int composeClusID(int lr, int idx) { return (lr << ClusLayerShift) + idx; } +constexpr int clusID2Layer(int id) { return id >> ClusLayerShift; } +constexpr int clusID2Index(int id) { return id & ClusIndexMask; } + +} // namespace o2::itsmft + +#endif diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClustersPerLayer.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClustersPerLayer.h new file mode 100644 index 0000000000000..77e97618a00a1 --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/ClustersPerLayer.h @@ -0,0 +1,109 @@ +// 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 ClustersPerLayer.h +/// \brief Container of the ITS/MFT clusters addressed by the composed (layer,index) ID +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_ITSMFT_CLUSTERSPERLAYER_H +#define ALICEO2_ITSMFT_CLUSTERSPERLAYER_H + +#include "DataFormatsITSMFT/ClusterID.h" +#include "Framework/Logger.h" +#include +#include + +namespace o2::itsmft +{ + +///< Container of the ITS/MFT clusters supplied either as a single (monolithic) array or per layer +///< (staggered readout). The clusters of all layers are kept in a single vector, layer by layer, +///< with the per-layer starting offsets recorded, so that a cluster referred to by the composed ID +///< (layer << ClusLayerShift) + index_in_layer can be looked up directly. With the monolithic input +///< only the layer slot 0 is filled and the composed ID coincides with the flat cluster index, hence +///< the same lookup works for both cases. +///< +///< The conversion of the compact clusters to the stored objects is detector specific (and needs the +///< geometry), so it is left to the caller: the container only records where each layer starts. +///< Expected usage (nLr == 1 for the monolithic input): +///< cont.init(nLr); +///< for (int lr = 0; lr < nLr; lr++) { +///< cont.beginLayer(lr); +///< auto pattIt = recoData.getITSClustersPatterns(lr).begin(); +///< o2::its::ioutils::convertCompactClusters(recoData.getITSClusters(lr), pattIt, cont.getClusters(), dict); +///< } +///< cont.finalize(); +///< after which cont[composedID] gives the cluster referred to by a track cluster reference. +template +class ClustersPerLayer +{ + public: + ///< prepare for filling nLr layer slots, discarding the previous content + void init(int nLr) + { + if (nLr < 1 || nLr > MaxClusLayers) { + LOGP(fatal, "Clusters container cannot be initialized for {} layers, must be within 1:{}", nLr, MaxClusLayers); + } + mClusters.clear(); + mLrFirst.fill(0); + mNLayers = nLr; + } + + ///< record the start of the layer lr data, the layers must be filled in the increasing order + void beginLayer(int lr) + { + if (lr < 0 || lr >= mNLayers) { + LOGP(fatal, "Clusters container was initialized for {} layers, cannot fill the layer {}", mNLayers, lr); + } + mLrFirst[lr] = int(mClusters.size()); + } + + ///< to be called once all the layers were filled + void finalize() + { + for (int lr = mNLayers; lr <= MaxClusLayers; lr++) { // the slots above the filled ones are empty + mLrFirst[lr] = int(mClusters.size()); + } + } + + void clear() + { + mClusters.clear(); + mLrFirst.fill(0); + mNLayers = 1; + } + + ///< the clusters of all layers, to be appended to by the caller between beginLayer and finalize + auto& getClusters() { return mClusters; } + const auto& getClusters() const { return mClusters; } + + auto getNLayers() const { return mNLayers; } + auto getFirstIndex(int lr) const { return mLrFirst[lr]; } + auto getNClusters(int lr) const { return mLrFirst[lr + 1] - mLrFirst[lr]; } + auto size() const { return mClusters.size(); } + bool empty() const { return mClusters.empty(); } + + ///< flat index of the cluster referred to by its composed ID + int flatIndex(int composedID) const + { + return mLrFirst[clusID2Layer(composedID)] + clusID2Index(composedID); + } + const T& operator[](int composedID) const { return mClusters[flatIndex(composedID)]; } + + private: + std::vector mClusters{}; ///< clusters of all layers, layer by layer + std::array mLrFirst{}; ///< 1st cluster of every layer, + the total in the last slot + int mNLayers = 1; ///< number of filled layer slots +}; + +} // namespace o2::itsmft + +#endif diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/DPLAlpideParam.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/DPLAlpideParam.h index a06ba0745edbd..714d156dd5f80 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/DPLAlpideParam.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/DPLAlpideParam.h @@ -16,6 +16,7 @@ #include "CommonUtils/ConfigurableParam.h" #include "CommonUtils/ConfigurableParamHelper.h" #include "CommonConstants/LHCConstants.h" +#include "DataFormatsITSMFT/ClusterID.h" #include namespace o2 @@ -76,6 +77,10 @@ struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); bool loadTPCCalib = false; Options opts{ ConfigParamSpec{"apply-xor", o2::framework::VariantType::Bool, false, {"flip the 8-th bit of slope and position (for processing TRD CTFs from 2021 pilot beam)"}}, diff --git a/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx b/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx index 276c7a4e82601..ba8bfcff9f0cd 100644 --- a/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx +++ b/Detectors/Align/Workflow/src/barrel-alignment-workflow.cxx @@ -95,6 +95,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) bool loadTPCTracks = configcontext.options().get("enable-tpc-tracks"); bool enableCosmic = configcontext.options().get("enable-cosmic"); bool useMC = configcontext.options().get("enable-mc"); + bool doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); DetID::mask_t dets = allowedDets & DetID::getMask(configcontext.options().get("detectors")); DetID::mask_t skipDetClusters; // optionally skip automatically loaded clusters @@ -154,7 +155,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt)); } - specs.emplace_back(o2::align::getBarrelAlignmentSpec(srcMP, src, dets, skipDetClusters, enableCosmic, postprocess, useMC)); + specs.emplace_back(o2::align::getBarrelAlignmentSpec(srcMP, src, dets, skipDetClusters, enableCosmic, postprocess, useMC, doStag)); // RS FIXME: check which clusters are really needed if (!postprocess) { GID::mask_t dummy; diff --git a/Detectors/Align/include/Align/AlignableDetectorITS.h b/Detectors/Align/include/Align/AlignableDetectorITS.h index 5f1816d8368b8..d7ae3a899a74e 100644 --- a/Detectors/Align/include/Align/AlignableDetectorITS.h +++ b/Detectors/Align/include/Align/AlignableDetectorITS.h @@ -22,6 +22,7 @@ #include "ReconstructionDataFormats/TrackParametrizationWithError.h" #include "ReconstructionDataFormats/BaseCluster.h" #include "ITSMFTReconstruction/ChipMappingITS.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" namespace o2 { @@ -76,9 +77,9 @@ class AlignableDetectorITS : public AlignableDetector // protected: // - std::vector mITSClustersArray; - std::vector mOverlapCandidateID; // pool of indices for potentially overlapping clusters - std::vector mOverlapClusRef; // 1st entry in mOverlapCandidateID for the overlapping cluster indices of each cluster + o2::itsmft::ClustersPerLayer mITSClustersArray; + std::vector mOverlapCandidateID; // pool of composed IDs of the potentially overlapping clusters + std::vector mOverlapClusRef; // 1st entry in mOverlapCandidateID for the overlapping clusters of each cluster, indexed by the flat cluster index std::vector mOverlaps; const o2::itsmft::TopologyDictionary* mITSDict{nullptr}; // cluster patterns dictionary // diff --git a/Detectors/Align/src/AlignableDetectorITS.cxx b/Detectors/Align/src/AlignableDetectorITS.cxx index 7387ae4620bf3..1528102369ec8 100644 --- a/Detectors/Align/src/AlignableDetectorITS.cxx +++ b/Detectors/Align/src/AlignableDetectorITS.cxx @@ -219,7 +219,7 @@ int AlignableDetectorITS::processPoints(GIndex gid, int npntCut, bool inv) if (clus.getCount()) { // there is an overlap, find best matching cluster nOverlaps--; - int bestClusID = -1, clusIDtoCheck = mOverlapClusRef[clusIDs[icl]]; + int bestClusID = -1, clusIDtoCheck = mOverlapClusRef[mITSClustersArray.flatIndex(clusIDs[icl])]; float bestChi2 = algConf.ITSOverlapMaxChi2; auto trPropOvl = trcProp; for (int iov = 0; iov < clus.getCount(); iov++) { @@ -256,18 +256,11 @@ bool AlignableDetectorITS::prepareDetectorData() // prepare TF data for processing: convert clusters const auto& algConf = AlignConfig::Instance(); auto recoData = mController->getRecoContainer(); - const auto clusITS = recoData->getITSClusters(); - const auto clusITSROF = recoData->getITSClustersROFRecords(); - const auto patterns = recoData->getITSClustersPatterns(); - auto pattIt = patterns.begin(); - mITSClustersArray.clear(); - mITSClustersArray.reserve(clusITS.size()); + int nLr = recoData->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITSClustersArray.init(nLr); if (algConf.ITSOverlapMargin > 0) { mOverlapClusRef.clear(); - mOverlapClusRef.resize(clusITS.size(), -1); - mOverlapCandidateID.clear(); - mOverlapCandidateID.reserve(clusITS.size()); } static std::vector edgeClusters; int ROFCount = 0; @@ -278,103 +271,118 @@ bool AlignableDetectorITS::prepareDetectorData() }; std::array chipROFStart{}; // fill only for clusters with overlaps - for (const auto& rof : clusITSROF) { - int maxic = rof.getFirstEntry() + rof.getNEntries(); - edgeClusters.clear(); - for (int ic = rof.getFirstEntry(); ic < maxic; ic++) { - const auto& c = clusITS[ic]; - int16_t sensID = c.getSensorID(); - auto* sensor = getSensor(sensID); - double sigmaY2, sigmaZ2, sigmaYZ = 0, locXYZC[3], traXYZ[3]; - auto pattItCopy = pattIt; - auto locXYZ = o2::its::ioutils::extractClusterDataA(c, pattIt, mITSDict, sigmaY2, sigmaZ2); // local ideal coordinates - const auto& matAlg = sensor->getMatrixClAlg(); // local alignment matrix !!! RS FIXME - matAlg.LocalToMaster(locXYZ.data(), locXYZC); // aligned point in the local frame - const auto& mat = sensor->getMatrixT2L(); // RS FIXME check if correct - mat.MasterToLocal(locXYZC, traXYZ); - auto& cl3d = mITSClustersArray.emplace_back(sensID, traXYZ[0], traXYZ[1], traXYZ[2], sigmaY2, sigmaZ2, sigmaYZ); // local --> tracking + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITSClustersArray.beginLayer(lr); + const auto clusITS = recoData->getITSClusters(lr); + const auto clusITSROF = recoData->getITSClustersROFRecords(lr); + const auto patterns = recoData->getITSClustersPatterns(lr); + auto pattIt = patterns.begin(); + const int clOffs = mITSClustersArray.getFirstIndex(lr); // flat index of the 1st cluster of this layer slot + mITSClustersArray.getClusters().reserve(clOffs + clusITS.size()); + if (algConf.ITSOverlapMargin > 0) { + mOverlapClusRef.resize(clOffs + clusITS.size(), -1); + mOverlapCandidateID.reserve(clOffs + clusITS.size()); + } + + for (const auto& rof : clusITSROF) { + int maxic = rof.getFirstEntry() + rof.getNEntries(); + edgeClusters.clear(); + for (int ic = rof.getFirstEntry(); ic < maxic; ic++) { + const auto& c = clusITS[ic]; + int16_t sensID = c.getSensorID(); + auto* sensor = getSensor(sensID); + double sigmaY2, sigmaZ2, sigmaYZ = 0, locXYZC[3], traXYZ[3]; + auto pattItCopy = pattIt; + auto locXYZ = o2::its::ioutils::extractClusterDataA(c, pattIt, mITSDict, sigmaY2, sigmaZ2); // local ideal coordinates + const auto& matAlg = sensor->getMatrixClAlg(); // local alignment matrix !!! RS FIXME + matAlg.LocalToMaster(locXYZ.data(), locXYZC); // aligned point in the local frame + const auto& mat = sensor->getMatrixT2L(); // RS FIXME check if correct + mat.MasterToLocal(locXYZC, traXYZ); + auto& cl3d = mITSClustersArray.getClusters().emplace_back(sensID, traXYZ[0], traXYZ[1], traXYZ[2], sigmaY2, sigmaZ2, sigmaYZ); // local --> tracking - if (algConf.ITSOverlapMargin > 0) { - // fill chips overlaps info for clusters whose center is within of the algConf.ITSOverlapMargin distance from the chip min or max row edge - // but the pixel closest to this edge has distance of at least algConf.ITSOverlapEdgeRows from the edge - int row = 0, col = 0; - o2::itsmft::SegmentationAlpide::localToDetectorUnchecked(locXYZ[0], locXYZ[2], row, col); - int drow = row < o2::itsmft::SegmentationAlpide::NRows / 2 ? row : o2::itsmft::SegmentationAlpide::NRows - row - 1; // distance to the edge - if (drow * o2::itsmft::SegmentationAlpide::PitchRow < algConf.ITSOverlapMargin) { // rough check is passed, check if the edge cluster is indeed good - cl3d.setBit(row < o2::itsmft::SegmentationAlpide::NRows / 2 ? EdgeFlags::LowRow : EdgeFlags::HighRow); // flag that this is an edge cluster and indicate the low/high row side - // check if it is not too close to the edge (to be biased) - if (algConf.ITSOverlapEdgeRows > 0) { // is there a restriction? - auto pattID = c.getPatternID(); - drow = c.getRow(); - if (pattID != itsmft::CompCluster::InvalidPatternID) { - if (!mITSDict->isGroup(pattID)) { - const auto& patt = mITSDict->getPattern(pattID); // reference pixel is min row/col corner + if (algConf.ITSOverlapMargin > 0) { + // fill chips overlaps info for clusters whose center is within of the algConf.ITSOverlapMargin distance from the chip min or max row edge + // but the pixel closest to this edge has distance of at least algConf.ITSOverlapEdgeRows from the edge + int row = 0, col = 0; + o2::itsmft::SegmentationAlpide::localToDetectorUnchecked(locXYZ[0], locXYZ[2], row, col); + int drow = row < o2::itsmft::SegmentationAlpide::NRows / 2 ? row : o2::itsmft::SegmentationAlpide::NRows - row - 1; // distance to the edge + if (drow * o2::itsmft::SegmentationAlpide::PitchRow < algConf.ITSOverlapMargin) { // rough check is passed, check if the edge cluster is indeed good + cl3d.setBit(row < o2::itsmft::SegmentationAlpide::NRows / 2 ? EdgeFlags::LowRow : EdgeFlags::HighRow); // flag that this is an edge cluster and indicate the low/high row side + // check if it is not too close to the edge (to be biased) + if (algConf.ITSOverlapEdgeRows > 0) { // is there a restriction? + auto pattID = c.getPatternID(); + drow = c.getRow(); + if (pattID != itsmft::CompCluster::InvalidPatternID) { + if (!mITSDict->isGroup(pattID)) { + const auto& patt = mITSDict->getPattern(pattID); // reference pixel is min row/col corner + if (row > o2::itsmft::SegmentationAlpide::NRows / 2) { + drow = o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() - 1); + } + } else { // group: reference pixel is the one containing the COG + o2::itsmft::ClusterPattern patt(pattItCopy); + drow = row < o2::itsmft::SegmentationAlpide::NRows / 2 ? drow - patt.getRowSpan() / 2 : o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() / 2 - 1); + } + } else { + o2::itsmft::ClusterPattern patt(pattItCopy); // reference pixel is min row/col corner if (row > o2::itsmft::SegmentationAlpide::NRows / 2) { drow = o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() - 1); } - } else { // group: reference pixel is the one containing the COG - o2::itsmft::ClusterPattern patt(pattItCopy); - drow = row < o2::itsmft::SegmentationAlpide::NRows / 2 ? drow - patt.getRowSpan() / 2 : o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() / 2 - 1); } - } else { - o2::itsmft::ClusterPattern patt(pattItCopy); // reference pixel is min row/col corner - if (row > o2::itsmft::SegmentationAlpide::NRows / 2) { - drow = o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() - 1); + if (drow < algConf.ITSOverlapEdgeRows) { // too close to the edge, flag this + cl3d.setBit(EdgeFlags::Biased); } } - if (drow < algConf.ITSOverlapEdgeRows) { // too close to the edge, flag this - cl3d.setBit(EdgeFlags::Biased); - } - } - if (!cl3d.isBitSet(EdgeFlags::Biased)) { - if (chipROFStart[sensID].rofCount != ROFCount) { // remember 1st entry - chipROFStart[sensID].rofCount = ROFCount; - chipROFStart[sensID].chipFirstEntry = edgeClusters.size(); // remember 1st entry of edge cluster for this chip + if (!cl3d.isBitSet(EdgeFlags::Biased)) { + if (chipROFStart[sensID].rofCount != ROFCount) { // remember 1st entry + chipROFStart[sensID].rofCount = ROFCount; + chipROFStart[sensID].chipFirstEntry = edgeClusters.size(); // remember 1st entry of edge cluster for this chip + } + edgeClusters.push_back(clOffs + ic); } - edgeClusters.push_back(ic); } } - } - } // clusters of ROF - // relate edge clusters of ROF to each other - int prevSensID = -1; - for (auto ic : edgeClusters) { - auto& cl = mITSClustersArray[ic]; - int sensID = cl.getSensorID(); - auto ovl = mOverlaps[sensID]; - int ovlCount = 0; - for (int ir = 0; ir < OVL::NSides; ir++) { - if (ovl.rowSide[ir] == OVL::NONE) { // no overlap from this row side - continue; - } - int chipOvl = ovl.rowSide[ir]; // look for overlaps with this chip - // are there clusters with overlaps on chipOvl? - if (chipROFStart[chipOvl].rofCount == ROFCount) { - auto oClusID = edgeClusters[chipROFStart[chipOvl].chipFirstEntry]; - while (oClusID < int(mITSClustersArray.size())) { - auto oClus = mITSClustersArray[oClusID]; - if (oClus.getSensorID() != sensID) { - break; // no more clusters on the overlapping chip - } - if (oClus.isBitSet(ovl.rowSideOverlap[ir]) && // make sure that the edge cluster is on the right side of the row - !oClus.isBitSet(EdgeFlags::Biased) && // not too close to the edge - std::abs(oClus.getZ() - cl.getZ()) < algConf.ITSOverlapMaxDZ) { // apply fiducial cut on Z distance of 2 clusters - // register overlaping cluster - if (!ovlCount) { // 1st overlap - mOverlapClusRef[ic] = mOverlapCandidateID.size(); + } // clusters of ROF + // relate edge clusters of ROF to each other + int prevSensID = -1; + for (auto ic : edgeClusters) { // ic is the flat cluster index here + auto& cl = mITSClustersArray.getClusters()[ic]; + int sensID = cl.getSensorID(); + auto ovl = mOverlaps[sensID]; + int ovlCount = 0; + for (int ir = 0; ir < OVL::NSides; ir++) { + if (ovl.rowSide[ir] == OVL::NONE) { // no overlap from this row side + continue; + } + int chipOvl = ovl.rowSide[ir]; // look for overlaps with this chip + // are there clusters with overlaps on chipOvl? + if (chipROFStart[chipOvl].rofCount == ROFCount) { + auto oClusID = edgeClusters[chipROFStart[chipOvl].chipFirstEntry]; + while (oClusID < int(mITSClustersArray.size())) { + auto oClus = mITSClustersArray.getClusters()[oClusID]; + if (oClus.getSensorID() != sensID) { + break; // no more clusters on the overlapping chip } - mOverlapCandidateID.push_back(oClusID); - ovlCount++; + if (oClus.isBitSet(ovl.rowSideOverlap[ir]) && // make sure that the edge cluster is on the right side of the row + !oClus.isBitSet(EdgeFlags::Biased) && // not too close to the edge + std::abs(oClus.getZ() - cl.getZ()) < algConf.ITSOverlapMaxDZ) { // apply fiducial cut on Z distance of 2 clusters + // register overlaping cluster + if (!ovlCount) { // 1st overlap + mOverlapClusRef[ic] = mOverlapCandidateID.size(); + } + mOverlapCandidateID.push_back(o2::itsmft::composeClusID(lr, oClusID - clOffs)); // store the composed ID + ovlCount++; + } + oClusID++; } - oClusID++; } } + cl.setCount(std::min(127, ovlCount)); } - cl.setCount(std::min(127, ovlCount)); - } - ROFCount++; - } // loop over ROFs + ROFCount++; + } // loop over ROFs + } // loop over the layer slots + mITSClustersArray.finalize(); return true; } diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h index 896351f7baa06..28cf1ab846412 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchCosmics.h @@ -23,6 +23,7 @@ #include "ReconstructionDataFormats/GlobalTrackAccessor.h" #include "ReconstructionDataFormats/BaseCluster.h" #include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "SimulationDataFormat/MCCompLabel.h" #include "GlobalTracking/MatchCosmicsParams.h" #include "CommonUtils/TreeStreamRedirector.h" @@ -134,7 +135,7 @@ class MatchCosmics bool validateMatch(int partner0); void selectWinners(); void refitWinners(const o2::globaltracking::RecoContainer& data); - std::vector> prepareITSClusters(const o2::globaltracking::RecoContainer& data) const; + o2::itsmft::ClustersPerLayer> prepareITSClusters(const o2::globaltracking::RecoContainer& data) const; std::vector mSeeds; std::vector mRecords; diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index e736f0c9c8a42..177c2eec4d137 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -34,6 +34,7 @@ #include "ReconstructionDataFormats/GlobalTrackID.h" #include "MathUtils/Primitive2D.h" #include "CommonDataFormat/EvIndex.h" +#include #include "CommonDataFormat/InteractionRecord.h" #include "CommonDataFormat/RangeReference.h" #include "CommonDataFormat/BunchFilling.h" @@ -42,6 +43,7 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "DataFormatsITSMFT/Cluster.h" #include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DataFormatsITS/TrackITS.h" #include "DataFormatsFT0/RecPoints.h" #include "FT0Reconstruction/InteractionTag.h" @@ -53,6 +55,7 @@ #include "GlobalTracking/MatchTPCITSParams.h" #include "DataFormatsITSMFT/TopologyDictionary.h" #include "DataFormatsITSMFT/TrkClusRef.h" +#include "DataFormatsITSMFT/ClusterID.h" #include "ITSMFTReconstruction/ChipMappingITS.h" #include "TPCFastTransformPOD.h" #if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) @@ -107,6 +110,9 @@ constexpr int MinusOne = -1; constexpr int MinusTen = -10; constexpr int Validated = -2; +///< per-layer status of ITS clusters (e.g. for the AfterBurner) +using ITSClusStatus = std::array, o2::its::RecoGeomHelper::getNLayers()>; + ///< flags to tell the status of TPC-ITS tracks comparison enum TrackRejFlag : int { Accept = 0, @@ -264,25 +270,25 @@ struct TPCABSeed { { return lowestLayer < o2::its::RecoGeomHelper::getNLayers() ? firstInLr[lowestLayer] : -1; } - bool checkLinkHasUsedClusters(int linkID, const std::vector& clStatus) const + bool checkLinkHasUsedClusters(int linkID, const ITSClusStatus& clStatus) const { // check if some clusters used by the link or its parents are forbidden (already used by validatet track) while (linkID > MinusOne) { const auto& link = getLink(linkID); - if (link.clID > MinusOne && clStatus[link.clID] != MinusOne) { + if (link.clID > MinusOne && clStatus[o2::itsmft::clusID2Layer(link.clID)][o2::itsmft::clusID2Index(link.clID)] != MinusOne) { return true; } linkID = link.parentID; } return false; } - void flagLinkUsedClusters(int linkID, std::vector& clStatus) const + void flagLinkUsedClusters(int linkID, ITSClusStatus& clStatus) const { // check if some clusters used by the link or its parents are forbidden (already used by validated track) while (linkID > MinusOne) { const auto& link = getLink(linkID); if (link.clID > MinusOne) { - clStatus[link.clID] = MinusTen; + clStatus[o2::itsmft::clusID2Layer(link.clID)][o2::itsmft::clusID2Index(link.clID)] = MinusTen; } linkID = link.parentID; } @@ -293,40 +299,59 @@ struct TPCABSeed { struct InteractionCandidate : public o2::InteractionRecord { o2::math_utils::Bracketf_t tBracket; // interaction time - int rofITS; // corresponding ITS ROF entry (in the ROFRecord vectors) + int rofITS; // corresponding ITS clock-layer cluster ROF entry (in the ROFRecord vectors) uint32_t flag; // origin, etc. o2::dataformats::RangeReference seedsRef; // references to AB seeds - InteractionCandidate(const o2::InteractionRecord& ir, float t, float dt, int rof, uint32_t f = 0) : o2::InteractionRecord(ir), tBracket(t - dt, t + dt), rofITS(rof), flag(f) {} -}; - -struct ITSChipClustersRefs { - ///< contaner for sorted cluster indices for certain time window (usually ROF) and reference on the start and N clusters - ///< for every chip - using ClusRange = o2::dataformats::RangeReference; - std::vector clusterID; // indices of sorted clusters - -#ifndef ENABLE_UPGRADES - std::array chipRefs; // offset and number of clusters in each chip - ITSChipClustersRefs(int nclIni = 50000) - { - clusterID.reserve(nclIni); - } -#else - std::vector chipRefs; // offset and number of clusters in each chip - ITSChipClustersRefs(int nchips = o2::its::RecoGeomHelper::getNChips(), int nclIni = 50000) + std::array rofLr; // per ITS layer: cluster ROF entry compatible with the candidate time, -1: none + uint8_t rofNextLr = 0; // bit lr set: the candidate time is compatible also with the ROF rofLr[lr]+1 of the layer + InteractionCandidate(const o2::InteractionRecord& ir, float t, float dt, int rof, uint32_t f = 0) : o2::InteractionRecord(ir), tBracket(t - dt, t + dt), rofITS(rof), flag(f) { - clusterID.reserve(nclIni); - chipRefs.resize(nchips, ClusRange()); + rofLr.fill(MinusOne); } -#endif +}; + +struct ABClusterInfo { + ///< compact info on an ITS cluster usable by the AfterBurner + float y = 0.f, z = 0.f; ///< Y, Z of the cluster in the tracking frame of its sensor + int id = MinusOne; ///< composed cluster ID, see o2::itsmft::composeClusID + int chip = -1; ///< global chip (sensor) ID +}; +struct ABLayerClusters { + ///< clusters of one ITS layer usable by the AfterBurner (not attached to ITS tracks), stored in per-ROF + ///< blocks sorted in (chip, Z). Only the blocks (ROFs) referenced by some interaction candidate are built. + using ClusRange = o2::dataformats::RangeReference; + std::vector rofTimes; ///< time brackets of all cluster ROFs of the layer + std::vector rofRefs; ///< block of every ROF in the clus vector, firstEntry < 0 if the block was not built + std::vector clus; ///< clusters of the built blocks + std::vector needROF; ///< scratch buffer: blocks to build for the current TF void clear() { - clusterID.clear(); - std::memset(chipRefs.data(), 0, chipRefs.size() * sizeof(ClusRange)); // reset chip->cluster references + rofTimes.clear(); + rofRefs.clear(); + clus.clear(); + needROF.clear(); } - size_t sizeInternal() const { return sizeof(int) * clusterID.size(); } - size_t capInternal() const { return sizeof(int) * clusterID.capacity(); } + size_t sizeInternal() const { return sizeof(ABClusterInfo) * clus.size() + sizeof(o2::math_utils::Bracketf_t) * rofTimes.size() + sizeof(ClusRange) * rofRefs.size() + needROF.size(); } + size_t capInternal() const { return sizeof(ABClusterInfo) * clus.capacity() + sizeof(o2::math_utils::Bracketf_t) * rofTimes.capacity() + sizeof(ClusRange) * rofRefs.capacity() + needROF.capacity(); } +}; + +struct ABLayerView { + ///< thread-local view of the ABLayerClusters block(s) covering the time of the interaction candidate being processed + using ClusRange = o2::dataformats::RangeReference; + int rofKey = -2; ///< 1st ROF of the loaded block(s): -1: no compatible ROF, -2: nothing loaded yet + int nROFsKey = 0; ///< number of consecutive ROFs loaded (1 or 2) + int chipOffs = 0; ///< global ID of the 1st chip of the layer + int nData = 0; ///< number of clusters in the view + const ABClusterInfo* data = nullptr; ///< clusters of the loaded block(s), sorted in (chip, Z) + std::vector chipRefs; ///< cluster range in data for every chip of the layer + std::vector touchedChips; ///< chips with non-empty chipRefs, for fast reset + std::vector merged; ///< buffer to merge 2 blocks when the candidate time is compatible with 2 ROFs +}; + +struct ABThreadClusterViews { + ///< per-thread views of the AB clusters of all layers + std::array layers; }; class MatchTPCITS @@ -340,6 +365,7 @@ class MatchTPCITS using Params = o2::globaltracking::MatchTPCITSParams; using MatCorrType = o2::base::Propagator::MatCorrType; using VDTriplet = o2::dataformats::Triplet; + using AlpParamITS = o2::itsmft::DPLAlpideParam; MatchTPCITS(); // std::unique_ptr to forward declared type needs constructor / destructor in .cxx ~MatchTPCITS(); @@ -348,6 +374,8 @@ class MatchTPCITS static constexpr int MaxLadderCand = 2 * MaxUpDnLadders + 1; // max ladders to check for matching clusters static constexpr int MaxSeedsPerLayer = 50; // TODO static constexpr int NITSLayers = o2::its::RecoGeomHelper::getNLayers(); + static_assert(NITSLayers == AlpParamITS::getNLayers(), "ITS layers count mismatch between geometry helper and DPLAlpideParam"); + static_assert(NITSLayers == o2::itsmft::MaxITSClusLayers, "ITS layers count mismatch between geometry helper and the composed cluster ID encoding"); ///< perform matching for provided input #if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) void run(const o2::globaltracking::RecoContainer& inp, @@ -394,7 +422,13 @@ class MatchTPCITS void setNHBPerTF(int n) { mNHBPerTF = n; } ///< ITS readout mode - void setITSTriggered(bool v) { mITSTriggered = v; } + void setITSTriggered(bool v) + { + mITSTriggered = v; + if (mAlpParams) { // the ROF length depends on the readout mode + setAlpideParam(mAlpParams); + } + } bool isITSTriggered() const { return mITSTriggered; } void setUseFT0(bool v) { mUseFT0 = v; } @@ -403,14 +437,29 @@ class MatchTPCITS void setUseBCFilling(bool v) { mUseBCFilling = v; } bool getUseBCFilling() const { return mUseBCFilling; } - ///< set ITS ROFrame duration in microseconds - void setITSROFrameLengthMUS(float fums); - ///< set ITS ROFrame duration in BC (continuous mode only) - void setITSROFrameLengthInBC(int nbc); - - void setITSTimeBiasInBC(int n); - int getITSTimeBiasInBC() const { return mITSTimeBiasInBC; } - float getITSTimeBiasMUS() const { return mITSTimeBiasMUS; } + ///< set ITS Alpide parameters: all per-layer ITS ROF lengths, biases and the clock layer + ///< are derived from them, no other ITS timing setter is needed. Can be called in any order + ///< wrt setITSTriggered(). + void setAlpideParam(const AlpParamITS* p); + const AlpParamITS* getAlpideParam() const { return mAlpParams; } + + ///< layer whose ROF defines the granularity of the ITS tracks ROFRecords (0 if all layers share the same ROF) + int getITSClockLayer() const { return mITSClockLayer; } + + ///< per-layer ITS ROF length and bias, always defined for all NITSLayers + int getITSROFrameLengthInBC(int lr) const { return mITSROFrameLengthInBC[lr]; } + float getITSROFrameLengthMUS(int lr) const { return mITSROFrameLengthMUS[lr]; } + float getITSROFrameLengthMUSInv(int lr) const { return mITSROFrameLengthMUSInv[lr]; } + float getITSTimeResMUS(int lr) const { return mITSTimeResMUS[lr]; } + int getITSTimeBiasInBC(int lr) const { return mITSTimeBiasInBC[lr]; } + float getITSTimeBiasMUS(int lr) const { return mITSTimeBiasMUS[lr]; } + + ///< time bracket (wrt TF start) of the ROF starting at nBC of the given layer + BracketF getITSROFTimeBracket(long nBC, int lr) const + { + float tMin = (nBC + mITSTimeBiasInBC[lr]) * o2::constants::lhc::LHCBunchSpacingMUS; + return {tMin, tMin + mITSROFrameLengthMUS[lr]}; + } // ==================== >> DPL-driven input >> ======================= void setITSDictionary(const o2::itsmft::TopologyDictionary* d) { mITSDict = d; } @@ -493,9 +542,8 @@ class MatchTPCITS int prepareTPCTracksAfterBurner(); int addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float terr, o2::dataformats::GlobalTrackID srcGID, int tpcID); - int preselectChipClusters(std::vector& clVecOut, const ClusRange& clRange, const ITSChipClustersRefs& itsChipClRefs, + int preselectChipClusters(std::vector& clVecOut, const ClusRange& clRange, const ABLayerView& clView, float trackY, float trackZ, float tolerY, float tolerZ) const; - void fillClustersForAfterBurner(int rofStart, int nROFs, ITSChipClustersRefs& itsChipClRefs); void flagUsedITSClusters(const o2::its::TrackITS& track); void doMatching(int sec); @@ -533,7 +581,7 @@ class MatchTPCITS ///< convert time to ITS ROFrame units in case of continuous ITS readout int time2ITSROFrameCont(float t) const { - int rof = (t - mITSTimeBiasMUS) * mITSROFrameLengthMUSInv; + int rof = (t - mITSTimeBiasMUS[mITSClockLayer]) * mITSROFrameLengthMUSInv[mITSClockLayer]; if (rof < 0) { rof = 0; } @@ -544,7 +592,7 @@ class MatchTPCITS ///< convert time to ITS ROFrame units in case of triggered ITS readout int time2ITSROFrameTrig(float t, int start) const { - t -= mITSTimeBiasMUS; + t -= mITSTimeBiasMUS[mITSClockLayer]; while (start < int(mITSROFTimes.size())) { if (mITSROFTimes[start].getMax() > t) { return start; @@ -575,10 +623,17 @@ class MatchTPCITS return delta > toler ? rejFlag : (delta < -toler ? -rejFlag : Accept); } + const ITSCluster& getITSCluster(int composedID) const + { + return mITSClustersArray[o2::itsmft::clusID2Layer(composedID)][o2::itsmft::clusID2Index(composedID)]; + } + // ========================= AFTERBURNER ========================= int prepareABSeeds(); - void processABSeed(int sid, const ITSChipClustersRefs& itsChipClRefs, uint8_t tID); - int followABSeed(const o2::track::TrackParCov& seed, const ITSChipClustersRefs& itsChipClRefs, int seedID, int lrID, TPCABSeed& ABSeed); + void prepareABClusters(); + void updateABLayerView(ABLayerView& view, int lr, int rof, int nROFs) const; + void processABSeed(int sid, const ABThreadClusterViews& itsClViews, uint8_t tID); + int followABSeed(const o2::track::TrackParCov& seed, const ABLayerView& clView, int seedID, int lrID, TPCABSeed& ABSeed); int registerABTrackLink(TPCABSeed& ABSeed, const o2::track::TrackParCov& trc, int clID, int parentID, int lr, int laddID, float chi2Cl); bool isBetter(float chi2A, float chi2B) { return chi2A < chi2B; } // RS FIMXE TODO void accountForOverlapsAB(int lrSeed); @@ -600,6 +655,7 @@ class MatchTPCITS ///========== Parameters to be set externally, e.g. from CCDB ==================== const Params* mParams = nullptr; const o2::ft0::InteractionTag* mFT0Params = nullptr; + const AlpParamITS* mAlpParams = nullptr; ///< ITS Alpide parameters, set externally MatCorrType mUseMatCorrFlag = MatCorrType::USEMatCorrTGeo; bool mUseBCFilling = false; ///< use BC filling for candidates validation @@ -618,12 +674,15 @@ class MatchTPCITS ///< assigned time0 and its track Z position (converted from mTPCTimeEdgeZSafeMargin) float mTPCTimeEdgeTSafeMargin = 0.f; float mTPCExtConstrainedNSigmaInv = 0.f; // inverse for NSigmas for TPC time-interval from external constraint time sigma - int mITSROFrameLengthInBC = 0; ///< ITS RO frame in BC (for ITS cont. mode only) - float mITSROFrameLengthMUS = -1.; ///< ITS RO frame in \mus - float mITSTimeResMUS = -1.; ///< nominal ITS time resolution derived from ROF - float mITSROFrameLengthMUSInv = -1.; ///< ITS RO frame in \mus inverse - int mITSTimeBiasInBC = 0; ///< ITS RO frame shift in BCs, i.e. t_i = (I_ROF*mITSROFrameLengthInBC + mITSTimeBiasInBC)*BCLength_MUS - float mITSTimeBiasMUS = 0.; ///< ITS RO frame shift in \mus, i.e. t_i = (I_ROF*mITSROFrameLengthInBC)*BCLength_MUS + mITSTimeBiasMUS + ///< ITS ROF timings, always filled for all NITSLayers, also when all layers share the same ROF. + ///< t_i(lr) = (I_ROF*mITSROFrameLengthInBC[lr] + mITSTimeBiasInBC[lr])*BCLength_MUS + int mITSClockLayer = 0; ///< layer defining the ITS tracks ROFRecords granularity + std::array mITSROFrameLengthInBC{}; ///< ITS RO frame in BC per layer (cont. mode only) + std::array mITSROFrameLengthMUS{}; ///< ITS RO frame in \mus per layer + std::array mITSROFrameLengthMUSInv{}; ///< inverse ITS RO frame in \mus per layer + std::array mITSTimeResMUS{}; ///< nominal ITS time resolution derived from per-layer ROF + std::array mITSTimeBiasInBC{}; ///< ITS RO frame shift in BC per layer + std::array mITSTimeBiasMUS{}; ///< ITS RO frame shift in \mus per layer float mTPCVDrift = -1.; ///< TPC drift speed in cm/microseconds float mTPCVDriftInv = -1.; ///< inverse TPC nominal drift speed in cm/microseconds float mTPCDriftTimeOffset = 0; ///< drift time offset in mus @@ -662,15 +721,14 @@ class MatchTPCITS gsl::span mITSTrackROFRec; ///< input ITS tracks ROFRecord span gsl::span mITSTracksArray; ///< input ITS tracks span gsl::span mITSTrackClusIdx; ///< input ITS track cluster indices span - std::vector mITSClustersArray; ///< ITS clusters created in loadInput - std::vector mITSClusterSizes; ///< ITS cluster sizes created in loadInput - - gsl::span mITSClusterROFRec; ///< input ITS clusters ROFRecord span + std::array, NITSLayers> mITSClustersArray{}; ///< ITS clusters created in loadInput + std::array, NITSLayers> mITSClusterSizes{}; ///< ITS cluster sizes created in loadInput + std::array, NITSLayers> mITSClusterROFRec; ///< input ITS clusters ROFRecord span + int mNITSClusters = 0; gsl::span mFITInfo; ///< optional input FIT info span gsl::span mTPCRefitterShMap; ///< externally set TPC clusters sharing map gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map - const o2::itsmft::TopologyDictionary* mITSDict{nullptr}; // cluster patterns dictionary #ifdef ENABLE_UPGRADES const o2::its3::TopologyDictionary* mIT3Dict{nullptr}; // cluster patterns dictionary @@ -678,7 +736,7 @@ class MatchTPCITS const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices - const o2::dataformats::MCTruthContainer* mITSClsLabels = nullptr; ///< input ITS Cluster MC labels + std::array*, NITSLayers> mITSClsLabels{}; ///< input ITS Cluster MC labels gsl::span mITSTrkLabels; ///< input ITS Track MC labels gsl::span mTPCTrkLabels; ///< input TPC Track MC labels /// <<<----- @@ -711,7 +769,13 @@ class MatchTPCITS ///< indices of selected track entries in mTPCWork (for tracks selected by AfterBurner) std::vector mTPCABIndexCache; std::vector mABWinnersIDs; - std::vector mABClusterLinkIndex; ///< index of 1st ABClusterLink for every cluster used by AfterBurner, -1: unused, -10: used by external ITS tracks + ///< per storage-slot status of ITS clusters wrt AfterBurner: -1: free, -10: used by an external ITS track or a validated AB track. + ///< The slot is the layer for per-layer clusters input, 0 for the monolithic one; only the slots used by the AfterBurner are booked + ITSClusStatus mABClusterStatus; + std::array mABLayerClusters; ///< per (layer, ROF) blocks of AB-usable clusters; filled for the AB layers and the ROF times also for the clock layer + std::array mABChipsBounds{}; ///< the layer lr owns the global chip IDs [mABChipsBounds[lr], mABChipsBounds[lr+1]) + float mABROFMarginMUS = 0.f; ///< effective margin for candidate time to ITS ROF matching: abROFMarginMUS clamped to below half of the shortest AB layer ROF + float mITSMaxROFOverhangMUS = 0.f; ///< max excess of ITS track time brackets over the end of their clock-layer ROF in the current TF LinksPoolMT mABLinksPool; ///< per sector indices of TPC track entry in mTPCWork diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h index 3ec189deff54b..a45b8e135a20a 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h @@ -85,6 +85,8 @@ struct MatchTPCITSParams : public o2::conf::ConfigurableParamHelper> MatchCosmics::prepareITSClusters(const o2::globaltracking::RecoContainer& data) const +o2::itsmft::ClustersPerLayer> MatchCosmics::prepareITSClusters(const o2::globaltracking::RecoContainer& data) const { - std::vector> itscl; - const auto& clusITS = data.getITSClusters(); - if (clusITS.size()) { - const auto& patterns = data.getITSClustersPatterns(); - itscl.reserve(clusITS.size()); - auto pattIt = patterns.begin(); - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, itscl, mITSDict); + o2::itsmft::ClustersPerLayer> itscl; + int nLr = data.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + itscl.init(nLr); + for (int lr = 0; lr < nLr; lr++) { + itscl.beginLayer(lr); + const auto& clusITS = data.getITSClusters(lr); + if (clusITS.size()) { + auto pattIt = data.getITSClustersPatterns(lr).begin(); + itscl.getClusters().reserve(itscl.size() + clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, itscl.getClusters(), mITSDict); + } } - return std::move(itscl); + itscl.finalize(); + return itscl; } //______________________________________________ diff --git a/Detectors/GlobalTracking/src/MatchTPCITS.cxx b/Detectors/GlobalTracking/src/MatchTPCITS.cxx index cc7adfc399785..6d2a8fcb691c3 100644 --- a/Detectors/GlobalTracking/src/MatchTPCITS.cxx +++ b/Detectors/GlobalTracking/src/MatchTPCITS.cxx @@ -172,12 +172,19 @@ void MatchTPCITS::clear() mInteractions.clear(); mITSROFTimes.clear(); mITSTrackROFContMapping.clear(); - mITSClustersArray.clear(); - mITSClusterSizes.clear(); + for (int lr = 0; lr < NITSLayers; lr++) { + mITSClustersArray[lr].clear(); + mITSClusterSizes[lr].clear(); + } mTPCABSeeds.clear(); mTPCABIndexCache.clear(); mABWinnersIDs.clear(); - mABClusterLinkIndex.clear(); + for (auto& clStatus : mABClusterStatus) { + clStatus.clear(); + } + for (auto& abClus : mABLayerClusters) { + abClus.clear(); + } mNMatchesControl = 0; for (int sec = o2::constants::math::NSectors; sec--;) { @@ -249,6 +256,13 @@ void MatchTPCITS::init() if (mParams->runAfterBurner) { // only used in AfterBurner mRGHelper.init(mParams->lowestLayerAB); // prepare helper for TPC track / ITS clusters matching } + { + const auto* geomITS = o2::its::GeometryTGeo::Instance(); + for (int lr = 0; lr < NITSLayers; lr++) { + mABChipsBounds[lr] = geomITS->getFirstChipIndex(lr); + } + mABChipsBounds[NITSLayers] = geomITS->getLastChipIndex(NITSLayers - 1) + 1; + } clear(); @@ -262,30 +276,53 @@ void MatchTPCITS::init() //______________________________________________ void MatchTPCITS::updateTimeDependentParams() { - ///< update parameters depending on time (once per TF) - auto& elParam = o2::tpc::ParameterElectronics::Instance(); - auto& detParam = o2::tpc::ParameterDetector::Instance(); - mTPCTBinMUS = elParam.ZbinWidth; - mTPCTBinNS = mTPCTBinMUS * 1e3; - mTPCZMax = detParam.TPClength; - mTPCTBinMUSInv = 1. / mTPCTBinMUS; - assert(mITSROFrameLengthMUS > 0.0f); + ///< update parameters depending on time (once per TF or beginning of run) + mBz = o2::base::Propagator::Instance()->getNominalBz(); + mFieldON = std::abs(mBz) > 0.01; + + static bool initOnceDone = false; + if (!initOnceDone) { + initOnceDone = true; + if (mParams->runAfterBurner) { + // margin for matching interaction candidate times to per-layer ITS ROFs in the AfterBurner: must stay + // below half of the shortest AB layer ROF length to guarantee at most 2 compatible ROFs per layer + float margin = std::max(0.f, mParams->abROFMarginMUS), marginMax = mITSROFrameLengthMUS[mParams->lowestLayerAB]; + for (int lr = mParams->lowestLayerAB + 1; lr < NITSLayers; lr++) { + if (mITSROFrameLengthMUS[lr] < marginMax) { + marginMax = mITSROFrameLengthMUS[lr]; + } + } + marginMax *= 0.45f; + if (margin > marginMax) { + if (mABROFMarginMUS != marginMax) { + LOGP(warn, "abROFMarginMUS={} exceeds 45% of the shortest AfterBurner layer ROF length, clamping to {}", margin, marginMax); + } + margin = marginMax; + } + mABROFMarginMUS = margin; + } + auto& elParam = o2::tpc::ParameterElectronics::Instance(); + auto& detParam = o2::tpc::ParameterDetector::Instance(); + mTPCTBinMUS = elParam.ZbinWidth; + mTPCTBinNS = mTPCTBinMUS * 1e3; + mTPCZMax = detParam.TPClength; + mTPCTBinMUSInv = 1. / mTPCTBinMUS; + assert(mITSROFrameLengthMUS[mITSClockLayer] > 0.0f); + + o2::math_utils::Point3D p0(90., 1., 1), p1(90., 100., 100.); + auto matbd = o2::base::Propagator::Instance()->getMatBudget(mParams->matCorr, p0, p1); + mTPCmeanX0Inv = matbd.meanX2X0 / matbd.length; + } mTPCBin2Z = mTPCTBinMUS * mTPCVDrift; mZ2TPCBin = 1. / mTPCBin2Z; mTPCVDriftInv = 1. / mTPCVDrift; mNTPCBinsFullDrift = mTPCZMax * mZ2TPCBin; mTPCTimeEdgeTSafeMargin = z2TPCBin(mParams->safeMarginTPCTimeEdge); mTPCExtConstrainedNSigmaInv = 1.f / mParams->tpcExtConstrainedNSigma; - mBz = o2::base::Propagator::Instance()->getNominalBz(); - mFieldON = std::abs(mBz) > 0.01; mMinTPCTrackPtInv = (mFieldON && mParams->minTPCTrackR > 0) ? 1. / std::abs(mParams->minTPCTrackR * mBz * o2::constants::math::B2C) : 999.; mMinITSTrackPtInv = (mFieldON && mParams->minITSTrackR > 0) ? 1. / std::abs(mParams->minITSTrackR * mBz * o2::constants::math::B2C) : 999.; - o2::math_utils::Point3D p0(90., 1., 1), p1(90., 100., 100.); - auto matbd = o2::base::Propagator::Instance()->getMatBudget(mParams->matCorr, p0, p1); - mTPCmeanX0Inv = matbd.meanX2X0 / matbd.length; - const auto& trackTune = TrackTuneParams::Instance(); float scale = mLumiCTP; if (scale < 0.f) { @@ -645,57 +682,83 @@ bool MatchTPCITS::prepareITSData() const auto& inp = *mRecoCont; // ITS clusters - mITSClusterROFRec = inp.getITSClustersROFRecords(); - const auto clusITS = inp.getITSClusters(); - if (mITSClusterROFRec.empty() || clusITS.empty()) { - LOG(info) << "No ITS clusters"; - return false; - } - const auto patterns = inp.getITSClustersPatterns(); - auto pattIt = patterns.begin(); - mITSClustersArray.reserve(clusITS.size()); + int nClLr = inp.getITSPerLayer() ? NITSLayers : 1; + mNITSClusters = 0; + for (int lr = 0; lr < nClLr; lr++) { + mITSClusterROFRec[lr] = inp.getITSClustersROFRecords(lr); + const auto clusITS = inp.getITSClusters(lr); + mNITSClusters += clusITS.size(); + const auto patterns = inp.getITSClustersPatterns(lr); + auto pattIt = patterns.begin(); + mITSClustersArray[lr].reserve(clusITS.size()); #ifdef ENABLE_UPGRADES - bool withITS3 = o2::GlobalParams::Instance().withITS3; - if (withITS3) { - o2::its3::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mIT3Dict); - } else { - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); - } + bool withITS3 = o2::GlobalParams::Instance().withITS3; + if (withITS3) { + o2::its3::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray[lr], mIT3Dict); + } else { + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray[lr], mITSDict); + } #else - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray[lr], mITSDict); #endif - - // ITS clusters sizes - mITSClusterSizes.reserve(clusITS.size()); - auto pattIt2 = patterns.begin(); - for (auto& clus : clusITS) { - auto pattID = clus.getPatternID(); - unsigned int npix; + // ITS clusters sizes + mITSClusterSizes[lr].reserve(clusITS.size()); + auto pattIt2 = patterns.begin(); + for (auto& clus : clusITS) { + auto pattID = clus.getPatternID(); + unsigned int npix; #ifdef ENABLE_UPGRADES - auto ib = o2::its3::constants::detID::isDetITS3(clus.getChipID()); - if ((pattID == o2::itsmft::CompCluster::InvalidPatternID) || ((withITS3) ? mIT3Dict->isGroup(pattID, ib) : mITSDict->isGroup(pattID))) { // braces guarantee evaluation order + auto ib = o2::its3::constants::detID::isDetITS3(clus.getChipID()); + if ((pattID == o2::itsmft::CompCluster::InvalidPatternID) || ((withITS3) ? mIT3Dict->isGroup(pattID, ib) : mITSDict->isGroup(pattID))) { // braces guarantee evaluation order #else - if (pattID == o2::itsmft::CompCluster::InvalidPatternID || mITSDict->isGroup(pattID)) { + if (pattID == o2::itsmft::CompCluster::InvalidPatternID || mITSDict->isGroup(pattID)) { #endif - o2::itsmft::ClusterPattern patt; - patt.acquirePattern(pattIt2); - npix = patt.getNPixels(); - } else { -#ifdef ENABLE_UPGRADES - if (withITS3) { - npix = mIT3Dict->getNpixels(pattID, ib); + o2::itsmft::ClusterPattern patt; + patt.acquirePattern(pattIt2); + npix = patt.getNPixels(); } else { - npix = mITSDict->getNpixels(pattID); - } +#ifdef ENABLE_UPGRADES + if (withITS3) { + npix = mIT3Dict->getNpixels(pattID, ib); + } else { + npix = mITSDict->getNpixels(pattID); + } #else - npix = mITSDict->getNpixels(pattID); + npix = mITSDict->getNpixels(pattID); #endif + } + mITSClusterSizes[lr].push_back(std::clamp(npix, 0u, 255u)); + } + if (mMCTruthON) { + mITSClsLabels[lr] = inp.getITSClustersMCLabels(lr); + } + } + if (!mNITSClusters) { + LOGP(warn, "No ITS clusters"); + return false; + } + // time brackets of the cluster ROFs: the clock-layer ones relate interaction candidates to ITS ROFs, + // the AfterBurner layers ones select the clusters compatible with the candidate time + for (int lr = 0; lr < NITSLayers; lr++) { + auto& abClus = mABLayerClusters[lr]; + abClus.clear(); + if (lr != mITSClockLayer && !(mParams->runAfterBurner && lr >= mParams->lowestLayerAB)) { + continue; + } + const auto& rofs = mITSClusterROFRec[inp.getITSPerLayer() ? lr : 0]; + abClus.rofTimes.reserve(rofs.size()); + for (const auto& rofRec : rofs) { + abClus.rofTimes.push_back(getITSROFTimeBracket(rofRec.getBCData().differenceInBC(mStartIR), lr)); } - mITSClusterSizes.push_back(std::clamp(npix, 0u, 255u)); } - if (mMCTruthON) { - mITSClsLabels = inp.getITSClustersMCLabels(); + // the AfterBurner uses only layers from mParams->lowestLayerAB, with single ITS clusters input all of them are in the slot 0 + if (inp.getITSPerLayer()) { + for (int lr = mParams->lowestLayerAB; lr < NITSLayers; lr++) { + mABClusterStatus[lr].resize(mITSClustersArray[lr].size(), MinusOne); + } + } else { + mABClusterStatus[0].resize(mITSClustersArray[0].size(), MinusOne); } // ITS tracks @@ -708,10 +771,6 @@ bool MatchTPCITS::prepareITSData() int nROFs = mITSTrackROFRec.size(); mITSWork.reserve(mITSTracksArray.size()); - // total N ITS clusters in TF - const auto& lastClROF = mITSClusterROFRec.back(); - int nITSClus = lastClROF.getFirstEntry() + lastClROF.getNEntries(); - mABClusterLinkIndex.resize(nITSClus, MinusOne); for (int sec = o2::constants::math::NSectors; sec--;) { mITSTimeStart[sec].resize(nROFs, -1); // start of ITS work tracks in every sector } @@ -719,6 +778,8 @@ bool MatchTPCITS::prepareITSData() long maxBCs = nHBF * long(o2::constants::lhc::LHCMaxBunches); o2::track::TrackLTIntegral trackLTInt; trackLTInt.setTimeNotNeeded(); + mITSMaxROFOverhangMUS = 0.f; + const float trackTimeMarginBC = std::max(0.f, mParams->itsTimeStampMarginBC); for (int irof = 0; irof < nROFs; irof++) { const auto& rofRec = mITSTrackROFRec[irof]; @@ -730,17 +791,17 @@ bool MatchTPCITS::prepareITSData() } break; } - float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS + mITSTimeBiasMUS; - float tMax = (nBC + mITSROFrameLengthInBC) * o2::constants::lhc::LHCBunchSpacingMUS + mITSTimeBiasMUS; + auto tBracket = getITSROFTimeBracket(nBC, mITSClockLayer); + float tMin = tBracket.getMin(), tMax = tBracket.getMax(); if (!mITSTriggered) { - size_t irofCont = nBC / mITSROFrameLengthInBC; + size_t irofCont = nBC / mITSROFrameLengthInBC[mITSClockLayer]; if (mITSTrackROFContMapping.size() <= irofCont) { // there might be gaps in the non-empty rofs, this will map continuous ROFs index to non empty ones mITSTrackROFContMapping.resize((1 + irofCont / 128) * 128, 0); } mITSTrackROFContMapping[irofCont] = irof; } - mITSROFTimes.emplace_back(tMin, tMax); // ITS ROF min/max time + mITSROFTimes.emplace_back(tMin, tMax); // nominal ITS ROF min/max time, to be extended to the envelope of the per-track time brackets for (int sec = o2::constants::math::NSectors; sec--;) { // start of sector's tracks for this ROF mITSTimeStart[sec][irof] = mITSSectIndexCache[sec].size(); // The sorting does not affect this @@ -758,9 +819,31 @@ bool MatchTPCITS::prepareITSData() if (std::abs(trcOrig.getQ2Pt()) > mMinITSTrackPtInv) { continue; } + // per-track time bracket from the tracker time stamp (bias-corrected BC since the TF start), + // widened by the itsTimeStampMarginBC safety margin; the nominal ROF bracket is used as a + // fallback when the time stamp is invalid (legacy input) + float tMinTrc = tMin, tMaxTrc = tMax; + const auto& tstamp = trcOrig.getTimeStamp(); + if (tstamp.getTimeStampError() > 0.f) { + // the tracker guarantees the raw lower edge of the time stamp to be within the assigned clock-layer ROF + assert(tstamp.getTimeStamp() - tstamp.getTimeStampError() >= nBC + mITSTimeBiasInBC[mITSClockLayer] - 0.5f); + float errBC = tstamp.getTimeStampError() + trackTimeMarginBC; + tMinTrc = (tstamp.getTimeStamp() - errBC) * o2::constants::lhc::LHCBunchSpacingMUS; + tMaxTrc = (tstamp.getTimeStamp() + errBC) * o2::constants::lhc::LHCBunchSpacingMUS; + auto& rofEnv = mITSROFTimes.back(); // extend the ROF envelope used by the TPC-side and triggered-mode entry caches + if (tMinTrc < rofEnv.getMin()) { + rofEnv.setMin(tMinTrc); + } + if (tMaxTrc > rofEnv.getMax()) { + rofEnv.setMax(tMaxTrc); + if (tMaxTrc - tMax > mITSMaxROFOverhangMUS) { + mITSMaxROFOverhangMUS = tMaxTrc - tMax; // max excess of the track brackets over their ROF end + } + } + } int nWorkTracks = mITSWork.size(); // working copy of outer track param - auto& trc = mITSWork.emplace_back(TrackLocITS{trcOrig.getParamOut(), {tMin, tMax}, it, irof, MinusOne}); + auto& trc = mITSWork.emplace_back(TrackLocITS{trcOrig.getParamOut(), {tMinTrc, tMaxTrc}, it, irof, MinusOne}); if (!trc.rotate(o2::math_utils::angle2Alpha(trc.getPhiPos()))) { mITSWork.pop_back(); // discard failed track continue; @@ -810,8 +893,10 @@ bool MatchTPCITS::prepareITSData() } } - // sort tracks in each sector according to their min time, then tgl - // RSTODO: sorting in tgl will be dangerous once the tracks with different time uncertaincies will be added + // Sort tracks in each sector according to their bracket min time (tgl serves only as a deterministic tie-break). + // Since the raw lower edge of every track time stamp is guaranteed to be within its clock-layer ROF and the + // safety margin shifts all tracks alike, the sorting cannot mix tracks of different ROFs, hence the + // mITSTimeStart entries assigned at the filling stage above remain valid. for (int sec = o2::constants::math::NSectors; sec--;) { auto& indexCache = mITSSectIndexCache[sec]; if (mParams->verbosity > 0) { @@ -834,7 +919,7 @@ bool MatchTPCITS::prepareITSData() mMatchRecordsITS.reserve(mITSWork.size() * mParams->maxMatchCandidates); mTimer[SWPrepITS].Stop(); - return nITSClus > 0; + return mNITSClusters > 0; } //_____________________________________________________ @@ -887,7 +972,9 @@ void MatchTPCITS::doMatching(int sec) // estimate ITS 1st ROframe bin this track may match to: TPC track are sorted according to their // timeMax, hence the timeMax - MaxmNTPCBinsFullDrift are non-decreasing auto tmn = trefTPC.tBracket.getMax() - maxTDriftSafe; - itsROBin = mITSTriggered ? time2ITSROFrameTrig(tmn, itsROBin) : time2ITSROFrameCont(tmn); + // in continuous mode the lookup time is decreased by the max excess of the ITS track brackets over their + // ROF end, since the mITSTimeStart binning is in ROF units while the brackets may extend beyond the ROF + itsROBin = mITSTriggered ? time2ITSROFrameTrig(tmn, itsROBin) : time2ITSROFrameCont(tmn - mITSMaxROFOverhangMUS); if (itsROBin >= int(timeStartITS.size())) { // time of TPC track exceeds the max time of ITS in the cache break; @@ -942,27 +1029,6 @@ void MatchTPCITS::doMatching(int sec) fillTPCITSmatchTree(cacheITS[iits], cacheTPC[itpc], rejFlag, chi2, timeCorr); } #endif - /* - // RS: this might be dangerous for ITS tracks with different time coverages. - if (rejFlag == RejectOnTgl) { - // ITS tracks in each ROFrame are ordered in Tgl, hence if this check failed on Tgl check - // (i.e. tgl_its>tgl_tpc+tolerance), then all other ITS tracks in this ROFrame will also have tgl too large. - // Jump on the 1st ITS track of the next ROFrame - int rof = trefITS.roFrame; - bool stop = false; - do { - if (++rof >= int(timeStartITS.size())) { - stop = true; - break; // no more ITS ROFrames in cache - } - iits = timeStartITS[rof] - 1; // next track to be checked -1 - } while (iits <= timeStartITS[trefITS.roFrame]); // skip empty bins - if (stop) { - break; - } - continue; - } - */ if (rejFlag != Accept) { continue; } @@ -1569,7 +1635,7 @@ void MatchTPCITS::fillCalibDebug(int ifit, int iTPC, const o2::dataformats::Trac (*mDBGOut) << "refit" << "multTPC=" << mltTPC << "multITSTr=" << mITSTrackROFRec[tITS.roFrame].getNEntries() - << "multITSCl=" << mITSClusterROFRec[tITS.roFrame].getNEntries() + << "multITSCl=" << mNITSClusters << "tf=" << mTFCount << "\n"; } #endif @@ -1599,8 +1665,9 @@ bool MatchTPCITS::refitTrackTPCITS(int slot, int iTPC, int& iITS, pmr::vector mITSTimeResMUS && tTPC.constraint != TrackLocTPC::Constrained) { - timeErr = mITSTimeResMUS; // chose smallest error + float itsTimeRes = tITS.tBracket.delta() / std::sqrt(12.f); // ITS time resolution from the track time-stamp bracket (uniform distribution) + if (timeErr > itsTimeRes && tTPC.constraint != TrackLocTPC::Constrained) { + timeErr = itsTimeRes; // chose smallest error deltaT = tTPC.constraint == TrackLocTPC::ASide ? tITS.tBracket.mean() - tTPC.time0 : tTPC.time0 - tITS.tBracket.mean(); } timeErr += mParams->globalTimeExtraErrorMUS; @@ -1638,7 +1705,7 @@ bool MatchTPCITS::refitTrackTPCITS(int slot, int iTPC, int& iITS, pmr::vectorgetSensorRefAlpha(clus.getSensorID()), x = clus.getX(); if (!trfit.rotate(alpha) || // note: here we also calculate the L,T integral (in the inward direction, but this is irrelevant) @@ -1763,7 +1830,7 @@ bool MatchTPCITS::refitABTrack(int iITSAB, const TPCABSeed& seed, pmr::vectorgetSensorRefAlpha(clus.getSensorID()), x = clus.getX(); if (!tracOut.rotate(alpha, refLin, propagator->getNominalBz()) || // note: here we also calculate the L,T integral @@ -1921,10 +1988,15 @@ int MatchTPCITS::prepareABSeeds() //______________________________________________ int MatchTPCITS::prepareInteractionTimes() { - // guess interaction times from various sources and relate with ITS rofs + // Guess interaction times from various sources and relate them to the ITS cluster ROFs of the clock layer. + // For every candidate define also the per-layer cluster ROFs compatible with its time within the + // mABROFMarginMUS margin: they define the clusters the AfterBurner will check for this candidate. const float ft0Uncertainty = 0.5e-3; - int nITSROFs = mITSROFTimes.size(); - if (mFITInfo.size()) { + const auto& clockROFTimes = mABLayerClusters[mITSClockLayer].rofTimes; + int nClockROFs = clockROFTimes.size(); + int lowestAB = mParams->runAfterBurner ? mParams->lowestLayerAB : NITSLayers; + std::array ptrLr{}; // monotonic pointers on the per-layer ROFs (candidates are time-ordered) + if (mFITInfo.size() && nClockROFs) { int rof = 0; for (const auto& ft : mFITInfo) { if (!mFT0Params->isSelected(ft)) { @@ -1934,22 +2006,33 @@ int MatchTPCITS::prepareInteractionTimes() if (fitTime < 0) { // should not happen continue; } + while (rof < nClockROFs && clockROFTimes[rof].getMax() + mABROFMarginMUS < fitTime) { + rof++; + } + if (rof >= nClockROFs) { // no candidates beyond the last cluster ROF of the clock layer + break; + } if (size_t(fitTime) >= mInteractionMUSLUT.size()) { mInteractionMUSLUT.resize(size_t(fitTime) + 1, -1); } if (mInteractionMUSLUT[fitTime] < 0) { mInteractionMUSLUT[fitTime] = mInteractions.size(); } - for (; rof < nITSROFs; rof++) { - if (mITSROFTimes[rof] < fitTime) { - continue; + auto& intCand = mInteractions.emplace_back(ft.getInteractionRecord(), fitTime, ft0Uncertainty, rof, o2::detectors::DetID::FT0); + for (int lr = lowestAB; lr < NITSLayers; lr++) { // relate the candidate time to compatible ROFs of the AB layers + const auto& rofTimes = mABLayerClusters[lr].rofTimes; + int nROFsLr = (int)rofTimes.size(); + int& ptr = ptrLr[lr]; + while (ptr < nROFsLr && rofTimes[ptr].getMax() + mABROFMarginMUS < fitTime) { + ptr++; + } + if (ptr < nROFsLr && fitTime >= rofTimes[ptr].getMin() - mABROFMarginMUS) { + intCand.rofLr[lr] = ptr; + if (ptr + 1 < nROFsLr && fitTime >= rofTimes[ptr + 1].getMin() - mABROFMarginMUS) { + intCand.rofNextLr |= 0x1 << lr; // compatible also with the next ROF of the layer + } } - break; - } - if (rof >= nITSROFs) { - break; } - mInteractions.emplace_back(ft.getInteractionRecord(), fitTime, ft0Uncertainty, rof, o2::detectors::DetID::FT0); } } int ent = 0; @@ -1963,6 +2046,164 @@ int MatchTPCITS::prepareInteractionTimes() return mInteractions.size(); } +//______________________________________________ +void MatchTPCITS::prepareABClusters() +{ + // Build per (layer, ROF) blocks of the clusters usable by the AfterBurner (i.e. not attached to ITS + // tracks), sorted in (chip, Z). Only the blocks referenced by interaction candidates with seeds are built. + const bool perLayer = mRecoCont->getITSPerLayer(); + const int lowestAB = mParams->lowestLayerAB; + for (int lr = lowestAB; lr < NITSLayers; lr++) { + auto& abClus = mABLayerClusters[lr]; + abClus.needROF.assign(abClus.rofTimes.size(), 0); + abClus.rofRefs.assign(abClus.rofTimes.size(), ClusRange(-1, 0)); + } + for (const auto& intCand : mInteractions) { // mark the blocks to build + if (!intCand.seedsRef.getEntries()) { + continue; + } + for (int lr = lowestAB; lr < NITSLayers; lr++) { + int rof = intCand.rofLr[lr]; + if (rof < 0) { + continue; + } + auto& need = mABLayerClusters[lr].needROF; + need[rof] = 1; + if ((intCand.rofNextLr >> lr) & 0x1) { + need[rof + 1] = 1; + } + } + } + struct ABBlock { + int lr = 0, rof = 0, nCl = 0, offs = 0; + }; + std::vector blocks; + for (int lr = lowestAB; lr < NITSLayers; lr++) { + const auto& need = mABLayerClusters[lr].needROF; + for (int rof = 0; rof < (int)need.size(); rof++) { + if (need[rof]) { + blocks.push_back({lr, rof}); + } + } + } + if (blocks.empty()) { + return; + } + int nBlocks = blocks.size(); + // count AB-usable clusters of every block +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#endif + for (int ib = 0; ib < nBlocks; ib++) { + auto& blk = blocks[ib]; + int slot = perLayer ? blk.lr : 0; + const auto& rofRec = mITSClusterROFRec[slot][blk.rof]; + const auto& status = mABClusterStatus[slot]; + int last = rofRec.getFirstEntry() + rofRec.getNEntries(), nCl = 0; + if (perLayer) { + for (int icl = rofRec.getFirstEntry(); icl < last; icl++) { + if (status[icl] != MinusTen) { + nCl++; + } + } + } else { // select only the clusters of the block layer + const auto& clusArr = mITSClustersArray[0]; + int chipMin = mABChipsBounds[blk.lr], chipMax = mABChipsBounds[blk.lr + 1]; + for (int icl = rofRec.getFirstEntry(); icl < last; icl++) { + int chip = clusArr[icl].getSensorID(); + if (chip >= chipMin && chip < chipMax && status[icl] != MinusTen) { + nCl++; + } + } + } + blk.nCl = nCl; + } + // assign per-layer storage offsets + std::array layerSizes{}; + for (auto& blk : blocks) { + blk.offs = layerSizes[blk.lr]; + layerSizes[blk.lr] += blk.nCl; + } + for (int lr = lowestAB; lr < NITSLayers; lr++) { + mABLayerClusters[lr].clus.resize(layerSizes[lr]); + } + // fill and sort the blocks +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#endif + for (int ib = 0; ib < nBlocks; ib++) { + const auto& blk = blocks[ib]; + auto& abClus = mABLayerClusters[blk.lr]; + int slot = perLayer ? blk.lr : 0; + const auto& rofRec = mITSClusterROFRec[slot][blk.rof]; + const auto& status = mABClusterStatus[slot]; + const auto& clusArr = mITSClustersArray[slot]; + int last = rofRec.getFirstEntry() + rofRec.getNEntries(); + int chipMin = mABChipsBounds[blk.lr], chipMax = mABChipsBounds[blk.lr + 1]; + ABClusterInfo* dst = abClus.clus.data() + blk.offs; + int nCl = 0; + for (int icl = rofRec.getFirstEntry(); icl < last; icl++) { + const auto& cls = clusArr[icl]; + int chip = cls.getSensorID(); + if ((perLayer || (chip >= chipMin && chip < chipMax)) && status[icl] != MinusTen) { + assert(chip >= chipMin && chip < chipMax); // clusters of a per-layer slot must belong to its layer + dst[nCl++] = {cls.getY(), cls.getZ(), o2::itsmft::composeClusID(slot, icl), chip}; + } + } + assert(nCl == blk.nCl); + std::sort(dst, dst + nCl, [](const ABClusterInfo& a, const ABClusterInfo& b) { return a.chip < b.chip || (a.chip == b.chip && a.z < b.z); }); + abClus.rofRefs[blk.rof].set(blk.offs, nCl); + } +} + +//______________________________________________ +void MatchTPCITS::updateABLayerView(ABLayerView& view, int lr, int rof, int nROFs) const +{ + // Point the thread-local view to the AB clusters block(s) of the layer covering the requested ROF(s), + // refreshing the chip->clusters references. Does nothing if the requested block(s) are already loaded. + if (view.rofKey == rof && view.nROFsKey == nROFs) { + return; + } + for (int chip : view.touchedChips) { // reset previously registered references + view.chipRefs[chip].setEntries(0); + } + view.touchedChips.clear(); + view.rofKey = rof; + view.nROFsKey = nROFs; + view.data = nullptr; + view.nData = 0; + if (rof < 0) { // no ROF of this layer is compatible with the candidate time + return; + } + const auto& abClus = mABLayerClusters[lr]; + const auto& ref0 = abClus.rofRefs[rof]; + assert(ref0.getFirstEntry() >= 0); // the block must have been built in prepareABClusters + if (nROFs == 1) { + view.data = abClus.clus.data() + ref0.getFirstEntry(); + view.nData = ref0.getEntries(); + } else { // merge the 2 blocks, each sorted in (chip, Z) + const auto& ref1 = abClus.rofRefs[rof + 1]; + assert(ref1.getFirstEntry() >= 0); + view.merged.resize(ref0.getEntries() + ref1.getEntries()); + std::merge(abClus.clus.begin() + ref0.getFirstEntry(), abClus.clus.begin() + ref0.getEntriesBound(), + abClus.clus.begin() + ref1.getFirstEntry(), abClus.clus.begin() + ref1.getEntriesBound(), + view.merged.begin(), [](const ABClusterInfo& a, const ABClusterInfo& b) { return a.chip < b.chip || (a.chip == b.chip && a.z < b.z); }); + view.data = view.merged.data(); + view.nData = (int)view.merged.size(); + } + int icl = 0; + while (icl < view.nData) { // register the cluster ranges of the chips + int chip = view.data[icl].chip, jcl = icl + 1; + while (jcl < view.nData && view.data[jcl].chip == chip) { + jcl++; + } + int chipLoc = chip - view.chipOffs; + view.chipRefs[chipLoc].set(icl, jcl - icl); + view.touchedChips.push_back(chipLoc); + icl = jcl; + } +} + //______________________________________________ bool MatchTPCITS::runAfterBurner(pmr::vector& matchedTracks, pmr::vector& matchLabels, pmr::vector& ABTrackletLabels, pmr::vector& ABTrackletClusterIDs, pmr::vector& ABTrackletRefs, pmr::vector>& calib) @@ -1977,33 +2218,77 @@ bool MatchTPCITS::runAfterBurner(pmr::vector& matc return false; } mTimer[SWABMatch].Start(false); - - std::vector itsChipClRefsBuff(mNThreads); -#ifdef ENABLE_UPGRADES - // with upgrades the datatype changed, hence we need to initialize - // each element individually - std::generate(itsChipClRefsBuff.begin(), itsChipClRefsBuff.end(), []() { - return ITSChipClustersRefs(o2::its::GeometryTGeo::Instance()->getNumberOfChips()); - }); -#endif - -#ifdef WITH_OPENMP -#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) -#endif + prepareABClusters(); // build the blocks of AB-usable clusters for the (layer, ROF)s referenced by the candidates + + // Group together consecutive candidates with seeds sharing the same per-layer ROFs: within a group the + // thread-local cluster views stay valid, so they are (re)loaded at most once per group and layer + int lowestAB = mParams->lowestLayerAB; + std::vector seededIC; + std::vector> icGroups; // ranges (1st, last entry) in seededIC + seededIC.reserve(nIntCand); for (int ic = 0; ic < nIntCand; ic++) { const auto& intCand = mInteractions[ic]; - LOGP(debug, "cand T {} Entries: {} : {} : {} | ITS ROF: {}", intCand.tBracket.mean(), intCand.seedsRef.getEntries(), intCand.seedsRef.getFirstEntry(), intCand.seedsRef.getEntriesBound(), intCand.rofITS); if (!intCand.seedsRef.getEntries()) { continue; } + bool anyROF = false; + for (int lr = lowestAB; lr < NITSLayers; lr++) { + if (intCand.rofLr[lr] >= 0) { + anyROF = true; + break; + } + } + if (!anyROF) { // no AB layer has clusters at the candidate time: discard the seeds of this candidate + for (int is = intCand.seedsRef.getFirstEntry(); is < intCand.seedsRef.getEntriesBound(); is++) { + mTPCABSeeds[is].disable(); + } + continue; + } + bool sameROFs = false; + if (!seededIC.empty()) { + const auto& prevCand = mInteractions[seededIC.back()]; + sameROFs = prevCand.rofNextLr == intCand.rofNextLr; + for (int lr = lowestAB; sameROFs && lr < NITSLayers; lr++) { + sameROFs = prevCand.rofLr[lr] == intCand.rofLr[lr]; + } + } + if (sameROFs) { + icGroups.back().second = (int)seededIC.size(); + } else { + icGroups.emplace_back((int)seededIC.size(), (int)seededIC.size()); + } + seededIC.push_back(ic); + } + + std::vector itsClViewsBuff(mNThreads); + for (auto& views : itsClViewsBuff) { // book the chip->clusters references of the AB layers + for (int lr = lowestAB; lr < NITSLayers; lr++) { + auto& view = views.layers[lr]; + view.chipOffs = mABChipsBounds[lr]; + view.chipRefs.resize(mABChipsBounds[lr + 1] - mABChipsBounds[lr], ClusRange(0, 0)); + } + } + +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic) num_threads(mNThreads) +#endif + for (int ig = 0; ig < (int)icGroups.size(); ig++) { #ifdef WITH_OPENMP uint8_t tid = (uint8_t)omp_get_thread_num(); #else uint8_t tid = 0; #endif - fillClustersForAfterBurner(intCand.rofITS, 1, itsChipClRefsBuff[tid]); // RS FIXME account for possibility of filling 2 ROFs - for (int is = intCand.seedsRef.getFirstEntry(); is < intCand.seedsRef.getEntriesBound(); is++) { // loop over all seeds of this interaction candidate - processABSeed(is, itsChipClRefsBuff[tid], tid); + auto& views = itsClViewsBuff[tid]; + const auto& groupCand = mInteractions[seededIC[icGroups[ig].first]]; // all candidates of the group share the same ROFs + for (int lr = lowestAB; lr < NITSLayers; lr++) { + updateABLayerView(views.layers[lr], lr, groupCand.rofLr[lr], (groupCand.rofNextLr >> lr) & 0x1 ? 2 : 1); + } + for (int j = icGroups[ig].first; j <= icGroups[ig].second; j++) { + const auto& intCand = mInteractions[seededIC[j]]; + LOGP(debug, "cand T {} Entries: {} : {} : {} | ITS clock ROF: {}", intCand.tBracket.mean(), intCand.seedsRef.getEntries(), intCand.seedsRef.getFirstEntry(), intCand.seedsRef.getEntriesBound(), intCand.rofITS); + for (int is = intCand.seedsRef.getFirstEntry(); is < intCand.seedsRef.getEntriesBound(); is++) { // loop over all seeds of this interaction candidate + processABSeed(is, views, tid); + } } } mTimer[SWABMatch].Stop(); @@ -2039,13 +2324,13 @@ bool MatchTPCITS::runAfterBurner(pmr::vector& matc continue; } auto bestID = ABSeed.getBestLinkID(); - if (ABSeed.checkLinkHasUsedClusters(bestID, mABClusterLinkIndex)) { + if (ABSeed.checkLinkHasUsedClusters(bestID, mABClusterStatus)) { ABSeed.setNeedAlternative(); // flag for later processing // RSTMP LOG(info) << "Iter: " << iter << " seed has used clusters " << i << "[" << candAB[i].seedID << "/" << candAB[i].chi2 << "]" << " last lr: " << int(ABSeed.lowestLayer) << " Ncont: " << int(link.nContLayers);; continue; } ABSeed.validate(bestID); - ABSeed.flagLinkUsedClusters(bestID, mABClusterLinkIndex); + ABSeed.flagLinkUsedClusters(bestID, mABClusterStatus); mABWinnersIDs.push_back(tTPC.matchID = candAB[i].seedID); mNABRefsClus += ABSeed.getNLayers(); nwin++; @@ -2079,8 +2364,8 @@ void MatchTPCITS::refitABWinners(pmr::vector& matc } std::map labelOccurence; - auto accountClusterLabel = [&labelOccurence, itsClLabs = mITSClsLabels](int clID) { - auto labels = itsClLabs->getLabels(clID); + auto accountClusterLabel = [&labelOccurence, this](int clID) { + auto labels = mITSClsLabels[o2::itsmft::clusID2Layer(clID)]->getLabels(o2::itsmft::clusID2Index(clID)); for (auto lab : labels) { // check all labels of the cluster if (lab.isSet()) { labelOccurence[lab]++; @@ -2099,7 +2384,7 @@ void MatchTPCITS::refitABWinners(pmr::vector& matc ABTrackletClusterIDs.push_back(winL.clID); ncl++; clref.pattern |= 0x1 << winL.layerID; - clref.setClusterSize(winL.layerID, mITSClusterSizes[winL.clID]); + clref.setClusterSize(winL.layerID, mITSClusterSizes[o2::itsmft::clusID2Layer(winL.clID)][o2::itsmft::clusID2Index(winL.clID)]); if (mMCTruthON) { accountClusterLabel(winL.clID); } @@ -2139,13 +2424,13 @@ void MatchTPCITS::refitABWinners(pmr::vector& matc } //______________________________________________ -void MatchTPCITS::processABSeed(int sid, const ITSChipClustersRefs& itsChipClRefs, uint8_t tID) +void MatchTPCITS::processABSeed(int sid, const ABThreadClusterViews& itsClViews, uint8_t tID) { // prepare matching hypothesis tree for given seed auto& ABSeed = mTPCABSeeds[sid]; ABSeed.threadID = tID; ABSeed.linksEntry = mABLinksPool.threadPool[tID].size(); - followABSeed(ABSeed.track, itsChipClRefs, MinusTen, NITSLayers - 1, ABSeed); // check matches on outermost layer + followABSeed(ABSeed.track, itsClViews.layers[NITSLayers - 1], MinusTen, NITSLayers - 1, ABSeed); // check matches on outermost layer for (int ilr = NITSLayers - 1; ilr > mParams->lowestLayerAB; ilr--) { int nextLinkID = ABSeed.firstInLr[ilr]; if (nextLinkID < 0) { @@ -2158,7 +2443,7 @@ void MatchTPCITS::processABSeed(int sid, const ITSChipClustersRefs& itsChipClRef continue; } int next2nextLinkID = seedLink.nextOnLr; // fetch now since the seedLink may change due to the relocation - followABSeed(seedLink, itsChipClRefs, nextLinkID, ilr - 1, ABSeed); // check matches on the next layer + followABSeed(seedLink, itsClViews.layers[ilr - 1], nextLinkID, ilr - 1, ABSeed); // check matches on the next layer nextLinkID = next2nextLinkID; } } @@ -2185,9 +2470,11 @@ void MatchTPCITS::processABSeed(int sid, const ITSChipClustersRefs& itsChipClRef } //______________________________________________ -int MatchTPCITS::followABSeed(const o2::track::TrackParCov& seed, const ITSChipClustersRefs& itsChipClRefs, int seedID, int lrID, TPCABSeed& ABSeed) +int MatchTPCITS::followABSeed(const o2::track::TrackParCov& seed, const ABLayerView& clView, int seedID, int lrID, TPCABSeed& ABSeed) { - + if (!clView.nData) { // no AB-usable clusters on this layer at the interaction candidate time + return 0; + } auto propagator = o2::base::Propagator::Instance(); float xTgt; const auto& lr = mRGHelper.layers[lrID]; @@ -2248,7 +2535,7 @@ int MatchTPCITS::followABSeed(const o2::track::TrackParCov& seed, const ITSChipC if (lad.chips[chipID].zRange.isOutside(zCross, mParams->nABSigmaZ * errZ)) { continue; } - const auto& clRange = itsChipClRefs.chipRefs[lad.chips[chipID].id]; + const auto& clRange = clView.chipRefs[lad.chips[chipID].id - clView.chipOffs]; if (!clRange.getEntries()) { LOG(debug) << "No clusters in chip range"; continue; @@ -2257,7 +2544,7 @@ int MatchTPCITS::followABSeed(const o2::track::TrackParCov& seed, const ITSChipC float errYcalp = errY * (csa * chipC.csAlp + sna * chipC.snAlp); // sigY_rotate(from alpha0 to alpha1) = sigY * cos(alpha1 - alpha0); float tolerZ = errZ * mParams->nABSigmaZ, tolerY = errYcalp * mParams->nABSigmaY; float yTrack = -xCross * chipC.snAlp + yCross * chipC.csAlp; // track-chip crossing Y in chip frame - if (!preselectChipClusters(chipSelClusters, clRange, itsChipClRefs, yTrack, zCross, tolerY, tolerZ)) { // select candidate clusters for this chip + if (!preselectChipClusters(chipSelClusters, clRange, clView, yTrack, zCross, tolerY, tolerZ)) { // select candidate clusters for this chip LOG(debug) << "No compatible clusters found"; continue; } @@ -2270,7 +2557,7 @@ int MatchTPCITS::followABSeed(const o2::track::TrackParCov& seed, const ITSChipC } for (auto clID : chipSelClusters) { - const auto& cls = mITSClustersArray[clID]; + const auto& cls = getITSCluster(clID); auto chi2 = trcLC.getPredictedChi2(cls); if (chi2 > mParams->cutABTrack2ClChi2) { continue; @@ -2470,79 +2757,44 @@ float MatchTPCITS::correctTPCTrack(o2::track::TrackParCov& trc, const TrackLocTP } //______________________________________________ -void MatchTPCITS::fillClustersForAfterBurner(int rofStart, int nROFs, ITSChipClustersRefs& itsChipClRefs) -{ - // Prepare unused clusters of given ROFs range for matching in the afterburner - // Note: normally only 1 ROF needs to be filled (nROFs==1 ) unless we want - // to account for interaction on the boundary of 2 rofs, which then may contribute to both ROFs. - int first = mITSClusterROFRec[rofStart].getFirstEntry(), last = first; - for (int ir = nROFs; ir--;) { - last += mITSClusterROFRec[rofStart + ir].getNEntries(); - } - itsChipClRefs.clear(); - auto& idxSort = itsChipClRefs.clusterID; - for (int icl = first; icl < last; icl++) { - if (mABClusterLinkIndex[icl] != MinusTen) { // clusters with MinusOne are used in main matching - idxSort.push_back(icl); - } - } - // sort in chip, Z - const auto& clusArr = mITSClustersArray; - std::sort(idxSort.begin(), idxSort.end(), [&clusArr](int i, int j) { - const auto &clI = clusArr[i], &clJ = clusArr[j]; - if (clI.getSensorID() < clJ.getSensorID()) { - return true; - } - if (clI.getSensorID() == clJ.getSensorID()) { - return clI.getZ() < clJ.getZ(); - } - return false; - }); - - int ncl = idxSort.size(); - int lastSens = -1, nClInSens = 0; - ClusRange* chipClRefs = nullptr; - for (int icl = 0; icl < ncl; icl++) { - const auto& clus = mITSClustersArray[idxSort[icl]]; - int sens = clus.getSensorID(); - if (sens != lastSens) { - if (chipClRefs) { // finalize chip reference - chipClRefs->setEntries(nClInSens); - nClInSens = 0; - } - chipClRefs = &itsChipClRefs.chipRefs[(lastSens = sens)]; - chipClRefs->setFirstEntry(icl); - } - nClInSens++; - } - if (chipClRefs) { - chipClRefs->setEntries(nClInSens); // finalize last chip reference - } -} - -//______________________________________________ -void MatchTPCITS::setITSTimeBiasInBC(int n) +void MatchTPCITS::setAlpideParam(const AlpParamITS* p) { - mITSTimeBiasInBC = n; - mITSTimeBiasMUS = mITSTimeBiasInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; -} - -//______________________________________________ -void MatchTPCITS::setITSROFrameLengthMUS(float fums) -{ - mITSROFrameLengthMUS = fums; - mITSTimeResMUS = mITSROFrameLengthMUS / std::sqrt(12.f); - mITSROFrameLengthMUSInv = 1. / mITSROFrameLengthMUS; - mITSROFrameLengthInBC = std::max(1, int(mITSROFrameLengthMUS / (o2::constants::lhc::LHCBunchSpacingNS * 1e-3))); -} - -//______________________________________________ -void MatchTPCITS::setITSROFrameLengthInBC(int nbc) -{ - mITSROFrameLengthInBC = nbc; - mITSROFrameLengthMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; - mITSTimeResMUS = mITSROFrameLengthMUS / std::sqrt(12.f); - mITSROFrameLengthMUSInv = 1. / mITSROFrameLengthMUS; + ///< derive all ITS ROF timings from the Alpide parameters. The per-layer arrays are always + ///< filled for all NITSLayers, also when every layer shares the same ROF length and bias. + if (!p) { + LOG(fatal) << "ITS Alpide parameters pointer is null"; + } + mAlpParams = p; + constexpr float BCLenMUS = o2::constants::lhc::LHCBunchSpacingMUS; + unsigned int maxNROFsPerOrbit = 0; + mITSClockLayer = 0; + for (int lr = 0; lr < NITSLayers; lr++) { + if (mITSTriggered) { // in the triggered mode all layers are read out together + mITSROFrameLengthMUS[lr] = p->roFrameLengthTrig * 1e-3; + mITSROFrameLengthInBC[lr] = std::max(1, int(mITSROFrameLengthMUS[lr] / BCLenMUS)); + } else { + mITSROFrameLengthInBC[lr] = p->getROFLengthInBC(lr); + mITSROFrameLengthMUS[lr] = mITSROFrameLengthInBC[lr] * BCLenMUS; + } + mITSROFrameLengthMUSInv[lr] = 1.f / mITSROFrameLengthMUS[lr]; + mITSTimeResMUS[lr] = mITSROFrameLengthMUS[lr] / std::sqrt(12.f); + mITSTimeBiasInBC[lr] = p->getROFBiasInBC(lr); + mITSTimeBiasMUS[lr] = mITSTimeBiasInBC[lr] * BCLenMUS; + // the ITS tracks ROFRecords are defined by the layer with the largest number of ROFs per orbit, + // see o2::its::ITSTrackingInterface (o2::its::ROFOverlapView::getClock()). If all layers have the + // same timing, this is the layer 0. + unsigned int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / mITSROFrameLengthInBC[lr]; + if (nROFsPerOrbit > maxNROFsPerOrbit) { + maxNROFsPerOrbit = nROFsPerOrbit; + mITSClockLayer = lr; + } + } + std::string rep; + for (int lr = 0; lr < NITSLayers; lr++) { + rep += fmt::format(" L{}:{}/{}", lr, mITSROFrameLengthInBC[lr], mITSTimeBiasInBC[lr]); + } + LOGP(info, "ITS {} readout, per-layer ROFLength/Bias in BC:{} | clock layer {}", + mITSTriggered ? "triggered" : "continuous", rep, mITSClockLayer); } //___________________________________________________________________ @@ -2655,35 +2907,37 @@ void MatchTPCITS::flagUsedITSClusters(const o2::its::TrackITS& track) // flag clusters used by this track int clEntry = track.getFirstClusterEntry(); for (int icl = track.getNumberOfClusters(); icl--;) { - mABClusterLinkIndex[mITSTrackClusIdx[clEntry++]] = MinusTen; + const int clID = mITSTrackClusIdx[clEntry++]; // composed ID: (layer << o2::itsmft::ClusLayerShift) + index_in_layer + auto& clStatus = mABClusterStatus[o2::itsmft::clusID2Layer(clID)]; + if (!clStatus.empty()) { // layers not used by the AfterBurner are not booked + clStatus[o2::itsmft::clusID2Index(clID)] = MinusTen; + } } } //__________________________________________________________ -int MatchTPCITS::preselectChipClusters(std::vector& clVecOut, const ClusRange& clRange, const ITSChipClustersRefs& itsChipClRefs, +int MatchTPCITS::preselectChipClusters(std::vector& clVecOut, const ClusRange& clRange, const ABLayerView& clView, float trackY, float trackZ, float tolerY, float tolerZ) const { clVecOut.clear(); int icID = clRange.getFirstEntry(); for (int icl = clRange.getEntries(); icl--;) { // note: clusters within a chip are sorted in Z - int clID = itsChipClRefs.clusterID[icID++]; // so, we go in clusterID increasing direction - const auto& cls = mITSClustersArray[clID]; - float dz = cls.getZ() - trackZ; - LOG(debug) << "cl" << icl << '/' << clID << " " - << " dZ: " << dz << " [" << tolerZ << "| dY: " << trackY - cls.getY() << " [" << tolerY << "]"; + const auto& cls = clView.data[icID++]; + float dz = cls.z - trackZ; + LOG(debug) << "cl" << icl << '/' << cls.id << " " + << " dZ: " << dz << " [" << tolerZ << "| dY: " << trackY - cls.y << " [" << tolerY << "]"; if (dz > tolerZ) { - float clsZ = cls.getZ(); - LOG(debug) << "Skip the rest since " << trackZ << " < " << clsZ << "\n"; + LOG(debug) << "Skip the rest since " << trackZ << " < " << cls.z << "\n"; break; } else if (dz < -tolerZ) { - LOG(debug) << "Skip cluster dz=" << dz << " Ztr=" << trackZ << " zCl=" << cls.getZ(); + LOG(debug) << "Skip cluster dz=" << dz << " Ztr=" << trackZ << " zCl=" << cls.z; continue; } - if (fabs(trackY - cls.getY()) > tolerY) { - LOG(debug) << "Skip cluster dy= " << trackY - cls.getY() << " Ytr=" << trackY << " yCl=" << cls.getY(); + if (fabs(trackY - cls.y) > tolerY) { + LOG(debug) << "Skip cluster dy= " << trackY - cls.y << " Ytr=" << trackY << " yCl=" << cls.y; continue; } - clVecOut.push_back(clID); + clVecOut.push_back(cls.id); } return clVecOut.size(); } @@ -2735,12 +2989,24 @@ void MatchTPCITS::reportSizes(pmr::vector& matched LOGP(info, "Size SHM, calib : size {:9} cap {:9}", siz, cap); } { - siz = mITSClustersArray.size() * sizeof(ITSCluster); - cap = mITSClustersArray.capacity() * sizeof(ITSCluster); + siz = cap = 0; + for (const auto& clusV : mITSClustersArray) { + siz += clusV.size() * sizeof(ITSCluster); + cap += clusV.capacity() * sizeof(ITSCluster); + } sizTot += siz; capTot += cap; LOGP(info, "Size RSS, mITSClustersArray : size {:9} cap {:9}", siz, cap); // + siz = cap = 0; + for (const auto& abClus : mABLayerClusters) { + siz += abClus.sizeInternal(); + cap += abClus.capInternal(); + } + sizTot += siz; + capTot += cap; + LOGP(info, "Size RSS, mABLayerClusters : size {:9} cap {:9}", siz, cap); + // siz = mMatchRecordsTPC.size() * sizeof(MatchRecord); cap = mMatchRecordsTPC.capacity() * sizeof(MatchRecord); sizTot += siz; @@ -2803,11 +3069,14 @@ void MatchTPCITS::reportSizes(pmr::vector& matched capTot += cap; LOGP(info, "Size RSS, mABWinnersIDs : size {:9} cap {:9}", siz, cap); // - siz = mABClusterLinkIndex.size() * sizeof(int); - cap = mABClusterLinkIndex.capacity() * sizeof(int); + siz = cap = 0; + for (const auto& clStatus : mABClusterStatus) { + siz += clStatus.size() * sizeof(int); + cap += clStatus.capacity() * sizeof(int); + } sizTot += siz; capTot += cap; - LOGP(info, "Size RSS, mABClusterLinkIndex : size {:9} cap {:9}", siz, cap); + LOGP(info, "Size RSS, mABClusterStatus : size {:9} cap {:9}", siz, cap); // for (int is = 0; is < o2::constants::math::NSectors; is++) { siz += mTPCSectIndexCache[is].size() * sizeof(int); @@ -2951,7 +3220,7 @@ void MatchTPCITS::fillTPCITSmatchTree(int itsID, int tpcID, int rejFlag, float c << "rejFlag=" << rejFlag << "multTPC=" << mltTPC << "multITSTr=" << mITSTrackROFRec[trackITS.roFrame].getNEntries() - << "multITSCl=" << mITSClusterROFRec[trackITS.roFrame].getNEntries() + << "multITSCl=" << mITSClusterROFRec[mRecoCont->getITSPerLayer() ? mITSClockLayer : 0][trackITS.roFrame].getNEntries() << "\n"; mTimer[SWDBG].Stop(); @@ -2986,7 +3255,7 @@ void MatchTPCITS::dumpWinnerMatches() (*mDBGOut) << "matchWin" << "multTPC=" << mltTPC << "multITSTr=" << mITSTrackROFRec[tITS.roFrame].getNEntries() - << "multITSCl=" << mITSClusterROFRec[tITS.roFrame].getNEntries() + << "multITSCl=" << mITSClusterROFRec[mRecoCont->getITSPerLayer() ? mITSClockLayer : 0][tITS.roFrame].getNEntries() << "\n"; } mTimer[SWDBG].Stop(); diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h index ed1b0aa1c105d..1b1d9c494dc6c 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/CosmicsMatchingSpec.h @@ -24,7 +24,7 @@ namespace globaltracking { /// create a processor spec -framework::DataProcessorSpec getCosmicsMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool usePV, bool useMC); +framework::DataProcessorSpec getCosmicsMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool usePV, bool useMC, bool itsStag); } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h index 9211a9cb0c264..1efb8d4216cd3 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/SecondaryVertexingSpec.h @@ -25,7 +25,7 @@ namespace vertexing { /// create a processor spec -o2::framework::DataProcessorSpec getSecondaryVertexingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool enableCasc, bool enable3body, bool enableStrangenesTracking, bool enableCCDBParams, bool useMC, bool useGeom); +o2::framework::DataProcessorSpec getSecondaryVertexingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool enableCasc, bool enable3body, bool enableStrangenesTracking, bool enableCCDBParams, bool useMC, bool useGeom, bool itsStag); } // namespace vertexing } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/StrangenessTrackingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/StrangenessTrackingSpec.h index bbc2cdc80995e..48ba7ad8416e7 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/StrangenessTrackingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/StrangenessTrackingSpec.h @@ -60,7 +60,7 @@ class StrangenessTrackerSpec : public framework::Task std::unique_ptr mGRP = nullptr; }; -o2::framework::DataProcessorSpec getStrangenessTrackerSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool useGeom); +o2::framework::DataProcessorSpec getStrangenessTrackerSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool useGeom, bool itsStag); o2::framework::WorkflowSpec getWorkflow(bool upstreamClusters = false, bool upstreamV0s = false); } // namespace strangeness_tracking diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h index 56240fd2c8f98..775e7b8c676f2 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/TPCITSMatchingSpec.h @@ -23,7 +23,7 @@ namespace o2 namespace globaltracking { /// create a processor spec -framework::DataProcessorSpec getTPCITSMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, bool requestCTPLumi); +framework::DataProcessorSpec getTPCITSMatchingSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, bool requestCTPLumi, bool itsStag); } // namespace globaltracking } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx index 338bb86bd8033..20941d8333e27 100644 --- a/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/CosmicsMatchingSpec.cxx @@ -183,7 +183,7 @@ void CosmicsMatchingSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getCosmicsMatchingSpec(GTrackID::mask_t src, bool usePV, bool useMC) +DataProcessorSpec getCosmicsMatchingSpec(GTrackID::mask_t src, bool usePV, bool useMC, bool itsStag) { std::vector outputs; Options opts{ @@ -191,6 +191,7 @@ DataProcessorSpec getCosmicsMatchingSpec(GTrackID::mask_t src, bool usePV, bool {"debug-tree-flags", VariantType::Int, 0, {"DebugFlagTypes bit-pattern for debug tree"}}}; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestTracks(src, useMC); dataRequest->requestClusters(src, false); // no MC labels for clusters needed for refit only diff --git a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx index 3a9de8662f4b5..406b780e28a15 100644 --- a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx @@ -245,7 +245,7 @@ void SecondaryVertexingSpec::updateTimeDependentParams(ProcessingContext& pc) } DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCasc, bool enable3body, bool enableStrangenesTracking, bool enableCCDBParams, - bool useMC, bool useGeom) + bool useMC, bool useGeom, bool itsStag) { std::vector outputs; Options opts{ @@ -255,6 +255,7 @@ DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCas if (enableCCDBParams) { dataRequest->inputs.emplace_back("SVParam", "GLO", "SVPARAM", 0, Lifetime::Condition, ccdbParamSpec("GLO/Config/SVertexerParam")); } + dataRequest->setITSPerLayer(itsStag); GTrackID::mask_t srcClus{}; if (enableStrangenesTracking) { src |= (srcClus = GTrackID::getSourceMask(GTrackID::ITS)); diff --git a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx index c438f869773a5..ec158a1749398 100644 --- a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx @@ -154,10 +154,11 @@ void StrangenessTrackerSpec::endOfStream(framework::EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getStrangenessTrackerSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool useGeom) +DataProcessorSpec getStrangenessTrackerSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool useGeom, bool itsStag) { // ITS auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestITSClusters(useMC); dataRequest->requestTracks(src, useMC); dataRequest->requestPrimaryVertices(useMC); diff --git a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx index 7f63b61e02be0..90a02fd6fc493 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx @@ -210,15 +210,10 @@ void TPCITSMatchingDPL::updateTimeDependentParams(ProcessingContext& pc) pc.inputs().get("MatchParam"); // Note: ITS/CLUSDICT and ITS/ALPIDEPARAM are requested/loaded by the recocontainer - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); - if (mMatching.isITSTriggered()) { - mMatching.setITSROFrameLengthMUS(alpParams.roFrameLengthTrig / 1.e3); // ITS ROFrame duration in \mus - } else { - mMatching.setITSROFrameLengthInBC(alpParams.roFrameLengthInBC); // ITS ROFrame duration in \mus - } - mMatching.setITSTimeBiasInBC(alpParams.roFrameBiasInBC); - mMatching.setSkipTPCOnly(mSkipTPCOnly); + // all per-layer ITS ROF lengths and biases are derived in MatchTPCITS::setAlpideParam() mMatching.setITSTriggered(!o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS)); + mMatching.setAlpideParam(&o2::itsmft::DPLAlpideParam::Instance()); + mMatching.setSkipTPCOnly(mSkipTPCOnly); mMatching.setNHBPerTF(o2::base::GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF()); mMatching.setMCTruthOn(mUseMC); mMatching.setUseFT0(mUseFT0); @@ -250,10 +245,11 @@ void TPCITSMatchingDPL::updateTimeDependentParams(ProcessingContext& pc) } } -DataProcessorSpec getTPCITSMatchingSpec(GTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, bool requestCTPLumi) +DataProcessorSpec getTPCITSMatchingSpec(GTrackID::mask_t src, bool useFT0, bool calib, bool skipTPCOnly, bool useGeom, bool useMC, bool requestCTPLumi, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); if ((src & GTrackID::getSourcesMask("TPC-TRD,TPC-TOF,TPC-TRD-TOF")).any()) { // preliminary stage of extended workflow ? dataRequest->setMatchingInputStrict(); } diff --git a/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx index 46cfd641b3165..67e2fd6cdc4cd 100644 --- a/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/cosmics-match-workflow.cxx @@ -88,6 +88,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::writeINI("o2match-cosmics-workflow_configuration.ini"); auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); auto useMC = !configcontext.options().get("disable-mc"); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); auto disableRootOut = configcontext.options().get("disable-root-output"); GID::mask_t src = alowedSources & GID::getSourcesMask(configcontext.options().get("track-sources")); @@ -110,7 +111,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt)); } bool usePV = configcontext.options().get("use-pv-info"); - specs.emplace_back(o2::globaltracking::getCosmicsMatchingSpec(src, usePV, useMC)); + specs.emplace_back(o2::globaltracking::getCosmicsMatchingSpec(src, usePV, useMC, doStag)); o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, src, src, src, useMC, dummy); // clusters MC is not needed if (usePV) { diff --git a/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx index 937c995626ef5..85483337e35ab 100644 --- a/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/secondary-vertexing-workflow.cxx @@ -88,6 +88,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto enable3body = !configcontext.options().get("disable-3body-finder"); auto enableStrTr = !configcontext.options().get("disable-strangeness-tracker"); auto useGeom = configcontext.options().get("use-full-geometry"); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); GID::mask_t src = allowedSources & GID::getSourcesMask(configcontext.options().get("vertexing-sources")); GID::mask_t dummy, srcClus = GID::includesDet(DetID::TOF, src) ? GID::getSourceMask(GID::TOF) : dummy; // eventually, TPC clusters will be needed for refit @@ -104,7 +105,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!configcontext.options().get("disable-root-input")) { specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt)); } - specs.emplace_back(o2::vertexing::getSecondaryVertexingSpec(src, enableCasc, enable3body, enableStrTr, enableCCDBParams, useMC, useGeom)); + specs.emplace_back(o2::vertexing::getSecondaryVertexingSpec(src, enableCasc, enable3body, enableStrTr, enableCCDBParams, useMC, useGeom, doStag)); // only TOF clusters are needed if TOF is involved, no clusters MC needed WorkflowSpec inputspecs; diff --git a/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx index 8c42871ac05bf..4d47cc15e1306 100644 --- a/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/strangeness-tracking-workflow.cxx @@ -64,13 +64,14 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto useRootInput = !configcontext.options().get("disable-root-input"); auto disableRootOut = configcontext.options().get("disable-root-output"); auto useGeom = configcontext.options().get("use-full-geometry"); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); o2::conf::ConfigurableParam::writeINI("o2strangeness_tracking_workflow_configuration.ini"); GID::mask_t itsSource = GID::getSourceMask(GID::ITS); // ITS tracks and clusters WorkflowSpec specs; - specs.emplace_back(o2::strangeness_tracking::getStrangenessTrackerSpec(itsSource, useMC, useGeom)); + specs.emplace_back(o2::strangeness_tracking::getStrangenessTrackerSpec(itsSource, useMC, useGeom, doStag)); o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, itsSource, itsSource, itsSource, useMC, itsSource); o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); // P-vertex is always needed o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); // S-vertex is always needed diff --git a/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx b/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx index 79ca13430ccd9..05c3f15d6df51 100644 --- a/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/tpcits-match-workflow.cxx @@ -96,7 +96,7 @@ WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& configcont if (!configcontext.options().get("disable-root-input")) { specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt)); } - specs.emplace_back(o2::globaltracking::getTPCITSMatchingSpec(srcL, useFT0, calib, !GID::includesSource(GID::TPC, src), useGeom, useMC, sclOpt.requestCTPLumi)); + specs.emplace_back(o2::globaltracking::getTPCITSMatchingSpec(srcL, useFT0, calib, !GID::includesSource(GID::TPC, src), useGeom, useMC, sclOpt.requestCTPLumi, doStag)); if (!configcontext.options().get("disable-root-output")) { specs.emplace_back(o2::globaltracking::getTrackWriterTPCITSSpec(useMC)); diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h index 3cae8e94b8e68..f9a2c7cdab912 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h @@ -19,7 +19,7 @@ namespace o2::checkresid { /// create a processor spec -o2::framework::DataProcessorSpec getCheckResidSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool drawOnly, bool postProcOnly); +o2::framework::DataProcessorSpec getCheckResidSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool drawOnly, bool postProcOnly, bool itsStag); } // namespace o2::checkresid diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h index 18ce3dbf8ab87..097b4600bcc52 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackMCStudy.h @@ -20,7 +20,7 @@ namespace o2::trackstudy { /// create a processor spec -o2::framework::DataProcessorSpec getTrackMCStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool checkSV); +o2::framework::DataProcessorSpec getTrackMCStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool checkSV, bool itsStag); } // namespace o2::trackstudy diff --git a/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx index 93249946c9011..12546e81b0c9c 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx @@ -17,6 +17,7 @@ #include #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DataFormatsITSMFT/TrkClusRef.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include "ReconstructionDataFormats/GlobalTrackID.h" @@ -70,6 +71,7 @@ using PVertex = o2::dataformats::PrimaryVertex; using V2TRef = o2::dataformats::VtxTrackRef; using VTIndex = o2::dataformats::VtxTrackIndex; using GTrackID = o2::dataformats::GlobalTrackID; +using ITSClusters = o2::itsmft::ClustersPerLayer>; using timeEst = o2::dataformats::TimeStampWithError; class CheckResidSpec final : public Task @@ -101,7 +103,7 @@ class CheckResidSpec final : public Task bool mMeanVertexUpdated = false; float mITSROFrameLengthMUS = 0.f; o2::dataformats::MeanVertexObject mMeanVtx{}; - std::vector> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters + ITSClusters mITSClustersArray; ///< ITS clusters from compact clusters, by composed ID const o2::itsmft::TopologyDictionary* mITSDict = nullptr; ///< cluster patterns dictionary o2::vertexing::PVertexer mVertexer; std::shared_ptr mDataRequest; @@ -240,14 +242,17 @@ void CheckResidSpec::process() const auto itsTracks = mRecoData->getITSTracks(); // const auto itsLbls = mRecoData->getITSTracksMCLabels(); const auto itsClRefs = mRecoData->getITSTracksClusterRefs(); - const auto clusITS = mRecoData->getITSClusters(); - const auto patterns = mRecoData->getITSClustersPatterns(); const auto& params = o2::checkresid::CheckResidConfig::Instance(); - auto pattIt = patterns.begin(); - mITSClustersArray.clear(); - mITSClustersArray.reserve(clusITS.size()); - - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + int nLr = mDataRequest->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITSClustersArray.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITSClustersArray.beginLayer(lr); + const auto clusITS = mRecoData->getITSClusters(lr); + auto pattIt = mRecoData->getITSClustersPatterns(lr).begin(); + mITSClustersArray.getClusters().reserve(mITSClustersArray.size() + clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mITSDict); + } + mITSClustersArray.finalize(); auto pvvec = mRecoData->getPrimaryVertices(); auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks @@ -990,10 +995,11 @@ void CheckResidSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) } } -DataProcessorSpec getCheckResidSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool drawOnly, bool postProcOnly) +DataProcessorSpec getCheckResidSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool drawOnly, bool postProcOnly, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); if (!drawOnly && !postProcOnly) { bool useMC = false; dataRequest->requestTracks(srcTracks, useMC); diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx index 70cdf67099d76..ec70cfc9e2115 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx @@ -33,6 +33,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" #include "FT0Reconstruction/InteractionTag.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "DataFormatsITSMFT/DPLAlpideParam.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/GRPGeomHelper.h" @@ -80,6 +81,7 @@ using VTIndex = o2::dataformats::VtxTrackIndex; using VTIndexV = std::pair; using GTrackID = o2::dataformats::GlobalTrackID; using TBracket = o2::math_utils::Bracketf_t; +using ITSClusters = o2::itsmft::ClustersPerLayer>; using timeEst = o2::dataformats::TimeStampWithError; @@ -121,7 +123,7 @@ class TrackMCStudy final : public Task std::vector mIntBC; ///< interaction global BC wrt TF start std::vector mTPCOcc; ///< TPC occupancy for this interaction time std::vector mITSOcc; //< N ITS clusters in the ROF containing collision - std::vector> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters + ITSClusters mITSClustersArray; ///< ITS clusters from compact clusters, by composed ID const o2::itsmft::TopologyDictionary* mITSDict = nullptr; ///< cluster patterns dictionary bool mCheckSV = false; //< check SV binding (apart from prongs availability) @@ -321,10 +323,18 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) { const auto* digconst = mcReader.getDigitizationContext(); const auto& mcEvRecords = digconst->getEventRecords(false); - int ITSTimeBias = o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC; - int ITSROFLen = o2::itsmft::DPLAlpideParam::Instance().roFrameLengthInBC; - unsigned int rofCount = 0; - const auto ITSClusROFRec = recoData.getITSClustersROFRecords(); + // in the staggered readout every layer has its own ROF length, bias and ROFRecords, hence the + // occupancy is summed over the layer slots, each with its own (monotonic) ROF cursor + const int nLrOcc = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + const auto& alpParITS = o2::itsmft::DPLAlpideParam::Instance(); + std::array, o2::globaltracking::MaxITSLayers> ITSClusROFRec{}; + std::array ITSTimeBias{}, ITSROFLen{}; + std::array rofCount{}; + for (int lr = 0; lr < nLrOcc; lr++) { + ITSClusROFRec[lr] = recoData.getITSClustersROFRecords(lr); + ITSTimeBias[lr] = alpParITS.getROFBiasInBC(lr); + ITSROFLen[lr] = alpParITS.getROFLengthInBC(lr); + } for (const auto& mcIR : mcEvRecords) { long tbc = mcIR.differenceInBC(recoData.startIR); auto& mcVtx = mMCVtVec.emplace_back(); @@ -335,18 +345,21 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) mTPCOcc.push_back(occBin < 0 ? mTBinClOcc[0] : (occBin >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[occBin])); // fill ITS occupancy long gbc = mcIR.toLong(); - while (rofCount < ITSClusROFRec.size()) { - long rofbcMin = ITSClusROFRec[rofCount].getBCData().toLong() + ITSTimeBias, rofbcMax = rofbcMin + ITSROFLen; - if (gbc < rofbcMin) { // IRs and ROFs are sorted, so this IR is prior of all ROFs - mITSOcc.push_back(0); - } else if (gbc < rofbcMax) { - mITSOcc.push_back(ITSClusROFRec[rofCount].getNEntries()); - } else { - rofCount++; // test next ROF - continue; + int itsOcc = 0; + for (int lr = 0; lr < nLrOcc; lr++) { + const auto& rofs = ITSClusROFRec[lr]; + while (rofCount[lr] < rofs.size()) { + long rofbcMin = rofs[rofCount[lr]].getBCData().toLong() + ITSTimeBias[lr], rofbcMax = rofbcMin + ITSROFLen[lr]; + if (gbc < rofbcMin) { // IRs and ROFs are sorted, so this IR is prior of all remaining ROFs of this layer + break; + } else if (gbc < rofbcMax) { + itsOcc += rofs[rofCount[lr]].getNEntries(); + break; + } + rofCount[lr]++; // test next ROF } - break; } + mITSOcc.push_back(itsOcc); // 0 if the IR is before the 1st or after the last ROF of every layer if (mNTPCOccBinLengthInv > 0.f) { mcVtx.occTPCV.resize(params.nOccBinsDrift); int grp = TMath::Max(1, TMath::Nint(params.nTBPerOccBin * mNTPCOccBinLengthInv)); @@ -362,9 +375,6 @@ void TrackMCStudy::process(const o2::globaltracking::RecoContainer& recoData) mcVtx.occTPCV[ib] = smb; } } - if (rofCount >= ITSClusROFRec.size()) { - mITSOcc.push_back(0); // IR after the last ROF - } } } // collect interesting MC particle (tracks and parents) @@ -940,18 +950,21 @@ void TrackMCStudy::fillMCClusterInfo(const o2::globaltracking::RecoContainer& re } } // fill ITS cluster info - const auto* mcITSClusters = recoData.getITSClustersMCLabels(); - const auto& ITSClusters = recoData.getITSClusters(); - for (unsigned int icl = 0; icl < ITSClusters.size(); icl++) { - const auto labels = mcITSClusters->getLabels(icl); - for (const auto& lbl : labels) { - auto entry = mSelMCTracks.find(lbl); - if (entry == mSelMCTracks.end()) { // not selected - continue; + int nLrCl = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + for (int lr = 0; lr < nLrCl; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + const auto* mcITSClusters = recoData.getITSClustersMCLabels(lr); + const auto& ITSClusters = recoData.getITSClusters(lr); + for (unsigned int icl = 0; icl < ITSClusters.size(); icl++) { + const auto labels = mcITSClusters->getLabels(icl); + for (const auto& lbl : labels) { + auto entry = mSelMCTracks.find(lbl); + if (entry == mSelMCTracks.end()) { // not selected + continue; + } + auto& mctr = entry->second.mcTrackInfo; + mctr.nITSCl++; + mctr.pattITSCl |= 0x1 << o2::itsmft::ChipMappingITS::getLayer(ITSClusters[icl].getChipID()); } - auto& mctr = entry->second.mcTrackInfo; - mctr.nITSCl++; - mctr.pattITSCl |= 0x1 << o2::itsmft::ChipMappingITS::getLayer(ITSClusters[icl].getChipID()); } } @@ -1306,17 +1319,22 @@ void TrackMCStudy::processITSTracks(const o2::globaltracking::RecoContainer& rec const auto itsTracks = recoData.getITSTracks(); const auto itsLbls = recoData.getITSTracksMCLabels(); const auto itsClRefs = recoData.getITSTracksClusterRefs(); - const auto clusITS = recoData.getITSClusters(); - const auto patterns = recoData.getITSClustersPatterns(); const auto& params = o2::trackstudy::TrackMCStudyConfig::Instance(); - auto pattIt = patterns.begin(); - mITSClustersArray.clear(); - mITSClustersArray.reserve(clusITS.size()); - - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + int nLr = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITSClustersArray.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITSClustersArray.beginLayer(lr); + const auto clusITS = recoData.getITSClusters(lr); + const auto patterns = recoData.getITSClustersPatterns(lr); + auto pattIt = patterns.begin(); + mITSClustersArray.getClusters().reserve(mITSClustersArray.size() + clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mITSDict); + LOGP(info, "We have {} ITS clusters and the number of patterns is {} on the layer slot {}", clusITS.size(), patterns.size(), lr); + } + mITSClustersArray.finalize(); auto geom = o2::its::GeometryTGeo::Instance(); int ntr = itsLbls.size(); - LOGP(info, "We have {} ITS clusters and the number of patterns is {}, ITSdict:{} NMCLabels: {}", clusITS.size(), patterns.size(), mITSDict != nullptr, itsLbls.size()); + LOGP(info, "In total {} ITS clusters, ITSdict:{} NMCLabels: {}", mITSClustersArray.size(), mITSDict != nullptr, itsLbls.size()); std::vector evord(ntr); std::iota(evord.begin(), evord.end(), 0); @@ -1376,7 +1394,7 @@ void TrackMCStudy::processITSTracks(const o2::globaltracking::RecoContainer& rec } } -DataProcessorSpec getTrackMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool checkSV) +DataProcessorSpec getTrackMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool checkSV, bool itsStag) { std::vector outputs; Options opts{ @@ -1387,6 +1405,7 @@ DataProcessorSpec getTrackMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask {"max-tpc-dcaz", VariantType::Float, 2.f, {"Cut on TPC dcaZ"}}, {"min-x-prop", VariantType::Float, 6.f, {"track should be propagated to this X at least"}}}; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); bool useMC = true; dataRequest->requestTracks(srcTracks, useMC); dataRequest->requestClusters(srcClusters, useMC); diff --git a/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx index 0791d72474ad3..ca1c12e3217a3 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx @@ -59,6 +59,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) bool drawOnly = configcontext.options().get("draw-external-only"); bool postProcOnly = configcontext.options().get("postproc-external-only"); + bool doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); GID::mask_t allowedSourcesClus = GID::getSourcesMask("ITS"); @@ -75,7 +76,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) allowedSourcesTrc = {}; allowedSourcesClus = {}; } - specs.emplace_back(o2::checkresid::getCheckResidSpec(srcTrc, srcCls, drawOnly, postProcOnly)); + specs.emplace_back(o2::checkresid::getCheckResidSpec(srcTrc, srcCls, drawOnly, postProcOnly, doStag)); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit if (!drawOnly) { diff --git a/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx index 07eb271f66580..4b6212d01b018 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/trackMCStudy-workflow.cxx @@ -60,6 +60,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) WorkflowSpec specs; auto useMC = !configcontext.options().get("disable-mc"); auto checkSV = !configcontext.options().get("ignore-sv-check"); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); if (!useMC) { throw std::runtime_error("MC cannot be disabled for this workflow"); } @@ -86,7 +87,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt)); } - specs.emplace_back(o2::trackstudy::getTrackMCStudySpec(srcTrc, srcCls, checkSV)); + specs.emplace_back(o2::trackstudy::getTrackMCStudySpec(srcTrc, srcCls, checkSV, doStag)); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h index 83dbb1bd0f5fe..bb3ebef84032c 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h @@ -68,7 +68,7 @@ class TPCInterpolationDPL : public Task /// create a processor spec framework::DataProcessorSpec getTPCInterpolationSpec(o2::dataformats::GlobalTrackID::mask_t srcCls, o2::dataformats::GlobalTrackID::mask_t srcVtx, o2::dataformats::GlobalTrackID::mask_t srcTrk, - o2::dataformats::GlobalTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput, bool extDetResid); + o2::dataformats::GlobalTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput, bool extDetResid, bool itsStag); } // namespace tpc } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx index fe2677416edc2..2af349be4fd37 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx @@ -159,9 +159,10 @@ void TPCInterpolationDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mask_t srcVtx, GTrackID::mask_t srcTrk, GTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput, bool extDetResid) +DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mask_t srcVtx, GTrackID::mask_t srcTrk, GTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput, bool extDetResid, bool itsStag) { auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); std::vector outputs; if (useMC) { diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx index 65a79a8635a49..e8b6aaa07eaba 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx @@ -105,11 +105,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::writeINI("o2tpcinterpolation-workflow_configuration.ini"); auto useMC = !configcontext.options().get("disable-mc"); useMC = false; // force disabling MC as long as it is not implemented + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); auto sendTrackData = configcontext.options().get("send-track-data"); auto debugOutput = configcontext.options().get("debug-output"); auto extDetResid = !configcontext.options().get("skip-ext-det-residuals"); - specs.emplace_back(o2::tpc::getTPCInterpolationSpec(srcClusters, srcVtx, srcTracks, srcTracksMap, useMC, processITSTPConly, sendTrackData, debugOutput, extDetResid)); + specs.emplace_back(o2::tpc::getTPCInterpolationSpec(srcClusters, srcVtx, srcTracks, srcTracksMap, useMC, processITSTPConly, sendTrackData, debugOutput, extDetResid, doStag)); if (!configcontext.options().get("disable-root-output")) { specs.emplace_back(o2::tpc::getTPCResidualWriterSpec(sendTrackData, debugOutput)); } diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AnomalyStudy.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AnomalyStudy.h index 946b5ef08fd48..67ce02593d670 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AnomalyStudy.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AnomalyStudy.h @@ -22,7 +22,7 @@ namespace study using mask_t = o2::dataformats::GlobalTrackID::mask_t; -o2::framework::DataProcessorSpec getAnomalyStudy(mask_t srcClustersMask, bool useMC); +o2::framework::DataProcessorSpec getAnomalyStudy(mask_t srcClustersMask, bool useMC, bool itsStag); } // namespace study } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AvgClusSize.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AvgClusSize.h index 766bb1f94ca1f..7658fd6bc8fe9 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AvgClusSize.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/AvgClusSize.h @@ -28,7 +28,7 @@ namespace study using mask_t = o2::dataformats::GlobalTrackID::mask_t; -o2::framework::DataProcessorSpec getAvgClusSizeStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader); +o2::framework::DataProcessorSpec getAvgClusSizeStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag); } // namespace study } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/Efficiency.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/Efficiency.h index b6f43bb772390..1c9bb6f7e568a 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/Efficiency.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/Efficiency.h @@ -26,7 +26,7 @@ namespace its namespace study { using mask_t = o2::dataformats::GlobalTrackID::mask_t; -o2::framework::DataProcessorSpec getEfficiencyStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader); +o2::framework::DataProcessorSpec getEfficiencyStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag); float mEtaCuts[2] = {-1.0, 1.0}; float mPtCuts[2] = {0, 10}; /// no cut for B=0 diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h index cd96a9df8dee6..9e852b6379dac 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h @@ -20,7 +20,7 @@ namespace o2::its::study using mask_t = o2::dataformats::GlobalTrackID::mask_t; -o2::framework::DataProcessorSpec getITSBeamBackgroundStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC); +o2::framework::DataProcessorSpec getITSBeamBackgroundStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, bool itsStag); } // namespace o2::its::study #endif diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/PIDStudy.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/PIDStudy.h index 54c7e5f387e90..dadeae0671cfc 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/PIDStudy.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/PIDStudy.h @@ -28,7 +28,7 @@ namespace study using mask_t = o2::dataformats::GlobalTrackID::mask_t; -o2::framework::DataProcessorSpec getPIDStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader); +o2::framework::DataProcessorSpec getPIDStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag); } // namespace study } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackCheck.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackCheck.h index 406677796a9b3..ec0651bfbd018 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackCheck.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackCheck.h @@ -26,7 +26,7 @@ namespace its namespace study { using mask_t = o2::dataformats::GlobalTrackID::mask_t; -o2::framework::DataProcessorSpec getTrackCheckStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader); +o2::framework::DataProcessorSpec getTrackCheckStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag); } // namespace study } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackExtension.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackExtension.h index fd5b93b0f9509..af59a762b2207 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackExtension.h +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/TrackExtension.h @@ -24,7 +24,7 @@ class MCKinematicsReader; namespace its::study { using mask_t = o2::dataformats::GlobalTrackID::mask_t; -o2::framework::DataProcessorSpec getTrackExtensionStudy(mask_t srcTracksMask, mask_t srcClustersMask, std::shared_ptr kineReader); +o2::framework::DataProcessorSpec getTrackExtensionStudy(mask_t srcTracksMask, mask_t srcClustersMask, std::shared_ptr kineReader, bool itsStag); } // namespace its::study } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/AnomalyStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/AnomalyStudy.cxx index c56c2bff2e0d2..5ac3107339f1e 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/AnomalyStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/AnomalyStudy.cxx @@ -197,41 +197,47 @@ void AnomalyStudy::process(o2::globaltracking::RecoContainer& recoData) auto nROF = o2::its::study::AnomalyStudyParamConfig::Instance().nRofTimeFrames; auto nLayProc = o2::its::study::AnomalyStudyParamConfig::Instance().nLayersToProcess; auto doROFAnalysis = o2::its::study::AnomalyStudyParamConfig::Instance().doROFAnalysis; - int rofCount = 0; - auto clusRofRecords = recoData.getITSClustersROFRecords(); - auto compClus = recoData.getITSClusters(); - auto clusPatt = recoData.getITSClustersPatterns(); - - getClusterPatterns(compClus, clusPatt, *mDict); - - auto pattIt = clusPatt.begin(); - std::vector globalClusters; - o2::its::ioutils::convertCompactClusters(compClus, pattIt, globalClusters, mDict); - int lay, sta, ssta, mod, chipInMod; - for (auto& rofRecord : clusRofRecords) { - auto clustersInRof = rofRecord.getROFData(compClus); - auto patternsInRof = rofRecord.getROFData(mPatterns); - auto locClustersInRof = rofRecord.getROFData(globalClusters); - for (unsigned int clusInd{0}; clusInd < clustersInRof.size(); clusInd++) { - const auto& compClus = clustersInRof[clusInd]; - auto& locClus = locClustersInRof[clusInd]; - auto& clusPattern = patternsInRof[clusInd]; - auto gloC = locClus.getXYZGlo(*mGeom); - mChipMapping.expandChipInfoHW(compClus.getChipID(), lay, sta, ssta, mod, chipInMod); - if (lay >= nLayProc) { - continue; - } - float phi = TMath::ATan2(gloC.Y(), gloC.X()); - mTFvsPhiHist[lay]->Fill(phi, mTFCount); - mTFvsPhiClusSizeHist[lay]->Fill(phi, mTFCount, clusPattern.getNPixels()); - if (doROFAnalysis) { - mROFvsPhiHist[lay]->Fill(phi, (mTFCount - 1) * nROF + rofCount); - mROFvsPhiClusSizeHist[lay]->Fill(phi, (mTFCount - 1) * nROF + rofCount, clusPattern.getNPixels()); + // in the staggered readout the clusters and their ROFs are provided per layer, every layer having its + // own ROF length and numbering; all the filled histograms are per layer, hence each layer slot is + // processed with its own ROF counter + int nLr = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + int rofCount = 0; + auto clusRofRecords = recoData.getITSClustersROFRecords(lr); + auto compClus = recoData.getITSClusters(lr); + auto clusPatt = recoData.getITSClustersPatterns(lr); + + getClusterPatterns(compClus, clusPatt, *mDict); + + auto pattIt = clusPatt.begin(); + std::vector globalClusters; + o2::its::ioutils::convertCompactClusters(compClus, pattIt, globalClusters, mDict); + + for (auto& rofRecord : clusRofRecords) { + auto clustersInRof = rofRecord.getROFData(compClus); + auto patternsInRof = rofRecord.getROFData(mPatterns); + auto locClustersInRof = rofRecord.getROFData(globalClusters); + for (unsigned int clusInd{0}; clusInd < clustersInRof.size(); clusInd++) { + const auto& compClus = clustersInRof[clusInd]; + auto& locClus = locClustersInRof[clusInd]; + auto& clusPattern = patternsInRof[clusInd]; + auto gloC = locClus.getXYZGlo(*mGeom); + mChipMapping.expandChipInfoHW(compClus.getChipID(), lay, sta, ssta, mod, chipInMod); + if (lay >= nLayProc) { + continue; + } + float phi = TMath::ATan2(gloC.Y(), gloC.X()); + mTFvsPhiHist[lay]->Fill(phi, mTFCount); + mTFvsPhiClusSizeHist[lay]->Fill(phi, mTFCount, clusPattern.getNPixels()); + if (doROFAnalysis) { + mROFvsPhiHist[lay]->Fill(phi, (mTFCount - 1) * nROF + rofCount); + mROFvsPhiClusSizeHist[lay]->Fill(phi, (mTFCount - 1) * nROF + rofCount, clusPattern.getNPixels()); + } } + ++rofCount; } - ++rofCount; - } + } // loop over the layer slots mStopwatch.Stop(); LOGP(info, "Processed TF: {} in {} s", mTFCount, mStopwatch.RealTime()); } @@ -263,10 +269,11 @@ void AnomalyStudy::getClusterPatterns(gsl::span outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestClusters(srcClustersMask, useMC); dataRequest->requestTracks(GTrackID::getSourcesMask(""), useMC); diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx index f7efae8677516..aa200c9a041bc 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx @@ -25,6 +25,7 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsITS/TrackITS.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/PID.h" @@ -90,7 +91,7 @@ class AvgClusSizeStudy final : public Task float getAverageClusterSize(o2::its::TrackITS*); float calcV0HypoMass(const V0&, PID, PID); void calcAPVars(const V0&, float*, float*); - void getClusterSizes(std::vector&, const gsl::span, gsl::span::iterator&, const o2::itsmft::TopologyDictionary*); + void getClusterSizes(std::vector&, int offs, const gsl::span, gsl::span::iterator&, const o2::itsmft::TopologyDictionary*); void saveHistograms(); void plotHistograms(); void fillEtaBin(float eta, float clusSize, int i); @@ -101,7 +102,7 @@ class AvgClusSizeStudy final : public Task // Data std::shared_ptr mGGCCDBRequest; std::shared_ptr mDataRequest; - std::vector mClusterSizes; + o2::itsmft::ClustersPerLayer mClusterSizes; // addressed by the composed (layer,index) ID gsl::span mInputITSidxs; std::vector mMCTracks; const o2::itsmft::TopologyDictionary* mDict = nullptr; @@ -294,7 +295,7 @@ void AvgClusSizeStudy::run(ProcessingContext& pc) process(recoData); } -void AvgClusSizeStudy::getClusterSizes(std::vector& clusSizeVec, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::itsmft::TopologyDictionary* mdict) +void AvgClusSizeStudy::getClusterSizes(std::vector& clusSizeVec, int offs, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::itsmft::TopologyDictionary* mdict) { for (unsigned int iClus{0}; iClus < ITSclus.size(); ++iClus) { auto& clus = ITSclus[iClus]; @@ -309,18 +310,26 @@ void AvgClusSizeStudy::getClusterSizes(std::vector& clusSizeVec, const gsl: npix = mdict->getNpixels(pattID); patt = mdict->getPattern(pattID); } - clusSizeVec[iClus] = npix; + clusSizeVec[offs + iClus] = npix; } } void AvgClusSizeStudy::loadData(o2::globaltracking::RecoContainer& recoData) { mInputITSidxs = recoData.getITSTracksClusterRefs(); - auto compClus = recoData.getITSClusters(); - auto clusPatt = recoData.getITSClustersPatterns(); - mClusterSizes.resize(compClus.size()); - auto pattIt = clusPatt.begin(); - getClusterSizes(mClusterSizes, compClus, pattIt, mDict); + int nLr = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mClusterSizes.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mClusterSizes.beginLayer(lr); + auto compClus = recoData.getITSClusters(lr); + auto clusPatt = recoData.getITSClustersPatterns(lr); + auto pattIt = clusPatt.begin(); + auto& sizes = mClusterSizes.getClusters(); + int offs = (int)sizes.size(); + sizes.resize(offs + compClus.size()); + getClusterSizes(sizes, offs, compClus, pattIt, mDict); + } + mClusterSizes.finalize(); } void AvgClusSizeStudy::process(o2::globaltracking::RecoContainer& recoData) @@ -646,10 +655,11 @@ void AvgClusSizeStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) } } -DataProcessorSpec getAvgClusSizeStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader) +DataProcessorSpec getAvgClusSizeStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestTracks(srcTracksMask, useMC); dataRequest->requestClusters(srcClustersMask, useMC); dataRequest->requestSecondaryVertices(useMC); diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx index f6ee014abdabd..743d954df41a4 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/Efficiency.cxx @@ -558,6 +558,14 @@ void EfficiencyStudy::run(ProcessingContext& pc) void EfficiencyStudy::initialiseRun(o2::globaltracking::RecoContainer& recoData) { LOGP(info, "--------------- initialiseRun"); + if (recoData.getITSPerLayer()) { + // The duplicated-cluster search scans the cluster ROF whose index equals that of the track ROF and + // relies on the two ROF series being the same. With the staggered readout every layer has its own + // ROF length and numbering, while the track ROFs follow the clock layer only, so the ROF of the + // layer to scan has to be found from the track time instead. This requires deciding whether a + // duplicate is searched in a single ROF or in all the ROFs compatible with the track time bracket. + LOGP(fatal, "EfficiencyStudy does not support the per-layer (staggered) ITS clusters input yet"); + } if (mUseMC) { mTracksMCLabels = recoData.getITSTracksMCLabels(); mClustersMCLCont = recoData.getITSClustersMCLabels(); @@ -2837,10 +2845,11 @@ void EfficiencyStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) } } -DataProcessorSpec getEfficiencyStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader) +DataProcessorSpec getEfficiencyStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestTracks(srcTracksMask, useMC); dataRequest->requestClusters(srcClustersMask, useMC); diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx index fc9e139648672..80742c2dd6503 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx @@ -286,6 +286,14 @@ void ITSBeamBackgroundStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* ob // Custom area void ITSBeamBackgroundStudy::process(o2::globaltracking::RecoContainer& recoData) { + if (recoData.getITSPerLayer()) { + // The study chains consecutive ROFs (ChipSeenInLastROF/ChipSeenInLast2ROF) into a single time + // series over the 3 inner barrel layers and derives the strobe length from the number of ROFs. + // With the staggered readout each layer has its own ROF length and numbering, so it has to be + // decided whether the 3 layers are followed as independent series (and how the ROF counters and + // the background tagging are then normalized). + LOGP(fatal, "ITSBeamBackgroundStudy does not support the per-layer (staggered) ITS clusters input yet"); + } LOGP(info, "Processing RecoContainer"); Counters->Fill(1); @@ -708,13 +716,14 @@ void ITSBeamBackgroundStudy::getClusterPatterns(gsl::span outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestClusters(srcClustersMask, useMC); // dataRequest->requestTracks(GTrackID::getSourcesMask("ZDC"), useMC); diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx index 9a7f6c218cd12..740d4f0a036f5 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx @@ -27,6 +27,7 @@ #include "DataFormatsTPC/TrackTPC.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/PID.h" @@ -106,7 +107,7 @@ class PIDStudy : public Task // Helper functions void saveOutput(); void updateTimeDependentParams(ProcessingContext& pc); - void getClusterSizes(std::vector&, const gsl::span, gsl::span::iterator&, const o2::itsmft::TopologyDictionary*); + void getClusterSizes(std::vector&, int offs, const gsl::span, gsl::span::iterator&, const o2::itsmft::TopologyDictionary*); std::array getTrackClusterSizes(const TrackITS& track); float computeNSigma(PID pid, TrackTPC& tpcTrack, float resolution); @@ -118,8 +119,8 @@ class PIDStudy : public Task // Data std::shared_ptr mGGCCDBRequest; std::shared_ptr mDataRequest; - std::vector mClusterSizes; - gsl::span mClusters; + o2::itsmft::ClustersPerLayer mClusterSizes; // addressed by the composed (layer,index) ID + std::array, o2::globaltracking::MaxITSLayers> mClusters; // per layer slot gsl::span mInputITSidxs; const o2::itsmft::TopologyDictionary* mDict = nullptr; @@ -155,7 +156,7 @@ void PIDStudy::run(ProcessingContext& pc) process(recoData); } -void PIDStudy::getClusterSizes(std::vector& clusSizeVec, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::itsmft::TopologyDictionary* mdict) +void PIDStudy::getClusterSizes(std::vector& clusSizeVec, int offs, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::itsmft::TopologyDictionary* mdict) { for (unsigned int iClus{0}; iClus < ITSclus.size(); ++iClus) { auto& clus = ITSclus[iClus]; @@ -170,18 +171,25 @@ void PIDStudy::getClusterSizes(std::vector& clusSizeVec, const gsl::spangetNpixels(pattID); patt = mdict->getPattern(pattID); } - clusSizeVec[iClus] = npix; + clusSizeVec[offs + iClus] = npix; } } void PIDStudy::loadData(o2::globaltracking::RecoContainer& recoData) { mInputITSidxs = recoData.getITSTracksClusterRefs(); - mClusters = recoData.getITSClusters(); - auto clusPatt = recoData.getITSClustersPatterns(); - mClusterSizes.resize(mClusters.size()); - auto pattIt = clusPatt.begin(); - getClusterSizes(mClusterSizes, mClusters, pattIt, mDict); + int nLr = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mClusterSizes.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mClusterSizes.beginLayer(lr); + mClusters[lr] = recoData.getITSClusters(lr); + auto pattIt = recoData.getITSClustersPatterns(lr).begin(); + auto& sizes = mClusterSizes.getClusters(); + int offs = (int)sizes.size(); + sizes.resize(offs + mClusters[lr].size()); + getClusterSizes(sizes, offs, mClusters[lr], pattIt, mDict); + } + mClusterSizes.finalize(); } void PIDStudy::process(o2::globaltracking::RecoContainer& recoData) @@ -272,8 +280,9 @@ std::array PIDStudy::getTrackClusterSizes(const TrackITS& track) auto firstClus = track.getFirstClusterEntry(); auto ncl = track.getNumberOfClusters(); for (int icl = 0; icl < ncl; icl++) { - auto& clus = mClusters[mInputITSidxs[firstClus + icl]]; - auto& clSize = mClusterSizes[mInputITSidxs[firstClus + icl]]; + int clID = mInputITSidxs[firstClus + icl]; + auto& clus = mClusters[o2::itsmft::clusID2Layer(clID)][o2::itsmft::clusID2Index(clID)]; + auto& clSize = mClusterSizes[clID]; auto layer = geom->getLayer(clus.getSensorID()); clusSizes[layer] = clSize; } @@ -324,10 +333,11 @@ float PIDStudy::computeNSigma(PID pid, TrackTPC& tpcTrack, float resolution) return nSigma; } -DataProcessorSpec getPIDStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader) +DataProcessorSpec getPIDStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestTracks(srcTracksMask, useMC); dataRequest->requestClusters(srcClustersMask, useMC); diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx index 482f9bf1cc97d..05f21b9897f5e 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx @@ -16,6 +16,7 @@ #include "SimulationDataFormat/MCTrack.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "CommonUtils/TreeStreamRedirector.h" #include "Framework/Task.h" @@ -98,9 +99,10 @@ class TrackCheckStudy final : public Task gsl::span mTracksROFRecords; gsl::span mTracks; gsl::span mTracksMCLabels; - gsl::span mClusters; + std::array, o2::globaltracking::MaxITSLayers> mClusters; // per layer slot + int mNLayerSlots = 1; // 1 for the monolithic input gsl::span mInputITSidxs; - const o2::dataformats::MCLabelContainer* mClustersMCLCont; + std::array mClustersMCLCont{}; // per layer slot // Data GTrackID::mask_t mTracksSrc{}; @@ -433,12 +435,18 @@ void TrackCheckStudy::initialiseRun(o2::globaltracking::RecoContainer& recoData) mTracksROFRecords = recoData.getITSTracksROFRecords(); mTracks = recoData.getITSTracks(); mTracksMCLabels = recoData.getITSTracksMCLabels(); - mClusters = recoData.getITSClusters(); - mClustersMCLCont = recoData.getITSClustersMCLabels(); + mNLayerSlots = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + size_t nClTot = 0, nClLbl = 0; + for (int lr = 0; lr < mNLayerSlots; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mClusters[lr] = recoData.getITSClusters(lr); + mClustersMCLCont[lr] = recoData.getITSClustersMCLabels(lr); + nClTot += mClusters[lr].size(); + nClLbl += mClustersMCLCont[lr]->getIndexedSize(); + } mInputITSidxs = recoData.getITSTracksClusterRefs(); LOGP(info, "** Found in {} rofs:\n\t- {} clusters with {} labels\n\t- {} tracks with {} labels", - mTracksROFRecords.size(), mClusters.size(), mClustersMCLCont->getIndexedSize(), mTracks.size(), mTracksMCLabels.size()); + mTracksROFRecords.size(), nClTot, nClLbl, mTracks.size(), mTracksMCLabels.size()); LOGP(info, "** Found {} sources from kinematic files", mKineReader->getNSources()); } @@ -469,20 +477,22 @@ void TrackCheckStudy::process() } LOGP(info, "** Creating particle/clusters correspondance ... "); for (auto iSource{0}; iSource < mParticleInfo.size(); ++iSource) { - for (auto iCluster{0}; iCluster < mClusters.size(); ++iCluster) { - auto labs = mClustersMCLCont->getLabels(iCluster); // ideally I can have more than one label per cluster - for (auto& lab : labs) { - if (!lab.isValid()) { - continue; // We want to skip channels related to noise, e.g. sID = 99: QED + for (int lr = 0; lr < mNLayerSlots; lr++) { + for (auto iCluster{0}; iCluster < mClusters[lr].size(); ++iCluster) { + auto labs = mClustersMCLCont[lr]->getLabels(iCluster); // ideally I can have more than one label per cluster + for (auto& lab : labs) { + if (!lab.isValid()) { + continue; // We want to skip channels related to noise, e.g. sID = 99: QED + } + int trackID, evID, srcID; + bool fake; + lab.get(trackID, evID, srcID, fake); + auto& cluster = mClusters[lr][iCluster]; + auto layer = mGeometry->getLayer(cluster.getSensorID()); + mParticleInfo[srcID][evID][trackID].clusters |= (1 << layer); } - int trackID, evID, srcID; - bool fake; - lab.get(trackID, evID, srcID, fake); - auto& cluster = mClusters[iCluster]; - auto layer = mGeometry->getLayer(cluster.getSensorID()); - mParticleInfo[srcID][evID][trackID].clusters |= (1 << layer); } - } + } // loop over the layer slots } LOGP(info, "** Analysing tracks ... "); int unaccounted{0}, good{0}, fakes{0}; @@ -715,7 +725,8 @@ void TrackCheckStudy::process() histLength3FakeNoCl[len - 4][idxPart]->Fill(iLayer); } } - auto labs = mClustersMCLCont->getLabels(mInputITSidxs[firstclu - 1 - iLayer + track.getFirstClusterLayer() + nclu]); + int clIDlbl = mInputITSidxs[firstclu - 1 - iLayer + track.getFirstClusterLayer() + nclu]; + auto labs = mClustersMCLCont[o2::itsmft::clusID2Layer(clIDlbl)]->getLabels(o2::itsmft::clusID2Index(clIDlbl)); for (auto& lab : labs) { if (!lab.isValid()) { @@ -1353,10 +1364,11 @@ void TrackCheckStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) { } -DataProcessorSpec getTrackCheckStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader) +DataProcessorSpec getTrackCheckStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC, std::shared_ptr kineReader, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestTracks(srcTracksMask, useMC); dataRequest->requestClusters(srcClustersMask, useMC); diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackExtension.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackExtension.cxx index 6826d441cc815..f5c9d56c3f91f 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackExtension.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackExtension.cxx @@ -11,6 +11,7 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "DataFormatsITS/TrackITS.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DetectorsBase/GRPGeomHelper.h" @@ -96,9 +97,10 @@ class TrackExtensionStudy final : public Task gsl::span mTracksROFRecords; gsl::span mTracks; gsl::span mTracksMCLabels; - gsl::span mClusters; + std::array, o2::globaltracking::MaxITSLayers> mClusters; // per layer slot + int mNLayerSlots = 1; // 1 for the monolithic input gsl::span mInputITSidxs; - const o2::dataformats::MCLabelContainer* mClustersMCLCont{}; + std::array mClustersMCLCont{}; // per layer slot GTrackID::mask_t mTracksSrc{}; std::shared_ptr mDataRequest; @@ -253,12 +255,18 @@ void TrackExtensionStudy::run(ProcessingContext& pc) mTracksROFRecords = recoData.getITSTracksROFRecords(); mTracks = recoData.getITSTracks(); mTracksMCLabels = recoData.getITSTracksMCLabels(); - mClusters = recoData.getITSClusters(); - mClustersMCLCont = recoData.getITSClustersMCLabels(); + mNLayerSlots = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + size_t nClTot = 0, nClLbl = 0; + for (int lr = 0; lr < mNLayerSlots; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mClusters[lr] = recoData.getITSClusters(lr); + mClustersMCLCont[lr] = recoData.getITSClustersMCLabels(lr); + nClTot += mClusters[lr].size(); + nClLbl += mClustersMCLCont[lr]->getIndexedSize(); + } mInputITSidxs = recoData.getITSTracksClusterRefs(); LOGP(info, "** Found in {} rofs:\n\t- {} clusters with {} labels\n\t- {} tracks with {} labels", - mTracksROFRecords.size(), mClusters.size(), mClustersMCLCont->getIndexedSize(), mTracks.size(), mTracksMCLabels.size()); + mTracksROFRecords.size(), nClTot, nClLbl, mTracks.size(), mTracksMCLabels.size()); LOGP(info, "** Found {} sources from kinematic files", mKineReader->getNSources()); process(); @@ -293,23 +301,25 @@ void TrackExtensionStudy::process() } LOGP(info, "** Creating particle/clusters correspondance ... "); for (auto iSource{0}; iSource < mParticleInfo.size(); ++iSource) { - for (auto iCluster{0}; iCluster < mClusters.size(); ++iCluster) { - auto labs = mClustersMCLCont->getLabels(iCluster); // ideally I can have more than one label per cluster - for (auto& lab : labs) { - if (!lab.isValid()) { - continue; // We want to skip channels related to noise, e.g. sID = 99: QED - } - int trackID, evID, srcID; - bool fake; - lab.get(trackID, evID, srcID, fake); - auto& cluster = mClusters[iCluster]; - auto layer = mGeometry->getLayer(cluster.getSensorID()); - mParticleInfo[srcID][evID][trackID].clusters |= (1 << layer); - if (fake) { - mParticleInfo[srcID][evID][trackID].fakeClusters |= (1 << layer); + for (int lr = 0; lr < mNLayerSlots; lr++) { + for (auto iCluster{0}; iCluster < mClusters[lr].size(); ++iCluster) { + auto labs = mClustersMCLCont[lr]->getLabels(iCluster); // ideally I can have more than one label per cluster + for (auto& lab : labs) { + if (!lab.isValid()) { + continue; // We want to skip channels related to noise, e.g. sID = 99: QED + } + int trackID, evID, srcID; + bool fake; + lab.get(trackID, evID, srcID, fake); + auto& cluster = mClusters[lr][iCluster]; + auto layer = mGeometry->getLayer(cluster.getSensorID()); + mParticleInfo[srcID][evID][trackID].clusters |= (1 << layer); + if (fake) { + mParticleInfo[srcID][evID][trackID].fakeClusters |= (1 << layer); + } } } - } + } // loop over the layer slots } LOGP(info, "** Analysing tracks ... "); @@ -628,10 +638,11 @@ void TrackExtensionStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) } } -DataProcessorSpec getTrackExtensionStudy(mask_t srcTracksMask, mask_t srcClustersMask, std::shared_ptr kineReader) +DataProcessorSpec getTrackExtensionStudy(mask_t srcTracksMask, mask_t srcClustersMask, std::shared_ptr kineReader, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestTracks(srcTracksMask, true); dataRequest->requestClusters(srcClustersMask, true); diff --git a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx index 405e80475bd25..754cb2deac684 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx @@ -71,6 +71,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); auto useMC = !configcontext.options().get("disable-mc"); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); std::shared_ptr mcKinematicsReader; if (useMC) { @@ -90,14 +91,14 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) srcTrc = GID::getSourcesMask(configcontext.options().get("track-sources")); srcCls = GID::getSourcesMask(configcontext.options().get("cluster-sources")); o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); - specs.emplace_back(o2::its::study::getAvgClusSizeStudy(srcTrc, srcCls, useMC, mcKinematicsReader)); + specs.emplace_back(o2::its::study::getAvgClusSizeStudy(srcTrc, srcCls, useMC, mcKinematicsReader, doStag)); } if (configcontext.options().get("pid-study")) { anyStudy = true; srcTrc = GID::getSourcesMask(configcontext.options().get("track-sources")); srcCls = GID::getSourcesMask(configcontext.options().get("cluster-sources")); o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); - specs.emplace_back(o2::its::study::getPIDStudy(srcTrc, srcCls, useMC, mcKinematicsReader)); + specs.emplace_back(o2::its::study::getPIDStudy(srcTrc, srcCls, useMC, mcKinematicsReader, doStag)); } if (configcontext.options().get("track-study")) { anyStudy = true; @@ -106,7 +107,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!configcontext.options().get("input-from-upstream")) { o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); } - specs.emplace_back(o2::its::study::getTrackCheckStudy(GID::getSourcesMask("ITS"), GID::getSourcesMask("ITS"), useMC, mcKinematicsReader)); + specs.emplace_back(o2::its::study::getTrackCheckStudy(GID::getSourcesMask("ITS"), GID::getSourcesMask("ITS"), useMC, mcKinematicsReader, doStag)); } if (configcontext.options().get("anomaly-study")) { anyStudy = true; @@ -114,7 +115,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!configcontext.options().get("input-from-upstream")) { o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); } - specs.emplace_back(o2::its::study::getAnomalyStudy(srcCls, useMC)); + specs.emplace_back(o2::its::study::getAnomalyStudy(srcCls, useMC, doStag)); } if (configcontext.options().get("its-beambkg-study")) { anyStudy = true; @@ -125,7 +126,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!configcontext.options().get("input-from-upstream")) { o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); } - specs.emplace_back(o2::its::study::getITSBeamBackgroundStudy(srcTrc, srcCls, useMC)); + specs.emplace_back(o2::its::study::getITSBeamBackgroundStudy(srcTrc, srcCls, useMC, doStag)); } if (configcontext.options().get("track-extension-study")) { if (!useMC) { @@ -135,7 +136,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) srcTrc = GID::getSourcesMask(configcontext.options().get("track-sources")); srcCls = GID::getSourcesMask("ITS"); o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, true, srcCls, srcTrc); - specs.emplace_back(o2::its::study::getTrackExtensionStudy(srcTrc, srcCls, mcKinematicsReader)); + specs.emplace_back(o2::its::study::getTrackExtensionStudy(srcTrc, srcCls, mcKinematicsReader, doStag)); } if (configcontext.options().get("efficiency-study")) { anyStudy = true; @@ -144,7 +145,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!configcontext.options().get("input-from-upstream")) { o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); } - specs.emplace_back(o2::its::study::getEfficiencyStudy(GID::getSourcesMask("ITS"), GID::getSourcesMask("ITS"), useMC, mcKinematicsReader)); + specs.emplace_back(o2::its::study::getEfficiencyStudy(GID::getSourcesMask("ITS"), GID::getSourcesMask("ITS"), useMC, mcKinematicsReader, doStag)); } if (!anyStudy) { LOGP(info, "No study selected, dryrunning"); diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx index a0e8d708cffa2..732a68208732a 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx @@ -26,6 +26,7 @@ #include "ITSMFTTracking/ITSTrackingConfigParam.h" #include "ITStracking/TrackingInterface.h" +#include "DataFormatsITSMFT/ClusterID.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "DataFormatsITSMFT/PhysTrigger.h" #include "DataFormatsTRD/TriggerRecord.h" @@ -333,7 +334,9 @@ void ITSTrackingInterface::run(framework::ProcessingContext& pc) auto clid = trc.getClusterIndex(ic); if (clid >= 0) { trc.setClusterSize(ic, mTimeFrame->getClusterSize((mDoStaggering) ? ic : 0, clid)); - allClusIdx.push_back(clid); + // with the per-layer clusters input the index is local to the layer, hence the layer must be + // encoded into the stored reference; with the monolithic input the composed ID is just the index + allClusIdx.push_back(o2::itsmft::composeClusID((mDoStaggering) ? ic : 0, clid)); nclf++; } } diff --git a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx index 5e8ee4b99c092..b22469535bd03 100644 --- a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx @@ -33,7 +33,7 @@ namespace itsmft { template -ClusterReader::ClusterReader(bool useMC, bool doStag, bool usePatterns, bool triggerOut) : mUseMC(useMC), mUsePatterns(usePatterns), mTriggerOut(triggerOut), mDetName(Origin.as()), mDetNameLC(mDetName) +ClusterReader::ClusterReader(bool useMC, bool doStag, bool usePatterns, bool triggerOut) : mUseMC(useMC), mDoStaggering(doStag), mUsePatterns(usePatterns), mTriggerOut(triggerOut), mDetName(Origin.as()), mDetNameLC(mDetName) { std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower); if (doStag) { diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h index 99e85cf19101a..aa7b71510eebe 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h @@ -39,6 +39,7 @@ #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "DetectorsBase/Propagator.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "GPUTRDRecoParam.h" #include "TRDBase/Geometry.h" #include "CommonUtils/TreeStreamRedirector.h" @@ -245,6 +246,7 @@ class TrackInterpolation { public: using MatCorrType = o2::base::Propagator::MatCorrType; + using ITSClusters = o2::itsmft::ClustersPerLayer>; /// Default constructor TrackInterpolation() = default; @@ -468,7 +470,7 @@ class TrackInterpolation // ITS specific input only needed for debugging gsl::span mITSTrackClusIdx; ///< input ITS track cluster indices span - std::vector> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters + ITSClusters mITSClustersArray; ///< ITS clusters created in run() from compact clusters, by composed ID std::vector mITSRefitSeedID; ///< seed ID first using refitted ITS track const o2::itsmft::TopologyDictionary* mITSDict = nullptr; ///< cluster patterns dictionary diff --git a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx index 571bc00a48763..a3600666ced51 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx @@ -351,13 +351,18 @@ void TrackInterpolation::process() return; } mITSTrackClusIdx = mRecoCont->getITSTracksClusterRefs(); - const auto clusITS = mRecoCont->getITSClusters(); - const auto patterns = mRecoCont->getITSClustersPatterns(); - auto pattIt = patterns.begin(); - mITSClustersArray.clear(); - mITSClustersArray.reserve(clusITS.size()); - LOGP(info, "We have {} ITS clusters and the number of patterns is {}", clusITS.size(), patterns.size()); - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + int nLr = mRecoCont->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITSClustersArray.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITSClustersArray.beginLayer(lr); + const auto clusITS = mRecoCont->getITSClusters(lr); + const auto patterns = mRecoCont->getITSClustersPatterns(lr); + auto pattIt = patterns.begin(); + mITSClustersArray.getClusters().reserve(mITSClustersArray.size() + clusITS.size()); + LOGP(info, "We have {} ITS clusters and the number of patterns is {} on the layer slot {}", clusITS.size(), patterns.size(), lr); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mITSDict); + } + mITSClustersArray.finalize(); } // In case we have more input tracks available than are required per TF diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h index 244a3bc0a9a8c..8f83b98c4f075 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h @@ -23,6 +23,7 @@ #include "GPUTRDRecoParam.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "DataFormatsTRD/TrackTRD.h" #include "DataFormatsTRD/TrackTriggerRecord.h" #include "DataFormatsTRD/PID.h" @@ -51,6 +52,8 @@ namespace trd class TRDGlobalTracking : public o2::framework::Task { public: + using ITSClusters = o2::itsmft::ClustersPerLayer>; + TRDGlobalTracking(bool useMC, bool withPID, PIDPolicy policy, std::shared_ptr dataRequest, std::shared_ptr gr, o2::dataformats::GlobalTrackID::mask_t src, bool trigRecFilterActive, bool strict, bool requestCTPLumi) : mUseMC(useMC), mWithPID(withPID), mDataRequest(dataRequest), mGGCCDBRequest(gr), mTrkMask(src), mTrigRecFilter(trigRecFilterActive), mStrict(strict), mPolicy(policy), mRequestCTPLumi(requestCTPLumi) {} ~TRDGlobalTracking() override = default; @@ -99,7 +102,7 @@ class TRDGlobalTracking : public o2::framework::Task gsl::span mITSABRefsArray; ///< input ITS-TPC Afterburner ITS tracklets references gsl::span mITSTrackClusIdx; ///< input ITS track cluster indices span gsl::span mITSABTrackClusIdx; ///< input ITSAB track cluster indices span - std::vector> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters + ITSClusters mITSClustersArray; ///< ITS clusters created in run() from compact clusters, by composed ID const o2::itsmft::TopologyDictionary* mITSDict = nullptr; ///< ITS cluster patterns dictionary #ifdef ENABLE_UPGRADES const o2::its3::TopologyDictionary* mIT3Dict = nullptr; ///< IT3 cluster patterns dictionary @@ -114,7 +117,7 @@ class TRDGlobalTracking : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, o2::dataformats::GlobalTrackID::mask_t src, bool trigRecFilterActive, bool strict /* = false*/, bool withPID /* = false*/, PIDPolicy policy /* = PIDPolicy::DEFAULT*/, bool requestCTPLumi); +framework::DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, o2::dataformats::GlobalTrackID::mask_t src, bool trigRecFilterActive, bool strict /* = false*/, bool withPID /* = false*/, PIDPolicy policy /* = PIDPolicy::DEFAULT*/, bool requestCTPLumi, bool itsStag); } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx index 2539d09eb509b..4cbe5ca7a3609 100644 --- a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx @@ -331,20 +331,24 @@ void TRDGlobalTracking::run(ProcessingContext& pc) mITSTrackClusIdx = inputTracks.getITSTracksClusterRefs(); mITSABRefsArray = inputTracks.getITSABRefs(); mITSABTrackClusIdx = inputTracks.getITSABClusterRefs(); - const auto clusITS = inputTracks.getITSClusters(); - const auto patterns = inputTracks.getITSClustersPatterns(); - auto pattIt = patterns.begin(); - mITSClustersArray.clear(); - mITSClustersArray.reserve(clusITS.size()); + int nLr = mDataRequest->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITSClustersArray.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITSClustersArray.beginLayer(lr); + const auto clusITS = inputTracks.getITSClusters(lr); + auto pattIt = inputTracks.getITSClustersPatterns(lr).begin(); + mITSClustersArray.getClusters().reserve(mITSClustersArray.size() + clusITS.size()); #ifdef ENABLE_UPGRADES - if (o2::GlobalParams::Instance().withITS3) { - o2::its3::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mIT3Dict); - } else { - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); - } + if (o2::GlobalParams::Instance().withITS3) { + o2::its3::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mIT3Dict); + } else { + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mITSDict); + } #else - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mITSDict); #endif + } + mITSClustersArray.finalize(); } LOGF(info, "There are %i tracklets in total from %i trigger records", mChainTracking->mIOPtrs.nTRDTracklets, mChainTracking->mIOPtrs.nTRDTriggerRecords); @@ -971,11 +975,12 @@ void TRDGlobalTracking::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, GTrackID::mask_t src, bool trigRecFilterActive, bool strict, bool withPID, PIDPolicy policy, bool requestCTPLumi) +DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, GTrackID::mask_t src, bool trigRecFilterActive, bool strict, bool withPID, PIDPolicy policy, bool requestCTPLumi, bool itsStag) { std::vector outputs; uint32_t ss = o2::globaltracking::getSubSpec(strict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard); std::shared_ptr dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); if (strict) { dataRequest->setMatchingInputStrict(); } diff --git a/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx b/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx index bc0da73c09dd5..e5db74716cbd3 100644 --- a/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx +++ b/Detectors/TRD/workflow/src/trd-tracking-workflow.cxx @@ -89,6 +89,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto pulseHeight = configcontext.options().get("enable-ph"); auto digitsSpec = configcontext.options().get("trd-digits-spec"); auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); bool rootInput = !configcontext.options().get("disable-root-input"); GTrackID::mask_t srcTRD = allowedSources & GTrackID::getSourcesMask(configcontext.options().get("track-sources")); if (strict && (srcTRD & ~GTrackID::getSourcesMask("TPC")).any()) { @@ -118,7 +119,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (!configcontext.options().get("disable-root-input")) { specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt)); } - specs.emplace_back(o2::trd::getTRDGlobalTrackingSpec(useMC, srcTRD, trigRecFilterActive, strict, pid, policy, sclOpt.requestCTPLumi)); + specs.emplace_back(o2::trd::getTRDGlobalTrackingSpec(useMC, srcTRD, trigRecFilterActive, strict, pid, policy, sclOpt.requestCTPLumi, doStag)); if (vdexb || gain) { specs.emplace_back(o2::trd::getTRDTrackBasedCalibSpec(srcTRD, vdexb, gain)); } diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h index d171454bc4794..ddf450beabd01 100644 --- a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h @@ -29,7 +29,7 @@ enum class OutputOpt : uint8_t { }; using OutputEnum = utils::EnumFlags; -o2::framework::DataProcessorSpec getAlignmentSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, bool withPV, bool withITS3, OutputEnum out); +o2::framework::DataProcessorSpec getAlignmentSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, bool withPV, bool withITS3, OutputEnum out, bool itsStag); } // namespace o2::its3::align #endif diff --git a/Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx b/Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx index edba6718ab268..142dd55579dde 100644 --- a/Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx +++ b/Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx @@ -31,6 +31,7 @@ #include "Framework/Task.h" #include "ITSBase/GeometryTGeo.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/Propagator.h" #include "DetectorsBase/GRPGeomHelper.h" @@ -124,7 +125,7 @@ class AlignmentSpec final : public Task bool prepareITSTrack(int iTrk, const o2::its::TrackITS& itsTrack, Track& resTrack); // prepare ITS measuremnt points - void prepareMeasurments(std::span clusters, std::span pattIt); + void prepareMeasurments(); // build track to vertex association void buildT2V(); @@ -143,7 +144,7 @@ class AlignmentSpec final : public Task const o2::its3::TopologyDictionary* mIT3Dict{nullptr}; o2::globaltracking::RecoContainer* mRecoData = nullptr; std::unique_ptr mcReader; - std::vector mITSTrackingInfo; + o2::itsmft::ClustersPerLayer mITSTrackingInfo; // addressed by the composed (layer,index) ID std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; std::unique_ptr mHierarchy; // tree-hiearchy @@ -194,13 +195,11 @@ void AlignmentSpec::process() const auto bz = prop->getNominalBz(); const auto itsTracks = mRecoData->getITSTracks(); const auto itsClRefs = mRecoData->getITSTracksClusterRefs(); - const auto clusITS = mRecoData->getITSClusters(); - const auto patterns = mRecoData->getITSClustersPatterns(); std::span mcLbls; if (mUseMC) { mcLbls = mRecoData->getITSTracksMCLabels(); } - prepareMeasurments(clusITS, patterns); + prepareMeasurments(); if (mWithPV) { buildT2V(); @@ -731,53 +730,60 @@ bool AlignmentSpec::prepareITSTrack(int iTrk, const o2::its::TrackITS& itsTrack, return true; } -void AlignmentSpec::prepareMeasurments(std::span clusters, std::span patterns) +void AlignmentSpec::prepareMeasurments() { - LOGP(info, "Preparing {} measurments", clusters.size()); auto geom = its::GeometryTGeo::Instance(); geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); - mITSTrackingInfo.clear(); - mITSTrackingInfo.reserve(clusters.size()); - auto pattIt = patterns.begin(); - for (const auto& cls : clusters) { - const auto sens = cls.getSensorID(); - const auto lay = geom->getLayer(sens); - double sigmaY2{0}, sigmaZ2{0}; - math_utils::Point3D locXYZ; - if (mIsITS3) { - locXYZ = o2::its3::ioutils::extractClusterData(cls, pattIt, mIT3Dict, sigmaY2, sigmaZ2); - } else { - locXYZ = o2::its::ioutils::extractClusterData(cls, pattIt, mITSDict, sigmaY2, sigmaZ2); - } - sigmaY2 += mParams->extraClsErrY[lay] * mParams->extraClsErrY[lay]; - sigmaZ2 += mParams->extraClsErrZ[lay] * mParams->extraClsErrZ[lay]; - // Transformation to the local --> global - const auto gloXYZ = geom->getMatrixL2G(sens) * locXYZ; - // Inverse transformation to the local --> tracking - auto trkXYZf = geom->getMatrixT2L(sens) ^ locXYZ; - o2::math_utils::Point3D trkXYZ; - trkXYZ.SetCoordinates(trkXYZf.X(), trkXYZf.Y(), trkXYZf.Z()); - // Tracking alpha angle - // We want that each cluster rotates its tracking frame to the clusters phi - // that way the track linearization around the measurement is less biases to the arc - // this means automatically that the measurement on the arc is at 0 for the curved layers - double alpha = geom->getSensorRefAlpha(sens); - double x = trkXYZ.x(); - if (mIsITS3 && constants::detID::isDetITS3(sens)) { - trkXYZ.SetY(0.f); - // alpha&x always have to be defined wrt to the global Z axis! - x = std::hypot(gloXYZ.x(), gloXYZ.y()); - trkXYZ.SetX(x); - alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); - auto chip = constants::detID::getSensorID(sens); - sigmaY2 += mParams->extraClsErrY[chip] * mParams->extraClsErrY[chip]; - sigmaZ2 += mParams->extraClsErrZ[chip] * mParams->extraClsErrZ[chip]; + int nLr = mRecoData->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITSTrackingInfo.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITSTrackingInfo.beginLayer(lr); + const auto clusters = mRecoData->getITSClusters(lr); + const auto patterns = mRecoData->getITSClustersPatterns(lr); + LOGP(info, "Preparing {} measurments of the layer slot {}", clusters.size(), lr); + mITSTrackingInfo.getClusters().reserve(mITSTrackingInfo.size() + clusters.size()); + auto pattIt = patterns.begin(); + for (const auto& cls : clusters) { + const auto sens = cls.getSensorID(); + const auto lay = geom->getLayer(sens); + double sigmaY2{0}, sigmaZ2{0}; + math_utils::Point3D locXYZ; + if (mIsITS3) { + locXYZ = o2::its3::ioutils::extractClusterData(cls, pattIt, mIT3Dict, sigmaY2, sigmaZ2); + } else { + locXYZ = o2::its::ioutils::extractClusterData(cls, pattIt, mITSDict, sigmaY2, sigmaZ2); + } + sigmaY2 += mParams->extraClsErrY[lay] * mParams->extraClsErrY[lay]; + sigmaZ2 += mParams->extraClsErrZ[lay] * mParams->extraClsErrZ[lay]; + // Transformation to the local --> global + const auto gloXYZ = geom->getMatrixL2G(sens) * locXYZ; + // Inverse transformation to the local --> tracking + auto trkXYZf = geom->getMatrixT2L(sens) ^ locXYZ; + o2::math_utils::Point3D trkXYZ; + trkXYZ.SetCoordinates(trkXYZf.X(), trkXYZf.Y(), trkXYZf.Z()); + // Tracking alpha angle + // We want that each cluster rotates its tracking frame to the clusters phi + // that way the track linearization around the measurement is less biases to the arc + // this means automatically that the measurement on the arc is at 0 for the curved layers + double alpha = geom->getSensorRefAlpha(sens); + double x = trkXYZ.x(); + if (mIsITS3 && constants::detID::isDetITS3(sens)) { + trkXYZ.SetY(0.f); + // alpha&x always have to be defined wrt to the global Z axis! + x = std::hypot(gloXYZ.x(), gloXYZ.y()); + trkXYZ.SetX(x); + alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); + auto chip = constants::detID::getSensorID(sens); + sigmaY2 += mParams->extraClsErrY[chip] * mParams->extraClsErrY[chip]; + sigmaZ2 += mParams->extraClsErrZ[chip] * mParams->extraClsErrZ[chip]; + } + math_utils::bringToPMPid(alpha); + mITSTrackingInfo.getClusters().emplace_back(sens, lay, x, alpha, + std::array{trkXYZ.y(), trkXYZ.z()}, + std::array{sigmaY2, 0., sigmaZ2}); } - math_utils::bringToPMPid(alpha); - mITSTrackingInfo.emplace_back(sens, lay, x, alpha, - std::array{trkXYZ.y(), trkXYZ.z()}, - std::array{sigmaY2, 0., sigmaZ2}); - } + } // loop over the layer slots + mITSTrackingInfo.finalize(); } void AlignmentSpec::buildT2V() @@ -941,9 +947,10 @@ void AlignmentSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) } } -DataProcessorSpec getAlignmentSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, bool withPV, bool withITS, OutputEnum out) +DataProcessorSpec getAlignmentSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, bool withPV, bool withITS, OutputEnum out, bool itsStag) { auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); std::shared_ptr ggRequest{nullptr}; if (!out[OutputOpt::MilleRes]) { dataRequest->requestTracks(srcTracks, useMC); diff --git a/Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx b/Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx index fd9495fb3f206..31ab211d6709c 100644 --- a/Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx +++ b/Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx @@ -54,6 +54,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfg) const auto useMC = !cfg.options().get("disable-mc"); const auto withPV = !cfg.options().get("without-pv"); const auto withITS = cfg.options().get("with-its"); + const auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(cfg); const OutputEnum output(cfg.options().get("output")); WorkflowSpec specs; @@ -66,7 +67,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfg) specs.emplace_back(o2::globaltracking::getNoInpDummyOutSpec(0)); } - specs.emplace_back(o2::its3::align::getAlignmentSpec(srcTrc, srcCls, useMC, withPV, withITS, output)); + specs.emplace_back(o2::its3::align::getAlignmentSpec(srcTrc, srcCls, useMC, withPV, withITS, output, doStag)); o2::raw::HBFUtilsInitializer hbfIni(cfg, specs); return std::move(specs); diff --git a/Detectors/Upgrades/ITS3/study/include/ITS3TrackingStudy/TrackingStudy.h b/Detectors/Upgrades/ITS3/study/include/ITS3TrackingStudy/TrackingStudy.h index 6d55dfc80aa8a..9d2ee9e1a009b 100644 --- a/Detectors/Upgrades/ITS3/study/include/ITS3TrackingStudy/TrackingStudy.h +++ b/Detectors/Upgrades/ITS3/study/include/ITS3TrackingStudy/TrackingStudy.h @@ -18,7 +18,7 @@ namespace o2::its3::study { -o2::framework::DataProcessorSpec getTrackingStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, bool withPV); +o2::framework::DataProcessorSpec getTrackingStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, bool withPV, bool itsStag); } // namespace o2::its3::study diff --git a/Detectors/Upgrades/ITS3/study/src/TrackingStudy.cxx b/Detectors/Upgrades/ITS3/study/src/TrackingStudy.cxx index 04ba817fb5187..2dee7727f2054 100644 --- a/Detectors/Upgrades/ITS3/study/src/TrackingStudy.cxx +++ b/Detectors/Upgrades/ITS3/study/src/TrackingStudy.cxx @@ -18,6 +18,7 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" #include "DataFormatsITSMFT/Digit.h" #include "ITSMFTSimulation/Hit.h" @@ -139,7 +140,7 @@ class TrackingStudySpec final : public Task TrackCounter mTrackCounter; using TrackingCluster = align::TrackingCluster; - std::vector mITScl; + o2::itsmft::ClustersPerLayer mITScl; // addressed by the composed (layer,index) ID std::span mITSclRef; const ITS3TrackingStudyParam* mParams{nullptr}; @@ -237,39 +238,43 @@ void TrackingStudySpec::process() void TrackingStudySpec::prepareITSClusters() { - const auto& clusITS = mRecoData.getITSClusters(); - LOGP(info, "Preparing {} measurments", clusITS.size()); - const auto& patterns = mRecoData.getITSClustersPatterns(); - mITScl.reserve(clusITS.size()); - auto pattIt = patterns.begin(); auto geom = its::GeometryTGeo::Instance(); mITSclRef = mRecoData.getITSTracksClusterRefs(); - mITScl.clear(); - mITScl.reserve(clusITS.size()); - for (const auto& cls : clusITS) { - const auto sens = cls.getSensorID(); - float sigmaY2{0}, sigmaZ2{0}; - math_utils::Point3D locXYZ = o2::its3::ioutils::extractClusterData(cls, pattIt, mITSDict, sigmaY2, sigmaZ2); - // Transformation to the local --> global - const auto gloXYZ = geom->getMatrixL2G(sens) * locXYZ; - // Inverse transformation to the local --> tracking - o2::math_utils::Point3D trkXYZ = geom->getMatrixT2L(sens) ^ locXYZ; - // Tracking alpha angle - // We want that each cluster rotates its tracking frame to the clusters phi - // that way the track linearization around the measurement is less biases to the arc - // this means automatically that the measurement on the arc is at 0 for the curved layers - float alpha = geom->getSensorRefAlpha(sens); - if (constants::detID::isDetITS3(sens)) { - trkXYZ.SetY(0.f); - // alpha&x always have to be defined wrt to the global Z axis! - trkXYZ.SetX(std::hypot(gloXYZ.x(), gloXYZ.y())); - alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); + int nLr = mRecoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITScl.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITScl.beginLayer(lr); + const auto& clusITS = mRecoData.getITSClusters(lr); + const auto& patterns = mRecoData.getITSClustersPatterns(lr); + LOGP(info, "Preparing {} measurments of the layer slot {}", clusITS.size(), lr); + mITScl.getClusters().reserve(mITScl.size() + clusITS.size()); + auto pattIt = patterns.begin(); + for (const auto& cls : clusITS) { + const auto sens = cls.getSensorID(); + float sigmaY2{0}, sigmaZ2{0}; + math_utils::Point3D locXYZ = o2::its3::ioutils::extractClusterData(cls, pattIt, mITSDict, sigmaY2, sigmaZ2); + // Transformation to the local --> global + const auto gloXYZ = geom->getMatrixL2G(sens) * locXYZ; + // Inverse transformation to the local --> tracking + o2::math_utils::Point3D trkXYZ = geom->getMatrixT2L(sens) ^ locXYZ; + // Tracking alpha angle + // We want that each cluster rotates its tracking frame to the clusters phi + // that way the track linearization around the measurement is less biases to the arc + // this means automatically that the measurement on the arc is at 0 for the curved layers + float alpha = geom->getSensorRefAlpha(sens); + if (constants::detID::isDetITS3(sens)) { + trkXYZ.SetY(0.f); + // alpha&x always have to be defined wrt to the global Z axis! + trkXYZ.SetX(std::hypot(gloXYZ.x(), gloXYZ.y())); + alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); + } + auto& cl3d = mITScl.getClusters().emplace_back(sens, trkXYZ); + cl3d.setErrors(sigmaY2, sigmaZ2, 0.f); + cl3d.alpha = alpha; + math_utils::detail::bringToPMPi(cl3d.alpha); // alpha is defined on -Pi,Pi } - auto& cl3d = mITScl.emplace_back(sens, trkXYZ); - cl3d.setErrors(sigmaY2, sigmaZ2, 0.f); - cl3d.alpha = alpha; - math_utils::detail::bringToPMPi(cl3d.alpha); // alpha is defined on -Pi,Pi - } + } // loop over the layer slots + mITScl.finalize(); } bool TrackingStudySpec::selectTrack(GTrackID trkID, bool checkMCTruth) const @@ -787,26 +792,29 @@ void TrackingStudySpec::doMCStudy() } } LOGP(info, "** Creating particle/clusters correspondence ... "); - const auto& clusters = mRecoData.getITSClusters(); - const auto& clustersMCLCont = mRecoData.getITSClustersMCLabels(); - for (auto iCluster{0}; iCluster < clusters.size(); ++iCluster) { - auto labs = clustersMCLCont->getLabels(iCluster); - for (auto& lab : labs) { - if (!lab.isValid() || lab.getSourceID() != 0 || !lab.isCorrect()) { - continue; - } - int trackID = 0, evID = 0, srcID = 0; - bool fake = false; - lab.get(trackID, evID, srcID, fake); - auto& cluster = clusters[iCluster]; - auto layer = o2::its::GeometryTGeo::Instance()->getLayer(cluster.getSensorID()); - auto& part = info[{trackID, evID, srcID}]; - part.clusters |= (1 << layer); - if (fake) { - part.fakeClusters |= (1 << layer); + int nLrCl = mRecoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + for (int lr = 0; lr < nLrCl; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + const auto& clusters = mRecoData.getITSClusters(lr); + const auto& clustersMCLCont = mRecoData.getITSClustersMCLabels(lr); + for (auto iCluster{0}; iCluster < clusters.size(); ++iCluster) { + auto labs = clustersMCLCont->getLabels(iCluster); + for (auto& lab : labs) { + if (!lab.isValid() || lab.getSourceID() != 0 || !lab.isCorrect()) { + continue; + } + int trackID = 0, evID = 0, srcID = 0; + bool fake = false; + lab.get(trackID, evID, srcID, fake); + auto& cluster = clusters[iCluster]; + auto layer = o2::its::GeometryTGeo::Instance()->getLayer(cluster.getSensorID()); + auto& part = info[{trackID, evID, srcID}]; + part.clusters |= (1 << layer); + if (fake) { + part.fakeClusters |= (1 << layer); + } } } - } + } // loop over the layer slots LOGP(info, "** Analysing tracks ... "); auto accountLbl = [&](const globaltracking::RecoContainer::GlobalIDSet& contributorsGID, DetID::ID det) { if (contributorsGID[det].isIndexSet()) { @@ -1242,10 +1250,11 @@ void TrackingStudySpec::getImpactParams(const o2::track::TrackParCov& trk, const ip[1] = trk.getZ() + (trk.getTgl() / rp4 * std::asin((f2 * r1) - (f1 * r2))) - z; } -DataProcessorSpec getTrackingStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, bool withPV) +DataProcessorSpec getTrackingStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, bool withPV, bool itsStag) { std::vector outputs; auto dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(itsStag); dataRequest->requestTracks(srcTracks, useMC); dataRequest->requestIT3Clusters(useMC); diff --git a/Detectors/Upgrades/ITS3/study/src/its3-tracking-study-workflow.cxx b/Detectors/Upgrades/ITS3/study/src/its3-tracking-study-workflow.cxx index c26ce34dea403..f17578b83fe09 100644 --- a/Detectors/Upgrades/ITS3/study/src/its3-tracking-study-workflow.cxx +++ b/Detectors/Upgrades/ITS3/study/src/its3-tracking-study-workflow.cxx @@ -62,6 +62,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); auto useMC = !configcontext.options().get("disable-mc"); auto usePV = !configcontext.options().get("without-pv"); + auto doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources")); @@ -71,7 +72,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); } - specs.emplace_back(o2::its3::study::getTrackingStudySpec(srcTrc, srcCls, useMC, usePV)); + specs.emplace_back(o2::its3::study::getTrackingStudySpec(srcTrc, srcCls, useMC, usePV, doStag)); o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); diff --git a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h index b30be4dd081e3..dcfcdde95da6c 100644 --- a/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h +++ b/Detectors/Vertexing/StrangenessTracking/include/StrangenessTracking/StrangenessTracker.h @@ -19,6 +19,7 @@ #include #include "DataFormatsITSMFT/TopologyDictionary.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "StrangenessTracking/IndexTableUtils.h" #include "StrangenessTracking/StrangenessTrackingConfigParam.h" #include "ReconstructionDataFormats/PID.h" @@ -66,6 +67,7 @@ class StrangenessTracker using PID = o2::track::PID; using TrackITS = o2::its::TrackITS; using ITSCluster = o2::BaseCluster; + using ITSClusters = o2::itsmft::ClustersPerLayer; using V0 = o2::dataformats::V0; using V0Index = o2::dataformats::V0Index; using Cascade = o2::dataformats::Cascade; @@ -247,12 +249,12 @@ class StrangenessTracker auto firstClus = itsTrack.getFirstClusterEntry(); auto ncl = itsTrack.getNumberOfClusters(); for (int icl = 0; icl < ncl; icl++) { - outVec.push_back(mInputClusterSizes[mInputITSidxs[firstClus + icl]]); + outVec.push_back(mInputClusterSizes[mInputITSclusters.flatIndex(mInputITSidxs[firstClus + icl])]); } return outVec; }; - void getClusterSizesITS(std::vector& clusSizeVec, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::itsmft::TopologyDictionary* mdict) + void getClusterSizesITS(std::vector& clusSizeVec, int offs, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::itsmft::TopologyDictionary* mdict) { for (unsigned int iClus{0}; iClus < ITSclus.size(); ++iClus) { auto& clus = ITSclus[iClus]; @@ -268,13 +270,13 @@ class StrangenessTracker npix = mdict->getNpixels(pattID); patt = mdict->getPattern(pattID); } - clusSizeVec[iClus] = npix; + clusSizeVec[offs + iClus] = npix; } // LOG(info) << " Patt Npixel: " << pattVec[0].getNPixels(); } #ifdef ENABLE_UPGRADES - void getClusterSizesIT3(std::vector& clusSizeVec, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::its3::TopologyDictionary* mdict) + void getClusterSizesIT3(std::vector& clusSizeVec, int offs, const gsl::span ITSclus, gsl::span::iterator& pattIt, const o2::its3::TopologyDictionary* mdict) { for (unsigned int iClus{0}; iClus < ITSclus.size(); ++iClus) { auto& clus = ITSclus[iClus]; @@ -291,7 +293,7 @@ class StrangenessTracker npix = mdict->getNpixels(pattID, ib); patt = mdict->getPattern(pattID, ib); } - clusSizeVec[iClus] = npix; + clusSizeVec[offs + iClus] = npix; } } #endif @@ -326,7 +328,7 @@ class StrangenessTracker std::vector mITSvtxBrackets; // time brackets for ITS tracks std::vector mTracksIdxTable; // index table for ITS tracks std::vector mInputClusterSizes; // input cluster sizes - std::vector mInputITSclusters; // input ITS clusters + ITSClusters mInputITSclusters; // input ITS clusters, by composed (layer,index) ID gsl::span mInputITSidxs; // input ITS track-cluster indexes gsl::span mInputV0tracks; // input V0 of decay daughters gsl::span mInputV0Indices; // input V0 indices of decay daughters diff --git a/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx b/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx index 00f903ea42de9..1b7fe53cc7fea 100644 --- a/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx +++ b/Detectors/Vertexing/StrangenessTracking/src/StrangenessTracker.cxx @@ -42,24 +42,32 @@ bool StrangenessTracker::loadData(const o2::globaltracking::RecoContainer& recoD mInputITStracks = recoData.getITSTracks(); mInputITSidxs = recoData.getITSTracksClusterRefs(); - auto compClus = recoData.getITSClusters(); - auto clusPatt = recoData.getITSClustersPatterns(); - auto pattIt = clusPatt.begin(); - auto pattIt2 = clusPatt.begin(); - mInputITSclusters.reserve(compClus.size()); - mInputClusterSizes.resize(compClus.size()); + int nLr = recoData.getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mInputITSclusters.init(nLr); + mInputClusterSizes.clear(); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mInputITSclusters.beginLayer(lr); + auto compClus = recoData.getITSClusters(lr); + auto clusPatt = recoData.getITSClustersPatterns(lr); + auto pattIt = clusPatt.begin(); + auto pattIt2 = clusPatt.begin(); + int offs = (int)mInputClusterSizes.size(); + mInputITSclusters.getClusters().reserve(offs + compClus.size()); + mInputClusterSizes.resize(offs + compClus.size()); #ifdef ENABLE_UPGRADES - if (o2::GlobalParams::Instance().withITS3) { - o2::its3::ioutils::convertCompactClusters(compClus, pattIt, mInputITSclusters, mIT3Dict); - getClusterSizesIT3(mInputClusterSizes, compClus, pattIt2, mIT3Dict); - } else { - o2::its::ioutils::convertCompactClusters(compClus, pattIt, mInputITSclusters, mITSDict); - getClusterSizesITS(mInputClusterSizes, compClus, pattIt2, mITSDict); - } + if (o2::GlobalParams::Instance().withITS3) { + o2::its3::ioutils::convertCompactClusters(compClus, pattIt, mInputITSclusters.getClusters(), mIT3Dict); + getClusterSizesIT3(mInputClusterSizes, offs, compClus, pattIt2, mIT3Dict); + } else { + o2::its::ioutils::convertCompactClusters(compClus, pattIt, mInputITSclusters.getClusters(), mITSDict); + getClusterSizesITS(mInputClusterSizes, offs, compClus, pattIt2, mITSDict); + } #else - o2::its::ioutils::convertCompactClusters(compClus, pattIt, mInputITSclusters, mITSDict); - getClusterSizesITS(mInputClusterSizes, compClus, pattIt2, mITSDict); + o2::its::ioutils::convertCompactClusters(compClus, pattIt, mInputITSclusters.getClusters(), mITSDict); + getClusterSizesITS(mInputClusterSizes, offs, compClus, pattIt2, mITSDict); #endif + } + mInputITSclusters.finalize(); mITSvtxBrackets.resize(mInputITStracks.size()); for (int i = 0; i < mInputITStracks.size(); i++) { diff --git a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h index 6b3ec653c5350..dcbba84a12bec 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h @@ -21,6 +21,7 @@ #include "Framework/DataProcessingHeader.h" #include "DataFormatsTRD/TrackTRD.h" #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/ClustersPerLayer.h" #include "EveWorkflow/EveConfiguration.h" #include "EventVisualisationDataConverter/VisualisationEvent.h" #include "MFTBase/GeometryTGeo.h" @@ -201,7 +202,7 @@ class EveWorkflowHelper std::unordered_map> mPrimaryVertexTriggerGIDs; std::unordered_map mGIDTrackTime; std::vector mItsROFBrackets; - std::vector> mITSClustersArray; + o2::itsmft::ClustersPerLayer> mITSClustersArray; // addressed by the composed (layer,index) ID std::vector> mMFTClustersArray; o2::mft::GeometryTGeo* mMFTGeom; o2::its::GeometryTGeo* mITSGeom; diff --git a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx index b4f7655648001..a906cfcd2a412 100644 --- a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx +++ b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx @@ -618,14 +618,19 @@ void EveWorkflowHelper::addTrackToEvent(const o2::track::TrackPar& tr, GID gid, void EveWorkflowHelper::prepareITSClusters(const o2::itsmft::TopologyDictionary* dict) { - const auto& ITSClusterROFRec = mRecoCont->getITSClustersROFRecords(); - const auto& clusITS = mRecoCont->getITSClusters(); - if (clusITS.size() && ITSClusterROFRec.size()) { - const auto& patterns = mRecoCont->getITSClustersPatterns(); - auto pattIt = patterns.begin(); - mITSClustersArray.reserve(clusITS.size()); - o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, dict); + int nLr = mRecoCont->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1; + mITSClustersArray.init(nLr); + for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0 + mITSClustersArray.beginLayer(lr); + const auto& ITSClusterROFRec = mRecoCont->getITSClustersROFRecords(lr); + const auto& clusITS = mRecoCont->getITSClusters(lr); + if (clusITS.size() && ITSClusterROFRec.size()) { + auto pattIt = mRecoCont->getITSClustersPatterns(lr).begin(); + mITSClustersArray.getClusters().reserve(mITSClustersArray.size() + clusITS.size()); + o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), dict); + } } + mITSClustersArray.finalize(); } void EveWorkflowHelper::prepareMFTClusters( diff --git a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx index 946602d8c4802..b062c436e18c5 100644 --- a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx +++ b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx @@ -372,6 +372,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) }; std::shared_ptr dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(cfgc)); dataRequest->requestTracks(srcTrk, useMC); dataRequest->requestClusters(srcCl, useMC); diff --git a/GPU/Workflow/src/O2GPUDPLDisplay.cxx b/GPU/Workflow/src/O2GPUDPLDisplay.cxx index 4788eb207a344..fa68289517e68 100644 --- a/GPU/Workflow/src/O2GPUDPLDisplay.cxx +++ b/GPU/Workflow/src/O2GPUDPLDisplay.cxx @@ -183,6 +183,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) throw std::runtime_error("No input configured"); } std::shared_ptr dataRequest = std::make_shared(); + dataRequest->setITSPerLayer(o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(cfgc)); dataRequest->requestTracks(srcTrk, useMC); dataRequest->requestClusters(srcCl, useMC);