diff --git a/Detectors/GLOQC/CMakeLists.txt b/Detectors/GLOQC/CMakeLists.txt index cdb307a6515c8..9d2db85460b69 100644 --- a/Detectors/GLOQC/CMakeLists.txt +++ b/Detectors/GLOQC/CMakeLists.txt @@ -15,7 +15,9 @@ o2_add_library(GLOQC SOURCES src/MatchITSTPCQC.cxx src/ITSTPCMatchingQCParams.cxx - PUBLIC_LINK_LIBRARIES O2::DetectorsVertexing) + PUBLIC_LINK_LIBRARIES O2::DetectorsVertexing + PRIVATE_LINK_LIBRARIES O2::GPUO2Interface + O2::GPUTracking) o2_target_root_dictionary(GLOQC HEADERS include/GLOQC/MatchITSTPCQC.h diff --git a/Detectors/GLOQC/include/GLOQC/MatchITSTPCQC.h b/Detectors/GLOQC/include/GLOQC/MatchITSTPCQC.h index 035aada3a765f..83da8e42f3110 100644 --- a/Detectors/GLOQC/include/GLOQC/MatchITSTPCQC.h +++ b/Detectors/GLOQC/include/GLOQC/MatchITSTPCQC.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include "DataFormatsGlobalTracking/RecoContainer.h" @@ -28,6 +29,11 @@ #include "Steer/MCKinematicsReader.h" #include "ReconstructionDataFormats/PID.h" #include "DCAFitter/DCAFitterN.h" +#include "GPUO2InterfaceConfiguration.h" +// #include "GPUSettingsO2.h" +#include "GPUParam.h" +#include "GPUParam.inc" + #include #include #include @@ -63,7 +69,7 @@ class MatchITSTPCQC void setDataRequest(const std::shared_ptr& dr) { mDataRequest = dr; } void finalize(); void reset(); - bool processV0(int iv, o2::globaltracking::RecoContainer& recoData); + bool processV0(int iv, o2::globaltracking::RecoContainer& recoData, std::vector& mTBinClOcc, float pvTime); bool refitV0(const o2::dataformats::V0Index& id, o2::dataformats::V0& v0, o2::globaltracking::RecoContainer& recoData); TH1D* getHistoPtNum(matchType m) const { return mPtNum[m]; } @@ -130,7 +136,7 @@ class MatchITSTPCQC TH1D* getHisto1OverPtPhysPrimDen(matchType m) const { return m1OverPtPhysPrimDen[m]; } TEfficiency* getFractionITSTPCmatchPhysPrim1OverPt(matchType m) const { return mFractionITSTPCmatchPhysPrim1OverPt[m]; } - TH2F* getHistoK0MassVsPt() const { return mK0MassVsPt; } + TH3F* getHistoK0MassVsPtVsOcc() const { return mK0MassVsPtVsOcc; } void getHistos(TObjArray& objar); @@ -228,7 +234,7 @@ class MatchITSTPCQC publisher->startPublishing(mDCArVsPtDen); publisher->startPublishing(mFractionITSTPCmatchDCArVsPt); if (mDoK0QC) { - publisher->startPublishing(mK0MassVsPt); + publisher->startPublishing(mK0MassVsPtVsOcc); } } @@ -408,12 +414,21 @@ class MatchITSTPCQC // for V0s o2::vertexing::DCAFitterN<2> mFitterV0; - TH2F* mK0MassVsPt = nullptr; + TH3F* mK0MassVsPtVsOcc = nullptr; bool mDoK0QC = false; // whether to fill the K0 QC plot(s) float mCutK0Mass = 0.05; // cut on the difference between the K0 mass and the PDG mass bool mRefit = false; // whether to refit or not float mMaxEtaK0 = 0.8; // cut on the K0 eta long int mTimestamp = -1; // timestamp used to load the SVertexParam object: if differnt from -1, we don't load (it means we already did it) + std::unique_ptr mConfig; + std::unique_ptr mConfParam; + // std::unique_ptr mParam; + std::shared_ptr mParam = nullptr; + int mNHBPerTF = 0; + int mNTPCOccBinLength = 0; ///< TPC occ. histo bin length in TBs + float mNTPCOccBinLengthInv; + std::vector mTBinClOcc; ///< TPC occupancy histo: i-th entry is the integrated occupancy for ~1 orbit starting from the TB = i*mNTPCOccBinLength + gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map ClassDefNV(MatchITSTPCQC, 3); }; diff --git a/Detectors/GLOQC/src/MatchITSTPCQC.cxx b/Detectors/GLOQC/src/MatchITSTPCQC.cxx index a0ae896105d2d..f6e249a6939e2 100644 --- a/Detectors/GLOQC/src/MatchITSTPCQC.cxx +++ b/Detectors/GLOQC/src/MatchITSTPCQC.cxx @@ -26,6 +26,11 @@ #include "DetectorsVertexing/SVertexerParams.h" #include "Framework/InputRecord.h" #include "Framework/TimingInfo.h" +#include "GPUO2InterfaceUtils.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsTPC/Constants.h" + +#include "GPUO2InterfaceRefit.h" using namespace o2::gloqc; using namespace o2::mcutils; @@ -42,6 +47,7 @@ MatchITSTPCQC::~MatchITSTPCQC() void MatchITSTPCQC::deleteHistograms() { + LOG(info) << "Deleting histos..."; for (int i = 0; i < matchType::SIZE; ++i) { // Pt delete mPtNum[i]; @@ -124,7 +130,7 @@ void MatchITSTPCQC::deleteHistograms() delete mFractionITSTPCmatchDCArVsPt; // K0 - delete mK0MassVsPt; + delete mK0MassVsPtVsOcc; } //__________________________________________________________ @@ -205,7 +211,7 @@ void MatchITSTPCQC::reset() // K0 if (mDoK0QC) { - mK0MassVsPt->Reset(); + mK0MassVsPtVsOcc->Reset(); } } @@ -375,9 +381,39 @@ bool MatchITSTPCQC::init() } } + // log binning for pT for K0s + const Int_t nbinsPtK0 = 10; + const Double_t xminPtK0 = 0.01; + const Double_t xmaxPtK0 = 20; + Double_t* xbinsPtK0 = new Double_t[nbinsPtK0 + 1]; + Double_t xlogminPtK0 = TMath::Log10(xminPtK0); + Double_t xlogmaxPtK0 = TMath::Log10(xmaxPtK0); + Double_t dlogxPtK0 = (xlogmaxPtK0 - xlogminPtK0) / nbinsPtK0; + for (int i = 0; i <= nbinsPtK0; i++) { + Double_t xlogPtK0 = xlogminPtK0 + i * dlogxPtK0; + xbinsPtK0[i] = TMath::Exp(TMath::Log(10) * xlogPtK0); + } + // the other bins + const Int_t nbinsMassK0 = 100; + Double_t* ybinsMassK0 = new Double_t[nbinsMassK0 + 1]; + Double_t yminMassK0 = 0.4; + Double_t ymaxMassK0 = 0.6; + Double_t dyMassK0 = (ymaxMassK0 - yminMassK0) / nbinsMassK0; + for (int i = 0; i <= nbinsMassK0; i++) { + ybinsMassK0[i] = yminMassK0 + i * dyMassK0; + } + const Int_t nbinsMultK0 = 5; + Double_t* zbinsMultK0 = new Double_t[nbinsMultK0 + 1]; + Double_t zminMultK0 = 100000.; + Double_t zmaxMultK0 = 1000000.; + Double_t dzMultK0 = (zmaxMultK0 - zminMultK0) / nbinsMultK0; + for (int i = 0; i <= nbinsMultK0; i++) { + zbinsMultK0[i] = zminMultK0 + i * dzMultK0; + } + if (mDoK0QC) { // V0s - mK0MassVsPt = new TH2F("mK0MassVsPt", "K0 invariant mass vs Pt; Pt [GeV/c]; K0s mass [GeV/c^2]", 100, 0.f, 20.f, 100, 0.3, 0.7); + mK0MassVsPtVsOcc = new TH3F("mK0MassVsPt", "K0 invariant mass vs Pt; Pt [GeV/c]; K0s mass [GeV/c^2]", nbinsPtK0, xbinsPtK0, nbinsMassK0, ybinsMassK0, nbinsMultK0, zbinsMultK0); } LOG(info) << "Printing configuration cuts"; @@ -404,6 +440,7 @@ void MatchITSTPCQC::initDataRequest() if (mDoK0QC) { mDataRequest->requestPrimaryVertices(mUseMC); mDataRequest->requestSecondaryVertices(mUseMC); + mDataRequest->requestTPCClusters(false); } } @@ -900,6 +937,67 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) const auto pvertices = mRecoCont.getPrimaryVertices(); LOG(info) << "Found " << pvertices.size() << " primary vertices"; + // getting occupancy estimator + mNHBPerTF = o2::base::GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF(); + if (!mParam) { + // for occupancy estimator + mParam = o2::gpu::GPUO2InterfaceUtils::getFullParamShared(0.f, mNHBPerTF); + } + size_t occupancyMapSizeBytes = o2::gpu::GPUO2InterfaceRefit::fillOccupancyMapGetSize(mNHBPerTF, mParam.get()); + LOG(debug) << "occupancyMapSizeBytes = " << occupancyMapSizeBytes; + mTPCRefitterOccMap = mRecoCont.occupancyMapTPC; + o2::gpu::GPUO2InterfaceUtils::paramUseExternalOccupancyMap(mParam.get(), mNHBPerTF, mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size()); + + std::vector mTBinClOcc; ///< TPC occupancy histo: i-th entry is the integrated occupancy for ~1 orbit starting from the TB = i * mNTPCOccBinLength + mTBinClOcc.clear(); + int mNTPCOccBinLength = mParam->rec.tpc.occupancyMapTimeBins; + mNTPCOccBinLengthInv = 1. / mNTPCOccBinLength; + if (mNTPCOccBinLength > 1 && mTPCRefitterOccMap.size()) { + int nTPCBinsInTF = mNHBPerTF * o2::constants::lhc::LHCMaxBunches / 8; // number of TPC time bins in 1 TF, considering that 1 TPC time bin is 8 bunches + int ninteg = 0; + int nTPCOccBinsInTF = nTPCBinsInTF * mNTPCOccBinLengthInv; // how many occupancy bins in 1 TF; mNTPCOccBinLengthInv is the inverse of the length of an occupancy bin + int sumBins = std::max(1, int(o2::constants::lhc::LHCMaxBunches / 8 * mNTPCOccBinLengthInv)); // we will integrate occupancy at max for this number of bins: the max between 1 and the number of occupancy bins in 1 orbit + LOG(debug) << "number of TPC TB in 1 TF = nTPCBinsInTF = " << nTPCBinsInTF << " ; number of occupancy bins in 1 TF = nTPCOccBinsInTF = " << nTPCOccBinsInTF; + LOG(debug) << "bins to integrate = sumBins = " << sumBins; + mTBinClOcc.resize(nTPCOccBinsInTF); + std::vector mltHistTB(nTPCOccBinsInTF); + float sm = 0., tb = 0.5 * mNTPCOccBinLength; + bool foundNotZero = false; + for (int i = 0; i < nTPCOccBinsInTF; i++) { // for every occupancy bin in the TF + mltHistTB[i] = mParam->GetUnscaledMult(tb); + if (mParam->GetUnscaledMult(tb) != 0) { + LOG(debug) << "i = " << i << " tb = " << tb << " mltHistTB[" << i << "] = " << mltHistTB[i]; + foundNotZero = true; + } + tb += mNTPCOccBinLength; + } + if (!foundNotZero) { + LOG(debug) << "No mult bin was found different from 0!"; + } + foundNotZero = false; + // now we fill the occupancy map; we integrate the sumBins after the current one, but when we are at the last 27 bins of the TF, where we integrate what we have left till the end of the TF; for practical reasons, we start from the end, adding all the time, and then also removing the last bin, when we have enough, so that we always add together sumBins bins (except, as said, for the last part of the TF) + for (int i = nTPCOccBinsInTF; i--;) { + if (mltHistTB[i] != 0) { + foundNotZero = true; + } + LOG(debug) << "i = " << i << " sm before = " << sm; + sm += mltHistTB[i]; + LOG(debug) << "i = " << i << " sm after = " << sm; + if (i + sumBins < nTPCOccBinsInTF) { + LOG(debug) << "i = " << i << " sumBins = " << sumBins << " nTPCOccBinsInTF = " << nTPCOccBinsInTF << " we have to decrease sm by = " << mltHistTB[i + sumBins]; + sm -= mltHistTB[i + sumBins]; + LOG(debug) << "i = " << i << " sm after 2 = " << sm; + } + mTBinClOcc[i] = sm; + LOG(debug) << "i = " << i << " mTBinClOcc[" << i << "] = " << mTBinClOcc[i]; + } + if (!foundNotZero) { + LOG(debug) << "No mult bin was found different from 0! sm = " << sm; + } + } else { + mTBinClOcc.resize(1); + } + auto v0IDs = mRecoCont.getV0sIdx(); auto nv0 = v0IDs.size(); if (nv0 > mRecoCont.getV0s().size()) { @@ -922,8 +1020,10 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) if (pvID < 0 || vv.size() == 0) { continue; } + const auto& pv = mRecoCont.getPrimaryVertex(pvID); + float pvTime = pv.getTimeStamp().getTimeStamp(); // in \mus for (int iv0 : vv) { - nV0sOk += processV0(iv0, mRecoCont) ? 1 : 0; + nV0sOk += processV0(iv0, mRecoCont, mTBinClOcc, pvTime) ? 1 : 0; } } @@ -933,7 +1033,7 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) } //__________________________________________________________ -bool MatchITSTPCQC::processV0(int iv, o2::globaltracking::RecoContainer& recoData) +bool MatchITSTPCQC::processV0(int iv, o2::globaltracking::RecoContainer& recoData, std::vector& mTBinClOcc, float pvTime) { o2::dataformats::V0 v0; auto v0s = recoData.getV0s(); @@ -948,11 +1048,15 @@ bool MatchITSTPCQC::processV0(int iv, o2::globaltracking::RecoContainer& recoDat if (mMaxEtaK0 < std::abs(v0sel.getEta())) { return false; } - LOG(info) << "Find K0 with mass " << std::sqrt(v0sel.calcMass2AsK0()); if (mCutK0Mass > 0 && std::abs(std::sqrt(v0sel.calcMass2AsK0()) - 0.497) > mCutK0Mass) { return false; } - mK0MassVsPt->Fill(v0sel.getPt(), std::sqrt(v0sel.calcMass2AsK0())); + // get the corresponding PV + int tb = pvTime / (8 * o2::constants::lhc::LHCBunchSpacingMUS) * mNTPCOccBinLengthInv; // V0 time in TPC time bins + LOG(debug) << "pvTime = " << pvTime << " tb = " << tb; + float mltTPC = tb < 0 ? mTBinClOcc[0] : (tb >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[tb]); + LOG(debug) << "Filling plot with pt = " << v0sel.getPt() << " mass = " << std::sqrt(v0sel.calcMass2AsK0()) << " mult TPC = " << mltTPC; + mK0MassVsPtVsOcc->Fill(v0sel.getPt(), std::sqrt(v0sel.calcMass2AsK0()), mltTPC); return true; } @@ -1228,5 +1332,5 @@ void MatchITSTPCQC::getHistos(TObjArray& objar) objar.Add(mFractionITSTPCmatchDCArVsPt); // V0 - objar.Add(mK0MassVsPt); + objar.Add(mK0MassVsPtVsOcc); } diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index a4ca1f126f013..2fd512e8f7cfb 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -166,6 +166,7 @@ set(HDRS_INSTALL TRDTracking/GPUTRDTrackletLabels.h TRDTracking/GPUTRDTrackPoint.h TRDTracking/GPUTRDTrackPoint.h + DataTypes/GPUTPCGMPolynomialField.h ) # Sources for O2 and for Standalone if requested in config file diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx index f81da3b52ad1b..55122b7de4af6 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx @@ -99,35 +99,26 @@ size_t GPUO2InterfaceRefit::fillOccupancyMapGetSize(unsigned int nHbfPerTf, cons GPUO2InterfaceRefit::GPUO2InterfaceRefit(const ClusterNativeAccess* cl, const CorrectionMapsHelper* trans, float bzNominalGPU, const TPCClRefElem* trackRef, unsigned int nHbfPerTf, const unsigned char* sharedmap, const unsigned int* occupancymap, int occupancyMapSize, const std::vector* trks, o2::base::Propagator* p) { mParam = GPUO2InterfaceUtils::getFullParam(bzNominalGPU, nHbfPerTf); - size_t expectedSharedMapSize = nHbfPerTf ? fillOccupancyMapGetSize(nHbfPerTf, mParam.get()) : 0; + size_t expectedOccMapSize = nHbfPerTf ? fillOccupancyMapGetSize(nHbfPerTf, mParam.get()) : 0; if (cl->nClustersTotal) { if (sharedmap == nullptr && trks == nullptr) { throw std::runtime_error("Must provide either shared cluster map or vector of tpc tracks to build the map"); } - if ((sharedmap == nullptr) ^ (expectedSharedMapSize && occupancymap == nullptr)) { + if ((sharedmap == nullptr) ^ (expectedOccMapSize && occupancymap == nullptr)) { throw std::runtime_error("Must provide either both shared cluster map and occupancy map or none of them"); } if (sharedmap == nullptr) { mSharedMap.resize(cl->nClustersTotal); sharedmap = mSharedMap.data(); - mOccupancyMap.resize(expectedSharedMapSize / sizeof(*mOccupancyMap.data())); + mOccupancyMap.resize(expectedOccMapSize / sizeof(*mOccupancyMap.data())); occupancymap = mOccupancyMap.data(); + occupancyMapSize = expectedOccMapSize; fillSharedClustersAndOccupancyMap(cl, *trks, trackRef, mSharedMap.data(), mOccupancyMap.data(), nHbfPerTf, mParam.get()); } } - if (occupancymap && occupancyMapSize > sizeof(*occupancymap) && occupancymap[1] != (mParam->rec.tpc.occupancyMapTimeBins * 0x10000 + mParam->rec.tpc.occupancyMapTimeBinsAverage)) { - throw std::runtime_error("Occupancy map has invalid paramters occupancyMapTimeBins and occupancyMapTimeBinsAverage"); - } - if (occupancyMapSize != -1 && nHbfPerTf && (size_t)occupancyMapSize != expectedSharedMapSize) { - throw std::runtime_error("Received occupancy map of wrong size, most likely --configKeyValues or HBperTF of map creator and map consumer are different"); - } + GPUO2InterfaceUtils::paramUseExternalOccupancyMap(mParam.get(), nHbfPerTf, occupancymap, occupancyMapSize); + mRefit = std::make_unique(); - if (occupancymap) { - mParam->occupancyTotal = *occupancymap; - if (mParam->rec.tpc.occupancyMapTimeBins) { - mParam->occupancyMap = occupancymap + 2; - } - } mRefit->SetGPUParam(mParam.get()); mRefit->SetClusterStateArray(sharedmap); mRefit->SetPropagator(p); diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx index f56e3dde1ea48..bb9c38c291fe2 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx @@ -14,6 +14,7 @@ #include "GPUO2InterfaceUtils.h" #include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceRefit.h" #include "TPCPadGainCalib.h" #include "CalibdEdxContainer.h" #include "TPCBase/Sector.h" @@ -115,3 +116,20 @@ std::shared_ptr GPUO2InterfaceUtils::getFullParamShared(float solenoid { return std::move(getFullParam(solenoidBz, nHbfPerTf, pConfiguration, pO2Settings, autoMaxTimeBin)); } + +void GPUO2InterfaceUtils::paramUseExternalOccupancyMap(GPUParam* param, unsigned int nHbfPerTf, const unsigned int* occupancymap, int occupancyMapSize) +{ + size_t expectedOccMapSize = nHbfPerTf ? GPUO2InterfaceRefit::fillOccupancyMapGetSize(nHbfPerTf, param) : 0; + if (occupancyMapSize != -1 && nHbfPerTf && (size_t)occupancyMapSize != expectedOccMapSize) { + throw std::runtime_error("Received occupancy map of wrong size, most likely --configKeyValues or HBperTF of map creator and map consumer are different"); + } + if (occupancymap && occupancyMapSize > sizeof(*occupancymap) && occupancymap[1] != (param->rec.tpc.occupancyMapTimeBins * 0x10000 + param->rec.tpc.occupancyMapTimeBinsAverage)) { + throw std::runtime_error("Occupancy map has invalid paramters occupancyMapTimeBins and occupancyMapTimeBinsAverage"); + } + if (occupancymap) { + param->occupancyTotal = *occupancymap; + if (param->rec.tpc.occupancyMapTimeBins) { + param->occupancyMap = occupancymap + 2; + } + } +} diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h index c375f4d646a00..d2c3ee495c9ea 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h @@ -57,6 +57,7 @@ class GPUO2InterfaceUtils } static std::unique_ptr getFullParam(float solenoidBz, unsigned int nHbfPerTf = 0, std::unique_ptr* pConfiguration = nullptr, std::unique_ptr* pO2Settings = nullptr, bool* autoMaxTimeBin = nullptr); static std::shared_ptr getFullParamShared(float solenoidBz, unsigned int nHbfPerTf = 0, std::unique_ptr* pConfiguration = nullptr, std::unique_ptr* pO2Settings = nullptr, bool* autoMaxTimeBin = nullptr); // Return owning pointer + static void paramUseExternalOccupancyMap(GPUParam* param, unsigned int nHbfPerTf, const unsigned int* occupancymap, int occupancyMapSize); class GPUReconstructionZSDecoder {